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