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"
44 static gint
pop3_greeting_recv (Pop3Session
*session
,
46 static gint
pop3_getauth_user_send (Pop3Session
*session
);
47 static gint
pop3_getauth_pass_send (Pop3Session
*session
);
48 static gint
pop3_getauth_apop_send (Pop3Session
*session
);
50 static gint
pop3_stls_send (Pop3Session
*session
);
51 static gint
pop3_stls_recv (Pop3Session
*session
);
53 static gint
pop3_getrange_stat_send (Pop3Session
*session
);
54 static gint
pop3_getrange_stat_recv (Pop3Session
*session
,
56 static gint
pop3_getrange_last_send (Pop3Session
*session
);
57 static gint
pop3_getrange_last_recv (Pop3Session
*session
,
59 static gint
pop3_getrange_uidl_send (Pop3Session
*session
);
60 static gint
pop3_getrange_uidl_recv (Pop3Session
*session
,
63 static gint
pop3_getsize_list_send (Pop3Session
*session
);
64 static gint
pop3_getsize_list_recv (Pop3Session
*session
,
67 static gint
pop3_retr_send (Pop3Session
*session
);
68 static gint
pop3_retr_recv (Pop3Session
*session
,
71 static gint
pop3_delete_send (Pop3Session
*session
);
72 static gint
pop3_delete_recv (Pop3Session
*session
);
73 static gint
pop3_logout_send (Pop3Session
*session
);
75 static void pop3_gen_send (Pop3Session
*session
,
76 const gchar
*format
, ...);
78 static void pop3_session_destroy (Session
*session
);
80 static gint
pop3_write_msg_to_file (const gchar
*file
,
85 static Pop3State
pop3_lookup_next (Pop3Session
*session
);
86 static Pop3ErrorValue
pop3_ok (Pop3Session
*session
,
89 static gint
pop3_session_recv_msg (Session
*session
,
91 static gint
pop3_session_recv_data_finished (Session
*session
,
94 static void pop3_get_uidl_table(PrefsAccount
*ac_prefs
, Pop3Session
*session
);
96 static gint
pop3_greeting_recv(Pop3Session
*session
, const gchar
*msg
)
98 session
->state
= POP3_GREETING
;
100 session
->greeting
= g_strdup(msg
);
105 static gint
pop3_stls_send(Pop3Session
*session
)
107 session
->state
= POP3_STLS
;
108 pop3_gen_send(session
, "STLS");
112 static gint
pop3_stls_recv(Pop3Session
*session
)
114 if (session_start_tls(SESSION(session
)) < 0) {
115 session
->error_val
= PS_SOCKET
;
120 #endif /* USE_GNUTLS */
122 static gint
pop3_getauth_user_send(Pop3Session
*session
)
124 cm_return_val_if_fail(session
->user
!= NULL
, -1);
126 session
->state
= POP3_GETAUTH_USER
;
127 pop3_gen_send(session
, "USER %s", session
->user
);
131 static gint
pop3_getauth_pass_send(Pop3Session
*session
)
133 cm_return_val_if_fail(session
->pass
!= NULL
, -1);
135 session
->state
= POP3_GETAUTH_PASS
;
136 pop3_gen_send(session
, "PASS %s", session
->pass
);
140 static gint
pop3_getauth_apop_send(Pop3Session
*session
)
146 cm_return_val_if_fail(session
->user
!= NULL
, -1);
147 cm_return_val_if_fail(session
->pass
!= NULL
, -1);
149 session
->state
= POP3_GETAUTH_APOP
;
151 if ((start
= strchr(session
->greeting
, '<')) == NULL
) {
152 log_error(LOG_PROTOCOL
, _("Required APOP timestamp not found "
154 session
->error_val
= PS_PROTOCOL
;
158 if ((end
= strchr(start
, '>')) == NULL
|| end
== start
+ 1) {
159 log_error(LOG_PROTOCOL
, _("Timestamp syntax error in greeting\n"));
160 session
->error_val
= PS_PROTOCOL
;
165 if (!is_ascii_str(start
)) {
166 log_error(LOG_PROTOCOL
, _("Timestamp syntax error in greeting (not ASCII)\n"));
167 session
->error_val
= PS_PROTOCOL
;
171 apop_str
= g_strconcat(start
, session
->pass
, NULL
);
172 md5_hex_digest(md5sum
, apop_str
);
175 pop3_gen_send(session
, "APOP %s %s", session
->user
, md5sum
);
180 static gint
pop3_getrange_stat_send(Pop3Session
*session
)
182 session
->state
= POP3_GETRANGE_STAT
;
183 pop3_gen_send(session
, "STAT");
187 static gint
pop3_getrange_stat_recv(Pop3Session
*session
, const gchar
*msg
)
189 if (sscanf(msg
, "%d %d", &session
->count
, &session
->total_bytes
) != 2) {
190 log_error(LOG_PROTOCOL
, _("POP protocol error\n"));
191 session
->error_val
= PS_PROTOCOL
;
194 if (session
->count
== 0) {
195 session
->uidl_is_valid
= TRUE
;
197 session
->msg
= g_new0(Pop3MsgInfo
, session
->count
+ 1);
198 session
->cur_msg
= 1;
205 static gint
pop3_getrange_last_send(Pop3Session
*session
)
207 session
->state
= POP3_GETRANGE_LAST
;
208 pop3_gen_send(session
, "LAST");
212 static gint
pop3_getrange_last_recv(Pop3Session
*session
, const gchar
*msg
)
216 if (sscanf(msg
, "%d", &last
) == 0) {
217 log_warning(LOG_PROTOCOL
, _("POP protocol error\n"));
218 session
->error_val
= PS_PROTOCOL
;
221 if (session
->count
> last
) {
222 session
->new_msg_exist
= TRUE
;
223 session
->cur_msg
= last
+ 1;
225 session
->cur_msg
= 0;
231 static gint
pop3_getrange_uidl_send(Pop3Session
*session
)
233 session
->state
= POP3_GETRANGE_UIDL
;
234 pop3_gen_send(session
, "UIDL");
238 static gint
pop3_getrange_uidl_recv(Pop3Session
*session
, const gchar
*data
,
242 gchar buf
[POPBUFSIZE
];
247 const gchar
*p
= data
;
248 const gchar
*lastp
= data
+ len
;
249 const gchar
*newline
;
252 if ((newline
= memchr(p
, '\r', lastp
- p
)) == NULL
)
254 buf_len
= MIN(newline
- p
, sizeof(buf
) - 1);
255 memcpy(buf
, p
, buf_len
);
259 if (p
< lastp
&& *p
== '\n') p
++;
261 if (sscanf(buf
, "%d %" Xstr(IDLEN
) "s", &num
, id
) != 2 ||
262 num
<= 0 || num
> session
->count
) {
263 log_warning(LOG_PROTOCOL
, _("invalid UIDL response: %s\n"), buf
);
267 session
->msg
[num
].uidl
= g_strdup(id
);
269 recv_time
= (time_t)(GPOINTER_TO_INT(g_hash_table_lookup(
270 session
->uidl_table
, id
)));
271 session
->msg
[num
].recv_time
= recv_time
;
273 if (recv_time
!= RECV_TIME_NONE
) {
274 debug_print("num %d uidl %s: already got it\n", num
, id
);
276 debug_print("num %d uidl %s: unknown\n", num
, id
);
279 partial_recv
= (gint
)(GPOINTER_TO_INT(g_hash_table_lookup(
280 session
->partial_recv_table
, id
)));
282 if (recv_time
!= RECV_TIME_NONE
283 || partial_recv
!= POP3_TOTALLY_RECEIVED
) {
284 session
->msg
[num
].received
=
285 (partial_recv
!= POP3_MUST_COMPLETE_RECV
);
286 session
->msg
[num
].partial_recv
= partial_recv
;
287 if (partial_recv
== POP3_MUST_COMPLETE_RECV
)
288 session
->new_msg_exist
= TRUE
;
290 if (!session
->new_msg_exist
&&
291 (recv_time
== RECV_TIME_NONE
||
292 session
->ac_prefs
->rmmail
)) {
293 session
->cur_msg
= num
;
294 session
->new_msg_exist
= TRUE
;
298 session
->uidl_is_valid
= TRUE
;
302 static gint
pop3_getsize_list_send(Pop3Session
*session
)
304 session
->state
= POP3_GETSIZE_LIST
;
305 pop3_gen_send(session
, "LIST");
309 static gint
pop3_getsize_list_recv(Pop3Session
*session
, const gchar
*data
,
312 gchar buf
[POPBUFSIZE
];
315 const gchar
*p
= data
;
316 const gchar
*lastp
= data
+ len
;
317 const gchar
*newline
;
320 if ((newline
= memchr(p
, '\r', lastp
- p
)) == NULL
)
322 buf_len
= MIN(newline
- p
, sizeof(buf
) - 1);
323 memcpy(buf
, p
, buf_len
);
327 if (p
< lastp
&& *p
== '\n') p
++;
329 if (sscanf(buf
, "%u %u", &num
, &size
) != 2) {
330 session
->error_val
= PS_PROTOCOL
;
334 if (num
> 0 && num
<= session
->count
)
335 session
->msg
[num
].size
= size
;
336 if (num
> 0 && num
< session
->cur_msg
)
337 session
->cur_total_bytes
+= size
;
343 static gint
pop3_retr_send(Pop3Session
*session
)
345 session
->state
= POP3_RETR
;
346 debug_print("retrieving %d [%s]\n", session
->cur_msg
,
347 session
->msg
[session
->cur_msg
].uidl
?
348 session
->msg
[session
->cur_msg
].uidl
:" ");
349 pop3_gen_send(session
, "RETR %d", session
->cur_msg
);
353 static gint
pop3_retr_recv(Pop3Session
*session
, const gchar
*data
, guint len
)
357 MailReceiveData mail_receive_data
;
359 /* NOTE: we allocate a slightly larger buffer with a zero terminator
360 * because some plugins may think that it has a C string. */
361 mail_receive_data
.session
= session
;
362 mail_receive_data
.data
= g_new0(gchar
, len
+ 1);
363 mail_receive_data
.data_len
= len
;
364 memcpy(mail_receive_data
.data
, data
, len
);
366 hooks_invoke(MAIL_RECEIVE_HOOKLIST
, &mail_receive_data
);
368 file
= get_tmp_file();
369 if (pop3_write_msg_to_file(file
, mail_receive_data
.data
,
370 mail_receive_data
.data_len
, NULL
) < 0) {
372 g_free(mail_receive_data
.data
);
373 session
->error_val
= PS_IOERR
;
376 g_free(mail_receive_data
.data
);
378 if (session
->msg
[session
->cur_msg
].partial_recv
379 == POP3_MUST_COMPLETE_RECV
) {
380 gchar
*old_file
= partial_get_filename(
381 session
->ac_prefs
->recv_server
,
382 session
->ac_prefs
->userid
,
383 session
->msg
[session
->cur_msg
].uidl
);
386 partial_delete_old(old_file
);
391 /* drop_ok: 0: success 1: don't receive -1: error */
392 drop_ok
= session
->drop_message(session
, file
);
396 session
->error_val
= PS_IOERR
;
400 session
->cur_total_bytes
+= session
->msg
[session
->cur_msg
].size
;
401 session
->cur_total_recv_bytes
+= session
->msg
[session
->cur_msg
].size
;
402 session
->cur_total_num
++;
404 session
->msg
[session
->cur_msg
].received
= TRUE
;
405 session
->msg
[session
->cur_msg
].partial_recv
= POP3_TOTALLY_RECEIVED
;
407 session
->msg
[session
->cur_msg
].recv_time
=
408 drop_ok
== 1 ? RECV_TIME_KEEP
: session
->current_time
;
413 static gint
pop3_top_send(Pop3Session
*session
, gint max_size
)
415 gint num_lines
= (max_size
*1024)/82; /* consider lines to be 80 chars */
416 session
->state
= POP3_TOP
;
417 pop3_gen_send(session
, "TOP %d %d", session
->cur_msg
, num_lines
);
421 static gint
pop3_top_recv(Pop3Session
*session
, const gchar
*data
, guint len
)
425 MailReceiveData mail_receive_data
;
426 gchar
*partial_notice
= NULL
;
428 /* NOTE: we allocate a slightly larger buffer with a zero terminator
429 * because some plugins may think that it has a C string. */
430 mail_receive_data
.session
= session
;
431 mail_receive_data
.data
= g_new0(gchar
, len
+ 1);
432 mail_receive_data
.data_len
= len
;
433 memcpy(mail_receive_data
.data
, data
, len
);
435 hooks_invoke(MAIL_RECEIVE_HOOKLIST
, &mail_receive_data
);
437 partial_notice
= g_strdup_printf("SC-Marked-For-Download: 0\n"
438 "SC-Partially-Retrieved: %s\n"
439 "SC-Account-Server: %s\n"
440 "SC-Account-Login: %s\n"
441 "SC-Message-Size: %d",
442 session
->msg
[session
->cur_msg
].uidl
,
443 session
->ac_prefs
->recv_server
,
444 session
->ac_prefs
->userid
,
445 session
->msg
[session
->cur_msg
].size
);
446 file
= get_tmp_file();
447 if (pop3_write_msg_to_file(file
, mail_receive_data
.data
,
448 mail_receive_data
.data_len
,
449 partial_notice
) < 0) {
451 g_free(mail_receive_data
.data
);
452 session
->error_val
= PS_IOERR
;
453 g_free(partial_notice
);
456 g_free(mail_receive_data
.data
);
457 g_free(partial_notice
);
459 /* drop_ok: 0: success 1: don't receive -1: error */
460 drop_ok
= session
->drop_message(session
, file
);
463 session
->error_val
= PS_IOERR
;
467 session
->cur_total_bytes
+= session
->msg
[session
->cur_msg
].size
;
468 session
->cur_total_recv_bytes
+= session
->msg
[session
->cur_msg
].size
;
469 session
->cur_total_num
++;
471 session
->msg
[session
->cur_msg
].received
= TRUE
;
472 session
->msg
[session
->cur_msg
].partial_recv
= POP3_PARTIALLY_RECEIVED
;
473 session
->msg
[session
->cur_msg
].recv_time
=
474 drop_ok
== 1 ? RECV_TIME_KEEP
: session
->current_time
;
479 static gint
pop3_delete_send(Pop3Session
*session
)
481 session
->state
= POP3_DELETE
;
482 pop3_gen_send(session
, "DELE %d", session
->cur_msg
);
486 static gint
pop3_delete_recv(Pop3Session
*session
)
488 session
->msg
[session
->cur_msg
].deleted
= TRUE
;
492 static gint
pop3_logout_send(Pop3Session
*session
)
494 session
->state
= POP3_LOGOUT
;
495 pop3_gen_send(session
, "QUIT");
499 static void pop3_gen_send(Pop3Session
*session
, const gchar
*format
, ...)
501 gchar buf
[POPBUFSIZE
+ 1];
504 va_start(args
, format
);
505 g_vsnprintf(buf
, sizeof(buf
) - 2, format
, args
);
508 if (!g_ascii_strncasecmp(buf
, "PASS ", 5))
509 log_print(LOG_PROTOCOL
, "POP> PASS ********\n");
511 log_print(LOG_PROTOCOL
, "POP> %s\n", buf
);
513 session_send_msg(SESSION(session
), buf
);
516 Session
*pop3_session_new(PrefsAccount
*account
)
518 Pop3Session
*session
;
520 cm_return_val_if_fail(account
!= NULL
, NULL
);
522 account
->receive_in_progress
= TRUE
;
524 session
= g_new0(Pop3Session
, 1);
526 session_init(SESSION(session
), account
, FALSE
);
528 SESSION(session
)->type
= SESSION_POP3
;
530 SESSION(session
)->recv_msg
= pop3_session_recv_msg
;
531 SESSION(session
)->recv_data_finished
= pop3_session_recv_data_finished
;
532 SESSION(session
)->send_data_finished
= NULL
;
533 SESSION(session
)->ssl_cert_auto_accept
= account
->ssl_certs_auto_accept
;
534 SESSION(session
)->destroy
= pop3_session_destroy
;
537 if (account
->set_gnutls_priority
&& account
->gnutls_priority
&&
538 strlen(account
->gnutls_priority
) != 0)
539 SESSION(session
)->gnutls_priority
= g_strdup(account
->gnutls_priority
);
542 session
->state
= POP3_READY
;
543 session
->ac_prefs
= account
;
544 session
->pop_before_smtp
= FALSE
;
545 pop3_get_uidl_table(account
, session
);
546 session
->current_time
= time(NULL
);
547 session
->error_val
= PS_SUCCESS
;
548 session
->error_msg
= NULL
;
550 return SESSION(session
);
553 static void pop3_session_destroy(Session
*session
)
555 Pop3Session
*pop3_session
= POP3_SESSION(session
);
558 cm_return_if_fail(session
!= NULL
);
560 for (n
= 1; n
<= pop3_session
->count
; n
++)
561 g_free(pop3_session
->msg
[n
].uidl
);
562 g_free(pop3_session
->msg
);
564 if (pop3_session
->uidl_table
) {
565 hash_free_strings(pop3_session
->uidl_table
);
566 g_hash_table_destroy(pop3_session
->uidl_table
);
569 if (pop3_session
->partial_recv_table
) {
570 hash_free_strings(pop3_session
->partial_recv_table
);
571 g_hash_table_destroy(pop3_session
->partial_recv_table
);
574 g_free(pop3_session
->greeting
);
575 g_free(pop3_session
->user
);
576 g_free(pop3_session
->pass
);
577 g_free(pop3_session
->error_msg
);
579 pop3_session
->ac_prefs
->receive_in_progress
= FALSE
;
582 static void pop3_get_uidl_table(PrefsAccount
*ac_prefs
, Pop3Session
*session
)
585 GHashTable
*partial_recv_table
;
588 gchar buf
[POPBUFSIZE
];
589 gchar uidl
[POPBUFSIZE
];
593 gchar
*sanitized_uid
= g_strdup(ac_prefs
->userid
);
595 subst_for_filename(sanitized_uid
);
597 table
= g_hash_table_new(g_str_hash
, g_str_equal
);
598 partial_recv_table
= g_hash_table_new(g_str_hash
, g_str_equal
);
600 path
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
601 "uidl", G_DIR_SEPARATOR_S
, ac_prefs
->recv_server
,
602 "-", sanitized_uid
, NULL
);
604 g_free(sanitized_uid
);
605 if ((fp
= g_fopen(path
, "rb")) == NULL
) {
606 if (ENOENT
!= errno
) FILE_OP_ERROR(path
, "fopen");
608 path
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
609 "uidl-", ac_prefs
->recv_server
,
610 "-", ac_prefs
->userid
, NULL
);
611 if ((fp
= g_fopen(path
, "rb")) == NULL
) {
612 if (ENOENT
!= errno
) FILE_OP_ERROR(path
, "fopen");
614 session
->uidl_table
= table
;
615 session
->partial_recv_table
= partial_recv_table
;
623 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
624 gchar tmp
[POPBUFSIZE
];
626 recv_time
= RECV_TIME_NONE
;
627 partial_recv
= POP3_TOTALLY_RECEIVED
;
629 if (sscanf(buf
, "%s\t%ld\t%s", uidl
, (long int *) &recv_time
, tmp
) < 3) {
630 if (sscanf(buf
, "%s\t%ld", uidl
, (long int *) &recv_time
) != 2) {
631 if (sscanf(buf
, "%s", uidl
) != 1)
642 if (recv_time
== RECV_TIME_NONE
)
643 recv_time
= RECV_TIME_RECEIVED
;
644 g_hash_table_insert(table
, g_strdup(uidl
),
645 GINT_TO_POINTER(recv_time
));
646 if (strlen(tmp
) == 1)
647 partial_recv
= atoi(tmp
); /* totally received ?*/
649 partial_recv
= POP3_MUST_COMPLETE_RECV
;
651 g_hash_table_insert(partial_recv_table
, g_strdup(uidl
),
652 GINT_TO_POINTER(partial_recv
));
656 session
->uidl_table
= table
;
657 session
->partial_recv_table
= partial_recv_table
;
665 g_warning("failed to write"); \
669 gint pop3_write_uidl_list(Pop3Session *session)
671 gchar
*path
, *tmp_path
;
675 gchar
*sanitized_uid
= g_strdup(session
->ac_prefs
->userid
);
677 subst_for_filename(sanitized_uid
);
679 if (!session
->uidl_is_valid
) {
680 g_free(sanitized_uid
);
684 path
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
685 "uidl", G_DIR_SEPARATOR_S
,
686 session
->ac_prefs
->recv_server
,
687 "-", sanitized_uid
, NULL
);
688 tmp_path
= g_strconcat(path
, ".tmp", NULL
);
690 g_free(sanitized_uid
);
692 if ((fp
= g_fopen(tmp_path
, "wb")) == NULL
) {
693 FILE_OP_ERROR(tmp_path
, "fopen");
697 for (n
= 1; n
<= session
->count
; n
++) {
698 msg
= &session
->msg
[n
];
699 if (msg
->uidl
&& msg
->received
&&
700 (!msg
->deleted
|| session
->state
!= POP3_DONE
))
701 TRY(fprintf(fp
, "%s\t%ld\t%d\n",
702 msg
->uidl
, (long int)
708 if (fclose(fp
) == EOF
) {
709 FILE_OP_ERROR(tmp_path
, "fclose");
717 if (g_rename(tmp_path
, path
) < 0) {
718 FILE_OP_ERROR(path
, "rename");
734 static gint
pop3_write_msg_to_file(const gchar
*file
, const gchar
*data
,
735 guint len
, const gchar
*prefix
)
738 const gchar
*prev
, *cur
;
740 cm_return_val_if_fail(file
!= NULL
, -1);
742 if ((fp
= g_fopen(file
, "wb")) == NULL
) {
743 FILE_OP_ERROR(file
, "fopen");
747 if (change_file_mode_rw(fp
, file
) < 0)
748 FILE_OP_ERROR(file
, "chmod");
750 if (prefix
!= NULL
) {
751 if (fprintf(fp
, "%s\n", prefix
) < 0) {
752 FILE_OP_ERROR(file
, "fprintf");
759 /* +------------------+----------------+--------------------------+ *
760 * ^data ^prev ^cur data+len-1^ */
763 while ((cur
= (gchar
*)my_memmem(prev
, len
- (prev
- data
), "\r\n", 2))
765 if ((cur
> prev
&& fwrite(prev
, 1, cur
- prev
, fp
) < 1) ||
766 fputc('\n', fp
) == EOF
) {
767 FILE_OP_ERROR(file
, "fwrite");
768 g_warning("can't write to file: %s", file
);
774 if (cur
== data
+ len
- 1) {
779 if (*(cur
+ 1) == '\n')
784 if (prev
- data
< len
- 1 && *prev
== '.' && *(prev
+ 1) == '.')
787 if (prev
- data
>= len
)
791 if (prev
- data
< len
&&
792 fwrite(prev
, 1, len
- (prev
- data
), fp
) < 1) {
793 FILE_OP_ERROR(file
, "fwrite");
794 g_warning("can't write to file: %s", file
);
799 if (data
[len
- 1] != '\r' && data
[len
- 1] != '\n') {
800 if (fputc('\n', fp
) == EOF
) {
801 FILE_OP_ERROR(file
, "fputc");
802 g_warning("can't write to file: %s", file
);
809 if (fclose(fp
) == EOF
) {
810 FILE_OP_ERROR(file
, "fclose");
818 static Pop3State
pop3_lookup_next(Pop3Session
*session
)
821 PrefsAccount
*ac
= session
->ac_prefs
;
823 gboolean size_limit_over
;
826 msg
= &session
->msg
[session
->cur_msg
];
829 (ac
->enable_size_limit
&&
830 ac
->size_limit
> 0 &&
831 size
> ac
->size_limit
* 1024);
834 msg
->recv_time
!= RECV_TIME_NONE
&&
835 msg
->recv_time
!= RECV_TIME_KEEP
&&
836 msg
->partial_recv
== POP3_TOTALLY_RECEIVED
&&
837 session
->current_time
- msg
->recv_time
>=
838 ((ac
->msg_leave_time
* 24 * 60 * 60) +
839 (ac
->msg_leave_hour
* 60 * 60))) {
840 log_message(LOG_PROTOCOL
,
841 _("POP: Deleting expired message %d [%s]\n"),
842 session
->cur_msg
, msg
->uidl
?msg
->uidl
:" ");
843 session
->cur_total_bytes
+= size
;
844 pop3_delete_send(session
);
848 if (size_limit_over
) {
849 if (!msg
->received
&& msg
->partial_recv
!=
850 POP3_MUST_COMPLETE_RECV
) {
851 pop3_top_send(session
, ac
->size_limit
);
853 } else if (msg
->partial_recv
== POP3_MUST_COMPLETE_RECV
)
856 log_message(LOG_PROTOCOL
,
857 _("POP: Skipping message %d [%s] (%d bytes)\n"),
858 session
->cur_msg
, msg
->uidl
?msg
->uidl
:" ", size
);
861 if (size
== 0 || msg
->received
|| size_limit_over
) {
862 session
->cur_total_bytes
+= size
;
863 if (session
->cur_msg
== session
->count
) {
864 pop3_logout_send(session
);
872 pop3_retr_send(session
);
876 static Pop3ErrorValue
pop3_ok(Pop3Session
*session
, const gchar
*msg
)
880 log_print(LOG_PROTOCOL
, "POP< %s\n", msg
);
882 if (!strncmp(msg
, "+OK", 3))
884 else if (!strncmp(msg
, "-ERR", 4)) {
885 if (strstr(msg
+ 4, "lock") ||
886 strstr(msg
+ 4, "Lock") ||
887 strstr(msg
+ 4, "LOCK") ||
888 strstr(msg
+ 4, "wait")) {
889 log_error(LOG_PROTOCOL
, _("mailbox is locked\n"));
891 } else if (strcasestr(msg
+ 4, "timeout")) {
892 log_error(LOG_PROTOCOL
, _("Session timeout\n"));
895 switch (session
->state
) {
898 log_error(LOG_PROTOCOL
, _("couldn't start STARTTLS session\n"));
902 case POP3_GETAUTH_USER
:
903 case POP3_GETAUTH_PASS
:
904 case POP3_GETAUTH_APOP
:
905 log_error(LOG_PROTOCOL
, _("error occurred on authentication\n"));
908 case POP3_GETRANGE_LAST
:
909 case POP3_GETRANGE_UIDL
:
911 log_warning(LOG_PROTOCOL
, _("command not supported\n"));
912 ok
= PS_NOTSUPPORTED
;
916 log_error(LOG_PROTOCOL
, _("error occurred on POP session\n"));
921 g_free(session
->error_msg
);
922 session
->error_msg
= g_strdup(msg
);
923 g_printerr("POP: %s\n", msg
);
927 session
->error_val
= ok
;
931 static gint
pop3_session_recv_msg(Session
*session
, const gchar
*msg
)
933 Pop3Session
*pop3_session
= POP3_SESSION(session
);
934 Pop3ErrorValue val
= PS_SUCCESS
;
938 if (pop3_session
->state
!= POP3_GETRANGE_UIDL_RECV
&&
939 pop3_session
->state
!= POP3_GETSIZE_LIST_RECV
) {
940 val
= pop3_ok(pop3_session
, msg
);
941 if (val
!= PS_SUCCESS
) {
942 if (val
!= PS_NOTSUPPORTED
) {
943 pop3_session
->state
= POP3_ERROR
;
948 if (*body
== '+' || *body
== '-')
950 while (g_ascii_isalpha(*body
))
952 while (g_ascii_isspace(*body
))
956 switch (pop3_session
->state
) {
959 pop3_greeting_recv(pop3_session
, body
);
961 if (pop3_session
->ac_prefs
->ssl_pop
== SSL_STARTTLS
)
962 val
= pop3_stls_send(pop3_session
);
965 if (pop3_session
->ac_prefs
->use_apop_auth
)
966 val
= pop3_getauth_apop_send(pop3_session
);
968 val
= pop3_getauth_user_send(pop3_session
);
972 if (pop3_stls_recv(pop3_session
) != PS_SUCCESS
)
974 if (pop3_session
->ac_prefs
->use_apop_auth
)
975 val
= pop3_getauth_apop_send(pop3_session
);
977 val
= pop3_getauth_user_send(pop3_session
);
980 case POP3_GETAUTH_USER
:
981 val
= pop3_getauth_pass_send(pop3_session
);
983 case POP3_GETAUTH_PASS
:
984 case POP3_GETAUTH_APOP
:
985 if (!pop3_session
->pop_before_smtp
)
986 val
= pop3_getrange_stat_send(pop3_session
);
988 val
= pop3_logout_send(pop3_session
);
990 case POP3_GETRANGE_STAT
:
991 if (pop3_getrange_stat_recv(pop3_session
, body
) < 0)
993 if (pop3_session
->count
> 0)
994 val
= pop3_getrange_uidl_send(pop3_session
);
996 val
= pop3_logout_send(pop3_session
);
998 case POP3_GETRANGE_LAST
:
999 if (val
== PS_NOTSUPPORTED
)
1000 pop3_session
->error_val
= PS_SUCCESS
;
1001 else if (pop3_getrange_last_recv(pop3_session
, body
) < 0)
1003 if (pop3_session
->cur_msg
> 0)
1004 val
= pop3_getsize_list_send(pop3_session
);
1006 val
= pop3_logout_send(pop3_session
);
1008 case POP3_GETRANGE_UIDL
:
1009 if (val
== PS_NOTSUPPORTED
) {
1010 pop3_session
->error_val
= PS_SUCCESS
;
1011 val
= pop3_getrange_last_send(pop3_session
);
1013 pop3_session
->state
= POP3_GETRANGE_UIDL_RECV
;
1014 session_recv_data(session
, 0, ".\r\n");
1017 case POP3_GETSIZE_LIST
:
1018 pop3_session
->state
= POP3_GETSIZE_LIST_RECV
;
1019 session_recv_data(session
, 0, ".\r\n");
1022 pop3_session
->state
= POP3_RETR_RECV
;
1023 session_recv_data(session
, 0, ".\r\n");
1026 if (val
== PS_NOTSUPPORTED
) {
1027 pop3_session
->error_val
= PS_SUCCESS
;
1029 pop3_session
->state
= POP3_TOP_RECV
;
1030 session_recv_data(session
, 0, ".\r\n");
1034 pop3_delete_recv(pop3_session
);
1035 if (pop3_session
->cur_msg
== pop3_session
->count
)
1036 val
= pop3_logout_send(pop3_session
);
1038 pop3_session
->cur_msg
++;
1039 if (pop3_lookup_next(pop3_session
) == POP3_ERROR
)
1044 pop3_session
->state
= POP3_DONE
;
1045 session_disconnect(session
);
1052 return val
== PS_SUCCESS
?0:-1;
1055 static gint
pop3_session_recv_data_finished(Session
*session
, guchar
*data
,
1058 Pop3Session
*pop3_session
= POP3_SESSION(session
);
1059 Pop3ErrorValue val
= PS_SUCCESS
;
1061 switch (pop3_session
->state
) {
1062 case POP3_GETRANGE_UIDL_RECV
:
1063 val
= pop3_getrange_uidl_recv(pop3_session
, data
, len
);
1064 if (val
== PS_SUCCESS
) {
1065 if (pop3_session
->new_msg_exist
)
1066 pop3_getsize_list_send(pop3_session
);
1068 pop3_logout_send(pop3_session
);
1072 case POP3_GETSIZE_LIST_RECV
:
1073 val
= pop3_getsize_list_recv(pop3_session
, data
, len
);
1074 if (val
== PS_SUCCESS
) {
1075 if (pop3_lookup_next(pop3_session
) == POP3_ERROR
)
1080 case POP3_RETR_RECV
:
1081 if (pop3_retr_recv(pop3_session
, data
, len
) < 0)
1084 if (pop3_session
->ac_prefs
->rmmail
&&
1085 pop3_session
->ac_prefs
->msg_leave_time
== 0 &&
1086 pop3_session
->ac_prefs
->msg_leave_hour
== 0 &&
1087 pop3_session
->msg
[pop3_session
->cur_msg
].recv_time
1089 pop3_delete_send(pop3_session
);
1090 else if (pop3_session
->cur_msg
== pop3_session
->count
)
1091 pop3_logout_send(pop3_session
);
1093 pop3_session
->cur_msg
++;
1094 if (pop3_lookup_next(pop3_session
) == POP3_ERROR
)
1099 if (pop3_top_recv(pop3_session
, data
, len
) < 0)
1102 if (pop3_session
->cur_msg
== pop3_session
->count
)
1103 pop3_logout_send(pop3_session
);
1105 pop3_session
->cur_msg
++;
1106 if (pop3_lookup_next(pop3_session
) == POP3_ERROR
)
1111 log_warning(LOG_PROTOCOL
, _("TOP command unsupported\n"));
1112 if (pop3_session
->cur_msg
== pop3_session
->count
)
1113 pop3_logout_send(pop3_session
);
1115 pop3_session
->cur_msg
++;
1116 if (pop3_lookup_next(pop3_session
) == POP3_ERROR
)