aboutsummaryrefslogtreecommitdiff
path: root/mail/mutt-devel/files/extra-patch-imap-header-cache
diff options
context:
space:
mode:
Diffstat (limited to 'mail/mutt-devel/files/extra-patch-imap-header-cache')
-rw-r--r--mail/mutt-devel/files/extra-patch-imap-header-cache873
1 files changed, 873 insertions, 0 deletions
diff --git a/mail/mutt-devel/files/extra-patch-imap-header-cache b/mail/mutt-devel/files/extra-patch-imap-header-cache
new file mode 100644
index 000000000000..0c6fb7984a37
--- /dev/null
+++ b/mail/mutt-devel/files/extra-patch-imap-header-cache
@@ -0,0 +1,873 @@
+diff -ru old/globals.h work/mutt-1.5.5.1/globals.h
+--- old/globals.h Wed Nov 5 10:41:31 2003
++++ globals.h Fri Nov 28 18:30:37 2003
+@@ -57,6 +57,7 @@
+ WHERE char *ImapHomeNamespace INITVAL (NULL);
+ WHERE char *ImapPass INITVAL (NULL);
+ WHERE char *ImapUser INITVAL (NULL);
++WHERE char *ImapHeadercache INITVAL (NULL);
+ #endif
+ WHERE char *Inbox;
+ WHERE char *Ispell;
+diff -ru old/imap/Makefile.am work/mutt-1.5.5.1/imap/Makefile.am
+--- old/imap/Makefile.am Thu Jan 24 14:35:57 2002
++++ imap/Makefile.am Fri Nov 28 18:30:37 2003
+@@ -22,4 +22,5 @@
+ noinst_HEADERS = auth.h imap_private.h message.h
+
+ libimap_a_SOURCES = auth.c auth_login.c browse.c command.c imap.c imap.h \
+- message.c utf7.c util.c $(AUTHENTICATORS) $(GSSSOURCES)
++ imap_headercache.c imap_headercache.h message.c utf7.c util.c \
++ $(AUTHENTICATORS) $(GSSSOURCES)
+diff -ru old/imap/imap.c work/mutt-1.5.5.1/imap/imap.c
+--- old/imap/imap.c Wed Nov 5 10:41:36 2003
++++ imap/imap.c Fri Nov 28 18:30:37 2003
+@@ -29,6 +29,7 @@
+ #include "browser.h"
+ #include "message.h"
+ #include "imap_private.h"
++#include "imap_headercache.h"
+ #ifdef USE_SSL
+ # include "mutt_ssl.h"
+ #endif
+@@ -546,6 +547,13 @@
+
+ /* Clean up path and replace the one in the ctx */
+ imap_fix_path (idata, mx.mbox, buf, sizeof (buf));
++
++ if (idata->hcache)
++ {
++ imap_headercache_close(idata->hcache);
++ idata->hcache = NULL;
++ }
++
+ FREE(&(idata->mailbox));
+ idata->mailbox = safe_strdup (buf);
+ imap_qualify_path (buf, sizeof (buf), &mx, idata->mailbox);
+@@ -556,6 +564,7 @@
+ idata->ctx = ctx;
+
+ /* clear mailbox status */
++ idata->uidvalidity = 0;
+ idata->status = 0;
+ memset (idata->rights, 0, (RIGHTSMAX+7)/8);
+ idata->newMailCount = 0;
+@@ -601,6 +610,15 @@
+ if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
+ goto fail;
+ }
++ /* save UIDVALIDITY for the header cache */
++ else if (ascii_strncasecmp("OK [UIDVALIDITY", pc, 14) == 0)
++ {
++ dprint(2, (debugfile, "Getting mailbox UIDVALIDITY\n"));
++ pc += 3;
++ pc = imap_next_word(pc);
++
++ sscanf(pc, "%u", &(idata->uidvalidity));
++ }
+ else
+ {
+ pc = imap_next_word (pc);
+@@ -684,6 +702,9 @@
+ ctx->hdrs = safe_calloc (count, sizeof (HEADER *));
+ ctx->v2r = safe_calloc (count, sizeof (int));
+ ctx->msgcount = 0;
++
++ idata->hcache = imap_headercache_open(idata);
++
+ if (count && (imap_read_headers (idata, 0, count-1) < 0))
+ {
+ mutt_error _("Error opening mailbox");
+@@ -693,6 +714,7 @@
+
+ dprint (2, (debugfile, "imap_open_mailbox: msgcount is %d\n", ctx->msgcount));
+ FREE (&mx.mbox);
++
+ return 0;
+
+ fail:
+@@ -914,6 +936,7 @@
+ int n;
+ int err_continue = M_NO; /* continue on error? */
+ int rc;
++ IMAP_HEADER h;
+
+ idata = (IMAP_DATA*) ctx->data;
+
+@@ -953,8 +976,20 @@
+ /* mark these messages as unchanged so second pass ignores them. Done
+ * here so BOGUS UW-IMAP 4.7 SILENT FLAGS updates are ignored. */
+ for (n = 0; n < ctx->msgcount; n++)
+- if (ctx->hdrs[n]->deleted && ctx->hdrs[n]->changed)
+- ctx->hdrs[n]->active = 0;
++ {
++ if (ctx->hdrs[n]->deleted)
++ {
++ if (idata->hcache)
++ {
++ h.data = HEADER_DATA(ctx->hdrs[n]);
++ imap_headercache_delete(idata->hcache, &h);
++ }
++
++ if (ctx->hdrs[n]->changed)
++ ctx->hdrs[n]->active = 0;
++ }
++ }
++
+ if (imap_exec (idata, cmd.data, 0) != 0)
+ {
+ mutt_error (_("Expunge failed"));
+@@ -972,6 +1007,23 @@
+ {
+ ctx->hdrs[n]->changed = 0;
+
++ if (idata->hcache)
++ {
++ h.data = HEADER_DATA(ctx->hdrs[n]);
++
++ h.read = ctx->hdrs[n]->read;
++ h.old = ctx->hdrs[n]->old;
++ h.deleted = ctx->hdrs[n]->deleted;
++ h.flagged = ctx->hdrs[n]->flagged;
++ h.replied = ctx->hdrs[n]->replied;
++ h.changed = ctx->hdrs[n]->changed;
++ h.sid = ctx->hdrs[n]->index + 1;
++ h.received = ctx->hdrs[n]->received;
++ h.content_length = ctx->hdrs[n]->content->length;
++
++ imap_headercache_update(idata->hcache, &h);
++ }
++
+ mutt_message (_("Saving message status flags... [%d/%d]"), n+1,
+ ctx->msgcount);
+
+@@ -1099,6 +1151,11 @@
+
+ idata->reopen &= IMAP_REOPEN_ALLOW;
+ idata->state = IMAP_AUTHENTICATED;
++ if (idata->hcache)
++ {
++ imap_headercache_close(idata->hcache);
++ idata->hcache = NULL;
++ }
+ FREE (&(idata->mailbox));
+ mutt_free_list (&idata->flags);
+ idata->ctx = NULL;
+diff -ru old/imap/imap_private.h work/mutt-1.5.5.1/imap/imap_private.h
+--- old/imap/imap_private.h Wed Nov 5 10:41:36 2003
++++ imap/imap_private.h Fri Nov 28 18:30:37 2003
+@@ -21,6 +21,7 @@
+ #define _IMAP_PRIVATE_H 1
+
+ #include "imap.h"
++#include "imap_headercache.h"
+ #include "mutt_socket.h"
+
+ /* -- symbols -- */
+@@ -148,7 +149,7 @@
+ int state;
+ } IMAP_COMMAND;
+
+-typedef struct
++typedef struct IMAP_DATA
+ {
+ /* This data is specific to a CONNECTION to an IMAP server */
+ CONNECTION *conn;
+@@ -175,6 +176,7 @@
+ char *mailbox;
+ unsigned short check_status;
+ unsigned char reopen;
++ unsigned int uidvalidity;
+ unsigned char rights[(RIGHTSMAX + 7)/8];
+ unsigned int newMailCount;
+ IMAP_CACHE cache[IMAP_CACHE_LEN];
+@@ -182,6 +184,7 @@
+
+ /* all folder flags - system flags AND keywords */
+ LIST *flags;
++ IMAP_HEADERCACHE *hcache;
+ } IMAP_DATA;
+ /* I wish that were called IMAP_CONTEXT :( */
+
+diff -ru old/imap/message.c work/mutt-1.5.5.1/imap/message.c
+--- old/imap/message.c Wed Nov 5 10:41:36 2003
++++ imap/message.c Fri Nov 28 18:30:38 2003
+@@ -25,6 +25,7 @@
+ #include "mutt.h"
+ #include "mutt_curses.h"
+ #include "imap_private.h"
++#include "imap_headercache.h"
+ #include "message.h"
+ #include "mx.h"
+
+@@ -54,9 +55,14 @@
+ int msgno;
+ IMAP_HEADER h;
+ int rc, mfhrc, oldmsgcount;
++ IMAP_HEADERCACHE *hc = NULL;
++ int msgbegin_hc;
+ int fetchlast = 0;
++
+ const char *want_headers = "DATE FROM SUBJECT TO CC MESSAGE-ID REFERENCES CONTENT-TYPE IN-REPLY-TO REPLY-TO LINES X-LABEL";
+
++ msgno = msgbegin;
++
+ ctx = idata->ctx;
+
+ if (mutt_bit_isset (idata->capabilities,IMAP4REV1))
+@@ -87,36 +93,150 @@
+ }
+ unlink (tempfile);
+
++ oldmsgcount = ctx->msgcount;
++
++ msgbegin_hc = msgbegin;
++
++ hc = idata->hcache;
++
++restart:
+ /* make sure context has room to hold the mailbox */
+ while ((msgend) >= idata->ctx->hdrmax)
+ mx_alloc_memory (idata->ctx);
+
+- oldmsgcount = ctx->msgcount;
+ idata->reopen &= ~IMAP_NEWMAIL_PENDING;
+ idata->newMailCount = 0;
+
++ if (hc)
++ {
++ snprintf(buf, sizeof(buf), "FETCH %d:%d (UID)", msgbegin_hc + 1,
++ msgend + 1);
++ imap_cmd_start(idata, buf);
++
++ for (msgno = msgbegin_hc; msgno <= msgend; msgno++)
++ {
++ if (ReadInc && (!msgno || ((msgno+1) % ReadInc == 0)))
++ mutt_message (_("Fetching message UIDs... [%d/%d]"), msgno + 1,
++ msgend + 1);
++
++ /* XXX */
++ ctx->hdrs[msgno] = NULL;
++
++ /* XXX leaking h.data on successful exit */
++ memset (&h, 0, sizeof (h));
++ h.data = safe_calloc (1, sizeof (IMAP_HEADER_DATA));
++
++ do
++ {
++ FILE *cache_fp;
++
++ mfhrc = 0;
++
++ rc = imap_cmd_step (idata);
++ if (rc != IMAP_CMD_CONTINUE)
++ break;
++
++ if ((mfhrc = msg_fetch_header (idata->ctx, &h, idata->cmd.buf, NULL)) == -1)
++ continue;
++ else if (mfhrc < 0)
++ break;
++
++ cache_fp = imap_headercache_find(hc, &h);
++ if (cache_fp)
++ {
++ /* update context with message header */
++ ctx->hdrs[msgno] = mutt_new_header ();
++
++ ctx->hdrs[msgno]->index = h.sid - 1;
++
++ /* messages which have not been expunged are ACTIVE (borrowed from mh
++ * folders) */
++ ctx->hdrs[msgno]->active = 1;
++ ctx->hdrs[msgno]->read = h.read;
++ ctx->hdrs[msgno]->old = h.old;
++ ctx->hdrs[msgno]->deleted = h.deleted;
++ ctx->hdrs[msgno]->flagged = h.flagged;
++ ctx->hdrs[msgno]->replied = h.replied;
++ ctx->hdrs[msgno]->changed = h.changed;
++ ctx->hdrs[msgno]->received = h.received;
++ ctx->hdrs[msgno]->data = (void *) (h.data);
++
++ /* NOTE: if Date: header is missing, mutt_read_rfc822_header depends
++ * on h.received being set */
++ ctx->hdrs[msgno]->env = mutt_read_rfc822_header (cache_fp, ctx->hdrs[msgno],
++ 0, 0);
++ /* content built as a side-effect of mutt_read_rfc822_header */
++ ctx->hdrs[msgno]->content->length = h.content_length;
++
++ imap_headercache_done(hc, cache_fp);
++ }
++ }
++ while (mfhrc == -1);
++
++ /* in case we get new mail while fetching the headers */
++ if (idata->reopen & IMAP_NEWMAIL_PENDING)
++ {
++ msgbegin_hc = msgno + 1;
++ msgend = idata->newMailCount - 1;
++ goto restart;
++ }
++ /* XXX freshen... etc */
++ }
++ }
++
++ /* Remember where we left if we get new mail while fetching actual headers */
++ msgbegin_hc = msgno;
++
++ /* Now, either one of the following is true:
++ * 1. We don't have a headercache (hc == 0)
++ * 2. All messages found in the cache have ctx->hdrs[msgno] != NULL, and
++ * filled up.
++ */
++
++ /*
++ * Make one request for everything. This makes fetching headers an
++ * order of magnitude faster if you have a large mailbox.
++ *
++ * If we get more messages while doing this, we make another
++ * request for all the new messages.
++ */
++ if (!hc)
++ {
++ snprintf (buf, sizeof (buf),
++ "FETCH %d:%d (UID FLAGS INTERNALDATE RFC822.SIZE %s)", msgbegin + 1,
++ msgend + 1, hdrreq);
++
++ imap_cmd_start (idata, buf);
++ }
++
+ for (msgno = msgbegin; msgno <= msgend ; msgno++)
+ {
+ if (ReadInc && (!msgno || ((msgno+1) % ReadInc == 0)))
+ mutt_message (_("Fetching message headers... [%d/%d]"), msgno + 1,
+ msgend + 1);
+
+- if (msgno + 1 > fetchlast)
++ /* If the message is in the cache, skip it */
++ if (hc)
+ {
+- /*
+- * Make one request for everything. This makes fetching headers an
+- * order of magnitude faster if you have a large mailbox.
+- *
+- * If we get more messages while doing this, we make another
+- * request for all the new messages.
+- */
+- snprintf (buf, sizeof (buf),
+- "FETCH %d:%d (UID FLAGS INTERNALDATE RFC822.SIZE %s)", msgno + 1,
+- msgend + 1, hdrreq);
+-
+- imap_cmd_start (idata, buf);
++ if (ctx->hdrs[msgno])
++ {
++ ctx->msgcount++;
++ continue;
++ }
++ else if (msgno >= fetchlast)
++ {
++ /* Find the longest "run" of messages not in the cache and fetch it in
++ * one go
++ */
++ for (fetchlast = msgno + 1;
++ fetchlast <= msgend && !ctx->hdrs[fetchlast]; fetchlast++);
++
++ snprintf (buf, sizeof (buf),
++ "FETCH %d:%d (UID FLAGS INTERNALDATE RFC822.SIZE %s)", msgno + 1,
++ fetchlast, hdrreq);
+
+- fetchlast = msgend + 1;
++ imap_cmd_start (idata, buf);
++ }
+ }
+
+ /* freshen fp, h */
+@@ -130,6 +250,8 @@
+ */
+ do
+ {
++ size_t hdrsz;
++
+ mfhrc = 0;
+
+ rc = imap_cmd_step (idata);
+@@ -144,12 +266,16 @@
+ /* make sure we don't get remnants from older larger message headers */
+ fputs ("\n\n", fp);
+
++ hdrsz = (size_t)ftell(fp);
++
+ /* update context with message header */
+ ctx->hdrs[msgno] = mutt_new_header ();
+
+ ctx->hdrs[msgno]->index = h.sid - 1;
++#if 0
+ if (h.sid != ctx->msgcount + 1)
+ dprint (1, (debugfile, "imap_read_headers: msgcount and sequence ID are inconsistent!"));
++#endif
+ /* messages which have not been expunged are ACTIVE (borrowed from mh
+ * folders) */
+ ctx->hdrs[msgno]->active = 1;
+@@ -163,6 +289,13 @@
+ ctx->hdrs[msgno]->data = (void *) (h.data);
+
+ rewind (fp);
++
++ if (hc)
++ {
++ imap_headercache_add(hc, &h, fp, hdrsz);
++ rewind(fp);
++ }
++
+ /* NOTE: if Date: header is missing, mutt_read_rfc822_header depends
+ * on h.received being set */
+ ctx->hdrs[msgno]->env = mutt_read_rfc822_header (fp, ctx->hdrs[msgno],
+@@ -172,8 +305,7 @@
+
+ ctx->msgcount++;
+ }
+- while ((rc != IMAP_CMD_OK) && ((mfhrc == -1) ||
+- ((msgno + 1) >= fetchlast)));
++ while (mfhrc == -1);
+
+ if ((mfhrc < -1) || ((rc != IMAP_CMD_CONTINUE) && (rc != IMAP_CMD_OK)))
+ {
+@@ -186,11 +318,9 @@
+ /* in case we get new mail while fetching the headers */
+ if (idata->reopen & IMAP_NEWMAIL_PENDING)
+ {
++ msgbegin = msgno + 1;
+ msgend = idata->newMailCount - 1;
+- while ((msgend) >= ctx->hdrmax)
+- mx_alloc_memory (ctx);
+- idata->reopen &= ~IMAP_NEWMAIL_PENDING;
+- idata->newMailCount = 0;
++ goto restart;
+ }
+ }
+
+@@ -735,6 +865,7 @@
+ IMAP_DATA* idata;
+ long bytes;
+ int rc = -1; /* default now is that string isn't FETCH response*/
++ int fetch_rc;
+
+ idata = (IMAP_DATA*) ctx->data;
+
+@@ -757,9 +888,15 @@
+
+ /* FIXME: current implementation - call msg_parse_fetch - if it returns -2,
+ * read header lines and call it again. Silly. */
+- if (msg_parse_fetch (h, buf) != -2)
++ fetch_rc = msg_parse_fetch(h, buf);
++ if (fetch_rc == 0)
++ return 0;
++ else if (fetch_rc != -2)
+ return rc;
+-
++
++ if (!fp)
++ return -2;
++
+ if (imap_get_literal_count (buf, &bytes) < 0)
+ return rc;
+ imap_read_literal (fp, idata, bytes);
+diff -ru old/init.h work/mutt-1.5.5.1/init.h
+--- old/init.h Wed Nov 5 10:41:32 2003
++++ init.h Fri Nov 28 18:30:37 2003
+@@ -856,6 +856,11 @@
+ ** .pp
+ ** This variable defaults to your user name on the local machine.
+ */
++ { "imap_headercache", DT_STR, R_NONE, UL &ImapHeadercache, UL 0 },
++ /*
++ ** .pp
++ ** The location of the IMAP headercache directory.
++ */
+ #endif
+ { "implicit_autoview", DT_BOOL,R_NONE, OPTIMPLICITAUTOVIEW, 0},
+ /*
+diff -ruN old/imap/imap_headercache.c work/mutt-1.5.5.1/imap/imap_headercache.c
+--- old/imap/imap_headercache.c Thu Jan 1 01:00:00 1970
++++ imap/imap_headercache.c Fri Nov 28 18:30:55 2003
+@@ -0,0 +1,330 @@
++/*
++ * Copyright (C) 2002 Tudor Bosman <tudorb-mutt@dwyn.net>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
++ */
++
++#include "mutt.h"
++#include "imap.h"
++#include "imap_private.h"
++#include "imap_headercache.h"
++#include "mx.h"
++#include <stdio.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <unistd.h>
++#include <dirent.h>
++#include <assert.h>
++
++/* Delete all messages from headercache */
++static int imap_headercache_purge(IMAP_HEADERCACHE *hc)
++{
++ int rc = -1;
++ DIR *dir;
++ struct dirent *ent;
++
++ dir = opendir(hc->name);
++ if (!dir)
++ {
++ mutt_error(_("IMAP headercache: can't purge directory %s: %s"), hc->name,
++ strerror(errno));
++ mutt_sleep(2);
++ return -1;
++ }
++
++ while ((ent = readdir(dir)) != NULL)
++ {
++ if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
++ continue;
++
++ sprintf(hc->tmpname, "%s/%s", hc->name, ent->d_name);
++ if (unlink(hc->tmpname) == -1)
++ {
++ mutt_error(_("IMAP headercache: can't unlink file %s: %s"), hc->tmpname,
++ strerror(errno));
++ mutt_sleep(2);
++ goto bail;
++ }
++ }
++
++ rc = 0;
++
++bail:
++ closedir(dir);
++
++ return rc;
++}
++
++/* Open headercache */
++IMAP_HEADERCACHE *imap_headercache_open(IMAP_DATA *idata)
++{
++ IMAP_HEADERCACHE *hc;
++ char hcdir[_POSIX_PATH_MAX + 1];
++ FILE *f;
++ size_t len;
++ char *p;
++
++ if (!ImapHeadercache || ImapHeadercache[0] == '\0')
++ return NULL;
++
++ strfcpy(hcdir, ImapHeadercache, _POSIX_PATH_MAX);
++ mutt_expand_path(hcdir, _POSIX_PATH_MAX);
++
++ hc = safe_malloc(sizeof(IMAP_HEADERCACHE));
++
++ len = strlen(hcdir) + strlen(idata->conn->account.host) +
++ strlen(idata->mailbox) + 5;
++
++ hc->name = safe_malloc(len);
++ hc->tmpname = safe_malloc(len + NAME_MAX + 2);
++
++ sprintf(hc->name, "%s/%s", hcdir, idata->conn->account.host);
++
++ if (mkdir(hcdir, 0777) == -1 && errno != EEXIST)
++ {
++ mutt_error(_("Can't create IMAP headercache root directory %s: %s"),
++ hcdir, strerror(errno));
++ mutt_sleep(2);
++ goto bail;
++ }
++
++ if (mkdir(hc->name, 0700) == -1 && errno != EEXIST)
++ {
++ mutt_error(_("Can't create IMAP headercache server directory %s: %s"),
++ hc->name, strerror(errno));
++ mutt_sleep(2);
++ goto bail;
++ }
++
++ p = idata->mailbox;
++ while ((p = strchr(p, '/')) != NULL)
++ {
++ *p = '\0';
++ sprintf(hc->name, "%s/%s/%s", hcdir,
++ idata->conn->account.host, idata->mailbox);
++
++ if (mkdir(hc->name, 0700) == -1 && errno != EEXIST)
++ {
++ mutt_error(_("Can't create IMAP headercache mailbox directory %s: %s"),
++ hc->name, strerror(errno));
++ mutt_sleep(2);
++ goto bail;
++ }
++
++ *p = '/';
++ p++;
++ }
++
++ sprintf(hc->name, "%s/%s/%s", hcdir,
++ idata->conn->account.host, idata->mailbox);
++
++ if (mkdir(hc->name, 0700) == -1 && errno != EEXIST)
++ {
++ mutt_error(_("Can't create IMAP headercache mailbox directory %s: %s"),
++ hc->name, strerror(errno));
++ mutt_sleep(2);
++ goto bail;
++ }
++
++ sprintf(hc->tmpname, "%s/uidvalidity", hc->name);
++ f = fopen(hc->tmpname, "r");
++
++ if (f)
++ {
++ fscanf(f, "%u", &hc->uidvalidity);
++ if (idata->uidvalidity != hc->uidvalidity)
++ {
++ fclose(f);
++ f = NULL;
++ }
++ }
++
++ if (!f)
++ {
++ if (imap_headercache_purge(hc) == -1)
++ goto bail;
++
++ sprintf(hc->tmpname, "%s/uidvalidity", hc->name);
++ f = fopen(hc->tmpname, "w");
++ if (!f)
++ {
++ mutt_error(_("Can't create IMAP headercache uidvalidity file %s: %s"),
++ hc->tmpname, strerror(errno));
++ mutt_sleep(2);
++ goto bail;
++ }
++
++ hc->uidvalidity = idata->uidvalidity;
++
++ fprintf(f, "%u\n", hc->uidvalidity);
++ fclose(f);
++ }
++
++ return hc;
++
++bail:
++ safe_free((void **)&hc->tmpname);
++ safe_free((void **)&hc->name);
++ safe_free((void **)&hc);
++
++ return NULL;
++}
++
++/* Close headercache */
++void imap_headercache_close(IMAP_HEADERCACHE *hc)
++{
++ safe_free((void **)&hc->tmpname);
++ safe_free((void **)&hc->name);
++ safe_free((void **)&hc);
++}
++
++static void imap_headercache_writehdr(FILE *f, IMAP_HEADER *h)
++{
++ /* Write the stuff in the header. This must have a fixed length, as it is
++ * overwritten in case of imap_headercache_update
++ */
++ fprintf(f, "%1x %1x %1x %1x %1x %1x %8x %16lx %16lx %8x\n",
++ h->read, h->old, h->deleted, h->flagged, h->replied, h->changed,
++ h->sid, h->received, h->content_length, HEADER_DATA(h)->uid);
++}
++
++/* Add message to headercache */
++int imap_headercache_add(IMAP_HEADERCACHE *hc, IMAP_HEADER *h, FILE *from,
++ size_t hdrsz)
++{
++ FILE *f;
++#define BUFSIZE 4096
++ char buf[BUFSIZE];
++ size_t sz;
++ int rc = -1;
++
++ sprintf(hc->tmpname, "%s/%u", hc->name, HEADER_DATA(h)->uid);
++
++ f = fopen(hc->tmpname, "w");
++ if (!f)
++ {
++ mutt_error(_("Can't create IMAP headercache message file %s: %s"),
++ hc->tmpname, strerror(errno));
++ mutt_sleep(2);
++ goto bail;
++ }
++
++ imap_headercache_writehdr(f, h);
++
++ while ((sz = fread(buf, 1, (hdrsz < BUFSIZE ? hdrsz : BUFSIZE), from)) != 0)
++ {
++ hdrsz -= sz;
++ fwrite(buf, 1, sz, f);
++ }
++
++ fclose(f);
++
++ rc = 0;
++
++bail:
++ return rc;
++}
++
++/* Update flags in headercache message */
++int imap_headercache_update(IMAP_HEADERCACHE *hc, IMAP_HEADER *h)
++{
++ FILE *f;
++ int rc = -1;
++
++ sprintf(hc->tmpname, "%s/%u", hc->name, HEADER_DATA(h)->uid);
++
++ f = fopen(hc->tmpname, "r+");
++ if (!f)
++ goto bail;
++
++ imap_headercache_writehdr(f, h);
++
++ fclose(f);
++
++ rc = 0;
++
++bail:
++ return rc;
++}
++
++/* Delete message from headercache */
++int imap_headercache_delete(IMAP_HEADERCACHE *hc, IMAP_HEADER *h)
++{
++ int rc = -1;
++
++ sprintf(hc->tmpname, "%s/%u", hc->name, HEADER_DATA(h)->uid);
++
++ if (unlink(hc->tmpname) == -1)
++ {
++ mutt_error(_("Can't delete IMAP headercache message %s: %s"),
++ hc->tmpname, strerror(errno));
++ mutt_sleep(2);
++ goto bail;
++ }
++
++ rc = 0;
++
++bail:
++ return rc;
++}
++
++/* Find message in headercache */
++FILE *imap_headercache_find(IMAP_HEADERCACHE *hc, IMAP_HEADER *h)
++{
++ FILE *f = NULL;
++ unsigned int flag_read, flag_old, flag_deleted, flag_flagged, flag_replied;
++ unsigned int flag_changed;
++ unsigned int uid;
++ unsigned long received;
++ unsigned long content_length;
++
++ sprintf(hc->tmpname, "%s/%u", hc->name, HEADER_DATA(h)->uid);
++
++ f = fopen(hc->tmpname, "r");
++ if (!f)
++ goto bail;
++
++ fscanf(f, "%x %x %x %x %x %x %x %lx %lx %x\n",
++ &flag_read, &flag_old, &flag_deleted, &flag_flagged, &flag_replied,
++ &flag_changed, &h->sid, &received, &content_length, &uid);
++
++ if (uid != HEADER_DATA(h)->uid)
++ {
++ fclose(f);
++ f = NULL;
++ goto bail;
++ }
++
++ h->received = received;
++ h->read = flag_read;
++ h->old = flag_old;
++ h->deleted = flag_deleted;
++ h->flagged = flag_flagged;
++ h->replied = flag_replied;
++ h->changed = flag_changed;
++ h->content_length = (long)content_length;
++
++bail:
++ return f;
++}
++
++/* Close file returned by imap_headercache_find */
++void imap_headercache_done(IMAP_HEADERCACHE *hc, FILE *f)
++{
++ fclose(f);
++}
++
+diff -ruN old/imap/imap_headercache.h work/mutt-1.5.5.1/imap/imap_headercache.h
+--- old/imap/imap_headercache.h Thu Jan 1 01:00:00 1970
++++ imap/imap_headercache.h Fri Nov 28 18:30:55 2003
+@@ -0,0 +1,47 @@
++/*
++ * Copyright (C) 2002 Tudor Bosman <tudorb-mutt@dwyn.net>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
++ */
++
++#ifndef _IMAP_HEADERCACHE_H
++#define _IMAP_HEADERCACHE_H
++#include "imap_private.h"
++#include "message.h"
++
++typedef struct IMAP_HEADERCACHE
++{
++ char *name;
++ char *tmpname;
++ unsigned int uidvalidity;
++ int exists;
++} IMAP_HEADERCACHE;
++
++struct IMAP_DATA;
++
++IMAP_HEADERCACHE *imap_headercache_open(struct IMAP_DATA *idata);
++
++void imap_headercache_close(IMAP_HEADERCACHE *hc);
++
++int imap_headercache_add(IMAP_HEADERCACHE *hc, IMAP_HEADER *h, FILE *from,
++ size_t hdrsz);
++int imap_headercache_update(IMAP_HEADERCACHE *hc, IMAP_HEADER *h);
++int imap_headercache_delete(IMAP_HEADERCACHE *hc, IMAP_HEADER *h);
++
++FILE *imap_headercache_find(IMAP_HEADERCACHE *hc, IMAP_HEADER *h);
++void imap_headercache_done(IMAP_HEADERCACHE *hc, FILE *f);
++
++#endif
++