0.9.3claws64
[claws.git] / src / imap.c
index 297da51d925f878b1283eaee13979418c96a2d82..0df7e4318a27bb1af2cb067225e8c3ea2a94c685 100644 (file)
@@ -163,7 +163,10 @@ static void imap_session_destroy(Session * session);
 static gchar *imap_fetch_msg(Folder * folder, FolderItem * item, gint uid);
 static gint imap_add_msg(Folder * folder,
                         FolderItem * dest,
-                        const gchar * file);
+                        const gchar * file, MsgFlags * flags);
+static gint imap_add_msgs(Folder * folder, FolderItem * dest,
+                         GSList * file_list,
+                         GRelation *relation);
 
 static gint imap_copy_msg(Folder * folder,
                          FolderItem * dest, MsgInfo * msginfo);
@@ -174,6 +177,8 @@ static gint imap_remove_all_msg(Folder * folder, FolderItem * item);
 static gboolean imap_is_msg_changed(Folder * folder,
                                    FolderItem * item, MsgInfo * msginfo);
 
+static gint imap_close(Folder * folder, FolderItem * item);
+
 static void imap_scan_tree(Folder * folder);
 
 static gint imap_create_tree(Folder * folder);
@@ -245,9 +250,10 @@ static SockInfo *imap_init_sock(SockInfo *sock, SSLType    ssl_type);
 static SockInfo *imap_init_sock(SockInfo *sock);
 #endif
 
+static gchar *imap_get_flag_str                (IMAPFlags       flags);
 static gint imap_set_message_flags     (IMAPSession    *session,
                                         MsgNumberList  *numlist,
-                                        IMAPFlags       flag,
+                                        IMAPFlags       flags,
                                         gboolean        is_set);
 static gint imap_select                        (IMAPSession    *session,
                                         IMAPFolder     *folder,
@@ -344,6 +350,7 @@ static gint imap_cmd_fetch  (IMAPSession    *sock,
 static gint imap_cmd_append    (IMAPSession    *session,
                                 const gchar    *destfolder,
                                 const gchar    *file,
+                                IMAPFlags       flags,
                                 gint32         *newuid);
 static gint imap_cmd_copy      (IMAPSession    *session,
                                 gint32         msgnum,
@@ -353,13 +360,14 @@ static gint imap_cmd_store        (IMAPSession    *sock,
                                 IMAPSet         set,
                                 gchar          *sub_cmd);
 static gint imap_cmd_expunge   (IMAPSession    *sock);
+static gint imap_cmd_close     (IMAPSession    *session);
 
 static gint imap_cmd_ok                (IMAPSession    *session,
                                 GPtrArray      *argbuf);
 static void imap_gen_send      (IMAPSession    *sock,
                                 const gchar    *format, ...);
 static gint imap_gen_recv      (IMAPSession    *sock,
-                                gchar         **buf);
+                                gchar         **ret);
 
 /* misc utility functions */
 static gchar *strchr_cpy                       (const gchar    *src,
@@ -420,6 +428,7 @@ FolderClass imap_class =
        imap_create_folder,
        imap_rename_folder,
        imap_remove_folder,
+       imap_close,
        imap_get_num_list,
        NULL,
        NULL,
@@ -431,7 +440,7 @@ FolderClass imap_class =
        imap_get_msginfos,
        imap_fetch_msg,
        imap_add_msg,
-       NULL,
+       imap_add_msgs,
        imap_copy_msg,
        NULL,
        imap_remove_msg,
@@ -779,29 +788,79 @@ gchar *imap_fetch_msg(Folder *folder, FolderItem *item, gint uid)
        return filename;
 }
 
-gint imap_add_msg(Folder *folder, FolderItem *dest, const gchar *file)
+gint imap_add_msg(Folder *folder, FolderItem *dest, const gchar *file, MsgFlags *flags)
+{
+       gint ret;
+       GSList file_list;
+       MsgFileInfo fileinfo;
+
+       g_return_val_if_fail(file != NULL, -1);
+
+       fileinfo.file = (gchar *)file;
+       fileinfo.flags = flags;
+       file_list.data = &fileinfo;
+       file_list.next = NULL;
+
+       ret = imap_add_msgs(folder, dest, &file_list, NULL);
+       return ret;
+}
+
+gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
+                  GRelation *relation)
 {
        gchar *destdir;
        IMAPSession *session;
-       gint ok, newuid;
+       guint32 last_uid = 0;
+       GSList *cur;
+       MsgFileInfo *fileinfo;
+       gint ok, newnum;
 
        g_return_val_if_fail(folder != NULL, -1);
        g_return_val_if_fail(dest != NULL, -1);
-       g_return_val_if_fail(file != NULL, -1);
+       g_return_val_if_fail(file_list != NULL, -1);
 
        session = imap_session_get(folder);
        if (!session) return -1;
 
        destdir = imap_get_real_path(IMAP_FOLDER(folder), dest->path);
-       ok = imap_cmd_append(session, destdir, file, &newuid);
-       g_free(destdir);
 
-       if (ok != IMAP_SUCCESS) {
-               g_warning("can't append message %s\n", file);
-               return -1;
+       for (cur = file_list; cur != NULL; cur = cur->next) {
+               IMAPFlags iflags = 0;
+
+               fileinfo = (MsgFileInfo *)cur->data;
+
+               if (fileinfo->flags) {
+                       if (MSG_IS_MARKED(*fileinfo->flags))
+                               iflags |= IMAP_FLAG_FLAGGED;
+                       if (MSG_IS_REPLIED(*fileinfo->flags))
+                               iflags |= IMAP_FLAG_ANSWERED;
+                       if (!MSG_IS_UNREAD(*fileinfo->flags))
+                               iflags |= IMAP_FLAG_SEEN;
+               }
+
+               if (dest->stype == F_OUTBOX ||
+                   dest->stype == F_QUEUE  ||
+                   dest->stype == F_DRAFT  ||
+                   dest->stype == F_TRASH)
+                       iflags |= IMAP_FLAG_SEEN;
+
+               ok = imap_cmd_append(session, destdir, fileinfo->file, iflags, &newnum);
+
+               if (ok != IMAP_SUCCESS) {
+                       g_warning("can't append message %s\n", fileinfo->file);
+                       g_free(destdir);
+                       return -1;
+               }
+
+               if (relation != NULL)
+                       g_relation_insert(relation, fileinfo, GINT_TO_POINTER(newnum));
+               if (newnum > last_uid)
+                       last_uid = newnum;
        }
 
-       return newuid;
+       g_free(destdir);
+
+       return last_uid;
 }
 
 static gint imap_do_copy(Folder *folder, FolderItem *dest, MsgInfo *msginfo,
@@ -879,7 +938,7 @@ gint imap_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
        srcfile = procmsg_get_message_file(msginfo);
        if (!srcfile) return -1;
 
-       ret = imap_add_msg(folder, dest, srcfile);
+       ret = imap_add_msg(folder, dest, srcfile, NULL);
 
        g_free(srcfile);
 
@@ -979,6 +1038,30 @@ gboolean imap_is_msg_changed(Folder *folder, FolderItem *item, MsgInfo *msginfo)
        return FALSE;
 }
 
+gint imap_close(Folder *folder, FolderItem *item)
+{
+       gint ok;
+       IMAPSession *session;
+
+       g_return_val_if_fail(folder != NULL, -1);
+
+       session = imap_session_get(folder);
+       if (!session) return -1;
+
+       if (session->mbox) {
+               ok = imap_cmd_close(session);
+               if (ok != IMAP_SUCCESS)
+                       log_warning(_("can't close folder\n"));
+
+               g_free(session->mbox);
+               session->mbox = NULL;
+
+               return ok;
+       }
+
+       return 0;
+}
+
 void imap_scan_tree(Folder *folder)
 {
        FolderItem *item;
@@ -2101,35 +2184,49 @@ static MsgInfo *imap_parse_envelope(SockInfo *sock, FolderItem *item,
        return msginfo;
 }
 
+static gchar *imap_get_flag_str(IMAPFlags flags)
+{
+       GString *str;
+       gchar *ret;
+
+       str = g_string_new(NULL);
+
+       if (IMAP_IS_SEEN(flags))        g_string_append(str, "\\Seen ");
+       if (IMAP_IS_ANSWERED(flags))    g_string_append(str, "\\Answered ");
+       if (IMAP_IS_FLAGGED(flags))     g_string_append(str, "\\Flagged ");
+       if (IMAP_IS_DELETED(flags))     g_string_append(str, "\\Deleted ");
+       if (IMAP_IS_DRAFT(flags))       g_string_append(str, "\\Draft");
+
+       if (str->len > 0 && str->str[str->len - 1] == ' ')
+               g_string_truncate(str, str->len - 1);
+
+       ret = str->str;
+       g_string_free(str, FALSE);
+
+       return ret;
+}
+
 static gint imap_set_message_flags(IMAPSession *session,
                                   MsgNumberList *numlist,
                                   IMAPFlags flags,
                                   gboolean is_set)
 {
-       GString *buf;
+       gchar *cmd;
+       gchar *flag_str;
        gint ok;
        IMAPSet imapset;
 
-       buf = g_string_new(is_set ? "+FLAGS (" : "-FLAGS (");
-
-       if (IMAP_IS_SEEN(flags))        g_string_append(buf, "\\Seen ");
-       if (IMAP_IS_ANSWERED(flags))    g_string_append(buf, "\\Answered ");
-       if (IMAP_IS_FLAGGED(flags))     g_string_append(buf, "\\Flagged ");
-       if (IMAP_IS_DELETED(flags))     g_string_append(buf, "\\Deleted ");
-       if (IMAP_IS_DRAFT(flags))       g_string_append(buf, "\\Draft");
-
-       if (buf->str[buf->len - 1] == ' ')
-               g_string_truncate(buf, buf->len - 1);
-
-       g_string_append_c(buf, ')');
+       flag_str = imap_get_flag_str(flags);
+       cmd = g_strconcat(is_set ? "+FLAGS.SILENT (" : "-FLAGS.SILENT (",
+                         flag_str, ")", NULL);
+       g_free(flag_str);
 
        imapset = numberlist_to_imapset(numlist);
        while (imapset != NULL) {
-               ok = imap_cmd_store(session, imapset,
-                                   buf->str);
+               ok = imap_cmd_store(session, imapset, cmd);
                imapset = numberlist_to_imapset(NULL);
        }
-       g_string_free(buf, TRUE);
+       g_free(cmd);
 
        return ok;
 }
@@ -2244,7 +2341,7 @@ static gint imap_cmd_authenticate(IMAPSession *session, const gchar *user,
 {
        gchar *auth_type;
        gint ok;
-       gchar *buf;
+       gchar *buf = NULL;
        gchar *challenge;
        gint challenge_len;
        gchar hexdigest[33];
@@ -2263,8 +2360,8 @@ static gint imap_cmd_authenticate(IMAPSession *session, const gchar *user,
        challenge = g_malloc(strlen(buf + 2) + 1);
        challenge_len = base64_decode(challenge, buf + 2, -1);
        challenge[challenge_len] = '\0';
-       log_print("IMAP< [Decoded: %s]\n", challenge);
        g_free(buf);
+       log_print("IMAP< [Decoded: %s]\n", challenge);
 
        md5_hex_hmac(hexdigest, challenge, challenge_len, pass, strlen(pass));
        g_free(challenge);
@@ -2630,7 +2727,7 @@ static gint imap_cmd_search(IMAPSession *session, const gchar *criteria, GSList
 static gint imap_cmd_fetch(IMAPSession *session, guint32 uid, const gchar *filename)
 {
        gint ok;
-       gchar *buf;
+       gchar *buf = NULL;
        gchar *cur_pos;
        gchar size_str[32];
        glong size_num;
@@ -2639,14 +2736,12 @@ static gint imap_cmd_fetch(IMAPSession *session, guint32 uid, const gchar *filen
 
        imap_gen_send(session, "UID FETCH %d BODY.PEEK[]", uid);
 
-       while ((ok = imap_gen_recv(session, &buf))
-              == IMAP_SUCCESS) {
+       while ((ok = imap_gen_recv(session, &buf)) == IMAP_SUCCESS) {
                if (buf[0] != '*' || buf[1] != ' ') {
                        g_free(buf);
                        return IMAP_ERROR;
                }
-               if (strstr(buf, "FETCH") != NULL)
-                       break;
+               if (strstr(buf, "FETCH") != NULL) break;
                g_free(buf);
        }
        if (ok != IMAP_SUCCESS) {
@@ -2654,29 +2749,27 @@ static gint imap_cmd_fetch(IMAPSession *session, guint32 uid, const gchar *filen
                return ok;
        }
 
-       cur_pos = strchr(buf, '{');
-       if (cur_pos == NULL) {
-               g_free(buf);
-               return IMAP_ERROR;
+#define RETURN_ERROR_IF_FAIL(cond)     \
+       if (!(cond)) {                  \
+               g_free(buf);            \
+               return IMAP_ERROR;      \
        }
 
+       cur_pos = strchr(buf, '{');
+       RETURN_ERROR_IF_FAIL(cur_pos != NULL);
        cur_pos = strchr_cpy(cur_pos + 1, '}', size_str, sizeof(size_str));
-       if (cur_pos == NULL) {
-               g_free(buf);
-               return IMAP_ERROR;
-       }
+       RETURN_ERROR_IF_FAIL(cur_pos != NULL);
        size_num = atol(size_str);
-       g_return_val_if_fail(size_num > 0, IMAP_ERROR);
+       RETURN_ERROR_IF_FAIL(size_num > 0);
 
-       if (*cur_pos != '\0') {
-               g_free(buf);
-               return IMAP_ERROR;
-       }
+       RETURN_ERROR_IF_FAIL(*cur_pos == '\0');
 
-       if (recv_bytes_write_to_file(SESSION(session)->sock, size_num, filename) != 0) {
-               g_free(buf);
+#undef RETURN_ERROR_IF_FAIL
+
+       g_free(buf);
+
+       if (recv_bytes_write_to_file(SESSION(session)->sock, size_num, filename) != 0)
                return IMAP_ERROR;
-       }
 
        if (imap_gen_recv(session, &buf) != IMAP_SUCCESS) {
                g_free(buf);
@@ -2687,20 +2780,22 @@ static gint imap_cmd_fetch(IMAPSession *session, guint32 uid, const gchar *filen
                g_free(buf);
                return IMAP_ERROR;
        }
-
        g_free(buf);
+
        ok = imap_cmd_ok(session, NULL);
 
        return ok;
 }
 
 static gint imap_cmd_append(IMAPSession *session, const gchar *destfolder,
-                           const gchar *file, gint32 *new_uid)
+                           const gchar *file, IMAPFlags flags, gint32 *new_uid)
 {
        gint ok;
        gint size, newuid;
        gchar *destfolder_;
-       gchar buf[BUFFSIZE], *imapbuf;
+       gchar *flag_str;
+       gchar *ret = NULL;
+       gchar buf[BUFFSIZE];
        FILE *fp;
        GPtrArray *reply;
        gchar *okmsginfo;
@@ -2713,16 +2808,19 @@ static gint imap_cmd_append(IMAPSession *session, const gchar *destfolder,
                return -1;
        }
        QUOTE_IF_REQUIRED(destfolder_, destfolder);
-       imap_gen_send(session, "APPEND %s (\\Seen) {%d}", destfolder_, size);
+       flag_str = imap_get_flag_str(flags);
+       imap_gen_send(session, "APPEND %s (%s) {%d}", 
+                     destfolder_, flag_str, size);
+       g_free(flag_str);
 
-       ok = imap_gen_recv(session, &imapbuf);
-       if (ok != IMAP_SUCCESS || imapbuf[0] != '+' || imapbuf[1] != ' ') {
+       ok = imap_gen_recv(session, &ret);
+       if (ok != IMAP_SUCCESS || ret[0] != '+' || ret[1] != ' ') {
                log_warning(_("can't append %s to %s\n"), file, destfolder_);
-               g_free(imapbuf);
+               g_free(ret);
                fclose(fp);
                return IMAP_ERROR;
        }
-       g_free(imapbuf);
+       g_free(ret);
 
        log_print("IMAP4> %s\n", _("(sending file...)"));
 
@@ -2865,6 +2963,17 @@ static gint imap_cmd_expunge(IMAPSession *session)
        return IMAP_SUCCESS;
 }
 
+static gint imap_cmd_close(IMAPSession *session)
+{
+       gint ok;
+
+       imap_gen_send(session, "CLOSE");
+       if ((ok = imap_cmd_ok(session, NULL)) != IMAP_SUCCESS)
+               log_warning(_("error while imap command: CLOSE\n"));
+
+       return ok;
+}
+
 static gint imap_cmd_ok(IMAPSession *session, GPtrArray *argbuf)
 {
        gint ok = IMAP_SUCCESS;
@@ -2938,14 +3047,14 @@ static void imap_gen_send(IMAPSession *session, const gchar *format, ...)
        g_free(buf);
 }
 
-static gint imap_gen_recv(IMAPSession *session, gchar **buf)
+static gint imap_gen_recv(IMAPSession *session, gchar **ret)
 {
-       if ((*buf = sock_getline(SESSION(session)->sock)) == NULL)
+       if ((*ret = sock_getline(SESSION(session)->sock)) == NULL)
                return IMAP_SOCKET;
 
-       strretchomp(*buf);
+       strretchomp(*ret);
 
-       log_print("IMAP4< %s\n", *buf);
+       log_print("IMAP4< %s\n", *ret);
 
        return IMAP_SUCCESS;
 }