Statistics
| Revision:

root / src / imap.c @ 521

History | View | Annotate | Download (97.7 kB)

1 1 hiro
/*
2 1 hiro
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 41 hiro
 * Copyright (C) 1999-2005 Hiroyuki Yamamoto
4 1 hiro
 *
5 1 hiro
 * This program is free software; you can redistribute it and/or modify
6 1 hiro
 * it under the terms of the GNU General Public License as published by
7 1 hiro
 * the Free Software Foundation; either version 2 of the License, or
8 1 hiro
 * (at your option) any later version.
9 1 hiro
 *
10 1 hiro
 * This program is distributed in the hope that it will be useful,
11 1 hiro
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 1 hiro
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 1 hiro
 * GNU General Public License for more details.
14 1 hiro
 *
15 1 hiro
 * You should have received a copy of the GNU General Public License
16 1 hiro
 * along with this program; if not, write to the Free Software
17 1 hiro
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 1 hiro
 */
19 1 hiro
20 1 hiro
#ifdef HAVE_CONFIG_H
21 1 hiro
#  include "config.h"
22 1 hiro
#endif
23 1 hiro
24 1 hiro
#include "defs.h"
25 1 hiro
26 1 hiro
#include <glib.h>
27 92 hiro
#include <glib/gi18n.h>
28 1 hiro
#include <stdio.h>
29 1 hiro
#include <string.h>
30 1 hiro
#include <stdlib.h>
31 1 hiro
#include <dirent.h>
32 1 hiro
#include <unistd.h>
33 1 hiro
#include <ctype.h>
34 1 hiro
#include <time.h>
35 1 hiro
#if HAVE_ICONV
36 1 hiro
#  include <iconv.h>
37 1 hiro
#endif
38 1 hiro
39 1 hiro
#include "imap.h"
40 1 hiro
#include "socket.h"
41 1 hiro
#include "ssl.h"
42 1 hiro
#include "recv.h"
43 1 hiro
#include "procmsg.h"
44 1 hiro
#include "procheader.h"
45 1 hiro
#include "folder.h"
46 1 hiro
#include "prefs_account.h"
47 1 hiro
#include "codeconv.h"
48 1 hiro
#include "md5.h"
49 1 hiro
#include "base64.h"
50 1 hiro
#include "utils.h"
51 1 hiro
#include "prefs_common.h"
52 1 hiro
#include "inputdialog.h"
53 1 hiro
54 1 hiro
#define IMAP4_PORT        143
55 1 hiro
#if USE_SSL
56 1 hiro
#define IMAPS_PORT        993
57 1 hiro
#endif
58 1 hiro
59 1 hiro
#define IMAP_CMD_LIMIT        1000
60 1 hiro
61 1 hiro
#define QUOTE_IF_REQUIRED(out, str)                                \
62 1 hiro
{                                                                \
63 1 hiro
        if (*str != '"' && strpbrk(str, " \t(){}%*") != NULL) {        \
64 1 hiro
                gchar *__tmp;                                        \
65 1 hiro
                gint len;                                        \
66 1 hiro
                                                                \
67 1 hiro
                len = strlen(str) + 3;                                \
68 1 hiro
                Xalloca(__tmp, len, return IMAP_ERROR);                \
69 1 hiro
                g_snprintf(__tmp, len, "\"%s\"", str);                \
70 1 hiro
                out = __tmp;                                        \
71 1 hiro
        } else {                                                \
72 1 hiro
                Xstrdup_a(out, str, return IMAP_ERROR);                \
73 1 hiro
        }                                                        \
74 1 hiro
}
75 1 hiro
76 1 hiro
static GList *session_list = NULL;
77 1 hiro
78 1 hiro
static void imap_folder_init                (Folder                *folder,
79 1 hiro
                                         const gchar        *name,
80 1 hiro
                                         const gchar        *path);
81 1 hiro
82 1 hiro
static Folder        *imap_folder_new        (const gchar        *name,
83 1 hiro
                                         const gchar        *path);
84 1 hiro
static void         imap_folder_destroy        (Folder                *folder);
85 1 hiro
86 1 hiro
static Session *imap_session_new        (PrefsAccount        *account);
87 292 hiro
static gint imap_session_connect        (IMAPSession        *session);
88 292 hiro
static gint imap_session_reconnect        (IMAPSession        *session);
89 1 hiro
static void imap_session_destroy        (Session        *session);
90 1 hiro
/* static void imap_session_destroy_all        (void); */
91 1 hiro
92 1 hiro
static gint imap_search_flags                (IMAPSession        *session,
93 1 hiro
                                         GArray               **uids,
94 1 hiro
                                         GHashTable    **flags_table);
95 1 hiro
static gint imap_fetch_flags                (IMAPSession        *session,
96 1 hiro
                                         GArray               **uids,
97 1 hiro
                                         GHashTable    **flags_table);
98 1 hiro
99 1 hiro
static GSList *imap_get_msg_list        (Folder                *folder,
100 1 hiro
                                         FolderItem        *item,
101 1 hiro
                                         gboolean         use_cache);
102 1 hiro
static gchar *imap_fetch_msg                (Folder                *folder,
103 1 hiro
                                         FolderItem        *item,
104 1 hiro
                                         gint                 uid);
105 1 hiro
static MsgInfo *imap_get_msginfo        (Folder                *folder,
106 1 hiro
                                         FolderItem        *item,
107 1 hiro
                                         gint                 uid);
108 1 hiro
static gint imap_add_msg                (Folder                *folder,
109 1 hiro
                                         FolderItem        *dest,
110 1 hiro
                                         const gchar        *file,
111 1 hiro
                                         MsgFlags        *flags,
112 1 hiro
                                         gboolean         remove_source);
113 1 hiro
static gint imap_add_msgs                (Folder                *folder,
114 1 hiro
                                         FolderItem        *dest,
115 1 hiro
                                         GSList                *file_list,
116 1 hiro
                                         gboolean         remove_source,
117 1 hiro
                                         gint                *first);
118 1 hiro
119 1 hiro
static gint imap_move_msg                (Folder                *folder,
120 1 hiro
                                         FolderItem        *dest,
121 1 hiro
                                         MsgInfo        *msginfo);
122 1 hiro
static gint imap_move_msgs                (Folder                *folder,
123 1 hiro
                                         FolderItem        *dest,
124 1 hiro
                                         GSList                *msglist);
125 1 hiro
static gint imap_copy_msg                (Folder                *folder,
126 1 hiro
                                         FolderItem        *dest,
127 1 hiro
                                         MsgInfo        *msginfo);
128 1 hiro
static gint imap_copy_msgs                (Folder                *folder,
129 1 hiro
                                         FolderItem        *dest,
130 1 hiro
                                         GSList                *msglist);
131 1 hiro
132 1 hiro
static gint imap_remove_msg                (Folder                *folder,
133 1 hiro
                                         FolderItem        *item,
134 1 hiro
                                         MsgInfo        *msginfo);
135 1 hiro
static gint imap_remove_msgs                (Folder                *folder,
136 1 hiro
                                         FolderItem        *item,
137 1 hiro
                                         GSList                *msglist);
138 1 hiro
static gint imap_remove_all_msg                (Folder                *folder,
139 1 hiro
                                         FolderItem        *item);
140 1 hiro
141 1 hiro
static gboolean imap_is_msg_changed        (Folder                *folder,
142 1 hiro
                                         FolderItem        *item,
143 1 hiro
                                         MsgInfo        *msginfo);
144 1 hiro
145 1 hiro
static gint imap_close                        (Folder                *folder,
146 1 hiro
                                         FolderItem        *item);
147 1 hiro
148 1 hiro
static gint imap_scan_folder                (Folder                *folder,
149 1 hiro
                                         FolderItem        *item);
150 1 hiro
static gint imap_scan_tree                (Folder                *folder);
151 1 hiro
152 1 hiro
static gint imap_create_tree                (Folder                *folder);
153 1 hiro
154 1 hiro
static FolderItem *imap_create_folder        (Folder                *folder,
155 1 hiro
                                         FolderItem        *parent,
156 1 hiro
                                         const gchar        *name);
157 1 hiro
static gint imap_rename_folder                (Folder                *folder,
158 1 hiro
                                         FolderItem        *item,
159 1 hiro
                                         const gchar        *name);
160 390 hiro
static gint imap_move_folder                (Folder                *folder,
161 390 hiro
                                         FolderItem        *item,
162 390 hiro
                                         FolderItem        *new_parent);
163 1 hiro
static gint imap_remove_folder                (Folder                *folder,
164 1 hiro
                                         FolderItem        *item);
165 1 hiro
166 1 hiro
static IMAPSession *imap_session_get        (Folder                *folder);
167 1 hiro
168 1 hiro
static gint imap_greeting                (IMAPSession        *session);
169 1 hiro
static gint imap_auth                        (IMAPSession        *session,
170 1 hiro
                                         const gchar        *user,
171 1 hiro
                                         const gchar        *pass,
172 1 hiro
                                         IMAPAuthType         type);
173 1 hiro
174 1 hiro
static gint imap_scan_tree_recursive        (IMAPSession        *session,
175 1 hiro
                                         FolderItem        *item);
176 1 hiro
static GSList *imap_parse_list                (IMAPSession        *session,
177 1 hiro
                                         const gchar        *real_path,
178 1 hiro
                                         gchar                *separator);
179 1 hiro
180 1 hiro
static void imap_create_missing_folders        (Folder                        *folder);
181 1 hiro
static FolderItem *imap_create_special_folder
182 1 hiro
                                        (Folder                        *folder,
183 1 hiro
                                         SpecialFolderItemType         stype,
184 1 hiro
                                         const gchar                *name);
185 1 hiro
186 1 hiro
static gint imap_do_copy_msgs                (Folder                *folder,
187 1 hiro
                                         FolderItem        *dest,
188 1 hiro
                                         GSList                *msglist,
189 1 hiro
                                         gboolean         remove_source);
190 1 hiro
static gint imap_remove_msgs_by_seq_set        (Folder                *folder,
191 1 hiro
                                         FolderItem        *item,
192 1 hiro
                                         GSList                *seq_list);
193 1 hiro
194 1 hiro
static GSList *imap_get_uncached_messages        (IMAPSession        *session,
195 1 hiro
                                                 FolderItem        *item,
196 1 hiro
                                                 guint32         first_uid,
197 1 hiro
                                                 guint32         last_uid,
198 1 hiro
                                                 gboolean         update_count);
199 1 hiro
static void imap_delete_cached_message                (FolderItem        *item,
200 1 hiro
                                                 guint32         uid);
201 1 hiro
static GSList *imap_delete_cached_messages        (GSList                *mlist,
202 1 hiro
                                                 FolderItem        *item,
203 1 hiro
                                                 guint32         first_uid,
204 1 hiro
                                                 guint32         last_uid);
205 1 hiro
static void imap_delete_all_cached_messages        (FolderItem        *item);
206 1 hiro
207 1 hiro
#if USE_SSL
208 1 hiro
static SockInfo *imap_open                (const gchar        *server,
209 1 hiro
                                         gushort         port,
210 1 hiro
                                         SSLType         ssl_type);
211 1 hiro
#else
212 1 hiro
static SockInfo *imap_open                (const gchar        *server,
213 1 hiro
                                         gushort         port);
214 1 hiro
#endif
215 1 hiro
216 1 hiro
static gint imap_msg_list_change_perm_flags        (GSList                *msglist,
217 1 hiro
                                                 MsgPermFlags         flags,
218 1 hiro
                                                 gboolean         is_set);
219 1 hiro
static gchar *imap_get_flag_str                        (IMAPFlags         flags);
220 1 hiro
static gint imap_set_message_flags                (IMAPSession        *session,
221 1 hiro
                                                 const gchar        *seq_set,
222 1 hiro
                                                 IMAPFlags         flags,
223 1 hiro
                                                 gboolean         is_set);
224 1 hiro
static gint imap_select                                (IMAPSession        *session,
225 1 hiro
                                                 IMAPFolder        *folder,
226 1 hiro
                                                 const gchar        *path,
227 1 hiro
                                                 gint                *exists,
228 1 hiro
                                                 gint                *recent,
229 1 hiro
                                                 gint                *unseen,
230 1 hiro
                                                 guint32        *uid_validity);
231 1 hiro
static gint imap_status                                (IMAPSession        *session,
232 1 hiro
                                                 IMAPFolder        *folder,
233 1 hiro
                                                 const gchar        *path,
234 1 hiro
                                                 gint                *messages,
235 1 hiro
                                                 gint                *recent,
236 1 hiro
                                                 guint32        *uid_next,
237 1 hiro
                                                 guint32        *uid_validity,
238 1 hiro
                                                 gint                *unseen);
239 1 hiro
240 1 hiro
static void imap_parse_namespace                (IMAPSession        *session,
241 1 hiro
                                                 IMAPFolder        *folder);
242 1 hiro
static void imap_get_namespace_by_list                (IMAPSession        *session,
243 1 hiro
                                                 IMAPFolder        *folder);
244 1 hiro
static IMAPNameSpace *imap_find_namespace        (IMAPFolder        *folder,
245 1 hiro
                                                 const gchar        *path);
246 1 hiro
static gchar imap_get_path_separator                (IMAPFolder        *folder,
247 1 hiro
                                                 const gchar        *path);
248 1 hiro
static gchar *imap_get_real_path                (IMAPFolder        *folder,
249 1 hiro
                                                 const gchar        *path);
250 1 hiro
251 1 hiro
static gchar *imap_parse_atom                (IMAPSession        *session,
252 1 hiro
                                         gchar                *src,
253 1 hiro
                                         gchar                *dest,
254 1 hiro
                                         gint                 dest_len,
255 1 hiro
                                         GString        *str);
256 1 hiro
static MsgFlags imap_parse_flags        (const gchar        *flag_str);
257 1 hiro
static IMAPFlags imap_parse_imap_flags        (const gchar        *flag_str);
258 1 hiro
static MsgInfo *imap_parse_envelope        (IMAPSession        *session,
259 1 hiro
                                         FolderItem        *item,
260 1 hiro
                                         GString        *line_str);
261 1 hiro
262 1 hiro
static gboolean imap_has_capability        (IMAPSession        *session,
263 1 hiro
                                         const gchar        *capability);
264 1 hiro
static void imap_capability_free        (IMAPSession        *session);
265 1 hiro
266 1 hiro
/* low-level IMAP4rev1 commands */
267 1 hiro
static gint imap_cmd_capability        (IMAPSession        *session);
268 1 hiro
static gint imap_cmd_authenticate
269 1 hiro
                                (IMAPSession        *session,
270 1 hiro
                                 const gchar        *user,
271 1 hiro
                                 const gchar        *pass,
272 1 hiro
                                 IMAPAuthType         type);
273 1 hiro
static gint imap_cmd_login        (IMAPSession        *session,
274 1 hiro
                                 const gchar        *user,
275 1 hiro
                                 const gchar        *pass);
276 1 hiro
static gint imap_cmd_logout        (IMAPSession        *session);
277 1 hiro
static gint imap_cmd_noop        (IMAPSession        *session);
278 1 hiro
#if USE_SSL
279 1 hiro
static gint imap_cmd_starttls        (IMAPSession        *session);
280 1 hiro
#endif
281 1 hiro
static gint imap_cmd_namespace        (IMAPSession        *session,
282 1 hiro
                                 gchar               **ns_str);
283 1 hiro
static gint imap_cmd_list        (IMAPSession        *session,
284 1 hiro
                                 const gchar        *ref,
285 1 hiro
                                 const gchar        *mailbox,
286 1 hiro
                                 GPtrArray        *argbuf);
287 1 hiro
static gint imap_cmd_do_select        (IMAPSession        *session,
288 1 hiro
                                 const gchar        *folder,
289 1 hiro
                                 gboolean         examine,
290 1 hiro
                                 gint                *exists,
291 1 hiro
                                 gint                *recent,
292 1 hiro
                                 gint                *unseen,
293 1 hiro
                                 guint32        *uid_validity);
294 1 hiro
static gint imap_cmd_select        (IMAPSession        *session,
295 1 hiro
                                 const gchar        *folder,
296 1 hiro
                                 gint                *exists,
297 1 hiro
                                 gint                *recent,
298 1 hiro
                                 gint                *unseen,
299 1 hiro
                                 guint32        *uid_validity);
300 1 hiro
static gint imap_cmd_examine        (IMAPSession        *session,
301 1 hiro
                                 const gchar        *folder,
302 1 hiro
                                 gint                *exists,
303 1 hiro
                                 gint                *recent,
304 1 hiro
                                 gint                *unseen,
305 1 hiro
                                 guint32        *uid_validity);
306 1 hiro
static gint imap_cmd_create        (IMAPSession        *session,
307 1 hiro
                                 const gchar        *folder);
308 1 hiro
static gint imap_cmd_rename        (IMAPSession        *session,
309 1 hiro
                                 const gchar        *oldfolder,
310 1 hiro
                                 const gchar        *newfolder);
311 1 hiro
static gint imap_cmd_delete        (IMAPSession        *session,
312 1 hiro
                                 const gchar        *folder);
313 1 hiro
static gint imap_cmd_envelope        (IMAPSession        *session,
314 1 hiro
                                 const gchar        *seq_set);
315 1 hiro
static gint imap_cmd_search        (IMAPSession        *session,
316 1 hiro
                                 const gchar        *criteria,
317 1 hiro
                                 GArray        **result);
318 1 hiro
static gint imap_cmd_fetch        (IMAPSession        *session,
319 1 hiro
                                 guint32         uid,
320 1 hiro
                                 const gchar        *filename);
321 1 hiro
static gint imap_cmd_append        (IMAPSession        *session,
322 1 hiro
                                 const gchar        *destfolder,
323 1 hiro
                                 const gchar        *file,
324 1 hiro
                                 IMAPFlags         flags,
325 1 hiro
                                 guint32        *new_uid);
326 1 hiro
static gint imap_cmd_copy        (IMAPSession        *session,
327 1 hiro
                                 const gchar        *seq_set,
328 1 hiro
                                 const gchar        *destfolder);
329 1 hiro
static gint imap_cmd_store        (IMAPSession        *session,
330 1 hiro
                                 const gchar        *seq_set,
331 1 hiro
                                 const gchar        *sub_cmd);
332 1 hiro
static gint imap_cmd_expunge        (IMAPSession        *session);
333 1 hiro
static gint imap_cmd_close        (IMAPSession        *session);
334 1 hiro
335 1 hiro
static gint imap_cmd_ok                (IMAPSession        *session,
336 1 hiro
                                 GPtrArray        *argbuf);
337 1 hiro
static void imap_cmd_gen_send        (IMAPSession        *session,
338 1 hiro
                                 const gchar        *format, ...);
339 1 hiro
static gint imap_cmd_gen_recv        (IMAPSession        *session,
340 1 hiro
                                 gchar               **ret);
341 1 hiro
342 1 hiro
/* misc utility functions */
343 1 hiro
static gchar *strchr_cpy                        (const gchar        *src,
344 1 hiro
                                                 gchar                 ch,
345 1 hiro
                                                 gchar                *dest,
346 1 hiro
                                                 gint                 len);
347 1 hiro
static gchar *get_quoted                        (const gchar        *src,
348 1 hiro
                                                 gchar                 ch,
349 1 hiro
                                                 gchar                *dest,
350 1 hiro
                                                 gint                 len);
351 1 hiro
static gchar *search_array_contain_str                (GPtrArray        *array,
352 1 hiro
                                                 gchar                *str);
353 1 hiro
static gchar *search_array_str                        (GPtrArray        *array,
354 1 hiro
                                                 gchar                *str);
355 1 hiro
static void imap_path_separator_subst                (gchar                *str,
356 1 hiro
                                                 gchar                 separator);
357 1 hiro
358 7 hiro
static gchar *imap_modified_utf7_to_utf8        (const gchar        *mutf7_str);
359 7 hiro
static gchar *imap_utf8_to_modified_utf7        (const gchar        *from);
360 1 hiro
361 1 hiro
static GSList *imap_get_seq_set_from_msglist        (GSList                *msglist);
362 1 hiro
static void imap_seq_set_free                        (GSList                *seq_list);
363 1 hiro
364 1 hiro
static GHashTable *imap_get_uid_table                (GArray                *array);
365 1 hiro
366 1 hiro
static gboolean imap_rename_folder_func                (GNode                *node,
367 1 hiro
                                                 gpointer         data);
368 1 hiro
369 1 hiro
static FolderClass imap_class =
370 1 hiro
{
371 1 hiro
        F_IMAP,
372 1 hiro
373 1 hiro
        imap_folder_new,
374 1 hiro
        imap_folder_destroy,
375 1 hiro
376 1 hiro
        imap_scan_tree,
377 1 hiro
        imap_create_tree,
378 1 hiro
379 1 hiro
        imap_get_msg_list,
380 1 hiro
        imap_fetch_msg,
381 1 hiro
        imap_get_msginfo,
382 1 hiro
        imap_add_msg,
383 1 hiro
        imap_add_msgs,
384 1 hiro
        imap_move_msg,
385 1 hiro
        imap_move_msgs,
386 1 hiro
        imap_copy_msg,
387 1 hiro
        imap_copy_msgs,
388 1 hiro
        imap_remove_msg,
389 1 hiro
        imap_remove_msgs,
390 1 hiro
        imap_remove_all_msg,
391 1 hiro
        imap_is_msg_changed,
392 1 hiro
        imap_close,
393 1 hiro
        imap_scan_folder,
394 1 hiro
395 1 hiro
        imap_create_folder,
396 1 hiro
        imap_rename_folder,
397 390 hiro
        imap_move_folder,
398 1 hiro
        imap_remove_folder
399 1 hiro
};
400 1 hiro
401 1 hiro
402 1 hiro
FolderClass *imap_get_class(void)
403 1 hiro
{
404 1 hiro
        return &imap_class;
405 1 hiro
}
406 1 hiro
407 1 hiro
static Folder *imap_folder_new(const gchar *name, const gchar *path)
408 1 hiro
{
409 1 hiro
        Folder *folder;
410 1 hiro
411 1 hiro
        folder = (Folder *)g_new0(IMAPFolder, 1);
412 1 hiro
        imap_folder_init(folder, name, path);
413 1 hiro
414 1 hiro
        return folder;
415 1 hiro
}
416 1 hiro
417 1 hiro
static void imap_folder_destroy(Folder *folder)
418 1 hiro
{
419 1 hiro
        gchar *dir;
420 1 hiro
421 1 hiro
        dir = folder_get_path(folder);
422 1 hiro
        if (is_dir_exist(dir))
423 1 hiro
                remove_dir_recursive(dir);
424 1 hiro
        g_free(dir);
425 1 hiro
426 1 hiro
        folder_remote_folder_destroy(REMOTE_FOLDER(folder));
427 1 hiro
}
428 1 hiro
429 1 hiro
static void imap_folder_init(Folder *folder, const gchar *name,
430 1 hiro
                             const gchar *path)
431 1 hiro
{
432 1 hiro
        folder->klass = imap_get_class();
433 1 hiro
        folder_remote_folder_init(folder, name, path);
434 1 hiro
}
435 1 hiro
436 1 hiro
static IMAPSession *imap_session_get(Folder *folder)
437 1 hiro
{
438 1 hiro
        RemoteFolder *rfolder = REMOTE_FOLDER(folder);
439 1 hiro
440 1 hiro
        g_return_val_if_fail(folder != NULL, NULL);
441 1 hiro
        g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, NULL);
442 1 hiro
        g_return_val_if_fail(folder->account != NULL, NULL);
443 1 hiro
444 1 hiro
        if (!prefs_common.online_mode)
445 1 hiro
                return NULL;
446 1 hiro
447 1 hiro
        if (!rfolder->session) {
448 1 hiro
                rfolder->session = imap_session_new(folder->account);
449 1 hiro
                if (rfolder->session)
450 1 hiro
                        imap_parse_namespace(IMAP_SESSION(rfolder->session),
451 1 hiro
                                             IMAP_FOLDER(folder));
452 1 hiro
                return IMAP_SESSION(rfolder->session);
453 1 hiro
        }
454 1 hiro
455 1 hiro
        if (time(NULL) - rfolder->session->last_access_time <
456 1 hiro
                SESSION_TIMEOUT_INTERVAL) {
457 1 hiro
                return IMAP_SESSION(rfolder->session);
458 1 hiro
        }
459 1 hiro
460 1 hiro
        if (imap_cmd_noop(IMAP_SESSION(rfolder->session)) != IMAP_SUCCESS) {
461 1 hiro
                log_warning(_("IMAP4 connection to %s has been"
462 1 hiro
                              " disconnected. Reconnecting...\n"),
463 1 hiro
                            folder->account->recv_server);
464 292 hiro
                if (imap_session_reconnect(IMAP_SESSION(rfolder->session))
465 292 hiro
                    == IMAP_SUCCESS)
466 1 hiro
                        imap_parse_namespace(IMAP_SESSION(rfolder->session),
467 1 hiro
                                             IMAP_FOLDER(folder));
468 292 hiro
                else {
469 292 hiro
                        session_destroy(rfolder->session);
470 292 hiro
                        rfolder->session = NULL;
471 292 hiro
                }
472 1 hiro
        }
473 1 hiro
474 1 hiro
        return IMAP_SESSION(rfolder->session);
475 1 hiro
}
476 1 hiro
477 1 hiro
static gint imap_greeting(IMAPSession *session)
478 1 hiro
{
479 1 hiro
        gchar *greeting;
480 1 hiro
        gint ok;
481 1 hiro
482 1 hiro
        if ((ok = imap_cmd_gen_recv(session, &greeting)) != IMAP_SUCCESS)
483 1 hiro
                return ok;
484 1 hiro
485 1 hiro
        if (greeting[0] != '*' || greeting[1] != ' ')
486 1 hiro
                ok = IMAP_ERROR;
487 1 hiro
        else if (!strncmp(greeting + 2, "OK", 2))
488 1 hiro
                ok = IMAP_SUCCESS;
489 1 hiro
        else if (!strncmp(greeting + 2, "PREAUTH", 7)) {
490 1 hiro
                session->authenticated = TRUE;
491 1 hiro
                ok = IMAP_SUCCESS;
492 1 hiro
        } else
493 1 hiro
                ok = IMAP_ERROR;
494 1 hiro
495 1 hiro
        g_free(greeting);
496 1 hiro
        return ok;
497 1 hiro
}
498 1 hiro
499 1 hiro
static gint imap_auth(IMAPSession *session, const gchar *user,
500 1 hiro
                      const gchar *pass, IMAPAuthType type)
501 1 hiro
{
502 231 hiro
        gboolean nologin;
503 231 hiro
        gint ok = IMAP_AUTHFAIL;
504 1 hiro
505 231 hiro
        nologin = imap_has_capability(session, "LOGINDISABLED");
506 231 hiro
507 231 hiro
        switch (type) {
508 231 hiro
        case 0:
509 231 hiro
                if (imap_has_capability(session, "AUTH=CRAM-MD5"))
510 231 hiro
                        ok = imap_cmd_authenticate(session, user, pass, type);
511 231 hiro
                else if (nologin)
512 231 hiro
                        log_print(_("IMAP4 server disables LOGIN.\n"));
513 231 hiro
                else
514 231 hiro
                        ok = imap_cmd_login(session, user, pass);
515 231 hiro
                break;
516 231 hiro
        case IMAP_AUTH_LOGIN:
517 231 hiro
                if (nologin)
518 231 hiro
                        log_warning(_("IMAP4 server disables LOGIN.\n"));
519 231 hiro
                else
520 231 hiro
                        ok = imap_cmd_login(session, user, pass);
521 231 hiro
                break;
522 231 hiro
        case IMAP_AUTH_CRAM_MD5:
523 1 hiro
                ok = imap_cmd_authenticate(session, user, pass, type);
524 231 hiro
                break;
525 231 hiro
        default:
526 231 hiro
                break;
527 231 hiro
        }
528 1 hiro
529 1 hiro
        if (ok == IMAP_SUCCESS)
530 1 hiro
                session->authenticated = TRUE;
531 1 hiro
532 1 hiro
        return ok;
533 1 hiro
}
534 1 hiro
535 1 hiro
static Session *imap_session_new(PrefsAccount *account)
536 1 hiro
{
537 1 hiro
        IMAPSession *session;
538 1 hiro
        gushort port;
539 1 hiro
540 1 hiro
        g_return_val_if_fail(account != NULL, NULL);
541 1 hiro
        g_return_val_if_fail(account->recv_server != NULL, NULL);
542 1 hiro
        g_return_val_if_fail(account->userid != NULL, NULL);
543 1 hiro
544 1 hiro
#if USE_SSL
545 1 hiro
        port = account->set_imapport ? account->imapport
546 1 hiro
                : account->ssl_imap == SSL_TUNNEL ? IMAPS_PORT : IMAP4_PORT;
547 1 hiro
#else
548 1 hiro
        port = account->set_imapport ? account->imapport : IMAP4_PORT;
549 1 hiro
#endif
550 1 hiro
551 1 hiro
        session = g_new0(IMAPSession, 1);
552 1 hiro
553 1 hiro
        session_init(SESSION(session));
554 1 hiro
555 1 hiro
        SESSION(session)->type             = SESSION_IMAP;
556 292 hiro
        SESSION(session)->sock             = NULL;
557 1 hiro
        SESSION(session)->server           = g_strdup(account->recv_server);
558 292 hiro
        SESSION(session)->port             = port;
559 292 hiro
#if USE_SSL
560 292 hiro
        SESSION(session)->ssl_type         = account->ssl_imap;
561 292 hiro
#endif
562 1 hiro
        SESSION(session)->last_access_time = time(NULL);
563 292 hiro
        SESSION(session)->data             = account;
564 1 hiro
565 1 hiro
        SESSION(session)->destroy          = imap_session_destroy;
566 1 hiro
567 1 hiro
        session->authenticated = FALSE;
568 334 hiro
        session->capability    = NULL;
569 334 hiro
        session->uidplus       = FALSE;
570 334 hiro
        session->mbox          = NULL;
571 334 hiro
        session->cmd_count     = 0;
572 1 hiro
573 1 hiro
        session_list = g_list_append(session_list, session);
574 1 hiro
575 292 hiro
        if (imap_session_connect(session) != IMAP_SUCCESS) {
576 1 hiro
                session_destroy(SESSION(session));
577 1 hiro
                return NULL;
578 1 hiro
        }
579 1 hiro
580 292 hiro
        return SESSION(session);
581 292 hiro
}
582 292 hiro
583 292 hiro
static gint imap_session_connect(IMAPSession *session)
584 292 hiro
{
585 292 hiro
        SockInfo *sock;
586 292 hiro
        PrefsAccount *account;
587 292 hiro
        gchar *pass;
588 292 hiro
589 292 hiro
        g_return_val_if_fail(session != NULL, IMAP_ERROR);
590 292 hiro
591 292 hiro
        account = (PrefsAccount *)(SESSION(session)->data);
592 292 hiro
593 292 hiro
        log_message(_("creating IMAP4 connection to %s:%d ...\n"),
594 292 hiro
                    SESSION(session)->server, SESSION(session)->port);
595 292 hiro
596 292 hiro
        pass = account->passwd;
597 292 hiro
        if (!pass) {
598 292 hiro
                gchar *tmp_pass;
599 292 hiro
                tmp_pass = input_dialog_query_password(account->recv_server,
600 292 hiro
                                                       account->userid);
601 292 hiro
                if (!tmp_pass)
602 292 hiro
                        return IMAP_ERROR;
603 292 hiro
                Xstrdup_a(pass, tmp_pass,
604 292 hiro
                          {g_free(tmp_pass); return IMAP_ERROR;});
605 292 hiro
                g_free(tmp_pass);
606 1 hiro
        }
607 292 hiro
608 292 hiro
#if USE_SSL
609 292 hiro
        if ((sock = imap_open(SESSION(session)->server, SESSION(session)->port,
610 292 hiro
                              SESSION(session)->ssl_type)) == NULL)
611 292 hiro
#else
612 292 hiro
        if ((sock = imap_open(SESSION(session)->server, SESSION(session)->port))
613 292 hiro
            == NULL)
614 292 hiro
#endif
615 292 hiro
                return IMAP_ERROR;
616 292 hiro
617 292 hiro
        SESSION(session)->sock = sock;
618 292 hiro
619 292 hiro
        if (imap_greeting(session) != IMAP_SUCCESS)
620 292 hiro
                return IMAP_ERROR;
621 292 hiro
        if (imap_cmd_capability(session) != IMAP_SUCCESS)
622 292 hiro
                return IMAP_ERROR;
623 292 hiro
624 1 hiro
        if (imap_has_capability(session, "UIDPLUS"))
625 1 hiro
                session->uidplus = TRUE;
626 1 hiro
627 1 hiro
#if USE_SSL
628 1 hiro
        if (account->ssl_imap == SSL_STARTTLS &&
629 1 hiro
            imap_has_capability(session, "STARTTLS")) {
630 1 hiro
                gint ok;
631 1 hiro
632 1 hiro
                ok = imap_cmd_starttls(session);
633 1 hiro
                if (ok != IMAP_SUCCESS) {
634 1 hiro
                        log_warning(_("Can't start TLS session.\n"));
635 292 hiro
                        return IMAP_ERROR;
636 1 hiro
                }
637 292 hiro
                if (!ssl_init_socket_with_method(sock, SSL_METHOD_TLSv1))
638 292 hiro
                        return IMAP_SOCKET;
639 334 hiro
640 334 hiro
                /* capability can be changed after STARTTLS */
641 334 hiro
                if (imap_cmd_capability(session) != IMAP_SUCCESS)
642 334 hiro
                        return IMAP_ERROR;
643 1 hiro
        }
644 1 hiro
#endif
645 1 hiro
646 1 hiro
        if (!session->authenticated &&
647 1 hiro
            imap_auth(session, account->userid, pass, account->imap_auth_type)
648 1 hiro
            != IMAP_SUCCESS) {
649 1 hiro
                imap_cmd_logout(session);
650 292 hiro
                return IMAP_AUTHFAIL;
651 1 hiro
        }
652 1 hiro
653 292 hiro
        return IMAP_SUCCESS;
654 1 hiro
}
655 1 hiro
656 292 hiro
static gint imap_session_reconnect(IMAPSession *session)
657 292 hiro
{
658 292 hiro
        g_return_val_if_fail(session != NULL, IMAP_ERROR);
659 292 hiro
660 292 hiro
        session_disconnect(SESSION(session));
661 292 hiro
662 292 hiro
        imap_capability_free(session);
663 292 hiro
        session->uidplus = FALSE;
664 292 hiro
        g_free(session->mbox);
665 292 hiro
        session->mbox = NULL;
666 292 hiro
        session->authenticated = FALSE;
667 292 hiro
        SESSION(session)->state = SESSION_READY;
668 292 hiro
669 292 hiro
        return imap_session_connect(session);
670 292 hiro
}
671 292 hiro
672 1 hiro
static void imap_session_destroy(Session *session)
673 1 hiro
{
674 1 hiro
        imap_capability_free(IMAP_SESSION(session));
675 1 hiro
        g_free(IMAP_SESSION(session)->mbox);
676 1 hiro
        session_list = g_list_remove(session_list, session);
677 1 hiro
}
678 1 hiro
679 1 hiro
#if 0
680 1 hiro
static void imap_session_destroy_all(void)
681 1 hiro
{
682 1 hiro
        while (session_list != NULL) {
683 1 hiro
                IMAPSession *session = (IMAPSession *)session_list->data;
684 1 hiro
685 1 hiro
                imap_cmd_logout(session);
686 1 hiro
                session_destroy(SESSION(session));
687 1 hiro
        }
688 1 hiro
}
689 1 hiro
#endif
690 1 hiro
691 1 hiro
#define THROW goto catch
692 1 hiro
693 1 hiro
static gint imap_search_flags(IMAPSession *session, GArray **uids,
694 1 hiro
                              GHashTable **flags_table)
695 1 hiro
{
696 1 hiro
        gint ok;
697 1 hiro
        gint i;
698 1 hiro
        GArray *flag_uids;
699 1 hiro
        GHashTable *unseen_table;
700 1 hiro
        GHashTable *flagged_table;
701 1 hiro
        GHashTable *answered_table;
702 1 hiro
        guint32 uid;
703 1 hiro
        IMAPFlags flags;
704 1 hiro
705 1 hiro
        ok = imap_cmd_search(session, "ALL", uids);
706 1 hiro
        if (ok != IMAP_SUCCESS) return ok;
707 1 hiro
708 1 hiro
        ok = imap_cmd_search(session, "UNSEEN", &flag_uids);
709 1 hiro
        if (ok != IMAP_SUCCESS) {
710 1 hiro
                g_array_free(*uids, TRUE);
711 1 hiro
                return ok;
712 1 hiro
        }
713 1 hiro
        unseen_table = imap_get_uid_table(flag_uids);
714 1 hiro
        g_array_free(flag_uids, TRUE);
715 1 hiro
        ok = imap_cmd_search(session, "FLAGGED", &flag_uids);
716 1 hiro
        if (ok != IMAP_SUCCESS) {
717 1 hiro
                g_hash_table_destroy(unseen_table);
718 1 hiro
                g_array_free(*uids, TRUE);
719 1 hiro
                return ok;
720 1 hiro
        }
721 1 hiro
        flagged_table = imap_get_uid_table(flag_uids);
722 1 hiro
        g_array_free(flag_uids, TRUE);
723 1 hiro
        ok = imap_cmd_search(session, "ANSWERED", &flag_uids);
724 1 hiro
        if (ok != IMAP_SUCCESS) {
725 1 hiro
                g_hash_table_destroy(flagged_table);
726 1 hiro
                g_hash_table_destroy(unseen_table);
727 1 hiro
                g_array_free(*uids, TRUE);
728 1 hiro
                return ok;
729 1 hiro
        }
730 1 hiro
        answered_table = imap_get_uid_table(flag_uids);
731 1 hiro
        g_array_free(flag_uids, TRUE);
732 1 hiro
733 1 hiro
        *flags_table = g_hash_table_new(NULL, g_direct_equal);
734 1 hiro
735 1 hiro
        for (i = 0; i < (*uids)->len; i++) {
736 1 hiro
                uid = g_array_index(*uids, guint32, i);
737 1 hiro
                flags = IMAP_FLAG_DRAFT;
738 1 hiro
                if (!g_hash_table_lookup(unseen_table, GUINT_TO_POINTER(uid)))
739 1 hiro
                        flags |= IMAP_FLAG_SEEN;
740 1 hiro
                if (g_hash_table_lookup(flagged_table, GUINT_TO_POINTER(uid)))
741 1 hiro
                        flags |= IMAP_FLAG_FLAGGED;
742 1 hiro
                if (g_hash_table_lookup(answered_table, GUINT_TO_POINTER(uid)))
743 1 hiro
                        flags |= IMAP_FLAG_ANSWERED;
744 1 hiro
                g_hash_table_insert(*flags_table, GUINT_TO_POINTER(uid),
745 1 hiro
                                    GINT_TO_POINTER(flags));
746 1 hiro
        }
747 1 hiro
748 1 hiro
        g_hash_table_destroy(answered_table);
749 1 hiro
        g_hash_table_destroy(flagged_table);
750 1 hiro
        g_hash_table_destroy(unseen_table);
751 1 hiro
752 1 hiro
        return IMAP_SUCCESS;
753 1 hiro
}
754 1 hiro
755 1 hiro
static gint imap_fetch_flags(IMAPSession *session, GArray **uids,
756 1 hiro
                             GHashTable **flags_table)
757 1 hiro
{
758 1 hiro
        gint ok;
759 1 hiro
        gchar *tmp;
760 1 hiro
        gchar *cur_pos;
761 1 hiro
        gchar buf[IMAPBUFSIZE];
762 1 hiro
        guint32 uid;
763 1 hiro
        IMAPFlags flags;
764 1 hiro
765 1 hiro
        imap_cmd_gen_send(session, "UID FETCH 1:* (UID FLAGS)");
766 1 hiro
767 1 hiro
        *uids = g_array_new(FALSE, FALSE, sizeof(guint32));
768 1 hiro
        *flags_table = g_hash_table_new(NULL, g_direct_equal);
769 1 hiro
770 1 hiro
        while ((ok = imap_cmd_gen_recv(session, &tmp)) == IMAP_SUCCESS) {
771 1 hiro
                if (tmp[0] != '*' || tmp[1] != ' ') {
772 1 hiro
                        g_free(tmp);
773 1 hiro
                        break;
774 1 hiro
                }
775 1 hiro
                cur_pos = tmp + 2;
776 1 hiro
777 1 hiro
#define PARSE_ONE_ELEMENT(ch)                                        \
778 1 hiro
{                                                                \
779 1 hiro
        cur_pos = strchr_cpy(cur_pos, ch, buf, sizeof(buf));        \
780 1 hiro
        if (cur_pos == NULL) {                                        \
781 1 hiro
                g_warning("cur_pos == NULL\n");                        \
782 1 hiro
                g_free(tmp);                                        \
783 1 hiro
                g_hash_table_destroy(*flags_table);                \
784 1 hiro
                g_array_free(*uids, TRUE);                        \
785 1 hiro
                return IMAP_ERROR;                                \
786 1 hiro
        }                                                        \
787 1 hiro
}
788 1 hiro
789 1 hiro
                PARSE_ONE_ELEMENT(' ');
790 1 hiro
                PARSE_ONE_ELEMENT(' ');
791 1 hiro
                if (strcmp(buf, "FETCH") != 0) {
792 1 hiro
                        g_free(tmp);
793 1 hiro
                        continue;
794 1 hiro
                }
795 1 hiro
                if (*cur_pos != '(') {
796 1 hiro
                        g_free(tmp);
797 1 hiro
                        continue;
798 1 hiro
                }
799 1 hiro
                cur_pos++;
800 1 hiro
                uid = 0;
801 1 hiro
                flags = 0;
802 1 hiro
803 1 hiro
                while (*cur_pos != '\0' && *cur_pos != ')') {
804 1 hiro
                        while (*cur_pos == ' ') cur_pos++;
805 1 hiro
806 1 hiro
                        if (!strncmp(cur_pos, "UID ", 4)) {
807 1 hiro
                                cur_pos += 4;
808 1 hiro
                                uid = strtoul(cur_pos, &cur_pos, 10);
809 1 hiro
                        } else if (!strncmp(cur_pos, "FLAGS ", 6)) {
810 1 hiro
                                cur_pos += 6;
811 1 hiro
                                if (*cur_pos != '(') {
812 1 hiro
                                        g_warning("*cur_pos != '('\n");
813 1 hiro
                                        break;
814 1 hiro
                                }
815 1 hiro
                                cur_pos++;
816 1 hiro
                                PARSE_ONE_ELEMENT(')');
817 1 hiro
                                flags = imap_parse_imap_flags(buf);
818 1 hiro
                                flags |= IMAP_FLAG_DRAFT;
819 1 hiro
                        } else {
820 1 hiro
                                g_warning("invalid FETCH response: %s\n", cur_pos);
821 1 hiro
                                break;
822 1 hiro
                        }
823 1 hiro
                }
824 1 hiro
825 1 hiro
#undef PARSE_ONE_ELEMENT
826 1 hiro
827 1 hiro
                if (uid > 0) {
828 1 hiro
                        g_array_append_val(*uids, uid);
829 1 hiro
                        g_hash_table_insert(*flags_table, GUINT_TO_POINTER(uid),
830 1 hiro
                                            GINT_TO_POINTER(flags));
831 1 hiro
                }
832 1 hiro
833 1 hiro
                g_free(tmp);
834 1 hiro
        }
835 1 hiro
836 1 hiro
        if (ok != IMAP_SUCCESS) {
837 1 hiro
                g_hash_table_destroy(*flags_table);
838 1 hiro
                g_array_free(*uids, TRUE);
839 1 hiro
        }
840 1 hiro
841 1 hiro
        return ok;
842 1 hiro
}
843 1 hiro
844 1 hiro
static GSList *imap_get_msg_list(Folder *folder, FolderItem *item,
845 1 hiro
                                 gboolean use_cache)
846 1 hiro
{
847 1 hiro
        GSList *mlist = NULL;
848 1 hiro
        IMAPSession *session;
849 1 hiro
        gint ok, exists = 0, recent = 0, unseen = 0;
850 1 hiro
        guint32 uid_validity = 0;
851 1 hiro
        guint32 first_uid = 0, last_uid = 0;
852 1 hiro
853 1 hiro
        g_return_val_if_fail(folder != NULL, NULL);
854 1 hiro
        g_return_val_if_fail(item != NULL, NULL);
855 1 hiro
        g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, NULL);
856 1 hiro
        g_return_val_if_fail(folder->account != NULL, NULL);
857 1 hiro
858 1 hiro
        item->new = item->unread = item->total = 0;
859 1 hiro
860 1 hiro
        session = imap_session_get(folder);
861 1 hiro
862 1 hiro
        if (!session) {
863 1 hiro
                mlist = procmsg_read_cache(item, FALSE);
864 1 hiro
                item->last_num = procmsg_get_last_num_in_msg_list(mlist);
865 1 hiro
                procmsg_set_flags(mlist, item);
866 1 hiro
                return mlist;
867 1 hiro
        }
868 1 hiro
869 1 hiro
        ok = imap_select(session, IMAP_FOLDER(folder), item->path,
870 1 hiro
                         &exists, &recent, &unseen, &uid_validity);
871 1 hiro
        if (ok != IMAP_SUCCESS) THROW;
872 1 hiro
873 1 hiro
        if (exists == 0) {
874 1 hiro
                imap_delete_all_cached_messages(item);
875 1 hiro
                return NULL;
876 1 hiro
        }
877 1 hiro
878 1 hiro
        /* invalidate current cache if UIDVALIDITY has been changed */
879 1 hiro
        if (item->mtime != uid_validity) {
880 1 hiro
                debug_print("imap_get_msg_list: "
881 1 hiro
                            "UIDVALIDITY has been changed.\n");
882 1 hiro
                use_cache = FALSE;
883 1 hiro
        }
884 1 hiro
885 1 hiro
        if (use_cache) {
886 1 hiro
                GArray *uids;
887 1 hiro
                GHashTable *msg_table;
888 1 hiro
                GHashTable *flags_table;
889 1 hiro
                guint32 cache_last;
890 1 hiro
                guint32 begin = 0;
891 1 hiro
                GSList *cur, *next = NULL;
892 1 hiro
                MsgInfo *msginfo;
893 1 hiro
                IMAPFlags imap_flags;
894 1 hiro
895 1 hiro
                /* get cache data */
896 1 hiro
                mlist = procmsg_read_cache(item, FALSE);
897 1 hiro
                procmsg_set_flags(mlist, item);
898 1 hiro
                cache_last = procmsg_get_last_num_in_msg_list(mlist);
899 1 hiro
900 1 hiro
                /* get all UID list and flags */
901 1 hiro
                ok = imap_search_flags(session, &uids, &flags_table);
902 1 hiro
                if (ok != IMAP_SUCCESS) {
903 1 hiro
                        if (ok == IMAP_SOCKET || ok == IMAP_IOERR) THROW;
904 1 hiro
                        ok = imap_fetch_flags(session, &uids, &flags_table);
905 1 hiro
                        if (ok != IMAP_SUCCESS) THROW;
906 1 hiro
                }
907 1 hiro
908 1 hiro
                if (uids->len > 0) {
909 1 hiro
                        first_uid = g_array_index(uids, guint32, 0);
910 1 hiro
                        last_uid = g_array_index(uids, guint32, uids->len - 1);
911 1 hiro
                } else {
912 1 hiro
                        g_array_free(uids, TRUE);
913 1 hiro
                        g_hash_table_destroy(flags_table);
914 1 hiro
                        THROW;
915 1 hiro
                }
916 1 hiro
917 1 hiro
                /* sync message flags with server */
918 1 hiro
                for (cur = mlist; cur != NULL; cur = next) {
919 1 hiro
                        msginfo = (MsgInfo *)cur->data;
920 1 hiro
                        next = cur->next;
921 1 hiro
                        imap_flags = GPOINTER_TO_INT(g_hash_table_lookup
922 1 hiro
                                (flags_table,
923 1 hiro
                                 GUINT_TO_POINTER(msginfo->msgnum)));
924 1 hiro
925 1 hiro
                        if (imap_flags == 0) {
926 1 hiro
                                debug_print("imap_get_msg_list: "
927 1 hiro
                                            "message %u has been deleted.\n",
928 1 hiro
                                            msginfo->msgnum);
929 1 hiro
                                imap_delete_cached_message
930 1 hiro
                                        (item, msginfo->msgnum);
931 1 hiro
                                if (MSG_IS_NEW(msginfo->flags))
932 1 hiro
                                        item->new--;
933 1 hiro
                                if (MSG_IS_UNREAD(msginfo->flags))
934 1 hiro
                                        item->unread--;
935 1 hiro
                                item->total--;
936 1 hiro
                                mlist = g_slist_remove(mlist, msginfo);
937 1 hiro
                                procmsg_msginfo_free(msginfo);
938 285 hiro
                                item->cache_dirty = TRUE;
939 293 hiro
                                item->mark_dirty = TRUE;
940 1 hiro
                                continue;
941 1 hiro
                        }
942 1 hiro
943 1 hiro
                        if (!IMAP_IS_SEEN(imap_flags)) {
944 1 hiro
                                if (!MSG_IS_UNREAD(msginfo->flags)) {
945 1 hiro
                                        item->unread++;
946 1 hiro
                                        MSG_SET_PERM_FLAGS(msginfo->flags,
947 1 hiro
                                                           MSG_UNREAD);
948 293 hiro
                                        item->mark_dirty = TRUE;
949 1 hiro
                                }
950 1 hiro
                        } else {
951 293 hiro
                                if (MSG_IS_NEW(msginfo->flags)) {
952 1 hiro
                                        item->new--;
953 293 hiro
                                        item->mark_dirty = TRUE;
954 293 hiro
                                }
955 293 hiro
                                if (MSG_IS_UNREAD(msginfo->flags)) {
956 1 hiro
                                        item->unread--;
957 293 hiro
                                        item->mark_dirty = TRUE;
958 293 hiro
                                }
959 1 hiro
                                MSG_UNSET_PERM_FLAGS(msginfo->flags,
960 1 hiro
                                                     MSG_NEW|MSG_UNREAD);
961 1 hiro
                        }
962 1 hiro
963 1 hiro
                        if (IMAP_IS_FLAGGED(imap_flags)) {
964 293 hiro
                                if (!MSG_IS_MARKED(msginfo->flags)) {
965 293 hiro
                                        MSG_SET_PERM_FLAGS(msginfo->flags,
966 293 hiro
                                                           MSG_MARKED);
967 293 hiro
                                        item->mark_dirty = TRUE;
968 293 hiro
                                }
969 1 hiro
                        } else {
970 293 hiro
                                if (MSG_IS_MARKED(msginfo->flags)) {
971 293 hiro
                                        MSG_UNSET_PERM_FLAGS(msginfo->flags,
972 293 hiro
                                                             MSG_MARKED);
973 293 hiro
                                        item->mark_dirty = TRUE;
974 293 hiro
                                }
975 1 hiro
                        }
976 1 hiro
                        if (IMAP_IS_ANSWERED(imap_flags)) {
977 293 hiro
                                if (!MSG_IS_REPLIED(msginfo->flags)) {
978 293 hiro
                                        MSG_SET_PERM_FLAGS(msginfo->flags,
979 293 hiro
                                                           MSG_REPLIED);
980 293 hiro
                                        item->mark_dirty = TRUE;
981 293 hiro
                                }
982 1 hiro
                        } else {
983 293 hiro
                                if (MSG_IS_REPLIED(msginfo->flags)) {
984 293 hiro
                                        MSG_UNSET_PERM_FLAGS(msginfo->flags,
985 293 hiro
                                                             MSG_REPLIED);
986 293 hiro
                                        item->mark_dirty = TRUE;
987 293 hiro
                                }
988 1 hiro
                        }
989 1 hiro
                }
990 1 hiro
991 1 hiro
                /* check for the first new message */
992 1 hiro
                msg_table = procmsg_msg_hash_table_create(mlist);
993 1 hiro
                if (msg_table == NULL)
994 1 hiro
                        begin = first_uid;
995 1 hiro
                else {
996 1 hiro
                        gint i;
997 1 hiro
998 1 hiro
                        for (i = 0; i < uids->len; i++) {
999 1 hiro
                                guint32 uid;
1000 1 hiro
1001 1 hiro
                                uid = g_array_index(uids, guint32, i);
1002 1 hiro
                                if (g_hash_table_lookup
1003 1 hiro
                                        (msg_table, GUINT_TO_POINTER(uid))
1004 1 hiro
                                        == NULL) {
1005 1 hiro
                                        debug_print("imap_get_msg_list: "
1006 1 hiro
                                                    "first new UID: %u\n", uid);
1007 1 hiro
                                        begin = uid;
1008 1 hiro
                                        break;
1009 1 hiro
                                }
1010 1 hiro
                        }
1011 1 hiro
                        g_hash_table_destroy(msg_table);
1012 1 hiro
                }
1013 1 hiro
1014 1 hiro
                g_array_free(uids, TRUE);
1015 1 hiro
                g_hash_table_destroy(flags_table);
1016 1 hiro
1017 1 hiro
                /* remove ununsed caches */
1018 1 hiro
                if (first_uid > 0 && last_uid > 0) {
1019 1 hiro
                        mlist = imap_delete_cached_messages
1020 1 hiro
                                (mlist, item, 0, first_uid - 1);
1021 1 hiro
                        mlist = imap_delete_cached_messages
1022 1 hiro
                                (mlist, item, begin > 0 ? begin : last_uid + 1,
1023 1 hiro
                                 UINT_MAX);
1024 1 hiro
                }
1025 1 hiro
1026 1 hiro
                if (begin > 0 && begin <= last_uid) {
1027 1 hiro
                        GSList *newlist;
1028 1 hiro
                        newlist = imap_get_uncached_messages(session, item,
1029 1 hiro
                                                             begin, last_uid,
1030 1 hiro
                                                             TRUE);
1031 285 hiro
                        if (newlist)
1032 285 hiro
                                item->cache_dirty = TRUE;
1033 1 hiro
                        mlist = g_slist_concat(mlist, newlist);
1034 1 hiro
                }
1035 1 hiro
        } else {
1036 1 hiro
                imap_delete_all_cached_messages(item);
1037 1 hiro
                mlist = imap_get_uncached_messages(session, item, 0, 0, TRUE);
1038 1 hiro
                last_uid = procmsg_get_last_num_in_msg_list(mlist);
1039 285 hiro
                item->cache_dirty = TRUE;
1040 1 hiro
        }
1041 1 hiro
1042 1 hiro
        item->mtime = uid_validity;
1043 1 hiro
1044 1 hiro
        mlist = procmsg_sort_msg_list(mlist, item->sort_key, item->sort_type);
1045 1 hiro
1046 1 hiro
        item->last_num = last_uid;
1047 1 hiro
1048 293 hiro
        debug_print("cache_dirty: %d, mark_dirty: %d\n",
1049 293 hiro
                    item->cache_dirty, item->mark_dirty);
1050 285 hiro
1051 1 hiro
catch:
1052 1 hiro
        return mlist;
1053 1 hiro
}
1054 1 hiro
1055 1 hiro
#undef THROW
1056 1 hiro
1057 1 hiro
static gchar *imap_fetch_msg(Folder *folder, FolderItem *item, gint uid)
1058 1 hiro
{
1059 1 hiro
        gchar *path, *filename;
1060 1 hiro
        IMAPSession *session;
1061 1 hiro
        gint ok;
1062 1 hiro
1063 1 hiro
        g_return_val_if_fail(folder != NULL, NULL);
1064 1 hiro
        g_return_val_if_fail(item != NULL, NULL);
1065 1 hiro
1066 1 hiro
        path = folder_item_get_path(item);
1067 1 hiro
        if (!is_dir_exist(path))
1068 1 hiro
                make_dir_hier(path);
1069 1 hiro
        filename = g_strconcat(path, G_DIR_SEPARATOR_S, itos(uid), NULL);
1070 1 hiro
        g_free(path);
1071 1 hiro
1072 1 hiro
        if (is_file_exist(filename)) {
1073 1 hiro
                debug_print("message %d has been already cached.\n", uid);
1074 1 hiro
                return filename;
1075 1 hiro
        }
1076 1 hiro
1077 1 hiro
        session = imap_session_get(folder);
1078 1 hiro
        if (!session) {
1079 1 hiro
                g_free(filename);
1080 1 hiro
                return NULL;
1081 1 hiro
        }
1082 1 hiro
1083 1 hiro
        ok = imap_select(session, IMAP_FOLDER(folder), item->path,
1084 1 hiro
                         NULL, NULL, NULL, NULL);
1085 1 hiro
        if (ok != IMAP_SUCCESS) {
1086 1 hiro
                g_warning("can't select mailbox %s\n", item->path);
1087 1 hiro
                g_free(filename);
1088 1 hiro
                return NULL;
1089 1 hiro
        }
1090 1 hiro
1091 1 hiro
        debug_print("getting message %d...\n", uid);
1092 1 hiro
        ok = imap_cmd_fetch(session, (guint32)uid, filename);
1093 1 hiro
1094 1 hiro
        if (ok != IMAP_SUCCESS) {
1095 1 hiro
                g_warning("can't fetch message %d\n", uid);
1096 1 hiro
                g_free(filename);
1097 1 hiro
                return NULL;
1098 1 hiro
        }
1099 1 hiro
1100 1 hiro
        return filename;
1101 1 hiro
}
1102 1 hiro
1103 1 hiro
static MsgInfo *imap_get_msginfo(Folder *folder, FolderItem *item, gint uid)
1104 1 hiro
{
1105 1 hiro
        IMAPSession *session;
1106 1 hiro
        GSList *list;
1107 1 hiro
        MsgInfo *msginfo = NULL;
1108 1 hiro
1109 1 hiro
        g_return_val_if_fail(folder != NULL, NULL);
1110 1 hiro
        g_return_val_if_fail(item != NULL, NULL);
1111 1 hiro
1112 1 hiro
        session = imap_session_get(folder);
1113 1 hiro
        g_return_val_if_fail(session != NULL, NULL);
1114 1 hiro
1115 1 hiro
        list = imap_get_uncached_messages(session, item, uid, uid, FALSE);
1116 1 hiro
        if (list) {
1117 1 hiro
                msginfo = (MsgInfo *)list->data;
1118 1 hiro
                list->data = NULL;
1119 1 hiro
        }
1120 1 hiro
        procmsg_msg_list_free(list);
1121 1 hiro
1122 1 hiro
        return msginfo;
1123 1 hiro
}
1124 1 hiro
1125 1 hiro
static gint imap_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
1126 1 hiro
                         MsgFlags *flags, gboolean remove_source)
1127 1 hiro
{
1128 1 hiro
        GSList file_list;
1129 1 hiro
        MsgFileInfo fileinfo;
1130 1 hiro
1131 1 hiro
        g_return_val_if_fail(file != NULL, -1);
1132 1 hiro
1133 1 hiro
        fileinfo.file = (gchar *)file;
1134 1 hiro
        fileinfo.flags = flags;
1135 1 hiro
        file_list.data = &fileinfo;
1136 1 hiro
        file_list.next = NULL;
1137 1 hiro
1138 1 hiro
        return imap_add_msgs(folder, dest, &file_list, remove_source, NULL);
1139 1 hiro
}
1140 1 hiro
1141 1 hiro
static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
1142 1 hiro
                          gboolean remove_source, gint *first)
1143 1 hiro
{
1144 1 hiro
        gchar *destdir;
1145 1 hiro
        IMAPSession *session;
1146 1 hiro
        gint messages, recent, unseen;
1147 1 hiro
        guint32 uid_next, uid_validity;
1148 1 hiro
        guint32 last_uid = 0;
1149 1 hiro
        GSList *cur;
1150 1 hiro
        MsgFileInfo *fileinfo;
1151 1 hiro
        gint ok;
1152 1 hiro
1153 1 hiro
        g_return_val_if_fail(folder != NULL, -1);
1154 1 hiro
        g_return_val_if_fail(dest != NULL, -1);
1155 1 hiro
        g_return_val_if_fail(file_list != NULL, -1);
1156 1 hiro
1157 1 hiro
        session = imap_session_get(folder);
1158 1 hiro
        if (!session) return -1;
1159 1 hiro
1160 1 hiro
        ok = imap_status(session, IMAP_FOLDER(folder), dest->path,
1161 1 hiro
                         &messages, &recent, &uid_next, &uid_validity, &unseen);
1162 1 hiro
        if (ok != IMAP_SUCCESS) {
1163 1 hiro
                g_warning("can't append messages\n");
1164 1 hiro
                return -1;
1165 1 hiro
        }
1166 1 hiro
1167 1 hiro
        destdir = imap_get_real_path(IMAP_FOLDER(folder), dest->path);
1168 1 hiro
1169 1 hiro
        if (!session->uidplus)
1170 1 hiro
                last_uid = uid_next - 1;
1171 1 hiro
        if (first)
1172 1 hiro
                *first = uid_next;
1173 1 hiro
1174 1 hiro
        for (cur = file_list; cur != NULL; cur = cur->next) {
1175 1 hiro
                IMAPFlags iflags = 0;
1176 1 hiro
                guint32 new_uid = 0;
1177 1 hiro
1178 1 hiro
                fileinfo = (MsgFileInfo *)cur->data;
1179 1 hiro
1180 1 hiro
                if (fileinfo->flags) {
1181 1 hiro
                        if (MSG_IS_MARKED(*fileinfo->flags))
1182 1 hiro
                                iflags |= IMAP_FLAG_FLAGGED;
1183 1 hiro
                        if (MSG_IS_REPLIED(*fileinfo->flags))
1184 1 hiro
                                iflags |= IMAP_FLAG_ANSWERED;
1185 1 hiro
                        if (!MSG_IS_UNREAD(*fileinfo->flags))
1186 1 hiro
                                iflags |= IMAP_FLAG_SEEN;
1187 1 hiro
                }
1188 1 hiro
1189 1 hiro
                if (dest->stype == F_OUTBOX ||
1190 1 hiro
                    dest->stype == F_QUEUE  ||
1191 1 hiro
                    dest->stype == F_DRAFT  ||
1192 1 hiro
                    dest->stype == F_TRASH)
1193 1 hiro
                        iflags |= IMAP_FLAG_SEEN;
1194 1 hiro
1195 1 hiro
                ok = imap_cmd_append(session, destdir, fileinfo->file, iflags,
1196 1 hiro
                                     &new_uid);
1197 1 hiro
1198 1 hiro
                if (ok != IMAP_SUCCESS) {
1199 1 hiro
                        g_warning("can't append message %s\n", fileinfo->file);
1200 1 hiro
                        g_free(destdir);
1201 1 hiro
                        return -1;
1202 1 hiro
                }
1203 1 hiro
1204 1 hiro
                if (!session->uidplus)
1205 1 hiro
                        last_uid++;
1206 1 hiro
                else if (last_uid < new_uid)
1207 1 hiro
                        last_uid = new_uid;
1208 1 hiro
1209 1 hiro
                dest->last_num = last_uid;
1210 1 hiro
                dest->total++;
1211 1 hiro
                dest->updated = TRUE;
1212 1 hiro
1213 1 hiro
                if (fileinfo->flags) {
1214 1 hiro
                        if (MSG_IS_UNREAD(*fileinfo->flags))
1215 1 hiro
                                dest->unread++;
1216 1 hiro
                } else
1217 1 hiro
                        dest->unread++;
1218 1 hiro
        }
1219 1 hiro
1220 1 hiro
        g_free(destdir);
1221 1 hiro
1222 1 hiro
        if (remove_source) {
1223 1 hiro
                for (cur = file_list; cur != NULL; cur = cur->next) {
1224 1 hiro
                        fileinfo = (MsgFileInfo *)cur->data;
1225 478 hiro
                        if (g_unlink(fileinfo->file) < 0)
1226 1 hiro
                                 FILE_OP_ERROR(fileinfo->file, "unlink");
1227 1 hiro
                }
1228 1 hiro
        }
1229 1 hiro
1230 1 hiro
        return last_uid;
1231 1 hiro
}
1232 1 hiro
1233 1 hiro
static gint imap_do_copy_msgs(Folder *folder, FolderItem *dest, GSList *msglist,
1234 1 hiro
                              gboolean remove_source)
1235 1 hiro
{
1236 1 hiro
        FolderItem *src;
1237 1 hiro
        gchar *destdir;
1238 1 hiro
        GSList *seq_list, *cur;
1239 1 hiro
        MsgInfo *msginfo;
1240 1 hiro
        IMAPSession *session;
1241 1 hiro
        gint ok = IMAP_SUCCESS;
1242 1 hiro
1243 1 hiro
        g_return_val_if_fail(folder != NULL, -1);
1244 1 hiro
        g_return_val_if_fail(dest != NULL, -1);
1245 1 hiro
        g_return_val_if_fail(msglist != NULL, -1);
1246 1 hiro
1247 1 hiro
        session = imap_session_get(folder);
1248 1 hiro
        if (!session) return -1;
1249 1 hiro
1250 1 hiro
        msginfo = (MsgInfo *)msglist->data;
1251 1 hiro
1252 1 hiro
        src = msginfo->folder;
1253 1 hiro
        if (src == dest) {
1254 1 hiro
                g_warning("the src folder is identical to the dest.\n");
1255 1 hiro
                return -1;
1256 1 hiro
        }
1257 1 hiro
1258 1 hiro
        ok = imap_select(session, IMAP_FOLDER(folder), src->path,
1259 1 hiro
                         NULL, NULL, NULL, NULL);
1260 1 hiro
        if (ok != IMAP_SUCCESS)
1261 1 hiro
                return ok;
1262 1 hiro
1263 1 hiro
        destdir = imap_get_real_path(IMAP_FOLDER(folder), dest->path);
1264 1 hiro
1265 1 hiro
        seq_list = imap_get_seq_set_from_msglist(msglist);
1266 1 hiro
1267 1 hiro
        for (cur = seq_list; cur != NULL; cur = cur->next) {
1268 1 hiro
                gchar *seq_set = (gchar *)cur->data;
1269 1 hiro
1270 1 hiro
                if (remove_source)
1271 1 hiro
                        debug_print("Moving message %s%c[%s] to %s ...\n",
1272 1 hiro
                                    src->path, G_DIR_SEPARATOR,
1273 1 hiro
                                    seq_set, destdir);
1274 1 hiro
                else
1275 1 hiro
                        debug_print("Copying message %s%c[%s] to %s ...\n",
1276 1 hiro
                                    src->path, G_DIR_SEPARATOR,
1277 1 hiro
                                    seq_set, destdir);
1278 1 hiro
1279 1 hiro
                ok = imap_cmd_copy(session, seq_set, destdir);
1280 1 hiro
                if (ok != IMAP_SUCCESS) {
1281 1 hiro
                        imap_seq_set_free(seq_list);
1282 1 hiro
                        return -1;
1283 1 hiro
                }
1284 1 hiro
        }
1285 1 hiro
1286 1 hiro
        dest->updated = TRUE;
1287 1 hiro
1288 1 hiro
        if (remove_source) {
1289 1 hiro
                imap_remove_msgs_by_seq_set(folder, src, seq_list);
1290 1 hiro
                if (ok != IMAP_SUCCESS) {
1291 1 hiro
                        imap_seq_set_free(seq_list);
1292 1 hiro
                        return ok;
1293 1 hiro
                }
1294 1 hiro
        }
1295 1 hiro
1296 1 hiro
        imap_seq_set_free(seq_list);
1297 1 hiro
1298 1 hiro
        for (cur = msglist; cur != NULL; cur = cur->next) {
1299 1 hiro
                msginfo = (MsgInfo *)cur->data;
1300 1 hiro
                dest->total++;
1301 1 hiro
                if (MSG_IS_NEW(msginfo->flags))
1302 1 hiro
                        dest->new++;
1303 1 hiro
                if (MSG_IS_UNREAD(msginfo->flags))
1304 1 hiro
                        dest->unread++;
1305 1 hiro
1306 1 hiro
                if (remove_source) {
1307 1 hiro
                        src->total--;
1308 1 hiro
                        if (MSG_IS_NEW(msginfo->flags))
1309 1 hiro
                                src->new--;
1310 1 hiro
                        if (MSG_IS_UNREAD(msginfo->flags))
1311 1 hiro
                                src->unread--;
1312 1 hiro
                        MSG_SET_TMP_FLAGS(msginfo->flags, MSG_INVALID);
1313 1 hiro
                }
1314 1 hiro
        }
1315 1 hiro
1316 1 hiro
        g_free(destdir);
1317 1 hiro
1318 1 hiro
        if (ok == IMAP_SUCCESS)
1319 1 hiro
                return 0;
1320 1 hiro
        else
1321 1 hiro
                return -1;
1322 1 hiro
}
1323 1 hiro
1324 1 hiro
static gint imap_move_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
1325 1 hiro
{
1326 1 hiro
        GSList msglist;
1327 1 hiro
1328 1 hiro
        g_return_val_if_fail(msginfo != NULL, -1);
1329 1 hiro
1330 1 hiro
        msglist.data = msginfo;
1331 1 hiro
        msglist.next = NULL;
1332 1 hiro
1333 1 hiro
        return imap_move_msgs(folder, dest, &msglist);
1334 1 hiro
}
1335 1 hiro
1336 1 hiro
static gint imap_move_msgs(Folder *folder, FolderItem *dest, GSList *msglist)
1337 1 hiro
{
1338 1 hiro
        MsgInfo *msginfo;
1339 1 hiro
        GSList *file_list;
1340 1 hiro
        gint ret = 0;
1341 1 hiro
1342 1 hiro
        g_return_val_if_fail(folder != NULL, -1);
1343 1 hiro
        g_return_val_if_fail(dest != NULL, -1);
1344 1 hiro
        g_return_val_if_fail(msglist != NULL, -1);
1345 1 hiro
1346 1 hiro
        msginfo = (MsgInfo *)msglist->data;
1347 1 hiro
        g_return_val_if_fail(msginfo->folder != NULL, -1);
1348 1 hiro
1349 1 hiro
        if (folder == msginfo->folder->folder)
1350 1 hiro
                return imap_do_copy_msgs(folder, dest, msglist, TRUE);
1351 1 hiro
1352 1 hiro
        file_list = procmsg_get_message_file_list(msglist);
1353 1 hiro
        g_return_val_if_fail(file_list != NULL, -1);
1354 1 hiro
1355 1 hiro
        ret = imap_add_msgs(folder, dest, file_list, FALSE, NULL);
1356 1 hiro
1357 1 hiro
        procmsg_message_file_list_free(file_list);
1358 1 hiro
1359 1 hiro
        if (ret != -1)
1360 1 hiro
                ret = folder_item_remove_msgs(msginfo->folder, msglist);
1361 1 hiro
1362 1 hiro
        return ret;
1363 1 hiro
}
1364 1 hiro
1365 1 hiro
static gint imap_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
1366 1 hiro
{
1367 1 hiro
        GSList msglist;
1368 1 hiro
1369 1 hiro
        g_return_val_if_fail(msginfo != NULL, -1);
1370 1 hiro
1371 1 hiro
        msglist.data = msginfo;
1372 1 hiro
        msglist.next = NULL;
1373 1 hiro
1374 1 hiro
        return imap_copy_msgs(folder, dest, &msglist);
1375 1 hiro
}
1376 1 hiro
1377 1 hiro
static gint imap_copy_msgs(Folder *folder, FolderItem *dest, GSList *msglist)
1378 1 hiro
{
1379 1 hiro
        MsgInfo *msginfo;
1380 1 hiro
        GSList *file_list;
1381 1 hiro
        gint ret;
1382 1 hiro
1383 1 hiro
        g_return_val_if_fail(folder != NULL, -1);
1384 1 hiro
        g_return_val_if_fail(dest != NULL, -1);
1385 1 hiro
        g_return_val_if_fail(msglist != NULL, -1);
1386 1 hiro
1387 1 hiro
        msginfo = (MsgInfo *)msglist->data;
1388 1 hiro
        g_return_val_if_fail(msginfo->folder != NULL, -1);
1389 1 hiro
1390 1 hiro
        if (folder == msginfo->folder->folder)
1391 1 hiro
                return imap_do_copy_msgs(folder, dest, msglist, FALSE);
1392 1 hiro
1393 1 hiro
        file_list = procmsg_get_message_file_list(msglist);
1394 1 hiro
        g_return_val_if_fail(file_list != NULL, -1);
1395 1 hiro
1396 1 hiro
        ret = imap_add_msgs(folder, dest, file_list, FALSE, NULL);
1397 1 hiro
1398 1 hiro
        procmsg_message_file_list_free(file_list);
1399 1 hiro
1400 1 hiro
        return ret;
1401 1 hiro
}
1402 1 hiro
1403 1 hiro
static gint imap_remove_msgs_by_seq_set(Folder *folder, FolderItem *item,
1404 1 hiro
                                        GSList *seq_list)
1405 1 hiro
{
1406 1 hiro
        gint ok;
1407 1 hiro
        IMAPSession *session;
1408 1 hiro
        GSList *cur;
1409 1 hiro
1410 1 hiro
        g_return_val_if_fail(seq_list != NULL, -1);
1411 1 hiro
1412 1 hiro
        session = imap_session_get(folder);
1413 1 hiro
        if (!session) return -1;
1414 1 hiro
1415 1 hiro
        for (cur = seq_list; cur != NULL; cur = cur->next) {
1416 1 hiro
                gchar *seq_set = (gchar *)cur->data;
1417 1 hiro
1418 1 hiro
                ok = imap_set_message_flags(session, seq_set, IMAP_FLAG_DELETED,
1419 1 hiro
                                            TRUE);
1420 1 hiro
                if (ok != IMAP_SUCCESS) {
1421 1 hiro
                        log_warning(_("can't set deleted flags: %s\n"),
1422 1 hiro
                                    seq_set);
1423 1 hiro
                        return ok;
1424 1 hiro
                }
1425 1 hiro
        }
1426 1 hiro
1427 1 hiro
        ok = imap_cmd_expunge(session);
1428 1 hiro
        if (ok != IMAP_SUCCESS)
1429 1 hiro
                log_warning(_("can't expunge\n"));
1430 1 hiro
1431 1 hiro
        item->updated = TRUE;
1432 1 hiro
1433 1 hiro
        return ok;
1434 1 hiro
}
1435 1 hiro
1436 1 hiro
static gint imap_remove_msg(Folder *folder, FolderItem *item, MsgInfo *msginfo)
1437 1 hiro
{
1438 1 hiro
        GSList msglist;
1439 1 hiro
1440 1 hiro
        g_return_val_if_fail(msginfo != NULL, -1);
1441 1 hiro
1442 1 hiro
        msglist.data = msginfo;
1443 1 hiro
        msglist.next = NULL;
1444 1 hiro
1445 1 hiro
        return imap_remove_msgs(folder, item, &msglist);
1446 1 hiro
}
1447 1 hiro
1448 1 hiro
static gint imap_remove_msgs(Folder *folder, FolderItem *item, GSList *msglist)
1449 1 hiro
{
1450 1 hiro
        gint ok;
1451 1 hiro
        IMAPSession *session;
1452 1 hiro
        GSList *seq_list, *cur;
1453 1 hiro
        gchar *dir;
1454 1 hiro
        gboolean dir_exist;
1455 1 hiro
1456 1 hiro
        g_return_val_if_fail(folder != NULL, -1);
1457 1 hiro
        g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, -1);
1458 1 hiro
        g_return_val_if_fail(item != NULL, -1);
1459 1 hiro
        g_return_val_if_fail(msglist != NULL, -1);
1460 1 hiro
1461 1 hiro
        session = imap_session_get(folder);
1462 1 hiro
        if (!session) return -1;
1463 1 hiro
1464 1 hiro
        ok = imap_select(session, IMAP_FOLDER(folder), item->path,
1465 1 hiro
                         NULL, NULL, NULL, NULL);
1466 1 hiro
        if (ok != IMAP_SUCCESS)
1467 1 hiro
                return ok;
1468 1 hiro
1469 1 hiro
        seq_list = imap_get_seq_set_from_msglist(msglist);
1470 1 hiro
        ok = imap_remove_msgs_by_seq_set(folder, item, seq_list);
1471 1 hiro
        imap_seq_set_free(seq_list);
1472 1 hiro
        if (ok != IMAP_SUCCESS)
1473 1 hiro
                return ok;
1474 1 hiro
1475 1 hiro
        dir = folder_item_get_path(item);
1476 1 hiro
        dir_exist = is_dir_exist(dir);
1477 1 hiro
        for (cur = msglist; cur != NULL; cur = cur->next) {
1478 1 hiro
                MsgInfo *msginfo = (MsgInfo *)cur->data;
1479 1 hiro
                guint32 uid = msginfo->msgnum;
1480 1 hiro
1481 1 hiro
                if (dir_exist)
1482 1 hiro
                        remove_numbered_files(dir, uid, uid);
1483 1 hiro
                item->total--;
1484 1 hiro
                if (MSG_IS_NEW(msginfo->flags))
1485 1 hiro
                        item->new--;
1486 1 hiro
                if (MSG_IS_UNREAD(msginfo->flags))
1487 1 hiro
                        item->unread--;
1488 1 hiro
                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_INVALID);
1489 1 hiro
        }
1490 1 hiro
        g_free(dir);
1491 1 hiro
1492 1 hiro
        return IMAP_SUCCESS;
1493 1 hiro
}
1494 1 hiro
1495 1 hiro
static gint imap_remove_all_msg(Folder *folder, FolderItem *item)
1496 1 hiro
{
1497 1 hiro
        gint ok;
1498 1 hiro
        IMAPSession *session;
1499 1 hiro
        gchar *dir;
1500 1 hiro
1501 1 hiro
        g_return_val_if_fail(folder != NULL, -1);
1502 1 hiro
        g_return_val_if_fail(item != NULL, -1);
1503 1 hiro
1504 1 hiro
        session = imap_session_get(folder);
1505 1 hiro
        if (!session) return -1;
1506 1 hiro
1507 1 hiro
        ok = imap_select(session, IMAP_FOLDER(folder), item->path,
1508 1 hiro
                         NULL, NULL, NULL, NULL);
1509 1 hiro
        if (ok != IMAP_SUCCESS)
1510 1 hiro
                return ok;
1511 1 hiro
1512 1 hiro
        imap_cmd_gen_send(session, "STORE 1:* +FLAGS.SILENT (\\Deleted)");
1513 1 hiro
        ok = imap_cmd_ok(session, NULL);
1514 1 hiro
        if (ok != IMAP_SUCCESS) {
1515 1 hiro
                log_warning(_("can't set deleted flags: 1:*\n"));
1516 1 hiro
                return ok;
1517 1 hiro
        }
1518 1 hiro
1519 1 hiro
        ok = imap_cmd_expunge(session);
1520 1 hiro
        if (ok != IMAP_SUCCESS) {
1521 1 hiro
                log_warning(_("can't expunge\n"));
1522 1 hiro
                return ok;
1523 1 hiro
        }
1524 1 hiro
1525 1 hiro
        item->new = item->unread = item->total = 0;
1526 1 hiro
        item->updated = TRUE;
1527 1 hiro
1528 1 hiro
        dir = folder_item_get_path(item);
1529 1 hiro
        if (is_dir_exist(dir))
1530 1 hiro
                remove_all_numbered_files(dir);
1531 1 hiro
        g_free(dir);
1532 1 hiro
1533 1 hiro
        return IMAP_SUCCESS;
1534 1 hiro
}
1535 1 hiro
1536 1 hiro
static gboolean imap_is_msg_changed(Folder *folder, FolderItem *item,
1537 1 hiro
                                    MsgInfo *msginfo)
1538 1 hiro
{
1539 1 hiro
        /* TODO: properly implement this method */
1540 1 hiro
        return FALSE;
1541 1 hiro
}
1542 1 hiro
1543 1 hiro
static gint imap_close(Folder *folder, FolderItem *item)
1544 1 hiro
{
1545 1 hiro
        gint ok;
1546 1 hiro
        IMAPSession *session;
1547 1 hiro
1548 1 hiro
        g_return_val_if_fail(folder != NULL, -1);
1549 1 hiro
1550 217 hiro
        if (!item->path) return 0;
1551 217 hiro
1552 1 hiro
        session = imap_session_get(folder);
1553 1 hiro
        if (!session) return -1;
1554 1 hiro
1555 1 hiro
        if (session->mbox) {
1556 1 hiro
                if (strcmp2(session->mbox, item->path) != 0) return -1;
1557 1 hiro
1558 1 hiro
                ok = imap_cmd_close(session);
1559 1 hiro
                if (ok != IMAP_SUCCESS)
1560 1 hiro
                        log_warning(_("can't close folder\n"));
1561 1 hiro
1562 1 hiro
                g_free(session->mbox);
1563 1 hiro
                session->mbox = NULL;
1564 1 hiro
1565 1 hiro
                return ok;
1566 1 hiro
        } else
1567 1 hiro
                return 0;
1568 1 hiro
}
1569 1 hiro
1570 1 hiro
static gint imap_scan_folder(Folder *folder, FolderItem *item)
1571 1 hiro
{
1572 1 hiro
        IMAPSession *session;
1573 1 hiro
        gint messages, recent, unseen;
1574 1 hiro
        guint32 uid_next, uid_validity;
1575 1 hiro
        gint ok;
1576 1 hiro
1577 1 hiro
        g_return_val_if_fail(folder != NULL, -1);
1578 1 hiro
        g_return_val_if_fail(item != NULL, -1);
1579 1 hiro
1580 1 hiro
        session = imap_session_get(folder);
1581 1 hiro
        if (!session) return -1;
1582 1 hiro
1583 1 hiro
        ok = imap_status(session, IMAP_FOLDER(folder), item->path,
1584 1 hiro
                         &messages, &recent, &uid_next, &uid_validity, &unseen);
1585 1 hiro
        if (ok != IMAP_SUCCESS) return -1;
1586 1 hiro
1587 1 hiro
        item->new = unseen > 0 ? recent : 0;
1588 1 hiro
        item->unread = unseen;
1589 1 hiro
        item->total = messages;
1590 1 hiro
        item->last_num = (messages > 0 && uid_next > 0) ? uid_next - 1 : 0;
1591 1 hiro
        /* item->mtime = uid_validity; */
1592 1 hiro
        item->updated = TRUE;
1593 1 hiro
1594 1 hiro
        return 0;
1595 1 hiro
}
1596 1 hiro
1597 1 hiro
static gint imap_scan_tree(Folder *folder)
1598 1 hiro
{
1599 1 hiro
        FolderItem *item = NULL;
1600 1 hiro
        IMAPSession *session;
1601 1 hiro
        gchar *root_folder = NULL;
1602 1 hiro
1603 1 hiro
        g_return_val_if_fail(folder != NULL, -1);
1604 1 hiro
        g_return_val_if_fail(folder->account != NULL, -1);
1605 1 hiro
1606 1 hiro
        session = imap_session_get(folder);
1607 1 hiro
        if (!session) {
1608 1 hiro
                if (!folder->node) {
1609 1 hiro
                        folder_tree_destroy(folder);
1610 1 hiro
                        item = folder_item_new(folder->name, NULL);
1611 1 hiro
                        item->folder = folder;
1612 1 hiro
                        folder->node = item->node = g_node_new(item);
1613 1 hiro
                }
1614 1 hiro
                return -1;
1615 1 hiro
        }
1616 1 hiro
1617 1 hiro
        if (folder->account->imap_dir && *folder->account->imap_dir) {
1618 1 hiro
                gchar *real_path;
1619 1 hiro
                GPtrArray *argbuf;
1620 1 hiro
                gint ok;
1621 1 hiro
1622 1 hiro
                Xstrdup_a(root_folder, folder->account->imap_dir, return -1);
1623 1 hiro
                extract_quote(root_folder, '"');
1624 1 hiro
                subst_char(root_folder,
1625 1 hiro
                           imap_get_path_separator(IMAP_FOLDER(folder),
1626 1 hiro
                                                   root_folder),
1627 1 hiro
                           '/');
1628 1 hiro
                strtailchomp(root_folder, '/');
1629 1 hiro
                real_path = imap_get_real_path
1630 1 hiro
                        (IMAP_FOLDER(folder), root_folder);
1631 1 hiro
                debug_print("IMAP root directory: %s\n", real_path);
1632 1 hiro
1633 1 hiro
                /* check if root directory exist */
1634 1 hiro
                argbuf = g_ptr_array_new();
1635 1 hiro
                ok = imap_cmd_list(session, NULL, real_path, argbuf);
1636 1 hiro
                if (ok != IMAP_SUCCESS ||
1637 1 hiro
                    search_array_str(argbuf, "LIST ") == NULL) {
1638 1 hiro
                        log_warning(_("root folder %s not exist\n"), real_path);
1639 1 hiro
                        g_ptr_array_free(argbuf, TRUE);
1640 1 hiro
                        g_free(real_path);
1641 1 hiro
                        return -1;
1642 1 hiro
                }
1643 1 hiro
                g_ptr_array_free(argbuf, TRUE);
1644 1 hiro
                g_free(real_path);
1645 1 hiro
        }
1646 1 hiro
1647 1 hiro
        if (folder->node)
1648 1 hiro
                item = FOLDER_ITEM(folder->node->data);
1649 1 hiro
        if (!item || ((item->path || root_folder) &&
1650 1 hiro
                      strcmp2(item->path, root_folder) != 0)) {
1651 1 hiro
                folder_tree_destroy(folder);
1652 1 hiro
                item = folder_item_new(folder->name, root_folder);
1653 1 hiro
                item->folder = folder;
1654 1 hiro
                folder->node = item->node = g_node_new(item);
1655 1 hiro
        }
1656 1 hiro
1657 1 hiro
        imap_scan_tree_recursive(session, FOLDER_ITEM(folder->node->data));
1658 1 hiro
        imap_create_missing_folders(folder);
1659 1 hiro
1660 1 hiro
        return 0;
1661 1 hiro
}
1662 1 hiro
1663 1 hiro
static gint imap_scan_tree_recursive(IMAPSession *session, FolderItem *item)
1664 1 hiro
{
1665 1 hiro
        Folder *folder;
1666 1 hiro
        IMAPFolder *imapfolder;
1667 1 hiro
        FolderItem *new_item;
1668 1 hiro
        GSList *item_list, *cur;
1669 1 hiro
        GNode *node;
1670 1 hiro
        gchar *real_path;
1671 1 hiro
        gchar *wildcard_path;
1672 1 hiro
        gchar separator;
1673 1 hiro
        gchar wildcard[3];
1674 1 hiro
1675 1 hiro
        g_return_val_if_fail(item != NULL, -1);
1676 1 hiro
        g_return_val_if_fail(item->folder != NULL, -1);
1677 1 hiro
        g_return_val_if_fail(item->no_sub == FALSE, -1);
1678 1 hiro
1679 1 hiro
        folder = item->folder;
1680 1 hiro
        imapfolder = IMAP_FOLDER(folder);
1681 1 hiro
1682 1 hiro
        separator = imap_get_path_separator(imapfolder, item->path);
1683 1 hiro
1684 1 hiro
        if (folder->ui_func)
1685 1 hiro
                folder->ui_func(folder, item, folder->ui_func_data);
1686 1 hiro
1687 1 hiro
        if (item->path) {
1688 1 hiro
                wildcard[0] = separator;
1689 1 hiro
                wildcard[1] = '%';
1690 1 hiro
                wildcard[2] = '\0';
1691 1 hiro
                real_path = imap_get_real_path(imapfolder, item->path);
1692 1 hiro
        } else {
1693 1 hiro
                wildcard[0] = '%';
1694 1 hiro
                wildcard[1] = '\0';
1695 1 hiro
                real_path = g_strdup("");
1696 1 hiro
        }
1697 1 hiro
1698 1 hiro
        Xstrcat_a(wildcard_path, real_path, wildcard,
1699 1 hiro
                  {g_free(real_path); return IMAP_ERROR;});
1700 1 hiro
        QUOTE_IF_REQUIRED(wildcard_path, wildcard_path);
1701 1 hiro
1702 1 hiro
        imap_cmd_gen_send(session, "LIST \"\" %s", wildcard_path);
1703 1 hiro
1704 1 hiro
        strtailchomp(real_path, separator);
1705 1 hiro
        item_list = imap_parse_list(session, real_path, NULL);
1706 1 hiro
        g_free(real_path);
1707 1 hiro
1708 1 hiro
        node = item->node->children;
1709 1 hiro
        while (node != NULL) {
1710 1 hiro
                FolderItem *old_item = FOLDER_ITEM(node->data);
1711 1 hiro
                GNode *next = node->next;
1712 1 hiro
1713 1 hiro
                new_item = NULL;
1714 1 hiro
1715 1 hiro
                for (cur = item_list; cur != NULL; cur = cur->next) {
1716 1 hiro
                        FolderItem *cur_item = FOLDER_ITEM(cur->data);
1717 1 hiro
                        if (!strcmp2(old_item->path, cur_item->path)) {
1718 1 hiro
                                new_item = cur_item;
1719 1 hiro
                                break;
1720 1 hiro
                        }
1721 1 hiro
                }
1722 1 hiro
                if (!new_item) {
1723 1 hiro
                        debug_print("folder '%s' not found. removing...\n",
1724 1 hiro
                                    old_item->path);
1725 1 hiro
                        folder_item_remove(old_item);
1726 1 hiro
                } else {
1727 1 hiro
                        old_item->no_sub = new_item->no_sub;
1728 1 hiro
                        old_item->no_select = new_item->no_select;
1729 1 hiro
                        if (old_item->no_select == TRUE)
1730 1 hiro
                                old_item->new = old_item->unread =
1731 1 hiro
                                        old_item->total = 0;
1732 1 hiro
                        if (old_item->no_sub == TRUE && node->children) {
1733 1 hiro
                                debug_print("folder '%s' doesn't have "
1734 1 hiro
                                            "subfolders. removing...\n",
1735 1 hiro
                                            old_item->path);
1736 1 hiro
                                folder_item_remove_children(old_item);
1737 1 hiro
                        }
1738 1 hiro
                }
1739 1 hiro
1740 1 hiro
                node = next;
1741 1 hiro
        }
1742 1 hiro
1743 1 hiro
        for (cur = item_list; cur != NULL; cur = cur->next) {
1744 1 hiro
                FolderItem *cur_item = FOLDER_ITEM(cur->data);
1745 1 hiro
                new_item = NULL;
1746 1 hiro
                for (node = item->node->children; node != NULL;
1747 1 hiro
                     node = node->next) {
1748 1 hiro
                        if (!strcmp2(FOLDER_ITEM(node->data)->path,
1749 1 hiro
                                     cur_item->path)) {
1750 1 hiro
                                new_item = FOLDER_ITEM(node->data);
1751 1 hiro
                                folder_item_destroy(cur_item);
1752 1 hiro
                                cur_item = NULL;
1753 1 hiro
                                break;
1754 1 hiro
                        }
1755 1 hiro
                }
1756 1 hiro
                if (!new_item) {
1757 1 hiro
                        new_item = cur_item;
1758 1 hiro
                        debug_print("new folder '%s' found.\n", new_item->path);
1759 1 hiro
                        folder_item_append(item, new_item);
1760 1 hiro
                }
1761 1 hiro
1762 1 hiro
                if (!strcmp(new_item->path, "INBOX")) {
1763 1 hiro
                        new_item->stype = F_INBOX;
1764 1 hiro
                        folder->inbox = new_item;
1765 1 hiro
                } else if (!item->parent || item->stype == F_INBOX) {
1766 1 hiro
                        const gchar *base;
1767 1 hiro
1768 1 hiro
                        base = g_basename(new_item->path);
1769 1 hiro
1770 333 hiro
                        if (!folder->outbox &&
1771 333 hiro
                            !g_ascii_strcasecmp(base, "Sent")) {
1772 1 hiro
                                new_item->stype = F_OUTBOX;
1773 1 hiro
                                folder->outbox = new_item;
1774 333 hiro
                        } else if (!folder->draft &&
1775 333 hiro
                                   !g_ascii_strcasecmp(base, "Drafts")) {
1776 1 hiro
                                new_item->stype = F_DRAFT;
1777 1 hiro
                                folder->draft = new_item;
1778 333 hiro
                        } else if (!folder->queue &&
1779 333 hiro
                                   !g_ascii_strcasecmp(base, "Queue")) {
1780 1 hiro
                                new_item->stype = F_QUEUE;
1781 1 hiro
                                folder->queue = new_item;
1782 333 hiro
                        } else if (!folder->trash &&
1783 333 hiro
                                   !g_ascii_strcasecmp(base, "Trash")) {
1784 1 hiro
                                new_item->stype = F_TRASH;
1785 1 hiro
                                folder->trash = new_item;
1786 1 hiro
                        }
1787 1 hiro
                }
1788 1 hiro
1789 302 hiro
#if 0
1790 1 hiro
                if (new_item->no_select == FALSE)
1791 1 hiro
                        imap_scan_folder(folder, new_item);
1792 302 hiro
#endif
1793 1 hiro
                if (new_item->no_sub == FALSE)
1794 1 hiro
                        imap_scan_tree_recursive(session, new_item);
1795 1 hiro
        }
1796 1 hiro
1797 1 hiro
        g_slist_free(item_list);
1798 1 hiro
1799 1 hiro
        return IMAP_SUCCESS;
1800 1 hiro
}
1801 1 hiro
1802 1 hiro
static GSList *imap_parse_list(IMAPSession *session, const gchar *real_path,
1803 1 hiro
                               gchar *separator)
1804 1 hiro
{
1805 1 hiro
        gchar buf[IMAPBUFSIZE];
1806 1 hiro
        gchar flags[256];
1807 1 hiro
        gchar separator_str[16];
1808 1 hiro
        gchar *p;
1809 1 hiro
        const gchar *name;
1810 1 hiro
        gchar *loc_name, *loc_path;
1811 1 hiro
        GSList *item_list = NULL;
1812 1 hiro
        GString *str;
1813 1 hiro
        FolderItem *new_item;
1814 1 hiro
1815 1 hiro
        debug_print("getting list of %s ...\n",
1816 1 hiro
                    *real_path ? real_path : "\"\"");
1817 1 hiro
1818 1 hiro
        str = g_string_new(NULL);
1819 1 hiro
1820 1 hiro
        for (;;) {
1821 1 hiro
                if (sock_gets(SESSION(session)->sock, buf, sizeof(buf)) <= 0) {
1822 1 hiro
                        log_warning(_("error occurred while getting LIST.\n"));
1823 1 hiro
                        break;
1824 1 hiro
                }
1825 1 hiro
                strretchomp(buf);
1826 1 hiro
                if (buf[0] != '*' || buf[1] != ' ') {
1827 1 hiro
                        log_print("IMAP4< %s\n", buf);
1828 1 hiro
                        if (sscanf(buf, "%*d %16s", buf) < 1 ||
1829 1 hiro
                            strcmp(buf, "OK") != 0)
1830 1 hiro
                                log_warning(_("error occurred while getting LIST.\n"));
1831 1 hiro
1832 1 hiro
                        break;
1833 1 hiro
                }
1834 1 hiro
                debug_print("IMAP4< %s\n", buf);
1835 1 hiro
1836 1 hiro
                g_string_assign(str, buf);
1837 1 hiro
                p = str->str + 2;
1838 1 hiro
                if (strncmp(p, "LIST ", 5) != 0) continue;
1839 1 hiro
                p += 5;
1840 1 hiro
1841 1 hiro
                if (*p != '(') continue;
1842 1 hiro
                p++;
1843 1 hiro
                p = strchr_cpy(p, ')', flags, sizeof(flags));
1844 1 hiro
                if (!p) continue;
1845 1 hiro
                while (*p == ' ') p++;
1846 1 hiro
1847 1 hiro
                p = strchr_cpy(p, ' ', separator_str, sizeof(separator_str));
1848 1 hiro
                if (!p) continue;
1849 1 hiro
                extract_quote(separator_str, '"');
1850 1 hiro
                if (!strcmp(separator_str, "NIL"))
1851 1 hiro
                        separator_str[0] = '\0';
1852 1 hiro
                if (separator)
1853 1 hiro
                        *separator = separator_str[0];
1854 1 hiro
1855 1 hiro
                buf[0] = '\0';
1856 1 hiro
                while (*p == ' ') p++;
1857 1 hiro
                if (*p == '{' || *p == '"')
1858 1 hiro
                        p = imap_parse_atom(session, p, buf, sizeof(buf), str);
1859 1 hiro
                else
1860 1 hiro
                        strncpy2(buf, p, sizeof(buf));
1861 1 hiro
                strtailchomp(buf, separator_str[0]);
1862 1 hiro
                if (buf[0] == '\0') continue;
1863 1 hiro
                if (!strcmp(buf, real_path)) continue;
1864 1 hiro
1865 1 hiro
                if (separator_str[0] != '\0')
1866 1 hiro
                        subst_char(buf, separator_str[0], '/');
1867 1 hiro
                name = g_basename(buf);
1868 1 hiro
                if (name[0] == '.') continue;
1869 1 hiro
1870 7 hiro
                loc_name = imap_modified_utf7_to_utf8(name);
1871 7 hiro
                loc_path = imap_modified_utf7_to_utf8(buf);
1872 1 hiro
                new_item = folder_item_new(loc_name, loc_path);
1873 1 hiro
                if (strcasestr(flags, "\\Noinferiors") != NULL)
1874 1 hiro
                        new_item->no_sub = TRUE;
1875 1 hiro
                if (strcmp(buf, "INBOX") != 0 &&
1876 1 hiro
                    strcasestr(flags, "\\Noselect") != NULL)
1877 1 hiro
                        new_item->no_select = TRUE;
1878 1 hiro
1879 1 hiro
                item_list = g_slist_append(item_list, new_item);
1880 1 hiro
1881 1 hiro
                debug_print("folder '%s' found.\n", loc_path);
1882 1 hiro
                g_free(loc_path);
1883 1 hiro
                g_free(loc_name);
1884 1 hiro
        }
1885 1 hiro
1886 1 hiro
        g_string_free(str, TRUE);
1887 1 hiro
1888 1 hiro
        return item_list;
1889 1 hiro
}
1890 1 hiro
1891 1 hiro
static gint imap_create_tree(Folder *folder)
1892 1 hiro
{
1893 1 hiro
        g_return_val_if_fail(folder != NULL, -1);
1894 1 hiro
        g_return_val_if_fail(folder->node != NULL, -1);
1895 1 hiro
        g_return_val_if_fail(folder->node->data != NULL, -1);
1896 1 hiro
        g_return_val_if_fail(folder->account != NULL, -1);
1897 1 hiro
1898 1 hiro
        imap_scan_tree(folder);
1899 1 hiro
        imap_create_missing_folders(folder);
1900 1 hiro
1901 1 hiro
        return 0;
1902 1 hiro
}
1903 1 hiro
1904 1 hiro
static void imap_create_missing_folders(Folder *folder)
1905 1 hiro
{
1906 1 hiro
        g_return_if_fail(folder != NULL);
1907 1 hiro
1908 1 hiro
        if (!folder->inbox)
1909 1 hiro
                folder->inbox = imap_create_special_folder
1910 1 hiro
                        (folder, F_INBOX, "INBOX");
1911 1 hiro
#if 0
1912 1 hiro
        if (!folder->outbox)
1913 1 hiro
                folder->outbox = imap_create_special_folder
1914 1 hiro
                        (folder, F_OUTBOX, "Sent");
1915 1 hiro
        if (!folder->draft)
1916 1 hiro
                folder->draft = imap_create_special_folder
1917 1 hiro
                        (folder, F_DRAFT, "Drafts");
1918 1 hiro
        if (!folder->queue)
1919 1 hiro
                folder->queue = imap_create_special_folder
1920 1 hiro
                        (folder, F_QUEUE, "Queue");
1921 1 hiro
#endif
1922 1 hiro
        if (!folder->trash)
1923 1 hiro
                folder->trash = imap_create_special_folder
1924 1 hiro
                        (folder, F_TRASH, "Trash");
1925 1 hiro
}
1926 1 hiro
1927 1 hiro
static FolderItem *imap_create_special_folder(Folder *folder,
1928 1 hiro
                                              SpecialFolderItemType stype,
1929 1 hiro
                                              const gchar *name)
1930 1 hiro
{
1931 1 hiro
        FolderItem *item;
1932 1 hiro
        FolderItem *new_item;
1933 1 hiro
1934 1 hiro
        g_return_val_if_fail(folder != NULL, NULL);
1935 1 hiro
        g_return_val_if_fail(folder->node != NULL, NULL);
1936 1 hiro
        g_return_val_if_fail(folder->node->data != NULL, NULL);
1937 1 hiro
        g_return_val_if_fail(folder->account != NULL, NULL);
1938 1 hiro
        g_return_val_if_fail(name != NULL, NULL);
1939 1 hiro
1940 1 hiro
        item = FOLDER_ITEM(folder->node->data);
1941 1 hiro
        new_item = imap_create_folder(folder, item, name);
1942 1 hiro
1943 1 hiro
        if (!new_item) {
1944 1 hiro
                g_warning(_("Can't create '%s'\n"), name);
1945 1 hiro
                if (!folder->inbox) return NULL;
1946 1 hiro
1947 1 hiro
                new_item = imap_create_folder(folder, folder->inbox, name);
1948 1 hiro
                if (!new_item)
1949 1 hiro
                        g_warning(_("Can't create '%s' under INBOX\n"), name);
1950 1 hiro
                else
1951 1 hiro
                        new_item->stype = stype;
1952 1 hiro
        } else
1953 1 hiro
                new_item->stype = stype;
1954 1 hiro
1955 1 hiro
        return new_item;
1956 1 hiro
}
1957 1 hiro
1958 1 hiro
static FolderItem *imap_create_folder(Folder *folder, FolderItem *parent,
1959 1 hiro
                                      const gchar *name)
1960 1 hiro
{
1961 1 hiro
        gchar *dirpath, *imap_path;
1962 1 hiro
        IMAPSession *session;
1963 1 hiro
        FolderItem *new_item;
1964 1 hiro
        gchar separator;
1965 1 hiro
        gchar *new_name;
1966 1 hiro
        const gchar *p;
1967 1 hiro
        gint ok;
1968 1 hiro
1969 1 hiro
        g_return_val_if_fail(folder != NULL, NULL);
1970 1 hiro
        g_return_val_if_fail(folder->account != NULL, NULL);
1971 1 hiro
        g_return_val_if_fail(parent != NULL, NULL);
1972 1 hiro
        g_return_val_if_fail(name != NULL, NULL);
1973 1 hiro
1974 1 hiro
        session = imap_session_get(folder);
1975 1 hiro
        if (!session) return NULL;
1976 1 hiro
1977 1 hiro
        if (!parent->parent && strcmp(name, "INBOX") == 0)
1978 1 hiro
                dirpath = g_strdup(name);
1979 1 hiro
        else if (parent->path)
1980 1 hiro
                dirpath = g_strconcat(parent->path, "/", name, NULL);
1981 1 hiro
        else if ((p = strchr(name, '/')) != NULL && *(p + 1) != '\0')
1982 1 hiro
                dirpath = g_strdup(name);
1983 1 hiro
        else if (folder->account->imap_dir && *folder->account->imap_dir) {
1984 1 hiro
                gchar *imap_dir;
1985 1 hiro
1986 1 hiro
                Xstrdup_a(imap_dir, folder->account->imap_dir, return NULL);
1987 1 hiro
                strtailchomp(imap_dir, '/');
1988 1 hiro
                dirpath = g_strconcat(imap_dir, "/", name, NULL);
1989 1 hiro
        } else
1990 1 hiro
                dirpath = g_strdup(name);
1991 1 hiro
1992 1 hiro
        /* keep trailing directory separator to create a folder that contains
1993 1 hiro
           sub folder */
1994 7 hiro
        imap_path = imap_utf8_to_modified_utf7(dirpath);
1995 1 hiro
        strtailchomp(dirpath, '/');
1996 1 hiro
        Xstrdup_a(new_name, name, {g_free(dirpath); return NULL;});
1997 1 hiro
        strtailchomp(new_name, '/');
1998 1 hiro
        separator = imap_get_path_separator(IMAP_FOLDER(folder), imap_path);
1999 1 hiro
        imap_path_separator_subst(imap_path, separator);
2000 1 hiro
        subst_char(new_name, '/', separator);
2001 1 hiro
2002 1 hiro
        if (strcmp(name, "INBOX") != 0) {
2003 1 hiro
                GPtrArray *argbuf;
2004 1 hiro
                gint i;
2005 1 hiro
                gboolean exist = FALSE;
2006 1 hiro
2007 1 hiro
                argbuf = g_ptr_array_new();
2008 1 hiro
                ok = imap_cmd_list(session, NULL, imap_path, argbuf);
2009 1 hiro
                if (ok != IMAP_SUCCESS) {
2010 1 hiro
                        log_warning(_("can't create mailbox: LIST failed\n"));
2011 1 hiro
                        g_free(imap_path);
2012 1 hiro
                        g_free(dirpath);
2013 1 hiro
                        g_ptr_array_free(argbuf, TRUE);
2014 1 hiro
                        return NULL;
2015 1 hiro
                }
2016 1 hiro
2017 1 hiro
                for (i = 0; i < argbuf->len; i++) {
2018 1 hiro
                        gchar *str;
2019 1 hiro
                        str = g_ptr_array_index(argbuf, i);
2020 1 hiro
                        if (!strncmp(str, "LIST ", 5)) {
2021 1 hiro
                                exist = TRUE;
2022 1 hiro
                                break;
2023 1 hiro
                        }
2024 1 hiro
                }
2025 1 hiro
                g_ptr_array_free(argbuf, TRUE);
2026 1 hiro
2027 1 hiro
                if (!exist) {
2028 1 hiro
                        ok = imap_cmd_create(session, imap_path);
2029 1 hiro
                        if (ok != IMAP_SUCCESS) {
2030 1 hiro
                                log_warning(_("can't create mailbox\n"));
2031 1 hiro
                                g_free(imap_path);
2032 1 hiro
                                g_free(dirpath);
2033 1 hiro
                                return NULL;
2034 1 hiro
                        }
2035 1 hiro
                }
2036 1 hiro
        }
2037 1 hiro
2038 1 hiro
        new_item = folder_item_new(new_name, dirpath);
2039 1 hiro
        folder_item_append(parent, new_item);
2040 1 hiro
        g_free(imap_path);
2041 1 hiro
        g_free(dirpath);
2042 1 hiro
2043 1 hiro
        dirpath = folder_item_get_path(new_item);
2044 1 hiro
        if (!is_dir_exist(dirpath))
2045 1 hiro
                make_dir_hier(dirpath);
2046 1 hiro
        g_free(dirpath);
2047 1 hiro
2048 1 hiro
        return new_item;
2049 1 hiro
}
2050 1 hiro
2051 390 hiro
static gint imap_rename_folder_real(Folder *folder, FolderItem *item,
2052 390 hiro
                                    FolderItem *new_parent, const gchar *name)
2053 1 hiro
{
2054 1 hiro
        gchar *newpath;
2055 1 hiro
        gchar *real_oldpath;
2056 1 hiro
        gchar *real_newpath;
2057 1 hiro
        gchar *paths[2];
2058 1 hiro
        gchar *old_cache_dir;
2059 1 hiro
        gchar *new_cache_dir;
2060 1 hiro
        IMAPSession *session;
2061 1 hiro
        gchar separator;
2062 1 hiro
        gint ok;
2063 1 hiro
        gint exists, recent, unseen;
2064 1 hiro
        guint32 uid_validity;
2065 1 hiro
2066 1 hiro
        g_return_val_if_fail(folder != NULL, -1);
2067 1 hiro
        g_return_val_if_fail(item != NULL, -1);
2068 390 hiro
        g_return_val_if_fail(folder == item->folder, -1);
2069 1 hiro
        g_return_val_if_fail(item->path != NULL, -1);
2070 390 hiro
        g_return_val_if_fail(new_parent != NULL || name != NULL, -1);
2071 390 hiro
        if (new_parent) {
2072 390 hiro
                g_return_val_if_fail(item != new_parent, -1);
2073 390 hiro
                g_return_val_if_fail(item->parent != new_parent, -1);
2074 390 hiro
                g_return_val_if_fail(item->folder == new_parent->folder, -1);
2075 390 hiro
                if (g_node_is_ancestor(item->node, new_parent->node)) {
2076 390 hiro
                        g_warning("folder to be moved is ancestor of new parent\n");
2077 390 hiro
                        return -1;
2078 390 hiro
                }
2079 390 hiro
        }
2080 1 hiro
2081 1 hiro
        session = imap_session_get(folder);
2082 1 hiro
        if (!session) return -1;
2083 1 hiro
2084 1 hiro
        real_oldpath = imap_get_real_path(IMAP_FOLDER(folder), item->path);
2085 1 hiro
2086 1 hiro
        g_free(session->mbox);
2087 1 hiro
        session->mbox = NULL;
2088 1 hiro
        ok = imap_cmd_examine(session, "INBOX",
2089 1 hiro
                              &exists, &recent, &unseen, &uid_validity);
2090 1 hiro
        if (ok != IMAP_SUCCESS) {
2091 1 hiro
                g_free(real_oldpath);
2092 1 hiro
                return -1;
2093 1 hiro
        }
2094 1 hiro
2095 1 hiro
        separator = imap_get_path_separator(IMAP_FOLDER(folder), item->path);
2096 390 hiro
        if (new_parent) {
2097 390 hiro
                if (name) {
2098 390 hiro
                        newpath = g_strconcat(new_parent->path,
2099 390 hiro
                                              G_DIR_SEPARATOR_S, name, NULL);
2100 390 hiro
                } else {
2101 390 hiro
                        gchar *name_;
2102 1 hiro
2103 390 hiro
                        name_ = g_path_get_basename(item->path);
2104 390 hiro
                        newpath = g_strconcat(new_parent->path,
2105 390 hiro
                                              G_DIR_SEPARATOR_S, name_, NULL);
2106 390 hiro
                        AUTORELEASE_STR(name_, );
2107 390 hiro
                        name = name_;
2108 390 hiro
                }
2109 390 hiro
        } else {
2110 390 hiro
                if (strchr(item->path, G_DIR_SEPARATOR)) {
2111 390 hiro
                        gchar *dirpath;
2112 390 hiro
2113 390 hiro
                        dirpath = g_dirname(item->path);
2114 390 hiro
                        newpath = g_strconcat(dirpath, G_DIR_SEPARATOR_S, name,
2115 390 hiro
                                              NULL);
2116 390 hiro
                        g_free(dirpath);
2117 390 hiro
                } else
2118 390 hiro
                        newpath = g_strdup(name);
2119 390 hiro
        }
2120 390 hiro
2121 7 hiro
        real_newpath = imap_utf8_to_modified_utf7(newpath);
2122 1 hiro
        imap_path_separator_subst(real_newpath, separator);
2123 1 hiro
2124 1 hiro
        ok = imap_cmd_rename(session, real_oldpath, real_newpath);
2125 1 hiro
        if (ok != IMAP_SUCCESS) {
2126 1 hiro
                log_warning(_("can't rename mailbox: %s to %s\n"),
2127 1 hiro
                            real_oldpath, real_newpath);
2128 1 hiro
                g_free(real_oldpath);
2129 1 hiro
                g_free(newpath);
2130 1 hiro
                g_free(real_newpath);
2131 1 hiro
                return -1;
2132 1 hiro
        }
2133 1 hiro
2134 390 hiro
        if (new_parent) {
2135 390 hiro
                g_node_unlink(item->node);
2136 390 hiro
                g_node_append(new_parent->node, item->node);
2137 390 hiro
                item->parent = new_parent;
2138 390 hiro
        }
2139 390 hiro
2140 1 hiro
        g_free(item->name);
2141 1 hiro
        item->name = g_strdup(name);
2142 1 hiro
2143 1 hiro
        old_cache_dir = folder_item_get_path(item);
2144 1 hiro
2145 1 hiro
        paths[0] = g_strdup(item->path);
2146 1 hiro
        paths[1] = newpath;
2147 1 hiro
        g_node_traverse(item->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
2148 1 hiro
                        imap_rename_folder_func, paths);
2149 1 hiro
2150 1 hiro
        if (is_dir_exist(old_cache_dir)) {
2151 1 hiro
                new_cache_dir = folder_item_get_path(item);
2152 478 hiro
                if (g_rename(old_cache_dir, new_cache_dir) < 0) {
2153 1 hiro
                        FILE_OP_ERROR(old_cache_dir, "rename");
2154 1 hiro
                }
2155 1 hiro
                g_free(new_cache_dir);
2156 1 hiro
        }
2157 1 hiro
2158 1 hiro
        g_free(old_cache_dir);
2159 1 hiro
        g_free(paths[0]);
2160 1 hiro
        g_free(newpath);
2161 1 hiro
        g_free(real_oldpath);
2162 1 hiro
        g_free(real_newpath);
2163 1 hiro
2164 1 hiro
        return 0;
2165 1 hiro
}
2166 1 hiro
2167 390 hiro
static gint imap_rename_folder(Folder *folder, FolderItem *item,
2168 390 hiro
                               const gchar *name)
2169 390 hiro
{
2170 390 hiro
        return imap_rename_folder_real(folder, item, NULL, name);
2171 390 hiro
}
2172 390 hiro
2173 390 hiro
static gint imap_move_folder(Folder *folder, FolderItem *item,
2174 390 hiro
                             FolderItem *new_parent)
2175 390 hiro
{
2176 390 hiro
        return imap_rename_folder_real(folder, item, new_parent, NULL);
2177 390 hiro
}
2178 390 hiro
2179 1 hiro
static gint imap_remove_folder(Folder *folder, FolderItem *item)
2180 1 hiro
{
2181 1 hiro
        gint ok;
2182 1 hiro
        IMAPSession *session;
2183 1 hiro
        gchar *path;
2184 1 hiro
        gchar *cache_dir;
2185 1 hiro
        gint exists, recent, unseen;
2186 1 hiro
        guint32 uid_validity;
2187 1 hiro
2188 1 hiro
        g_return_val_if_fail(folder != NULL, -1);
2189 1 hiro
        g_return_val_if_fail(item != NULL, -1);
2190 1 hiro
        g_return_val_if_fail(item->path != NULL, -1);
2191 1 hiro
2192 1 hiro
        session = imap_session_get(folder);
2193 1 hiro
        if (!session) return -1;
2194 1 hiro
2195 1 hiro
        path = imap_get_real_path(IMAP_FOLDER(folder), item->path);
2196 1 hiro
2197 1 hiro
        ok = imap_cmd_examine(session, "INBOX",
2198 1 hiro
                              &exists, &recent, &unseen, &uid_validity);
2199 1 hiro
        if (ok != IMAP_SUCCESS) {
2200 1 hiro
                g_free(path);
2201 1 hiro
                return -1;
2202 1 hiro
        }
2203 1 hiro
2204 1 hiro
        ok = imap_cmd_delete(session, path);
2205 1 hiro
        if (ok != IMAP_SUCCESS) {
2206 1 hiro
                log_warning(_("can't delete mailbox\n"));
2207 1 hiro
                g_free(path);
2208 1 hiro
                return -1;
2209 1 hiro
        }
2210 1 hiro
2211 1 hiro
        g_free(path);
2212 1 hiro
        cache_dir = folder_item_get_path(item);
2213 1 hiro
        if (is_dir_exist(cache_dir) && remove_dir_recursive(cache_dir) < 0)
2214 1 hiro
                g_warning("can't remove directory '%s'\n", cache_dir);
2215 1 hiro
        g_free(cache_dir);
2216 1 hiro
        folder_item_remove(item);
2217 1 hiro
2218 1 hiro
        return 0;
2219 1 hiro
}
2220 1 hiro
2221 1 hiro
static GSList *imap_get_uncached_messages(IMAPSession *session,
2222 1 hiro
                                          FolderItem *item,
2223 1 hiro
                                          guint32 first_uid, guint32 last_uid,
2224 1 hiro
                                          gboolean update_count)
2225 1 hiro
{
2226 1 hiro
        gchar *tmp;
2227 1 hiro
        GSList *newlist = NULL;
2228 1 hiro
        GSList *llast = NULL;
2229 1 hiro
        GString *str;
2230 1 hiro
        MsgInfo *msginfo;
2231 1 hiro
        gchar seq_set[22];
2232 1 hiro
2233 1 hiro
        g_return_val_if_fail(session != NULL, NULL);
2234 1 hiro
        g_return_val_if_fail(item != NULL, NULL);
2235 1 hiro
        g_return_val_if_fail(item->folder != NULL, NULL);
2236 1 hiro
        g_return_val_if_fail(FOLDER_TYPE(item->folder) == F_IMAP, NULL);
2237 1 hiro
        g_return_val_if_fail(first_uid <= last_uid, NULL);
2238 1 hiro
2239 1 hiro
        if (first_uid == 0 && last_uid == 0)
2240 1 hiro
                strcpy(seq_set, "1:*");
2241 1 hiro
        else
2242 1 hiro
                g_snprintf(seq_set, sizeof(seq_set), "%u:%u",
2243 1 hiro
                           first_uid, last_uid);
2244 1 hiro
        if (imap_cmd_envelope(session, seq_set) != IMAP_SUCCESS) {
2245 1 hiro
                log_warning(_("can't get envelope\n"));
2246 1 hiro
                return NULL;
2247 1 hiro
        }
2248 1 hiro
2249 1 hiro
        str = g_string_new(NULL);
2250 1 hiro
2251 1 hiro
        for (;;) {
2252 353 hiro
                if (sock_getline(SESSION(session)->sock, &tmp) < 0) {
2253 1 hiro
                        log_warning(_("error occurred while getting envelope.\n"));
2254 1 hiro
                        g_string_free(str, TRUE);
2255 1 hiro
                        return newlist;
2256 1 hiro
                }
2257 1 hiro
                strretchomp(tmp);
2258 1 hiro
                if (tmp[0] != '*' || tmp[1] != ' ') {
2259 1 hiro
                        log_print("IMAP4< %s\n", tmp);
2260 1 hiro
                        g_free(tmp);
2261 1 hiro
                        break;
2262 1 hiro
                }
2263 1 hiro
                if (strstr(tmp, "FETCH") == NULL) {
2264 1 hiro
                        log_print("IMAP4< %s\n", tmp);
2265 1 hiro
                        g_free(tmp);
2266 1 hiro
                        continue;
2267 1 hiro
                }
2268 1 hiro
                log_print("IMAP4< %s\n", tmp);
2269 1 hiro
                g_string_assign(str, tmp);
2270 1 hiro
                g_free(tmp);
2271 1 hiro
2272 1 hiro
                msginfo = imap_parse_envelope(session, item, str);
2273 1 hiro
                if (!msginfo) {
2274 1 hiro
                        log_warning(_("can't parse envelope: %s\n"), str->str);
2275 1 hiro
                        continue;
2276 1 hiro
                }
2277 1 hiro
                if (update_count) {
2278 1 hiro
                        if (MSG_IS_NEW(msginfo->flags))
2279 1 hiro
                                item->new++;
2280 1 hiro
                        if (MSG_IS_UNREAD(msginfo->flags))
2281 1 hiro
                                item->unread++;
2282 1 hiro
                }
2283 1 hiro
                if (item->stype == F_QUEUE) {
2284 1 hiro
                        MSG_SET_TMP_FLAGS(msginfo->flags, MSG_QUEUED);
2285 1 hiro
                } else if (item->stype == F_DRAFT) {
2286 1 hiro
                        MSG_SET_TMP_FLAGS(msginfo->flags, MSG_DRAFT);
2287 1 hiro
                }
2288 1 hiro
2289 1 hiro
                msginfo->folder = item;
2290 1 hiro
2291 1 hiro
                if (!newlist)
2292 1 hiro
                        llast = newlist = g_slist_append(newlist, msginfo);
2293 1 hiro
                else {
2294 1 hiro
                        llast = g_slist_append(llast, msginfo);
2295 1 hiro
                        llast = llast->next;
2296 1 hiro
                }
2297 1 hiro
2298 1 hiro
                if (update_count)
2299 1 hiro
                        item->total++;
2300 1 hiro
        }
2301 1 hiro
2302 1 hiro
        g_string_free(str, TRUE);
2303 1 hiro
2304 1 hiro
        session_set_access_time(SESSION(session));
2305 1 hiro
2306 1 hiro
        return newlist;
2307 1 hiro
}
2308 1 hiro
2309 1 hiro
static void imap_delete_cached_message(FolderItem *item, guint32 uid)
2310 1 hiro
{
2311 1 hiro
        gchar *dir;
2312 1 hiro
        gchar *file;
2313 1 hiro
2314 1 hiro
        g_return_if_fail(item != NULL);
2315 1 hiro
        g_return_if_fail(item->folder != NULL);
2316 1 hiro
        g_return_if_fail(FOLDER_TYPE(item->folder) == F_IMAP);
2317 1 hiro
2318 1 hiro
        dir = folder_item_get_path(item);
2319 1 hiro
        file = g_strdup_printf("%s%c%u", dir, G_DIR_SEPARATOR, uid);
2320 1 hiro
2321 1 hiro
        debug_print("Deleting cached message: %s\n", file);
2322 1 hiro
2323 478 hiro
        g_unlink(file);
2324 1 hiro
2325 1 hiro
        g_free(file);
2326 1 hiro
        g_free(dir);
2327 1 hiro
}
2328 1 hiro
2329 1 hiro
static GSList *imap_delete_cached_messages(GSList *mlist, FolderItem *item,
2330 1 hiro
                                           guint32 first_uid, guint32 last_uid)
2331 1 hiro
{
2332 1 hiro
        GSList *cur, *next;
2333 1 hiro
        MsgInfo *msginfo;
2334 1 hiro
        gchar *dir;
2335 1 hiro
2336 1 hiro
        g_return_val_if_fail(item != NULL, mlist);
2337 1 hiro
        g_return_val_if_fail(item->folder != NULL, mlist);
2338 1 hiro
        g_return_val_if_fail(FOLDER_TYPE(item->folder) == F_IMAP, mlist);
2339 1 hiro
2340 1 hiro
        if (first_uid == 0 && last_uid == 0)
2341 1 hiro
                return mlist;
2342 1 hiro
2343 1 hiro
        debug_print("Deleting cached messages %u - %u ... ",
2344 1 hiro
                    first_uid, last_uid);
2345 1 hiro
2346 1 hiro
        dir = folder_item_get_path(item);
2347 1 hiro
        if (is_dir_exist(dir))
2348 1 hiro
                remove_numbered_files(dir, first_uid, last_uid);
2349 1 hiro
        g_free(dir);
2350 1 hiro
2351 1 hiro
        for (cur = mlist; cur != NULL; ) {
2352 1 hiro
                next = cur->next;
2353 1 hiro
2354 1 hiro
                msginfo = (MsgInfo *)cur->data;
2355 1 hiro
                if (msginfo != NULL && first_uid <= msginfo->msgnum &&
2356 1 hiro
                    msginfo->msgnum <= last_uid) {
2357 1 hiro
                        procmsg_msginfo_free(msginfo);
2358 1 hiro
                        mlist = g_slist_remove(mlist, msginfo);
2359 1 hiro
                }
2360 1 hiro
2361 1 hiro
                cur = next;
2362 1 hiro
        }
2363 1 hiro
2364 1 hiro
        debug_print("done.\n");
2365 1 hiro
2366 1 hiro
        return mlist;
2367 1 hiro
}
2368 1 hiro
2369 1 hiro
static void imap_delete_all_cached_messages(FolderItem *item)
2370 1 hiro
{
2371 1 hiro
        gchar *dir;
2372 1 hiro
2373 1 hiro
        g_return_if_fail(item != NULL);
2374 1 hiro
        g_return_if_fail(item->folder != NULL);
2375 1 hiro
        g_return_if_fail(FOLDER_TYPE(item->folder) == F_IMAP);
2376 1 hiro
2377 1 hiro
        debug_print("Deleting all cached messages... ");
2378 1 hiro
2379 1 hiro
        dir = folder_item_get_path(item);
2380 1 hiro
        if (is_dir_exist(dir))
2381 1 hiro
                remove_all_numbered_files(dir);
2382 1 hiro
        g_free(dir);
2383 1 hiro
2384 1 hiro
        debug_print("done.\n");
2385 1 hiro
}
2386 1 hiro
2387 1 hiro
#if USE_SSL
2388 1 hiro
static SockInfo *imap_open(const gchar *server, gushort port,
2389 1 hiro
                           SSLType ssl_type)
2390 1 hiro
#else
2391 1 hiro
static SockInfo *imap_open(const gchar *server, gushort port)
2392 1 hiro
#endif
2393 1 hiro
{
2394 1 hiro
        SockInfo *sock;
2395 1 hiro
2396 1 hiro
        if ((sock = sock_connect(server, port)) == NULL) {
2397 1 hiro
                log_warning(_("Can't connect to IMAP4 server: %s:%d\n"),
2398 1 hiro
                            server, port);
2399 1 hiro
                return NULL;
2400 1 hiro
        }
2401 1 hiro
2402 1 hiro
#if USE_SSL
2403 1 hiro
        if (ssl_type == SSL_TUNNEL && !ssl_init_socket(sock)) {
2404 1 hiro
                log_warning(_("Can't establish IMAP4 session with: %s:%d\n"),
2405 1 hiro
                            server, port);
2406 1 hiro
                sock_close(sock);
2407 1 hiro
                return NULL;
2408 1 hiro
        }
2409 1 hiro
#endif
2410 1 hiro
2411 1 hiro
        return sock;
2412 1 hiro
}
2413 1 hiro
2414 1 hiro
static GList *imap_parse_namespace_str(gchar *str)
2415 1 hiro
{
2416 1 hiro
        guchar *p = str;
2417 1 hiro
        gchar *name;
2418 1 hiro
        gchar *separator;
2419 1 hiro
        IMAPNameSpace *namespace;
2420 1 hiro
        GList *ns_list = NULL;
2421 1 hiro
2422 1 hiro
        while (*p != '\0') {
2423 1 hiro
                /* parse ("#foo" "/") */
2424 1 hiro
2425 1 hiro
                while (*p && *p != '(') p++;
2426 1 hiro
                if (*p == '\0') break;
2427 1 hiro
                p++;
2428 1 hiro
2429 1 hiro
                while (*p && *p != '"') p++;
2430 1 hiro
                if (*p == '\0') break;
2431 1 hiro
                p++;
2432 1 hiro
                name = p;
2433 1 hiro
2434 1 hiro
                while (*p && *p != '"') p++;
2435 1 hiro
                if (*p == '\0') break;
2436 1 hiro
                *p = '\0';
2437 1 hiro
                p++;
2438 1 hiro
2439 457 hiro
                while (*p && g_ascii_isspace(*p)) p++;
2440 1 hiro
                if (*p == '\0') break;
2441 1 hiro
                if (strncmp(p, "NIL", 3) == 0)
2442 1 hiro
                        separator = NULL;
2443 1 hiro
                else if (*p == '"') {
2444 1 hiro
                        p++;
2445 1 hiro
                        separator = p;
2446 1 hiro
                        while (*p && *p != '"') p++;
2447 1 hiro
                        if (*p == '\0') break;
2448 1 hiro
                        *p = '\0';
2449 1 hiro
                        p++;
2450 1 hiro
                } else break;
2451 1 hiro
2452 1 hiro
                while (*p && *p != ')') p++;
2453 1 hiro
                if (*p == '\0') break;
2454 1 hiro
                p++;
2455 1 hiro
2456 1 hiro
                namespace = g_new(IMAPNameSpace, 1);
2457 1 hiro
                namespace->name = g_strdup(name);
2458 1 hiro
                namespace->separator = separator ? separator[0] : '\0';
2459 1 hiro
                ns_list = g_list_append(ns_list, namespace);
2460 1 hiro
        }
2461 1 hiro
2462 1 hiro
        return ns_list;
2463 1 hiro
}
2464 1 hiro
2465 1 hiro
static void imap_parse_namespace(IMAPSession *session, IMAPFolder *folder)
2466 1 hiro
{
2467 478 hiro
        gchar *ns_str = NULL;
2468 1 hiro
        gchar **str_array;
2469 1 hiro
2470 1 hiro
        g_return_if_fail(session != NULL);
2471 1 hiro
        g_return_if_fail(folder != NULL);
2472 1 hiro
2473 1 hiro
        if (folder->ns_personal != NULL ||
2474 1 hiro
            folder->ns_others   != NULL ||
2475 1 hiro
            folder->ns_shared   != NULL)
2476 1 hiro
                return;
2477 1 hiro
2478 1 hiro
        if (imap_cmd_namespace(session, &ns_str) != IMAP_SUCCESS) {
2479 1 hiro
                log_warning(_("can't get namespace\n"));
2480 1 hiro
                imap_get_namespace_by_list(session, folder);
2481 1 hiro
                return;
2482 1 hiro
        }
2483 1 hiro
2484 1 hiro
        str_array = strsplit_parenthesis(ns_str, '(', ')', 3);
2485 1 hiro
        if (str_array[0])
2486 1 hiro
                folder->ns_personal = imap_parse_namespace_str(str_array[0]);
2487 1 hiro
        if (str_array[0] && str_array[1])
2488 1 hiro
                folder->ns_others = imap_parse_namespace_str(str_array[1]);
2489 1 hiro
        if (str_array[0] && str_array[1] && str_array[2])
2490 1 hiro
                folder->ns_shared = imap_parse_namespace_str(str_array[2]);
2491 1 hiro
        g_strfreev(str_array);
2492 1 hiro
        g_free(ns_str);
2493 1 hiro
}
2494 1 hiro
2495 1 hiro
static void imap_get_namespace_by_list(IMAPSession *session, IMAPFolder *folder)
2496 1 hiro
{
2497 1 hiro
        GSList *item_list, *cur;
2498 1 hiro
        gchar separator = '\0';
2499 1 hiro
        IMAPNameSpace *namespace;
2500 1 hiro
2501 1 hiro
        g_return_if_fail(session != NULL);
2502 1 hiro
        g_return_if_fail(folder != NULL);
2503 1 hiro
2504 1 hiro
        if (folder->ns_personal != NULL ||
2505 1 hiro
            folder->ns_others   != NULL ||
2506 1 hiro
            folder->ns_shared   != NULL)
2507 1 hiro
                return;
2508 1 hiro
2509 1 hiro
        imap_cmd_gen_send(session, "LIST \"\" \"\"");
2510 1 hiro
        item_list = imap_parse_list(session, "", &separator);
2511 1 hiro
        for (cur = item_list; cur != NULL; cur = cur->next)
2512 1 hiro
                folder_item_destroy(FOLDER_ITEM(cur->data));
2513 1 hiro
        g_slist_free(item_list);
2514 1 hiro
2515 1 hiro
        namespace = g_new(IMAPNameSpace, 1);
2516 1 hiro
        namespace->name = g_strdup("");
2517 1 hiro
        namespace->separator = separator;
2518 1 hiro
        folder->ns_personal = g_list_append(NULL, namespace);
2519 1 hiro
}
2520 1 hiro
2521 1 hiro
static IMAPNameSpace *imap_find_namespace_from_list(GList *ns_list,
2522 1 hiro
                                                    const gchar *path)
2523 1 hiro
{
2524 1 hiro
        IMAPNameSpace *namespace = NULL;
2525 1 hiro
        gchar *tmp_path, *name;
2526 1 hiro
2527 1 hiro
        if (!path) path = "";
2528 1 hiro
2529 1 hiro
        for (; ns_list != NULL; ns_list = ns_list->next) {
2530 1 hiro
                IMAPNameSpace *tmp_ns = ns_list->data;
2531 1 hiro
2532 1 hiro
                Xstrcat_a(tmp_path, path, "/", return namespace);
2533 1 hiro
                Xstrdup_a(name, tmp_ns->name, return namespace);
2534 1 hiro
                if (tmp_ns->separator && tmp_ns->separator != '/') {
2535 1 hiro
                        subst_char(tmp_path, tmp_ns->separator, '/');
2536 1 hiro
                        subst_char(name, tmp_ns->separator, '/');
2537 1 hiro
                }
2538 1 hiro
                if (strncmp(tmp_path, name, strlen(name)) == 0)
2539 1 hiro
                        namespace = tmp_ns;
2540 1 hiro
        }
2541 1 hiro
2542 1 hiro
        return namespace;
2543 1 hiro
}
2544 1 hiro
2545 1 hiro
static IMAPNameSpace *imap_find_namespace(IMAPFolder *folder,
2546 1 hiro
                                          const gchar *path)
2547 1 hiro
{
2548 1 hiro
        IMAPNameSpace *namespace;
2549 1 hiro
2550 1 hiro
        g_return_val_if_fail(folder != NULL, NULL);
2551 1 hiro
2552 1 hiro
        namespace = imap_find_namespace_from_list(folder->ns_personal, path);
2553 1 hiro
        if (namespace) return namespace;
2554 1 hiro
        namespace = imap_find_namespace_from_list(folder->ns_others, path);
2555 1 hiro
        if (namespace) return namespace;
2556 1 hiro
        namespace = imap_find_namespace_from_list(folder->ns_shared, path);
2557 1 hiro
        if (namespace) return namespace;
2558 1 hiro
2559 1 hiro
        return NULL;
2560 1 hiro
}
2561 1 hiro
2562 1 hiro
static gchar imap_get_path_separator(IMAPFolder *folder, const gchar *path)
2563 1 hiro
{
2564 1 hiro
        IMAPNameSpace *namespace;
2565 1 hiro
        gchar separator = '/';
2566 1 hiro
2567 1 hiro
        namespace = imap_find_namespace(folder, path);
2568 1 hiro
        if (namespace && namespace->separator)
2569 1 hiro
                separator = namespace->separator;
2570 1 hiro
2571 1 hiro
        return separator;
2572 1 hiro
}
2573 1 hiro
2574 1 hiro
static gchar *imap_get_real_path(IMAPFolder *folder, const gchar *path)
2575 1 hiro
{
2576 1 hiro
        gchar *real_path;
2577 1 hiro
        gchar separator;
2578 1 hiro
2579 1 hiro
        g_return_val_if_fail(folder != NULL, NULL);
2580 1 hiro
        g_return_val_if_fail(path != NULL, NULL);
2581 1 hiro
2582 7 hiro
        real_path = imap_utf8_to_modified_utf7(path);
2583 1 hiro
        separator = imap_get_path_separator(folder, path);
2584 1 hiro
        imap_path_separator_subst(real_path, separator);
2585 1 hiro
2586 1 hiro
        return real_path;
2587 1 hiro
}
2588 1 hiro
2589 1 hiro
static gchar *imap_parse_atom(IMAPSession *session, gchar *src,
2590 1 hiro
                              gchar *dest, gint dest_len, GString *str)
2591 1 hiro
{
2592 1 hiro
        gchar *cur_pos = src;
2593 1 hiro
        gchar *nextline;
2594 1 hiro
2595 1 hiro
        g_return_val_if_fail(str != NULL, cur_pos);
2596 1 hiro
2597 1 hiro
        /* read the next line if the current response buffer is empty */
2598 457 hiro
        while (g_ascii_isspace(*cur_pos)) cur_pos++;
2599 1 hiro
        while (*cur_pos == '\0') {
2600 353 hiro
                if (sock_getline(SESSION(session)->sock, &nextline) < 0)
2601 1 hiro
                        return cur_pos;
2602 1 hiro
                g_string_assign(str, nextline);
2603 1 hiro
                cur_pos = str->str;
2604 1 hiro
                strretchomp(nextline);
2605 1 hiro
                /* log_print("IMAP4< %s\n", nextline); */
2606 1 hiro
                debug_print("IMAP4< %s\n", nextline);
2607 1 hiro
                g_free(nextline);
2608 1 hiro
2609 457 hiro
                while (g_ascii_isspace(*cur_pos)) cur_pos++;
2610 1 hiro
        }
2611 1 hiro
2612 1 hiro
        if (!strncmp(cur_pos, "NIL", 3)) {
2613 1 hiro
                *dest = '\0';
2614 1 hiro
                cur_pos += 3;
2615 1 hiro
        } else if (*cur_pos == '\"') {
2616 1 hiro
                gchar *p;
2617 1 hiro
2618 1 hiro
                p = get_quoted(cur_pos, '\"', dest, dest_len);
2619 1 hiro
                cur_pos = p ? p : cur_pos + 2;
2620 1 hiro
        } else if (*cur_pos == '{') {
2621 1 hiro
                gchar buf[32];
2622 1 hiro
                gint len;
2623 353 hiro
                gint block_len = 0;
2624 1 hiro
2625 1 hiro
                cur_pos = strchr_cpy(cur_pos + 1, '}', buf, sizeof(buf));
2626 1 hiro
                len = atoi(buf);
2627 1 hiro
                g_return_val_if_fail(len >= 0, cur_pos);
2628 1 hiro
2629 1 hiro
                g_string_truncate(str, 0);
2630 1 hiro
                cur_pos = str->str;
2631 1 hiro
2632 1 hiro
                do {
2633 353 hiro
                        gint cur_len;
2634 353 hiro
2635 353 hiro
                        cur_len = sock_getline(SESSION(session)->sock,
2636 353 hiro
                                               &nextline);
2637 353 hiro
                        if (cur_len < 0)
2638 1 hiro
                                return cur_pos;
2639 353 hiro
                        block_len += cur_len;
2640 353 hiro
                        subst_null(nextline, cur_len, ' ');
2641 1 hiro
                        g_string_append(str, nextline);
2642 1 hiro
                        cur_pos = str->str;
2643 1 hiro
                        strretchomp(nextline);
2644 1 hiro
                        /* log_print("IMAP4< %s\n", nextline); */
2645 1 hiro
                        debug_print("IMAP4< %s\n", nextline);
2646 1 hiro
                        g_free(nextline);
2647 353 hiro
                } while (block_len < len);
2648 1 hiro
2649 1 hiro
                memcpy(dest, cur_pos, MIN(len, dest_len - 1));
2650 1 hiro
                dest[MIN(len, dest_len - 1)] = '\0';
2651 1 hiro
                cur_pos += len;
2652 1 hiro
        }
2653 1 hiro
2654 1 hiro
        return cur_pos;
2655 1 hiro
}
2656 1 hiro
2657 1 hiro
static gchar *imap_get_header(IMAPSession *session, gchar *cur_pos,
2658 1 hiro
                              gchar **headers, GString *str)
2659 1 hiro
{
2660 1 hiro
        gchar *nextline;
2661 1 hiro
        gchar buf[32];
2662 1 hiro
        gint len;
2663 1 hiro
        gint block_len = 0;
2664 1 hiro
2665 1 hiro
        *headers = NULL;
2666 1 hiro
2667 1 hiro
        g_return_val_if_fail(str != NULL, cur_pos);
2668 1 hiro
2669 457 hiro
        while (g_ascii_isspace(*cur_pos)) cur_pos++;
2670 1 hiro
2671 1 hiro
        g_return_val_if_fail(*cur_pos == '{', cur_pos);
2672 1 hiro
2673 1 hiro
        cur_pos = strchr_cpy(cur_pos + 1, '}', buf, sizeof(buf));
2674 1 hiro
        len = atoi(buf);
2675 1 hiro
        g_return_val_if_fail(len >= 0, cur_pos);
2676 1 hiro
2677 1 hiro
        g_string_truncate(str, 0);
2678 1 hiro
        cur_pos = str->str;
2679 1 hiro
2680 1 hiro
        do {
2681 353 hiro
                gint cur_len;
2682 353 hiro
2683 353 hiro
                cur_len = sock_getline(SESSION(session)->sock, &nextline);
2684 353 hiro
                if (cur_len < 0)
2685 1 hiro
                        return cur_pos;
2686 353 hiro
                block_len += cur_len;
2687 353 hiro
                subst_null(nextline, cur_len, ' ');
2688 1 hiro
                g_string_append(str, nextline);
2689 1 hiro
                cur_pos = str->str;
2690 353 hiro
                /* strretchomp(nextline); */
2691 1 hiro
                /* debug_print("IMAP4< %s\n", nextline); */
2692 1 hiro
                g_free(nextline);
2693 1 hiro
        } while (block_len < len);
2694 1 hiro
2695 1 hiro
        debug_print("IMAP4< [contents of RFC822.HEADER]\n");
2696 1 hiro
2697 1 hiro
        *headers = g_strndup(cur_pos, len);
2698 1 hiro
        cur_pos += len;
2699 1 hiro
2700 457 hiro
        while (g_ascii_isspace(*cur_pos)) cur_pos++;
2701 1 hiro
        while (*cur_pos == '\0') {
2702 353 hiro
                if (sock_getline(SESSION(session)->sock, &nextline) < 0)
2703 1 hiro
                        return cur_pos;
2704 1 hiro
                g_string_assign(str, nextline);
2705 1 hiro
                cur_pos = str->str;
2706 1 hiro
                strretchomp(nextline);
2707 1 hiro
                debug_print("IMAP4< %s\n", nextline);
2708 1 hiro
                g_free(nextline);
2709 1 hiro
2710 457 hiro
                while (g_ascii_isspace(*cur_pos)) cur_pos++;
2711 1 hiro
        }
2712 1 hiro
2713 1 hiro
        return cur_pos;
2714 1 hiro
}
2715 1 hiro
2716 1 hiro
static MsgFlags imap_parse_flags(const gchar *flag_str)
2717 1 hiro
{
2718 1 hiro
        const gchar *p = flag_str;
2719 1 hiro
        MsgFlags flags = {0, 0};
2720 1 hiro
2721 1 hiro
        flags.perm_flags = MSG_UNREAD;
2722 1 hiro
2723 1 hiro
        while ((p = strchr(p, '\\')) != NULL) {
2724 1 hiro
                p++;
2725 1 hiro
2726 333 hiro
                if (g_ascii_strncasecmp(p, "Recent", 6) == 0 &&
2727 333 hiro
                    MSG_IS_UNREAD(flags)) {
2728 1 hiro
                        MSG_SET_PERM_FLAGS(flags, MSG_NEW);
2729 333 hiro
                } else if (g_ascii_strncasecmp(p, "Seen", 4) == 0) {
2730 1 hiro
                        MSG_UNSET_PERM_FLAGS(flags, MSG_NEW|MSG_UNREAD);
2731 333 hiro
                } else if (g_ascii_strncasecmp(p, "Deleted", 7) == 0) {
2732 1 hiro
                        MSG_SET_PERM_FLAGS(flags, MSG_DELETED);
2733 333 hiro
                } else if (g_ascii_strncasecmp(p, "Flagged", 7) == 0) {
2734 1 hiro
                        MSG_SET_PERM_FLAGS(flags, MSG_MARKED);
2735 333 hiro
                } else if (g_ascii_strncasecmp(p, "Answered", 8) == 0) {
2736 1 hiro
                        MSG_SET_PERM_FLAGS(flags, MSG_REPLIED);
2737 1 hiro
                }
2738 1 hiro
        }
2739 1 hiro
2740 1 hiro
        return flags;
2741 1 hiro
}
2742 1 hiro
2743 1 hiro
static IMAPFlags imap_parse_imap_flags(const gchar *flag_str)
2744 1 hiro
{
2745 1 hiro
        const gchar *p = flag_str;
2746 1 hiro
        IMAPFlags flags = 0;
2747 1 hiro
2748 1 hiro
        while ((p = strchr(p, '\\')) != NULL) {
2749 1 hiro
                p++;
2750 1 hiro
2751 333 hiro
                if (g_ascii_strncasecmp(p, "Seen", 4) == 0) {
2752 1 hiro
                        flags |= IMAP_FLAG_SEEN;
2753 333 hiro
                } else if (g_ascii_strncasecmp(p, "Deleted", 7) == 0) {
2754 1 hiro
                        flags |= IMAP_FLAG_DELETED;
2755 333 hiro
                } else if (g_ascii_strncasecmp(p, "Flagged", 7) == 0) {
2756 1 hiro
                        flags |= IMAP_FLAG_FLAGGED;
2757 333 hiro
                } else if (g_ascii_strncasecmp(p, "Answered", 8) == 0) {