2007-03-20 [colin] 2.8.1cvs23
[claws.git] / src / imap.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include "defs.h"
25
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include "imap.h"
31 #include "imap_gtk.h"
32 #include "inc.h"
33 #include "xml.h"
34 #include "alertpanel.h"
35
36 #ifdef HAVE_LIBETPAN
37
38 #include <stdlib.h>
39 #include <dirent.h>
40 #include <unistd.h>
41 #include <ctype.h>
42 #include <time.h>
43 #include <errno.h>
44 #if HAVE_ICONV
45 #  include <iconv.h>
46 #endif
47
48 #if USE_OPENSSL
49 #  include "ssl.h"
50 #endif
51
52 #include "folder.h"
53 #include "session.h"
54 #include "procmsg.h"
55 #include "socket.h"
56 #include "recv.h"
57 #include "procheader.h"
58 #include "prefs_account.h"
59 #include "codeconv.h"
60 #include "md5.h"
61 #include "base64.h"
62 #include "utils.h"
63 #include "prefs_common.h"
64 #include "inputdialog.h"
65 #include "log.h"
66 #include "remotefolder.h"
67 #include "claws.h"
68 #include "statusbar.h"
69 #include "msgcache.h"
70 #include "imap-thread.h"
71 #include "account.h"
72
73 typedef struct _IMAPFolder      IMAPFolder;
74 typedef struct _IMAPSession     IMAPSession;
75 typedef struct _IMAPNameSpace   IMAPNameSpace;
76 typedef struct _IMAPFolderItem  IMAPFolderItem;
77
78 #include "prefs_account.h"
79
80 #define IMAP_FOLDER(obj)        ((IMAPFolder *)obj)
81 #define IMAP_FOLDER_ITEM(obj)   ((IMAPFolderItem *)obj)
82 #define IMAP_SESSION(obj)       ((IMAPSession *)obj)
83
84 struct _IMAPFolder
85 {
86         RemoteFolder rfolder;
87
88         /* list of IMAPNameSpace */
89         GList *ns_personal;
90         GList *ns_others;
91         GList *ns_shared;
92         gchar last_seen_separator;
93         guint refcnt;
94 };
95
96 struct _IMAPSession
97 {
98         Session session;
99
100         gboolean authenticated;
101
102         GSList *capability;
103         gboolean uidplus;
104
105         gchar *mbox;
106         guint cmd_count;
107
108         /* CLAWS */
109         gboolean folder_content_changed;
110         guint exists;
111         Folder * folder;
112         gboolean busy;
113 };
114
115 struct _IMAPNameSpace
116 {
117         gchar *name;
118         gchar separator;
119 };
120
121 #define IMAP_SUCCESS    0
122 #define IMAP_SOCKET     2
123 #define IMAP_AUTHFAIL   3
124 #define IMAP_PROTOCOL   4
125 #define IMAP_SYNTAX     5
126 #define IMAP_IOERR      6
127 #define IMAP_ERROR      7
128
129 #define IMAPBUFSIZE     8192
130
131 typedef enum
132 {
133         IMAP_FLAG_SEEN          = 1 << 0,
134         IMAP_FLAG_ANSWERED      = 1 << 1,
135         IMAP_FLAG_FLAGGED       = 1 << 2,
136         IMAP_FLAG_DELETED       = 1 << 3,
137         IMAP_FLAG_DRAFT         = 1 << 4
138 } IMAPFlags;
139
140 #define IMAP_IS_SEEN(flags)     ((flags & IMAP_FLAG_SEEN) != 0)
141 #define IMAP_IS_ANSWERED(flags) ((flags & IMAP_FLAG_ANSWERED) != 0)
142 #define IMAP_IS_FLAGGED(flags)  ((flags & IMAP_FLAG_FLAGGED) != 0)
143 #define IMAP_IS_DELETED(flags)  ((flags & IMAP_FLAG_DELETED) != 0)
144 #define IMAP_IS_DRAFT(flags)    ((flags & IMAP_FLAG_DRAFT) != 0)
145
146
147 #define IMAP4_PORT      143
148 #if USE_OPENSSL
149 #define IMAPS_PORT      993
150 #endif
151
152 #define IMAP_CMD_LIMIT  1000
153
154 struct _IMAPFolderItem
155 {
156         FolderItem item;
157
158         guint lastuid;
159         guint uid_next;
160         GSList *uid_list;
161         gboolean batching;
162
163         time_t use_cache;
164         gint c_messages;
165         guint32 c_uid_next;
166         guint32 c_uid_validity;
167         gint c_unseen;
168
169         GHashTable *flags_set_table;
170         GHashTable *flags_unset_table;
171 };
172
173 static XMLTag *imap_item_get_xml(Folder *folder, FolderItem *item);
174 static void imap_item_set_xml(Folder *folder, FolderItem *item, XMLTag *tag);
175
176 static void imap_folder_init            (Folder         *folder,
177                                          const gchar    *name,
178                                          const gchar    *path);
179
180 static Folder   *imap_folder_new        (const gchar    *name,
181                                          const gchar    *path);
182 static void      imap_folder_destroy    (Folder         *folder);
183
184 static IMAPSession *imap_session_new    (Folder         *folder,
185                                          const PrefsAccount     *account);
186 static void     imap_session_authenticate(IMAPSession           *session,
187                                           const PrefsAccount    *account);
188 static void     imap_session_destroy    (Session        *session);
189
190 static gchar   *imap_fetch_msg          (Folder         *folder, 
191                                          FolderItem     *item, 
192                                          gint            uid);
193 static gchar   *imap_fetch_msg_full     (Folder         *folder, 
194                                          FolderItem     *item, 
195                                          gint            uid,
196                                          gboolean        headers,
197                                          gboolean        body);
198 static gint     imap_add_msg            (Folder         *folder,
199                                          FolderItem     *dest,
200                                          const gchar    *file, 
201                                          MsgFlags       *flags);
202 static gint     imap_add_msgs           (Folder         *folder, 
203                                          FolderItem     *dest,
204                                          GSList         *file_list,
205                                          GRelation      *relation);
206
207 static gint     imap_copy_msg           (Folder         *folder,
208                                          FolderItem     *dest, 
209                                          MsgInfo        *msginfo);
210 static gint     imap_copy_msgs          (Folder         *folder, 
211                                          FolderItem     *dest, 
212                                          MsgInfoList    *msglist, 
213                                          GRelation      *relation);
214
215 static gint     imap_remove_msg         (Folder         *folder, 
216                                          FolderItem     *item, 
217                                          gint            uid);
218 static gint     imap_remove_msgs        (Folder         *folder, 
219                                          FolderItem     *dest, 
220                                          MsgInfoList    *msglist, 
221                                          GRelation      *relation);
222 static gint     imap_remove_all_msg     (Folder         *folder, 
223                                          FolderItem     *item);
224
225 static gboolean imap_is_msg_changed     (Folder         *folder,
226                                          FolderItem     *item, 
227                                          MsgInfo        *msginfo);
228
229 static gint     imap_close              (Folder         *folder, 
230                                          FolderItem     *item);
231
232 static gint     imap_scan_tree          (Folder         *folder);
233
234 static gint     imap_create_tree        (Folder         *folder);
235
236 static FolderItem *imap_create_folder   (Folder         *folder,
237                                          FolderItem     *parent,
238                                          const gchar    *name);
239 static gint     imap_rename_folder      (Folder         *folder,
240                                          FolderItem     *item, 
241                                          const gchar    *name);
242 static gint     imap_remove_folder      (Folder         *folder, 
243                                          FolderItem     *item);
244
245 static FolderItem *imap_folder_item_new (Folder         *folder);
246 static void imap_folder_item_destroy    (Folder         *folder,
247                                          FolderItem     *item);
248
249 static IMAPSession *imap_session_get    (Folder         *folder);
250
251 static gint imap_auth                   (IMAPSession    *session,
252                                          const gchar    *user,
253                                          const gchar    *pass,
254                                          IMAPAuthType    type);
255
256 static gint imap_scan_tree_recursive    (IMAPSession    *session,
257                                          FolderItem     *item,
258                                          gboolean        subs_only);
259
260 static void imap_create_missing_folders (Folder         *folder);
261 static FolderItem *imap_create_special_folder
262                                         (Folder                 *folder,
263                                          SpecialFolderItemType   stype,
264                                          const gchar            *name);
265
266 static gint imap_do_copy_msgs           (Folder         *folder,
267                                          FolderItem     *dest,
268                                          MsgInfoList    *msglist,
269                                          GRelation      *relation);
270
271 static void imap_delete_all_cached_messages     (FolderItem     *item);
272 static void imap_set_batch              (Folder         *folder,
273                                          FolderItem     *item,
274                                          gboolean        batch);
275 static gint imap_set_message_flags      (IMAPSession    *session,
276                                          MsgNumberList  *numlist,
277                                          IMAPFlags       flags,
278                                          gboolean        is_set);
279 static gint imap_select                 (IMAPSession    *session,
280                                          IMAPFolder     *folder,
281                                          const gchar    *path,
282                                          gint           *exists,
283                                          gint           *recent,
284                                          gint           *unseen,
285                                          guint32        *uid_validity,
286                                          gboolean        block);
287 static gint imap_status                 (IMAPSession    *session,
288                                          IMAPFolder     *folder,
289                                          const gchar    *path,
290                                          IMAPFolderItem *item,
291                                          gint           *messages,
292                                          guint32        *uid_next,
293                                          guint32        *uid_validity,
294                                          gint           *unseen,
295                                          gboolean        block);
296
297 static gchar imap_get_path_separator            (IMAPSession    *session,
298                                                  IMAPFolder     *folder,
299                                                  const gchar    *path);
300 static gchar *imap_get_real_path                (IMAPSession    *session,
301                                                  IMAPFolder     *folder,
302                                                  const gchar    *path);
303 static void imap_synchronise            (FolderItem     *item);
304
305 static void imap_free_capabilities      (IMAPSession    *session);
306
307 /* low-level IMAP4rev1 commands */
308 static gint imap_cmd_login      (IMAPSession    *session,
309                                  const gchar    *user,
310                                  const gchar    *pass,
311                                  const gchar    *type);
312 static gint imap_cmd_noop       (IMAPSession    *session);
313 #if USE_OPENSSL
314 static gint imap_cmd_starttls   (IMAPSession    *session);
315 #endif
316 static gint imap_cmd_select     (IMAPSession    *session,
317                                  const gchar    *folder,
318                                  gint           *exists,
319                                  gint           *recent,
320                                  gint           *unseen,
321                                  guint32        *uid_validity,
322                                  gboolean        block);
323 static gint imap_cmd_examine    (IMAPSession    *session,
324                                  const gchar    *folder,
325                                  gint           *exists,
326                                  gint           *recent,
327                                  gint           *unseen,
328                                  guint32        *uid_validity,
329                                  gboolean        block);
330 static gint imap_cmd_create     (IMAPSession    *sock,
331                                  const gchar    *folder);
332 static gint imap_cmd_rename     (IMAPSession    *sock,
333                                  const gchar    *oldfolder,
334                                  const gchar    *newfolder);
335 static gint imap_cmd_delete     (IMAPSession    *session,
336                                  const gchar    *folder);
337 static gint imap_cmd_fetch      (IMAPSession    *sock,
338                                  guint32         uid,
339                                  const gchar    *filename,
340                                  gboolean        headers,
341                                  gboolean        body);
342 static gint imap_cmd_append     (IMAPSession    *session,
343                                  const gchar    *destfolder,
344                                  const gchar    *file,
345                                  IMAPFlags       flags,
346                                  guint32        *new_uid);
347 static gint imap_cmd_copy       (IMAPSession *session,
348                                  struct mailimap_set * set,
349                                  const gchar *destfolder,
350                                  GRelation *uid_mapping,
351                                  struct mailimap_set ** source,
352                                  struct mailimap_set ** dest);
353 static gint imap_cmd_store      (IMAPSession    *session,
354                                  struct mailimap_set * set,
355                                  IMAPFlags flags,
356                                  int do_add);
357 static gint imap_cmd_expunge    (IMAPSession    *session);
358
359 static void imap_path_separator_subst           (gchar          *str,
360                                                  gchar           separator);
361
362 static gchar *imap_utf8_to_modified_utf7        (const gchar    *from);
363 static gchar *imap_modified_utf7_to_utf8        (const gchar    *mutf7_str);
364
365 static gboolean imap_rename_folder_func         (GNode          *node,
366                                                  gpointer        data);
367 static gint imap_get_num_list                   (Folder         *folder,
368                                                  FolderItem     *item,
369                                                  GSList        **list,
370                                                  gboolean       *old_uids_valid);
371 static GSList *imap_get_msginfos                (Folder         *folder,
372                                                  FolderItem     *item,
373                                                  GSList         *msgnum_list);
374 static MsgInfo *imap_get_msginfo                (Folder         *folder,
375                                                  FolderItem     *item,
376                                                  gint            num);
377 static gboolean imap_scan_required              (Folder         *folder,
378                                                  FolderItem     *item);
379 static void imap_change_flags                   (Folder         *folder,
380                                                  FolderItem     *item,
381                                                  MsgInfo        *msginfo,
382                                                  MsgPermFlags    newflags);
383 static gint imap_get_flags                      (Folder         *folder,
384                                                  FolderItem     *item,
385                                                  MsgInfoList    *msglist,
386                                                  GRelation      *msgflags);
387 static gchar *imap_folder_get_path              (Folder         *folder);
388 static gchar *imap_item_get_path                (Folder         *folder,
389                                                  FolderItem     *item);
390 static MsgInfo *imap_parse_msg(const gchar *file, FolderItem *item);
391
392
393 /* data types conversion libetpan <-> claws */
394 static GSList * imap_list_from_lep(IMAPFolder * folder,
395                                    clist * list, const gchar * real_path, gboolean all);
396 static GSList * imap_get_lep_set_from_numlist(MsgNumberList *numlist);
397 static GSList * imap_get_lep_set_from_msglist(MsgInfoList *msglist);
398 static GSList * imap_uid_list_from_lep(clist * list);
399 static GSList * imap_uid_list_from_lep_tab(carray * list);
400 static MsgInfo *imap_envelope_from_lep(struct imap_fetch_env_info * info,
401                                        FolderItem *item);
402 static void imap_lep_set_free(GSList *seq_list);
403 static struct mailimap_flag_list * imap_flag_to_lep(IMAPFlags flags);
404
405 typedef struct _hashtable_data {
406         IMAPSession *session;
407         GSList *msglist;
408         IMAPFolderItem *item;
409 } hashtable_data;
410
411 static FolderClass imap_class;
412
413 typedef struct _thread_data {
414         gchar *server;
415         gushort port;
416         gboolean done;
417         SockInfo *sock;
418 #ifdef USE_OPENSSL
419         SSLType ssl_type;
420 #endif
421 } thread_data;
422
423 FolderClass *imap_get_class(void)
424 {
425         if (imap_class.idstr == NULL) {
426                 imap_class.type = F_IMAP;
427                 imap_class.idstr = "imap";
428                 imap_class.uistr = "IMAP4";
429
430                 /* Folder functions */
431                 imap_class.new_folder = imap_folder_new;
432                 imap_class.destroy_folder = imap_folder_destroy;
433                 imap_class.scan_tree = imap_scan_tree;
434                 imap_class.create_tree = imap_create_tree;
435
436                 /* FolderItem functions */
437                 imap_class.item_new = imap_folder_item_new;
438                 imap_class.item_destroy = imap_folder_item_destroy;
439                 imap_class.item_get_path = imap_item_get_path;
440                 imap_class.create_folder = imap_create_folder;
441                 imap_class.rename_folder = imap_rename_folder;
442                 imap_class.remove_folder = imap_remove_folder;
443                 imap_class.close = imap_close;
444                 imap_class.get_num_list = imap_get_num_list;
445                 imap_class.scan_required = imap_scan_required;
446                 imap_class.set_xml = folder_set_xml;
447                 imap_class.get_xml = folder_get_xml;
448                 imap_class.item_set_xml = imap_item_set_xml;
449                 imap_class.item_get_xml = imap_item_get_xml;
450
451                 /* Message functions */
452                 imap_class.get_msginfo = imap_get_msginfo;
453                 imap_class.get_msginfos = imap_get_msginfos;
454                 imap_class.fetch_msg = imap_fetch_msg;
455                 imap_class.fetch_msg_full = imap_fetch_msg_full;
456                 imap_class.add_msg = imap_add_msg;
457                 imap_class.add_msgs = imap_add_msgs;
458                 imap_class.copy_msg = imap_copy_msg;
459                 imap_class.copy_msgs = imap_copy_msgs;
460                 imap_class.remove_msg = imap_remove_msg;
461                 imap_class.remove_msgs = imap_remove_msgs;
462                 imap_class.remove_all_msg = imap_remove_all_msg;
463                 imap_class.is_msg_changed = imap_is_msg_changed;
464                 imap_class.change_flags = imap_change_flags;
465                 imap_class.get_flags = imap_get_flags;
466                 imap_class.set_batch = imap_set_batch;
467                 imap_class.synchronise = imap_synchronise;
468 #ifdef USE_PTREAD
469                 pthread_mutex_init(&imap_mutex, NULL);
470 #endif
471         }
472         
473         return &imap_class;
474 }
475
476 static Folder *imap_folder_new(const gchar *name, const gchar *path)
477 {
478         Folder *folder;
479
480         folder = (Folder *)g_new0(IMAPFolder, 1);
481         folder->klass = &imap_class;
482         imap_folder_init(folder, name, path);
483
484         return folder;
485 }
486
487 static void imap_folder_destroy(Folder *folder)
488 {
489         while (imap_folder_get_refcnt(folder) > 0)
490                 gtk_main_iteration();
491         
492         folder_remote_folder_destroy(REMOTE_FOLDER(folder));
493         imap_done(folder);
494 }
495
496 static void imap_folder_init(Folder *folder, const gchar *name,
497                              const gchar *path)
498 {
499         folder_remote_folder_init((Folder *)folder, name, path);
500 }
501
502 static FolderItem *imap_folder_item_new(Folder *folder)
503 {
504         IMAPFolderItem *item;
505         
506         item = g_new0(IMAPFolderItem, 1);
507         item->lastuid = 0;
508         item->uid_next = 0;
509         item->uid_list = NULL;
510
511         return (FolderItem *)item;
512 }
513
514 static void imap_folder_item_destroy(Folder *folder, FolderItem *_item)
515 {
516         IMAPFolderItem *item = (IMAPFolderItem *)_item;
517
518         g_return_if_fail(item != NULL);
519         g_slist_free(item->uid_list);
520
521         g_free(_item);
522 }
523
524 static gboolean imap_reset_uid_lists_func(GNode *node, gpointer data)
525 {
526         IMAPFolderItem *item = (IMAPFolderItem *)node->data;
527         
528         item->lastuid = 0;
529         g_slist_free(item->uid_list);
530         item->uid_list = NULL;
531         
532         return FALSE;
533 }
534
535 static void imap_reset_uid_lists(Folder *folder)
536 {
537         if(folder->node == NULL)
538                 return;
539         
540         /* Destroy all uid lists and rest last uid */
541         g_node_traverse(folder->node, G_IN_ORDER, G_TRAVERSE_ALL, -1, imap_reset_uid_lists_func, NULL); 
542 }
543
544 static int imap_get_capabilities(IMAPSession *session)
545 {
546         struct mailimap_capability_data *capabilities = NULL;
547         clistiter *cur;
548         int result = -1;
549
550         if (session->capability != NULL)
551                 return MAILIMAP_NO_ERROR;
552
553         capabilities = imap_threaded_capability(session->folder, &result);
554
555         if (result != MAILIMAP_NO_ERROR) {
556                 return MAILIMAP_ERROR_CAPABILITY;
557         }
558
559         if (capabilities == NULL) {
560                 return MAILIMAP_NO_ERROR;
561         }
562
563         for(cur = clist_begin(capabilities->cap_list) ; cur != NULL ;
564             cur = clist_next(cur)) {
565                 struct mailimap_capability * cap = 
566                         clist_content(cur);
567                 if (!cap || cap->cap_data.cap_name == NULL)
568                         continue;
569                 session->capability = g_slist_append
570                                 (session->capability,
571                                  g_strdup(cap->cap_data.cap_name));
572                 debug_print("got capa %s\n", cap->cap_data.cap_name);
573         }
574         mailimap_capability_data_free(capabilities);
575         return MAILIMAP_NO_ERROR;
576 }
577
578 static gboolean imap_has_capability(IMAPSession *session, const gchar *cap) 
579 {
580         GSList *cur;
581         for (cur = session->capability; cur; cur = cur->next) {
582                 if (!g_ascii_strcasecmp(cur->data, cap))
583                         return TRUE;
584         }
585         return FALSE;
586 }
587
588 static gint imap_auth(IMAPSession *session, const gchar *user, const gchar *pass,
589                       IMAPAuthType type)
590 {
591         gint ok = IMAP_ERROR;
592         static time_t last_login_err = 0;
593         gchar *ext_info = "";
594         
595         if (imap_get_capabilities(session) != MAILIMAP_NO_ERROR)
596                 return IMAP_ERROR;
597
598         switch(type) {
599         case IMAP_AUTH_ANON:
600                 ok = imap_cmd_login(session, user, pass, "ANONYMOUS");
601                 break;
602         case IMAP_AUTH_CRAM_MD5:
603                 ok = imap_cmd_login(session, user, pass, "CRAM-MD5");
604                 break;
605         case IMAP_AUTH_LOGIN:
606                 ok = imap_cmd_login(session, user, pass, "LOGIN");
607                 break;
608         case IMAP_AUTH_GSSAPI:
609                 ok = imap_cmd_login(session, user, pass, "GSSAPI");
610                 break;
611         default:
612                 debug_print("capabilities:\n"
613                                 "\t ANONYMOUS %d\n"
614                                 "\t CRAM-MD5 %d\n"
615                                 "\t LOGIN %d\n"
616                                 "\t GSSAPI %d\n", 
617                         imap_has_capability(session, "ANONYMOUS"),
618                         imap_has_capability(session, "CRAM-MD5"),
619                         imap_has_capability(session, "LOGIN"),
620                         imap_has_capability(session, "GSSAPI"));
621                 if (imap_has_capability(session, "CRAM-MD5"))
622                         ok = imap_cmd_login(session, user, pass, "CRAM-MD5");
623                 if (ok == IMAP_ERROR && imap_has_capability(session, "GSSAPI"))
624                         ok = imap_cmd_login(session, user, pass, "GSSAPI");
625                 if (ok == IMAP_ERROR) /* we always try LOGIN before giving up */
626                         ok = imap_cmd_login(session, user, pass, "LOGIN");
627         }
628
629         if (ok == IMAP_SUCCESS)
630                 session->authenticated = TRUE;
631         else {
632                 if (type == IMAP_AUTH_CRAM_MD5) {
633                         ext_info = _("\n\nCRAM-MD5 logins only work if libetpan has been "
634                                      "compiled with SASL support and the "
635                                      "CRAM-MD5 SASL plugin is installed.");
636                 } 
637
638                 if (time(NULL) - last_login_err > 10) {
639                         if (!prefs_common.no_recv_err_panel) {
640                                 alertpanel_error(_("Connection to %s failed: "
641                                         "login refused.%s"),
642                                         SESSION(session)->server, ext_info);
643                         } else {
644                                 log_error(_("Connection to %s failed: "
645                                         "login refused.%s\n"),
646                                         SESSION(session)->server, ext_info);
647                         }
648                 }
649                 last_login_err = time(NULL);
650         }
651         return ok;
652 }
653
654 static IMAPSession *imap_reconnect_if_possible(Folder *folder, IMAPSession *session)
655 {
656         RemoteFolder *rfolder = REMOTE_FOLDER(folder);
657         /* Check if this is the first try to establish a
658            connection, if yes we don't try to reconnect */
659         debug_print("reconnecting\n");
660         if (rfolder->session == NULL) {
661                 log_warning(_("Connecting to %s failed"),
662                             folder->account->recv_server);
663                 session_destroy(SESSION(session));
664                 session = NULL;
665         } else {
666                 log_warning(_("IMAP4 connection to %s has been"
667                             " disconnected. Reconnecting...\n"),
668                             folder->account->recv_server);
669                 statusbar_print_all(_("IMAP4 connection to %s has been"
670                             " disconnected. Reconnecting...\n"),
671                             folder->account->recv_server);
672                 SESSION(session)->state = SESSION_DISCONNECTED;
673                 session_destroy(SESSION(session));
674                 /* Clear folders session to make imap_session_get create
675                    a new session, because of rfolder->session == NULL
676                    it will not try to reconnect again and so avoid an
677                    endless loop */
678                 rfolder->session = NULL;
679                 debug_print("getting session...\n");
680                 session = imap_session_get(folder);
681                 rfolder->session = SESSION(session);
682                 statusbar_pop_all();
683         }
684         return session;
685 }
686
687 #define lock_session() {\
688         if (session) { \
689                 debug_print("locking session %p (%d)\n", session, session->busy); \
690                 if (session->busy) \
691                         debug_print("         SESSION WAS LOCKED !!      \n"); \
692                 session->busy = TRUE;\
693         } else {\
694                 debug_print("can't lock null session\n"); \
695         }\
696 }
697
698 #define unlock_session() {\
699         if (session) { \
700                 debug_print("unlocking session %p\n", session); \
701                 session->busy = FALSE;\
702         } else {\
703                 debug_print("can't unlock null session\n"); \
704         }\
705 }
706
707 static IMAPSession *imap_session_get(Folder *folder)
708 {
709         RemoteFolder *rfolder = REMOTE_FOLDER(folder);
710         IMAPSession *session = NULL;
711
712         g_return_val_if_fail(folder != NULL, NULL);
713         g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, NULL);
714         g_return_val_if_fail(folder->account != NULL, NULL);
715         
716         if (prefs_common.work_offline && 
717             !inc_offline_should_override(
718                 _("Claws Mail needs network access in order "
719                   "to access the IMAP server."))) {
720                 return NULL;
721         }
722
723         /* Make sure we have a session */
724         if (rfolder->session != NULL) {
725                 session = IMAP_SESSION(rfolder->session);
726         } else if (rfolder->connecting) {
727                 debug_print("already connecting\n");
728                 return NULL;
729         } else {
730                 imap_reset_uid_lists(folder);
731                 if (time(NULL) - rfolder->last_failure <= 2)
732                         return NULL;
733                 rfolder->connecting = TRUE;
734                 session = imap_session_new(folder, folder->account);
735         }
736         if(session == NULL) {
737                 rfolder->last_failure = time(NULL);
738                 rfolder->connecting = FALSE;
739                 return NULL;
740         }
741
742         /* Make sure session is authenticated */
743         if (!IMAP_SESSION(session)->authenticated)
744                 imap_session_authenticate(IMAP_SESSION(session), folder->account);
745         
746         if (!IMAP_SESSION(session)->authenticated) {
747                 imap_threaded_disconnect(session->folder);
748                 SESSION(session)->state = SESSION_DISCONNECTED;
749                 session_destroy(SESSION(session));
750                 rfolder->session = NULL;
751                 rfolder->last_failure = time(NULL);
752                 rfolder->connecting = FALSE;
753                 return NULL;
754         }
755
756         lock_session();
757
758         /* I think the point of this code is to avoid sending a
759          * keepalive if we've used the session recently and therefore
760          * think it's still alive.  Unfortunately, most of the code
761          * does not yet check for errors on the socket, and so if the
762          * connection drops we don't notice until the timeout expires.
763          * A better solution than sending a NOOP every time would be
764          * for every command to be prepared to retry until it is
765          * successfully sent. -- mbp */
766         if (time(NULL) - SESSION(session)->last_access_time > SESSION_TIMEOUT_INTERVAL) {
767                 /* verify that the session is still alive */
768                 if (imap_cmd_noop(session) != IMAP_SUCCESS) {
769                         debug_print("disconnected!\n");
770                         session = imap_reconnect_if_possible(folder, session);
771                 }
772         }
773
774         rfolder->session = SESSION(session);
775         rfolder->connecting = FALSE;
776
777         return IMAP_SESSION(session);
778 }
779
780 static IMAPSession *imap_session_new(Folder * folder,
781                                      const PrefsAccount *account)
782 {
783         IMAPSession *session;
784         gushort port;
785         int r;
786         int authenticated = FALSE;
787         
788 #ifdef USE_OPENSSL
789         /* FIXME: IMAP over SSL only... */ 
790         SSLType ssl_type;
791
792         port = account->set_imapport ? account->imapport
793                 : account->ssl_imap == SSL_TUNNEL ? IMAPS_PORT : IMAP4_PORT;
794         ssl_type = account->ssl_imap;   
795 #else
796         if (account->ssl_imap != SSL_NONE) {
797                 if (alertpanel_full(_("Insecure connection"),
798                         _("This connection is configured to be secured "
799                           "using SSL, but SSL is not available in this "
800                           "build of Claws Mail. \n\n"
801                           "Do you want to continue connecting to this "
802                           "server? The communication would not be "
803                           "secure."),
804                           GTK_STOCK_CANCEL, _("Con_tinue connecting"), 
805                           NULL, FALSE, NULL, ALERT_WARNING,
806                           G_ALERTDEFAULT) != G_ALERTALTERNATE)
807                         return NULL;
808         }
809         port = account->set_imapport ? account->imapport
810                 : IMAP4_PORT;
811 #endif
812
813         imap_init(folder);
814         statusbar_print_all(_("Connecting to IMAP4 server: %s..."), folder->account->recv_server);
815         if (account->set_tunnelcmd) {
816                 r = imap_threaded_connect_cmd(folder,
817                                               account->tunnelcmd,
818                                               account->recv_server,
819                                               port);
820         }
821         else {
822 #ifdef USE_OPENSSL
823                 if (ssl_type == SSL_TUNNEL) {
824                         r = imap_threaded_connect_ssl(folder,
825                                                       account->recv_server,
826                                                       port);
827                 }
828                 else 
829 #endif
830                 {
831                         r = imap_threaded_connect(folder,
832                                                   account->recv_server,
833                                                   port);
834                 }
835         }
836         
837         statusbar_pop_all();
838         if (r == MAILIMAP_NO_ERROR_AUTHENTICATED) {
839                 authenticated = TRUE;
840         }
841         else if (r == MAILIMAP_NO_ERROR_NON_AUTHENTICATED) {
842                 authenticated = FALSE;
843         }
844         else {
845 #if (LIBETPAN_VERSION_MAJOR > 0 || LIBETPAN_VERSION_MINOR > 48)
846 #ifdef USE_OPENSSL
847                 if (r == MAILIMAP_ERROR_SSL)
848                         log_error(_("SSL handshake failed\n"));
849 #endif
850 #endif
851                 if(!prefs_common.no_recv_err_panel) {
852                         alertpanel_error_log(_("Can't connect to IMAP4 server: %s:%d"),
853                                          account->recv_server, port);
854                 } else {
855                         log_error(_("Can't connect to IMAP4 server: %s:%d\n"),
856                                          account->recv_server, port);
857                 } 
858                 
859                 return NULL;
860         }
861         
862         session = g_new0(IMAPSession, 1);
863         session_init(SESSION(session));
864         SESSION(session)->type             = SESSION_IMAP;
865         SESSION(session)->server           = g_strdup(account->recv_server);
866         SESSION(session)->sock             = NULL;
867         
868         SESSION(session)->destroy          = imap_session_destroy;
869
870         session->capability = NULL;
871         
872         session->authenticated = authenticated;
873         session->mbox = NULL;
874         session->cmd_count = 0;
875         session->folder = folder;
876         IMAP_FOLDER(session->folder)->last_seen_separator = 0;
877
878 #if USE_OPENSSL
879         if (account->ssl_imap == SSL_STARTTLS) {
880                 gint ok;
881
882                 ok = imap_cmd_starttls(session);
883                 if (ok != IMAP_SUCCESS) {
884                         log_warning(_("Can't start TLS session.\n"));
885                         session_destroy(SESSION(session));
886                         return NULL;
887                 }
888
889                 imap_free_capabilities(session);
890                 session->authenticated = FALSE;
891                 session->uidplus = FALSE;
892                 session->cmd_count = 1;
893         }
894 #endif
895         log_message("IMAP connection is %s-authenticated\n",
896                     (session->authenticated) ? "pre" : "un");
897         
898         return session;
899 }
900
901 static void imap_session_authenticate(IMAPSession *session, 
902                                       const PrefsAccount *account)
903 {
904         gchar *pass, *acc_pass;
905         gboolean failed = FALSE;
906
907         g_return_if_fail(account->userid != NULL);
908         acc_pass = account->passwd;
909 try_again:
910         pass = acc_pass;
911         if (!pass && account->imap_auth_type != IMAP_AUTH_ANON) {
912                 gchar *tmp_pass;
913                 tmp_pass = input_dialog_query_password(account->recv_server, account->userid);
914                 if (!tmp_pass)
915                         return;
916                 Xstrdup_a(pass, tmp_pass, {g_free(tmp_pass); return;});
917                 g_free(tmp_pass);
918         } else if (account->imap_auth_type == IMAP_AUTH_ANON) {
919                 pass = "";
920         }
921         statusbar_print_all(_("Connecting to IMAP4 server %s...\n"),
922                                 account->recv_server);
923         if (imap_auth(session, account->userid, pass, account->imap_auth_type) != IMAP_SUCCESS) {
924                 statusbar_pop_all();
925                 
926                 if (!failed) {
927                         acc_pass = NULL;
928                         failed = TRUE;
929                         goto try_again;
930                 } else {
931                         if (prefs_common.no_recv_err_panel) {
932                                 log_error(_("Couldn't login to IMAP server %s."), account->recv_server);
933                                 mainwindow_show_error();
934                         } else
935                                 alertpanel_error_log(_("Couldn't login to IMAP server %s."), account->recv_server);
936                 }               
937
938                 return;
939         } 
940
941         statusbar_pop_all();
942         session->authenticated = TRUE;
943         return;
944 }
945
946 static void imap_session_destroy(Session *session)
947 {
948         if (session->state != SESSION_DISCONNECTED)
949                 imap_threaded_disconnect(IMAP_SESSION(session)->folder);
950         
951         imap_free_capabilities(IMAP_SESSION(session));
952         g_free(IMAP_SESSION(session)->mbox);
953         sock_close(session->sock);
954         session->sock = NULL;
955 }
956
957 static gchar *imap_fetch_msg(Folder *folder, FolderItem *item, gint uid)
958 {
959         return imap_fetch_msg_full(folder, item, uid, TRUE, TRUE);
960 }
961
962 static guint get_size_with_crs(MsgInfo *info) 
963 {
964         FILE *fp = NULL;
965         guint cnt = 0;
966         gchar buf[4096];
967         
968         if (info == NULL)
969                 return -1;
970         
971         fp = procmsg_open_message(info);
972         if (!fp)
973                 return -1;
974         
975         while (fgets(buf, sizeof (buf), fp) != NULL) {
976                 cnt += strlen(buf);
977                 if (!strstr(buf, "\r") && strstr(buf, "\n"))
978                         cnt++;
979         }
980         
981         fclose(fp);
982         return cnt;
983 }
984
985 static gchar *imap_fetch_msg_full(Folder *folder, FolderItem *item, gint uid,
986                                   gboolean headers, gboolean body)
987 {
988         gchar *path, *filename;
989         IMAPSession *session;
990         gint ok;
991
992         g_return_val_if_fail(folder != NULL, NULL);
993         g_return_val_if_fail(item != NULL, NULL);
994
995         if (uid == 0)
996                 return NULL;
997
998         path = folder_item_get_path(item);
999         if (!is_dir_exist(path))
1000                 make_dir_hier(path);
1001         filename = g_strconcat(path, G_DIR_SEPARATOR_S, itos(uid), NULL);
1002         g_free(path);
1003         debug_print("trying to fetch cached %s\n", filename);
1004         if (is_file_exist(filename)) {
1005                 /* see whether the local file represents the whole message
1006                  * or not. As the IMAP server reports size with \r chars,
1007                  * we have to update the local file (UNIX \n only) size */
1008                 MsgInfo *msginfo = imap_parse_msg(filename, item);
1009                 MsgInfo *cached = msgcache_get_msg(item->cache,uid);
1010                 guint have_size = get_size_with_crs(msginfo);
1011
1012                 if (cached)
1013                         debug_print("message %d has been already %scached (%d/%d).\n", uid,
1014                                 have_size >= cached->size ? "fully ":"",
1015                                 have_size, (int)cached->size);
1016                 
1017                 if (cached && (cached->size <= have_size || !body)) {
1018                         procmsg_msginfo_free(cached);
1019                         procmsg_msginfo_free(msginfo);
1020                         file_strip_crs(filename);
1021                         return filename;
1022                 } else if (!cached && time(NULL) - get_file_mtime(filename) < 60) {
1023                         debug_print("message not cached and file recent, considering file complete\n");
1024                         procmsg_msginfo_free(msginfo);
1025                         file_strip_crs(filename);
1026                         return filename;
1027                 } else {
1028                         procmsg_msginfo_free(cached);
1029                         procmsg_msginfo_free(msginfo);
1030                 }
1031         }
1032
1033         debug_print("getting session...\n");
1034         session = imap_session_get(folder);
1035         
1036         if (!session) {
1037                 g_free(filename);
1038                 return NULL;
1039         }
1040
1041         debug_print("IMAP fetching messages\n");
1042         ok = imap_select(session, IMAP_FOLDER(folder), item->path,
1043                          NULL, NULL, NULL, NULL, FALSE);
1044         if (ok != IMAP_SUCCESS) {
1045                 g_warning("can't select mailbox %s\n", item->path);
1046                 g_free(filename);
1047                 unlock_session();
1048                 return NULL;
1049         }
1050
1051         debug_print("getting message %d...\n", uid);
1052         ok = imap_cmd_fetch(session, (guint32)uid, filename, headers, body);
1053
1054         if (ok != IMAP_SUCCESS) {
1055                 g_warning("can't fetch message %d\n", uid);
1056                 g_free(filename);
1057                 unlock_session();
1058                 return NULL;
1059         }
1060
1061         unlock_session();
1062         file_strip_crs(filename);
1063         return filename;
1064 }
1065
1066 static gint imap_add_msg(Folder *folder, FolderItem *dest, 
1067                          const gchar *file, MsgFlags *flags)
1068 {
1069         gint ret;
1070         GSList file_list;
1071         MsgFileInfo fileinfo;
1072
1073         g_return_val_if_fail(file != NULL, -1);
1074
1075         fileinfo.msginfo = NULL;
1076         fileinfo.file = (gchar *)file;
1077         fileinfo.flags = flags;
1078         file_list.data = &fileinfo;
1079         file_list.next = NULL;
1080
1081         ret = imap_add_msgs(folder, dest, &file_list, NULL);
1082         return ret;
1083 }
1084
1085 static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
1086                    GRelation *relation)
1087 {
1088         gchar *destdir;
1089         IMAPSession *session;
1090         guint32 last_uid = 0;
1091         GSList *cur;
1092         MsgFileInfo *fileinfo;
1093         gint ok;
1094         gint curnum = 0, total = 0;
1095
1096
1097         g_return_val_if_fail(folder != NULL, -1);
1098         g_return_val_if_fail(dest != NULL, -1);
1099         g_return_val_if_fail(file_list != NULL, -1);
1100         
1101         debug_print("getting session...\n");
1102         session = imap_session_get(folder);
1103         if (!session) {
1104                 return -1;
1105         }
1106         destdir = imap_get_real_path(session, IMAP_FOLDER(folder), dest->path);
1107
1108         statusbar_print_all(_("Adding messages..."));
1109         total = g_slist_length(file_list);
1110         for (cur = file_list; cur != NULL; cur = cur->next) {
1111                 IMAPFlags iflags = 0;
1112                 guint32 new_uid = 0;
1113                 gchar *real_file = NULL;
1114                 fileinfo = (MsgFileInfo *)cur->data;
1115
1116                 statusbar_progress_all(curnum, total, total < 10 ? 1:10);
1117                 curnum++;
1118
1119                 if (fileinfo->flags) {
1120                         if (MSG_IS_MARKED(*fileinfo->flags))
1121                                 iflags |= IMAP_FLAG_FLAGGED;
1122                         if (MSG_IS_REPLIED(*fileinfo->flags))
1123                                 iflags |= IMAP_FLAG_ANSWERED;
1124                         if (!MSG_IS_UNREAD(*fileinfo->flags))
1125                                 iflags |= IMAP_FLAG_SEEN;
1126                 }
1127                 
1128                 if (real_file == NULL)
1129                         real_file = g_strdup(fileinfo->file);
1130                 
1131                 if (folder_has_parent_of_type(dest, F_QUEUE) ||
1132                     folder_has_parent_of_type(dest, F_OUTBOX) ||
1133                     folder_has_parent_of_type(dest, F_DRAFT) ||
1134                     folder_has_parent_of_type(dest, F_TRASH))
1135                         iflags |= IMAP_FLAG_SEEN;
1136
1137                 ok = imap_cmd_append(session, destdir, real_file, iflags, 
1138                                      &new_uid);
1139
1140                 if (ok != IMAP_SUCCESS) {
1141                         g_warning("can't append message %s\n", real_file);
1142                         g_free(real_file);
1143                         g_free(destdir);
1144                         unlock_session();
1145                         statusbar_progress_all(0,0,0);
1146                         statusbar_pop_all();
1147                         return -1;
1148                 } else {
1149                         debug_print("appended new message as %d\n", new_uid);
1150                         /* put the local file in the imapcache, so that we don't
1151                          * have to fetch it back later. */
1152                         if (new_uid > 0) {
1153                                 gchar *cache_path = folder_item_get_path(dest);
1154                                 if (!is_dir_exist(cache_path))
1155                                         make_dir_hier(cache_path);
1156                                 if (is_dir_exist(cache_path)) {
1157                                         gchar *cache_file = g_strconcat(
1158                                                 cache_path, G_DIR_SEPARATOR_S, 
1159                                                 itos(new_uid), NULL);
1160                                         copy_file(real_file, cache_file, TRUE);
1161                                         debug_print("copied to cache: %s\n", cache_file);
1162                                         g_free(cache_file);
1163                                 }
1164                                 g_free(cache_path);
1165                         }
1166                 }
1167
1168                 if (relation != NULL)
1169                         g_relation_insert(relation, fileinfo->msginfo != NULL ? 
1170                                           (gpointer) fileinfo->msginfo : (gpointer) fileinfo,
1171                                           GINT_TO_POINTER(dest->last_num + 1));
1172                 if (new_uid == 0) {
1173                         new_uid = dest->last_num+1;
1174                 }
1175                 if (last_uid < new_uid) {
1176                         last_uid = new_uid;
1177                 }
1178
1179                 g_free(real_file);
1180         }
1181         statusbar_progress_all(0,0,0);
1182         statusbar_pop_all();
1183         
1184         imap_cmd_expunge(session);
1185         unlock_session();
1186         
1187         g_free(destdir);
1188
1189         return last_uid;
1190 }
1191
1192 static gint imap_do_copy_msgs(Folder *folder, FolderItem *dest, 
1193                               MsgInfoList *msglist, GRelation *relation)
1194 {
1195         FolderItem *src;
1196         gchar *destdir;
1197         GSList *seq_list, *cur;
1198         MsgInfo *msginfo;
1199         IMAPSession *session;
1200         gint ok = IMAP_SUCCESS;
1201         GRelation *uid_mapping;
1202         gint last_num = 0;
1203         gboolean single = FALSE;
1204
1205         g_return_val_if_fail(folder != NULL, -1);
1206         g_return_val_if_fail(dest != NULL, -1);
1207         g_return_val_if_fail(msglist != NULL, -1);
1208         
1209         debug_print("getting session...\n");
1210         session = imap_session_get(folder);
1211         
1212         if (!session) {
1213                 return -1;
1214         }
1215
1216         msginfo = (MsgInfo *)msglist->data;
1217         if (msglist->next == NULL)
1218                 single = TRUE;
1219         src = msginfo->folder;
1220         if (src == dest) {
1221                 g_warning("the src folder is identical to the dest.\n");
1222                 unlock_session();
1223                 return -1;
1224         }
1225
1226         if (src->folder != dest->folder) {
1227                 GSList *infolist = NULL, *cur;
1228                 int res = -1;
1229                 for (cur = msglist; cur; cur = cur->next) {
1230                         msginfo = (MsgInfo *)cur->data;
1231                         MsgFileInfo *fileinfo = g_new0(MsgFileInfo, 1);
1232                         fileinfo->file = procmsg_get_message_file(msginfo);
1233                         fileinfo->flags = &(msginfo->flags);
1234                         infolist = g_slist_prepend(infolist, fileinfo);
1235                 }
1236                 infolist = g_slist_reverse(infolist);
1237                 unlock_session();
1238                 res = folder_item_add_msgs(dest, infolist, FALSE);
1239                 for (cur = infolist; cur; cur = cur->next) {
1240                         MsgFileInfo *info = (MsgFileInfo *)cur->data;
1241                         g_free(info->file);
1242                         g_free(info);
1243                 }
1244                 g_slist_free(infolist);
1245                 return res;
1246         } 
1247
1248         ok = imap_select(session, IMAP_FOLDER(folder), msginfo->folder->path,
1249                          NULL, NULL, NULL, NULL, FALSE);
1250         if (ok != IMAP_SUCCESS) {
1251                 unlock_session();
1252                 return ok;
1253         }
1254
1255         destdir = imap_get_real_path(session, IMAP_FOLDER(folder), dest->path);
1256         seq_list = imap_get_lep_set_from_msglist(msglist);
1257         uid_mapping = g_relation_new(2);
1258         g_relation_index(uid_mapping, 0, g_direct_hash, g_direct_equal);
1259         
1260         statusbar_print_all(_("Copying messages..."));
1261         for (cur = seq_list; cur != NULL; cur = g_slist_next(cur)) {
1262                 struct mailimap_set * seq_set;
1263                 struct mailimap_set * source = NULL;
1264                 struct mailimap_set * dest = NULL;
1265                 seq_set = cur->data;
1266
1267                 debug_print("Copying messages from %s to %s ...\n",
1268                             src->path, destdir);
1269
1270                 ok = imap_cmd_copy(session, seq_set, destdir, uid_mapping,
1271                         &source, &dest);
1272                 
1273                 if (ok == IMAP_SUCCESS) {
1274                         if (single && relation && source && dest) {
1275                                 clistiter *l = clist_begin(source->set_list);
1276                                 struct mailimap_set_item *i = (struct mailimap_set_item *)clist_content(l);
1277                                 int snum = i->set_first;
1278                                 int dnum = 0;
1279                                 l = clist_begin(dest->set_list);
1280                                 i = (struct mailimap_set_item *)clist_content(l);
1281                                 dnum = i->set_first;
1282                                 g_relation_insert(uid_mapping, GINT_TO_POINTER(snum), 
1283                                         GINT_TO_POINTER(dnum));
1284                         }
1285                 }
1286
1287
1288                 if (source)
1289                         mailimap_set_free(source);
1290                 if (dest)
1291                         mailimap_set_free(dest);
1292
1293                 if (ok != IMAP_SUCCESS) {
1294                         g_relation_destroy(uid_mapping);
1295                         imap_lep_set_free(seq_list);
1296                         unlock_session();
1297                         statusbar_pop_all();
1298                         return -1;
1299                 }
1300         }
1301
1302         for (cur = msglist; cur != NULL; cur = g_slist_next(cur)) {
1303                 MsgInfo *msginfo = (MsgInfo *)cur->data;
1304                 GTuples *tuples;
1305
1306                 tuples = g_relation_select(uid_mapping, 
1307                                            GINT_TO_POINTER(msginfo->msgnum),
1308                                            0);
1309                 if (tuples->len > 0) {
1310                         gint num = GPOINTER_TO_INT(g_tuples_index(tuples, 0, 1));
1311                         g_relation_insert(relation, msginfo,
1312                                           GINT_TO_POINTER(num));
1313                         if (num > last_num)
1314                                 last_num = num;
1315                         debug_print("copied new message as %d\n", num);
1316                         /* put the local file in the imapcache, so that we don't
1317                          * have to fetch it back later. */
1318                         if (num > 0) {
1319                                 gchar *cache_path = folder_item_get_path(msginfo->folder);
1320                                 gchar *real_file = g_strconcat(
1321                                         cache_path, G_DIR_SEPARATOR_S, 
1322                                         itos(msginfo->msgnum), NULL);
1323                                 gchar *cache_file = NULL;
1324                                 g_free(cache_path);
1325                                 cache_path = folder_item_get_path(dest);
1326                                 cache_file = g_strconcat(
1327                                         cache_path, G_DIR_SEPARATOR_S, 
1328                                         itos(num), NULL);
1329                                 if (!is_dir_exist(cache_path))
1330                                         make_dir_hier(cache_path);
1331                                 if (is_file_exist(real_file) && is_dir_exist(cache_path)) {
1332                                         copy_file(real_file, cache_file, TRUE);
1333                                         debug_print("copied to cache: %s\n", cache_file);
1334                                 }
1335                                 g_free(real_file);
1336                                 g_free(cache_file);
1337                                 g_free(cache_path);
1338                         }
1339                 } else
1340                         g_relation_insert(relation, msginfo,
1341                                           GINT_TO_POINTER(0));
1342                 g_tuples_destroy(tuples);
1343         }
1344         statusbar_pop_all();
1345
1346         g_relation_destroy(uid_mapping);
1347         imap_lep_set_free(seq_list);
1348
1349         g_free(destdir);
1350         
1351         IMAP_FOLDER_ITEM(dest)->lastuid = 0;
1352         IMAP_FOLDER_ITEM(dest)->uid_next = 0;
1353         g_slist_free(IMAP_FOLDER_ITEM(dest)->uid_list);
1354         IMAP_FOLDER_ITEM(dest)->uid_list = NULL;
1355
1356         unlock_session();
1357         if (ok == IMAP_SUCCESS)
1358                 return last_num;
1359         else
1360                 return -1;
1361 }
1362
1363 static gint imap_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
1364 {
1365         GSList msglist;
1366
1367         g_return_val_if_fail(msginfo != NULL, -1);
1368
1369         msglist.data = msginfo;
1370         msglist.next = NULL;
1371
1372         return imap_copy_msgs(folder, dest, &msglist, NULL);
1373 }
1374
1375 static gint imap_copy_msgs(Folder *folder, FolderItem *dest, 
1376                     MsgInfoList *msglist, GRelation *relation)
1377 {
1378         MsgInfo *msginfo;
1379         gint ret;
1380
1381         g_return_val_if_fail(folder != NULL, -1);
1382         g_return_val_if_fail(dest != NULL, -1);
1383         g_return_val_if_fail(msglist != NULL, -1);
1384
1385         msginfo = (MsgInfo *)msglist->data;
1386         g_return_val_if_fail(msginfo->folder != NULL, -1);
1387
1388         ret = imap_do_copy_msgs(folder, dest, msglist, relation);
1389         return ret;
1390 }
1391
1392
1393 static gint imap_do_remove_msgs(Folder *folder, FolderItem *dest, 
1394                                 MsgInfoList *msglist, GRelation *relation)
1395 {
1396         gchar *destdir, *dir;
1397         GSList *numlist = NULL, *cur;
1398         MsgInfo *msginfo;
1399         IMAPSession *session;
1400         gint ok = IMAP_SUCCESS;
1401         GRelation *uid_mapping;
1402         
1403         g_return_val_if_fail(folder != NULL, -1);
1404         g_return_val_if_fail(dest != NULL, -1);
1405         g_return_val_if_fail(msglist != NULL, -1);
1406
1407         debug_print("getting session...\n");
1408         session = imap_session_get(folder);
1409         if (!session) {
1410                 return -1;
1411         }
1412
1413         msginfo = (MsgInfo *)msglist->data;
1414
1415         ok = imap_select(session, IMAP_FOLDER(folder), msginfo->folder->path,
1416                          NULL, NULL, NULL, NULL, FALSE);
1417         if (ok != IMAP_SUCCESS) {
1418                 unlock_session();
1419                 return ok;
1420         }
1421
1422         destdir = imap_get_real_path(session, IMAP_FOLDER(folder), dest->path);
1423         for (cur = msglist; cur; cur = cur->next) {
1424                 msginfo = (MsgInfo *)cur->data;
1425                 if (!MSG_IS_DELETED(msginfo->flags))
1426                         numlist = g_slist_prepend(numlist, GINT_TO_POINTER(msginfo->msgnum));
1427         }
1428         numlist = g_slist_reverse(numlist);
1429
1430         uid_mapping = g_relation_new(2);
1431         g_relation_index(uid_mapping, 0, g_direct_hash, g_direct_equal);
1432
1433         ok = imap_set_message_flags
1434                 (IMAP_SESSION(REMOTE_FOLDER(folder)->session),
1435                 numlist, IMAP_FLAG_DELETED, TRUE);
1436         if (ok != IMAP_SUCCESS) {
1437                 log_warning(_("can't set deleted flags\n"));
1438                 unlock_session();
1439                 return ok;
1440         }
1441         ok = imap_cmd_expunge(session);
1442         if (ok != IMAP_SUCCESS) {
1443                 log_warning(_("can't expunge\n"));
1444                 unlock_session();
1445                 return ok;
1446         }
1447         
1448         dir = folder_item_get_path(msginfo->folder);
1449         if (is_dir_exist(dir)) {
1450                 for (cur = msglist; cur; cur = cur->next) {
1451                         msginfo = (MsgInfo *)cur->data;
1452                         remove_numbered_files(dir, msginfo->msgnum, msginfo->msgnum);
1453                 }
1454         }
1455         g_free(dir);
1456
1457         g_relation_destroy(uid_mapping);
1458         g_slist_free(numlist);
1459
1460         g_free(destdir);
1461         unlock_session();
1462         if (ok == IMAP_SUCCESS)
1463                 return 0;
1464         else
1465                 return -1;
1466 }
1467
1468 static gint imap_remove_msgs(Folder *folder, FolderItem *dest, 
1469                     MsgInfoList *msglist, GRelation *relation)
1470 {
1471         MsgInfo *msginfo;
1472
1473         g_return_val_if_fail(folder != NULL, -1);
1474         g_return_val_if_fail(dest != NULL, -1);
1475         if (msglist == NULL)
1476                 return 0;
1477
1478         msginfo = (MsgInfo *)msglist->data;
1479         g_return_val_if_fail(msginfo->folder != NULL, -1);
1480
1481         return imap_do_remove_msgs(folder, dest, msglist, relation);
1482 }
1483
1484 static gint imap_remove_all_msg(Folder *folder, FolderItem *item)
1485 {
1486         GSList *list = folder_item_get_msg_list(item);
1487         gint res = imap_remove_msgs(folder, item, list, NULL);
1488         procmsg_msg_list_free(list);
1489         return res;
1490 }
1491
1492 static gboolean imap_is_msg_changed(Folder *folder, FolderItem *item,
1493                                     MsgInfo *msginfo)
1494 {
1495         /* TODO: properly implement this method */
1496         return FALSE;
1497 }
1498
1499 static gint imap_close(Folder *folder, FolderItem *item)
1500 {
1501         return 0;
1502 }
1503
1504 gint imap_scan_tree_real(Folder *folder, gboolean subs_only)
1505 {
1506         FolderItem *item = NULL;
1507         IMAPSession *session;
1508         gchar *root_folder = NULL;
1509
1510         g_return_val_if_fail(folder != NULL, -1);
1511         g_return_val_if_fail(folder->account != NULL, -1);
1512
1513         debug_print("getting session...\n");
1514         session = imap_session_get(folder);
1515         if (!session) {
1516                 if (!folder->node) {
1517                         folder_tree_destroy(folder);
1518                         item = folder_item_new(folder, folder->name, NULL);
1519                         item->folder = folder;
1520                         folder->node = item->node = g_node_new(item);
1521                 }
1522                 return -1;
1523         }
1524
1525         if (folder->account->imap_dir && *folder->account->imap_dir) {
1526                 gchar *real_path;
1527                 int r;
1528                 clist * lep_list;
1529
1530                 Xstrdup_a(root_folder, folder->account->imap_dir, {unlock_session();return -1;});
1531                 extract_quote(root_folder, '"');
1532                 subst_char(root_folder,
1533                            imap_get_path_separator(session, IMAP_FOLDER(folder),
1534                                                    root_folder),
1535                            '/');
1536                 strtailchomp(root_folder, '/');
1537                 real_path = imap_get_real_path
1538                         (session, IMAP_FOLDER(folder), root_folder);
1539                 debug_print("IMAP root directory: %s\n", real_path);
1540
1541                 /* check if root directory exist */
1542
1543                 r = imap_threaded_list(session->folder, "", real_path,
1544                                        &lep_list);
1545                 if ((r != MAILIMAP_NO_ERROR) || (clist_count(lep_list) == 0)) {
1546                         if (!folder->node) {
1547                                 item = folder_item_new(folder, folder->name, NULL);
1548                                 item->folder = folder;
1549                                 folder->node = item->node = g_node_new(item);
1550                         }
1551                         unlock_session();
1552                         return -1;
1553                 }
1554                 mailimap_list_result_free(lep_list);
1555                                 
1556                 g_free(real_path);
1557         }
1558
1559         if (folder->node)
1560                 item = FOLDER_ITEM(folder->node->data);
1561                 
1562         if (item && !item->path && root_folder) {
1563                 item->path = g_strdup(root_folder);
1564         }
1565
1566         if (!item || ((item->path || root_folder) &&
1567                       strcmp2(item->path, root_folder) != 0)) {
1568                 folder_tree_destroy(folder);
1569                 item = folder_item_new(folder, folder->name, root_folder);
1570                 item->folder = folder;
1571                 folder->node = item->node = g_node_new(item);
1572         }
1573
1574         imap_scan_tree_recursive(session, FOLDER_ITEM(folder->node->data), subs_only);
1575         imap_create_missing_folders(folder);
1576         unlock_session();
1577
1578         return 0;
1579 }
1580
1581 static gint imap_scan_tree(Folder *folder)
1582 {
1583         gboolean subs_only = FALSE;
1584         if (folder->account) {
1585                 debug_print(" scanning only subs %d\n", folder->account->imap_subsonly);
1586                 subs_only = folder->account->imap_subsonly;
1587         }
1588         return imap_scan_tree_real(folder, subs_only);
1589 }
1590
1591 static gint imap_scan_tree_recursive(IMAPSession *session, FolderItem *item, gboolean subs_only)
1592 {
1593         Folder *folder;
1594         IMAPFolder *imapfolder;
1595         FolderItem *new_item;
1596         GSList *item_list, *cur;
1597         GNode *node;
1598         gchar *real_path;
1599         gchar *wildcard_path;
1600         gchar separator;
1601         gchar wildcard[3];
1602         clist * lep_list;
1603         int r;
1604         
1605         g_return_val_if_fail(item != NULL, -1);
1606         g_return_val_if_fail(item->folder != NULL, -1);
1607         g_return_val_if_fail(item->no_sub == FALSE, -1);
1608
1609         folder = item->folder;
1610         imapfolder = IMAP_FOLDER(folder);
1611
1612         separator = imap_get_path_separator(session, imapfolder, item->path);
1613
1614         if (folder->ui_func)
1615                 folder->ui_func(folder, item, folder->ui_func_data);
1616
1617         if (item->path) {
1618                 wildcard[0] = separator;
1619                 wildcard[1] = '%';
1620                 wildcard[2] = '\0';
1621                 real_path = imap_get_real_path(session, imapfolder, item->path);
1622         } else {
1623                 wildcard[0] = '%';
1624                 wildcard[1] = '\0';
1625                 real_path = g_strdup("");
1626         }
1627
1628         Xstrcat_a(wildcard_path, real_path, wildcard,
1629                   {g_free(real_path); return IMAP_ERROR;});
1630         lep_list = NULL;
1631         
1632         if (subs_only)
1633                 r = imap_threaded_lsub(folder, "", wildcard_path, &lep_list);
1634         else
1635                 r = imap_threaded_list(folder, "", wildcard_path, &lep_list);
1636
1637         if (r != MAILIMAP_NO_ERROR) {
1638                 item_list = NULL;
1639         }
1640         else {
1641                 item_list = imap_list_from_lep(imapfolder,
1642                                                lep_list, real_path, FALSE);
1643                 mailimap_list_result_free(lep_list);
1644         }
1645         
1646         g_free(real_path);
1647
1648         node = item->node->children;
1649         while (node != NULL) {
1650                 FolderItem *old_item = FOLDER_ITEM(node->data);
1651                 GNode *next = node->next;
1652
1653                 new_item = NULL;
1654                 for (cur = item_list; cur != NULL; cur = cur->next) {
1655                         FolderItem *cur_item = FOLDER_ITEM(cur->data);
1656                         if (!strcmp2(old_item->path, cur_item->path)) {
1657                                 new_item = cur_item;
1658                                 break;
1659                         }
1660                 }
1661                 if (!new_item) {
1662                         if (old_item && old_item->path && !strcmp(old_item->path, "INBOX")) {
1663                                 debug_print("not removing INBOX\n");
1664                         } else {
1665                                 debug_print("folder '%s' not found. removing...\n",
1666                                             old_item->path);
1667                                 folder_item_remove(old_item);
1668                         }
1669                 } else {
1670                         old_item->no_sub = new_item->no_sub;
1671                         old_item->no_select = new_item->no_select;
1672                         if (old_item->no_sub == TRUE && node->children) {
1673                                 debug_print("folder '%s' doesn't have "
1674                                             "subfolders. removing...\n",
1675                                             old_item->path);
1676                                 folder_item_remove_children(old_item);
1677                         }
1678                 }
1679
1680                 node = next;
1681         }
1682
1683         for (cur = item_list; cur != NULL; cur = cur->next) {
1684                 FolderItem *cur_item = FOLDER_ITEM(cur->data);
1685                 new_item = NULL;
1686
1687                 for (node = item->node->children; node != NULL;
1688                      node = node->next) {
1689                         if (!strcmp2(FOLDER_ITEM(node->data)->path,
1690                                      cur_item->path)) {
1691                                 new_item = FOLDER_ITEM(node->data);
1692                                 folder_item_destroy(cur_item);
1693                                 cur_item = NULL;
1694                                 break;
1695                         }
1696                 }
1697                 if (!new_item) {
1698                         new_item = cur_item;
1699                         debug_print("new folder '%s' found.\n", new_item->path);
1700                         folder_item_append(item, new_item);
1701                 }
1702
1703                 if (!strcmp(new_item->path, "INBOX")) {
1704                         new_item->stype = F_INBOX;
1705                         folder->inbox = new_item;
1706                 } else if (!folder_item_parent(item) || item->stype == F_INBOX) {
1707                         gchar *base;
1708
1709                         base = g_path_get_basename(new_item->path);
1710
1711                         if (!folder->outbox && !g_ascii_strcasecmp(base, "Sent")) {
1712                                 new_item->stype = F_OUTBOX;
1713                                 folder->outbox = new_item;
1714                         } else if (!folder->draft && !g_ascii_strcasecmp(base, "Drafts")) {
1715                                 new_item->stype = F_DRAFT;
1716                                 folder->draft = new_item;
1717                         } else if (!folder->queue && !g_ascii_strcasecmp(base, "Queue")) {
1718                                 new_item->stype = F_QUEUE;
1719                                 folder->queue = new_item;
1720                         } else if (!folder->trash && !g_ascii_strcasecmp(base, "Trash")) {
1721                                 new_item->stype = F_TRASH;
1722                                 folder->trash = new_item;
1723                         }
1724                         g_free(base);
1725                 }
1726
1727                 if (new_item->no_sub == FALSE)
1728                         imap_scan_tree_recursive(session, new_item, subs_only);
1729         }
1730
1731         g_slist_free(item_list);
1732
1733         return IMAP_SUCCESS;
1734 }
1735
1736 GList *imap_scan_subtree(Folder *folder, FolderItem *item, gboolean unsubs_only, gboolean recursive)
1737 {
1738         IMAPSession *session = imap_session_get(folder);
1739         gchar *real_path;
1740         gchar *wildcard_path;
1741         gchar separator;
1742         gchar wildcard[3];
1743         clist * lep_list;
1744         GSList *item_list = NULL, *cur;
1745         GList *child_list = NULL, *tmplist = NULL;
1746         GSList *sub_list = NULL;
1747         int r;
1748
1749         if (!session)
1750                 return NULL;
1751
1752         separator = imap_get_path_separator(session, IMAP_FOLDER(folder), item->path);
1753
1754         if (item->path) {
1755                 wildcard[0] = separator;
1756                 wildcard[1] = '%';
1757                 wildcard[2] = '\0';
1758                 real_path = imap_get_real_path(session, IMAP_FOLDER(folder), item->path);
1759         } else {
1760                 wildcard[0] = '%';
1761                 wildcard[1] = '\0';
1762                 real_path = g_strdup("");
1763         }
1764
1765         Xstrcat_a(wildcard_path, real_path, wildcard,
1766                   {g_free(real_path); return NULL;});
1767         lep_list = NULL;
1768         
1769         if (unsubs_only)
1770                 statusbar_print_all(_("Looking for unsubscribed folders in %s..."), 
1771                                 item->path?item->path:item->name);
1772         else
1773                 statusbar_print_all(_("Looking for subfolders of %s..."), 
1774                                 item->path?item->path:item->name);
1775
1776         r = imap_threaded_list(folder, "", wildcard_path, &lep_list);
1777         if (r) {
1778                 statusbar_pop_all();
1779                 return NULL;
1780         }
1781         item_list = imap_list_from_lep(IMAP_FOLDER(folder),
1782                                lep_list, real_path, FALSE);
1783         mailimap_list_result_free(lep_list);
1784
1785         for (cur = item_list; cur != NULL; cur = cur->next) {
1786                 FolderItem *cur_item = FOLDER_ITEM(cur->data);
1787                 if (recursive) {
1788                         tmplist = imap_scan_subtree(folder, cur_item, 
1789                                         unsubs_only, recursive);
1790                         if (tmplist)
1791                                 child_list = g_list_concat(child_list, tmplist);
1792                 }
1793                 child_list = g_list_prepend(child_list,
1794                                 imap_get_real_path(session, 
1795                                         IMAP_FOLDER(folder), cur_item->path));
1796                 
1797                 folder_item_destroy(cur_item);
1798         }
1799         child_list = g_list_reverse(child_list);
1800         g_slist_free(item_list);
1801
1802         if (unsubs_only) {
1803                 r = imap_threaded_lsub(folder, "", wildcard_path, &lep_list);
1804                 if (r) {
1805                         statusbar_pop_all();
1806                         return NULL;
1807                 }
1808                 sub_list = imap_list_from_lep(IMAP_FOLDER(folder),
1809                                        lep_list, real_path, FALSE);
1810                 mailimap_list_result_free(lep_list);
1811
1812                 for (cur = sub_list; cur != NULL; cur = cur->next) {
1813                         FolderItem *cur_item = FOLDER_ITEM(cur->data);
1814                         GList *oldlitem = NULL;
1815                         gchar *tmp = imap_get_real_path(session, 
1816                                         IMAP_FOLDER(folder), cur_item->path);
1817                         folder_item_destroy(cur_item);
1818                         oldlitem = g_list_find_custom(
1819                                         child_list, tmp, (GCompareFunc)strcmp2);
1820                         if (oldlitem) {
1821                                 child_list = g_list_remove_link(child_list, oldlitem);
1822                                 g_free(oldlitem->data);
1823                                 g_list_free(oldlitem);
1824                         }
1825                         g_free(tmp);
1826                 }
1827         }
1828
1829         statusbar_pop_all();
1830
1831         return child_list;
1832 }
1833
1834 static gint imap_create_tree(Folder *folder)
1835 {
1836         g_return_val_if_fail(folder != NULL, -1);
1837         g_return_val_if_fail(folder->node != NULL, -1);
1838         g_return_val_if_fail(folder->node->data != NULL, -1);
1839         g_return_val_if_fail(folder->account != NULL, -1);
1840
1841         imap_scan_tree(folder);
1842         imap_create_missing_folders(folder);
1843
1844         return 0;
1845 }
1846
1847 static void imap_create_missing_folders(Folder *folder)
1848 {
1849         g_return_if_fail(folder != NULL);
1850
1851         if (!folder->inbox)
1852                 folder->inbox = imap_create_special_folder
1853                         (folder, F_INBOX, "INBOX");
1854         if (!folder->trash)
1855                 folder->trash = imap_create_special_folder
1856                         (folder, F_TRASH, "Trash");
1857         if (!folder->queue)
1858                 folder->queue = imap_create_special_folder
1859                         (folder, F_QUEUE, "Queue");
1860         if (!folder->outbox)
1861                 folder->outbox = imap_create_special_folder
1862                         (folder, F_OUTBOX, "Sent");
1863         if (!folder->draft)
1864                 folder->draft = imap_create_special_folder
1865                         (folder, F_DRAFT, "Drafts");
1866 }
1867
1868 static FolderItem *imap_create_special_folder(Folder *folder,
1869                                               SpecialFolderItemType stype,
1870                                               const gchar *name)
1871 {
1872         FolderItem *item;
1873         FolderItem *new_item;
1874
1875         g_return_val_if_fail(folder != NULL, NULL);
1876         g_return_val_if_fail(folder->node != NULL, NULL);
1877         g_return_val_if_fail(folder->node->data != NULL, NULL);
1878         g_return_val_if_fail(folder->account != NULL, NULL);
1879         g_return_val_if_fail(name != NULL, NULL);
1880
1881         item = FOLDER_ITEM(folder->node->data);
1882         new_item = imap_create_folder(folder, item, name);
1883
1884         if (!new_item) {
1885                 g_warning("Can't create '%s'\n", name);
1886                 if (!folder->inbox) return NULL;
1887
1888                 new_item = imap_create_folder(folder, folder->inbox, name);
1889                 if (!new_item)
1890                         g_warning("Can't create '%s' under INBOX\n", name);
1891                 else
1892                         new_item->stype = stype;
1893         } else
1894                 new_item->stype = stype;
1895
1896         return new_item;
1897 }
1898
1899 static gchar *imap_folder_get_path(Folder *folder)
1900 {
1901         gchar *folder_path;
1902
1903         g_return_val_if_fail(folder != NULL, NULL);
1904         g_return_val_if_fail(folder->account != NULL, NULL);
1905
1906         folder_path = g_strconcat(get_imap_cache_dir(),
1907                                   G_DIR_SEPARATOR_S,
1908                                   folder->account->recv_server,
1909                                   G_DIR_SEPARATOR_S,
1910                                   folder->account->userid,
1911                                   NULL);
1912
1913         return folder_path;
1914 }
1915
1916 static gchar *imap_item_get_path(Folder *folder, FolderItem *item)
1917 {
1918         gchar *folder_path, *path;
1919
1920         g_return_val_if_fail(folder != NULL, NULL);
1921         g_return_val_if_fail(item != NULL, NULL);
1922         folder_path = imap_folder_get_path(folder);
1923
1924         g_return_val_if_fail(folder_path != NULL, NULL);
1925         if (folder_path[0] == G_DIR_SEPARATOR) {
1926                 if (item->path)
1927                         path = g_strconcat(folder_path, G_DIR_SEPARATOR_S,
1928                                            item->path, NULL);
1929                 else
1930                         path = g_strdup(folder_path);
1931         } else {
1932                 if (item->path)
1933                         path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
1934                                            folder_path, G_DIR_SEPARATOR_S,
1935                                            item->path, NULL);
1936                 else
1937                         path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
1938                                            folder_path, NULL);
1939         }
1940         g_free(folder_path);
1941
1942         return path;
1943 }
1944
1945 static FolderItem *imap_create_folder(Folder *folder, FolderItem *parent,
1946                                const gchar *name)
1947 {
1948         gchar *dirpath, *imap_path;
1949         IMAPSession *session;
1950         FolderItem *new_item;
1951         gchar separator;
1952         gchar *new_name;
1953         const gchar *p;
1954         gint ok;
1955         gboolean no_select = FALSE, no_sub = FALSE;
1956         gboolean exist = FALSE;
1957         
1958         g_return_val_if_fail(folder != NULL, NULL);
1959         g_return_val_if_fail(folder->account != NULL, NULL);
1960         g_return_val_if_fail(parent != NULL, NULL);
1961         g_return_val_if_fail(name != NULL, NULL);
1962
1963         debug_print("getting session...\n");
1964         session = imap_session_get(folder);
1965         if (!session) {
1966                 return NULL;
1967         }
1968
1969         if (!folder_item_parent(parent) && strcmp(name, "INBOX") == 0) {
1970                 dirpath = g_strdup(name);
1971         }else if (parent->path)
1972                 dirpath = g_strconcat(parent->path, "/", name, NULL);
1973         else if ((p = strchr(name, '/')) != NULL && *(p + 1) != '\0')
1974                 dirpath = g_strdup(name);
1975         else if (folder->account->imap_dir && *folder->account->imap_dir) {
1976                 gchar *imap_dir;
1977
1978                 Xstrdup_a(imap_dir, folder->account->imap_dir, {unlock_session();return NULL;});
1979                 strtailchomp(imap_dir, '/');
1980                 dirpath = g_strconcat(imap_dir, "/", name, NULL);
1981         } else
1982                 dirpath = g_strdup(name);
1983                 
1984         
1985
1986         /* keep trailing directory separator to create a folder that contains
1987            sub folder */
1988         imap_path = imap_utf8_to_modified_utf7(dirpath);
1989
1990         strtailchomp(dirpath, '/');
1991         Xstrdup_a(new_name, name, {
1992                 g_free(dirpath); 
1993                 unlock_session();               
1994                 return NULL;});
1995
1996         separator = imap_get_path_separator(session, IMAP_FOLDER(folder), imap_path);
1997         imap_path_separator_subst(imap_path, separator);
1998         /* remove trailing / for display */
1999         strtailchomp(new_name, '/');
2000
2001         if (strcmp(dirpath, "INBOX") != 0) {
2002                 GPtrArray *argbuf;
2003                 int r;
2004                 clist * lep_list;
2005                 
2006                 argbuf = g_ptr_array_new();
2007                 r = imap_threaded_list(folder, "", imap_path, &lep_list);
2008                 if (r != MAILIMAP_NO_ERROR) {
2009                         log_warning(_("can't create mailbox: LIST failed\n"));
2010                         g_free(imap_path);
2011                         g_free(dirpath);
2012                         ptr_array_free_strings(argbuf);
2013                         g_ptr_array_free(argbuf, TRUE);
2014                         unlock_session();
2015                         return NULL;
2016                 }
2017                 
2018                 if (clist_count(lep_list) > 0)
2019                         exist = TRUE;
2020                 mailimap_list_result_free(lep_list);
2021                 lep_list = NULL;
2022                 if (!exist) {
2023                         ok = imap_cmd_create(session, imap_path);
2024                         if (ok != IMAP_SUCCESS) {
2025                                 log_warning(_("can't create mailbox\n"));
2026                                 g_free(imap_path);
2027                                 g_free(dirpath);
2028                                 unlock_session();
2029                                 return NULL;
2030                         }
2031                         r = imap_threaded_list(folder, "", imap_path, &lep_list);
2032                         if (r == MAILIMAP_NO_ERROR) {
2033                                 GSList *item_list = imap_list_from_lep(IMAP_FOLDER(folder),
2034                                                lep_list, dirpath, TRUE);
2035                                 if (item_list) {
2036                                         FolderItem *cur_item = FOLDER_ITEM(item_list->data);
2037                                         no_select = cur_item->no_select;
2038                                         no_sub = cur_item->no_sub;
2039                                         g_slist_free(item_list);
2040                                 } 
2041                                 mailimap_list_result_free(lep_list);
2042                         }
2043                 }
2044                 imap_threaded_subscribe(folder, imap_path, TRUE);
2045         } else {
2046                 clist *lep_list;
2047                 int r;
2048                 /* just get flags */
2049                 r = imap_threaded_list(folder, "", "INBOX", &lep_list);
2050                 if (r == MAILIMAP_NO_ERROR) {
2051                         GSList *item_list = imap_list_from_lep(IMAP_FOLDER(folder),
2052                                        lep_list, dirpath, TRUE);
2053                         if (item_list) {
2054                                 FolderItem *cur_item = FOLDER_ITEM(item_list->data);
2055                                 no_select = cur_item->no_select;
2056                                 no_sub = cur_item->no_sub;
2057                                 g_slist_free(item_list);
2058                         } 
2059                         mailimap_list_result_free(lep_list);
2060                 }
2061         }
2062
2063         new_item = folder_item_new(folder, new_name, dirpath);
2064         new_item->no_select = no_select;
2065         new_item->no_sub = no_sub;
2066         folder_item_append(parent, new_item);
2067         g_free(imap_path);
2068         g_free(dirpath);
2069
2070         dirpath = folder_item_get_path(new_item);
2071         if (!is_dir_exist(dirpath))
2072                 make_dir_hier(dirpath);
2073         g_free(dirpath);
2074         unlock_session();
2075
2076         if (exist) {
2077                 /* folder existed, scan it */
2078                 folder_item_scan_full(new_item, FALSE);
2079         }
2080
2081         return new_item;
2082 }
2083
2084 static gint imap_rename_folder(Folder *folder, FolderItem *item,
2085                                const gchar *name)
2086 {
2087         gchar *dirpath;
2088         gchar *newpath;
2089         gchar *real_oldpath;
2090         gchar *real_newpath;
2091         gchar *paths[2];
2092         gchar *old_cache_dir;
2093         gchar *new_cache_dir;
2094         IMAPSession *session;
2095         gchar separator;
2096         gint ok;
2097         gint exists, recent, unseen;
2098         guint32 uid_validity;
2099
2100         g_return_val_if_fail(folder != NULL, -1);
2101         g_return_val_if_fail(item != NULL, -1);
2102         g_return_val_if_fail(item->path != NULL, -1);
2103         g_return_val_if_fail(name != NULL, -1);
2104
2105         debug_print("getting session...\n");
2106         session = imap_session_get(folder);
2107         if (!session) {
2108                 return -1;
2109         }
2110
2111         if (strchr(name, imap_get_path_separator(session, IMAP_FOLDER(folder), item->path)) != NULL) {
2112                 g_warning(_("New folder name must not contain the namespace "
2113                             "path separator"));
2114                 unlock_session();
2115                 return -1;
2116         }
2117
2118         real_oldpath = imap_get_real_path(session, IMAP_FOLDER(folder), item->path);
2119
2120         g_free(session->mbox);
2121         session->mbox = NULL;
2122         ok = imap_cmd_examine(session, "INBOX",
2123                               &exists, &recent, &unseen, &uid_validity, FALSE);
2124         if (ok != IMAP_SUCCESS) {
2125                 g_free(real_oldpath);
2126                 unlock_session();
2127                 return -1;
2128         }
2129
2130         separator = imap_get_path_separator(session, IMAP_FOLDER(folder), item->path);
2131         if (strchr(item->path, G_DIR_SEPARATOR)) {
2132                 dirpath = g_path_get_dirname(item->path);
2133                 newpath = g_strconcat(dirpath, G_DIR_SEPARATOR_S, name, NULL);
2134                 g_free(dirpath);
2135         } else
2136                 newpath = g_strdup(name);
2137
2138         real_newpath = imap_utf8_to_modified_utf7(newpath);
2139         imap_path_separator_subst(real_newpath, separator);
2140
2141         ok = imap_cmd_rename(session, real_oldpath, real_newpath);
2142         if (ok != IMAP_SUCCESS) {
2143                 log_warning(_("can't rename mailbox: %s to %s\n"),
2144                             real_oldpath, real_newpath);
2145                 g_free(real_oldpath);
2146                 g_free(newpath);
2147                 g_free(real_newpath);
2148                 unlock_session();
2149                 return -1;
2150         }
2151
2152         g_free(item->name);
2153         item->name = g_strdup(name);
2154
2155         old_cache_dir = folder_item_get_path(item);
2156
2157         paths[0] = g_strdup(item->path);
2158         paths[1] = newpath;
2159         g_node_traverse(item->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
2160                         imap_rename_folder_func, paths);
2161
2162         if (is_dir_exist(old_cache_dir)) {
2163                 new_cache_dir = folder_item_get_path(item);
2164                 if (rename(old_cache_dir, new_cache_dir) < 0) {
2165                         FILE_OP_ERROR(old_cache_dir, "rename");
2166                 }
2167                 g_free(new_cache_dir);
2168         }
2169
2170         g_free(old_cache_dir);
2171         g_free(paths[0]);
2172         g_free(newpath);
2173         g_free(real_oldpath);
2174         g_free(real_newpath);
2175         unlock_session();
2176         return 0;
2177 }
2178
2179 gint imap_subscribe(Folder *folder, FolderItem *item, gchar *rpath, gboolean sub)
2180 {
2181         gchar *path;
2182         gint r = -1;
2183         IMAPSession *session;
2184         debug_print("getting session...\n");
2185
2186         session = imap_session_get(folder);
2187         if (!session) {
2188                 return -1;
2189         }
2190         if (item && item->path) {
2191                 path = imap_get_real_path(session, IMAP_FOLDER(folder), item->path);
2192                 if (!path)
2193                         return -1;
2194                 if (!strcmp(path, "INBOX") && sub == FALSE)
2195                         return -1;
2196                 debug_print("%ssubscribing %s\n", sub?"":"un", path);
2197                 r = imap_threaded_subscribe(folder, path, sub);
2198                 g_free(path);
2199         } else if (rpath) {
2200                 r = imap_threaded_subscribe(folder, rpath, sub);
2201         } else
2202                 return -1;
2203         return r;
2204 }
2205
2206 static gint imap_remove_folder_real(Folder *folder, FolderItem *item)
2207 {
2208         gint ok;
2209         IMAPSession *session;
2210         gchar *path;
2211         gchar *cache_dir;
2212
2213         g_return_val_if_fail(folder != NULL, -1);
2214         g_return_val_if_fail(item != NULL, -1);
2215         g_return_val_if_fail(item->path != NULL, -1);
2216
2217         debug_print("getting session...\n");
2218         session = imap_session_get(folder);
2219         if (!session) {
2220                 return -1;
2221         }
2222         path = imap_get_real_path(session, IMAP_FOLDER(folder), item->path);
2223
2224         imap_threaded_subscribe(folder, path, FALSE);
2225         ok = imap_cmd_delete(session, path);
2226         if (ok != IMAP_SUCCESS) {
2227                 gchar *tmp = g_strdup_printf("%s%c", path, 
2228                                 imap_get_path_separator(session, IMAP_FOLDER(folder), path));
2229                 g_free(path);
2230                 path = tmp;
2231                 ok = imap_cmd_delete(session, path);
2232         }
2233
2234         if (ok != IMAP_SUCCESS) {
2235                 log_warning(_("can't delete mailbox\n"));
2236                 g_free(path);
2237                 unlock_session();
2238                 return -1;
2239         }
2240
2241         g_free(path);
2242         cache_dir = folder_item_get_path(item);
2243         if (is_dir_exist(cache_dir) && remove_dir_recursive(cache_dir) < 0)
2244                 g_warning("can't remove directory '%s'\n", cache_dir);
2245         g_free(cache_dir);
2246         folder_item_remove(item);
2247         unlock_session();
2248         return 0;
2249 }
2250
2251 static gint imap_remove_folder(Folder *folder, FolderItem *item)
2252 {
2253         GNode *node, *next;
2254
2255         g_return_val_if_fail(item != NULL, -1);
2256         g_return_val_if_fail(item->folder != NULL, -1);
2257         g_return_val_if_fail(item->node != NULL, -1);
2258
2259         node = item->node->children;
2260         while (node != NULL) {
2261                 next = node->next;
2262                 if (imap_remove_folder(folder, FOLDER_ITEM(node->data)) < 0)
2263                         return -1;
2264                 node = next;
2265         }
2266         debug_print("IMAP removing %s\n", item->path);
2267
2268         if (imap_remove_all_msg(folder, item) < 0)
2269                 return -1;
2270         return imap_remove_folder_real(folder, item);
2271 }
2272
2273 typedef struct _uncached_data {
2274         IMAPSession *session;
2275         FolderItem *item;
2276         MsgNumberList *numlist;
2277         guint cur;
2278         guint total;
2279         gboolean done;
2280 } uncached_data;
2281
2282 static void *imap_get_uncached_messages_thread(void *data)
2283 {
2284         uncached_data *stuff = (uncached_data *)data;
2285         IMAPSession *session = stuff->session;
2286         FolderItem *item = stuff->item;
2287         MsgNumberList *numlist = stuff->numlist;
2288         
2289         GSList *newlist = NULL;
2290         GSList *llast = NULL;
2291         GSList *seq_list, *cur;
2292
2293         debug_print("uncached_messages\n");
2294         
2295         if (session == NULL || item == NULL || item->folder == NULL
2296             || FOLDER_CLASS(item->folder) != &imap_class) {
2297                 stuff->done = TRUE;
2298                 return NULL;
2299         }
2300         
2301         seq_list = imap_get_lep_set_from_numlist(numlist);
2302         debug_print("get msgs info\n");
2303         for (cur = seq_list; cur != NULL; cur = g_slist_next(cur)) {
2304                 struct mailimap_set * imapset;
2305                 unsigned int i;
2306                 int r;
2307                 carray * env_list;
2308                 int count;
2309                 
2310                 imapset = cur->data;
2311                 
2312                 r = imap_threaded_fetch_env(session->folder,
2313                                             imapset, &env_list);
2314                 if (r != MAILIMAP_NO_ERROR)
2315                         continue;
2316                 
2317                 session_set_access_time(SESSION(session));
2318
2319                 count = 0;
2320                 for(i = 0 ; i < carray_count(env_list) ; i ++) {
2321                         struct imap_fetch_env_info * info;
2322                         MsgInfo * msginfo;
2323                         
2324                         info = carray_get(env_list, i);
2325                         msginfo = imap_envelope_from_lep(info, item);
2326                         if (msginfo == NULL)
2327                                 continue;
2328                         msginfo->folder = item;
2329                         if (!newlist)
2330                                 llast = newlist = g_slist_append(newlist, msginfo);
2331                         else {
2332                                 llast = g_slist_append(llast, msginfo);
2333                                 llast = llast->next;
2334                         }
2335                         count ++;
2336                 }
2337                 
2338                 imap_fetch_env_free(env_list);
2339         }
2340         
2341         for (cur = seq_list; cur != NULL; cur = g_slist_next(cur)) {
2342                 struct mailimap_set * imapset;
2343                 
2344                 imapset = cur->data;
2345                 mailimap_set_free(imapset);
2346         }
2347         
2348         session_set_access_time(SESSION(session));
2349         stuff->done = TRUE;
2350         return newlist;
2351 }
2352
2353 #define MAX_MSG_NUM 50
2354
2355 static GSList *imap_get_uncached_messages(IMAPSession *session,
2356                                         FolderItem *item,
2357                                         MsgNumberList *numlist)
2358 {
2359         GSList *result = NULL;
2360         GSList * cur;
2361         uncached_data *data = g_new0(uncached_data, 1);
2362         int finished;
2363         
2364         finished = 0;
2365         cur = numlist;
2366         data->total = g_slist_length(numlist);
2367         debug_print("messages list : %i\n", data->total);
2368
2369         while (cur != NULL) {
2370                 GSList * partial_result;
2371                 int count;
2372                 GSList * newlist;
2373                 GSList * llast;
2374                 
2375                 llast = NULL;
2376                 count = 0;
2377                 newlist = NULL;
2378                 while (count < MAX_MSG_NUM) {
2379                         void * p;
2380                         
2381                         p = cur->data;
2382                         
2383                         if (newlist == NULL)
2384                                 llast = newlist = g_slist_append(newlist, p);
2385                         else {
2386                                 llast = g_slist_append(llast, p);
2387                                 llast = llast->next;
2388                         }
2389                         count ++;
2390                         
2391                         cur = cur->next;
2392                         if (cur == NULL)
2393                                 break;
2394                 }
2395                 
2396                 data->done = FALSE;
2397                 data->session = session;
2398                 data->item = item;
2399                 data->numlist = newlist;
2400                 data->cur += count;
2401                 
2402                 if (prefs_common.work_offline && 
2403                     !inc_offline_should_override(
2404                         _("Claws Mail needs network access in order "
2405                           "to access the IMAP server."))) {
2406                         g_free(data);
2407                         return NULL;
2408                 }
2409                 
2410                 partial_result =
2411                         (GSList *)imap_get_uncached_messages_thread(data);
2412                 
2413                 statusbar_progress_all(data->cur,data->total, 1);
2414                 
2415                 g_slist_free(newlist);
2416                 
2417                 result = g_slist_concat(result, partial_result);
2418         }
2419         g_free(data);
2420         
2421         statusbar_progress_all(0,0,0);
2422         statusbar_pop_all();
2423         
2424         return result;
2425 }
2426
2427 static void imap_delete_all_cached_messages(FolderItem *item)
2428 {
2429         gchar *dir;
2430
2431         g_return_if_fail(item != NULL);
2432         g_return_if_fail(item->folder != NULL);
2433         g_return_if_fail(FOLDER_CLASS(item->folder) == &imap_class);
2434
2435         debug_print("Deleting all cached messages...\n");
2436
2437         dir = folder_item_get_path(item);
2438         if (is_dir_exist(dir))
2439                 remove_all_numbered_files(dir);
2440         g_free(dir);
2441
2442         debug_print("done.\n");
2443 }
2444
2445 gchar imap_get_path_separator_for_item(FolderItem *item)
2446 {
2447         Folder *folder = NULL;
2448         IMAPFolder *imap_folder = NULL;
2449         IMAPSession *session = NULL;
2450         gchar result = '/';
2451         
2452         if (!item)
2453                 return '/';
2454         folder = item->folder;
2455         
2456         if (!folder)
2457                 return '/';
2458         
2459         imap_folder = IMAP_FOLDER(folder);
2460         
2461         if (!imap_folder)
2462                 return '/';
2463         
2464         debug_print("getting session...");
2465         session = imap_session_get(FOLDER(folder));
2466         result = imap_get_path_separator(session, imap_folder, item->path);
2467         unlock_session();
2468         return result;
2469 }
2470
2471 static gchar imap_refresh_path_separator(IMAPSession *session, IMAPFolder *folder, const gchar *subfolder)
2472 {
2473         clist * lep_list;
2474         int r;
2475         gchar separator = '\0';
2476         
2477         g_return_val_if_fail(session != NULL, '/');
2478         r = imap_threaded_list((Folder *)folder, "", subfolder, &lep_list);
2479         
2480         if (r != MAILIMAP_NO_ERROR) {
2481                 log_warning(_("LIST failed\n"));
2482                 return '\0';
2483         }
2484
2485         if (clist_count(lep_list) > 0) {
2486                 clistiter * iter = clist_begin(lep_list); 
2487                 struct mailimap_mailbox_list * mb;
2488                 mb = clist_content(iter);
2489
2490                 separator = mb->mb_delimiter;
2491                 debug_print("got separator: %c\n", folder->last_seen_separator);
2492         }
2493         mailimap_list_result_free(lep_list);
2494         return separator;
2495 }
2496
2497 static gchar imap_get_path_separator(IMAPSession *session, IMAPFolder *folder, const gchar *path)
2498 {
2499         gchar separator = '/';
2500
2501         if (folder->last_seen_separator == 0) {
2502                 folder->last_seen_separator = imap_refresh_path_separator(session, folder, "");
2503         }
2504
2505         if (folder->last_seen_separator == 0) {
2506                 folder->last_seen_separator = imap_refresh_path_separator(session, folder, "INBOX");
2507         }
2508
2509         if (folder->last_seen_separator != 0) {
2510                 debug_print("using separator: %c\n", folder->last_seen_separator);
2511                 return folder->last_seen_separator;
2512         }
2513
2514         return separator;
2515 }
2516
2517 static gchar *imap_get_real_path(IMAPSession *session, IMAPFolder *folder, const gchar *path)
2518 {
2519         gchar *real_path;
2520         gchar separator;
2521
2522         g_return_val_if_fail(folder != NULL, NULL);
2523         g_return_val_if_fail(path != NULL, NULL);
2524
2525         real_path = imap_utf8_to_modified_utf7(path);
2526         separator = imap_get_path_separator(session, folder, path);
2527         imap_path_separator_subst(real_path, separator);
2528
2529         return real_path;
2530 }
2531
2532 static gint imap_set_message_flags(IMAPSession *session,
2533                                    MsgNumberList *numlist,
2534                                    IMAPFlags flags,
2535                                    gboolean is_set)
2536 {
2537         gint ok = 0;
2538         GSList *seq_list;
2539         GSList * cur;
2540
2541         seq_list = imap_get_lep_set_from_numlist(numlist);
2542         
2543         for(cur = seq_list ; cur != NULL ; cur = g_slist_next(cur)) {
2544                 struct mailimap_set * imapset;
2545                 
2546                 imapset = cur->data;
2547                 
2548                 ok = imap_cmd_store(session, imapset,
2549                                     flags, is_set);
2550         }
2551         
2552         imap_lep_set_free(seq_list);
2553         
2554         return IMAP_SUCCESS;
2555 }
2556
2557 typedef struct _select_data {
2558         IMAPSession *session;
2559         gchar *real_path;
2560         gint *exists;
2561         gint *recent;
2562         gint *unseen;
2563         guint32 *uid_validity;
2564         gboolean done;
2565 } select_data;
2566
2567 static gint imap_select(IMAPSession *session, IMAPFolder *folder,
2568                         const gchar *path,
2569                         gint *exists, gint *recent, gint *unseen,
2570                         guint32 *uid_validity, gboolean block)
2571 {
2572         gchar *real_path;
2573         gint ok;
2574         gint exists_, recent_, unseen_;
2575         guint32 uid_validity_;
2576         
2577         if (!exists && !recent && !unseen && !uid_validity) {
2578                 if (session->mbox && strcmp(session->mbox, path) == 0)
2579                         return IMAP_SUCCESS;
2580         }
2581         if (!exists)
2582                 exists = &exists_;
2583         if (!recent)
2584                 recent = &recent_;
2585         if (!unseen)
2586                 unseen = &unseen_;
2587         if (!uid_validity)
2588                 uid_validity = &uid_validity_;
2589
2590         g_free(session->mbox);
2591         session->mbox = NULL;
2592
2593         real_path = imap_get_real_path(session, folder, path);
2594
2595         ok = imap_cmd_select(session, real_path,
2596                              exists, recent, unseen, uid_validity, block);
2597         if (ok != IMAP_SUCCESS)
2598                 log_warning(_("can't select folder: %s\n"), real_path);
2599         else {
2600                 session->mbox = g_strdup(path);
2601                 session->folder_content_changed = FALSE;
2602         }
2603         g_free(real_path);
2604
2605         return ok;
2606 }
2607
2608 static gint imap_status(IMAPSession *session, IMAPFolder *folder,
2609                         const gchar *path, IMAPFolderItem *item,
2610                         gint *messages,
2611                         guint32 *uid_next, guint32 *uid_validity,
2612                         gint *unseen, gboolean block)
2613 {
2614         int r;
2615         clistiter * iter;
2616         struct mailimap_mailbox_data_status * data_status;
2617         int got_values;
2618         gchar *real_path;
2619         guint mask = 0;
2620         
2621         real_path = imap_get_real_path(session, folder, path);
2622
2623         if (messages) {
2624                 mask |= 1 << 0;
2625         }
2626         if (uid_next) {
2627                 mask |= 1 << 2;
2628         }
2629         if (uid_validity) {
2630                 mask |= 1 << 3;
2631         }
2632         if (unseen) {
2633                 mask |= 1 << 4;
2634         }
2635         r = imap_threaded_status(FOLDER(folder), real_path, 
2636                 &data_status, mask);
2637
2638         g_free(real_path);
2639         if (r != MAILIMAP_NO_ERROR) {
2640                 debug_print("status err %d\n", r);
2641                 return IMAP_ERROR;
2642         }
2643         
2644         if (data_status->st_info_list == NULL) {
2645                 mailimap_mailbox_data_status_free(data_status);
2646                 debug_print("status->st_info_list == NULL\n");
2647                 return IMAP_ERROR;
2648         }
2649         
2650         got_values = 0;
2651         for(iter = clist_begin(data_status->st_info_list) ; iter != NULL ;
2652             iter = clist_next(iter)) {
2653                 struct mailimap_status_info * info;             
2654                 
2655                 info = clist_content(iter);
2656                 switch (info->st_att) {
2657                 case MAILIMAP_STATUS_ATT_MESSAGES:
2658                         * messages = info->st_value;
2659                         got_values |= 1 << 0;
2660                         break;
2661                         
2662                 case MAILIMAP_STATUS_ATT_UIDNEXT:
2663                         * uid_next = info->st_value;
2664                         got_values |= 1 << 2;
2665                         break;
2666                         
2667                 case MAILIMAP_STATUS_ATT_UIDVALIDITY:
2668                         * uid_validity = info->st_value;
2669                         got_values |= 1 << 3;
2670                         break;
2671                         
2672                 case MAILIMAP_STATUS_ATT_UNSEEN:
2673                         * unseen = info->st_value;
2674                         got_values |= 1 << 4;
2675                         break;
2676                 }
2677         }
2678         mailimap_mailbox_data_status_free(data_status);
2679         
2680         if (got_values != mask) {
2681                 debug_print("status: incomplete values received (%d)\n", got_values);
2682                 return IMAP_ERROR;
2683         }
2684         return IMAP_SUCCESS;
2685 }
2686
2687 static void imap_free_capabilities(IMAPSession *session)
2688 {
2689         slist_free_strings(session->capability);
2690         g_slist_free(session->capability);
2691         session->capability = NULL;
2692 }
2693
2694 /* low-level IMAP4rev1 commands */
2695
2696 static gint imap_cmd_login(IMAPSession *session,
2697                            const gchar *user, const gchar *pass,
2698                            const gchar *type)
2699 {
2700         int r;
2701         gint ok;
2702
2703         if (!strcmp(type, "LOGIN") && imap_has_capability(session, "LOGINDISABLED")) {
2704                 gint ok = IMAP_ERROR;
2705                 if (imap_has_capability(session, "STARTTLS")) {
2706 #if USE_OPENSSL
2707                         log_warning(_("Server requires TLS to log in.\n"));
2708                         ok = imap_cmd_starttls(session);
2709                         if (ok != IMAP_SUCCESS) {
2710                                 log_warning(_("Can't start TLS session.\n"));
2711                                 return IMAP_ERROR;
2712                         } else {
2713                                 /* refresh capas */
2714                                 imap_free_capabilities(session);
2715                                 if (imap_get_capabilities(session) != MAILIMAP_NO_ERROR) {
2716                                         log_warning(_("Can't refresh capabilities.\n"));
2717                                         return IMAP_ERROR;
2718                                 }
2719                         }
2720 #else           
2721                         log_error(_("Connection to %s failed: "
2722                                         "server requires TLS, but Claws Mail "
2723                                         "has been compiled without OpenSSL "
2724                                         "support.\n"),
2725                                         SESSION(session)->server);
2726                         return IMAP_ERROR;
2727 #endif
2728                 } else {
2729                         log_error(_("Server logins are disabled.\n"));
2730                         return IMAP_ERROR;
2731                 }
2732         }
2733
2734         log_print("IMAP4> Logging %s to %s using %s\n", 
2735                         user,
2736                         SESSION(session)->server,
2737                         type);
2738         r = imap_threaded_login(session->folder, user, pass, type);
2739         if (r != MAILIMAP_NO_ERROR) {
2740                 log_print("IMAP4< Error logging in to %s\n",
2741                                 SESSION(session)->server);
2742                 ok = IMAP_ERROR;
2743         } else {
2744                 log_print("IMAP4< Login to %s successful\n",
2745                                 SESSION(session)->server);
2746                 ok = IMAP_SUCCESS;
2747         }
2748         return ok;
2749 }
2750
2751 static gint imap_cmd_noop(IMAPSession *session)
2752 {
2753         int r;
2754         unsigned int exists;
2755         
2756         r = imap_threaded_noop(session->folder, &exists);
2757         if (r != MAILIMAP_NO_ERROR) {
2758                 debug_print("noop err %d\n", r);
2759                 return IMAP_ERROR;
2760         }
2761         session->exists = exists;
2762         session_set_access_time(SESSION(session));
2763
2764         return IMAP_SUCCESS;
2765 }
2766
2767 #if USE_OPENSSL
2768 static gint imap_cmd_starttls(IMAPSession *session)
2769 {
2770         int r;
2771         
2772         r = imap_threaded_starttls(session->folder, 
2773                 SESSION(session)->server, SESSION(session)->port);
2774         if (r != MAILIMAP_NO_ERROR) {
2775                 debug_print("starttls err %d\n", r);
2776                 return IMAP_ERROR;
2777         }
2778         return IMAP_SUCCESS;
2779 }
2780 #endif
2781
2782 static gint imap_cmd_select(IMAPSession *session, const gchar *folder,
2783                             gint *exists, gint *recent, gint *unseen,
2784                             guint32 *uid_validity, gboolean block)
2785 {
2786         int r;
2787
2788         r = imap_threaded_select(session->folder, folder,
2789                                  exists, recent, unseen, uid_validity);
2790         if (r != MAILIMAP_NO_ERROR) {
2791                 debug_print("select err %d\n", r);
2792                 return IMAP_ERROR;
2793         }
2794         return IMAP_SUCCESS;
2795 }
2796
2797 static gint imap_cmd_examine(IMAPSession *session, const gchar *folder,
2798                              gint *exists, gint *recent, gint *unseen,
2799                              guint32 *uid_validity, gboolean block)
2800 {
2801         int r;
2802
2803         r = imap_threaded_examine(session->folder, folder,
2804                                   exists, recent, unseen, uid_validity);
2805         if (r != MAILIMAP_NO_ERROR) {
2806                 debug_print("examine err %d\n", r);
2807                 
2808                 return IMAP_ERROR;
2809         }
2810         return IMAP_SUCCESS;
2811 }
2812
2813 static gint imap_cmd_create(IMAPSession *session, const gchar *folder)
2814 {
2815         int r;
2816
2817         r = imap_threaded_create(session->folder, folder);
2818         if (r != MAILIMAP_NO_ERROR) {
2819                 
2820                 return IMAP_ERROR;
2821         }
2822
2823         return IMAP_SUCCESS;
2824 }
2825
2826 static gint imap_cmd_rename(IMAPSession *session, const gchar *old_folder,
2827                             const gchar *new_folder)
2828 {
2829         int r;
2830
2831         r = imap_threaded_rename(session->folder, old_folder,
2832                                  new_folder);
2833         if (r != MAILIMAP_NO_ERROR) {
2834                 
2835                 return IMAP_ERROR;
2836         }
2837
2838         return IMAP_SUCCESS;
2839 }
2840
2841 static gint imap_cmd_delete(IMAPSession *session, const gchar *folder)
2842 {
2843         int r;
2844         
2845
2846         r = imap_threaded_delete(session->folder, folder);
2847         if (r != MAILIMAP_NO_ERROR) {
2848                 
2849                 return IMAP_ERROR;
2850         }
2851
2852         return IMAP_SUCCESS;
2853 }
2854
2855 typedef struct _fetch_data {
2856         IMAPSession *session;
2857         guint32 uid;
2858         const gchar *filename;
2859         gboolean headers;
2860         gboolean body;
2861         gboolean done;
2862 } fetch_data;
2863
2864 static void *imap_cmd_fetch_thread(void *data)
2865 {
2866         fetch_data *stuff = (fetch_data *)data;
2867         IMAPSession *session = stuff->session;
2868         guint32 uid = stuff->uid;
2869         const gchar *filename = stuff->filename;
2870         int r;
2871         
2872         if (stuff->body) {
2873                 r = imap_threaded_fetch_content(session->folder,
2874                                                uid, 1, filename);
2875         }
2876         else {
2877                 r = imap_threaded_fetch_content(session->folder,
2878                                                 uid, 0, filename);
2879         }
2880         if (r != MAILIMAP_NO_ERROR) {
2881                 debug_print("fetch err %d\n", r);
2882                 return GINT_TO_POINTER(IMAP_ERROR);
2883         }
2884         return GINT_TO_POINTER(IMAP_SUCCESS);
2885 }
2886
2887 static gint imap_cmd_fetch(IMAPSession *session, guint32 uid,
2888                                 const gchar *filename, gboolean headers,
2889                                 gboolean body)
2890 {
2891         fetch_data *data = g_new0(fetch_data, 1);
2892         int result = 0;
2893         data->done = FALSE;
2894         data->session = session;
2895         data->uid = uid;
2896         data->filename = filename;
2897         data->headers = headers;
2898         data->body = body;
2899
2900         if (prefs_common.work_offline && 
2901             !inc_offline_should_override(
2902                 _("Claws Mail needs network access in order "
2903                   "to access the IMAP server."))) {
2904                 g_free(data);
2905                 return -1;
2906         }
2907         statusbar_print_all(_("Fetching message..."));
2908         result = GPOINTER_TO_INT(imap_cmd_fetch_thread(data));
2909         statusbar_pop_all();
2910         g_free(data);
2911         return result;
2912 }
2913
2914
2915 static gint imap_cmd_append(IMAPSession *session, const gchar *destfolder,
2916                             const gchar *file, IMAPFlags flags, 
2917                             guint32 *new_uid)
2918 {
2919         struct mailimap_flag_list * flag_list;
2920         int r;
2921         
2922         g_return_val_if_fail(file != NULL, IMAP_ERROR);
2923
2924         flag_list = imap_flag_to_lep(flags);
2925         r = imap_threaded_append(session->folder, destfolder,
2926                          file, flag_list, (int *)new_uid);
2927         mailimap_flag_list_free(flag_list);
2928
2929         if (r != MAILIMAP_NO_ERROR) {
2930                 debug_print("append err %d\n", r);
2931                 return IMAP_ERROR;
2932         }
2933         return IMAP_SUCCESS;
2934 }
2935
2936 static gint imap_cmd_copy(IMAPSession *session, struct mailimap_set * set,
2937                           const gchar *destfolder, GRelation *uid_mapping,
2938                           struct mailimap_set **source, struct mailimap_set **dest)
2939 {
2940         int r;
2941         
2942         g_return_val_if_fail(session != NULL, IMAP_ERROR);
2943         g_return_val_if_fail(set != NULL, IMAP_ERROR);
2944         g_return_val_if_fail(destfolder != NULL, IMAP_ERROR);
2945
2946         r = imap_threaded_copy(session->folder, set, destfolder, source, dest);
2947         if (r != MAILIMAP_NO_ERROR) {
2948                 
2949                 return IMAP_ERROR;
2950         }
2951
2952         return IMAP_SUCCESS;
2953 }
2954
2955 static gint imap_cmd_store(IMAPSession *session, struct mailimap_set * set,
2956                            IMAPFlags flags, int do_add)
2957 {
2958         int r;
2959         struct mailimap_flag_list * flag_list;
2960         struct mailimap_store_att_flags * store_att_flags;
2961         
2962         flag_list = imap_flag_to_lep(flags);
2963         
2964         if (do_add)
2965                 store_att_flags =
2966                         mailimap_store_att_flags_new_add_flags_silent(flag_list);
2967         else
2968                 store_att_flags =
2969                         mailimap_store_att_flags_new_remove_flags_silent(flag_list);
2970         
2971         r = imap_threaded_store(session->folder, set, store_att_flags);
2972         mailimap_store_att_flags_free(store_att_flags);
2973         if (r != MAILIMAP_NO_ERROR) {
2974                 
2975                 return IMAP_ERROR;
2976         }
2977         
2978         return IMAP_SUCCESS;
2979 }
2980
2981 static gint imap_cmd_expunge(IMAPSession *session)
2982 {
2983         int r;
2984         
2985         if (prefs_common.work_offline && 
2986             !inc_offline_should_override(
2987                 _("Claws Mail needs network access in order "
2988                   "to access the IMAP server."))) {
2989                 return -1;
2990         }
2991
2992         r = imap_threaded_expunge(session->folder);
2993         if (r != MAILIMAP_NO_ERROR) {
2994                 
2995                 return IMAP_ERROR;
2996         }
2997
2998         return IMAP_SUCCESS;
2999 }
3000
3001 static void imap_path_separator_subst(gchar *str, gchar separator)
3002 {
3003         gchar *p;
3004         gboolean in_escape = FALSE;
3005
3006         if (!separator || separator == '/') return;
3007
3008         for (p = str; *p != '\0'; p++) {
3009                 if (*p == '/' && !in_escape)
3010                         *p = separator;
3011                 else if (*p == '&' && *(p + 1) != '-' && !in_escape)
3012                         in_escape = TRUE;
3013                 else if (*p == '-' && in_escape)
3014                         in_escape = FALSE;
3015         }
3016 }
3017
3018 static gchar *imap_modified_utf7_to_utf8(const gchar *mutf7_str)
3019 {
3020         static iconv_t cd = (iconv_t)-1;
3021         static gboolean iconv_ok = TRUE;
3022         GString *norm_utf7;
3023         gchar *norm_utf7_p;
3024         size_t norm_utf7_len;
3025         const gchar *p;
3026         gchar *to_str, *to_p;
3027         size_t to_len;
3028         gboolean in_escape = FALSE;
3029
3030         if (!iconv_ok) return g_strdup(mutf7_str);
3031
3032         if (cd == (iconv_t)-1) {
3033                 cd = iconv_open(CS_INTERNAL, CS_UTF_7);
3034                 if (cd == (iconv_t)-1) {
3035                         g_warning("iconv cannot convert UTF-7 to %s\n",
3036                                   CS_INTERNAL);
3037                         iconv_ok = FALSE;
3038                         return g_strdup(mutf7_str);
3039                 }
3040         }
3041
3042         /* modified UTF-7 to normal UTF-7 conversion */
3043         norm_utf7 = g_string_new(NULL);
3044
3045         for (p = mutf7_str; *p != '\0'; p++) {
3046                 /* replace: '&'  -> '+',
3047                             "&-" -> '&',
3048                             escaped ','  -> '/' */
3049                 if (!in_escape && *p == '&') {
3050                         if (*(p + 1) != '-') {
3051                                 g_string_append_c(norm_utf7, '+');
3052                                 in_escape = TRUE;
3053                         } else {
3054                                 g_string_append_c(norm_utf7, '&');
3055                                 p++;
3056                         }
3057                 } else if (in_escape && *p == ',') {
3058                         g_string_append_c(norm_utf7, '/');
3059                 } else if (in_escape && *p == '-') {
3060                         g_string_append_c(norm_utf7, '-');
3061                         in_escape = FALSE;
3062                 } else {
3063                         g_string_append_c(norm_utf7, *p);
3064                 }
3065         }
3066
3067         norm_utf7_p = norm_utf7->str;
3068         norm_utf7_len = norm_utf7->len;
3069         to_len = strlen(mutf7_str) * 5;
3070         to_p = to_str = g_malloc(to_len + 1);
3071
3072         if (iconv(cd, (ICONV_CONST gchar **)&norm_utf7_p, &norm_utf7_len,
3073                   &to_p, &to_len) == -1) {
3074                 g_warning(_("iconv cannot convert UTF-7 to %s\n"),
3075                           conv_get_locale_charset_str());
3076                 g_string_free(norm_utf7, TRUE);
3077                 g_free(to_str);
3078                 return g_strdup(mutf7_str);
3079         }
3080
3081         /* second iconv() call for flushing */
3082         iconv(cd, NULL, NULL, &to_p, &to_len);
3083         g_string_free(norm_utf7, TRUE);
3084         *to_p = '\0';
3085
3086         return to_str;
3087 }
3088
3089 static gchar *imap_utf8_to_modified_utf7(const gchar *from)
3090 {
3091         static iconv_t cd = (iconv_t)-1;
3092         static gboolean iconv_ok = TRUE;
3093         gchar *norm_utf7, *norm_utf7_p;
3094         size_t from_len, norm_utf7_len;
3095         GString *to_str;
3096         gchar *from_tmp, *to, *p;
3097         gboolean in_escape = FALSE;
3098
3099         if (!iconv_ok) return g_strdup(from);
3100
3101         if (cd == (iconv_t)-1) {
3102                 cd = iconv_open(CS_UTF_7, CS_INTERNAL);
3103                 if (cd == (iconv_t)-1) {
3104                         g_warning(_("iconv cannot convert %s to UTF-7\n"),
3105                                   CS_INTERNAL);
3106                         iconv_ok = FALSE;
3107                         return g_strdup(from);
3108                 }
3109         }
3110
3111         /* UTF-8 to normal UTF-7 conversion */
3112         Xstrdup_a(from_tmp, from, return g_strdup(from));
3113         from_len = strlen(from);
3114         norm_utf7_len = from_len * 5;
3115         Xalloca(norm_utf7, norm_utf7_len + 1, return g_strdup(from));
3116         norm_utf7_p = norm_utf7;
3117
3118 #define IS_PRINT(ch) (isprint(ch) && IS_ASCII(ch))
3119
3120         while (from_len > 0) {
3121                 if (*from_tmp == '+') {
3122                         *norm_utf7_p++ = '+';
3123                         *norm_utf7_p++ = '-';
3124                         norm_utf7_len -= 2;
3125                         from_tmp++;
3126                         from_len--;
3127                 } else if (IS_PRINT(*(guchar *)from_tmp)) {
3128                         /* printable ascii char */
3129                         *norm_utf7_p = *from_tmp;
3130                         norm_utf7_p++;
3131                         norm_utf7_len--;
3132                         from_tmp++;
3133                         from_len--;
3134                 } else {
3135                         size_t conv_len = 0;
3136
3137                         /* unprintable char: convert to UTF-7 */
3138                         p = from_tmp;
3139                         while (!IS_PRINT(*(guchar *)p) && conv_len < from_len) {
3140                                 conv_len += g_utf8_skip[*(guchar *)p];
3141                                 p += g_utf8_skip[*(guchar *)p];
3142                         }
3143
3144                         from_len -= conv_len;
3145                         if (iconv(cd, (ICONV_CONST gchar **)&from_tmp,
3146                                   &conv_len,
3147                                   &norm_utf7_p, &norm_utf7_len) == -1) {
3148                                 g_warning(_("iconv cannot convert UTF-8 to UTF-7\n"));
3149                                 return g_strdup(from);
3150                         }
3151
3152                         /* second iconv() call for flushing */
3153                         iconv(cd, NULL, NULL, &norm_utf7_p, &norm_utf7_len);
3154                 }
3155         }
3156
3157 #undef IS_PRINT
3158
3159         *norm_utf7_p = '\0';
3160         to_str = g_string_new(NULL);
3161         for (p = norm_utf7; p < norm_utf7_p; p++) {
3162                 /* replace: '&' -> "&-",
3163                             '+' -> '&',
3164                             "+-" -> '+',
3165                             BASE64 '/' -> ',' */
3166                 if (!in_escape && *p == '&') {
3167                         g_string_append(to_str, "&-");
3168                 } else if (!in_escape && *p == '+') {
3169                         if (*(p + 1) == '-') {
3170                                 g_string_append_c(to_str, '+');
3171                                 p++;
3172                         } else {
3173                                 g_string_append_c(to_str, '&');
3174                                 in_escape = TRUE;
3175                         }
3176                 } else if (in_escape && *p == '/') {
3177                         g_string_append_c(to_str, ',');
3178                 } else if (in_escape && *p == '-') {
3179                         g_string_append_c(to_str, '-');
3180                         in_escape = FALSE;
3181                 } else {
3182                         g_string_append_c(to_str, *p);
3183                 }
3184         }
3185
3186         if (in_escape) {
3187                 in_escape = FALSE;
3188                 g_string_append_c(to_str, '-');
3189         }
3190
3191         to = to_str->str;
3192         g_string_free(to_str, FALSE);
3193
3194         return to;
3195 }
3196
3197 static gboolean imap_rename_folder_func(GNode *node, gpointer data)
3198 {
3199         FolderItem *item = node->data;
3200         gchar **paths = data;
3201         const gchar *oldpath = paths[0];
3202         const gchar *newpath = paths[1];
3203         gchar *base;
3204         gchar *new_itempath;
3205         gint oldpathlen;
3206
3207         oldpathlen = strlen(oldpath);
3208         if (strncmp(oldpath, item->path, oldpathlen) != 0) {
3209                 g_warning("path doesn't match: %s, %s\n", oldpath, item->path);
3210                 return TRUE;
3211         }
3212
3213         base = item->path + oldpathlen;
3214         while (*base == G_DIR_SEPARATOR) base++;
3215         if (*base == '\0')
3216                 new_itempath = g_strdup(newpath);
3217         else
3218                 new_itempath = g_strconcat(newpath, G_DIR_SEPARATOR_S, base,
3219                                            NULL);
3220         g_free(item->path);
3221         item->path = new_itempath;
3222
3223         return FALSE;
3224 }
3225
3226 typedef struct _get_list_uid_data {
3227         Folder *folder;
3228         IMAPSession *session;
3229         IMAPFolderItem *item;
3230         GSList **msgnum_list;
3231         gboolean done;
3232 } get_list_uid_data;
3233
3234 static void *get_list_of_uids_thread(void *data)
3235 {
3236         get_list_uid_data *stuff = (get_list_uid_data *)data;
3237         Folder *folder = stuff->folder;
3238         IMAPFolderItem *item = stuff->item;
3239         GSList **msgnum_list = stuff->msgnum_list;
3240         gint ok, nummsgs = 0, lastuid_old;
3241         IMAPSession *session;
3242         GSList *uidlist, *elem;
3243         clist * lep_uidlist;
3244         int r;
3245
3246         session = stuff->session;
3247         if (session == NULL) {
3248                 stuff->done = TRUE;
3249                 return GINT_TO_POINTER(-1);
3250         }
3251         /* no session locking here, it's already locked by caller */
3252         ok = imap_select(session, IMAP_FOLDER(folder), item->item.path,
3253                          NULL, NULL, NULL, NULL, TRUE);
3254         if (ok != IMAP_SUCCESS) {
3255                 stuff->done = TRUE;
3256                 return GINT_TO_POINTER(-1);
3257         }
3258
3259         uidlist = NULL;
3260         
3261         r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SIMPLE, NULL,
3262                                  &lep_uidlist);
3263         
3264         if (r == MAILIMAP_NO_ERROR) {
3265                 GSList * fetchuid_list;
3266                 
3267                 fetchuid_list =
3268                         imap_uid_list_from_lep(lep_uidlist);
3269                 mailimap_search_result_free(lep_uidlist);
3270                 
3271                 uidlist = g_slist_concat(fetchuid_list, uidlist);
3272         }
3273         else {
3274                 GSList * fetchuid_list;
3275                 carray * lep_uidtab;
3276                 
3277                 r = imap_threaded_fetch_uid(folder, item->lastuid + 1,
3278                                             &lep_uidtab);
3279                 if (r == MAILIMAP_NO_ERROR) {
3280                         fetchuid_list =
3281                                 imap_uid_list_from_lep_tab(lep_uidtab);
3282                         imap_fetch_uid_list_free(lep_uidtab);
3283                         uidlist = g_slist_concat(fetchuid_list, uidlist);
3284                 }
3285         }
3286         
3287         lastuid_old = item->lastuid;
3288         *msgnum_list = g_slist_copy(item->uid_list);
3289         nummsgs = g_slist_length(*msgnum_list);
3290         debug_print("Got %d uids from cache\n", g_slist_length(item->uid_list));
3291
3292         for (elem = uidlist; elem != NULL; elem = g_slist_next(elem)) {
3293                 guint msgnum;
3294
3295                 msgnum = GPOINTER_TO_INT(elem->data);
3296                 if (msgnum > lastuid_old) {
3297                         *msgnum_list = g_slist_prepend(*msgnum_list, GINT_TO_POINTER(msgnum));
3298                         item->uid_list = g_slist_prepend(item->uid_list, GINT_TO_POINTER(msgnum));
3299                         nummsgs++;
3300
3301                         if(msgnum > item->lastuid)
3302                                 item->lastuid = msgnum;
3303                 }
3304         }
3305         g_slist_free(uidlist);
3306         stuff->done = TRUE;
3307         return GINT_TO_POINTER(nummsgs);
3308 }
3309
3310 static gint get_list_of_uids(IMAPSession *session, Folder *folder, IMAPFolderItem *item, GSList **msgnum_list)
3311 {
3312         gint result;
3313         get_list_uid_data *data = g_new0(get_list_uid_data, 1);
3314         data->done = FALSE;
3315         data->folder = folder;
3316         data->item = item;
3317         data->msgnum_list = msgnum_list;
3318         data->session = session;
3319         if (prefs_common.work_offline && 
3320             !inc_offline_should_override(
3321                 _("Claws Mail needs network access in order "
3322                   "to access the IMAP server."))) {
3323                 g_free(data);
3324                 return -1;
3325         }
3326
3327         result = GPOINTER_TO_INT(get_list_of_uids_thread(data));
3328         g_free(data);
3329         return result;
3330
3331 }
3332
3333 gint imap_get_num_list(Folder *folder, FolderItem *_item, GSList **msgnum_list, gboolean *old_uids_valid)
3334 {
3335         IMAPFolderItem *item = (IMAPFolderItem *)_item;
3336         IMAPSession *session;
3337         gint ok, nummsgs = 0, exists;
3338         guint32 uid_next = 0, uid_val = 0;
3339         GSList *uidlist = NULL;
3340         gchar *dir;
3341         gboolean selected_folder;
3342         debug_print("get_num_list\n");
3343         
3344         g_return_val_if_fail(folder != NULL, -1);
3345         g_return_val_if_fail(item != NULL, -1);
3346         g_return_val_if_fail(item->item.path != NULL, -1);
3347         g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, -1);
3348         g_return_val_if_fail(folder->account != NULL, -1);
3349
3350         debug_print("getting session...\n");
3351         session = imap_session_get(folder);
3352         g_return_val_if_fail(session != NULL, -1);
3353
3354         if (FOLDER_ITEM(item)->path) 
3355                 statusbar_print_all(_("Scanning folder %s%c%s ..."),
3356                                       FOLDER_ITEM(item)->folder->name, 
3357                                       G_DIR_SEPARATOR,
3358                                       FOLDER_ITEM(item)->path);
3359         else
3360                 statusbar_print_all(_("Scanning folder %s ..."),
3361                                       FOLDER_ITEM(item)->folder->name);
3362
3363         selected_folder = (session->mbox != NULL) &&
3364                           (!strcmp(session->mbox, item->item.path));
3365         if (selected_folder && time(NULL) - item->use_cache < 2) {
3366                 ok = imap_cmd_noop(session);
3367                 if (ok != IMAP_SUCCESS) {
3368                         debug_print("disconnected!\n");
3369                         session = imap_reconnect_if_possible(folder, session);
3370                         if (session == NULL) {
3371                                 statusbar_pop_all();
3372                                 unlock_session();
3373                                 return -1;
3374                         }
3375                 }
3376                 exists = session->exists;
3377
3378                 uid_next = item->c_uid_next;
3379                 uid_val = item->c_uid_validity;
3380                 *old_uids_valid = TRUE;
3381         } else {
3382                 if (item->use_cache && time(NULL) - item->use_cache < 2) {
3383                         exists = item->c_messages;
3384                         uid_next = item->c_uid_next;
3385                         uid_val = item->c_uid_validity;
3386                         ok = IMAP_SUCCESS;
3387                         debug_print("using cache %d %d %d\n", exists, uid_next, uid_val);
3388                 } else {
3389                         ok = imap_status(session, IMAP_FOLDER(folder), item->item.path, item,
3390                                  &exists, &uid_next, &uid_val, NULL, FALSE);
3391                 }
3392                 item->item.last_num = uid_next - 1;
3393                 
3394                 item->use_cache = (time_t)0;
3395                 if (ok != IMAP_SUCCESS) {
3396                         statusbar_pop_all();
3397                         unlock_session();
3398                         return -1;
3399                 }
3400                 if(item->item.mtime == uid_val)
3401                         *old_uids_valid = TRUE;
3402                 else {
3403                         *old_uids_valid = FALSE;
3404
3405                         debug_print("Freeing imap uid cache (%d != %d)\n",
3406                                         (int)item->item.mtime, uid_val);
3407                         item->lastuid = 0;
3408