Index: head/mail/mutt-devel/Makefile =================================================================== --- head/mail/mutt-devel/Makefile (revision 111332) +++ head/mail/mutt-devel/Makefile (revision 111333) @@ -1,410 +1,411 @@ # ex:ts=8 # Ports collection makefile for: mutt development # Date created: 6 Jun 2001 # Whom: Udo Schweigert # # $FreeBSD$ # # There are several knobs which are used to define additions to the core # mutt functionality. # # As all of the knobs have a unique name which should not interfere with # other ports you can add them to /etc/make.conf, e.g. a line like # "WITH_MUTT_NNTP=yes" will enable mutt's nntp facilities. # # In addition to the knobs listed below you can enable other configuration # options of mutt by adding them to the MUTT_CONFIGURE_ARGS variable. For # example you could say "MUTT_CONFIGURE_ARGS=--with-homespool=MyMail" to # configure a different file for mutt's homespool. # # The two most important knobs are: # # In general you can choose between using the SLANG port (WITH_MUTT_SLANG) # and ncurses (WITH_MUTT_NCURSES) which is the default. Note that you may # have to set the variables COLORTERM=yes and COLORFGBG=color,color in your # environment to get slang function properly. # # If you want to install the mutt documentation in html and ps format define: # WITH_MUTT_HTML # This is a default knob and can be disabled by WITHOUT_MUTT_HTML # # If you do not want that the documentation is rebuilt using sgmlformat # define: # WITHOUT_MUTT_SGMLFORMAT # (this can only be stated if WITHOUT_MUTT_HTML is defined) # # If you want to access compressed email folders define: # WITH_MUTT_COMPRESSED_FOLDERS # This is a default knob and can be disabled by WITHOUT_MUTT_COMPRESSED_FOLDERS # # If you do not want mutt to use the iconv library define: # WITHOUT_MUTT_ICONV # # If you want to enable extended quoting functions define: # WITH_MUTT_QUOTE_PATCH # This is a default knob and can be disabled by WITHOUT_MUTT_QUOTE_PATCH # # If you want to have the IMAP header cache define: # WITH_MUTT_IMAP_HEADER_CACHE # # If you want to have the Maildir header cache define: # WITH_MUTT_MAILDIR_HEADER_CACHE # # If you want to make SMIME outlook compatible define: # WITH_MUTT_SMIME_OUTLOOK_COMPAT # This is a default knob and can be disabled by # WITHOUT_MUTT_SMIME_OUTLOOK_COMPAT # # If you want to use enhanced pgp features define: # WITH_MUTT_PGP_PATCH # This is a default knob and can be disabled by WITHOUT_MUTT_PGP_PATCH # # If you want to read and post news with mutt define: # WITH_MUTT_NNTP # # If you want to use the SASL authentication features with your email server # define # WITH_MUTT_CYRUS_SASL # # If you want to use the rethreading functions define: # WITH_MUTT_EDIT_THREADS # # If you want to use the signature menu define: # WITH_MUTT_SIGNATURE_MENU # # If you want to use the printf-like enhancement to the mbox-hook command # define: # WITH_MUTT_MBOX_HOOK_PATCH # # If you want to use the ifdef feature define: # WITH_MUTT_IFDEF_PATCH PORTNAME= mutt-devel PORTVERSION= 1.5.6 -PORTREVISION= 2 +PORTREVISION= 3 CATEGORIES+= mail ipv6 .if defined(WITH_MUTT_NNTP) CATEGORIES+= news .endif MASTER_SITES= ftp://ftp.mutt.org/mutt/devel/ \ ftp://ftp.fu-berlin.de/pub/unix/mail/mutt/devel/ \ ftp://ftp.demon.co.uk/pub/mirrors/mutt/devel/ \ ftp://ftp.parodius.com/pub/mutt/devel/ DISTNAME= mutt-${PORTVERSION}i PATCH_SITES+= http://www.mutt.org.ua/download/mutt-${VVV_PATCH_VERSION}/:vvv \ http://www2.mutt.org.ua/download/mutt-${VVV_PATCH_VERSION}/:vvv \ http://www3.mutt.org.ua/download/mutt-${VVV_PATCH_VERSION}/:vvv \ ftp://ftp.mutt.org.ua/pub/mutt/mutt-${VVV_PATCH_VERSION}/:vvv \ ftp://ftp3.mutt.org.ua/pub/mutt/mutt-${VVV_PATCH_VERSION}/:vvv \ http://cedricduval.free.fr/mutt/patches/download/:cd \ http://home.woolridge.ca/mutt/patches/:dw MAINTAINER?= udo.schweigert@siemens.com COMMENT?= The Mongrel of Mail User Agents (part Elm, Pine, Mush, mh, etc.) CONFLICTS= mutt-[0-9]* DIST_SUBDIR= mutt DOCSDIR?= ${PREFIX}/share/doc/mutt EXAMPLESDIR?= ${PREFIX}/share/examples/mutt DATADIR?= ${PREFIX}/share/mutt LDFLAGS+= -L${LOCALBASE}/lib CONFIGURE_ENV= CC="${CC} -I${LOCALBASE}/include" LDFLAGS="${LDFLAGS}" CONFIGURE_ARGS= --enable-flock --disable-fcntl --with-ssl=${OPENSSLBASE} \ --with-sharedir=${PREFIX}/share/mutt --with-docdir=${DOCSDIR} \ --sysconfdir=${PREFIX}/etc --enable-external-dotlock \ --enable-pop --enable-imap .if defined(MUTT_CONFIGURE_ARGS) CONFIGURE_ARGS+= ${MUTT_CONFIGURE_ARGS} .endif USE_REINPLACE= yes -USE_AUTOMAKE_VER= 14 -USE_AUTOCONF_VER= 213 +USE_AUTOMAKE_VER= 18 +USE_AUTOCONF_VER= 259 USE_OPENSSL= yes PLIST= ${WRKDIR}/PLIST PKGMESSAGE= ${WRKDIR}/pkg-message SCRIPTS_ENV= WRKDIR="${WRKDIR}" .include CD_PATCH_VERSION= 1.5.5.1 CD_IFDEF_PATCH_VERSION= 1.5.4 .if !defined(VVV_PATCH_VERSION) VVV_PATCH_VERSION= ${PORTVERSION} .endif .if !defined(CD_PATCH_VERSION) CD_PATCH_VERSION= ${PORTVERSION} .endif .if !defined(CD_IFDEF_PATCH_VERSION) CD_IFDEF_PATCH_VERSION= ${CD_PATCH_VERSION} .endif .if !defined(DW_PATCH_VERSION) DW_PATCH_VERSION= ${PORTVERSION} .endif .if !defined(DW_MBOX_PATCH_VERSION) DW_MBOX_PATCH_VERSION= ${DW_PATCH_VERSION} .endif # XXX # this should be done automagically by aclocal but .... # for now, this will have to do pre-build: @${REINPLACE_CMD} -E -e "s|^(ACLOCAL = ).+|\1${ACLOCAL}|" \ -e "s|^(AUTOCONF = ).+|\1${AUTOCONF}|" \ -e "s|^(AUTOMAKE = ).+|\1${AUTOMAKE}|" \ -e "s|^(AUTOHEADER = ).+|\1${AUTOHEADER}|" \ ${BUILD_WRKSRC}/Makefile .if defined(PACKAGE_BUILDING) BUILD_DEPENDS+= ispell:${PORTSDIR}/textproc/ispell RUN_DEPENDS= ispell:${PORTSDIR}/textproc/ispell \ urlview:${PORTSDIR}/textproc/urlview .endif .if defined(WITH_MUTT_NCURSES_PORT) WITH_MUTT_NCURSES= yes .endif .if defined(WITH_MUTT_NCURSES) -USE_NCURSES= yes +MUTT_USES_NCURSES= yes .endif -.if defined(WITH_MUTT_SLANG) && !defined(USE_NCURSES) -USE_SLANG= yes +.if defined(WITH_MUTT_SLANG) && !defined(MUTT_USES_NCURSES) +MUTT_USES_SLANG= yes .endif -.if !defined(USE_NCURSES) && !defined(WITHOUT_MUTT_NCURSES) && !defined(USE_SLANG) -USE_NCURSES= yes +.if !defined(MUTT_USES_NCURSES) && !defined(WITHOUT_MUTT_NCURSES) && !defined(MUTT_USES_SLANG) +MUTT_USES_NCURSES= yes .endif .if defined(WITHOUT_MUTT_SGMLFORMAT) SGML_USED= no .endif .if !defined(SGML_USED) SGML_USED= no .endif .if !defined(WITHOUT_NLS) USE_GETTEXT= yes .endif .if !defined(WITHOUT_MUTT_ICONV) USE_ICONV= yes .endif .if defined(NOPORTDOCS) SGML_USED= no .endif -.if defined(USE_NCURSES) && ${OSVERSION} < 400000 +.if defined(MUTT_USES_NCURSES) && ${OSVERSION} < 400000 LIB_DEPENDS+= ncurses.5:${PORTSDIR}/devel/ncurses CFLAGS+= -I${PREFIX}/include/ncurses -I${PREFIX}/include -.elif defined(USE_SLANG) +.elif defined(MUTT_USES_SLANG) LIB_DEPENDS+= slang.1:${PORTSDIR}/devel/libslang .endif .if defined(WITH_MUTT_CYRUS_SASL) BROKEN= "mutt-devel's SASL code appears to be broken" LIB_DEPENDS+= sasl.8:${PORTSDIR}/security/cyrus-sasl .endif .if defined(WITH_MUTT_MAILDIR_HEADER_CACHE) -LIB_DEPENDS+= gdbm.3:${PORTSDIR}/databases/gdbm +LIB_DEPENDS+= db-4.2.2:${PORTSDIR}/databases/db42 +CFLAGS+= -I${PREFIX}/include/db42 .endif .if ! defined(WITHOUT_MUTT_SMIME_OUTLOOK_COMPAT) pre-configure:: @${PATCH} ${PATCH_ARGS} < ${PATCHDIR}/extra-patch-smime-outlook .endif .if defined(WITH_MUTT_IMAP_HEADER_CACHE) pre-configure:: @${PATCH} ${PATCH_ARGS} < ${PATCHDIR}/extra-patch-imap-header-cache .endif .if defined(WITH_MUTT_MAILDIR_HEADER_CACHE) pre-configure:: @${PATCH} ${PATCH_ARGS} < ${PATCHDIR}/extra-patch-maildir-header-cache .endif .if ! defined(WITHOUT_MUTT_PGP_PATCH) SGML_NEEDED= yes pre-configure:: @${PATCH} ${PATCH_ARGS} < ${PATCHDIR}/extra-patch-pgp-dw .endif .if defined(WITH_MUTT_EDIT_THREADS) pre-configure:: @${PATCH} ${PATCH_ARGS} < ${PATCHDIR}/extra-patch-edit-threads .endif .if defined(WITH_MUTT_LOCALES_FIX) CONFIGURE_ARGS+= --enable-locales-fix .endif -.if defined(USE_NCURSES) && ${OSVERSION} < 400000 +.if defined(MUTT_USES_NCURSES) && ${OSVERSION} < 400000 CONFIGURE_ARGS+= --with-curses=${PREFIX} -.elif defined(USE_SLANG) +.elif defined(MUTT_USES_SLANG) CONFIGURE_ARGS+= --with-slang=${PREFIX} PATCHFILES+= patch-${VVV_PATCH_VERSION}.vvv.slang.gz:vvv .endif .if defined(WITH_MUTT_CYRUS_SASL) CONFIGURE_ARGS+= --with-sasl=${LOCALBASE} .endif .if defined(WITHOUT_NLS) CONFIGURE_ARGS+= --disable-nls .endif -.if defined(WITHOUT_MUTT_ICONV) +.if defined(WITHOUT_MUTT_ICONV) CONFIGURE_ARGS+= --disable-iconv .else CONFIGURE_ARGS+= --with-libiconv-prefix=${PREFIX} .endif PATCH_DIST_STRIP= -p1 .if ! defined (WITHOUT_MUTT_COMPRESSED_FOLDERS) PATCHFILES+= patch-${VVV_PATCH_VERSION}.rr.compressed.gz:vvv CONFIGURE_ARGS+= --enable-compressed SGML_NEEDED= yes .endif .if defined(WITH_MUTT_NNTP) PATCHFILES+= patch-${VVV_PATCH_VERSION}.vvv.nntp.gz:vvv CONFIGURE_ARGS+= --enable-nntp SGML_NEEDED= yes .endif .if ! defined(WITHOUT_MUTT_QUOTE_PATCH) PATCHFILES+= patch-${VVV_PATCH_VERSION}.vvv.initials.gz:vvv \ patch-${VVV_PATCH_VERSION}.vvv.quote.gz:vvv SGML_NEEDED= yes .endif .if defined(WITH_MUTT_EDIT_THREADS) CONFIGURE_ARGS+= --enable-imap-edit-threads SGML_NEEDED= yes .endif .if defined(WITH_MUTT_SIGNATURE_MENU) PATCHFILES+= patch-${CD_PATCH_VERSION}.cd.signatures_menu.2.1:cd SGML_NEEDED= yes .endif .if defined(WITH_MUTT_IFDEF_PATCH) PATCHFILES+= patch-${CD_IFDEF_PATCH_VERSION}.cd.ifdef.1:cd SGML_NEEDED= yes .endif .if defined(WITH_MUTT_MBOX_HOOK_PATCH) PATCHFILES+= p0-patch-${DW_MBOX_PATCH_VERSION}.dw.mbox-hook.1:dw .endif WRKSRC= ${WRKDIR}/${DISTNAME:S/i$//} MAN1= flea.1 mutt.1 mutt_dotlock.1 muttbug.1 MAN5= muttrc.5 mbox.5 post-patch:: @${REINPLACE_CMD} -e 's,/usr/bin/gpg,${LOCALBASE}/bin/gpg,g' \ ${WRKSRC}/contrib/gpg.rc @${REINPLACE_CMD} -E -e 's|@samplesdir@|${EXAMPLESDIR}|g' \ ${WRKSRC}/contrib/Makefile.in pre-configure:: @(cd ${WRKSRC}; ${SETENV} ${AUTOMAKE_ENV} ${ACLOCAL} -I m4) .if defined(WITH_MUTT_NNTP) SCRIPTS_ENV+= MUTT_NNTP="yes" .endif .if ! defined (WITHOUT_MUTT_COMPRESSED_FOLDERS) SCRIPTS_ENV+= MUTT_COMPRESSED_FOLDERS="yes" .endif .if ! defined(WITHOUT_MUTT_QUOTE_PATCH) SCRIPTS_ENV+= MUTT_QUOTE_PATCH="yes" .endif .if defined(WITH_MUTT_IMAP_HEADER_CACHE) SCRIPTS_ENV+= MUTT_IMAP_HEADER_CACHE="yes" .endif .if defined(WITH_MUTT_MAILDIR_HEADER_CACHE) SCRIPTS_ENV+= MUTT_MAILDIR_HEADER_CACHE="yes" CONFIGURE_ARGS+= --enable-hcache .endif .if defined(WITH_MUTT_EDIT_THREADS) SCRIPTS_ENV+= MUTT_EDIT_THREADS="yes" .endif .if defined(WITH_MUTT_SIGNATURE_MENU) SCRIPTS_ENV+= MUTT_SIGNATURE_MENU="yes" .endif .if defined(WITH_MUTT_IFDEF_PATCH) SCRIPTS_ENV+= MUTT_IFDEF_PATCH="yes" .endif .if ! defined(WITHOUT_MUTT_PGP_PATCH) SCRIPTS_ENV+= MUTT_PGP_PATCH="yes" .endif .if ! defined(WITHOUT_MUTT_HTML) SCRIPTS_ENV+= MUTT_HTML="yes" .endif .if !defined(WITHOUT_NLS) SCRIPTS_ENV+= MUTT_NLS="yes" .endif .if !defined(NOPORTDOCS) SCRIPTS_ENV+= MUTT_PORTDOCS="yes" post-build: @${PATCH} ${PATCH_ARGS} < ${PATCHDIR}/extra-patch-doc-ref @${REINPLACE_CMD} -E -e 's|\$$\{PREFIX\}|${PREFIX}|g' \ -e 's|\$$\{DOCSDIR\}|${DOCSDIR}|g' \ -e 's|\$$\{EXAMPLESDIR\}|${EXAMPLESDIR}|g' \ ${WRKSRC}/doc/mutt.man @${REINPLACE_CMD} -E -e 's|\$$\{PREFIX\}|${PREFIX}|g' \ -e 's|\$$\{DOCSDIR\}|${DOCSDIR}|g' \ -e 's|\$$\{EXAMPLESDIR\}|${EXAMPLESDIR}|g' \ ${WRKSRC}/doc/muttrc.man .if ! defined(WITHOUT_MUTT_HTML) SGML_USED= yes .endif .if defined(SGML_NEEDED) && !defined(WITHOUT_MUTT_SGMLFORMAT) SGML_USED= yes .endif .else # ! NOPORTDOCS post-patch:: @${PATCH} ${PATCH_ARGS} < ${PATCHDIR}/extra-patch-nodoc-contrib .endif # ! NOPORTDOCS .if ${SGML_USED} == yes SCRIPTS_ENV+= MUTT_SGML="yes" BUILD_DEPENDS+= sgmlfmt:${PORTSDIR}/textproc/sgmlformat post-patch:: @${PATCH} ${PATCH_ARGS} < ${PATCHDIR}/extra-patch-sgmlformat .endif pre-install: @${SETENV} ${SCRIPTS_ENV} ${SH} ${SCRIPTDIR}/generate-plist > ${PLIST} post-install: @${ECHO} > ${PKGMESSAGE} ${INSTALL_DATA} ${WRKSRC}/Muttrc ${PREFIX}/etc/Muttrc.dist ${INSTALL_DATA} ${WRKSRC}/mime.types ${PREFIX}/etc/mime.types.dist .if !defined(NOPORTDOCS) @${ECHO} "===> Installing Mutt documentation" @${MKDIR} ${DOCSDIR} && ${CHMOD} a+rx ${DOCSDIR} @cd ${WRKSRC}/doc ; ${INSTALL_MAN} manual.txt PGP-Notes.txt \ ../ABOUT-NLS ../contrib/language* ${DOCSDIR} .if ${SGML_USED} == yes @cd ${WRKSRC}/doc ; ${INSTALL_MAN} manual.latin1 manual.ps ${DOCSDIR} .endif .if defined(WITH_MUTT_NNTP) @cd ${WRKSRC} ; ${INSTALL_MAN} ChangeLog.nntp ${DOCSDIR} .endif .if ! defined(WITHOUT_MUTT_HTML) @${MKDIR} ${DOCSDIR}/html && ${CHMOD} a+rx ${DOCSDIR}/html ${INSTALL_MAN} ${WRKSRC}/doc/*.html ${DOCSDIR}/html .endif .endif -.if defined(USE_SLANG) +.if defined(MUTT_USES_SLANG) @${ECHO} "====================================================" >> ${PKGMESSAGE} @${ECHO} "You have installed ${PORTNAME} with SLANG support." >> ${PKGMESSAGE} @${ECHO} "This may work for a color terminal only when defining" >> ${PKGMESSAGE} @${ECHO} "COLORTERM=yes and COLORFGBG=color,color in your" >> ${PKGMESSAGE} @${ECHO} "environment." >> ${PKGMESSAGE} @${ECHO} "====================================================" >> ${PKGMESSAGE} .endif .if defined(WITH_MUTT_IMAP_HEADER_CACHE) @${ECHO} "====================================================" >> ${PKGMESSAGE} @${ECHO} "You have installed ${PORTNAME} with the IMAP header cache enabled." >> ${PKGMESSAGE} @${ECHO} "Please be aware that this - at the moment - could result in" >> ${PKGMESSAGE} @${ECHO} "incorrect display of message flags if there is another client" >> ${PKGMESSAGE} @${ECHO} "simultaneously using the same mailbox." >> ${PKGMESSAGE} @${ECHO} "====================================================" >> ${PKGMESSAGE} .endif .if !defined(BATCH) @${ECHO} @${CAT} ${PKGMESSAGE} @${ECHO} .endif .include Property changes on: head/mail/mutt-devel/Makefile ___________________________________________________________________ Modified: cvs2svn:cvs-rev ## -1 +1 ## -1.223 \ No newline at end of property +1.224 \ No newline at end of property Index: head/mail/mutt-devel/files/extra-patch-imap-header-cache =================================================================== --- head/mail/mutt-devel/files/extra-patch-imap-header-cache (revision 111332) +++ head/mail/mutt-devel/files/extra-patch-imap-header-cache (revision 111333) @@ -1,873 +1,877 @@ 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +/* 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 + * + * 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 + +--- PATCHES.orig Tue Nov 6 19:59:33 2001 ++++ PATCHES Tue Nov 6 19:59:42 2001 +@@ -1,0 +1 @@ ++imap-header-cache.1 Property changes on: head/mail/mutt-devel/files/extra-patch-imap-header-cache ___________________________________________________________________ Modified: cvs2svn:cvs-rev ## -1 +1 ## -1.1 \ No newline at end of property +1.2 \ No newline at end of property Index: head/mail/mutt-devel/files/extra-patch-maildir-header-cache =================================================================== --- head/mail/mutt-devel/files/extra-patch-maildir-header-cache (revision 111332) +++ head/mail/mutt-devel/files/extra-patch-maildir-header-cache (revision 111333) @@ -1,629 +1,1024 @@ --- Makefile.am.orig Fri Mar 5 15:34:57 2004 +++ Makefile.am Fri Mar 5 15:35:55 2004 @@ -20,2 +20,3 @@ mutt_SOURCES = $(BUILT_SOURCES) \ + hcache.c \ addrbook.c alias.c attach.c base64.c browser.c buffy.c color.c \ diff -Nru a/configure.in b/configure.in ---- configure.in Sat Feb 28 11:16:57 2004 -+++ configure.in Sat Feb 28 11:16:57 2004 -@@ -768,6 +767,21 @@ +--- configure.in.orig Sat Jun 12 09:49:17 2004 ++++ configure.in Sat Jun 12 09:50:18 2004 +@@ -773,6 +773,80 @@ fi]) +dnl -- start cache -- +AC_ARG_ENABLE(hcache, [ --enable-hcache Enable header caching for Maildir folders], +[if test x$enableval = xyes; then -+ AC_DEFINE(USE_HCACHE, 1, [Enable header caching for Maildir style mailboxes]) -+ LIBS="$LIBS -lgdbm" -+ AC_CACHE_CHECK(for gdbm_open, ac_cv_gdbmopen, -+ [ac_cv_gdbmopen=no -+ AC_TRY_LINK([#include ],[gdbm_open(0,0,0,0,0);],[ac_cv_gdbmopen=yes])]) ++ AC_DEFINE(USE_HCACHE, 1, [Enable header caching for Maildir style mailboxes]) + -+ if test $ac_cv_gdbmopen = no; then -+ AC_MSG_ERROR(You must install libgdbm with --enable-hcache) -+ fi ++ OLDCPPFLAGS="$CPPFLAGS" ++ OLDLIBS="$LIBS" ++ ++ BDB_VERSIONS="db-4 db4 db-4.3 db4.3 db43 db-4.2 db4.2 db42 db-4.1 db4.1 db41 db" ++ ++ AC_MSG_CHECKING([for BerkeleyDB > 4.0]) ++ ++ for d in /opt/csw/bdb4 /opt /usr/local /usr; do ++ for v in `echo $BDB_VERSIONS .`; do ++ if test -r "$d/include/$v/db.h"; then ++ BDB_INCLUDE_DIR="$d/include/$v" ++ break ++ fi ++ done ++ for v in `echo $BDB_VERSIONS .`; do ++ if test -d "$d/lib/$v"; then ++ BDB_LIB_DIR="$d/lib/$v" ++ break ++ fi ++ done ++ for v in BerkeleyDB.4.3 BerkeleyDB.4.2 BerkeleyDB.4.1; do ++ test -r "$d/$v/include/db.h" && BDB_INCLUDE_DIR="$d/$v/include" ++ test -d "$d/$v/lib" && BDB_LIB_DIR="$d/$v/lib" ++ done ++ test x$BDB_INCLUDE_DIR = x -o x$BDB_LIB_DIR = x && continue ++ for v in `echo $BDB_VERSIONS`; do ++ CPPFLAGS="$OLDCPPFLAGS -I$BDB_INCLUDE_DIR" ++ LIBS="$OLDLIBS -L$BDB_LIB_DIR -l$v" ++ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ ++ #include ++ #include ++ ]],[[ ++ DB *db = NULL; ++ db->open(db,NULL,NULL,NULL,0,0,0); ++ ]])],[ ++ ac_cv_dbcreate=yes ++ BDB_LIB="$v" ++ break ++ ]) ++ done ++ test x$BDB_LIB != x && break ++ done ++ ++ if test x$ac_cv_dbcreate = xyes; then ++ AC_MSG_RESULT(yes) ++ else ++ AC_MSG_RESULT(no) ++ fi ++ ++ CPPFLAGS="$OLDCPPFLAGS" ++ LIBS="$OLDLIBS -lgdbm"; ++ AC_CACHE_CHECK(for gdbm_open, ac_cv_gdbmopen, ++ [ac_cv_gdbmopen=no ++ AC_TRY_LINK([#include ],[gdbm_open(0,0,0,0,0);],[ac_cv_gdbmopen=yes])]) ++ ++ if test x$ac_cv_dbcreate = xyes; then ++ CPPFLAGS="$OLDCPPFLAGS -I$BDB_INCLUDE_DIR" ++ LIBS="$OLDLIBS -L$BDB_LIB_DIR -l$BDB_LIB" ++ AC_DEFINE(HAVE_DB4, 1, [Sleepycat DB4 Support]) ++ elif test x$ac_cv_gdbmopen = xyes; then ++ CPPFLAGS="$OLDCPPFLAGS" ++ LIBS="$OLDLIBS -lgdbm"; ++ AC_DEFINE(HAVE_GDBM, 1, [GDBM Support]) ++ else ++ AC_MSG_ERROR(You need Sleepycat DB4 or GDBM for --enable-hcache) ++ fi +fi]) +dnl -- end cache -- + AC_SUBST(MUTTLIBS) AC_SUBST(MUTT_LIB_OBJECTS) AC_SUBST(LIBIMAP) diff -Nru a/globals.h b/globals.h ---- globals.h Sat Feb 28 11:16:57 2004 -+++ globals.h Sat Feb 28 11:16:57 2004 -@@ -63,6 +63,9 @@ +--- globals.h 2004-06-10 14:03:44 +02:00 ++++ globals.h 2004-06-10 14:03:44 +02:00 +@@ -63,6 +63,10 @@ WHERE char *Locale; WHERE char *MailcapPath; WHERE char *Maildir; +#if USE_HCACHE +WHERE char *MaildirCache; ++WHERE short MaildirCachePageSize; +#endif WHERE char *MhFlagged; WHERE char *MhReplied; WHERE char *MhUnseen; diff -Nru a/hcache.c b/hcache.c ---- /dev/null Wed Dec 31 16:00:00 1969 -+++ hcache.c Sat Feb 28 11:16:57 2004 -@@ -0,0 +1,420 @@ +--- hcache.c.orig Sat Jun 12 09:52:31 2004 ++++ hcache.c Sat Jun 12 09:52:56 2004 +@@ -0,0 +1,676 @@ +/* + * Copyright (C) 2004 Thomas Glanzmann ++ * Copyright (C) 2004 Brian Fundakowski Feldman + * + * 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. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + ++#if HAVE_GDBM +#include ++#elif HAVE_DB4 ++#include ++#endif ++ ++#include +#include +#include "mutt.h" +#include "mime.h" +#include "mx.h" +#include "lib.h" + +static unsigned char * -+dump_int(unsigned int i, unsigned char *d, unsigned int *off) ++dump_int(unsigned int i, unsigned char *d, int *off) +{ + safe_realloc(&d, *off + sizeof(int)); + memcpy(d + *off, &i, sizeof(int)); + (*off) += sizeof(int); + + return d; +} + +static void -+restore_int(unsigned int *i, unsigned char *d, unsigned int *off) ++restore_int(unsigned int *i, const unsigned char *d, int *off) +{ + memcpy(i, d + *off, sizeof(int)); + (*off) += sizeof(int); +} + +static unsigned char * -+dump_char(char *c, unsigned char *d, unsigned int *off) ++dump_char(char *c, unsigned char *d, int *off) +{ + unsigned int size; + + if (c == NULL) { + size = 0; + d = dump_int(size, d, off); + return d; + } + + size = strlen(c) + 1; + d = dump_int(size, d, off); + safe_realloc(&d, *off + size); + memcpy(d + *off, c, size); + *off += size; + + return d; +} + +static void -+restore_char(char **c, unsigned char *d, unsigned int *off) ++restore_char(char **c, const unsigned char *d, int *off) +{ + unsigned int size; + restore_int(&size, d, off); + + if (size == 0) { + *c = NULL; + return; + } + + *c = safe_malloc(size); + memcpy(*c, d + *off, size); + *off += size; +} + +static void -+skip_char(unsigned char *d, unsigned int *off) ++skip_char(const unsigned char *d, int *off) +{ + unsigned int size; + restore_int(&size, d, off); + *off += size; +} + +static unsigned char * -+dump_address(ADDRESS *a, unsigned char *d, unsigned int *off) ++dump_address(ADDRESS *a, unsigned char *d, int *off) +{ + unsigned int counter = 0; + unsigned int start_off = *off; + -+ d = dump_int(0xdeadbeaf, d, off); ++ d = dump_int(0xdeadbeef, d, off); + + while (a) { +#ifdef EXACT_ADDRESS + d = dump_char(a->val, d, off); +#endif + d = dump_char(a->personal, d, off); + d = dump_char(a->mailbox, d, off); + d = dump_int(a->group, d, off); + a = a->next; + counter++; + } + + memcpy(d + start_off, &counter, sizeof(int)); + + return d; +} + +static void -+restore_address(ADDRESS **a, unsigned char *d, unsigned int *off) ++restore_address(ADDRESS **a, const unsigned char *d, int *off) +{ + unsigned int counter; + + restore_int(&counter, d, off); + + while (counter) { + *a = safe_malloc(sizeof(ADDRESS)); +#ifdef EXACT_ADDRESS + restore_char(&(*a)->val, d, off); +#endif + restore_char(&(*a)->personal, d, off); + restore_char(&(*a)->mailbox, d, off); + restore_int((unsigned int *)&(*a)->group, d, off); + a = &(*a)->next; + counter--; + } + + *a = NULL; + return; +} + +static unsigned char * -+dump_list(LIST *l, unsigned char *d, unsigned int *off) ++dump_list(LIST *l, unsigned char *d, int *off) +{ + unsigned int counter = 0; + unsigned int start_off = *off; + -+ d = dump_int(0xdeadbeaf, d, off); ++ d = dump_int(0xdeadbeef, d, off); + + while (l) { + d = dump_char(l->data, d, off); + l = l->next; + counter++; + } + + memcpy(d + start_off, &counter, sizeof(int)); + + return d; +} + +static void -+restore_list(LIST **l, unsigned char *d, unsigned int *off) ++restore_list(LIST **l, const unsigned char *d, int *off) +{ + unsigned int counter; + + restore_int(&counter, d, off); + + while (counter) { + *l = safe_malloc(sizeof(LIST)); + restore_char(&(*l)->data, d, off); + l = &(*l)->next; + counter--; + } + + *l = NULL; + return; +} + +static unsigned char * -+dump_parameter(PARAMETER *p, unsigned char *d, unsigned int *off) ++dump_parameter(PARAMETER *p, unsigned char *d, int *off) +{ + unsigned int counter = 0; + unsigned int start_off = *off; + -+ d = dump_int(0xdeadbeaf, d, off); ++ d = dump_int(0xdeadbeef, d, off); + + while (p) { + d = dump_char(p->attribute, d, off); + d = dump_char(p->value, d, off); + p = p->next; + counter++; + } + + memcpy(d + start_off, &counter, sizeof(int)); + + return d; +} + +static void -+restore_parameter(PARAMETER **p, unsigned char *d, unsigned int *off) ++restore_parameter(PARAMETER **p, const unsigned char *d, int *off) +{ + unsigned int counter; + + restore_int(&counter, d, off); + + while (counter) { + *p = safe_malloc(sizeof(PARAMETER)); + restore_char(&(*p)->attribute, d, off); + restore_char(&(*p)->value, d, off); + p = &(*p)->next; + counter--; + } + + *p = NULL; + return; +} + +static unsigned char * -+dump_body(BODY *c, unsigned char *d, unsigned int *off) ++dump_body(BODY *c, unsigned char *d, int *off) +{ + safe_realloc(&d, *off + sizeof(BODY)); + memcpy(d + *off, c, sizeof(BODY)); + *off += sizeof(BODY); + + d = dump_char(c->xtype, d, off); + d = dump_char(c->subtype, d, off); + + d = dump_parameter(c->parameter, d, off); + + d = dump_char(c->description, d, off); + d = dump_char(c->form_name, d, off); + d = dump_char(c->filename, d, off); + d = dump_char(c->d_filename, d, off); + + return d; +} + +static void -+restore_body(BODY *c, unsigned char *d, unsigned int *off) ++restore_body(BODY *c, const unsigned char *d, int *off) +{ + memcpy(c, d + *off, sizeof(BODY)); + *off += sizeof(BODY); + + restore_char(& c->xtype, d, off); + restore_char(& c->subtype, d, off); + + restore_parameter(& c->parameter, d, off); + + restore_char(& c->description, d, off); + restore_char(& c->form_name, d, off); + restore_char(& c->filename, d, off); + restore_char(& c->d_filename, d, off); +} + +static unsigned char * -+dump_envelope(ENVELOPE *e, unsigned char *d, unsigned int *off) ++dump_envelope(ENVELOPE *e, unsigned char *d, int *off) +{ + d = dump_address(e->return_path, d, off); + d = dump_address(e->from, d, off); + d = dump_address(e->to, d, off); + d = dump_address(e->cc, d, off); + d = dump_address(e->bcc, d, off); + d = dump_address(e->sender, d, off); + d = dump_address(e->reply_to, d, off); + d = dump_address(e->mail_followup_to, d, off); + + d = dump_char(e->subject, d, off); -+ d = dump_char(e->real_subj, d, off); ++ if (e->real_subj) { ++ d = dump_int(e->real_subj - e->subject, d, off); ++ } else { ++ d = dump_int(-1, d, off); ++ } + d = dump_char(e->message_id, d, off); + d = dump_char(e->supersedes, d, off); + d = dump_char(e->date, d, off); + d = dump_char(e->x_label, d, off); + + d = dump_list(e->references, d, off); + d = dump_list(e->in_reply_to, d, off); + d = dump_list(e->userhdrs, d, off); + + return d; +} + +static void -+restore_envelope(ENVELOPE *e, unsigned char *d, unsigned int *off) ++restore_envelope(ENVELOPE *e, const unsigned char *d, int *off) +{ ++ int real_subj_off; ++ + restore_address(& e->return_path, d, off); + restore_address(& e->from, d, off); + restore_address(& e->to, d, off); + restore_address(& e->cc, d, off); + restore_address(& e->bcc, d, off); + restore_address(& e->sender, d, off); + restore_address(& e->reply_to, d, off); + restore_address(& e->mail_followup_to, d, off); + + restore_char(& e->subject, d, off); -+ restore_char(& e->real_subj, d, off); ++ restore_int(& real_subj_off, d, off); ++ if (0 <= real_subj_off) { ++ e->real_subj = e->subject + real_subj_off; ++ } else { ++ e->real_subj = NULL; ++ } + restore_char(& e->message_id, d, off); + restore_char(& e->supersedes, d, off); + restore_char(& e->date, d, off); + restore_char(& e->x_label, d, off); + + restore_list(& e->references, d, off); + restore_list(& e->in_reply_to, d, off); + restore_list(& e->userhdrs, d, off); +} + + +/* This function transforms a header into a char so that it is useable by + * gdbm_store */ + +#if HAVE_LANGINFO_CODESET +int -+mutt_hcache_charset_matches(char *d) ++mutt_hcache_charset_matches(const char *d) +{ -+ unsigned int off = sizeof(struct timeval); ++ int matches; ++ int off = sizeof(struct timeval); + char *charset = NULL; + + restore_char(&charset, (unsigned char *) d, &off); ++ matches = (0 == mutt_strcmp(charset, Charset)); ++ FREE(&charset); + -+ return (0 == mutt_strcmp(charset, Charset)); ++ return (matches); +} +#endif /* HAVE_LANGINFO_CODESET */ + -+void * -+mutt_hcache_dump(HEADER *h, unsigned int *off) ++static void * ++mutt_hcache_dump(HEADER *h, int *off) +{ + unsigned char *d = NULL; + struct timeval now; + *off = 0; + + d = safe_malloc(sizeof(struct timeval)); + gettimeofday(&now, NULL); + memcpy(d, &now, sizeof(struct timeval)); + *off += sizeof(struct timeval); + +#if HAVE_LANGINFO_CODESET + d = dump_char(Charset, d, off); +#endif /* HAVE_LANGINFO_CODESET */ + + + safe_realloc(&d, *off + sizeof(HEADER)); + memcpy(d + *off, h, sizeof(HEADER)); + *off += sizeof(HEADER); + + d = dump_envelope(h->env, d, off); + d = dump_body(h->content, d, off); + d = dump_char(h->maildir_flags, d, off); + + return d; +} + +HEADER * -+mutt_hcache_restore(unsigned char *d, HEADER **oh) ++mutt_hcache_restore(const unsigned char *d, HEADER **oh) +{ -+ unsigned int off = 0; ++ int off = 0; + HEADER *h = mutt_new_header(); + + /* skip timeval */ + off += sizeof(struct timeval); + +#if HAVE_LANGINFO_CODESET + skip_char(d, &off); +#endif /* HAVE_LANGINFO_CODESET */ + + memcpy(h, d + off, sizeof(HEADER)); + off += sizeof(HEADER); + + h->env = mutt_new_envelope(); + restore_envelope(h->env, d, &off); + + h->content = mutt_new_body(); + restore_body(h->content, d, &off); + + restore_char(&h->maildir_flags, d, &off); + + h->old = (*oh)->old; + h->path = safe_strdup((*oh)->path); + mutt_free_header (oh); + + return h; +} + -+GDBM_FILE -+mutt_hcache_open(char *path) ++static size_t mutt_hcache_keylen (const char *fn) +{ -+ GDBM_FILE db = NULL; ++ const char * p = strchr (fn, ':'); ++ return p ? (size_t) (p - fn) : strlen (fn); ++} + ++#if HAVE_GDBM ++static struct ++header_cache ++{ ++ GDBM_FILE db; ++ char *folder; ++} HEADER_CACHE; ++ ++void * ++mutt_hcache_open(const char *path, const char *folder) ++{ ++ struct header_cache *h = malloc(sizeof(HEADER_CACHE)); ++ h->db = NULL; ++ h->folder = safe_strdup (folder); ++ + if (! path || path[0] == '\0') { + return NULL; + } + -+ db = gdbm_open(path, 0, GDBM_WRCREAT, 00600, NULL); -+ if (db) { -+ return db; ++ h->db = gdbm_open((char *) path, (int) MaildirCachePageSize, GDBM_WRCREAT, 00600, NULL); ++ if (h->db) { ++ return h; + } + + /* if rw failed try ro */ -+ return gdbm_open(path, 0, GDBM_READER, 00600, NULL); ++ h->db = gdbm_open((char *) path, (int) MaildirCachePageSize, GDBM_READER, 00600, NULL); ++ if(h->db) { ++ return h; ++ } else { ++ FREE(& h->folder); ++ FREE(& h); ++ ++ return NULL; ++ } +} + +void -+mutt_hcache_close(GDBM_FILE db) ++mutt_hcache_close(void *db) +{ -+ if (db) { -+ gdbm_close(db); ++ struct header_cache *h = db; ++ ++ if (! h) { ++ return; + } ++ ++ gdbm_close(h->db); ++ FREE(& h->folder); ++ FREE(& h); +} + -+datum -+mutt_hcache_fetch(GDBM_FILE db, datum key) ++void * ++mutt_hcache_fetch(void *db, const char *filename) +{ -+ if (! db) { -+ datum ret = {NULL, 0}; -+ return ret; ++ struct header_cache *h = db; ++ datum key; ++ datum data; ++ char path[_POSIX_PATH_MAX]; ++ ++ if (! h) { ++ return NULL; + } -+ return gdbm_fetch(db, key); ++ ++ strncpy(path, h->folder, sizeof(path)); ++ strncat(path, filename, sizeof(path) - strlen(path)); ++ ++ key.dptr = path; ++ key.dsize = mutt_hcache_keylen(path); ++ ++ data = gdbm_fetch(h->db, key); ++ ++ return data.dptr; +} + +int -+mutt_hcache_store(GDBM_FILE db, datum key, datum data) ++mutt_hcache_store(void *db, const char *filename, HEADER *header) +{ -+ if (! db) { ++ struct header_cache *h = db; ++ datum key; ++ datum data; ++ char path[_POSIX_PATH_MAX]; ++ int ret; ++ ++ if (! h) { + return -1; + } -+ return gdbm_store(db, key, data, GDBM_REPLACE); ++ ++ strncpy(path, h->folder, sizeof(path)); ++ strncat(path, filename, sizeof(path) - strlen(path)); ++ ++ key.dptr = path; ++ key.dsize = mutt_hcache_keylen(path); ++ ++ data.dptr = mutt_hcache_dump(header, &data.dsize); ++ ++ ret = gdbm_store(h->db, key, data, GDBM_REPLACE); ++ ++ FREE(& data.dptr); ++ ++ return ret; +} ++ ++int ++mutt_hcache_delete(void *db, const char *filename) ++{ ++ datum key; ++ struct header_cache *h = db; ++ char path[_POSIX_PATH_MAX]; ++ ++ if (! h) { ++ return -1; ++ } ++ ++ strncpy(path, h->folder, sizeof(path)); ++ strncat(path, filename, sizeof(path) - strlen(path)); ++ ++ key.dptr = path; ++ key.dsize = mutt_hcache_keylen(path); ++ ++ return gdbm_delete(h->db, key); ++} ++#elif HAVE_DB4 ++ ++static struct ++header_cache ++{ ++ DB_ENV *env; ++ DB *db; ++} HEADER_CACHE; ++ ++static void ++mutt_hcache_dbt_init(DBT *dbt, void *data, size_t len) ++{ ++ dbt->data = data; ++ dbt->size = dbt->ulen = len; ++ dbt->dlen = dbt->doff = 0; ++ dbt->flags = DB_DBT_USERMEM; ++} ++ ++static void ++mutt_hcache_dbt_empty_init(DBT *dbt) ++{ ++ dbt->data = NULL; ++ dbt->size = dbt->ulen = dbt->dlen = dbt->doff = 0; ++ dbt->flags = 0; ++} ++ ++void * ++mutt_hcache_open(const char *path, const char *folder) ++{ ++ struct stat sb; ++ u_int32_t createflags = DB_CREATE; ++ int ret; ++ struct header_cache *h = malloc(sizeof(HEADER_CACHE)); ++ ++ if (! path || path[0] == '\0') { ++ FREE(& h); ++ return NULL; ++ } ++ ++ ret = db_env_create(&h->env, 0); ++ if (ret) { ++ FREE(& h); ++ return NULL; ++ } ++ ++ ret = h->env->open(h->env, NULL, DB_INIT_MPOOL | DB_CREATE | DB_PRIVATE, 0600); ++ if (! ret) { ++ ret = db_create(&h->db, h->env, 0); ++ if (ret) { ++ h->env->close(h->env, 0); ++ FREE(& h); ++ return NULL; ++ } ++ } ++ ++ if (stat(path, &sb) != 0 && errno == ENOENT) { ++ createflags |= DB_EXCL; ++ h->db->set_pagesize(h->db, (int) MaildirCachePageSize); ++ } ++ ++ ret = h->db->open(h->db, NULL, path, folder, DB_BTREE, createflags, 0600); ++ if (ret) { ++ h->db->close(h->db, 0); ++ h->env->close(h->env, 0); ++ FREE(& h); ++ return NULL; ++ } ++ ++ return h; ++} ++ ++void ++mutt_hcache_close(void *db) ++{ ++ struct header_cache *h = db; ++ int ret; ++ ++ if (! h) { ++ return; ++ } ++ ++ h->db->close(h->db, 0); ++ h->env->close(h->env, 0); ++ ++ FREE(& h); ++} ++ ++void * ++mutt_hcache_fetch(void *db, const char *filename) ++{ ++ DBT key; ++ DBT data; ++ struct header_cache *h = db; ++ ++ if (! h) { ++ return NULL; ++ } ++ ++ filename++; /* skip '/' */ ++ ++ mutt_hcache_dbt_init(&key, (void *) filename, mutt_hcache_keylen(filename)); ++ mutt_hcache_dbt_empty_init(&data); ++ data.flags = DB_DBT_MALLOC; ++ ++ h->db->get(h->db, NULL, &key, &data, 0); ++ ++ return data.data; ++} ++ ++int ++mutt_hcache_store(void *db, const char *filename, HEADER *header) ++{ ++ DBT key; ++ DBT data; ++ int ret; ++ struct header_cache *h = db; ++ ++ if (! h) { ++ return -1; ++ } ++ ++ filename++; /* skip '/' */ ++ ++ mutt_hcache_dbt_init(&key, (void *) filename, mutt_hcache_keylen(filename)); ++ ++ mutt_hcache_dbt_empty_init(&data); ++ data.flags = DB_DBT_USERMEM; ++ data.data = mutt_hcache_dump(header, (signed int *) &data.size); ++ data.ulen = data.size; ++ ++ ret = h->db->put(h->db, NULL, &key, &data, 0); ++ ++ FREE(& data.data); ++ ++ return ret; ++} ++ ++int ++mutt_hcache_delete(void *db, const char *filename) ++{ ++ DBT key; ++ struct header_cache *h = db; ++ ++ if (! h) { ++ return -1; ++ } ++ ++ filename++; /* skip '/' */ ++ ++ mutt_hcache_dbt_init(&key, (void *) filename, mutt_hcache_keylen(filename)); ++ return h->db->del(h->db, NULL, &key, 0); ++} ++#endif diff -Nru a/init.h b/init.h ---- init.h Sat Feb 28 11:16:57 2004 -+++ init.h Sat Feb 28 11:16:57 2004 -@@ -981,6 +981,13 @@ +--- init.h 2004-06-10 14:03:44 +02:00 ++++ init.h 2004-06-10 14:03:44 +02:00 +@@ -981,6 +981,28 @@ ** \fBDON'T CHANGE THIS SETTING UNLESS YOU ARE REALLY SURE WHAT YOU ARE ** DOING!\fP */ +#if USE_HCACHE + { "maildir_cache", DT_PATH, R_NONE, UL &MaildirCache, 0 }, + /* + ** .pp + ** Path to the maildir cache file. If unset no cache will be used. + */ ++ { "maildir_cache_verify", DT_BOOL, R_NONE, OPTHCACHEVERIFY, 1 }, ++ /* ++ ** .pp ++ ** Check for programs other than mutt having modified maildir ++ ** files when the header cache is in use. This incurs one stat(2) ++ ** per message every time the folder is opened. ++ */ ++ { "maildir_cache_page_size", DT_NUM, R_NONE, UL &MaildirCachePageSize, 2048 }, ++ /* ++ ** .pp ++ ** Change the maildir header cache database page size. Too large ++ ** or too small of a page size for the common header can waste ++ ** space, memory effectiveness, or CPU time. You can use the ++ ** db_dump utility to determine the optimal page size. ++ */ +#endif /* USE_HCACHE */ { "maildir_trash", DT_BOOL, R_NONE, OPTMAILDIRTRASH, 0 }, /* ** .pp diff -Nru a/main.c b/main.c ---- main.c Sat Feb 28 11:16:57 2004 -+++ main.c Sat Feb 28 11:16:57 2004 +--- main.c 2004-06-10 14:03:44 +02:00 ++++ main.c 2004-06-10 14:03:44 +02:00 @@ -411,6 +411,12 @@ "-HAVE_GETADDRINFO " #endif +#if USE_HCACHE + "+USE_HCACHE " +#else + "-USE_HCACHE " +#endif + ); #ifdef ISPELL diff -Nru a/mh.c b/mh.c ---- mh.c Sat Feb 28 11:16:57 2004 -+++ mh.c Sat Feb 28 11:16:57 2004 -@@ -42,6 +42,10 @@ - #include - #include - -+#if USE_HCACHE -+#include -+#endif /* USE_HCACHE */ -+ - struct maildir - { - HEADER *h; -@@ -779,11 +783,82 @@ +--- mh.c 2004-06-10 14:03:44 +02:00 ++++ mh.c 2004-06-10 14:03:44 +02:00 +@@ -779,11 +779,65 @@ return r; } +#if USE_HCACHE -+ -+static ssize_t -+maildir_cache_keylen(const char *fn) -+{ -+ char *lastcolon = strrchr(fn, ':'); -+ -+ if (lastcolon) { -+ *lastcolon = '\0'; -+ } -+ -+ return strlen(fn) + 1; -+} /* * This function does the second parsing pass for a maildir-style * folder. */ +void maildir_delayed_parsing (CONTEXT * ctx, struct maildir *md) +{ + struct maildir *p; -+ GDBM_FILE db = NULL; ++ void *hc = NULL; + char fn[_POSIX_PATH_MAX]; -+ char key_fn[_POSIX_PATH_MAX]; -+ datum key; -+ datum data; ++ void *data; + unsigned int size; + struct timeval *when = NULL; + struct stat lastchanged; + int ret; + -+ db = mutt_hcache_open(MaildirCache); ++ hc = mutt_hcache_open (MaildirCache, ctx->path); + + for (p = md; p; p = p->next) { + if (! (p && p->h && !p->header_parsed)) { + continue; + } + -+ snprintf(key_fn, sizeof(key_fn), "%s/%s", ctx->path, p->h->path + 4); -+ key.dptr = key_fn; -+ key.dsize = maildir_cache_keylen(key_fn); -+ data = mutt_hcache_fetch(db, key); -+ when = (struct timeval *) data.dptr; ++ data = mutt_hcache_fetch (hc, p->h->path + 3); ++ when = (struct timeval *) data; + + snprintf(fn, sizeof (fn), "%s/%s", ctx->path, p->h->path); -+ ret = stat(fn, &lastchanged); + -+ if (data.dptr != NULL ++ if (option(OPTHCACHEVERIFY)) { ++ ret = stat(fn, &lastchanged); ++ } else { ++ lastchanged.st_mtime = 0; ++ ret = 0; ++ } ++ ++ if (data != NULL + && ret == 0 + && lastchanged.st_mtime <= when->tv_sec +#if HAVE_LANGINFO_CODESET -+ && mutt_hcache_charset_matches(data.dptr) ++ && mutt_hcache_charset_matches (data) +#endif /* HAVE_LANGINFO_CODESET */ + ) { -+ p->h = mutt_hcache_restore((unsigned char *)data.dptr, &p->h); -+ FREE(& data.dptr); -+ maildir_parse_flags(p->h, fn); ++ p->h = mutt_hcache_restore ((unsigned char *)data, &p->h); ++ maildir_parse_flags (p->h, fn); + + } else if (maildir_parse_message (ctx->magic, fn, p->h->old, p->h)) { + maildir_parse_flags(p->h, fn); + p->header_parsed = 1; -+ if (db) { -+ /* only try this if db connection is available */ -+ data.dptr = mutt_hcache_dump(p->h, &size); -+ data.dsize = size; -+ mutt_hcache_store(db, key, data); -+ FREE(& data.dptr); -+ } ++ mutt_hcache_store (hc, p->h->path + 3, p->h); + } else { + mutt_free_header (&p->h); + } ++ FREE(&data); + } -+ mutt_hcache_close(db); ++ mutt_hcache_close (hc); +} + +#else /* USE_HCACHE */ void maildir_delayed_parsing (CONTEXT * ctx, struct maildir *md) { -@@ -801,7 +876,7 @@ +@@ -801,7 +855,7 @@ } } - +#endif /* USE_HCACHE */ /* Read a MH/maildir style mailbox. * +@@ -1293,6 +1347,9 @@ + { + char path[_POSIX_PATH_MAX], tmp[_POSIX_PATH_MAX]; + int i, j; ++#if USE_HCACHE ++ void *hc = NULL; ++#endif /* USE_HCACHE */ + + if (ctx->magic == M_MH) + i = mh_check_mailbox (ctx, index_hint); +@@ -1302,6 +1359,11 @@ + if (i != 0) + return i; + ++#if USE_HCACHE ++ if (ctx->magic == M_MAILDIR) ++ hc = mutt_hcache_open(MaildirCache, ctx->path); ++#endif /* USE_HCACHE */ ++ + for (i = 0; i < ctx->msgcount; i++) + { + if (ctx->hdrs[i]->deleted +@@ -1310,7 +1372,13 @@ + snprintf (path, sizeof (path), "%s/%s", ctx->path, ctx->hdrs[i]->path); + if (ctx->magic == M_MAILDIR + || (option (OPTMHPURGE) && ctx->magic == M_MH)) ++ { ++#if USE_HCACHE ++ if (ctx->magic == M_MAILDIR) ++ mutt_hcache_delete (hc, ctx->hdrs[i]->path + 3); ++#endif /* USE_HCACHE */ + unlink (path); ++ } + else if (ctx->magic == M_MH) + { + /* MH just moves files out of the way when you delete them */ +@@ -1332,16 +1400,21 @@ + if (ctx->magic == M_MAILDIR) + { + if (maildir_sync_message (ctx, i) == -1) +- return -1; ++ goto err; + } + else + { + if (mh_sync_message (ctx, i) == -1) +- return -1; ++ goto err; + } + } + } + ++#if USE_HCACHE ++ if (ctx->magic == M_MAILDIR) ++ mutt_hcache_close (hc); ++#endif /* USE_HCACHE */ ++ + if (ctx->magic == M_MH) + mh_update_sequences (ctx); + +@@ -1362,6 +1435,13 @@ + } + + return 0; ++ ++err: ++#if USE_HCACHE ++ if (ctx->magic == M_MAILDIR) ++ mutt_hcache_close (hc); ++#endif /* USE_HCACHE */ ++ return -1; + } + + static char *maildir_canon_filename (char *dest, const char *src, size_t l) +diff -Nru a/mutt.h b/mutt.h +--- mutt.h 2004-06-10 14:03:44 +02:00 ++++ mutt.h 2004-06-10 14:03:44 +02:00 +@@ -345,6 +345,9 @@ + OPTFORCENAME, + OPTFORWDECODE, + OPTFORWQUOTE, ++#if USE_HCACHE ++ OPTHCACHEVERIFY, ++#endif + OPTHDRS, + OPTHEADER, + OPTHELP, diff -Nru a/protos.h b/protos.h ---- protos.h Sat Feb 28 11:16:57 2004 -+++ protos.h Sat Feb 28 11:16:57 2004 -@@ -99,6 +99,18 @@ +--- protos.h 2004-06-10 14:03:44 +02:00 ++++ protos.h 2004-06-10 14:03:44 +02:00 +@@ -99,6 +99,19 @@ ENVELOPE *mutt_read_rfc822_header (FILE *, HEADER *, short, short); HEADER *mutt_dup_header (HEADER *); +#if USE_HCACHE -+#include -+GDBM_FILE mutt_hcache_open(char *path); -+void mutt_hcache_close(GDBM_FILE db); -+void * mutt_hcache_dump(HEADER *h, unsigned int *off); -+HEADER * mutt_hcache_restore(unsigned char *d, HEADER **oh); -+datum mutt_hcache_fetch(GDBM_FILE db, datum key); -+int mutt_hcache_store(GDBM_FILE db, datum key, datum data); -+int mutt_hcache_charset_matches(char *d); ++void *mutt_hcache_open(const char *path, const char *folder); ++void mutt_hcache_close(void *db); ++HEADER *mutt_hcache_restore(const unsigned char *d, HEADER **oh); ++void *mutt_hcache_fetch(void *db, const char *filename); ++int mutt_hcache_store(void *db, const char *filename, HEADER *h); ++int mutt_hcache_delete(void *db, const char *filename); ++#if HAVE_LANGINFO_CODESET ++int mutt_hcache_charset_matches(const char *d); ++#endif /* HAVE_LANGINFO_CODESET */ +#endif /* USE_HCACHE */ + + ATTACHPTR **mutt_gen_attach_list (BODY *, int, ATTACHPTR **, short *, short *, int, int); time_t mutt_decrease_mtime (const char *, struct stat *); +--- PATCHES.orig Tue Nov 6 19:59:33 2001 ++++ PATCHES Tue Nov 6 19:59:42 2001 +@@ -1,0 +1 @@ ++maildir-header-cache.18 Property changes on: head/mail/mutt-devel/files/extra-patch-maildir-header-cache ___________________________________________________________________ Modified: cvs2svn:cvs-rev ## -1 +1 ## -1.1 \ No newline at end of property +1.2 \ No newline at end of property Index: head/mail/mutt-devel/scripts/generate-plist =================================================================== --- head/mail/mutt-devel/scripts/generate-plist (revision 111332) +++ head/mail/mutt-devel/scripts/generate-plist (revision 111333) @@ -1,179 +1,179 @@ #!/bin/sh # # $FreeBSD$ # # set -x trap ' cleanup ' 0 trap ' echo_signal; exit 1' 1 2 3 15 tmp_first=$(mktemp ${WRKDIR:=/tmp}/.plist-first.XXXXXXXXXX) tmp_last=$(mktemp ${WRKDIR}/.plist-last.XXXXXXXXXX) cleanup() { rm -f $tmp_first $tmp_last } echo_signal() { echo "Got Signal -- aborting `basename $0`" } PATH=/bin:/usr/bin cat > $tmp_first <> $tmp_first <> $tmp_first <> $tmp_first fi if [ "$MUTT_SGML" = "yes" ]; then echo "%%DOCSDIR%%/manual.latin1" >> $tmp_first echo "%%DOCSDIR%%/manual.ps" >> $tmp_first fi if [ "$MUTT_HTML" = "yes" ]; then html=371 if [ "$MUTT_COMPRESSED_FOLDERS" = "yes" ]; then html=$(($html + 5)) fi if [ "$MUTT_NNTP" = "yes" ]; then html=$(($html + 22)) fi if [ "$MUTT_QUOTE_PATCH" = "yes" ]; then html=$(($html + 2)) fi if [ "$MUTT_EDIT_THREADS" = "yes" ]; then html=$(($html + 3)) fi if [ "$MUTT_IMAP_HEADER_CACHE" = "yes" ]; then html=$(($html + 1)) fi if [ "$MUTT_MAILDIR_HEADER_CACHE" = "yes" ]; then - html=$(($html + 1)) + html=$(($html + 3)) fi if [ "$MUTT_SIGNATURE_MENU" = "yes" ]; then html=$(($html + 1)) fi if [ "$MUTT_IFDEF_PATCH" = "yes" ]; then html=$(($html + 1)) fi if [ "$MUTT_PGP_PATCH" = "yes" ]; then html=$(($html + 3)) fi echo "%%DOCSDIR%%/html/manual.html" >> $tmp_first echo "%%DOCSDIR%%/html/manual_toc.html" >> $tmp_first i=1 while [ $i -le $html ]; do echo "%%DOCSDIR%%/html/manual$i.html" >> $tmp_first i=$(($i + 1)) done echo "@dirrm %%DOCSDIR%%/html" >> $tmp_last fi cat >> $tmp_last <