]> granicus.if.org Git - neomutt/commitdiff
Add neomutt version of sidebar patch. (closes #3829)
authorRichard Russon <rich@flatcap.org>
Sat, 4 Jun 2016 18:31:56 +0000 (11:31 -0700)
committerRichard Russon <rich@flatcap.org>
Sat, 4 Jun 2016 18:31:56 +0000 (11:31 -0700)
This is the patch from neomutt; branch 'devel/win-sidebar'; commit
c796fa85f9cacefb69b8f7d8545fc9ba71674180 with the following changes:

  - move the sample muttrc and vimrc to contrib.
  - remove the README.sidebar.
  - empty out the PATCHES file.

32 files changed:
Makefile.am
OPS.SIDEBAR [new file with mode: 0644]
buffy.c
buffy.h
color.c
configure.ac
contrib/sample.muttrc-sidebar [new file with mode: 0644]
contrib/sample.vimrc-sidebar [new file with mode: 0644]
curs_main.c
doc/manual.xml.head
flags.c
functions.h
globals.h
imap/command.c
imap/imap.c
init.c
init.h
keymap.c
mailbox.h
main.c
mbox.c
menu.c
mh.c
mutt.h
mutt_curses.h
mutt_menu.h
mx.c
mx.h
pager.c
sidebar.c [new file with mode: 0644]
sidebar.h [new file with mode: 0644]
sort.h

index 9afb6ce74acc99bee2af256a4acdf5d4f0896ab4..f2f67cf445f65e6899648eccebcbd23d854fd98b 100644 (file)
@@ -77,6 +77,12 @@ EXTRA_DIST = COPYRIGHT GPL OPS OPS.PGP OPS.CRYPT OPS.SMIME TODO UPDATING \
 
 EXTRA_SCRIPTS = smime_keys
 
+if BUILD_SIDEBAR
+mutt_SOURCES += sidebar.c sidebar.h
+endif
+
+EXTRA_DIST += OPS.SIDEBAR
+
 mutt_dotlock_SOURCES = mutt_dotlock.c
 mutt_dotlock_LDADD = $(LIBOBJS)
 mutt_dotlock_DEPENDENCIES = $(LIBOBJS)
@@ -129,10 +135,10 @@ smime_keys: $(srcdir)/smime_keys.pl
 keymap_defs.h: $(OPS) $(srcdir)/gen_defs
        $(srcdir)/gen_defs $(OPS) > keymap_defs.h
 
-keymap_alldefs.h: $(srcdir)/OPS $(srcdir)/OPS.PGP $(srcdir)/OPS.MIX $(srcdir)/OPS.CRYPT $(srcdir)/OPS.SMIME $(srcdir)/gen_defs
+keymap_alldefs.h: $(srcdir)/OPS $(srcdir)/OPS.SIDEBAR $(srcdir)/OPS.PGP $(srcdir)/OPS.MIX $(srcdir)/OPS.CRYPT $(srcdir)/OPS.SMIME $(srcdir)/gen_defs
        rm -f $@
        $(srcdir)/gen_defs $(srcdir)/OPS $(srcdir)/OPS.PGP \
-               $(srcdir)/OPS.MIX $(srcdir)/OPS.CRYPT $(srcdir)/OPS.SMIME \
+               $(srcdir)/OPS.SIDEBAR $(srcdir)/OPS.MIX $(srcdir)/OPS.CRYPT $(srcdir)/OPS.SMIME \
                        > keymap_alldefs.h
 
 reldate.h: $(srcdir)/ChangeLog
diff --git a/OPS.SIDEBAR b/OPS.SIDEBAR
new file mode 100644 (file)
index 0000000..d09ec1f
--- /dev/null
@@ -0,0 +1,8 @@
+OP_SIDEBAR_NEXT "Move the highlight to next mailbox"
+OP_SIDEBAR_NEXT_NEW "Move the highlight to next mailbox with new mail"
+OP_SIDEBAR_OPEN "Open highlighted mailbox"
+OP_SIDEBAR_PAGE_DOWN "Scroll the Sidebar down 1 page"
+OP_SIDEBAR_PAGE_UP "Scroll the Sidebar up 1 page"
+OP_SIDEBAR_PREV "Move the highlight to previous mailbox"
+OP_SIDEBAR_PREV_NEW "Move the highlight to previous mailbox with new mail"
+OP_SIDEBAR_TOGGLE_VISIBLE "Make the Sidebar (in)visible"
diff --git a/buffy.c b/buffy.c
index 733b8bf530cc7dcb272c8963bad15e0ad3dfdef8..325a2d7438e3764bfe2c7b85a9dfc2fc62da44d9 100644 (file)
--- a/buffy.c
+++ b/buffy.c
 
 #include "mutt_curses.h"
 
+#ifdef USE_SIDEBAR
+#include "sidebar.h"
+#endif
+
 #ifdef USE_IMAP
 #include "imap.h"
 #endif
@@ -196,9 +200,17 @@ void mutt_update_mailbox (BUFFY * b)
 static BUFFY *buffy_new (const char *path)
 {
   BUFFY* buffy;
+#ifdef USE_SIDEBAR
+  char rp[PATH_MAX] = "";
+  char *r = NULL;
+#endif
 
   buffy = (BUFFY *) safe_calloc (1, sizeof (BUFFY));
   strfcpy (buffy->path, path, sizeof (buffy->path));
+#ifdef USE_SIDEBAR
+  r = realpath (path, rp);
+  strfcpy (buffy->realpath, r ? rp : path, sizeof (buffy->realpath));
+#endif
   buffy->next = NULL;
   buffy->magic = 0;
 
@@ -215,7 +227,10 @@ int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *e
   BUFFY **tmp,*tmp1;
   char buf[_POSIX_PATH_MAX];
   struct stat sb;
-  char f1[PATH_MAX], f2[PATH_MAX];
+  char f1[PATH_MAX];
+#ifndef USE_SIDEBAR
+  char f2[PATH_MAX];
+#endif
   char *p, *q;
 
   while (MoreArgs (s))
@@ -228,6 +243,9 @@ int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *e
       for (tmp = &Incoming; *tmp;)
       {
         tmp1=(*tmp)->next;
+#ifdef USE_SIDEBAR
+       sb_notify_mailbox (*tmp, 0);
+#endif
         buffy_free (tmp);
         *tmp=tmp1;
       }
@@ -243,8 +261,13 @@ int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *e
     p = realpath (buf, f1);
     for (tmp = &Incoming; *tmp; tmp = &((*tmp)->next))
     {
+#ifdef USE_SIDEBAR
+      q = (*tmp)->realpath;
+      if (mutt_strcmp (p ? p : buf, q) == 0)
+#else
       q = realpath ((*tmp)->path, f2);
       if (mutt_strcmp (p ? p : buf, q ? q : (*tmp)->path) == 0)
+#endif
       {
        dprint(3,(debugfile,"mailbox '%s' already registered as '%s'\n", buf, (*tmp)->path));
        break;
@@ -256,14 +279,21 @@ int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *e
       if(*tmp)
       {
         tmp1=(*tmp)->next;
+#ifdef USE_SIDEBAR
+       sb_notify_mailbox (*tmp, 0);
+#endif
         buffy_free (tmp);
         *tmp=tmp1;
       }
       continue;
     }
 
-    if (!*tmp)
+    if (!*tmp) {
       *tmp = buffy_new (buf);
+#ifdef USE_SIDEBAR
+      sb_notify_mailbox (*tmp, 1);
+#endif
+    }
 
     (*tmp)->new = 0;
     (*tmp)->notified = 1;
@@ -306,6 +336,13 @@ static int buffy_maildir_dir_hasnew(BUFFY* mailbox, const char *dir_name)
       return 0;
   }
 
+#ifdef USE_SIDEBAR
+  if (option (OPTSIDEBAR) && mailbox->msg_unread > 0) {
+    mailbox->new = 1;
+    return 1;
+  }
+#endif
+
   if ((dirp = opendir (path)) == NULL)
   {
     mailbox->magic = 0;
@@ -357,6 +394,89 @@ static int buffy_maildir_hasnew (BUFFY* mailbox)
 
   return 0;
 }
+
+#ifdef USE_SIDEBAR
+/**
+ * buffy_maildir_update_dir - Update counts for one directory
+ * @mailbox: BUFFY representing a maildir mailbox
+ * @dir:     Which directory to search
+ *
+ * Look through one directory of a maildir mailbox.  The directory could
+ * be either "new" or "cur".
+ *
+ * Count how many new, or flagged, messages there are.
+ */
+static void
+buffy_maildir_update_dir (BUFFY *mailbox, const char *dir)
+{
+       char path[_POSIX_PATH_MAX] = "";
+       DIR *dirp = NULL;
+       struct dirent *de = NULL;
+       char *p = NULL;
+       int read;
+
+       snprintf (path, sizeof (path), "%s/%s", mailbox->path, dir);
+
+       dirp = opendir (path);
+       if (!dirp) {
+               mailbox->magic = 0;
+               return;
+       }
+
+       while ((de = readdir (dirp)) != NULL) {
+               if (*de->d_name == '.')
+                       continue;
+
+               /* Matches maildir_parse_flags logic */
+               read = 0;
+               mailbox->msg_count++;
+               p = strstr (de->d_name, ":2,");
+               if (p) {
+                       p += 3;
+                       if (strchr (p, 'S'))
+                               read = 1;
+                       if (strchr (p, 'F'))
+                               mailbox->msg_flagged++;
+               }
+               if (!read) {
+                       mailbox->msg_unread++;
+               }
+       }
+
+       closedir (dirp);
+}
+
+/**
+ * buffy_maildir_update - Update messages counts for a maildir mailbox
+ * @mailbox: BUFFY representing a maildir mailbox
+ *
+ * Open a mailbox directories and update our record of how many new, or
+ * flagged, messages there are.
+ */
+void
+buffy_maildir_update (BUFFY *mailbox)
+{
+       if (!option (OPTSIDEBAR))
+               return;
+
+       mailbox->msg_count   = 0;
+       mailbox->msg_unread  = 0;
+       mailbox->msg_flagged = 0;
+
+       buffy_maildir_update_dir (mailbox, "new");
+       if (mailbox->msg_count) {
+               mailbox->new = 1;
+       }
+       buffy_maildir_update_dir (mailbox, "cur");
+
+       mailbox->sb_last_checked = time (NULL);
+
+       /* make sure the updates are actually put on screen */
+       sb_draw();
+}
+
+#endif
+
 /* returns 1 if mailbox has new mail */ 
 static int buffy_mbox_hasnew (BUFFY* mailbox, struct stat *sb)
 {
@@ -368,7 +488,11 @@ static int buffy_mbox_hasnew (BUFFY* mailbox, struct stat *sb)
   else
     statcheck = sb->st_mtime > sb->st_atime
       || (mailbox->newly_created && sb->st_ctime == sb->st_mtime && sb->st_ctime == sb->st_atime);
+#ifdef USE_SIDEBAR
+  if ((!option (OPTSIDEBAR) && statcheck) || (option (OPTSIDEBAR) && mailbox->msg_unread > 0))
+#else
   if (statcheck)
+#endif
   {
     if (!option(OPTMAILCHECKRECENT) || sb->st_mtime > mailbox->last_visited)
     {
@@ -388,6 +512,40 @@ static int buffy_mbox_hasnew (BUFFY* mailbox, struct stat *sb)
   return rc;
 }
 
+#ifdef USE_SIDEBAR
+/**
+ * buffy_mbox_update - Update messages counts for an mbox mailbox
+ * @mailbox: BUFFY representing an mbox mailbox
+ * @sb:      stat(2) infomation about the mailbox file
+ *
+ * Open a mbox file and update our record of how many new, or flagged,
+ * messages there are. If the mailbox hasn't changed since the last call,
+ * the function does nothing.
+ */
+void
+buffy_mbox_update (BUFFY *mailbox, struct stat *sb)
+{
+       CONTEXT *ctx = NULL;
+
+       if (!option (OPTSIDEBAR))
+               return;
+       if ((mailbox->sb_last_checked > sb->st_mtime) && (mailbox->msg_count != 0))
+               return; /* no check necessary */
+
+       ctx = mx_open_mailbox (mailbox->path, MUTT_READONLY | MUTT_QUIET | MUTT_NOSORT | MUTT_PEEK, NULL);
+       if (ctx) {
+               mailbox->msg_count       = ctx->msgcount;
+               mailbox->msg_unread      = ctx->unread;
+               mailbox->msg_flagged     = ctx->flagged;
+               mailbox->sb_last_checked = time (NULL);
+               mx_close_mailbox (ctx, 0);
+       }
+
+       /* make sure the updates are actually put on screen */
+       sb_draw();
+}
+#endif
+
 int mutt_buffy_check (int force)
 {
   BUFFY *tmp;
@@ -428,6 +586,9 @@ int mutt_buffy_check (int force)
     contex_sb.st_ino=0;
   }
   
+#ifdef USE_SIDEBAR
+  int should_refresh = sb_should_refresh();
+#endif
   for (tmp = Incoming; tmp; tmp = tmp->next)
   {
     if (tmp->magic != MUTT_IMAP)
@@ -461,16 +622,30 @@ int mutt_buffy_check (int force)
       {
       case MUTT_MBOX:
       case MUTT_MMDF:
+#ifdef USE_SIDEBAR
+       if (should_refresh)
+         buffy_mbox_update (tmp, &sb);
+#endif
        if (buffy_mbox_hasnew (tmp, &sb) > 0)
          BuffyCount++;
        break;
 
       case MUTT_MAILDIR:
+#ifdef USE_SIDEBAR
+       if (should_refresh)
+         buffy_maildir_update (tmp);
+#endif
        if (buffy_maildir_hasnew (tmp) > 0)
          BuffyCount++;
        break;
 
       case MUTT_MH:
+#ifdef USE_SIDEBAR
+       if (sb_should_refresh()) {
+         mh_buffy_update (tmp);
+         sb_set_update_time();
+       }
+#endif
        mh_buffy(tmp);
        if (tmp->new)
          BuffyCount++;
@@ -485,6 +660,10 @@ int mutt_buffy_check (int force)
     else if (!tmp->notified)
       BuffyNotify++;
   }
+#ifdef USE_SIDEBAR
+  if (should_refresh)
+         sb_set_update_time();
+#endif
 
   BuffyDoneTime = BuffyTime;
   return (BuffyCount);
diff --git a/buffy.h b/buffy.h
index 92ac7c18db76401acbef8d4d486d75af562a854f..7f2f1d542c63a3e3f601fa0b74db90f409e9b070 100644 (file)
--- a/buffy.h
+++ b/buffy.h
@@ -16,6 +16,9 @@
  *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
+#ifndef _BUFFY_H
+#define _BUFFY_H
+
 /*parameter to mutt_parse_mailboxes*/
 #define MUTT_MAILBOXES   1
 #define MUTT_UNMAILBOXES 2 
 typedef struct buffy_t
 {
   char path[_POSIX_PATH_MAX];
+#ifdef USE_SIDEBAR
+  char realpath[_POSIX_PATH_MAX];
+#endif
   off_t size;
   struct buffy_t *next;
+#ifdef USE_SIDEBAR
+  struct buffy_t *prev;
+#endif
   short new;                   /* mailbox has new mail */
+#ifdef USE_SIDEBAR
+  int msg_count;               /* total number of messages */
+  int msg_unread;              /* number of unread messages */
+  int msg_flagged;             /* number of flagged messages */
+  short is_hidden;             /* is hidden from the sidebar */
+#endif
   short notified;              /* user has been notified */
   short magic;                 /* mailbox type */
   short newly_created;         /* mbox or mmdf just popped into existence */
   time_t last_visited;         /* time of last exit from this mailbox */
+#ifdef USE_SIDEBAR
+  time_t sb_last_checked;      /* time of last buffy check from sidebar */
+#endif
 }
 BUFFY;
 
@@ -49,3 +67,5 @@ void mutt_buffy_cleanup (const char *buf, struct stat *st);
 void mutt_buffy_setnotified (const char *path);
 
 void mh_buffy (BUFFY *);
+
+#endif /* _BUFFY_H */
diff --git a/color.c b/color.c
index 6270a85f6eb8da58568e2024957f23505cbcc5a6..c33d41ebc2250cb42219911a87a0b79ed59c4eae 100644 (file)
--- a/color.c
+++ b/color.c
@@ -94,6 +94,14 @@ static const struct mapping_t Fields[] =
   { "underline",       MT_COLOR_UNDERLINE },
   { "index",           MT_COLOR_INDEX },
   { "prompt",          MT_COLOR_PROMPT },
+#ifdef USE_SIDEBAR
+  { "sidebar_divider", MT_COLOR_DIVIDER },
+  { "sidebar_flagged", MT_COLOR_FLAGGED },
+  { "sidebar_highlight",MT_COLOR_HIGHLIGHT },
+  { "sidebar_indicator",MT_COLOR_SB_INDICATOR },
+  { "sidebar_new",     MT_COLOR_NEW },
+  { "sidebar_spoolfile",MT_COLOR_SB_SPOOLFILE },
+#endif
   { NULL,              0 }
 };
 
@@ -146,6 +154,9 @@ void ci_start_color (void)
   ColorDefs[MT_COLOR_INDICATOR] = A_REVERSE;
   ColorDefs[MT_COLOR_SEARCH] = A_REVERSE;
   ColorDefs[MT_COLOR_MARKERS] = A_REVERSE;
+#ifdef USE_SIDEBAR
+  ColorDefs[MT_COLOR_HIGHLIGHT] = A_UNDERLINE;
+#endif
   /* special meaning: toggle the relevant attribute */
   ColorDefs[MT_COLOR_BOLD] = 0;
   ColorDefs[MT_COLOR_UNDERLINE] = 0;
index 6096dbb3c2db2d02bb77137453ddd1ff2dda5eb1..f8d71a199a693ac8cc4942140a93f2e96323e697 100644 (file)
@@ -175,6 +175,15 @@ if test x$have_smime != xno ; then
        SMIMEAUX_TARGET="smime_keys"
 fi
 
+AC_ARG_ENABLE(sidebar, AC_HELP_STRING([--enable-sidebar], [Enable Sidebar support]),
+[       if test x$enableval = xyes ; then
+               AC_DEFINE(USE_SIDEBAR,1,[ Define if you want support for the sidebar. ])
+               OPS="$OPS \$(srcdir)/OPS.SIDEBAR"
+               need_sidebar="yes"
+        fi
+])
+AM_CONDITIONAL(BUILD_SIDEBAR, test x$need_sidebar = xyes)
+
 AC_ARG_WITH(mixmaster, AS_HELP_STRING([--with-mixmaster@<:@=PATH@:>@],[Include Mixmaster support]),
   [if test "$withval" != no
    then
diff --git a/contrib/sample.muttrc-sidebar b/contrib/sample.muttrc-sidebar
new file mode 100644 (file)
index 0000000..1b5cda7
--- /dev/null
@@ -0,0 +1,116 @@
+# This is a complete list of sidebar-related configuration.
+
+# --------------------------------------------------------------------------
+# VARIABLES - shown with their default values
+# --------------------------------------------------------------------------
+
+# Should the Sidebar be shown?
+set sidebar_visible = no
+
+# How wide should the Sidebar be in screen columns?
+# Note: Some characters, e.g. Chinese, take up two columns each.
+set sidebar_width = 20
+
+# Should the mailbox paths be abbreviated?
+set sidebar_short_path = no
+
+# When abbreviating mailbox path names, use any of these characters as path
+# separators.  Only the part after the last separators will be shown.
+# For file folders '/' is good.  For IMAP folders, often '.' is useful.
+set sidebar_delim_chars = '/.'
+
+# If the mailbox path is abbreviated, should it be indented?
+set sidebar_folder_indent = no
+
+# Indent mailbox paths with this string.
+set sidebar_indent_string = '  '
+
+# Make the Sidebar only display mailboxes that contain new, or flagged,
+# mail.
+set sidebar_new_mail_only = no
+
+# Any mailboxes that are whitelisted will always be visible, even if the
+# sidebar_new_mail_only option is enabled.
+sidebar_whitelist '/home/user/mailbox1'
+sidebar_whitelist '/home/user/mailbox2'
+
+# When searching for mailboxes containing new mail, should the search wrap
+# around when it reaches the end of the list?
+set sidebar_next_new_wrap = no
+
+# The character to use as the divider between the Sidebar and the other Mutt
+# panels.
+# Note: Only the first character of this string is used.
+set sidebar_divider_char = '|'
+
+# Display the Sidebar mailboxes using this format string.
+set sidebar_format = '%B%?F? [%F]?%* %?N?%N/?%S'
+
+# Sidebar will not refresh its list of mailboxes any more frequently than
+# this number of seconds.  This will help reduce disk/network traffic.
+set sidebar_refresh_time = 60
+
+# Sort the mailboxes in the Sidebar using this method:
+#       count    - total number of messages
+#       flagged  - number of flagged messages
+#       new      - number of new messages
+#       path     - mailbox path
+#       unsorted - do not sort the mailboxes
+set sidebar_sort_method = 'unsorted'
+
+# --------------------------------------------------------------------------
+# FUNCTIONS - shown with an example mapping
+# --------------------------------------------------------------------------
+
+# Move the highlight to the previous mailbox
+bind index,pager \Cp sidebar-prev
+
+# Move the highlight to the next mailbox
+bind index,pager \Cn sidebar-next
+
+# Open the highlighted mailbox
+bind index,pager \Co sidebar-open
+
+# Move the highlight to the previous page
+# This is useful if you have a LOT of mailboxes.
+bind index,pager <F3> sidebar-page-up
+
+# Move the highlight to the next page
+# This is useful if you have a LOT of mailboxes.
+bind index,pager <F4> sidebar-page-down
+
+# Move the highlight to the previous mailbox containing new, or flagged,
+# mail.
+bind index,pager <F5> sidebar-prev-new
+
+# Move the highlight to the next mailbox containing new, or flagged, mail.
+bind index,pager <F6> sidebar-next-new
+
+# Toggle the visibility of the Sidebar.
+bind index,pager B sidebar-toggle-visible
+
+# --------------------------------------------------------------------------
+# COLORS - some unpleasant examples are given
+# --------------------------------------------------------------------------
+# Note: All color operations are of the form:
+#       color OBJECT FOREGROUND BACKGROUND
+
+# Color of the current, open, mailbox
+# Note: This is a general Mutt option which colors all selected items.
+color indicator cyan black
+
+# Color of the highlighted, but not open, mailbox.
+color sidebar_highlight black color8
+
+# Color of the divider separating the Sidebar from Mutt panels
+color sidebar_divider color8 black
+
+# Color to give mailboxes containing flagged mail
+color sidebar_flagged red black
+
+# Color to give mailboxes containing new mail
+color sidebar_new green black
+
+# --------------------------------------------------------------------------
+
+# vim: syntax=muttrc
diff --git a/contrib/sample.vimrc-sidebar b/contrib/sample.vimrc-sidebar
new file mode 100644 (file)
index 0000000..c5be50d
--- /dev/null
@@ -0,0 +1,35 @@
+" Vim syntax file for the mutt sidebar patch
+
+syntax keyword muttrcVarBool    skipwhite contained sidebar_folder_indent nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+syntax keyword muttrcVarBool    skipwhite contained sidebar_new_mail_only nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+syntax keyword muttrcVarBool    skipwhite contained sidebar_next_new_wrap nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+syntax keyword muttrcVarBool    skipwhite contained sidebar_short_path    nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+syntax keyword muttrcVarBool    skipwhite contained sidebar_visible       nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+
+syntax keyword muttrcVarNum     skipwhite contained sidebar_refresh_time  nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+syntax keyword muttrcVarNum     skipwhite contained sidebar_width         nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+
+syntax keyword muttrcVarStr     contained skipwhite sidebar_divider_char  nextgroup=muttrcVarEqualsIdxFmt
+syntax keyword muttrcVarStr     contained skipwhite sidebar_delim_chars   nextgroup=muttrcVarEqualsIdxFmt
+syntax keyword muttrcVarStr     contained skipwhite sidebar_format        nextgroup=muttrcVarEqualsIdxFmt
+syntax keyword muttrcVarStr     contained skipwhite sidebar_indent_string nextgroup=muttrcVarEqualsIdxFmt
+syntax keyword muttrcVarStr     contained skipwhite sidebar_sort_method   nextgroup=muttrcVarEqualsIdxFmt
+
+syntax keyword muttrcCommand    sidebar_whitelist
+
+syntax match muttrcFunction     contained "\<sidebar-next\>"
+syntax match muttrcFunction     contained "\<sidebar-next-new\>"
+syntax match muttrcFunction     contained "\<sidebar-open\>"
+syntax match muttrcFunction     contained "\<sidebar-page-down\>"
+syntax match muttrcFunction     contained "\<sidebar-page-up\>"
+syntax match muttrcFunction     contained "\<sidebar-prev\>"
+syntax match muttrcFunction     contained "\<sidebar-prev-new\>"
+syntax match muttrcFunction     contained "\<sidebar-toggle-visible\>"
+
+syntax keyword muttrcColorField contained sidebar_divider
+syntax keyword muttrcColorField contained sidebar_flagged
+syntax keyword muttrcColorField contained sidebar_highlight
+syntax keyword muttrcColorField contained sidebar_indicator
+syntax keyword muttrcColorField contained sidebar_new
+
+" vim: syntax=vim
index f5ac2458cde26d724cb20bf31507bd5c3b2e6bb6..e138906c76248f5bac53c30c26ff74975e8d154b 100644 (file)
 #include "mailbox.h"
 #include "mapping.h"
 #include "sort.h"
+#include "buffy.h"
 #include "mx.h"
 
+#ifdef USE_SIDEBAR
+#include "sidebar.h"
+#endif
+
 #ifdef USE_POP
 #include "pop.h"
 #endif
@@ -593,21 +598,39 @@ int mutt_index_menu (void)
        menu->redraw |= REDRAW_STATUS;
      if (do_buffy_notify)
      {
-       if (mutt_buffy_notify () && option (OPTBEEPNEW))
-       beep ();
+       if (mutt_buffy_notify())
+       {
+         menu->redraw |= REDRAW_STATUS;
+         if (option (OPTBEEPNEW))
+           beep();
+       }
      }
      else
        do_buffy_notify = 1;
     }
 
+#ifdef USE_SIDEBAR
+    if (option (OPTSIDEBAR))
+        menu->redraw |= REDRAW_SIDEBAR;
+#endif
+
     if (op != -1)
       mutt_curs_set (0);
 
     if (menu->redraw & REDRAW_FULL)
     {
       menu_redraw_full (menu);
+#ifdef USE_SIDEBAR
+      sb_draw();
+#endif
       mutt_show_error ();
     }
+#ifdef USE_SIDEBAR
+    else if (menu->redraw & REDRAW_SIDEBAR) {
+      sb_draw();
+      menu->redraw &= ~REDRAW_SIDEBAR;
+    }
+#endif
 
     if (menu->menu == MENU_MAIN)
     {
@@ -631,6 +654,9 @@ int mutt_index_menu (void)
        menu_status_line (buf, sizeof (buf), menu, NONULL (Status));
         mutt_window_move (MuttStatusWindow, 0, 0);
        SETCOLOR (MT_COLOR_STATUS);
+#ifdef USE_SIDEBAR
+       sb_set_buffystats (Context);
+#endif
        mutt_paddstr (MuttStatusWindow->cols, buf);
        NORMAL_COLOR;
        menu->redraw &= ~REDRAW_STATUS;
@@ -1090,6 +1116,9 @@ int mutt_index_menu (void)
          break;
 
        CHECK_MSGCOUNT;
+#ifdef USE_SIDEBAR
+       CHECK_VISIBLE;
+#endif
        CHECK_READONLY;
        {
          int oldvcount = Context->vcount;
@@ -1149,6 +1178,9 @@ int mutt_index_menu (void)
          menu->redraw = REDRAW_FULL;
        break;
 
+#ifdef USE_SIDEBAR
+      case OP_SIDEBAR_OPEN:
+#endif
       case OP_MAIN_CHANGE_FOLDER:
       case OP_MAIN_NEXT_UNREAD_MAILBOX:
 
@@ -1180,6 +1212,14 @@ int mutt_index_menu (void)
        {
          mutt_buffy (buf, sizeof (buf));
 
+#ifdef USE_SIDEBAR
+         if (op == OP_SIDEBAR_OPEN) {
+           const char *path = sb_get_highlight();
+           if (!path)
+             break;
+           strncpy (buf, path, sizeof (buf));
+         } else
+#endif
          if (mutt_enter_fname (cp, buf, sizeof (buf), &menu->redraw, 1) == -1)
          {
            if (menu->menu == MENU_PAGER)
@@ -1198,6 +1238,9 @@ int mutt_index_menu (void)
        }
 
        mutt_expand_path (buf, sizeof (buf));
+#ifdef USE_SIDEBAR
+       sb_set_open_buffy (buf);
+#endif
        if (mx_get_magic (buf) <= 0)
        {
          mutt_error (_("%s is not a mailbox."), buf);
@@ -2309,6 +2352,22 @@ int mutt_index_menu (void)
        mutt_what_key();
        break;
 
+#ifdef USE_SIDEBAR
+      case OP_SIDEBAR_NEXT:
+      case OP_SIDEBAR_NEXT_NEW:
+      case OP_SIDEBAR_PAGE_DOWN:
+      case OP_SIDEBAR_PAGE_UP:
+      case OP_SIDEBAR_PREV:
+      case OP_SIDEBAR_PREV_NEW:
+        sb_change_mailbox (op);
+        break;
+
+      case OP_SIDEBAR_TOGGLE_VISIBLE:
+       toggle_option (OPTSIDEBAR);
+        mutt_reflow_windows();
+       menu->redraw = REDRAW_FULL;
+       break;
+#endif
       default:
        if (menu->menu == MENU_MAIN)
          km_error_key (MENU_MAIN);
index a3711d093858eeeff9c54d90282d7b7661e50c90..da7a659c9ea73e507623c9e71852ce0f8fc248cc 100644 (file)
@@ -405,6 +405,623 @@ attach to a message, select multiple files to attach and many more.
 
 </sect2>
 
+<sect2 id="intro-sidebar">
+       <title>Sidebar</title>
+       <para>
+               The Sidebar shows a list of all your mailboxes.  The list can be
+               turned on and off, it can be themed and the list style can be
+               configured.
+       </para>
+       <para>
+               This part of the manual is suitable for beginners.
+               If you already know Mutt you could skip ahead to the main
+               <link linkend="sidebar">Sidebar guide</link>.
+               If you just want to get started, you could use the sample
+               <link linkend="sidebar-muttrc">Sidebar muttrc</link>.
+       </para>
+       <para>
+               This version of Sidebar is based on Terry Chan's
+               <ulink url="http://www.lunar-linux.org/mutt-sidebar/">2015-11-11 release</ulink>.
+               It contains many
+               <emphasis role="bold"><link linkend="intro-sidebar-features">new features</link></emphasis>,
+               lots of
+               <emphasis role="bold"><link linkend="intro-sidebar-bugfixes">bugfixes</link></emphasis>
+               and a generous helping of
+               <emphasis role="bold">new documentation</emphasis> which you are already reading.
+       </para>
+       <para>
+               To check if Mutt supports <quote>Sidebar</quote>, look for the string
+               <literal>+USE_SIDEBAR</literal> in the mutt version.
+       </para>
+<screen>
+mutt -v
+</screen>
+       <para>
+               <emphasis role="bold">Let's turn on the Sidebar:</emphasis>
+       </para>
+       <screen>set sidebar_visible</screen>
+       <para>
+               You will see something like this.
+               A list of mailboxes on the left.
+               A list of emails, from the selected mailbox, on the right.
+       </para>
+<screen>
+<emphasis role="indicator">Fruit [1]     3/8</emphasis>|  1    + Jan 24  Rhys Lee         (192)  Yew
+Animals [1]   2/6|  2    + Feb 11  Grace Hall       (167)  Ilama
+Cars            4|  3      Feb 23  Aimee Scott      (450)  Nectarine
+Seas          1/7|  4    ! Feb 28  Summer Jackson   (264)  Lemon
+                 |  5      Mar 07  Callum Harrison  (464)  Raspberry
+                 |<emphasis role="indicator">  6 N  + Mar 24  Samuel Harris    (353)  Tangerine          </emphasis>
+                 |  7 N  + Sep 05  Sofia Graham     (335)  Cherry
+                 |  8 N    Sep 16  Ewan Brown       (105)  Ugli
+                 |
+                 |
+</screen>
+<para>
+       This user has four mailboxes: <quote>Fruit</quote>,
+       <quote>Cars</quote>, <quote>Animals</quote> and
+       <quote>Seas</quote>.
+</para>
+<para>
+       The current, open, mailbox is <quote>Fruit</quote>.  We can
+       also see information about the other mailboxes.  For example:
+       The <quote>Animals</quote> mailbox contains, 1 flagged email, 2
+       new emails out of a total of 6 emails.
+</para>
+       <sect3 id="intro-sidebar-navigation">
+               <title>Navigation</title>
+               <para>
+                       The Sidebar adds some new <link linkend="sidebar-functions">functions</link>
+                       to Mutt.
+               </para>
+               <para>
+                       The user pressed the <quote>c</quote> key to
+                       <literal>&lt;change-folder&gt;</literal> to the
+                       <quote>Animals</quote> mailbox.  The Sidebar automatically
+                       updated the indicator to match.
+               </para>
+<screen>
+Fruit [1]     3/8|  1      Jan 03  Tia Gibson       (362)  Caiman
+<emphasis role="indicator">Animals [1]   2/6</emphasis>|  2    + Jan 22  Rhys Lee         ( 48)  Dolphin
+Cars            4|  3    ! Aug 16  Ewan Brown       (333)  Hummingbird
+Seas          1/7|  4      Sep 25  Grace Hall       ( 27)  Capybara
+                 |<emphasis role="indicator">  5 N  + Nov 12  Evelyn Rogers    (453)  Tapir              </emphasis>
+                 |  6 N  + Nov 16  Callum Harrison  (498)  Hedgehog
+                 |
+                 |
+                 |
+                 |
+</screen>
+               <para>
+                       Let's map some functions:
+               </para>
+<screen>
+bind index,pager \CP sidebar-prev       <emphasis role="comment"># Ctrl-Shift-P - Previous Mailbox</emphasis>
+bind index,pager \CN sidebar-next       <emphasis role="comment"># Ctrl-Shift-N - Next Mailbox</emphasis>
+bind index,pager \CO sidebar-open       <emphasis role="comment"># Ctrl-Shift-O - Open Highlighted Mailbox</emphasis>
+</screen>
+               <para>
+                       Press <quote>Ctrl-Shift-N</quote> (Next mailbox) twice will
+                       move the Sidebar <emphasis role="bold">highlight</emphasis> to
+                       down to the <quote>Seas</quote> mailbox.
+               </para>
+<screen>
+Fruit [1]     3/8|  1      Jan 03  Tia Gibson       (362)  Caiman
+<emphasis role="indicator">Animals [1]   2/6</emphasis>|  2    + Jan 22  Rhys Lee         ( 48)  Dolphin
+Cars            4|  3    ! Aug 16  Ewan Brown       (333)  Hummingbird
+<emphasis role="highlight">Seas          1/7</emphasis>|  4      Sep 25  Grace Hall       ( 27)  Capybara
+                 |<emphasis role="indicator">  5 N  + Nov 12  Evelyn Rogers    (453)  Tapir              </emphasis>
+                 |  6 N  + Nov 16  Callum Harrison  (498)  Hedgehog
+                 |
+                 |
+                 |
+                 |
+</screen>
+               <note>
+                       Functions <literal>&lt;sidebar-next&gt;</literal> and
+                       <literal>&lt;sidebar-prev&gt;</literal> move the Sidebar
+                       <emphasis role="bold">highlight</emphasis>.
+                       They <emphasis role="bold">do not</emphasis> change the open
+                       mailbox.
+               </note>
+               <para>
+                       Press <quote>Ctrl-Shift-O</quote>
+                       (<literal>&lt;sidebar-open&gt;</literal>)
+                       to open the highlighted mailbox.
+               </para>
+<screen>
+Fruit [1]     3/8|  1    ! Mar 07  Finley Jones     (139)  Molucca Sea
+Animals [1]   2/6|  2    + Mar 24  Summer Jackson   ( 25)  Arafura Sea
+Cars            4|  3    + Feb 28  Imogen Baker     (193)  Pechora Sea
+<emphasis role="indicator">Seas          1/7</emphasis>|<emphasis role="indicator">  4 N  + Feb 23  Isla Hussain     (348)  Balearic Sea       </emphasis>
+                 |
+                 |
+                 |
+                 |
+                 |
+                 |
+</screen>
+       </sect3>
+       <sect3 id="intro-sidebar-features">
+               <title>Features</title>
+               <para>
+                       The Sidebar shows a list of mailboxes in a panel.
+               <para>
+               </para>
+                       Everything about the Sidebar can be configured.
+               </para>
+               <itemizedlist>
+               <title><link linkend="intro-sidebar-basics">State of the Sidebar</link></title>
+                       <listitem><para>Visibility</para></listitem>
+                       <listitem><para>Width</para></listitem>
+               </itemizedlist>
+               <itemizedlist>
+               <title><link linkend="intro-sidebar-limit">Which mailboxes are displayed</link></title>
+                       <listitem><para>Display all</para></listitem>
+                       <listitem><para>Limit to mailboxes with new mail</para></listitem>
+                       <listitem><para>Whitelist mailboxes to display always</para></listitem>
+               </itemizedlist>
+               <itemizedlist>
+               <title><link linkend="sidebar-sort">The order in which mailboxes are displayed</link></title>
+               <title></title>
+                       <listitem><para>Unsorted (order of mailboxes commands)</para></listitem>
+                       <listitem><para>Sorted alphabetically</para></listitem>
+                       <listitem><para>Sorted by number of new mails</para></listitem>
+               </itemizedlist>
+               <itemizedlist>
+               <title><link linkend="intro-sidebar-colors">Color</link></title>
+                       <listitem><para>Sidebar indicators and divider</para></listitem>
+                       <listitem><para>Mailboxes depending on their type</para></listitem>
+                       <listitem><para>Mailboxes depending on their contents</para></listitem>
+               </itemizedlist>
+               <itemizedlist>
+               <title><link linkend="sidebar-functions">Key bindings</link></title>
+                       <listitem><para>Hide/Unhide the Sidebar</para></listitem>
+                       <listitem><para>Select previous/next mailbox</para></listitem>
+                       <listitem><para>Select previous/next mailbox with new mail</para></listitem>
+                       <listitem><para>Page up/down through a list of mailboxes</para></listitem>
+               </itemizedlist>
+               <itemizedlist>
+               <title>Misc</title>
+                       <listitem><para><link linkend="intro-sidebar-format">Formatting string for mailbox</link></para></listitem>
+                       <listitem><para><link linkend="sidebar-next-new-wrap">Wraparound searching</link></para></listitem>
+                       <listitem><para><link linkend="intro-sidebar-abbrev">Flexible mailbox abbreviations</link></para></listitem>
+                       <listitem><para>Support for Unicode mailbox names (utf-8)</para></listitem>
+               </itemizedlist>
+       </sect3>
+       <sect3 id="intro-sidebar-display">
+               <title>Display</title>
+               <para>
+                       Everything about the Sidebar can be configured.
+               </para>
+               <itemizedlist>
+                       <title>For a quick reference:</title>
+                       <listitem><para><link linkend="sidebar-variables">Sidebar variables to set</link> </para></listitem>
+                       <listitem><para><link linkend="sidebar-colors">Sidebar colors to apply</link></para></listitem>
+                       <listitem><para><link linkend="sidebar-sort">Sidebar sort methods</link></para></listitem>
+               </itemizedlist>
+               <sect4 id="intro-sidebar-basics">
+                       <title>Sidebar Basics</title>
+                       <para>
+                               The most important variable is <literal>$sidebar_visible</literal>.
+                               You can set this in your <quote>muttrc</quote>, or bind a key to the
+                               function <literal>&lt;sidebar-toggle-visible&gt;</literal>.
+                       </para>
+<screen>
+set sidebar_visible                         <emphasis role="comment"># Make the Sidebar visible by default</emphasis>
+bind index,pager B sidebar-toggle-visible   <emphasis role="comment"># Use 'B' to switch the Sidebar on and off</emphasis>
+</screen>
+                       <para>
+                               Next, decide how wide you want the Sidebar to be.  25
+                               characters might be enough for the mailbox name and some numbers.
+               Remember, you can hide/show the Sidebar at the press of button.
+               </para>
+               <para>
+               Finally, you might want to change the divider character.
+               By default, Sidebar draws an ASCII line between it and the Index panel
+                               If your terminal supports it, you can use a Unicode line-drawing character.
+                       </para>
+<screen>
+set sidebar_width = 25                  <emphasis role="comment"># Plenty of space</emphasis>
+set sidebar_divider_char = '│'          <emphasis role="comment"># Pretty line-drawing character</emphasis>
+</screen>
+               </sect4>
+               <sect4 id="intro-sidebar-format">
+                       <title>Sidebar Format String</title>
+                       <para>
+                               <literal>$sidebar_format</literal> allows you to customize the Sidebar display.
+                               For an introduction, read <link linkend="index-format">format strings</link>
+                               including the section about <link linkend="formatstrings-conditionals">conditionals</link>.
+                       </para>
+                       <para>
+                               The default value is <literal>%B%?F? [%F]?%* %?N?%N/?%S</literal>
+                       </para>
+                       <itemizedlist>
+                               <title>Which breaks down as:</title>
+                               <listitem><para><literal>%B</literal> - Mailbox name</para></listitem>
+                               <listitem><para><literal>%?F? [%F]?</literal> - If flagged emails <literal>[%F]</literal>, otherwise nothing</para></listitem>
+                               <listitem><para><literal>%* </literal> - Pad with spaces</para></listitem>
+                               <listitem><para><literal>%?N?%N/?</literal> - If new emails <literal>%N/</literal>, otherwise nothing</para></listitem>
+                               <listitem><para><literal>%S</literal> - Total number of emails</para></listitem>
+                       </itemizedlist>
+                       <table>
+                               <title>sidebar_format</title>
+                               <tgroup cols="3">
+                                       <thead>
+                                               <row>
+                                                       <entry>Format</entry>
+                                                       <entry>Notes</entry>
+                                                       <entry>Description</entry>
+                                               </row>
+                                       </thead>
+                                       <tbody>
+                                               <row>
+                                                       <entry>%B</entry>
+                                                       <entry></entry>
+                                                       <entry>Name of the mailbox</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>%S</entry>
+                                                       <entry>*</entry>
+                                                       <entry>Size of mailbox (total number of messages)</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>%N</entry>
+                                                       <entry>*</entry>
+                                                       <entry>Number of New messages in the mailbox</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>%F</entry>
+                                                       <entry>*</entry>
+                                                       <entry>Number of Flagged messages in the mailbox</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>%!</entry>
+                                                       <entry></entry>
+                                                       <entry>
+                                                               <quote>!</quote>: one flagged message;
+                                                               <quote>!!</quote>: two flagged messages;
+                                                               <quote>n!</quote>: n flagged messages (for n &gt; 2).
+                                                               Otherwise prints nothing.
+                                                       </entry>
+                                               </row>
+                                               <row>
+                                                       <entry>%d</entry>
+                                                       <entry>* â€¡</entry>
+                                                       <entry>Number of deleted messages</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>%L</entry>
+                                                       <entry>* â€¡</entry>
+                                                       <entry>Number of messages after limiting</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>%t</entry>
+                                                       <entry>* â€¡</entry>
+                                                       <entry>Number of tagged messages</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>%&gt;X</entry>
+                                                       <entry></entry>
+                                                       <entry>Right justify the rest of the string and pad with <quote>X</quote></entry>
+                                               </row>
+                                               <row>
+                                                       <entry>%|X</entry>
+                                                       <entry></entry>
+                                                       <entry>Pad to the end of the line with
+                                                       <quote>X</quote></entry>
+                                               </row>
+                                               <row>
+                                                       <entry>%*X</entry>
+                                                       <entry></entry>
+                                                       <entry>Soft-fill with character <quote>X</quote>as pad</entry>
+                                               </row>
+                                       </tbody>
+                               </tgroup>
+                       </table>
+                       <para>
+                       * = Can be optionally printed if nonzero
+                       </para>
+                       <para>
+                       â€¡ = Only applicable to the current folder
+                       </para>
+                       <para>
+                               Here are some examples.
+                               They show the number of (F)lagged, (N)ew and (S)ize.
+                       </para>
+                       <table>
+                               <title>sidebar_format</title>
+                               <tgroup cols="2">
+                                       <thead>
+                                               <row>
+                                                       <entry>Format</entry>
+                                                       <entry>Example</entry>
+                                               </row>
+                                       </thead>
+                                       <tbody>
+                                               <row>
+                                                       <entry><literal>%B%?F? [%F]?%* %?N?%N/?%S</literal></entry>
+                                                       <entry><screen>mailbox [F]            N/S</screen></entry>
+                                               </row>
+                                               <row>
+                                                       <entry><literal>%B%* %F:%N:%S</literal></entry>
+                                                       <entry><screen>mailbox              F:N:S</screen></entry>
+                                               </row>
+                                               <row>
+                                                       <entry><literal>%B %?N?(%N)?%* %S</literal></entry>
+                                                       <entry><screen>mailbox (N)              S</screen></entry>
+                                               </row>
+                                               <row>
+                                                       <entry><literal>%B%* ?F?%F/?%N</literal></entry>
+                                                       <entry><screen>mailbox                F/S</screen></entry>
+                                               </row>
+                                       </tbody>
+                               </tgroup>
+                       </table>
+               </sect4>
+               <sect4 id="intro-sidebar-abbrev">
+                       <title>Abbreviating Mailbox Names</title>
+                       <para>
+                               <literal>$sidebar_delim_chars</literal> tells Sidebar
+                               how to split up mailbox paths.  For local directories
+                               use <quote>/</quote>; for IMAP folders use <quote>.</quote>
+                       </para>
+                       <sect5 id="intro-sidebar-abbrev-ex1">
+                               <title>Example 1</title>
+                               <para>
+                                       This example works well if your mailboxes have unique names
+                                       after the last separator.
+                               </para>
+                               <para>
+                                       Add some mailboxes of diffent depths.
+                               </para>
+<screen>
+set folder="~/mail"
+mailboxes =fruit/apple          =fruit/banana          =fruit/cherry
+mailboxes =water/sea/sicily     =water/sea/archipelago =water/sea/sibuyan
+mailboxes =water/ocean/atlantic =water/ocean/pacific   =water/ocean/arctic
+</screen>
+                               <para>
+                                       Shorten the names:
+                               </para>
+<screen>
+set sidebar_short_path                  <emphasis role="comment"># Shorten mailbox names</emphasis>
+set sidebar_delim_chars="/"             <emphasis role="comment"># Delete everything up to the last / character</emphasis>
+</screen>
+                               <para>
+                                       The screenshot below shows what the Sidebar would look like
+                                       before and after shortening.
+                               </para>
+<screen>
+|fruit/apple                            |apple
+|fruit/banana                           |banana
+|fruit/cherry                           |cherry
+|water/sea/sicily                       |sicily
+|water/sea/archipelago                  |archipelago
+|water/sea/sibuyan                      |sibuyan
+|water/ocean/atlantic                   |atlantic
+|water/ocean/pacific                    |pacific
+|water/ocean/arctic                     |arctic
+</screen>
+                       </sect5>
+                       <sect5 id="intro-sidebar-abbrev-ex2">
+                               <title>Example 2</title>
+                               <para>
+                                       This example works well if you have lots of mailboxes which are arranged
+                                       in a tree.
+                               </para>
+                               <para>
+                                       Add some mailboxes of diffent depths.
+                               </para>
+<screen>
+set folder="~/mail"
+mailboxes =fruit
+mailboxes =fruit/apple =fruit/banana =fruit/cherry
+mailboxes =water
+mailboxes =water/sea
+mailboxes =water/sea/sicily =water/sea/archipelago =water/sea/sibuyan
+mailboxes =water/ocean
+mailboxes =water/ocean/atlantic =water/ocean/pacific =water/ocean/arctic
+</screen>
+                               <para>
+                                       Shorten the names:
+                               </para>
+<screen>
+set sidebar_short_path                  <emphasis role="comment"># Shorten mailbox names</emphasis>
+set sidebar_delim_chars="/"             <emphasis role="comment"># Delete everything up to the last / character</emphasis>
+set sidebar_folder_indent               <emphasis role="comment"># Indent folders whose names we've shortened</emphasis>
+set sidebar_indent_string="  "          <emphasis role="comment"># Indent with two spaces</emphasis>
+</screen>
+                               <para>
+                                       The screenshot below shows what the Sidebar would look like
+                                       before and after shortening.
+                               </para>
+<screen>
+|fruit                                  |fruit
+|fruit/apple                            |  apple
+|fruit/banana                           |  banana
+|fruit/cherry                           |  cherry
+|water                                  |water
+|water/sea                              |  sea
+|water/sea/sicily                       |    sicily
+|water/sea/archipelago                  |    archipelago
+|water/sea/sibuyan                      |    sibuyan
+|water/ocean                            |  ocean
+|water/ocean/atlantic                   |    atlantic
+|water/ocean/pacific                    |    pacific
+|water/ocean/arctic                     |    arctic
+</screen>
+                               <para>
+                                       Sometimes, it will be necessary to add mailboxes, that you
+                                       don't use, to fill in part of the tree.  This will trade
+                                       vertical space for horizonal space (but it looks good).
+                               </para>
+                       </sect5>
+               </sect4>
+               <sect4 id="intro-sidebar-limit">
+                       <title>Limiting the Number of Mailboxes</title>
+                       <para>
+                               If you have a lot of mailboxes, sometimes it can be useful to hide
+                               the ones you aren't using.      <literal>$sidebar_new_mail_only</literal>
+                               tells Sidebar to only show mailboxes that contain new, or flagged, email.
+                       </para>
+                       <para>
+                               If you want some mailboxes to be always visible, then use the
+                               <literal>sidebar_whitelist</literal> command.  It takes a list of
+                               mailboxes as parameters.
+                       </para>
+<screen>
+set sidebar_new_mail_only               <emphasis role="comment"># Only mailboxes with new/flagged email</emphasis>
+sidebar_whitelist fruit fruit/apple     <emphasis role="comment"># Always display these two mailboxes</emphasis>
+</screen>
+               </sect4>
+       </sect3>
+       <sect3 id="intro-sidebar-colors">
+               <title>Colors</title>
+               <para>
+                       Here is a sample color scheme:
+               </para>
+<screen>
+color sidebar_indicator default color17         <emphasis role="comment"># Dark blue background</emphasis>
+color sidebar_highlight white   color238        <emphasis role="comment"># Grey background</emphasis>
+color sidebar_spoolfile yellow  default         <emphasis role="comment"># Yellow</emphasis>
+color sidebar_new       green   default         <emphasis role="comment"># Green</emphasis>
+color sidebar_flagged   red     default         <emphasis role="comment"># Red</emphasis>
+color sidebar_divider   color8  default         <emphasis role="comment"># Dark grey</emphasis>
+</screen>
+               <para>
+                       There is a priority order when coloring Sidebar mailboxes.
+                       e.g.  If a mailbox has new mail it will have the
+                       <literal>sidebar_new</literal> color, even if it also contains
+                       flagged mails.
+               </para>
+               <table id="table-intro-sidebar-colors">
+                       <title>Sidebar Color Priority</title>
+                       <tgroup cols="3">
+                               <thead>
+                                       <row>
+                                               <entry>Priority</entry>
+                                               <entry>Color</entry>
+                                               <entry>Description</entry>
+                                       </row>
+                               </thead>
+                               <tbody>
+                                       <row>
+                                               <entry>Highest</entry>
+                                               <entry><literal>sidebar_indicator</literal></entry>
+                                               <entry>Mailbox is open</entry>
+                                       </row>
+                                       <row>
+                                               <entry></entry>
+                                               <entry><literal>sidebar_highlight</literal></entry>
+                                               <entry>Mailbox is highlighed</entry>
+                                       </row>
+                                       <row>
+                                               <entry></entry>
+                                               <entry><literal>sidebar_spoolfile</literal></entry>
+                                               <entry>Mailbox is the spoolfile (receives incoming mail)</entry>
+                                       </row>
+                                       <row>
+                                               <entry></entry>
+                                               <entry><literal>sidebar_new</literal></entry>
+                                               <entry>Mailbox contains new mail</entry>
+                                       </row>
+                                       <row>
+                                               <entry></entry>
+                                               <entry><literal>sidebar_flagged</literal></entry>
+                                               <entry>Mailbox contains flagged mail</entry>
+                                       </row>
+                                       <row>
+                                               <entry>Lowest</entry>
+                                               <entry>(None)</entry>
+                                               <entry>Mailbox does not match above</entry>
+                                       </row>
+                               </tbody>
+                       </tgroup>
+               </table>
+       </sect3>
+       <sect3 id="intro-sidebar-bugfixes">
+               <title>Bug-fixes</title>
+               <para>
+                       If you haven't used Sidebar before, you can ignore this section.
+               </para>
+               <para>
+                       These bugs have been fixed since the previous Sidebar release: 2015-11-11.
+               </para>
+               <itemizedlist>
+                       <listitem><para>Fix bug when starting in compose mode</para></listitem>
+                       <listitem><para>Fix bug with empty sidebar_divider_char string</para></listitem>
+                       <listitem><para>Fix bug with header wrapping</para></listitem>
+                       <listitem><para>Correctly handle utf8 character sequences</para></listitem>
+                       <listitem><para>Fix a bug in mh_buffy_update</para></listitem>
+                       <listitem><para>Fix refresh -- time overflowed short</para></listitem>
+                       <listitem><para>Protect against empty format strings</para></listitem>
+                       <listitem><para>Limit Sidebar width to COLS</para></listitem>
+                       <listitem><para>Handle unmailboxes * safely</para></listitem>
+                       <listitem><para>Refresh Sidebar after timeout</para></listitem>
+               </itemizedlist>
+       </sect3>
+       <sect3 id="intro-sidebar-config-changes">
+               <title>Config Changes</title>
+               <para>
+                       If you haven't used Sidebar before, you can ignore this section.
+               </para>
+               <para>
+                       Some of the Sidebar config has been changed to make its meaning clearer.
+                       These changes have been made since the previous Sidebar release: 2015-11-11.
+               </para>
+               <table id="table-intro-sidebar-config-changes">
+                       <title>Config Changes</title>
+                       <tgroup cols="2">
+                               <thead>
+                                       <row>
+                                               <entry>Old Name</entry>
+                                               <entry>New Name</entry>
+                                       </row>
+                               </thead>
+                               <tbody>
+                                       <row>
+                                               <entry><literal>$sidebar_delim</literal></entry>
+                                               <entry><literal>$sidebar_divider_char</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>$sidebar_folderindent</literal></entry>
+                                               <entry><literal>$sidebar_folder_indent</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>$sidebar_indentstr</literal></entry>
+                                               <entry><literal>$sidebar_indent_string</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>$sidebar_newmail_only</literal></entry>
+                                               <entry><literal>$sidebar_new_mail_only</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>$sidebar_refresh</literal></entry>
+                                               <entry><literal>$sidebar_refresh_time</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>$sidebar_shortpath</literal></entry>
+                                               <entry><literal>$sidebar_short_path</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>$sidebar_sort</literal></entry>
+                                               <entry><literal>$sidebar_sort_method</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>&lt;sidebar-scroll-down&gt;</literal></entry>
+                                               <entry><literal>&lt;sidebar-page-down&gt;</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>&lt;sidebar-scroll-up&gt;</literal></entry>
+                                               <entry><literal>&lt;sidebar-page-up&gt;</literal></entry>
+                                       </row>
+                               </tbody>
+                       </tgroup>
+               </table>
+       </sect3>
+</sect2>
+
 <sect2 id="intro-help">
 <title>Help</title>
 
@@ -8092,6 +8709,469 @@ please have a look at the mixmaster documentation.
 
 </sect1>
 
+<sect1 id="sidebar">
+       <title>Sidebar Patch</title>
+       <subtitle>Overview of mailboxes</subtitle>
+
+       <sect2 id="sidebar-patch">
+               <title>Patch</title>
+
+               <para>
+                       To check if Mutt supports <quote>Sidebar</quote>, look for
+                       <quote>+USE_SIDEBAR</quote> in the mutt version.
+                       See: <xref linkend="compile-time-features"/>.
+               </para>
+
+               <itemizedlist>
+                       <title>Dependencies:</title>
+                       <listitem><para>mutt-1.5.24</para></listitem>
+               </itemizedlist>
+
+               <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
+       </sect2>
+
+       <sect2 id="sidebar-intro">
+               <title>Introduction</title>
+
+               <para>
+                       The Sidebar shows a list of all your mailboxes.  The list can be
+                       turned on and off, it can be themed and the list style can be
+                       configured.
+               </para>
+
+               <para>
+                       This part of the manual is a reference guide.
+                       If you want a simple introduction with examples see the
+                       <link linkend="intro-sidebar">Sidebar Howto</link>.
+                       If you just want to get started, you could use the sample
+                       <link linkend="sidebar-muttrc">Sidebar muttrc</link>.
+               </para>
+
+               <para>
+                       This version of Sidebar is based on Terry Chan's
+                       <ulink url="http://www.lunar-linux.org/mutt-sidebar/">2015-11-11 release</ulink>.
+                       It contains many
+                       <emphasis role="bold"><link linkend="intro-sidebar-features">new features</link></emphasis>,
+                       lots of
+                       <emphasis role="bold"><link linkend="intro-sidebar-bugfixes">bugfixes</link></emphasis>.
+               </para>
+       </sect2>
+
+       <sect2 id="sidebar-variables">
+               <title>Variables</title>
+
+               <table id="table-sidebar-variables">
+                       <title>Sidebar Variables</title>
+                       <tgroup cols="3">
+                               <thead>
+                                       <row>
+                                               <entry>Name</entry>
+                                               <entry>Type</entry>
+                                               <entry>Default</entry>
+                                       </row>
+                               </thead>
+                               <tbody>
+                                       <row>
+                                               <entry><literal>sidebar_delim_chars</literal></entry>
+                                               <entry>string</entry>
+                                               <entry><literal>/.</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_divider_char</literal></entry>
+                                               <entry>string</entry>
+                                               <entry><literal>|</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_folder_indent</literal></entry>
+                                               <entry>boolean</entry>
+                                               <entry><literal>no</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_format</literal></entry>
+                                               <entry>string</entry>
+                                               <entry><literal>%B%?F? [%F]?%* %?N?%N/?%S</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_indent_string</literal></entry>
+                                               <entry>string</entry>
+                                               <entry><literal>&nbsp;&nbsp;</literal> (two spaces)</entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_new_mail_only</literal></entry>
+                                               <entry>boolean</entry>
+                                               <entry><literal>no</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_next_new_wrap</literal></entry>
+                                               <entry>boolean</entry>
+                                               <entry><literal>no</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_refresh_time</literal></entry>
+                                               <entry>number</entry>
+                                               <entry><literal>60</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_short_path</literal></entry>
+                                               <entry>boolean</entry>
+                                               <entry><literal>no</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_sort_method</literal></entry>
+                                               <entry>enum</entry>
+                                               <entry><literal>SORT_ORDER</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_visible</literal></entry>
+                                               <entry>boolean</entry>
+                                               <entry><literal>no</literal></entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_whitelist</literal></entry>
+                                               <entry>list</entry>
+                                               <entry>(empty)</entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_width</literal></entry>
+                                               <entry>number</entry>
+                                               <entry><literal>20</literal></entry>
+                                       </row>
+                               </tbody>
+                       </tgroup>
+               </table>
+       </sect2>
+
+       <sect2 id="sidebar-functions">
+               <title>Functions</title>
+
+               <para>
+                       Sidebar adds the following functions to Mutt.
+                       By default, none of them are bound to keys.
+               </para>
+
+               <table id="table-sidebar-functions">
+                       <title>Sidebar Functions</title>
+                       <tgroup cols="3">
+                               <thead>
+                                       <row>
+                                               <entry>Menus</entry>
+                                               <entry>Function</entry>
+                                               <entry>Description</entry>
+                                       </row>
+                               </thead>
+                               <tbody>
+                                       <row>
+                                               <entry>index,pager</entry>
+                                               <entry><literal>&lt;sidebar-next&gt;</literal></entry>
+                                               <entry>Move the highlight to next mailbox</entry>
+                                       </row>
+                                       <row>
+                                               <entry>index,pager</entry>
+                                               <entry><literal>&lt;sidebar-next-new&gt;</literal></entry>
+                                               <entry>Move the highlight to next mailbox with new mail</entry>
+                                       </row>
+                                       <row>
+                                               <entry>index,pager</entry>
+                                               <entry><literal>&lt;sidebar-open&gt;</literal></entry>
+                                               <entry>Open highlighted mailbox</entry>
+                                       </row>
+                                       <row>
+                                               <entry>index,pager</entry>
+                                               <entry><literal>&lt;sidebar-page-down&gt;</literal></entry>
+                                               <entry>Scroll the Sidebar down 1 page</entry>
+                                       </row>
+                                       <row>
+                                               <entry>index,pager</entry>
+                                               <entry><literal>&lt;sidebar-page-up&gt;</literal></entry>
+                                               <entry>Scroll the Sidebar up 1 page</entry>
+                                       </row>
+                                       <row>
+                                               <entry>index,pager</entry>
+                                               <entry><literal>&lt;sidebar-prev&gt;</literal></entry>
+                                               <entry>Move the highlight to previous mailbox</entry>
+                                       </row>
+                                       <row>
+                                               <entry>index,pager</entry>
+                                               <entry><literal>&lt;sidebar-prev-new&gt;</literal></entry>
+                                               <entry>Move the highlight to previous mailbox with new mail</entry>
+                                       </row>
+                                       <row>
+                                               <entry>index,pager</entry>
+                                               <entry><literal>&lt;sidebar-toggle-visible&gt;</literal></entry>
+                                               <entry>Make the Sidebar (in)visible</entry>
+                                       </row>
+                               </tbody>
+                       </tgroup>
+               </table>
+       </sect2>
+
+       <sect2 id="sidebar-commands">
+               <title>Commands</title>
+               <cmdsynopsis>
+                       <command>sidebar_whitelist</command>
+                       <arg choice="plain">
+                               <replaceable class="parameter">mailbox</replaceable>
+                       </arg>
+                       <arg choice="opt" rep="repeat">
+                               <replaceable class="parameter">mailbox</replaceable>
+                       </arg>
+               </cmdsynopsis>
+       </sect2>
+
+       <sect2 id="sidebar-colors">
+               <title>Colors</title>
+
+               <table id="table-sidebar-colors">
+                       <title>Sidebar Colors</title>
+                       <tgroup cols="3">
+                               <thead>
+                                       <row>
+                                               <entry>Name</entry>
+                                               <entry>Default Color</entry>
+                                               <entry>Description</entry>
+                                       </row>
+                               </thead>
+                               <tbody>
+                                       <row>
+                                               <entry><literal>sidebar_divider</literal></entry>
+                                               <entry>default</entry>
+                                               <entry>The dividing line between the Sidebar and the Index/Pager panels</entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_flagged</literal></entry>
+                                               <entry>default</entry>
+                                               <entry>Mailboxes containing flagged mail</entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_highlight</literal></entry>
+                                               <entry>underline</entry>
+                                               <entry>Cursor to select a mailbox</entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_indicator</literal></entry>
+                                               <entry>mutt <literal>indicator</literal></entry>
+                                               <entry>The mailbox open in the Index panel</entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_new</literal></entry>
+                                               <entry>default</entry>
+                                               <entry>Mailboxes containing new mail</entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>sidebar_spoolfile</literal></entry>
+                                               <entry>default</entry>
+                                               <entry>Mailbox that receives incoming mail</entry>
+                                       </row>
+                               </tbody>
+                       </tgroup>
+               </table>
+
+               If the <literal>sidebar_indicator</literal> color isn't set, then the default Mutt
+               indicator color will be used (the color used in the index panel).
+       </sect2>
+
+       <sect2 id="sidebar-sort">
+               <title>Sort</title>
+
+               <table id="table-sidebar-sort">
+                       <title>Sidebar Sort</title>
+                       <tgroup cols="2">
+                               <thead>
+                                       <row>
+                                               <entry>Sort</entry>
+                                               <entry>Description</entry>
+                                       </row>
+                               </thead>
+                               <tbody>
+                                       <row>
+                                               <entry><literal>alpha</literal></entry>
+                                               <entry>Alphabetically by path</entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>count</literal></entry>
+                                               <entry>Total number of messages</entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>flagged</literal></entry>
+                                               <entry>Number of flagged messages</entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>name</literal></entry>
+                                               <entry>Alphabetically by path</entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>new</literal></entry>
+                                               <entry>Number of new messages</entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>path</literal></entry>
+                                               <entry>Alphabetically by path</entry>
+                                       </row>
+                                       <row>
+                                               <entry><literal>unsorted</literal></entry>
+                                               <entry>Do not resort the paths</entry>
+                                       </row>
+                               </tbody>
+                       </tgroup>
+               </table>
+       </sect2>
+
+       <sect2 id="sidebar-muttrc">
+               <title>Muttrc</title>
+<screen>
+<emphasis role="comment"># This is a complete list of sidebar-related configuration.
+# --------------------------------------------------------------------------
+# VARIABLES - shown with their default values
+# --------------------------------------------------------------------------
+# Should the Sidebar be shown?</emphasis>
+set sidebar_visible = no
+<emphasis role="comment"># How wide should the Sidebar be in screen columns?
+# Note: Some characters, e.g. Chinese, take up two columns each.</emphasis>
+set sidebar_width = 20
+<emphasis role="comment"># Should the mailbox paths be abbreviated?</emphasis>
+set sidebar_short_path = no
+<emphasis role="comment"># When abbreviating mailbox path names, use any of these characters as path
+# separators.  Only the part after the last separators will be shown.
+# For file folders '/' is good.  For IMAP folders, often '.' is useful.</emphasis>
+set sidebar_delim_chars = '/.'
+<emphasis role="comment"># If the mailbox path is abbreviated, should it be indented?</emphasis>
+set sidebar_folder_indent = no
+<emphasis role="comment"># Indent mailbox paths with this string.</emphasis>
+set sidebar_indent_string = '  '
+<emphasis role="comment"># Make the Sidebar only display mailboxes that contain new, or flagged,
+# mail.</emphasis>
+set sidebar_new_mail_only = no
+<emphasis role="comment"># Any mailboxes that are whitelisted will always be visible, even if the
+# sidebar_new_mail_only option is enabled.</emphasis>
+sidebar_whitelist '/home/user/mailbox1'
+sidebar_whitelist '/home/user/mailbox2'
+<emphasis role="comment"># When searching for mailboxes containing new mail, should the search wrap
+# around when it reaches the end of the list?</emphasis>
+set sidebar_next_new_wrap = no
+<emphasis role="comment"># The character to use as the divider between the Sidebar and the other Mutt
+# panels.
+# Note: Only the first character of this string is used.</emphasis>
+set sidebar_divider_char = '|'
+<emphasis role="comment"># Display the Sidebar mailboxes using this format string.</emphasis>
+set sidebar_format = '%B%?F? [%F]?%* %?N?%N/?%S'
+<emphasis role="comment"># Sidebar will not refresh its list of mailboxes any more frequently than
+# this number of seconds.  This will help reduce disk/network traffic.</emphasis>
+set sidebar_refresh_time = 60
+<emphasis role="comment"># Sort the mailboxes in the Sidebar using this method:
+#       count    - total number of messages
+#       flagged  - number of flagged messages
+#       new      - number of new messages
+#       path     - mailbox path
+#       unsorted - do not sort the mailboxes</emphasis>
+set sidebar_sort_method = 'unsorted'
+<emphasis role="comment"># --------------------------------------------------------------------------
+# FUNCTIONS - shown with an example mapping
+# --------------------------------------------------------------------------
+# Move the highlight to the previous mailbox</emphasis>
+bind index,pager \Cp sidebar-prev
+<emphasis role="comment"># Move the highlight to the next mailbox</emphasis>
+bind index,pager \Cn sidebar-next
+<emphasis role="comment"># Open the highlighted mailbox</emphasis>
+bind index,pager \Co sidebar-open
+<emphasis role="comment"># Move the highlight to the previous page
+# This is useful if you have a LOT of mailboxes.</emphasis>
+bind index,pager &lt;F3&gt; sidebar-page-up
+<emphasis role="comment"># Move the highlight to the next page
+# This is useful if you have a LOT of mailboxes.</emphasis>
+bind index,pager &lt;F4&gt; sidebar-page-down
+<emphasis role="comment"># Move the highlight to the previous mailbox containing new, or flagged,
+# mail.</emphasis>
+bind index,pager &lt;F5&gt; sidebar-prev-new
+<emphasis role="comment"># Move the highlight to the next mailbox containing new, or flagged, mail.</emphasis>
+bind index,pager &lt;F6&gt; sidebar-next-new
+<emphasis role="comment"># Toggle the visibility of the Sidebar.</emphasis>
+bind index,pager B sidebar-toggle-visible
+<emphasis role="comment"># --------------------------------------------------------------------------
+# COLORS - some unpleasant examples are given
+# --------------------------------------------------------------------------
+# Note: All color operations are of the form:
+#       color OBJECT FOREGROUND BACKGROUND
+# Color of the current, open, mailbox
+# Note: This is a general Mutt option which colors all selected items.</emphasis>
+color indicator cyan black
+<emphasis role="comment"># Color of the highlighted, but not open, mailbox.</emphasis>
+color sidebar_highlight black color8
+<emphasis role="comment"># Color of the divider separating the Sidebar from Mutt panels</emphasis>
+color sidebar_divider color8 black
+<emphasis role="comment"># Color to give mailboxes containing flagged mail</emphasis>
+color sidebar_flagged red black
+<emphasis role="comment"># Color to give mailboxes containing new mail</emphasis>
+color sidebar_new green black
+<emphasis role="comment"># --------------------------------------------------------------------------
+# vim: syntax=muttrc</emphasis>
+</screen>
+       </sect2>
+
+       <sect2 id="sidebar-see-also">
+               <title>See Also</title>
+
+               <itemizedlist>
+                       <listitem><para><link linkend="regexp">Regular Expressions</link></para></listitem>
+                       <listitem><para><link linkend="patterns">Patterns</link></para></listitem>
+                       <listitem><para><link linkend="color">Color command</link></para></listitem>
+                       <listitem><para><link linkend="notmuch">notmuch patch</link></para></listitem>
+               </itemizedlist>
+       </sect2>
+
+       <sect2 id="sidebar-known-bugs">
+               <title>Known Bugs</title>
+               Unsorted isn't
+       </sect2>
+
+       <sect2 id="sidebar-credits">
+               <title>Credits</title>
+               <itemizedlist>
+               <listitem><para>Justin Hibbits <email>jrh29@po.cwru.edu</email></para></listitem>
+               <listitem><para>Thomer M. Gil <email>mutt@thomer.com</email></para></listitem>
+               <listitem><para>David Sterba <email>dsterba@suse.cz</email></para></listitem>
+               <listitem><para>Evgeni Golov <email>evgeni@debian.org</email></para></listitem>
+               <listitem><para>Fabian Groffen <email>grobian@gentoo.org</email></para></listitem>
+               <listitem><para>Jason DeTiberus <email>jdetiber@redhat.com</email></para></listitem>
+               <listitem><para>Stefan Assmann <email>sassmann@kpanic.de</email></para></listitem>
+               <listitem><para>Steve Kemp <email>steve@steve.org.uk</email></para></listitem>
+               <listitem><para>Terry Chan <email>tchan@lunar-linux.org</email></para></listitem>
+               <listitem><para>Tyler Earnest <email>tylere@rne.st</email></para></listitem>
+               <listitem><para>Richard Russon <email>rich@flatcap.org</email></para></listitem>
+               </itemizedlist>
+       </sect2>
+</sect1>
+
 </chapter>
 
 <chapter id="security">
@@ -9246,6 +10326,17 @@ The following are the commands understood by Mutt:
 </cmdsynopsis>
 </listitem>
 
+<listitem>
+<cmdsynopsis>
+<command>sidebar_whitelist</command>
+<arg choice="plain">
+<replaceable class="parameter">item</replaceable>
+</arg>
+<arg choice="plain">
+<replaceable class="parameter">command</replaceable>
+</arg>
+</cmdsynopsis>
+</listitem>
 <listitem>
 <cmdsynopsis>
 <command><link linkend="source">source</link></command>
diff --git a/flags.c b/flags.c
index 2680265150dbc26e5173aec7cff3cb509d82636b..2d404f60f3c736755cba9f95d88378acfdef8207 100644 (file)
--- a/flags.c
+++ b/flags.c
 #include "sort.h"
 #include "mx.h"
 
+#ifdef USE_SIDEBAR
+#include "sidebar.h"
+#endif
+
 void _mutt_set_flag (CONTEXT *ctx, HEADER *h, int flag, int bf, int upd_ctx)
 {
   int changed = h->changed;
@@ -263,6 +267,9 @@ void _mutt_set_flag (CONTEXT *ctx, HEADER *h, int flag, int bf, int upd_ctx)
    */
   if (h->searched && (changed != h->changed || deleted != ctx->deleted || tagged != ctx->tagged || flagged != ctx->flagged))
     h->searched = 0;
+#ifdef USE_SIDEBAR
+  sb_draw();
+#endif
 }
 
 void mutt_tag_set_flag (int flag, int bf)
index 684b196a9e1746f127e467a3a511e87503eb6709..2af8827d7e6d2b4ef2d3dc57a0148fa7b711d307 100644 (file)
@@ -168,6 +168,16 @@ const struct binding_t OpMain[] = { /* map: index */
   { "decrypt-copy",            OP_DECRYPT_COPY,                NULL },
   { "decrypt-save",            OP_DECRYPT_SAVE,                NULL },
 
+#ifdef USE_SIDEBAR
+  { "sidebar-next",            OP_SIDEBAR_NEXT,                NULL },
+  { "sidebar-next-new",                OP_SIDEBAR_NEXT_NEW,            NULL },
+  { "sidebar-open",            OP_SIDEBAR_OPEN,                NULL },
+  { "sidebar-page-down",       OP_SIDEBAR_PAGE_DOWN,           NULL },
+  { "sidebar-page-up",         OP_SIDEBAR_PAGE_UP,             NULL },
+  { "sidebar-prev",            OP_SIDEBAR_PREV,                NULL },
+  { "sidebar-prev-new",                OP_SIDEBAR_PREV_NEW,            NULL },
+  { "sidebar-toggle-visible",  OP_SIDEBAR_TOGGLE_VISIBLE,      NULL },
+#endif
 
   { NULL,                      0,                              NULL }
 };
@@ -272,6 +282,17 @@ const struct binding_t OpPager[] = { /* map: pager */
 
   { "what-key",                OP_WHAT_KEY,            NULL },
 
+#ifdef USE_SIDEBAR
+  { "sidebar-next",            OP_SIDEBAR_NEXT,                NULL },
+  { "sidebar-next-new",                OP_SIDEBAR_NEXT_NEW,            NULL },
+  { "sidebar-open",            OP_SIDEBAR_OPEN,                NULL },
+  { "sidebar-page-down",       OP_SIDEBAR_PAGE_DOWN,           NULL },
+  { "sidebar-page-up",         OP_SIDEBAR_PAGE_UP,             NULL },
+  { "sidebar-prev",            OP_SIDEBAR_PREV,                NULL },
+  { "sidebar-prev-new",                OP_SIDEBAR_PREV_NEW,            NULL },
+  { "sidebar-toggle-visible",  OP_SIDEBAR_TOGGLE_VISIBLE,      NULL },
+#endif
+
   { NULL,              0,                              NULL }
 };
 
index abefade3d1423e253e8ec5422259d7759d03ea9f..cf8c5f0cc713d6c01c39f2b18ae61dc2067b72f4 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -118,6 +118,12 @@ WHERE short SearchContext;
 WHERE char *SendCharset;
 WHERE char *Sendmail;
 WHERE char *Shell;
+#ifdef USE_SIDEBAR
+WHERE char *SidebarDelimChars;
+WHERE char *SidebarDividerChar;
+WHERE char *SidebarFormat;
+WHERE char *SidebarIndentString;
+#endif
 WHERE char *Signature;
 WHERE char *SimpleSearch;
 #if USE_SMTP
@@ -214,6 +220,14 @@ WHERE short ScoreThresholdDelete;
 WHERE short ScoreThresholdRead;
 WHERE short ScoreThresholdFlag;
 
+/* This isn't excluded from the build because it's too entwined in the code.
+ * For now. */
+WHERE short SidebarWidth;
+#ifdef USE_SIDEBAR
+WHERE short SidebarRefreshTime;
+WHERE LIST *SidebarWhitelist INITVAL(0);
+#endif
+
 #ifdef USE_IMAP
 WHERE short ImapKeepalive;
 WHERE short ImapPipelineDepth;
index fedcfba94b4c00e9d8957722e0cbca9cda5cbb7f..f73e895dccdea332f0c197891ef74b858cfb9bee 100644 (file)
@@ -1016,6 +1016,14 @@ static void cmd_parse_status (IMAP_DATA* idata, char* s)
             opened */
          status->uidnext = oldun;
 
+#ifdef USE_SIDEBAR
+       /* Make the sidebar show the correct numbers */
+       if (status->messages) {
+         inc->msg_count  = status->messages;
+         inc->msg_unread = status->unseen;
+       }
+#endif
+
         FREE (&value);
         return;
       }
index c334c441a1e4a97294892aba02946044e14bacf8..8a73ec9add97ea4d7db47366cf7bec55a3ced545 100644 (file)
@@ -1559,7 +1559,11 @@ int imap_buffy_check (int force)
 
     imap_munge_mbox_name (idata, munged, sizeof (munged), name);
     snprintf (command, sizeof (command),
+#ifdef USE_SIDEBAR
+             "STATUS %s (UIDNEXT UIDVALIDITY UNSEEN RECENT MESSAGES)", munged);
+#else
              "STATUS %s (UIDNEXT UIDVALIDITY UNSEEN RECENT)", munged);
+#endif
 
     if (imap_exec (idata, command, IMAP_CMD_QUEUE) < 0)
     {
diff --git a/init.c b/init.c
index eed9c73b57c70ec75ef79e4b0724bba271c4309e..04d668595cf32ca25805045ba81d5211872f8bc2 100644 (file)
--- a/init.c
+++ b/init.c
@@ -2175,6 +2175,9 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err)
        case DT_SORT_AUX:
          map = SortAuxMethods;
          break;
+       case DT_SORT_SIDEBAR:
+         map = SortSidebarMethods;
+         break;
        default:
          map = SortMethods;
          break;
diff --git a/init.h b/init.h
index 06fb1eae05a5221d8196d45e86c77370ebcbe79a..b101582ee099fbc12efdb9c666ab082039c61f46 100644 (file)
--- a/init.h
+++ b/init.h
 #define DTYPE(x) ((x) & DT_MASK)
 
 /* subtypes */
-#define DT_SUBTYPE_MASK        0xf0
+#define DT_SUBTYPE_MASK        0xff0
 #define DT_SORT_ALIAS  0x10
 #define DT_SORT_BROWSER 0x20
 #define DT_SORT_KEYS   0x40
 #define DT_SORT_AUX    0x80
+#define DT_SORT_SIDEBAR        0x100
 
 /* flags to parse_set() */
 #define MUTT_SET_INV   (1<<0)  /* default is to invert all vars */
@@ -2666,6 +2667,146 @@ struct option_t MuttVars[] = {
   ** Command to use when spawning a subshell.  By default, the user's login
   ** shell from \fC/etc/passwd\fP is used.
   */
+#ifdef USE_SIDEBAR
+  { "sidebar_divider_char", DT_STR, R_BOTH, UL &SidebarDividerChar, UL "|" },
+  /*
+  ** .pp
+  ** This specifies the characters to be drawn between the sidebar (when
+  ** visible) and the other Mutt panels. ASCII and Unicode line-drawing
+  ** characters are supported.
+  */
+  { "sidebar_delim_chars", DT_STR, R_NONE, UL &SidebarDelimChars, UL "/." },
+  /*
+  ** .pp
+  ** This contains the list of characters which you would like to treat
+  ** as folder separators for displaying paths in the sidebar.
+  ** .pp
+  ** Local mail is often arranged in directories: `dir1/dir2/mailbox'.
+  ** .ts
+  ** set sidebar_delim_chars='/'
+  ** .te
+  ** IMAP mailboxes are often named: `folder1.folder2.mailbox'.
+  ** .ts
+  ** set sidebar_delim_chars='.'
+  ** .te
+  ** .pp
+  ** \fBSee also:\fP $$sidebar_short_path, $$sidebar_folder_indent, $$sidebar_indent_string.
+  */
+  { "sidebar_folder_indent", DT_BOOL, R_BOTH, OPTSIDEBARFOLDERINDENT, 0 },
+  /*
+  ** .pp
+  ** Set this to indent mailboxes in the sidebar.
+  ** .pp
+  ** \fBSee also:\fP $$sidebar_short_path, $$sidebar_indent_string, $$sidebar_delim_chars.
+  */
+  { "sidebar_format", DT_STR, R_NONE, UL &SidebarFormat, UL "%B%?F? [%F]?%* %?N?%N/?%S" },
+  /*
+  ** .pp
+  ** This variable allows you to customize the sidebar display. This string is
+  ** similar to $$index_format, but has its own set of \fCprintf(3)\fP-like
+  ** sequences:
+  ** .dl
+  ** .dt %B  .dd Name of the mailbox
+  ** .dt %S  .dd * Size of mailbox (total number of messages)
+  ** .dt %N  .dd * Number of New messages in the mailbox
+  ** .dt %F  .dd * Number of Flagged messages in the mailbox
+  ** .dt %!  .dd ``!'' : one flagged message;
+  **             ``!!'' : two flagged messages;
+  **             ``n!'' : n flagged messages (for n > 2).
+  **             Otherwise prints nothing.
+  ** .dt %d  .dd * @ Number of deleted messages
+  ** .dt %L  .dd * @ Number of messages after limiting
+  ** .dt %t  .dd * @ Number of tagged messages
+  ** .dt %>X .dd right justify the rest of the string and pad with ``X''
+  ** .dt %|X .dd pad to the end of the line with ``X''
+  ** .dt %*X .dd soft-fill with character ``X'' as pad
+  ** .de
+  ** .pp
+  ** * = Can be optionally printed if nonzero
+  ** @ = Only applicable to the current folder
+  */
+  { "sidebar_indent_string", DT_STR, R_BOTH, UL &SidebarIndentString, UL "  " },
+  /*
+  ** .pp
+  ** This specifies the string that is used to indent mailboxes in the sidebar.
+  ** It defaults to two spaces.
+  ** .pp
+  ** \fBSee also:\fP $$sidebar_short_path, $$sidebar_folder_indent, $$sidebar_delim_chars.
+  */
+  { "sidebar_new_mail_only", DT_BOOL, R_BOTH, OPTSIDEBARNEWMAILONLY, 0 },
+  /*
+  ** .pp
+  ** When set, the sidebar will only display mailboxes containing new, or
+  ** flagged, mail.
+  ** .pp
+  ** \fBSee also:\fP $sidebar_whitelist.
+  */
+  { "sidebar_next_new_wrap", DT_BOOL, R_BOTH, UL OPTSIDEBARNEXTNEWWRAP, 0 },
+  /*
+  ** .pp
+  ** When set, the \fC<sidebar-next-new>\fP command will not stop and the end of
+  ** the list of mailboxes, but wrap around to the beginning. The
+  ** \fC<sidebar-prev-new>\fP command is similarly affected, wrapping around to
+  ** the end of the list.
+  */
+  { "sidebar_refresh_time", DT_NUM, R_BOTH, UL &SidebarRefreshTime, 60 },
+  /*
+  ** .pp
+  ** Set sidebar_refresh_time to the minimum number of seconds between refreshes.
+  ** This will reduced network traffic.
+  ** .pp
+  ** \fBNote:\fP Set to 0 to disable refreshing.
+  */
+  { "sidebar_short_path", DT_BOOL, R_BOTH, OPTSIDEBARSHORTPATH, 0 },
+  /*
+  ** .pp
+  ** By default the sidebar will show the mailbox's path, relative to the
+  ** $$folder variable. Setting \fCsidebar_shortpath=yes\fP will shorten the
+  ** names relative to the previous name. Here's an example:
+  ** .dl
+  ** .dt \fBshortpath=no\fP .dd \fBshortpath=yes\fP .dd \fBshortpath=yes, folderindent=yes, indentstr=".."\fP
+  ** .dt \fCfruit\fP        .dd \fCfruit\fP         .dd \fCfruit\fP
+  ** .dt \fCfruit.apple\fP  .dd \fCapple\fP         .dd \fC..apple\fP
+  ** .dt \fCfruit.banana\fP .dd \fCbanana\fP        .dd \fC..banana\fP
+  ** .dt \fCfruit.cherry\fP .dd \fCcherry\fP        .dd \fC..cherry\fP
+  ** .de
+  ** .pp
+  ** \fBSee also:\fP $$sidebar_delim_chars, $$sidebar_folder_indent, $$sidebar_indent_string.
+  */
+  { "sidebar_sort_method", DT_SORT|DT_SORT_SIDEBAR, R_NONE, UL &SidebarSortMethod, SORT_ORDER },
+  /*
+  ** .pp
+  ** Specifies how to sort entries in the file browser.  By default, the
+  ** entries are sorted alphabetically.  Valid values:
+  ** .il
+  ** .dd alpha (alphabetically)
+  ** .dd count (all message count)
+  ** .dd date
+  ** .dd desc (description)
+  ** .dd new (new message count)
+  ** .dd size
+  ** .dd unsorted
+  ** .ie
+  ** .pp
+  ** You may optionally use the ``reverse-'' prefix to specify reverse sorting
+  ** order (example: ``\fCset sort_browser=reverse-date\fP'').
+  */
+  { "sidebar_visible", DT_BOOL, R_BOTH|R_REFLOW, OPTSIDEBAR, 0 },
+  /*
+  ** .pp
+  ** This specifies whether or not to show sidebar. The sidebar shows a list of
+  ** all your mailboxes.
+  ** .pp
+  ** \fBSee also:\fP $$sidebar_format, $$sidebar_width
+  */
+  { "sidebar_width", DT_NUM, R_BOTH|R_REFLOW, UL &SidebarWidth, 30 },
+  /*
+  ** .pp
+  ** This controls the width of the sidebar.  It is measured in screen columns.
+  ** For example: sidebar_width=20 could display 20 ASCII characters, or 10
+  ** Chinese characters.
+  */
+#endif
   { "sig_dashes",      DT_BOOL, R_NONE, OPTSIGDASHES, 1 },
   /*
   ** .pp
@@ -3653,6 +3794,19 @@ const struct mapping_t SortKeyMethods[] = {
   { NULL,       0 }
 };
 
+const struct mapping_t SortSidebarMethods[] = {
+  { "alpha",           SORT_PATH },
+  { "count",           SORT_COUNT },
+  { "desc",            SORT_DESC },
+  { "flagged",         SORT_FLAGGED },
+  { "mailbox-order",   SORT_ORDER },
+  { "name",            SORT_PATH },
+  { "new",             SORT_COUNT_NEW },
+  { "path",            SORT_PATH },
+  { "unsorted",                SORT_ORDER },
+  { NULL,              0 }
+};
+
 
 /* functions used to parse commands in a rc file */
 
@@ -3742,6 +3896,9 @@ const struct command_t Commands[] = {
   { "send-hook",       mutt_parse_hook,        MUTT_SENDHOOK },
   { "send2-hook",      mutt_parse_hook,        MUTT_SEND2HOOK },
   { "set",             parse_set,              0 },
+#ifdef USE_SIDEBAR
+  { "sidebar_whitelist",parse_list,            UL &SidebarWhitelist },
+#endif
   { "source",          parse_source,           0 },
   { "spam",            parse_spam_list,        MUTT_SPAM },
   { "nospam",          parse_spam_list,        MUTT_NOSPAM },
index 8b8b972b5bd7f1707a8ff21707c5d2e133d73496..301ef653783d5b8fc0d9f24c3d9bc43da5658ecb 100644 (file)
--- a/keymap.c
+++ b/keymap.c
@@ -457,6 +457,9 @@ int km_dokey (int menu)
     }
 #endif
 
+    /* update sidebar stats */
+    mutt_buffy_check(0);
+
     timeout (i * 1000);
     tmp = mutt_getch();
     timeout (-1);
index 322b8a90bac8c8fa47290a7ff6ebd07d890d464d..bdbfeac2905297a52c6423feaec5458e69de1906 100644 (file)
--- a/mailbox.h
+++ b/mailbox.h
@@ -27,6 +27,9 @@
 #define MUTT_NEWFOLDER  (1<<4) /* create a new folder - same as MUTT_APPEND, but uses
                                 * safe_fopen() for mbox-style folders.
                                 */
+#ifdef USE_SIDEBAR
+#define MUTT_PEEK       (1<<5) /* revert atime back after taking a look (if applicable) */
+#endif
 
 /* mx_open_new_message() */
 #define MUTT_ADD_FROM   (1<<0)  /* add a From_ line */
diff --git a/main.c b/main.c
index 1cb9180538447dee39f06514802b146815bf50e7..11e3cdcec89c2f78057286779ffe1faa2a1f2051 100644 (file)
--- a/main.c
+++ b/main.c
@@ -31,6 +31,9 @@
 #include "url.h"
 #include "mutt_crypt.h"
 #include "mutt_idna.h"
+#ifdef USE_SIDEBAR
+#include "sidebar.h"
+#endif
 
 #ifdef USE_SASL
 #include "mutt_sasl.h"
@@ -485,6 +488,12 @@ static void show_version (void)
        "-USE_HCACHE  "
 #endif
 
+#ifdef USE_SIDEBAR
+       "+USE_SIDEBAR  "
+#else
+       "-USE_SIDEBAR  "
+#endif
+
        );
 
 #ifdef ISPELL
@@ -558,7 +567,11 @@ init_extended_keys();
 
 int main (int argc, char **argv)
 {
+#ifdef USE_SIDEBAR
+  char folder[PATH_MAX] = "";
+#else
   char folder[_POSIX_PATH_MAX] = "";
+#endif
   char *subject = NULL;
   char *includeFile = NULL;
   char *draftFile = NULL;
@@ -1189,6 +1202,15 @@ int main (int argc, char **argv)
       strfcpy (folder, NONULL(Spoolfile), sizeof (folder));
     mutt_expand_path (folder, sizeof (folder));
 
+#ifdef USE_SIDEBAR
+    {
+      char tmpfolder[PATH_MAX] = "";
+      strfcpy (tmpfolder, folder, sizeof (tmpfolder));
+      if (!realpath (tmpfolder, folder))
+        strfcpy (folder, tmpfolder, sizeof (tmpfolder));
+    }
+#endif
+
     mutt_str_replace (&CurrentFolder, folder);
     mutt_str_replace (&LastFolder, folder);
 
@@ -1211,6 +1233,9 @@ int main (int argc, char **argv)
     if((Context = mx_open_mailbox (folder, ((flags & MUTT_RO) || option (OPTREADONLY)) ? MUTT_READONLY : 0, NULL))
        || !explicit_folder)
     {
+#ifdef USE_SIDEBAR
+      sb_set_open_buffy (folder);
+#endif
       mutt_index_menu ();
       if (Context)
        FREE (&Context);
diff --git a/mbox.c b/mbox.c
index da69210084ec3a62ef006e102255c0fca350b5d2..3d071dc46b5bbf8dde1e5c398bee95f77763c374 100644 (file)
--- a/mbox.c
+++ b/mbox.c
@@ -100,6 +100,9 @@ int mmdf_parse_mailbox (CONTEXT *ctx)
     mutt_perror (ctx->path);
     return (-1);
   }
+#ifdef USE_SIDEBAR
+  ctx->atime = sb.st_atime;
+#endif
   ctx->mtime = sb.st_mtime;
   ctx->size = sb.st_size;
 
@@ -251,6 +254,9 @@ int mbox_parse_mailbox (CONTEXT *ctx)
 
   ctx->size = sb.st_size;
   ctx->mtime = sb.st_mtime;
+#ifdef USE_SIDEBAR
+  ctx->atime = sb.st_atime;
+#endif
 
 #ifdef NFS_ATTRIBUTE_HACK
   if (sb.st_mtime > sb.st_atime)
diff --git a/menu.c b/menu.c
index fa5f27a7462cd88a916281936126cfc38aa61ef1..a8be371dc3471864673a92f470a2f00631366dc3 100644 (file)
--- a/menu.c
+++ b/menu.c
@@ -24,6 +24,9 @@
 #include "mutt_curses.h"
 #include "mutt_menu.h"
 #include "mbyte.h"
+#ifdef USE_SIDEBAR
+#include "sidebar.h"
+#endif
 
 char* SearchBuffers[MENU_MAX];
 
@@ -235,6 +238,9 @@ void menu_redraw_index (MUTTMENU *menu)
   int do_color;
   int attr;
 
+#ifdef USE_SIDEBAR
+  sb_draw();
+#endif
   for (i = menu->top; i < menu->top + menu->pagelen; i++)
   {
     if (i < menu->max)
diff --git a/mh.c b/mh.c
index c33745a20ca1c0f73ed4bc47e1215d5ee34b8d09..23b7502ae91da6c2bface826ecefadd0cba82b4d 100644 (file)
--- a/mh.c
+++ b/mh.c
@@ -298,6 +298,49 @@ void mh_buffy(BUFFY *b)
   mhs_free_sequences (&mhs);
 }
 
+#ifdef USE_SIDEBAR
+/**
+ * mh_buffy_update - Update messages counts for an mh mailbox
+ * @mailbox: BUFFY representing a maildir mailbox
+ *
+ * Read through an mh mailbox and count messages.  Save the number of new,
+ * flagged messages and a timestamp for now.
+ */
+void
+mh_buffy_update (BUFFY *mailbox)
+{
+       if (!mailbox)
+               return;
+
+       if (!option (OPTSIDEBAR))
+               return;
+
+       struct mh_sequences mhs;
+       memset (&mhs, 0, sizeof (mhs));
+
+       if (mh_read_sequences (&mhs, mailbox->path) < 0)
+               return;
+
+       mailbox->msg_count   = 0;
+       mailbox->msg_unread  = 0;
+       mailbox->msg_flagged = 0;
+
+       int i;
+       for (i = 0; i <= mhs.max; i++) {
+               mailbox->msg_count++;
+       }
+       if (mhs_check (&mhs, i) & MH_SEQ_UNSEEN) {
+               mailbox->msg_unread++;
+       }
+       if (mhs_check (&mhs, i) & MH_SEQ_FLAGGED) {
+               mailbox->msg_flagged++;
+       }
+       mhs_free_sequences (&mhs);
+       mailbox->sb_last_checked = time (NULL);
+}
+
+#endif
+
 static int mh_mkstemp (CONTEXT * dest, FILE ** fp, char **tgt)
 {
   int fd;
diff --git a/mutt.h b/mutt.h
index f6ca62d31ca58f10f8ebd0ed09a117d6bbed7e01..cb386fb4983816defadd28bfdd60cb45a198528f 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -428,6 +428,13 @@ enum
   OPTSAVEEMPTY,
   OPTSAVENAME,
   OPTSCORE,
+#ifdef USE_SIDEBAR
+  OPTSIDEBAR,
+  OPTSIDEBARFOLDERINDENT,
+  OPTSIDEBARNEWMAILONLY,
+  OPTSIDEBARNEXTNEWWRAP,
+  OPTSIDEBARSHORTPATH,
+#endif
   OPTSIGDASHES,
   OPTSIGONTOP,
   OPTSORTRE,
@@ -893,6 +900,9 @@ typedef struct _context
 {
   char *path;
   FILE *fp;
+#ifdef USE_SIDEBAR
+  time_t atime;
+#endif
   time_t mtime;
   off_t size;
   off_t vsize;
@@ -927,6 +937,9 @@ typedef struct _context
   unsigned int quiet : 1;      /* inhibit status messages? */
   unsigned int collapsed : 1;   /* are all threads collapsed? */
   unsigned int closing : 1;    /* mailbox is being closed */
+#ifdef USE_SIDEBAR
+  unsigned int peekonly : 1;   /* just taking a glance, revert atime */
+#endif
 
   /* driver hooks */
   void *data;                  /* driver specific data */
index fbdc45c24f79c3183c851dcdffa47999ab617356..62004491fcb44f0cec4574dd8c881f5492989303 100644 (file)
@@ -123,6 +123,14 @@ enum
   MT_COLOR_UNDERLINE,
   MT_COLOR_INDEX,
   MT_COLOR_PROMPT,
+#ifdef USE_SIDEBAR
+  MT_COLOR_DIVIDER,
+  MT_COLOR_FLAGGED,
+  MT_COLOR_HIGHLIGHT,
+  MT_COLOR_NEW,
+  MT_COLOR_SB_INDICATOR,
+  MT_COLOR_SB_SPOOLFILE,
+#endif
   MT_COLOR_MAX
 };
 
index bb738b5c70cf8654b153597953652a892b603117..bf5522c07ce843e195d57eed715800914dfaa0b7 100644 (file)
@@ -35,6 +35,9 @@
 #define REDRAW_FULL            (1<<5)
 #define REDRAW_BODY            (1<<6)
 #define REDRAW_SIGWINCH                (1<<7)
+#ifdef USE_SIDEBAR
+#define REDRAW_SIDEBAR         (1<<8)
+#endif
 
 #define MUTT_MODEFMT "-- Mutt: %s"
 
diff --git a/mx.c b/mx.c
index d15fba372187d28cbdae436528c9710336320f61..9f3a7a991e9885749dbc1a762de0449327571a79 100644 (file)
--- a/mx.c
+++ b/mx.c
@@ -29,6 +29,9 @@
 #include "copy.h"
 #include "keymap.h"
 #include "url.h"
+#ifdef USE_SIDEBAR
+#include "sidebar.h"
+#endif
 
 #ifdef USE_IMAP
 #include "imap.h"
@@ -613,6 +616,7 @@ static int mx_close_mailbox_append (CONTEXT *ctx)
  *             MUTT_APPEND     open mailbox for appending
  *             MUTT_READONLY   open mailbox in read-only mode
  *             MUTT_QUIET              only print error messages
+ *             MUTT_PEEK               revert atime where applicable
  *     ctx     if non-null, context struct to use
  */
 CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
@@ -635,6 +639,10 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
     ctx->quiet = 1;
   if (flags & MUTT_READONLY)
     ctx->readonly = 1;
+#ifdef USE_SIDEBAR
+  if (flags & MUTT_PEEK)
+    ctx->peekonly = 1;
+#endif
 
   if (flags & (MUTT_APPEND|MUTT_NEWFOLDER))
   {
@@ -708,8 +716,21 @@ void mx_fastclose_mailbox (CONTEXT *ctx)
   if(!ctx) 
     return;
 
+#ifdef USE_SIDEBAR
+  /* fix up the times so buffy won't get confused */
+  struct utimbuf ut;
+  if (ctx->peekonly && ctx->path && (ctx->mtime > ctx->atime)) {
+    ut.actime  = ctx->atime;
+    ut.modtime = ctx->mtime;
+    utime (ctx->path, &ut);
+  }
+#endif
+
   /* never announce that a mailbox we've just left has new mail. #3290
    * XXX: really belongs in mx_close_mailbox, but this is a nice hook point */
+#ifdef USE_SIDEBAR
+  if (!ctx->peekonly)
+#endif
   mutt_buffy_setnotified(ctx->path);
 
   if (ctx->mx_ops)
@@ -722,6 +743,10 @@ void mx_fastclose_mailbox (CONTEXT *ctx)
   mutt_clear_threads (ctx);
   for (i = 0; i < ctx->msgcount; i++)
     mutt_free_header (&ctx->hdrs[i]);
+#ifdef USE_SIDEBAR
+  ctx->msgcount -= ctx->deleted;
+  sb_set_buffystats (ctx);
+#endif
   FREE (&ctx->hdrs);
   FREE (&ctx->v2r);
   FREE (&ctx->path);
@@ -815,6 +840,12 @@ int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
     if (!ctx->hdrs[i]->deleted && ctx->hdrs[i]->read 
         && !(ctx->hdrs[i]->flagged && option (OPTKEEPFLAGGED)))
       read_msgs++;
+#ifdef USE_SIDEBAR
+    if (ctx->hdrs[i]->deleted && !ctx->hdrs[i]->read)
+      ctx->unread--;
+    if (ctx->hdrs[i]->deleted && ctx->hdrs[i]->flagged)
+      ctx->flagged--;
+#endif
   }
 
   if (read_msgs && quadoption (OPT_MOVE) != MUTT_NO)
diff --git a/mx.h b/mx.h
index ef83595131016bdde7dc035245dfb94c3a9191e5..6bc11b4355ef0792bd240c6d61e559c90d64caac 100644 (file)
--- a/mx.h
+++ b/mx.h
@@ -26,6 +26,7 @@
 #define _MX_H
 
 #include "mailbox.h"
+#include "buffy.h"
 
 /* supported mailbox formats */
 enum
@@ -52,6 +53,9 @@ int mbox_check_empty (const char *);
 void mbox_reset_atime (CONTEXT *, struct stat *);
 
 int mh_sync_mailbox (CONTEXT *, int *);
+#ifdef USE_SIDEBAR
+void mh_buffy_update (BUFFY *mailbox);
+#endif
 int mh_check_empty (const char *);
 
 int maildir_check_empty (const char *);
diff --git a/pager.c b/pager.c
index 27319990ce785bd8a5d5d5438dd2a2d941b00830..06bed3abf82e9cce24ba4b93788f68ad923149d7 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -29,6 +29,9 @@
 #include "pager.h"
 #include "attach.h"
 #include "mbyte.h"
+#ifdef USE_SIDEBAR
+#include "sidebar.h"
+#endif
 
 #include "mutt_crypt.h"
 
@@ -1668,6 +1671,9 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
       /* clear() doesn't optimize screen redraws */
       move (0, 0);
       clrtobot ();
+#ifdef USE_SIDEBAR
+      sb_draw();
+#endif
 
       if (IsHeader (extra) && Context->vcount + 1 < PagerIndexLines)
        indexlen = Context->vcount + 1;
@@ -2537,8 +2543,12 @@ search_next:
          ch = 0;
        }
 
-       if (option (OPTFORCEREDRAWPAGER))
+       if (option (OPTFORCEREDRAWPAGER)) {
          redraw = REDRAW_FULL;
+#ifdef USE_SIDEBAR
+         sb_draw();
+#endif
+       }
        unset_option (OPTFORCEREDRAWINDEX);
        unset_option (OPTFORCEREDRAWPAGER);
        break;
@@ -2816,6 +2826,23 @@ search_next:
        mutt_what_key ();
        break;
 
+#ifdef USE_SIDEBAR
+      case OP_SIDEBAR_NEXT:
+      case OP_SIDEBAR_NEXT_NEW:
+      case OP_SIDEBAR_PAGE_DOWN:
+      case OP_SIDEBAR_PAGE_UP:
+      case OP_SIDEBAR_PREV:
+      case OP_SIDEBAR_PREV_NEW:
+       sb_change_mailbox (ch);
+       break;
+
+      case OP_SIDEBAR_TOGGLE_VISIBLE:
+       toggle_option (OPTSIDEBAR);
+        mutt_reflow_windows();
+       redraw = REDRAW_FULL;
+       break;
+#endif
+
       default:
        ch = -1;
        break;
diff --git a/sidebar.c b/sidebar.c
new file mode 100644 (file)
index 0000000..6f8093d
--- /dev/null
+++ b/sidebar.c
@@ -0,0 +1,987 @@
+/* Copyright (C) 2004 Justin Hibbits <jrh29@po.cwru.edu>
+ * Copyright (C) 2004 Thomer M. Gil <mutt@thomer.com>
+ * Copyright (C) 2015-2016 Richard Russon <rich@flatcap.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
+ *     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
+
+#include "mutt.h"
+#include "buffy.h"
+#include "keymap.h"
+#include "mutt_curses.h"
+#include "mutt_menu.h"
+#include "sort.h"
+
+/* Previous values for some sidebar config */
+static short  PreviousSort;    /* sidebar_sort_method */
+static time_t LastRefresh;     /* Time of last refresh */
+
+/* Keep track of various BUFFYs */
+static BUFFY *TopBuffy;                /* First mailbox visible in sidebar */
+static BUFFY *OpnBuffy;                /* Current (open) mailbox */
+static BUFFY *HilBuffy;                /* Highlighted mailbox */
+static BUFFY *BotBuffy;                /* Last mailbox visible in sidebar */
+static BUFFY *Outgoing;                /* Last mailbox in the linked list */
+
+/**
+ * struct sidebar_entry - Info about folders in the sidebar
+ *
+ * Used in the mutt_FormatString callback
+ */
+struct sidebar_entry {
+       char         box[SHORT_STRING];
+       BUFFY       *buffy;
+};
+
+
+/**
+ * find_next_new - Find the next folder that contains new mail
+ * @wrap: Wrap around to the beginning if the end is reached
+ *
+ * Search down the list of mail folders for one containing new mail.
+ *
+ * Returns:
+ *     BUFFY*: Success
+ *     NULL:   Failure
+ */
+static BUFFY *
+find_next_new (int wrap)
+{
+       BUFFY *b = HilBuffy;
+       if (!b)
+               return NULL;
+
+       do {
+               b = b->next;
+               if (!b && wrap) {
+                       b = Incoming;
+               }
+               if (!b || (b == HilBuffy)) {
+                       break;
+               }
+               if (b->msg_unread > 0) {
+                       return b;
+               }
+       } while (b);
+
+       return NULL;
+}
+
+/**
+ * find_prev_new - Find the previous folder that contains new mail
+ * @wrap: Wrap around to the beginning if the end is reached
+ *
+ * Search up the list of mail folders for one containing new mail.
+ *
+ * Returns:
+ *     BUFFY*: Success
+ *     NULL:   Failure
+ */
+static BUFFY *
+find_prev_new (int wrap)
+{
+       BUFFY *b = HilBuffy;
+       if (!b)
+               return NULL;
+
+       do {
+               b = b->prev;
+               if (!b && wrap) {
+                       b = Outgoing;
+               }
+               if (!b || (b == HilBuffy)) {
+                       break;
+               }
+               if (b->msg_unread > 0) {
+                       return b;
+               }
+       } while (b);
+
+       return NULL;
+}
+
+/**
+ * cb_format_str - Create the string to show in the sidebar
+ * @dest:        Buffer in which to save string
+ * @destlen:     Buffer length
+ * @col:         Starting column, UNUSED
+ * @op:          printf-like operator, e.g. 'B'
+ * @src:         printf-like format string
+ * @prefix:      Field formatting string, UNUSED
+ * @ifstring:    If condition is met, display this string
+ * @elsestring:  Otherwise, display this string
+ * @data:        Pointer to our sidebar_entry
+ * @flags:       Format flags, e.g. MUTT_FORMAT_OPTIONAL
+ *
+ * cb_format_str is a callback function for mutt_FormatString.  It understands
+ * five operators. '%B' : Mailbox name, '%F' : Number of flagged messages,
+ * '%N' : Number of new messages, '%S' : Size (total number of messages),
+ * '%!' : Icon denoting number of flagged messages.
+ *
+ * Returns: src (unchanged)
+ */
+static const char *
+cb_format_str (char *dest, size_t destlen, size_t col, int cols, char op,
+       const char *src, const char *prefix, const char *ifstring,
+       const char *elsestring, unsigned long data, format_flag flags)
+{
+       struct sidebar_entry *sbe = (struct sidebar_entry *) data;
+       unsigned int optional;
+       char fmt[SHORT_STRING], buf[SHORT_STRING];
+
+       if (!sbe || !dest)
+               return src;
+
+       dest[0] = 0;    /* Just in case there's nothing to do */
+
+       BUFFY *b = sbe->buffy;
+       if (!b)
+               return src;
+
+       int c = Context && (mutt_strcmp (Context->path, b->path) == 0);
+
+       optional = flags & MUTT_FORMAT_OPTIONAL;
+
+       switch (op) {
+               case 'B':
+                       mutt_format_s (dest, destlen, prefix, sbe->box);
+                       break;
+
+               case 'd':
+                       if (!optional) {
+                               snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+                               snprintf (dest, destlen, fmt, c ? Context->deleted : 0);
+                       } else if ((c && Context->deleted == 0) || !c) {
+                               optional = 0;
+                       }
+                       break;
+
+               case 'F':
+                       if (!optional) {
+                               snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+                               snprintf (dest, destlen, fmt, b->msg_flagged);
+                       } else if (b->msg_flagged == 0) {
+                               optional = 0;
+                       }
+                       break;
+
+               case 'L':
+                       if (!optional) {
+                               snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+                               snprintf (dest, destlen, fmt, c ? Context->vcount : b->msg_count);
+                       } else if ((c && Context->vcount == b->msg_count) || !c) {
+                               optional = 0;
+                       }
+                       break;
+
+               case 'N':
+                       if (!optional) {
+                               snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+                               snprintf (dest, destlen, fmt, b->msg_unread);
+                       } else if (b->msg_unread == 0) {
+                               optional = 0;
+                       }
+                       break;
+
+               case 'S':
+                       if (!optional) {
+                               snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+                               snprintf (dest, destlen, fmt, b->msg_count);
+                       } else if (b->msg_count == 0) {
+                               optional = 0;
+                       }
+                       break;
+
+               case 't':
+                       if (!optional) {
+                               snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+                               snprintf (dest, destlen, fmt, c ? Context->tagged : 0);
+                       } else if ((c && Context->tagged == 0) || !c) {
+                               optional = 0;
+                       }
+                       break;
+
+               case '!':
+                       if (b->msg_flagged == 0) {
+                               mutt_format_s (dest, destlen, prefix, "");
+                       } else if (b->msg_flagged == 1) {
+                               mutt_format_s (dest, destlen, prefix, "!");
+                       } else if (b->msg_flagged == 2) {
+                               mutt_format_s (dest, destlen, prefix, "!!");
+                       } else {
+                               snprintf (buf, sizeof (buf), "%d!", b->msg_flagged);
+                               mutt_format_s (dest, destlen, prefix, buf);
+                       }
+                       break;
+       }
+
+       if (optional)
+               mutt_FormatString (dest, destlen, col, SidebarWidth, ifstring,   cb_format_str, (unsigned long) sbe, flags);
+       else if (flags & MUTT_FORMAT_OPTIONAL)
+               mutt_FormatString (dest, destlen, col, SidebarWidth, elsestring, cb_format_str, (unsigned long) sbe, flags);
+
+       /* We return the format string, unchanged */
+       return src;
+}
+
+/**
+ * make_sidebar_entry - Turn mailbox data into a sidebar string
+ * @buf:     Buffer in which to save string
+ * @buflen:  Buffer length
+ * @width:   Desired width in screen cells
+ * @box:     Mailbox name
+ * @b:       Mailbox object
+ *
+ * Take all the relevant mailbox data and the desired screen width and then get
+ * mutt_FormatString to do the actual work. mutt_FormatString will callback to
+ * us using cb_format_str() for the sidebar specific formatting characters.
+ */
+static void
+make_sidebar_entry (char *buf, unsigned int buflen, int width, char *box,
+       BUFFY *b)
+{
+       struct sidebar_entry sbe;
+
+       if (!buf || !box || !b)
+               return;
+
+       sbe.buffy = b;
+       strncpy (sbe.box, box, sizeof (sbe.box) - 1);
+
+       int box_len = strlen (box);
+       sbe.box[box_len] = '\0';
+
+       mutt_FormatString (buf, buflen, 0, width, NONULL(SidebarFormat), cb_format_str, (unsigned long) &sbe, 0);
+
+       /* Force string to be exactly the right width */
+       int w = mutt_strwidth (buf);
+       int s = strlen (buf);
+       if (w < width) {
+               /* Pad with spaces */
+               memset (buf + s, ' ', width - w);
+               buf[s + width - w] = 0;
+       } else if (w > width) {
+               /* Truncate to fit */
+               int len = mutt_wstr_trunc (buf, buflen, width, NULL);
+               buf[len] = 0;
+       }
+}
+
+/**
+ * cb_qsort_buffy - qsort callback to sort BUFFYs
+ * @a: First  BUFFY to compare
+ * @b: Second BUFFY to compare
+ *
+ * Compare the paths of two BUFFYs taking the locale into account.
+ *
+ * Returns:
+ *     -1: a precedes b
+ *      0: a and b are identical
+ *      1: b precedes a
+ */
+static int
+cb_qsort_buffy (const void *a, const void *b)
+{
+       const BUFFY *b1 = *(const BUFFY **) a;
+       const BUFFY *b2 = *(const BUFFY **) b;
+
+       /* Special case -- move hidden BUFFYs to the end */
+       if (b1->is_hidden != b2->is_hidden) {
+               if (b1->is_hidden)
+                       return 1;
+               else
+                       return -1;
+       }
+
+       int result = 0;
+
+       switch ((SidebarSortMethod & SORT_MASK)) {
+               case SORT_COUNT:
+                       result = (b2->msg_count - b1->msg_count);
+                       break;
+               case SORT_COUNT_NEW:
+                       result = (b2->msg_unread - b1->msg_unread);
+                       break;
+               case SORT_FLAGGED:
+                       result = (b2->msg_flagged - b1->msg_flagged);
+                       break;
+               case SORT_PATH:
+                       result = mutt_strcasecmp (b1->path, b2->path);
+                       break;
+       }
+
+       if (SidebarSortMethod & SORT_REVERSE)
+               result = -result;
+
+       return result;
+}
+
+/**
+ * buffy_going - Prevent our pointers becoming invalid
+ * @b: BUFFY about to be deleted
+ *
+ * If we receive a delete-notification for a BUFFY, we need to change any
+ * pointers we have to reference a different BUFFY, or set them to NULL.
+ *
+ * We don't update the prev/next pointers, they'll be fixed on the next
+ * call to prepare_sidebar().
+ *
+ * Returns:
+ *     A valid alternative BUFFY, or NULL
+ */
+static BUFFY *
+buffy_going (const BUFFY *b)
+{
+       if (!b)
+               return NULL;
+
+       if (b->prev) {
+               b->prev->next = NULL;
+       }
+
+       if (b->next) {
+               b->next->prev = NULL;
+               return b->next;
+       }
+
+       return b->prev;
+}
+
+/**
+ * update_buffy_visibility - Should a BUFFY be displayed in the sidebar
+ * @arr:     array of BUFFYs
+ * @arr_len: number of BUFFYs in array
+ *
+ * For each BUFFY in the array, check whether we should display it.
+ * This is determined by several criteria.  If the BUFFY:
+ *     is the currently open mailbox
+ *     is the currently highlighted mailbox
+ *     has unread messages
+ *     has flagged messages
+ *     is whitelisted
+ */
+static void
+update_buffy_visibility (BUFFY **arr, int arr_len)
+{
+       if (!arr)
+               return;
+
+       short new_only = option (OPTSIDEBARNEWMAILONLY);
+
+       BUFFY *b;
+       int i;
+       for (i = 0; i < arr_len; i++) {
+               b = arr[i];
+
+               b->is_hidden = 0;
+
+               if (!new_only)
+                       continue;
+
+               if ((b == OpnBuffy) || (b->msg_unread  > 0) ||
+                   (b == HilBuffy) || (b->msg_flagged > 0)) {
+                       continue;
+               }
+
+               if (Context && (strcmp (b->path, Context->path) == 0)) {
+                       /* Spool directory */
+                       continue;
+               }
+
+               if (mutt_find_list (SidebarWhitelist, b->path)) {
+                       /* Explicitly asked to be visible */
+                       continue;
+               }
+
+               b->is_hidden = 1;
+       }
+}
+
+/**
+ * sort_buffy_array - Sort an array of BUFFY pointers
+ * @arr:     array of BUFFYs
+ * @arr_len: number of BUFFYs in array
+ *
+ * Sort an array of BUFFY pointers according to the current sort config
+ * option "sidebar_sort_method". This calls qsort to do the work which calls our
+ * callback function "cb_qsort_buffy".
+ *
+ * Once sorted, the prev/next links will be reconstructed.
+ */
+static void
+sort_buffy_array (BUFFY **arr, int arr_len)
+{
+       if (!arr)
+               return;
+
+       /* These are the only sort methods we understand */
+       short ssm = (SidebarSortMethod & SORT_MASK);
+       if ((ssm == SORT_COUNT)     ||
+           (ssm == SORT_COUNT_NEW) ||
+           (ssm == SORT_DESC)      ||
+           (ssm == SORT_FLAGGED)   ||
+           (ssm == SORT_PATH)) {
+               qsort (arr, arr_len, sizeof (*arr), cb_qsort_buffy);
+       }
+
+       int i;
+       for (i = 0; i < (arr_len - 1); i++) {
+               arr[i]->next = arr[i + 1];
+       }
+       arr[arr_len - 1]->next = NULL;
+
+       for (i = 1; i < arr_len; i++) {
+               arr[i]->prev = arr[i - 1];
+       }
+       arr[0]->prev = NULL;
+}
+
+/**
+ * prepare_sidebar - Prepare the list of BUFFYs for the sidebar display
+ * @page_size:  The number of lines on a page
+ *
+ * Before painting the sidebar, we count the BUFFYs, determine which are
+ * visible, sort them and set up our page pointers.
+ *
+ * This is a lot of work to do each refresh, but there are many things that
+ * can change outside of the sidebar that we don't hear about.
+ *
+ * Returns:
+ *     0: No, don't draw the sidebar
+ *     1: Yes, draw the sidebar
+ */
+static int
+prepare_sidebar (int page_size)
+{
+       BUFFY *b = Incoming;
+       if (!b)
+               return 0;
+
+       int count = 0;
+       for (; b; b = b->next)
+               count++;
+
+       BUFFY **arr = safe_malloc (count * sizeof (*arr));
+       if (!arr)
+               return 0;
+
+       int i = 0;
+       for (b = Incoming; b; b = b->next, i++) {
+               arr[i] = b;
+       }
+
+       update_buffy_visibility (arr, count);
+       sort_buffy_array        (arr, count);
+
+       Incoming = arr[0];
+
+       int top_index =  0;
+       int opn_index = -1;
+       int hil_index = -1;
+       int bot_index = -1;
+
+       for (i = 0; i < count; i++) {
+               if (OpnBuffy == arr[i])
+                       opn_index = i;
+               if (HilBuffy == arr[i])
+                       hil_index = i;
+       }
+
+       if (!HilBuffy || (SidebarSortMethod != PreviousSort)) {
+               if (OpnBuffy) {
+                       HilBuffy  = OpnBuffy;
+                       hil_index = opn_index;
+               } else {
+                       HilBuffy  = arr[0];
+                       hil_index = 0;
+               }
+       }
+       if (TopBuffy) {
+               top_index = (hil_index / page_size) * page_size;
+       } else {
+               top_index = hil_index;
+       }
+       TopBuffy = arr[top_index];
+
+       bot_index = top_index + page_size - 1;
+       if (bot_index > (count - 1)) {
+               bot_index = count - 1;
+       }
+       BotBuffy  = arr[bot_index];
+
+       Outgoing = arr[count - 1];
+
+       PreviousSort = SidebarSortMethod;
+       free (arr);
+       return 1;
+}
+
+/**
+ * draw_divider - Draw a line between the sidebar and the rest of mutt
+ * @num_rows:   Height of the Sidebar
+ * @num_cols:   Width of the Sidebar
+ *
+ * Draw a divider using characters from the config option "sidebar_divider_char".
+ * This can be an ASCII or Unicode character.  First we calculate this
+ * characters' width in screen columns, then subtract that from the config
+ * option "sidebar_width".
+ *
+ * Returns:
+ *     -1: Error: bad character, etc
+ *     0:  Error: 0 width character
+ *     n:  Success: character occupies n screen columns
+ */
+static int
+draw_divider (int num_rows, int num_cols)
+{
+       /* Calculate the width of the delimiter in screen cells */
+       int delim_len = mutt_strwidth (SidebarDividerChar);
+
+       if (delim_len < 1)
+               return delim_len;
+
+       if (delim_len > num_cols)
+               return 0;
+
+       SETCOLOR(MT_COLOR_DIVIDER);
+
+       int i;
+       for (i = 0; i < num_rows; i++) {
+               mutt_window_move (MuttSidebarWindow, i, SidebarWidth - delim_len);      //RAR 0 for rhs
+               addstr (NONULL(SidebarDividerChar));
+       }
+
+       return delim_len;
+}
+
+/**
+ * fill_empty_space - Wipe the remaining Sidebar space
+ * @first_row:  Window line to start (0-based)
+ * @num_rows:   Number of rows to fill
+ * @width:      Width of the Sidebar (minus the divider)
+ *
+ * Write spaces over the area the sidebar isn't using.
+ */
+static void
+fill_empty_space (int first_row, int num_rows, int width)
+{
+       /* Fill the remaining rows with blank space */
+       SETCOLOR(MT_COLOR_NORMAL);
+
+       int r;
+       for (r = 0; r < num_rows; r++) {
+               mutt_window_move (MuttSidebarWindow, first_row + r, 0); //RAR rhs
+               int i;
+               for (i = 0; i < width; i++)
+                       addch (' ');
+       }
+}
+
+/**
+ * draw_sidebar - Write out a list of mailboxes, on the left
+ * @num_rows:   Height of the Sidebar
+ * @num_cols:   Width of the Sidebar
+ * @div_width:  Width in screen characters taken by the divider
+ *
+ * Display a list of mailboxes in a panel on the left.  What's displayed will
+ * depend on our index markers: TopBuffy, OpnBuffy, HilBuffy, BotBuffy.
+ * On the first run they'll be NULL, so we display the top of Mutt's list
+ * (Incoming).
+ *
+ * TopBuffy - first visible mailbox
+ * BotBuffy - last  visible mailbox
+ * OpnBuffy - mailbox shown in Mutt's Index Panel
+ * HilBuffy - Unselected mailbox (the paging follows this)
+ *
+ * The entries are formatted using "sidebar_format" and may be abbreviated:
+ * "sidebar_short_path", indented: "sidebar_folder_indent",
+ * "sidebar_indent_string" and sorted: "sidebar_sort_method".  Finally, they're
+ * trimmed to fit the available space.
+ */
+static void
+draw_sidebar (int num_rows, int num_cols, int div_width)
+{
+       BUFFY *b = TopBuffy;
+       if (!b)
+               return;
+
+       int w = MIN(num_cols, (SidebarWidth - div_width));
+       int row = 0;
+       for (b = TopBuffy; b && (row < num_rows); b = b->next) {
+               if (b->is_hidden) {
+                       continue;
+               }
+
+               if (b == OpnBuffy) {
+                       if ((ColorDefs[MT_COLOR_SB_INDICATOR] != 0)) {
+                               SETCOLOR(MT_COLOR_SB_INDICATOR);
+                       } else {
+                               SETCOLOR(MT_COLOR_INDICATOR);
+                       }
+               } else if (b == HilBuffy) {
+                       SETCOLOR(MT_COLOR_HIGHLIGHT);
+               } else if ((ColorDefs[MT_COLOR_SB_SPOOLFILE] != 0) &&
+                       (mutt_strcmp (b->path, Spoolfile) == 0)) {
+                       SETCOLOR(MT_COLOR_SB_SPOOLFILE);
+               } else if (b->msg_unread > 0) {
+                       SETCOLOR(MT_COLOR_NEW);
+               } else if (b->msg_flagged > 0) {
+                       SETCOLOR(MT_COLOR_FLAGGED);
+               } else {
+                       SETCOLOR(MT_COLOR_NORMAL);
+               }
+
+               mutt_window_move (MuttSidebarWindow, row, 0);
+               if (Context && Context->path &&
+                       (!strcmp (b->path, Context->path)||
+                        !strcmp (b->realpath, Context->path))) {
+                       b->msg_unread  = Context->unread;
+                       b->msg_count   = Context->msgcount;
+                       b->msg_flagged = Context->flagged;
+               }
+
+               /* compute length of Maildir without trailing separator */
+               size_t maildirlen = strlen (Maildir);
+               if (SidebarDelimChars && strchr (SidebarDelimChars, Maildir[maildirlen - 1])) {
+                       maildirlen--;
+               }
+
+               /* check whether Maildir is a prefix of the current folder's path */
+               short maildir_is_prefix = 0;
+               if ((strlen (b->path) > maildirlen) && (strncmp (Maildir, b->path, maildirlen) == 0)) {
+                       maildir_is_prefix = 1;
+               }
+               /* calculate depth of current folder and generate its display name with indented spaces */
+               int sidebar_folder_depth = 0;
+               char *sidebar_folder_name;
+               int i;
+               if (option (OPTSIDEBARSHORTPATH)) {
+                       /* disregard a trailing separator, so strlen() - 2 */
+                       sidebar_folder_name = b->path;
+                       for (i = strlen (sidebar_folder_name) - 2; i >= 0; i--) {
+                               if (SidebarDelimChars &&
+                                               strchr (SidebarDelimChars, sidebar_folder_name[i])) {
+                                       sidebar_folder_name += (i + 1);
+                                       break;
+                               }
+                       }
+               } else {
+                       sidebar_folder_name = b->path + maildir_is_prefix * (maildirlen + 1);
+               }
+               if (maildir_is_prefix && option (OPTSIDEBARFOLDERINDENT)) {
+                       const char *tmp_folder_name;
+                       int lastsep = 0;
+                       tmp_folder_name = b->path + maildirlen + 1;
+                       int tmplen = (int) strlen (tmp_folder_name) - 1;
+                       for (i = 0; i < tmplen; i++) {
+                               if (SidebarDelimChars && strchr (SidebarDelimChars, tmp_folder_name[i])) {
+                                       sidebar_folder_depth++;
+                                       lastsep = i + 1;
+                               }
+                       }
+                       if (sidebar_folder_depth > 0) {
+                               if (option (OPTSIDEBARSHORTPATH)) {
+                                       tmp_folder_name += lastsep;  /* basename */
+                               }
+                               sidebar_folder_name = malloc (strlen (tmp_folder_name) + sidebar_folder_depth*strlen (NONULL(SidebarIndentString)) + 1);
+                               sidebar_folder_name[0]=0;
+                               for (i=0; i < sidebar_folder_depth; i++)
+                                       strncat (sidebar_folder_name, NONULL(SidebarIndentString), strlen (NONULL(SidebarIndentString)));
+                               strncat (sidebar_folder_name, tmp_folder_name, strlen (tmp_folder_name));
+                       }
+               }
+               char str[SHORT_STRING];
+               make_sidebar_entry (str, sizeof (str), w, sidebar_folder_name, b);
+               printw ("%s", str);
+               if (sidebar_folder_depth > 0)
+                       free (sidebar_folder_name);
+               row++;
+       }
+
+       fill_empty_space (row, num_rows - row, w);
+}
+
+
+/**
+ * sb_draw - Completely redraw the sidebar
+ *
+ * Completely refresh the sidebar region.  First draw the divider; then, for
+ * each BUFFY, call make_sidebar_entry; finally blank out any remaining space.
+ */
+void
+sb_draw (void)
+{
+       if (!option (OPTSIDEBAR))
+               return;
+
+       int num_rows  = MuttSidebarWindow->rows;
+       int num_cols  = MuttSidebarWindow->cols;
+
+       int div_width = draw_divider (num_rows, num_cols);
+       if (div_width < 0)
+               return;
+
+       if (!Incoming) {
+               fill_empty_space (0, num_rows, SidebarWidth - div_width);
+               return;
+       }
+
+       if (!prepare_sidebar (num_rows))
+               return;
+
+       draw_sidebar (num_rows, num_cols, div_width);
+}
+
+/**
+ * sb_should_refresh - Check if the sidebar is due to be refreshed
+ *
+ * The "sidebar_refresh_time" config option allows the user to limit the frequency
+ * with which the sidebar is refreshed.
+ *
+ * Returns:
+ *     1  Yes, refresh is due
+ *     0  No,  refresh happened recently
+ */
+int
+sb_should_refresh (void)
+{
+       if (!option (OPTSIDEBAR))
+               return 0;
+
+       if (SidebarRefreshTime == 0)
+               return 0;
+
+       time_t diff = (time (NULL) - LastRefresh);
+
+       return (diff >= SidebarRefreshTime);
+}
+
+/**
+ * sb_change_mailbox - Change the selected mailbox
+ * @op: Operation code
+ *
+ * Change the selected mailbox, e.g. "Next mailbox", "Previous Mailbox
+ * with new mail". The operations are listed OPS.SIDEBAR which is built
+ * into an enum in keymap_defs.h.
+ *
+ * If the operation is successful, HilBuffy will be set to the new mailbox.
+ * This function only *selects* the mailbox, doesn't *open* it.
+ *
+ * Allowed values are: OP_SIDEBAR_NEXT, OP_SIDEBAR_NEXT_NEW,
+ * OP_SIDEBAR_PAGE_DOWN, OP_SIDEBAR_PAGE_UP, OP_SIDEBAR_PREV,
+ * OP_SIDEBAR_PREV_NEW.
+ */
+void
+sb_change_mailbox (int op)
+{
+       if (!option (OPTSIDEBAR))
+               return;
+
+       BUFFY *b;
+       if (!HilBuffy)  /* It'll get reset on the next draw */
+               return;
+
+       switch (op) {
+               case OP_SIDEBAR_NEXT:
+                       if (!HilBuffy->next)
+                               return;
+                       if (HilBuffy->next->is_hidden)
+                               return;
+                       HilBuffy = HilBuffy->next;
+                       break;
+               case OP_SIDEBAR_NEXT_NEW:
+                       b = find_next_new (option (OPTSIDEBARNEXTNEWWRAP));
+                       if (!b) {
+                               return;
+                       } else {
+                               HilBuffy = b;
+                       }
+                       break;
+               case OP_SIDEBAR_PAGE_DOWN:
+                       HilBuffy = BotBuffy;
+                       if (HilBuffy->next) {
+                               HilBuffy = HilBuffy->next;
+                       }
+                       break;
+               case OP_SIDEBAR_PAGE_UP:
+                       HilBuffy = TopBuffy;
+                       if (HilBuffy != Incoming) {
+                               HilBuffy = HilBuffy->prev;
+                       }
+                       break;
+               case OP_SIDEBAR_PREV:
+                       if (!HilBuffy->prev)
+                               return;
+                       if (HilBuffy->prev->is_hidden)  /* Can't happen, we've sorted the hidden to the end */
+                               return;
+                       HilBuffy = HilBuffy->prev;
+                       break;
+               case OP_SIDEBAR_PREV_NEW:
+                       b = find_prev_new (option (OPTSIDEBARNEXTNEWWRAP));
+                       if (!b) {
+                               return;
+                       } else {
+                               HilBuffy = b;
+                       }
+                       break;
+               default:
+                       return;
+       }
+       sb_draw();
+}
+
+/**
+ * sb_set_buffystats - Update the BUFFY's message counts from the CONTEXT
+ * @ctx:  A mailbox CONTEXT
+ *
+ * Given a mailbox CONTEXT, find a matching mailbox BUFFY and copy the message
+ * counts into it.
+ */
+void
+sb_set_buffystats (const CONTEXT *ctx)
+{
+       /* Even if the sidebar's hidden,
+        * we should take note of the new data. */
+       BUFFY *b = Incoming;
+       if (!ctx || !b)
+               return;
+
+       for (; b; b = b->next) {
+               if (!strcmp (b->path,     ctx->path) ||
+                   !strcmp (b->realpath, ctx->path)) {
+                       b->msg_unread  = ctx->unread;
+                       b->msg_count   = ctx->msgcount;
+                       b->msg_flagged = ctx->flagged;
+                       break;
+               }
+       }
+}
+
+/**
+ * sb_get_highlight - Get the BUFFY that's highlighted in the sidebar
+ *
+ * Get the path of the mailbox that's highlighted in the sidebar.
+ *
+ * Returns:
+ *     Mailbox path
+ */
+const char *
+sb_get_highlight (void)
+{
+       if (!option (OPTSIDEBAR))
+               return NULL;
+
+       if (!HilBuffy)
+               return NULL;
+
+       return HilBuffy->path;
+}
+
+/**
+ * sb_set_open_buffy - Set the OpnBuffy based on a mailbox path
+ * @path: Mailbox path
+ *
+ * Search through the list of mailboxes.  If a BUFFY has a matching path, set
+ * OpnBuffy to it.
+ */
+BUFFY *
+sb_set_open_buffy (const char *path)
+{
+       /* Even if the sidebar is hidden */
+
+       BUFFY *b = Incoming;
+
+       if (!path || !b)
+               return NULL;
+
+       OpnBuffy = NULL;
+
+       for (; b; b = b->next) {
+               if (!strcmp (b->path,     path) ||
+                   !strcmp (b->realpath, path)) {
+                       OpnBuffy = b;
+                       HilBuffy = b;
+                       break;
+               }
+       }
+
+       return OpnBuffy;
+}
+
+/**
+ * sb_set_update_time - Note the time that the sidebar was updated
+ *
+ * Update the timestamp representing the last sidebar update.  If the user
+ * configures "sidebar_refresh_time", this will help to reduce traffic.
+ */
+void
+sb_set_update_time (void)
+{
+       /* XXX - should this be public? */
+
+       LastRefresh = time (NULL);
+}
+
+/**
+ * sb_notify_mailbox - The state of a BUFFY is about to change
+ *
+ * We receive a notification:
+ *     After a new BUFFY has been created
+ *     Before a BUFFY is deleted
+ *
+ * Before a deletion, check that our pointers won't be invalidated.
+ */
+void
+sb_notify_mailbox (BUFFY *b, int created)
+{
+       if (!b)
+               return;
+
+       /* Any new/deleted mailboxes will cause a refresh.  As long as
+        * they're valid, our pointers will be updated in prepare_sidebar() */
+
+       if (created) {
+               if (!TopBuffy)
+                       TopBuffy = b;
+               if (!HilBuffy)
+                       HilBuffy = b;
+               if (!BotBuffy)
+                       BotBuffy = b;
+               if (!Outgoing)
+                       Outgoing = b;
+               if (!OpnBuffy && Context) {
+                       /* This might happen if the user "unmailboxes *", then
+                        * "mailboxes" our current mailbox back again */
+                       if (mutt_strcmp (b->path, Context->path) == 0) {
+                               OpnBuffy = b;
+                       }
+               }
+       } else {
+               if (TopBuffy == b)
+                       TopBuffy = buffy_going (TopBuffy);
+               if (OpnBuffy == b)
+                       OpnBuffy = buffy_going (OpnBuffy);
+               if (HilBuffy == b)
+                       HilBuffy = buffy_going (HilBuffy);
+               if (BotBuffy == b)
+                       BotBuffy = buffy_going (BotBuffy);
+               if (Outgoing == b)
+                       Outgoing = buffy_going (Outgoing);
+       }
+}
diff --git a/sidebar.h b/sidebar.h
new file mode 100644 (file)
index 0000000..d56b02a
--- /dev/null
+++ b/sidebar.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 2004 Justin Hibbits <jrh29@po.cwru.edu>
+ * Copyright (C) 2004 Thomer M. Gil <mutt@thomer.com>
+ * Copyright (C) 2015-2016 Richard Russon <rich@flatcap.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
+ *     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 SIDEBAR_H
+#define SIDEBAR_H
+
+#include "mutt.h"
+#include "buffy.h"
+
+void         sb_change_mailbox (int op);
+void         sb_draw (void);
+const char * sb_get_highlight (void);
+void         sb_init (void);
+void         sb_notify_mailbox (BUFFY *b, int created);
+void         sb_set_buffystats (const CONTEXT *ctx);
+BUFFY *      sb_set_open_buffy (const char *path);
+void         sb_set_update_time (void);
+int          sb_should_refresh (void);
+
+#endif /* SIDEBAR_H */
diff --git a/sort.h b/sort.h
index f2832b21ea28de06f4955be60bb2504f1e0d9272..f24491b95ef8d6f9c2a3f3e15be69e54cbbaebd1 100644 (file)
--- a/sort.h
+++ b/sort.h
 #define SORT_KEYID     12
 #define SORT_TRUST     13
 #define SORT_SPAM      14
+#define SORT_COUNT     15
+#define SORT_COUNT_NEW 16
+#define SORT_DESC      17
+#define SORT_FLAGGED   18
+#define SORT_PATH      19
+
 /* dgc: Sort & SortAux are shorts, so I'm bumping these bitflags up from
  * bits 4 & 5 to bits 8 & 9 to make room for more sort keys in the future. */
 #define SORT_MASK      0xff
@@ -50,6 +56,7 @@ WHERE short BrowserSort INITVAL (SORT_SUBJECT);
 WHERE short Sort INITVAL (SORT_DATE);
 WHERE short SortAux INITVAL (SORT_DATE); /* auxiliary sorting method */
 WHERE short SortAlias INITVAL (SORT_ALIAS);
+WHERE short SidebarSortMethod INITVAL (SORT_ORDER);
 
 /* FIXME: This one does not belong to here */
 WHERE short PgpSortKeys INITVAL (SORT_ADDRESS);