Statistics
| Revision:

root / libsylph / pop.c @ 895

History | View | Annotate | Download (20.8 kB)

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