h->last = 0;
}
+void mutt_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, 0);
+ 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) /* __FOPEN_CHECKED__ */
+ {
+ 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", 0);
+
+ /* 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;
OldSize = HistSize;
}
-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];
*/
if (*s != ' ' && (!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;
** 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
** \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