fix use of incorrect uidl string
[claws.git] / src / pop.c
index 48853c49a175c7073abb861564a1d7499320b45b..901a3b2eebe2052ad48ee5aa897e0c7142d14c3f 100644 (file)
--- a/src/pop.c
+++ b/src/pop.c
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2001 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2002 Hiroyuki Yamamoto
  *
  * 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
 #include "utils.h"
 #include "inc.h"
 #include "recv.h"
+#include "selective_download.h"
+
+#define LOOKUP_NEXT_MSG() \
+       for (;;) { \
+               gint size = state->msg[state->cur_msg].size; \
+               gboolean size_limit_over = \
+                   (state->ac_prefs->enable_size_limit && \
+                    state->ac_prefs->size_limit > 0 && \
+                    size > state->ac_prefs->size_limit * 1024); \
+ \
+               if (size_limit_over) \
+                       log_print(_("POP3: Skipping message %d (%d bytes)\n"), \
+                                 state->cur_msg, size); \
+ \
+               if (size == 0 || state->msg[state->cur_msg].received || \
+                   size_limit_over) { \
+                       if (size > 0) \
+                               state->cur_total_bytes += size; \
+                       if (state->cur_msg == state->count) \
+                               return POP3_LOGOUT_SEND; \
+                       else \
+                               state->cur_msg++; \
+               } else \
+                       break; \
+       }
 
 static gint pop3_ok(SockInfo *sock, gchar *argbuf);
 static void pop3_gen_send(SockInfo *sock, const gchar *format, ...);
 static gint pop3_gen_recv(SockInfo *sock, gchar *buf, gint size);
+static gboolean pop3_delete_header (Pop3State *state);
+static gboolean should_delete (const char *uidl, gpointer data); 
 
 gint pop3_greeting_recv(SockInfo *sock, gpointer data)
 {
@@ -71,10 +98,16 @@ gint pop3_getauth_user_send(SockInfo *sock, gpointer data)
 
 gint pop3_getauth_user_recv(SockInfo *sock, gpointer data)
 {
+       Pop3State *state = (Pop3State *)data;
+
        if (pop3_ok(sock, NULL) == PS_SUCCESS)
                return POP3_GETAUTH_PASS_SEND;
-       else
+       else {
+               log_warning(_("error occurred on authentication\n"));
+               state->error_val = PS_AUTHFAIL;
+               state->inc_state = INC_AUTH_FAILED;
                return -1;
+       }
 }
 
 gint pop3_getauth_pass_send(SockInfo *sock, gpointer data)
@@ -92,8 +125,13 @@ gint pop3_getauth_pass_recv(SockInfo *sock, gpointer data)
 {
        Pop3State *state = (Pop3State *)data;
 
-       if (pop3_ok(sock, NULL) == PS_SUCCESS)
-               return POP3_GETRANGE_STAT_SEND;
+       if (pop3_ok(sock, NULL) == PS_SUCCESS) {
+               
+               if (pop3_delete_header(state) == TRUE)
+                       return POP3_DELETE_SEND;
+               else
+                       return POP3_GETRANGE_STAT_SEND;
+       }
        else {
                log_warning(_("error occurred on authentication\n"));
                state->error_val = PS_AUTHFAIL;
@@ -140,8 +178,14 @@ gint pop3_getauth_apop_recv(SockInfo *sock, gpointer data)
 {
        Pop3State *state = (Pop3State *)data;
 
-       if (pop3_ok(sock, NULL) == PS_SUCCESS)
+       if (pop3_ok(sock, NULL) == PS_SUCCESS) {
+               
+               if (pop3_delete_header(state) == TRUE)
+                       return POP3_DELETE_SEND;
+               else
                return POP3_GETRANGE_STAT_SEND;
+       }
+
        else {
                log_warning(_("error occurred on authentication\n"));
                state->error_val = PS_AUTHFAIL;
@@ -173,16 +217,14 @@ gint pop3_getrange_stat_recv(SockInfo *sock, gpointer data)
                        log_warning(_("POP3 protocol error\n"));
                        return -1;
                } else {
-                       if (state->count == 0)
+                       if (state->count == 0) {
+                               state->uidl_is_valid = TRUE;
                                return POP3_LOGOUT_SEND;
-                       else {
+                       } else {
+                               state->msg = g_new0
+                                       (Pop3MsgInfo, state->count + 1);
                                state->cur_msg = 1;
-                               state->new = state->count;
-                               if (state->ac_prefs->rmmail ||
-                                   state->ac_prefs->getall)
-                                       return POP3_GETSIZE_LIST_SEND;
-                               else
-                                       return POP3_GETRANGE_UIDL_SEND;
+                               return POP3_GETRANGE_UIDL_SEND;
                        }
                }
        } else if (ok == PS_PROTOCOL)
@@ -217,7 +259,6 @@ gint pop3_getrange_last_recv(SockInfo *sock, gpointer data)
                        if (state->count == last)
                                return POP3_LOGOUT_SEND;
                        else {
-                               state->new = state->count - last;
                                state->cur_msg = last + 1;
                                return POP3_GETSIZE_LIST_SEND;
                        }
@@ -241,12 +282,15 @@ gint pop3_getrange_uidl_recv(SockInfo *sock, gpointer data)
 {
        Pop3State *state = (Pop3State *)data;
        gboolean new = FALSE;
+       gboolean get_all = FALSE;
        gchar buf[POPBUFSIZE];
        gchar id[IDLEN + 1];
 
        if (pop3_ok(sock, NULL) != PS_SUCCESS) return POP3_GETRANGE_LAST_SEND;
 
-       if (!state->id_table) new = TRUE;
+       if (!state->uidl_table) new = TRUE;
+       if (state->ac_prefs->getall)
+               get_all = TRUE;
 
        while (sock_gets(sock, buf, sizeof(buf)) >= 0) {
                gint num;
@@ -254,28 +298,76 @@ gint pop3_getrange_uidl_recv(SockInfo *sock, gpointer data)
                if (buf[0] == '.') break;
                if (sscanf(buf, "%d %" Xstr(IDLEN) "s", &num, id) != 2)
                        continue;
+               if (num <= 0 || num > state->count) continue;
 
-               if (new == FALSE &&
-                   g_hash_table_lookup(state->id_table, id) == NULL) {
-                       state->new = state->count - num + 1;
-                       state->cur_msg = num;
-                       new = TRUE;
+               state->msg[num].uidl = g_strdup(id);
+
+               if (state->uidl_table) {
+                       if (!get_all &&
+                           g_hash_table_lookup(state->uidl_table, id) != NULL)
+                               state->msg[num].received = TRUE;
+                       else {
+                               if (new == FALSE) {
+                                       state->cur_msg = num;
+                                       new = TRUE;
+                               }
+                       }
                }
 
-               if (new == TRUE)
-                       state->new_id_list = g_slist_append
-                               (state->new_id_list, g_strdup(id));
-               else
-                       state->id_list = g_slist_append
-                               (state->id_list, g_strdup(id));
+               if (should_delete(buf, (Pop3State *) state))
+                       state->uidl_todelete_list = g_slist_append
+                                       (state->uidl_todelete_list, g_strdup(buf));             
+               
        }
 
+       state->uidl_is_valid = TRUE;
+
        if (new == TRUE)
                return POP3_GETSIZE_LIST_SEND;
        else
                return POP3_LOGOUT_SEND;
 }
 
+static gboolean should_delete(const char *uidl, gpointer data) 
+{
+       /* answer[0] will contain id
+        * answer[0] will contain uidl */
+       Pop3State *state = (Pop3State *) data;
+       gchar **answer;
+       int  id;
+       gboolean result;
+       int tdate, keep_for, today, nb_days;
+       const gchar *sdate;
+       GDate curdate;
+       gchar *tuidl;
+
+       if (!state->ac_prefs->rmmail || !strchr(uidl, ' '))
+               return FALSE;
+
+       /* remove \r\n */
+       tuidl  = g_strndup(uidl, strlen(uidl) - 2);
+       answer = g_strsplit(tuidl, " ", 2);
+       id     = atoi(answer[0]);
+
+       if (NULL != (sdate = g_hash_table_lookup(state->uidl_table, answer[1]))) {
+               tdate    = atoi(sdate);
+               keep_for = atoi(state->ac_prefs->leave_time); /* FIXME: leave time should be an int */
+
+               g_date_clear(&curdate, time(NULL));
+               g_date_set_time(&curdate, time(NULL));
+               today = g_date_day_of_year(&curdate);
+               
+               nb_days = g_date_is_leap_year(g_date_year(&curdate)) ? 366 : 365;
+               result  = ((tdate + keep_for) % nb_days <= today);
+       } else
+               result = FALSE;
+
+       g_free(tuidl);
+       g_strfreev(answer);
+       
+       return result;
+}
+
 gint pop3_getsize_list_send(SockInfo *sock, gpointer data)
 {
        Pop3State *state = (Pop3State *)data;
@@ -294,7 +386,6 @@ gint pop3_getsize_list_recv(SockInfo *sock, gpointer data)
 
        if (pop3_ok(sock, NULL) != PS_SUCCESS) return POP3_LOGOUT_SEND;
 
-       state->sizes = g_new0(gint, state->count + 1);
        state->cur_total_bytes = 0;
 
        while (sock_gets(sock, buf, sizeof(buf)) >= 0) {
@@ -305,19 +396,73 @@ gint pop3_getsize_list_recv(SockInfo *sock, gpointer data)
                        return -1;
 
                if (num > 0 && num <= state->count)
-                       state->sizes[num] = size;
+                       state->msg[num].size = size;
                if (num > 0 && num < state->cur_msg)
                        state->cur_total_bytes += size;
        }
 
-       while (state->sizes[state->cur_msg] == 0) {
-               if (state->cur_msg == state->count)
-                       return POP3_LOGOUT_SEND;
-               else
-                       state->cur_msg++;
+       LOOKUP_NEXT_MSG();
+       if (state->ac_prefs->session_type == RETR_HEADER) 
+               return POP3_TOP_SEND;
+       else
+               return POP3_RETR_SEND;
+ }
+gint pop3_top_send(SockInfo *sock, gpointer data)
+{
+       Pop3State *state = (Pop3State *)data;
+
+       inc_progress_update(state, POP3_TOP_SEND); 
+
+       pop3_gen_send(sock, "TOP %i 0", state->cur_msg );
+
+       return POP3_TOP_RECV;
+}
+
+gint pop3_top_recv(SockInfo *sock, gpointer data)
+{
+       Pop3State *state = (Pop3State *)data;
+       FILE  *fp;
+       gchar buf[POPBUFSIZE];
+       gchar *header;
+       gchar *filename, *path;
+       
+       inc_progress_update(state, POP3_TOP_RECV); 
+
+       if (pop3_ok(sock, NULL) != PS_SUCCESS) 
+               return POP3_LOGOUT_SEND;
+
+       path = g_strconcat(get_header_cache_dir(), G_DIR_SEPARATOR_S, NULL);
+
+       if ( !is_dir_exist(path) )
+               make_dir_hier(path);
+       
+       filename = g_strdup_printf("%s%i", path, state->cur_msg);
+                                  
+       if (recv_write_to_file(sock, filename) < 0) {
+               state->inc_state = INC_NOSPACE;
+               return -1;
        }
+       /* we add a Complete-Size Header Item ...
+          note: overwrites first line  --> this is dirty */
+       if ( (fp = fopen(filename, "rb+")) != NULL ) {
+               gchar *buf = g_strdup_printf("%s%i", SIZE_HEADER, 
+                                            state->msg[state->cur_msg].size);
+       
+               if (change_file_mode_rw(fp, filename) == 0) 
+                       fprintf(fp, "%s\n", buf);
+               g_free(buf);    
+               fclose(fp);
+       }
+       
+       g_free(path);
+       g_free(filename);
 
-       return POP3_RETR_SEND;
+       if (state->cur_msg < state->count) {
+               state->cur_msg++;
+               return POP3_TOP_SEND;
+       } else
+               return POP3_LOGOUT_SEND;
 }
 
 gint pop3_retr_send(SockInfo *sock, gpointer data)
@@ -336,10 +481,12 @@ gint pop3_retr_recv(SockInfo *sock, gpointer data)
        Pop3State *state = (Pop3State *)data;
        const gchar *file;
        gint ok, drop_ok;
-
+       int keep_for;
+       
        if ((ok = pop3_ok(sock, NULL)) == PS_SUCCESS) {
                if (recv_write_to_file(sock, (file = get_tmp_file())) < 0) {
-                       state->inc_state = INC_NOSPACE;
+                       if (state->inc_state == INC_SUCCESS)
+                               state->inc_state = INC_NOSPACE;
                        return -1;
                }
 
@@ -347,29 +494,21 @@ gint pop3_retr_recv(SockInfo *sock, gpointer data)
                        state->inc_state = INC_ERROR;
                        return -1;
                }
-
-               state->cur_total_bytes += state->sizes[state->cur_msg];
+       
+               state->cur_total_bytes += state->msg[state->cur_msg].size;
                state->cur_total_num++;
 
-               if (drop_ok == 0 && state->ac_prefs->rmmail)
+               keep_for = (state->ac_prefs && state->ac_prefs->leave_time) ? 
+                          atoi(state->ac_prefs->leave_time) : 0;
+
+               if (drop_ok == 0 && state->ac_prefs->rmmail && keep_for == 0)
                        return POP3_DELETE_SEND;
 
-               if (state->new_id_list) {
-                       state->id_list = g_slist_append
-                               (state->id_list, state->new_id_list->data);
-                       state->new_id_list =
-                               g_slist_remove(state->new_id_list,
-                                              state->new_id_list->data);
-               }
+               state->msg[state->cur_msg].received = TRUE;
 
                if (state->cur_msg < state->count) {
                        state->cur_msg++;
-                       while (state->sizes[state->cur_msg] == 0) {
-                               if (state->cur_msg == state->count)
-                                       return POP3_LOGOUT_SEND;
-                               else
-                                       state->cur_msg++;
-                       }
+                       LOOKUP_NEXT_MSG();
                        return POP3_RETR_SEND;
                } else
                        return POP3_LOGOUT_SEND;
@@ -383,7 +522,7 @@ gint pop3_delete_send(SockInfo *sock, gpointer data)
 {
        Pop3State *state = (Pop3State *)data;
 
-       /*inc_progress_update(state, POP3_DELETE_SEND);*/
+       /* inc_progress_update(state, POP3_DELETE_SEND); */
 
        pop3_gen_send(sock, "DELE %d", state->cur_msg);
 
@@ -396,14 +535,15 @@ gint pop3_delete_recv(SockInfo *sock, gpointer data)
        gint ok;
 
        if ((ok = pop3_ok(sock, NULL)) == PS_SUCCESS) {
+               if (state->ac_prefs->session_type == RETR_NORMAL)
+                       state->msg[state->cur_msg].deleted = TRUE;
+
+               if (pop3_delete_header(state) == TRUE) 
+                       return POP3_DELETE_SEND;
+
                if (state->cur_msg < state->count) {
                        state->cur_msg++;
-                       while (state->sizes[state->cur_msg] == 0) {
-                               if (state->cur_msg == state->count)
-                                       return POP3_LOGOUT_SEND;
-                               else
-                                       state->cur_msg++;
-                       }
+                       LOOKUP_NEXT_MSG();
                        return POP3_RETR_SEND;
                } else
                        return POP3_LOGOUT_SEND;
@@ -416,7 +556,21 @@ gint pop3_delete_recv(SockInfo *sock, gpointer data)
 gint pop3_logout_send(SockInfo *sock, gpointer data)
 {
        Pop3State *state = (Pop3State *)data;
-
+       gchar **parts;
+       
+       while (state->uidl_todelete_list != NULL) {
+               /*
+                * FIXME: doesn't feel right - no checks for parts
+                */
+               parts = g_strsplit((gchar *) state->uidl_todelete_list->data, " ", 2);
+               state->uidl_todelete_list = g_slist_remove
+                       (state->uidl_todelete_list, state->uidl_todelete_list->data);
+               pop3_gen_send(sock, "DELE %s", parts[0]);
+               if (pop3_ok(sock, NULL) != PS_SUCCESS)
+                       log_warning(_("error occurred on DELE\n"));
+               g_strfreev(parts);      
+       }
+       
        inc_progress_update(state, POP3_LOGOUT_SEND);
 
        pop3_gen_send(sock, "QUIT");
@@ -503,3 +657,18 @@ static gint pop3_gen_recv(SockInfo *sock, gchar *buf, gint size)
                return PS_SUCCESS;
        }
 }
+
+gboolean pop3_delete_header (Pop3State *state)
+{
+       
+       if ( (state->ac_prefs->session_type == DELE_HEADER) &&
+            (g_slist_length(state->ac_prefs->to_delete) > 0) ) {
+
+               state->cur_msg = (gint) state->ac_prefs->to_delete->data;
+               debug_print(_("next to delete %i\n"), state->cur_msg);
+               state->ac_prefs->to_delete = g_slist_remove 
+                       (state->ac_prefs->to_delete, state->ac_prefs->to_delete->data);
+               return TRUE;
+       }
+       return FALSE;
+}