Statistics
| Revision:

root / src / pop.c @ 1

History | View | Annotate | Download (20.8 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 <glib.h>
25
#include <stdio.h>
26
#include <string.h>
27
#include <stdarg.h>
28
#include <ctype.h>
29
#include <unistd.h>
30
#include <time.h>
31
#include <errno.h>
32

    
33
#include "intl.h"
34
#include "pop.h"
35
#include "md5.h"
36
#include "prefs_account.h"
37
#include "utils.h"
38
#include "recv.h"
39

    
40
static gint pop3_greeting_recv                (Pop3Session *session,
41
                                         const gchar *msg);
42
static gint pop3_getauth_user_send        (Pop3Session *session);
43
static gint pop3_getauth_pass_send        (Pop3Session *session);
44
static gint pop3_getauth_apop_send        (Pop3Session *session);
45
#if USE_SSL
46
static gint pop3_stls_send                (Pop3Session *session);
47
static gint pop3_stls_recv                (Pop3Session *session);
48
#endif
49
static gint pop3_getrange_stat_send        (Pop3Session *session);
50
static gint pop3_getrange_stat_recv        (Pop3Session *session,
51
                                         const gchar *msg);
52
static gint pop3_getrange_last_send        (Pop3Session *session);
53
static gint pop3_getrange_last_recv        (Pop3Session *session,
54
                                         const gchar *msg);
55
static gint pop3_getrange_uidl_send        (Pop3Session *session);
56
static gint pop3_getrange_uidl_recv        (Pop3Session *session,
57
                                         const gchar *data,
58
                                         guint        len);
59
static gint pop3_getsize_list_send        (Pop3Session *session);
60
static gint pop3_getsize_list_recv        (Pop3Session *session,
61
                                         const gchar *data,
62
                                         guint        len);
63
static gint pop3_retr_send                (Pop3Session *session);
64
static gint pop3_retr_recv                (Pop3Session *session,
65
                                         const gchar *data,
66
                                         guint        len);
67
static gint pop3_delete_send                (Pop3Session *session);
68
static gint pop3_delete_recv                (Pop3Session *session);
69
static gint pop3_logout_send                (Pop3Session *session);
70

    
71
static void pop3_gen_send                (Pop3Session        *session,
72
                                         const gchar        *format, ...);
73

    
74
static void pop3_session_destroy        (Session        *session);
75

    
76
static gint pop3_write_msg_to_file        (const gchar        *file,
77
                                         const gchar        *data,
78
                                         guint                 len);
79

    
80
static Pop3State pop3_lookup_next        (Pop3Session        *session);
81
static Pop3ErrorValue pop3_ok                (Pop3Session        *session,
82
                                         const gchar        *msg);
83

    
84
static gint pop3_session_recv_msg                (Session        *session,
85
                                                 const gchar        *msg);
86
static gint pop3_session_recv_data_finished        (Session        *session,
87
                                                 guchar                *data,
88
                                                 guint                 len);
89

    
90

    
91
static gint pop3_greeting_recv(Pop3Session *session, const gchar *msg)
92
{
93
        session->state = POP3_GREETING;
94

    
95
        session->greeting = g_strdup(msg);
96
        return PS_SUCCESS;
97
}
98

    
99
#if USE_SSL
100
static gint pop3_stls_send(Pop3Session *session)
101
{
102
        session->state = POP3_STLS;
103
        pop3_gen_send(session, "STLS");
104
        return PS_SUCCESS;
105
}
106

    
107
static gint pop3_stls_recv(Pop3Session *session)
108
{
109
        if (session_start_tls(SESSION(session)) < 0) {
110
                session->error_val = PS_SOCKET;
111
                return -1;
112
        }
113
        return PS_SUCCESS;
114
}
115
#endif /* USE_SSL */
116

    
117
static gint pop3_getauth_user_send(Pop3Session *session)
118
{
119
        g_return_val_if_fail(session->user != NULL, -1);
120

    
121
        session->state = POP3_GETAUTH_USER;
122
        pop3_gen_send(session, "USER %s", session->user);
123
        return PS_SUCCESS;
124
}
125

    
126
static gint pop3_getauth_pass_send(Pop3Session *session)
127
{
128
        g_return_val_if_fail(session->pass != NULL, -1);
129

    
130
        session->state = POP3_GETAUTH_PASS;
131
        pop3_gen_send(session, "PASS %s", session->pass);
132
        return PS_SUCCESS;
133
}
134

    
135
static gint pop3_getauth_apop_send(Pop3Session *session)
136
{
137
        gchar *start, *end;
138
        gchar *apop_str;
139
        gchar md5sum[33];
140

    
141
        g_return_val_if_fail(session->user != NULL, -1);
142
        g_return_val_if_fail(session->pass != NULL, -1);
143

    
144
        session->state = POP3_GETAUTH_APOP;
145

    
146
        if ((start = strchr(session->greeting, '<')) == NULL) {
147
                log_warning(_("Required APOP timestamp not found "
148
                              "in greeting\n"));
149
                session->error_val = PS_PROTOCOL;
150
                return -1;
151
        }
152

    
153
        if ((end = strchr(start, '>')) == NULL || end == start + 1) {
154
                log_warning(_("Timestamp syntax error in greeting\n"));
155
                session->error_val = PS_PROTOCOL;
156
                return -1;
157
        }
158

    
159
        *(end + 1) = '\0';
160

    
161
        apop_str = g_strconcat(start, session->pass, NULL);
162
        md5_hex_digest(md5sum, apop_str);
163
        g_free(apop_str);
164

    
165
        pop3_gen_send(session, "APOP %s %s", session->user, md5sum);
166

    
167
        return PS_SUCCESS;
168
}
169

    
170
static gint pop3_getrange_stat_send(Pop3Session *session)
171
{
172
        session->state = POP3_GETRANGE_STAT;
173
        pop3_gen_send(session, "STAT");
174
        return PS_SUCCESS;
175
}
176

    
177
static gint pop3_getrange_stat_recv(Pop3Session *session, const gchar *msg)
178
{
179
        if (sscanf(msg, "%d %d", &session->count, &session->total_bytes) != 2) {
180
                log_warning(_("POP3 protocol error\n"));
181
                session->error_val = PS_PROTOCOL;
182
                return -1;
183
        } else {
184
                if (session->count == 0) {
185
                        session->uidl_is_valid = TRUE;
186
                } else {
187
                        session->msg = g_new0(Pop3MsgInfo, session->count + 1);
188
                        session->cur_msg = 1;
189
                }
190
        }
191

    
192
        return PS_SUCCESS;
193
}
194

    
195
static gint pop3_getrange_last_send(Pop3Session *session)
196
{
197
        session->state = POP3_GETRANGE_LAST;
198
        pop3_gen_send(session, "LAST");
199
        return PS_SUCCESS;
200
}
201

    
202
static gint pop3_getrange_last_recv(Pop3Session *session, const gchar *msg)
203
{
204
        gint last;
205

    
206
        if (sscanf(msg, "%d", &last) == 0) {
207
                log_warning(_("POP3 protocol error\n"));
208
                session->error_val = PS_PROTOCOL;
209
                return -1;
210
        } else {
211
                if (session->count > last) {
212
                        session->new_msg_exist = TRUE;
213
                        session->cur_msg = last + 1;
214
                } else
215
                        session->cur_msg = 0;
216
        }
217

    
218
        return PS_SUCCESS;
219
}
220

    
221
static gint pop3_getrange_uidl_send(Pop3Session *session)
222
{
223
        session->state = POP3_GETRANGE_UIDL;
224
        pop3_gen_send(session, "UIDL");
225
        return PS_SUCCESS;
226
}
227

    
228
static gint pop3_getrange_uidl_recv(Pop3Session *session, const gchar *data,
229
                                    guint len)
230
{
231
        gchar id[IDLEN + 1];
232
        gchar buf[POPBUFSIZE];
233
        gint buf_len;
234
        gint num;
235
        time_t recv_time;
236
        const gchar *p = data;
237
        const gchar *lastp = data + len;
238
        const gchar *newline;
239

    
240
        while (p < lastp) {
241
                if ((newline = memchr(p, '\r', lastp - p)) == NULL)
242
                        return -1;
243
                buf_len = MIN(newline - p, sizeof(buf) - 1);
244
                memcpy(buf, p, buf_len);
245
                buf[buf_len] = '\0';
246

    
247
                p = newline + 1;
248
                if (p < lastp && *p == '\n') p++;
249

    
250
                if (sscanf(buf, "%d %" Xstr(IDLEN) "s", &num, id) != 2 ||
251
                    num <= 0 || num > session->count) {
252
                        log_warning(_("invalid UIDL response: %s\n"), buf);
253
                        continue;
254
                }
255

    
256
                session->msg[num].uidl = g_strdup(id);
257

    
258
                recv_time = (time_t)g_hash_table_lookup(session->uidl_table, id);
259
                session->msg[num].recv_time = recv_time;
260

    
261
                if (!session->ac_prefs->getall && recv_time != RECV_TIME_NONE)
262
                        session->msg[num].received = TRUE;
263

    
264
                if (!session->new_msg_exist &&
265
                    (session->ac_prefs->getall || recv_time == RECV_TIME_NONE ||
266
                     session->ac_prefs->rmmail)) {
267
                        session->cur_msg = num;
268
                        session->new_msg_exist = TRUE;
269
                }
270
        }
271

    
272
        session->uidl_is_valid = TRUE;
273
        return PS_SUCCESS;
274
}
275

    
276
static gint pop3_getsize_list_send(Pop3Session *session)
277
{
278
        session->state = POP3_GETSIZE_LIST;
279
        pop3_gen_send(session, "LIST");
280
        return PS_SUCCESS;
281
}
282

    
283
static gint pop3_getsize_list_recv(Pop3Session *session, const gchar *data,
284
                                   guint len)
285
{
286
        gchar buf[POPBUFSIZE];
287
        gint buf_len;
288
        guint num, size;
289
        const gchar *p = data;
290
        const gchar *lastp = data + len;
291
        const gchar *newline;
292

    
293
        while (p < lastp) {
294
                if ((newline = memchr(p, '\r', lastp - p)) == NULL)
295
                        return -1;
296
                buf_len = MIN(newline - p, sizeof(buf) - 1);
297
                memcpy(buf, p, buf_len);
298
                buf[buf_len] = '\0';
299

    
300
                p = newline + 1;
301
                if (p < lastp && *p == '\n') p++;
302

    
303
                if (sscanf(buf, "%u %u", &num, &size) != 2) {
304
                        session->error_val = PS_PROTOCOL;
305
                        return -1;
306
                }
307

    
308
                if (num > 0 && num <= session->count)
309
                        session->msg[num].size = size;
310
                if (num > 0 && num < session->cur_msg)
311
                        session->cur_total_bytes += size;
312
        }
313

    
314
        return PS_SUCCESS;
315
}
316

    
317
static gint pop3_retr_send(Pop3Session *session)
318
{
319
        session->state = POP3_RETR;
320
        pop3_gen_send(session, "RETR %d", session->cur_msg);
321
        return PS_SUCCESS;
322
}
323

    
324
static gint pop3_retr_recv(Pop3Session *session, const gchar *data, guint len)
325
{
326
        gchar *file;
327
        gint drop_ok;
328

    
329
        file = get_tmp_file();
330
        if (pop3_write_msg_to_file(file, data, len) < 0) {
331
                g_free(file);
332
                session->error_val = PS_IOERR;
333
                return -1;
334
        }
335

    
336
        drop_ok = session->drop_message(session, file);
337
        unlink(file);
338
        g_free(file);
339
        if (drop_ok < 0) {
340
                session->error_val = PS_IOERR;
341
                return -1;
342
        }
343

    
344
        session->cur_total_bytes += session->msg[session->cur_msg].size;
345
        session->cur_total_recv_bytes += session->msg[session->cur_msg].size;
346
        session->cur_total_num++;
347

    
348
        session->msg[session->cur_msg].received = TRUE;
349
        session->msg[session->cur_msg].recv_time =
350
                drop_ok == DROP_DONT_RECEIVE ? RECV_TIME_KEEP
351
                        : drop_ok == DROP_DELETE ? RECV_TIME_DELETE
352
                        : session->current_time;
353

    
354
        return PS_SUCCESS;
355
}
356

    
357
static gint pop3_delete_send(Pop3Session *session)
358
{
359
        session->state = POP3_DELETE;
360
        pop3_gen_send(session, "DELE %d", session->cur_msg);
361
        return PS_SUCCESS;
362
}
363

    
364
static gint pop3_delete_recv(Pop3Session *session)
365
{
366
        session->msg[session->cur_msg].deleted = TRUE;
367
        return PS_SUCCESS;
368
}
369

    
370
static gint pop3_logout_send(Pop3Session *session)
371
{
372
        session->state = POP3_LOGOUT;
373
        pop3_gen_send(session, "QUIT");
374
        return PS_SUCCESS;
375
}
376

    
377
static void pop3_gen_send(Pop3Session *session, const gchar *format, ...)
378
{
379
        gchar buf[POPBUFSIZE + 1];
380
        va_list args;
381

    
382
        va_start(args, format);
383
        g_vsnprintf(buf, sizeof(buf) - 2, format, args);
384
        va_end(args);
385

    
386
        if (!strncasecmp(buf, "PASS ", 5))
387
                log_print("POP3> PASS ********\n");
388
        else
389
                log_print("POP3> %s\n", buf);
390

    
391
        session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf);
392
}
393

    
394
Session *pop3_session_new(PrefsAccount *account)
395
{
396
        Pop3Session *session;
397

    
398
        g_return_val_if_fail(account != NULL, NULL);
399

    
400
        session = g_new0(Pop3Session, 1);
401

    
402
        session_init(SESSION(session));
403

    
404
        SESSION(session)->type = SESSION_POP3;
405

    
406
        SESSION(session)->recv_msg = pop3_session_recv_msg;
407
        SESSION(session)->recv_data_finished = pop3_session_recv_data_finished;
408
        SESSION(session)->send_data_finished = NULL;
409

    
410
        SESSION(session)->destroy = pop3_session_destroy;
411

    
412
        session->state = POP3_READY;
413
        session->ac_prefs = account;
414
        session->uidl_table = pop3_get_uidl_table(account);
415
        session->current_time = time(NULL);
416
        session->error_val = PS_SUCCESS;
417
        session->error_msg = NULL;
418

    
419
        return SESSION(session);
420
}
421

    
422
static void pop3_session_destroy(Session *session)
423
{
424
        Pop3Session *pop3_session = POP3_SESSION(session);
425
        gint n;
426

    
427
        g_return_if_fail(session != NULL);
428

    
429
        for (n = 1; n <= pop3_session->count; n++)
430
                g_free(pop3_session->msg[n].uidl);
431
        g_free(pop3_session->msg);
432

    
433
        if (pop3_session->uidl_table) {
434
                hash_free_strings(pop3_session->uidl_table);
435
                g_hash_table_destroy(pop3_session->uidl_table);
436
        }
437

    
438
        g_free(pop3_session->greeting);
439
        g_free(pop3_session->user);
440
        g_free(pop3_session->pass);
441
        g_free(pop3_session->error_msg);
442
}
443

    
444
GHashTable *pop3_get_uidl_table(PrefsAccount *ac_prefs)
445
{
446
        GHashTable *table;
447
        gchar *path;
448
        FILE *fp;
449
        gchar buf[POPBUFSIZE];
450
        gchar uidl[POPBUFSIZE];
451
        time_t recv_time;
452
        time_t now;
453

    
454
        table = g_hash_table_new(g_str_hash, g_str_equal);
455

    
456
        path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
457
                           "uidl", G_DIR_SEPARATOR_S, ac_prefs->recv_server,
458
                           "-", ac_prefs->userid, NULL);
459
        if ((fp = fopen(path, "rb")) == NULL) {
460
                if (ENOENT != errno) FILE_OP_ERROR(path, "fopen");
461
                g_free(path);
462
                path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
463
                                   "uidl-", ac_prefs->recv_server,
464
                                   "-", ac_prefs->userid, NULL);
465
                if ((fp = fopen(path, "rb")) == NULL) {
466
                        if (ENOENT != errno) FILE_OP_ERROR(path, "fopen");
467
                        g_free(path);
468
                        return table;
469
                }
470
        }
471
        g_free(path);
472

    
473
        now = time(NULL);
474

    
475
        while (fgets(buf, sizeof(buf), fp) != NULL) {
476
                strretchomp(buf);
477
                recv_time = RECV_TIME_NONE;
478
                if (sscanf(buf, "%s\t%ld", uidl, &recv_time) != 2) {
479
                        if (sscanf(buf, "%s", uidl) != 1)
480
                                continue;
481
                        else
482
                                recv_time = now;
483
                }
484
                if (recv_time == RECV_TIME_NONE)
485
                        recv_time = RECV_TIME_RECEIVED;
486
                g_hash_table_insert(table, g_strdup(uidl),
487
                                    GINT_TO_POINTER(recv_time));
488
        }
489

    
490
        fclose(fp);
491
        return table;
492
}
493

    
494
gint pop3_write_uidl_list(Pop3Session *session)
495
{
496
        gchar *path;
497
        FILE *fp;
498
        Pop3MsgInfo *msg;
499
        gint n;
500

    
501
        if (!session->uidl_is_valid) return 0;
502

    
503
        path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
504
                           "uidl", G_DIR_SEPARATOR_S,
505
                           session->ac_prefs->recv_server,
506
                           "-", session->ac_prefs->userid, NULL);
507
        if ((fp = fopen(path, "wb")) == NULL) {
508
                FILE_OP_ERROR(path, "fopen");
509
                g_free(path);
510
                return -1;
511
        }
512

    
513
        for (n = 1; n <= session->count; n++) {
514
                msg = &session->msg[n];
515
                if (msg->uidl && msg->received && !msg->deleted)
516
                        fprintf(fp, "%s\t%ld\n", msg->uidl, msg->recv_time);
517
        }
518

    
519
        if (fclose(fp) == EOF) FILE_OP_ERROR(path, "fclose");
520
        g_free(path);
521

    
522
        return 0;
523
}
524

    
525
static gint pop3_write_msg_to_file(const gchar *file, const gchar *data,
526
                                   guint len)
527
{
528
        FILE *fp;
529
        const gchar *prev, *cur;
530

    
531
        g_return_val_if_fail(file != NULL, -1);
532

    
533
        if ((fp = fopen(file, "wb")) == NULL) {
534
                FILE_OP_ERROR(file, "fopen");
535
                return -1;
536
        }
537

    
538
        if (change_file_mode_rw(fp, file) < 0)
539
                FILE_OP_ERROR(file, "chmod");
540

    
541
        /* +------------------+----------------+--------------------------+ *
542
         * ^data              ^prev            ^cur             data+len-1^ */
543

    
544
        prev = data;
545
        while ((cur = (gchar *)my_memmem(prev, len - (prev - data), "\r\n", 2))
546
               != NULL) {
547
                if ((cur > prev && fwrite(prev, cur - prev, 1, fp) < 1) ||
548
                    fputc('\n', fp) == EOF) {
549
                        FILE_OP_ERROR(file, "fwrite");
550
                        g_warning("can't write to file: %s\n", file);
551
                        fclose(fp);
552
                        unlink(file);
553
                        return -1;
554
                }
555

    
556
                if (cur == data + len - 1) {
557
                        prev = cur + 1;
558
                        break;
559
                }
560

    
561
                if (*(cur + 1) == '\n')
562
                        prev = cur + 2;
563
                else
564
                        prev = cur + 1;
565

    
566
                if (prev - data < len - 1 && *prev == '.' && *(prev + 1) == '.')
567
                        prev++;
568

    
569
                if (prev - data >= len)
570
                        break;
571
        }
572

    
573
        if (prev - data < len &&
574
            fwrite(prev, len - (prev - data), 1, fp) < 1) {
575
                FILE_OP_ERROR(file, "fwrite");
576
                g_warning("can't write to file: %s\n", file);
577
                fclose(fp);
578
                unlink(file);
579
                return -1;
580
        }
581
        if (data[len - 1] != '\r' && data[len - 1] != '\n') {
582
                if (fputc('\n', fp) == EOF) {
583
                        FILE_OP_ERROR(file, "fputc");
584
                        g_warning("can't write to file: %s\n", file);
585
                        fclose(fp);
586
                        unlink(file);
587
                        return -1;
588
                }
589
        }
590

    
591
        if (fclose(fp) == EOF) {
592
                FILE_OP_ERROR(file, "fclose");
593
                unlink(file);
594
                return -1;
595
        }
596

    
597
        return 0;
598
}
599

    
600
static Pop3State pop3_lookup_next(Pop3Session *session)
601
{
602
        Pop3MsgInfo *msg;
603
        PrefsAccount *ac = session->ac_prefs;
604
        gint size;
605
        gboolean size_limit_over;
606

    
607
        for (;;) {
608
                msg = &session->msg[session->cur_msg];
609
                size = msg->size;
610
                size_limit_over =
611
                    (ac->enable_size_limit &&
612
                     ac->size_limit > 0 &&
613
                     size > ac->size_limit * 1024);
614

    
615
                if (msg->recv_time == RECV_TIME_DELETE ||
616
                    (ac->rmmail &&
617
                     msg->recv_time != RECV_TIME_NONE &&
618
                     msg->recv_time != RECV_TIME_KEEP &&
619
                     session->current_time - msg->recv_time >=
620
                     ac->msg_leave_time * 24 * 60 * 60)) {
621
                        log_print(_("POP3: Deleting expired message %d\n"),
622
                                  session->cur_msg);
623
                        pop3_delete_send(session);
624
                        return POP3_DELETE;
625
                }
626

    
627
                if (size_limit_over)
628
                        log_print
629
                                (_("POP3: Skipping message %d (%d bytes)\n"),
630
                                  session->cur_msg, size);
631

    
632
                if (size == 0 || msg->received || size_limit_over) {
633
                        session->cur_total_bytes += size;
634
                        if (session->cur_msg == session->count) {
635
                                pop3_logout_send(session);
636
                                return POP3_LOGOUT;
637
                        } else
638
                                session->cur_msg++;
639
                } else
640
                        break;
641
        }
642

    
643
        pop3_retr_send(session);
644
        return POP3_RETR;
645
}
646

    
647
static Pop3ErrorValue pop3_ok(Pop3Session *session, const gchar *msg)
648
{
649
        Pop3ErrorValue ok;
650

    
651
        log_print("POP3< %s\n", msg);
652

    
653
        if (!strncmp(msg, "+OK", 3))
654
                ok = PS_SUCCESS;
655
        else if (!strncmp(msg, "-ERR", 4)) {
656
                if (strstr(msg + 4, "lock") ||
657
                    strstr(msg + 4, "Lock") ||
658
                    strstr(msg + 4, "LOCK") ||
659
                    strstr(msg + 4, "wait")) {
660
                        log_warning(_("mailbox is locked\n"));
661
                        ok = PS_LOCKBUSY;
662
                } else if (strcasestr(msg + 4, "timeout")) {
663
                        log_warning(_("session timeout\n"));
664
                        ok = PS_ERROR;
665
                } else {
666
                        switch (session->state) {
667
#if USE_SSL
668
                        case POP3_STLS:
669
                                log_warning(_("can't start TLS session\n"));
670
                                ok = PS_ERROR;
671
                                break;
672
#endif
673
                        case POP3_GETAUTH_USER:
674
                        case POP3_GETAUTH_PASS:
675
                        case POP3_GETAUTH_APOP:
676
                                log_warning(_("error occurred on authentication\n"));
677
                                ok = PS_AUTHFAIL;
678
                                break;
679
                        case POP3_GETRANGE_LAST:
680
                        case POP3_GETRANGE_UIDL:
681
                                log_warning(_("command not supported\n"));
682
                                ok = PS_NOTSUPPORTED;
683
                                break;
684
                        default:
685
                                log_warning(_("error occurred on POP3 session\n"));
686
                                ok = PS_ERROR;
687
                        }
688
                }
689

    
690
                g_free(session->error_msg);
691
                session->error_msg = g_strdup(msg);
692
                fprintf(stderr, "POP3: %s\n", msg);
693
        } else
694
                ok = PS_PROTOCOL;
695

    
696
        session->error_val = ok;
697
        return ok;
698
}
699

    
700
static gint pop3_session_recv_msg(Session *session, const gchar *msg)
701
{
702
        Pop3Session *pop3_session = POP3_SESSION(session);
703
        Pop3ErrorValue val = PS_SUCCESS;
704
        const guchar *body;
705

    
706
        body = msg;
707
        if (pop3_session->state != POP3_GETRANGE_UIDL_RECV &&
708
            pop3_session->state != POP3_GETSIZE_LIST_RECV) {
709
                val = pop3_ok(pop3_session, msg);
710
                if (val != PS_SUCCESS) {
711
                        if (val != PS_NOTSUPPORTED) {
712
                                pop3_session->state = POP3_ERROR;
713
                                return -1;
714
                        }
715
                }
716

    
717
                if (*body == '+' || *body == '-')
718
                        body++;
719
                while (isalpha(*body))
720
                        body++;
721
                while (isspace(*body))
722
                        body++;
723
        }
724

    
725
        switch (pop3_session->state) {
726
        case POP3_READY:
727
        case POP3_GREETING:
728
                pop3_greeting_recv(pop3_session, body);
729
#if USE_SSL
730
                if (pop3_session->ac_prefs->ssl_pop == SSL_STARTTLS)
731
                        pop3_stls_send(pop3_session);
732
                else
733
#endif
734
                if (pop3_session->ac_prefs->use_apop_auth)
735
                        pop3_getauth_apop_send(pop3_session);
736
                else
737
                        pop3_getauth_user_send(pop3_session);
738
                break;
739
#if USE_SSL
740
        case POP3_STLS:
741
                if (pop3_stls_recv(pop3_session) != PS_SUCCESS)
742
                        return -1;
743
                if (pop3_session->ac_prefs->use_apop_auth)
744
                        pop3_getauth_apop_send(pop3_session);
745
                else
746
                        pop3_getauth_user_send(pop3_session);
747
                break;
748
#endif
749
        case POP3_GETAUTH_USER:
750
                pop3_getauth_pass_send(pop3_session);
751
                break;
752
        case POP3_GETAUTH_PASS:
753
        case POP3_GETAUTH_APOP:
754
                pop3_getrange_stat_send(pop3_session);
755
                break;
756
        case POP3_GETRANGE_STAT:
757
                if (pop3_getrange_stat_recv(pop3_session, body) < 0)
758
                        return -1;
759
                if (pop3_session->count > 0)
760
                        pop3_getrange_uidl_send(pop3_session);
761
                else
762
                        pop3_logout_send(pop3_session);
763
                break;
764
        case POP3_GETRANGE_LAST:
765
                if (val == PS_NOTSUPPORTED)
766
                        pop3_session->error_val = PS_SUCCESS;
767
                else if (pop3_getrange_last_recv(pop3_session, body) < 0)
768
                        return -1;
769
                if (pop3_session->cur_msg > 0)
770
                        pop3_getsize_list_send(pop3_session);
771
                else
772
                        pop3_logout_send(pop3_session);
773
                break;
774
        case POP3_GETRANGE_UIDL:
775
                if (val == PS_NOTSUPPORTED) {
776
                        pop3_session->error_val = PS_SUCCESS;
777
                        pop3_getrange_last_send(pop3_session);
778
                } else {
779
                        pop3_session->state = POP3_GETRANGE_UIDL_RECV;
780
                        session_recv_data(session, 0, ".\r\n");
781
                }
782
                break;
783
        case POP3_GETSIZE_LIST:
784
                pop3_session->state = POP3_GETSIZE_LIST_RECV;
785
                session_recv_data(session, 0, ".\r\n");
786
                break;
787
        case POP3_RETR:
788
                pop3_session->state = POP3_RETR_RECV;
789
                session_recv_data(session, 0, ".\r\n");
790
                break;
791
        case POP3_DELETE:
792
                pop3_delete_recv(pop3_session);
793
                if (pop3_session->cur_msg == pop3_session->count)
794
                        pop3_logout_send(pop3_session);
795
                else {
796
                        pop3_session->cur_msg++;
797
                        if (pop3_lookup_next(pop3_session) == POP3_ERROR)
798
                                return -1;
799
                }
800
                break;
801
        case POP3_LOGOUT:
802
                session_disconnect(session);
803
                break;
804
        case POP3_ERROR:
805
        default:
806
                return -1;
807
        }
808

    
809
        return 0;
810
}
811

    
812
static gint pop3_session_recv_data_finished(Session *session, guchar *data,
813
                                            guint len)
814
{
815
        Pop3Session *pop3_session = POP3_SESSION(session);
816
        Pop3ErrorValue val = PS_SUCCESS;
817

    
818
        switch (pop3_session->state) {
819
        case POP3_GETRANGE_UIDL_RECV:
820
                val = pop3_getrange_uidl_recv(pop3_session, data, len);
821
                if (val == PS_SUCCESS) {
822
                        if (pop3_session->new_msg_exist)
823
                                pop3_getsize_list_send(pop3_session);
824
                        else
825
                                pop3_logout_send(pop3_session);
826
                } else
827
                        return -1;
828
                break;
829
        case POP3_GETSIZE_LIST_RECV:
830
                val = pop3_getsize_list_recv(pop3_session, data, len);
831
                if (val == PS_SUCCESS) {
832
                        if (pop3_lookup_next(pop3_session) == POP3_ERROR)
833
                                return -1;
834
                } else
835
                        return -1;
836
                break;
837
        case POP3_RETR_RECV:
838
                if (pop3_retr_recv(pop3_session, data, len) < 0)
839
                        return -1;
840

    
841
                if (pop3_session->msg[pop3_session->cur_msg].recv_time
842
                    == RECV_TIME_DELETE ||
843
                    (pop3_session->ac_prefs->rmmail &&
844
                     pop3_session->ac_prefs->msg_leave_time == 0 &&
845
                     pop3_session->msg[pop3_session->cur_msg].recv_time
846
                     != RECV_TIME_KEEP))
847
                        pop3_delete_send(pop3_session);
848
                else if (pop3_session->cur_msg == pop3_session->count)
849
                        pop3_logout_send(pop3_session);
850
                else {
851
                        pop3_session->cur_msg++;
852
                        if (pop3_lookup_next(pop3_session) == POP3_ERROR)
853
                                return -1;
854
                }
855
                break;
856
        case POP3_ERROR:
857
        default:
858
                return -1;
859
        }
860

    
861
        return 0;
862
}