updated selective download
[claws.git] / src / pop.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2002 Hiroyuki Yamamoto
4  *
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 2 of the License, or
8  * (at your option) any later version.
9  *
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.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <glib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <ctype.h>
29 #include <unistd.h>
30
31 #include "intl.h"
32 #include "pop.h"
33 #include "socket.h"
34 #include "md5.h"
35 #include "prefs_account.h"
36 #include "utils.h"
37 #include "inc.h"
38 #include "recv.h"
39 #include "selective_download.h"
40 #if USE_SSL
41 #  include "ssl.h"
42 #endif
43
44 #define LOOKUP_NEXT_MSG() \
45         for (;;) { \
46                 gint size = state->msg[state->cur_msg].size; \
47                 gboolean size_limit_over = \
48                     (state->ac_prefs->enable_size_limit && \
49                      state->ac_prefs->size_limit > 0 && \
50                      size > state->ac_prefs->size_limit * 1024); \
51  \
52                 if (size_limit_over) \
53                         log_print(_("POP3: Skipping message %d (%d bytes)\n"), \
54                                   state->cur_msg, size); \
55  \
56                 if (size == 0 || state->msg[state->cur_msg].received || \
57                     size_limit_over) { \
58                         if (size > 0) \
59                                 state->cur_total_bytes += size; \
60                         if (state->cur_msg == state->count) \
61                                 return POP3_LOGOUT_SEND; \
62                         else \
63                                 state->cur_msg++; \
64                 } else \
65                         break; \
66         }
67
68 static gint pop3_ok(SockInfo *sock, gchar *argbuf);
69 static void pop3_gen_send(SockInfo *sock, const gchar *format, ...);
70 static gint pop3_gen_recv(SockInfo *sock, gchar *buf, gint size);
71 static gboolean pop3_sd_get_next (Pop3State *state);
72 static void pop3_sd_new_header(Pop3State *state);
73 gboolean pop3_sd_state(Pop3State *state, gint cur_state, guint *next_state);
74 static gboolean should_delete (const char *uidl, gpointer data); 
75
76 gint pop3_greeting_recv(SockInfo *sock, gpointer data)
77 {
78         Pop3State *state = (Pop3State *)data;
79         gchar buf[POPBUFSIZE];
80
81         if (pop3_ok(sock, buf) == PS_SUCCESS) {
82 #if USE_SSL
83                 if (state->ac_prefs->ssl_pop == SSL_STARTTLS) {
84                         state->greeting = g_strdup(buf);
85                         return POP3_STLS_SEND;
86                 }
87 #endif
88                 if (state->ac_prefs->protocol == A_APOP) {
89                         state->greeting = g_strdup(buf);
90                         return POP3_GETAUTH_APOP_SEND;
91                 } else
92                         return POP3_GETAUTH_USER_SEND;
93         } else
94                 return -1;
95 }
96
97 #if USE_SSL
98 gint pop3_stls_send(SockInfo *sock, gpointer data)
99 {
100         pop3_gen_send(sock, "STLS");
101
102         return POP3_STLS_RECV;
103 }
104
105 gint pop3_stls_recv(SockInfo *sock, gpointer data)
106 {
107         Pop3State *state = (Pop3State *)data;
108         gint ok;
109
110         if ((ok = pop3_ok(sock, NULL)) == PS_SUCCESS) {
111                 if (!ssl_init_socket_with_method(sock, SSL_METHOD_TLSv1))
112                         return -1;
113                 if (state->ac_prefs->protocol == A_APOP) {
114                         return POP3_GETAUTH_APOP_SEND;
115                 } else
116                         return POP3_GETAUTH_USER_SEND;
117         } else if (ok == PS_PROTOCOL) {
118                 log_warning(_("can't start TLS session\n"));
119                 state->error_val = PS_PROTOCOL;
120                 state->inc_state = INC_ERROR;
121                 return POP3_LOGOUT_SEND;
122         } else
123                 return -1;
124 }
125 #endif /* USE_SSL */
126
127 gint pop3_getauth_user_send(SockInfo *sock, gpointer data)
128 {
129         Pop3State *state = (Pop3State *)data;
130
131         g_return_val_if_fail(state->user != NULL, -1);
132
133         pop3_gen_send(sock, "USER %s", state->user);
134
135         return POP3_GETAUTH_USER_RECV;
136 }
137
138 gint pop3_getauth_user_recv(SockInfo *sock, gpointer data)
139 {
140         Pop3State *state = (Pop3State *)data;
141
142         if (pop3_ok(sock, NULL) == PS_SUCCESS)
143                 return POP3_GETAUTH_PASS_SEND;
144         else {
145                 log_warning(_("error occurred on authentication\n"));
146                 state->error_val = PS_AUTHFAIL;
147                 state->inc_state = INC_AUTH_FAILED;
148                 return -1;
149         }
150 }
151
152 gint pop3_getauth_pass_send(SockInfo *sock, gpointer data)
153 {
154         Pop3State *state = (Pop3State *)data;
155
156         g_return_val_if_fail(state->pass != NULL, -1);
157
158         pop3_gen_send(sock, "PASS %s", state->pass);
159
160         return POP3_GETAUTH_PASS_RECV;
161 }
162
163 gint pop3_getauth_pass_recv(SockInfo *sock, gpointer data)
164 {
165         Pop3State *state = (Pop3State *)data;
166
167         if (pop3_ok(sock, NULL) == PS_SUCCESS) 
168                 return POP3_GETRANGE_STAT_SEND;
169         
170         else {
171                 log_warning(_("error occurred on authentication\n"));
172                 state->error_val = PS_AUTHFAIL;
173                 state->inc_state = INC_AUTH_FAILED;
174                 return -1;
175         }
176 }
177
178 gint pop3_getauth_apop_send(SockInfo *sock, gpointer data)
179 {
180         Pop3State *state = (Pop3State *)data;
181         gchar *start, *end;
182         gchar *apop_str;
183         gchar md5sum[33];
184
185         g_return_val_if_fail(state->user != NULL, -1);
186         g_return_val_if_fail(state->pass != NULL, -1);
187
188         if ((start = strchr(state->greeting, '<')) == NULL) {
189                 log_warning(_("Required APOP timestamp not found "
190                               "in greeting\n"));
191                 return -1;
192         }
193
194         if ((end = strchr(start, '>')) == NULL || end == start + 1) {
195                 log_warning(_("Timestamp syntax error in greeting\n"));
196                 return -1;
197         }
198
199         *(end + 1) = '\0';
200
201         apop_str = g_strconcat(start, state->pass, NULL);
202         md5_hex_digest(md5sum, apop_str);
203         g_free(apop_str);
204
205         pop3_gen_send(sock, "APOP %s %s", state->user, md5sum);
206
207         return POP3_GETAUTH_APOP_RECV;
208 }
209
210 gint pop3_getauth_apop_recv(SockInfo *sock, gpointer data)
211 {
212         Pop3State *state = (Pop3State *)data;
213
214         if (pop3_ok(sock, NULL) == PS_SUCCESS) 
215                 return POP3_GETRANGE_STAT_SEND;
216
217         else {
218                 log_warning(_("error occurred on authentication\n"));
219                 state->error_val = PS_AUTHFAIL;
220                 state->inc_state = INC_AUTH_FAILED;
221                 return -1;
222         }
223 }
224
225 gint pop3_getrange_stat_send(SockInfo *sock, gpointer data)
226 {
227         pop3_gen_send(sock, "STAT");
228
229         return POP3_GETRANGE_STAT_RECV;
230 }
231
232 gint pop3_getrange_stat_recv(SockInfo *sock, gpointer data)
233 {
234         Pop3State *state = (Pop3State *)data;
235         gchar buf[POPBUFSIZE + 1];
236         gint ok;
237
238         if ((ok = pop3_ok(sock, buf)) == PS_SUCCESS) {
239                 if (sscanf(buf, "%d %d", &state->count, &state->total_bytes)
240                     != 2) {
241                         log_warning(_("POP3 protocol error\n"));
242                         return -1;
243                 } else {
244                         if (state->count == 0) {
245                                 state->uidl_is_valid = TRUE;
246                                 return POP3_LOGOUT_SEND;
247                         } else {
248                                 state->msg = g_new0
249                                         (Pop3MsgInfo, state->count + 1);
250                                 state->cur_msg = 1;
251                                 return POP3_GETRANGE_UIDL_SEND;
252                         }
253                 }
254         } else if (ok == PS_PROTOCOL)
255                 return POP3_LOGOUT_SEND;
256         else
257                 return -1;
258 }
259
260 gint pop3_getrange_last_send(SockInfo *sock, gpointer data)
261 {
262         pop3_gen_send(sock, "LAST");
263
264         return POP3_GETRANGE_LAST_RECV;
265 }
266
267 gint pop3_getrange_last_recv(SockInfo *sock, gpointer data)
268 {
269         Pop3State *state = (Pop3State *)data;
270         gchar buf[POPBUFSIZE + 1];
271
272         if (pop3_ok(sock, buf) == PS_SUCCESS) {
273                 gint last;
274
275                 if (sscanf(buf, "%d", &last) == 0) {
276                         log_warning(_("POP3 protocol error\n"));
277                         return -1;
278                 } else {
279                         if (state->count == last)
280                                 return POP3_LOGOUT_SEND;
281                         else {
282                                 state->cur_msg = last + 1;
283                                 return POP3_GETSIZE_LIST_SEND;
284                         }
285                 }
286         } else
287                 return POP3_GETSIZE_LIST_SEND;
288 }
289
290 gint pop3_getrange_uidl_send(SockInfo *sock, gpointer data)
291 {
292         pop3_gen_send(sock, "UIDL");
293
294         return POP3_GETRANGE_UIDL_RECV;
295 }
296
297 gint pop3_getrange_uidl_recv(SockInfo *sock, gpointer data)
298 {
299         Pop3State *state = (Pop3State *)data;
300         gboolean new = FALSE;
301         gboolean get_all = FALSE;
302         gchar buf[POPBUFSIZE];
303         gchar id[IDLEN + 1];
304         gint next_state;
305
306         if (!state->uidl_table) new = TRUE;
307         if (state->ac_prefs->getall)
308                 get_all = TRUE;
309
310         if (pop3_ok(sock, NULL) != PS_SUCCESS) {
311                 /* UIDL is not supported */
312                 if (pop3_sd_state(state, POP3_GETRANGE_UIDL_RECV, &next_state))
313                         return next_state;
314
315                 if (!get_all)
316                         return POP3_GETRANGE_LAST_SEND;
317                 else
318                         return POP3_GETSIZE_LIST_SEND;
319         }
320
321         while (sock_gets(sock, buf, sizeof(buf)) >= 0) {
322                 gint num;
323
324                 if (buf[0] == '.') break;
325                 if (sscanf(buf, "%d %" Xstr(IDLEN) "s", &num, id) != 2)
326                         continue;
327                 if (num <= 0 || num > state->count) continue;
328
329                 state->msg[num].uidl = g_strdup(id);
330
331                 if (state->uidl_table) {
332                         if (!get_all &&
333                             g_hash_table_lookup(state->uidl_table, id) != NULL)
334                                 state->msg[num].received = TRUE;
335                         else {
336                                 if (new == FALSE) {
337                                         state->cur_msg = num;
338                                         new = TRUE;
339                                 }
340                         }
341                 }
342
343                 if (should_delete(buf, (Pop3State *) state))
344                         state->uidl_todelete_list = g_slist_append
345                                         (state->uidl_todelete_list, g_strdup(buf));             
346                 
347         }
348
349         state->uidl_is_valid = TRUE;
350
351         if (pop3_sd_state(state, POP3_GETRANGE_UIDL_RECV, &next_state))
352                 return next_state;
353
354         if (new == TRUE)
355                 return POP3_GETSIZE_LIST_SEND;
356         else
357                 return POP3_LOGOUT_SEND;
358 }
359
360 static gboolean should_delete(const char *uidl, gpointer data) 
361 {
362         /* answer[0] will contain id
363          * answer[0] will contain uidl */
364         Pop3State *state = (Pop3State *) data;
365         gchar **answer;
366         int  id;
367         gboolean result;
368         int tdate, keep_for, today, nb_days;
369         const gchar *sdate;
370         GDate curdate;
371         gchar *tuidl;
372
373         if (!state->ac_prefs->rmmail || !strchr(uidl, ' '))
374                 return FALSE;
375
376         /* remove \r\n */
377         tuidl  = g_strndup(uidl, strlen(uidl) - 2);
378         answer = g_strsplit(tuidl, " ", 2);
379         id     = atoi(answer[0]);
380
381         if (NULL != (sdate = g_hash_table_lookup(state->uidl_table, answer[1]))) {
382                 tdate    = atoi(sdate);
383                 keep_for = atoi(state->ac_prefs->leave_time); /* FIXME: leave time should be an int */
384
385                 g_date_clear(&curdate, 1);
386                 g_date_set_time(&curdate, time(NULL));
387                 today = g_date_day_of_year(&curdate);
388                 
389                 nb_days = g_date_is_leap_year(g_date_year(&curdate)) ? 366 : 365;
390                 result  = ((tdate + keep_for) % nb_days <= today);
391         } else
392                 result = FALSE;
393
394         g_free(tuidl);
395         g_strfreev(answer);
396         
397         return result;
398 }
399
400 gint pop3_getsize_list_send(SockInfo *sock, gpointer data)
401 {
402         pop3_gen_send(sock, "LIST");
403
404         return POP3_GETSIZE_LIST_RECV;
405 }
406
407 gint pop3_getsize_list_recv(SockInfo *sock, gpointer data)
408 {
409         Pop3State *state = (Pop3State *)data;
410         gchar buf[POPBUFSIZE];
411         gint next_state;
412
413         if (pop3_ok(sock, NULL) != PS_SUCCESS) return POP3_LOGOUT_SEND;
414
415         state->cur_total_bytes = 0;
416
417         while (sock_gets(sock, buf, sizeof(buf)) >= 0) {
418                 guint num, size;
419
420                 if (buf[0] == '.') break;
421                 if (sscanf(buf, "%u %u", &num, &size) != 2)
422                         return -1;
423
424                 if (num > 0 && num <= state->count)
425                         state->msg[num].size = size;
426                 if (num > 0 && num < state->cur_msg)
427                         state->cur_total_bytes += size;
428         }
429
430         if (pop3_sd_state(state, POP3_GETSIZE_LIST_RECV, &next_state))
431                 return next_state;
432
433         LOOKUP_NEXT_MSG();      
434         return POP3_RETR_SEND;
435 }
436  
437 gint pop3_top_send(SockInfo *sock, gpointer data)
438 {
439         Pop3State *state = (Pop3State *)data;
440
441         inc_progress_update(state, POP3_TOP_SEND); 
442
443         pop3_gen_send(sock, "TOP %i 0", state->cur_msg );
444
445         return POP3_TOP_RECV;
446 }
447
448 gint pop3_top_recv(SockInfo *sock, gpointer data)
449 {
450         Pop3State *state = (Pop3State *)data;
451         gchar *filename, *path;
452         gint next_state;
453         
454         if (pop3_ok(sock, NULL) != PS_SUCCESS) 
455                 return POP3_LOGOUT_SEND;
456
457         path = g_strconcat(get_header_cache_dir(), G_DIR_SEPARATOR_S, NULL);
458
459         if ( !is_dir_exist(path) )
460                 make_dir_hier(path);
461         
462         filename = g_strdup_printf("%s%i", path, state->cur_msg);
463                                    
464         if (recv_write_to_file(sock, filename) < 0) {
465                 state->inc_state = INC_NOSPACE;
466                 return -1;
467         }
468
469         pop3_sd_state(state, POP3_TOP_RECV, &next_state);
470         
471         if (state->cur_msg < state->count) {
472                 state->cur_msg++;
473                 return POP3_TOP_SEND;
474         } else
475                 return POP3_LOGOUT_SEND;
476 }
477
478 gint pop3_retr_send(SockInfo *sock, gpointer data)
479 {
480         Pop3State *state = (Pop3State *)data;
481
482         pop3_gen_send(sock, "RETR %d", state->cur_msg);
483
484         return POP3_RETR_RECV;
485 }
486
487 gint pop3_retr_recv(SockInfo *sock, gpointer data)
488 {
489         Pop3State *state = (Pop3State *)data;
490         const gchar *file;
491         gint ok, drop_ok;
492         gint next_state;
493         int keep_for;
494         
495         if ((ok = pop3_ok(sock, NULL)) == PS_SUCCESS) {
496                 if (recv_write_to_file(sock, (file = get_tmp_file())) < 0) {
497                         if (state->inc_state == INC_SUCCESS)
498                                 state->inc_state = INC_NOSPACE;
499                         return -1;
500                 }
501
502                 if ((drop_ok = inc_drop_message(file, state)) < 0) {
503                         state->inc_state = INC_ERROR;
504                         return -1;
505                 }
506
507                 if (pop3_sd_state(state, POP3_RETR_RECV, &next_state))
508                         return next_state;
509         
510                 state->cur_total_bytes += state->msg[state->cur_msg].size;
511                 state->cur_total_num++;
512
513                 keep_for = (state->ac_prefs && state->ac_prefs->leave_time) ? 
514                            atoi(state->ac_prefs->leave_time) : 0;
515
516                 if (drop_ok == 0 && state->ac_prefs->rmmail && keep_for == 0)
517                         return POP3_DELETE_SEND;
518
519                 state->msg[state->cur_msg].received = TRUE;
520
521                 if (state->cur_msg < state->count) {
522                         state->cur_msg++;
523                         LOOKUP_NEXT_MSG();
524                         return POP3_RETR_SEND;
525                 } else
526                         return POP3_LOGOUT_SEND;
527         } else if (ok == PS_PROTOCOL)
528                 return POP3_LOGOUT_SEND;
529         else
530                 return -1;
531 }
532
533 gint pop3_delete_send(SockInfo *sock, gpointer data)
534 {
535         Pop3State *state = (Pop3State *)data;
536
537         pop3_gen_send(sock, "DELE %d", state->cur_msg);
538
539         return POP3_DELETE_RECV;
540 }
541
542 gint pop3_delete_recv(SockInfo *sock, gpointer data)
543 {
544         Pop3State *state = (Pop3State *)data;
545         gint next_state;
546         gint ok;
547
548         if ((ok = pop3_ok(sock, NULL)) == PS_SUCCESS) {
549
550                 state->msg[state->cur_msg].deleted = TRUE;
551                 
552                 if (pop3_sd_state(state, POP3_DELETE_RECV, &next_state))
553                         return next_state;      
554
555                 if (state->cur_msg < state->count) {
556                         state->cur_msg++;
557                         LOOKUP_NEXT_MSG();
558                         return POP3_RETR_SEND;
559                 } else
560                         return POP3_LOGOUT_SEND;
561         } else if (ok == PS_PROTOCOL)
562                 return POP3_LOGOUT_SEND;
563         else
564                 return -1;
565 }
566
567 gint pop3_logout_send(SockInfo *sock, gpointer data)
568 {
569         Pop3State *state = (Pop3State *)data;
570         gchar **parts;
571         
572         while (state->uidl_todelete_list != NULL) {
573                 /*
574                  * FIXME: doesn't feel right - no checks for parts
575                  */
576                 parts = g_strsplit((gchar *) state->uidl_todelete_list->data, " ", 2);
577                 state->uidl_todelete_list = g_slist_remove
578                         (state->uidl_todelete_list, state->uidl_todelete_list->data);
579                 pop3_gen_send(sock, "DELE %s", parts[0]);
580                 if (pop3_ok(sock, NULL) != PS_SUCCESS)
581                         log_warning(_("error occurred on DELE\n"));
582                 g_strfreev(parts);      
583         }
584         
585         pop3_gen_send(sock, "QUIT");
586
587         return POP3_LOGOUT_RECV;
588 }
589
590 gint pop3_logout_recv(SockInfo *sock, gpointer data)
591 {
592         if (pop3_ok(sock, NULL) == PS_SUCCESS)
593                 return -1;
594         else
595                 return -1;
596 }
597
598 static gint pop3_ok(SockInfo *sock, gchar *argbuf)
599 {
600         gint ok;
601         gchar buf[POPBUFSIZE + 1];
602         gchar *bufp;
603
604         if ((ok = pop3_gen_recv(sock, buf, sizeof(buf))) == PS_SUCCESS) {
605                 bufp = buf;
606                 if (*bufp == '+' || *bufp == '-')
607                         bufp++;
608                 else
609                         return PS_PROTOCOL;
610
611                 while (isalpha(*bufp))
612                         bufp++;
613
614                 if (*bufp)
615                         *(bufp++) = '\0';
616
617                 if (!strcmp(buf, "+OK"))
618                         ok = PS_SUCCESS;
619                 else if (!strncmp(buf, "-ERR", 4)) {
620                         if (strstr(bufp, "lock") ||
621                                  strstr(bufp, "Lock") ||
622                                  strstr(bufp, "LOCK") ||
623                                  strstr(bufp, "wait"))
624                                 ok = PS_LOCKBUSY;
625                         else
626                                 ok = PS_PROTOCOL;
627
628                         if (*bufp)
629                                 fprintf(stderr, "POP3: %s\n", bufp);
630                 } else
631                         ok = PS_PROTOCOL;
632
633                 if (argbuf)
634                         strcpy(argbuf, bufp);
635         }
636
637         return ok;
638 }
639
640 static void pop3_gen_send(SockInfo *sock, const gchar *format, ...)
641 {
642         gchar buf[POPBUFSIZE + 1];
643         va_list args;
644
645         va_start(args, format);
646         g_vsnprintf(buf, sizeof(buf) - 2, format, args);
647         va_end(args);
648
649         if (!strncasecmp(buf, "PASS ", 5))
650                 log_print("POP3> PASS ********\n");
651         else
652                 log_print("POP3> %s\n", buf);
653
654         strcat(buf, "\r\n");
655         sock_write(sock, buf, strlen(buf));
656 }
657
658 static gint pop3_gen_recv(SockInfo *sock, gchar *buf, gint size)
659 {
660         if (sock_gets(sock, buf, size) < 0) {
661                 return PS_SOCKET;
662         } else {
663                 strretchomp(buf);
664                 log_print("POP3< %s\n", buf);
665
666                 return PS_SUCCESS;
667         }
668 }
669
670 static void pop3_sd_new_header(Pop3State *state)
671 {
672         HeaderItems *new_msg;
673         if (state->cur_msg <= state->count) {
674                 new_msg = g_new0(HeaderItems, 1); 
675                 
676                 new_msg->index              = state->cur_msg;
677                 new_msg->state              = SD_UNCHECKED;
678                 new_msg->size               = state->msg[state->cur_msg].size; 
679                 new_msg->received           = state->msg[state->cur_msg].received;
680                 new_msg->del_by_old_session = FALSE;
681                 
682                 state->ac_prefs->msg_list = g_slist_append(state->ac_prefs->msg_list, 
683                                                            new_msg);
684         }
685 }
686
687 gboolean pop3_sd_state(Pop3State *state, gint cur_state, guint *next_state) 
688 {
689         gint session = state->ac_prefs->session;
690         guint goto_state = -1;
691
692         switch (cur_state) { 
693         case POP3_GETRANGE_UIDL_RECV:
694                 switch (session) {
695                 case STYPE_DOWNLOAD:
696                 case STYPE_DELETE:
697                 case STYPE_PREVIEW_ALL:
698                         goto_state = POP3_GETSIZE_LIST_SEND;
699                 default:
700                         break;
701                 }
702                 break;
703         case POP3_GETSIZE_LIST_RECV:
704                 switch (session) {
705                 case STYPE_PREVIEW_ALL:
706                         state->cur_msg = 1;
707                 case STYPE_PREVIEW_NEW:
708                         goto_state = POP3_TOP_SEND;
709                         break;
710                 case STYPE_DELETE:
711                         if (pop3_sd_get_next(state))
712                                 goto_state = POP3_DELETE_SEND;          
713                         else
714                                 goto_state = POP3_LOGOUT_SEND;
715                         break;
716                 case STYPE_DOWNLOAD:
717                         if (pop3_sd_get_next(state))
718                                 goto_state = POP3_RETR_SEND;
719                         else
720                                 goto_state = POP3_LOGOUT_SEND;
721                 default:
722                         break;
723                 }
724                 break;
725         case POP3_TOP_RECV: 
726                 switch (session) { 
727                 case STYPE_PREVIEW_ALL:
728                 case STYPE_PREVIEW_NEW:
729                         pop3_sd_new_header(state);
730                 default:
731                         break;
732                 }
733                 break;
734         case POP3_RETR_RECV:
735                 switch (session) {
736                 case STYPE_DOWNLOAD:
737                         if (state->ac_prefs->sd_rmmail_on_download) 
738                                 goto_state = POP3_DELETE_SEND;
739                         else {
740                                 if (pop3_sd_get_next(state)) 
741                                         goto_state = POP3_RETR_SEND;
742                                 else
743                                         goto_state = POP3_LOGOUT_SEND;
744                         }
745                 default:        
746                         break;
747                 }
748                 break;
749         case POP3_DELETE_RECV:
750                 switch (session) {
751                 case STYPE_DELETE:
752                         if (pop3_sd_get_next(state)) 
753                                 goto_state = POP3_DELETE_SEND;
754                         else
755                                 goto_state =  POP3_LOGOUT_SEND;
756                         break;
757                 case STYPE_DOWNLOAD:
758                         if (pop3_sd_get_next(state)) 
759                                 goto_state = POP3_RETR_SEND;
760                         else
761                                 goto_state = POP3_LOGOUT_SEND;
762                 default:
763                         break;
764                 }
765         default:
766                 break;
767                 
768         }                 
769
770         *next_state = goto_state;
771         if (goto_state != -1)
772                 return TRUE;
773         else 
774                 return FALSE;
775 }
776
777 gboolean pop3_sd_get_next(Pop3State *state)
778 {
779         GSList *cur;
780         gint deleted_msgs = 0;
781         
782         switch (state->ac_prefs->session) {
783         case STYPE_DOWNLOAD:
784         case STYPE_DELETE:      
785                 for (cur = state->ac_prefs->msg_list; cur != NULL; cur = cur->next) {
786                         HeaderItems *items = (HeaderItems*)cur->data;
787
788                         if (items->del_by_old_session)
789                                 deleted_msgs++;
790
791                         switch (items->state) {
792                         case SD_REMOVE:
793                                 items->state = SD_REMOVED;
794                                 break;
795                         case SD_DOWNLOAD:
796                                 items->state = SD_DOWNLOADED;
797                                 break;
798                         case SD_CHECKED:
799                                 state->cur_msg = items->index - deleted_msgs;
800                                 if (state->ac_prefs->session == STYPE_DELETE)
801                                         items->state = SD_REMOVE;
802                                 else
803                                         items->state = SD_DOWNLOAD;
804                                 return TRUE;
805                         default:
806                                 break;
807                         }
808                 }
809                 return FALSE;
810         default:
811                 return FALSE;
812         }
813 }