]> git.llucax.com Git - software/mutt-debian.git/blob - pop.c
Move Mutt with NNTP support to mutt-nntp package
[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, sizeof (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   safe_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, deleted;
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, deleted = 0; i < old_count; i++)
278     {
279       if (ctx->hdrs[i]->refno == -1)
280       {
281         ctx->hdrs[i]->deleted = 1;
282         deleted++;
283       }
284     }
285     if (deleted > 0)
286     {
287       mutt_error (_("%d messages have been lost. Try reopening the mailbox."),
288                   deleted);
289       mutt_sleep (2);
290     }
291
292     for (i = old_count; i < new_count; i++)
293     {
294       if (!ctx->quiet)
295         mutt_progress_update (&progress, i + 1 - old_count, -1);
296 #if USE_HCACHE
297       if ((data = mutt_hcache_fetch (hc, ctx->hdrs[i]->data, strlen)))
298       {
299         char *uidl = safe_strdup (ctx->hdrs[i]->data);
300         int refno = ctx->hdrs[i]->refno;
301         int index = ctx->hdrs[i]->index;
302         /*
303          * - POP dynamically numbers headers and relies on h->refno
304          *   to map messages; so restore header and overwrite restored
305          *   refno with current refno, same for index
306          * - h->data needs to a separate pointer as it's driver-specific
307          *   data freed separately elsewhere
308          *   (the old h->data should point inside a malloc'd block from
309          *   hcache so there shouldn't be a memleak here)
310          */
311         HEADER *h = mutt_hcache_restore ((unsigned char *) data, NULL);
312         mutt_free_header (&ctx->hdrs[i]);
313         ctx->hdrs[i] = h;
314         ctx->hdrs[i]->refno = refno;
315         ctx->hdrs[i]->index = index;
316         ctx->hdrs[i]->data = uidl;
317         ret = 0;
318         hcached = 1;
319       }
320       else
321 #endif
322       if ((ret = pop_read_header (pop_data, ctx->hdrs[i])) < 0)
323         break;
324 #if USE_HCACHE
325       else
326       {
327         mutt_hcache_store (hc, ctx->hdrs[i]->data, ctx->hdrs[i], 0, strlen);
328       }
329
330       FREE(&data);
331 #endif
332
333       /*
334        * faked support for flags works like this:
335        * - if 'hcached' is 1, we have the message in our hcache:
336        *        - if we also have a body: read
337        *        - if we don't have a body: old
338        *          (if $mark_old is set which is maybe wrong as
339        *          $mark_old should be considered for syncing the
340        *          folder and not when opening it XXX)
341        * - if 'hcached' is 0, we don't have the message in our hcache:
342        *        - if we also have a body: read
343        *        - if we don't have a body: new
344        */
345       bcached = mutt_bcache_exists (pop_data->bcache, ctx->hdrs[i]->data) == 0;
346       ctx->hdrs[i]->old = 0;
347       ctx->hdrs[i]->read = 0;
348       if (hcached)
349       {
350         if (bcached)
351           ctx->hdrs[i]->read = 1;
352         else if (option (OPTMARKOLD))
353           ctx->hdrs[i]->old = 1;
354       }
355       else
356       {
357         if (bcached)
358           ctx->hdrs[i]->read = 1;
359       }
360
361       ctx->msgcount++;
362     }
363
364     if (i > old_count)
365       mx_update_context (ctx, i - old_count);
366   }
367
368 #if USE_HCACHE
369     mutt_hcache_close (hc);
370 #endif
371
372   if (ret < 0)
373   {
374     for (i = ctx->msgcount; i < new_count; i++)
375       mutt_free_header (&ctx->hdrs[i]);
376     return ret;
377   }
378
379   /* after putting the result into our structures,
380    * clean up cache, i.e. wipe messages deleted outside
381    * the availability of our cache
382    */
383   if (option (OPTMESSAGECACHECLEAN))
384     mutt_bcache_list (pop_data->bcache, msg_cache_check, (void*)ctx);
385
386   mutt_clear_error ();
387   return (new_count - old_count);
388 }
389
390 /* open POP mailbox - fetch only headers */
391 int pop_open_mailbox (CONTEXT *ctx)
392 {
393   int ret;
394   char buf[LONG_STRING];
395   CONNECTION *conn;
396   ACCOUNT acct;
397   POP_DATA *pop_data;
398   ciss_url_t url;
399
400   if (pop_parse_path (ctx->path, &acct))
401   {
402     mutt_error (_("%s is an invalid POP path"), ctx->path);
403     mutt_sleep (2);
404     return -1;
405   }
406
407   mutt_account_tourl (&acct, &url);
408   url.path = NULL;
409   url_ciss_tostring (&url, buf, sizeof (buf), 0);
410   conn = mutt_conn_find (NULL, &acct);
411   if (!conn)
412     return -1;
413
414   FREE (&ctx->path);
415   ctx->path = safe_strdup (buf);
416
417   pop_data = safe_calloc (1, sizeof (POP_DATA));
418   pop_data->conn = conn;
419   ctx->data = pop_data;
420   ctx->mx_close = pop_close_mailbox;
421
422   if (pop_open_connection (pop_data) < 0)
423     return -1;
424
425   conn->data = pop_data;
426   pop_data->bcache = mutt_bcache_open (&acct, NULL);
427
428   /* init (hard-coded) ACL rights */
429   memset (ctx->rights, 0, sizeof (ctx->rights));
430   mutt_bit_set (ctx->rights, M_ACL_SEEN);
431   mutt_bit_set (ctx->rights, M_ACL_DELETE);
432 #if USE_HCACHE
433   /* flags are managed using header cache, so it only makes sense to
434    * enable them in that case */
435   mutt_bit_set (ctx->rights, M_ACL_WRITE);
436 #endif
437
438   FOREVER
439   {
440     if (pop_reconnect (ctx) < 0)
441       return -1;
442
443     ctx->size = pop_data->size;
444
445     mutt_message _("Fetching list of messages...");
446
447     ret = pop_fetch_headers (ctx);
448
449     if (ret >= 0)
450       return 0;
451
452     if (ret < -1)
453     {
454       mutt_sleep (2);
455       return -1;
456     }
457   }
458 }
459
460 /* delete all cached messages */
461 static void pop_clear_cache (POP_DATA *pop_data)
462 {
463   int i;
464
465   if (!pop_data->clear_cache)
466     return;
467
468   dprint (1, (debugfile, "pop_clear_cache: delete cached messages\n"));
469
470   for (i = 0; i < POP_CACHE_LEN; i++)
471   {
472     if (pop_data->cache[i].path)
473     {
474       unlink (pop_data->cache[i].path);
475       FREE (&pop_data->cache[i].path);
476     }
477   }
478 }
479
480 /* close POP mailbox */
481 int pop_close_mailbox (CONTEXT *ctx)
482 {
483   POP_DATA *pop_data = (POP_DATA *)ctx->data;
484
485   if (!pop_data)
486     return 0;
487
488   pop_logout (ctx);
489
490   if (pop_data->status != POP_NONE)
491     mutt_socket_close (pop_data->conn);
492
493   pop_data->status = POP_NONE;
494
495   pop_data->clear_cache = 1;
496   pop_clear_cache (pop_data);
497
498   if (!pop_data->conn->data)
499     mutt_socket_free (pop_data->conn);
500
501   mutt_bcache_close (&pop_data->bcache);
502
503   return 0;
504 }
505
506 /* fetch message from POP server */
507 int pop_fetch_message (MESSAGE* msg, CONTEXT* ctx, int msgno)
508 {
509   int ret;
510   void *uidl;
511   char buf[LONG_STRING];
512   char path[_POSIX_PATH_MAX];
513   progress_t progressbar;
514   POP_DATA *pop_data = (POP_DATA *)ctx->data;
515   POP_CACHE *cache;
516   HEADER *h = ctx->hdrs[msgno];
517   unsigned short bcache = 1;
518
519   /* see if we already have the message in body cache */
520   if ((msg->fp = mutt_bcache_get (pop_data->bcache, h->data)))
521     return 0;
522
523   /*
524    * see if we already have the message in our cache in
525    * case $message_cachedir is unset
526    */
527   cache = &pop_data->cache[h->index % POP_CACHE_LEN];
528
529   if (cache->path)
530   {
531     if (cache->index == h->index)
532     {
533       /* yes, so just return a pointer to the message */
534       msg->fp = fopen (cache->path, "r");
535       if (msg->fp)
536         return 0;
537       
538       mutt_perror (cache->path);
539       mutt_sleep (2);
540       return -1;
541     }
542     else
543     {
544       /* clear the previous entry */
545       unlink (cache->path);
546       FREE (&cache->path);
547     }
548   }
549
550   FOREVER
551   {
552     if (pop_reconnect (ctx) < 0)
553       return -1;
554
555     /* verify that massage index is correct */
556     if (h->refno < 0)
557     {
558       mutt_error _("The message index is incorrect. Try reopening the mailbox.");
559       mutt_sleep (2);
560       return -1;
561     }
562
563     mutt_progress_init (&progressbar, _("Fetching message..."),
564                         M_PROGRESS_SIZE, NetInc, h->content->length + h->content->offset - 1);
565
566     /* see if we can put in body cache; use our cache as fallback */
567     if (!(msg->fp = mutt_bcache_put (pop_data->bcache, h->data, 1)))
568     {
569       /* no */
570       bcache = 0;
571       mutt_mktemp (path, sizeof (path));
572       if (!(msg->fp = safe_fopen (path, "w+")))
573       {
574         mutt_perror (path);
575         mutt_sleep (2);
576         return -1;
577       }
578     }
579
580     snprintf (buf, sizeof (buf), "RETR %d\r\n", h->refno);
581
582     ret = pop_fetch_data (pop_data, buf, &progressbar, fetch_message, msg->fp);
583     if (ret == 0)
584       break;
585
586     safe_fclose (&msg->fp);
587
588     /* if RETR failed (e.g. connection closed), be sure to remove either
589      * the file in bcache or from POP's own cache since the next iteration
590      * of the loop will re-attempt to put() the message */
591     if (!bcache)
592       unlink (path);
593
594     if (ret == -2)
595     {
596       mutt_error ("%s", pop_data->err_msg);
597       mutt_sleep (2);
598       return -1;
599     }
600
601     if (ret == -3)
602     {
603       mutt_error _("Can't write message to temporary file!");
604       mutt_sleep (2);
605       return -1;
606     }
607   }
608
609   /* Update the header information.  Previously, we only downloaded a
610    * portion of the headers, those required for the main display.
611    */
612   if (bcache)
613     mutt_bcache_commit (pop_data->bcache, h->data);
614   else
615   {
616     cache->index = h->index;
617     cache->path = safe_strdup (path);
618   }
619   rewind (msg->fp);
620   uidl = h->data;
621   mutt_free_envelope (&h->env);
622   h->env = mutt_read_rfc822_header (msg->fp, h, 0, 0);
623   h->data = uidl;
624   h->lines = 0;
625   fgets (buf, sizeof (buf), msg->fp);
626   while (!feof (msg->fp))
627   {
628     ctx->hdrs[msgno]->lines++;
629     fgets (buf, sizeof (buf), msg->fp);
630   }
631
632   h->content->length = ftello (msg->fp) - h->content->offset;
633
634   /* This needs to be done in case this is a multipart message */
635   if (!WithCrypto)
636     h->security = crypt_query (h->content);
637
638   mutt_clear_error();
639   rewind (msg->fp);
640
641   return 0;
642 }
643
644 /* update POP mailbox - delete messages from server */
645 int pop_sync_mailbox (CONTEXT *ctx, int *index_hint)
646 {
647   int i, j, ret = 0;
648   char buf[LONG_STRING];
649   POP_DATA *pop_data = (POP_DATA *)ctx->data;
650   progress_t progress;
651 #ifdef USE_HCACHE
652   header_cache_t *hc = NULL;
653 #endif
654
655   pop_data->check_time = 0;
656
657   FOREVER
658   {
659     if (pop_reconnect (ctx) < 0)
660       return -1;
661
662     mutt_progress_init (&progress, _("Marking messages deleted..."),
663                         M_PROGRESS_MSG, WriteInc, ctx->deleted);
664
665 #if USE_HCACHE
666     hc = pop_hcache_open (pop_data, ctx->path);
667 #endif
668
669     for (i = 0, j = 0, ret = 0; ret == 0 && i < ctx->msgcount; i++)
670     {
671       if (ctx->hdrs[i]->deleted && ctx->hdrs[i]->refno != -1)
672       {
673         j++;
674         if (!ctx->quiet)
675           mutt_progress_update (&progress, j, -1);
676         snprintf (buf, sizeof (buf), "DELE %d\r\n", ctx->hdrs[i]->refno);
677         if ((ret = pop_query (pop_data, buf, sizeof (buf))) == 0)
678         {
679           mutt_bcache_del (pop_data->bcache, ctx->hdrs[i]->data);
680 #if USE_HCACHE
681           mutt_hcache_delete (hc, ctx->hdrs[i]->data, strlen);
682 #endif
683         }
684       }
685
686 #if USE_HCACHE
687       if (ctx->hdrs[i]->changed)
688       {
689         mutt_hcache_store (hc, ctx->hdrs[i]->data, ctx->hdrs[i], 0, strlen);
690       }
691 #endif
692
693     }
694
695 #if USE_HCACHE
696     mutt_hcache_close (hc);
697 #endif
698
699     if (ret == 0)
700     {
701       strfcpy (buf, "QUIT\r\n", sizeof (buf));
702       ret = pop_query (pop_data, buf, sizeof (buf));
703     }
704
705     if (ret == 0)
706     {
707       pop_data->clear_cache = 1;
708       pop_clear_cache (pop_data);
709       pop_data->status = POP_DISCONNECTED;
710       return 0;
711     }
712
713     if (ret == -2)
714     {
715       mutt_error ("%s", pop_data->err_msg);
716       mutt_sleep (2);
717       return -1;
718     }
719   }
720 }
721
722 /* Check for new messages and fetch headers */
723 int pop_check_mailbox (CONTEXT *ctx, int *index_hint)
724 {
725   int ret;
726   POP_DATA *pop_data = (POP_DATA *)ctx->data;
727
728   if ((pop_data->check_time + PopCheckTimeout) > time (NULL))
729     return 0;
730
731   pop_logout (ctx);
732
733   mutt_socket_close (pop_data->conn);
734
735   if (pop_open_connection (pop_data) < 0)
736     return -1;
737
738   ctx->size = pop_data->size;
739
740   mutt_message _("Checking for new messages...");
741
742   ret = pop_fetch_headers (ctx);
743   pop_clear_cache (pop_data);
744
745   if (ret < 0)
746     return -1;
747
748   if (ret > 0)
749     return M_NEW_MAIL;
750
751   return 0;
752 }
753
754 /* Fetch messages and save them in $spoolfile */
755 void pop_fetch_mail (void)
756 {
757   char buffer[LONG_STRING];
758   char msgbuf[SHORT_STRING];
759   char *url, *p;
760   int i, delanswer, last = 0, msgs, bytes, rset = 0, ret;
761   CONNECTION *conn;
762   CONTEXT ctx;
763   MESSAGE *msg = NULL;
764   ACCOUNT acct;
765   POP_DATA *pop_data;
766
767   if (!PopHost)
768   {
769     mutt_error _("POP host is not defined.");
770     return;
771   }
772
773   url = p = safe_calloc (strlen (PopHost) + 7, sizeof (char));
774   if (url_check_scheme (PopHost) == U_UNKNOWN)
775   {
776     strcpy (url, "pop://");     /* __STRCPY_CHECKED__ */
777     p = strchr (url, '\0');
778   }
779   strcpy (p, PopHost);          /* __STRCPY_CHECKED__ */
780
781   ret = pop_parse_path (url, &acct);
782   FREE (&url);
783   if (ret)
784   {
785     mutt_error (_("%s is an invalid POP path"), PopHost);
786     return;
787   }
788
789   conn = mutt_conn_find (NULL, &acct);
790   if (!conn)
791     return;
792
793   pop_data = safe_calloc (1, sizeof (POP_DATA));
794   pop_data->conn = conn;
795
796   if (pop_open_connection (pop_data) < 0)
797   {
798     mutt_socket_free (pop_data->conn);
799     FREE (&pop_data);
800     return;
801   }
802
803   conn->data = pop_data;
804
805   mutt_message _("Checking for new messages...");
806
807   /* find out how many messages are in the mailbox. */
808   strfcpy (buffer, "STAT\r\n", sizeof (buffer));
809   ret = pop_query (pop_data, buffer, sizeof (buffer));
810   if (ret == -1)
811     goto fail;
812   if (ret == -2)
813   {
814     mutt_error ("%s", pop_data->err_msg);
815     goto finish;
816   }
817
818   sscanf (buffer, "+OK %d %d", &msgs, &bytes);
819
820   /* only get unread messages */
821   if (msgs > 0 && option (OPTPOPLAST))
822   {
823     strfcpy (buffer, "LAST\r\n", sizeof (buffer));
824     ret = pop_query (pop_data, buffer, sizeof (buffer));
825     if (ret == -1)
826       goto fail;
827     if (ret == 0)
828       sscanf (buffer, "+OK %d", &last);
829   }
830
831   if (msgs <= last)
832   {
833     mutt_message _("No new mail in POP mailbox.");
834     goto finish;
835   }
836
837   if (mx_open_mailbox (NONULL (Spoolfile), M_APPEND, &ctx) == NULL)
838     goto finish;
839
840   delanswer = query_quadoption (OPT_POPDELETE, _("Delete messages from server?"));
841
842   snprintf (msgbuf, sizeof (msgbuf), _("Reading new messages (%d bytes)..."), bytes);
843   mutt_message ("%s", msgbuf);
844
845   for (i = last + 1 ; i <= msgs ; i++)
846   {
847     if ((msg = mx_open_new_message (&ctx, NULL, M_ADD_FROM)) == NULL)
848       ret = -3;
849     else
850     {
851       snprintf (buffer, sizeof (buffer), "RETR %d\r\n", i);
852       ret = pop_fetch_data (pop_data, buffer, NULL, fetch_message, msg->fp);
853       if (ret == -3)
854         rset = 1;
855
856       if (ret == 0 && mx_commit_message (msg, &ctx) != 0)
857       {
858         rset = 1;
859         ret = -3;
860       }
861
862       mx_close_message (&msg);
863     }
864
865     if (ret == 0 && delanswer == M_YES)
866     {
867       /* delete the message on the server */
868       snprintf (buffer, sizeof (buffer), "DELE %d\r\n", i);
869       ret = pop_query (pop_data, buffer, sizeof (buffer));
870     }
871
872     if (ret == -1)
873     {
874       mx_close_mailbox (&ctx, NULL);
875       goto fail;
876     }
877     if (ret == -2)
878     {
879       mutt_error ("%s", pop_data->err_msg);
880       break;
881     }
882     if (ret == -3)
883     {
884       mutt_error _("Error while writing mailbox!");
885       break;
886     }
887
888     mutt_message (_("%s [%d of %d messages read]"), msgbuf, i - last, msgs - last);
889   }
890
891   mx_close_mailbox (&ctx, NULL);
892
893   if (rset)
894   {
895     /* make sure no messages get deleted */
896     strfcpy (buffer, "RSET\r\n", sizeof (buffer));
897     if (pop_query (pop_data, buffer, sizeof (buffer)) == -1)
898       goto fail;
899   }
900
901 finish:
902   /* exit gracefully */
903   strfcpy (buffer, "QUIT\r\n", sizeof (buffer));
904   if (pop_query (pop_data, buffer, sizeof (buffer)) == -1)
905     goto fail;
906   mutt_socket_close (conn);
907   FREE (&pop_data);
908   return;
909
910 fail:
911   mutt_error _("Server closed connection!");
912   mutt_socket_close (conn);
913   FREE (&pop_data);
914 }