2007-01-17 [colin] 2.7.1cvs16
[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
35 #ifdef HAVE_LIBETPAN
36
37 #include <stdlib.h>
38 #include <dirent.h>
39 #include <unistd.h>
40 #include <ctype.h>
41 #include <time.h>
42 #include <errno.h>
43 #if HAVE_ICONV
44 #  include <iconv.h>
45 #endif
46
47 #if USE_OPENSSL
48 #  include "ssl.h"
49 #endif
50
51 #include "folder.h"
52 #include "session.h"
53 #include "procmsg.h"
54 #include "socket.h"
55 #include "recv.h"
56 #include "procheader.h"
57 #include "prefs_account.h"
58 #include "codeconv.h"
59 #include "md5.h"
60 #include "base64.h"
61 #include "utils.h"
62 #include "prefs_common.h"
63 #include "inputdialog.h"
64 #include "log.h"
65 #include "remotefolder.h"
66 #include "alertpanel.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 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 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                         return -1;
1291                 }
1292         }
1293
1294         for (cur = msglist; cur != NULL; cur = g_slist_next(cur)) {
1295                 MsgInfo *msginfo = (MsgInfo *)cur->data;
1296                 GTuples *tuples;
1297
1298                 tuples = g_relation_select(uid_mapping, 
1299                                            GINT_TO_POINTER(msginfo->msgnum),
1300                                            0);
1301                 if (tuples->len > 0) {
1302                         gint num = GPOINTER_TO_INT(g_tuples_index(tuples, 0, 1));
1303                         g_relation_insert(relation, msginfo,
1304                                           GINT_TO_POINTER(num));
1305                         if (num > last_num)
1306                                 last_num = num;
1307                         debug_print("copied new message as %d\n", num);
1308                         /* put the local file in the imapcache, so that we don't
1309                          * have to fetch it back later. */
1310                         if (num > 0) {
1311                                 gchar *cache_path = folder_item_get_path(msginfo->folder);
1312                                 gchar *real_file = g_strconcat(
1313                                         cache_path, G_DIR_SEPARATOR_S, 
1314                                         itos(msginfo->msgnum), NULL);
1315                                 gchar *cache_file = NULL;
1316                                 g_free(cache_path);
1317                                 cache_path = folder_item_get_path(dest);
1318                                 cache_file = g_strconcat(
1319                                         cache_path, G_DIR_SEPARATOR_S, 
1320                                         itos(num), NULL);
1321                                 if (!is_dir_exist(cache_path))
1322                                         make_dir_hier(cache_path);
1323                                 if (is_file_exist(real_file) && is_dir_exist(cache_path)) {
1324                                         copy_file(real_file, cache_file, TRUE);
1325                                         debug_print("copied to cache: %s\n", cache_file);
1326                                 }
1327                                 g_free(real_file);
1328                                 g_free(cache_file);
1329                                 g_free(cache_path);
1330                         }
1331                 } else
1332                         g_relation_insert(relation, msginfo,
1333                                           GINT_TO_POINTER(0));
1334                 g_tuples_destroy(tuples);
1335         }
1336         statusbar_pop_all();
1337
1338         g_relation_destroy(uid_mapping);
1339         imap_lep_set_free(seq_list);
1340
1341         g_free(destdir);
1342         
1343         IMAP_FOLDER_ITEM(dest)->lastuid = 0;
1344         IMAP_FOLDER_ITEM(dest)->uid_next = 0;
1345         g_slist_free(IMAP_FOLDER_ITEM(dest)->uid_list);
1346         IMAP_FOLDER_ITEM(dest)->uid_list = NULL;
1347
1348         unlock_session();
1349         if (ok == IMAP_SUCCESS)
1350                 return last_num;
1351         else
1352                 return -1;
1353 }
1354
1355 static gint imap_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
1356 {
1357         GSList msglist;
1358
1359         g_return_val_if_fail(msginfo != NULL, -1);
1360
1361         msglist.data = msginfo;
1362         msglist.next = NULL;
1363
1364         return imap_copy_msgs(folder, dest, &msglist, NULL);
1365 }
1366
1367 static gint imap_copy_msgs(Folder *folder, FolderItem *dest, 
1368                     MsgInfoList *msglist, GRelation *relation)
1369 {
1370         MsgInfo *msginfo;
1371         gint ret;
1372
1373         g_return_val_if_fail(folder != NULL, -1);
1374         g_return_val_if_fail(dest != NULL, -1);
1375         g_return_val_if_fail(msglist != NULL, -1);
1376
1377         msginfo = (MsgInfo *)msglist->data;
1378         g_return_val_if_fail(msginfo->folder != NULL, -1);
1379
1380         ret = imap_do_copy_msgs(folder, dest, msglist, relation);
1381         return ret;
1382 }
1383
1384
1385 static gint imap_do_remove_msgs(Folder *folder, FolderItem *dest, 
1386                                 MsgInfoList *msglist, GRelation *relation)
1387 {
1388         gchar *destdir, *dir;
1389         GSList *numlist = NULL, *cur;
1390         MsgInfo *msginfo;
1391         IMAPSession *session;
1392         gint ok = IMAP_SUCCESS;
1393         GRelation *uid_mapping;
1394         
1395         g_return_val_if_fail(folder != NULL, -1);
1396         g_return_val_if_fail(dest != NULL, -1);
1397         g_return_val_if_fail(msglist != NULL, -1);
1398
1399         debug_print("getting session...\n");
1400         session = imap_session_get(folder);
1401         if (!session) {
1402                 return -1;
1403         }
1404
1405         msginfo = (MsgInfo *)msglist->data;
1406
1407         ok = imap_select(session, IMAP_FOLDER(folder), msginfo->folder->path,
1408                          NULL, NULL, NULL, NULL, FALSE);
1409         if (ok != IMAP_SUCCESS) {
1410                 unlock_session();
1411                 return ok;
1412         }
1413
1414         destdir = imap_get_real_path(session, IMAP_FOLDER(folder), dest->path);
1415         for (cur = msglist; cur; cur = cur->next) {
1416                 msginfo = (MsgInfo *)cur->data;
1417                 if (!MSG_IS_DELETED(msginfo->flags))
1418                         numlist = g_slist_prepend(numlist, GINT_TO_POINTER(msginfo->msgnum));
1419         }
1420         numlist = g_slist_reverse(numlist);
1421
1422         uid_mapping = g_relation_new(2);
1423         g_relation_index(uid_mapping, 0, g_direct_hash, g_direct_equal);
1424
1425         ok = imap_set_message_flags
1426                 (IMAP_SESSION(REMOTE_FOLDER(folder)->session),
1427                 numlist, IMAP_FLAG_DELETED, TRUE);
1428         if (ok != IMAP_SUCCESS) {
1429                 log_warning(_("can't set deleted flags\n"));
1430                 unlock_session();
1431                 return ok;
1432         }
1433         ok = imap_cmd_expunge(session);
1434         if (ok != IMAP_SUCCESS) {
1435                 log_warning(_("can't expunge\n"));
1436                 unlock_session();
1437                 return ok;
1438         }
1439         
1440         dir = folder_item_get_path(msginfo->folder);
1441         if (is_dir_exist(dir)) {
1442                 for (cur = msglist; cur; cur = cur->next) {
1443                         msginfo = (MsgInfo *)cur->data;
1444                         remove_numbered_files(dir, msginfo->msgnum, msginfo->msgnum);
1445                 }
1446         }
1447         g_free(dir);
1448
1449         g_relation_destroy(uid_mapping);
1450         g_slist_free(numlist);
1451
1452         g_free(destdir);
1453         unlock_session();
1454         if (ok == IMAP_SUCCESS)
1455                 return 0;
1456         else
1457                 return -1;
1458 }
1459
1460 static gint imap_remove_msgs(Folder *folder, FolderItem *dest, 
1461                     MsgInfoList *msglist, GRelation *relation)
1462 {
1463         MsgInfo *msginfo;
1464
1465         g_return_val_if_fail(folder != NULL, -1);
1466         g_return_val_if_fail(dest != NULL, -1);
1467         if (msglist == NULL)
1468                 return 0;
1469
1470         msginfo = (MsgInfo *)msglist->data;
1471         g_return_val_if_fail(msginfo->folder != NULL, -1);
1472
1473         return imap_do_remove_msgs(folder, dest, msglist, relation);
1474 }
1475
1476 static gint imap_remove_all_msg(Folder *folder, FolderItem *item)
1477 {
1478         GSList *list = folder_item_get_msg_list(item);
1479         gint res = imap_remove_msgs(folder, item, list, NULL);
1480         procmsg_msg_list_free(list);
1481         return res;
1482 }
1483
1484 static gboolean imap_is_msg_changed(Folder *folder, FolderItem *item,
1485                                     MsgInfo *msginfo)
1486 {
1487         /* TODO: properly implement this method */
1488         return FALSE;
1489 }
1490
1491 static gint imap_close(Folder *folder, FolderItem *item)
1492 {
1493         return 0;
1494 }
1495
1496 gint imap_scan_tree_real(Folder *folder, gboolean subs_only)
1497 {
1498         FolderItem *item = NULL;
1499         IMAPSession *session;
1500         gchar *root_folder = NULL;
1501
1502         g_return_val_if_fail(folder != NULL, -1);
1503         g_return_val_if_fail(folder->account != NULL, -1);
1504
1505         debug_print("getting session...\n");
1506         session = imap_session_get(folder);
1507         if (!session) {
1508                 if (!folder->node) {
1509                         folder_tree_destroy(folder);
1510                         item = folder_item_new(folder, folder->name, NULL);
1511                         item->folder = folder;
1512                         folder->node = item->node = g_node_new(item);
1513                 }
1514                 return -1;
1515         }
1516
1517         if (folder->account->imap_dir && *folder->account->imap_dir) {
1518                 gchar *real_path;
1519                 int r;
1520                 clist * lep_list;
1521
1522                 Xstrdup_a(root_folder, folder->account->imap_dir, {unlock_session();return -1;});
1523                 extract_quote(root_folder, '"');
1524                 subst_char(root_folder,
1525                            imap_get_path_separator(session, IMAP_FOLDER(folder),
1526                                                    root_folder),
1527                            '/');
1528                 strtailchomp(root_folder, '/');
1529                 real_path = imap_get_real_path
1530                         (session, IMAP_FOLDER(folder), root_folder);
1531                 debug_print("IMAP root directory: %s\n", real_path);
1532
1533                 /* check if root directory exist */
1534
1535                 r = imap_threaded_list(session->folder, "", real_path,
1536                                        &lep_list);
1537                 if ((r != MAILIMAP_NO_ERROR) || (clist_count(lep_list) == 0)) {
1538                         if (!folder->node) {
1539                                 item = folder_item_new(folder, folder->name, NULL);
1540                                 item->folder = folder;
1541                                 folder->node = item->node = g_node_new(item);
1542                         }
1543                         unlock_session();
1544                         return -1;
1545                 }
1546                 mailimap_list_result_free(lep_list);
1547                                 
1548                 g_free(real_path);
1549         }
1550
1551         if (folder->node)
1552                 item = FOLDER_ITEM(folder->node->data);
1553                 
1554         if (item && !item->path && root_folder) {
1555                 item->path = g_strdup(root_folder);
1556         }
1557
1558         if (!item || ((item->path || root_folder) &&
1559                       strcmp2(item->path, root_folder) != 0)) {
1560                 folder_tree_destroy(folder);
1561                 item = folder_item_new(folder, folder->name, root_folder);
1562                 item->folder = folder;
1563                 folder->node = item->node = g_node_new(item);
1564         }
1565
1566         imap_scan_tree_recursive(session, FOLDER_ITEM(folder->node->data), subs_only);
1567         imap_create_missing_folders(folder);
1568         unlock_session();
1569
1570         return 0;
1571 }
1572
1573 static gint imap_scan_tree(Folder *folder)
1574 {
1575         gboolean subs_only = FALSE;
1576         if (folder->account) {
1577                 debug_print(" scanning only subs %d\n", folder->account->imap_subsonly);
1578                 subs_only = folder->account->imap_subsonly;
1579         }
1580         return imap_scan_tree_real(folder, subs_only);
1581 }
1582
1583 static gint imap_scan_tree_recursive(IMAPSession *session, FolderItem *item, gboolean subs_only)
1584 {
1585         Folder *folder;
1586         IMAPFolder *imapfolder;
1587         FolderItem *new_item;
1588         GSList *item_list, *cur;
1589         GNode *node;
1590         gchar *real_path;
1591         gchar *wildcard_path;
1592         gchar separator;
1593         gchar wildcard[3];
1594         clist * lep_list;
1595         int r;
1596         
1597         g_return_val_if_fail(item != NULL, -1);
1598         g_return_val_if_fail(item->folder != NULL, -1);
1599         g_return_val_if_fail(item->no_sub == FALSE, -1);
1600
1601         folder = item->folder;
1602         imapfolder = IMAP_FOLDER(folder);
1603
1604         separator = imap_get_path_separator(session, imapfolder, item->path);
1605
1606         if (folder->ui_func)
1607                 folder->ui_func(folder, item, folder->ui_func_data);
1608
1609         if (item->path) {
1610                 wildcard[0] = separator;
1611                 wildcard[1] = '%';
1612                 wildcard[2] = '\0';
1613                 real_path = imap_get_real_path(session, imapfolder, item->path);
1614         } else {
1615                 wildcard[0] = '%';
1616                 wildcard[1] = '\0';
1617                 real_path = g_strdup("");
1618         }
1619
1620         Xstrcat_a(wildcard_path, real_path, wildcard,
1621                   {g_free(real_path); return IMAP_ERROR;});
1622         lep_list = NULL;
1623         
1624         if (subs_only)
1625                 r = imap_threaded_lsub(folder, "", wildcard_path, &lep_list);
1626         else
1627                 r = imap_threaded_list(folder, "", wildcard_path, &lep_list);
1628
1629         if (r != MAILIMAP_NO_ERROR) {
1630                 item_list = NULL;
1631         }
1632         else {
1633                 item_list = imap_list_from_lep(imapfolder,
1634                                                lep_list, real_path, FALSE);
1635                 mailimap_list_result_free(lep_list);
1636         }
1637         
1638         g_free(real_path);
1639
1640         node = item->node->children;
1641         while (node != NULL) {
1642                 FolderItem *old_item = FOLDER_ITEM(node->data);
1643                 GNode *next = node->next;
1644
1645                 new_item = NULL;
1646                 for (cur = item_list; cur != NULL; cur = cur->next) {
1647                         FolderItem *cur_item = FOLDER_ITEM(cur->data);
1648                         if (!strcmp2(old_item->path, cur_item->path)) {
1649                                 new_item = cur_item;
1650                                 break;
1651                         }
1652                 }
1653                 if (!new_item) {
1654                         if (old_item && old_item->path && !strcmp(old_item->path, "INBOX")) {
1655                                 debug_print("not removing INBOX\n");
1656                         } else {
1657                                 debug_print("folder '%s' not found. removing...\n",
1658                                             old_item->path);
1659                                 folder_item_remove(old_item);
1660                         }
1661                 } else {
1662                         old_item->no_sub = new_item->no_sub;
1663                         old_item->no_select = new_item->no_select;
1664                         if (old_item->no_sub == TRUE && node->children) {
1665                                 debug_print("folder '%s' doesn't have "
1666                                             "subfolders. removing...\n",
1667                                             old_item->path);
1668                                 folder_item_remove_children(old_item);
1669                         }
1670                 }
1671
1672                 node = next;
1673         }
1674
1675         for (cur = item_list; cur != NULL; cur = cur->next) {
1676                 FolderItem *cur_item = FOLDER_ITEM(cur->data);
1677                 new_item = NULL;
1678
1679                 for (node = item->node->children; node != NULL;
1680                      node = node->next) {
1681                         if (!strcmp2(FOLDER_ITEM(node->data)->path,
1682                                      cur_item->path)) {
1683                                 new_item = FOLDER_ITEM(node->data);
1684                                 folder_item_destroy(cur_item);
1685                                 cur_item = NULL;
1686                                 break;
1687                         }
1688                 }
1689                 if (!new_item) {
1690                         new_item = cur_item;
1691                         debug_print("new folder '%s' found.\n", new_item->path);
1692                         folder_item_append(item, new_item);
1693                 }
1694
1695                 if (!strcmp(new_item->path, "INBOX")) {
1696                         new_item->stype = F_INBOX;
1697                         folder->inbox = new_item;
1698                 } else if (!folder_item_parent(item) || item->stype == F_INBOX) {
1699                         gchar *base;
1700
1701                         base = g_path_get_basename(new_item->path);
1702
1703                         if (!folder->outbox && !g_ascii_strcasecmp(base, "Sent")) {
1704                                 new_item->stype = F_OUTBOX;
1705                                 folder->outbox = new_item;
1706                         } else if (!folder->draft && !g_ascii_strcasecmp(base, "Drafts")) {
1707                                 new_item->stype = F_DRAFT;
1708                                 folder->draft = new_item;
1709                         } else if (!folder->queue && !g_ascii_strcasecmp(base, "Queue")) {
1710                                 new_item->stype = F_QUEUE;
1711                                 folder->queue = new_item;
1712                         } else if (!folder->trash && !g_ascii_strcasecmp(base, "Trash")) {
1713                                 new_item->stype = F_TRASH;
1714                                 folder->trash = new_item;
1715                         }
1716                         g_free(base);
1717                 }
1718
1719                 if (new_item->no_sub == FALSE)
1720                         imap_scan_tree_recursive(session, new_item, subs_only);
1721         }
1722
1723         g_slist_free(item_list);
1724
1725         return IMAP_SUCCESS;
1726 }
1727
1728 GList *imap_scan_subtree(Folder *folder, FolderItem *item, gboolean unsubs_only, gboolean recursive)
1729 {
1730         IMAPSession *session = imap_session_get(folder);
1731         gchar *real_path;
1732         gchar *wildcard_path;
1733         gchar separator;
1734         gchar wildcard[3];
1735         clist * lep_list;
1736         GSList *item_list = NULL, *cur;
1737         GList *child_list = NULL, *tmplist = NULL;
1738         GSList *sub_list = NULL;
1739         int r;
1740
1741         if (!session)
1742                 return NULL;
1743
1744         separator = imap_get_path_separator(session, IMAP_FOLDER(folder), item->path);
1745
1746         if (item->path) {
1747                 wildcard[0] = separator;
1748                 wildcard[1] = '%';
1749                 wildcard[2] = '\0';
1750                 real_path = imap_get_real_path(session, IMAP_FOLDER(folder), item->path);
1751         } else {
1752                 wildcard[0] = '%';
1753                 wildcard[1] = '\0';
1754                 real_path = g_strdup("");
1755         }
1756
1757         Xstrcat_a(wildcard_path, real_path, wildcard,
1758                   {g_free(real_path); return NULL;});
1759         lep_list = NULL;
1760         
1761         if (unsubs_only)
1762                 statusbar_print_all(_("Looking for unsubscribed folders in %s..."), 
1763                                 item->path?item->path:item->name);
1764         else
1765                 statusbar_print_all(_("Looking for subfolders of %s..."), 
1766                                 item->path?item->path:item->name);
1767
1768         r = imap_threaded_list(folder, "", wildcard_path, &lep_list);
1769         if (r) {
1770                 statusbar_pop_all();
1771                 return NULL;
1772         }
1773         item_list = imap_list_from_lep(IMAP_FOLDER(folder),
1774                                lep_list, real_path, FALSE);
1775         mailimap_list_result_free(lep_list);
1776
1777         for (cur = item_list; cur != NULL; cur = cur->next) {
1778                 FolderItem *cur_item = FOLDER_ITEM(cur->data);
1779                 if (recursive) {
1780                         tmplist = imap_scan_subtree(folder, cur_item, 
1781                                         unsubs_only, recursive);
1782                         if (tmplist)
1783                                 child_list = g_list_concat(child_list, tmplist);
1784                 }
1785                 child_list = g_list_prepend(child_list,
1786                                 imap_get_real_path(session, 
1787                                         IMAP_FOLDER(folder), cur_item->path));
1788                 
1789                 folder_item_destroy(cur_item);
1790         }
1791         child_list = g_list_reverse(child_list);
1792         g_slist_free(item_list);
1793
1794         if (unsubs_only) {
1795                 r = imap_threaded_lsub(folder, "", wildcard_path, &lep_list);
1796                 if (r) {
1797                         statusbar_pop_all();
1798                         return NULL;
1799                 }
1800                 sub_list = imap_list_from_lep(IMAP_FOLDER(folder),
1801                                        lep_list, real_path, FALSE);
1802                 mailimap_list_result_free(lep_list);
1803
1804                 for (cur = sub_list; cur != NULL; cur = cur->next) {
1805                         FolderItem *cur_item = FOLDER_ITEM(cur->data);
1806                         GList *oldlitem = NULL;
1807                         gchar *tmp = imap_get_real_path(session, 
1808                                         IMAP_FOLDER(folder), cur_item->path);
1809                         folder_item_destroy(cur_item);
1810                         oldlitem = g_list_find_custom(
1811                                         child_list, tmp, (GCompareFunc)strcmp2);
1812                         if (oldlitem) {
1813                                 child_list = g_list_remove_link(child_list, oldlitem);
1814                                 g_free(oldlitem->data);
1815                                 g_list_free(oldlitem);
1816                         }
1817                         g_free(tmp);
1818                 }
1819         }
1820
1821         statusbar_pop_all();
1822
1823         return child_list;
1824 }
1825
1826 static gint imap_create_tree(Folder *folder)
1827 {
1828         g_return_val_if_fail(folder != NULL, -1);
1829         g_return_val_if_fail(folder->node != NULL, -1);
1830         g_return_val_if_fail(folder->node->data != NULL, -1);
1831         g_return_val_if_fail(folder->account != NULL, -1);
1832
1833         imap_scan_tree(folder);
1834         imap_create_missing_folders(folder);
1835
1836         return 0;
1837 }
1838
1839 static void imap_create_missing_folders(Folder *folder)
1840 {
1841         g_return_if_fail(folder != NULL);
1842
1843         if (!folder->inbox)
1844                 folder->inbox = imap_create_special_folder
1845                         (folder, F_INBOX, "INBOX");
1846         if (!folder->trash)
1847                 folder->trash = imap_create_special_folder
1848                         (folder, F_TRASH, "Trash");
1849         if (!folder->queue)
1850                 folder->queue = imap_create_special_folder
1851                         (folder, F_QUEUE, "Queue");
1852         if (!folder->outbox)
1853                 folder->outbox = imap_create_special_folder
1854                         (folder, F_OUTBOX, "Sent");
1855         if (!folder->draft)
1856                 folder->draft = imap_create_special_folder
1857                         (folder, F_DRAFT, "Drafts");
1858 }
1859
1860 static FolderItem *imap_create_special_folder(Folder *folder,
1861                                               SpecialFolderItemType stype,
1862                                               const gchar *name)
1863 {
1864         FolderItem *item;
1865         FolderItem *new_item;
1866
1867         g_return_val_if_fail(folder != NULL, NULL);
1868         g_return_val_if_fail(folder->node != NULL, NULL);
1869         g_return_val_if_fail(folder->node->data != NULL, NULL);
1870         g_return_val_if_fail(folder->account != NULL, NULL);
1871         g_return_val_if_fail(name != NULL, NULL);
1872
1873         item = FOLDER_ITEM(folder->node->data);
1874         new_item = imap_create_folder(folder, item, name);
1875
1876         if (!new_item) {
1877                 g_warning("Can't create '%s'\n", name);
1878                 if (!folder->inbox) return NULL;
1879
1880                 new_item = imap_create_folder(folder, folder->inbox, name);
1881                 if (!new_item)
1882                         g_warning("Can't create '%s' under INBOX\n", name);
1883                 else
1884                         new_item->stype = stype;
1885         } else
1886                 new_item->stype = stype;
1887
1888         return new_item;
1889 }
1890
1891 static gchar *imap_folder_get_path(Folder *folder)
1892 {
1893         gchar *folder_path;
1894
1895         g_return_val_if_fail(folder != NULL, NULL);
1896         g_return_val_if_fail(folder->account != NULL, NULL);
1897
1898         folder_path = g_strconcat(get_imap_cache_dir(),
1899                                   G_DIR_SEPARATOR_S,
1900                                   folder->account->recv_server,
1901                                   G_DIR_SEPARATOR_S,
1902                                   folder->account->userid,
1903                                   NULL);
1904
1905         return folder_path;
1906 }
1907
1908 static gchar *imap_item_get_path(Folder *folder, FolderItem *item)
1909 {
1910         gchar *folder_path, *path;
1911
1912         g_return_val_if_fail(folder != NULL, NULL);
1913         g_return_val_if_fail(item != NULL, NULL);
1914         folder_path = imap_folder_get_path(folder);
1915
1916         g_return_val_if_fail(folder_path != NULL, NULL);
1917         if (folder_path[0] == G_DIR_SEPARATOR) {
1918                 if (item->path)
1919                         path = g_strconcat(folder_path, G_DIR_SEPARATOR_S,
1920                                            item->path, NULL);
1921                 else
1922                         path = g_strdup(folder_path);
1923         } else {
1924                 if (item->path)
1925                         path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
1926                                            folder_path, G_DIR_SEPARATOR_S,
1927                                            item->path, NULL);
1928                 else
1929                         path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
1930                                            folder_path, NULL);
1931         }
1932         g_free(folder_path);
1933
1934         return path;
1935 }
1936
1937 static FolderItem *imap_create_folder(Folder *folder, FolderItem *parent,
1938                                const gchar *name)
1939 {
1940         gchar *dirpath, *imap_path;
1941         IMAPSession *session;
1942         FolderItem *new_item;
1943         gchar separator;
1944         gchar *new_name;
1945         const gchar *p;
1946         gint ok;
1947         gboolean no_select = FALSE, no_sub = FALSE;
1948         gboolean exist = FALSE;
1949         
1950         g_return_val_if_fail(folder != NULL, NULL);
1951         g_return_val_if_fail(folder->account != NULL, NULL);
1952         g_return_val_if_fail(parent != NULL, NULL);
1953         g_return_val_if_fail(name != NULL, NULL);
1954
1955         debug_print("getting session...\n");
1956         session = imap_session_get(folder);
1957         if (!session) {
1958                 return NULL;
1959         }
1960
1961         if (!folder_item_parent(parent) && strcmp(name, "INBOX") == 0) {
1962                 dirpath = g_strdup(name);
1963         }else if (parent->path)
1964                 dirpath = g_strconcat(parent->path, "/", name, NULL);
1965         else if ((p = strchr(name, '/')) != NULL && *(p + 1) != '\0')
1966                 dirpath = g_strdup(name);
1967         else if (folder->account->imap_dir && *folder->account->imap_dir) {
1968                 gchar *imap_dir;
1969
1970                 Xstrdup_a(imap_dir, folder->account->imap_dir, {unlock_session();return NULL;});
1971                 strtailchomp(imap_dir, '/');
1972                 dirpath = g_strconcat(imap_dir, "/", name, NULL);
1973         } else
1974                 dirpath = g_strdup(name);
1975                 
1976         
1977
1978         /* keep trailing directory separator to create a folder that contains
1979            sub folder */
1980         imap_path = imap_utf8_to_modified_utf7(dirpath);
1981
1982         strtailchomp(dirpath, '/');
1983         Xstrdup_a(new_name, name, {
1984                 g_free(dirpath); 
1985                 unlock_session();               
1986                 return NULL;});
1987
1988         separator = imap_get_path_separator(session, IMAP_FOLDER(folder), imap_path);
1989         imap_path_separator_subst(imap_path, separator);
1990         /* remove trailing / for display */
1991         strtailchomp(new_name, '/');
1992
1993         if (strcmp(dirpath, "INBOX") != 0) {
1994                 GPtrArray *argbuf;
1995                 int r;
1996                 clist * lep_list;
1997                 
1998                 argbuf = g_ptr_array_new();
1999                 r = imap_threaded_list(folder, "", imap_path, &lep_list);
2000                 if (r != MAILIMAP_NO_ERROR) {
2001                         log_warning(_("can't create mailbox: LIST failed\n"));
2002                         g_free(imap_path);
2003                         g_free(dirpath);
2004                         ptr_array_free_strings(argbuf);
2005                         g_ptr_array_free(argbuf, TRUE);
2006                         unlock_session();
2007                         return NULL;
2008                 }
2009                 
2010                 if (clist_count(lep_list) > 0)
2011                         exist = TRUE;
2012                 mailimap_list_result_free(lep_list);
2013                 lep_list = NULL;
2014                 if (!exist) {
2015                         ok = imap_cmd_create(session, imap_path);
2016                         if (ok != IMAP_SUCCESS) {
2017                                 log_warning(_("can't create mailbox\n"));
2018                                 g_free(imap_path);
2019                                 g_free(dirpath);
2020                                 unlock_session();
2021                                 return NULL;
2022                         }
2023                         r = imap_threaded_list(folder, "", imap_path, &lep_list);
2024                         if (r == MAILIMAP_NO_ERROR) {
2025                                 GSList *item_list = imap_list_from_lep(IMAP_FOLDER(folder),
2026                                                lep_list, dirpath, TRUE);
2027                                 if (item_list) {
2028                                         FolderItem *cur_item = FOLDER_ITEM(item_list->data);
2029                                         no_select = cur_item->no_select;
2030                                         no_sub = cur_item->no_sub;
2031                                         g_slist_free(item_list);
2032                                 } 
2033                                 mailimap_list_result_free(lep_list);
2034                         }
2035                 }
2036                 imap_threaded_subscribe(folder, imap_path, TRUE);
2037         } else {
2038                 clist *lep_list;
2039                 int r;
2040                 /* just get flags */
2041                 r = imap_threaded_list(folder, "", "INBOX", &lep_list);
2042                 if (r == MAILIMAP_NO_ERROR) {
2043                         GSList *item_list = imap_list_from_lep(IMAP_FOLDER(folder),
2044                                        lep_list, dirpath, TRUE);
2045                         if (item_list) {
2046                                 FolderItem *cur_item = FOLDER_ITEM(item_list->data);
2047                                 no_select = cur_item->no_select;
2048                                 no_sub = cur_item->no_sub;
2049                                 g_slist_free(item_list);
2050                         } 
2051                         mailimap_list_result_free(lep_list);
2052                 }
2053         }
2054
2055         new_item = folder_item_new(folder, new_name, dirpath);
2056         new_item->no_select = no_select;
2057         new_item->no_sub = no_sub;
2058         folder_item_append(parent, new_item);
2059         g_free(imap_path);
2060         g_free(dirpath);
2061
2062         dirpath = folder_item_get_path(new_item);
2063         if (!is_dir_exist(dirpath))
2064                 make_dir_hier(dirpath);
2065         g_free(dirpath);
2066         unlock_session();
2067
2068         if (exist) {
2069                 /* folder existed, scan it */
2070                 folder_item_scan_full(new_item, FALSE);
2071         }
2072
2073         return new_item;
2074 }
2075
2076 static gint imap_rename_folder(Folder *folder, FolderItem *item,
2077                                const gchar *name)
2078 {
2079         gchar *dirpath;
2080         gchar *newpath;
2081         gchar *real_oldpath;
2082         gchar *real_newpath;
2083         gchar *paths[2];
2084         gchar *old_cache_dir;
2085         gchar *new_cache_dir;
2086         IMAPSession *session;
2087         gchar separator;
2088         gint ok;
2089         gint exists, recent, unseen;
2090         guint32 uid_validity;
2091
2092         g_return_val_if_fail(folder != NULL, -1);
2093         g_return_val_if_fail(item != NULL, -1);
2094         g_return_val_if_fail(item->path != NULL, -1);
2095         g_return_val_if_fail(name != NULL, -1);
2096
2097         debug_print("getting session...\n");
2098         session = imap_session_get(folder);
2099         if (!session) {
2100                 return -1;
2101         }
2102
2103         if (strchr(name, imap_get_path_separator(session, IMAP_FOLDER(folder), item->path)) != NULL) {
2104                 g_warning(_("New folder name must not contain the namespace "
2105                             "path separator"));
2106                 unlock_session();
2107                 return -1;
2108         }
2109
2110         real_oldpath = imap_get_real_path(session, IMAP_FOLDER(folder), item->path);
2111
2112         g_free(session->mbox);
2113         session->mbox = NULL;
2114         ok = imap_cmd_examine(session, "INBOX",
2115                               &exists, &recent, &unseen, &uid_validity, FALSE);
2116         if (ok != IMAP_SUCCESS) {
2117                 g_free(real_oldpath);
2118                 unlock_session();
2119                 return -1;
2120         }
2121
2122         separator = imap_get_path_separator(session, IMAP_FOLDER(folder), item->path);
2123         if (strchr(item->path, G_DIR_SEPARATOR)) {
2124                 dirpath = g_path_get_dirname(item->path);
2125                 newpath = g_strconcat(dirpath, G_DIR_SEPARATOR_S, name, NULL);
2126                 g_free(dirpath);
2127         } else
2128                 newpath = g_strdup(name);
2129
2130         real_newpath = imap_utf8_to_modified_utf7(newpath);
2131         imap_path_separator_subst(real_newpath, separator);
2132
2133         ok = imap_cmd_rename(session, real_oldpath, real_newpath);
2134         if (ok != IMAP_SUCCESS) {
2135                 log_warning(_("can't rename mailbox: %s to %s\n"),
2136                             real_oldpath, real_newpath);
2137                 g_free(real_oldpath);
2138                 g_free(newpath);
2139                 g_free(real_newpath);
2140                 unlock_session();
2141                 return -1;
2142         }
2143
2144         g_free(item->name);
2145         item->name = g_strdup(name);
2146
2147         old_cache_dir = folder_item_get_path(item);
2148
2149         paths[0] = g_strdup(item->path);
2150         paths[1] = newpath;
2151         g_node_traverse(item->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
2152                         imap_rename_folder_func, paths);
2153
2154         if (is_dir_exist(old_cache_dir)) {
2155                 new_cache_dir = folder_item_get_path(item);
2156                 if (rename(old_cache_dir, new_cache_dir) < 0) {
2157                         FILE_OP_ERROR(old_cache_dir, "rename");
2158                 }
2159                 g_free(new_cache_dir);
2160         }
2161
2162         g_free(old_cache_dir);
2163         g_free(paths[0]);
2164         g_free(newpath);
2165         g_free(real_oldpath);
2166         g_free(real_newpath);
2167         unlock_session();
2168         return 0;
2169 }
2170
2171 gint imap_subscribe(Folder *folder, FolderItem *item, gchar *rpath, gboolean sub)
2172 {
2173         gchar *path;
2174         gint r = -1;
2175         IMAPSession *session;
2176         debug_print("getting session...\n");
2177
2178         session = imap_session_get(folder);
2179         if (!session) {
2180                 return -1;
2181         }
2182         if (item && item->path) {
2183                 path = imap_get_real_path(session, IMAP_FOLDER(folder), item->path);
2184                 if (!path)
2185                         return -1;
2186                 if (!strcmp(path, "INBOX") && sub == FALSE)
2187                         return -1;
2188                 debug_print("%ssubscribing %s\n", sub?"":"un", path);
2189                 r = imap_threaded_subscribe(folder, path, sub);
2190                 g_free(path);
2191         } else if (rpath) {
2192                 r = imap_threaded_subscribe(folder, rpath, sub);
2193         } else
2194                 return -1;
2195         return r;
2196 }
2197
2198 static gint imap_remove_folder_real(Folder *folder, FolderItem *item)
2199 {
2200         gint ok;
2201         IMAPSession *session;
2202         gchar *path;
2203         gchar *cache_dir;
2204
2205         g_return_val_if_fail(folder != NULL, -1);
2206         g_return_val_if_fail(item != NULL, -1);
2207         g_return_val_if_fail(item->path != NULL, -1);
2208
2209         debug_print("getting session...\n");
2210         session = imap_session_get(folder);
2211         if (!session) {
2212                 return -1;
2213         }
2214         path = imap_get_real_path(session, IMAP_FOLDER(folder), item->path);
2215
2216         imap_threaded_subscribe(folder, path, FALSE);
2217         ok = imap_cmd_delete(session, path);
2218         if (ok != IMAP_SUCCESS) {
2219                 gchar *tmp = g_strdup_printf("%s%c", path, 
2220                                 imap_get_path_separator(session, IMAP_FOLDER(folder), path));
2221                 g_free(path);
2222                 path = tmp;
2223                 ok = imap_cmd_delete(session, path);
2224         }
2225
2226         if (ok != IMAP_SUCCESS) {
2227                 log_warning(_("can't delete mailbox\n"));
2228                 g_free(path);
2229                 unlock_session();
2230                 return -1;
2231         }
2232
2233         g_free(path);
2234         cache_dir = folder_item_get_path(item);
2235         if (is_dir_exist(cache_dir) && remove_dir_recursive(cache_dir) < 0)
2236                 g_warning("can't remove directory '%s'\n", cache_dir);
2237         g_free(cache_dir);
2238         folder_item_remove(item);
2239         unlock_session();
2240         return 0;
2241 }
2242
2243 static gint imap_remove_folder(Folder *folder, FolderItem *item)
2244 {
2245         GNode *node, *next;
2246
2247         g_return_val_if_fail(item != NULL, -1);
2248         g_return_val_if_fail(item->folder != NULL, -1);
2249         g_return_val_if_fail(item->node != NULL, -1);
2250
2251         node = item->node->children;
2252         while (node != NULL) {
2253                 next = node->next;
2254                 if (imap_remove_folder(folder, FOLDER_ITEM(node->data)) < 0)
2255                         return -1;
2256                 node = next;
2257         }
2258         debug_print("IMAP removing %s\n", item->path);
2259
2260         if (imap_remove_all_msg(folder, item) < 0)
2261                 return -1;
2262         return imap_remove_folder_real(folder, item);
2263 }
2264
2265 typedef struct _uncached_data {
2266         IMAPSession *session;
2267         FolderItem *item;
2268         MsgNumberList *numlist;
2269         guint cur;
2270         guint total;
2271         gboolean done;
2272 } uncached_data;
2273
2274 static void *imap_get_uncached_messages_thread(void *data)
2275 {
2276         uncached_data *stuff = (uncached_data *)data;
2277         IMAPSession *session = stuff->session;
2278         FolderItem *item = stuff->item;
2279         MsgNumberList *numlist = stuff->numlist;
2280         
2281         GSList *newlist = NULL;
2282         GSList *llast = NULL;
2283         GSList *seq_list, *cur;
2284
2285         debug_print("uncached_messages\n");
2286         
2287         if (session == NULL || item == NULL || item->folder == NULL
2288             || FOLDER_CLASS(item->folder) != &imap_class) {
2289                 stuff->done = TRUE;
2290                 return NULL;
2291         }
2292         
2293         seq_list = imap_get_lep_set_from_numlist(numlist);
2294         debug_print("get msgs info\n");
2295         for (cur = seq_list; cur != NULL; cur = g_slist_next(cur)) {
2296                 struct mailimap_set * imapset;
2297                 unsigned int i;
2298                 int r;
2299                 carray * env_list;
2300                 int count;
2301                 
2302                 imapset = cur->data;
2303                 
2304                 r = imap_threaded_fetch_env(session->folder,
2305                                             imapset, &env_list);
2306                 if (r != MAILIMAP_NO_ERROR)
2307                         continue;
2308                 
2309                 session_set_access_time(SESSION(session));
2310
2311                 count = 0;
2312                 for(i = 0 ; i < carray_count(env_list) ; i ++) {
2313                         struct imap_fetch_env_info * info;
2314                         MsgInfo * msginfo;
2315                         
2316                         info = carray_get(env_list, i);
2317                         msginfo = imap_envelope_from_lep(info, item);
2318                         if (msginfo == NULL)
2319                                 continue;
2320                         msginfo->folder = item;
2321                         if (!newlist)
2322                                 llast = newlist = g_slist_append(newlist, msginfo);
2323                         else {
2324                                 llast = g_slist_append(llast, msginfo);
2325                                 llast = llast->next;
2326                         }
2327                         count ++;
2328                 }
2329                 
2330                 imap_fetch_env_free(env_list);
2331         }
2332         
2333         for (cur = seq_list; cur != NULL; cur = g_slist_next(cur)) {
2334                 struct mailimap_set * imapset;
2335                 
2336                 imapset = cur->data;
2337                 mailimap_set_free(imapset);
2338         }
2339         
2340         session_set_access_time(SESSION(session));
2341         stuff->done = TRUE;
2342         return newlist;
2343 }
2344
2345 #define MAX_MSG_NUM 50
2346
2347 static GSList *imap_get_uncached_messages(IMAPSession *session,
2348                                         FolderItem *item,
2349                                         MsgNumberList *numlist)
2350 {
2351         GSList *result = NULL;
2352         GSList * cur;
2353         uncached_data *data = g_new0(uncached_data, 1);
2354         int finished;
2355         
2356         finished = 0;
2357         cur = numlist;
2358         data->total = g_slist_length(numlist);
2359         debug_print("messages list : %i\n", data->total);
2360
2361         while (cur != NULL) {
2362                 GSList * partial_result;
2363                 int count;
2364                 GSList * newlist;
2365                 GSList * llast;
2366                 
2367                 llast = NULL;
2368                 count = 0;
2369                 newlist = NULL;
2370                 while (count < MAX_MSG_NUM) {
2371                         void * p;
2372                         
2373                         p = cur->data;
2374                         
2375                         if (newlist == NULL)
2376                                 llast = newlist = g_slist_append(newlist, p);
2377                         else {
2378                                 llast = g_slist_append(llast, p);
2379                                 llast = llast->next;
2380                         }
2381                         count ++;
2382                         
2383                         cur = cur->next;
2384                         if (cur == NULL)
2385                                 break;
2386                 }
2387                 
2388                 data->done = FALSE;
2389                 data->session = session;
2390                 data->item = item;
2391                 data->numlist = newlist;
2392                 data->cur += count;
2393                 
2394                 if (prefs_common.work_offline && 
2395                     !inc_offline_should_override(
2396                         _("Claws Mail needs network access in order "
2397                           "to access the IMAP server."))) {
2398                         g_free(data);
2399                         return NULL;
2400                 }
2401                 
2402                 partial_result =
2403                         (GSList *)imap_get_uncached_messages_thread(data);
2404                 
2405                 statusbar_progress_all(data->cur,data->total, 1);
2406                 
2407                 g_slist_free(newlist);
2408                 
2409                 result = g_slist_concat(result, partial_result);
2410         }
2411         g_free(data);
2412         
2413         statusbar_progress_all(0,0,0);
2414         statusbar_pop_all();
2415         
2416         return result;
2417 }
2418
2419 static void imap_delete_all_cached_messages(FolderItem *item)
2420 {
2421         gchar *dir;
2422
2423         g_return_if_fail(item != NULL);
2424         g_return_if_fail(item->folder != NULL);
2425         g_return_if_fail(FOLDER_CLASS(item->folder) == &imap_class);
2426
2427         debug_print("Deleting all cached messages...\n");
2428
2429         dir = folder_item_get_path(item);
2430         if (is_dir_exist(dir))
2431                 remove_all_numbered_files(dir);
2432         g_free(dir);
2433
2434         debug_print("done.\n");
2435 }
2436
2437 gchar imap_get_path_separator_for_item(FolderItem *item)
2438 {
2439         Folder *folder = NULL;
2440         IMAPFolder *imap_folder = NULL;
2441         IMAPSession *session = NULL;
2442         gchar result = '/';
2443         
2444         if (!item)
2445                 return '/';
2446         folder = item->folder;
2447         
2448         if (!folder)
2449                 return '/';
2450         
2451         imap_folder = IMAP_FOLDER(folder);
2452         
2453         if (!imap_folder)
2454                 return '/';
2455         
2456         debug_print("getting session...");
2457         session = imap_session_get(FOLDER(folder));
2458         result = imap_get_path_separator(session, imap_folder, item->path);
2459         unlock_session();
2460         return result;
2461 }
2462
2463 static gchar imap_refresh_path_separator(IMAPSession *session, IMAPFolder *folder, const gchar *subfolder)
2464 {
2465         clist * lep_list;
2466         int r;
2467         gchar separator = '\0';
2468         
2469         g_return_val_if_fail(session != NULL, '/');
2470         r = imap_threaded_list((Folder *)folder, "", subfolder, &lep_list);
2471         
2472         if (r != MAILIMAP_NO_ERROR) {
2473                 log_warning(_("LIST failed\n"));
2474                 return '\0';
2475         }
2476
2477         if (clist_count(lep_list) > 0) {
2478                 clistiter * iter = clist_begin(lep_list); 
2479                 struct mailimap_mailbox_list * mb;
2480                 mb = clist_content(iter);
2481
2482                 separator = mb->mb_delimiter;
2483                 debug_print("got separator: %c\n", folder->last_seen_separator);
2484         }
2485         mailimap_list_result_free(lep_list);
2486         return separator;
2487 }
2488
2489 static gchar imap_get_path_separator(IMAPSession *session, IMAPFolder *folder, const gchar *path)
2490 {
2491         gchar separator = '/';
2492
2493         if (folder->last_seen_separator == 0) {
2494                 folder->last_seen_separator = imap_refresh_path_separator(session, folder, "");
2495         }
2496
2497         if (folder->last_seen_separator == 0) {
2498                 folder->last_seen_separator = imap_refresh_path_separator(session, folder, "INBOX");
2499         }
2500
2501         if (folder->last_seen_separator != 0) {
2502                 debug_print("using separator: %c\n", folder->last_seen_separator);
2503                 return folder->last_seen_separator;
2504         }
2505
2506         return separator;
2507 }
2508
2509 static gchar *imap_get_real_path(IMAPSession *session, IMAPFolder *folder, const gchar *path)
2510 {
2511         gchar *real_path;
2512         gchar separator;
2513
2514         g_return_val_if_fail(folder != NULL, NULL);
2515         g_return_val_if_fail(path != NULL, NULL);
2516
2517         real_path = imap_utf8_to_modified_utf7(path);
2518         separator = imap_get_path_separator(session, folder, path);
2519         imap_path_separator_subst(real_path, separator);
2520
2521         return real_path;
2522 }
2523
2524 static gint imap_set_message_flags(IMAPSession *session,
2525                                    MsgNumberList *numlist,
2526                                    IMAPFlags flags,
2527                                    gboolean is_set)
2528 {
2529         gint ok = 0;
2530         GSList *seq_list;
2531         GSList * cur;
2532
2533         seq_list = imap_get_lep_set_from_numlist(numlist);
2534         
2535         for(cur = seq_list ; cur != NULL ; cur = g_slist_next(cur)) {
2536                 struct mailimap_set * imapset;
2537                 
2538                 imapset = cur->data;
2539                 
2540                 ok = imap_cmd_store(session, imapset,
2541                                     flags, is_set);
2542         }
2543         
2544         imap_lep_set_free(seq_list);
2545         
2546         return IMAP_SUCCESS;
2547 }
2548
2549 typedef struct _select_data {
2550         IMAPSession *session;
2551         gchar *real_path;
2552         gint *exists;
2553         gint *recent;
2554         gint *unseen;
2555         guint32 *uid_validity;
2556         gboolean done;
2557 } select_data;
2558
2559 static gint imap_select(IMAPSession *session, IMAPFolder *folder,
2560                         const gchar *path,
2561                         gint *exists, gint *recent, gint *unseen,
2562                         guint32 *uid_validity, gboolean block)
2563 {
2564         gchar *real_path;
2565         gint ok;
2566         gint exists_, recent_, unseen_;
2567         guint32 uid_validity_;
2568         
2569         if (!exists && !recent && !unseen && !uid_validity) {
2570                 if (session->mbox && strcmp(session->mbox, path) == 0)
2571                         return IMAP_SUCCESS;
2572         }
2573         if (!exists)
2574                 exists = &exists_;
2575         if (!recent)
2576                 recent = &recent_;
2577         if (!unseen)
2578                 unseen = &unseen_;
2579         if (!uid_validity)
2580                 uid_validity = &uid_validity_;
2581
2582         g_free(session->mbox);
2583         session->mbox = NULL;
2584
2585         real_path = imap_get_real_path(session, folder, path);
2586
2587         ok = imap_cmd_select(session, real_path,
2588                              exists, recent, unseen, uid_validity, block);
2589         if (ok != IMAP_SUCCESS)
2590                 log_warning(_("can't select folder: %s\n"), real_path);
2591         else {
2592                 session->mbox = g_strdup(path);
2593                 session->folder_content_changed = FALSE;
2594         }
2595         g_free(real_path);
2596
2597         return ok;
2598 }
2599
2600 static gint imap_status(IMAPSession *session, IMAPFolder *folder,
2601                         const gchar *path, IMAPFolderItem *item,
2602                         gint *messages,
2603                         guint32 *uid_next, guint32 *uid_validity,
2604                         gint *unseen, gboolean block)
2605 {
2606         int r;
2607         clistiter * iter;
2608         struct mailimap_mailbox_data_status * data_status;
2609         int got_values;
2610         gchar *real_path;
2611         guint mask = 0;
2612         
2613         real_path = imap_get_real_path(session, folder, path);
2614
2615         if (messages) {
2616                 mask |= 1 << 0;
2617         }
2618         if (uid_next) {
2619                 mask |= 1 << 2;
2620         }
2621         if (uid_validity) {
2622                 mask |= 1 << 3;
2623         }
2624         if (unseen) {
2625                 mask |= 1 << 4;
2626         }
2627         r = imap_threaded_status(FOLDER(folder), real_path, 
2628                 &data_status, mask);
2629
2630         g_free(real_path);
2631         if (r != MAILIMAP_NO_ERROR) {
2632                 debug_print("status err %d\n", r);
2633                 return IMAP_ERROR;
2634         }
2635         
2636         if (data_status->st_info_list == NULL) {
2637                 mailimap_mailbox_data_status_free(data_status);
2638                 debug_print("status->st_info_list == NULL\n");
2639                 return IMAP_ERROR;
2640         }
2641         
2642         got_values = 0;
2643         for(iter = clist_begin(data_status->st_info_list) ; iter != NULL ;
2644             iter = clist_next(iter)) {
2645                 struct mailimap_status_info * info;             
2646                 
2647                 info = clist_content(iter);
2648                 switch (info->st_att) {
2649                 case MAILIMAP_STATUS_ATT_MESSAGES:
2650                         * messages = info->st_value;
2651                         got_values |= 1 << 0;
2652                         break;
2653                         
2654                 case MAILIMAP_STATUS_ATT_UIDNEXT:
2655                         * uid_next = info->st_value;
2656                         got_values |= 1 << 2;
2657                         break;
2658                         
2659                 case MAILIMAP_STATUS_ATT_UIDVALIDITY:
2660                         * uid_validity = info->st_value;
2661                         got_values |= 1 << 3;
2662                         break;
2663                         
2664                 case MAILIMAP_STATUS_ATT_UNSEEN:
2665                         * unseen = info->st_value;
2666                         got_values |= 1 << 4;
2667                         break;
2668                 }
2669         }
2670         mailimap_mailbox_data_status_free(data_status);
2671         
2672         if (got_values != mask) {
2673                 debug_print("status: incomplete values received (%d)\n", got_values);
2674                 return IMAP_ERROR;
2675         }
2676         return IMAP_SUCCESS;
2677 }
2678
2679 static void imap_free_capabilities(IMAPSession *session)
2680 {
2681         slist_free_strings(session->capability);
2682         g_slist_free(session->capability);
2683         session->capability = NULL;
2684 }
2685
2686 /* low-level IMAP4rev1 commands */
2687
2688 static gint imap_cmd_login(IMAPSession *session,
2689                            const gchar *user, const gchar *pass,
2690                            const gchar *type)
2691 {
2692         int r;
2693         gint ok;
2694
2695         if (!strcmp(type, "LOGIN") && imap_has_capability(session, "LOGINDISABLED")) {
2696                 gint ok = IMAP_ERROR;
2697                 if (imap_has_capability(session, "STARTTLS")) {
2698 #if USE_OPENSSL
2699                         log_warning(_("Server requires TLS to log in.\n"));
2700                         ok = imap_cmd_starttls(session);
2701                         if (ok != IMAP_SUCCESS) {
2702                                 log_warning(_("Can't start TLS session.\n"));
2703                                 return IMAP_ERROR;
2704                         } else {
2705                                 /* refresh capas */
2706                                 imap_free_capabilities(session);
2707                                 if (imap_get_capabilities(session) != MAILIMAP_NO_ERROR) {
2708                                         log_warning(_("Can't refresh capabilities.\n"));
2709                                         return IMAP_ERROR;
2710                                 }
2711                         }
2712 #else           
2713                         log_error(_("Connection to %s failed: "
2714                                         "server requires TLS, but Claws Mail "
2715                                         "has been compiled without OpenSSL "
2716                                         "support.\n"),
2717                                         SESSION(session)->server);
2718                         return IMAP_ERROR;
2719 #endif
2720                 } else {
2721                         log_error(_("Server logins are disabled.\n"));
2722                         return IMAP_ERROR;
2723                 }
2724         }
2725
2726         log_print("IMAP4> Logging %s to %s using %s\n", 
2727                         user,
2728                         SESSION(session)->server,
2729                         type);
2730         r = imap_threaded_login(session->folder, user, pass, type);
2731         if (r != MAILIMAP_NO_ERROR) {
2732                 log_print("IMAP4< Error logging in to %s\n",
2733                                 SESSION(session)->server);
2734                 ok = IMAP_ERROR;
2735         } else {
2736                 log_print("IMAP4< Login to %s successful\n",
2737                                 SESSION(session)->server);
2738                 ok = IMAP_SUCCESS;
2739         }
2740         return ok;
2741 }
2742
2743 static gint imap_cmd_noop(IMAPSession *session)
2744 {
2745         int r;
2746         unsigned int exists;
2747         
2748         r = imap_threaded_noop(session->folder, &exists);
2749         if (r != MAILIMAP_NO_ERROR) {
2750                 debug_print("noop err %d\n", r);
2751                 return IMAP_ERROR;
2752         }
2753         session->exists = exists;
2754         session_set_access_time(SESSION(session));
2755
2756         return IMAP_SUCCESS;
2757 }
2758
2759 #if USE_OPENSSL
2760 static gint imap_cmd_starttls(IMAPSession *session)
2761 {
2762         int r;
2763         
2764         r = imap_threaded_starttls(session->folder, 
2765                 SESSION(session)->server, SESSION(session)->port);
2766         if (r != MAILIMAP_NO_ERROR) {
2767                 debug_print("starttls err %d\n", r);
2768                 return IMAP_ERROR;
2769         }
2770         return IMAP_SUCCESS;
2771 }
2772 #endif
2773
2774 static gint imap_cmd_select(IMAPSession *session, const gchar *folder,
2775                             gint *exists, gint *recent, gint *unseen,
2776                             guint32 *uid_validity, gboolean block)
2777 {
2778         int r;
2779
2780         r = imap_threaded_select(session->folder, folder,
2781                                  exists, recent, unseen, uid_validity);
2782         if (r != MAILIMAP_NO_ERROR) {
2783                 debug_print("select err %d\n", r);
2784                 return IMAP_ERROR;
2785         }
2786         return IMAP_SUCCESS;
2787 }
2788
2789 static gint imap_cmd_examine(IMAPSession *session, const gchar *folder,
2790                              gint *exists, gint *recent, gint *unseen,
2791                              guint32 *uid_validity, gboolean block)
2792 {
2793         int r;
2794
2795         r = imap_threaded_examine(session->folder, folder,
2796                                   exists, recent, unseen, uid_validity);
2797         if (r != MAILIMAP_NO_ERROR) {
2798                 debug_print("examine err %d\n", r);
2799                 
2800                 return IMAP_ERROR;
2801         }
2802         return IMAP_SUCCESS;
2803 }
2804
2805 static gint imap_cmd_create(IMAPSession *session, const gchar *folder)
2806 {
2807         int r;
2808
2809         r = imap_threaded_create(session->folder, folder);
2810         if (r != MAILIMAP_NO_ERROR) {
2811                 
2812                 return IMAP_ERROR;
2813         }
2814
2815         return IMAP_SUCCESS;
2816 }
2817
2818 static gint imap_cmd_rename(IMAPSession *session, const gchar *old_folder,
2819                             const gchar *new_folder)
2820 {
2821         int r;
2822
2823         r = imap_threaded_rename(session->folder, old_folder,
2824                                  new_folder);
2825         if (r != MAILIMAP_NO_ERROR) {
2826                 
2827                 return IMAP_ERROR;
2828         }
2829
2830         return IMAP_SUCCESS;
2831 }
2832
2833 static gint imap_cmd_delete(IMAPSession *session, const gchar *folder)
2834 {
2835         int r;
2836         
2837
2838         r = imap_threaded_delete(session->folder, folder);
2839         if (r != MAILIMAP_NO_ERROR) {
2840                 
2841                 return IMAP_ERROR;
2842         }
2843
2844         return IMAP_SUCCESS;
2845 }
2846
2847 typedef struct _fetch_data {
2848         IMAPSession *session;
2849         guint32 uid;
2850         const gchar *filename;
2851         gboolean headers;
2852         gboolean body;
2853         gboolean done;
2854 } fetch_data;
2855
2856 static void *imap_cmd_fetch_thread(void *data)
2857 {
2858         fetch_data *stuff = (fetch_data *)data;
2859         IMAPSession *session = stuff->session;
2860         guint32 uid = stuff->uid;
2861         const gchar *filename = stuff->filename;
2862         int r;
2863         
2864         if (stuff->body) {
2865                 r = imap_threaded_fetch_content(session->folder,
2866                                                uid, 1, filename);
2867         }
2868         else {
2869                 r = imap_threaded_fetch_content(session->folder,
2870                                                 uid, 0, filename);
2871         }
2872         if (r != MAILIMAP_NO_ERROR) {
2873                 debug_print("fetch err %d\n", r);
2874                 return GINT_TO_POINTER(IMAP_ERROR);
2875         }
2876         return GINT_TO_POINTER(IMAP_SUCCESS);
2877 }
2878
2879 static gint imap_cmd_fetch(IMAPSession *session, guint32 uid,
2880                                 const gchar *filename, gboolean headers,
2881                                 gboolean body)
2882 {
2883         fetch_data *data = g_new0(fetch_data, 1);
2884         int result = 0;
2885         data->done = FALSE;
2886         data->session = session;
2887         data->uid = uid;
2888         data->filename = filename;
2889         data->headers = headers;
2890         data->body = body;
2891
2892         if (prefs_common.work_offline && 
2893             !inc_offline_should_override(
2894                 _("Claws Mail needs network access in order "
2895                   "to access the IMAP server."))) {
2896                 g_free(data);
2897                 return -1;
2898         }
2899         statusbar_print_all(_("Fetching message..."));
2900         result = GPOINTER_TO_INT(imap_cmd_fetch_thread(data));
2901         statusbar_pop_all();
2902         g_free(data);
2903         return result;
2904 }
2905
2906
2907 static gint imap_cmd_append(IMAPSession *session, const gchar *destfolder,
2908                             const gchar *file, IMAPFlags flags, 
2909                             guint32 *new_uid)
2910 {
2911         struct mailimap_flag_list * flag_list;
2912         int r;
2913         
2914         g_return_val_if_fail(file != NULL, IMAP_ERROR);
2915
2916         flag_list = imap_flag_to_lep(flags);
2917         r = imap_threaded_append(session->folder, destfolder,
2918                          file, flag_list, (int *)new_uid);
2919         mailimap_flag_list_free(flag_list);
2920
2921         if (r != MAILIMAP_NO_ERROR) {
2922                 debug_print("append err %d\n", r);
2923                 return IMAP_ERROR;
2924         }
2925         return IMAP_SUCCESS;
2926 }
2927
2928 static gint imap_cmd_copy(IMAPSession *session, struct mailimap_set * set,
2929                           const gchar *destfolder, GRelation *uid_mapping,
2930                           struct mailimap_set **source, struct mailimap_set **dest)
2931 {
2932         int r;
2933         
2934         g_return_val_if_fail(session != NULL, IMAP_ERROR);
2935         g_return_val_if_fail(set != NULL, IMAP_ERROR);
2936         g_return_val_if_fail(destfolder != NULL, IMAP_ERROR);
2937
2938         r = imap_threaded_copy(session->folder, set, destfolder, source, dest);
2939         if (r != MAILIMAP_NO_ERROR) {
2940                 
2941                 return IMAP_ERROR;
2942         }
2943
2944         return IMAP_SUCCESS;
2945 }
2946
2947 static gint imap_cmd_store(IMAPSession *session, struct mailimap_set * set,
2948                            IMAPFlags flags, int do_add)
2949 {
2950         int r;
2951         struct mailimap_flag_list * flag_list;
2952         struct mailimap_store_att_flags * store_att_flags;
2953         
2954         flag_list = imap_flag_to_lep(flags);
2955         
2956         if (do_add)
2957                 store_att_flags =
2958                         mailimap_store_att_flags_new_add_flags_silent(flag_list);
2959         else
2960                 store_att_flags =
2961                         mailimap_store_att_flags_new_remove_flags_silent(flag_list);
2962         
2963         r = imap_threaded_store(session->folder, set, store_att_flags);
2964         mailimap_store_att_flags_free(store_att_flags);
2965         if (r != MAILIMAP_NO_ERROR) {
2966                 
2967                 return IMAP_ERROR;
2968         }
2969         
2970         return IMAP_SUCCESS;
2971 }
2972
2973 static gint imap_cmd_expunge(IMAPSession *session)
2974 {
2975         int r;
2976         
2977         if (prefs_common.work_offline && 
2978             !inc_offline_should_override(
2979                 _("Claws Mail needs network access in order "
2980                   "to access the IMAP server."))) {
2981                 return -1;
2982         }
2983
2984         r = imap_threaded_expunge(session->folder);
2985         if (r != MAILIMAP_NO_ERROR) {
2986                 
2987                 return IMAP_ERROR;
2988         }
2989
2990         return IMAP_SUCCESS;
2991 }
2992
2993 static void imap_path_separator_subst(gchar *str, gchar separator)
2994 {
2995         gchar *p;
2996         gboolean in_escape = FALSE;
2997
2998         if (!separator || separator == '/') return;
2999
3000         for (p = str; *p != '\0'; p++) {
3001                 if (*p == '/' && !in_escape)
3002                         *p = separator;
3003                 else if (*p == '&' && *(p + 1) != '-' && !in_escape)
3004                         in_escape = TRUE;
3005                 else if (*p == '-' && in_escape)
3006                         in_escape = FALSE;
3007         }
3008 }
3009
3010 static gchar *imap_modified_utf7_to_utf8(const gchar *mutf7_str)
3011 {
3012         static iconv_t cd = (iconv_t)-1;
3013         static gboolean iconv_ok = TRUE;
3014         GString *norm_utf7;
3015         gchar *norm_utf7_p;
3016         size_t norm_utf7_len;
3017         const gchar *p;
3018         gchar *to_str, *to_p;
3019         size_t to_len;
3020         gboolean in_escape = FALSE;
3021
3022         if (!iconv_ok) return g_strdup(mutf7_str);
3023
3024         if (cd == (iconv_t)-1) {
3025                 cd = iconv_open(CS_INTERNAL, CS_UTF_7);
3026                 if (cd == (iconv_t)-1) {
3027                         g_warning("iconv cannot convert UTF-7 to %s\n",
3028                                   CS_INTERNAL);
3029                         iconv_ok = FALSE;
3030                         return g_strdup(mutf7_str);
3031                 }
3032         }
3033
3034         /* modified UTF-7 to normal UTF-7 conversion */
3035         norm_utf7 = g_string_new(NULL);
3036
3037         for (p = mutf7_str; *p != '\0'; p++) {
3038                 /* replace: '&'  -> '+',
3039                             "&-" -> '&',
3040                             escaped ','  -> '/' */
3041                 if (!in_escape && *p == '&') {
3042                         if (*(p + 1) != '-') {
3043                                 g_string_append_c(norm_utf7, '+');
3044                                 in_escape = TRUE;
3045                         } else {
3046                                 g_string_append_c(norm_utf7, '&');
3047                                 p++;
3048                         }
3049                 } else if (in_escape && *p == ',') {
3050                         g_string_append_c(norm_utf7, '/');
3051                 } else if (in_escape && *p == '-') {
3052                         g_string_append_c(norm_utf7, '-');
3053                         in_escape = FALSE;
3054                 } else {
3055                         g_string_append_c(norm_utf7, *p);
3056                 }
3057         }
3058
3059         norm_utf7_p = norm_utf7->str;
3060         norm_utf7_len = norm_utf7->len;
3061         to_len = strlen(mutf7_str) * 5;
3062         to_p = to_str = g_malloc(to_len + 1);
3063
3064         if (iconv(cd, (ICONV_CONST gchar **)&norm_utf7_p, &norm_utf7_len,
3065                   &to_p, &to_len) == -1) {
3066                 g_warning(_("iconv cannot convert UTF-7 to %s\n"),
3067                           conv_get_locale_charset_str());
3068                 g_string_free(norm_utf7, TRUE);
3069                 g_free(to_str);
3070                 return g_strdup(mutf7_str);
3071         }
3072
3073         /* second iconv() call for flushing */
3074         iconv(cd, NULL, NULL, &to_p, &to_len);
3075         g_string_free(norm_utf7, TRUE);
3076         *to_p = '\0';
3077
3078         return to_str;
3079 }
3080
3081 static gchar *imap_utf8_to_modified_utf7(const gchar *from)
3082 {
3083         static iconv_t cd = (iconv_t)-1;
3084         static gboolean iconv_ok = TRUE;
3085         gchar *norm_utf7, *norm_utf7_p;
3086         size_t from_len, norm_utf7_len;
3087         GString *to_str;
3088         gchar *from_tmp, *to, *p;
3089         gboolean in_escape = FALSE;
3090
3091         if (!iconv_ok) return g_strdup(from);
3092
3093         if (cd == (iconv_t)-1) {
3094                 cd = iconv_open(CS_UTF_7, CS_INTERNAL);
3095                 if (cd == (iconv_t)-1) {
3096                         g_warning(_("iconv cannot convert %s to UTF-7\n"),
3097                                   CS_INTERNAL);
3098                         iconv_ok = FALSE;
3099                         return g_strdup(from);
3100                 }
3101         }
3102
3103         /* UTF-8 to normal UTF-7 conversion */
3104         Xstrdup_a(from_tmp, from, return g_strdup(from));
3105         from_len = strlen(from);
3106         norm_utf7_len = from_len * 5;
3107         Xalloca(norm_utf7, norm_utf7_len + 1, return g_strdup(from));
3108         norm_utf7_p = norm_utf7;
3109
3110 #define IS_PRINT(ch) (isprint(ch) && IS_ASCII(ch))
3111
3112         while (from_len > 0) {
3113                 if (*from_tmp == '+') {
3114                         *norm_utf7_p++ = '+';
3115                         *norm_utf7_p++ = '-';
3116                         norm_utf7_len -= 2;
3117                         from_tmp++;
3118                         from_len--;
3119                 } else if (IS_PRINT(*(guchar *)from_tmp)) {
3120                         /* printable ascii char */
3121                         *norm_utf7_p = *from_tmp;
3122                         norm_utf7_p++;
3123                         norm_utf7_len--;
3124                         from_tmp++;
3125                         from_len--;
3126                 } else {
3127                         size_t conv_len = 0;
3128
3129                         /* unprintable char: convert to UTF-7 */
3130                         p = from_tmp;
3131                         while (!IS_PRINT(*(guchar *)p) && conv_len < from_len) {
3132                                 conv_len += g_utf8_skip[*(guchar *)p];
3133                                 p += g_utf8_skip[*(guchar *)p];
3134                         }
3135
3136                         from_len -= conv_len;
3137                         if (iconv(cd, (ICONV_CONST gchar **)&from_tmp,
3138                                   &conv_len,
3139                                   &norm_utf7_p, &norm_utf7_len) == -1) {
3140                                 g_warning(_("iconv cannot convert UTF-8 to UTF-7\n"));
3141                                 return g_strdup(from);
3142                         }
3143
3144                         /* second iconv() call for flushing */
3145                         iconv(cd, NULL, NULL, &norm_utf7_p, &norm_utf7_len);
3146                 }
3147         }
3148
3149 #undef IS_PRINT
3150
3151         *norm_utf7_p = '\0';
3152         to_str = g_string_new(NULL);
3153         for (p = norm_utf7; p < norm_utf7_p; p++) {
3154                 /* replace: '&' -> "&-",
3155                             '+' -> '&',
3156                             "+-" -> '+',
3157                             BASE64 '/' -> ',' */
3158                 if (!in_escape && *p == '&') {
3159                         g_string_append(to_str, "&-");
3160                 } else if (!in_escape && *p == '+') {
3161                         if (*(p + 1) == '-') {
3162                                 g_string_append_c(to_str, '+');
3163                                 p++;
3164                         } else {
3165                                 g_string_append_c(to_str, '&');
3166                                 in_escape = TRUE;
3167                         }
3168                 } else if (in_escape && *p == '/') {
3169                         g_string_append_c(to_str, ',');
3170                 } else if (in_escape && *p == '-') {
3171                         g_string_append_c(to_str, '-');
3172                         in_escape = FALSE;
3173                 } else {
3174                         g_string_append_c(to_str, *p);
3175                 }
3176         }
3177
3178         if (in_escape) {
3179                 in_escape = FALSE;
3180                 g_string_append_c(to_str, '-');
3181         }
3182
3183         to = to_str->str;
3184         g_string_free(to_str, FALSE);
3185
3186         return to;
3187 }
3188
3189 static gboolean imap_rename_folder_func(GNode *node, gpointer data)
3190 {
3191         FolderItem *item = node->data;
3192         gchar **paths = data;
3193         const gchar *oldpath = paths[0];
3194         const gchar *newpath = paths[1];
3195         gchar *base;
3196         gchar *new_itempath;
3197         gint oldpathlen;
3198
3199         oldpathlen = strlen(oldpath);
3200         if (strncmp(oldpath, item->path, oldpathlen) != 0) {
3201                 g_warning("path doesn't match: %s, %s\n", oldpath, item->path);
3202                 return TRUE;
3203         }
3204
3205         base = item->path + oldpathlen;
3206         while (*base == G_DIR_SEPARATOR) base++;
3207         if (*base == '\0')
3208                 new_itempath = g_strdup(newpath);
3209         else
3210                 new_itempath = g_strconcat(newpath, G_DIR_SEPARATOR_S, base,
3211                                            NULL);
3212         g_free(item->path);
3213         item->path = new_itempath;
3214
3215         return FALSE;
3216 }
3217
3218 typedef struct _get_list_uid_data {
3219         Folder *folder;
3220         IMAPSession *session;
3221         IMAPFolderItem *item;
3222         GSList **msgnum_list;
3223         gboolean done;
3224 } get_list_uid_data;
3225
3226 static void *get_list_of_uids_thread(void *data)
3227 {
3228         get_list_uid_data *stuff = (get_list_uid_data *)data;
3229         Folder *folder = stuff->folder;
3230         IMAPFolderItem *item = stuff->item;
3231         GSList **msgnum_list = stuff->msgnum_list;
3232         gint ok, nummsgs = 0, lastuid_old;
3233         IMAPSession *session;
3234         GSList *uidlist, *elem;
3235         clist * lep_uidlist;
3236         int r;
3237
3238         session = stuff->session;
3239         if (session == NULL) {
3240                 stuff->done = TRUE;
3241                 return GINT_TO_POINTER(-1);
3242         }
3243         /* no session locking here, it's already locked by caller */
3244         ok = imap_select(session, IMAP_FOLDER(folder), item->item.path,
3245                          NULL, NULL, NULL, NULL, TRUE);
3246         if (ok != IMAP_SUCCESS) {
3247                 stuff->done = TRUE;
3248                 return GINT_TO_POINTER(-1);
3249         }
3250
3251         uidlist = NULL;
3252         
3253         r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SIMPLE, NULL,
3254                                  &lep_uidlist);
3255         
3256         if (r == MAILIMAP_NO_ERROR) {
3257                 GSList * fetchuid_list;
3258                 
3259                 fetchuid_list =
3260                         imap_uid_list_from_lep(lep_uidlist);
3261                 mailimap_search_result_free(lep_uidlist);
3262                 
3263                 uidlist = g_slist_concat(fetchuid_list, uidlist);
3264         }
3265         else {
3266                 GSList * fetchuid_list;
3267                 carray * lep_uidtab;
3268                 
3269                 r = imap_threaded_fetch_uid(folder, item->lastuid + 1,
3270                                             &lep_uidtab);
3271                 if (r == MAILIMAP_NO_ERROR) {
3272                         fetchuid_list =
3273                                 imap_uid_list_from_lep_tab(lep_uidtab);
3274                         imap_fetch_uid_list_free(lep_uidtab);
3275                         uidlist = g_slist_concat(fetchuid_list, uidlist);
3276                 }
3277         }
3278         
3279         lastuid_old = item->lastuid;
3280         *msgnum_list = g_slist_copy(item->uid_list);
3281         nummsgs = g_slist_length(*msgnum_list);
3282         debug_print("Got %d uids from cache\n", g_slist_length(item->uid_list));
3283
3284         for (elem = uidlist; elem != NULL; elem = g_slist_next(elem)) {
3285                 guint msgnum;
3286
3287                 msgnum = GPOINTER_TO_INT(elem->data);
3288                 if (msgnum > lastuid_old) {
3289                         *msgnum_list = g_slist_prepend(*msgnum_list, GINT_TO_POINTER(msgnum));
3290                         item->uid_list = g_slist_prepend(item->uid_list, GINT_TO_POINTER(msgnum));
3291                         nummsgs++;
3292
3293                         if(msgnum > item->lastuid)
3294                                 item->lastuid = msgnum;
3295                 }
3296         }
3297         g_slist_free(uidlist);
3298         stuff->done = TRUE;
3299         return GINT_TO_POINTER(nummsgs);
3300 }
3301
3302 static gint get_list_of_uids(IMAPSession *session, Folder *folder, IMAPFolderItem *item, GSList **msgnum_list)
3303 {
3304         gint result;
3305         get_list_uid_data *data = g_new0(get_list_uid_data, 1);
3306         data->done = FALSE;
3307         data->folder = folder;
3308         data->item = item;
3309         data->msgnum_list = msgnum_list;
3310         data->session = session;
3311         if (prefs_common.work_offline && 
3312             !inc_offline_should_override(
3313                 _("Claws Mail needs network access in order "
3314                   "to access the IMAP server."))) {
3315                 g_free(data);
3316                 return -1;
3317         }
3318
3319         result = GPOINTER_TO_INT(get_list_of_uids_thread(data));
3320         g_free(data);
3321         return result;
3322
3323 }
3324
3325 gint imap_get_num_list(Folder *folder, FolderItem *_item, GSList **msgnum_list, gboolean *old_uids_valid)
3326 {
3327         IMAPFolderItem *item = (IMAPFolderItem *)_item;
3328         IMAPSession *session;
3329         gint ok, nummsgs = 0, exists;
3330         guint32 uid_next = 0, uid_val = 0;
3331         GSList *uidlist = NULL;
3332         gchar *dir;
3333         gboolean selected_folder;
3334         debug_print("get_num_list\n");
3335         
3336         g_return_val_if_fail(folder != NULL, -1);
3337         g_return_val_if_fail(item != NULL, -1);
3338         g_return_val_if_fail(item->item.path != NULL, -1);
3339         g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, -1);
3340         g_return_val_if_fail(folder->account != NULL, -1);
3341
3342         debug_print("getting session...\n");
3343         session = imap_session_get(folder);
3344         g_return_val_if_fail(session != NULL, -1);
3345
3346         if (FOLDER_ITEM(item)->path) 
3347                 statusbar_print_all(_("Scanning folder %s%c%s ..."),
3348                                       FOLDER_ITEM(item)->folder->name, 
3349                                       G_DIR_SEPARATOR,
3350                                       FOLDER_ITEM(item)->path);
3351         else
3352                 statusbar_print_all(_("Scanning folder %s ..."),
3353                                       FOLDER_ITEM(item)->folder->name);
3354
3355         selected_folder = (session->mbox != NULL) &&
3356                           (!strcmp(session->mbox, item->item.path));
3357         if (selected_folder && time(NULL) - item->use_cache < 2) {
3358                 ok = imap_cmd_noop(session);
3359                 if (ok != IMAP_SUCCESS) {
3360                         debug_print("disconnected!\n");
3361                         session = imap_reconnect_if_possible(folder, session);
3362                         if (session == NULL) {
3363                                 statusbar_pop_all();
3364                                 unlock_session();
3365                                 return -1;
3366                         }
3367                 }
3368                 exists = session->exists;
3369
3370                 uid_next = item->c_uid_next;
3371                 uid_val = item->c_uid_validity;
3372                 *old_uids_valid = TRUE;
3373         } else {
3374                 if (item->use_cache && time(NULL) - item->use_cache < 2) {
3375                         exists = item->c_messages;
3376                         uid_next = item->c_uid_next;
3377                         uid_val = item->c_uid_validity;
3378                         ok = IMAP_SUCCESS;
3379                         debug_print("using cache %d %d %d\n", exists, uid_next, uid_val);
3380                 } else {
3381                         ok = imap_status(session, IMAP_FOLDER(folder), item->item.path, item,
3382                                  &exists, &uid_next, &uid_val, NULL, FALSE);
3383                 }
3384                 item->item.last_num = uid_next - 1;
3385                 
3386                 item->use_cache = (time_t)0;
3387                 if (ok != IMAP_SUCCESS) {
3388                         statusbar_pop_all();
3389                         unlock_session();
3390                         return -1;
3391                 }
3392                 if(item->item.mtime == uid_val)
3393                         *old_uids_valid = TRUE;
3394                 else {
3395                         *old_uids_valid = FALSE;
3396
3397                         debug_print("Freeing imap uid cache (%d != %d)\n",
3398                                         (int)item->item.mtime, uid_val);
3399                         item->lastuid = 0;
3400                         g_slist_free(item->uid_list);
3401                         item->uid_list = NULL;
3402                 
3403                         item->item.mtime = uid_val;
3404
3405                         imap_delete_all_cached_messages((FolderItem *)item);
3406                 }
3407         }
3408