Latest version of my "save history" (savehist) patch
I've attached the latest version of my "save history" (savehist)
patch, whose purpose is to save the history to a file (read when
Mutt is restarted).
Two bugs have been fixed in this version.
* First, the history no longer gets corrupted when a string to be
saved contains a newline character; this character is just dropped
(it has here no meaning, probably comes from buggy mail software
and Mutt does not handle it correctly anyway [bug 2173]).
* Also, the history is now stored in the UTF-8 encoding; this fixes
the problem with non-ASCII characters (accented letters...) that
occurred when Mutt was started under different locales (based on
different encodings, e.g. ISO-8859-1 and UTF-8).
--
Vincent Lefèvre <vincent@xxxxxxxxxx> - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA
diff -Naurd mutt-cvs/PATCHES mutt-new/PATCHES
--- mutt-cvs/PATCHES 2002-12-09 17:44:54.000000000 +0000
+++ mutt-new/PATCHES 2006-01-30 15:56:23.000000000 +0000
@@ -0,0 +1 @@
+patch-1.5.11.vl.savehist.2
diff -Naurd mutt-cvs/enter.c mutt-new/enter.c
--- mutt-cvs/enter.c 2005-09-17 23:18:45.000000000 +0000
+++ mutt-new/enter.c 2006-01-30 12:33:35.000000000 +0000
@@ -548,7 +548,7 @@
{
mutt_pretty_mailbox (buf);
if (!pass)
- mutt_history_add (hclass, buf);
+ mutt_history_add (hclass, buf, 1);
rv = 0;
goto bye;
}
@@ -653,7 +653,7 @@
/* Convert from wide characters */
my_wcstombs (buf, buflen, state->wbuf, state->lastchar);
if (!pass)
- mutt_history_add (hclass, buf);
+ mutt_history_add (hclass, buf, 1);
if (multiple)
{
diff -Naurd mutt-cvs/globals.h mutt-new/globals.h
--- mutt-cvs/globals.h 2006-01-11 10:58:35.000000000 +0000
+++ mutt-new/globals.h 2006-01-30 12:33:35.000000000 +0000
@@ -51,6 +51,7 @@
WHERE char *ForwFmt;
WHERE char *Fqdn;
WHERE char *HdrFmt;
+WHERE char *HistFile;
WHERE char *Homedir;
WHERE char *Hostname;
#ifdef USE_IMAP
@@ -183,6 +184,7 @@
WHERE short PagerContext;
WHERE short PagerIndexLines;
WHERE short ReadInc;
+WHERE short SaveHist;
WHERE short SendmailWait;
WHERE short SleepTime INITVAL (1);
WHERE short Timeout;
diff -Naurd mutt-cvs/history.c mutt-new/history.c
--- mutt-cvs/history.c 2005-09-17 23:18:45.000000000 +0000
+++ mutt-new/history.c 2006-01-30 15:56:11.000000000 +0000
@@ -56,6 +56,144 @@
h->last = 0;
}
+static void read_histfile (void)
+{
+ FILE *f;
+ int line = 0, hclass, read;
+ char *linebuf = NULL, *p;
+ size_t buflen;
+
+ if ((f = fopen (HistFile, "r")) == NULL)
+ return;
+
+ while ((linebuf = mutt_read_line (linebuf, &buflen, f, &line)) != NULL)
+ {
+ read = 0;
+ if (sscanf (linebuf, "%d:%n", &hclass, &read) < 1 || read == 0 ||
+ *(p = linebuf + strlen (linebuf) - 1) != '|')
+ {
+ mutt_error (_("Bad history file format (line %d)"), line);
+ break;
+ }
+ *p = '\0';
+ p = safe_strdup (linebuf + read);
+ if (p)
+ {
+ mutt_convert_string (&p, "utf-8", Charset, M_ICONV_HOOK_TO);
+ mutt_history_add (hclass, p, 0);
+ FREE (&p);
+ }
+ }
+
+ fclose (f);
+ FREE (&linebuf);
+}
+
+static void shrink_histfile (void)
+{
+ char tmpfname[_POSIX_PATH_MAX];
+ FILE *f, *tmp = NULL;
+ int n[HC_LAST] = { 0 };
+ int line, hclass;
+ char *linebuf = NULL;
+ size_t buflen;
+
+ if ((f = fopen (HistFile, "r")) == NULL)
+ return;
+
+ line = 0;
+ while ((linebuf = mutt_read_line (linebuf, &buflen, f, &line)) != NULL)
+ {
+ if (sscanf (linebuf, "%d", &hclass) < 1)
+ {
+ mutt_error (_("Bad history file format (line %d)"), line);
+ goto cleanup;
+ }
+ n[hclass]++;
+ }
+
+ for(hclass = HC_FIRST; hclass < HC_LAST; hclass++)
+ if (n[hclass] > SaveHist)
+ {
+ mutt_mktemp (tmpfname);
+ if ((tmp = safe_fopen (tmpfname, "w+")) == NULL)
+ mutt_perror (tmpfname);
+ break;
+ }
+
+ if (tmp != NULL)
+ {
+ rewind (f);
+ line = 0;
+ while ((linebuf = mutt_read_line (linebuf, &buflen, f, &line)) != NULL)
+ {
+ if (sscanf (linebuf, "%d", &hclass) < 1)
+ {
+ mutt_error (_("Bad history file format (line %d)"), line);
+ goto cleanup;
+ }
+ if (n[hclass]-- <= SaveHist)
+ fprintf (tmp, "%s\n", linebuf);
+ }
+ }
+
+cleanup:
+ fclose (f);
+ FREE (&linebuf);
+ if (tmp != NULL)
+ {
+ if (fflush (tmp) == 0 && (f = fopen (HistFile, "w")) != NULL)
+ {
+ rewind (tmp);
+ mutt_copy_stream (tmp, f);
+ fclose (f);
+ }
+ fclose (tmp);
+ unlink (tmpfname);
+ }
+}
+
+static void save_history (history_class_t hclass, const char *s)
+{
+ static int n = 0;
+ FILE *f;
+ char *tmp, *p;
+
+ if (!s || !*s) /* This shouldn't happen, but it's safer. */
+ return;
+
+ if ((f = fopen (HistFile, "a")) == NULL)
+ {
+ mutt_perror ("fopen");
+ return;
+ }
+
+ tmp = safe_strdup (s);
+ mutt_convert_string (&tmp, Charset, "utf-8", M_ICONV_HOOK_FROM);
+
+ /* Format of a history item (1 line): "<histclass>:<string>|".
+ We add a '|' in order to avoid lines ending with '\'. */
+ fprintf (f, "%d:", (int) hclass);
+ for (p = tmp; *p; p++)
+ {
+ /* Don't copy \n as a history item must fit on one line. The string
+ shouldn't contain such a character anyway, but as this can happen
+ in practice, we must deal with that. */
+ if (*p != '\n')
+ putc ((unsigned char) *p, f);
+ }
+ fputs ("|\n", f);
+
+ fclose (f);
+ FREE (&tmp);
+
+ if (--n < 0)
+ {
+ n = SaveHist;
+ shrink_histfile();
+ }
+}
+
void mutt_init_history(void)
{
history_class_t hclass;
@@ -67,9 +205,10 @@
init_history(&History[hclass]);
OldSize = HistSize;
+ read_histfile();
}
-void mutt_history_add (history_class_t hclass, const char *s)
+void mutt_history_add (history_class_t hclass, const char *s, int save)
{
int prev;
struct history *h = &History[hclass];
@@ -83,6 +222,8 @@
if (prev < 0) prev = HistSize - 1;
if (!h->hist[prev] || mutt_strcmp (h->hist[prev], s) != 0)
{
+ if (save && SaveHist)
+ save_history (hclass, s);
mutt_str_replace (&h->hist[h->last++], s);
if (h->last > HistSize - 1)
h->last = 0;
diff -Naurd mutt-cvs/history.h mutt-new/history.h
--- mutt-cvs/history.h 2005-09-17 23:18:45.000000000 +0000
+++ mutt-new/history.h 2006-01-30 12:33:35.000000000 +0000
@@ -35,7 +35,7 @@
typedef enum history_class history_class_t;
void mutt_init_history(void);
-void mutt_history_add(history_class_t, const char *);
+void mutt_history_add(history_class_t, const char *, int);
char *mutt_history_next(history_class_t);
char *mutt_history_prev(history_class_t);
diff -Naurd mutt-cvs/init.h mutt-new/init.h
--- mutt-cvs/init.h 2006-01-11 10:58:35.000000000 +0000
+++ mutt-new/init.h 2006-01-30 12:33:35.000000000 +0000
@@ -775,6 +775,11 @@
** the string history buffer. The buffer is cleared each time the
** variable is set.
*/
+ { "history_file", DT_PATH, R_NONE, UL &HistFile, UL "~/.mutthistory" },
+ /*
+ ** .pp
+ ** The file in which Mutt will save its history.
+ */
{ "honor_followup_to", DT_QUAD, R_NONE, OPT_MFUPTO, M_YES },
/*
** .pp
@@ -2377,6 +2382,12 @@
** \fBNote:\fP This only applies to mbox and MMDF folders, Mutt does not
** delete MH and Maildir directories.
*/
+ { "save_history", DT_NUM, R_NONE, UL &SaveHist, 0 },
+ /*
+ ** .pp
+ ** This variable controls the size of the history saved in the
+ ** ``$$history_file'' file.
+ */
{ "save_name", DT_BOOL, R_NONE, OPTSAVENAME, 0 },
/*
** .pp