FolderItem item;
guint lastuid;
+ guint uid_next;
GSList *uid_list;
};
static gint imap_cmd_fetch (SockInfo *sock,
guint32 uid,
const gchar *filename);
-static gint imap_cmd_append (SockInfo *sock,
+static gint imap_cmd_append (IMAPSession *session,
const gchar *destfolder,
- const gchar *file);
+ const gchar *file,
+ gint32 *newuid);
static gint imap_cmd_copy (IMAPSession *session,
gint32 msgnum,
const gchar *destfolder,
gint num);
gboolean imap_check_msgnum_validity (Folder *folder,
FolderItem *item);
+void imap_change_flags (Folder *folder,
+ FolderItem *item,
+ MsgInfo *msginfo,
+ MsgPermFlags newflags);
FolderClass imap_class =
{
F_IMAP,
"imap",
+ "IMAP4",
+
+ /* Folder functions */
+ imap_folder_new,
+ imap_folder_destroy,
+ imap_scan_tree,
+ imap_create_tree,
+ /* FolderItem functions */
imap_folder_item_new,
imap_folder_item_destroy,
- imap_fetch_msg,
+ imap_create_folder,
+ imap_rename_folder,
+ imap_remove_folder,
+ imap_get_num_list,
+ NULL,
+ NULL,
+ NULL,
+ imap_check_msgnum_validity,
+
+ /* Message functions */
imap_get_msginfo,
imap_get_msginfos,
+ imap_fetch_msg,
imap_add_msg,
imap_move_msg,
NULL,
imap_remove_msgs,
imap_remove_all_msg,
imap_is_msg_changed,
- NULL,
- imap_get_num_list,
- imap_scan_tree,
- imap_create_tree,
- imap_create_folder,
- imap_rename_folder,
- imap_remove_folder,
- imap_folder_destroy,
- NULL,
- NULL,
- NULL,
- NULL,
- imap_check_msgnum_validity,
+ imap_change_flags,
};
FolderClass *imap_get_class()
item = g_new0(IMAPFolderItem, 1);
item->lastuid = 0;
+ item->uid_next = 0;
item->uid_list = NULL;
return (FolderItem *)item;
IMAPFolderItem *item = (IMAPFolderItem *)node->data;
item->lastuid = 0;
+ item->uid_next = 0;
g_slist_free(item->uid_list);
item->uid_list = NULL;
gushort port;
g_return_val_if_fail(folder != NULL, NULL);
- g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, NULL);
+ g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, NULL);
g_return_val_if_fail(folder->account != NULL, NULL);
#if USE_OPENSSL
{
gchar *destdir;
IMAPSession *session;
- gint ok;
+ gint ok, newuid;
g_return_val_if_fail(folder != NULL, -1);
g_return_val_if_fail(dest != NULL, -1);
if (!session) return -1;
destdir = imap_get_real_path(IMAP_FOLDER(folder), dest->path);
- ok = imap_cmd_append(SESSION(session)->sock, destdir, file);
+ ok = imap_cmd_append(session, destdir, file, &newuid);
g_free(destdir);
if (ok != IMAP_SUCCESS) {
FILE_OP_ERROR(file, "unlink");
}
- return 0;
+ return newuid;
}
static gint imap_do_copy(Folder *folder, FolderItem *dest, MsgInfo *msginfo,
gchar *destdir;
IMAPSession *session;
IMAPFlags iflags = 0;
- gint messages, recent, unseen;
- guint32 newuid = 0, uid_validity;
+ guint32 newuid = 0;
gint ok;
g_return_val_if_fail(folder != NULL, -1);
- g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, -1);
+ g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, -1);
g_return_val_if_fail(dest != NULL, -1);
g_return_val_if_fail(msginfo != NULL, -1);
return -1;
}
- /* if we don't have UIDPLUS we get UID-NEXT and hope that the
- message really gets this uid */
- if (!imap_has_capability(session, "UIDPLUS")) {
- ok = imap_status(session, IMAP_FOLDER(folder), dest->path,
- &messages, &recent, &newuid, &uid_validity, &unseen);
- if (ok != IMAP_SUCCESS) {
- g_warning("can't copy message\n");
- return -1;
- }
- }
-
destdir = imap_get_real_path(IMAP_FOLDER(folder), dest->path);
/* ensure source folder selected */
gchar *dir;
g_return_val_if_fail(folder != NULL, -1);
- g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, -1);
+ g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, -1);
g_return_val_if_fail(item != NULL, -1);
session = imap_session_get(folder);
guint32 uid;
g_return_val_if_fail(folder != NULL, -1);
- g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, -1);
+ g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, -1);
g_return_val_if_fail(item != NULL, -1);
g_return_val_if_fail(msglist != NULL, -1);
g_return_val_if_fail(session != NULL, NULL);
g_return_val_if_fail(item != NULL, NULL);
g_return_val_if_fail(item->folder != NULL, NULL);
- g_return_val_if_fail(FOLDER_TYPE(item->folder) == F_IMAP, NULL);
+ g_return_val_if_fail(FOLDER_CLASS(item->folder) == &imap_class, NULL);
g_return_val_if_fail(first_uid <= last_uid, NULL);
if (imap_cmd_envelope(SESSION(session)->sock, first_uid, last_uid)
g_return_if_fail(item != NULL);
g_return_if_fail(item->folder != NULL);
- g_return_if_fail(FOLDER_TYPE(item->folder) == F_IMAP);
+ g_return_if_fail(FOLDER_CLASS(item->folder) == &imap_class);
debug_print("Deleting all cached messages...\n");
g_return_val_if_fail(msginfo->folder->folder != NULL, -1);
folder = msginfo->folder->folder;
- g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, -1);
+ g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, -1);
session = imap_session_get(folder);
if (!session) return -1;
g_return_val_if_fail(msginfo->folder->folder != NULL, -1);
folder = msginfo->folder->folder;
- g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, -1);
+ g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, -1);
session = imap_session_get(folder);
if (!session) return -1;
return ok;
}
-static gint imap_cmd_append(SockInfo *sock, const gchar *destfolder,
- const gchar *file)
+static gint imap_cmd_append(IMAPSession *session, const gchar *destfolder,
+ const gchar *file, gint32 *new_uid)
{
gint ok;
- gint size;
+ gint size, newuid;
gchar *destfolder_;
gchar buf[BUFFSIZE], *imapbuf;
FILE *fp;
+ GPtrArray *reply;
+ gchar *okmsginfo;
g_return_val_if_fail(file != NULL, IMAP_ERROR);
return -1;
}
QUOTE_IF_REQUIRED(destfolder_, destfolder);
- imap_cmd_gen_send(sock, "APPEND %s (\\Seen) {%d}", destfolder_, size);
+ imap_cmd_gen_send(SESSION(session)->sock, "APPEND %s (\\Seen) {%d}", destfolder_, size);
- ok = imap_cmd_gen_recv(sock, &imapbuf);
+ ok = imap_cmd_gen_recv(SESSION(session)->sock, &imapbuf);
if (ok != IMAP_SUCCESS || imapbuf[0] != '+' || imapbuf[1] != ' ') {
log_warning(_("can't append %s to %s\n"), file, destfolder_);
g_free(imapbuf);
while (fgets(buf, sizeof(buf), fp) != NULL) {
strretchomp(buf);
- if (sock_puts(sock, buf) < 0) {
+ if (sock_puts(SESSION(session)->sock, buf) < 0) {
fclose(fp);
- sock_close(sock);
+ sock_close(SESSION(session)->sock);
return -1;
}
}
if (ferror(fp)) {
FILE_OP_ERROR(file, "fgets");
fclose(fp);
- sock_close(sock);
+ sock_close(SESSION(session)->sock);
return -1;
}
- sock_puts(sock, "");
+ sock_puts(SESSION(session)->sock, "");
fclose(fp);
- return imap_cmd_ok(sock, NULL);
-}
-
-#if 0
-static void imap_uidplus_copy(IMAPSession *session, MsgInfo *msginfo,
- const gchar *destfolder, const gchar *okmsginfo)
-{
- unsigned int olduid, newuid;
- IMAPFlags iflags = 0;
-
- if (okmsginfo == NULL)
- return;
- if (sscanf(okmsginfo, "%*u OK [COPYUID %*llu %u %u]", &olduid, &newuid) != 2)
- return;
-
- if (olduid != msginfo->msgnum) /* this should NEVER happen */
- return;
-
- if (imap_select(session, IMAP_FOLDER(msginfo->folder->folder), destfolder,
- NULL, NULL, NULL, NULL) != IMAP_SUCCESS)
- return;
-
- if (msginfo->flags.perm_flags & MSG_MARKED) iflags |= IMAP_FLAG_FLAGGED;
- if (msginfo->flags.perm_flags & MSG_REPLIED) iflags |= IMAP_FLAG_ANSWERED;
- if (iflags)
- imap_set_message_flags(session, newuid, newuid, iflags, TRUE);
+ reply = g_ptr_array_new();
- if (msginfo->flags.perm_flags & MSG_UNREAD)
- imap_set_message_flags(session, newuid, newuid, IMAP_FLAG_SEEN, FALSE);
+ *new_uid = 0;
+ ok = imap_cmd_ok(SESSION(session)->sock, reply);
+ if (ok != IMAP_SUCCESS)
+ log_warning(_("can't append message to %s\n"), destfolder_);
+ else if (
+ (new_uid != NULL) &&
+ (imap_has_capability(session, "UIDPLUS") && reply->len > 0) &&
+ ((okmsginfo = g_ptr_array_index(reply, reply->len - 1)) != NULL) &&
+ (sscanf(okmsginfo, "%*u OK [APPENDUID %*u %u]", &newuid) == 1)) {
+ *new_uid = newuid;
+ }
- imap_select(session, IMAP_FOLDER(msginfo->folder->folder), msginfo->folder->path,
- NULL, NULL, NULL, NULL);
+ ptr_array_free_strings(reply);
+ g_ptr_array_free(reply, TRUE);
+ return ok;
}
-#endif
-static gint imap_cmd_copy(IMAPSession *session,
- gint32 msgnum, const gchar *destfolder, gint32 *new_uid)
+
+static gint imap_cmd_copy(IMAPSession * session,
+ gint32 msgnum,
+ const gchar * destfolder, gint32 * new_uid)
{
gint ok;
gint32 olduid, newuid;
reply = g_ptr_array_new();
+ *new_uid = 0;
ok = imap_cmd_ok(SESSION(session)->sock, reply);
if (ok != IMAP_SUCCESS)
log_warning(_("can't copy %d to %s\n"), msgnum, destfolder_);
return FALSE;
}
-gint imap_get_num_list(Folder *folder, FolderItem *_item, GSList **msgnum_list)
+static gint get_list_of_uids(Folder *folder, IMAPFolderItem *item, GSList **msgnum_list)
{
- IMAPFolderItem *item = (IMAPFolderItem *)_item;
+ gint ok, nummsgs = 0, lastuid_old;
IMAPSession *session;
- gint ok, lastuid_old, nummsgs = 0, exists, resent, unseen, uid_val;
GSList *uidlist, *elem;
- gchar *dir, *cmd_buf;
-
- g_return_val_if_fail(folder != NULL, -1);
- g_return_val_if_fail(item != NULL, -1);
- g_return_val_if_fail(item->item.path != NULL, -1);
- g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, -1);
- g_return_val_if_fail(folder->account != NULL, -1);
+ gchar *cmd_buf;
session = imap_session_get(folder);
g_return_val_if_fail(session != NULL, -1);
ok = imap_select(session, IMAP_FOLDER(folder), item->item.path,
- &exists, &resent, &unseen, &uid_val);
+ NULL, NULL, NULL, NULL);
if (ok != IMAP_SUCCESS)
return -1;
- if (exists == 0)
- return 0;
-
cmd_buf = g_strdup_printf("UID %d:*", item->lastuid + 1);
ok = imap_cmd_search(SESSION(session)->sock, cmd_buf, &uidlist);
g_free(cmd_buf);
lastuid_old = item->lastuid;
*msgnum_list = g_slist_copy(item->uid_list);
+ nummsgs = g_slist_length(*msgnum_list);
debug_print("Got %d uids from cache\n", g_slist_length(item->uid_list));
for (elem = uidlist; elem != NULL; elem = g_slist_next(elem)) {
}
g_slist_free(uidlist);
- if (g_slist_length(item->uid_list) != exists) {
+ return nummsgs;
+}
+
+gint imap_get_num_list(Folder *folder, FolderItem *_item, GSList **msgnum_list)
+{
+ IMAPFolderItem *item = (IMAPFolderItem *)_item;
+ IMAPSession *session;
+ gint ok, nummsgs = 0, exists, recent, unseen, uid_val, uid_next;
+ GSList *uidlist;
+ gchar *dir;
+
+ g_return_val_if_fail(folder != NULL, -1);
+ g_return_val_if_fail(item != NULL, -1);
+ g_return_val_if_fail(item->item.path != NULL, -1);
+ g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, -1);
+ g_return_val_if_fail(folder->account != NULL, -1);
+
+ session = imap_session_get(folder);
+ g_return_val_if_fail(session != NULL, -1);
+
+ ok = imap_status(session, IMAP_FOLDER(folder), item->item.path,
+ &exists, &recent, &uid_next, &uid_val, &unseen);
+ if (ok != IMAP_SUCCESS)
+ return -1;
+
+ /* If old uid_next matches new uid_next we can be sure no message
+ was added to the folder */
+ if (uid_next == item->uid_next) {
+ nummsgs = g_slist_length(item->uid_list);
+
+ /* If number of messages is still the same we
+ know our caches message numbers are still valid,
+ otherwise if the number of messages has decrease
+ we discard our cache to start a new scan to find
+ out which numbers have been removed */
+ if (exists == nummsgs) {
+ *msgnum_list = g_slist_copy(item->uid_list);
+ return nummsgs;
+ } else if (exists < nummsgs) {
+ debug_print("Freeing imap uid cache");
+ item->lastuid = 0;
+ g_slist_free(item->uid_list);
+ item->uid_list = NULL;
+ }
+ }
+ item->uid_next = uid_next;
+
+ if (exists == 0) {
+ *msgnum_list = NULL;
+ return 0;
+ }
+
+ nummsgs = get_list_of_uids(folder, item, &uidlist);
+
+ if (nummsgs != exists) {
/* Cache contains more messages then folder, we have cached
- an old UID of a message that was removed */
+ an old UID of a message that was removed and new messages
+ have been added too, otherwise the uid_next check would
+ not have failed */
debug_print("Freeing imap uid cache");
item->lastuid = 0;
g_slist_free(item->uid_list);
g_slist_free(*msgnum_list);
- return imap_get_num_list(folder, _item, msgnum_list);
+ nummsgs = get_list_of_uids(folder, item, &uidlist);
}
+ *msgnum_list = uidlist;
+
dir = folder_item_get_path((FolderItem *)item);
debug_print("removing old messages from %s\n", dir);
remove_numbered_files_not_in_list(dir, *msgnum_list);
g_return_val_if_fail(folder != NULL, FALSE);
g_return_val_if_fail(item != NULL, FALSE);
g_return_val_if_fail(item->item.folder != NULL, FALSE);
- g_return_val_if_fail(FOLDER_TYPE(item->item.folder) == F_IMAP, FALSE);
+ g_return_val_if_fail(FOLDER_CLASS(item->item.folder) == &imap_class, FALSE);
session = imap_session_get(folder);
g_return_val_if_fail(session != NULL, FALSE);
return FALSE;
}
+
+void imap_change_flags(Folder *folder, FolderItem *item, MsgInfo *msginfo, MsgPermFlags newflags)
+{
+ IMAPSession *session;
+ IMAPFlags flags_set = 0, flags_unset = 0;
+ gint ok = IMAP_SUCCESS;
+
+ g_return_if_fail(folder != NULL);
+ g_return_if_fail(folder->class == &imap_class);
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(item->folder == folder);
+ g_return_if_fail(msginfo != NULL);
+ g_return_if_fail(msginfo->folder == item);
+
+ session = imap_session_get(folder);
+ if (!session) return;
+
+ if ((ok = imap_select(session, IMAP_FOLDER(folder), msginfo->folder->path,
+ NULL, NULL, NULL, NULL)) != IMAP_SUCCESS)
+ return;
+
+ if (!MSG_IS_MARKED(msginfo->flags) && (newflags & MSG_MARKED))
+ flags_set |= IMAP_FLAG_FLAGGED;
+ if ( MSG_IS_MARKED(msginfo->flags) && !(newflags & MSG_MARKED))
+ flags_unset |= IMAP_FLAG_FLAGGED;
+
+ if (!MSG_IS_UNREAD(msginfo->flags) && (newflags & MSG_UNREAD))
+ flags_unset |= IMAP_FLAG_SEEN;
+ if ( MSG_IS_UNREAD(msginfo->flags) && !(newflags & MSG_UNREAD))
+ flags_set |= IMAP_FLAG_SEEN;
+
+ if (!MSG_IS_REPLIED(msginfo->flags) && (newflags & MSG_REPLIED))
+ flags_set |= IMAP_FLAG_ANSWERED;
+ if ( MSG_IS_REPLIED(msginfo->flags) && !(newflags & MSG_REPLIED))
+ flags_set |= IMAP_FLAG_ANSWERED;
+
+ if (flags_set) {
+ ok = imap_set_message_flags(session, msginfo->msgnum,
+ msginfo->msgnum, flags_set, TRUE);
+ if (ok != IMAP_SUCCESS) return;
+ }
+
+ if (flags_unset) {
+ ok = imap_set_message_flags(session, msginfo->msgnum,
+ msginfo->msgnum, flags_unset, FALSE);
+ if (ok != IMAP_SUCCESS) return;
+ }
+
+ msginfo->flags.perm_flags = newflags;
+
+ return;
+}