2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 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/>.
25 #include <glib/gi18n.h>
36 #include "prefs_account.h"
39 #include "partial_download.h"
43 static gint
pop3_greeting_recv (Pop3Session
*session
,
45 static gint
pop3_getauth_user_send (Pop3Session
*session
);
46 static gint
pop3_getauth_pass_send (Pop3Session
*session
);
47 static gint
pop3_getauth_apop_send (Pop3Session
*session
);
49 static gint
pop3_stls_send (Pop3Session
*session
);
50 static gint
pop3_stls_recv (Pop3Session
*session
);
52 static gint
pop3_getrange_stat_send (Pop3Session
*session
);
53 static gint
pop3_getrange_stat_recv (Pop3Session
*session
,
55 static gint
pop3_getrange_last_send (Pop3Session
*session
);
56 static gint
pop3_getrange_last_recv (Pop3Session
*session
,
58 static gint
pop3_getrange_uidl_send (Pop3Session
*session
);
59 static gint
pop3_getrange_uidl_recv (Pop3Session
*session
,
62 static gint
pop3_getsize_list_send (Pop3Session
*session
);
63 static gint
pop3_getsize_list_recv (Pop3Session
*session
,
66 static gint
pop3_retr_send (Pop3Session
*session
);
67 static gint
pop3_retr_recv (Pop3Session
*session
,
70 static gint
pop3_delete_send (Pop3Session
*session
);
71 static gint
pop3_delete_recv (Pop3Session
*session
);
72 static gint
pop3_logout_send (Pop3Session
*session
);
74 static void pop3_gen_send (Pop3Session
*session
,
75 const gchar
*format
, ...);
77 static void pop3_session_destroy (Session
*session
);
79 static gint
pop3_write_msg_to_file (const gchar
*file
,
84 static Pop3State
pop3_lookup_next (Pop3Session
*session
);
85 static Pop3ErrorValue
pop3_ok (Pop3Session
*session
,
88 static gint
pop3_session_recv_msg (Session
*session
,
90 static gint
pop3_session_recv_data_finished (Session
*session
,
94 static gint
pop3_greeting_recv(Pop3Session
*session
, const gchar
*msg
)
96 session
->state
= POP3_GREETING
;
98 session
->greeting
= g_strdup(msg
);
103 static gint
pop3_stls_send(Pop3Session
*session
)
105 session
->state
= POP3_STLS
;
106 pop3_gen_send(session
, "STLS");
110 static gint
pop3_stls_recv(Pop3Session
*session
)
112 if (session_start_tls(SESSION(session
)) < 0) {
113 session
->error_val
= PS_SOCKET
;
118 #endif /* USE_OPENSSL */
120 static gint
pop3_getauth_user_send(Pop3Session
*session
)
122 g_return_val_if_fail(session
->user
!= NULL
, -1);
124 session
->state
= POP3_GETAUTH_USER
;
125 pop3_gen_send(session
, "USER %s", session
->user
);
129 static gint
pop3_getauth_pass_send(Pop3Session
*session
)
131 g_return_val_if_fail(session
->pass
!= NULL
, -1);
133 session
->state
= POP3_GETAUTH_PASS
;
134 pop3_gen_send(session
, "PASS %s", session
->pass
);
138 static gint
pop3_getauth_apop_send(Pop3Session
*session
)
144 g_return_val_if_fail(session
->user
!= NULL
, -1);
145 g_return_val_if_fail(session
->pass
!= NULL
, -1);
147 session
->state
= POP3_GETAUTH_APOP
;
149 if ((start
= strchr(session
->greeting
, '<')) == NULL
) {
150 log_error(LOG_PROTOCOL
, _("Required APOP timestamp not found "
152 session
->error_val
= PS_PROTOCOL
;
156 if ((end
= strchr(start
, '>')) == NULL
|| end
== start
+ 1) {
157 log_error(LOG_PROTOCOL
, _("Timestamp syntax error in greeting\n"));
158 session
->error_val
= PS_PROTOCOL
;
163 if (!is_ascii_str(start
)) {
164 log_error(LOG_PROTOCOL
, _("Timestamp syntax error in greeting (not ascii)\n"));
165 session
->error_val
= PS_PROTOCOL
;
169 apop_str
= g_strconcat(start
, session
->pass
, NULL
);
170 md5_hex_digest(md5sum
, apop_str
);
173 pop3_gen_send(session
, "APOP %s %s", session
->user
, md5sum
);
178 static gint
pop3_getrange_stat_send(Pop3Session
*session
)
180 session
->state
= POP3_GETRANGE_STAT
;
181 pop3_gen_send(session
, "STAT");
185 static gint
pop3_getrange_stat_recv(Pop3Session
*session
, const gchar
*msg
)
187 if (sscanf(msg
, "%d %d", &session
->count
, &session
->total_bytes
) != 2) {
188 log_error(LOG_PROTOCOL
, _("POP3 protocol error\n"));
189 session
->error_val
= PS_PROTOCOL
;
192 if (session
->count
== 0) {
193 session
->uidl_is_valid
= TRUE
;
195 session
->msg
= g_new0(Pop3MsgInfo
, session
->count
+ 1);
196 session
->cur_msg
= 1;
203 static gint
pop3_getrange_last_send(Pop3Session
*session
)
205 session
->state
= POP3_GETRANGE_LAST
;
206 pop3_gen_send(session
, "LAST");
210 static gint
pop3_getrange_last_recv(Pop3Session
*session
, const gchar
*msg
)
214 if (sscanf(msg
, "%d", &last
) == 0) {
215 log_warning(LOG_PROTOCOL
, _("POP3 protocol error\n"));
216 session
->error_val
= PS_PROTOCOL
;
219 if (session
->count
> last
) {
220 session
->new_msg_exist
= TRUE
;
221 session
->cur_msg
= last
+ 1;
223 session
->cur_msg
= 0;
229 static gint
pop3_getrange_uidl_send(Pop3Session
*session
)
231 session
->state
= POP3_GETRANGE_UIDL
;
232 pop3_gen_send(session
, "UIDL");
236 static gint
pop3_getrange_uidl_recv(Pop3Session
*session
, const gchar
*data
,
240 gchar buf
[POPBUFSIZE
];
245 const gchar
*p
= data
;
246 const gchar
*lastp
= data
+ len
;
247 const gchar
*newline
;
250 if ((newline
= memchr(p
, '\r', lastp
- p
)) == NULL
)
252 buf_len
= MIN(newline
- p
, sizeof(buf
) - 1);
253 memcpy(buf
, p
, buf_len
);
257 if (p
< lastp
&& *p
== '\n') p
++;
259 if (sscanf(buf
, "%d %" Xstr(IDLEN
) "s", &num
, id
) != 2 ||
260 num
<= 0 || num
> session
->count
) {
261 log_warning(LOG_PROTOCOL
, _("invalid UIDL response: %s\n"), buf
);
265 session
->msg
[num
].uidl
= g_strdup(id
);
267 recv_time
= (time_t)g_hash_table_lookup(
268 session
->uidl_table
, id
);
269 session
->msg
[num
].recv_time
= recv_time
;
271 if (recv_time
!= RECV_TIME_NONE
) {
272 debug_print("num %d uidl %s: already got it\n", num
, id
);
274 debug_print("num %d uidl %s: unknown\n", num
, id
);
277 partial_recv
= (gint
)g_hash_table_lookup(
278 session
->partial_recv_table
, id
);
280 if (recv_time
!= RECV_TIME_NONE
281 || partial_recv
!= POP3_TOTALLY_RECEIVED
) {
282 session
->msg
[num
].received
=
283 (partial_recv
!= POP3_MUST_COMPLETE_RECV
);
284 session
->msg
[num
].partial_recv
= partial_recv
;
285 if (partial_recv
== POP3_MUST_COMPLETE_RECV
)
286 session
->new_msg_exist
= TRUE
;
288 if (!session
->new_msg_exist
&&
289 (recv_time
== RECV_TIME_NONE
||
290 session
->ac_prefs
->rmmail
)) {
291 session
->cur_msg
= num
;
292 session
->new_msg_exist
= TRUE
;
296 session
->uidl_is_valid
= TRUE
;
300 static gint
pop3_getsize_list_send(Pop3Session
*session
)
302 session
->state
= POP3_GETSIZE_LIST
;
303 pop3_gen_send(session
, "LIST");
307 static gint
pop3_getsize_list_recv(Pop3Session
*session
, const gchar
*data
,
310 gchar buf
[POPBUFSIZE
];
313 const gchar
*p
= data
;
314 const gchar
*lastp
= data
+ len
;
315 const gchar
*newline
;
318 if ((newline
= memchr(p
, '\r', lastp
- p
)) == NULL
)
320 buf_len
= MIN(newline
- p
, sizeof(buf
) - 1);
321 memcpy(buf
, p
, buf_len
);
325 if (p
< lastp
&& *p
== '\n') p
++;
327 if (sscanf(buf
, "%u %u", &num
, &size
) != 2) {
328 session
->error_val
= PS_PROTOCOL
;
332 if (num
> 0 && num
<= session
->count
)
333 session
->msg
[num
].size
= size
;
334 if (num
> 0 && num
< session
->cur_msg
)
335 session
->cur_total_bytes
+= size
;
341 static gint
pop3_retr_send(Pop3Session
*session
)
343 session
->state
= POP3_RETR
;
344 debug_print("retrieving %d [%s]\n", session
->cur_msg
,
345 session
->msg
[session
->cur_msg
].uidl
?
346 session
->msg
[session
->cur_msg
].uidl
:" ");
347 pop3_gen_send(session
, "RETR %d", session
->cur_msg
);
351 static gint
pop3_retr_recv(Pop3Session
*session
, const gchar
*data
, guint len
)
355 MailReceiveData mail_receive_data
;
357 /* NOTE: we allocate a slightly larger buffer with a zero terminator
358 * because some plugins may think that it has a C string. */
359 mail_receive_data
.session
= session
;
360 mail_receive_data
.data
= g_new0(gchar
, len
+ 1);
361 mail_receive_data
.data_len
= len
;
362 memcpy(mail_receive_data
.data
, data
, len
);
364 hooks_invoke(MAIL_RECEIVE_HOOKLIST
, &mail_receive_data
);
366 file
= get_tmp_file();
367 if (pop3_write_msg_to_file(file
, mail_receive_data
.data
,
368 mail_receive_data
.data_len
, NULL
) < 0) {
370 g_free(mail_receive_data
.data
);
371 session
->error_val
= PS_IOERR
;
374 g_free(mail_receive_data
.data
);
376 if (session
->msg
[session
->cur_msg
].partial_recv
377 == POP3_MUST_COMPLETE_RECV
) {
378 gchar
*old_file
= partial_get_filename(
379 session
->ac_prefs
->recv_server
,
380 session
->ac_prefs
->userid
,
381 session
->msg
[session
->cur_msg
].uidl
);
384 partial_delete_old(old_file
);
389 /* drop_ok: 0: success 1: don't receive -1: error */
390 drop_ok
= session
->drop_message(session
, file
);
394 session
->error_val
= PS_IOERR
;
398 session
->cur_total_bytes
+= session
->msg
[session
->cur_msg
].size
;
399 session
->cur_total_recv_bytes
+= session
->msg
[session
->cur_msg
].size
;
400 session
->cur_total_num
++;
402 session
->msg
[session
->cur_msg
].received
= TRUE
;
403 session
->msg
[session
->cur_msg
].partial_recv
= POP3_TOTALLY_RECEIVED
;
405 session
->msg
[session
->cur_msg
].recv_time
=
406 drop_ok
== 1 ? RECV_TIME_KEEP
: session
->current_time
;
411 static gint
pop3_top_send(Pop3Session
*session
, gint max_size
)
413 gint num_lines
= (max_size
*1024)/82; /* consider lines to be 80 chars */
414 session
->state
= POP3_TOP
;
415 pop3_gen_send(session
, "TOP %d %d", session
->cur_msg
, num_lines
);
419 static gint
pop3_top_recv(Pop3Session
*session
, const gchar
*data
, guint len
)
423 MailReceiveData mail_receive_data
;
424 gchar
*partial_notice
= NULL
;
426 /* NOTE: we allocate a slightly larger buffer with a zero terminator
427 * because some plugins may think that it has a C string. */
428 mail_receive_data
.session
= session
;
429 mail_receive_data
.data
= g_new0(gchar
, len
+ 1);
430 mail_receive_data
.data_len
= len
;
431 memcpy(mail_receive_data
.data
, data
, len
);
433 hooks_invoke(MAIL_RECEIVE_HOOKLIST
, &mail_receive_data
);
435 partial_notice
= g_strdup_printf("SC-Marked-For-Download: 0\n"
436 "SC-Partially-Retrieved: %s\n"
437 "SC-Account-Server: %s\n"
438 "SC-Account-Login: %s\n"
439 "SC-Message-Size: %d",
440 session
->msg
[session
->cur_msg
].uidl
,
441 session
->ac_prefs
->recv_server
,
442 session
->ac_prefs
->userid
,
443 session
->msg
[session
->cur_msg
].size
);
444 file
= get_tmp_file();
445 if (pop3_write_msg_to_file(file
, mail_receive_data
.data
,
446 mail_receive_data
.data_len
,
447 partial_notice
) < 0) {
449 g_free(mail_receive_data
.data
);
450 session
->error_val
= PS_IOERR
;
451 g_free(partial_notice
);
454 g_free(mail_receive_data
.data
);
455 g_free(partial_notice
);
457 /* drop_ok: 0: success 1: don't receive -1: error */
458 drop_ok
= session
->drop_message(session
, file
);
461 session
->error_val
= PS_IOERR
;
465 session
->cur_total_bytes
+= session
->msg
[session
->cur_msg
].size
;
466 session
->cur_total_recv_bytes
+= session
->msg
[session
->cur_msg
].size
;
467 session
->cur_total_num
++;
469 session
->msg
[session
->cur_msg
].received
= TRUE
;
470 session
->msg
[session
->cur_msg
].partial_recv
= POP3_PARTIALLY_RECEIVED
;
471 session
->msg
[session
->cur_msg
].recv_time
=
472 drop_ok
== 1 ? RECV_TIME_KEEP
: session
->current_time
;
477 static gint
pop3_delete_send(Pop3Session
*session
)
479 session
->state
= POP3_DELETE
;
480 pop3_gen_send(session
, "DELE %d", session
->cur_msg
);
484 static gint
pop3_delete_recv(Pop3Session
*session
)
486 session
->msg
[session
->cur_msg
].deleted
= TRUE
;
490 static gint
pop3_logout_send(Pop3Session
*session
)
492 session
->state
= POP3_LOGOUT
;
493 pop3_gen_send(session
, "QUIT");
497 static void pop3_gen_send(Pop3Session
*session
, const gchar
*format
, ...)
499 gchar buf
[POPBUFSIZE
+ 1];
502 va_start(args
, format
);
503 g_vsnprintf(buf
, sizeof(buf
) - 2, format
, args
);
506 if (!g_ascii_strncasecmp(buf
, "PASS ", 5))
507 log_print(LOG_PROTOCOL
, "POP3> PASS ********\n");
509 log_print(LOG_PROTOCOL
, "POP3> %s\n", buf
);
511 session_send_msg(SESSION(session
), SESSION_MSG_NORMAL
, buf
);
514 Session
*pop3_session_new(PrefsAccount
*account
)
516 Pop3Session
*session
;
518 g_return_val_if_fail(account
!= NULL
, NULL
);
520 session
= g_new0(Pop3Session
, 1);
522 session_init(SESSION(session
));
524 SESSION(session
)->type
= SESSION_POP3
;
526 SESSION(session
)->recv_msg
= pop3_session_recv_msg
;
527 SESSION(session
)->recv_data_finished
= pop3_session_recv_data_finished
;
528 SESSION(session
)->send_data_finished
= NULL
;
530 SESSION(session
)->destroy
= pop3_session_destroy
;
532 session
->state
= POP3_READY
;
533 session
->ac_prefs
= account
;
534 session
->pop_before_smtp
= FALSE
;
535 pop3_get_uidl_table(account
, session
);
536 session
->current_time
= time(NULL
);
537 session
->error_val
= PS_SUCCESS
;
538 session
->error_msg
= NULL
;
540 return SESSION(session
);
543 static void pop3_session_destroy(Session
*session
)
545 Pop3Session
*pop3_session
= POP3_SESSION(session
);
548 g_return_if_fail(session
!= NULL
);
550 for (n
= 1; n
<= pop3_session
->count
; n
++)
551 g_free(pop3_session
->msg
[n
].uidl
);
552 g_free(pop3_session
->msg
);
554 if (pop3_session
->uidl_table
) {
555 hash_free_strings(pop3_session
->uidl_table
);
556 g_hash_table_destroy(pop3_session
->uidl_table
);
559 if (pop3_session
->partial_recv_table
) {
560 hash_free_strings(pop3_session
->partial_recv_table
);
561 g_hash_table_destroy(pop3_session
->partial_recv_table
);
564 g_free(pop3_session
->greeting
);
565 g_free(pop3_session
->user
);
566 g_free(pop3_session
->pass
);
567 g_free(pop3_session
->error_msg
);
570 void pop3_get_uidl_table(PrefsAccount
*ac_prefs
, Pop3Session
*session
)
573 GHashTable
*partial_recv_table
;
576 gchar buf
[POPBUFSIZE
];
577 gchar uidl
[POPBUFSIZE
];
581 gchar
*sanitized_uid
= g_strdup(ac_prefs
->userid
);
583 subst_for_filename(sanitized_uid
);
585 table
= g_hash_table_new(g_str_hash
, g_str_equal
);
586 partial_recv_table
= g_hash_table_new(g_str_hash
, g_str_equal
);
588 path
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
589 "uidl", G_DIR_SEPARATOR_S
, ac_prefs
->recv_server
,
590 "-", sanitized_uid
, NULL
);
592 g_free(sanitized_uid
);
593 if ((fp
= g_fopen(path
, "rb")) == NULL
) {
594 if (ENOENT
!= errno
) FILE_OP_ERROR(path
, "fopen");
596 path
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
597 "uidl-", ac_prefs
->recv_server
,
598 "-", ac_prefs
->userid
, NULL
);
599 if ((fp
= g_fopen(path
, "rb")) == NULL
) {
600 if (ENOENT
!= errno
) FILE_OP_ERROR(path
, "fopen");
602 session
->uidl_table
= table
;
603 session
->partial_recv_table
= partial_recv_table
;
611 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
612 gchar tmp
[POPBUFSIZE
];
614 recv_time
= RECV_TIME_NONE
;
615 partial_recv
= POP3_TOTALLY_RECEIVED
;
617 if (sscanf(buf
, "%s\t%ld\t%s", uidl
, (long int *) &recv_time
, tmp
) < 3) {
618 if (sscanf(buf
, "%s\t%ld", uidl
, (long int *) &recv_time
) != 2) {
619 if (sscanf(buf
, "%s", uidl
) != 1)
630 if (recv_time
== RECV_TIME_NONE
)
631 recv_time
= RECV_TIME_RECEIVED
;
632 g_hash_table_insert(table
, g_strdup(uidl
),
633 GINT_TO_POINTER(recv_time
));
634 if (strlen(tmp
) == 1)
635 partial_recv
= atoi(tmp
); /* totally received ?*/
637 partial_recv
= POP3_MUST_COMPLETE_RECV
;
639 g_hash_table_insert(partial_recv_table
, g_strdup(uidl
),
640 GINT_TO_POINTER(partial_recv
));
644 session
->uidl_table
= table
;
645 session
->partial_recv_table
= partial_recv_table
;
653 g_warning("failed to write\n"); \
657 gint pop3_write_uidl_list(Pop3Session *session)
659 gchar
*path
, *tmp_path
;
663 gchar
*sanitized_uid
= g_strdup(session
->ac_prefs
->userid
);
665 subst_for_filename(sanitized_uid
);
668 if (!session
->uidl_is_valid
) return 0;
670 path
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
671 "uidl", G_DIR_SEPARATOR_S
,
672 session
->ac_prefs
->recv_server
,
673 "-", sanitized_uid
, NULL
);
674 tmp_path
= g_strconcat(path
, ".tmp", NULL
);
676 g_free(sanitized_uid
);
678 if ((fp
= g_fopen(tmp_path
, "wb")) == NULL
) {
679 FILE_OP_ERROR(tmp_path
, "fopen");
683 for (n
= 1; n
<= session
->count
; n
++) {
684 msg
= &session
->msg
[n
];
685 if (msg
->uidl
&& msg
->received
&&
686 (!msg
->deleted
|| session
->state
!= POP3_DONE
))
687 TRY(fprintf(fp
, "%s\t%ld\t%d\n",
688 msg
->uidl
, (long int)
694 if (fclose(fp
) == EOF
) {
695 FILE_OP_ERROR(tmp_path
, "fclose");
703 if (g_rename(tmp_path
, path
) < 0) {
704 FILE_OP_ERROR(path
, "rename");
720 static gint
pop3_write_msg_to_file(const gchar
*file
, const gchar
*data
,
721 guint len
, const gchar
*prefix
)
724 const gchar
*prev
, *cur
;
726 g_return_val_if_fail(file
!= NULL
, -1);
728 if ((fp
= g_fopen(file
, "wb")) == NULL
) {
729 FILE_OP_ERROR(file
, "fopen");
733 if (change_file_mode_rw(fp
, file
) < 0)
734 FILE_OP_ERROR(file
, "chmod");
736 if (prefix
!= NULL
) {
737 fprintf(fp
, "%s", prefix
);
741 /* +------------------+----------------+--------------------------+ *
742 * ^data ^prev ^cur data+len-1^ */
745 while ((cur
= (gchar
*)my_memmem(prev
, len
- (prev
- data
), "\r\n", 2))
747 if ((cur
> prev
&& fwrite(prev
, 1, cur
- prev
, fp
) < 1) ||
748 fputc('\n', fp
) == EOF
) {
749 FILE_OP_ERROR(file
, "fwrite");
750 g_warning("can't write to file: %s\n", file
);
756 if (cur
== data
+ len
- 1) {
761 if (*(cur
+ 1) == '\n')
766 if (prev
- data
< len
- 1 && *prev
== '.' && *(prev
+ 1) == '.')
769 if (prev
- data
>= len
)
773 if (prev
- data
< len
&&
774 fwrite(prev
, 1, len
- (prev
- data
), fp
) < 1) {
775 FILE_OP_ERROR(file
, "fwrite");
776 g_warning("can't write to file: %s\n", file
);
781 if (data
[len
- 1] != '\r' && data
[len
- 1] != '\n') {
782 if (fputc('\n', fp
) == EOF
) {
783 FILE_OP_ERROR(file
, "fputc");
784 g_warning("can't write to file: %s\n", file
);
791 if (fclose(fp
) == EOF
) {
792 FILE_OP_ERROR(file
, "fclose");
800 static Pop3State
pop3_lookup_next(Pop3Session
*session
)
803 PrefsAccount
*ac
= session
->ac_prefs
;
805 gboolean size_limit_over
;
808 msg
= &session
->msg
[session
->cur_msg
];
811 (ac
->enable_size_limit
&&
812 ac
->size_limit
> 0 &&
813 size
> ac
->size_limit
* 1024);
816 msg
->recv_time
!= RECV_TIME_NONE
&&
817 msg
->recv_time
!= RECV_TIME_KEEP
&&
818 msg
->partial_recv
== POP3_TOTALLY_RECEIVED
&&
819 session
->current_time
- msg
->recv_time
>=
820 ac
->msg_leave_time
* 24 * 60 * 60) {
821 log_message(LOG_PROTOCOL
,
822 _("POP3: Deleting expired message %d [%s]\n"),
823 session
->cur_msg
, msg
->uidl
?msg
->uidl
:" ");
824 session
->cur_total_bytes
+= size
;
825 pop3_delete_send(session
);
829 if (size_limit_over
) {
830 if (!msg
->received
&& msg
->partial_recv
!=
831 POP3_MUST_COMPLETE_RECV
) {
832 pop3_top_send(session
, ac
->size_limit
);
834 } else if (msg
->partial_recv
== POP3_MUST_COMPLETE_RECV
)
837 log_message(LOG_PROTOCOL
,
838 _("POP3: Skipping message %d [%s] (%d bytes)\n"),
839 session
->cur_msg
, msg
->uidl
?msg
->uidl
:" ", size
);
842 if (size
== 0 || msg
->received
|| size_limit_over
) {
843 session
->cur_total_bytes
+= size
;
844 if (session
->cur_msg
== session
->count
) {
845 pop3_logout_send(session
);
853 pop3_retr_send(session
);
857 static Pop3ErrorValue
pop3_ok(Pop3Session
*session
, const gchar
*msg
)
861 log_print(LOG_PROTOCOL
, "POP3< %s\n", msg
);
863 if (!strncmp(msg
, "+OK", 3))
865 else if (!strncmp(msg
, "-ERR", 4)) {
866 if (strstr(msg
+ 4, "lock") ||
867 strstr(msg
+ 4, "Lock") ||
868 strstr(msg
+ 4, "LOCK") ||
869 strstr(msg
+ 4, "wait")) {
870 log_error(LOG_PROTOCOL
, _("mailbox is locked\n"));
872 } else if (strcasestr(msg
+ 4, "timeout")) {
873 log_error(LOG_PROTOCOL
, _("Session timeout\n"));
876 switch (session
->state
) {
879 log_error(LOG_PROTOCOL
, _("couldn't start TLS session\n"));
883 case POP3_GETAUTH_USER
:
884 case POP3_GETAUTH_PASS
:
885 case POP3_GETAUTH_APOP
:
886 log_error(LOG_PROTOCOL
, _("error occurred on authentication\n"));
889 case POP3_GETRANGE_LAST
:
890 case POP3_GETRANGE_UIDL
:
892 log_warning(LOG_PROTOCOL
, _("command not supported\n"));
893 ok
= PS_NOTSUPPORTED
;
897 log_error(LOG_PROTOCOL
, _("error occurred on POP3 session\n"));
902 g_free(session
->error_msg
);
903 session
->error_msg
= g_strdup(msg
);
904 g_printerr("POP3: %s\n", msg
);
908 session
->error_val
= ok
;
912 static gint
pop3_session_recv_msg(Session
*session
, const gchar
*msg
)
914 Pop3Session
*pop3_session
= POP3_SESSION(session
);
915 Pop3ErrorValue val
= PS_SUCCESS
;
919 if (pop3_session
->state
!= POP3_GETRANGE_UIDL_RECV
&&
920 pop3_session
->state
!= POP3_GETSIZE_LIST_RECV
) {
921 val
= pop3_ok(pop3_session
, msg
);
922 if (val
!= PS_SUCCESS
) {
923 if (val
!= PS_NOTSUPPORTED
) {
924 pop3_session
->state
= POP3_ERROR
;
929 if (*body
== '+' || *body
== '-')
931 while (g_ascii_isalpha(*body
))
933 while (g_ascii_isspace(*body
))
937 switch (pop3_session
->state
) {
940 pop3_greeting_recv(pop3_session
, body
);
942 if (pop3_session
->ac_prefs
->ssl_pop
== SSL_STARTTLS
)
943 val
= pop3_stls_send(pop3_session
);
946 if (pop3_session
->ac_prefs
->use_apop_auth
)
947 val
= pop3_getauth_apop_send(pop3_session
);
949 val
= pop3_getauth_user_send(pop3_session
);
953 if (pop3_stls_recv(pop3_session
) != PS_SUCCESS
)
955 if (pop3_session
->ac_prefs
->use_apop_auth
)
956 val
= pop3_getauth_apop_send(pop3_session
);
958 val
= pop3_getauth_user_send(pop3_session
);
961 case POP3_GETAUTH_USER
:
962 val
= pop3_getauth_pass_send(pop3_session
);
964 case POP3_GETAUTH_PASS
:
965 case POP3_GETAUTH_APOP
:
966 if (!pop3_session
->pop_before_smtp
)
967 val
= pop3_getrange_stat_send(pop3_session
);
969 val
= pop3_logout_send(pop3_session
);
971 case POP3_GETRANGE_STAT
:
972 if (pop3_getrange_stat_recv(pop3_session
, body
) < 0)
974 if (pop3_session
->count
> 0)
975 val
= pop3_getrange_uidl_send(pop3_session
);
977 val
= pop3_logout_send(pop3_session
);
979 case POP3_GETRANGE_LAST
:
980 if (val
== PS_NOTSUPPORTED
)
981 pop3_session
->error_val
= PS_SUCCESS
;
982 else if (pop3_getrange_last_recv(pop3_session
, body
) < 0)
984 if (pop3_session
->cur_msg
> 0)
985 val
= pop3_getsize_list_send(pop3_session
);
987 val
= pop3_logout_send(pop3_session
);
989 case POP3_GETRANGE_UIDL
:
990 if (val
== PS_NOTSUPPORTED
) {
991 pop3_session
->error_val
= PS_SUCCESS
;
992 val
= pop3_getrange_last_send(pop3_session
);
994 pop3_session
->state
= POP3_GETRANGE_UIDL_RECV
;
995 session_recv_data(session
, 0, ".\r\n");
998 case POP3_GETSIZE_LIST
:
999 pop3_session
->state
= POP3_GETSIZE_LIST_RECV
;
1000 session_recv_data(session
, 0, ".\r\n");
1003 pop3_session
->state
= POP3_RETR_RECV
;
1004 session_recv_data(session
, 0, ".\r\n");
1007 if (val
== PS_NOTSUPPORTED
) {
1008 pop3_session
->error_val
= PS_SUCCESS
;
1010 pop3_session
->state
= POP3_TOP_RECV
;
1011 session_recv_data(session
, 0, ".\r\n");
1015 pop3_delete_recv(pop3_session
);
1016 if (pop3_session
->cur_msg
== pop3_session
->count
)
1017 val
= pop3_logout_send(pop3_session
);
1019 pop3_session
->cur_msg
++;
1020 if (pop3_lookup_next(pop3_session
) == POP3_ERROR
)
1025 pop3_session
->state
= POP3_DONE
;
1026 session_disconnect(session
);
1033 return val
== PS_SUCCESS
?0:-1;
1036 static gint
pop3_session_recv_data_finished(Session
*session
, guchar
*data
,
1039 Pop3Session
*pop3_session
= POP3_SESSION(session
);
1040 Pop3ErrorValue val
= PS_SUCCESS
;
1042 switch (pop3_session
->state
) {
1043 case POP3_GETRANGE_UIDL_RECV
:
1044 val
= pop3_getrange_uidl_recv(pop3_session
, data
, len
);
1045 if (val
== PS_SUCCESS
) {
1046 if (pop3_session
->new_msg_exist
)
1047 pop3_getsize_list_send(pop3_session
);
1049 pop3_logout_send(pop3_session
);
1053 case POP3_GETSIZE_LIST_RECV
:
1054 val
= pop3_getsize_list_recv(pop3_session
, data
, len
);
1055 if (val
== PS_SUCCESS
) {
1056 if (pop3_lookup_next(pop3_session
) == POP3_ERROR
)
1061 case POP3_RETR_RECV
:
1062 if (pop3_retr_recv(pop3_session
, data
, len
) < 0)
1065 if (pop3_session
->ac_prefs
->rmmail
&&
1066 pop3_session
->ac_prefs
->msg_leave_time
== 0 &&
1067 pop3_session
->msg
[pop3_session
->cur_msg
].recv_time
1069 pop3_delete_send(pop3_session
);
1070 else if (pop3_session
->cur_msg
== pop3_session
->count
)
1071 pop3_logout_send(pop3_session
);
1073 pop3_session
->cur_msg
++;
1074 if (pop3_lookup_next(pop3_session
) == POP3_ERROR
)
1079 if (pop3_top_recv(pop3_session
, data
, len
) < 0)
1082 if (pop3_session
->cur_msg
== pop3_session
->count
)
1083 pop3_logout_send(pop3_session
);
1085 pop3_session
->cur_msg
++;
1086 if (pop3_lookup_next(pop3_session
) == POP3_ERROR
)
1091 log_warning(LOG_PROTOCOL
, _("TOP command unsupported\n"));
1092 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
)