Partial downloading of pop3 mails
authorColin Leroy <colin@colino.net>
Wed, 14 Jul 2004 10:59:38 +0000 (10:59 +0000)
committerColin Leroy <colin@colino.net>
Wed, 14 Jul 2004 10:59:38 +0000 (10:59 +0000)
synced from gtk2
Please break it ;-) (and provide backtraces if you do)

24 files changed:
ChangeLog.claws
PATCHSETS
configure.ac
src/common/Makefile.am
src/common/defs.h
src/common/partial_download.c [new file with mode: 0644]
src/common/partial_download.h [new file with mode: 0644]
src/folder.c
src/gtk/quicksearch.c
src/inc.c
src/matcher.c
src/matcher.h
src/matcher_parser_parse.y
src/messageview.c
src/msgcache.c
src/noticeview.c
src/noticeview.h
src/pop.c
src/pop.h
src/prefs_matcher.c
src/procheader.c
src/procmsg.c
src/procmsg.h
src/summaryview.c

index 6af5c15042cf4817dae0e5902dba988c401cf81d..58a06ba4680723f87cd9c29f2fe46c2c28931b9d 100644 (file)
@@ -1,3 +1,28 @@
+2004-07-14 [colin]     0.9.12cvs21
+
+       * src/folder.c
+       * src/inc.c
+       * src/matcher.c
+       * src/matcher.h
+       * src/matcher_parser_parse.y
+       * src/messageview.c
+       * src/msgcache.c
+       * src/noticeview.c
+       * src/noticeview.h
+       * src/pop.c
+       * src/pop.h
+       * src/prefs_matcher.c
+       * src/procheader.c
+       * src/procmsg.c
+       * src/procmsg.h
+       * src/summaryview.c
+       * src/common/Makefile.am
+       * src/common/defs.h
+       * src/gtk/quicksearch.c
+       * src/common/partial_download.c ** NEW FILES **
+       * src/common/partial_download.h ** NEW FILES **
+               Partial downloading of pop3 mails
+
 2004-07-13 [christoph] 0.9.12cvs20
 
        * src/mimeview.c
index 701632f7dc89f01c9806c9a4e6cd59fa31af3e23..2d274867f76d1987188a4c3e4b46bb7099c5a0a2 100644 (file)
--- a/PATCHSETS
+++ b/PATCHSETS
@@ -7,3 +7,4 @@
 ( cvs diff -u -r 1.5 -r 1.6 src/gtk/quicksearch.c; ) > 0.9.12cvs19.patchset
 ( cvs diff -u -r 1.5 -r 1.6 src/gtk/quicksearch.c; ) > 0.9.12cvs19.patchset
 ( cvs diff -u -r 1.119 -r 1.120 src/mimeview.c; ) > 0.9.12cvs20.patchset
+( cvs diff -u -r 1.250 -r 1.251 src/folder.c; cvs diff -u -r 1.174 -r 1.175 src/inc.c; cvs diff -u -r 1.87 -r 1.88 src/matcher.c; cvs diff -u -r 1.47 -r 1.48 src/matcher.h; cvs diff -u -r 1.34 -r 1.35 src/matcher_parser_parse.y; cvs diff -u -r 1.118 -r 1.119 src/messageview.c; cvs diff -u -r 1.23 -r 1.24 src/msgcache.c; cvs diff -u -r 1.9 -r 1.10 src/noticeview.c; cvs diff -u -r 1.4 -r 1.5 src/noticeview.h; cvs diff -u -r 1.61 -r 1.62 src/pop.c; cvs diff -u -r 1.20 -r 1.21 src/pop.h; cvs diff -u -r 1.46 -r 1.47 src/prefs_matcher.c; cvs diff -u -r 1.56 -r 1.57 src/procheader.c; cvs diff -u -r 1.164 -r 1.165 src/procmsg.c; cvs diff -u -r 1.68 -r 1.69 src/procmsg.h; cvs diff -u -r 1.437 -r 1.438 src/summaryview.c; cvs diff -u -r 1.26 -r 1.27 src/common/Makefile.am; cvs diff -u -r 1.14 -r 1.15 src/common/defs.h; cvs diff -u -r 1.6 -r 1.7 src/gtk/quicksearch.c; ) > 0.9.12cvs21.patchset
index e67e81e0b5d7b969f38a3f6e6673c512ed0d7036..fdd453761e69352fa9d33833d9b015eff0538fe5 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=9
 MICRO_VERSION=12
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=20
+EXTRA_VERSION=21
 EXTRA_RELEASE=
 
 if test \( $EXTRA_VERSION -eq 0 \) -o \( "x$EXTRA_RELEASE" != "x" \); then
index 9d0d4e16081d7f6343851e41f6bfbfcbec8709f2..5a7ff1e6981f4937fbb31df9f56fb311f2d476bf 100644 (file)
@@ -7,6 +7,7 @@ libsylpheedcommon_la_SOURCES = \
        md5.c \
        mgutils.c \
        nntp.c \
+       partial_download.c \
        passcrypt.c \
        plugin.c \
        prefs.c \
@@ -36,6 +37,7 @@ sylpheedcommoninclude_HEADERS = \
        md5.h \
        mgutils.h \
        nntp.h \
+       partial_download.h \
        passcrypt.h \
        plugin.h \
        prefs.h \
index 6b5716c02fa88f62e46bbde94649d545ab436338..b6873c8c3e30d2a3e90a4c60c5122b54af32fd96 100644 (file)
@@ -77,7 +77,7 @@
 #define FOLDER_LIST            "folderlist.xml"
 #define CACHE_FILE             ".sylpheed_cache"
 #define MARK_FILE              ".sylpheed_mark"
-#define CACHE_VERSION          20
+#define CACHE_VERSION          21
 #define MARK_VERSION           2
 
 #define DEFAULT_SIGNATURE      ".signature"
diff --git a/src/common/partial_download.c b/src/common/partial_download.c
new file mode 100644 (file)
index 0000000..e5bbfc9
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ * This file (C) 2004 Colin Leroy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* Partial download:
+ * A mail which has been completely downloaded will have no special headers,
+ * and its entry in the uidl file will end by 0 (POP3_TOTALLY_RECEIVED);
+ *
+ * A mail which has been partially downloaded will have some special headers,
+ * and its entry in the uidl file will first be 1 (POP3_PARTIALLY_RECEIVED);
+ * the special headers will be including "SC-Marked-For-Download" which can 
+ * have three values:
+ * 0 (POP3_PARTIAL_DLOAD_UNKN) meaning that the user has not yet chosen to
+ *  download the mail or let it be deleted - this header is absent until the
+ *  user first chooses an action
+ * 1 (POP3_PARTIAL_DLOAD_DLOAD) meaning that the user wants to finish 
+ *  downloading the mail
+ * 2 (POP3_PARTIAL_DLOAD_DELE) meaning that the user does not want to finish
+ *  downloading the mail
+ * When updating this header to POP3_PARTIAL_DLOAD_DLOAD, the uidl line of
+ * this mail will end with the mail's physical path, which Sylpheed will remove
+ * after having downloaded the complete mail. msg->partial_recv will equal
+ * 2 (POP3_MUST_COMPLETE_RECV).
+ * When updating this header to POP3_PARTIAL_DLOAD_DELE, the uidl line of
+ * this mail will be 0 (POP3_TOTALLY_RECEIVED), which will let Sylpheed delete
+ * this mail from the server as soon as the leave_time preference specifies.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+
+#include "intl.h"
+#include "partial_download.h"
+#include "utils.h"
+#include "../pop.h"
+#include "../folder.h"
+
+int partial_msg_in_uidl_list(MsgInfo *msginfo)
+{
+       gchar *path;
+       FILE *fp;
+       gchar buf[POPBUFSIZE];
+       gchar uidl[POPBUFSIZE];
+       time_t recv_time;
+       time_t now;
+       gint partial_recv;
+       
+       if (!msginfo->account_server
+       ||  !msginfo->account_login
+       ||  !msginfo->partial_recv)
+               return FALSE;
+       
+       path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                          "uidl", G_DIR_SEPARATOR_S, msginfo->account_server,
+                          "-", msginfo->account_login, NULL);
+       if ((fp = fopen(path, "rb")) == NULL) {
+               if (ENOENT != errno) FILE_OP_ERROR(path, "fopen");
+               g_free(path);
+               path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                                  "uidl-", msginfo->account_server,
+                                  "-", msginfo->account_login, NULL);
+               if ((fp = fopen(path, "rb")) == NULL) {
+                       if (ENOENT != errno) FILE_OP_ERROR(path, "fopen");
+                       g_free(path);
+                       return FALSE;
+               }
+       }
+       g_free(path);
+
+       now = time(NULL);
+
+       while (fgets(buf, sizeof(buf), fp) != NULL) {
+               gchar tmp[POPBUFSIZE];
+               strretchomp(buf);
+               recv_time = RECV_TIME_NONE;
+               partial_recv = POP3_TOTALLY_RECEIVED;
+               
+               if (sscanf(buf, "%s\t%ld\t%s", uidl, &recv_time, &tmp) < 2) {
+                       if (sscanf(buf, "%s", uidl) != 1)
+                               continue;
+                       else {
+                               recv_time = now;
+                       }
+               }
+               if (!strcmp(uidl, msginfo->partial_recv)) {
+                       fclose(fp);
+                       return TRUE;
+               }
+       }
+
+       fclose(fp);     
+       return FALSE;
+}
+
+static int partial_uidl_mark_mail(MsgInfo *msginfo, int download)
+{
+       gchar *path;
+       gchar *pathnew;
+       FILE *fp;
+       FILE *fpnew;
+       gchar buf[POPBUFSIZE];
+       gchar uidl[POPBUFSIZE];
+       time_t recv_time;
+       time_t now;
+       int len;
+       int start = TRUE;
+       gchar partial_recv[POPBUFSIZE];
+       int err = -1;
+
+       gchar *filename;
+       MsgInfo *tinfo;
+       filename = procmsg_get_message_file_path(msginfo);
+       if (!filename) {
+               g_warning("can't get message file path.\n");
+               return err;
+       }
+       tinfo = procheader_parse_file(filename, msginfo->flags, TRUE, TRUE);
+
+       if (!tinfo->account_server
+       ||  !tinfo->account_login
+       ||  !tinfo->partial_recv) {
+               goto bail;
+       }
+       path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                          "uidl", G_DIR_SEPARATOR_S, tinfo->account_server,
+                          "-", tinfo->account_login, NULL);
+       if ((fp = fopen(path, "rb")) == NULL) {
+               perror("fopen1");
+               if (ENOENT != errno) FILE_OP_ERROR(path, "fopen");
+               g_free(path);
+               path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                                  "uidl-", tinfo->account_server,
+                                  "-", tinfo->account_login, NULL);
+               if ((fp = fopen(path, "rb")) == NULL) {
+                       if (ENOENT != errno) FILE_OP_ERROR(path, "fopen");
+                       g_free(path);
+               }
+               goto bail;
+       }
+
+       pathnew = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                          "uidl", G_DIR_SEPARATOR_S, tinfo->account_server,
+                          "-", tinfo->account_login, ".new", NULL);
+       if ((fpnew = fopen(pathnew, "wb")) == NULL) {
+               perror("fopen2");
+               fclose(fp);
+               g_free(pathnew);
+               goto bail;
+       }
+       
+       now = time(NULL);
+
+       while (fgets(buf, sizeof(buf), fp) != NULL) {
+               strretchomp(buf);
+               recv_time = RECV_TIME_NONE;
+               sprintf(partial_recv,"0");
+               
+               if (sscanf(buf, "%s\t%ld\t%s", 
+                          uidl, &recv_time, &partial_recv) < 2) {
+                       if (sscanf(buf, "%s", uidl) != 1)
+                               continue;
+                       else {
+                               recv_time = now;
+                       }
+               }
+               if (strcmp(tinfo->partial_recv, uidl)) {
+                       fprintf(fpnew, "%s\t%ld\t%s\n", 
+                               uidl, recv_time, partial_recv);
+               } else {
+                       gchar *stat = NULL;
+                       if (download == POP3_PARTIAL_DLOAD_DLOAD) {
+                               gchar *folder_id = folder_item_get_identifier(
+                                                       msginfo->folder);
+                               stat = g_strdup_printf("%s:%d",
+                                       folder_id, msginfo->msgnum);
+                               g_free(folder_id);
+                       }
+                       else if (download == POP3_PARTIAL_DLOAD_UNKN)
+                               stat = strdup("1");
+                       else if (download == POP3_PARTIAL_DLOAD_DELE)
+                               stat = strdup("0");
+                       
+                       fprintf(fpnew, "%s\t%ld\t%s\n", 
+                               uidl, recv_time, stat);
+                       g_free(stat);
+               }
+       }
+       fclose(fpnew);
+       fclose(fp);
+
+       move_file(pathnew, path, TRUE);
+
+       g_free(path);
+       g_free(pathnew);
+       
+       if ((fp = fopen(filename,"rb")) == NULL) {
+               perror("fopen3");
+               goto bail;
+       }
+       pathnew = g_strdup_printf("%s.new", filename);
+       if ((fpnew = fopen(pathnew, "wb")) == NULL) {
+               perror("fopen4");
+               fclose(fp);
+               g_free(pathnew);
+               goto bail;
+       }
+       
+       while ((len = fread(buf, sizeof(gchar), sizeof(buf), fp)) > 0) {
+               buf[len]='\0';
+               if (start) {
+                       start = FALSE;
+                       fprintf(fpnew, "SC-Marked-For-Download: %d\n", 
+                                       download);
+                       
+                       if(strlen(buf) > strlen("SC-Marked-For-Download: x\n")
+                       && !strncmp(buf, "SC-Marked-For-Download:", 
+                                   strlen("SC-Marked-For-Download:"))) {
+                               fprintf(fpnew, "%s", 
+                                buf+strlen("SC-Marked-For-Download: x\n"));
+                               continue;
+                       }
+               }
+               fprintf(fpnew, "%s", buf);
+       }
+       fclose(fpnew);
+       fclose(fp);
+       unlink(filename);
+       rename(pathnew, filename);
+       g_free(pathnew);
+       msginfo->planned_download = download;
+       msgcache_update_msg(msginfo->folder->cache, msginfo);
+
+       err = 0;
+bail:
+       g_free(filename);
+       procmsg_msginfo_free(tinfo);
+       
+       return err;
+}
+int partial_mark_for_delete(MsgInfo *msginfo)
+{
+       return partial_uidl_mark_mail(msginfo, POP3_PARTIAL_DLOAD_DELE);
+}
+
+int partial_mark_for_download(MsgInfo *msginfo)
+{
+       return partial_uidl_mark_mail(msginfo, POP3_PARTIAL_DLOAD_DLOAD);
+}
+
+int partial_unmark(MsgInfo *msginfo)
+{
+       return partial_uidl_mark_mail(msginfo, POP3_PARTIAL_DLOAD_UNKN);
+}
+
+void partial_delete_old(const gchar *file) 
+{
+       gchar *id = strdup(file);
+       gchar *snum = strrchr(file, ':');
+       int num = 0;
+       FolderItem *item = NULL;
+
+       debug_print("too big message updated,should remove %s\n", file);
+
+       if (snum) {
+               snum++;
+       } else {
+               g_free(id);
+               return; /* not a real problem */
+       }
+
+       num = atoi(snum);
+
+       if (strrchr(id, ':'))
+               *(strrchr(id, ':'))='\0';
+
+       item = folder_find_item_from_identifier(id);
+       if (item) {
+               debug_print("removing %d in %s\n", num, id);
+               folder_item_remove_msg(item, num);
+       } 
+       g_free(id);
+}
+
+gchar *partial_get_filename(const gchar *server, const gchar *login,
+                                  const gchar *muidl)
+{
+       gchar *path;
+       gchar *result = NULL;
+       FILE *fp;
+       gchar buf[POPBUFSIZE];
+       gchar uidl[POPBUFSIZE];
+       time_t recv_time;
+       time_t now;
+       gint partial_recv;
+       
+       path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                          "uidl", G_DIR_SEPARATOR_S, 
+                          server, "-", login, NULL);
+       if ((fp = fopen(path, "rb")) == NULL) {
+               if (ENOENT != errno) FILE_OP_ERROR(path, "fopen");
+               g_free(path);
+               path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                                  "uidl-", server,
+                                  "-", login, NULL);
+               if ((fp = fopen(path, "rb")) == NULL) {
+                       if (ENOENT != errno) FILE_OP_ERROR(path, "fopen");
+                       g_free(path);
+                       return result;
+               }
+       }
+       g_free(path);
+
+       now = time(NULL);
+
+       while (fgets(buf, sizeof(buf), fp) != NULL) {
+               gchar tmp[POPBUFSIZE];
+               strretchomp(buf);
+               recv_time = RECV_TIME_NONE;
+               partial_recv = POP3_TOTALLY_RECEIVED;
+               
+               if (sscanf(buf, "%s\t%ld\t%s", uidl, &recv_time, &tmp) < 2) {
+                       if (sscanf(buf, "%s", uidl) != 1)
+                               continue;
+                       else {
+                               recv_time = now;
+                       }
+               }
+               if (!strcmp(muidl, uidl)) {
+                       result = strdup(tmp);
+                       break;
+               }
+       }
+
+       fclose(fp);
+       
+       return result;
+}
+
diff --git a/src/common/partial_download.h b/src/common/partial_download.h
new file mode 100644 (file)
index 0000000..2ac6b77
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ * This file (C) 2004 Colin Leroy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef __PARTIAL_DOWNLOAD_H__
+#define __PARTIAL_DOWNLOAD_H__
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <glib.h>
+#include <time.h>
+
+#include "../procmsg.h"
+
+typedef enum {
+       POP3_PARTIAL_DLOAD_UNKN = 0,
+       POP3_PARTIAL_DLOAD_DLOAD= 1,
+       POP3_PARTIAL_DLOAD_DELE = 2
+} PartialDownloadAction;
+
+typedef enum {
+       POP3_TOTALLY_RECEIVED   = 0,
+       POP3_PARTIALLY_RECEIVED = 1,
+       POP3_MUST_COMPLETE_RECV = 2
+} PartialDownloadStatus;
+
+gint   partial_msg_in_uidl_list        (MsgInfo        *msginfo);
+int    partial_mark_for_download(MsgInfo       *msginfo);
+int    partial_mark_for_delete (MsgInfo        *msginfo);
+int    partial_unmark          (MsgInfo        *msginfo);
+gchar *partial_get_filename    (const gchar    *server,
+                                const gchar    *login, 
+                                const gchar    *muidl);
+void   partial_delete_old      (const gchar    *file);
+
+#endif /* __PARTIAL_DOWNLOAD_H__ */
index be367c83a8028718f1be650a9c1444e4ebfb7e4a..b6aa8fdf344bdd82c3b75b41b49fe6685bb2151b 100644 (file)
@@ -48,6 +48,7 @@
 #include "log.h"
 #include "folder_item_prefs.h"
 #include "remotefolder.h"
+#include "partial_download.h"
 
 /* Dependecies to be removed ?! */
 #include "prefs_common.h"
@@ -2523,6 +2524,17 @@ static gint do_copy_msgs(FolderItem *dest, GSList *msglist, gboolean remove_sour
        g_relation_index(relation, 0, g_direct_hash, g_direct_equal);
        g_relation_index(relation, 1, g_direct_hash, g_direct_equal);
 
+       for (l = msglist ; l != NULL ; l = g_slist_next(l)) {
+               MsgInfo * msginfo = (MsgInfo *) l->data;
+
+               if (msginfo->planned_download != 0) {
+                       int old_planned = msginfo->planned_download;
+                       partial_unmark(msginfo);
+                       /* little hack to reenable after */
+                       msginfo->planned_download = old_planned;
+               }
+       }
+
        /* 
         * Copy messages to destination folder and 
         * store new message numbers in newmsgnums
@@ -2570,17 +2582,26 @@ static gint do_copy_msgs(FolderItem *dest, GSList *msglist, gboolean remove_sour
                                        if (newmsginfo != NULL) {
                                                copy_msginfo_flags(msginfo, newmsginfo);
                                                num = newmsginfo->msgnum;
-                                               procmsg_msginfo_free(newmsginfo);
                                        }
                                }
                        } else {
                                newmsginfo = get_msginfo(dest, num);
                                if (newmsginfo != NULL) {
                                        add_msginfo_to_cache(dest, newmsginfo, msginfo);
-                                       procmsg_msginfo_free(newmsginfo);
                                }
                        }
 
+                       if (msginfo->planned_download 
+                           == POP3_PARTIAL_DLOAD_DELE) {
+                               partial_mark_for_delete(newmsginfo);
+                       }
+                       if (msginfo->planned_download 
+                           == POP3_PARTIAL_DLOAD_DLOAD) {
+                               partial_mark_for_download(newmsginfo);
+                       }
+                       procmsg_msginfo_free(newmsginfo);
+
+
                        if (num > lastnum)
                                lastnum = num;
                }
index 8bf385c6c1e46fc3cffc43191012b787461f255c..ce1b87dfcbf053fde2eec0d2237edcbd20e65274 100644 (file)
@@ -170,6 +170,7 @@ static gchar *search_descr_strings[] = {
        "n S",   N_("messages which are in newsgroup S"),
        "N",     N_("new messages"),
        "O",     N_("old messages"),
+       "p",     N_("incomplete messages (not entirely downloaded)"),
        "r",     N_("messages which have been replied to"),
        "R",     N_("read messages"),
        "s S",   N_("messages which contain S in subject"),
@@ -480,6 +481,7 @@ gchar *expand_search_string(const gchar *search_string)
                { "y",  "header \"X-Label\"",           1,      TRUE,   TRUE  },
                { "&",  "&",                            0,      FALSE,  FALSE },
                { "|",  "|",                            0,      FALSE,  FALSE },
+               { "p",  "partial",                      0,      FALSE,  FALSE },
                { NULL, NULL,                           0,      FALSE,  FALSE }
        };
 
index 8c2f0d182d7ac20bfac7970686d315a9f6016586..f9191dc8a92d2cc7817ab4217b4931a9a66b39de 100644 (file)
--- a/src/inc.c
+++ b/src/inc.c
@@ -1066,7 +1066,8 @@ static gint inc_drop_message(Pop3Session *session, const gchar *file)
        dropfolder = folder_get_default_processing();
 
        /* add msg file to drop folder */
-       if ((msgnum = folder_item_add_msg(dropfolder, file, NULL, TRUE)) < 0) {
+       if ((msgnum = folder_item_add_msg(
+                       dropfolder, file, NULL, TRUE)) < 0) {
                unlink(file);
                return -1;
        }
index de1bdea55e001f58e173e072207dc2ab5842c400..3bbbc130e74b50d99a7f7a345d75311876410691 100644 (file)
@@ -88,6 +88,8 @@ static const MatchParser matchparser_tab[] = {
        {MATCHCRITERIA_SCORE_GREATER, "score_greater"},
        {MATCHCRITERIA_SCORE_LOWER, "score_lower"},
        {MATCHCRITERIA_SCORE_EQUAL, "score_equal"},
+       {MATCHCRITERIA_PARTIAL, "partial"},
+       {MATCHCRITERIA_NOT_PARTIAL, "~partial"},
 
        {MATCHCRITERIA_SIZE_GREATER, "size_greater"},
        {MATCHCRITERIA_SIZE_SMALLER, "size_smaller"},
@@ -601,6 +603,10 @@ static gboolean matcherprop_match_one_header(MatcherProp *matcher,
        case MATCHCRITERIA_NOT_MESSAGE:
        case MATCHCRITERIA_NOT_HEADERS_PART:
                return !matcherprop_string_match(matcher, buf);
+       case MATCHCRITERIA_PARTIAL:
+               return matcherprop_string_match(matcher, buf);
+       case MATCHCRITERIA_NOT_PARTIAL:
+               return !matcherprop_string_match(matcher, buf);
        }
        return FALSE;
 }
@@ -621,6 +627,8 @@ static gboolean matcherprop_criteria_headers(const MatcherProp *matcher)
        case MATCHCRITERIA_NOT_HEADER:
        case MATCHCRITERIA_HEADERS_PART:
        case MATCHCRITERIA_NOT_HEADERS_PART:
+       case MATCHCRITERIA_PARTIAL:
+       case MATCHCRITERIA_NOT_PARTIAL:
                return TRUE;
        default:
                return FALSE;
index c8d2484b7f197faa02a084b365e78912881ae5d0..e3d5c31f6a62e131bf1b7f8eb386b6cb5f46ec24 100644 (file)
@@ -78,6 +78,7 @@ enum {
        MC_(REPLIED), MC_(NOT_REPLIED),
        MC_(FORWARDED), MC_(NOT_FORWARDED),
        MC_(LOCKED), MC_(NOT_LOCKED),
+       MC_(PARTIAL), MC_(NOT_PARTIAL),
        MC_(COLORLABEL), MC_(NOT_COLORLABEL),
        MC_(IGNORE_THREAD), MC_(NOT_IGNORE_THREAD),
        MC_(SUBJECT), MC_(NOT_SUBJECT),
index d9b16519c82e03bc8eac2db8046881ca2300b4ea..07d95bb563ad192d87454febd19f6e12bd7305da 100644 (file)
@@ -235,6 +235,7 @@ int matcher_parserwrap(void)
 %token MATCHER_COLOR MATCHER_SCORE_EQUAL MATCHER_REDIRECT 
 %token MATCHER_SIZE_GREATER MATCHER_SIZE_SMALLER MATCHER_SIZE_EQUAL
 %token MATCHER_LOCKED MATCHER_NOT_LOCKED
+%token MATCHER_PARTIAL MATCHER_NOT_PARTIAL
 %token MATCHER_COLORLABEL MATCHER_NOT_COLORLABEL
 %token MATCHER_IGNORE_THREAD MATCHER_NOT_IGNORE_THREAD
 %token MATCHER_CHANGE_SCORE MATCHER_SET_SCORE
@@ -543,6 +544,20 @@ MATCHER_ALL
        criteria = MATCHCRITERIA_NOT_LOCKED;
        prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
 }
+| MATCHER_PARTIAL
+{
+       gint criteria = 0;
+
+       criteria = MATCHCRITERIA_PARTIAL;
+       prop = matcherprop_new(criteria, NULL, MATCHTYPE_MATCH, "SC-Partially-Retrieved", 0);
+}
+| MATCHER_NOT_PARTIAL
+{
+       gint criteria = 0;
+
+       criteria = MATCHCRITERIA_NOT_PARTIAL;
+       prop = matcherprop_new(criteria, NULL, MATCHTYPE_MATCH, "SC-Partially-Retrieved", 0);
+}
 | MATCHER_COLORLABEL MATCHER_INTEGER
 {
        gint criteria = 0;
index 890e9c99f7dd4c7c42099e3f2f12a07ee1c1708a..d92f79d9738759120864170f92cd635e908b5607 100644 (file)
@@ -62,6 +62,7 @@
 #include "stock_pixmap.h"
 #include "hooks.h"
 #include "filtering.h"
+#include "partial_download.h"
 
 static GList *messageview_list = NULL;
 
@@ -77,6 +78,14 @@ static void return_receipt_show              (NoticeView     *noticeview,
                                         MsgInfo        *msginfo);      
 static void return_receipt_send_clicked (NoticeView    *noticeview, 
                                          MsgInfo        *msginfo);
+static void partial_recv_show          (NoticeView     *noticeview, 
+                                        MsgInfo        *msginfo);      
+static void partial_recv_dload_clicked         (NoticeView     *noticeview, 
+                                         MsgInfo        *msginfo);
+static void partial_recv_del_clicked   (NoticeView     *noticeview, 
+                                         MsgInfo        *msginfo);
+static void partial_recv_unmark_clicked (NoticeView    *noticeview, 
+                                         MsgInfo        *msginfo);
 static void save_as_cb                 (gpointer        data,
                                         guint           action,
                                         GtkWidget      *widget);
@@ -717,10 +726,14 @@ gint messageview_show(MessageView *messageview, MsgInfo *msginfo,
 
        mimeview_show_message(messageview->mimeview, mimeinfo, file);
 
-       if ((messageview->msginfo->dispositionnotificationto || 
+       if (messageview->msginfo->partial_recv)
+               partial_recv_show(messageview->noticeview, 
+                                 messageview->msginfo);
+       else if ((messageview->msginfo->dispositionnotificationto || 
             messageview->msginfo->returnreceiptto) &&
            !MSG_IS_RETRCPT_SENT(messageview->msginfo->flags))
-               return_receipt_show(messageview->noticeview, messageview->msginfo);
+               return_receipt_show(messageview->noticeview, 
+                                   messageview->msginfo);
        else 
                noticeview_hide(messageview->noticeview);
 
@@ -1011,7 +1024,7 @@ void messageview_toggle_view_real(MessageView *messageview)
 
 static void return_receipt_show(NoticeView *noticeview, MsgInfo *msginfo)
 {
-       noticeview_set_text(noticeview, _("This message asks for a return receipt"));
+       noticeview_set_text(noticeview, _("This message asks for a return receipt."));
        noticeview_set_button_text(noticeview, _("Send receipt"));
        noticeview_set_button_press_callback(noticeview,
                                             GTK_SIGNAL_FUNC(return_receipt_send_clicked),
@@ -1043,6 +1056,89 @@ static void return_receipt_send_clicked(NoticeView *noticeview, MsgInfo *msginfo
        g_free(file);
 }
 
+static void partial_recv_show(NoticeView *noticeview, MsgInfo *msginfo)
+{
+       gchar *text = NULL;
+       gchar *button1 = NULL;
+       gchar *button2 = NULL;
+       void  *button1_cb = NULL;
+       void  *button2_cb = NULL;
+
+       if (!partial_msg_in_uidl_list(msginfo))
+               return;
+
+       switch (msginfo->planned_download) {
+       case POP3_PARTIAL_DLOAD_UNKN:
+               text = g_strdup_printf(_("This message has been partially "
+                               "retrieved;\nit is %s."),
+                               to_human_readable(
+                                       (off_t)(msginfo->total_size)));
+               button1 = _("Mark for download");
+               button2 = _("Mark for deletion");
+               button1_cb = partial_recv_dload_clicked;
+               button2_cb = partial_recv_del_clicked;
+               break;
+       case POP3_PARTIAL_DLOAD_DLOAD:
+               text = g_strdup_printf(_("This message has been partially "
+                               "retrieved;\nit is %s and will be downloaded."),
+                               to_human_readable(
+                                       (off_t)(msginfo->total_size)));
+               button1 = _("Unmark");
+               button1_cb = partial_recv_unmark_clicked;
+               button2 = _("Mark for deletion");
+               button2_cb = partial_recv_del_clicked;
+               break;
+       case POP3_PARTIAL_DLOAD_DELE:
+               text = g_strdup_printf(_("This message has been partially "
+                               "retrieved;\nit is %s and will be deleted."),
+                               to_human_readable(
+                                       (off_t)(msginfo->total_size)));
+               button1 = _("Mark for download");
+               button1_cb = partial_recv_dload_clicked;
+               button2 = _("Unmark");
+               button2_cb = partial_recv_unmark_clicked;
+               break;
+       default:
+               return;
+       }
+       
+       noticeview_set_text(noticeview, text);
+       g_free(text);
+       noticeview_set_button_text(noticeview, button1);
+       noticeview_set_button_press_callback(noticeview,
+                    GTK_SIGNAL_FUNC(button1_cb), (gpointer) msginfo);
+
+       noticeview_set_2ndbutton_text(noticeview, button2);
+       noticeview_set_2ndbutton_press_callback(noticeview,
+                    GTK_SIGNAL_FUNC(button2_cb), (gpointer) msginfo);
+
+       noticeview_show(noticeview);
+}
+
+static void partial_recv_dload_clicked(NoticeView *noticeview, 
+                                      MsgInfo *msginfo)
+{
+       if (partial_mark_for_download(msginfo) == 0) {
+               partial_recv_show(noticeview, msginfo);
+       }
+}
+
+static void partial_recv_del_clicked(NoticeView *noticeview, 
+                                      MsgInfo *msginfo)
+{
+       if (partial_mark_for_delete(msginfo) == 0) {
+               partial_recv_show(noticeview, msginfo);
+       }
+}
+
+static void partial_recv_unmark_clicked(NoticeView *noticeview, 
+                                      MsgInfo *msginfo)
+{
+       if (partial_unmark(msginfo) == 0) {
+               partial_recv_show(noticeview, msginfo);
+       }
+}
+
 static void select_account_cb(GtkWidget *w, gpointer data)
 {
        *(gint*)data = GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(w)));
index b9651dcd66fcbf75570e1c9cebd75aed0fd485dd..cfc1d095b16a664c94077551789776c2e2b3d116 100644 (file)
@@ -392,6 +392,7 @@ MsgCache *msgcache_read_cache(FolderItem *item, const gchar *cache_file)
                READ_CACHE_DATA(msginfo->inreplyto, fp);
                READ_CACHE_DATA(msginfo->references, fp);
                READ_CACHE_DATA(msginfo->xref, fp);
+               READ_CACHE_DATA_INT(msginfo->planned_download, fp);
 
                msginfo->folder = item;
                msginfo->flags.tmp_flags |= tmp_flags;
@@ -462,6 +463,7 @@ void msgcache_write_cache(MsgInfo *msginfo, FILE *fp)
        WRITE_CACHE_DATA(msginfo->inreplyto, fp);
        WRITE_CACHE_DATA(msginfo->references, fp);
        WRITE_CACHE_DATA(msginfo->xref, fp);
+       WRITE_CACHE_DATA_INT(msginfo->planned_download, fp);
 }
 
 static void msgcache_write_flags(MsgInfo *msginfo, FILE *fp)
index 69cb87a10c9eacc05a5bc8f4c12e84a8edc8a661..d4c83aa0c8cf16ca8e720ce184f4b93ed459c41c 100644 (file)
@@ -46,6 +46,7 @@
 #include "noticeview.h"
 
 static void noticeview_button_pressed  (GtkButton *button, NoticeView *noticeview);
+static void noticeview_2ndbutton_pressed(GtkButton *button, NoticeView *noticeview);
 
 NoticeView *noticeview_create(MainWindow *mainwin)
 {
@@ -56,6 +57,7 @@ NoticeView *noticeview_create(MainWindow *mainwin)
        GtkWidget  *icon;
        GtkWidget  *text;
        GtkWidget  *widget;
+       GtkWidget  *widget2;
 
        debug_print("Creating notice view...\n");
        noticeview = g_new0(NoticeView, 1);
@@ -65,11 +67,11 @@ NoticeView *noticeview_create(MainWindow *mainwin)
        vbox = gtk_vbox_new(FALSE, 4);
        gtk_widget_show(vbox);
        hsep = gtk_hseparator_new();
-       gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, TRUE, 0);
+       gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, TRUE, 1);
        
        hbox = gtk_hbox_new(FALSE, 4);
        gtk_widget_show(hbox);
-       gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
+       gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 1);
 
        icon = stock_pixmap_widget(noticeview->window, STOCK_PIXMAP_NOTICE_WARN); 
 #if 0
@@ -85,17 +87,26 @@ NoticeView *noticeview_create(MainWindow *mainwin)
        gtk_box_pack_start(GTK_BOX(hbox), text, FALSE, FALSE, 0);
 
        widget = gtk_button_new_with_label("");
+       gtk_widget_set_usize(widget, 120, -1);
        gtk_signal_connect(GTK_OBJECT(widget), "clicked", 
                           GTK_SIGNAL_FUNC(noticeview_button_pressed),
                           (gpointer) noticeview);
        gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 4);
        
+       widget2 = gtk_button_new_with_label("");
+       gtk_widget_set_usize(widget2, 120, -1);
+       gtk_signal_connect(GTK_OBJECT(widget2), "clicked", 
+                          GTK_SIGNAL_FUNC(noticeview_2ndbutton_pressed),
+                          (gpointer) noticeview);
+       gtk_box_pack_start(GTK_BOX(hbox), widget2, FALSE, FALSE, 0);
+       
        noticeview->vbox   = vbox;
        noticeview->hsep   = hsep;
        noticeview->hbox   = hbox;
        noticeview->icon   = icon;
        noticeview->text   = text;
        noticeview->button = widget;
+       noticeview->button2 = widget2;
 
        noticeview->visible = TRUE;
 
@@ -144,6 +155,12 @@ void noticeview_set_button_text(NoticeView *noticeview, const char *text)
                gtk_widget_show(noticeview->button);
        } else
                gtk_widget_hide(noticeview->button);
+       
+       /* Callers defining only one button don't have to mind 
+        * resetting the second one. Callers defining two have
+        * to define the second button after the first one. 
+        */
+       gtk_widget_hide(noticeview->button2);
 }
 
 void noticeview_set_button_press_callback(NoticeView   *noticeview,
@@ -161,6 +178,33 @@ static void noticeview_button_pressed(GtkButton *button, NoticeView *noticeview)
        }
 }
 
+void noticeview_set_2ndbutton_text(NoticeView *noticeview, const char *text)
+{
+       g_return_if_fail(noticeview);
+
+       if (text != NULL) {
+               gtk_label_set_text
+                       (GTK_LABEL(GTK_BIN(noticeview->button2)->child), text);
+               gtk_widget_show(noticeview->button2);
+       } else
+               gtk_widget_hide(noticeview->button2);
+}
+
+void noticeview_set_2ndbutton_press_callback(NoticeView        *noticeview,
+                                         GtkSignalFunc  callback,
+                                         gpointer      *user_data)
+{
+       noticeview->press2     = (void (*) (NoticeView *, gpointer)) callback;
+       noticeview->user_data2 = user_data;
+}
+
+static void noticeview_2ndbutton_pressed(GtkButton *button, NoticeView *noticeview)
+{
+       if (noticeview->press2) {
+               noticeview->press2(noticeview, noticeview->user_data2);
+       }
+}
+
 void noticeview_set_icon(NoticeView *noticeview, StockPixmap icon)
 {
        GdkPixmap *pixmap;
index 054317ccf2a34e3b2b8fe51e30bbb5640aa8d2c9..634bd91934bfe3301e92a9399c5d635133fc6d17 100644 (file)
@@ -32,10 +32,13 @@ struct _NoticeView
        GtkWidget       *icon;
        GtkWidget       *text;
        GtkWidget       *button;
+       GtkWidget       *button2;
        GtkWidget       *window;
        gboolean         visible;
        gpointer         user_data;
+       gpointer         user_data2;
        void            (*press) (NoticeView *, gpointer user_data);
+       void            (*press2) (NoticeView *, gpointer user_data);
 };
 
 NoticeView     *noticeview_create      (MainWindow     *mainwin);
@@ -48,6 +51,9 @@ void           noticeview_set_text    (NoticeView     *noticeview,
 void            noticeview_set_button_text 
                                        (NoticeView     *noticeview,
                                         const gchar    *text);
+void            noticeview_set_2ndbutton_text 
+                                       (NoticeView     *noticeview,
+                                        const gchar    *text);
 gboolean        noticeview_is_visible  (NoticeView     *noticeview);
 void            noticeview_show        (NoticeView     *noticeview);
 void            noticeview_hide        (NoticeView     *noticeview);
@@ -56,5 +62,9 @@ void           noticeview_set_button_press_callback
                                        (NoticeView     *noticeview,
                                         GtkSignalFunc   callback,
                                         gpointer       *user_data);
+void            noticeview_set_2ndbutton_press_callback
+                                       (NoticeView     *noticeview,
+                                        GtkSignalFunc   callback,
+                                        gpointer       *user_data);
                                        
 #endif /* NOTICEVIEW_H__ */
index 248e241a595a21a2c98f05509ef290644a7e6380..560a815eb3819fabc2632d5510810ad7251563b0 100644 (file)
--- a/src/pop.c
+++ b/src/pop.c
 #include "prefs_account.h"
 #include "utils.h"
 #include "recv.h"
-
+#include "folder.h"
+#include "procmsg.h"
+#include "procheader.h"
+#include "msgcache.h"
+#include "partial_download.h"
 #include "log.h"
 #include "hooks.h"
 
@@ -78,7 +82,8 @@ static void pop3_session_destroy      (Session        *session);
 
 static gint pop3_write_msg_to_file     (const gchar    *file,
                                         const gchar    *data,
-                                        guint           len);
+                                        guint           len,
+                                        const gchar    *prefix);
 
 static Pop3State pop3_lookup_next      (Pop3Session    *session);
 static Pop3ErrorValue pop3_ok          (Pop3Session    *session,
@@ -90,7 +95,6 @@ static gint pop3_session_recv_data_finished   (Session        *session,
                                                 guchar         *data,
                                                 guint           len);
 
-
 static gint pop3_greeting_recv(Pop3Session *session, const gchar *msg)
 {
        session->state = POP3_GREETING;
@@ -236,6 +240,7 @@ static gint pop3_getrange_uidl_recv(Pop3Session *session, const gchar *data,
        gint buf_len;
        gint num;
        time_t recv_time;
+       gint partial_recv;
        const gchar *p = data;
        const gchar *lastp = data + len;
        const gchar *newline;
@@ -257,12 +262,19 @@ static gint pop3_getrange_uidl_recv(Pop3Session *session, const gchar *data,
 
                session->msg[num].uidl = g_strdup(id);
 
-               recv_time = (time_t)g_hash_table_lookup(session->uidl_table, id);
+               recv_time = (time_t)g_hash_table_lookup(
+                                       session->uidl_table, id);
                session->msg[num].recv_time = recv_time;
 
-               if (!session->ac_prefs->getall && recv_time != RECV_TIME_NONE)
-                       session->msg[num].received = TRUE;
+               partial_recv = (gint)g_hash_table_lookup(
+                                       session->partial_recv_table, id);
+
+               if (!session->ac_prefs->getall && recv_time != RECV_TIME_NONE) {
+                       session->msg[num].received = 
+                               (partial_recv != POP3_MUST_COMPLETE_RECV);
+                       session->msg[num].partial_recv = partial_recv;
 
+               }
                if (!session->new_msg_exist &&
                    (session->ac_prefs->getall || recv_time == RECV_TIME_NONE ||
                     session->ac_prefs->rmmail)) {
@@ -335,7 +347,7 @@ static gint pop3_retr_recv(Pop3Session *session, const gchar *data, guint len)
 
        file = get_tmp_file();
        if (pop3_write_msg_to_file(file, mail_receive_data.data,
-               strlen(mail_receive_data.data)) < 0) {
+               strlen(mail_receive_data.data), NULL) < 0) {
                g_free(file);
                g_free(mail_receive_data.data);
                session->error_val = PS_IOERR;
@@ -343,6 +355,81 @@ static gint pop3_retr_recv(Pop3Session *session, const gchar *data, guint len)
        }
        g_free(mail_receive_data.data);
 
+       if (session->msg[session->cur_msg].partial_recv 
+           == POP3_MUST_COMPLETE_RECV) {
+               gchar *old_file = partial_get_filename(
+                               session->ac_prefs->recv_server,
+                               session->ac_prefs->userid,
+                               session->msg[session->cur_msg].uidl);
+               
+               if (old_file) {
+                       partial_delete_old(old_file);
+                       g_free(old_file);
+               }
+       } 
+
+       /* drop_ok: 0: success 1: don't receive -1: error */
+       drop_ok = session->drop_message(session, file);
+
+       g_free(file);
+       if (drop_ok < 0) {
+               session->error_val = PS_IOERR;
+               return -1;
+       }
+       
+       session->cur_total_bytes += session->msg[session->cur_msg].size;
+       session->cur_total_recv_bytes += session->msg[session->cur_msg].size;
+       session->cur_total_num++;
+
+       session->msg[session->cur_msg].received = TRUE;
+       session->msg[session->cur_msg].partial_recv = POP3_TOTALLY_RECEIVED;
+
+       session->msg[session->cur_msg].recv_time =
+               drop_ok == 1 ? RECV_TIME_KEEP : session->current_time;
+
+       return PS_SUCCESS;
+}
+
+static gint pop3_top_send(Pop3Session *session, gint max_size)
+{
+       gint num_lines = (max_size*1024)/82; /* consider lines to be 80 chars */
+       session->state = POP3_TOP;
+       pop3_gen_send(session, "TOP %d %d", session->cur_msg, num_lines);
+       return PS_SUCCESS;
+}
+
+static gint pop3_top_recv(Pop3Session *session, const gchar *data, guint len)
+{
+       gchar *file;
+       gint drop_ok;
+       MailReceiveData mail_receive_data;
+       gchar *partial_notice = NULL;
+       
+       mail_receive_data.session = session;
+       mail_receive_data.data = g_strndup(data, len);
+       hooks_invoke(MAIL_RECEIVE_HOOKLIST, &mail_receive_data);
+
+       partial_notice = g_strdup_printf("SC-Marked-For-Download: 0\n"
+                                        "SC-Partially-Retrieved: %s\n"
+                                        "SC-Account-Server: %s\n"
+                                        "SC-Account-Login: %s\n"
+                                        "SC-Message-Size: %d",
+                                        session->msg[session->cur_msg].uidl,
+                                        session->ac_prefs->recv_server,
+                                        session->ac_prefs->userid,
+                                        session->msg[session->cur_msg].size);
+       file = get_tmp_file();
+       if (pop3_write_msg_to_file(file, mail_receive_data.data,
+               strlen(mail_receive_data.data), partial_notice) < 0) {
+               g_free(file);
+               g_free(mail_receive_data.data);
+               session->error_val = PS_IOERR;
+               g_free(partial_notice);
+               return -1;
+       }
+       g_free(mail_receive_data.data);
+       g_free(partial_notice);
+
        /* drop_ok: 0: success 1: don't receive -1: error */
        drop_ok = session->drop_message(session, file);
        g_free(file);
@@ -356,6 +443,7 @@ static gint pop3_retr_recv(Pop3Session *session, const gchar *data, guint len)
        session->cur_total_num++;
 
        session->msg[session->cur_msg].received = TRUE;
+       session->msg[session->cur_msg].partial_recv = POP3_PARTIALLY_RECEIVED;
        session->msg[session->cur_msg].recv_time =
                drop_ok == 1 ? RECV_TIME_KEEP : session->current_time;
 
@@ -420,7 +508,7 @@ Session *pop3_session_new(PrefsAccount *account)
        session->state = POP3_READY;
        session->ac_prefs = account;
        session->pop_before_smtp = FALSE;
-       session->uidl_table = pop3_get_uidl_table(account);
+       pop3_get_uidl_table(account, session);
        session->current_time = time(NULL);
        session->error_val = PS_SUCCESS;
        session->error_msg = NULL;
@@ -444,23 +532,31 @@ static void pop3_session_destroy(Session *session)
                g_hash_table_destroy(pop3_session->uidl_table);
        }
 
+       if (pop3_session->partial_recv_table) {
+               hash_free_strings(pop3_session->partial_recv_table);
+               g_hash_table_destroy(pop3_session->partial_recv_table);
+       }
+
        g_free(pop3_session->greeting);
        g_free(pop3_session->user);
        g_free(pop3_session->pass);
        g_free(pop3_session->error_msg);
 }
 
-GHashTable *pop3_get_uidl_table(PrefsAccount *ac_prefs)
+void pop3_get_uidl_table(PrefsAccount *ac_prefs, Pop3Session *session)
 {
        GHashTable *table;
+       GHashTable *partial_recv_table;
        gchar *path;
        FILE *fp;
        gchar buf[POPBUFSIZE];
        gchar uidl[POPBUFSIZE];
        time_t recv_time;
        time_t now;
-
+       gint partial_recv;
+       
        table = g_hash_table_new(g_str_hash, g_str_equal);
+       partial_recv_table = g_hash_table_new(g_str_hash, g_str_equal);
 
        path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
                           "uidl", G_DIR_SEPARATOR_S, ac_prefs->recv_server,
@@ -474,7 +570,9 @@ GHashTable *pop3_get_uidl_table(PrefsAccount *ac_prefs)
                if ((fp = fopen(path, "rb")) == NULL) {
                        if (ENOENT != errno) FILE_OP_ERROR(path, "fopen");
                        g_free(path);
-                       return table;
+                       session->uidl_table = table;
+                       session->partial_recv_table = partial_recv_table;
+                       return;
                }
        }
        g_free(path);
@@ -482,22 +580,36 @@ GHashTable *pop3_get_uidl_table(PrefsAccount *ac_prefs)
        now = time(NULL);
 
        while (fgets(buf, sizeof(buf), fp) != NULL) {
+               gchar tmp[POPBUFSIZE];
                strretchomp(buf);
                recv_time = RECV_TIME_NONE;
-               if (sscanf(buf, "%s\t%ld", uidl, &recv_time) != 2) {
+               partial_recv = POP3_TOTALLY_RECEIVED;
+               
+               if (sscanf(buf, "%s\t%ld\t%s", uidl, &recv_time, &tmp) < 2) {
                        if (sscanf(buf, "%s", uidl) != 1)
                                continue;
-                       else
+                       else {
                                recv_time = now;
+                       }
                }
                if (recv_time == RECV_TIME_NONE)
                        recv_time = RECV_TIME_RECEIVED;
                g_hash_table_insert(table, g_strdup(uidl),
                                    GINT_TO_POINTER(recv_time));
+               if (strlen(tmp) == 1)
+                       partial_recv = atoi(tmp); /* totally received ?*/
+               else
+                       partial_recv = POP3_MUST_COMPLETE_RECV;
+
+               g_hash_table_insert(partial_recv_table, g_strdup(uidl),
+                                   GINT_TO_POINTER(partial_recv));
        }
 
        fclose(fp);
-       return table;
+       session->uidl_table = table;
+       session->partial_recv_table = partial_recv_table;
+       
+       return;
 }
 
 gint pop3_write_uidl_list(Pop3Session *session)
@@ -521,8 +633,10 @@ gint pop3_write_uidl_list(Pop3Session *session)
 
        for (n = 1; n <= session->count; n++) {
                msg = &session->msg[n];
-               if (msg->uidl && msg->received && !msg->deleted)
-                       fprintf(fp, "%s\t%ld\n", msg->uidl, msg->recv_time);
+               if (msg->uidl && msg->received && !msg->deleted) {
+                       fprintf(fp, "%s\t%ld\t%d\n", 
+                               msg->uidl, msg->recv_time, msg->partial_recv);
+               }
        }
 
        if (fclose(fp) == EOF) FILE_OP_ERROR(path, "fclose");
@@ -532,7 +646,7 @@ gint pop3_write_uidl_list(Pop3Session *session)
 }
 
 static gint pop3_write_msg_to_file(const gchar *file, const gchar *data,
-                                  guint len)
+                                  guint len, const gchar *prefix)
 {
        FILE *fp;
        const gchar *prev, *cur;
@@ -547,6 +661,11 @@ static gint pop3_write_msg_to_file(const gchar *file, const gchar *data,
        if (change_file_mode_rw(fp, file) < 0)
                FILE_OP_ERROR(file, "chmod");
 
+       if (prefix != NULL) {
+               fprintf(fp, prefix);
+               fprintf(fp, "\n");
+       }
+       
        /* +------------------+----------------+--------------------------+ *
         * ^data              ^prev            ^cur             data+len-1^ */
 
@@ -623,20 +742,29 @@ static Pop3State pop3_lookup_next(Pop3Session *session)
                if (ac->rmmail &&
                    msg->recv_time != RECV_TIME_NONE &&
                    msg->recv_time != RECV_TIME_KEEP &&
+                   msg->partial_recv == POP3_TOTALLY_RECEIVED &&
                    session->current_time - msg->recv_time >=
                    ac->msg_leave_time * 24 * 60 * 60) {
                        log_message
-                               (_("POP3: Deleting expired message %d\n"),
-                                  session->cur_msg);
+                               (_("POP3: Deleting expired message "
+                                  "%d\n"), session->cur_msg);
                        pop3_delete_send(session);
                        return POP3_DELETE;
                }
 
-               if (size_limit_over)
+               if (size_limit_over) {
+                       if (!msg->received && msg->partial_recv != 
+                           POP3_MUST_COMPLETE_RECV) {
+                               pop3_top_send(session, ac->size_limit);
+                               return POP3_TOP;
+                       } else if (msg->partial_recv == POP3_MUST_COMPLETE_RECV)
+                               break;
+
                        log_message
                                (_("POP3: Skipping message %d (%d bytes)\n"),
                                   session->cur_msg, size);
-
+               }
+               
                if (size == 0 || msg->received || size_limit_over) {
                        session->cur_total_bytes += size;
                        if (session->cur_msg == session->count) {
@@ -686,9 +814,11 @@ static Pop3ErrorValue pop3_ok(Pop3Session *session, const gchar *msg)
                                break;
                        case POP3_GETRANGE_LAST:
                        case POP3_GETRANGE_UIDL:
+                       case POP3_TOP:
                                log_warning(_("command not supported\n"));
                                ok = PS_NOTSUPPORTED;
                                break;
+                               
                        default:
                                log_warning(_("error occurred on POP3 session\n"));
                                ok = PS_ERROR;
@@ -799,6 +929,14 @@ static gint pop3_session_recv_msg(Session *session, const gchar *msg)
                pop3_session->state = POP3_RETR_RECV;
                session_recv_data(session, 0, ".\r\n");
                break;
+       case POP3_TOP:
+               if (val == PS_NOTSUPPORTED) {
+                       pop3_session->error_val = PS_SUCCESS;
+               } else {
+                       pop3_session->state = POP3_TOP_RECV;
+                       session_recv_data(session, 0, ".\r\n");
+               }
+               break;
        case POP3_DELETE:
                pop3_delete_recv(pop3_session);
                if (pop3_session->cur_msg == pop3_session->count)
@@ -862,6 +1000,28 @@ static gint pop3_session_recv_data_finished(Session *session, guchar *data,
                                return -1;
                }
                break;
+       case POP3_TOP_RECV:
+               if (pop3_top_recv(pop3_session, data, len) < 0)
+                       return -1;
+
+               if (pop3_session->cur_msg == pop3_session->count)
+                       pop3_logout_send(pop3_session);
+               else {
+                       pop3_session->cur_msg++;
+                       if (pop3_lookup_next(pop3_session) == POP3_ERROR)
+                               return -1;
+               }
+               break;
+       case POP3_TOP:
+               log_warning(_("TOP command unsupported\n"));
+               if (pop3_session->cur_msg == pop3_session->count)
+                       pop3_logout_send(pop3_session);
+               else {
+                       pop3_session->cur_msg++;
+                       if (pop3_lookup_next(pop3_session) == POP3_ERROR)
+                               return -1;
+               }
+               break;
        case POP3_ERROR:
        default:
                return -1;
index 63655d49212c7ea1868e64847681af99263d3974..b8ffd2326dcf93498033f657e15ac467a3e352c3 100644 (file)
--- a/src/pop.h
+++ b/src/pop.h
@@ -60,6 +60,8 @@ typedef enum {
        POP3_GETSIZE_LIST_RECV,
        POP3_RETR,
        POP3_RETR_RECV,
+       POP3_TOP,
+       POP3_TOP_RECV,
        POP3_DELETE,
        POP3_LOGOUT,
        POP3_ERROR,
@@ -101,8 +103,9 @@ struct _Pop3MsgInfo
        gint size;
        gchar *uidl;
        time_t recv_time;
-       guint received : 1;
-       guint deleted  : 1;
+       guint received     : 1;
+       guint deleted      : 1;
+       guint partial_recv : 2;
 };
 
 struct _Pop3Session
@@ -128,7 +131,8 @@ struct _Pop3Session
        Pop3MsgInfo *msg;
 
        GHashTable *uidl_table;
-
+       GHashTable *partial_recv_table;
+       
        gboolean new_msg_exist;
        gboolean uidl_is_valid;
 
@@ -149,7 +153,7 @@ struct _Pop3Session
 
 
 Session *pop3_session_new      (PrefsAccount   *account);
-GHashTable *pop3_get_uidl_table        (PrefsAccount   *account);
+void pop3_get_uidl_table       (PrefsAccount   *account, Pop3Session *session);
 gint pop3_write_uidl_list      (Pop3Session    *session);
 
 #endif /* __POP_H__ */
index 8a32d9beed606e228f06de866cb5ca2fa11bd789..c532e270b78c95d8cb0186ddeb1d1f265072a818 100644 (file)
@@ -132,7 +132,9 @@ enum {
 
        CRITERIA_SIZE_GREATER = 28,
        CRITERIA_SIZE_SMALLER = 29,
-       CRITERIA_SIZE_EQUAL   = 30
+       CRITERIA_SIZE_EQUAL   = 30,
+       
+       CRITERIA_PARTIAL = 31
 };
 
 /*!
@@ -828,6 +830,9 @@ static gint prefs_matcher_get_criteria_from_matching(gint matching_id)
        case MATCHCRITERIA_LOCKED:
        case MATCHCRITERIA_NOT_LOCKED:
                return CRITERIA_LOCKED;
+       case MATCHCRITERIA_PARTIAL:
+       case MATCHCRITERIA_NOT_PARTIAL:
+               return CRITERIA_PARTIAL;
        case MATCHCRITERIA_COLORLABEL:
        case MATCHCRITERIA_NOT_COLORLABEL:
                return CRITERIA_COLORLABEL;
@@ -922,6 +927,8 @@ static gint prefs_matcher_get_matching_from_criteria(gint criteria_id)
                return MATCHCRITERIA_FORWARDED;
        case CRITERIA_LOCKED:
                return MATCHCRITERIA_LOCKED;
+       case CRITERIA_PARTIAL:
+               return MATCHCRITERIA_PARTIAL;
        case CRITERIA_COLORLABEL:
                return MATCHCRITERIA_COLORLABEL;
        case CRITERIA_IGNORE_THREAD:
@@ -998,6 +1005,8 @@ static gint prefs_matcher_not_criteria(gint matcher_criteria)
                return MATCHCRITERIA_NOT_FORWARDED;
        case MATCHCRITERIA_LOCKED:
                return MATCHCRITERIA_NOT_LOCKED;
+       case MATCHCRITERIA_PARTIAL:
+               return MATCHCRITERIA_NOT_PARTIAL;
        case MATCHCRITERIA_COLORLABEL:
                return MATCHCRITERIA_NOT_COLORLABEL;
        case MATCHCRITERIA_IGNORE_THREAD:
@@ -1072,6 +1081,7 @@ static MatcherProp *prefs_matcher_dialog_to_matcher(void)
        case CRITERIA_REPLIED:
        case CRITERIA_FORWARDED:
        case CRITERIA_LOCKED:
+       case CRITERIA_PARTIAL:
        case CRITERIA_TEST:
        case CRITERIA_COLORLABEL:
        case CRITERIA_IGNORE_THREAD:
@@ -1123,6 +1133,7 @@ static MatcherProp *prefs_matcher_dialog_to_matcher(void)
        case CRITERIA_REPLIED:
        case CRITERIA_FORWARDED:
        case CRITERIA_LOCKED:
+       case CRITERIA_PARTIAL:
        case CRITERIA_IGNORE_THREAD:
                break;
 
@@ -1330,6 +1341,7 @@ static void prefs_matcher_select(GtkCList *clist, gint row, gint column,
        case MATCHCRITERIA_NOT_REPLIED:
        case MATCHCRITERIA_NOT_FORWARDED:
        case MATCHCRITERIA_NOT_LOCKED:
+       case MATCHCRITERIA_NOT_PARTIAL:
        case MATCHCRITERIA_NOT_COLORLABEL:
        case MATCHCRITERIA_NOT_IGNORE_THREAD:
        case MATCHCRITERIA_NOT_SUBJECT:
@@ -1504,6 +1516,7 @@ static void prefs_matcher_criteria_select(GtkList *list,
        case CRITERIA_REPLIED:
        case CRITERIA_FORWARDED:
        case CRITERIA_LOCKED:
+       case CRITERIA_PARTIAL:
        case CRITERIA_IGNORE_THREAD:
                gtk_widget_set_sensitive(matcher.header_combo, FALSE);
                gtk_widget_set_sensitive(matcher.header_label, FALSE);
index 6d651f721f201c8b8c0197310f537e33f77838f0..0a4abf030fc6343abb8204298d08d4a5886eec78 100644 (file)
@@ -500,9 +500,14 @@ enum
        H_STATUS        = 11,
        H_X_STATUS      = 12,
        H_FROM_SPACE    = 13,
-       H_X_FACE        = 14,
-       H_DISPOSITION_NOTIFICATION_TO = 15,
-       H_RETURN_RECEIPT_TO = 16
+       H_SC_PLANNED_DOWNLOAD = 14,
+       H_X_FACE        = 15,
+       H_DISPOSITION_NOTIFICATION_TO = 16,
+       H_RETURN_RECEIPT_TO = 17,
+       H_SC_PARTIALLY_RETRIEVED = 18,
+       H_SC_ACCOUNT_SERVER = 19,
+       H_SC_ACCOUNT_LOGIN = 20,
+       H_SC_MESSAGE_SIZE = 21
 };
 
 static HeaderEntry hentry_full[] = {{"Date:",          NULL, FALSE},
@@ -519,9 +524,14 @@ static HeaderEntry hentry_full[] = {{"Date:",              NULL, FALSE},
                                   {"Status:",          NULL, FALSE},
                                   {"X-Status:",        NULL, FALSE},
                                   {"From ",            NULL, FALSE},
+                                  {"SC-Marked-For-Download:", NULL, FALSE},
                                   {"X-Face:",          NULL, FALSE},
                                   {"Disposition-Notification-To:", NULL, FALSE},
                                   {"Return-Receipt-To:", NULL, FALSE},
+                                  {"SC-Partially-Retrieved:", NULL, FALSE},
+                                  {"SC-Account-Server:", NULL, FALSE},
+                                  {"SC-Account-Login:",NULL, FALSE},
+                                  {"SC-Message-Size:", NULL, FALSE},
                                   {NULL,               NULL, FALSE}};
 
 static HeaderEntry hentry_short[] = {{"Date:",         NULL, FALSE},
@@ -538,6 +548,7 @@ static HeaderEntry hentry_short[] = {{"Date:",              NULL, FALSE},
                                    {"Status:",         NULL, FALSE},
                                    {"X-Status:",       NULL, FALSE},
                                    {"From ",           NULL, FALSE},
+                                   {"SC-Marked-For-Download:", NULL, FALSE},
                                    {NULL,              NULL, FALSE}};
 
 HeaderEntry* procheader_get_headernames(gboolean full)
@@ -676,6 +687,25 @@ static MsgInfo *parse_stream(void *data, gboolean isstring, MsgFlags flags,
                        if (msginfo->returnreceiptto) break;
                        msginfo->returnreceiptto = g_strdup(hp);
                        break;
+               case H_SC_PARTIALLY_RETRIEVED:
+                       if (msginfo->partial_recv) break;
+                       msginfo->partial_recv = g_strdup(hp);
+                       break;
+               case H_SC_ACCOUNT_SERVER:
+                       if (msginfo->account_server) break;
+                       msginfo->account_server = g_strdup(hp);
+                       break;
+               case H_SC_ACCOUNT_LOGIN:
+                       if (msginfo->account_login) break;
+                       msginfo->account_login = g_strdup(hp);
+                       break;
+               case H_SC_MESSAGE_SIZE:
+                       if (msginfo->total_size) break;
+                       msginfo->total_size = atoi(hp);
+                       break;
+               case H_SC_PLANNED_DOWNLOAD:
+                       msginfo->planned_download = atoi(hp);
+                       break;
 #ifdef ALLOW_HEADER_HINT                       
                case H_STATUS:
                        if (strchr(hp, 'R') != NULL)
index c16b058a0ed2ee57f83885cebc85ac904b949d82..f6b71f13d9a0fe3420362db7fe6d6a88325545b7 100644 (file)
@@ -41,6 +41,7 @@
 #include "news.h"
 #include "hooks.h"
 #include "msgcache.h"
+#include "partial_download.h"
 
 GHashTable *procmsg_msg_hash_table_create(GSList *mlist)
 {
@@ -606,8 +607,17 @@ void procmsg_empty_trash(void)
 
        for (cur = folder_get_list(); cur != NULL; cur = cur->next) {
                trash = FOLDER(cur->data)->trash;
-               if (trash && trash->total_msgs > 0)
+               if (trash && trash->total_msgs > 0) {
+                       GSList *mlist = folder_item_get_msg_list(trash);
+                       GSList *cur;
+                       for (cur = mlist ; cur != NULL ; cur = cur->next) {
+                               MsgInfo * msginfo = (MsgInfo *) cur->data;
+                               partial_mark_for_delete(msginfo);
+                               procmsg_msginfo_free(msginfo);
+                       }
+
                        folder_item_remove_all_msg(trash);
+               }
        }
 }
 
@@ -895,6 +905,17 @@ MsgInfo *procmsg_msginfo_get_full_info(MsgInfo *msginfo)
        if (!msginfo->returnreceiptto)
                msginfo->returnreceiptto = g_strdup
                        (full_msginfo->returnreceiptto);
+       if (!msginfo->partial_recv && full_msginfo->partial_recv)
+               msginfo->partial_recv = g_strdup
+                       (full_msginfo->partial_recv);
+       msginfo->total_size = full_msginfo->total_size;
+       if (!msginfo->account_server && full_msginfo->account_server)
+               msginfo->account_server = g_strdup
+                       (full_msginfo->account_server);
+       if (!msginfo->account_login && full_msginfo->account_login)
+               msginfo->account_login = g_strdup
+                       (full_msginfo->account_login);
+       msginfo->planned_download = full_msginfo->planned_download;
        procmsg_msginfo_free(full_msginfo);
 
        return procmsg_msginfo_new_ref(msginfo);
@@ -931,6 +952,10 @@ void procmsg_msginfo_free(MsgInfo *msginfo)
        g_free(msginfo->inreplyto);
        g_free(msginfo->xref);
 
+       g_free(msginfo->partial_recv);
+       g_free(msginfo->account_server);
+       g_free(msginfo->account_login);
+
        g_free(msginfo);
 }
 
index cb08752aa003f3a710fb709769acf2c49fc75ec8..d084427cd24ff938bcab242bc1a366038799811a 100644 (file)
@@ -206,6 +206,13 @@ struct _MsgInfo
        guint decryption_failed : 1;
         
         gint hidden;
+       
+       /* used only for partially received messages */
+       gchar *partial_recv;
+       gint total_size;
+       gchar *account_server;
+       gchar *account_login;
+       gint planned_download;
 };
 
 struct _MsgFileInfo
index 9c53e8025b2408a8f02c8a9e2ff810a80c0cc1bc..3c689f3b47a519e693fa89491aae4a0027b9659e 100644 (file)
@@ -83,6 +83,7 @@
 #include "description_window.h"
 #include "folderutils.h"
 #include "quicksearch.h"
+#include "partial_download.h"
 
 #define SUMMARY_COL_MARK_WIDTH         10
 #define SUMMARY_COL_STATUS_WIDTH       13
@@ -2956,11 +2957,19 @@ void summary_delete(SummaryView *summaryview)
        /* if current folder is trash, ask for confirmation */
        if (item->stype == F_TRASH) {
                AlertValue aval;
+               MsgInfo *msginfo;
 
                aval = alertpanel(_("Delete message(s)"),
                                  _("Do you really want to delete message(s) from the trash?"),
                                  _("Yes"), _("No"), NULL);
                if (aval != G_ALERTDEFAULT) return;
+
+               for (cur = GTK_CLIST(ctree)->selection; cur != NULL; cur = cur->next) {
+                       GtkCTreeNode *row = GTK_CTREE_NODE(cur->data);
+                       msginfo = gtk_ctree_node_get_row_data(ctree, row);
+                       partial_mark_for_delete(msginfo);
+               }
+       
        }
 
        main_window_cursor_wait(summaryview->mainwin);