2007-03-04 [colin] 2.8.0cvs16
[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 {
727                 imap_reset_uid_lists(folder);
728                 if (time(NULL) - rfolder->last_failure <= 2)
729                         return NULL;
730                 session = imap_session_new(folder, folder->account);
731         }
732         if(session == NULL) {
733                 rfolder->last_failure = time(NULL);
734                 return NULL;
735         }
736
737         /* Make sure session is authenticated */
738         if (!IMAP_SESSION(session)->authenticated)
739                 imap_session_authenticate(IMAP_SESSION(session), folder->account);
740         
741         if (!IMAP_SESSION(session)->authenticated) {
742                 imap_threaded_disconnect(session->folder);
743                 SESSION(session)->state = SESSION_DISCONNECTED;
744                 session_destroy(SESSION(session));
745                 rfolder->session = NULL;
746                 rfolder->last_failure = time(NULL);
747                 return NULL;
748         }
749
750         lock_session();
751
752         /* I think the point of this code is to avoid sending a
753          * keepalive if we've used the session recently and therefore
754          * think it's still alive.  Unfortunately, most of the code
755          * does not yet check for errors on the socket, and so if the
756          * connection drops we don't notice until the timeout expires.
757          * A better solution than sending a NOOP every time would be
758          * for every command to be prepared to retry until it is
759          * successfully sent. -- mbp */
760         if (time(NULL) - SESSION(session)->last_access_time > SESSION_TIMEOUT_INTERVAL) {
761                 /* verify that the session is still alive */
762                 if (imap_cmd_noop(session) != IMAP_SUCCESS) {
763                         debug_print("disconnected!\n");
764                         session = imap_reconnect_if_possible(folder, session);
765                 }
766         }
767
768         rfolder->session = SESSION(session);
769
770         return IMAP_SESSION(session);
771 }
772
773 static IMAPSession *imap_session_new(Folder * folder,
774                                      const PrefsAccount *account)
775 {
776         IMAPSession *session;
777         gushort port;
778         int r;
779         int authenticated = FALSE;
780         
781 #ifdef USE_OPENSSL
782         /* FIXME: IMAP over SSL only... */ 
783         SSLType ssl_type;
784
785         port = account->set_imapport ? account->imapport
786                 : account->ssl_imap == SSL_TUNNEL ? IMAPS_PORT : IMAP4_PORT;
787         ssl_type = account->ssl_imap;   
788 #else
789         if (account->ssl_imap != SSL_NONE) {
790                 if (alertpanel_full(_("Insecure connection"),
791                         _("This connection is configured to be secured "
792                           "using SSL, but SSL is not available in this "
793                           "build of Claws Mail. \n\n"
794                           "Do you want to continue connecting to this "
795                           "server? The communication would not be "
796                           "secure."),
797                           GTK_STOCK_CANCEL, _("Con_tinue connecting"), 
798                           NULL, FALSE, NULL, ALERT_WARNING,
799                           G_ALERTDEFAULT) != G_ALERTALTERNATE)
800                         return NULL;
801         }
802         port = account->set_imapport ? account->imapport
803                 : IMAP4_PORT;
804 #endif
805
806         imap_init(folder);
807         statusbar_print_all(_("Connecting to IMAP4 server: %s..."), folder->account->recv_server);
808         if (account->set_tunnelcmd) {
809                 r = imap_threaded_connect_cmd(folder,
810                                               account->tunnelcmd,
811                                               account->recv_server,
812                                               port);
813         }
814         else {
815 #ifdef USE_OPENSSL
816                 if (ssl_type == SSL_TUNNEL) {
817                         r = imap_threaded_connect_ssl(folder,
818                                                       account->recv_server,
819                                                       port);
820                 }
821                 else 
822 #endif
823                 {
824                         r = imap_threaded_connect(folder,
825                                                   account->recv_server,
826                                                   port);
827                 }
828         }
829         
830         statusbar_pop_all();
831         if (r == MAILIMAP_NO_ERROR_AUTHENTICATED) {
832                 authenticated = TRUE;
833         }
834         else if (r == MAILIMAP_NO_ERROR_NON_AUTHENTICATED) {
835                 authenticated = FALSE;
836         }
837         else {
838 #if (LIBETPAN_VERSION_MAJOR > 0 || LIBETPAN_VERSION_MINOR > 48)
839 #ifdef USE_OPENSSL
840                 if (r == MAILIMAP_ERROR_SSL)
841                         log_error(_("SSL handshake failed\n"));
842 #endif
843 #endif
844                 if(!prefs_common.no_recv_err_panel) {
845                         alertpanel_error_log(_("Can't connect to IMAP4 server: %s:%d"),
846                                          account->recv_server, port);
847                 } else {
848                         log_error(_("Can't connect to IMAP4 server: %s:%d\n"),
849                                          account->recv_server, port);
850                 } 
851                 
852                 return NULL;
853         }
854         
855         session = g_new0(IMAPSession, 1);
856         session_init(SESSION(session));
857         SESSION(session)->type             = SESSION_IMAP;
858         SESSION(session)->server           = g_strdup(account->recv_server);
859         SESSION(session)->sock             = NULL;
860         
861         SESSION(session)->destroy          = imap_session_destroy;
862
863         session->capability = NULL;
864         
865         session->authenticated = authenticated;
866         session->mbox = NULL;
867         session->cmd_count = 0;
868         session->folder = folder;
869         IMAP_FOLDER(session->folder)->last_seen_separator = 0;
870
871 #if USE_OPENSSL
872         if (account->ssl_imap == SSL_STARTTLS) {
873                 gint ok;
874
875                 ok = imap_cmd_starttls(session);
876                 if (ok != IMAP_SUCCESS) {
877                         log_warning(_("Can't start TLS session.\n"));
878                         session_destroy(SESSION(session));
879                         return NULL;
880                 }
881
882                 imap_free_capabilities(session);
883                 session->authenticated = FALSE;
884                 session->uidplus = FALSE;
885                 session->cmd_count = 1;
886         }
887 #endif
888         log_message("IMAP connection is %s-authenticated\n",
889                     (session->authenticated) ? "pre" : "un");
890         
891         return session;
892 }
893
894 static void imap_session_authenticate(IMAPSession *session, 
895                                       const PrefsAccount *account)
896 {
897         gchar *pass, *acc_pass;
898         gboolean failed = FALSE;
899
900         g_return_if_fail(account->userid != NULL);
901         acc_pass = account->passwd;
902 try_again:
903         pass = acc_pass;
904         if (!pass && account->imap_auth_type != IMAP_AUTH_ANON) {
905                 gchar *tmp_pass;
906                 tmp_pass = input_dialog_query_password(account->recv_server, account->userid);
907                 if (!tmp_pass)
908                         return;
909                 Xstrdup_a(pass, tmp_pass, {g_free(tmp_pass); return;});
910                 g_free(tmp_pass);
911         } else if (account->imap_auth_type == IMAP_AUTH_ANON) {
912                 pass = "";
913         }
914         statusbar_print_all(_("Connecting to IMAP4 server %s...\n"),
915                                 account->recv_server);
916         if (imap_auth(session, account->userid, pass, account->imap_auth_type) != IMAP_SUCCESS) {
917                 statusbar_pop_all();
918                 
919                 if (!failed) {
920                         acc_pass = NULL;
921                         failed = TRUE;
922                         goto try_again;
923                 } else {
924                         if (prefs_common.no_recv_err_panel) {
925                                 log_error(_("Couldn't login to IMAP server %s."), account->recv_server);
926                                 mainwindow_show_error();
927                         } else
928                                 alertpanel_error_log(_("Couldn't login to IMAP server %s."), account->recv_server);
929                 }               
930
931                 return;
932         } 
933
934         statusbar_pop_all();
935         session->authenticated = TRUE;
936         return;
937 }
938
939 static void imap_session_destroy(Session *session)
940 {
941         if (session->state != SESSION_DISCONNECTED)
942                 imap_threaded_disconnect(IMAP_SESSION(session)->folder);
943         
944         imap_free_capabilities(IMAP_SESSION(session));
945         g_free(IMAP_SESSION(session)->mbox);
946         sock_close(session->sock);
947         session->sock = NULL;
948 }
949
950 static gchar *imap_fetch_msg(Folder *folder, FolderItem *item, gint uid)
951 {
952         return imap_fetch_msg_full(folder, item, uid, TRUE, TRUE);
953 }
954
955 static guint get_size_with_crs(MsgInfo *info) 
956 {
957         FILE *fp = NULL;
958         guint cnt = 0;
959         gchar buf[4096];
960         
961         if (info == NULL)
962                 return -1;
963         
964         fp = procmsg_open_message(info);
965         if (!fp)
966                 return -1;
967         
968         while (fgets(buf, sizeof (buf), fp) != NULL) {
969                 cnt += strlen(buf);
970                 if (!strstr(buf, "\r") && strstr(buf, "\n"))
971                         cnt++;
972         }
973         
974         fclose(fp);
975         return cnt;
976 }
977
978 static gchar *imap_fetch_msg_full(Folder *folder, FolderItem *item, gint uid,
979                                   gboolean headers, gboolean body)
980 {
981         gchar *path, *filename;
982         IMAPSession *session;
983         gint ok;
984
985         g_return_val_if_fail(folder != NULL, NULL);
986         g_return_val_if_fail(item != NULL, NULL);
987
988         if (uid == 0)
989                 return NULL;
990
991         path = folder_item_get_path(item);
992         if (!is_dir_exist(path))
993                 make_dir_hier(path);
994         filename = g_strconcat(path, G_DIR_SEPARATOR_S, itos(uid), NULL);
995         g_free(path);
996         debug_print("trying to fetch cached %s\n", filename);
997         if (is_file_exist(filename)) {
998                 /* see whether the local file represents the whole message
999                  * or not. As the IMAP server reports size with \r chars,
1000                  * we have to update the local file (UNIX \n only) size */
1001                 MsgInfo *msginfo = imap_parse_msg(filename, item);
1002                 MsgInfo *cached = msgcache_get_msg(item->cache,uid);
1003                 guint have_size = get_size_with_crs(msginfo);
1004
1005                 if (cached)
1006                         debug_print("message %d has been already %scached (%d/%d).\n", uid,
1007                                 have_size >= cached->size ? "fully ":"",
1008                                 have_size, (int)cached->size);
1009                 
1010                 if (cached && (cached->size <= have_size || !body)) {
1011                         procmsg_msginfo_free(cached);
1012                         procmsg_msginfo_free(msginfo);
1013                         file_strip_crs(filename);
1014                         return filename;
1015                 } else if (!cached && time(NULL) - get_file_mtime(filename) < 60) {
1016                         debug_print("message not cached and file recent, considering file complete\n");
1017                         procmsg_msginfo_free(msginfo);
1018                         file_strip_crs(filename);
1019                         return filename;
1020                 } else {
1021                         procmsg_msginfo_free(cached);
1022                         procmsg_msginfo_free(msginfo);
1023                 }
1024         }
1025
1026         debug_print("getting session...\n");
1027         session = imap_session_get(folder);
1028         
1029         if (!session) {
1030                 g_free(filename);
1031                 return NULL;
1032         }
1033
1034         debug_print("IMAP fetching messages\n");
1035         ok = imap_select(session, IMAP_FOLDER(folder), item->path,
1036                          NULL, NULL, NULL, NULL, FALSE);
1037         if (ok != IMAP_SUCCESS) {
1038                 g_warning("can't select mailbox %s\n", item->path);
1039                 g_free(filename);
1040                 unlock_session();
1041                 return NULL;
1042         }
1043
1044         debug_print("getting message %d...\n", uid);
1045         ok = imap_cmd_fetch(session, (guint32)uid, filename, headers, body);
1046
1047         if (ok != IMAP_SUCCESS) {
1048                 g_warning("can't fetch message %d\n", uid);
1049                 g_free(filename);
1050                 unlock_session();
1051                 return NULL;
1052         }
1053
1054         unlock_session();
1055         file_strip_crs(filename);
1056         return filename;
1057 }
1058
1059 static gint imap_add_msg(Folder *folder, FolderItem *dest, 
1060                          const gchar *file, MsgFlags *flags)
1061 {
1062         gint ret;
1063         GSList file_list;
1064         MsgFileInfo fileinfo;
1065
1066         g_return_val_if_fail(file != NULL, -1);
1067
1068         fileinfo.msginfo = NULL;
1069         fileinfo.file = (gchar *)file;
1070         fileinfo.flags = flags;
1071         file_list.data = &fileinfo;
1072         file_list.next = NULL;
1073
1074         ret = imap_add_msgs(folder, dest, &file_list, NULL);
1075         return ret;
1076 }
1077
1078 static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
1079                    GRelation *relation)
1080 {
1081         gchar *destdir;
1082         IMAPSession *session;
1083         guint32 last_uid = 0;
1084         GSList *cur;
1085         MsgFileInfo *fileinfo;
1086         gint ok;
1087         gint curnum = 0, total = 0;
1088
1089
1090         g_return_val_if_fail(folder != NULL, -1);
1091         g_return_val_if_fail(dest != NULL, -1);
1092         g_return_val_if_fail(file_list != NULL, -1);
1093         
1094         debug_print("getting session...\n");
1095         session = imap_session_get(folder);
1096         if (!session) {
1097                 return -1;
1098         }
1099         destdir = imap_get_real_path(session, IMAP_FOLDER(folder), dest->path);
1100
1101         statusbar_print_all(_("Adding messages..."));
1102         total = g_slist_length(file_list);
1103         for (cur = file_list; cur != NULL; cur = cur->next) {
1104                 IMAPFlags iflags = 0;
1105                 guint32 new_uid = 0;
1106                 gchar *real_file = NULL;
1107                 fileinfo = (MsgFileInfo *)cur->data;
1108
1109                 statusbar_progress_all(curnum, total, total < 10 ? 1:10);
1110                 curnum++;
1111
1112                 if (fileinfo->flags) {
1113                         if (MSG_IS_MARKED(*fileinfo->flags))
1114                                 iflags |= IMAP_FLAG_FLAGGED;
1115                         if (MSG_IS_REPLIED(*fileinfo->flags))
1116                                 iflags |= IMAP_FLAG_ANSWERED;
1117                         if (!MSG_IS_UNREAD(*fileinfo->flags))
1118                                 iflags |= IMAP_FLAG_SEEN;
1119                 }
1120                 
1121                 if (real_file == NULL)
1122                         real_file = g_strdup(fileinfo->file);
1123                 
1124                 if (folder_has_parent_of_type(dest, F_QUEUE) ||
1125                     folder_has_parent_of_type(dest, F_OUTBOX) ||
1126                     folder_has_parent_of_type(dest, F_DRAFT) ||
1127                     folder_has_parent_of_type(dest, F_TRASH))
1128                         iflags |= IMAP_FLAG_SEEN;
1129
1130                 ok = imap_cmd_append(session, destdir, real_file, iflags, 
1131                                      &new_uid);
1132
1133                 if (ok != IMAP_SUCCESS) {
1134                         g_warning("can't append message %s\n", real_file);
1135                         g_free(real_file);
1136                         g_free(destdir);
1137                         unlock_session();
1138                         statusbar_progress_all(0,0,0);
1139                         statusbar_pop_all();
1140                         return -1;
1141                 } else {
1142                         debug_print("appended new message as %d\n", new_uid);
1143                         /* put the local file in the imapcache, so that we don't
1144                          * have to fetch it back later. */
1145                         if (new_uid > 0) {
1146                                 gchar *cache_path = folder_item_get_path(dest);
1147                                 if (!is_dir_exist(cache_path))
1148                                         make_dir_hier(cache_path);
1149                                 if (is_dir_exist(cache_path)) {
1150                                         gchar *cache_file = g_strconcat(
1151                                                 cache_path, G_DIR_SEPARATOR_S, 
1152                                                 itos(new_uid), NULL);
1153                                         copy_file(real_file, cache_file, TRUE);
1154                                         debug_print("copied to cache: %s\n", cache_file);
1155                                         g_free(cache_file);
1156                                 }
1157                                 g_free(cache_path);
1158                         }
1159                 }
1160
1161                 if (relation != NULL)
1162                         g_relation_insert(relation, fileinfo->msginfo != NULL ? 
1163                                           (gpointer) fileinfo->msginfo : (gpointer) fileinfo,
1164                                           GINT_TO_POINTER(dest->last_num + 1));
1165                 if (new_uid == 0) {
1166                         new_uid = dest->last_num+1;
1167                 }
1168                 if (last_uid < new_uid) {
1169                         last_uid = new_uid;
1170                 }
1171
1172                 g_free(real_file);
1173         }
1174         statusbar_progress_all(0,0,0);
1175         statusbar_pop_all();
1176         
1177         imap_cmd_expunge(session);
1178         unlock_session();
1179         
1180         g_free(destdir);
1181
1182         return last_uid;
1183 }
1184
1185 static gint imap_do_copy_msgs(Folder *folder, FolderItem *dest, 
1186                               MsgInfoList *msglist, GRelation *relation)
1187 {
1188         FolderItem *src;
1189         gchar *destdir;
1190         GSList *seq_list, *cur;
1191         MsgInfo *msginfo;
1192         IMAPSession *session;
1193         gint ok = IMAP_SUCCESS;
1194         GRelation *uid_mapping;
1195         gint last_num = 0;
1196         gboolean single = FALSE;
1197
1198         g_return_val_if_fail(folder != NULL, -1);
1199         g_return_val_if_fail(dest != NULL, -1);
1200         g_return_val_if_fail(msglist != NULL, -1);
1201         
1202         debug_print("getting session...\n");
1203         session = imap_session_get(folder);
1204         
1205         if (!session) {
1206                 return -1;
1207         }
1208
1209         msginfo = (MsgInfo *)msglist->data;
1210         if (msglist->next == NULL)
1211                 single = TRUE;
1212         src = msginfo->folder;
1213         if (src == dest) {
1214                 g_warning("the src folder is identical to the dest.\n");
1215                 unlock_session();
1216                 return -1;
1217         }
1218
1219         if (src->folder != dest->folder) {
1220                 GSList *infolist = NULL, *cur;
1221                 int res = -1;
1222                 for (cur = msglist; cur; cur = cur->next) {
1223                         msginfo = (MsgInfo *)cur->data;
1224                         MsgFileInfo *fileinfo = g_new0(MsgFileInfo, 1);
1225                         fileinfo->file = procmsg_get_message_file(msginfo);
1226                         fileinfo->flags = &(msginfo->flags);
1227                         infolist = g_slist_prepend(infolist, fileinfo);
1228                 }
1229                 infolist = g_slist_reverse(infolist);
1230                 unlock_session();
1231                 res = folder_item_add_msgs(dest, infolist, FALSE);
1232                 for (cur = infolist; cur; cur = cur->next) {
1233                         MsgFileInfo *info = (MsgFileInfo *)cur->data;
1234                         g_free(info->file);
1235                         g_free(info);
1236                 }
1237                 g_slist_free(infolist);
1238                 return res;
1239         } 
1240
1241         ok = imap_select(session, IMAP_FOLDER(folder), msginfo->folder->path,
1242                          NULL, NULL, NULL, NULL, FALSE);
1243         if (ok != IMAP_SUCCESS) {
1244                 unlock_session();
1245                 return ok;
1246         }
1247
1248         destdir = imap_get_real_path(session, IMAP_FOLDER(folder), dest->path);
1249         seq_list = imap_get_lep_set_from_msglist(msglist);
1250         uid_mapping = g_relation_new(2);
1251         g_relation_index(uid_mapping, 0, g_direct_hash, g_direct_equal);
1252         
1253         statusbar_print_all(_("Copying messages..."));
1254         for (cur = seq_list; cur != NULL; cur = g_slist_next(cur)) {
1255                 struct mailimap_set * seq_set;
1256                 struct mailimap_set * source = NULL;
1257                 struct mailimap_set * dest = NULL;
1258                 seq_set = cur->data;
1259
1260                 debug_print("Copying messages from %s to %s ...\n",
1261                             src->path, destdir);
1262
1263                 ok = imap_cmd_copy(session, seq_set, destdir, uid_mapping,
1264                         &source, &dest);
1265                 
1266                 if (ok == IMAP_SUCCESS) {
1267                         if (single && relation && source && dest) {
1268                                 clistiter *l = clist_begin(source->set_list);
1269                                 struct mailimap_set_item *i = (struct mailimap_set_item *)clist_content(l);
1270                                 int snum = i->set_first;
1271                                 int dnum = 0;
1272                                 l = clist_begin(dest->set_list);
1273                                 i = (struct mailimap_set_item *)clist_content(l);
1274                                 dnum = i->set_first;
1275                                 g_relation_insert(uid_mapping, GINT_TO_POINTER(snum), 
1276                                         GINT_TO_POINTER(dnum));
1277                         }
1278                 }
1279
1280
1281                 if (source)
1282                         mailimap_set_free(source);
1283                 if (dest)
1284                         mailimap_set_free(dest);
1285
1286                 if (ok != IMAP_SUCCESS) {
1287                         g_relation_destroy(uid_mapping);
1288                         imap_lep_set_free(seq_list);
1289                         unlock_session();
1290                         statusbar_pop_all();
1291                         return -1;
1292                 }
1293         }
1294
1295         for (cur = msglist; cur != NULL; cur = g_slist_next(cur)) {
1296                 MsgInfo *msginfo = (MsgInfo *)cur->data;
1297                 GTuples *tuples;
1298
1299                 tuples = g_relation_select(uid_mapping, 
1300                                            GINT_TO_POINTER(msginfo->msgnum),
1301                                            0);
1302                 if (tuples->len > 0) {
1303                         gint num = GPOINTER_TO_INT(g_tuples_index(tuples, 0, 1));
1304                         g_relation_insert(relation, msginfo,
1305                                           GINT_TO_POINTER(num));
1306                         if (num > last_num)
1307                                 last_num = num;
1308                         debug_print("copied new message as %d\n", num);
1309                         /* put the local file in the imapcache, so that we don't
1310                          * have to fetch it back later. */
1311                         if (num > 0) {
1312                                 gchar *cache_path = folder_item_get_path(msginfo->folder);
1313                                 gchar *real_file = g_strconcat(
1314                                         cache_path, G_DIR_SEPARATOR_S, 
1315                                         itos(msginfo->msgnum), NULL);
1316                                 gchar *cache_file = NULL;
1317                                 g_free(cache_path);
1318                                 cache_path = folder_item_get_path(dest);
1319                                 cache_file = g_strconcat(
1320                                         cache_path, G_DIR_SEPARATOR_S, 
1321                                         itos(num), NULL);
1322                                 if (!is_dir_exist(cache_path))
1323                                         make_dir_hier(cache_path);
1324                                 if (is_file_exist(real_file) && is_dir_exist(cache_path)) {
1325                                         copy_file(real_file, cache_file, TRUE);
1326                                         debug_print("copied to cache: %s\n", cache_file);
1327                                 }
1328                                 g_free(real_file);
1329                                 g_free(cache_file);
1330                                 g_free(cache_path);
1331                         }
1332                 } else
1333                         g_relation_insert(relation, msginfo,
1334                                           GINT_TO_POINTER(0));
1335                 g_tuples_destroy(tuples);
1336         }
1337         statusbar_pop_all();
1338
1339         g_relation_destroy(uid_mapping);
1340         imap_lep_set_free(seq_list);
1341
1342         g_free(destdir);
1343         
1344         IMAP_FOLDER_ITEM(dest)->lastuid = 0;
1345         IMAP_FOLDER_ITEM(dest)->uid_next = 0;
1346         g_slist_free(IMAP_FOLDER_ITEM(dest)->uid_list);
1347         IMAP_FOLDER_ITEM(dest)->uid_list = NULL;
1348
1349         unlock_session();
1350         if (ok == IMAP_SUCCESS)
1351                 return last_num;
1352         else
1353                 return -1;
1354 }
1355
1356 static gint imap_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
1357 {
1358         GSList msglist;
1359
1360         g_return_val_if_fail(msginfo != NULL, -1);
1361
1362         msglist.data = msginfo;
1363         msglist.next = NULL;
1364
1365         return imap_copy_msgs(folder, dest, &msglist, NULL);
1366 }
1367
1368 static gint imap_copy_msgs(Folder *folder, FolderItem *dest, 
1369                     MsgInfoList *msglist, GRelation *relation)
1370 {
1371         MsgInfo *msginfo;
1372         gint ret;
1373
1374         g_return_val_if_fail(folder != NULL, -1);
1375         g_return_val_if_fail(dest != NULL, -1);
1376         g_return_val_if_fail(msglist != NULL, -1);
1377
1378         msginfo = (MsgInfo *)msglist->data;
1379         g_return_val_if_fail(msginfo->folder != NULL, -1);
1380
1381         ret = imap_do_copy_msgs(folder, dest, msglist, relation);
1382         return ret;
1383 }
1384
1385
1386 static gint imap_do_remove_msgs(Folder *folder, FolderItem *dest, 
1387                                 MsgInfoList *msglist, GRelation *relation)
1388 {
1389         gchar *destdir, *dir;
1390         GSList *numlist = NULL, *cur;
1391         MsgInfo *msginfo;
1392         IMAPSession *session;
1393         gint ok = IMAP_SUCCESS;
1394         GRelation *uid_mapping;
1395         
1396         g_return_val_if_fail(folder != NULL, -1);
1397         g_return_val_if_fail(dest != NULL, -1);
1398         g_return_val_if_fail(msglist != NULL, -1);
1399
1400         debug_print("getting session...\n");
1401         session = imap_session_get(folder);
1402         if (!session) {
1403                 return -1;
1404         }
1405
1406         msginfo = (MsgInfo *)msglist->data;
1407
1408         ok = imap_select(session, IMAP_FOLDER(folder), msginfo->folder->path,
1409                          NULL, NULL, NULL, NULL, FALSE);
1410         if (ok != IMAP_SUCCESS) {
1411                 unlock_session();
1412                 return ok;
1413         }
1414
1415         destdir = imap_get_real_path(session, IMAP_FOLDER(folder), dest->path);
1416         for (cur = msglist; cur; cur = cur->next) {
1417                 msginfo = (MsgInfo *)cur->data;
1418                 if (!MSG_IS_DELETED(msginfo->flags))
1419                         numlist = g_slist_prepend(numlist, GINT_TO_POINTER(msginfo->msgnum));
1420         }
1421         numlist = g_slist_reverse(numlist);
1422
1423         uid_mapping = g_relation_new(2);
1424         g_relation_index(uid_mapping, 0, g_direct_hash, g_direct_equal);
1425
1426         ok = imap_set_message_flags
1427                 (IMAP_SESSION(REMOTE_FOLDER(folder)->session),
1428                 numlist, IMAP_FLAG_DELETED, TRUE);
1429         if (ok != IMAP_SUCCESS) {
1430                 log_warning(_("can't set deleted flags\n"));
1431                 unlock_session();
1432                 return ok;
1433         }
1434         ok = imap_cmd_expunge(session);
1435         if (ok != IMAP_SUCCESS) {
1436                 log_warning(_("can't expunge\n"));
1437                 unlock_session();
1438                 return ok;
1439         }
1440         
1441         dir = folder_item_get_path(msginfo->folder);
1442         if (is_dir_exist(dir)) {
1443                 for (cur = msglist; cur; cur = cur->next) {
1444                         msginfo = (MsgInfo *)cur->data;
1445                         remove_numbered_files(dir, msginfo->msgnum, msginfo->msgnum);
1446                 }
1447         }
1448         g_free(dir);
1449
1450         g_relation_destroy(uid_mapping);
1451         g_slist_free(numlist);
1452
1453         g_free(destdir);
1454         unlock_session();
1455         if (ok == IMAP_SUCCESS)
1456                 return 0;
1457         else
1458                 return -1;
1459 }
1460
1461 static gint imap_remove_msgs(Folder *folder, FolderItem *dest, 
1462                     MsgInfoList *msglist, GRelation *relation)
1463 {
1464         MsgInfo *msginfo;
1465
1466         g_return_val_if_fail(folder != NULL, -1);
1467         g_return_val_if_fail(dest != NULL, -1);
1468         if (msglist == NULL)
1469                 return 0;
1470
1471         msginfo = (MsgInfo *)msglist->data;
1472         g_return_val_if_fail(msginfo->folder != NULL, -1);
1473
1474         return imap_do_remove_msgs(folder, dest, msglist, relation);
1475 }
1476
1477 static gint imap_remove_all_msg(Folder *folder, FolderItem *item)
1478 {
1479         GSList *list = folder_item_get_msg_list(item);
1480         gint res = imap_remove_msgs(folder, item, list, NULL);
1481         procmsg_msg_list_free(list);
1482         return res;
1483 }
1484
1485 static gboolean imap_is_msg_changed(Folder *folder, FolderItem *item,
1486                                     MsgInfo *msginfo)
1487 {
1488         /* TODO: properly implement this method */
1489         return FALSE;
1490 }
1491
1492 static gint imap_close(Folder *folder, FolderItem *item)
1493 {
1494         return 0;
1495 }
1496
1497 gint imap_scan_tree_real(Folder *folder, gboolean subs_only)
1498 {
1499         FolderItem *item = NULL;
1500         IMAPSession *session;
1501         gchar *root_folder = NULL;
1502
1503         g_return_val_if_fail(folder != NULL, -1);
1504         g_return_val_if_fail(folder->account != NULL, -1);
1505
1506         debug_print("getting session...\n");
1507         session = imap_session_get(folder);
1508         if (!session) {
1509                 if (!folder->node) {
1510                         folder_tree_destroy(folder);
1511                         item = folder_item_new(folder, folder->name, NULL);
1512                         item->folder = folder;
1513                         folder->node = item->node = g_node_new(item);
1514                 }
1515                 return -1;
1516         }
1517
1518         if (folder->account->imap_dir && *folder->account->imap_dir) {
1519                 gchar *real_path;
1520                 int r;
1521                 clist * lep_list;
1522
1523                 Xstrdup_a(root_folder, folder->account->imap_dir, {unlock_session();return -1;});
1524                 extract_quote(root_folder, '"');
1525                 subst_char(root_folder,
1526                            imap_get_path_separator(session, IMAP_FOLDER(folder),
1527                                                    root_folder),
1528                            '/');
1529                 strtailchomp(root_folder, '/');
1530                 real_path = imap_get_real_path
1531                         (session, IMAP_FOLDER(folder), root_folder);
1532                 debug_print("IMAP root directory: %s\n", real_path);
1533
1534                 /* check if root directory exist */
1535
1536                 r = imap_threaded_list(session->folder, "", real_path,
1537                                        &lep_list);
1538                 if ((r != MAILIMAP_NO_ERROR) || (clist_count(lep_list) == 0)) {
1539                         if (!folder->node) {
1540                                 item = folder_item_new(folder, folder->name, NULL);
1541                                 item->folder = folder;
1542                                 folder->node = item->node = g_node_new(item);
1543                         }
1544                         unlock_session();
1545                         return -1;
1546                 }
1547                 mailimap_list_result_free(lep_list);
1548                                 
1549                 g_free(real_path);
1550         }
1551
1552         if (folder->node)
1553                 item = FOLDER_ITEM(folder->node->data);
1554                 
1555         if (item && !item->path && root_folder) {
1556                 item->path = g_strdup(root_folder);
1557         }
1558
1559         if (!item || ((item->path || root_folder) &&
1560                       strcmp2(item->path, root_folder) != 0)) {
1561                 folder_tree_destroy(folder);
1562                 item = folder_item_new(folder, folder->name, root_folder);
1563                 item->folder = folder;
1564                 folder->node = item->node = g_node_new(item);
1565         }
1566
1567         imap_scan_tree_recursive(session, FOLDER_ITEM(folder->node->data), subs_only);
1568         imap_create_missing_folders(folder);
1569         unlock_session();
1570
1571         return 0;
1572 }
1573
1574 static gint imap_scan_tree(Folder *folder)
1575 {
1576         gboolean subs_only = FALSE;
1577         if (folder->account) {
1578                 debug_print(" scanning only subs %d\n", folder->account->imap_subsonly);
1579                 subs_only = folder->account->imap_subsonly;
1580         }
1581         return imap_scan_tree_real(folder, subs_only);
1582 }
1583
1584 static gint imap_scan_tree_recursive(IMAPSession *session, FolderItem *item, gboolean subs_only)
1585 {
1586         Folder *folder;
1587         IMAPFolder *imapfolder;
1588         FolderItem *new_item;
1589         GSList *item_list, *cur;
1590         GNode *node;
1591         gchar *real_path;
1592         gchar *wildcard_path;
1593         gchar separator;
1594         gchar wildcard[3];
1595         clist * lep_list;
1596         int r;
1597         
1598         g_return_val_if_fail(item != NULL, -1);
1599         g_return_val_if_fail(item->folder != NULL, -1);
1600         g_return_val_if_fail(item->no_sub == FALSE, -1);
1601
1602         folder = item->folder;
1603         imapfolder = IMAP_FOLDER(folder);
1604
1605         separator = imap_get_path_separator(session, imapfolder, item->path);
1606
1607         if (folder->ui_func)
1608                 folder->ui_func(folder, item, folder->ui_func_data);
1609
1610         if (item->path) {
1611                 wildcard[0] = separator;
1612                 wildcard[1] = '%';
1613                 wildcard[2] = '\0';
1614                 real_path = imap_get_real_path(session, imapfolder, item->path);
1615         } else {
1616                 wildcard[0] = '%';
1617                 wildcard[1] = '\0';
1618                 real_path = g_strdup("");
1619         }
1620
1621         Xstrcat_a(wildcard_path, real_path, wildcard,
1622                   {g_free(real_path); return IMAP_ERROR;});
1623         lep_list = NULL;
1624         
1625         if (subs_only)
1626                 r = imap_threaded_lsub(folder, "", wildcard_path, &lep_list);
1627         else
1628                 r = imap_threaded_list(folder, "", wildcard_path, &lep_list);
1629
1630         if (r != MAILIMAP_NO_ERROR) {
1631                 item_list = NULL;
1632         }
1633         else {
1634                 item_list = imap_list_from_lep(imapfolder,
1635                                                lep_list, real_path, FALSE);
1636                 mailimap_list_result_free(lep_list);
1637         }
1638         
1639         g_free(real_path);
1640
1641         node = item->node->children;
1642         while (node != NULL) {
1643                 FolderItem *old_item = FOLDER_ITEM(node->data);
1644                 GNode *next = node->next;
1645
1646                 new_item = NULL;
1647                 for (cur = item_list; cur != NULL; cur = cur->next) {
1648                         FolderItem *cur_item = FOLDER_ITEM(cur->data);
1649                         if (!strcmp2(old_item->path, cur_item->path)) {
1650                                 new_item = cur_item;
1651                                 break;
1652                         }
1653                 }
1654                 if (!new_item) {
1655                         if (old_item && old_item->path && !strcmp(old_item->path, "INBOX")) {
1656                                 debug_print("not removing INBOX\n");
1657                         } else {
1658                                 debug_print("folder '%s' not found. removing...\n",
1659                                             old_item->path);
1660                                 folder_item_remove(old_item);
1661                         }
1662                 } else {
1663                         old_item->no_sub = new_item->no_sub;
1664                         old_item->no_select = new_item->no_select;
1665                         if (old_item->no_sub == TRUE && node->children) {
1666                                 debug_print("folder '%s' doesn't have "
1667                                             "subfolders. removing...\n",
1668                                             old_item->path);
1669                                 folder_item_remove_children(old_item);
1670                         }
1671                 }
1672
1673                 node = next;
1674         }
1675
1676         for (cur = item_list; cur != NULL; cur = cur->next) {
1677                 FolderItem *cur_item = FOLDER_ITEM(cur->data);
1678                 new_item = NULL;
1679
1680                 for (node = item->node->children; node != NULL;
1681                      node = node->next) {
1682                         if (!strcmp2(FOLDER_ITEM(node->data)->path,
1683                                      cur_item->path)) {
1684                                 new_item = FOLDER_ITEM(node->data);
1685                                 folder_item_destroy(cur_item);
1686                                 cur_item = NULL;
1687                                 break;
1688                         }
1689                 }
1690                 if (!new_item) {
1691                         new_item = cur_item;
1692                         debug_print("new folder '%s' found.\n", new_item->path);
1693                         folder_item_append(item, new_item);
1694                 }
1695
1696                 if (!strcmp(new_item->path, "INBOX")) {
1697                         new_item->stype = F_INBOX;
1698                         folder->inbox = new_item;
1699                 } else if (!folder_item_parent(item) || item->stype == F_INBOX) {
1700                         gchar *base;
1701
1702                         base = g_path_get_basename(new_item->path);
1703
1704                         if (!folder->outbox && !g_ascii_strcasecmp(base, "Sent")) {
1705                                 new_item->stype = F_OUTBOX;
1706                                 folder->outbox = new_item;
1707                         } else if (!folder->draft && !g_ascii_strcasecmp(base, "Drafts")) {
1708                                 new_item->stype = F_DRAFT;
1709                                 folder->draft = new_item;
1710                         } else if (!folder->queue && !g_ascii_strcasecmp(base, "Queue")) {
1711                                 new_item->stype = F_QUEUE;
1712                                 folder->queue = new_item;
1713                         } else if (!folder->trash && !g_ascii_strcasecmp(base, "Trash")) {
1714                                 new_item->stype = F_TRASH;
1715                                 folder->trash = new_item;
1716                         }
1717                         g_free(base);
1718                 }
1719
1720                 if (new_item->no_sub == FALSE)
1721                         imap_scan_tree_recursive(session, new_item, subs_only);
1722         }
1723
1724         g_slist_free(item_list);
1725
1726         return IMAP_SUCCESS;
1727 }
1728
1729 GList *imap_scan_subtree(Folder *folder, FolderItem *item, gboolean unsubs_only, gboolean recursive)
1730 {
1731         IMAPSession *session = imap_session_get(folder);
1732         gchar *real_path;
1733         gchar *wildcard_path;
1734         gchar separator;
1735         gchar wildcard[3];
1736         clist * lep_list;
1737         GSList *item_list = NULL, *cur;
1738         GList *child_list = NULL, *tmplist = NULL;
1739         GSList *sub_list = NULL;
1740         int r;
1741
1742         if (!session)
1743                 return NULL;
1744
1745         separator = imap_get_path_separator(session, IMAP_FOLDER(folder), item->path);
1746
1747         if (item->path) {
1748                 wildcard[0] = separator;
1749                 wildcard[1] = '%';
1750                 wildcard[2] = '\0';
1751                 real_path = imap_get_real_path(session, IMAP_FOLDER(folder), item->path);
1752         } else {
1753                 wildcard[0] = '%';
1754                 wildcard[1] = '\0';
1755                 real_path = g_strdup("");
1756         }
1757
1758         Xstrcat_a(wildcard_path, real_path, wildcard,
1759                   {g_free(real_path); return NULL;});
1760         lep_list = NULL;
1761         
1762         if (unsubs_only)
1763                 statusbar_print_all(_("Looking for unsubscribed folders in %s..."), 
1764                                 item->path?item->path:item->name);
1765         else
1766                 statusbar_print_all(_("Looking for subfolders of %s..."), 
1767                                 item->path?item->path:item->name);
1768
1769         r = imap_threaded_list(folder, "", wildcard_path, &lep_list);
1770         if (r) {
1771                 statusbar_pop_all();
1772                 return NULL;
1773         }
1774         item_list = imap_list_from_lep(IMAP_FOLDER(folder),
1775                                lep_list, real_path, FALSE);
1776         mailimap_list_result_free(lep_list);
1777
1778         for (cur = item_list; cur != NULL; cur = cur->next) {
1779                 FolderItem *cur_item = FOLDER_ITEM(cur->data);
1780                 if (recursive) {
1781                         tmplist = imap_scan_subtree(folder, cur_item, 
1782                                         unsubs_only, recursive);
1783                         if (tmplist)
1784                                 child_list = g_list_concat(child_list, tmplist);
1785                 }
1786                 child_list = g_list_prepend(child_list,
1787                                 imap_get_real_path(session, 
1788                                         IMAP_FOLDER(folder), cur_item->path));
1789                 
1790                 folder_item_destroy(cur_item);
1791         }
1792         child_list = g_list_reverse(child_list);
1793         g_slist_free(item_list);
1794
1795         if (unsubs_only) {
1796                 r = imap_threaded_lsub(folder, "", wildcard_path, &lep_list);
1797                 if (r) {
1798                         statusbar_pop_all();
1799                         return NULL;
1800                 }
1801                 sub_list = imap_list_from_lep(IMAP_FOLDER(folder),
1802                                        lep_list, real_path, FALSE);
1803                 mailimap_list_result_free(lep_list);
1804
1805                 for (cur = sub_list; cur != NULL; cur = cur->next) {
1806                         FolderItem *cur_item = FOLDER_ITEM(cur->data);
1807                         GList *oldlitem = NULL;
1808                         gchar *tmp = imap_get_real_path(session, 
1809                                         IMAP_FOLDER(folder), cur_item->path);
1810                         folder_item_destroy(cur_item);
1811                         oldlitem = g_list_find_custom(
1812                                         child_list, tmp, (GCompareFunc)strcmp2);
1813                         if (oldlitem) {
1814                                 child_list = g_list_remove_link(child_list, oldlitem);
1815                                 g_free(oldlitem->data);
1816                                 g_list_free(oldlitem);
1817                         }
1818                         g_free(tmp);
1819                 }
1820         }
1821
1822         statusbar_pop_all();
1823
1824         return child_list;
1825 }
1826
1827 static gint imap_create_tree(Folder *folder)
1828 {
1829         g_return_val_if_fail(folder != NULL, -1);
1830         g_return_val_if_fail(folder->node != NULL, -1);
1831         g_return_val_if_fail(folder->node->data != NULL, -1);
1832         g_return_val_if_fail(folder->account != NULL, -1);
1833
1834         imap_scan_tree(folder);
1835         imap_create_missing_folders(folder);
1836
1837         return 0;
1838 }
1839
1840 static void imap_create_missing_folders(Folder *folder)
1841 {
1842         g_return_if_fail(folder != NULL);
1843
1844         if (!folder->inbox)
1845                 folder->inbox = imap_create_special_folder
1846                         (folder, F_INBOX, "INBOX");
1847         if (!folder->trash)
1848                 folder->trash = imap_create_special_folder
1849                         (folder, F_TRASH, "Trash");
1850         if (!folder->queue)
1851                 folder->queue = imap_create_special_folder
1852                         (folder, F_QUEUE, "Queue");
1853         if (!folder->outbox)
1854                 folder->outbox = imap_create_special_folder
1855                         (folder, F_OUTBOX, "Sent");
1856         if (!folder->draft)
1857                 folder->draft = imap_create_special_folder
1858                         (folder, F_DRAFT, "Drafts");
1859 }
1860
1861 static FolderItem *imap_create_special_folder(Folder *folder,
1862                                               SpecialFolderItemType stype,
1863                                               const gchar *name)
1864 {
1865         FolderItem *item;
1866         FolderItem *new_item;
1867
1868         g_return_val_if_fail(folder != NULL, NULL);
1869         g_return_val_if_fail(folder->node != NULL, NULL);
1870         g_return_val_if_fail(folder->node->data != NULL, NULL);
1871         g_return_val_if_fail(folder->account != NULL, NULL);
1872         g_return_val_if_fail(name != NULL, NULL);
1873
1874         item = FOLDER_ITEM(folder->node->data);
1875         new_item = imap_create_folder(folder, item, name);
1876
1877         if (!new_item) {
1878                 g_warning("Can't create '%s'\n", name);
1879                 if (!folder->inbox) return NULL;
1880
1881                 new_item = imap_create_folder(folder, folder->inbox, name);
1882                 if (!new_item)
1883                         g_warning("Can't create '%s' under INBOX\n", name);
1884                 else
1885                         new_item->stype = stype;
1886         } else
1887                 new_item->stype = stype;
1888
1889         return new_item;
1890 }
1891
1892 static gchar *imap_folder_get_path(Folder *folder)
1893 {
1894         gchar *folder_path;
1895
1896         g_return_val_if_fail(folder != NULL, NULL);
1897         g_return_val_if_fail(folder->account != NULL, NULL);
1898
1899         folder_path = g_strconcat(get_imap_cache_dir(),
1900                                   G_DIR_SEPARATOR_S,
1901                                   folder->account->recv_server,
1902                                   G_DIR_SEPARATOR_S,
1903                                   folder->account->userid,
1904                                   NULL);
1905
1906         return folder_path;
1907 }
1908
1909 static gchar *imap_item_get_path(Folder *folder, FolderItem *item)
1910 {
1911         gchar *folder_path, *path;
1912
1913         g_return_val_if_fail(folder != NULL, NULL);
1914         g_return_val_if_fail(item != NULL, NULL);
1915         folder_path = imap_folder_get_path(folder);
1916
1917         g_return_val_if_fail(folder_path != NULL, NULL);
1918         if (folder_path[0] == G_DIR_SEPARATOR) {
1919                 if (item->path)
1920                         path = g_strconcat(folder_path, G_DIR_SEPARATOR_S,
1921                                            item->path, NULL);
1922                 else
1923                         path = g_strdup(folder_path);
1924         } else {
1925                 if (item->path)
1926                         path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
1927                                            folder_path, G_DIR_SEPARATOR_S,
1928                                            item->path, NULL);
1929                 else
1930                         path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
1931                                            folder_path, NULL);
1932         }
1933         g_free(folder_path);
1934
1935         return path;
1936 }
1937
1938 static FolderItem *imap_create_folder(Folder *folder, FolderItem *parent,
1939                                const gchar *name)
1940 {
1941         gchar *dirpath, *imap_path;
1942         IMAPSession *session;
1943         FolderItem *new_item;
1944         gchar separator;
1945         gchar *new_name;
1946         const gchar *p;
1947         gint ok;
1948         gboolean no_select = FALSE, no_sub = FALSE;
1949         gboolean exist = FALSE;
1950         
1951         g_return_val_if_fail(folder != NULL, NULL);
1952         g_return_val_if_fail(folder->account != NULL, NULL);
1953         g_return_val_if_fail(parent != NULL, NULL);
1954         g_return_val_if_fail(name != NULL, NULL);
1955
1956         debug_print("getting session...\n");
1957         session = imap_session_get(folder);
1958         if (!session) {
1959                 return NULL;
1960         }
1961
1962         if (!folder_item_parent(parent) && strcmp(name, "INBOX") == 0) {
1963                 dirpath = g_strdup(name);
1964         }else if (parent->path)
1965                 dirpath = g_strconcat(parent->path, "/", name, NULL);
1966         else if ((p = strchr(name, '/')) != NULL && *(p + 1) != '\0')
1967                 dirpath = g_strdup(name);
1968         else if (folder->account->imap_dir && *folder->account->imap_dir) {
1969                 gchar *imap_dir;
1970
1971                 Xstrdup_a(imap_dir, folder->account->imap_dir, {unlock_session();return NULL;});
1972                 strtailchomp(imap_dir, '/');
1973                 dirpath = g_strconcat(imap_dir, "/", name, NULL);
1974         } else
1975                 dirpath = g_strdup(name);
1976                 
1977         
1978
1979         /* keep trailing directory separator to create a folder that contains
1980            sub folder */
1981         imap_path = imap_utf8_to_modified_utf7(dirpath);
1982
1983         strtailchomp(dirpath, '/');
1984         Xstrdup_a(new_name, name, {
1985                 g_free(dirpath); 
1986                 unlock_session();               
1987                 return NULL;});
1988
1989         separator = imap_get_path_separator(session, IMAP_FOLDER(folder), imap_path);
1990         imap_path_separator_subst(imap_path, separator);
1991         /* remove trailing / for display */
1992         strtailchomp(new_name, '/');
1993
1994         if (strcmp(dirpath, "INBOX") != 0) {
1995                 GPtrArray *argbuf;
1996                 int r;
1997                 clist * lep_list;
1998                 
1999                 argbuf = g_ptr_array_new();
2000                 r = imap_threaded_list(folder, "", imap_path, &lep_list);
2001                 if (r != MAILIMAP_NO_ERROR) {
2002                         log_warning(_("can't create mailbox: LIST failed\n"));
2003                         g_free(imap_path);
2004                         g_free(dirpath);
2005                         ptr_array_free_strings(argbuf);
2006                         g_ptr_array_free(argbuf, TRUE);
2007                         unlock_session();
2008                         return NULL;
2009                 }
2010                 
2011                 if (clist_count(lep_list) > 0)
2012                         exist = TRUE;
2013                 mailimap_list_result_free(lep_list);
2014                 lep_list = NULL;
2015                 if (!exist) {
2016                         ok = imap_cmd_create(session, imap_path);
2017                         if (ok != IMAP_SUCCESS) {
2018                                 log_warning(_("can't create mailbox\n"));
2019                                 g_free(imap_path);
2020                                 g_free(dirpath);
2021                                 unlock_session();
2022                                 return NULL;
2023                         }
2024                         r = imap_threaded_list(folder, "", imap_path, &lep_list);
2025                         if (r == MAILIMAP_NO_ERROR) {
2026                                 GSList *item_list = imap_list_from_lep(IMAP_FOLDER(folder),
2027                                                lep_list, dirpath, TRUE);
2028                                 if (item_list) {
2029                                         FolderItem *cur_item = FOLDER_ITEM(item_list->data);
2030                                         no_select = cur_item->no_select;
2031                                         no_sub = cur_item->no_sub;
2032                                         g_slist_free(item_list);
2033                                 } 
2034                                 mailimap_list_result_free(lep_list);
2035                         }
2036                 }
2037                 imap_threaded_subscribe(folder, imap_path, TRUE);
2038         } else {
2039                 clist *lep_list;
2040                 int r;
2041                 /* just get flags */
2042                 r = imap_threaded_list(folder, "", "INBOX", &lep_list);
2043                 if (r == MAILIMAP_NO_ERROR) {
2044                         GSList *item_list = imap_list_from_lep(IMAP_FOLDER(folder),
2045                                        lep_list, dirpath, TRUE);
2046                         if (item_list) {
2047                                 FolderItem *cur_item = FOLDER_ITEM(item_list->data);
2048                                 no_select = cur_item->no_select;
2049                                 no_sub = cur_item->no_sub;
2050                                 g_slist_free(item_list);
2051                         } 
2052                         mailimap_list_result_free(lep_list);
2053                 }
2054         }
2055
2056         new_item = folder_item_new(folder, new_name, dirpath);
2057         new_item->no_select = no_select;
2058         new_item->no_sub = no_sub;
2059         folder_item_append(parent, new_item);
2060         g_free(imap_path);
2061         g_free(dirpath);
2062
2063         dirpath = folder_item_get_path(new_item);
2064         if (!is_dir_exist(dirpath))
2065                 make_dir_hier(dirpath);
2066         g_free(dirpath);
2067         unlock_session();
2068
2069         if (exist) {
2070                 /* folder existed, scan it */
2071                 folder_item_scan_full(new_item, FALSE);
2072         }
2073
2074         return new_item;
2075 }
2076
2077 static gint imap_rename_folder(Folder *folder, FolderItem *item,
2078                                const gchar *name)
2079 {
2080         gchar *dirpath;
2081         gchar *newpath;
2082         gchar *real_oldpath;
2083         gchar *real_newpath;
2084         gchar *paths[2];
2085         gchar *old_cache_dir;
2086         gchar *new_cache_dir;
2087         IMAPSession *session;
2088         gchar separator;
2089         gint ok;
2090         gint exists, recent, unseen;
2091         guint32 uid_validity;
2092
2093         g_return_val_if_fail(folder != NULL, -1);
2094         g_return_val_if_fail(item != NULL, -1);
2095         g_return_val_if_fail(item->path != NULL, -1);
2096         g_return_val_if_fail(name != NULL, -1);
2097
2098         debug_print("getting session...\n");
2099         session = imap_session_get(folder);
2100         if (!session) {
2101                 return -1;
2102         }
2103
2104         if (strchr(name, imap_get_path_separator(session, IMAP_FOLDER(folder), item->path)) != NULL) {
2105                 g_warning(_("New folder name must not contain the namespace "
2106                             "path separator"));
2107                 unlock_session();
2108                 return -1;
2109         }
2110
2111         real_oldpath = imap_get_real_path(session, IMAP_FOLDER(folder), item->path);
2112
2113         g_free(session->mbox);
2114         session->mbox = NULL;
2115         ok = imap_cmd_examine(session, "INBOX",
2116                               &exists, &recent, &unseen, &uid_validity, FALSE);
2117         if (ok != IMAP_SUCCESS) {
2118                 g_free(real_oldpath);
2119                 unlock_session();
2120                 return -1;
2121         }
2122
2123         separator = imap_get_path_separator(session, IMAP_FOLDER(folder), item->path);
2124         if (strchr(item->path, G_DIR_SEPARATOR)) {
2125                 dirpath = g_path_get_dirname(item->path);
2126                 newpath = g_strconcat(dirpath, G_DIR_SEPARATOR_S, name, NULL);
2127                 g_free(dirpath);
2128         } else
2129                 newpath = g_strdup(name);
2130
2131         real_newpath = imap_utf8_to_modified_utf7(newpath);
2132         imap_path_separator_subst(real_newpath, separator);
2133
2134         ok = imap_cmd_rename(session, real_oldpath, real_newpath);
2135         if (ok != IMAP_SUCCESS) {
2136                 log_warning(_("can't rename mailbox: %s to %s\n"),
2137                             real_oldpath, real_newpath);
2138                 g_free(real_oldpath);
2139                 g_free(newpath);
2140                 g_free(real_newpath);
2141                 unlock_session();
2142                 return -1;
2143         }
2144
2145         g_free(item->name);
2146         item->name = g_strdup(name);
2147
2148         old_cache_dir = folder_item_get_path(item);
2149
2150         paths[0] = g_strdup(item->path);
2151         paths[1] = newpath;
2152         g_node_traverse(item->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
2153                         imap_rename_folder_func, paths);
2154
2155         if (is_dir_exist(old_cache_dir)) {
2156                 new_cache_dir = folder_item_get_path(item);
2157                 if (rename(old_cache_dir, new_cache_dir) < 0) {
2158                         FILE_OP_ERROR(old_cache_dir, "rename");
2159                 }
2160                 g_free(new_cache_dir);
2161         }
2162
2163         g_free(old_cache_dir);
2164         g_free(paths[0]);
2165         g_free(newpath);
2166         g_free(real_oldpath);
2167         g_free(real_newpath);
2168         unlock_session();
2169         return 0;
2170 }
2171
2172 gint imap_subscribe(Folder *folder, FolderItem *item, gchar *rpath, gboolean sub)
2173 {
2174         gchar *path;
2175         gint r = -1;
2176         IMAPSession *session;
2177         debug_print("getting session...\n");
2178
2179         session = imap_session_get(folder);
2180         if (!session) {
2181                 return -1;
2182         }
2183         if (item && item->path) {
2184                 path = imap_get_real_path(session, IMAP_FOLDER(folder), item->path);
2185                 if (!path)
2186                         return -1;
2187                 if (!strcmp(path, "INBOX") && sub == FALSE)
2188                         return -1;
2189                 debug_print("%ssubscribing %s\n", sub?"":"un", path);
2190                 r = imap_threaded_subscribe(folder, path, sub);
2191                 g_free(path);
2192         } else if (rpath) {
2193                 r = imap_threaded_subscribe(folder, rpath, sub);
2194         } else
2195                 return -1;
2196         return r;
2197 }
2198
2199 static gint imap_remove_folder_real(Folder *folder, FolderItem *item)
2200 {
2201         gint ok;
2202         IMAPSession *session;
2203         gchar *path;
2204         gchar *cache_dir;
2205
2206         g_return_val_if_fail(folder != NULL, -1);
2207         g_return_val_if_fail(item != NULL, -1);
2208         g_return_val_if_fail(item->path != NULL, -1);
2209
2210         debug_print("getting session...\n");
2211         session = imap_session_get(folder);
2212         if (!session) {
2213                 return -1;
2214         }
2215         path = imap_get_real_path(session, IMAP_FOLDER(folder), item->path);
2216
2217         imap_threaded_subscribe(folder, path, FALSE);
2218         ok = imap_cmd_delete(session, path);
2219         if (ok != IMAP_SUCCESS) {
2220                 gchar *tmp = g_strdup_printf("%s%c", path, 
2221                                 imap_get_path_separator(session, IMAP_FOLDER(folder), path));
2222                 g_free(path);
2223                 path = tmp;
2224                 ok = imap_cmd_delete(session, path);
2225         }
2226
2227         if (ok != IMAP_SUCCESS) {
2228                 log_warning(_("can't delete mailbox\n"));
2229                 g_free(path);
2230                 unlock_session();
2231                 return -1;
2232         }
2233
2234         g_free(path);
2235         cache_dir = folder_item_get_path(item);
2236         if (is_dir_exist(cache_dir) && remove_dir_recursive(cache_dir) < 0)
2237                 g_warning("can't remove directory '%s'\n", cache_dir);
2238         g_free(cache_dir);
2239         folder_item_remove(item);
2240         unlock_session();
2241         return 0;
2242 }
2243
2244 static gint imap_remove_folder(Folder *folder, FolderItem *item)
2245 {
2246         GNode *node, *next;
2247
2248         g_return_val_if_fail(item != NULL, -1);
2249         g_return_val_if_fail(item->folder != NULL, -1);
2250         g_return_val_if_fail(item->node != NULL, -1);
2251
2252         node = item->node->children;
2253         while (node != NULL) {
2254                 next = node->next;
2255                 if (imap_remove_folder(folder, FOLDER_ITEM(node->data)) < 0)
2256                         return -1;
2257                 node = next;
2258         }
2259         debug_print("IMAP removing %s\n", item->path);
2260
2261         if (imap_remove_all_msg(folder, item) < 0)
2262                 return -1;
2263         return imap_remove_folder_real(folder, item);
2264 }
2265
2266 typedef struct _uncached_data {
2267         IMAPSession *session;
2268         FolderItem *item;
2269         MsgNumberList *numlist;
2270         guint cur;
2271         guint total;
2272         gboolean done;
2273 } uncached_data;
2274
2275 static void *imap_get_uncached_messages_thread(void *data)
2276 {
2277         uncached_data *stuff = (uncached_data *)data;
2278         IMAPSession *session = stuff->session;
2279         FolderItem *item = stuff->item;
2280         MsgNumberList *numlist = stuff->numlist;
2281         
2282         GSList *newlist = NULL;
2283         GSList *llast = NULL;
2284         GSList *seq_list, *cur;
2285
2286         debug_print("uncached_messages\n");
2287         
2288         if (session == NULL || item == NULL || item->folder == NULL
2289             || FOLDER_CLASS(item->folder) != &imap_class) {
2290                 stuff->done = TRUE;
2291                 return NULL;
2292         }
2293         
2294         seq_list = imap_get_lep_set_from_numlist(numlist);
2295         debug_print("get msgs info\n");
2296         for (cur = seq_list; cur != NULL; cur = g_slist_next(cur)) {
2297                 struct mailimap_set * imapset;
2298                 unsigned int i;
2299                 int r;
2300                 carray * env_list;
2301                 int count;
2302                 
2303                 imapset = cur->data;
2304                 
2305                 r = imap_threaded_fetch_env(session->folder,
2306                                             imapset, &env_list);
2307                 if (r != MAILIMAP_NO_ERROR)
2308                         continue;
2309                 
2310                 session_set_access_time(SESSION(session));
2311
2312                 count = 0;
2313                 for(i = 0 ; i < carray_count(env_list) ; i ++) {
2314                         struct imap_fetch_env_info * info;
2315                         MsgInfo * msginfo;
2316                         
2317                         info = carray_get(env_list, i);
2318                         msginfo = imap_envelope_from_lep(info, item);
2319                         if (msginfo == NULL)
2320                                 continue;
2321                         msginfo->folder = item;
2322                         if (!newlist)
2323                                 llast = newlist = g_slist_append(newlist, msginfo);
2324                         else {
2325                                 llast = g_slist_append(llast, msginfo);
2326                                 llast = llast->next;
2327                         }
2328                         count ++;
2329                 }
2330                 
2331                 imap_fetch_env_free(env_list);
2332         }
2333         
2334         for (cur = seq_list; cur != NULL; cur = g_slist_next(cur)) {
2335                 struct mailimap_set * imapset;
2336                 
2337                 imapset = cur->data;
2338                 mailimap_set_free(imapset);
2339         }
2340         
2341         session_set_access_time(SESSION(session));
2342         stuff->done = TRUE;
2343         return newlist;
2344 }
2345
2346 #define MAX_MSG_NUM 50
2347
2348 static GSList *imap_get_uncached_messages(IMAPSession *session,
2349                                         FolderItem *item,
2350                                         MsgNumberList *numlist)
2351 {
2352         GSList *result = NULL;
2353         GSList * cur;
2354         uncached_data *data = g_new0(uncached_data, 1);
2355         int finished;
2356         
2357         finished = 0;
2358         cur = numlist;
2359         data->total = g_slist_length(numlist);
2360         debug_print("messages list : %i\n", data->total);
2361
2362         while (cur != NULL) {
2363                 GSList * partial_result;
2364                 int count;
2365                 GSList * newlist;
2366                 GSList * llast;
2367                 
2368                 llast = NULL;
2369                 count = 0;
2370                 newlist = NULL;
2371                 while (count < MAX_MSG_NUM) {
2372                         void * p;
2373                         
2374                         p = cur->data;
2375                         
2376                         if (newlist == NULL)
2377                                 llast = newlist = g_slist_append(newlist, p);
2378                         else {
2379                                 llast = g_slist_append(llast, p);
2380                                 llast = llast->next;
2381                         }
2382                         count ++;
2383                         
2384                         cur = cur->next;
2385                         if (cur == NULL)
2386                                 break;
2387                 }
2388                 
2389                 data->done = FALSE;
2390                 data->session = session;
2391                 data->item = item;
2392                 data->numlist = newlist;
2393                 data->cur += count;
2394                 
2395                 if (prefs_common.work_offline && 
2396                     !inc_offline_should_override(
2397                         _("Claws Mail needs network access in order "
2398                           "to access the IMAP server."))) {
2399                         g_free(data);
2400                         return NULL;
2401                 }
2402                 
2403                 partial_result =
2404                         (GSList *)imap_get_uncached_messages_thread(data);
2405                 
2406                 statusbar_progress_all(data->cur,data->total, 1);
2407                 
2408                 g_slist_free(newlist);
2409                 
2410                 result = g_slist_concat(result, partial_result);
2411         }
2412         g_free(data);
2413         
2414         statusbar_progress_all(0,0,0);
2415         statusbar_pop_all();
2416         
2417         return result;
2418 }
2419
2420 static void imap_delete_all_cached_messages(FolderItem *item)
2421 {
2422         gchar *dir;
2423
2424         g_return_if_fail(item != NULL);
2425         g_return_if_fail(item->folder != NULL);
2426         g_return_if_fail(FOLDER_CLASS(item->folder) == &imap_class);
2427
2428         debug_print("Deleting all cached messages...\n");
2429
2430         dir = folder_item_get_path(item);
2431         if (is_dir_exist(dir))
2432                 remove_all_numbered_files(dir);
2433         g_free(dir);
2434
2435         debug_print("done.\n");
2436 }
2437
2438 gchar imap_get_path_separator_for_item(FolderItem *item)
2439 {
2440         Folder *folder = NULL;
2441         IMAPFolder *imap_folder = NULL;
2442         IMAPSession *session = NULL;
2443         gchar result = '/';
2444         
2445         if (!item)
2446                 return '/';
2447         folder = item->folder;
2448         
2449         if (!folder)
2450                 return '/';
2451         
2452         imap_folder = IMAP_FOLDER(folder);
2453         
2454         if (!imap_folder)
2455                 return '/';
2456         
2457         debug_print("getting session...");
2458         session = imap_session_get(FOLDER(folder));
2459         result = imap_get_path_separator(session, imap_folder, item->path);
2460         unlock_session();
2461         return result;
2462 }
2463
2464 static gchar imap_refresh_path_separator(IMAPSession *session, IMAPFolder *folder, const gchar *subfolder)
2465 {
2466         clist * lep_list;
2467         int r;
2468         gchar separator = '\0';
2469         
2470         g_return_val_if_fail(session != NULL, '/');
2471         r = imap_threaded_list((Folder *)folder, "", subfolder, &lep_list);
2472         
2473         if (r != MAILIMAP_NO_ERROR) {
2474                 log_warning(_("LIST failed\n"));
2475                 return '\0';
2476         }
2477
2478         if (clist_count(lep_list) > 0) {
2479                 clistiter * iter = clist_begin(lep_list); 
2480                 struct mailimap_mailbox_list * mb;
2481                 mb = clist_content(iter);
2482
2483                 separator = mb->mb_delimiter;
2484                 debug_print("got separator: %c\n", folder->last_seen_separator);
2485         }
2486         mailimap_list_result_free(lep_list);
2487         return separator;
2488 }
2489
2490 static gchar imap_get_path_separator(IMAPSession *session, IMAPFolder *folder, const gchar *path)
2491 {
2492         gchar separator = '/';
2493
2494         if (folder->last_seen_separator == 0) {
2495                 folder->last_seen_separator = imap_refresh_path_separator(session, folder, "");
2496         }
2497
2498         if (folder->last_seen_separator == 0) {
2499                 folder->last_seen_separator = imap_refresh_path_separator(session, folder, "INBOX");
2500         }
2501
2502         if (folder->last_seen_separator != 0) {
2503                 debug_print("using separator: %c\n", folder->last_seen_separator);
2504                 return folder->last_seen_separator;
2505         }
2506
2507         return separator;
2508 }
2509
2510 static gchar *imap_get_real_path(IMAPSession *session, IMAPFolder *folder, const gchar *path)
2511 {
2512         gchar *real_path;
2513         gchar separator;
2514
2515         g_return_val_if_fail(folder != NULL, NULL);
2516         g_return_val_if_fail(path != NULL, NULL);
2517
2518         real_path = imap_utf8_to_modified_utf7(path);
2519         separator = imap_get_path_separator(session, folder, path);
2520         imap_path_separator_subst(real_path, separator);
2521
2522         return real_path;
2523 }
2524
2525 static gint imap_set_message_flags(IMAPSession *session,
2526                                    MsgNumberList *numlist,
2527                                    IMAPFlags flags,
2528                                    gboolean is_set)
2529 {
2530         gint ok = 0;
2531         GSList *seq_list;
2532         GSList * cur;
2533
2534         seq_list = imap_get_lep_set_from_numlist(numlist);
2535         
2536         for(cur = seq_list ; cur != NULL ; cur = g_slist_next(cur)) {
2537                 struct mailimap_set * imapset;
2538                 
2539                 imapset = cur->data;
2540                 
2541                 ok = imap_cmd_store(session, imapset,
2542                                     flags, is_set);
2543         }
2544         
2545         imap_lep_set_free(seq_list);
2546         
2547         return IMAP_SUCCESS;
2548 }
2549
2550 typedef struct _select_data {
2551         IMAPSession *session;
2552         gchar *real_path;
2553         gint *exists;
2554         gint *recent;
2555         gint *unseen;
2556         guint32 *uid_validity;
2557         gboolean done;
2558 } select_data;
2559
2560 static gint imap_select(IMAPSession *session, IMAPFolder *folder,
2561                         const gchar *path,
2562                         gint *exists, gint *recent, gint *unseen,
2563                         guint32 *uid_validity, gboolean block)
2564 {
2565         gchar *real_path;
2566         gint ok;
2567         gint exists_, recent_, unseen_;
2568         guint32 uid_validity_;
2569         
2570         if (!exists && !recent && !unseen && !uid_validity) {
2571                 if (session->mbox && strcmp(session->mbox, path) == 0)
2572                         return IMAP_SUCCESS;
2573         }
2574         if (!exists)
2575                 exists = &exists_;
2576         if (!recent)
2577                 recent = &recent_;
2578         if (!unseen)
2579                 unseen = &unseen_;
2580         if (!uid_validity)
2581                 uid_validity = &uid_validity_;
2582
2583         g_free(session->mbox);
2584         session->mbox = NULL;
2585
2586         real_path = imap_get_real_path(session, folder, path);
2587
2588         ok = imap_cmd_select(session, real_path,
2589                              exists, recent, unseen, uid_validity, block);
2590         if (ok != IMAP_SUCCESS)
2591                 log_warning(_("can't select folder: %s\n"), real_path);
2592         else {
2593                 session->mbox = g_strdup(path);
2594                 session->folder_content_changed = FALSE;
2595         }
2596         g_free(real_path);
2597
2598         return ok;
2599 }
2600
2601 static gint imap_status(IMAPSession *session, IMAPFolder *folder,
2602                         const gchar *path, IMAPFolderItem *item,
2603                         gint *messages,
2604                         guint32 *uid_next, guint32 *uid_validity,
2605                         gint *unseen, gboolean block)
2606 {
2607         int r;
2608         clistiter * iter;
2609         struct mailimap_mailbox_data_status * data_status;
2610         int got_values;
2611         gchar *real_path;
2612         guint mask = 0;
2613         
2614         real_path = imap_get_real_path(session, folder, path);
2615
2616         if (messages) {
2617                 mask |= 1 << 0;
2618         }
2619         if (uid_next) {
2620                 mask |= 1 << 2;
2621         }
2622         if (uid_validity) {
2623                 mask |= 1 << 3;
2624         }
2625         if (unseen) {
2626                 mask |= 1 << 4;
2627         }
2628         r = imap_threaded_status(FOLDER(folder), real_path, 
2629                 &data_status, mask);
2630
2631         g_free(real_path);
2632         if (r != MAILIMAP_NO_ERROR) {
2633                 debug_print("status err %d\n", r);
2634                 return IMAP_ERROR;
2635         }
2636         
2637         if (data_status->st_info_list == NULL) {
2638                 mailimap_mailbox_data_status_free(data_status);
2639                 debug_print("status->st_info_list == NULL\n");
2640                 return IMAP_ERROR;
2641         }
2642         
2643         got_values = 0;
2644         for(iter = clist_begin(data_status->st_info_list) ; iter != NULL ;
2645             iter = clist_next(iter)) {
2646                 struct mailimap_status_info * info;             
2647                 
2648                 info = clist_content(iter);
2649                 switch (info->st_att) {
2650                 case MAILIMAP_STATUS_ATT_MESSAGES:
2651                         * messages = info->st_value;
2652                         got_values |= 1 << 0;
2653                         break;
2654                         
2655                 case MAILIMAP_STATUS_ATT_UIDNEXT:
2656                         * uid_next = info->st_value;
2657                         got_values |= 1 << 2;
2658                         break;
2659                         
2660                 case MAILIMAP_STATUS_ATT_UIDVALIDITY:
2661                         * uid_validity = info->st_value;
2662                         got_values |= 1 << 3;
2663                         break;
2664                         
2665                 case MAILIMAP_STATUS_ATT_UNSEEN:
2666                         * unseen = info->st_value;
2667                         got_values |= 1 << 4;
2668                         break;
2669                 }
2670         }
2671         mailimap_mailbox_data_status_free(data_status);
2672         
2673         if (got_values != mask) {
2674                 debug_print("status: incomplete values received (%d)\n", got_values);
2675                 return IMAP_ERROR;
2676         }
2677         return IMAP_SUCCESS;
2678 }
2679
2680 static void imap_free_capabilities(IMAPSession *session)
2681 {
2682         slist_free_strings(session->capability);
2683         g_slist_free(session->capability);
2684         session->capability = NULL;
2685 }
2686
2687 /* low-level IMAP4rev1 commands */
2688
2689 static gint imap_cmd_login(IMAPSession *session,
2690                            const gchar *user, const gchar *pass,
2691                            const gchar *type)
2692 {
2693         int r;
2694         gint ok;
2695
2696         if (!strcmp(type, "LOGIN") && imap_has_capability(session, "LOGINDISABLED")) {
2697                 gint ok = IMAP_ERROR;
2698                 if (imap_has_capability(session, "STARTTLS")) {
2699 #if USE_OPENSSL
2700                         log_warning(_("Server requires TLS to log in.\n"));
2701                         ok = imap_cmd_starttls(session);
2702                         if (ok != IMAP_SUCCESS) {
2703                                 log_warning(_("Can't start TLS session.\n"));
2704                                 return IMAP_ERROR;
2705                         } else {
2706                                 /* refresh capas */
2707                                 imap_free_capabilities(session);
2708                                 if (imap_get_capabilities(session) != MAILIMAP_NO_ERROR) {
2709                                         log_warning(_("Can't refresh capabilities.\n"));
2710                                         return IMAP_ERROR;
2711                                 }
2712                         }
2713 #else           
2714                         log_error(_("Connection to %s failed: "
2715                                         "server requires TLS, but Claws Mail "
2716                                         "has been compiled without OpenSSL "
2717                                         "support.\n"),
2718                                         SESSION(session)->server);
2719                         return IMAP_ERROR;
2720 #endif
2721                 } else {
2722                         log_error(_("Server logins are disabled.\n"));
2723                         return IMAP_ERROR;
2724                 }
2725         }
2726
2727         log_print("IMAP4> Logging %s to %s using %s\n", 
2728                         user,
2729                         SESSION(session)->server,
2730                         type);
2731         r = imap_threaded_login(session->folder, user, pass, type);
2732         if (r != MAILIMAP_NO_ERROR) {
2733                 log_print("IMAP4< Error logging in to %s\n",
2734                                 SESSION(session)->server);
2735                 ok = IMAP_ERROR;
2736         } else {
2737                 log_print("IMAP4< Login to %s successful\n",
2738                                 SESSION(session)->server);
2739                 ok = IMAP_SUCCESS;
2740         }
2741         return ok;
2742 }
2743
2744 static gint imap_cmd_noop(IMAPSession *session)
2745 {
2746         int r;
2747         unsigned int exists;
2748         
2749         r = imap_threaded_noop(session->folder, &exists);
2750         if (r != MAILIMAP_NO_ERROR) {
2751                 debug_print("noop err %d\n", r);
2752                 return IMAP_ERROR;
2753         }
2754         session->exists = exists;
2755         session_set_access_time(SESSION(session));
2756
2757         return IMAP_SUCCESS;
2758 }
2759
2760 #if USE_OPENSSL
2761 static gint imap_cmd_starttls(IMAPSession *session)
2762 {
2763         int r;
2764         
2765         r = imap_threaded_starttls(session->folder, 
2766                 SESSION(session)->server, SESSION(session)->port);
2767         if (r != MAILIMAP_NO_ERROR) {
2768                 debug_print("starttls err %d\n", r);
2769                 return IMAP_ERROR;
2770         }
2771         return IMAP_SUCCESS;
2772 }
2773 #endif
2774
2775 static gint imap_cmd_select(IMAPSession *session, const gchar *folder,
2776                             gint *exists, gint *recent, gint *unseen,
2777                             guint32 *uid_validity, gboolean block)
2778 {
2779         int r;
2780
2781         r = imap_threaded_select(session->folder, folder,
2782                                  exists, recent, unseen, uid_validity);
2783         if (r != MAILIMAP_NO_ERROR) {
2784                 debug_print("select err %d\n", r);
2785                 return IMAP_ERROR;
2786         }
2787         return IMAP_SUCCESS;
2788 }
2789
2790 static gint imap_cmd_examine(IMAPSession *session, const gchar *folder,
2791                              gint *exists, gint *recent, gint *unseen,
2792                              guint32 *uid_validity, gboolean block)
2793 {
2794         int r;
2795
2796         r = imap_threaded_examine(session->folder, folder,
2797                                   exists, recent, unseen, uid_validity);
2798         if (r != MAILIMAP_NO_ERROR) {
2799                 debug_print("examine err %d\n", r);
2800                 
2801                 return IMAP_ERROR;
2802         }
2803         return IMAP_SUCCESS;
2804 }
2805
2806 static gint imap_cmd_create(IMAPSession *session, const gchar *folder)
2807 {
2808         int r;
2809
2810         r = imap_threaded_create(session->folder, folder);
2811         if (r != MAILIMAP_NO_ERROR) {
2812                 
2813                 return IMAP_ERROR;
2814         }
2815
2816         return IMAP_SUCCESS;
2817 }
2818
2819 static gint imap_cmd_rename(IMAPSession *session, const gchar *old_folder,
2820                             const gchar *new_folder)
2821 {
2822         int r;
2823
2824         r = imap_threaded_rename(session->folder, old_folder,
2825                                  new_folder);
2826         if (r != MAILIMAP_NO_ERROR) {
2827                 
2828                 return IMAP_ERROR;
2829         }
2830
2831         return IMAP_SUCCESS;
2832 }
2833
2834 static gint imap_cmd_delete(IMAPSession *session, const gchar *folder)
2835 {
2836         int r;
2837         
2838
2839         r = imap_threaded_delete(session->folder, folder);
2840         if (r != MAILIMAP_NO_ERROR) {
2841                 
2842                 return IMAP_ERROR;
2843         }
2844
2845         return IMAP_SUCCESS;
2846 }
2847
2848 typedef struct _fetch_data {
2849         IMAPSession *session;
2850         guint32 uid;
2851         const gchar *filename;
2852         gboolean headers;
2853         gboolean body;
2854         gboolean done;
2855 } fetch_data;
2856
2857 static void *imap_cmd_fetch_thread(void *data)
2858 {
2859         fetch_data *stuff = (fetch_data *)data;
2860         IMAPSession *session = stuff->session;
2861         guint32 uid = stuff->uid;
2862         const gchar *filename = stuff->filename;
2863         int r;
2864         
2865         if (stuff->body) {
2866                 r = imap_threaded_fetch_content(session->folder,
2867                                                uid, 1, filename);
2868         }
2869         else {
2870                 r = imap_threaded_fetch_content(session->folder,
2871                                                 uid, 0, filename);
2872         }
2873         if (r != MAILIMAP_NO_ERROR) {
2874                 debug_print("fetch err %d\n", r);
2875                 return GINT_TO_POINTER(IMAP_ERROR);
2876         }
2877         return GINT_TO_POINTER(IMAP_SUCCESS);
2878 }
2879
2880 static gint imap_cmd_fetch(IMAPSession *session, guint32 uid,
2881                                 const gchar *filename, gboolean headers,
2882                                 gboolean body)
2883 {
2884         fetch_data *data = g_new0(fetch_data, 1);
2885         int result = 0;
2886         data->done = FALSE;
2887         data->session = session;
2888         data->uid = uid;
2889         data->filename = filename;
2890         data->headers = headers;
2891         data->body = body;
2892
2893         if (prefs_common.work_offline && 
2894             !inc_offline_should_override(
2895                 _("Claws Mail needs network access in order "
2896                   "to access the IMAP server."))) {
2897                 g_free(data);
2898                 return -1;
2899         }
2900         statusbar_print_all(_("Fetching message..."));
2901         result = GPOINTER_TO_INT(imap_cmd_fetch_thread(data));
2902         statusbar_pop_all();
2903         g_free(data);
2904         return result;
2905 }
2906
2907
2908 static gint imap_cmd_append(IMAPSession *session, const gchar *destfolder,
2909                             const gchar *file, IMAPFlags flags, 
2910                             guint32 *new_uid)
2911 {
2912         struct mailimap_flag_list * flag_list;
2913         int r;
2914         
2915         g_return_val_if_fail(file != NULL, IMAP_ERROR);
2916
2917         flag_list = imap_flag_to_lep(flags);
2918         r = imap_threaded_append(session->folder, destfolder,
2919                          file, flag_list, (int *)new_uid);
2920         mailimap_flag_list_free(flag_list);
2921
2922         if (r != MAILIMAP_NO_ERROR) {
2923                 debug_print("append err %d\n", r);
2924                 return IMAP_ERROR;
2925         }
2926         return IMAP_SUCCESS;
2927 }
2928
2929 static gint imap_cmd_copy(IMAPSession *session, struct mailimap_set * set,
2930                           const gchar *destfolder, GRelation *uid_mapping,
2931                           struct mailimap_set **source, struct mailimap_set **dest)
2932 {
2933         int r;
2934         
2935         g_return_val_if_fail(session != NULL, IMAP_ERROR);
2936         g_return_val_if_fail(set != NULL, IMAP_ERROR);
2937         g_return_val_if_fail(destfolder != NULL, IMAP_ERROR);
2938
2939         r = imap_threaded_copy(session->folder, set, destfolder, source, dest);
2940         if (r != MAILIMAP_NO_ERROR) {
2941                 
2942                 return IMAP_ERROR;
2943         }
2944
2945         return IMAP_SUCCESS;
2946 }
2947
2948 static gint imap_cmd_store(IMAPSession *session, struct mailimap_set * set,
2949                            IMAPFlags flags, int do_add)
2950 {
2951         int r;
2952         struct mailimap_flag_list * flag_list;
2953         struct mailimap_store_att_flags * store_att_flags;
2954         
2955         flag_list = imap_flag_to_lep(flags);
2956         
2957         if (do_add)
2958                 store_att_flags =
2959                         mailimap_store_att_flags_new_add_flags_silent(flag_list);
2960         else
2961                 store_att_flags =
2962                         mailimap_store_att_flags_new_remove_flags_silent(flag_list);
2963         
2964         r = imap_threaded_store(session->folder, set, store_att_flags);
2965         mailimap_store_att_flags_free(store_att_flags);
2966         if (r != MAILIMAP_NO_ERROR) {
2967                 
2968                 return IMAP_ERROR;
2969         }
2970         
2971         return IMAP_SUCCESS;
2972 }
2973
2974 static gint imap_cmd_expunge(IMAPSession *session)
2975 {
2976         int r;
2977         
2978         if (prefs_common.work_offline && 
2979             !inc_offline_should_override(
2980                 _("Claws Mail needs network access in order "
2981                   "to access the IMAP server."))) {
2982                 return -1;
2983         }
2984
2985         r = imap_threaded_expunge(session->folder);
2986         if (r != MAILIMAP_NO_ERROR) {
2987                 
2988                 return IMAP_ERROR;
2989         }
2990
2991         return IMAP_SUCCESS;
2992 }
2993
2994 static void imap_path_separator_subst(gchar *str, gchar separator)
2995 {
2996         gchar *p;
2997         gboolean in_escape = FALSE;
2998
2999         if (!separator || separator == '/') return;
3000
3001         for (p = str; *p != '\0'; p++) {
3002                 if (*p == '/' && !in_escape)
3003                         *p = separator;
3004                 else if (*p == '&' && *(p + 1) != '-' && !in_escape)
3005                         in_escape = TRUE;
3006                 else if (*p == '-' && in_escape)
3007                         in_escape = FALSE;
3008         }
3009 }
3010
3011 static gchar *imap_modified_utf7_to_utf8(const gchar *mutf7_str)
3012 {
3013         static iconv_t cd = (iconv_t)-1;
3014         static gboolean iconv_ok = TRUE;
3015         GString *norm_utf7;
3016         gchar *norm_utf7_p;
3017         size_t norm_utf7_len;
3018         const gchar *p;
3019         gchar *to_str, *to_p;
3020         size_t to_len;
3021         gboolean in_escape = FALSE;
3022
3023         if (!iconv_ok) return g_strdup(mutf7_str);
3024
3025         if (cd == (iconv_t)-1) {
3026                 cd = iconv_open(CS_INTERNAL, CS_UTF_7);
3027                 if (cd == (iconv_t)-1) {
3028                         g_warning("iconv cannot convert UTF-7 to %s\n",
3029                                   CS_INTERNAL);
3030                         iconv_ok = FALSE;
3031                         return g_strdup(mutf7_str);
3032                 }
3033         }
3034
3035         /* modified UTF-7 to normal UTF-7 conversion */
3036         norm_utf7 = g_string_new(NULL);
3037
3038         for (p = mutf7_str; *p != '\0'; p++) {
3039                 /* replace: '&'  -> '+',
3040                             "&-" -> '&',
3041                             escaped ','  -> '/' */
3042                 if (!in_escape && *p == '&') {
3043                         if (*(p + 1) != '-') {
3044                                 g_string_append_c(norm_utf7, '+');
3045                                 in_escape = TRUE;
3046                         } else {
3047                                 g_string_append_c(norm_utf7, '&');
3048                                 p++;
3049                         }
3050                 } else if (in_escape && *p == ',') {
3051                         g_string_append_c(norm_utf7, '/');
3052                 } else if (in_escape && *p == '-') {
3053                         g_string_append_c(norm_utf7, '-');
3054                         in_escape = FALSE;
3055                 } else {
3056                         g_string_append_c(norm_utf7, *p);
3057                 }
3058         }
3059
3060         norm_utf7_p = norm_utf7->str;
3061         norm_utf7_len = norm_utf7->len;
3062         to_len = strlen(mutf7_str) * 5;
3063         to_p = to_str = g_malloc(to_len + 1);
3064
3065         if (iconv(cd, (ICONV_CONST gchar **)&norm_utf7_p, &norm_utf7_len,
3066                   &to_p, &to_len) == -1) {
3067                 g_warning(_("iconv cannot convert UTF-7 to %s\n"),
3068                           conv_get_locale_charset_str());
3069                 g_string_free(norm_utf7, TRUE);
3070                 g_free(to_str);
3071                 return g_strdup(mutf7_str);
3072         }
3073
3074         /* second iconv() call for flushing */
3075         iconv(cd, NULL, NULL, &to_p, &to_len);
3076         g_string_free(norm_utf7, TRUE);
3077         *to_p = '\0';
3078
3079         return to_str;
3080 }
3081
3082 static gchar *imap_utf8_to_modified_utf7(const gchar *from)
3083 {
3084         static iconv_t cd = (iconv_t)-1;
3085         static gboolean iconv_ok = TRUE;
3086         gchar *norm_utf7, *norm_utf7_p;
3087         size_t from_len, norm_utf7_len;
3088         GString *to_str;
3089         gchar *from_tmp, *to, *p;
3090         gboolean in_escape = FALSE;
3091
3092         if (!iconv_ok) return g_strdup(from);
3093
3094         if (cd == (iconv_t)-1) {
3095                 cd = iconv_open(CS_UTF_7, CS_INTERNAL);
3096                 if (cd == (iconv_t)-1) {
3097                         g_warning(_("iconv cannot convert %s to UTF-7\n"),
3098                                   CS_INTERNAL);
3099                         iconv_ok = FALSE;
3100                         return g_strdup(from);
3101                 }
3102         }
3103
3104         /* UTF-8 to normal UTF-7 conversion */
3105         Xstrdup_a(from_tmp, from, return g_strdup(from));
3106         from_len = strlen(from);
3107         norm_utf7_len = from_len * 5;
3108         Xalloca(norm_utf7, norm_utf7_len + 1, return g_strdup(from));
3109         norm_utf7_p = norm_utf7;
3110
3111 #define IS_PRINT(ch) (isprint(ch) && IS_ASCII(ch))
3112
3113         while (from_len > 0) {
3114                 if (*from_tmp == '+') {
3115                         *norm_utf7_p++ = '+';
3116                         *norm_utf7_p++ = '-';
3117                         norm_utf7_len -= 2;
3118                         from_tmp++;
3119                         from_len--;
3120                 } else if (IS_PRINT(*(guchar *)from_tmp)) {
3121                         /* printable ascii char */
3122                         *norm_utf7_p = *from_tmp;
3123                         norm_utf7_p++;
3124                         norm_utf7_len--;
3125                         from_tmp++;
3126                         from_len--;
3127                 } else {
3128                         size_t conv_len = 0;
3129
3130                         /* unprintable char: convert to UTF-7 */
3131                         p = from_tmp;
3132                         while (!IS_PRINT(*(guchar *)p) && conv_len < from_len) {
3133                                 conv_len += g_utf8_skip[*(guchar *)p];
3134                                 p += g_utf8_skip[*(guchar *)p];
3135                         }
3136
3137                         from_len -= conv_len;
3138                         if (iconv(cd, (ICONV_CONST gchar **)&from_tmp,
3139                                   &conv_len,
3140                                   &norm_utf7_p, &norm_utf7_len) == -1) {
3141                                 g_warning(_("iconv cannot convert UTF-8 to UTF-7\n"));
3142                                 return g_strdup(from);
3143                         }
3144
3145                         /* second iconv() call for flushing */
3146                         iconv(cd, NULL, NULL, &norm_utf7_p, &norm_utf7_len);
3147                 }
3148         }
3149
3150 #undef IS_PRINT
3151
3152         *norm_utf7_p = '\0';
3153         to_str = g_string_new(NULL);
3154         for (p = norm_utf7; p < norm_utf7_p; p++) {
3155                 /* replace: '&' -> "&-",
3156                             '+' -> '&',
3157                             "+-" -> '+',
3158                             BASE64 '/' -> ',' */
3159                 if (!in_escape && *p == '&') {
3160                         g_string_append(to_str, "&-");
3161                 } else if (!in_escape && *p == '+') {
3162                         if (*(p + 1) == '-') {
3163                                 g_string_append_c(to_str, '+');
3164                                 p++;
3165                         } else {
3166                                 g_string_append_c(to_str, '&');
3167                                 in_escape = TRUE;
3168                         }
3169                 } else if (in_escape && *p == '/') {
3170                         g_string_append_c(to_str, ',');
3171                 } else if (in_escape && *p == '-') {
3172                         g_string_append_c(to_str, '-');
3173                         in_escape = FALSE;
3174                 } else {
3175                         g_string_append_c(to_str, *p);
3176                 }
3177         }
3178
3179         if (in_escape) {
3180                 in_escape = FALSE;
3181                 g_string_append_c(to_str, '-');
3182         }
3183
3184         to = to_str->str;
3185         g_string_free(to_str, FALSE);
3186
3187         return to;
3188 }
3189
3190 static gboolean imap_rename_folder_func(GNode *node, gpointer data)
3191 {
3192         FolderItem *item = node->data;
3193         gchar **paths = data;
3194         const gchar *oldpath = paths[0];
3195         const gchar *newpath = paths[1];
3196         gchar *base;
3197         gchar *new_itempath;
3198         gint oldpathlen;
3199
3200         oldpathlen = strlen(oldpath);
3201         if (strncmp(oldpath, item->path, oldpathlen) != 0) {
3202                 g_warning("path doesn't match: %s, %s\n", oldpath, item->path);
3203                 return TRUE;
3204         }
3205
3206         base = item->path + oldpathlen;
3207         while (*base == G_DIR_SEPARATOR) base++;
3208         if (*base == '\0')
3209                 new_itempath = g_strdup(newpath);
3210         else
3211                 new_itempath = g_strconcat(newpath, G_DIR_SEPARATOR_S, base,
3212                                            NULL);
3213         g_free(item->path);
3214         item->path = new_itempath;
3215
3216         return FALSE;
3217 }
3218
3219 typedef struct _get_list_uid_data {
3220         Folder *folder;
3221         IMAPSession *session;
3222         IMAPFolderItem *item;
3223         GSList **msgnum_list;
3224         gboolean done;
3225 } get_list_uid_data;
3226
3227 static void *get_list_of_uids_thread(void *data)
3228 {
3229         get_list_uid_data *stuff = (get_list_uid_data *)data;
3230         Folder *folder = stuff->folder;
3231         IMAPFolderItem *item = stuff->item;
3232         GSList **msgnum_list = stuff->msgnum_list;
3233         gint ok, nummsgs = 0, lastuid_old;
3234         IMAPSession *session;
3235         GSList *uidlist, *elem;
3236         clist * lep_uidlist;
3237         int r;
3238
3239         session = stuff->session;
3240         if (session == NULL) {
3241                 stuff->done = TRUE;
3242                 return GINT_TO_POINTER(-1);
3243         }
3244         /* no session locking here, it's already locked by caller */
3245         ok = imap_select(session, IMAP_FOLDER(folder), item->item.path,
3246                          NULL, NULL, NULL, NULL, TRUE);
3247         if (ok != IMAP_SUCCESS) {
3248                 stuff->done = TRUE;
3249                 return GINT_TO_POINTER(-1);
3250         }
3251
3252         uidlist = NULL;
3253         
3254         r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SIMPLE, NULL,
3255                                  &lep_uidlist);
3256         
3257         if (r == MAILIMAP_NO_ERROR) {
3258                 GSList * fetchuid_list;
3259                 
3260                 fetchuid_list =
3261                         imap_uid_list_from_lep(lep_uidlist);
3262                 mailimap_search_result_free(lep_uidlist);
3263                 
3264                 uidlist = g_slist_concat(fetchuid_list, uidlist);
3265         }
3266         else {
3267                 GSList * fetchuid_list;
3268                 carray * lep_uidtab;
3269                 
3270                 r = imap_threaded_fetch_uid(folder, item->lastuid + 1,
3271                                             &lep_uidtab);
3272                 if (r == MAILIMAP_NO_ERROR) {
3273                         fetchuid_list =
3274                                 imap_uid_list_from_lep_tab(lep_uidtab);
3275                         imap_fetch_uid_list_free(lep_uidtab);
3276                         uidlist = g_slist_concat(fetchuid_list, uidlist);
3277                 }
3278         }
3279         
3280         lastuid_old = item->lastuid;
3281         *msgnum_list = g_slist_copy(item->uid_list);
3282         nummsgs = g_slist_length(*msgnum_list);
3283         debug_print("Got %d uids from cache\n", g_slist_length(item->uid_list));
3284
3285         for (elem = uidlist; elem != NULL; elem = g_slist_next(elem)) {
3286                 guint msgnum;
3287
3288                 msgnum = GPOINTER_TO_INT(elem->data);
3289                 if (msgnum > lastuid_old) {
3290                         *msgnum_list = g_slist_prepend(*msgnum_list, GINT_TO_POINTER(msgnum));
3291                         item->uid_list = g_slist_prepend(item->uid_list, GINT_TO_POINTER(msgnum));
3292                         nummsgs++;
3293
3294                         if(msgnum > item->lastuid)
3295                                 item->lastuid = msgnum;
3296                 }
3297         }
3298         g_slist_free(uidlist);
3299         stuff->done = TRUE;
3300         return GINT_TO_POINTER(nummsgs);
3301 }
3302
3303 static gint get_list_of_uids(IMAPSession *session, Folder *folder, IMAPFolderItem *item, GSList **msgnum_list)
3304 {
3305         gint result;
3306         get_list_uid_data *data = g_new0(get_list_uid_data, 1);
3307         data->done = FALSE;
3308         data->folder = folder;
3309         data->item = item;
3310         data->msgnum_list = msgnum_list;
3311         data->session = session;
3312         if (prefs_common.work_offline && 
3313             !inc_offline_should_override(
3314                 _("Claws Mail needs network access in order "
3315                   "to access the IMAP server."))) {
3316                 g_free(data);
3317                 return -1;
3318         }
3319
3320         result = GPOINTER_TO_INT(get_list_of_uids_thread(data));
3321         g_free(data);
3322         return result;
3323
3324 }
3325
3326 gint imap_get_num_list(Folder *folder, FolderItem *_item, GSList **msgnum_list, gboolean *old_uids_valid)
3327 {
3328         IMAPFolderItem *item = (IMAPFolderItem *)_item;
3329         IMAPSession *session;
3330         gint ok, nummsgs = 0, exists;
3331         guint32 uid_next = 0, uid_val = 0;
3332         GSList *uidlist = NULL;
3333         gchar *dir;
3334         gboolean selected_folder;
3335         debug_print("get_num_list\n");
3336         
3337         g_return_val_if_fail(folder != NULL, -1);
3338         g_return_val_if_fail(item != NULL, -1);
3339         g_return_val_if_fail(item->item.path != NULL, -1);
3340         g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, -1);
3341         g_return_val_if_fail(folder->account != NULL, -1);
3342
3343         debug_print("getting session...\n");
3344         session = imap_session_get(folder);
3345         g_return_val_if_fail(session != NULL, -1);
3346
3347         if (FOLDER_ITEM(item)->path) 
3348                 statusbar_print_all(_("Scanning folder %s%c%s ..."),
3349                                       FOLDER_ITEM(item)->folder->name, 
3350                                       G_DIR_SEPARATOR,
3351                                       FOLDER_ITEM(item)->path);
3352         else
3353                 statusbar_print_all(_("Scanning folder %s ..."),
3354                                       FOLDER_ITEM(item)->folder->name);
3355
3356         selected_folder = (session->mbox != NULL) &&
3357                           (!strcmp(session->mbox, item->item.path));
3358         if (selected_folder && time(NULL) - item->use_cache < 2) {
3359                 ok = imap_cmd_noop(session);
3360                 if (ok != IMAP_SUCCESS) {
3361                         debug_print("disconnected!\n");
3362                         session = imap_reconnect_if_possible(folder, session);
3363                         if (session == NULL) {
3364                                 statusbar_pop_all();
3365                                 unlock_session();
3366                                 return -1;
3367                         }
3368                 }
3369                 exists = session->exists;
3370
3371                 uid_next = item->c_uid_next;
3372                 uid_val = item->c_uid_validity;
3373                 *old_uids_valid = TRUE;
3374         } else {
3375                 if (item->use_cache && time(NULL) - item->use_cache < 2) {
3376                         exists = item->c_messages;
3377                         uid_next = item->c_uid_next;
3378                         uid_val = item->c_uid_validity;
3379                         ok = IMAP_SUCCESS;
3380                         debug_print("using cache %d %d %d\n", exists, uid_next, uid_val);
3381                 } else {
3382                         ok = imap_status(session, IMAP_FOLDER(folder), item->item.path, item,
3383                                  &exists, &uid_next, &uid_val, NULL, FALSE);
3384                 }
3385                 item->item.last_num = uid_next - 1;
3386                 
3387                 item->use_cache = (time_t)0;
3388                 if (ok != IMAP_SUCCESS) {
3389                         statusbar_pop_all();
3390                         unlock_session();
3391                         return -1;
3392                 }
3393                 if(item->item.mtime == uid_val)
3394                         *old_uids_valid = TRUE;
3395                 else {
3396                         *old_uids_valid = FALSE;
3397
3398                         debug_print("Freeing imap uid cache (%d != %d)\n",
3399                                         (int)item->item.mtime, uid_val);
3400                         item->lastuid = 0;
3401                         g_slist_free(item->uid_list);
3402                         item->uid_list = NULL;
3403                 
3404                         item->item.mtime = uid_val;
3405
3406                         imap_delete_all_cached_messages((FolderItem *)item);
3407                 }
3408  &n