sync with 0.7.4cvs49
[claws.git] / src / imap.c
index a684338d0ef9cbf8fce09e81d603166f970651c0..747c4a843477046d8130c227db684439d68b8d2f 100644 (file)
@@ -144,8 +144,9 @@ static gint imap_status                     (IMAPSession    *session,
                                         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);
@@ -463,7 +464,7 @@ void imap_session_destroy_all(void)
                IMAPSession *session = (IMAPSession *)session_list->data;
 
                imap_cmd_logout(SESSION(session)->sock);
-               imap_session_destroy(session);
+               session_destroy(SESSION(session));
        }
 }
 
@@ -589,6 +590,15 @@ gchar *imap_fetch_msg(Folder *folder, FolderItem *item, gint uid)
                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);
 
@@ -922,28 +932,31 @@ gboolean imap_is_msg_changed(Folder *folder, FolderItem *item, 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 = recent;
+       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)
@@ -1143,7 +1156,8 @@ static GSList *imap_parse_list(IMAPSession *session, const gchar *real_path)
                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);
@@ -1179,6 +1193,7 @@ static void imap_create_missing_folders(Folder *folder)
        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");
@@ -1188,6 +1203,7 @@ static void imap_create_missing_folders(Folder *folder)
        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");
@@ -1216,6 +1232,8 @@ static FolderItem *imap_create_special_folder(Folder *folder,
                new_item = imap_create_folder(folder, folder->inbox, name);
                if (!new_item)
                        g_warning(_("Can't create '%s' under INBOX\n"), name);
+               else
+                       new_item->stype = stype;
        } else
                new_item->stype = stype;
 
@@ -1342,6 +1360,8 @@ gint imap_rename_folder(Folder *folder, FolderItem *item, const gchar *name)
 
        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();
@@ -1482,6 +1502,10 @@ static GSList *imap_get_uncached_messages(IMAPSession *session,
                        g_free(tmp);
                        break;
                }
+               if (strstr(tmp, "FETCH") == NULL) {
+                       g_free(tmp);
+                       continue;
+               }
                g_string_assign(str, tmp);
                g_free(tmp);
 
@@ -1571,6 +1595,8 @@ static SockInfo *imap_open_tunnel(const gchar *server,
        SockInfo *sock;
 
        if ((sock = sock_connect_cmd(server, tunnelcmd)) == NULL)
+               log_warning(_("Can't establish IMAP4 session with: %s\n"),
+                           server);
                return NULL;
 
        return imap_init_sock(sock);
@@ -1594,6 +1620,8 @@ static SockInfo *imap_open(const gchar *server, gushort port)
 
 #if USE_SSL
        if (use_ssl && !ssl_init_socket(sock)) {
+               log_warning(_("Can't establish IMAP4 session with: %s:%d\n"),
+                           server, port);
                sock_close(sock);
                return NULL;
        }
@@ -1608,6 +1636,7 @@ static SockInfo *imap_init_sock(SockInfo *sock)
        imap_cmd_count = 0;
 
        if (imap_cmd_noop(sock) != IMAP_SUCCESS) {
+               log_warning(_("Can't establish IMAP4 session\n"));
                sock_close(sock);
                return NULL;
        }
@@ -1615,8 +1644,6 @@ static SockInfo *imap_init_sock(SockInfo *sock)
        return sock;
 }
 
-
-
 #define THROW goto catch
 
 static void imap_parse_namespace(IMAPSession *session, IMAPFolder *folder)
@@ -1737,10 +1764,23 @@ static gchar *imap_parse_atom(SockInfo *sock, gchar *src,
                              gchar *dest, gint dest_len, GString *str)
 {
        gchar *cur_pos = src;
+       gchar *nextline;
 
        g_return_val_if_fail(str != NULL, cur_pos);
 
-       while (*cur_pos == ' ') cur_pos++;
+       /* read the next line if the current response buffer is empty */
+       while (isspace(*cur_pos)) cur_pos++;
+       while (*cur_pos == '\0') {
+               if ((nextline = sock_getline(sock)) == NULL)
+                       return cur_pos;
+               g_string_assign(str, nextline);
+               cur_pos = str->str;
+               strretchomp(nextline);
+               log_print("IMAP4< %s\n", nextline);
+               g_free(nextline);
+
+               while (isspace(*cur_pos)) cur_pos++;
+       }
 
        if (!strncmp(cur_pos, "NIL", 3)) {
                *dest = '\0';
@@ -1753,21 +1793,28 @@ static gchar *imap_parse_atom(SockInfo *sock, gchar *src,
        } else if (*cur_pos == '{') {
                gchar buf[32];
                gint len;
-               gchar *nextline;
+               gint line_len = 0;
 
                cur_pos = strchr_cpy(cur_pos + 1, '}', buf, sizeof(buf));
                len = atoi(buf);
 
-               if ((nextline = sock_getline(sock)) == NULL)
-                       return cur_pos;
-               strretchomp(nextline);
-               log_print("IMAP4< %s\n", nextline);
-               g_string_assign(str, nextline);
-
-               len = MIN(len, strlen(nextline));
-               memcpy(dest, nextline, MIN(len, dest_len - 1));
+               g_string_truncate(str, 0);
+               cur_pos = str->str;
+
+               do {
+                       if ((nextline = sock_getline(sock)) == NULL)
+                               return cur_pos;
+                       line_len += strlen(nextline);
+                       g_string_append(str, nextline);
+                       cur_pos = str->str;
+                       strretchomp(nextline);
+                       log_print("IMAP4< %s\n", nextline);
+                       g_free(nextline);
+               } while (line_len < len);
+
+               memcpy(dest, cur_pos, MIN(len, dest_len - 1));
                dest[MIN(len, dest_len - 1)] = '\0';
-               cur_pos = str->str + len;
+               cur_pos += len;
        }
 
        return cur_pos;
@@ -1869,8 +1916,8 @@ static MsgFlags imap_parse_flags(const gchar *flag_str)
        while ((p = strchr(p, '\\')) != NULL) {
                p++;
 
-               if (g_strncasecmp(p, "Recent", 6) == 0) {
-                       MSG_SET_PERM_FLAGS(flags, MSG_NEW|MSG_UNREAD);
+               if (g_strncasecmp(p, "Recent", 6) == 0 && MSG_IS_UNREAD(flags)) {
+                       MSG_SET_PERM_FLAGS(flags, MSG_NEW);
                } else if (g_strncasecmp(p, "Seen", 4) == 0) {
                        MSG_UNSET_PERM_FLAGS(flags, MSG_NEW|MSG_UNREAD);
                } else if (g_strncasecmp(p, "Deleted", 7) == 0) {
@@ -2150,12 +2197,27 @@ static gint imap_select(IMAPSession *session, IMAPFolder *folder,
 {
        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;
@@ -2195,8 +2257,9 @@ catch:
 
 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_;
@@ -2204,14 +2267,15 @@ static gint imap_status(IMAPSession *session, IMAPFolder *folder,
        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);
@@ -2231,12 +2295,15 @@ static gint imap_status(IMAPSession *session, IMAPFolder *folder,
                } 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;
@@ -2470,12 +2537,15 @@ static gint imap_cmd_fetch(SockInfo *sock, guint32 uid, const gchar *filename)
 
        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);