]> git.llucax.com Git - software/mutt-debian.git/blob - pop.c
fixes two problems with subdirs on dovecot (Closes: 530671, 530887)
[software/mutt-debian.git] / pop.c
1 /*
2  * Copyright (C) 2000-2002 Vsevolod Volkov <vvv@mutt.org.ua>
3  * Copyright (C) 2006-7 Rocco Rutte <pdmef@gmx.net>
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  */ 
19
20 #if HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include "mutt.h"
25 #include "mutt_curses.h"
26 #include "mx.h"
27 #include "pop.h"
28 #include "mutt_crypt.h"
29 #include "bcache.h"
30 #if USE_HCACHE
31 #include "hcache.h"
32 #endif
33
34 #include <string.h>
35 #include <unistd.h>
36
37 #ifdef USE_HCACHE
38 #define HC_FNAME        "mutt"          /* filename for hcache as POP lacks paths */
39 #define HC_FEXT         "hcache"        /* extension for hcache as POP lacks paths */
40 #endif
41
42 /* write line to file */
43 static int fetch_message (char *line, void *file)
44 {
45   FILE *f = (FILE *) file;
46
47   fputs (line, f);
48   if (fputc ('\n', f) == EOF)
49     return -1;
50
51   return 0;
52 }
53
54 /*
55  * Read header
56  * returns:
57  *  0 on success
58  * -1 - conection lost,
59  * -2 - invalid command or execution error,
60  * -3 - error writing to tempfile
61  */
62 static int pop_read_header (POP_DATA *pop_data, HEADER *h)
63 {
64   FILE *f;
65   int ret, index;
66   long length;
67   char buf[LONG_STRING];
68   char tempfile[_POSIX_PATH_MAX];
69
70   mutt_mktemp (tempfile);
71   if (!(f = safe_fopen (tempfile, "w+")))
72   {
73     mutt_perror (tempfile);
74     return -3;
75   }
76
77   snprintf (buf, sizeof (buf), "LIST %d\r\n", h->refno);
78   ret = pop_query (pop_data, buf, sizeof (buf));
79   if (ret == 0)
80   {
81     sscanf (buf, "+OK %d %ld", &index, &length);
82
83     snprintf (buf, sizeof (buf), "TOP %d 0\r\n", h->refno);
84     ret = pop_fetch_data (pop_data, buf, NULL, fetch_message, f);
85
86     if (pop_data->cmd_top == 2)
87     {
88       if (ret == 0)
89       {
90         pop_data->cmd_top = 1;
91
92         dprint (1, (debugfile, "pop_read_header: set TOP capability\n"));
93       }
94
95       if (ret == -2)
96       {
97         pop_data->cmd_top = 0;
98
99         dprint (1, (debugfile, "pop_read_header: unset TOP capability\n"));
100         snprintf (pop_data->err_msg, sizeof (pop_data->err_msg),
101                 _("Command TOP is not supported by server."));
102       }
103     }
104   }
105
106   switch (ret)
107   {
108     case 0:
109     {
110       rewind (f);
111       h->env = mutt_read_rfc822_header (f, h, 0, 0);
112       h->content->length = length - h->content->offset + 1;
113       rewind (f);
114       while (!feof (f))
115       {
116         h->content->length--;
117         fgets (buf, sizeof (buf), f);
118       }
119       break;
120     }
121     case -2:
122     {
123       mutt_error ("%s", pop_data->err_msg);
124       break;
125     }
126     case -3:
127     {
128       mutt_error _("Can't write header to temporary file!");
129       break;
130     }
131   }
132
133   fclose (f);
134   unlink (tempfile);
135   return ret;
136 }
137
138 /* parse UIDL */
139 static int fetch_uidl (char *line, void *data)
140 {
141   int i, index;
142   CONTEXT *ctx = (CONTEXT *)data;
143   POP_DATA *pop_data = (POP_DATA *)ctx->data;
144
145   sscanf (line, "%d %s", &index, line);
146   for (i = 0; i < ctx->msgcount; i++)
147     if (!mutt_strcmp (line, ctx->hdrs[i]->data))
148       break;
149
150   if (i == ctx->msgcount)
151   {
152     dprint (1, (debugfile, "pop_fetch_headers: new header %d %s\n", index, line));
153
154     if (i >= ctx->hdrmax)
155       mx_alloc_memory(ctx);
156
157     ctx->msgcount++;
158     ctx->hdrs[i] = mutt_new_header ();
159     ctx->hdrs[i]->data = safe_strdup (line);
160   }
161   else if (ctx->hdrs[i]->index != index - 1)
162     pop_data->clear_cache = 1;
163
164   ctx->hdrs[i]->refno = index;
165   ctx->hdrs[i]->index = index - 1;
166
167   return 0;
168 }
169
170 static int msg_cache_check (const char *id, body_cache_t *bcache, void *data)
171 {
172   CONTEXT *ctx;
173   POP_DATA *pop_data;
174   int i;
175
176   if (!(ctx = (CONTEXT *)data))
177     return -1;
178   if (!(pop_data = (POP_DATA *)ctx->data))
179     return -1;
180
181 #ifdef USE_HCACHE
182   /* keep hcache file if hcache == bcache */
183   if (strcmp (HC_FNAME "." HC_FEXT, id) == 0)
184     return 0;
185 #endif
186
187   for (i = 0; i < ctx->msgcount; i++)
188     /* if the id we get is known for a header: done (i.e. keep in cache) */
189     if (ctx->hdrs[i]->data && mutt_strcmp (ctx->hdrs[i]->data, id) == 0)
190       return 0;
191
192   /* message not found in context -> remove it from cache
193    * return the result of bcache, so we stop upon its first error
194    */
195   return mutt_bcache_del (bcache, id);
196 }
197
198 #ifdef USE_HCACHE
199 static int pop_hcache_namer (const char *path, char *dest, size_t destlen)
200 {
201   return snprintf (dest, destlen, "%s." HC_FEXT, path);
202 }
203
204 static header_cache_t *pop_hcache_open (POP_DATA *pop_data, const char *path)
205 {
206   ciss_url_t url;
207   char p[LONG_STRING];
208
209   if (!pop_data || !pop_data->conn)
210     return mutt_hcache_open (HeaderCache, path, NULL);
211
212   mutt_account_tourl (&pop_data->conn->account, &url);
213   url.path = HC_FNAME;
214   url_ciss_tostring (&url, p, sizeof (p), U_PATH);
215   return mutt_hcache_open (HeaderCache, p, pop_hcache_namer);
216 }
217 #endif
218
219 /*
220  * Read headers
221  * returns:
222  *  0 on success
223  * -1 - conection lost,
224  * -2 - invalid command or execution error,
225  * -3 - error writing to tempfile
226  */
227 static int pop_fetch_headers (CONTEXT *ctx)
228 {
229   int i, ret, old_count, new_count;
230   unsigned short hcached = 0, bcached;
231   POP_DATA *pop_data = (POP_DATA *)ctx->data;
232   progress_t progress;
233
234 #ifdef USE_HCACHE
235   header_cache_t *hc = NULL;
236   void *data;
237
238   hc = pop_hcache_open (pop_data, ctx->path);
239 #endif
240
241   time (&pop_data->check_time);
242   pop_data->clear_cache = 0;
243
244   for (i = 0; i < ctx->msgcount; i++)
245     ctx->hdrs[i]->refno = -1;
246
247   old_count = ctx->msgcount;
248   ret = pop_fetch_data (pop_data, "UIDL\r\n", NULL, fetch_uidl, ctx);
249   new_count = ctx->msgcount;
250   ctx->msgcount = old_count;
251
252   if (pop_data->cmd_uidl == 2)
253   {
254     if (ret == 0)
255     {
256       pop_data->cmd_uidl = 1;
257
258       dprint (1, (debugfile, "pop_fetch_headers: set UIDL capability\n"));
259     }
260
261     if (ret == -2 && pop_data->cmd_uidl == 2)
262     {
263       pop_data->cmd_uidl = 0;
264
265       dprint (1, (debugfile, "pop_fetch_headers: unset UIDL capability\n"));
266       snprintf (pop_data->err_msg, sizeof (pop_data->err_msg),
267               _("Command UIDL is not supported by server."));
268     }
269   }
270
271   if (!ctx->quiet)
272     mutt_progress_init (&progress, _("Fetching message headers..."),
273                         M_PROGRESS_MSG, ReadInc, new_count - old_count);
274
275   if (ret == 0)
276   {
277     for (i = 0; i < old_count; i++)
278       if (ctx->hdrs[i]->refno == -1)
279         ctx->hdrs[i]->deleted = 1;
280
281     for (i = old_count; i < new_count; i++)
282     {
283       if (!ctx->quiet)
284         mutt_progress_update (&progress, i + 1 - old_count, -1);
285 #if USE_HCACHE
286       if ((data = mutt_hcache_fetch (hc, ctx->hdrs[i]->data, strlen)))
287       {
288         char *uidl = safe_strdup (ctx->hdrs[i]->data);
289         int refno = ctx->hdrs[i]->refno;
290         int index = ctx->hdrs[i]->index;
291         /*
292          * - POP dynamically numbers headers and relies on h->refno
293          *   to map messages; so restore header and overwrite restored
294          *   refno with current refno, same for index
295          * - h->data needs to a separate pointer as it's driver-specific
296          *   data freed separately elsewhere
297          *   (the old h->data should point inside a malloc'd block from
298          *   hcache so there shouldn't be a memleak here)
299          */
300         HEADER *h = mutt_hcache_restore ((unsigned char *) data, NULL);
301         mutt_free_header (&ctx->hdrs[i]);
302         ctx->hdrs[i] = h;
303         ctx->hdrs[i]->refno = refno;
304         ctx->hdrs[i]->index = index;
305         ctx->hdrs[i]->data = uidl;
306         ret = 0;
307         hcached = 1;
308       }
309       else
310 #endif
311       if ((ret = pop_read_header (pop_data, ctx->hdrs[i])) < 0)
312         break;
313 #if USE_HCACHE
314       else
315       {
316         mutt_hcache_store (hc, ctx->hdrs[i]->data, ctx->hdrs[i], 0, strlen);
317       }
318
319       FREE(&data);
320 #endif
321
322       /*
323        * faked support for flags works like this:
324        * - if 'hcached' is 1, we have the message in our hcache:
325        *        - if we also have a body: read
326        *        - if we don't have a body: old
327        *          (if $mark_old is set which is maybe wrong as
328        *          $mark_old should be considered for syncing the
329        *          folder and not when opening it XXX)
330        * - if 'hcached' is 0, we don't have the message in our hcache:
331        *        - if we also have a body: read
332        *        - if we don't have a body: new
333        */
334       bcached = mutt_bcache_exists (pop_data->bcache, ctx->hdrs[i]->data) == 0;
335       ctx->hdrs[i]->old = 0;
336       ctx->hdrs[i]->read = 0;
337       if (hcached)
338       {
339         if (bcached)
340           ctx->hdrs[i]->read = 1;
341         else if (option (OPTMARKOLD))
342           ctx->hdrs[i]->old = 1;
343       }
344       else
345       {
346         if (bcached)
347           ctx->hdrs[i]->read = 1;
348       }
349
350       ctx->msgcount++;
351     }
352
353     if (i > old_count)
354       mx_update_context (ctx, i - old_count);
355   }
356
357 #if USE_HCACHE
358     mutt_hcache_close (hc);
359 #endif
360
361   if (ret < 0)
362   {
363     for (i = ctx->msgcount; i < new_count; i++)
364       mutt_free_header (&ctx->hdrs[i]);
365     return ret;
366   }
367
368   /* after putting the result into our structures,
369    * clean up cache, i.e. wipe messages deleted outside
370    * the availability of our cache
371    */
372   if (option (OPTMESSAGECACHECLEAN))
373     mutt_bcache_list (pop_data->bcache, msg_cache_check, (void*)ctx);
374
375   mutt_clear_error ();
376   return (new_count - old_count);
377 }
378
379 /* open POP mailbox - fetch only headers */
380 int pop_open_mailbox (CONTEXT *ctx)
381 {
382   int ret;
383   char buf[LONG_STRING];
384   CONNECTION *conn;
385   ACCOUNT acct;
386   POP_DATA *pop_data;
387   ciss_url_t url;
388
389   if (pop_parse_path (ctx->path, &acct))
390   {
391     mutt_error (_("%s is an invalid POP path"), ctx->path);
392     mutt_sleep (2);
393     return -1;
394   }
395
396   mutt_account_tourl (&acct, &url);
397   url.path = NULL;
398   url_ciss_tostring (&url, buf, sizeof (buf), 0);
399   conn = mutt_conn_find (NULL, &acct);
400   if (!conn)
401     return -1;
402
403   FREE (&ctx->path);
404   ctx->path = safe_strdup (buf);
405
406   pop_data = safe_calloc (1, sizeof (POP_DATA));
407   pop_data->conn = conn;
408   ctx->data = pop_data;
409   ctx->mx_close = pop_close_mailbox;
410
411   if (pop_open_connection (pop_data) < 0)
412     return -1;
413
414   conn->data = pop_data;
415   pop_data->bcache = mutt_bcache_open (&acct, NULL);
416
417   /* init (hard-coded) ACL rights */
418   memset (ctx->rights, 0, sizeof (ctx->rights));
419   mutt_bit_set (ctx->rights, M_ACL_SEEN);
420   mutt_bit_set (ctx->rights, M_ACL_DELETE);
421
422   FOREVER
423   {
424     if (pop_reconnect (ctx) < 0)
425       return -1;
426
427     ctx->size = pop_data->size;
428
429     mutt_message _("Fetching list of messages...");
430
431     ret = pop_fetch_headers (ctx);
432
433     if (ret >= 0)
434       return 0;
435
436     if (ret < -1)
437     {
438       mutt_sleep (2);
439       return -1;
440     }
441   }
442 }
443
444 /* delete all cached messages */
445 static void pop_clear_cache (POP_DATA *pop_data)
446 {
447   int i;
448
449   if (!pop_data->clear_cache)
450     return;
451
452   dprint (1, (debugfile, "pop_clear_cache: delete cached messages\n"));
453
454   for (i = 0; i < POP_CACHE_LEN; i++)
455   {
456     if (pop_data->cache[i].path)
457     {
458       unlink (pop_data->cache[i].path);
459       FREE (&pop_data->cache[i].path);
460     }
461   }
462 }
463
464 /* close POP mailbox */
465 int pop_close_mailbox (CONTEXT *ctx)
466 {
467   POP_DATA *pop_data = (POP_DATA *)ctx->data;
468
469   if (!pop_data)
470     return 0;
471
472   pop_logout (ctx);
473
474   if (pop_data->status != POP_NONE)
475     mutt_socket_close (pop_data->conn);
476
477   pop_data->status = POP_NONE;
478
479   pop_data->clear_cache = 1;
480   pop_clear_cache (pop_data);
481
482   if (!pop_data->conn->data)
483     mutt_socket_free (pop_data->conn);
484
485   mutt_bcache_close (&pop_data->bcache);
486
487   return 0;
488 }
489
490 /* fetch message from POP server */
491 int pop_fetch_message (MESSAGE* msg, CONTEXT* ctx, int msgno)
492 {
493   int ret;
494   void *uidl;
495   char buf[LONG_STRING];
496   char path[_POSIX_PATH_MAX];
497   progress_t progressbar;
498   POP_DATA *pop_data = (POP_DATA *)ctx->data;
499   POP_CACHE *cache;
500   HEADER *h = ctx->hdrs[msgno];
501   unsigned short bcache = 1;
502
503   /* see if we already have the message in body cache */
504   if ((msg->fp = mutt_bcache_get (pop_data->bcache, h->data)))
505     return 0;
506
507   /*
508    * see if we already have the message in our cache in
509    * case $message_cachedir is unset
510    */
511   cache = &pop_data->cache[h->index % POP_CACHE_LEN];
512
513   if (cache->path)
514   {
515     if (cache->index == h->index)
516     {
517       /* yes, so just return a pointer to the message */
518       msg->fp = fopen (cache->path, "r");
519       if (msg->fp)
520         return 0;
521       
522       mutt_perror (cache->path);
523       mutt_sleep (2);
524       return -1;
525     }
526     else
527     {
528       /* clear the previous entry */
529       unlink (cache->path);
530       FREE (&cache->path);
531     }
532   }
533
534   FOREVER
535   {
536     if (pop_reconnect (ctx) < 0)
537       return -1;
538
539     /* verify that massage index is correct */
540     if (h->refno < 0)
541     {
542       mutt_error _("The message index is incorrect. Try reopening the mailbox.");
543       mutt_sleep (2);
544       return -1;
545     }
546
547     mutt_progress_init (&progressbar, _("Fetching message..."),
548                         M_PROGRESS_SIZE, NetInc, h->content->length + h->content->offset - 1);
549
550     /* see if we can put in body cache; use our cache as fallback */
551     if (!(msg->fp = mutt_bcache_put (pop_data->bcache, h->data, 1)))
552     {
553       /* no */
554       bcache = 0;
555       mutt_mktemp (path);
556       if (!(msg->fp = safe_fopen (path, "w+")))
557       {
558         mutt_perror (path);
559         mutt_sleep (2);
560         return -1;
561       }
562     }
563
564     snprintf (buf, sizeof (buf), "RETR %d\r\n", h->refno);
565
566     ret = pop_fetch_data (pop_data, buf, &progressbar, fetch_message, msg->fp);
567     if (ret == 0)
568       break;
569
570     safe_fclose (&msg->fp);
571
572     /* if RETR failed (e.g. connection closed), be sure to remove either
573      * the file in bcache or from POP's own cache since the next iteration
574      * of the loop will re-attempt to put() the message */
575     if (!bcache)
576       unlink (path);
577
578     if (ret == -2)
579     {
580       mutt_error ("%s", pop_data->err_msg);
581       mutt_sleep (2);
582       return -1;
583     }
584
585     if (ret == -3)
586     {
587       mutt_error _("Can't write message to temporary file!");
588       mutt_sleep (2);
589       return -1;
590     }
591   }
592
593   /* Update the header information.  Previously, we only downloaded a
594    * portion of the headers, those required for the main display.
595    */
596   if (bcache)
597     mutt_bcache_commit (pop_data->bcache, h->data);
598   else
599   {
600     cache->index = h->index;
601     cache->path = safe_strdup (path);
602   }
603   rewind (msg->fp);
604   uidl = h->data;
605   mutt_free_envelope (&h->env);
606   h->env = mutt_read_rfc822_header (msg->fp, h, 0, 0);
607   h->data = uidl;
608   h->lines = 0;
609   fgets (buf, sizeof (buf), msg->fp);
610   while (!feof (msg->fp))
611   {
612     ctx->hdrs[msgno]->lines++;
613     fgets (buf, sizeof (buf), msg->fp);
614   }
615
616   h->content->length = ftello (msg->fp) - h->content->offset;
617
618   /* This needs to be done in case this is a multipart message */
619   if (!WithCrypto)
620     h->security = crypt_query (h->content);
621
622   mutt_clear_error();
623   rewind (msg->fp);
624
625   return 0;
626 }
627
628 /* update POP mailbox - delete messages from server */
629 int pop_sync_mailbox (CONTEXT *ctx, int *index_hint)
630 {
631   int i, j, ret = 0;
632   char buf[LONG_STRING];
633   POP_DATA *pop_data = (POP_DATA *)ctx->data;
634   progress_t progress;
635 #ifdef USE_HCACHE
636   header_cache_t *hc = NULL;
637 #endif
638
639   pop_data->check_time = 0;
640
641   FOREVER
642   {
643     if (pop_reconnect (ctx) < 0)
644       return -1;
645
646     mutt_progress_init (&progress, _("Marking messages deleted..."),
647                         M_PROGRESS_MSG, WriteInc, ctx->deleted);
648
649 #if USE_HCACHE
650     hc = pop_hcache_open (pop_data, ctx->path);
651 #endif
652
653     for (i = 0, j = 0, ret = 0; ret == 0 && i < ctx->msgcount; i++)
654     {
655       if (ctx->hdrs[i]->deleted)
656       {
657         j++;
658         if (!ctx->quiet)
659           mutt_progress_update (&progress, j, -1);
660         snprintf (buf, sizeof (buf), "DELE %d\r\n", ctx->hdrs[i]->refno);
661         if ((ret = pop_query (pop_data, buf, sizeof (buf))) == 0)
662         {
663           mutt_bcache_del (pop_data->bcache, ctx->hdrs[i]->data);
664 #if USE_HCACHE
665           mutt_hcache_delete (hc, ctx->hdrs[i]->data, strlen);
666 #endif
667         }
668       }
669     }
670
671 #if USE_HCACHE
672     mutt_hcache_close (hc);
673 #endif
674
675     if (ret == 0)
676     {
677       strfcpy (buf, "QUIT\r\n", sizeof (buf));
678       ret = pop_query (pop_data, buf, sizeof (buf));
679     }
680
681     if (ret == 0)
682     {
683       pop_data->clear_cache = 1;
684       pop_clear_cache (pop_data);
685       pop_data->status = POP_DISCONNECTED;
686       return 0;
687     }
688
689     if (ret == -2)
690     {
691       mutt_error ("%s", pop_data->err_msg);
692       mutt_sleep (2);
693       return -1;
694     }
695   }
696 }
697
698 /* Check for new messages and fetch headers */
699 int pop_check_mailbox (CONTEXT *ctx, int *index_hint)
700 {
701   int ret;
702   POP_DATA *pop_data = (POP_DATA *)ctx->data;
703
704   if ((pop_data->check_time + PopCheckTimeout) > time (NULL))
705     return 0;
706
707   pop_logout (ctx);
708
709   mutt_socket_close (pop_data->conn);
710
711   if (pop_open_connection (pop_data) < 0)
712     return -1;
713
714   ctx->size = pop_data->size;
715
716   mutt_message _("Checking for new messages...");
717
718   ret = pop_fetch_headers (ctx);
719   pop_clear_cache (pop_data);
720
721   if (ret < 0)
722     return -1;
723
724   if (ret > 0)
725     return M_NEW_MAIL;
726
727   return 0;
728 }
729
730 /* Fetch messages and save them in $spoolfile */
731 void pop_fetch_mail (void)
732 {
733   char buffer[LONG_STRING];
734   char msgbuf[SHORT_STRING];
735   char *url, *p;
736   int i, delanswer, last = 0, msgs, bytes, rset = 0, ret;
737   CONNECTION *conn;
738   CONTEXT ctx;
739   MESSAGE *msg = NULL;
740   ACCOUNT acct;
741   POP_DATA *pop_data;
742
743   if (!PopHost)
744   {
745     mutt_error _("POP host is not defined.");
746     return;
747   }
748
749   url = p = safe_calloc (strlen (PopHost) + 7, sizeof (char));
750   if (url_check_scheme (PopHost) == U_UNKNOWN)
751   {
752     strcpy (url, "pop://");     /* __STRCPY_CHECKED__ */
753     p = strchr (url, '\0');
754   }
755   strcpy (p, PopHost);          /* __STRCPY_CHECKED__ */
756
757   ret = pop_parse_path (url, &acct);
758   FREE (&url);
759   if (ret)
760   {
761     mutt_error (_("%s is an invalid POP path"), PopHost);
762     return;
763   }
764
765   conn = mutt_conn_find (NULL, &acct);
766   if (!conn)
767     return;
768
769   pop_data = safe_calloc (1, sizeof (POP_DATA));
770   pop_data->conn = conn;
771
772   if (pop_open_connection (pop_data) < 0)
773   {
774     mutt_socket_free (pop_data->conn);
775     FREE (&pop_data);
776     return;
777   }
778
779   conn->data = pop_data;
780
781   mutt_message _("Checking for new messages...");
782
783   /* find out how many messages are in the mailbox. */
784   strfcpy (buffer, "STAT\r\n", sizeof (buffer));
785   ret = pop_query (pop_data, buffer, sizeof (buffer));
786   if (ret == -1)
787     goto fail;
788   if (ret == -2)
789   {
790     mutt_error ("%s", pop_data->err_msg);
791     goto finish;
792   }
793
794   sscanf (buffer, "+OK %d %d", &msgs, &bytes);
795
796   /* only get unread messages */
797   if (msgs > 0 && option (OPTPOPLAST))
798   {
799     strfcpy (buffer, "LAST\r\n", sizeof (buffer));
800     ret = pop_query (pop_data, buffer, sizeof (buffer));
801     if (ret == -1)
802       goto fail;
803     if (ret == 0)
804       sscanf (buffer, "+OK %d", &last);
805   }
806
807   if (msgs <= last)
808   {
809     mutt_message _("No new mail in POP mailbox.");
810     goto finish;
811   }
812
813   if (mx_open_mailbox (NONULL (Spoolfile), M_APPEND, &ctx) == NULL)
814     goto finish;
815
816   delanswer = query_quadoption (OPT_POPDELETE, _("Delete messages from server?"));
817
818   snprintf (msgbuf, sizeof (msgbuf), _("Reading new messages (%d bytes)..."), bytes);
819   mutt_message ("%s", msgbuf);
820
821   for (i = last + 1 ; i <= msgs ; i++)
822   {
823     if ((msg = mx_open_new_message (&ctx, NULL, M_ADD_FROM)) == NULL)
824       ret = -3;
825     else
826     {
827       snprintf (buffer, sizeof (buffer), "RETR %d\r\n", i);
828       ret = pop_fetch_data (pop_data, buffer, NULL, fetch_message, msg->fp);
829       if (ret == -3)
830         rset = 1;
831
832       if (ret == 0 && mx_commit_message (msg, &ctx) != 0)
833       {
834         rset = 1;
835         ret = -3;
836       }
837
838       mx_close_message (&msg);
839     }
840
841     if (ret == 0 && delanswer == M_YES)
842     {
843       /* delete the message on the server */
844       snprintf (buffer, sizeof (buffer), "DELE %d\r\n", i);
845       ret = pop_query (pop_data, buffer, sizeof (buffer));
846     }
847
848     if (ret == -1)
849     {
850       mx_close_mailbox (&ctx, NULL);
851       goto fail;
852     }
853     if (ret == -2)
854     {
855       mutt_error ("%s", pop_data->err_msg);
856       break;
857     }
858     if (ret == -3)
859     {
860       mutt_error _("Error while writing mailbox!");
861       break;
862     }
863
864     mutt_message (_("%s [%d of %d messages read]"), msgbuf, i - last, msgs - last);
865   }
866
867   mx_close_mailbox (&ctx, NULL);
868
869   if (rset)
870   {
871     /* make sure no messages get deleted */
872     strfcpy (buffer, "RSET\r\n", sizeof (buffer));
873     if (pop_query (pop_data, buffer, sizeof (buffer)) == -1)
874       goto fail;
875   }
876
877 finish:
878   /* exit gracefully */
879   strfcpy (buffer, "QUIT\r\n", sizeof (buffer));
880   if (pop_query (pop_data, buffer, sizeof (buffer)) == -1)
881     goto fail;
882   mutt_socket_close (conn);
883   FREE (&pop_data);
884   return;
885
886 fail:
887   mutt_error _("Server closed connection!");
888   mutt_socket_close (conn);
889   FREE (&pop_data);
890 }