Statistics
| Revision:

root / src / rpop3.c @ 3202

History | View | Annotate | Download (39.1 KB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2013 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

    
69
enum
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

    
81
static 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

    
112
static 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

    
131
static void rpop3_window_create        (PrefsAccount        *account);
132

    
133
gint pop3_greeting_recv          (Pop3Session *session,
134
                                  const gchar *msg);
135
gint pop3_getauth_user_send      (Pop3Session *session);
136
gint pop3_getauth_pass_send      (Pop3Session *session);
137
gint pop3_getauth_apop_send      (Pop3Session *session);
138
#if USE_SSL
139
gint pop3_stls_send              (Pop3Session *session);
140
gint pop3_stls_recv              (Pop3Session *session);
141
#endif
142
gint pop3_getrange_stat_send     (Pop3Session *session);
143
gint pop3_getrange_stat_recv     (Pop3Session *session,
144
                                  const gchar *msg);
145
gint pop3_getrange_last_send     (Pop3Session *session);
146
gint pop3_getrange_last_recv     (Pop3Session *session,
147
                                  const gchar *msg);
148
gint pop3_getrange_uidl_send     (Pop3Session *session);
149
gint pop3_getrange_uidl_recv     (Pop3Session *session,
150
                                  const gchar *data,
151
                                  guint        len);
152
gint pop3_getsize_list_send      (Pop3Session *session);
153
gint pop3_getsize_list_recv      (Pop3Session *session,
154
                                  const gchar *data,
155
                                  guint        len);
156
gint pop3_retr_send              (Pop3Session *session);
157
gint pop3_retr_recv              (Pop3Session *session,
158
                                  FILE        *fp,
159
                                  guint        len);
160
gint pop3_logout_send            (Pop3Session *session);
161

    
162
void pop3_gen_send               (Pop3Session    *session,
163
                                  const gchar    *format, ...);
164

    
165
gint pop3_write_msg_to_file        (const gchar        *file,
166
                                 FILE                *src_fp,
167
                                 guint                 len);
168

    
169
Pop3ErrorValue pop3_ok                (Pop3Session        *session,
170
                                 const gchar        *msg);
171

    
172
static gint rpop3_start                        (Session        *session);
173
static void rpop3_status_label_set        (const gchar        *fmt,
174
                                         ...) G_GNUC_PRINTF(1, 2);
175
static void rpop3_clear_list                (void);
176

    
177
static void rpop3_idle                (gboolean         is_idle);
178

    
179
static gint rpop3_noop_send        (Pop3Session        *session);
180

    
181
static gint rpop3_top_send        (Pop3Session        *session);
182
static gint rpop3_top_recv        (Pop3Session        *session,
183
                                 FILE                *fp,
184
                                 guint                 len);
185
static gint rpop3_retr_send        (Pop3Session        *session);
186
static gint rpop3_retr_recv        (Pop3Session        *session,
187
                                 FILE                *fp,
188
                                 guint                 len);
189
static gint rpop3_delete_send        (Pop3Session        *session);
190
static gint rpop3_delete_recv        (Pop3Session        *session);
191

    
192
static gint rpop3_session_recv_msg                (Session        *session,
193
                                                 const gchar        *msg);
194
static gint rpop3_session_recv_data_finished        (Session        *session,
195
                                                 guchar                *data,
196
                                                 guint                 len);
197
static gint rpop3_session_recv_data_as_file_finished
198
                                                (Session        *session,
199
                                                 FILE                *fp,
200
                                                 guint                 len);
201

    
202
static gint window_deleted        (GtkWidget        *widget,
203
                                 GdkEventAny        *event,
204
                                 gpointer         data);
205
static gboolean key_pressed        (GtkWidget        *widget,
206
                                 GdkEventKey        *event,
207
                                 gpointer         data);
208

    
209
static void rpop3_row_activated        (GtkTreeView                *treeview,
210
                                 GtkTreePath                *path,
211
                                 GtkTreeViewColumn        *column,
212
                                 gpointer                 data);
213

    
214
static void rpop3_recv                (GtkButton        *button,
215
                                 gpointer         data);
216
static void rpop3_open                (GtkButton        *button,
217
                                 gpointer         data);
218
static void rpop3_delete        (GtkButton        *button,
219
                                 gpointer         data);
220
static void rpop3_stop                (GtkButton        *button,
221
                                 gpointer         data);
222
static void rpop3_close                (GtkButton        *button,
223
                                 gpointer         data);
224

    
225
static void rpop3_recv_cb        (void);
226
static void rpop3_open_cb        (void);
227
static void rpop3_delete_cb        (void);
228
static void rpop3_resume_cb        (void);
229
static void rpop3_stop_cb        (void);
230
static void rpop3_close_cb        (void);
231
static void rpop3_about_cb        (void);
232

    
233
static gint cmp_by_subject        (GtkTreeModel        *model,
234
                                 GtkTreeIter        *a,
235
                                 GtkTreeIter        *b,
236
                                 gpointer         data);
237
static gint cmp_by_date                (GtkTreeModel        *model,
238
                                 GtkTreeIter        *a,
239
                                 GtkTreeIter        *b,
240
                                 gpointer         data);
241
static gint cmp_by_size                (GtkTreeModel        *model,
242
                                 GtkTreeIter        *a,
243
                                 GtkTreeIter        *b,
244
                                 gpointer         data);
245

    
246
static 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

    
260
gint 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

    
331
static 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, -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);
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
        APPEND_COLUMN(_("From"), COL_FROM, 160);
436
        APPEND_COLUMN(_("Date"), COL_DATE, 0);
437
        APPEND_COLUMN(_("Size"), COL_SIZE, 0);
438

    
439
        gtk_widget_show_all(scrwin);
440

    
441
        g_signal_connect(G_OBJECT(treeview), "row-activated",
442
                         G_CALLBACK(rpop3_row_activated), NULL);
443

    
444
        hbox = gtk_hbox_new(FALSE, 8);
445
        gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
446

    
447
        status_label = gtk_label_new("");
448
        gtk_box_pack_start(GTK_BOX(hbox), status_label, FALSE, FALSE, 0);
449

    
450
        hbbox = gtk_hbutton_box_new();
451
        gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
452
        gtk_box_set_spacing(GTK_BOX(hbbox), 6);
453
        gtk_box_pack_end(GTK_BOX(vbox2), hbbox, FALSE, FALSE, 0);
454

    
455
        recv_btn = gtk_button_new_with_mnemonic(_("_Get"));
456
        gtk_box_pack_start(GTK_BOX(hbbox), recv_btn, FALSE, FALSE, 0);
457
        gtk_widget_set_sensitive(recv_btn, FALSE);
458
        action = gtk_ui_manager_get_action(ui, "/RPop3Menu/File/Receive");
459
        g_object_set(action, "sensitive", FALSE, NULL);
460
        rpop3_window.recv_action = action;
461

    
462
        open_btn = gtk_button_new_from_stock(GTK_STOCK_OPEN);
463
        gtk_box_pack_start(GTK_BOX(hbbox), open_btn, FALSE, FALSE, 0);
464
        gtk_widget_set_sensitive(open_btn, FALSE);
465
        action = gtk_ui_manager_get_action(ui, "/RPop3Menu/File/Open");
466
        g_object_set(action, "sensitive", FALSE, NULL);
467
        rpop3_window.open_action = action;
468

    
469
        delete_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
470
        gtk_box_pack_start(GTK_BOX(hbbox), delete_btn, FALSE, FALSE, 0);
471
        gtk_widget_set_sensitive(delete_btn, FALSE);
472
        action = gtk_ui_manager_get_action(ui, "/RPop3Menu/File/Delete");
473
        g_object_set(action, "sensitive", FALSE, NULL);
474
        rpop3_window.delete_action = action;
475

    
476
        action = gtk_ui_manager_get_action(ui, "/RPop3Menu/File/Resume");
477
        g_object_set(action, "sensitive", FALSE, NULL);
478
        rpop3_window.update_action = action;
479

    
480
        stop_btn = gtk_button_new_from_stock(GTK_STOCK_STOP);
481
        gtk_box_pack_start(GTK_BOX(hbbox), stop_btn, FALSE, FALSE, 0);
482
        gtk_widget_set_sensitive(stop_btn, FALSE);
483
        action = gtk_ui_manager_get_action(ui, "/RPop3Menu/File/Stop");
484
        g_object_set(action, "sensitive", FALSE, NULL);
485
        rpop3_window.stop_action = action;
486

    
487
        close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
488
        gtk_box_pack_start(GTK_BOX(hbbox), close_btn, FALSE, FALSE, 0);
489

    
490
        g_signal_connect(G_OBJECT(recv_btn), "clicked",
491
                         G_CALLBACK(rpop3_recv), NULL);
492
        g_signal_connect(G_OBJECT(open_btn), "clicked",
493
                         G_CALLBACK(rpop3_open), NULL);
494
        g_signal_connect(G_OBJECT(delete_btn), "clicked",
495
                         G_CALLBACK(rpop3_delete), NULL);
496
        g_signal_connect(G_OBJECT(stop_btn), "clicked",
497
                         G_CALLBACK(rpop3_stop), NULL);
498
        g_signal_connect(G_OBJECT(close_btn), "clicked",
499
                         G_CALLBACK(rpop3_close), NULL);
500

    
501
        gtk_widget_show_all(window);
502

    
503
        rpop3_window.window = window;
504
        rpop3_window.treeview = treeview;
505
        rpop3_window.store = store;
506
        rpop3_window.status_label = status_label;
507
        rpop3_window.recv_btn = recv_btn;
508
        rpop3_window.open_btn = open_btn;
509
        rpop3_window.delete_btn = delete_btn;
510
        rpop3_window.stop_btn = stop_btn;
511
        rpop3_window.close_btn = close_btn;
512
}
513

    
514
static gint rpop3_start(Session *session)
515
{
516
        SessionState state;
517
        PrefsAccount *ac;
518
        SocksInfo *socks_info = NULL;
519

    
520
        g_return_val_if_fail(session != NULL, -1);
521

    
522
        rpop3_status_label_set(_("Connecting to %s:%d ..."),
523
                               session->server, session->port);
524

    
525
        ac = POP3_SESSION(session)->ac_prefs;
526
        if (ac->use_socks && ac->use_socks_for_recv) {
527
                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);
528
        }
529

    
530
        if (session_connect_full(session, session->server, session->port,
531
                                 socks_info) < 0) {
532
                manage_window_focus_in(rpop3_window.window, NULL, NULL);
533
                alertpanel_error(_("Can't connect to POP3 server: %s:%d"),
534
                                 session->server, session->port);
535
                return -1;
536
        }
537

    
538
        while (session_is_connected(session)) {
539
                if (session->state == SESSION_READY && rpop3_window.cancelled)
540
                        break;
541
                gtk_main_iteration();
542
        }
543

    
544
        state = session->state;
545
        session_disconnect(session);
546

    
547
        switch (POP3_SESSION(session)->error_val) {
548
        case PS_AUTHFAIL:
549
                manage_window_focus_in(rpop3_window.window, NULL, NULL);
550
                rpop3_status_label_set(_("Authentication failed."));
551
                if (POP3_SESSION(session)->error_msg)
552
                        alertpanel_error(_("Authentication failed:\n%s"),
553
                                         POP3_SESSION(session)->error_msg);
554
                else
555
                        alertpanel_error(_("Authentication failed."));
556
                return -1;
557
        case PS_SUCCESS:
558
                break;
559
        default:
560
                manage_window_focus_in(rpop3_window.window, NULL, NULL);
561
                rpop3_status_label_set(_("Error occurred during POP3 session."));
562
                if (POP3_SESSION(session)->error_msg)
563
                        alertpanel_error
564
                                (_("Error occurred during POP3 session:\n%s"),
565
                                 POP3_SESSION(session)->error_msg);
566
                else
567
                        alertpanel_error(_("Error occurred during POP3 session."));
568
                return -1;
569
        }
570

    
571
        switch (state) {
572
        case SESSION_EOF:
573
                manage_window_focus_in(rpop3_window.window, NULL, NULL);
574
                rpop3_status_label_set
575
                        (_("Connection closed by the remote host."));
576
                alertpanel_error(_("Connection closed by the remote host."));
577
                return -1;
578
        case SESSION_TIMEOUT:
579
                manage_window_focus_in(rpop3_window.window, NULL, NULL);
580
                rpop3_status_label_set(_("Session timed out."));
581
                alertpanel_error(_("Session timed out."));
582
                return -1;
583
        case SESSION_ERROR:
584
                manage_window_focus_in(rpop3_window.window, NULL, NULL);
585
                if (POP3_SESSION(session)->state == POP3_READY) {
586
                        rpop3_status_label_set
587
                                (_("Can't connect to POP3 server: %s:%d"),
588
                                 session->server, session->port);
589
                        alertpanel_error
590
                                (_("Can't connect to POP3 server: %s:%d"),
591
                                 session->server, session->port);
592
                } else {
593
                        rpop3_status_label_set
594
                                (_("Error occurred during POP3 session."));
595
                        alertpanel_error
596
                                (_("Error occurred during POP3 session."));
597
                }
598
                return -1;
599
        case SESSION_READY:
600
                debug_print("Session cancelled.\n");
601
                return -1;
602
        default:
603
                break;
604
        }
605

    
606
        return 0;
607
}
608

    
609
static void rpop3_status_label_set(const gchar *fmt, ...)
610
{
611
        va_list args;
612
        gchar buf[1024];
613

    
614
        va_start(args, fmt);
615
        g_vsnprintf(buf, sizeof(buf), fmt, args);
616
        va_end(args);
617

    
618
        gtk_label_set_text(GTK_LABEL(rpop3_window.status_label), buf);
619
}
620

    
621
static gboolean clear_func(GtkTreeModel *model, GtkTreePath *path,
622
                           GtkTreeIter *iter, gpointer data)
623
{
624
        MsgInfo *msginfo;
625

    
626
        gtk_tree_model_get(model, iter, COL_MSGINFO, &msginfo, -1);
627
        procmsg_msginfo_free(msginfo);
628

    
629
        return FALSE;
630
}
631

    
632
static void rpop3_clear_list(void)
633
{
634
        
635
        gtk_tree_model_foreach(GTK_TREE_MODEL(rpop3_window.store), clear_func,
636
                               NULL);
637
        gtk_list_store_clear(rpop3_window.store);
638
}
639

    
640
static gboolean rpop3_ping_cb(gpointer data)
641
{
642
        gdk_threads_enter();
643

    
644
        if (rpop3_window.ping_tag > 0) {
645
                g_source_remove(rpop3_window.ping_tag);
646
                rpop3_window.ping_tag = 0;
647
        }
648
        if (rpop3_window.session->state == POP3_IDLE)
649
                rpop3_noop_send(rpop3_window.session);
650

    
651
        gdk_threads_leave();
652

    
653
        return FALSE;
654
}
655

    
656
static void rpop3_idle(gboolean is_idle)
657
{
658
        if (rpop3_window.ping_tag > 0)
659
                g_source_remove(rpop3_window.ping_tag);
660
        rpop3_window.ping_tag = 0;
661

    
662
        if (is_idle) {
663
                debug_print("Entered idle state\n");
664
                rpop3_window.session->state = POP3_IDLE;
665
                if (POP3_PING_ITV < prefs_common.io_timeout_secs)
666
                        rpop3_window.ping_tag =
667
                                g_timeout_add_full(G_PRIORITY_LOW,
668
                                                   POP3_PING_ITV * 1000,
669
                                                   rpop3_ping_cb, NULL, NULL);
670
        }
671
}
672

    
673
static gint rpop3_noop_send(Pop3Session *session)
674
{
675
        session->state = POP3_NOOP;
676
        pop3_gen_send(session, "NOOP");
677
        return PS_SUCCESS;
678
}
679

    
680
static gint rpop3_top_send(Pop3Session *session)
681
{
682
        session->state = POP3_TOP;
683
        pop3_gen_send(session, "TOP %d 0", session->cur_msg);
684
        return PS_SUCCESS;
685
}
686

    
687
static gint rpop3_top_recv(Pop3Session *session, FILE *fp, guint len)
688
{
689
        MsgInfo *msginfo;
690
        MsgFlags flags = {0, 0};
691
        GtkTreeIter iter;
692
        const gchar *subject, *from, *date;
693
        gchar buf[1024];
694

    
695
        session->msg[session->cur_msg].received = TRUE;
696

    
697
        msginfo = procheader_parse_stream(fp, flags, FALSE);
698

    
699
        msginfo->size = session->msg[session->cur_msg].size;
700

    
701
        subject = msginfo->subject ? msginfo->subject : _("(No Subject)");
702
        from = msginfo->from ? msginfo->from : _("(No From)");
703
        if (msginfo->date_t) {
704
                procheader_date_get_localtime(buf, sizeof(buf),
705
                                              msginfo->date_t);
706
                date = buf;
707
        } else if (msginfo->date)
708
                date = msginfo->date;
709
        else
710
                date = _("(No Date)");
711

    
712
        gtk_list_store_append(rpop3_window.store, &iter);
713
        gtk_list_store_set(rpop3_window.store, &iter,
714
                           COL_NUMBER, session->cur_msg,
715
                           COL_SUBJECT, subject,
716
                           COL_FROM, from,
717
                           COL_DATE, date,
718
                           COL_SIZE, to_human_readable
719
                                (session->msg[session->cur_msg].size),
720
                           COL_MSGINFO, msginfo,
721
                           COL_DELETED, FALSE,
722
                           -1);
723

    
724
        rpop3_status_label_set(_("Retrieving message headers (%d / %d) ..."),
725
                               session->count - session->cur_msg + 1,
726
                               session->count);
727

    
728
        return PS_SUCCESS;
729
}
730

    
731
static gint rpop3_retr_send(Pop3Session *session)
732
{
733
        if (rpop3_window.recv_array) {
734
                g_return_val_if_fail(rpop3_window.recv_cur < rpop3_window.recv_array->len, -1);
735
                session->cur_msg = g_array_index(rpop3_window.recv_array, gint,
736
                                                 rpop3_window.recv_cur);
737
        }
738

    
739
        rpop3_idle(FALSE);
740
        session->state = POP3_RETR;
741
        pop3_gen_send(session, "RETR %d", session->cur_msg);
742
        return PS_SUCCESS;
743
}
744

    
745
static void msgview_destroy_cb(GtkWidget *widget, gpointer data)
746
{
747
        gchar *file = (gchar *)data;
748

    
749
        if (file) {
750
                debug_print("msgview_destroy_cb: removing temporary file: %s\n", file);
751
                g_unlink(file);
752
                g_free(file);
753
        }
754
}
755

    
756
static gint rpop3_retr_recv(Pop3Session *session, FILE *fp, guint len)
757
{
758
        gchar *file;
759
        MsgInfo *msginfo;
760
        MsgFlags flags = {MSG_NEW|MSG_UNREAD, MSG_RECEIVED};
761
        MessageView *msgview;
762

    
763
        file = get_tmp_file();
764
        if (pop3_write_msg_to_file(file, fp, len) < 0) {
765
                g_free(file);
766
                session->error_val = PS_IOERR;
767
                return -1;
768
        }
769

    
770
        if (rpop3_window.recv_array) {
771
                FolderItem *inbox;
772

    
773
                if (session->ac_prefs->inbox) {
774
                        inbox = folder_find_item_from_identifier
775
                                (session->ac_prefs->inbox);
776
                        if (!inbox)
777
                                inbox = folder_get_default_inbox();
778
                } else
779
                        inbox = folder_get_default_inbox();
780
                if (!inbox) {
781
                        session->error_val = PS_IOERR;
782
                        return -1;
783
                }
784

    
785
                if (folder_item_add_msg(inbox, file, &flags, FALSE) < 0) {
786
                        session->error_val = PS_IOERR;
787
                        return -1;
788
                }
789
                if (rpop3_window.recv_cur + 1 == rpop3_window.recv_array->len)
790
                        folderview_update_item(inbox, TRUE);
791
                else
792
                        folderview_update_item(inbox, FALSE);
793

    
794
                return PS_SUCCESS;
795
        }
796

    
797
        msginfo = procheader_parse_file(file, flags, FALSE);
798
        msginfo->file_path = g_strdup(file);
799

    
800
        msgview = messageview_create_with_new_window();
801
        messageview_show(msgview, msginfo, FALSE);
802

    
803
        g_signal_connect(G_OBJECT(msgview->window), "destroy",
804
                         G_CALLBACK(msgview_destroy_cb), file);
805

    
806
        return PS_SUCCESS;
807
}
808

    
809
static gint rpop3_delete_send(Pop3Session *session)
810
{
811
        g_return_val_if_fail(rpop3_window.delete_array != NULL, -1);
812
        g_return_val_if_fail
813
                (rpop3_window.delete_cur < rpop3_window.delete_array->len, -1);
814

    
815
        rpop3_idle(FALSE);
816
        session->state = POP3_DELETE;
817
        session->cur_msg = g_array_index(rpop3_window.delete_array, gint,
818
                                         rpop3_window.delete_cur);
819
        pop3_gen_send(session, "DELE %d", session->cur_msg);
820
        return PS_SUCCESS;
821
}
822

    
823
static gint rpop3_delete_recv(Pop3Session *session)
824
{
825
        session->msg[session->cur_msg].recv_time = RECV_TIME_DELETE;
826
        session->msg[session->cur_msg].deleted = TRUE;
827
        return PS_SUCCESS;
828
}
829

    
830
static gint rpop3_session_recv_msg(Session *session, const gchar *msg)
831
{
832
        Pop3Session *pop3_session = POP3_SESSION(session);
833
        gint val = PS_SUCCESS;
834
        const gchar *body;
835

    
836
        gdk_threads_enter();
837

    
838
        body = msg;
839
        if (pop3_session->state != POP3_GETRANGE_UIDL_RECV &&
840
            pop3_session->state != POP3_GETSIZE_LIST_RECV) {
841
                val = pop3_ok(pop3_session, msg);
842
                if (val != PS_SUCCESS) {
843
                        if (val == PS_SOCKET) {
844
                                pop3_session->state = POP3_ERROR;
845
                                gdk_threads_leave();
846
                                return -1;
847
                        }
848
                        if (val != PS_NOTSUPPORTED) {
849
                                if (pop3_session->state != POP3_LOGOUT) {
850
                                        if (pop3_logout_send(pop3_session) == PS_SUCCESS) {
851
                                                gdk_threads_leave();
852
                                                return 0;
853
                                        } else {
854
                                                gdk_threads_leave();
855
                                                return -1;
856
                                        }
857
                                }
858
                        }
859
                }
860

    
861
                if (*body == '+' || *body == '-')
862
                        body++;
863
                while (g_ascii_isalpha(*body))
864
                        body++;
865
                while (g_ascii_isspace(*body))
866
                        body++;
867
        }
868

    
869
        switch (pop3_session->state) {
870
        case POP3_READY:
871
        case POP3_GREETING:
872
                val = pop3_greeting_recv(pop3_session, body);
873
                rpop3_status_label_set(_("Authenticating..."));
874
#if USE_SSL
875
                if (pop3_session->ac_prefs->ssl_pop == SSL_STARTTLS)
876
                        val = pop3_stls_send(pop3_session);
877
                else
878
#endif
879
                if (pop3_session->ac_prefs->use_apop_auth)
880
                        val = pop3_getauth_apop_send(pop3_session);
881
                else
882
                        val = pop3_getauth_user_send(pop3_session);
883
                break;
884
#if USE_SSL
885
        case POP3_STLS:
886
                if ((val = pop3_stls_recv(pop3_session)) != PS_SUCCESS)
887
                        break;
888
                if (pop3_session->ac_prefs->use_apop_auth)
889
                        val = pop3_getauth_apop_send(pop3_session);
890
                else
891
                        val = pop3_getauth_user_send(pop3_session);
892
                break;
893
#endif
894
        case POP3_GETAUTH_USER:
895
                val = pop3_getauth_pass_send(pop3_session);
896
                break;
897
        case POP3_GETAUTH_PASS:
898
        case POP3_GETAUTH_APOP:
899
                rpop3_status_label_set(_("Getting the number of messages..."));
900
                val = pop3_getrange_stat_send(pop3_session);
901
                break;
902
        case POP3_GETRANGE_STAT:
903
                if ((val = pop3_getrange_stat_recv(pop3_session, body)) < 0)
904
                        break;
905
                if (pop3_session->count > 0)
906
                        val = pop3_getrange_uidl_send(pop3_session);
907
                else {
908
                        rpop3_status_label_set(_("No message"));
909
                        val = pop3_logout_send(pop3_session);
910
                }
911
                break;
912
        case POP3_GETRANGE_LAST:
913
                if (val == PS_NOTSUPPORTED)
914
                        pop3_session->error_val = PS_SUCCESS;
915
                else if ((val = pop3_getrange_last_recv
916
                        (pop3_session, body)) < 0)
917
                        break;
918
                if (pop3_session->cur_msg > 0)
919
                        val = pop3_getsize_list_send(pop3_session);
920
                else {
921
                        rpop3_status_label_set(_("No message"));
922
                        val = pop3_logout_send(pop3_session);
923
                }
924
                break;
925
        case POP3_GETRANGE_UIDL:
926
                if (val == PS_NOTSUPPORTED) {
927
                        pop3_session->error_val = PS_SUCCESS;
928
                        val = pop3_getrange_last_send(pop3_session);
929
                } else {
930
                        pop3_session->state = POP3_GETRANGE_UIDL_RECV;
931
                        val = session_recv_data(session, 0, ".\r\n");
932
                }
933
                break;
934
        case POP3_GETSIZE_LIST:
935
                pop3_session->state = POP3_GETSIZE_LIST_RECV;
936
                val = session_recv_data(session, 0, ".\r\n");
937
                break;
938
        case POP3_TOP:
939
                pop3_session->state = POP3_TOP_RECV;
940
                val = session_recv_data_as_file(session, 0, ".\r\n");
941
                break;
942
        case POP3_RETR:
943
                pop3_session->state = POP3_RETR_RECV;
944
                val = session_recv_data_as_file(session, 0, ".\r\n");
945
                break;
946
        case POP3_DELETE:
947
                val = rpop3_delete_recv(pop3_session);
948
                if (val != PS_SUCCESS)
949
                        break;
950
                if (rpop3_window.delete_cur + 1 < rpop3_window.delete_array->len) {
951
                        rpop3_window.delete_cur++;
952
                        val = rpop3_delete_send(pop3_session);
953
                } else {
954
                        rpop3_status_label_set(_("Deleted %d messages"),
955
                                                rpop3_window.delete_cur + 1);
956
                        g_array_free(rpop3_window.delete_array, TRUE);
957
                        rpop3_window.delete_array = NULL;
958
                        rpop3_window.delete_cur = 0;
959
                        rpop3_idle(TRUE);
960
                }
961
                break;
962
        case POP3_NOOP:
963
                rpop3_idle(TRUE);
964
                break;
965
        case POP3_LOGOUT:
966
                if (val == PS_SUCCESS)
967
                        pop3_session->state = POP3_DONE;
968
                else
969
                        pop3_session->state = POP3_ERROR;
970
                session_disconnect(session);
971
                break;
972
        case POP3_ERROR:
973
        default:
974
                val = -1;
975
                break;
976
        }
977

    
978
        gdk_threads_leave();
979

    
980
        if (val == PS_SUCCESS)
981
                return 0;
982
        else
983
                return -1;
984
}
985

    
986
static gint rpop3_session_recv_data_finished(Session *session, guchar *data,
987
                                             guint len)
988
{
989
        Pop3Session *pop3_session = POP3_SESSION(session);
990
        Pop3ErrorValue val = PS_SUCCESS;
991
        gint ret = 0;
992

    
993
        gdk_threads_enter();
994

    
995
        switch (pop3_session->state) {
996
        case POP3_GETRANGE_UIDL_RECV:
997
                val = pop3_getrange_uidl_recv(pop3_session, (gchar *)data, len);
998
                if (val == PS_SUCCESS) {
999
                        if (rpop3_window.cancelled) {
1000
                                rpop3_status_label_set(_("Quitting..."));
1001
                                pop3_logout_send(pop3_session);
1002
                        } else
1003
                                pop3_getsize_list_send(pop3_session);
1004
                } else
1005
                        ret = -1;
1006
                break;
1007
        case POP3_GETSIZE_LIST_RECV:
1008
                val = pop3_getsize_list_recv(pop3_session, (gchar *)data, len);
1009
                if (val == PS_SUCCESS) {
1010
                        pop3_session->cur_msg = 1;
1011
                        if (rpop3_window.cancelled || pop3_session->count == 0) {
1012
                                rpop3_status_label_set(_("Quitting..."));
1013
                                pop3_logout_send(pop3_session);
1014
                        } else {
1015
                                pop3_session->cur_msg = pop3_session->count;
1016
                                gtk_widget_set_sensitive(rpop3_window.stop_btn,
1017
                                                         TRUE);
1018
                                g_object_set(rpop3_window.update_action,
1019
                                             "sensitive", FALSE, NULL);
1020
                                g_object_set(rpop3_window.stop_action,
1021
                                             "sensitive", TRUE, NULL);
1022
                                rpop3_top_send(pop3_session);
1023
                        }
1024
                } else
1025
                        ret = -1;
1026
                break;
1027
        case POP3_ERROR:
1028
        default:
1029
                ret = -1;
1030
                break;
1031
        }
1032

    
1033
        gdk_threads_leave();
1034

    
1035
        return ret;
1036
}
1037

    
1038
static gint rpop3_session_recv_data_as_file_finished(Session *session,
1039
                                                     FILE *fp, guint len)
1040
{
1041
        Pop3Session *pop3_session = POP3_SESSION(session);
1042
        gint ret = 0;
1043

    
1044
        gdk_threads_enter();
1045

    
1046
        switch (pop3_session->state) {
1047
        case POP3_RETR_RECV:
1048
                if (rpop3_retr_recv(pop3_session, fp, len) < 0) {
1049
                        ret = -1;
1050
                        break;
1051
                }
1052
                if (rpop3_window.recv_array) {
1053
                        if (rpop3_window.recv_cur + 1 < rpop3_window.recv_array->len) {
1054
                                rpop3_window.recv_cur++;
1055
                                if (rpop3_retr_send(pop3_session) < 0)
1056
                                        ret = -1;
1057
                        } else {
1058
                                rpop3_status_label_set(_("Retrieved %d messages"), rpop3_window.recv_cur + 1);
1059
                                g_array_free(rpop3_window.recv_array, TRUE);
1060
                                rpop3_window.recv_array = NULL;
1061
                                rpop3_window.recv_cur = 0;
1062
                                rpop3_idle(TRUE);
1063
                        }
1064
                } else {
1065
                        rpop3_status_label_set(_("Opened message %d"),
1066
                                               pop3_session->cur_msg);
1067
                        rpop3_idle(TRUE);
1068
                }
1069
                break;
1070
        case POP3_TOP_RECV:
1071
                if (rpop3_top_recv(pop3_session, fp, len) == PS_SUCCESS) {
1072
                        if (rpop3_window.cancelled) {
1073
                                rpop3_status_label_set(_("Quitting..."));
1074
                                pop3_logout_send(pop3_session);
1075
                        } else if (!rpop3_window.stop_load &&
1076
                                 (pop3_session->cur_msg > 1)) {
1077
                                pop3_session->cur_msg--;
1078
                                rpop3_top_send(pop3_session);
1079
                        } else {
1080
                                if (pop3_session->cur_msg > 1)
1081
                                        rpop3_status_label_set
1082
                                                (_("Retrieved %d (of %d) message headers"),
1083
                                                 pop3_session->count - pop3_session->cur_msg + 1, pop3_session->count);
1084
                                else
1085
                                        rpop3_status_label_set
1086
                                                (_("Retrieved %d message headers"),
1087
                                                 pop3_session->count - pop3_session->cur_msg + 1);
1088
                                gtk_widget_set_sensitive
1089
                                        (rpop3_window.recv_btn, TRUE);
1090
                                gtk_widget_set_sensitive
1091
                                        (rpop3_window.open_btn, TRUE);
1092
                                gtk_widget_set_sensitive
1093
                                        (rpop3_window.delete_btn, TRUE);
1094
                                if (pop3_session->cur_msg == 1)
1095
                                        gtk_widget_set_sensitive(rpop3_window.stop_btn, FALSE);
1096
                                else
1097
                                        gtk_button_set_label(GTK_BUTTON(rpop3_window.stop_btn), _("_Resume"));
1098
                                g_object_set(rpop3_window.recv_action,
1099
                                             "sensitive", TRUE, NULL);
1100
                                g_object_set(rpop3_window.open_action,
1101
                                             "sensitive", TRUE, NULL);
1102
                                g_object_set(rpop3_window.delete_action,
1103
                                             "sensitive", TRUE, NULL);
1104
                                g_object_set(rpop3_window.stop_action,
1105
                                             "sensitive", FALSE, NULL);
1106
                                if (pop3_session->cur_msg == 1)
1107
                                        g_object_set(rpop3_window.update_action, "sensitive", FALSE, NULL);
1108
                                else
1109
                                        g_object_set(rpop3_window.update_action, "sensitive", TRUE, NULL);
1110
                                rpop3_idle(TRUE);
1111
                        }
1112
                } else
1113
                        ret = -1;
1114
                break;
1115
        default:
1116
                ret = -1;
1117
                break;
1118
        }
1119

    
1120
        gdk_threads_leave();
1121

    
1122
        return ret;
1123
}
1124

    
1125
static gint window_deleted(GtkWidget *widget, GdkEventAny *event,
1126
                           gpointer data)
1127
{
1128
        gtk_button_clicked(GTK_BUTTON(rpop3_window.close_btn));
1129
        return TRUE;
1130
}
1131

    
1132
static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
1133
                            gpointer data)
1134
{
1135
        return FALSE;
1136
}
1137

    
1138
static void rpop3_row_activated(GtkTreeView *treeview, GtkTreePath *path,
1139
                                GtkTreeViewColumn *column, gpointer data)
1140
{
1141
        gtk_button_clicked(GTK_BUTTON(rpop3_window.open_btn));
1142
}
1143

    
1144
static void rpop3_recv(GtkButton *button, gpointer data)
1145
{
1146
        GtkTreeModel *model = GTK_TREE_MODEL(rpop3_window.store);
1147
        GtkTreeSelection *selection;
1148
        GtkTreeIter iter;
1149
        GList *rows, *cur;
1150
        gint num;
1151
        gboolean deleted;
1152
        GArray *array;
1153

    
1154
        if (rpop3_window.session->state != POP3_IDLE)
1155
                return;
1156

    
1157
        selection = gtk_tree_view_get_selection
1158
                (GTK_TREE_VIEW(rpop3_window.treeview));
1159

    
1160
        rows = gtk_tree_selection_get_selected_rows(selection, NULL);
1161
        array = g_array_sized_new(FALSE, FALSE, sizeof(gint),
1162
                                  g_list_length(rows));
1163

    
1164
        for (cur = rows; cur != NULL; cur = cur->next) {
1165
                gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)cur->data);
1166
                gtk_tree_model_get(model, &iter, COL_NUMBER, &num,
1167
                                   COL_DELETED, &deleted, -1);
1168
                if (!deleted) {
1169
                        debug_print("rpop3_recv: receiving message %d\n", num);
1170
                        g_array_append_val(array, num);
1171
                }
1172
        }
1173

    
1174
        g_list_foreach(rows, (GFunc)gtk_tree_path_free, NULL);
1175
        g_list_free(rows);
1176

    
1177
        if (array->len > 0) {
1178
                rpop3_window.recv_array = array;
1179
                rpop3_window.recv_cur = 0;
1180
                rpop3_retr_send(rpop3_window.session);
1181
        } else
1182
                g_array_free(array, TRUE);
1183
}
1184

    
1185
static void rpop3_open(GtkButton *button, gpointer data)
1186
{
1187
        GtkTreeModel *model = GTK_TREE_MODEL(rpop3_window.store);
1188
        GtkTreeSelection *selection;
1189
        GtkTreeIter iter;
1190
        GList *rows, *cur;
1191
        gint num;
1192
        gboolean deleted;
1193

    
1194
        if (rpop3_window.session->state != POP3_IDLE)
1195
                return;
1196

    
1197
        selection = gtk_tree_view_get_selection
1198
                (GTK_TREE_VIEW(rpop3_window.treeview));
1199

    
1200
        rows = gtk_tree_selection_get_selected_rows(selection, NULL);
1201

    
1202
        for (cur = rows; cur != NULL; cur = cur->next) {
1203
                gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)cur->data);
1204
                gtk_tree_model_get(model, &iter, COL_NUMBER, &num,
1205
                                   COL_DELETED, &deleted, -1);
1206
                if (!deleted) {
1207
                        debug_print("rpop3_open: opening message %d\n", num);
1208
                        rpop3_status_label_set(_("Retrieving message %d ..."),
1209
                                               num);
1210
                        rpop3_window.session->cur_msg = num;
1211
                        rpop3_retr_send(rpop3_window.session);
1212
                        break;
1213
                }
1214
        }
1215

    
1216
        g_list_foreach(rows, (GFunc)gtk_tree_path_free, NULL);
1217
        g_list_free(rows);
1218
}
1219

    
1220
static void rpop3_delete(GtkButton *button, gpointer data)
1221
{
1222
        GtkTreeModel *model = GTK_TREE_MODEL(rpop3_window.store);
1223
        GtkTreeSelection *selection;
1224
        GtkTreeIter iter;
1225
        GList *rows, *cur;
1226
        gint num;
1227
        gboolean deleted;
1228
        GArray *array;
1229
        AlertValue val;
1230

    
1231
        if (rpop3_window.session->state != POP3_IDLE)
1232
                return;
1233

    
1234
        val = alertpanel(_("Delete messages"),
1235
                         _("Really delete selected messages from server?\n"
1236
                           "This operation cannot be reverted."),
1237
                         GTK_STOCK_YES, GTK_STOCK_NO, NULL);
1238
        if (val != G_ALERTDEFAULT)
1239
                return;
1240

    
1241
        selection = gtk_tree_view_get_selection
1242
                (GTK_TREE_VIEW(rpop3_window.treeview));
1243

    
1244
        rows = gtk_tree_selection_get_selected_rows(selection, NULL);
1245

    
1246
        array = g_array_sized_new(FALSE, FALSE, sizeof(gint),
1247
                                  g_list_length(rows));
1248

    
1249
        for (cur = rows; cur != NULL; cur = cur->next) {
1250
                gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)cur->data);
1251
                gtk_tree_model_get(model, &iter, COL_NUMBER, &num,
1252
                                   COL_DELETED, &deleted, -1);
1253
                if (!deleted) {
1254
                        debug_print("rpop3_delete: marked %d to delete\n", num);
1255
                        g_array_append_val(array, num);
1256
                        gtk_list_store_set(GTK_LIST_STORE(model), &iter,
1257
                                           COL_DELETED, TRUE, -1);
1258
                }
1259
        }
1260

    
1261
        g_list_foreach(rows, (GFunc)gtk_tree_path_free, NULL);
1262
        g_list_free(rows);
1263

    
1264
        if (array->len > 0) {
1265
                rpop3_window.delete_array = array;
1266
                rpop3_window.delete_cur = 0;
1267
                rpop3_delete_send(rpop3_window.session);
1268
        } else
1269
                g_array_free(array, TRUE);
1270
}
1271

    
1272
static void rpop3_read_next(GtkButton *button, gpointer data)
1273
{
1274
        gint i;
1275

    
1276
        if (rpop3_window.session->state != POP3_IDLE)
1277
                return;
1278

    
1279
        for (i = rpop3_window.session->count; i > 0; i--) {
1280
                if (!rpop3_window.session->msg[i].received)
1281
                        break;
1282
        }
1283

    
1284
        if (i == 0)
1285
                return;
1286

    
1287
        debug_print("rpop3_read_next: next: %d\n", i);
1288
        rpop3_window.session->cur_msg = i;
1289

    
1290
        rpop3_window.stop_load = FALSE;
1291

    
1292
        gtk_widget_set_sensitive(rpop3_window.recv_btn, FALSE);
1293
        gtk_widget_set_sensitive(rpop3_window.open_btn, FALSE);
1294
        gtk_widget_set_sensitive(rpop3_window.delete_btn, FALSE);
1295
        gtk_button_set_label(GTK_BUTTON(rpop3_window.stop_btn), GTK_STOCK_STOP);
1296
        gtk_widget_set_sensitive(rpop3_window.stop_btn, TRUE);
1297
        g_object_set(rpop3_window.update_action, "sensitive", FALSE, NULL);
1298
        g_object_set(rpop3_window.stop_action, "sensitive", TRUE, NULL);
1299
        rpop3_idle(FALSE);
1300
        rpop3_top_send(rpop3_window.session);
1301
}
1302

    
1303
static void rpop3_stop(GtkButton *button, gpointer data)
1304
{
1305
        if (rpop3_window.session->state == POP3_IDLE)
1306
                rpop3_read_next(NULL, NULL);
1307
        else
1308
                rpop3_window.stop_load = TRUE;
1309
}
1310

    
1311
static void rpop3_close(GtkButton *button, gpointer data)
1312
{
1313
        rpop3_window.finished = TRUE;
1314

    
1315
        if (rpop3_window.session->state == POP3_IDLE) {
1316
                rpop3_status_label_set(_("Quitting..."));
1317
                rpop3_idle(FALSE);
1318
                pop3_logout_send(rpop3_window.session);
1319
        } else if (rpop3_window.session->state != POP3_DONE ||
1320
                   rpop3_window.session->state != POP3_ERROR)
1321
                rpop3_window.cancelled = TRUE;
1322
}
1323

    
1324
static void rpop3_recv_cb(void)
1325
{
1326
        rpop3_recv(NULL, NULL);
1327
}
1328

    
1329
static void rpop3_open_cb(void)
1330
{
1331
        rpop3_open(NULL, NULL);
1332
}
1333

    
1334
static void rpop3_delete_cb(void)
1335
{
1336
        rpop3_delete(NULL, NULL);
1337
}
1338

    
1339
static void rpop3_resume_cb(void)
1340
{
1341
        rpop3_stop(NULL, NULL);
1342
}
1343

    
1344
static void rpop3_stop_cb(void)
1345
{
1346
        rpop3_stop(NULL, NULL);
1347
}
1348

    
1349
static void rpop3_close_cb(void)
1350
{
1351
        rpop3_close(NULL, NULL);
1352
}
1353

    
1354
static void rpop3_about_cb(void)
1355
{
1356
        about_show();
1357
}
1358

    
1359
static gint cmp_by_subject(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
1360
                           gpointer data)
1361
{
1362
        MsgInfo *msginfo_a = NULL, *msginfo_b = NULL;
1363
        gint ret;
1364

    
1365
        gtk_tree_model_get(model, a, COL_MSGINFO, &msginfo_a, -1);
1366
        gtk_tree_model_get(model, b, COL_MSGINFO, &msginfo_b, -1);
1367

    
1368
        if (!msginfo_a || !msginfo_b)
1369
                return 0;
1370

    
1371
        if (!msginfo_a->subject)
1372
                return -(msginfo_b->subject != NULL);
1373
        if (!msginfo_b->subject)
1374
                return (msginfo_a->subject != NULL);
1375

    
1376
        ret = subject_compare_for_sort(msginfo_a->subject, msginfo_b->subject);
1377
        return (ret != 0) ? ret : (msginfo_a->msgnum - msginfo_b->msgnum);
1378
}
1379

    
1380
static gint cmp_by_date(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
1381
                        gpointer data)
1382
{
1383
        MsgInfo *msginfo_a = NULL, *msginfo_b = NULL;
1384
        gint ret;
1385

    
1386
        gtk_tree_model_get(model, a, COL_MSGINFO, &msginfo_a, -1);
1387
        gtk_tree_model_get(model, b, COL_MSGINFO, &msginfo_b, -1);
1388

    
1389
        if (!msginfo_a || !msginfo_b)
1390
                return 0;
1391

    
1392
        ret = msginfo_a->date_t - msginfo_b->date_t;
1393
        return (ret != 0) ? ret : (msginfo_a->msgnum - msginfo_b->msgnum);
1394
}
1395

    
1396
static gint cmp_by_size(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
1397
                        gpointer data)
1398
{
1399
        MsgInfo *msginfo_a = NULL, *msginfo_b = NULL;
1400
        gint ret;
1401

    
1402
        gtk_tree_model_get(model, a, COL_MSGINFO, &msginfo_a, -1);
1403
        gtk_tree_model_get(model, b, COL_MSGINFO, &msginfo_b, -1);
1404

    
1405
        if (!msginfo_a || !msginfo_b)
1406
                return 0;
1407

    
1408
        ret = msginfo_a->size - msginfo_b->size;
1409
        return (ret != 0) ? ret : (msginfo_a->msgnum - msginfo_b->msgnum);
1410
}