Statistics
| Revision:

root / src / imap.c @ 127

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