]> git.llucax.com Git - software/mutt-debian.git/blobdiff - pager.c
Update and enable NNTP patch
[software/mutt-debian.git] / pager.c
diff --git a/pager.c b/pager.c
index c88b5d4c2be9e6b86d4d95b1532756db9168406f..e19174cd02c558e7ed8b804b681e02537353f2ae 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -1,5 +1,5 @@
 /*
- * 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>
@@ -117,6 +110,7 @@ struct line_t
   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)
@@ -719,27 +713,51 @@ resolve_types (char *buf, char *raw, struct line_t *lineInfo, int n, int last,
 
   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;
       }
     }
   }
@@ -819,8 +837,14 @@ resolve_types (char *buf, char *raw, struct line_t *lineInfo, int n, int last,
   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
@@ -870,6 +894,8 @@ resolve_types (char *buf, char *raw, struct line_t *lineInfo, int n, int last,
       else
        offset = (lineInfo[n].syntax)[i].last;
     } while (found || null_rx);
+    if (nl > 0)
+      buf[nl] = '\n';
   }
 }
 
@@ -995,18 +1021,18 @@ trim_incomplete_mbyte(unsigned char *buf, size_t len)
 }
 
 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);
@@ -1015,26 +1041,29 @@ fill_buffer (FILE *f, LOFF_T *last_pos, LOFF_T offset, unsigned char *buf,
     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))
       {
@@ -1048,9 +1077,9 @@ fill_buffer (FILE *f, LOFF_T *last_pos, LOFF_T offset, unsigned char *buf,
          ;
       }
       else
-       *fmt++ = *p++;
+       *q++ = *p++;
     }
-    *fmt = 0;
+    *q = 0;
   }
   return b_read;
 }
@@ -1065,9 +1094,11 @@ static int format_line (struct line_t **lineInfo, int n, unsigned char *buf,
   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));
 
@@ -1106,6 +1137,12 @@ static int format_line (struct line_t **lineInfo, int n, unsigned char *buf,
     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))
@@ -1229,7 +1266,8 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n,
              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;
@@ -1237,6 +1275,7 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n,
   int offset;
   int def_color;
   int m;
+  int rc = -1;
   ansi_attr a = {0,0,0,-1};
   regmatch_t pmatch[1];
 
@@ -1265,11 +1304,11 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n,
     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,
@@ -1294,11 +1333,11 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n,
   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,
@@ -1309,11 +1348,11 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n,
 
   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;
@@ -1342,20 +1381,22 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n,
   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 */
@@ -1367,7 +1408,8 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n,
   {
     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 */
@@ -1399,7 +1441,10 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n,
 
   /* 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);
@@ -1460,7 +1505,12 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n,
   if (!(flags & M_SHOW))
     flags = 0;
 
-  return (flags);
+  rc = flags;
+
+out:
+  FREE(&buf);
+  FREE(&fmt);
+  return rc;
 }
 
 static int
@@ -1500,7 +1550,7 @@ static struct mapping_t PagerHelpExtra[] = {
 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];
@@ -1509,7 +1559,7 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
   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;
@@ -1543,7 +1593,7 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
   if (stat (fname, &sb) != 0)
   {
     mutt_perror (fname);
-    fclose (fp);
+    safe_fclose (&fp);
     return (-1);
   }
   unlink (fname);
@@ -1584,10 +1634,6 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
   {
     mutt_curs_set (0);
 
-#ifdef USE_IMAP
-    imap_keepalive ();
-#endif
-    
     if (redraw & REDRAW_FULL)
     {
       SETCOLOR (MT_COLOR_NORMAL);
@@ -1654,8 +1700,7 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
        {
          /* 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;
@@ -1750,21 +1795,21 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
       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);
     }
@@ -1969,12 +2014,19 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
       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)
@@ -1983,13 +2035,19 @@ search_next:
 
            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)) && 
@@ -1999,12 +2057,23 @@ search_next:
 
            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;
        }
@@ -2013,9 +2082,10 @@ search_next:
       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))
@@ -2028,6 +2098,7 @@ search_next:
            else
              ch = OP_SEARCH_OPPOSITE;
 
+           wrapped = 0;
            goto search_next;
          }
        }
@@ -2058,7 +2129,6 @@ search_next:
        {
          regerror (err, &SearchRE, buffer, sizeof (buffer));
          mutt_error ("%s", buffer);
-         regfree (&SearchRE);
          for (i = 0; i < maxLine ; i++)
          {
            /* cleanup */
@@ -2111,7 +2181,17 @@ search_next:
            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;
@@ -2272,6 +2352,20 @@ search_next:
        }
        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));
@@ -2658,13 +2752,17 @@ search_next:
         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;