summaryrefslogtreecommitdiff
path: root/src/rpop3.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpop3.c')
-rw-r--r--src/rpop3.c1418
1 files changed, 1418 insertions, 0 deletions
diff --git a/src/rpop3.c b/src/rpop3.c
new file mode 100644
index 0000000..571671f
--- /dev/null
+++ b/src/rpop3.c
@@ -0,0 +1,1418 @@
1/*
2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2014 Hiroyuki Yamamoto
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20#ifdef HAVE_CONFIG_H
21# include "config.h"
22#endif
23
24#include "defs.h"
25
26#include <glib.h>
27#include <glib/gi18n.h>
28#include <gtk/gtkwindow.h>
29#include <gtk/gtkvbox.h>
30#include <gtk/gtkhbox.h>
31#include <gtk/gtklabel.h>
32#include <gtk/gtkentry.h>
33#include <gtk/gtkhbbox.h>
34#include <gtk/gtkbutton.h>
35#include <gtk/gtkstock.h>
36#include <gtk/gtktreemodel.h>
37#include <gtk/gtkliststore.h>
38#include <gtk/gtktreeview.h>
39#include <gtk/gtktreeselection.h>
40#include <gtk/gtkcellrenderertext.h>
41#include <gtk/gtkuimanager.h>
42#include <string.h>
43
44#include "rpop3.h"
45#include "mainwindow.h"
46#include "folderview.h"
47#include "prefs_account.h"
48#include "socks.h"
49#include "pop.h"
50#include "procheader.h"
51#include "procmsg.h"
52#include "folder.h"
53#include "inc.h"
54#include "utils.h"
55#include "gtkutils.h"
56#include "manage_window.h"
57#include "alertpanel.h"
58#include "prefs_common.h"
59#include "about.h"
60
61/* POP3 NOOP ping interval (sec) */
62#define POP3_PING_ITV 30
63
64#define POP3_TOP (N_POP3_STATE + 1000)
65#define POP3_TOP_RECV (N_POP3_STATE + 1001)
66#define POP3_NOOP (N_POP3_STATE + 1002)
67#define POP3_IDLE (N_POP3_STATE + 1003)
68
69enum
70{
71 COL_NUMBER,
72 COL_SUBJECT,
73 COL_FROM,
74 COL_DATE,
75 COL_SIZE,
76 COL_MSGINFO,
77 COL_DELETED,
78 N_COLS
79};
80
81static struct RPop3Window {
82 GtkWidget *window;
83
84 GtkWidget *treeview;
85 GtkListStore *store;
86
87 GtkWidget *status_label;
88
89 GtkWidget *recv_btn;
90 GtkWidget *open_btn;
91 GtkWidget *delete_btn;
92 GtkWidget *stop_btn;
93 GtkWidget *close_btn;
94
95 GtkAction *recv_action;
96 GtkAction *open_action;
97 GtkAction *delete_action;
98 GtkAction *update_action;
99 GtkAction *stop_action;
100
101 Pop3Session *session;
102 guint ping_tag;
103 gboolean stop_load;
104 gboolean cancelled;
105 gboolean finished;
106 GArray *delete_array;
107 gint delete_cur;
108 GArray *recv_array;
109 gint recv_cur;
110} rpop3_window;
111
112static const gchar *ui_def =
113 "<ui>"
114 " <menubar name='RPop3Menu'>"
115 " <menu name='File' action='FileAction'>"
116 " <menuitem name='Receive' action='ReceiveAction'/>"
117 " <menuitem name='Open' action='OpenAction'/>"
118 " <menuitem name='Delete' action='DeleteAction'/>"
119 " <separator />"
120 " <menuitem name='Resume' action='ResumeAction'/>"
121 " <menuitem name='Stop' action='StopAction'/>"
122 " <separator />"
123 " <menuitem name='Close' action='CloseAction'/>"
124 " </menu>"
125 " <menu name='Help' action='HelpAction'>"
126 " <menuitem name='About' action='AboutAction'/>"
127 " </menu>"
128 " </menubar>"
129 "</ui>";
130
131static void rpop3_window_create (PrefsAccount *account);
132
133gint pop3_greeting_recv (Pop3Session *session,
134 const gchar *msg);
135gint pop3_getauth_user_send (Pop3Session *session);
136gint pop3_getauth_pass_send (Pop3Session *session);
137gint pop3_getauth_apop_send (Pop3Session *session);
138#if USE_SSL
139gint pop3_stls_send (Pop3Session *session);
140gint pop3_stls_recv (Pop3Session *session);
141#endif
142gint pop3_getrange_stat_send (Pop3Session *session);
143gint pop3_getrange_stat_recv (Pop3Session *session,
144 const gchar *msg);
145gint pop3_getrange_last_send (Pop3Session *session);
146gint pop3_getrange_last_recv (Pop3Session *session,
147 const gchar *msg);
148gint pop3_getrange_uidl_send (Pop3Session *session);
149gint pop3_getrange_uidl_recv (Pop3Session *session,
150 const gchar *data,
151 guint len);
152gint pop3_getsize_list_send (Pop3Session *session);
153gint pop3_getsize_list_recv (Pop3Session *session,
154 const gchar *data,
155 guint len);
156gint pop3_retr_send (Pop3Session *session);
157gint pop3_retr_recv (Pop3Session *session,
158 FILE *fp,
159 guint len);
160gint pop3_logout_send (Pop3Session *session);
161
162void pop3_gen_send (Pop3Session *session,
163 const gchar *format, ...);
164
165gint pop3_write_msg_to_file (const gchar *file,
166 FILE *src_fp,
167 guint len);
168
169Pop3ErrorValue pop3_ok (Pop3Session *session,
170 const gchar *msg);
171
172static gint rpop3_start (Session *session);
173static void rpop3_status_label_set (const gchar *fmt,
174 ...) G_GNUC_PRINTF(1, 2);
175static void rpop3_clear_list (void);
176
177static void rpop3_idle (gboolean is_idle);
178
179static gint rpop3_noop_send (Pop3Session *session);
180
181static gint rpop3_top_send (Pop3Session *session);
182static gint rpop3_top_recv (Pop3Session *session,
183 FILE *fp,
184 guint len);
185static gint rpop3_retr_send (Pop3Session *session);
186static gint rpop3_retr_recv (Pop3Session *session,
187 FILE *fp,
188 guint len);
189static gint rpop3_delete_send (Pop3Session *session);
190static gint rpop3_delete_recv (Pop3Session *session);
191
192static gint rpop3_session_recv_msg (Session *session,
193 const gchar *msg);
194static gint rpop3_session_recv_data_finished (Session *session,
195 guchar *data,
196 guint len);
197static gint rpop3_session_recv_data_as_file_finished
198 (Session *session,
199 FILE *fp,
200 guint len);
201
202static gint window_deleted (GtkWidget *widget,
203 GdkEventAny *event,
204 gpointer data);
205static gboolean key_pressed (GtkWidget *widget,
206 GdkEventKey *event,
207 gpointer data);
208
209static void rpop3_row_activated (GtkTreeView *treeview,
210 GtkTreePath *path,
211 GtkTreeViewColumn *column,
212 gpointer data);
213
214static void rpop3_recv (GtkButton *button,
215 gpointer data);
216static void rpop3_open (GtkButton *button,
217 gpointer data);
218static void rpop3_delete (GtkButton *button,
219 gpointer data);
220static void rpop3_stop (GtkButton *button,
221 gpointer data);
222static void rpop3_close (GtkButton *button,
223 gpointer data);
224
225static void rpop3_recv_cb (void);
226static void rpop3_open_cb (void);
227static void rpop3_delete_cb (void);
228static void rpop3_resume_cb (void);
229static void rpop3_stop_cb (void);
230static void rpop3_close_cb (void);
231static void rpop3_about_cb (void);
232
233static gint cmp_by_subject (GtkTreeModel *model,
234 GtkTreeIter *a,
235 GtkTreeIter *b,
236 gpointer data);
237static gint cmp_by_date (GtkTreeModel *model,
238 GtkTreeIter *a,
239 GtkTreeIter *b,
240 gpointer data);
241static gint cmp_by_size (GtkTreeModel *model,
242 GtkTreeIter *a,
243 GtkTreeIter *b,
244 gpointer data);
245
246static GtkActionEntry action_entries[] = {
247 {"FileAction", NULL, N_("_File"), NULL, NULL, NULL},
248 {"ReceiveAction", NULL, N_("_Get"), "<Control>G", NULL, rpop3_recv_cb},
249 {"OpenAction", GTK_STOCK_OPEN, NULL, NULL, NULL, rpop3_open_cb},
250 {"DeleteAction", GTK_STOCK_DELETE, NULL, "<Shift>Delete", NULL, rpop3_delete_cb},
251 {"ResumeAction", GTK_STOCK_REFRESH, N_("_Resume"), NULL, NULL, rpop3_resume_cb},
252 {"StopAction", GTK_STOCK_STOP, NULL, NULL, NULL, rpop3_stop_cb},
253 {"CloseAction", GTK_STOCK_CLOSE, NULL, NULL, NULL, rpop3_close_cb},
254 {"HelpAction", NULL, N_("_Help"), NULL, NULL, NULL},
255 {"AboutAction", GTK_STOCK_ABOUT, N_("_About"), NULL, NULL,
256 rpop3_about_cb}
257};
258
259
260gint rpop3_account(PrefsAccount *account)
261{
262 Session *session;
263 gint ret;
264
265 if (!account || account->protocol != A_POP3)
266 return -1;
267 if (inc_is_active())
268 return -1;
269 if (rpop3_window.window)
270 return -1;
271
272 inc_lock();
273
274 rpop3_window_create(account);
275
276 session = pop3_session_new(account);
277 rpop3_window.session = POP3_SESSION(session);
278 rpop3_window.stop_load = FALSE;
279 rpop3_window.cancelled = FALSE;
280 rpop3_window.finished = FALSE;
281 if (POP3_SESSION(session)->uidl_table) {
282 hash_free_strings(POP3_SESSION(session)->uidl_table);
283 g_hash_table_destroy(POP3_SESSION(session)->uidl_table);
284 POP3_SESSION(session)->uidl_table =
285 g_hash_table_new(g_str_hash, g_str_equal);
286 }
287
288 /* override Pop3Session handlers */
289 session->recv_msg = rpop3_session_recv_msg;
290 session->send_data_finished = NULL;
291 session->recv_data_finished = rpop3_session_recv_data_finished;
292 session->recv_data_as_file_finished =
293 rpop3_session_recv_data_as_file_finished;
294
295 if (!POP3_SESSION(session)->pass) {
296 gchar *pass;
297
298 pass = input_query_password(account->recv_server,
299 account->userid);
300 if (pass) {
301 account->tmp_pass = g_strdup(pass);
302 POP3_SESSION(session)->pass = pass;
303 }
304 }
305
306 session_set_timeout(session, prefs_common.io_timeout_secs * 1000);
307
308 ret = rpop3_start(session);
309
310 while (!rpop3_window.finished)
311 gtk_main_iteration();
312
313 if (POP3_SESSION(session)->error_val == PS_AUTHFAIL &&
314 account->tmp_pass) {
315 debug_print("rpop3_account: remove temporary password because of authentication failure\n");
316 g_free(account->tmp_pass);
317 account->tmp_pass = NULL;
318 }
319
320 rpop3_idle(FALSE);
321 session_destroy(session);
322 rpop3_clear_list();
323 gtk_widget_destroy(rpop3_window.window);
324 memset(&rpop3_window, 0, sizeof(rpop3_window));
325
326 inc_unlock();
327
328 return ret;
329}
330
331static void rpop3_window_create(PrefsAccount *account)
332{
333 GtkWidget *window;
334 GtkWidget *vbox;
335 GtkActionGroup *group;
336 GtkUIManager *ui;
337 GtkAction *action;
338 GtkWidget *menubar;
339 GtkWidget *vbox2;
340 GtkWidget *scrwin;
341 GtkWidget *treeview;
342 GtkListStore *store;
343 GtkTreeViewColumn *column;
344 GtkCellRenderer *renderer;
345 GtkTreeSelection *selection;
346 GtkWidget *hbox;
347 GtkWidget *status_label;
348 GtkWidget *hbbox;
349 GtkWidget *recv_btn;
350 GtkWidget *open_btn;
351 GtkWidget *delete_btn;
352 GtkWidget *stop_btn;
353 GtkWidget *close_btn;
354 gchar buf[BUFFSIZE];
355
356 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
357 g_snprintf(buf, sizeof(buf), _("%s - POP3 Remote mailbox"),
358 account->account_name ? account->account_name : "");
359 gtk_window_set_title(GTK_WINDOW(window), buf);
360 gtk_widget_set_size_request(window, 640 * gtkut_get_dpi_multiplier(), -1);
361 gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, TRUE);
362 g_signal_connect(G_OBJECT(window), "delete_event",
363 G_CALLBACK(window_deleted), NULL);
364 g_signal_connect(G_OBJECT(window), "key_press_event",
365 G_CALLBACK(key_pressed), NULL);
366 MANAGE_WINDOW_SIGNALS_CONNECT(window);
367
368 vbox = gtk_vbox_new(FALSE, 0);
369 gtk_container_add(GTK_CONTAINER(window), vbox);
370
371 group = gtk_action_group_new("rpop3");
372 gtk_action_group_set_translation_domain(group, GETTEXT_PACKAGE);
373 gtk_action_group_add_actions(group, action_entries,
374 sizeof(action_entries) /
375 sizeof(action_entries[0]), NULL);
376
377 ui = gtk_ui_manager_new();
378 gtk_ui_manager_insert_action_group(ui, group, 0);
379 gtk_ui_manager_add_ui_from_string(ui, ui_def, -1, NULL);
380 menubar = gtk_ui_manager_get_widget(ui, "/RPop3Menu");
381 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
382 gtk_window_add_accel_group(GTK_WINDOW(window),
383 gtk_ui_manager_get_accel_group(ui));
384
385 vbox2 = gtk_vbox_new(FALSE, 6);
386 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
387 gtk_container_set_border_width(GTK_CONTAINER(vbox2), 8);
388
389 scrwin = gtk_scrolled_window_new(NULL, NULL);
390 gtk_box_pack_start(GTK_BOX(vbox2), scrwin, TRUE, TRUE, 0);
391 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrwin),
392 GTK_POLICY_AUTOMATIC,
393 GTK_POLICY_AUTOMATIC);
394 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrwin),
395 GTK_SHADOW_IN);
396 gtk_widget_set_size_request(scrwin, -1, 320 * gtkut_get_dpi_multiplier());
397
398 store = gtk_list_store_new(N_COLS, G_TYPE_INT, G_TYPE_STRING,
399 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
400 G_TYPE_POINTER, G_TYPE_BOOLEAN);
401 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
402 g_object_unref(store);
403 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
404
405 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), COL_SUBJECT,
406 cmp_by_subject, NULL, NULL);
407 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), COL_DATE,
408 cmp_by_date, NULL, NULL);
409 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), COL_SIZE,
410 cmp_by_size, NULL, NULL);
411
412 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
413 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
414
415 gtk_container_add(GTK_CONTAINER(scrwin), treeview);
416
417#define APPEND_COLUMN(label, col, width) \
418{ \
419 renderer = gtk_cell_renderer_text_new(); \
420 column = gtk_tree_view_column_new_with_attributes \
421 (label, renderer, "text", col, \
422 "strikethrough", COL_DELETED, NULL); \
423 gtk_tree_view_column_set_resizable(column, TRUE); \
424 if (width) { \
425 gtk_tree_view_column_set_sizing \
426 (column, GTK_TREE_VIEW_COLUMN_FIXED); \
427 gtk_tree_view_column_set_fixed_width(column, width); \
428 } \
429 gtk_tree_view_column_set_sort_column_id(column, col); \
430 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); \
431}
432
433 APPEND_COLUMN(_("No."), COL_NUMBER, 0);
434 APPEND_COLUMN(_("Subject"), COL_SUBJECT, 200);
435#if GTK_CHECK_VERSION(2, 14, 0)
436 gtk_tree_view_column_set_expand(column, TRUE);
437#endif
438 APPEND_COLUMN(_("From"), COL_FROM, 160);
439 APPEND_COLUMN(_("Date"), COL_DATE, 0);
440 APPEND_COLUMN(_("Size"), COL_SIZE, 0);
441
442 gtk_widget_show_all(scrwin);
443
444 g_signal_connect(G_OBJECT(treeview), "row-activated",
445 G_CALLBACK(rpop3_row_activated), NULL);
446
447 hbox = gtk_hbox_new(FALSE, 8);
448 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
449
450 status_label = gtk_label_new("");
451 gtk_box_pack_start(GTK_BOX(hbox), status_label, FALSE, FALSE, 0);
452
453 hbbox = gtk_hbutton_box_new();
454 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
455 gtk_box_set_spacing(GTK_BOX(hbbox), 6);
456 gtk_box_pack_end(GTK_BOX(vbox2), hbbox, FALSE, FALSE, 0);
457
458 recv_btn = gtk_button_new_with_mnemonic(_("_Get"));
459 gtk_box_pack_start(GTK_BOX(hbbox), recv_btn, FALSE, FALSE, 0);
460 gtk_widget_set_sensitive(recv_btn, FALSE);
461 action = gtk_ui_manager_get_action(ui, "/RPop3Menu/File/Receive");
462 g_object_set(action, "sensitive", FALSE, NULL);
463 rpop3_window.recv_action = action;
464
465 open_btn = gtk_button_new_from_stock(GTK_STOCK_OPEN);
466 gtk_box_pack_start(GTK_BOX(hbbox), open_btn, FALSE, FALSE, 0);
467 gtk_widget_set_sensitive(open_btn, FALSE);
468 action = gtk_ui_manager_get_action(ui, "/RPop3Menu/File/Open");
469 g_object_set(action, "sensitive", FALSE, NULL);
470 rpop3_window.open_action = action;
471
472 delete_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
473 gtk_box_pack_start(GTK_BOX(hbbox), delete_btn, FALSE, FALSE, 0);
474 gtk_widget_set_sensitive(delete_btn, FALSE);
475 action = gtk_ui_manager_get_action(ui, "/RPop3Menu/File/Delete");
476 g_object_set(action, "sensitive", FALSE, NULL);
477 rpop3_window.delete_action = action;
478
479 action = gtk_ui_manager_get_action(ui, "/RPop3Menu/File/Resume");
480 g_object_set(action, "sensitive", FALSE, NULL);
481 rpop3_window.update_action = action;
482
483 stop_btn = gtk_button_new_from_stock(GTK_STOCK_STOP);
484 gtk_box_pack_start(GTK_BOX(hbbox), stop_btn, FALSE, FALSE, 0);
485 gtk_widget_set_sensitive(stop_btn, FALSE);
486 action = gtk_ui_manager_get_action(ui, "/RPop3Menu/File/Stop");
487 g_object_set(action, "sensitive", FALSE, NULL);
488 rpop3_window.stop_action = action;
489
490 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
491 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, FALSE, FALSE, 0);
492
493 g_signal_connect(G_OBJECT(recv_btn), "clicked",
494 G_CALLBACK(rpop3_recv), NULL);
495 g_signal_connect(G_OBJECT(open_btn), "clicked",
496 G_CALLBACK(rpop3_open), NULL);
497 g_signal_connect(G_OBJECT(delete_btn), "clicked",
498 G_CALLBACK(rpop3_delete), NULL);
499 g_signal_connect(G_OBJECT(stop_btn), "clicked",
500 G_CALLBACK(rpop3_stop), NULL);
501 g_signal_connect(G_OBJECT(close_btn), "clicked",
502 G_CALLBACK(rpop3_close), NULL);
503
504 gtk_widget_show_all(window);
505
506 rpop3_window.window = window;
507 rpop3_window.treeview = treeview;
508 rpop3_window.store = store;
509 rpop3_window.status_label = status_label;
510 rpop3_window.recv_btn = recv_btn;
511 rpop3_window.open_btn = open_btn;
512 rpop3_window.delete_btn = delete_btn;
513 rpop3_window.stop_btn = stop_btn;
514 rpop3_window.close_btn = close_btn;
515}
516
517static gint rpop3_start(Session *session)
518{
519 SessionState state;
520 PrefsAccount *ac;
521 SocksInfo *socks_info = NULL;
522
523 g_return_val_if_fail(session != NULL, -1);
524
525 rpop3_status_label_set(_("Connecting to %s:%d ..."),
526 session->server, session->port);
527
528 ac = POP3_SESSION(session)->ac_prefs;
529 if (ac->use_socks && ac->use_socks_for_recv) {
530 socks_info = socks_info_new(ac->socks_type, ac->proxy_host, ac->proxy_port, ac->use_proxy_auth ? ac->proxy_name : NULL, ac->use_proxy_auth ? ac->proxy_pass : NULL);
531 }
532
533 if (session_connect_full(session, session->server, session->port,
534 socks_info) < 0) {
535 manage_window_focus_in(rpop3_window.window, NULL, NULL);
536 alertpanel_error(_("Can't connect to POP3 server: %s:%d"),
537 session->server, session->port);
538 return -1;
539 }
540
541 while (session_is_connected(session)) {
542 if (session->state == SESSION_READY && rpop3_window.cancelled)
543 break;
544 gtk_main_iteration();
545 }
546
547 state = session->state;
548 session_disconnect(session);
549
550 switch (POP3_SESSION(session)->error_val) {
551 case PS_AUTHFAIL:
552 manage_window_focus_in(rpop3_window.window, NULL, NULL);
553 rpop3_status_label_set(_("Authentication failed."));
554 if (POP3_SESSION(session)->error_msg)
555 alertpanel_error(_("Authentication failed:\n%s"),
556 POP3_SESSION(session)->error_msg);
557 else
558 alertpanel_error(_("Authentication failed."));
559 return -1;
560 case PS_SUCCESS:
561 break;
562 default:
563 manage_window_focus_in(rpop3_window.window, NULL, NULL);
564 rpop3_status_label_set(_("Error occurred during POP3 session."));
565 if (POP3_SESSION(session)->error_msg)
566 alertpanel_error
567 (_("Error occurred during POP3 session:\n%s"),
568 POP3_SESSION(session)->error_msg);
569 else
570 alertpanel_error(_("Error occurred during POP3 session."));
571 return -1;
572 }
573
574 switch (state) {
575 case SESSION_EOF:
576 manage_window_focus_in(rpop3_window.window, NULL, NULL);
577 rpop3_status_label_set
578 (_("Connection closed by the remote host."));
579 alertpanel_error(_("Connection closed by the remote host."));
580 return -1;
581 case SESSION_TIMEOUT:
582 manage_window_focus_in(rpop3_window.window, NULL, NULL);
583 rpop3_status_label_set(_("Session timed out."));
584 alertpanel_error(_("Session timed out."));
585 return -1;
586 case SESSION_ERROR:
587 manage_window_focus_in(rpop3_window.window, NULL, NULL);
588 if (POP3_SESSION(session)->state == POP3_READY) {
589 rpop3_status_label_set
590 (_("Can't connect to POP3 server: %s:%d"),
591 session->server, session->port);
592 alertpanel_error
593 (_("Can't connect to POP3 server: %s:%d"),
594 session->server, session->port);
595 } else {
596 rpop3_status_label_set
597 (_("Error occurred during POP3 session."));
598 alertpanel_error
599 (_("Error occurred during POP3 session."));
600 }
601 return -1;
602 case SESSION_READY:
603 debug_print("Session cancelled.\n");
604 return -1;
605 default:
606 break;
607 }
608
609 return 0;
610}
611
612static void rpop3_status_label_set(const gchar *fmt, ...)
613{
614 va_list args;
615 gchar buf[1024];
616
617 va_start(args, fmt);
618 g_vsnprintf(buf, sizeof(buf), fmt, args);
619 va_end(args);
620
621 gtk_label_set_text(GTK_LABEL(rpop3_window.status_label), buf);
622}
623
624static gboolean clear_func(GtkTreeModel *model, GtkTreePath *path,
625 GtkTreeIter *iter, gpointer data)
626{
627 MsgInfo *msginfo;
628
629 gtk_tree_model_get(model, iter, COL_MSGINFO, &msginfo, -1);
630 procmsg_msginfo_free(msginfo);
631
632 return FALSE;
633}
634
635static void rpop3_clear_list(void)
636{
637
638 gtk_tree_model_foreach(GTK_TREE_MODEL(rpop3_window.store), clear_func,
639 NULL);
640 gtk_list_store_clear(rpop3_window.store);
641}
642
643static gboolean rpop3_ping_cb(gpointer data)
644{
645 gdk_threads_enter();
646
647 if (rpop3_window.ping_tag > 0) {
648 g_source_remove(rpop3_window.ping_tag);
649 rpop3_window.ping_tag = 0;
650 }
651 if (rpop3_window.session->state == POP3_IDLE)
652 rpop3_noop_send(rpop3_window.session);
653
654 gdk_threads_leave();
655
656 return FALSE;
657}
658
659static void rpop3_idle(gboolean is_idle)
660{
661 if (rpop3_window.ping_tag > 0)
662 g_source_remove(rpop3_window.ping_tag);
663 rpop3_window.ping_tag = 0;
664
665 if (is_idle) {
666 debug_print("Entered idle state\n");
667 rpop3_window.session->state = POP3_IDLE;
668 if (POP3_PING_ITV < prefs_common.io_timeout_secs)
669 rpop3_window.ping_tag =
670 g_timeout_add_full(G_PRIORITY_LOW,
671 POP3_PING_ITV * 1000,
672 rpop3_ping_cb, NULL, NULL);
673 }
674}
675
676static gint rpop3_noop_send(Pop3Session *session)
677{
678 session->state = POP3_NOOP;
679 pop3_gen_send(session, "NOOP");
680 return PS_SUCCESS;
681}
682
683static gint rpop3_top_send(Pop3Session *session)
684{
685 session->state = POP3_TOP;
686 pop3_gen_send(session, "TOP %d 0", session->cur_msg);
687 return PS_SUCCESS;
688}
689
690static gint rpop3_top_recv(Pop3Session *session, FILE *fp, guint len)
691{
692 MsgInfo *msginfo;
693 MsgFlags flags = {0, 0};
694 GtkTreeIter iter;
695 const gchar *subject, *from, *date;
696 gchar buf[1024];
697
698 session->msg[session->cur_msg].received = TRUE;
699
700 msginfo = procheader_parse_stream(fp, flags, FALSE);
701
702 msginfo->size = session->msg[session->cur_msg].size;
703
704 subject = msginfo->subject ? msginfo->subject : _("(No Subject)");
705 from = msginfo->from ? msginfo->from : _("(No From)");
706 if (msginfo->date_t) {
707 procheader_date_get_localtime(buf, sizeof(buf),
708 msginfo->date_t);
709 date = buf;
710 } else if (msginfo->date)
711 date = msginfo->date;
712 else
713 date = _("(No Date)");
714
715 gtk_list_store_append(rpop3_window.store, &iter);
716 gtk_list_store_set(rpop3_window.store, &iter,
717 COL_NUMBER, session->cur_msg,
718 COL_SUBJECT, subject,
719 COL_FROM, from,
720 COL_DATE, date,
721 COL_SIZE, to_human_readable
722 (session->msg[session->cur_msg].size),
723 COL_MSGINFO, msginfo,
724 COL_DELETED, FALSE,
725 -1);
726
727 rpop3_status_label_set(_("Retrieving message headers (%d / %d) ..."),
728 session->count - session->cur_msg + 1,
729 session->count);
730
731 return PS_SUCCESS;
732}
733
734static gint rpop3_retr_send(Pop3Session *session)
735{
736 if (rpop3_window.recv_array) {
737 g_return_val_if_fail(rpop3_window.recv_cur < rpop3_window.recv_array->len, -1);
738 session->cur_msg = g_array_index(rpop3_window.recv_array, gint,
739 rpop3_window.recv_cur);
740 }
741
742 rpop3_idle(FALSE);
743 session->state = POP3_RETR;
744 pop3_gen_send(session, "RETR %d", session->cur_msg);
745 return PS_SUCCESS;
746}
747
748static void msgview_destroy_cb(GtkWidget *widget, gpointer data)
749{
750 gchar *file = (gchar *)data;
751
752 if (file) {
753 debug_print("msgview_destroy_cb: removing temporary file: %s\n", file);
754 g_unlink(file);
755 g_free(file);
756 }
757}
758
759static gint rpop3_retr_recv(Pop3Session *session, FILE *fp, guint len)
760{
761 gchar *file;
762 MsgInfo *msginfo;
763 MsgFlags flags = {MSG_NEW|MSG_UNREAD, MSG_RECEIVED};
764 MessageView *msgview;
765
766 file = get_tmp_file();
767 if (pop3_write_msg_to_file(file, fp, len) < 0) {
768 g_free(file);
769 session->error_val = PS_IOERR;
770 return -1;
771 }
772
773 if (rpop3_window.recv_array) {
774 FolderItem *inbox;
775
776 if (session->ac_prefs->inbox) {
777 inbox = folder_find_item_from_identifier
778 (session->ac_prefs->inbox);
779 if (!inbox)
780 inbox = folder_get_default_inbox();
781 } else
782 inbox = folder_get_default_inbox();
783 if (!inbox) {
784 session->error_val = PS_IOERR;
785 return -1;
786 }
787
788 if (folder_item_add_msg(inbox, file, &flags, FALSE) < 0) {
789 session->error_val = PS_IOERR;
790 return -1;
791 }
792 if (rpop3_window.recv_cur + 1 == rpop3_window.recv_array->len)
793 folderview_update_item(inbox, TRUE);
794 else
795 folderview_update_item(inbox, FALSE);
796
797 return PS_SUCCESS;
798 }
799
800 msginfo = procheader_parse_file(file, flags, FALSE);
801 if (!msginfo) {
802 session->error_val = PS_IOERR;
803 return -1;
804 }
805
806 msginfo->file_path = g_strdup(file);
807
808 msgview = messageview_create_with_new_window();
809 messageview_show(msgview, msginfo, FALSE);
810
811 g_signal_connect(G_OBJECT(msgview->window), "destroy",
812 G_CALLBACK(msgview_destroy_cb), file);
813
814 return PS_SUCCESS;
815}
816
817static gint rpop3_delete_send(Pop3Session *session)
818{
819 g_return_val_if_fail(rpop3_window.delete_array != NULL, -1);
820 g_return_val_if_fail
821 (rpop3_window.delete_cur < rpop3_window.delete_array->len, -1);
822
823 rpop3_idle(FALSE);
824 session->state = POP3_DELETE;
825 session->cur_msg = g_array_index(rpop3_window.delete_array, gint,
826 rpop3_window.delete_cur);
827 pop3_gen_send(session, "DELE %d", session->cur_msg);
828 return PS_SUCCESS;
829}
830
831static gint rpop3_delete_recv(Pop3Session *session)
832{
833 session->msg[session->cur_msg].recv_time = RECV_TIME_DELETE;
834 session->msg[session->cur_msg].deleted = TRUE;
835 return PS_SUCCESS;
836}
837
838static gint rpop3_session_recv_msg(Session *session, const gchar *msg)
839{
840 Pop3Session *pop3_session = POP3_SESSION(session);
841 gint val = PS_SUCCESS;
842 const gchar *body;
843
844 gdk_threads_enter();
845
846 body = msg;
847 if (pop3_session->state != POP3_GETRANGE_UIDL_RECV &&
848 pop3_session->state != POP3_GETSIZE_LIST_RECV) {
849 val = pop3_ok(pop3_session, msg);
850 if (val != PS_SUCCESS) {
851 if (val == PS_SOCKET) {
852 pop3_session->state = POP3_ERROR;
853 gdk_threads_leave();
854 return -1;
855 }
856 if (val != PS_NOTSUPPORTED) {
857 if (pop3_session->state != POP3_LOGOUT) {
858 if (pop3_logout_send(pop3_session) == PS_SUCCESS) {
859 gdk_threads_leave();
860 return 0;
861 } else {
862 gdk_threads_leave();
863 return -1;
864 }
865 }
866 }
867 }
868
869 if (*body == '+' || *body == '-')
870 body++;
871 while (g_ascii_isalpha(*body))
872 body++;
873 while (g_ascii_isspace(*body))
874 body++;
875 }
876
877 switch (pop3_session->state) {
878 case POP3_READY:
879 case POP3_GREETING:
880 val = pop3_greeting_recv(pop3_session, body);
881 rpop3_status_label_set(_("Authenticating..."));
882#if USE_SSL
883 if (pop3_session->ac_prefs->ssl_pop == SSL_STARTTLS)
884 val = pop3_stls_send(pop3_session);
885 else
886#endif
887 if (pop3_session->ac_prefs->use_apop_auth)
888 val = pop3_getauth_apop_send(pop3_session);
889 else
890 val = pop3_getauth_user_send(pop3_session);
891 break;
892#if USE_SSL
893 case POP3_STLS:
894 if ((val = pop3_stls_recv(pop3_session)) != PS_SUCCESS)
895 break;
896 if (pop3_session->ac_prefs->use_apop_auth)
897 val = pop3_getauth_apop_send(pop3_session);
898 else
899 val = pop3_getauth_user_send(pop3_session);
900 break;
901#endif
902 case POP3_GETAUTH_USER:
903 val = pop3_getauth_pass_send(pop3_session);
904 break;
905 case POP3_GETAUTH_PASS:
906 case POP3_GETAUTH_APOP:
907 rpop3_status_label_set(_("Getting the number of messages..."));
908 val = pop3_getrange_stat_send(pop3_session);
909 break;
910 case POP3_GETRANGE_STAT:
911 if ((val = pop3_getrange_stat_recv(pop3_session, body)) != PS_SUCCESS)
912 break;
913 if (pop3_session->count > 0)
914 val = pop3_getrange_uidl_send(pop3_session);
915 else {
916 rpop3_status_label_set(_("No message"));
917 val = pop3_logout_send(pop3_session);
918 }
919 break;
920 case POP3_GETRANGE_LAST:
921 if (val == PS_NOTSUPPORTED)
922 pop3_session->error_val = PS_SUCCESS;
923 else if ((val = pop3_getrange_last_recv
924 (pop3_session, body)) != PS_SUCCESS)
925 break;
926 if (pop3_session->cur_msg > 0)
927 val = pop3_getsize_list_send(pop3_session);
928 else {
929 rpop3_status_label_set(_("No message"));
930 val = pop3_logout_send(pop3_session);
931 }
932 break;
933 case POP3_GETRANGE_UIDL:
934 if (val == PS_NOTSUPPORTED) {
935 pop3_session->error_val = PS_SUCCESS;
936 val = pop3_getrange_last_send(pop3_session);
937 } else {
938 pop3_session->state = POP3_GETRANGE_UIDL_RECV;
939 val = session_recv_data(session, 0, ".\r\n");
940 }
941 break;
942 case POP3_GETSIZE_LIST:
943 pop3_session->state = POP3_GETSIZE_LIST_RECV;
944 val = session_recv_data(session, 0, ".\r\n");
945 break;
946 case POP3_TOP:
947 pop3_session->state = POP3_TOP_RECV;
948 val = session_recv_data_as_file(session, 0, ".\r\n");
949 break;
950 case POP3_RETR:
951 pop3_session->state = POP3_RETR_RECV;
952 val = session_recv_data_as_file(session, 0, ".\r\n");
953 break;
954 case POP3_DELETE:
955 val = rpop3_delete_recv(pop3_session);
956 if (val != PS_SUCCESS)
957 break;
958 if (rpop3_window.delete_cur + 1 < rpop3_window.delete_array->len) {
959 rpop3_window.delete_cur++;
960 val = rpop3_delete_send(pop3_session);
961 } else {
962 rpop3_status_label_set(_("Deleted %d messages"),
963 rpop3_window.delete_cur + 1);
964 g_array_free(rpop3_window.delete_array, TRUE);
965 rpop3_window.delete_array = NULL;
966 rpop3_window.delete_cur = 0;
967 rpop3_idle(TRUE);
968 }
969 break;
970 case POP3_NOOP:
971 rpop3_idle(TRUE);
972 break;
973 case POP3_LOGOUT:
974 if (val == PS_SUCCESS)
975 pop3_session->state = POP3_DONE;
976 else
977 pop3_session->state = POP3_ERROR;
978 session_disconnect(session);
979 break;
980 case POP3_ERROR:
981 default:
982 val = -1;
983 break;
984 }
985
986 gdk_threads_leave();
987
988 if (val == PS_SUCCESS)
989 return 0;
990 else
991 return -1;
992}
993
994static gint rpop3_session_recv_data_finished(Session *session, guchar *data,
995 guint len)
996{
997 Pop3Session *pop3_session = POP3_SESSION(session);
998 Pop3ErrorValue val = PS_SUCCESS;
999 gint ret = 0;
1000
1001 gdk_threads_enter();
1002
1003 switch (pop3_session->state) {
1004 case POP3_GETRANGE_UIDL_RECV:
1005 val = pop3_getrange_uidl_recv(pop3_session, (gchar *)data, len);
1006 if (val == PS_SUCCESS) {
1007 if (rpop3_window.cancelled) {
1008 rpop3_status_label_set(_("Quitting..."));
1009 pop3_logout_send(pop3_session);
1010 } else
1011 pop3_getsize_list_send(pop3_session);
1012 } else
1013 ret = -1;
1014 break;
1015 case POP3_GETSIZE_LIST_RECV:
1016 val = pop3_getsize_list_recv(pop3_session, (gchar *)data, len);
1017 if (val == PS_SUCCESS) {
1018 pop3_session->cur_msg = 1;
1019 if (rpop3_window.cancelled || pop3_session->count == 0) {
1020 rpop3_status_label_set(_("Quitting..."));
1021 pop3_logout_send(pop3_session);
1022 } else {
1023 pop3_session->cur_msg = pop3_session->count;
1024 gtk_widget_set_sensitive(rpop3_window.stop_btn,
1025 TRUE);
1026 g_object_set(rpop3_window.update_action,
1027 "sensitive", FALSE, NULL);
1028 g_object_set(rpop3_window.stop_action,
1029 "sensitive", TRUE, NULL);
1030 rpop3_top_send(pop3_session);
1031 }
1032 } else
1033 ret = -1;
1034 break;
1035 case POP3_ERROR:
1036 default:
1037 ret = -1;
1038 break;
1039 }
1040
1041 gdk_threads_leave();
1042
1043 return ret;
1044}
1045
1046static gint rpop3_session_recv_data_as_file_finished(Session *session,
1047 FILE *fp, guint len)
1048{
1049 Pop3Session *pop3_session = POP3_SESSION(session);
1050 gint ret = 0;
1051
1052 gdk_threads_enter();
1053
1054 switch (pop3_session->state) {
1055 case POP3_RETR_RECV:
1056 if (rpop3_retr_recv(pop3_session, fp, len) != PS_SUCCESS) {
1057 ret = -1;
1058 break;
1059 }
1060 if (rpop3_window.recv_array) {
1061 if (rpop3_window.recv_cur + 1 < rpop3_window.recv_array->len) {
1062 rpop3_window.recv_cur++;
1063 if (rpop3_retr_send(pop3_session) != PS_SUCCESS)
1064 ret = -1;
1065 } else {
1066 rpop3_status_label_set(_("Retrieved %d messages"), rpop3_window.recv_cur + 1);
1067 g_array_free(rpop3_window.recv_array, TRUE);
1068 rpop3_window.recv_array = NULL;
1069 rpop3_window.recv_cur = 0;
1070 rpop3_idle(TRUE);
1071 }
1072 } else {
1073 rpop3_status_label_set(_("Opened message %d"),
1074 pop3_session->cur_msg);
1075 rpop3_idle(TRUE);
1076 }
1077 break;
1078 case POP3_TOP_RECV:
1079 if (rpop3_top_recv(pop3_session, fp, len) == PS_SUCCESS) {
1080 if (rpop3_window.cancelled) {
1081 rpop3_status_label_set(_("Quitting..."));
1082 pop3_logout_send(pop3_session);
1083 } else if (!rpop3_window.stop_load &&
1084 (pop3_session->cur_msg > 1)) {
1085 pop3_session->cur_msg--;
1086 rpop3_top_send(pop3_session);
1087 } else {
1088 if (pop3_session->cur_msg > 1)
1089 rpop3_status_label_set
1090 (_("Retrieved %d (of %d) message headers"),
1091 pop3_session->count - pop3_session->cur_msg + 1, pop3_session->count);
1092 else
1093 rpop3_status_label_set
1094 (_("Retrieved %d message headers"),
1095 pop3_session->count - pop3_session->cur_msg + 1);
1096 gtk_widget_set_sensitive
1097 (rpop3_window.recv_btn, TRUE);
1098 gtk_widget_set_sensitive
1099 (rpop3_window.open_btn, TRUE);
1100 gtk_widget_set_sensitive
1101 (rpop3_window.delete_btn, TRUE);
1102 if (pop3_session->cur_msg == 1)
1103 gtk_widget_set_sensitive(rpop3_window.stop_btn, FALSE);
1104 else
1105 gtk_button_set_label(GTK_BUTTON(rpop3_window.stop_btn), _("_Resume"));
1106 g_object_set(rpop3_window.recv_action,
1107 "sensitive", TRUE, NULL);
1108 g_object_set(rpop3_window.open_action,
1109 "sensitive", TRUE, NULL);
1110 g_object_set(rpop3_window.delete_action,
1111 "sensitive", TRUE, NULL);
1112 g_object_set(rpop3_window.stop_action,
1113 "sensitive", FALSE, NULL);
1114 if (pop3_session->cur_msg == 1)
1115 g_object_set(rpop3_window.update_action, "sensitive", FALSE, NULL);
1116 else
1117 g_object_set(rpop3_window.update_action, "sensitive", TRUE, NULL);
1118 rpop3_idle(TRUE);
1119 }
1120 } else
1121 ret = -1;
1122 break;
1123 default:
1124 ret = -1;
1125 break;
1126 }
1127
1128 gdk_threads_leave();
1129
1130 return ret;
1131}
1132
1133static gint window_deleted(GtkWidget *widget, GdkEventAny *event,
1134 gpointer data)
1135{
1136 gtk_button_clicked(GTK_BUTTON(rpop3_window.close_btn));
1137 return TRUE;
1138}
1139
1140static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
1141 gpointer data)
1142{
1143 return FALSE;
1144}
1145
1146static void rpop3_row_activated(GtkTreeView *treeview, GtkTreePath *path,
1147 GtkTreeViewColumn *column, gpointer data)
1148{
1149 gtk_button_clicked(GTK_BUTTON(rpop3_window.open_btn));
1150}
1151
1152static void rpop3_recv(GtkButton *button, gpointer data)
1153{
1154 GtkTreeModel *model = GTK_TREE_MODEL(rpop3_window.store);
1155 GtkTreeSelection *selection;
1156 GtkTreeIter iter;
1157 GList *rows, *cur;
1158 gint num;
1159 gboolean deleted;
1160 GArray *array;
1161
1162 if (rpop3_window.session->state != POP3_IDLE)
1163 return;
1164
1165 selection = gtk_tree_view_get_selection
1166 (GTK_TREE_VIEW(rpop3_window.treeview));
1167
1168 rows = gtk_tree_selection_get_selected_rows(selection, NULL);
1169 array = g_array_sized_new(FALSE, FALSE, sizeof(gint),
1170 g_list_length(rows));
1171
1172 for (cur = rows; cur != NULL; cur = cur->next) {
1173 gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)cur->data);
1174 gtk_tree_model_get(model, &iter, COL_NUMBER, &num,
1175 COL_DELETED, &deleted, -1);
1176 if (!deleted) {
1177 debug_print("rpop3_recv: receiving message %d\n", num);
1178 g_array_append_val(array, num);
1179 }
1180 }
1181
1182 g_list_foreach(rows, (GFunc)gtk_tree_path_free, NULL);
1183 g_list_free(rows);
1184
1185 if (array->len > 0) {
1186 rpop3_window.recv_array = array;
1187 rpop3_window.recv_cur = 0;
1188 rpop3_retr_send(rpop3_window.session);
1189 } else
1190 g_array_free(array, TRUE);
1191}
1192
1193static void rpop3_open(GtkButton *button, gpointer data)
1194{
1195 GtkTreeModel *model = GTK_TREE_MODEL(rpop3_window.store);
1196 GtkTreeSelection *selection;
1197 GtkTreeIter iter;
1198 GList *rows, *cur;
1199 gint num;
1200 gboolean deleted;
1201
1202 if (rpop3_window.session->state != POP3_IDLE)
1203 return;
1204
1205 selection = gtk_tree_view_get_selection
1206 (GTK_TREE_VIEW(rpop3_window.treeview));
1207
1208 rows = gtk_tree_selection_get_selected_rows(selection, NULL);
1209
1210 for (cur = rows; cur != NULL; cur = cur->next) {
1211 gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)cur->data);
1212 gtk_tree_model_get(model, &iter, COL_NUMBER, &num,
1213 COL_DELETED, &deleted, -1);
1214 if (!deleted) {
1215 debug_print("rpop3_open: opening message %d\n", num);
1216 rpop3_status_label_set(_("Retrieving message %d ..."),
1217 num);
1218 rpop3_window.session->cur_msg = num;
1219 rpop3_retr_send(rpop3_window.session);
1220 break;
1221 }
1222 }
1223
1224 g_list_foreach(rows, (GFunc)gtk_tree_path_free, NULL);
1225 g_list_free(rows);
1226}
1227
1228static void rpop3_delete(GtkButton *button, gpointer data)
1229{
1230 GtkTreeModel *model = GTK_TREE_MODEL(rpop3_window.store);
1231 GtkTreeSelection *selection;
1232 GtkTreeIter iter;
1233 GList *rows, *cur;
1234 gint num;
1235 gboolean deleted;
1236 GArray *array;
1237 AlertValue val;
1238
1239 if (rpop3_window.session->state != POP3_IDLE)
1240 return;
1241
1242 val = alertpanel(_("Delete messages"),
1243 _("Really delete selected messages from server?\n"
1244 "This operation cannot be reverted."),
1245 GTK_STOCK_YES, GTK_STOCK_NO, NULL);
1246 if (val != G_ALERTDEFAULT)
1247 return;
1248
1249 selection = gtk_tree_view_get_selection
1250 (GTK_TREE_VIEW(rpop3_window.treeview));
1251
1252 rows = gtk_tree_selection_get_selected_rows(selection, NULL);
1253
1254 array = g_array_sized_new(FALSE, FALSE, sizeof(gint),
1255 g_list_length(rows));
1256
1257 for (cur = rows; cur != NULL; cur = cur->next) {
1258 gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)cur->data);
1259 gtk_tree_model_get(model, &iter, COL_NUMBER, &num,
1260 COL_DELETED, &deleted, -1);
1261 if (!deleted) {
1262 debug_print("rpop3_delete: marked %d to delete\n", num);
1263 g_array_append_val(array, num);
1264 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
1265 COL_DELETED, TRUE, -1);
1266 }
1267 }
1268
1269 g_list_foreach(rows, (GFunc)gtk_tree_path_free, NULL);
1270 g_list_free(rows);
1271
1272 if (array->len > 0) {
1273 rpop3_window.delete_array = array;
1274 rpop3_window.delete_cur = 0;
1275 rpop3_delete_send(rpop3_window.session);
1276 } else
1277 g_array_free(array, TRUE);
1278}
1279
1280static void rpop3_read_next(GtkButton *button, gpointer data)
1281{
1282 gint i;
1283
1284 if (rpop3_window.session->state != POP3_IDLE)
1285 return;
1286
1287 for (i = rpop3_window.session->count; i > 0; i--) {
1288 if (!rpop3_window.session->msg[i].received)
1289 break;
1290 }
1291
1292 if (i == 0)
1293 return;
1294
1295 debug_print("rpop3_read_next: next: %d\n", i);
1296 rpop3_window.session->cur_msg = i;
1297
1298 rpop3_window.stop_load = FALSE;
1299
1300 gtk_widget_set_sensitive(rpop3_window.recv_btn, FALSE);
1301 gtk_widget_set_sensitive(rpop3_window.open_btn, FALSE);
1302 gtk_widget_set_sensitive(rpop3_window.delete_btn, FALSE);
1303 gtk_button_set_label(GTK_BUTTON(rpop3_window.stop_btn), GTK_STOCK_STOP);
1304 gtk_widget_set_sensitive(rpop3_window.stop_btn, TRUE);
1305 g_object_set(rpop3_window.update_action, "sensitive", FALSE, NULL);
1306 g_object_set(rpop3_window.stop_action, "sensitive", TRUE, NULL);
1307 rpop3_idle(FALSE);
1308 rpop3_top_send(rpop3_window.session);
1309}
1310
1311static void rpop3_stop(GtkButton *button, gpointer data)
1312{
1313 if (rpop3_window.session->state == POP3_IDLE)
1314 rpop3_read_next(NULL, NULL);
1315 else
1316 rpop3_window.stop_load = TRUE;
1317}
1318
1319static void rpop3_close(GtkButton *button, gpointer data)
1320{
1321 rpop3_window.finished = TRUE;
1322
1323 if (rpop3_window.session->state == POP3_IDLE) {
1324 rpop3_status_label_set(_("Quitting..."));
1325 rpop3_idle(FALSE);
1326 pop3_logout_send(rpop3_window.session);
1327 } else if (rpop3_window.session->state != POP3_DONE &&
1328 rpop3_window.session->state != POP3_ERROR)
1329 rpop3_window.cancelled = TRUE;
1330}
1331
1332static void rpop3_recv_cb(void)
1333{
1334 rpop3_recv(NULL, NULL);
1335}
1336
1337static void rpop3_open_cb(void)
1338{
1339 rpop3_open(NULL, NULL);
1340}
1341
1342static void rpop3_delete_cb(void)
1343{
1344 rpop3_delete(NULL, NULL);
1345}
1346
1347static void rpop3_resume_cb(void)
1348{
1349 rpop3_stop(NULL, NULL);
1350}
1351
1352static void rpop3_stop_cb(void)
1353{
1354 rpop3_stop(NULL, NULL);
1355}
1356
1357static void rpop3_close_cb(void)
1358{
1359 rpop3_close(NULL, NULL);
1360}
1361
1362static void rpop3_about_cb(void)
1363{
1364 about_show();
1365}
1366
1367static gint cmp_by_subject(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
1368 gpointer data)
1369{
1370 MsgInfo *msginfo_a = NULL, *msginfo_b = NULL;
1371 gint ret;
1372
1373 gtk_tree_model_get(model, a, COL_MSGINFO, &msginfo_a, -1);
1374 gtk_tree_model_get(model, b, COL_MSGINFO, &msginfo_b, -1);
1375
1376 if (!msginfo_a || !msginfo_b)
1377 return 0;
1378
1379 if (!msginfo_a->subject)
1380 return -(msginfo_b->subject != NULL);
1381 if (!msginfo_b->subject)
1382 return (msginfo_a->subject != NULL);
1383
1384 ret = subject_compare_for_sort(msginfo_a->subject, msginfo_b->subject);
1385 return (ret != 0) ? ret : (msginfo_a->msgnum - msginfo_b->msgnum);
1386}
1387
1388static gint cmp_by_date(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
1389 gpointer data)
1390{
1391 MsgInfo *msginfo_a = NULL, *msginfo_b = NULL;
1392 gint ret;
1393
1394 gtk_tree_model_get(model, a, COL_MSGINFO, &msginfo_a, -1);
1395 gtk_tree_model_get(model, b, COL_MSGINFO, &msginfo_b, -1);
1396
1397 if (!msginfo_a || !msginfo_b)
1398 return 0;
1399
1400 ret = msginfo_a->date_t - msginfo_b->date_t;
1401 return (ret != 0) ? ret : (msginfo_a->msgnum - msginfo_b->msgnum);
1402}
1403
1404static gint cmp_by_size(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
1405 gpointer data)
1406{
1407 MsgInfo *msginfo_a = NULL, *msginfo_b = NULL;
1408 gint ret;
1409
1410 gtk_tree_model_get(model, a, COL_MSGINFO, &msginfo_a, -1);
1411 gtk_tree_model_get(model, b, COL_MSGINFO, &msginfo_b, -1);
1412
1413 if (!msginfo_a || !msginfo_b)
1414 return 0;
1415
1416 ret = msginfo_a->size - msginfo_b->size;
1417 return (ret != 0) ? ret : (msginfo_a->msgnum - msginfo_b->msgnum);
1418}