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);
541 SESSION(session)->use_tls_sni = account->use_tls_sni;
544 session->state = POP3_READY;
545 session->ac_prefs = account;
546 session->pop_before_smtp = FALSE;
547 pop3_get_uidl_table(account, session);
548 session->current_time = time(NULL);
549 session->error_val = PS_SUCCESS;
550 session->error_msg = NULL;
552 return SESSION(session);
555 static void pop3_session_destroy(Session *session)
557 Pop3Session *pop3_session = POP3_SESSION(session);
560 cm_return_if_fail(session != NULL);
562 for (n = 1; n <= pop3_session->count; n++)
563 g_free(pop3_session->msg[n].uidl);
564 g_free(pop3_session->msg);
566 if (pop3_session->uidl_table) {
567 hash_free_strings(pop3_session->uidl_table);
568 g_hash_table_destroy(pop3_session->uidl_table);
571 if (pop3_session->partial_recv_table) {
572 hash_free_strings(pop3_session->partial_recv_table);
573 g_hash_table_destroy(pop3_session->partial_recv_table);
576 g_free(pop3_session->greeting);
577 g_free(pop3_session->user);
578 g_free(pop3_session->pass);
579 g_free(pop3_session->error_msg);
581 pop3_session->ac_prefs->receive_in_progress = FALSE;
584 static void pop3_get_uidl_table(PrefsAccount *ac_prefs, Pop3Session *session)
587 GHashTable *partial_recv_table;
590 gchar buf[POPBUFSIZE];
591 gchar uidl[POPBUFSIZE];
595 gchar *sanitized_uid = g_strdup(ac_prefs->userid);
597 subst_for_filename(sanitized_uid);
599 table = g_hash_table_new(g_str_hash, g_str_equal);
600 partial_recv_table = g_hash_table_new(g_str_hash, g_str_equal);
602 path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
603 "uidl", G_DIR_SEPARATOR_S, ac_prefs->recv_server,
604 "-", sanitized_uid, NULL);
606 g_free(sanitized_uid);
607 if ((fp = claws_fopen(path, "rb")) == NULL) {
608 if (ENOENT != errno) FILE_OP_ERROR(path, "claws_fopen");
610 path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
611 "uidl-", ac_prefs->recv_server,
612 "-", ac_prefs->userid, NULL);
613 if ((fp = claws_fopen(path, "rb")) == NULL) {
614 if (ENOENT != errno) FILE_OP_ERROR(path, "claws_fopen");
616 session->uidl_table = table;
617 session->partial_recv_table = partial_recv_table;
625 while (claws_fgets(buf, sizeof(buf), fp) != NULL) {
626 gchar tmp[POPBUFSIZE];
628 recv_time = RECV_TIME_NONE;
629 partial_recv = POP3_TOTALLY_RECEIVED;
631 if (sscanf(buf, "%s\t%ld\t%s", uidl, (long int *) &recv_time, tmp) < 3) {
632 if (sscanf(buf, "%s\t%ld", uidl, (long int *) &recv_time) != 2) {
633 if (sscanf(buf, "%s", uidl) != 1)
644 if (recv_time == RECV_TIME_NONE)
645 recv_time = RECV_TIME_RECEIVED;
646 g_hash_table_insert(table, g_strdup(uidl),
647 GINT_TO_POINTER(recv_time));
648 if (strlen(tmp) == 1)
649 partial_recv = atoi(tmp); /* totally received ?*/
651 partial_recv = POP3_MUST_COMPLETE_RECV;
653 g_hash_table_insert(partial_recv_table, g_strdup(uidl),
654 GINT_TO_POINTER(partial_recv));
658 session->uidl_table = table;
659 session->partial_recv_table = partial_recv_table;
667 g_warning("failed to write"); \
671 gint pop3_write_uidl_list(Pop3Session *session)
673 gchar *path, *tmp_path;
677 gchar *sanitized_uid = g_strdup(session->ac_prefs->userid);
679 subst_for_filename(sanitized_uid);
681 if (!session->uidl_is_valid) {
682 g_free(sanitized_uid);
686 path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
687 "uidl", G_DIR_SEPARATOR_S,
688 session->ac_prefs->recv_server,
689 "-", sanitized_uid, NULL);
690 tmp_path = g_strconcat(path, ".tmp", NULL);
692 g_free(sanitized_uid);
694 if ((fp = claws_fopen(tmp_path, "wb")) == NULL) {
695 FILE_OP_ERROR(tmp_path, "claws_fopen");
699 for (n = 1; n <= session->count; n++) {
700 msg = &session->msg[n];
701 if (msg->uidl && msg->received &&
702 (!msg->deleted || session->state != POP3_DONE))
703 TRY(fprintf(fp, "%s\t%ld\t%d\n",
704 msg->uidl, (long int)
710 if (claws_safe_fclose(fp) == EOF) {
711 FILE_OP_ERROR(tmp_path, "claws_fclose");
719 if (g_rename(tmp_path, path) < 0) {
720 FILE_OP_ERROR(path, "rename");
736 static gint pop3_write_msg_to_file(const gchar *file, const gchar *data,
737 guint len, const gchar *prefix)
740 const gchar *prev, *cur;
742 cm_return_val_if_fail(file != NULL, -1);
744 if ((fp = claws_fopen(file, "wb")) == NULL) {
745 FILE_OP_ERROR(file, "claws_fopen");
749 if (change_file_mode_rw(fp, file) < 0)
750 FILE_OP_ERROR(file, "chmod");
752 if (prefix != NULL) {
753 if (fprintf(fp, "%s\n", prefix) < 0) {
754 FILE_OP_ERROR(file, "fprintf");
761 /* +------------------+----------------+--------------------------+ *
762 * ^data ^prev ^cur data+len-1^ */
765 while ((cur = (gchar *)my_memmem(prev, len - (prev - data), "\r\n", 2))
767 if ((cur > prev && claws_fwrite(prev, 1, cur - prev, fp) < 1) ||
768 claws_fputc('\n', fp) == EOF) {
769 FILE_OP_ERROR(file, "claws_fwrite");
770 g_warning("can't write to file: %s", file);
776 if (cur == data + len - 1) {
781 if (*(cur + 1) == '\n')
786 if (prev - data < len - 1 && *prev == '.' && *(prev + 1) == '.')
789 if (prev - data >= len)
793 if (prev - data < len &&
794 claws_fwrite(prev, 1, len - (prev - data), fp) < 1) {
795 FILE_OP_ERROR(file, "claws_fwrite");
796 g_warning("can't write to file: %s", file);
801 if (data[len - 1] != '\r' && data[len - 1] != '\n') {
802 if (claws_fputc('\n', fp) == EOF) {
803 FILE_OP_ERROR(file, "claws_fputc");
804 g_warning("can't write to file: %s", file);
811 if (claws_safe_fclose(fp) == EOF) {
812 FILE_OP_ERROR(file, "claws_fclose");
820 static Pop3State pop3_lookup_next(Pop3Session *session)
823 PrefsAccount *ac = session->ac_prefs;
825 gboolean size_limit_over;
828 msg = &session->msg[session->cur_msg];
831 (ac->enable_size_limit &&
832 ac->size_limit > 0 &&
833 size > ac->size_limit * 1024);
836 msg->recv_time != RECV_TIME_NONE &&
837 msg->recv_time != RECV_TIME_KEEP &&
838 msg->partial_recv == POP3_TOTALLY_RECEIVED &&
839 session->current_time - msg->recv_time >=
840 ((ac->msg_leave_time * 24 * 60 * 60) +
841 (ac->msg_leave_hour * 60 * 60))) {
842 log_message(LOG_PROTOCOL,
843 _("POP: Deleting expired message %d [%s]\n"),
844 session->cur_msg, msg->uidl?msg->uidl:" ");
845 session->cur_total_bytes += size;
846 pop3_delete_send(session);
850 if (size_limit_over) {
851 if (!msg->received && msg->partial_recv !=
852 POP3_MUST_COMPLETE_RECV) {
853 pop3_top_send(session, ac->size_limit);
855 } else if (msg->partial_recv == POP3_MUST_COMPLETE_RECV)
858 log_message(LOG_PROTOCOL,
859 _("POP: Skipping message %d [%s] (%d bytes)\n"),
860 session->cur_msg, msg->uidl?msg->uidl:" ", size);
863 if (size == 0 || msg->received || size_limit_over) {
864 session->cur_total_bytes += size;
865 if (session->cur_msg == session->count) {
866 pop3_logout_send(session);
874 pop3_retr_send(session);
878 static Pop3ErrorValue pop3_ok(Pop3Session *session, const gchar *msg)
882 log_print(LOG_PROTOCOL, "POP< %s\n", msg);
884 if (!strncmp(msg, "+OK", 3))
886 else if (!strncmp(msg, "-ERR", 4)) {
887 if (strstr(msg + 4, "lock") ||
888 strstr(msg + 4, "Lock") ||
889 strstr(msg + 4, "LOCK") ||
890 strstr(msg + 4, "wait")) {
891 log_error(LOG_PROTOCOL, _("mailbox is locked\n"));
893 } else if (strcasestr(msg + 4, "timeout")) {
894 log_error(LOG_PROTOCOL, _("Session timeout\n"));
897 switch (session->state) {
900 log_error(LOG_PROTOCOL, _("couldn't start STARTTLS session\n"));
904 case POP3_GETAUTH_USER:
905 case POP3_GETAUTH_PASS:
906 case POP3_GETAUTH_APOP:
907 log_error(LOG_PROTOCOL, _("error occurred on authentication\n"));
910 case POP3_GETRANGE_LAST:
911 case POP3_GETRANGE_UIDL:
913 log_warning(LOG_PROTOCOL, _("command not supported\n"));
914 ok = PS_NOTSUPPORTED;
918 log_error(LOG_PROTOCOL, _("error occurred on POP session\n"));
923 g_free(session->error_msg);
924 session->error_msg = g_strdup(msg);
925 g_printerr("POP: %s\n", msg);
929 session->error_val = ok;
933 static gint pop3_session_recv_msg(Session *session, const gchar *msg)
935 Pop3Session *pop3_session = POP3_SESSION(session);
936 Pop3ErrorValue val = PS_SUCCESS;
940 if (pop3_session->state != POP3_GETRANGE_UIDL_RECV &&
941 pop3_session->state != POP3_GETSIZE_LIST_RECV) {
942 val = pop3_ok(pop3_session, msg);
943 if (val != PS_SUCCESS) {
944 if (val != PS_NOTSUPPORTED) {
945 pop3_session->state = POP3_ERROR;
950 if (*body == '+' || *body == '-')
952 while (g_ascii_isalpha(*body))
954 while (g_ascii_isspace(*body))
958 switch (pop3_session->state) {
961 pop3_greeting_recv(pop3_session, body);
963 if (pop3_session->ac_prefs->ssl_pop == SSL_STARTTLS)
964 val = pop3_stls_send(pop3_session);
967 if (pop3_session->ac_prefs->use_apop_auth)
968 val = pop3_getauth_apop_send(pop3_session);
970 val = pop3_getauth_user_send(pop3_session);
974 if (pop3_stls_recv(pop3_session) != PS_SUCCESS)
976 if (pop3_session->ac_prefs->use_apop_auth)
977 val = pop3_getauth_apop_send(pop3_session);
979 val = pop3_getauth_user_send(pop3_session);
982 case POP3_GETAUTH_USER:
983 val = pop3_getauth_pass_send(pop3_session);
985 case POP3_GETAUTH_PASS:
986 case POP3_GETAUTH_APOP:
987 if (!pop3_session->pop_before_smtp)
988 val = pop3_getrange_stat_send(pop3_session);
990 val = pop3_logout_send(pop3_session);
992 case POP3_GETRANGE_STAT:
993 if (pop3_getrange_stat_recv(pop3_session, body) < 0)
995 if (pop3_session->count > 0)
996 val = pop3_getrange_uidl_send(pop3_session);
998 val = pop3_logout_send(pop3_session);
1000 case POP3_GETRANGE_LAST:
1001 if (val == PS_NOTSUPPORTED)
1002 pop3_session->error_val = PS_SUCCESS;
1003 else if (pop3_getrange_last_recv(pop3_session, body) < 0)
1005 if (pop3_session->cur_msg > 0)
1006 val = pop3_getsize_list_send(pop3_session);
1008 val = pop3_logout_send(pop3_session);
1010 case POP3_GETRANGE_UIDL:
1011 if (val == PS_NOTSUPPORTED) {
1012 pop3_session->error_val = PS_SUCCESS;
1013 val = pop3_getrange_last_send(pop3_session);
1015 pop3_session->state = POP3_GETRANGE_UIDL_RECV;
1016 session_recv_data(session, 0, ".\r\n");
1019 case POP3_GETSIZE_LIST:
1020 pop3_session->state = POP3_GETSIZE_LIST_RECV;
1021 session_recv_data(session, 0, ".\r\n");
1024 pop3_session->state = POP3_RETR_RECV;
1025 session_recv_data(session, 0, ".\r\n");
1028 if (val == PS_NOTSUPPORTED) {
1029 pop3_session->error_val = PS_SUCCESS;
1031 pop3_session->state = POP3_TOP_RECV;
1032 session_recv_data(session, 0, ".\r\n");
1036 pop3_delete_recv(pop3_session);
1037 if (pop3_session->cur_msg == pop3_session->count)
1038 val = pop3_logout_send(pop3_session);
1040 pop3_session->cur_msg++;
1041 if (pop3_lookup_next(pop3_session) == POP3_ERROR)
1046 pop3_session->state = POP3_DONE;
1047 session_disconnect(session);
1054 return val == PS_SUCCESS?0:-1;
1057 static gint pop3_session_recv_data_finished(Session *session, guchar *data,
1060 Pop3Session *pop3_session = POP3_SESSION(session);
1061 Pop3ErrorValue val = PS_SUCCESS;
1063 switch (pop3_session->state) {
1064 case POP3_GETRANGE_UIDL_RECV:
1065 val = pop3_getrange_uidl_recv(pop3_session, data, len);
1066 if (val == PS_SUCCESS) {
1067 if (pop3_session->new_msg_exist)
1068 pop3_getsize_list_send(pop3_session);
1070 pop3_logout_send(pop3_session);
1074 case POP3_GETSIZE_LIST_RECV:
1075 val = pop3_getsize_list_recv(pop3_session, data, len);
1076 if (val == PS_SUCCESS) {
1077 if (pop3_lookup_next(pop3_session) == POP3_ERROR)
1082 case POP3_RETR_RECV:
1083 if (pop3_retr_recv(pop3_session, data, len) < 0)
1086 if (pop3_session->ac_prefs->rmmail &&
1087 pop3_session->ac_prefs->msg_leave_time == 0 &&
1088 pop3_session->ac_prefs->msg_leave_hour == 0 &&
1089 pop3_session->msg[pop3_session->cur_msg].recv_time
1091 pop3_delete_send(pop3_session);
1092 else if (pop3_session->cur_msg == pop3_session->count)
1093 pop3_logout_send(pop3_session);
1095 pop3_session->cur_msg++;
1096 if (pop3_lookup_next(pop3_session) == POP3_ERROR)
1101 if (pop3_top_recv(pop3_session, data, len) < 0)
1104 if (pop3_session->cur_msg == pop3_session->count)
1105 pop3_logout_send(pop3_session);
1107 pop3_session->cur_msg++;
1108 if (pop3_lookup_next(pop3_session) == POP3_ERROR)
1113 log_warning(LOG_PROTOCOL, _("TOP command unsupported\n"));
1114 if (pop3_session->cur_msg == pop3_session->count)
1115 pop3_logout_send(pop3_session);
1117 pop3_session->cur_msg++;
1118 if (pop3_lookup_next(pop3_session) == POP3_ERROR)