#define IMAPS_PORT 993
#endif
-#define QUOTE_IF_REQUIRED(out, str) \
-{ \
- if (*str != '"' && strchr(str, ' ')) { \
- gchar *__tmp; \
- gint len; \
- \
- len = strlen(str) + 3; \
- Xalloca(__tmp, len, return IMAP_ERROR); \
- g_snprintf(__tmp, len, "\"%s\"", str); \
- out = __tmp; \
- } else { \
- Xstrdup_a(out, str, return IMAP_ERROR); \
- } \
+#define QUOTE_IF_REQUIRED(out, str) \
+{ \
+ if (*str != '"' && strpbrk(str, " \t(){}%*") != NULL) { \
+ gchar *__tmp; \
+ gint len; \
+ \
+ len = strlen(str) + 3; \
+ Xalloca(__tmp, len, return IMAP_ERROR); \
+ g_snprintf(__tmp, len, "\"%s\"", str); \
+ out = __tmp; \
+ } else { \
+ Xstrdup_a(out, str, return IMAP_ERROR); \
+ } \
}
static GList *session_list = NULL;
static IMAPSession *imap_session_get (Folder *folder);
static gint imap_scan_tree_recursive (IMAPSession *session,
- FolderItem *item,
- IMAPNameSpace *namespace);
+ FolderItem *item);
static GSList *imap_parse_list (IMAPSession *session,
const gchar *real_path);
const gchar *path,
gint *messages,
gint *recent,
- gint *unseen,
- guint32 *uid_validity);
+ guint32 *uid_next,
+ guint32 *uid_validity,
+ gint *unseen);
static void imap_parse_namespace (IMAPSession *session,
IMAPFolder *folder);
static IMAPNameSpace *imap_find_namespace (IMAPFolder *folder,
const gchar *path);
+static gchar imap_get_path_separator (IMAPFolder *folder,
+ const gchar *path);
static gchar *imap_get_real_path (IMAPFolder *folder,
const gchar *path);
static gboolean imap_rename_folder_func (GNode *node,
gpointer data);
+
Folder *imap_folder_new(const gchar *name, const gchar *path)
{
Folder *folder;
IMAPSession *session = (IMAPSession *)session_list->data;
imap_cmd_logout(SESSION(session)->sock);
- imap_session_destroy(session);
+ session_destroy(SESSION(session));
}
}
return NULL;
}
+ ok = imap_select(session, IMAP_FOLDER(folder), item->path,
+ NULL, NULL, NULL, NULL);
+ statusbar_pop_all();
+ if (ok != IMAP_SUCCESS) {
+ g_warning(_("can't select mailbox %s\n"), item->path);
+ g_free(filename);
+ return NULL;
+ }
+
debug_print(_("getting message %d...\n"), uid);
ok = imap_cmd_fetch(SESSION(session)->sock, (guint32)uid, filename);
{
gchar *destdir;
IMAPSession *session;
+ gint messages, recent, unseen;
+ guint32 uid_next, uid_validity;
gint ok;
g_return_val_if_fail(folder != NULL, -1);
session = imap_session_get(folder);
if (!session) return -1;
+ ok = imap_status(session, IMAP_FOLDER(folder), dest->path,
+ &messages, &recent, &uid_next, &uid_validity, &unseen);
+ statusbar_pop_all();
+ if (ok != IMAP_SUCCESS) {
+ g_warning(_("can't append message %s\n"), file);
+ return -1;
+ }
+
destdir = imap_get_real_path(IMAP_FOLDER(folder), dest->path);
ok = imap_cmd_append(SESSION(session)->sock, destdir, file);
g_free(destdir);
FILE_OP_ERROR(file, "unlink");
}
- return 0;
+ return uid_next;
}
static gint imap_do_copy(Folder *folder, FolderItem *dest, MsgInfo *msginfo,
return FALSE;
}
-void imap_scan_folder(Folder *folder, FolderItem *item)
+gint imap_scan_folder(Folder *folder, FolderItem *item)
{
IMAPSession *session;
gint messages, recent, unseen;
- guint32 uid_validity;
+ guint32 uid_next, uid_validity;
gint ok;
- g_return_if_fail(folder != NULL);
- g_return_if_fail(item != NULL);
+ g_return_val_if_fail(folder != NULL, -1);
+ g_return_val_if_fail(item != NULL, -1);
session = imap_session_get(folder);
- if (!session) return;
+ if (!session) return -1;
ok = imap_status(session, IMAP_FOLDER(folder), item->path,
- &messages, &recent, &unseen, &uid_validity);
+ &messages, &recent, &uid_next, &uid_validity, &unseen);
statusbar_pop_all();
- if (ok != IMAP_SUCCESS) return;
+ if (ok != IMAP_SUCCESS) return -1;
item->new = unseen > 0 ? recent : 0;
item->unread = unseen;
item->total = messages;
+ item->last_num = (messages > 0 && uid_next > 0) ? uid_next - 1 : 0;
/* item->mtime = uid_validity; */
+
+ return 0;
}
void imap_scan_tree(Folder *folder)
{
- IMAPFolder *imapfolder = IMAP_FOLDER(folder);
FolderItem *item;
IMAPSession *session;
- IMAPNameSpace *namespace = NULL;
gchar *root_folder = NULL;
g_return_if_fail(folder != NULL);
session = imap_session_get(folder);
if (!session) return;
- if (imapfolder->namespace && imapfolder->namespace->data)
- namespace = (IMAPNameSpace *)imapfolder->namespace->data;
-
if (folder->account->imap_dir && *folder->account->imap_dir) {
- gchar *imap_dir;
- Xstrdup_a(imap_dir, folder->account->imap_dir, return);
- strtailchomp(imap_dir, '/');
- root_folder = g_strconcat
- (namespace && namespace->name ? namespace->name : "",
- imap_dir, NULL);
- if (namespace && namespace->separator)
- subst_char(root_folder, namespace->separator, '/');
- }
-
- if (root_folder)
+ Xstrdup_a(root_folder, folder->account->imap_dir, return);
+ strtailchomp(root_folder, '/');
debug_print("IMAP root directory: %s\n", root_folder);
+ }
folder_tree_destroy(folder);
item = folder_item_new(folder->name, root_folder);
item->folder = folder;
folder->node = g_node_new(item);
- g_free(root_folder);
- imap_scan_tree_recursive(session, item, namespace);
+ imap_scan_tree_recursive(session, item);
imap_create_missing_folders(folder);
}
-static gint imap_scan_tree_recursive(IMAPSession *session, FolderItem *item,
- IMAPNameSpace *namespace)
+static gint imap_scan_tree_recursive(IMAPSession *session, FolderItem *item)
{
Folder *folder;
IMAPFolder *imapfolder;
GSList *item_list, *cur;
gchar *real_path;
gchar *wildcard_path;
- gchar separator = '/';
+ gchar separator;
gchar wildcard[3];
g_return_val_if_fail(item != NULL, -1);
folder = FOLDER(item->folder);
imapfolder = IMAP_FOLDER(folder);
- if (namespace && namespace->separator)
- separator = namespace->separator;
+ separator = imap_get_path_separator(imapfolder, item->path);
if (item->folder->ui_func)
item->folder->ui_func(folder, item, folder->ui_func_data);
} else {
wildcard[0] = '%';
wildcard[1] = '\0';
- real_path = g_strdup(namespace && namespace->name &&
- strncmp(namespace->name, "INBOX", 5) != 0
- ? namespace->name : "");
+ real_path = g_strdup("");
}
Xstrcat_a(wildcard_path, real_path, wildcard,
if (new_item->no_select == FALSE)
imap_scan_folder(folder, new_item);
if (new_item->no_sub == FALSE)
- imap_scan_tree_recursive(session, new_item, namespace);
+ imap_scan_tree_recursive(session, new_item);
}
return IMAP_SUCCESS;
new_item = folder_item_new(loc_name, loc_path);
if (strcasestr(flags, "\\Noinferiors") != NULL)
new_item->no_sub = TRUE;
- if (strcasestr(flags, "\\Noselect") != NULL)
+ if (strcmp(buf, "INBOX") != 0 &&
+ strcasestr(flags, "\\Noselect") != NULL)
new_item->no_select = TRUE;
item_list = g_slist_append(item_list, new_item);
if (!folder->inbox)
folder->inbox = imap_create_special_folder
(folder, F_INBOX, "INBOX");
+#if 0
if (!folder->outbox)
folder->outbox = imap_create_special_folder
(folder, F_OUTBOX, "Sent");
if (!folder->queue)
folder->queue = imap_create_special_folder
(folder, F_QUEUE, "Queue");
+#endif
if (!folder->trash)
folder->trash = imap_create_special_folder
(folder, F_TRASH, "Trash");
{
gchar *dirpath, *imap_path;
IMAPSession *session;
- IMAPNameSpace *namespace;
FolderItem *new_item;
+ gchar separator;
gchar *new_name;
const gchar *p;
gint ok;
session = imap_session_get(folder);
if (!session) return NULL;
- if (parent->path)
+ if (!parent->parent && strcmp(name, "INBOX") == 0)
+ dirpath = g_strdup(name);
+ else if (parent->path)
dirpath = g_strconcat(parent->path, "/", name, NULL);
else if ((p = strchr(name, '/')) != NULL && *(p + 1) != '\0')
dirpath = g_strdup(name);
} else
dirpath = g_strdup(name);
- strtailchomp(dirpath, '/');
+ /* keep trailing directory separator to create a folder that contains
+ sub folder */
imap_path = imap_locale_to_modified_utf7(dirpath);
+ strtailchomp(dirpath, '/');
Xstrdup_a(new_name, name, {g_free(dirpath); return NULL;});
strtailchomp(new_name, '/');
- namespace = imap_find_namespace(IMAP_FOLDER(folder), imap_path);
- if (namespace && namespace->separator) {
- imap_path_separator_subst(imap_path, namespace->separator);
- subst_char(new_name, '/', namespace->separator);
- }
+ separator = imap_get_path_separator(IMAP_FOLDER(folder), imap_path);
+ imap_path_separator_subst(imap_path, separator);
+ subst_char(new_name, '/', separator);
if (strcmp(name, "INBOX") != 0) {
GPtrArray *argbuf;
gchar *old_cache_dir;
gchar *new_cache_dir;
IMAPSession *session;
- IMAPNameSpace *namespace;
+ gchar separator;
gint ok;
gint exists, recent, unseen;
guint32 uid_validity;
real_oldpath = imap_get_real_path(IMAP_FOLDER(folder), item->path);
+ g_free(session->mbox);
+ session->mbox = NULL;
ok = imap_cmd_examine(SESSION(session)->sock, "INBOX",
&exists, &recent, &unseen, &uid_validity);
statusbar_pop_all();
return -1;
}
- namespace = imap_find_namespace(IMAP_FOLDER(folder), item->path);
+ separator = imap_get_path_separator(IMAP_FOLDER(folder), item->path);
if (strchr(item->path, G_DIR_SEPARATOR)) {
dirpath = g_dirname(item->path);
newpath = g_strconcat(dirpath, G_DIR_SEPARATOR_S, name, NULL);
newpath = g_strdup(name);
real_newpath = imap_locale_to_modified_utf7(newpath);
- if (namespace && namespace->separator)
- imap_path_separator_subst(real_newpath, namespace->separator);
+ imap_path_separator_subst(real_newpath, separator);
ok = imap_cmd_rename(SESSION(session)->sock, real_oldpath, real_newpath);
statusbar_pop_all();
return newlist;
}
strretchomp(tmp);
- log_print("IMAP4< %s\n", tmp);
if (tmp[0] != '*' || tmp[1] != ' ') {
+ log_print("IMAP4< %s\n", tmp);
g_free(tmp);
break;
}
+ if (strstr(tmp, "FETCH") == NULL) {
+ log_print("IMAP4< %s\n", tmp);
+ g_free(tmp);
+ continue;
+ }
+ /* log_print("IMAP4< %s\n", tmp); */
+ debug_print("IMAP4< %s\n", tmp);
g_string_assign(str, tmp);
g_free(tmp);
return sock;
}
-#define THROW goto catch
-
-static void imap_parse_namespace(IMAPSession *session, IMAPFolder *folder)
+static GList *imap_parse_namespace_str(gchar *str)
{
- gchar *ns_str;
+ gchar *p = str;
gchar *name;
gchar *separator;
- gchar *p;
IMAPNameSpace *namespace;
GList *ns_list = NULL;
- g_return_if_fail(session != NULL);
- g_return_if_fail(folder != NULL);
-
- if (folder->namespace != NULL) return;
-
- if (imap_cmd_namespace(SESSION(session)->sock, &ns_str)
- != IMAP_SUCCESS) {
- log_warning(_("can't get namespace\n"));
- return;
- }
-
- /* get the first element */
- extract_one_parenthesis_with_skip_quote(ns_str, '"', '(', ')');
- g_strstrip(ns_str);
- p = ns_str;
-
while (*p != '\0') {
/* parse ("#foo" "/") */
while (*p && *p != '(') p++;
- if (*p == '\0') THROW;
+ if (*p == '\0') break;
p++;
while (*p && *p != '"') p++;
- if (*p == '\0') THROW;
+ if (*p == '\0') break;
p++;
name = p;
while (*p && *p != '"') p++;
- if (*p == '\0') THROW;
+ if (*p == '\0') break;
*p = '\0';
p++;
while (*p && isspace(*p)) p++;
- if (*p == '\0') THROW;
+ if (*p == '\0') break;
if (strncmp(p, "NIL", 3) == 0)
separator = NULL;
else if (*p == '"') {
p++;
separator = p;
while (*p && *p != '"') p++;
- if (*p == '\0') THROW;
+ if (*p == '\0') break;
*p = '\0';
p++;
- } else THROW;
+ } else break;
while (*p && *p != ')') p++;
- if (*p == '\0') THROW;
+ if (*p == '\0') break;
p++;
namespace = g_new(IMAPNameSpace, 1);
namespace->name = g_strdup(name);
namespace->separator = separator ? separator[0] : '\0';
ns_list = g_list_append(ns_list, namespace);
- IMAP_FOLDER(folder)->namespace = ns_list;
}
-catch:
- g_free(ns_str);
- return;
+ return ns_list;
}
-#undef THROW
+static void imap_parse_namespace(IMAPSession *session, IMAPFolder *folder)
+{
+ gchar *ns_str;
+ gchar **str_array;
-static IMAPNameSpace *imap_find_namespace(IMAPFolder *folder,
- const gchar *path)
+ g_return_if_fail(session != NULL);
+ g_return_if_fail(folder != NULL);
+
+ if (folder->ns_personal != NULL ||
+ folder->ns_others != NULL ||
+ folder->ns_shared != NULL)
+ return;
+
+ if (imap_cmd_namespace(SESSION(session)->sock, &ns_str)
+ != IMAP_SUCCESS) {
+ log_warning(_("can't get namespace\n"));
+ return;
+ }
+
+ str_array = strsplit_parenthesis(ns_str, '(', ')', 3);
+ if (str_array[0])
+ folder->ns_personal = imap_parse_namespace_str(str_array[0]);
+ if (str_array[0] && str_array[1])
+ folder->ns_others = imap_parse_namespace_str(str_array[1]);
+ if (str_array[0] && str_array[1] && str_array[2])
+ folder->ns_shared = imap_parse_namespace_str(str_array[2]);
+ g_strfreev(str_array);
+ return;
+}
+
+static IMAPNameSpace *imap_find_namespace_from_list(GList *ns_list,
+ const gchar *path)
{
IMAPNameSpace *namespace = NULL;
- GList *ns_list;
- gchar *name;
+ gchar *tmp_path, *name;
- g_return_val_if_fail(folder != NULL, NULL);
- g_return_val_if_fail(path != NULL, NULL);
+ if (!path) path = "";
- ns_list = folder->namespace;
+ Xstrcat_a(tmp_path, path, "/", return NULL);
for (; ns_list != NULL; ns_list = ns_list->next) {
IMAPNameSpace *tmp_ns = ns_list->data;
Xstrdup_a(name, tmp_ns->name, return namespace);
if (tmp_ns->separator && tmp_ns->separator != '/')
subst_char(name, tmp_ns->separator, '/');
- if (strncmp(path, name, strlen(name)) == 0)
+ if (strncmp(tmp_path, name, strlen(name)) == 0)
namespace = tmp_ns;
}
return namespace;
}
+static IMAPNameSpace *imap_find_namespace(IMAPFolder *folder,
+ const gchar *path)
+{
+ IMAPNameSpace *namespace;
+
+ g_return_val_if_fail(folder != NULL, NULL);
+
+ namespace = imap_find_namespace_from_list(folder->ns_personal, path);
+ if (namespace) return namespace;
+ namespace = imap_find_namespace_from_list(folder->ns_others, path);
+ if (namespace) return namespace;
+ namespace = imap_find_namespace_from_list(folder->ns_shared, path);
+ if (namespace) return namespace;
+
+ return NULL;
+}
+
+static gchar imap_get_path_separator(IMAPFolder *folder, const gchar *path)
+{
+ IMAPNameSpace *namespace;
+ gchar separator = '/';
+
+ namespace = imap_find_namespace(folder, path);
+ if (namespace && namespace->separator)
+ separator = namespace->separator;
+
+ return separator;
+}
+
static gchar *imap_get_real_path(IMAPFolder *folder, const gchar *path)
{
gchar *real_path;
- IMAPNameSpace *namespace;
+ gchar separator;
g_return_val_if_fail(folder != NULL, NULL);
g_return_val_if_fail(path != NULL, NULL);
real_path = imap_locale_to_modified_utf7(path);
- namespace = imap_find_namespace(folder, path);
- if (namespace && namespace->separator)
- imap_path_separator_subst(real_path, namespace->separator);
+ separator = imap_get_path_separator(folder, path);
+ imap_path_separator_subst(real_path, separator);
return real_path;
}
g_string_assign(str, nextline);
cur_pos = str->str;
strretchomp(nextline);
- log_print("IMAP4< %s\n", nextline);
+ /* log_print("IMAP4< %s\n", nextline); */
+ debug_print("IMAP4< %s\n", nextline);
g_free(nextline);
while (isspace(*cur_pos)) cur_pos++;
g_string_append(str, nextline);
cur_pos = str->str;
strretchomp(nextline);
- log_print("IMAP4< %s\n", nextline);
+ /* log_print("IMAP4< %s\n", nextline); */
+ debug_print("IMAP4< %s\n", nextline);
g_free(nextline);
} while (line_len < len);
{
gchar *real_path;
gint ok;
+ gint exists_, recent_, unseen_, uid_validity_;
+
+ if (!exists || !recent || !unseen || !uid_validity) {
+ if (session->mbox && strcmp(session->mbox, path) == 0)
+ return IMAP_SUCCESS;
+ exists = &exists_;
+ recent = &recent_;
+ unseen = &unseen_;
+ uid_validity = &uid_validity_;
+ }
+
+ g_free(session->mbox);
+ session->mbox = NULL;
real_path = imap_get_real_path(folder, path);
ok = imap_cmd_select(SESSION(session)->sock, real_path,
exists, recent, unseen, uid_validity);
if (ok != IMAP_SUCCESS)
log_warning(_("can't select folder: %s\n"), real_path);
+ else
+ session->mbox = g_strdup(path);
g_free(real_path);
return ok;
static gint imap_status(IMAPSession *session, IMAPFolder *folder,
const gchar *path,
- gint *messages, gint *recent, gint *unseen,
- guint32 *uid_validity)
+ gint *messages, gint *recent,
+ guint32 *uid_next, guint32 *uid_validity,
+ gint *unseen)
{
gchar *real_path;
gchar *real_path_;
GPtrArray *argbuf;
gchar *str;
- *messages = *recent = *unseen = *uid_validity = 0;
+ *messages = *recent = *uid_next = *uid_validity = *unseen = 0;
argbuf = g_ptr_array_new();
real_path = imap_get_real_path(folder, path);
QUOTE_IF_REQUIRED(real_path_, real_path);
imap_cmd_gen_send(SESSION(session)->sock, "STATUS %s "
- "(MESSAGES RECENT UNSEEN UIDVALIDITY)", real_path_);
+ "(MESSAGES RECENT UIDNEXT UIDVALIDITY UNSEEN)",
+ real_path_);
ok = imap_cmd_ok(SESSION(session)->sock, argbuf);
if (ok != IMAP_SUCCESS) THROW(ok);
} else if (!strncmp(str, "RECENT ", 7)) {
str += 7;
*recent = strtol(str, &str, 10);
- } else if (!strncmp(str, "UNSEEN ", 7)) {
- str += 7;
- *unseen = strtol(str, &str, 10);
+ } else if (!strncmp(str, "UIDNEXT ", 8)) {
+ str += 8;
+ *uid_next = strtoul(str, &str, 10);
} else if (!strncmp(str, "UIDVALIDITY ", 12)) {
str += 12;
*uid_validity = strtoul(str, &str, 10);
+ } else if (!strncmp(str, "UNSEEN ", 7)) {
+ str += 7;
+ *unseen = strtol(str, &str, 10);
} else {
g_warning("invalid STATUS response: %s\n", str);
break;
imap_cmd_gen_send(sock, "UID FETCH %d BODY[]", uid);
- if (sock_gets(sock, buf, sizeof(buf)) < 0)
- return IMAP_ERROR;
- strretchomp(buf);
- if (buf[0] != '*' || buf[1] != ' ')
- return IMAP_ERROR;
- log_print("IMAP4< %s\n", buf);
+ while ((ok = imap_cmd_gen_recv(sock, buf, sizeof(buf)))
+ == IMAP_SUCCESS) {
+ if (buf[0] != '*' || buf[1] != ' ')
+ return IMAP_ERROR;
+ if (strstr(buf, "FETCH") != NULL)
+ break;
+ }
+ if (ok != IMAP_SUCCESS)
+ return ok;
cur_pos = strchr(buf, '{');
g_return_val_if_fail(cur_pos != NULL, IMAP_ERROR);