/*
* 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)
{
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)
{
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;
{
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;
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)
if (state->count == last)
return POP3_LOGOUT_SEND;
else {
- state->new = state->count - last;
state->cur_msg = last + 1;
return POP3_GETSIZE_LIST_SEND;
}
{
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;
if (buf[0] == '.') break;
if (sscanf(buf, "%d %" Xstr(IDLEN) "s", &num, id) != 2)
continue;
+ if (num <= 0 || num > state->count) continue;
+
+ state->msg[num].uidl = g_strdup(id);
- if (new == FALSE &&
- g_hash_table_lookup(state->id_table, id) == NULL) {
- state->new = state->count - num + 1;
- state->cur_msg = num;
- new = TRUE;
+ 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;
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) {
- gint num, size;
+ guint num, size;
if (buf[0] == '.') break;
if (sscanf(buf, "%u %u", &num, &size) != 2)
- break;
+ 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;
}
- return POP3_RETR_SEND;
+ 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);
+
+ 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)
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;
}
- state->cur_total_bytes += state->sizes[state->cur_msg];
-
if ((drop_ok = inc_drop_message(file, state)) < 0) {
state->inc_state = INC_ERROR;
return -1;
}
- if (drop_ok == 0 && state->ac_prefs->rmmail)
+
+ state->cur_total_bytes += state->msg[state->cur_msg].size;
+ state->cur_total_num++;
+
+ 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++;
+ LOOKUP_NEXT_MSG();
return POP3_RETR_SEND;
} else
return POP3_LOGOUT_SEND;
{
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);
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++;
+ LOOKUP_NEXT_MSG();
return POP3_RETR_SEND;
} else
return POP3_LOGOUT_SEND;
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");
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;
+}