From 82849c6daf5e071c7511f8d8553bc42a099c70e5 Mon Sep 17 00:00:00 2001 From: hiro Date: Wed, 17 Sep 2008 01:52:42 +0000 Subject: implemented remote POP3 mailbox. git-svn-id: svn://sylpheed.sraoss.jp/sylpheed/trunk@2031 ee746299-78ed-0310-b773-934348b2243d --- ChangeLog | 9 + ChangeLog.ja | 10 + libsylph/pop.c | 127 +++++---- libsylph/pop.h | 1 + libsylph/session.c | 19 +- src/Makefile.am | 1 + src/inc.c | 36 +-- src/mainwindow.c | 12 + src/rpop3.c | 736 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/rpop3.h | 34 +++ 10 files changed, 894 insertions(+), 91 deletions(-) create mode 100644 src/rpop3.c create mode 100644 src/rpop3.h diff --git a/ChangeLog b/ChangeLog index 1b640143..64c9ed4b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2008-09-17 + + * libsylph/pop.[ch]: made some functions non-static. + pop3_session_new(): set server, port, userid and password. + * src/inc.c: sync with the libsylph/pop.[ch] change. + * src/rpop3.[ch] + src/mainwindow.c: first implementation of remote POP3 mailbox + feature. Currently, only deletion of messages is available. + 2008-07-16 * src/compose.[ch]: fixed Enchant support. diff --git a/ChangeLog.ja b/ChangeLog.ja index a5d86352..a3abf1bc 100644 --- a/ChangeLog.ja +++ b/ChangeLog.ja @@ -1,3 +1,13 @@ +2008-09-17 + + * libsylph/pop.[ch]: 一部の関数を static でなくした。 + pop3_session_new(): サーバ、ポート、ユーザ ID 、パスワードをセット + するようにした。 + * src/inc.c: libsylph/pop.[ch] の変更に追従。 + * src/rpop3.[ch] + src/mainwindow.c: 最初のリモート POP3 メールボックス機能の実装。 + 現在はメッセージの削除のみ可能。 + 2008-07-16 * src/compose.[ch]: Enchant サポートを修正。 diff --git a/libsylph/pop.c b/libsylph/pop.c index 195c0ed3..872cfc01 100644 --- a/libsylph/pop.c +++ b/libsylph/pop.c @@ -40,39 +40,39 @@ #include "utils.h" #include "recv.h" -static gint pop3_greeting_recv (Pop3Session *session, - const gchar *msg); -static gint pop3_getauth_user_send (Pop3Session *session); -static gint pop3_getauth_pass_send (Pop3Session *session); -static gint pop3_getauth_apop_send (Pop3Session *session); +gint pop3_greeting_recv (Pop3Session *session, + const gchar *msg); +gint pop3_getauth_user_send (Pop3Session *session); +gint pop3_getauth_pass_send (Pop3Session *session); +gint pop3_getauth_apop_send (Pop3Session *session); #if USE_SSL -static gint pop3_stls_send (Pop3Session *session); -static gint pop3_stls_recv (Pop3Session *session); +gint pop3_stls_send (Pop3Session *session); +gint pop3_stls_recv (Pop3Session *session); #endif -static gint pop3_getrange_stat_send (Pop3Session *session); -static gint pop3_getrange_stat_recv (Pop3Session *session, - const gchar *msg); -static gint pop3_getrange_last_send (Pop3Session *session); -static gint pop3_getrange_last_recv (Pop3Session *session, - const gchar *msg); -static gint pop3_getrange_uidl_send (Pop3Session *session); -static gint pop3_getrange_uidl_recv (Pop3Session *session, - const gchar *data, - guint len); -static gint pop3_getsize_list_send (Pop3Session *session); -static gint pop3_getsize_list_recv (Pop3Session *session, - const gchar *data, - guint len); -static gint pop3_retr_send (Pop3Session *session); -static gint pop3_retr_recv (Pop3Session *session, - FILE *fp, - guint len); -static gint pop3_delete_send (Pop3Session *session); -static gint pop3_delete_recv (Pop3Session *session); -static gint pop3_logout_send (Pop3Session *session); - -static void pop3_gen_send (Pop3Session *session, - const gchar *format, ...); +gint pop3_getrange_stat_send (Pop3Session *session); +gint pop3_getrange_stat_recv (Pop3Session *session, + const gchar *msg); +gint pop3_getrange_last_send (Pop3Session *session); +gint pop3_getrange_last_recv (Pop3Session *session, + const gchar *msg); +gint pop3_getrange_uidl_send (Pop3Session *session); +gint pop3_getrange_uidl_recv (Pop3Session *session, + const gchar *data, + guint len); +gint pop3_getsize_list_send (Pop3Session *session); +gint pop3_getsize_list_recv (Pop3Session *session, + const gchar *data, + guint len); +gint pop3_retr_send (Pop3Session *session); +gint pop3_retr_recv (Pop3Session *session, + FILE *fp, + guint len); +gint pop3_delete_send (Pop3Session *session); +gint pop3_delete_recv (Pop3Session *session); +gint pop3_logout_send (Pop3Session *session); + +void pop3_gen_send (Pop3Session *session, + const gchar *format, ...); static void pop3_session_destroy (Session *session); @@ -81,8 +81,9 @@ static gint pop3_write_msg_to_file (const gchar *file, guint len); static Pop3State pop3_lookup_next (Pop3Session *session); -static Pop3ErrorValue pop3_ok (Pop3Session *session, - const gchar *msg); + +Pop3ErrorValue pop3_ok (Pop3Session *session, + const gchar *msg); static gint pop3_session_recv_msg (Session *session, const gchar *msg); @@ -95,7 +96,7 @@ static gint pop3_session_recv_data_as_file_finished guint len); -static gint pop3_greeting_recv(Pop3Session *session, const gchar *msg) +gint pop3_greeting_recv(Pop3Session *session, const gchar *msg) { session->state = POP3_GREETING; @@ -104,14 +105,14 @@ static gint pop3_greeting_recv(Pop3Session *session, const gchar *msg) } #if USE_SSL -static gint pop3_stls_send(Pop3Session *session) +gint pop3_stls_send(Pop3Session *session) { session->state = POP3_STLS; pop3_gen_send(session, "STLS"); return PS_SUCCESS; } -static gint pop3_stls_recv(Pop3Session *session) +gint pop3_stls_recv(Pop3Session *session) { if (session_start_tls(SESSION(session)) < 0) { session->error_val = PS_SOCKET; @@ -121,7 +122,7 @@ static gint pop3_stls_recv(Pop3Session *session) } #endif /* USE_SSL */ -static gint pop3_getauth_user_send(Pop3Session *session) +gint pop3_getauth_user_send(Pop3Session *session) { g_return_val_if_fail(session->user != NULL, -1); @@ -130,7 +131,7 @@ static gint pop3_getauth_user_send(Pop3Session *session) return PS_SUCCESS; } -static gint pop3_getauth_pass_send(Pop3Session *session) +gint pop3_getauth_pass_send(Pop3Session *session) { g_return_val_if_fail(session->pass != NULL, -1); @@ -139,7 +140,7 @@ static gint pop3_getauth_pass_send(Pop3Session *session) return PS_SUCCESS; } -static gint pop3_getauth_apop_send(Pop3Session *session) +gint pop3_getauth_apop_send(Pop3Session *session) { gchar *start, *end; gchar *apop_str; @@ -185,14 +186,14 @@ static gint pop3_getauth_apop_send(Pop3Session *session) return PS_SUCCESS; } -static gint pop3_getrange_stat_send(Pop3Session *session) +gint pop3_getrange_stat_send(Pop3Session *session) { session->state = POP3_GETRANGE_STAT; pop3_gen_send(session, "STAT"); return PS_SUCCESS; } -static gint pop3_getrange_stat_recv(Pop3Session *session, const gchar *msg) +gint pop3_getrange_stat_recv(Pop3Session *session, const gchar *msg) { if (sscanf(msg, "%d %lld", &session->count, &session->total_bytes) != 2) { log_warning(_("POP3 protocol error\n")); @@ -210,14 +211,14 @@ static gint pop3_getrange_stat_recv(Pop3Session *session, const gchar *msg) return PS_SUCCESS; } -static gint pop3_getrange_last_send(Pop3Session *session) +gint pop3_getrange_last_send(Pop3Session *session) { session->state = POP3_GETRANGE_LAST; pop3_gen_send(session, "LAST"); return PS_SUCCESS; } -static gint pop3_getrange_last_recv(Pop3Session *session, const gchar *msg) +gint pop3_getrange_last_recv(Pop3Session *session, const gchar *msg) { gint last; @@ -236,15 +237,14 @@ static gint pop3_getrange_last_recv(Pop3Session *session, const gchar *msg) return PS_SUCCESS; } -static gint pop3_getrange_uidl_send(Pop3Session *session) +gint pop3_getrange_uidl_send(Pop3Session *session) { session->state = POP3_GETRANGE_UIDL; pop3_gen_send(session, "UIDL"); return PS_SUCCESS; } -static gint pop3_getrange_uidl_recv(Pop3Session *session, const gchar *data, - guint len) +gint pop3_getrange_uidl_recv(Pop3Session *session, const gchar *data, guint len) { gchar id[IDLEN + 1]; gchar buf[POPBUFSIZE]; @@ -291,15 +291,14 @@ static gint pop3_getrange_uidl_recv(Pop3Session *session, const gchar *data, return PS_SUCCESS; } -static gint pop3_getsize_list_send(Pop3Session *session) +gint pop3_getsize_list_send(Pop3Session *session) { session->state = POP3_GETSIZE_LIST; pop3_gen_send(session, "LIST"); return PS_SUCCESS; } -static gint pop3_getsize_list_recv(Pop3Session *session, const gchar *data, - guint len) +gint pop3_getsize_list_recv(Pop3Session *session, const gchar *data, guint len) { gchar buf[POPBUFSIZE]; gint buf_len; @@ -332,14 +331,14 @@ static gint pop3_getsize_list_recv(Pop3Session *session, const gchar *data, return PS_SUCCESS; } -static gint pop3_retr_send(Pop3Session *session) +gint pop3_retr_send(Pop3Session *session) { session->state = POP3_RETR; pop3_gen_send(session, "RETR %d", session->cur_msg); return PS_SUCCESS; } -static gint pop3_retr_recv(Pop3Session *session, FILE *fp, guint len) +gint pop3_retr_recv(Pop3Session *session, FILE *fp, guint len) { gchar *file; gint drop_ok; @@ -372,28 +371,28 @@ static gint pop3_retr_recv(Pop3Session *session, FILE *fp, guint len) return PS_SUCCESS; } -static gint pop3_delete_send(Pop3Session *session) +gint pop3_delete_send(Pop3Session *session) { session->state = POP3_DELETE; pop3_gen_send(session, "DELE %d", session->cur_msg); return PS_SUCCESS; } -static gint pop3_delete_recv(Pop3Session *session) +gint pop3_delete_recv(Pop3Session *session) { session->msg[session->cur_msg].recv_time = RECV_TIME_DELETE; session->msg[session->cur_msg].deleted = TRUE; return PS_SUCCESS; } -static gint pop3_logout_send(Pop3Session *session) +gint pop3_logout_send(Pop3Session *session) { session->state = POP3_LOGOUT; pop3_gen_send(session, "QUIT"); return PS_SUCCESS; } -static void pop3_gen_send(Pop3Session *session, const gchar *format, ...) +void pop3_gen_send(Pop3Session *session, const gchar *format, ...) { gchar buf[POPBUFSIZE + 1]; va_list args; @@ -437,6 +436,22 @@ Session *pop3_session_new(PrefsAccount *account) session->error_val = PS_SUCCESS; session->error_msg = NULL; + session->user = g_strdup(account->userid); + session->pass = account->passwd ? g_strdup(account->passwd) : + account->tmp_pass ? g_strdup(account->tmp_pass) : NULL; + + SESSION(session)->server = g_strdup(account->recv_server); + +#if USE_SSL + SESSION(session)->port = account->set_popport ? + account->popport : account->ssl_pop == SSL_TUNNEL ? 995 : 110; + SESSION(session)->ssl_type = account->ssl_pop; + if (account->ssl_pop != SSL_NONE) + SESSION(session)->nonblocking = account->use_nonblocking_ssl; +#else + SESSION(session)->port = account->set_popport ? account->popport : 110; +#endif + return SESSION(session); } @@ -657,7 +672,7 @@ static Pop3State pop3_lookup_next(Pop3Session *session) return POP3_RETR; } -static Pop3ErrorValue pop3_ok(Pop3Session *session, const gchar *msg) +Pop3ErrorValue pop3_ok(Pop3Session *session, const gchar *msg) { Pop3ErrorValue ok; diff --git a/libsylph/pop.h b/libsylph/pop.h index ee2e983e..c3e67e89 100644 --- a/libsylph/pop.h +++ b/libsylph/pop.h @@ -149,6 +149,7 @@ struct _Pop3Session #define IDLEN POPBUFSIZE Session *pop3_session_new (PrefsAccount *account); + GHashTable *pop3_get_uidl_table (PrefsAccount *account); gint pop3_write_uidl_list (Pop3Session *session); diff --git a/libsylph/session.c b/libsylph/session.c index 01962b11..762c00b1 100644 --- a/libsylph/session.c +++ b/libsylph/session.c @@ -119,10 +119,20 @@ void session_init(Session *session) gint session_connect(Session *session, const gchar *server, gushort port) { -#ifdef G_OS_UNIX - session->server = g_strdup(server); +#ifndef G_OS_UNIX + SockInfo *sock; +#endif + g_return_val_if_fail(session != NULL, -1); + g_return_val_if_fail(server != NULL, -1); + g_return_val_if_fail(port > 0, -1); + + if (session->server && session->server != server) { + g_free(session->server); + session->server = g_strdup(server); + } session->port = port; +#ifdef G_OS_UNIX session->conn_id = sock_connect_async(server, port, session_connect_cb, session); if (session->conn_id < 0) { @@ -133,11 +143,6 @@ gint session_connect(Session *session, const gchar *server, gushort port) return 0; #else - SockInfo *sock; - - session->server = g_strdup(server); - session->port = port; - sock = sock_connect(server, port); if (sock == NULL) { g_warning("can't connect to server."); diff --git a/src/Makefile.am b/src/Makefile.am index 59b38aca..bc25307e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -76,6 +76,7 @@ sylpheed_SOURCES = \ gtkutils.c gtkutils.h \ send_message.c send_message.h \ inc.c inc.h \ + rpop3.c rpop3.h \ import.c import.h \ export.c export.h \ rfc2015.c rfc2015.h \ diff --git a/src/inc.c b/src/inc.c index 0fb949c8..17b83ce3 100644 --- a/src/inc.c +++ b/src/inc.c @@ -44,7 +44,6 @@ #include "account.h" #include "procmsg.h" #include "socket.h" -#include "ssl.h" #include "pop.h" #include "recv.h" #include "mbox.h" @@ -638,14 +637,7 @@ static gint inc_start(IncProgressDialog *inc_dialog) } pop3_session = POP3_SESSION(session->session); - pop3_session->user = g_strdup(pop3_session->ac_prefs->userid); - if (pop3_session->ac_prefs->passwd) - pop3_session->pass = - g_strdup(pop3_session->ac_prefs->passwd); - else if (pop3_session->ac_prefs->tmp_pass) - pop3_session->pass = - g_strdup(pop3_session->ac_prefs->tmp_pass); - else { + if (!pop3_session->pass) { gchar *pass; if (inc_dialog->show_dialog) @@ -826,8 +818,6 @@ static IncState inc_pop3_session_do(IncSession *session) { Pop3Session *pop3_session = POP3_SESSION(session->session); IncProgressDialog *inc_dialog = (IncProgressDialog *)session->data; - gchar *server; - gushort port; gchar *buf; debug_print(_("getting new messages of account %s...\n"), @@ -842,21 +832,8 @@ static IncState inc_pop3_session_do(IncSession *session) gtk_window_set_title(GTK_WINDOW(inc_dialog->dialog->window), buf); g_free(buf); - server = pop3_session->ac_prefs->recv_server; -#if USE_SSL - port = pop3_session->ac_prefs->set_popport ? - pop3_session->ac_prefs->popport : - pop3_session->ac_prefs->ssl_pop == SSL_TUNNEL ? 995 : 110; - SESSION(pop3_session)->ssl_type = pop3_session->ac_prefs->ssl_pop; - if (pop3_session->ac_prefs->ssl_pop != SSL_NONE) - SESSION(pop3_session)->nonblocking = - pop3_session->ac_prefs->use_nonblocking_ssl; -#else - port = pop3_session->ac_prefs->set_popport ? - pop3_session->ac_prefs->popport : 110; -#endif - - buf = g_strdup_printf(_("Connecting to POP3 server: %s..."), server); + buf = g_strdup_printf(_("Connecting to POP3 server: %s..."), + pop3_session->ac_prefs->recv_server); log_message("%s\n", buf); progress_dialog_set_label(inc_dialog->dialog, buf); g_free(buf); @@ -866,9 +843,12 @@ static IncState inc_pop3_session_do(IncSession *session) GTK_EVENTS_FLUSH(); - if (session_connect(SESSION(pop3_session), server, port) < 0) { + if (session_connect(SESSION(pop3_session), + SESSION(pop3_session)->server, + SESSION(pop3_session)->port) < 0) { log_warning(_("Can't connect to POP3 server: %s:%d\n"), - server, port); + SESSION(pop3_session)->server, + SESSION(pop3_session)->port); session->inc_state = INC_CONNECT_ERROR; statusbar_pop_all(); return INC_CONNECT_ERROR; diff --git a/src/mainwindow.c b/src/mainwindow.c index 6540e321..3b8b3c28 100644 --- a/src/mainwindow.c +++ b/src/mainwindow.c @@ -64,6 +64,7 @@ #include "stock_pixmap.h" #include "folder.h" #include "inc.h" +#include "rpop3.h" #include "compose.h" #include "procmsg.h" #include "send_message.h" @@ -321,6 +322,10 @@ static void inc_stop_cb (MainWindow *mainwin, guint action, GtkWidget *widget); +static void rpop3_cb (MainWindow *mainwin, + guint action, + GtkWidget *widget); + static void send_queue_cb (MainWindow *mainwin, guint action, GtkWidget *widget); @@ -766,6 +771,8 @@ static GtkItemFactoryEntry mainwin_entries[] = "I", inc_all_account_mail_cb, 0, NULL}, {N_("/_Message/Recei_ve/Stop receivin_g"), NULL, inc_stop_cb, 0, NULL}, + {N_("/_Message/Recei_ve/_Remote mailbox..."), + NULL, rpop3_cb, 0, NULL}, {N_("/_Message/Recei_ve/---"), NULL, NULL, 0, ""}, {N_("/_Message/_Send queued messages"), NULL, send_queue_cb, 0, NULL}, {N_("/_Message/---"), NULL, NULL, 0, ""}, @@ -3460,6 +3467,11 @@ static void inc_stop_cb(MainWindow *mainwin, guint action, GtkWidget *widget) inc_cancel_all(); } +static void rpop3_cb(MainWindow *mainwin, guint action, GtkWidget *widget) +{ + rpop3_account(cur_account); +} + static void send_queue_cb(MainWindow *mainwin, guint action, GtkWidget *widget) { main_window_send_queue(mainwin); diff --git a/src/rpop3.c b/src/rpop3.c new file mode 100644 index 00000000..25045ef5 --- /dev/null +++ b/src/rpop3.c @@ -0,0 +1,736 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999-2008 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 + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "defs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rpop3.h" +#include "mainwindow.h" +#include "prefs_account.h" +#include "pop.h" +#include "procheader.h" +#include "procmsg.h" +#include "inc.h" +#include "utils.h" +#include "gtkutils.h" +#include "manage_window.h" +#include "alertpanel.h" + +#define POP3_TOP (N_POP3_STATE + 1000) +#define POP3_TOP_RECV (N_POP3_STATE + 1001) +#define POP3_IDLE (N_POP3_STATE + 1002) + +enum +{ + COL_NUMBER, + COL_SUBJECT, + COL_FROM, + COL_DATE, + COL_SIZE, + COL_MSGINFO, + COL_DELETED, + N_COLS +}; + +static struct RPop3Window { + GtkWidget *window; + + GtkWidget *treeview; + GtkListStore *store; + + GtkWidget *status_label; + + GtkWidget *open_btn; + GtkWidget *delete_btn; + GtkWidget *close_btn; + + Pop3Session *session; + gboolean cancelled; + gboolean finished; + GArray *delete_array; + gint delete_cur; +} rpop3_window; + +static void rpop3_window_create (PrefsAccount *account); + +gint pop3_greeting_recv (Pop3Session *session, + const gchar *msg); +gint pop3_getauth_user_send (Pop3Session *session); +gint pop3_getauth_pass_send (Pop3Session *session); +gint pop3_getauth_apop_send (Pop3Session *session); +#if USE_SSL +gint pop3_stls_send (Pop3Session *session); +gint pop3_stls_recv (Pop3Session *session); +#endif +gint pop3_getrange_stat_send (Pop3Session *session); +gint pop3_getrange_stat_recv (Pop3Session *session, + const gchar *msg); +gint pop3_getrange_last_send (Pop3Session *session); +gint pop3_getrange_last_recv (Pop3Session *session, + const gchar *msg); +gint pop3_getrange_uidl_send (Pop3Session *session); +gint pop3_getrange_uidl_recv (Pop3Session *session, + const gchar *data, + guint len); +gint pop3_getsize_list_send (Pop3Session *session); +gint pop3_getsize_list_recv (Pop3Session *session, + const gchar *data, + guint len); +gint pop3_retr_send (Pop3Session *session); +gint pop3_retr_recv (Pop3Session *session, + FILE *fp, + guint len); +gint pop3_delete_send (Pop3Session *session); +gint pop3_delete_recv (Pop3Session *session); +gint pop3_logout_send (Pop3Session *session); + +void pop3_gen_send (Pop3Session *session, + const gchar *format, ...); + +Pop3ErrorValue pop3_ok (Pop3Session *session, + const gchar *msg); + +static gint rpop3_start (Session *session); +static void rpop3_status_label_set (const gchar *fmt, + ...) G_GNUC_PRINTF(1, 2); +static void rpop3_clear_list (void); + +static gint rpop3_top_send (Pop3Session *session); +static gint rpop3_top_recv (Pop3Session *session, + FILE *fp, + guint len); + +static gint rpop3_session_recv_msg (Session *session, + const gchar *msg); +static gint rpop3_session_recv_data_finished (Session *session, + guchar *data, + guint len); +static gint rpop3_session_recv_data_as_file_finished + (Session *session, + FILE *fp, + guint len); + +static gint window_deleted (GtkWidget *widget, + GdkEventAny *event, + gpointer data); +static gboolean key_pressed (GtkWidget *widget, + GdkEventKey *event, + gpointer data); + +static void rpop3_open (GtkButton *button, + gpointer data); +static void rpop3_delete (GtkButton *button, + gpointer data); +static void rpop3_close (GtkButton *button, + gpointer data); + + +gint rpop3_account(PrefsAccount *account) +{ + Session *session; + gint ret; + + if (!account || account->protocol != A_POP3) + return -1; + if (inc_is_active()) + return -1; + + inc_lock(); + + rpop3_window_create(account); + + session = pop3_session_new(account); + rpop3_window.session = POP3_SESSION(session); + rpop3_window.cancelled = FALSE; + rpop3_window.finished = FALSE; + + /* override Pop3Session handlers */ + session->recv_msg = rpop3_session_recv_msg; + session->send_data_finished = NULL; + session->recv_data_finished = rpop3_session_recv_data_finished; + session->recv_data_as_file_finished = + rpop3_session_recv_data_as_file_finished; + + if (!POP3_SESSION(session)->pass) { + gchar *pass; + + pass = input_query_password(account->recv_server, + account->userid); + if (pass) { + account->tmp_pass = g_strdup(pass); + POP3_SESSION(session)->pass = pass; + } + } + + ret = rpop3_start(session); + + while (!rpop3_window.finished) + gtk_main_iteration(); + + session_destroy(session); + rpop3_clear_list(); + gtk_widget_destroy(rpop3_window.window); + memset(&rpop3_window, 0, sizeof(rpop3_window)); + + inc_unlock(); + + return ret; +} + +static void rpop3_window_create(PrefsAccount *account) +{ + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *scrwin; + GtkWidget *treeview; + GtkListStore *store; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkTreeSelection *selection; + GtkWidget *hbox; + GtkWidget *status_label; + GtkWidget *hbbox; + GtkWidget *open_btn; + GtkWidget *delete_btn; + GtkWidget *close_btn; + gchar buf[BUFFSIZE]; + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + g_snprintf(buf, sizeof(buf), _("%s - Remote POP3 mailbox"), + account->account_name ? account->account_name : ""); + gtk_window_set_title(GTK_WINDOW(window), buf); + gtk_widget_set_size_request(window, 640, -1); + gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, TRUE); + gtk_container_set_border_width(GTK_CONTAINER (window), 8); + g_signal_connect(G_OBJECT(window), "delete_event", + G_CALLBACK(window_deleted), NULL); + g_signal_connect(G_OBJECT(window), "key_press_event", + G_CALLBACK(key_pressed), NULL); + MANAGE_WINDOW_SIGNALS_CONNECT(window); + + vbox = gtk_vbox_new(FALSE, 6); + gtk_container_add(GTK_CONTAINER(window), vbox); + + scrwin = gtk_scrolled_window_new(NULL, NULL); + gtk_box_pack_start(GTK_BOX(vbox), scrwin, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrwin), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_widget_set_size_request(scrwin, -1, 320); + + store = gtk_list_store_new(N_COLS, G_TYPE_INT, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_POINTER, G_TYPE_BOOLEAN); + treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + g_object_unref(store); + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); + + gtk_container_add(GTK_CONTAINER(scrwin), treeview); + +#define APPEND_COLUMN(label, col, width) \ +{ \ + renderer = gtk_cell_renderer_text_new(); \ + column = gtk_tree_view_column_new_with_attributes \ + (label, renderer, "text", col, \ + "strikethrough", COL_DELETED, NULL); \ + gtk_tree_view_column_set_resizable(column, TRUE); \ + if (width) { \ + gtk_tree_view_column_set_sizing \ + (column, GTK_TREE_VIEW_COLUMN_FIXED); \ + gtk_tree_view_column_set_fixed_width(column, width); \ + } \ + gtk_tree_view_column_set_sort_column_id(column, col); \ + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); \ +} + + APPEND_COLUMN(_("No."), COL_NUMBER, 0); + APPEND_COLUMN(_("Subject"), COL_SUBJECT, 200); + APPEND_COLUMN(_("From"), COL_FROM, 160); + APPEND_COLUMN(_("Date"), COL_DATE, 140); + APPEND_COLUMN(_("Size"), COL_SIZE, 0); + + gtk_widget_show_all(scrwin); + + hbox = gtk_hbox_new(FALSE, 8); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + status_label = gtk_label_new(""); + gtk_box_pack_start(GTK_BOX(hbox), status_label, FALSE, FALSE, 0); + + hbbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END); + gtk_box_set_spacing(GTK_BOX(hbbox), 6); + gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); + + open_btn = gtk_button_new_from_stock(GTK_STOCK_OPEN); + gtk_box_pack_start(GTK_BOX(hbbox), open_btn, FALSE, FALSE, 0); + gtk_widget_set_sensitive(open_btn, FALSE); + + delete_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE); + gtk_box_pack_start(GTK_BOX(hbbox), delete_btn, FALSE, FALSE, 0); + gtk_widget_set_sensitive(delete_btn, FALSE); + + close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE); + gtk_box_pack_start(GTK_BOX(hbbox), close_btn, FALSE, FALSE, 0); + + g_signal_connect(G_OBJECT(open_btn), "clicked", + G_CALLBACK(rpop3_open), NULL); + g_signal_connect(G_OBJECT(delete_btn), "clicked", + G_CALLBACK(rpop3_delete), NULL); + g_signal_connect(G_OBJECT(close_btn), "clicked", + G_CALLBACK(rpop3_close), NULL); + + gtk_widget_show_all(window); + + rpop3_window.window = window; + rpop3_window.treeview = treeview; + rpop3_window.store = store; + rpop3_window.status_label = status_label; + rpop3_window.open_btn = open_btn; + rpop3_window.delete_btn = delete_btn; + rpop3_window.close_btn = close_btn; +} + +static gint rpop3_start(Session *session) +{ + g_return_val_if_fail(session != NULL, -1); + + rpop3_status_label_set(_("Connecting to %s:%d"), + session->server, session->port); + + if (session_connect(session, session->server, session->port) < 0) { + log_warning(_("Can't connect to POP3 server: %s:%d\n"), + session->server, session->port); + return -1; + } + + while (session_is_connected(session)) + gtk_main_iteration(); + + return 0; +} + +static void rpop3_status_label_set(const gchar *fmt, ...) +{ + va_list args; + gchar buf[1024]; + + va_start(args, fmt); + g_vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + gtk_label_set_text(GTK_LABEL(rpop3_window.status_label), buf); +} + +static gboolean clear_func(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data) +{ + MsgInfo *msginfo; + + gtk_tree_model_get(model, iter, COL_MSGINFO, &msginfo, -1); + procmsg_msginfo_free(msginfo); + + return FALSE; +} + +static void rpop3_clear_list(void) +{ + + gtk_tree_model_foreach(GTK_TREE_MODEL(rpop3_window.store), clear_func, + NULL); + gtk_list_store_clear(rpop3_window.store); +} + +static gint rpop3_top_send(Pop3Session *session) +{ + session->state = POP3_TOP; + pop3_gen_send(session, "TOP %d 0", session->cur_msg); + return PS_SUCCESS; +} + +static gint rpop3_top_recv(Pop3Session *session, FILE *fp, guint len) +{ + MsgInfo *msginfo; + MsgFlags flags = {0, 0}; + GtkTreeIter iter; + const gchar *subject, *from, *date; + gchar buf[1024]; + + debug_print("rpop3_top_recv(): %d / %d (size %u)\n", session->cur_msg, session->count, len); + + msginfo = procheader_parse_stream(fp, flags, FALSE); + + subject = msginfo->subject ? msginfo->subject : _("(No Subject)"); + from = msginfo->from ? msginfo->from : _("(No From)"); + if (msginfo->date_t) { + procheader_date_get_localtime(buf, sizeof(buf), + msginfo->date_t); + date = buf; + } else if (msginfo->date) + date = msginfo->date; + else + date = _("(No Date)"); + + gtk_list_store_append(rpop3_window.store, &iter); + gtk_list_store_set(rpop3_window.store, &iter, + COL_NUMBER, session->cur_msg, + COL_SUBJECT, subject, + COL_FROM, from, + COL_DATE, date, + COL_SIZE, to_human_readable + (session->msg[session->cur_msg].size), + COL_MSGINFO, msginfo, + COL_DELETED, FALSE, + -1); + + rpop3_status_label_set(_("Retrieving message headers (%d / %d)"), + session->cur_msg, session->count); + + return PS_SUCCESS; +} + +static gint rpop3_delete_send(Pop3Session *session) +{ + g_return_val_if_fail(rpop3_window.delete_array != NULL, -1); + g_return_val_if_fail + (rpop3_window.delete_cur < rpop3_window.delete_array->len, -1); + + session->state = POP3_DELETE; + session->cur_msg = g_array_index(rpop3_window.delete_array, gint, + rpop3_window.delete_cur); + pop3_gen_send(session, "DELE %d", session->cur_msg); + return PS_SUCCESS; +} + +static gint rpop3_delete_recv(Pop3Session *session) +{ + session->msg[session->cur_msg].recv_time = RECV_TIME_DELETE; + session->msg[session->cur_msg].deleted = TRUE; + return PS_SUCCESS; +} + +static gint rpop3_session_recv_msg(Session *session, const gchar *msg) +{ + Pop3Session *pop3_session = POP3_SESSION(session); + gint val = PS_SUCCESS; + const gchar *body; + + body = msg; + if (pop3_session->state != POP3_GETRANGE_UIDL_RECV && + pop3_session->state != POP3_GETSIZE_LIST_RECV) { + val = pop3_ok(pop3_session, msg); + if (val != PS_SUCCESS) { + if (val != PS_NOTSUPPORTED) { + pop3_session->state = POP3_ERROR; + return -1; + } + } + + if (*body == '+' || *body == '-') + body++; + while (g_ascii_isalpha(*body)) + body++; + while (g_ascii_isspace(*body)) + body++; + } + + switch (pop3_session->state) { + case POP3_READY: + case POP3_GREETING: + val = pop3_greeting_recv(pop3_session, body); + rpop3_status_label_set(_("Authenticating...")); +#if USE_SSL + if (pop3_session->ac_prefs->ssl_pop == SSL_STARTTLS) + val = pop3_stls_send(pop3_session); + else +#endif + if (pop3_session->ac_prefs->use_apop_auth) + val = pop3_getauth_apop_send(pop3_session); + else + val = pop3_getauth_user_send(pop3_session); + break; +#if USE_SSL + case POP3_STLS: + if ((val = pop3_stls_recv(pop3_session)) != PS_SUCCESS) + return -1; + if (pop3_session->ac_prefs->use_apop_auth) + val = pop3_getauth_apop_send(pop3_session); + else + val = pop3_getauth_user_send(pop3_session); + break; +#endif + case POP3_GETAUTH_USER: + val = pop3_getauth_pass_send(pop3_session); + break; + case POP3_GETAUTH_PASS: + case POP3_GETAUTH_APOP: + rpop3_status_label_set(_("Getting the number of messages...")); + val = pop3_getrange_stat_send(pop3_session); + break; + case POP3_GETRANGE_STAT: + if ((val = pop3_getrange_stat_recv(pop3_session, body)) < 0) + return -1; + if (pop3_session->count > 0) + val = pop3_getrange_uidl_send(pop3_session); + else { + rpop3_status_label_set(_("No message")); + val = pop3_logout_send(pop3_session); + } + break; + case POP3_GETRANGE_LAST: + if (val == PS_NOTSUPPORTED) + pop3_session->error_val = PS_SUCCESS; + else if ((val = pop3_getrange_last_recv + (pop3_session, body)) < 0) + return -1; + if (pop3_session->cur_msg > 0) + val = pop3_getsize_list_send(pop3_session); + else { + rpop3_status_label_set(_("No message")); + val = pop3_logout_send(pop3_session); + } + break; + case POP3_GETRANGE_UIDL: + if (val == PS_NOTSUPPORTED) { + pop3_session->error_val = PS_SUCCESS; + val = pop3_getrange_last_send(pop3_session); + } else { + pop3_session->state = POP3_GETRANGE_UIDL_RECV; + val = session_recv_data(session, 0, ".\r\n"); + } + break; + case POP3_GETSIZE_LIST: + pop3_session->state = POP3_GETSIZE_LIST_RECV; + val = session_recv_data(session, 0, ".\r\n"); + break; + case POP3_TOP: + pop3_session->state = POP3_TOP_RECV; + val = session_recv_data_as_file(session, 0, ".\r\n"); + break; + case POP3_RETR: + pop3_session->state = POP3_RETR_RECV; + val = session_recv_data_as_file(session, 0, ".\r\n"); + break; + case POP3_DELETE: + val = rpop3_delete_recv(pop3_session); + if (val != PS_SUCCESS) + break; + if (rpop3_window.delete_cur + 1 < rpop3_window.delete_array->len) { + rpop3_window.delete_cur++; + val = rpop3_delete_send(pop3_session); + } else { + rpop3_status_label_set(_("Deleted %d messages"), + rpop3_window.delete_cur + 1); + g_array_free(rpop3_window.delete_array, TRUE); + rpop3_window.delete_array = NULL; + rpop3_window.delete_cur = 0; + pop3_session->state = POP3_IDLE; + } + break; + case POP3_LOGOUT: + pop3_session->state = POP3_DONE; + session_disconnect(session); + break; + case POP3_ERROR: + default: + return -1; + } + + if (val == PS_SUCCESS) + return 0; + else + return -1; +} + +static gint rpop3_session_recv_data_finished(Session *session, guchar *data, + guint len) +{ + Pop3Session *pop3_session = POP3_SESSION(session); + Pop3ErrorValue val = PS_SUCCESS; + + switch (pop3_session->state) { + case POP3_GETRANGE_UIDL_RECV: + val = pop3_getrange_uidl_recv(pop3_session, (gchar *)data, len); + if (val == PS_SUCCESS) { + if (rpop3_window.cancelled) + pop3_logout_send(rpop3_window.session); + else + pop3_getsize_list_send(pop3_session); + } else + return -1; + break; + case POP3_GETSIZE_LIST_RECV: + val = pop3_getsize_list_recv(pop3_session, (gchar *)data, len); + if (val == PS_SUCCESS) { + pop3_session->cur_msg = 1; + if (rpop3_window.cancelled || pop3_session->count == 0) + pop3_logout_send(rpop3_window.session); + else + rpop3_top_send(pop3_session); + } else + return -1; + break; + case POP3_ERROR: + default: + return -1; + } + + return 0; +} + +static gint rpop3_session_recv_data_as_file_finished(Session *session, + FILE *fp, guint len) +{ + Pop3Session *pop3_session = POP3_SESSION(session); + + switch (pop3_session->state) { + case POP3_RETR_RECV: + if (pop3_retr_recv(pop3_session, fp, len) < 0) + return -1; + break; + case POP3_TOP_RECV: + if (rpop3_top_recv(pop3_session, fp, len) == PS_SUCCESS) { + if (rpop3_window.cancelled) + pop3_logout_send(rpop3_window.session); + else if (pop3_session->cur_msg < pop3_session->count) { + pop3_session->cur_msg++; + rpop3_top_send(pop3_session); + } else { + rpop3_status_label_set + (_("Retrieved %d message headers"), + pop3_session->count); + gtk_widget_set_sensitive + (rpop3_window.open_btn, TRUE); + gtk_widget_set_sensitive + (rpop3_window.delete_btn, TRUE); + pop3_session->state = POP3_IDLE; + } + } else + return -1; + break; + default: + return -1; + } + + return 0; +} + +static gint window_deleted(GtkWidget *widget, GdkEventAny *event, + gpointer data) +{ + gtk_button_clicked(GTK_BUTTON(rpop3_window.close_btn)); + return TRUE; +} + +static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, + gpointer data) +{ + return FALSE; +} + +static void rpop3_open(GtkButton *button, gpointer data) +{ +} + +static void rpop3_delete(GtkButton *button, gpointer data) +{ + GtkTreeModel *model = GTK_TREE_MODEL(rpop3_window.store); + GtkTreeSelection *selection; + GtkTreeIter iter; + GList *rows, *cur; + gint num; + gboolean deleted; + GArray *array; + AlertValue val; + + if (rpop3_window.session->state != POP3_IDLE) + return; + + val = alertpanel(_("Delete messages"), + _("Really delete selected messages from server?\n" + "This operation cannot be reverted."), + GTK_STOCK_YES, GTK_STOCK_NO, NULL); + if (val != G_ALERTDEFAULT) + return; + + selection = gtk_tree_view_get_selection + (GTK_TREE_VIEW(rpop3_window.treeview)); + + rows = gtk_tree_selection_get_selected_rows(selection, NULL); + + array = g_array_sized_new(FALSE, FALSE, sizeof(gint), + g_list_length(rows)); + + for (cur = rows; cur != NULL; cur = cur->next) { + gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)cur->data); + gtk_tree_model_get(model, &iter, COL_NUMBER, &num, + COL_DELETED, &deleted, -1); + if (!deleted) { + debug_print("rpop3_delete: marked %d to delete\n", num); + g_array_append_val(array, num); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, + COL_DELETED, TRUE, -1); + } + } + + g_list_foreach(rows, (GFunc)gtk_tree_path_free, NULL); + g_list_free(rows); + + if (array->len > 0) { + rpop3_window.delete_array = array; + rpop3_window.delete_cur = 0; + + rpop3_delete_send(rpop3_window.session); + } else + g_array_free(array, TRUE); +} + +static void rpop3_close(GtkButton *button, gpointer data) +{ + rpop3_window.finished = TRUE; + + if (rpop3_window.session->state == POP3_IDLE) + pop3_logout_send(rpop3_window.session); + else if (rpop3_window.session->state != POP3_DONE || + rpop3_window.session->state != POP3_ERROR) + rpop3_window.cancelled = TRUE; +} diff --git a/src/rpop3.h b/src/rpop3.h new file mode 100644 index 00000000..7f5d89a4 --- /dev/null +++ b/src/rpop3.h @@ -0,0 +1,34 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999-2008 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 + * 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 __RPOP3_H__ +#define __RPOP3_H__ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "mainwindow.h" +#include "prefs_account.h" + +gint rpop3_account (PrefsAccount *account); + +#endif /* __RPOP3_H__ */ -- cgit v1.2.3