2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2012 Hiroyuki Yamamoto and the Claws Mail team
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 3 of the License, or
8 * (at your option) any later version.
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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "claws-features.h"
26 #include <glib/gi18n.h>
37 #include "prefs_account.h"
40 #include "partial_download.h"
43 #include "file-utils.h"
45 static gint pop3_greeting_recv (Pop3Session *session,
47 static gint pop3_getauth_user_send (Pop3Session *session);
48 static gint pop3_getauth_pass_send (Pop3Session *session);
49 static gint pop3_getauth_apop_send (Pop3Session *session);
51 static gint pop3_stls_send (Pop3Session *session);
52 static gint pop3_stls_recv (Pop3Session *session);
54 static gint pop3_getrange_stat_send (Pop3Session *session);
55 static gint pop3_getrange_stat_recv (Pop3Session *session,
57 static gint pop3_getrange_last_send (Pop3Session *session);
58 static gint pop3_getrange_last_recv (Pop3Session *session,
60 static gint pop3_getrange_uidl_send (Pop3Session *session);
61 static gint pop3_getrange_uidl_recv (Pop3Session *session,
64 static gint pop3_getsize_list_send (Pop3Session *session);
65 static gint pop3_getsize_list_recv (Pop3Session *session,
68 static gint pop3_retr_send (Pop3Session *session);
69 static gint pop3_retr_recv (Pop3Session *session,
72 static gint pop3_delete_send (Pop3Session *session);
73 static gint pop3_delete_recv (Pop3Session *session);
74 static gint pop3_logout_send (Pop3Session *session);
76 static void pop3_gen_send (Pop3Session *session,
77 const gchar *format, ...);
79 static void pop3_session_destroy (Session *session);
81 static gint pop3_write_msg_to_file (const gchar *file,
86 static Pop3State pop3_lookup_next (Pop3Session *session);
87 static Pop3ErrorValue pop3_ok (Pop3Session *session,
90 static gint pop3_session_recv_msg (Session *session,
92 static gint pop3_session_recv_data_finished (Session *session,
95 static void pop3_get_uidl_table(PrefsAccount *ac_prefs, Pop3Session *session);
97 static gint pop3_greeting_recv(Pop3Session *session, const gchar *msg)
99 session->state = POP3_GREETING;
101 session->greeting = g_strdup(msg);
106 static gint pop3_stls_send(Pop3Session *session)
108 session->state = POP3_STLS;
109 pop3_gen_send(session, "STLS");
113 static gint pop3_stls_recv(Pop3Session *session)
115 if (session_start_tls(SESSION(session)) < 0) {
116 session->error_val = PS_SOCKET;
121 #endif /* USE_GNUTLS */
123 static gint pop3_getauth_user_send(Pop3Session *session)
125 cm_return_val_if_fail(session->user != NULL, -1);
127 session->state = POP3_GETAUTH_USER;
128 pop3_gen_send(session, "USER %s", session->user);
132 static gint pop3_getauth_pass_send(Pop3Session *session)
134 cm_return_val_if_fail(session->pass != NULL, -1);
136 session->state = POP3_GETAUTH_PASS;
137 pop3_gen_send(session, "PASS %s", session->pass);
141 static gint pop3_getauth_apop_send(Pop3Session *session)
147 cm_return_val_if_fail(session->user != NULL, -1);
148 cm_return_val_if_fail(session->pass != NULL, -1);
150 session->state = POP3_GETAUTH_APOP;
152 if ((start = strchr(session->greeting, '<')) == NULL) {
153 log_error(LOG_PROTOCOL, _("Required APOP timestamp not found "
155 session->error_val = PS_PROTOCOL;
159 if ((end = strchr(start, '>')) == NULL || end == start + 1) {
160 log_error(LOG_PROTOCOL, _("Timestamp syntax error in greeting\n"));
161 session->error_val = PS_PROTOCOL;
166 if (!is_ascii_str(start)) {
167 log_error(LOG_PROTOCOL, _("Timestamp syntax error in greeting (not ASCII)\n"));
168 session->error_val = PS_PROTOCOL;
172 apop_str = g_strconcat(start, session->pass, NULL);
173 md5_hex_digest(md5sum, apop_str);
176 pop3_gen_send(session, "APOP %s %s", session->user, md5sum);
181 static gint pop3_getrange_stat_send(Pop3Session *session)
183 session->state = POP3_GETRANGE_STAT;
184 pop3_gen_send(session, "STAT");
188 static gint pop3_getrange_stat_recv(Pop3Session *session, const gchar *msg)
190 if (sscanf(msg, "%d %d", &session->count, &session->total_bytes) != 2) {
191 log_error(LOG_PROTOCOL, _("POP protocol error\n"));
192 session->error_val = PS_PROTOCOL;
195 if (session->count == 0) {
196 session->uidl_is_valid = TRUE;
198 session->msg = g_new0(Pop3MsgInfo, session->count + 1);
199 session->cur_msg = 1;
206 static gint pop3_getrange_last_send(Pop3Session *session)
208 session->state = POP3_GETRANGE_LAST;
209 pop3_gen_send(session, "LAST");
213 static gint pop3_getrange_last_recv(Pop3Session *session, const gchar *msg)
217 if (sscanf(msg, "%d", &last) == 0) {
218 log_warning(LOG_PROTOCOL, _("POP protocol error\n"));
219 session->error_val = PS_PROTOCOL;
222 if (session->count > last) {
223 session->new_msg_exist = TRUE;
224 session->cur_msg = last + 1;
226 session->cur_msg = 0;
232 static gint pop3_getrange_uidl_send(Pop3Session *session)
234 session->state = POP3_GETRANGE_UIDL;
235 pop3_gen_send(session, "UIDL");
239 static gint pop3_getrange_uidl_recv(Pop3Session *session, const gchar *data,
243 gchar buf[POPBUFSIZE];
248 const gchar *p = data;
249 const gchar *lastp = data + len;
250 const gchar *newline;
253 if ((newline = memchr(p, '\r', lastp - p)) == NULL)
255 buf_len = MIN(newline - p, sizeof(buf) - 1);
256 memcpy(buf, p, buf_len);
260 if (p < lastp && *p == '\n') p++;
262 if (sscanf(buf, "%d %" Xstr(IDLEN) "s", &num, id) != 2 ||
263 num <= 0 || num > session->count) {
264 log_warning(LOG_PROTOCOL, _("invalid UIDL response: %s\n"), buf);
268 session->msg[num].uidl = g_strdup(id);
270 recv_time = (time_t)(GPOINTER_TO_INT(g_hash_table_lookup(
271 session->uidl_table, id)));
272 session->msg[num].recv_time = recv_time;
274 if (recv_time != RECV_TIME_NONE) {
275 debug_print("num %d uidl %s: already got it\n", num, id);
277 debug_print("num %d uidl %s: unknown\n", num, id);
280 partial_recv = (gint)(GPOINTER_TO_INT(g_hash_table_lookup(
281 session->partial_recv_table, id)));
283 if (recv_time != RECV_TIME_NONE
284 || partial_recv != POP3_TOTALLY_RECEIVED) {
285 session->msg[num].received =
286 (partial_recv != POP3_MUST_COMPLETE_RECV);
287 session->msg[num].partial_recv = partial_recv;
288 if (partial_recv == POP3_MUST_COMPLETE_RECV)
289 session->new_msg_exist = TRUE;
291 if (!session->new_msg_exist &&
292 (recv_time == RECV_TIME_NONE ||
293 session->ac_prefs->rmmail)) {
294 session->cur_msg = num;
295 session->new_msg_exist = TRUE;
299 session->uidl_is_valid = TRUE;
303 static gint pop3_getsize_list_send(Pop3Session *session)
305 session->state = POP3_GETSIZE_LIST;
306 pop3_gen_send(session, "LIST");
310 static gint pop3_getsize_list_recv(Pop3Session *session, const gchar *data,
313 gchar buf[POPBUFSIZE];
316 const gchar *p = data;
317 const gchar *lastp = data + len;
318 const gchar *newline;
321 if ((newline = memchr(p, '\r', lastp - p)) == NULL)
323 buf_len = MIN(newline - p, sizeof(buf) - 1);
324 memcpy(buf, p, buf_len);
328 if (p < lastp && *p == '\n') p++;
330 if (sscanf(buf, "%u %u", &num, &size) != 2) {
331 session->error_val = PS_PROTOCOL;
335 if (num > 0 && num <= session->count)
336 session->msg[num].size = size;
337 if (num > 0 && num < session->cur_msg)
338 session->cur_total_bytes += size;
344 static gint pop3_retr_send(Pop3Session *session)
346 session->state = POP3_RETR;
347 debug_print("retrieving %d [%s]\n", session->cur_msg,
348 session->msg[session->cur_msg].uidl ?
349 session->msg[session->cur_msg].uidl:" ");
350 pop3_gen_send(session, "RETR %d", session->cur_msg);
354 static gint pop3_retr_recv(Pop3Session *session, const gchar *data, guint len)
358 MailReceiveData mail_receive_data;
360 /* NOTE: we allocate a slightly larger buffer with a zero terminator
361 * because some plugins may think that it has a C string. */
362 mail_receive_data.session = session;
363 mail_receive_data.data = g_new0(gchar, len + 1);
364 mail_receive_data.data_len = len;
365 memcpy(mail_receive_data.data, data, len);
367 hooks_invoke(MAIL_RECEIVE_HOOKLIST, &mail_receive_data);
369 file = get_tmp_file();
370 if (pop3_write_msg_to_file(file, mail_receive_data.data,
371 mail_receive_data.data_len, NULL) < 0) {
373 g_free(mail_receive_data.data);
374 session->error_val = PS_IOERR;
377 g_free(mail_receive_data.data);
379 if (session->msg[session->cur_msg].partial_recv
380 == POP3_MUST_COMPLETE_RECV) {
381 gchar *old_file = partial_get_filename(
382 session->ac_prefs->recv_server,
383 session->ac_prefs->userid,
384 session->msg[session->cur_msg].uidl);
387 partial_delete_old(old_file);
392 /* drop_ok: 0: success 1: don't receive -1: error */
393 drop_ok = session->drop_message(session, file);
397 session->error_val = PS_IOERR;
401 session->cur_total_bytes += session->msg[session->cur_msg].size;
402 session->cur_total_recv_bytes += session->msg[session->cur_msg].size;
403 session->cur_total_num++;
405 session->msg[session->cur_msg].received = TRUE;
406 session->msg[session->cur_msg].partial_recv = POP3_TOTALLY_RECEIVED;
408 session->msg[session->cur_msg].recv_time =
409 drop_ok == 1 ? RECV_TIME_KEEP : session->current_time;
414 static gint pop3_top_send(Pop3Session *session, gint max_size)
416 gint num_lines = (max_size*1024)/82; /* consider lines to be 80 chars */
417 session->state = POP3_TOP;
418 pop3_gen_send(session, "TOP %d %d", session->cur_msg, num_lines);
422 static gint pop3_top_recv(Pop3Session *session, const gchar *data, guint len)
426 MailReceiveData mail_receive_data;
427 gchar *partial_notice = NULL;
429 /* NOTE: we allocate a slightly larger buffer with a zero terminator
430 * because some plugins may think that it has a C string. */
431 mail_receive_data.session = session;
432 mail_receive_data.data = g_new0(gchar, len + 1);
433 mail_receive_data.data_len = len;
434 memcpy(mail_receive_data.data, data, len);
436 hooks_invoke(MAIL_RECEIVE_HOOKLIST, &mail_receive_data);
438 partial_notice = g_strdup_printf("SC-Marked-For-Download: 0\n"
439 "SC-Partially-Retrieved: %s\n"
440 "SC-Account-Server: %s\n"
441 "SC-Account-Login: %s\n"
442 "SC-Message-Size: %d",
443 session->msg[session->cur_msg].uidl,
444 session->ac_prefs->recv_server,
445 session->ac_prefs->userid,
446 session->msg[session->cur_msg].size);
447 file = get_tmp_file();
448 if (pop3_write_msg_to_file(file, mail_receive_data.data,
449 mail_receive_data.data_len,
450 partial_notice) < 0) {
452 g_free(mail_receive_data.data);
453 session->error_val = PS_IOERR;
454 g_free(partial_notice);
457 g_free(mail_receive_data.data);
458 g_free(partial_notice);
460 /* drop_ok: 0: success 1: don't receive -1: error */
461 drop_ok = session->drop_message(session, file);
464 session->error_val = PS_IOERR;
468 session->cur_total_bytes += session->msg[session->cur_msg].size;
469 session->cur_total_recv_bytes += session->msg[session->cur_msg].size;
470 session->cur_total_num++;
472 session->msg[session->cur_msg].received = TRUE;
473 session->msg[session->cur_msg].partial_recv = POP3_PARTIALLY_RECEIVED;
474 session->msg[session->cur_msg].recv_time =
475 drop_ok == 1 ? RECV_TIME_KEEP : session->current_time;
480 static gint pop3_delete_send(Pop3Session *session)
482 session->state = POP3_DELETE;
483 pop3_gen_send(session, "DELE %d", session->cur_msg);
487 static gint pop3_delete_recv(Pop3Session *session)
489 session->msg[session->cur_msg].deleted = TRUE;
493 static gint pop3_logout_send(Pop3Session *session)
495 session->state = POP3_LOGOUT;
496 pop3_gen_send(session, "QUIT");
500 static void pop3_gen_send(Pop3Session *session, const gchar *format, ...)
502 gchar buf[POPBUFSIZE + 1];
505 va_start(args, format);
506 g_vsnprintf(buf, sizeof(buf) - 2, format, args);
509 if (!g_ascii_strncasecmp(buf, "PASS ", 5))
510 log_print(LOG_PROTOCOL, "POP> PASS ********\n");
512 log_print(LOG_PROTOCOL, "POP> %s\n", buf);
514 session_send_msg(SESSION(session), buf);
517 Session *pop3_session_new(PrefsAccount *account)
519 Pop3Session *session;
521 cm_return_val_if_fail(account != NULL, NULL);
523 account->receive_in_progress = TRUE;
525 session = g_new0(Pop3Session, 1);
527 session_init(SESSION(session), account, FALSE);
529 SESSION(session)->type = SESSION_POP3;
531 SESSION(session)->recv_msg = pop3_session_recv_msg;
532 SESSION(session)->recv_data_finished = pop3_session_recv_data_finished;
533 SESSION(session)->send_data_finished = NULL;
534 SESSION(session)->ssl_cert_auto_accept = account->ssl_certs_auto_accept;
535 SESSION(session)->destroy = pop3_session_destroy;
538 if (account->set_gnutls_priority && account->gnutls_priority &&
539 strlen(account->gnutls_priority) != 0)
540 SESSION(session)->gnutls_priority = g_strdup(account->gnutls_priority);
543 session->state = POP3_READY;
544 session->ac_prefs = account;
545 session->pop_before_smtp = FALSE;
546 pop3_get_uidl_table(account, session);
547 session->current_time = time(NULL);
548 session->error_val = PS_SUCCESS;
549 session->error_msg = NULL;
551 return SESSION(session);
554 static void pop3_session_destroy(Session *session)
556 Pop3Session *pop3_session = POP3_SESSION(session);
559 cm_return_if_fail(session != NULL);
561 for (n = 1; n <= pop3_session->count; n++)
562 g_free(pop3_session->msg[n].uidl);
563 g_free(pop3_session->msg);
565 if (pop3_session->uidl_table) {
566 hash_free_strings(pop3_session->uidl_table);
567 g_hash_table_destroy(pop3_session->uidl_table);
570 if (pop3_session->partial_recv_table) {
571 hash_free_strings(pop3_session->partial_recv_table);
572 g_hash_table_destroy(pop3_session->partial_recv_table);
575 g_free(pop3_session->greeting);
576 g_free(pop3_session->user);
577 g_free(pop3_session->pass);
578 g_free(pop3_session->error_msg);
580 pop3_session->ac_prefs->receive_in_progress = FALSE;
583 static void pop3_get_uidl_table(PrefsAccount *ac_prefs, Pop3Session *session)
586 GHashTable *partial_recv_table;
589 gchar buf[POPBUFSIZE];
590 gchar uidl[POPBUFSIZE];
594 gchar *sanitized_uid = g_strdup(ac_prefs->userid);
596 subst_for_filename(sanitized_uid);
598 table = g_hash_table_new(g_str_hash, g_str_equal);
599 partial_recv_table = g_hash_table_new(g_str_hash, g_str_equal);
601 path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
602 "uidl", G_DIR_SEPARATOR_S, ac_prefs->recv_server,
603 "-", sanitized_uid, NULL);
605 g_free(sanitized_uid);
606 if ((fp = claws_fopen(path, "rb")) == NULL) {
607 if (ENOENT != errno) FILE_OP_ERROR(path, "claws_fopen");
609 path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
610 "uidl-", ac_prefs->recv_server,
611 "-", ac_prefs->userid, NULL);
612 if ((fp = claws_fopen(path, "rb")) == NULL) {
613 if (ENOENT != errno) FILE_OP_ERROR(path, "claws_fopen");
615 session->uidl_table = table;
616 session->partial_recv_table = partial_recv_table;
624 while (claws_fgets(buf, sizeof(buf), fp) != NULL) {
625 gchar tmp[POPBUFSIZE];
627 recv_time = RECV_TIME_NONE;
628 partial_recv = POP3_TOTALLY_RECEIVED;
630 if (sscanf(buf, "%s\t%ld\t%s", uidl, (long int *) &recv_time, tmp) < 3) {
631 if (sscanf(buf, "%s\t%ld", uidl, (long int *) &recv_time) != 2) {
632 if (sscanf(buf, "%s", uidl) != 1)
643 if (recv_time == RECV_TIME_NONE)
644 recv_time = RECV_TIME_RECEIVED;
645 g_hash_table_insert(table, g_strdup(uidl),
646 GINT_TO_POINTER(recv_time));
647 if (strlen(tmp) == 1)
648 partial_recv = atoi(tmp); /* totally received ?*/
650 partial_recv = POP3_MUST_COMPLETE_RECV;
652 g_hash_table_insert(partial_recv_table, g_strdup(uidl),
653 GINT_TO_POINTER(partial_recv));
657 session->uidl_table = table;
658 session->partial_recv_table = partial_recv_table;
666 g_warning("failed to write"); \
670 gint pop3_write_uidl_list(Pop3Session *session)
672 gchar *path, *tmp_path;
676 gchar *sanitized_uid = g_strdup(session->ac_prefs->userid);
678 subst_for_filename(sanitized_uid);
680 if (!session->uidl_is_valid) {
681 g_free(sanitized_uid);
685 path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
686 "uidl", G_DIR_SEPARATOR_S,
687 session->ac_prefs->recv_server,
688 "-", sanitized_uid, NULL);
689 tmp_path = g_strconcat(path, ".tmp", NULL);
691 g_free(sanitized_uid);
693 if ((fp = claws_fopen(tmp_path, "wb")) == NULL) {
694 FILE_OP_ERROR(tmp_path, "claws_fopen");
698 for (n = 1; n <= session->count; n++) {
699 msg = &session->msg[n];
700 if (msg->uidl && msg->received &&
701 (!msg->deleted || session->state != POP3_DONE))
702 TRY(fprintf(fp, "%s\t%ld\t%d\n",
703 msg->uidl, (long int)
709 if (claws_safe_fclose(fp) == EOF) {
710 FILE_OP_ERROR(tmp_path, "claws_fclose");
718 if (g_rename(tmp_path, path) < 0) {
719 FILE_OP_ERROR(path, "rename");
735 static gint pop3_write_msg_to_file(const gchar *file, const gchar *data,
736 guint len, const gchar *prefix)
739 const gchar *prev, *cur;
741 cm_return_val_if_fail(file != NULL, -1);
743 if ((fp = claws_fopen(file, "wb")) == NULL) {
744 FILE_OP_ERROR(file, "claws_fopen");
748 if (change_file_mode_rw(fp, file) < 0)
749 FILE_OP_ERROR(file, "chmod");
751 if (prefix != NULL) {
752 if (fprintf(fp, "%s\n", prefix) < 0) {
753 FILE_OP_ERROR(file, "fprintf");
760 /* +------------------+----------------+--------------------------+ *
761 * ^data ^prev ^cur data+len-1^ */
764 while ((cur = (gchar *)my_memmem(prev, len - (prev - data), "\r\n", 2))
766 if ((cur > prev && claws_fwrite(prev, 1, cur - prev, fp) < 1) ||
767 claws_fputc('\n', fp) == EOF) {
768 FILE_OP_ERROR(file, "claws_fwrite");
769 g_warning("can't write to file: %s", file);
775 if (cur == data + len - 1) {
780 if (*(cur + 1) == '\n')
785 if (prev - data < len - 1 && *prev == '.' && *(prev + 1) == '.')
788 if (prev - data >= len)
792 if (prev - data < len &&
793 claws_fwrite(prev, 1, len - (prev - data), fp) < 1) {
794 FILE_OP_ERROR(file, "claws_fwrite");
795 g_warning("can't write to file: %s", file);
800 if (data[len - 1] != '\r' && data[len - 1] != '\n') {
801 if (claws_fputc('\n', fp) == EOF) {
802 FILE_OP_ERROR(file, "claws_fputc");
803 g_warning("can't write to file: %s", file);
810 if (claws_safe_fclose(fp) == EOF) {
811 FILE_OP_ERROR(file, "claws_fclose");
819 static Pop3State pop3_lookup_next(Pop3Session *session)
822 PrefsAccount *ac = session->ac_prefs;
824 gboolean size_limit_over;
827 msg = &session->msg[session->cur_msg];
830 (ac->enable_size_limit &&
831 ac->size_limit > 0 &&
832 size > ac->size_limit * 1024);
835 msg->recv_time != RECV_TIME_NONE &&
836 msg->recv_time != RECV_TIME_KEEP &&
837 msg->partial_recv == POP3_TOTALLY_RECEIVED &&
838 session->current_time - msg->recv_time >=
839 ((ac->msg_leave_time * 24 * 60 * 60) +
840 (ac->msg_leave_hour * 60 * 60))) {
841 log_message(LOG_PROTOCOL,
842 _("POP: Deleting expired message %d [%s]\n"),
843 session->cur_msg, msg->uidl?msg->uidl:" ");
844 session->cur_total_bytes += size;
845 pop3_delete_send(session);
849 if (size_limit_over) {
850 if (!msg->received && msg->partial_recv !=
851 POP3_MUST_COMPLETE_RECV) {
852 pop3_top_send(session, ac->size_limit);
854 } else if (msg->partial_recv == POP3_MUST_COMPLETE_RECV)
857 log_message(LOG_PROTOCOL,
858 _("POP: Skipping message %d [%s] (%d bytes)\n"),
859 session->cur_msg, msg->uidl?msg->uidl:" ", size);
862 if (size == 0 || msg->received || size_limit_over) {
863 session->cur_total_bytes += size;
864 if (session->cur_msg == session->count) {
865 pop3_logout_send(session);
873 pop3_retr_send(session);
877 static Pop3ErrorValue pop3_ok(Pop3Session *session, const gchar *msg)
881 log_print(LOG_PROTOCOL, "POP< %s\n", msg);
883 if (!strncmp(msg, "+OK", 3))
885 else if (!strncmp(msg, "-ERR", 4)) {
886 if (strstr(msg + 4, "lock") ||
887 strstr(msg + 4, "Lock") ||
888 strstr(msg + 4, "LOCK") ||
889 strstr(msg + 4, "wait")) {
890 log_error(LOG_PROTOCOL, _("mailbox is locked\n"));
892 } else if (strcasestr(msg + 4, "timeout")) {
893 log_error(LOG_PROTOCOL, _("Session timeout\n"));
896 switch (session->state) {
899 log_error(LOG_PROTOCOL, _("couldn't start STARTTLS session\n"));
903 case POP3_GETAUTH_USER:
904 case POP3_GETAUTH_PASS:
905 case POP3_GETAUTH_APOP:
906 log_error(LOG_PROTOCOL, _("error occurred on authentication\n"));
909 case POP3_GETRANGE_LAST:
910 case POP3_GETRANGE_UIDL:
912 log_warning(LOG_PROTOCOL, _("command not supported\n"));
913 ok = PS_NOTSUPPORTED;
917 log_error(LOG_PROTOCOL, _("error occurred on POP session\n"));
922 g_free(session->error_msg);
923 session->error_msg = g_strdup(msg);
924 g_printerr("POP: %s\n", msg);
928 session->error_val = ok;
932 static gint pop3_session_recv_msg(Session *session, const gchar *msg)
934 Pop3Session *pop3_session = POP3_SESSION(session);
935 Pop3ErrorValue val = PS_SUCCESS;
939 if (pop3_session->state != POP3_GETRANGE_UIDL_RECV &&
940 pop3_session->state != POP3_GETSIZE_LIST_RECV) {
941 val = pop3_ok(pop3_session, msg);
942 if (val != PS_SUCCESS) {
943 if (val != PS_NOTSUPPORTED) {
944 pop3_session->state = POP3_ERROR;
949 if (*body == '+' || *body == '-')
951 while (g_ascii_isalpha(*body))
953 while (g_ascii_isspace(*body))
957 switch (pop3_session->state) {
960 pop3_greeting_recv(pop3_session, body);
962 if (pop3_session->ac_prefs->ssl_pop == SSL_STARTTLS)
963 val = pop3_stls_send(pop3_session);
966 if (pop3_session->ac_prefs->use_apop_auth)
967 val = pop3_getauth_apop_send(pop3_session);
969 val = pop3_getauth_user_send(pop3_session);
973 if (pop3_stls_recv(pop3_session) != PS_SUCCESS)
975 if (pop3_session->ac_prefs->use_apop_auth)
976 val = pop3_getauth_apop_send(pop3_session);
978 val = pop3_getauth_user_send(pop3_session);
981 case POP3_GETAUTH_USER:
982 val = pop3_getauth_pass_send(pop3_session);
984 case POP3_GETAUTH_PASS:
985 case POP3_GETAUTH_APOP:
986 if (!pop3_session->pop_before_smtp)
987 val = pop3_getrange_stat_send(pop3_session);
989 val = pop3_logout_send(pop3_session);
991 case POP3_GETRANGE_STAT:
992 if (pop3_getrange_stat_recv(pop3_session, body) < 0)
994 if (pop3_session->count > 0)
995 val = pop3_getrange_uidl_send(pop3_session);
997 val = pop3_logout_send(pop3_session);
999 case POP3_GETRANGE_LAST:
1000 if (val == PS_NOTSUPPORTED)
1001 pop3_session->error_val = PS_SUCCESS;
1002 else if (pop3_getrange_last_recv(pop3_session, body) < 0)
1004 if (pop3_session->cur_msg > 0)
1005 val = pop3_getsize_list_send(pop3_session);
1007 val = pop3_logout_send(pop3_session);
1009 case POP3_GETRANGE_UIDL:
1010 if (val == PS_NOTSUPPORTED) {
1011 pop3_session->error_val = PS_SUCCESS;
1012 val = pop3_getrange_last_send(pop3_session);
1014 pop3_session->state = POP3_GETRANGE_UIDL_RECV;
1015 session_recv_data(session, 0, ".\r\n");
1018 case POP3_GETSIZE_LIST:
1019 pop3_session->state = POP3_GETSIZE_LIST_RECV;
1020 session_recv_data(session, 0, ".\r\n");
1023 pop3_session->state = POP3_RETR_RECV;
1024 session_recv_data(session, 0, ".\r\n");
1027 if (val == PS_NOTSUPPORTED) {
1028 pop3_session->error_val = PS_SUCCESS;
1030 pop3_session->state = POP3_TOP_RECV;
1031 session_recv_data(session, 0, ".\r\n");
1035 pop3_delete_recv(pop3_session);
1036 if (pop3_session->cur_msg == pop3_session->count)
1037 val = pop3_logout_send(pop3_session);
1039 pop3_session->cur_msg++;
1040 if (pop3_lookup_next(pop3_session) == POP3_ERROR)
1045 pop3_session->state = POP3_DONE;
1046 session_disconnect(session);
1053 return val == PS_SUCCESS?0:-1;
1056 static gint pop3_session_recv_data_finished(Session *session, guchar *data,
1059 Pop3Session *pop3_session = POP3_SESSION(session);
1060 Pop3ErrorValue val = PS_SUCCESS;
1062 switch (pop3_session->state) {
1063 case POP3_GETRANGE_UIDL_RECV:
1064 val = pop3_getrange_uidl_recv(pop3_session, data, len);
1065 if (val == PS_SUCCESS) {
1066 if (pop3_session->new_msg_exist)
1067 pop3_getsize_list_send(pop3_session);
1069 pop3_logout_send(pop3_session);
1073 case POP3_GETSIZE_LIST_RECV:
1074 val = pop3_getsize_list_recv(pop3_session, data, len);
1075 if (val == PS_SUCCESS) {
1076 if (pop3_lookup_next(pop3_session) == POP3_ERROR)
1081 case POP3_RETR_RECV:
1082 if (pop3_retr_recv(pop3_session, data, len) < 0)
1085 if (pop3_session->ac_prefs->rmmail &&
1086 pop3_session->ac_prefs->msg_leave_time == 0 &&
1087 pop3_session->ac_prefs->msg_leave_hour == 0 &&
1088 pop3_session->msg[pop3_session->cur_msg].recv_time
1090 pop3_delete_send(pop3_session);
1091 else if (pop3_session->cur_msg == pop3_session->count)
1092 pop3_logout_send(pop3_session);
1094 pop3_session->cur_msg++;
1095 if (pop3_lookup_next(pop3_session) == POP3_ERROR)
1100 if (pop3_top_recv(pop3_session, data, len) < 0)
1103 if (pop3_session->cur_msg == pop3_session->count)
1104 pop3_logout_send(pop3_session);
1106 pop3_session->cur_msg++;
1107 if (pop3_lookup_next(pop3_session) == POP3_ERROR)
1112 log_warning(LOG_PROTOCOL, _("TOP command unsupported\n"));
1113 if (pop3_session->cur_msg == pop3_session->count)
1114 pop3_logout_send(pop3_session);
1116 pop3_session->cur_msg++;
1117 if (pop3_lookup_next(pop3_session) == POP3_ERROR)