Statistics
| Revision:

root / src / pop.c @ 416

History | View | Annotate | Download (20.6 kB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2004 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 <stdio.h>
29
#include <string.h>
30
#include <stdarg.h>
31
#include <ctype.h>
32
#include <unistd.h>
33
#include <time.h>
34
#include <errno.h>
35
36
#include "pop.h"
37
#include "md5.h"
38
#include "prefs_account.h"
39
#include "utils.h"
40
#include "recv.h"
41
42
static gint pop3_greeting_recv                (Pop3Session *session,
43
                                         const gchar *msg);
44
static gint pop3_getauth_user_send        (Pop3Session *session);
45
static gint pop3_getauth_pass_send        (Pop3Session *session);
46
static gint pop3_getauth_apop_send        (Pop3Session *session);
47
#if USE_SSL
48
static gint pop3_stls_send                (Pop3Session *session);
49
static gint pop3_stls_recv                (Pop3Session *session);
50
#endif
51
static gint pop3_getrange_stat_send        (Pop3Session *session);
52
static gint pop3_getrange_stat_recv        (Pop3Session *session,
53
                                         const gchar *msg);
54
static gint pop3_getrange_last_send        (Pop3Session *session);
55
static gint pop3_getrange_last_recv        (Pop3Session *session,
56
                                         const gchar *msg);
57
static gint pop3_getrange_uidl_send        (Pop3Session *session);
58
static gint pop3_getrange_uidl_recv        (Pop3Session *session,
59
                                         const gchar *data,
60
                                         guint        len);
61
static gint pop3_getsize_list_send        (Pop3Session *session);
62
static gint pop3_getsize_list_recv        (Pop3Session *session,
63
                                         const gchar *data,
64
                                         guint        len);
65
static gint pop3_retr_send                (Pop3Session *session);
66
static gint pop3_retr_recv                (Pop3Session *session,
67
                                         const gchar *data,
68
                                         guint        len);
69
static gint pop3_delete_send                (Pop3Session *session);
70
static gint pop3_delete_recv                (Pop3Session *session);
71
static gint pop3_logout_send                (Pop3Session *session);
72
73
static void pop3_gen_send                (Pop3Session        *session,
74
                                         const gchar        *format, ...);
75
76
static void pop3_session_destroy        (Session        *session);
77
78
static gint pop3_write_msg_to_file        (const gchar        *file,
79
                                         const gchar        *data,
80
                                         guint                 len);
81
82
static Pop3State pop3_lookup_next        (Pop3Session        *session);
83
static Pop3ErrorValue pop3_ok                (Pop3Session        *session,
84
                                         const gchar        *msg);
85
86
static gint pop3_session_recv_msg                (Session        *session,
87
                                                 const gchar        *msg);
88
static gint pop3_session_recv_data_finished        (Session        *session,
89
                                                 guchar                *data,
90
                                                 guint                 len);
91
92
93
static gint pop3_greeting_recv(Pop3Session *session, const gchar *msg)
94
{
95
        session->state = POP3_GREETING;
96
97
        session->greeting = g_strdup(msg);
98
        return PS_SUCCESS;
99
}
100
101
#if USE_SSL
102
static gint pop3_stls_send(Pop3Session *session)
103
{
104
        session->state = POP3_STLS;
105
        pop3_gen_send(session, "STLS");
106
        return PS_SUCCESS;
107
}
108
109
static gint pop3_stls_recv(Pop3Session *session)
110
{
111
        if (session_start_tls(SESSION(session)) < 0) {
112
                session->error_val = PS_SOCKET;
113
                return -1;
114
        }
115
        return PS_SUCCESS;
116
}
117
#endif /* USE_SSL */
118
119
static gint pop3_getauth_user_send(Pop3Session *session)
120
{
121
        g_return_val_if_fail(session->user != NULL, -1);
122
123
        session->state = POP3_GETAUTH_USER;
124
        pop3_gen_send(session, "USER %s", session->user);
125
        return PS_SUCCESS;
126
}
127
128
static gint pop3_getauth_pass_send(Pop3Session *session)
129
{
130
        g_return_val_if_fail(session->pass != NULL, -1);
131
132
        session->state = POP3_GETAUTH_PASS;
133
        pop3_gen_send(session, "PASS %s", session->pass);
134
        return PS_SUCCESS;
135
}
136
137
static gint pop3_getauth_apop_send(Pop3Session *session)
138
{
139
        gchar *start, *end;
140
        gchar *apop_str;
141
        gchar md5sum[33];
142
143
        g_return_val_if_fail(session->user != NULL, -1);
144
        g_return_val_if_fail(session->pass != NULL, -1);
145
146
        session->state = POP3_GETAUTH_APOP;
147
148
        if ((start = strchr(session->greeting, '<')) == NULL) {
149
                log_warning(_("Required APOP timestamp not found "
150
                              "in greeting\n"));
151
                session->error_val = PS_PROTOCOL;
152
                return -1;
153
        }
154
155
        if ((end = strchr(start, '>')) == NULL || end == start + 1) {
156
                log_warning(_("Timestamp syntax error in greeting\n"));
157
                session->error_val = PS_PROTOCOL;
158
                return -1;
159
        }
160
161
        *(end + 1) = '\0';
162
163
        apop_str = g_strconcat(start, session->pass, NULL);
164
        md5_hex_digest(md5sum, apop_str);
165
        g_free(apop_str);
166
167
        pop3_gen_send(session, "APOP %s %s", session->user, md5sum);
168
169
        return PS_SUCCESS;
170
}
171
172
static gint pop3_getrange_stat_send(Pop3Session *session)
173
{
174
        session->state = POP3_GETRANGE_STAT;
175
        pop3_gen_send(session, "STAT");
176
        return PS_SUCCESS;
177
}
178
179
static gint pop3_getrange_stat_recv(Pop3Session *session, const gchar *msg)
180
{
181
        if (sscanf(msg, "%d %d", &session->count, &session->total_bytes) != 2) {
182
                log_warning(_("POP3 protocol error\n"));
183
                session->error_val = PS_PROTOCOL;
184
                return -1;
185
        } else {
186
                if (session->count == 0) {
187
                        session->uidl_is_valid = TRUE;
188
                } else {
189
                        session->msg = g_new0(Pop3MsgInfo, session->count + 1);
190
                        session->cur_msg = 1;
191
                }
192
        }
193
194
        return PS_SUCCESS;
195
}
196
197
static gint pop3_getrange_last_send(Pop3Session *session)
198
{
199
        session->state = POP3_GETRANGE_LAST;
200
        pop3_gen_send(session, "LAST");
201
        return PS_SUCCESS;
202
}
203
204
static gint pop3_getrange_last_recv(Pop3Session *session, const gchar *msg)
205
{
206
        gint last;
207
208
        if (sscanf(msg, "%d", &last) == 0) {
209
                log_warning(_("POP3 protocol error\n"));
210
                session->error_val = PS_PROTOCOL;
211
                return -1;
212
        } else {
213
                if (session->count > last) {
214
                        session->new_msg_exist = TRUE;
215
                        session->cur_msg = last + 1;
216
                } else
217
                        session->cur_msg = 0;
218
        }
219
220
        return PS_SUCCESS;
221
}
222
223
static gint pop3_getrange_uidl_send(Pop3Session *session)
224
{
225
        session->state = POP3_GETRANGE_UIDL;
226
        pop3_gen_send(session, "UIDL");
227
        return PS_SUCCESS;
228
}
229
230
static gint pop3_getrange_uidl_recv(Pop3Session *session, const gchar *data,
231
                                    guint len)
232
{
233
        gchar id[IDLEN + 1];
234
        gchar buf[POPBUFSIZE];
235
        gint buf_len;
236
        gint num;
237
        time_t recv_time;
238
        const gchar *p = data;
239
        const gchar *lastp = data + len;
240
        const gchar *newline;
241
242
        while (p < lastp) {
243
                if ((newline = memchr(p, '\r', lastp - p)) == NULL)
244
                        return -1;
245
                buf_len = MIN(newline - p, sizeof(buf) - 1);
246
                memcpy(buf, p, buf_len);
247
                buf[buf_len] = '\0';
248
249
                p = newline + 1;
250
                if (p < lastp && *p == '\n') p++;
251
252
                if (sscanf(buf, "%d %" Xstr(IDLEN) "s", &num, id) != 2 ||
253
                    num <= 0 || num > session->count) {
254
                        log_warning(_("invalid UIDL response: %s\n"), buf);
255
                        continue;
256
                }
257
258
                session->msg[num].uidl = g_strdup(id);
259
260
                recv_time = (time_t)g_hash_table_lookup(session->uidl_table, id);
261
                session->msg[num].recv_time = recv_time;
262
263
                if (!session->ac_prefs->getall && recv_time != RECV_TIME_NONE)
264
                        session->msg[num].received = TRUE;
265
266
                if (!session->new_msg_exist &&
267
                    (session->ac_prefs->getall || recv_time == RECV_TIME_NONE ||
268
                     session->ac_prefs->rmmail)) {
269
                        session->cur_msg = num;
270
                        session->new_msg_exist = TRUE;
271
                }
272
        }
273
274
        session->uidl_is_valid = TRUE;
275
        return PS_SUCCESS;
276
}
277
278
static gint pop3_getsize_list_send(Pop3Session *session)
279
{
280
        session->state = POP3_GETSIZE_LIST;
281
        pop3_gen_send(session, "LIST");
282
        return PS_SUCCESS;
283
}
284
285
static gint pop3_getsize_list_recv(Pop3Session *session, const gchar *data,
286
                                   guint len)
287
{
288
        gchar buf[POPBUFSIZE];
289
        gint buf_len;
290
        guint num, size;
291
        const gchar *p = data;
292
        const gchar *lastp = data + len;
293
        const gchar *newline;
294
295
        while (p < lastp) {
296
                if ((newline = memchr(p, '\r', lastp - p)) == NULL)
297
                        return -1;
298
                buf_len = MIN(newline - p, sizeof(buf) - 1);
299
                memcpy(buf, p, buf_len);
300
                buf[buf_len] = '\0';
301
302
                p = newline + 1;
303
                if (p < lastp && *p == '\n') p++;
304
305
                if (sscanf(buf, "%u %u", &num, &size) != 2) {
306
                        session->error_val = PS_PROTOCOL;
307
                        return -1;
308
                }
309
310
                if (num > 0 && num <= session->count)
311
                        session->msg[num].size = size;
312
                if (num > 0 && num < session->cur_msg)
313
                        session->cur_total_bytes += size;
314
        }
315
316
        return PS_SUCCESS;
317
}
318
319
static gint pop3_retr_send(Pop3Session *session)
320
{
321
        session->state = POP3_RETR;
322
        pop3_gen_send(session, "RETR %d", session->cur_msg);
323
        return PS_SUCCESS;
324
}
325
326
static gint pop3_retr_recv(Pop3Session *session, const gchar *data, guint len)
327
{
328
        gchar *file;
329
        gint drop_ok;
330
331
        file = get_tmp_file();
332
        if (pop3_write_msg_to_file(file, data, len) < 0) {
333
                g_free(file);
334
                session->error_val = PS_IOERR;
335
                return -1;
336
        }
337
338
        drop_ok = session->drop_message(session, file);
339
        unlink(file);
340
        g_free(file);
341
        if (drop_ok < 0) {
342
                session->error_val = PS_IOERR;
343
                return -1;
344
        }
345
346
        session->cur_total_bytes += session->msg[session->cur_msg].size;
347
        session->cur_total_recv_bytes += session->msg[session->cur_msg].size;
348
        session->cur_total_num++;
349
350
        session->msg[session->cur_msg].received = TRUE;
351
        session->msg[session->cur_msg].recv_time =
352
                drop_ok == DROP_DONT_RECEIVE ? RECV_TIME_KEEP
353
                        : drop_ok == DROP_DELETE ? RECV_TIME_DELETE
354
                        : session->current_time;
355
356
        return PS_SUCCESS;
357
}
358
359
static gint pop3_delete_send(Pop3Session *session)
360
{
361
        session->state = POP3_DELETE;
362
        pop3_gen_send(session, "DELE %d", session->cur_msg);
363
        return PS_SUCCESS;
364
}
365
366
static gint pop3_delete_recv(Pop3Session *session)
367
{
368
        session->msg[session->cur_msg].deleted = TRUE;
369
        return PS_SUCCESS;
370
}
371
372
static gint pop3_logout_send(Pop3Session *session)
373
{
374
        session->state = POP3_LOGOUT;
375
        pop3_gen_send(session, "QUIT");
376
        return PS_SUCCESS;
377
}
378
379
static void pop3_gen_send(Pop3Session *session, const gchar *format, ...)
380
{
381
        gchar buf[POPBUFSIZE + 1];
382
        va_list args;
383
384
        va_start(args, format);
385
        g_vsnprintf(buf, sizeof(buf) - 2, format, args);
386
        va_end(args);
387
388
        if (!g_ascii_strncasecmp(buf, "PASS ", 5))
389
                log_print("POP3> PASS ********\n");
390
        else
391
                log_print("POP3> %s\n", buf);
392
393
        session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf);
394
}
395
396
Session *pop3_session_new(PrefsAccount *account)
397
{
398
        Pop3Session *session;
399
400
        g_return_val_if_fail(account != NULL, NULL);
401
402
        session = g_new0(Pop3Session, 1);
403
404
        session_init(SESSION(session));
405
406
        SESSION(session)->type = SESSION_POP3;
407
408
        SESSION(session)->recv_msg = pop3_session_recv_msg;
409
        SESSION(session)->recv_data_finished = pop3_session_recv_data_finished;
410
        SESSION(session)->send_data_finished = NULL;
411
412
        SESSION(session)->destroy = pop3_session_destroy;
413
414
        session->state = POP3_READY;
415
        session->ac_prefs = account;
416
        session->uidl_table = pop3_get_uidl_table(account);
417
        session->current_time = time(NULL);
418
        session->error_val = PS_SUCCESS;
419
        session->error_msg = NULL;
420
421
        return SESSION(session);
422
}
423
424
static void pop3_session_destroy(Session *session)
425
{
426
        Pop3Session *pop3_session = POP3_SESSION(session);
427
        gint n;
428
429
        g_return_if_fail(session != NULL);
430
431
        for (n = 1; n <= pop3_session->count; n++)
432
                g_free(pop3_session->msg[n].uidl);
433
        g_free(pop3_session->msg);
434
435
        if (pop3_session->uidl_table) {
436
                hash_free_strings(pop3_session->uidl_table);
437
                g_hash_table_destroy(pop3_session->uidl_table);
438
        }
439
440
        g_free(pop3_session->greeting);
441
        g_free(pop3_session->user);
442
        g_free(pop3_session->pass);
443
        g_free(pop3_session->error_msg);
444
}
445
446
GHashTable *pop3_get_uidl_table(PrefsAccount *ac_prefs)
447
{
448
        GHashTable *table;
449
        gchar *path;
450
        FILE *fp;
451
        gchar buf[POPBUFSIZE];
452
        gchar uidl[POPBUFSIZE];
453
        time_t recv_time;
454
        time_t now;
455
456
        table = g_hash_table_new(g_str_hash, g_str_equal);
457
458
        path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
459
                           UIDL_DIR, G_DIR_SEPARATOR_S, ac_prefs->recv_server,
460
                           "-", ac_prefs->userid, NULL);
461
        if ((fp = fopen(path, "rb")) == NULL) {
462
                if (ENOENT != errno) FILE_OP_ERROR(path, "fopen");
463
                g_free(path);
464
                return table;
465
        }
466
        g_free(path);
467
468
        now = time(NULL);
469
470
        while (fgets(buf, sizeof(buf), fp) != NULL) {
471
                strretchomp(buf);
472
                recv_time = RECV_TIME_NONE;
473
                if (sscanf(buf, "%s\t%ld", uidl, &recv_time) != 2) {
474
                        if (sscanf(buf, "%s", uidl) != 1)
475
                                continue;
476
                        else
477
                                recv_time = now;
478
                }
479
                if (recv_time == RECV_TIME_NONE)
480
                        recv_time = RECV_TIME_RECEIVED;
481
                g_hash_table_insert(table, g_strdup(uidl),
482
                                    GINT_TO_POINTER(recv_time));
483
        }
484
485
        fclose(fp);
486
        return table;
487
}
488
489
gint pop3_write_uidl_list(Pop3Session *session)
490
{
491
        gchar *path;
492
        FILE *fp;
493
        Pop3MsgInfo *msg;
494
        gint n;
495
496
        if (!session->uidl_is_valid) return 0;
497
498
        path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
499
                           "uidl", G_DIR_SEPARATOR_S,
500
                           session->ac_prefs->recv_server,
501
                           "-", session->ac_prefs->userid, NULL);
502
        if ((fp = fopen(path, "wb")) == NULL) {
503
                FILE_OP_ERROR(path, "fopen");
504
                g_free(path);
505
                return -1;
506
        }
507
508
        for (n = 1; n <= session->count; n++) {
509
                msg = &session->msg[n];
510
                if (msg->uidl && msg->received && !msg->deleted)
511
                        fprintf(fp, "%s\t%ld\n", msg->uidl, msg->recv_time);
512
        }
513
514
        if (fclose(fp) == EOF) FILE_OP_ERROR(path, "fclose");
515
        g_free(path);
516
517
        return 0;
518
}
519
520
static gint pop3_write_msg_to_file(const gchar *file, const gchar *data,
521
                                   guint len)
522
{
523
        FILE *fp;
524
        const gchar *prev, *cur;
525
526
        g_return_val_if_fail(file != NULL, -1);
527
528
        if ((fp = fopen(file, "wb")) == NULL) {
529
                FILE_OP_ERROR(file, "fopen");
530
                return -1;
531
        }
532
533
        if (change_file_mode_rw(fp, file) < 0)
534
                FILE_OP_ERROR(file, "chmod");
535
536
        /* +------------------+----------------+--------------------------+ *
537
         * ^data              ^prev            ^cur             data+len-1^ */
538
539
        prev = data;
540
        while ((cur = (gchar *)my_memmem(prev, len - (prev - data), "\r\n", 2))
541
               != NULL) {
542
                if ((cur > prev && fwrite(prev, cur - prev, 1, fp) < 1) ||
543
                    fputc('\n', fp) == EOF) {
544
                        FILE_OP_ERROR(file, "fwrite");
545
                        g_warning("can't write to file: %s\n", file);
546
                        fclose(fp);
547
                        unlink(file);
548
                        return -1;
549
                }
550
551
                if (cur == data + len - 1) {
552
                        prev = cur + 1;
553
                        break;
554
                }
555
556
                if (*(cur + 1) == '\n')
557
                        prev = cur + 2;
558
                else
559
                        prev = cur + 1;
560
561
                if (prev - data < len - 1 && *prev == '.' && *(prev + 1) == '.')
562
                        prev++;
563
564
                if (prev - data >= len)
565
                        break;
566
        }
567
568
        if (prev - data < len &&
569
            fwrite(prev, len - (prev - data), 1, fp) < 1) {
570
                FILE_OP_ERROR(file, "fwrite");
571
                g_warning("can't write to file: %s\n", file);
572
                fclose(fp);
573
                unlink(file);
574
                return -1;
575
        }
576
        if (data[len - 1] != '\r' && data[len - 1] != '\n') {
577
                if (fputc('\n', fp) == EOF) {
578
                        FILE_OP_ERROR(file, "fputc");
579
                        g_warning("can't write to file: %s\n", file);
580
                        fclose(fp);
581
                        unlink(file);
582
                        return -1;
583
                }
584
        }
585
586
        if (fclose(fp) == EOF) {
587
                FILE_OP_ERROR(file, "fclose");
588
                unlink(file);
589
                return -1;
590
        }
591
592
        return 0;
593
}
594
595
static Pop3State pop3_lookup_next(Pop3Session *session)
596
{
597
        Pop3MsgInfo *msg;
598
        PrefsAccount *ac = session->ac_prefs;
599
        gint size;
600
        gboolean size_limit_over;
601
602
        for (;;) {
603
                msg = &session->msg[session->cur_msg];
604
                size = msg->size;
605
                size_limit_over =
606
                    (ac->enable_size_limit &&
607
                     ac->size_limit > 0 &&
608
                     size > ac->size_limit * 1024);
609
610
                if (msg->recv_time == RECV_TIME_DELETE ||
611
                    (ac->rmmail &&
612
                     msg->recv_time != RECV_TIME_NONE &&
613
                     msg->recv_time != RECV_TIME_KEEP &&
614
                     session->current_time - msg->recv_time >=
615
                     ac->msg_leave_time * 24 * 60 * 60)) {
616
                        log_print(_("POP3: Deleting expired message %d\n"),
617
                                  session->cur_msg);
618
                        pop3_delete_send(session);
619
                        return POP3_DELETE;
620
                }
621
622
                if (size_limit_over)
623
                        log_print
624
                                (_("POP3: Skipping message %d (%d bytes)\n"),
625
                                  session->cur_msg, size);
626
627
                if (size == 0 || msg->received || size_limit_over) {
628
                        session->cur_total_bytes += size;
629
                        if (session->cur_msg == session->count) {
630
                                pop3_logout_send(session);
631
                                return POP3_LOGOUT;
632
                        } else
633
                                session->cur_msg++;
634
                } else
635
                        break;
636
        }
637
638
        pop3_retr_send(session);
639
        return POP3_RETR;
640
}
641
642
static Pop3ErrorValue pop3_ok(Pop3Session *session, const gchar *msg)
643
{
644
        Pop3ErrorValue ok;
645
646
        log_print("POP3< %s\n", msg);
647
648
        if (!strncmp(msg, "+OK", 3))
649
                ok = PS_SUCCESS;
650
        else if (!strncmp(msg, "-ERR", 4)) {
651
                if (strstr(msg + 4, "lock") ||
652
                    strstr(msg + 4, "Lock") ||
653
                    strstr(msg + 4, "LOCK") ||
654
                    strstr(msg + 4, "wait")) {
655
                        log_warning(_("mailbox is locked\n"));
656
                        ok = PS_LOCKBUSY;
657
                } else if (strcasestr(msg + 4, "timeout")) {
658
                        log_warning(_("session timeout\n"));
659
                        ok = PS_ERROR;
660
                } else {
661
                        switch (session->state) {
662
#if USE_SSL
663
                        case POP3_STLS:
664
                                log_warning(_("can't start TLS session\n"));
665
                                ok = PS_ERROR;
666
                                break;
667
#endif
668
                        case POP3_GETAUTH_USER:
669
                        case POP3_GETAUTH_PASS:
670
                        case POP3_GETAUTH_APOP:
671
                                log_warning(_("error occurred on authentication\n"));
672
                                ok = PS_AUTHFAIL;
673
                                break;
674
                        case POP3_GETRANGE_LAST:
675
                        case POP3_GETRANGE_UIDL:
676
                                log_warning(_("command not supported\n"));
677
                                ok = PS_NOTSUPPORTED;
678
                                break;
679
                        default:
680
                                log_warning(_("error occurred on POP3 session\n"));
681
                                ok = PS_ERROR;
682
                        }
683
                }
684
685
                g_free(session->error_msg);
686
                session->error_msg = g_strdup(msg);
687
                fprintf(stderr, "POP3: %s\n", msg);
688
        } else
689
                ok = PS_PROTOCOL;
690
691
        session->error_val = ok;
692
        return ok;
693
}
694
695
static gint pop3_session_recv_msg(Session *session, const gchar *msg)
696
{
697
        Pop3Session *pop3_session = POP3_SESSION(session);
698
        Pop3ErrorValue val = PS_SUCCESS;
699
        const guchar *body;
700
701
        body = msg;
702
        if (pop3_session->state != POP3_GETRANGE_UIDL_RECV &&
703
            pop3_session->state != POP3_GETSIZE_LIST_RECV) {
704
                val = pop3_ok(pop3_session, msg);
705
                if (val != PS_SUCCESS) {
706
                        if (val != PS_NOTSUPPORTED) {
707
                                pop3_session->state = POP3_ERROR;
708
                                return -1;
709
                        }
710
                }
711
712
                if (*body == '+' || *body == '-')
713
                        body++;
714
                while (isalpha(*body))
715
                        body++;
716
                while (isspace(*body))
717
                        body++;
718
        }
719
720
        switch (pop3_session->state) {
721
        case POP3_READY:
722
        case POP3_GREETING:
723
                pop3_greeting_recv(pop3_session, body);
724
#if USE_SSL
725
                if (pop3_session->ac_prefs->ssl_pop == SSL_STARTTLS)
726
                        pop3_stls_send(pop3_session);
727
                else
728
#endif
729
                if (pop3_session->ac_prefs->use_apop_auth)
730
                        pop3_getauth_apop_send(pop3_session);
731
                else
732
                        pop3_getauth_user_send(pop3_session);
733
                break;
734
#if USE_SSL
735
        case POP3_STLS:
736
                if (pop3_stls_recv(pop3_session) != PS_SUCCESS)
737
                        return -1;
738
                if (pop3_session->ac_prefs->use_apop_auth)
739
                        pop3_getauth_apop_send(pop3_session);
740
                else
741
                        pop3_getauth_user_send(pop3_session);
742
                break;
743
#endif
744
        case POP3_GETAUTH_USER:
745
                pop3_getauth_pass_send(pop3_session);
746
                break;
747
        case POP3_GETAUTH_PASS:
748
        case POP3_GETAUTH_APOP:
749
                pop3_getrange_stat_send(pop3_session);
750
                break;
751
        case POP3_GETRANGE_STAT:
752
                if (pop3_getrange_stat_recv(pop3_session, body) < 0)
753
                        return -1;
754
                if (pop3_session->count > 0)
755
                        pop3_getrange_uidl_send(pop3_session);
756
                else
757
                        pop3_logout_send(pop3_session);
758
                break;
759
        case POP3_GETRANGE_LAST:
760
                if (val == PS_NOTSUPPORTED)
761
                        pop3_session->error_val = PS_SUCCESS;
762
                else if (pop3_getrange_last_recv(pop3_session, body) < 0)
763
                        return -1;
764
                if (pop3_session->cur_msg > 0)
765
                        pop3_getsize_list_send(pop3_session);
766
                else
767
                        pop3_logout_send(pop3_session);
768
                break;
769
        case POP3_GETRANGE_UIDL:
770
                if (val == PS_NOTSUPPORTED) {
771
                        pop3_session->error_val = PS_SUCCESS;
772
                        pop3_getrange_last_send(pop3_session);
773
                } else {
774
                        pop3_session->state = POP3_GETRANGE_UIDL_RECV;
775
                        session_recv_data(session, 0, ".\r\n");
776
                }
777
                break;
778
        case POP3_GETSIZE_LIST:
779
                pop3_session->state = POP3_GETSIZE_LIST_RECV;
780
                session_recv_data(session, 0, ".\r\n");
781
                break;
782
        case POP3_RETR:
783
                pop3_session->state = POP3_RETR_RECV;
784
                session_recv_data(session, 0, ".\r\n");
785
                break;
786
        case POP3_DELETE:
787
                pop3_delete_recv(pop3_session);
788
                if (pop3_session->cur_msg == pop3_session->count)
789
                        pop3_logout_send(pop3_session);
790
                else {
791
                        pop3_session->cur_msg++;
792
                        if (pop3_lookup_next(pop3_session) == POP3_ERROR)
793
                                return -1;
794
                }
795
                break;
796
        case POP3_LOGOUT:
797
                session_disconnect(session);
798
                break;
799
        case POP3_ERROR:
800
        default:
801
                return -1;
802
        }
803
804
        return 0;
805
}
806
807
static gint pop3_session_recv_data_finished(Session *session, guchar *data,
808
                                            guint len)
809
{
810
        Pop3Session *pop3_session = POP3_SESSION(session);
811
        Pop3ErrorValue val = PS_SUCCESS;
812
813
        switch (pop3_session->state) {
814
        case POP3_GETRANGE_UIDL_RECV:
815
                val = pop3_getrange_uidl_recv(pop3_session, data, len);
816
                if (val == PS_SUCCESS) {
817
                        if (pop3_session->new_msg_exist)
818
                                pop3_getsize_list_send(pop3_session);
819
                        else
820
                                pop3_logout_send(pop3_session);
821
                } else
822
                        return -1;
823
                break;
824
        case POP3_GETSIZE_LIST_RECV:
825
                val = pop3_getsize_list_recv(pop3_session, data, len);
826
                if (val == PS_SUCCESS) {
827
                        if (pop3_lookup_next(pop3_session) == POP3_ERROR)
828
                                return -1;
829
                } else
830
                        return -1;
831
                break;
832
        case POP3_RETR_RECV:
833
                if (pop3_retr_recv(pop3_session, data, len) < 0)
834
                        return -1;
835
836
                if (pop3_session->msg[pop3_session->cur_msg].recv_time
837
                    == RECV_TIME_DELETE ||
838
                    (pop3_session->ac_prefs->rmmail &&
839
                     pop3_session->ac_prefs->msg_leave_time == 0 &&
840
                     pop3_session->msg[pop3_session->cur_msg].recv_time
841
                     != RECV_TIME_KEEP))
842
                        pop3_delete_send(pop3_session);
843
                else if (pop3_session->cur_msg == pop3_session->count)
844
                        pop3_logout_send(pop3_session);
845
                else {
846
                        pop3_session->cur_msg++;
847
                        if (pop3_lookup_next(pop3_session) == POP3_ERROR)
848
                                return -1;
849
                }
850
                break;
851
        case POP3_ERROR:
852
        default:
853
                return -1;
854
        }
855
856
        return 0;
857
}