/*
- * Copyright (C) 1996-2002 Michael R. Elkins <me@mutt.org>
+ * Copyright (C) 1996-2002,2007 Michael R. Elkins <me@mutt.org>
*
* 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
#include "keymap.h"
#include "mutt_menu.h"
#include "mapping.h"
-#include "sort.h"
#include "pager.h"
#include "attach.h"
#include "mbyte.h"
-#include "mx.h"
-
-#ifdef USE_IMAP
-#include "imap_private.h"
-#endif
-
#include "mutt_crypt.h"
#include <sys/stat.h>
struct syntax_t *syntax;
struct syntax_t *search;
struct q_class_t *quote;
+ unsigned int is_cont_hdr; /* this line is a continuation of the previous header line */
};
#define ANSI_OFF (1<<0)
if (n == 0 || ISHEADER (lineInfo[n-1].type))
{
- if (buf[0] == '\n') {
+ if (buf[0] == '\n') /* end of header */
+ {
lineInfo[n].type = MT_COLOR_NORMAL;
getyx(stdscr, brailleLine, brailleCol);
- } else if (n > 0 && (buf[0] == ' ' || buf[0] == '\t'))
- {
- lineInfo[n].type = lineInfo[n-1].type; /* wrapped line */
- (lineInfo[n].syntax)[0].color = (lineInfo[n-1].syntax)[0].color;
}
else
{
- lineInfo[n].type = MT_COLOR_HDEFAULT;
- color_line = ColorHdrList;
- while (color_line)
+ /* if this is a continuation of the previous line, use the previous
+ * line's color as default. */
+ if (n > 0 && (buf[0] == ' ' || buf[0] == '\t'))
+ {
+ lineInfo[n].type = lineInfo[n-1].type; /* wrapped line */
+ (lineInfo[n].syntax)[0].color = (lineInfo[n-1].syntax)[0].color;
+ lineInfo[n].is_cont_hdr = 1;
+ }
+ else
+ {
+ lineInfo[n].type = MT_COLOR_HDEFAULT;
+ }
+
+ for (color_line = ColorHdrList; color_line; color_line = color_line->next)
{
if (REGEXEC (color_line->rx, buf) == 0)
{
lineInfo[n].type = MT_COLOR_HEADER;
lineInfo[n].syntax[0].color = color_line->pair;
+ if (lineInfo[n].is_cont_hdr)
+ {
+ /* adjust the previous continuation lines to reflect the color of this continuation line */
+ int j;
+ for (j = n - 1; j >= 0 && lineInfo[j].is_cont_hdr; --j)
+ {
+ lineInfo[j].type = lineInfo[n].type;
+ lineInfo[j].syntax[0].color = lineInfo[n].syntax[0].color;
+ }
+ /* now adjust the first line of this header field */
+ if (j >= 0)
+ {
+ lineInfo[j].type = lineInfo[n].type;
+ lineInfo[j].syntax[0].color = lineInfo[n].syntax[0].color;
+ }
+ *force_redraw = 1; /* the previous lines have already been drawn on the screen */
+ }
break;
}
- color_line = color_line->next;
}
}
}
if (lineInfo[n].type == MT_COLOR_NORMAL ||
lineInfo[n].type == MT_COLOR_QUOTED)
{
- i = 0;
+ size_t nl;
+
+ /* don't consider line endings part of the buffer
+ * for regex matching */
+ if ((nl = mutt_strlen (buf)) > 0 && buf[nl-1] == '\n')
+ buf[nl-1] = 0;
+ i = 0;
offset = 0;
lineInfo[n].chunks = 0;
do
else
offset = (lineInfo[n].syntax)[i].last;
} while (found || null_rx);
+ if (nl > 0)
+ buf[nl] = '\n';
}
}
}
static int
-fill_buffer (FILE *f, LOFF_T *last_pos, LOFF_T offset, unsigned char *buf,
- unsigned char *fmt, size_t blen, int *buf_ready)
+fill_buffer (FILE *f, LOFF_T *last_pos, LOFF_T offset, unsigned char **buf,
+ unsigned char **fmt, size_t *blen, int *buf_ready)
{
- unsigned char *p;
+ unsigned char *p, *q;
static int b_read;
-
+ int l;
+
if (*buf_ready == 0)
{
- buf[blen - 1] = 0;
if (offset != *last_pos)
fseeko (f, offset, 0);
- if (fgets ((char *) buf, blen - 1, f) == NULL)
+ if ((*buf = (unsigned char *) mutt_read_line ((char *) *buf, blen, f, &l, M_EOL)) == NULL)
{
fmt[0] = 0;
return (-1);
b_read = (int) (*last_pos - offset);
*buf_ready = 1;
+ safe_realloc (fmt, *blen);
+
/* incomplete mbyte characters trigger a segfault in regex processing for
* certain versions of glibc. Trim them if necessary. */
- if (b_read == blen - 2)
- b_read -= trim_incomplete_mbyte(buf, b_read);
+ if (b_read == *blen - 2)
+ b_read -= trim_incomplete_mbyte(*buf, b_read);
/* copy "buf" to "fmt", but without bold and underline controls */
- p = buf;
+ p = *buf;
+ q = *fmt;
while (*p)
{
- if (*p == '\010' && (p > buf))
+ if (*p == '\010' && (p > *buf))
{
if (*(p+1) == '_') /* underline */
p += 2;
- else if (*(p+1)) /* bold or overstrike */
+ else if (*(p+1) && q > *fmt) /* bold or overstrike */
{
- *(fmt-1) = *(p+1);
+ *(q-1) = *(p+1);
p += 2;
}
else /* ^H */
- *fmt++ = *p++;
+ *q++ = *p++;
}
else if (*p == '\033' && *(p+1) == '[' && is_ansi (p + 2))
{
;
}
else
- *fmt++ = *p++;
+ *q++ = *p++;
}
- *fmt = 0;
+ *q = 0;
}
return b_read;
}
int ch, vch, k, last_special = -1, special = 0, t;
wchar_t wc;
mbstate_t mbstate;
-
int wrap_cols = mutt_term_width ((flags & M_PAGER_NOWRAP) ? 0 : Wrap);
-
+
+ if (check_attachment_marker ((char *)buf) == 0)
+ wrap_cols = COLS;
+
/* FIXME: this should come from lineInfo */
memset(&mbstate, 0, sizeof(mbstate));
if (k == 0)
k = 1;
+ if (Charset_is_utf8 && (wc == 0x200B || wc == 0xFEFF))
+ {
+ dprint (3, (debugfile, "skip zero-width character U+%04X\n", (unsigned short)wc));
+ continue;
+ }
+
/* Handle backspace */
special = 0;
if (IsWPrint (wc))
int *last, int *max, int flags, struct q_class_t **QuoteList,
int *q_level, int *force_redraw, regex_t *SearchRE)
{
- unsigned char buf[LONG_STRING], fmt[LONG_STRING];
+ unsigned char *buf = NULL, *fmt = NULL;
+ size_t buflen = 0;
unsigned char *buf_ptr = buf;
int ch, vch, col, cnt, b_read;
int buf_ready = 0, change_last = 0;
int offset;
int def_color;
int m;
+ int rc = -1;
ansi_attr a = {0,0,0,-1};
regmatch_t pmatch[1];
if ((*lineInfo)[n].type == -1)
{
/* determine the line class */
- if (fill_buffer (f, last_pos, (*lineInfo)[n].offset, buf, fmt, sizeof (buf), &buf_ready) < 0)
+ if (fill_buffer (f, last_pos, (*lineInfo)[n].offset, &buf, &fmt, &buflen, &buf_ready) < 0)
{
if (change_last)
(*last)--;
- return (-1);
+ goto out;
}
resolve_types ((char *) fmt, (char *) buf, *lineInfo, n, *last,
if ((flags & M_SHOWCOLOR) && !(*lineInfo)[n].continuation &&
(*lineInfo)[n].type == MT_COLOR_QUOTED && (*lineInfo)[n].quote == NULL)
{
- if (fill_buffer (f, last_pos, (*lineInfo)[n].offset, buf, fmt, sizeof (buf), &buf_ready) < 0)
+ if (fill_buffer (f, last_pos, (*lineInfo)[n].offset, &buf, &fmt, &buflen, &buf_ready) < 0)
{
if (change_last)
(*last)--;
- return (-1);
+ goto out;
}
regexec ((regex_t *) QuoteRegexp.rx, (char *) fmt, 1, pmatch, 0);
(*lineInfo)[n].quote = classify_quote (QuoteList,
if ((flags & M_SEARCH) && !(*lineInfo)[n].continuation && (*lineInfo)[n].search_cnt == -1)
{
- if (fill_buffer (f, last_pos, (*lineInfo)[n].offset, buf, fmt, sizeof (buf), &buf_ready) < 0)
+ if (fill_buffer (f, last_pos, (*lineInfo)[n].offset, &buf, &fmt, &buflen, &buf_ready) < 0)
{
if (change_last)
(*last)--;
- return (-1);
+ goto out;
}
offset = 0;
if (!(flags & M_SHOW) && (*lineInfo)[n+1].offset > 0)
{
/* we've already scanned this line, so just exit */
- return (0);
+ rc = 0;
+ goto out;
}
if ((flags & M_SHOWCOLOR) && *force_redraw && (*lineInfo)[n+1].offset > 0)
{
/* no need to try to display this line... */
- return (1); /* fake display */
+ rc = 1;
+ goto out; /* fake display */
}
- if ((b_read = fill_buffer (f, last_pos, (*lineInfo)[n].offset, buf, fmt,
- sizeof (buf), &buf_ready)) < 0)
+ if ((b_read = fill_buffer (f, last_pos, (*lineInfo)[n].offset, &buf, &fmt,
+ &buflen, &buf_ready)) < 0)
{
if (change_last)
(*last)--;
- return (-1);
+ goto out;
}
/* now chose a good place to break the line */
{
if (cnt < b_read)
{
- if (ch != -1 && buf[cnt] != ' ' && buf[cnt] != '\t' && buf[cnt] != '\n' && buf[cnt] != '\r')
+ if (ch != -1 && buf[0] != ' ' && buf[0] != '\t' &&
+ buf[cnt] != ' ' && buf[cnt] != '\t' && buf[cnt] != '\n' && buf[cnt] != '\r')
{
buf_ptr = buf + ch;
/* skip trailing blanks */
/* if we don't need to display the line we are done */
if (!(flags & M_SHOW))
- return 0;
+ {
+ rc = 0;
+ goto out;
+ }
/* display the line */
format_line (lineInfo, n, buf, flags, &a, cnt, &ch, &vch, &col, &special);
if (!(flags & M_SHOW))
flags = 0;
- return (flags);
+ rc = flags;
+
+out:
+ FREE(&buf);
+ FREE(&fmt);
+ return rc;
}
static int
int
mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
{
- static char searchbuf[STRING];
+ static char searchbuf[STRING] = "";
char buffer[LONG_STRING];
char helpstr[SHORT_STRING*2];
char tmphelp[SHORT_STRING*2];
struct q_class_t *QuoteList = NULL;
int i, j, ch = 0, rc = -1, hideQuoted = 0, q_level = 0, force_redraw = 0;
int lines = 0, curline = 0, topline = 0, oldtopline = 0, err, first = 1;
- int r = -1;
+ int r = -1, wrapped = 0, searchctx = 0;
int redraw = REDRAW_FULL;
FILE *fp = NULL;
LOFF_T last_pos = 0, last_offset = 0;
if (stat (fname, &sb) != 0)
{
mutt_perror (fname);
- fclose (fp);
+ safe_fclose (&fp);
return (-1);
}
unlink (fname);
{
mutt_curs_set (0);
-#ifdef USE_IMAP
- imap_keepalive ();
-#endif
-
if (redraw & REDRAW_FULL)
{
SETCOLOR (MT_COLOR_NORMAL);
{
/* only allocate the space if/when we need the index.
Initialise the menu as per the main index */
- index = mutt_new_menu();
- index->menu = MENU_MAIN;
+ index = mutt_new_menu(MENU_MAIN);
index->make_entry = index_make_entry;
index->color = index_color;
index->max = Context->vcount;
SETCOLOR (MT_COLOR_STATUS);
BKGDSET (MT_COLOR_STATUS);
CLEARLINE (statusoffset);
- if (IsHeader (extra))
+
+ if (IsHeader (extra) || IsMsgAttach (extra))
{
size_t l1 = COLS * MB_LEN_MAX;
size_t l2 = sizeof (buffer);
- hfi.hdr = extra->hdr;
+ hfi.hdr = (IsHeader (extra)) ? extra->hdr : extra->bdy->hdr;
mutt_make_string_info (buffer, l1 < l2 ? l1 : l2, NONULL (PagerFmt), &hfi, M_FORMAT_MAKEPRINT);
+ mutt_paddstr (COLS, buffer);
}
- else if (IsMsgAttach (extra))
+ else
{
- size_t l1 = COLS * MB_LEN_MAX;
- size_t l2 = sizeof (buffer);
- hfi.hdr = extra->bdy->hdr;
- mutt_make_string_info (buffer, l1 < l2 ? l1 : l2, NONULL (PagerFmt), &hfi, M_FORMAT_MAKEPRINT);
+ char bn[STRING];
+ snprintf (bn, sizeof (bn), "%s (%s)", banner, pager_progress_str);
+ mutt_paddstr (COLS, bn);
}
- mutt_paddstr (COLS, IsHeader (extra) || IsMsgAttach (extra) ? buffer : banner);
BKGDSET (MT_COLOR_NORMAL);
SETCOLOR (MT_COLOR_NORMAL);
}
case OP_SEARCH_OPPOSITE:
if (SearchCompiled)
{
+ wrapped = 0;
+
+ if (SearchContext > 0 && SearchContext < LINES - 2 - option (OPTHELP) ? 1 : 0)
+ searchctx = SearchContext;
+ else
+ searchctx = 0;
+
search_next:
if ((!SearchBack && ch==OP_SEARCH_NEXT) ||
(SearchBack &&ch==OP_SEARCH_OPPOSITE))
{
/* searching forward */
- for (i = topline + 1; i < lastLine; i++)
+ for (i = wrapped ? 0 : topline + searchctx + 1; i < lastLine; i++)
{
if ((!hideQuoted || lineInfo[i].type != MT_COLOR_QUOTED) &&
!lineInfo[i].continuation && lineInfo[i].search_cnt > 0)
if (i < lastLine)
topline = i;
- else
+ else if (wrapped || !option (OPTWRAPSEARCH))
mutt_error _("Not found.");
+ else
+ {
+ mutt_message _("Search wrapped to top.");
+ wrapped = 1;
+ goto search_next;
+ }
}
else
{
/* searching backward */
- for (i = topline - 1; i >= 0; i--)
+ for (i = wrapped ? lastLine : topline + searchctx - 1; i >= 0; i--)
{
if ((!hideQuoted || (has_types &&
lineInfo[i].type != MT_COLOR_QUOTED)) &&
if (i >= 0)
topline = i;
- else
+ else if (wrapped || !option (OPTWRAPSEARCH))
mutt_error _("Not found.");
+ else
+ {
+ mutt_message _("Search wrapped to bottom.");
+ wrapped = 1;
+ goto search_next;
+ }
}
if (lineInfo[topline].search_cnt > 0)
+ {
SearchFlag = M_SEARCH;
+ /* give some context for search results */
+ if (topline - searchctx > 0)
+ topline -= searchctx;
+ }
break;
}
case OP_SEARCH:
case OP_SEARCH_REVERSE:
strfcpy (buffer, searchbuf, sizeof (buffer));
- if (mutt_get_field ((SearchBack ? _("Reverse search: ") :
- _("Search: ")), buffer, sizeof (buffer),
- M_CLEAR) != 0)
+ if (mutt_get_field ((ch == OP_SEARCH || ch == OP_SEARCH_NEXT) ?
+ _("Search for: ") : _("Reverse search for: "),
+ buffer, sizeof (buffer),
+ M_CLEAR) != 0)
break;
if (!strcmp (buffer, searchbuf))
else
ch = OP_SEARCH_OPPOSITE;
+ wrapped = 0;
goto search_next;
}
}
{
regerror (err, &SearchRE, buffer, sizeof (buffer));
mutt_error ("%s", buffer);
- regfree (&SearchRE);
for (i = 0; i < maxLine ; i++)
{
/* cleanup */
mutt_error _("Not found.");
}
else
+ {
SearchFlag = M_SEARCH;
+ /* give some context for search results */
+ if (SearchContext > 0 && SearchContext < LINES - 2 - option (OPTHELP) ? 1 : 0)
+ searchctx = SearchContext;
+ else
+ searchctx = 0;
+ if (topline - searchctx > 0)
+ topline -= searchctx;
+ }
+
}
redraw = REDRAW_BODY;
break;
}
break;
+ case OP_MAIN_SET_FLAG:
+ case OP_MAIN_CLEAR_FLAG:
+ CHECK_MODE(IsHeader (extra));
+ CHECK_READONLY;
+
+ if (mutt_change_flag (extra->hdr, (ch == OP_MAIN_SET_FLAG)) == 0)
+ redraw |= REDRAW_STATUS | REDRAW_INDEX;
+ if (extra->hdr->deleted && option (OPTRESOLVE))
+ {
+ ch = -1;
+ rc = OP_MAIN_NEXT_UNDELETED;
+ }
+ break;
+
case OP_DELETE_THREAD:
case OP_DELETE_SUBTHREAD:
CHECK_MODE(IsHeader (extra));
redraw = REDRAW_FULL;
break;
+ case OP_WHAT_KEY:
+ mutt_what_key ();
+ break;
+
default:
ch = -1;
break;
}
}
- fclose (fp);
+ safe_fclose (&fp);
if (IsHeader (extra))
{
Context->msgnotreadyet = -1;