Statistics
| Revision:

root / src / rpop3.c @ 3308

History | View | Annotate | Download (39.2 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
        if (!msginfo) {
799
                session->error_val = PS_IOERR;
800
                return -1;
801
        }
802

    
803
        msginfo->file_path = g_strdup(file);
804

    
805
        msgview = messageview_create_with_new_window();
806
        messageview_show(msgview, msginfo, FALSE);
807

    
808
        g_signal_connect(G_OBJECT(msgview->window), "destroy",
809
                         G_CALLBACK(msgview_destroy_cb), file);
810

    
811
        return PS_SUCCESS;
812
}
813

    
814
static gint rpop3_delete_send(Pop3Session *session)
815
{
816
        g_return_val_if_fail(rpop3_window.delete_array != NULL, -1);
817
        g_return_val_if_fail
818
                (rpop3_window.delete_cur < rpop3_window.delete_array->len, -1);
819

    
820
        rpop3_idle(FALSE);
821
        session->state = POP3_DELETE;
822
        session->cur_msg = g_array_index(rpop3_window.delete_array, gint,
823
                                         rpop3_window.delete_cur);
824
        pop3_gen_send(session, "DELE %d", session->cur_msg);
825
        return PS_SUCCESS;
826
}
827

    
828
static gint rpop3_delete_recv(Pop3Session *session)
829
{
830
        session->msg[session->cur_msg].recv_time = RECV_TIME_DELETE;
831
        session->msg[session->cur_msg].deleted = TRUE;
832
        return PS_SUCCESS;
833
}
834

    
835
static gint rpop3_session_recv_msg(Session *session, const gchar *msg)
836
{
837
        Pop3Session *pop3_session = POP3_SESSION(session);
838
        gint val = PS_SUCCESS;
839
        const gchar *body;
840

    
841
        gdk_threads_enter();
842

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

    
866
                if (*body == '+' || *body == '-')
867
                        body++;
868
                while (g_ascii_isalpha(*body))
869
                        body++;
870
                while (g_ascii_isspace(*body))
871
                        body++;
872
        }
873

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

    
983
        gdk_threads_leave();
984

    
985
        if (val == PS_SUCCESS)
986
                return 0;
987
        else
988
                return -1;
989
}
990

    
991
static gint rpop3_session_recv_data_finished(Session *session, guchar *data,
992
                                             guint len)
993
{
994
        Pop3Session *pop3_session = POP3_SESSION(session);
995
        Pop3ErrorValue val = PS_SUCCESS;
996
        gint ret = 0;
997

    
998
        gdk_threads_enter();
999

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

    
1038
        gdk_threads_leave();
1039

    
1040
        return ret;
1041
}
1042

    
1043
static gint rpop3_session_recv_data_as_file_finished(Session *session,
1044
                                                     FILE *fp, guint len)
1045
{
1046
        Pop3Session *pop3_session = POP3_SESSION(session);
1047
        gint ret = 0;
1048

    
1049
        gdk_threads_enter();
1050

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

    
1125
        gdk_threads_leave();
1126

    
1127
        return ret;
1128
}
1129

    
1130
static gint window_deleted(GtkWidget *widget, GdkEventAny *event,
1131
                           gpointer data)
1132
{
1133
        gtk_button_clicked(GTK_BUTTON(rpop3_window.close_btn));
1134
        return TRUE;
1135
}
1136

    
1137
static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
1138
                            gpointer data)
1139
{
1140
        return FALSE;
1141
}
1142

    
1143
static void rpop3_row_activated(GtkTreeView *treeview, GtkTreePath *path,
1144
                                GtkTreeViewColumn *column, gpointer data)
1145
{
1146
        gtk_button_clicked(GTK_BUTTON(rpop3_window.open_btn));
1147
}
1148

    
1149
static void rpop3_recv(GtkButton *button, gpointer data)
1150
{
1151
        GtkTreeModel *model = GTK_TREE_MODEL(rpop3_window.store);
1152
        GtkTreeSelection *selection;
1153
        GtkTreeIter iter;
1154
        GList *rows, *cur;
1155
        gint num;
1156
        gboolean deleted;
1157
        GArray *array;
1158

    
1159
        if (rpop3_window.session->state != POP3_IDLE)
1160
                return;
1161

    
1162
        selection = gtk_tree_view_get_selection
1163
                (GTK_TREE_VIEW(rpop3_window.treeview));
1164

    
1165
        rows = gtk_tree_selection_get_selected_rows(selection, NULL);
1166
        array = g_array_sized_new(FALSE, FALSE, sizeof(gint),
1167
                                  g_list_length(rows));
1168

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

    
1179
        g_list_foreach(rows, (GFunc)gtk_tree_path_free, NULL);
1180
        g_list_free(rows);
1181

    
1182
        if (array->len > 0) {
1183
                rpop3_window.recv_array = array;
1184
                rpop3_window.recv_cur = 0;
1185
                rpop3_retr_send(rpop3_window.session);
1186
        } else
1187
                g_array_free(array, TRUE);
1188
}
1189

    
1190
static void rpop3_open(GtkButton *button, gpointer data)
1191
{
1192
        GtkTreeModel *model = GTK_TREE_MODEL(rpop3_window.store);
1193
        GtkTreeSelection *selection;
1194
        GtkTreeIter iter;
1195
        GList *rows, *cur;
1196
        gint num;
1197
        gboolean deleted;
1198

    
1199
        if (rpop3_window.session->state != POP3_IDLE)
1200
                return;
1201

    
1202
        selection = gtk_tree_view_get_selection
1203
                (GTK_TREE_VIEW(rpop3_window.treeview));
1204

    
1205
        rows = gtk_tree_selection_get_selected_rows(selection, NULL);
1206

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

    
1221
        g_list_foreach(rows, (GFunc)gtk_tree_path_free, NULL);
1222
        g_list_free(rows);
1223
}
1224

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

    
1236
        if (rpop3_window.session->state != POP3_IDLE)
1237
                return;
1238

    
1239
        val = alertpanel(_("Delete messages"),
1240
                         _("Really delete selected messages from server?\n"
1241
                           "This operation cannot be reverted."),
1242
                         GTK_STOCK_YES, GTK_STOCK_NO, NULL);
1243
        if (val != G_ALERTDEFAULT)
1244
                return;
1245

    
1246
        selection = gtk_tree_view_get_selection
1247
                (GTK_TREE_VIEW(rpop3_window.treeview));
1248

    
1249
        rows = gtk_tree_selection_get_selected_rows(selection, NULL);
1250

    
1251
        array = g_array_sized_new(FALSE, FALSE, sizeof(gint),
1252
                                  g_list_length(rows));
1253

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

    
1266
        g_list_foreach(rows, (GFunc)gtk_tree_path_free, NULL);
1267
        g_list_free(rows);
1268

    
1269
        if (array->len > 0) {
1270
                rpop3_window.delete_array = array;
1271
                rpop3_window.delete_cur = 0;
1272
                rpop3_delete_send(rpop3_window.session);
1273
        } else
1274
                g_array_free(array, TRUE);
1275
}
1276

    
1277
static void rpop3_read_next(GtkButton *button, gpointer data)
1278
{
1279
        gint i;
1280

    
1281
        if (rpop3_window.session->state != POP3_IDLE)
1282
                return;
1283

    
1284
        for (i = rpop3_window.session->count; i > 0; i--) {
1285
                if (!rpop3_window.session->msg[i].received)
1286
                        break;
1287
        }
1288

    
1289
        if (i == 0)
1290
                return;
1291

    
1292
        debug_print("rpop3_read_next: next: %d\n", i);
1293
        rpop3_window.session->cur_msg = i;
1294

    
1295
        rpop3_window.stop_load = FALSE;
1296

    
1297
        gtk_widget_set_sensitive(rpop3_window.recv_btn, FALSE);
1298
        gtk_widget_set_sensitive(rpop3_window.open_btn, FALSE);
1299
        gtk_widget_set_sensitive(rpop3_window.delete_btn, FALSE);
1300
        gtk_button_set_label(GTK_BUTTON(rpop3_window.stop_btn), GTK_STOCK_STOP);
1301
        gtk_widget_set_sensitive(rpop3_window.stop_btn, TRUE);
1302
        g_object_set(rpop3_window.update_action, "sensitive", FALSE, NULL);
1303
        g_object_set(rpop3_window.stop_action, "sensitive", TRUE, NULL);
1304
        rpop3_idle(FALSE);
1305
        rpop3_top_send(rpop3_window.session);
1306
}
1307

    
1308
static void rpop3_stop(GtkButton *button, gpointer data)
1309
{
1310
        if (rpop3_window.session->state == POP3_IDLE)
1311
                rpop3_read_next(NULL, NULL);
1312
        else
1313
                rpop3_window.stop_load = TRUE;
1314
}
1315

    
1316
static void rpop3_close(GtkButton *button, gpointer data)
1317
{
1318
        rpop3_window.finished = TRUE;
1319

    
1320
        if (rpop3_window.session->state == POP3_IDLE) {
1321
                rpop3_status_label_set(_("Quitting..."));
1322
                rpop3_idle(FALSE);
1323
                pop3_logout_send(rpop3_window.session);
1324
        } else if (rpop3_window.session->state != POP3_DONE &&
1325
                   rpop3_window.session->state != POP3_ERROR)
1326
                rpop3_window.cancelled = TRUE;
1327
}
1328

    
1329
static void rpop3_recv_cb(void)
1330
{
1331
        rpop3_recv(NULL, NULL);
1332
}
1333

    
1334
static void rpop3_open_cb(void)
1335
{
1336
        rpop3_open(NULL, NULL);
1337
}
1338

    
1339
static void rpop3_delete_cb(void)
1340
{
1341
        rpop3_delete(NULL, NULL);
1342
}
1343

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

    
1349
static void rpop3_stop_cb(void)
1350
{
1351
        rpop3_stop(NULL, NULL);
1352
}
1353

    
1354
static void rpop3_close_cb(void)
1355
{
1356
        rpop3_close(NULL, NULL);
1357
}
1358

    
1359
static void rpop3_about_cb(void)
1360
{
1361
        about_show();
1362
}
1363

    
1364
static gint cmp_by_subject(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
1365
                           gpointer data)
1366
{
1367
        MsgInfo *msginfo_a = NULL, *msginfo_b = NULL;
1368
        gint ret;
1369

    
1370
        gtk_tree_model_get(model, a, COL_MSGINFO, &msginfo_a, -1);
1371
        gtk_tree_model_get(model, b, COL_MSGINFO, &msginfo_b, -1);
1372

    
1373
        if (!msginfo_a || !msginfo_b)
1374
                return 0;
1375

    
1376
        if (!msginfo_a->subject)
1377
                return -(msginfo_b->subject != NULL);
1378
        if (!msginfo_b->subject)
1379
                return (msginfo_a->subject != NULL);
1380

    
1381
        ret = subject_compare_for_sort(msginfo_a->subject, msginfo_b->subject);
1382
        return (ret != 0) ? ret : (msginfo_a->msgnum - msginfo_b->msgnum);
1383
}
1384

    
1385
static gint cmp_by_date(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
1386
                        gpointer data)
1387
{
1388
        MsgInfo *msginfo_a = NULL, *msginfo_b = NULL;
1389
        gint ret;
1390

    
1391
        gtk_tree_model_get(model, a, COL_MSGINFO, &msginfo_a, -1);
1392
        gtk_tree_model_get(model, b, COL_MSGINFO, &msginfo_b, -1);
1393

    
1394
        if (!msginfo_a || !msginfo_b)
1395
                return 0;
1396

    
1397
        ret = msginfo_a->date_t - msginfo_b->date_t;
1398
        return (ret != 0) ? ret : (msginfo_a->msgnum - msginfo_b->msgnum);
1399
}
1400

    
1401
static gint cmp_by_size(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
1402
                        gpointer data)
1403
{
1404
        MsgInfo *msginfo_a = NULL, *msginfo_b = NULL;
1405
        gint ret;
1406

    
1407
        gtk_tree_model_get(model, a, COL_MSGINFO, &msginfo_a, -1);
1408
        gtk_tree_model_get(model, b, COL_MSGINFO, &msginfo_b, -1);
1409

    
1410
        if (!msginfo_a || !msginfo_b)
1411
                return 0;
1412

    
1413
        ret = msginfo_a->size - msginfo_b->size;
1414
        return (ret != 0) ? ret : (msginfo_a->msgnum - msginfo_b->msgnum);
1415
}