sup

A curses threads-with-tags style email client

sup.git

git clone https://supmua.dev/git/sup/
commit c1198c446f29e8220fa38abc7f965ee0f6366ca9
parent 21e41e9cc87e74b8a68557a983eb0aa1a0c01036
Author: Rich Lane <rlane@club.cc.cmu.edu>
Date:   Thu,  3 Jun 2010 19:04:16 -0700

Merge commit 'mainline/master'

Diffstat:
M HACKING | 4 ++--
M Rakefile | 2 +-
M bin/sup-dump | 4 ++--
M doc/FAQ.txt | 18 ++++++------------
M doc/NewUserGuide.txt | 25 ++++++++++---------------
M lib/sup/modes/thread-view-mode.rb | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
M lib/sup/source.rb | 3 ++-
M lib/sup/util.rb | 2 +-
M www/index.html | 6 ++++--
9 files changed, 75 insertions(+), 37 deletions(-)
diff --git a/HACKING b/HACKING
@@ -8,8 +8,8 @@ Invoke it like this:
 You'll have to install all gems mentioned in the Rakefile (look for the line
 setting p.extra_deps). If you're on a Debian or Debian-based system (e.g.
 Ubuntu), you'll have to make sure you have a complete Ruby installation,
-especially libssl-ruby. You will need libruby-devel, gcc, and make installed
-to build certain gems like Ferret. Gem install does not do a good job of
+especially libssl-ruby. You will need libruby-devel, gcc, and rake installed
+to build certain gems like Xapian. Gem install does not do a good job of
 detecting when these things are missing and the build fails.
 
 Rubygems also is particularly aggressive about picking up libraries from
diff --git a/Rakefile b/Rakefile
@@ -43,7 +43,7 @@ spec = Gem::Specification.new do |s|
   s.email = %q{wmorgan-sup@masanjin.net}
   s.summary = %q{A console-based email client with the best features of GMail, mutt, and emacs. Features full text search, labels, tagged operations, multiple buffers, recent contacts, and more.}
   s.homepage = %q{http://sup.rubyforge.org/}
-  s.description = %q{Sup is a console-based email client for people with a lot of email. It supports tagging, very fast full-text search, automatic contact-list management, and more. If you're the type of person who treats email as an extension of your long-term memory, Sup is for you.  Sup makes it easy to: - Handle massive amounts of email.  - Mix email from different sources: mbox files (even across different machines), Maildir directories, IMAP folders, POP accounts, and GMail accounts.  - Instantaneously search over your entire email collection. Search over body text, or use a query language to combine search predicates in any way.  - Handle multiple accounts. Replying to email sent to a particular account will use the correct SMTP server, signature, and from address.  - Add custom code to handle certain types of messages or to handle certain types of text within messages.  - Organize email with user-defined labels, automatically track recent contacts, and much more!  The goal of Sup is to become the email client of choice for nerds everywhere.}
+  s.description = %q{Sup is a console-based email client for people with a lot of email. It supports tagging, very fast full-text search, automatic contact-list management, and more. If you're the type of person who treats email as an extension of your long-term memory, Sup is for you.  Sup makes it easy to: - Handle massive amounts of email.  - Mix email from different sources: mbox files (even across different machines), Maildir directories, POP accounts, and GMail accounts.  - Instantaneously search over your entire email collection. Search over body text, or use a query language to combine search predicates in any way.  - Handle multiple accounts. Replying to email sent to a particular account will use the correct SMTP server, signature, and from address.  - Add custom code to handle certain types of messages or to handle certain types of text within messages.  - Organize email with user-defined labels, automatically track recent contacts, and much more!  The goal of Sup is to become the email client of choice for nerds everywhere.}
   s.files = SUP_FILES
   s.executables = SUP_EXECUTABLES
 
diff --git a/bin/sup-dump b/bin/sup-dump
@@ -10,8 +10,8 @@ $opts = Trollop::options do
 Dumps all message state from the sup index to standard out. You can
 later use sup-sync --restored --restore <filename> to recover the index.
 
-This tool is primarily useful in the event that a Ferret upgrade breaks
-the index format. This happened, for example, at Ferret version 0.11.
+This tool is primarily useful in the event that a Xapian upgrade breaks
+the index format.
 
 Usage:
   sup-dump > <filename>
diff --git a/doc/FAQ.txt b/doc/FAQ.txt
@@ -63,18 +63,18 @@ A: Run:
      sup-sync [<source>+] --restored --restore <dumpfile>
    where <dumpfile> was created as above.
 
-Q: Ferret crashed and I can't read my index. Luckily I made a state
+Q: Xapian crashed and I can't read my index. Luckily I made a state
    dump. What should I do?
 Q: How do I rebuild the index completely?
 A: Run:
-     rm -rf ~/.sup/ferret    # omg wtf
+     rm -rf ~/.sup/xapian    # omg wtf
      sup-sync --all-sources --all --restore <dumpfile>
    Voila! A brand new index.
 
 Q: I want to move messages from one source to another. (E.g., my
-   primary inbox is an IMAP server with a quota, and I want to move
-   some of those messages to local mbox files.) How do I do that while
-   preserving message state?
+   primary inbox is an mbox file, and I want to move some of those
+   messages to a Maildir.) How do I do that while preserving message
+   state?
 A: Move the messages from the source to the target using whatever tool
    you'd like. Mutt's a good one. :) Then run:
      sup-sync --changed <source1> <source2>
@@ -105,13 +105,7 @@ S: The current solution is to directly modify RubyMail. Change line 159 of
 P: I see this error:
      /usr/local/lib/ruby/1.8/yaml.rb:133:in `transfer': allocator undefined for Bignum (TypeError)
 S: You need to upgrade to Ruby 1.8.5. YAML in earlier versions can't
-   parse BigNums, but Sup relies on that for Maildir and IMAP.
-
-P: I see this error:
-     /usr/lib/ruby/1.8/net/imap.rb:204: uninitialized constant Net::IMAP::SSL (NameError)
-S: You need to install a package called libssl-ruby or something similar.
-   Or, don't use imaps:// sources. Ruby's IMAP library otherwise fails in
-   this completely uninformative manner.
+   parse BigNums, but Sup relies on that for Maildir.
 
 P: When I run Sup remotely and view an HTML attachment, an existing
    Firefox on the *local* machine is redirected to the attachment
diff --git a/doc/NewUserGuide.txt b/doc/NewUserGuide.txt
@@ -20,13 +20,13 @@ message labels), and all information necessary for searching and for
 threading messages. Sup only knows about messages in its index.
 
 We can add messages to the index by telling Sup about the "source"
-where the messages reside. Sources are things like IMAP folders, mbox
-folders, and maildir directories. Sup doesn't duplicate the actual
-message content in the index; it only stores whatever information is
-necessary for searching, threading and labelling. So when you search
-for messages or view your inbox, Sup talks only to the index (stored
-locally on disk). When you view a thread, Sup requests the full
-content of all the messages from the source.
+where the messages reside. Sources are things like mbox folders, and
+maildir directories. Sup doesn't duplicate the actual message content
+in the index; it only stores whatever information is necessary for
+searching, threading and labelling. So when you search for messages or
+view your inbox, Sup talks only to the index (stored locally on
+disk). When you view a thread, Sup requests the full content of all
+the messages from the source.
 
 The easiest way to set up all your sources is to run `sup-config`.
 This will interactively walk you through some basic configuration,
@@ -146,7 +146,8 @@ press '\' (backslash---forward slash is used for in-buffer search,
 following console conventions). Now type in your query (again, Ctrl-G to
 cancel at any point.) You can just type in arbitrary text, which will be
 matched on a per-word basis against the bodies of all email in the
-index, or you can make use of the full Ferret query syntax:
+index, or you can make use of the full Xapian query syntax
+(http://xapian.org/docs/queryparser.html):
 
 - Phrasal queries using double-quotes, e.g.: "three contiguous words"
 - Queries against a particular field using <field name>:<query>,
@@ -161,7 +162,7 @@ You can combine those all together. For example:
 
      label:ruby-talk subject:\[ANN\] -rails on:today
 
-Play around with the search, and see the Ferret documentation for
+Play around with the search, and see the Xapian documentation for
 details on more sophisticated queries (date ranges, "within n words",
 etc.)
 
@@ -206,9 +207,6 @@ Instead of using sup-config to add a new source, you can manually run
 
 - mbox://path/to/a/filename, for an mbox file on disk.
 - maildir://path/to/a/filename, for a maildir directory on disk.
-- imap://imap.server/folder for an unsecure IMAP folder.
-- imaps://secure.imap.server/folder for a secure IMAP folder.
-- mbox+ssh://remote.machine/path/to/a/filename for a remote mbox file.
 
 Before you add the source, you need make three decisions. The first is
 whether you want Sup to regularly poll this source for new messages.
@@ -227,9 +225,6 @@ lists that you don't want polluting your inbox.
 The final decision is whether you want any labels automatically
 applied to messages from this source. You can use `--labels` to do this.
 
-If Sup requires account information, e.g. for IMAP servers and remote
-mbox files, `sup-add` will ask for it.
-
 Now that you've added the source, let's import all the current
 messages from it, by running sup-sync with the source URI. You can
 specify `--archive` to automatically archive all messages in this
diff --git a/lib/sup/modes/thread-view-mode.rb b/lib/sup/modes/thread-view-mode.rb
@@ -3,7 +3,7 @@ module Redwood
 class ThreadViewMode < LineCursorMode
   ## this holds all info we need to lay out a message
   class MessageLayout
-    attr_accessor :top, :bot, :prev, :next, :depth, :width, :state, :color, :star_color, :orig_new
+    attr_accessor :top, :bot, :prev, :next, :depth, :width, :state, :color, :star_color, :orig_new, :toggled_state
   end
 
   class ChunkLayout
@@ -54,7 +54,9 @@ EOS
     k.add :edit_labels, "Edit or add labels for a thread", 'l'
     k.add :expand_all_quotes, "Expand/collapse all quotes in a message", 'o'
     k.add :jump_to_next_open, "Jump to next open message", 'n'
+    k.add :jump_to_next_and_open, "Jump to next message and open", "\C-n"
     k.add :jump_to_prev_open, "Jump to previous open message", 'p'
+    k.add :jump_to_prev_and_open, "Jump to previous message and open", "\C-p"
     k.add :align_current_message, "Align current message in buffer", 'z'
     k.add :toggle_starred, "Star or unstar message", '*'
     k.add :toggle_new, "Toggle unread/read status of message", 'N'
@@ -129,6 +131,7 @@ EOS
       next unless m
       earliest ||= m
       @layout[m].state = initial_state_for m
+      @layout[m].toggled_state = false
       @layout[m].color = altcolor ? :alternate_patina_color : :message_patina_color
       @layout[m].star_color = altcolor ? :alternate_starred_patina_color : :starred_patina_color
       @layout[m].orig_new = m.has_label? :read
@@ -440,6 +443,29 @@ EOS
     end
   end
 
+  def jump_to_next_and_open
+    return continue_search_in_buffer if in_search? # err.. don't know why im doing this
+
+    m = (curpos ... @message_lines.length).argfind { |i| @message_lines[i] }
+    return unless m
+
+    if @layout[m].toggled_state == true
+      @layout[m].state = :closed
+      @layout[m].toggled_state = false
+      update
+    end
+
+    nextm = @layout[m].next
+    if @layout[nextm].state == :closed
+      @layout[nextm].state = :open
+      @layout[nextm].toggled_state = true
+    end
+
+    jump_to_message nextm if nextm
+
+    update if @layout[nextm].toggled_state
+  end
+
   def jump_to_next_open force_alignment=nil
     return continue_search_in_buffer if in_search? # hack: allow 'n' to apply to both operations
     m = (curpos ... @message_lines.length).argfind { |i| @message_lines[i] }
@@ -456,6 +482,26 @@ EOS
     jump_to_message m, true
   end
 
+  def jump_to_prev_and_open force_alignment=nil
+    m = (0 .. curpos).to_a.reverse.argfind { |i| @message_lines[i] }
+    return unless m
+
+    if @layout[m].toggled_state == true
+      @layout[m].state = :closed
+      @layout[m].toggled_state = false
+      update
+    end
+
+    nextm = @layout[m].prev
+    if @layout[nextm].state == :closed
+      @layout[nextm].state = :open
+      @layout[nextm].toggled_state = true
+    end
+
+    jump_to_message nextm if nextm
+    update if @layout[nextm].toggled_state
+  end
+
   def jump_to_prev_open
     m = (0 .. curpos).to_a.reverse.argfind { |i| @message_lines[i] } # bah, .to_a
     return unless m
diff --git a/lib/sup/source.rb b/lib/sup/source.rb
@@ -63,7 +63,8 @@ class Source
   ##
   ## dirty? means cur_offset has changed, so the source info needs to
   ## be re-saved to sources.yaml.
-  bool_reader :usual, :archived, :dirty
+  bool_reader :dirty
+  bool_accessor :usual, :archived
   attr_reader :uri, :cur_offset
   attr_accessor :id
 
diff --git a/lib/sup/util.rb b/lib/sup/util.rb
@@ -302,7 +302,7 @@ class String
   end
 
   ## takes a list of words, and returns an array of symbols.  typically used in
-  ## Sup for translating Ferret's representation of a list of labels (a string)
+  ## Sup for translating Xapian's representation of a list of labels (a string)
   ## to an array of label symbols.
   ##
   ## split_on will be passed to String#split, so you can leave this nil for space.
diff --git a/www/index.html b/www/index.html
@@ -54,8 +54,10 @@
 			</li>
 
 			<li>
-			Mix email from different sources: mbox files, IMAP folders,
-            and Maildirs, across multiple machines.</li>
+			Mix email from different sources: mbox files and maildirs.
+			For remote sources (IMAP, IMAPS, ssh+file), use another
+			tool (offlineimap, fetchmail, rsync) to grab local copies.
+			</li>
 
 			<li>
 			Instantaneously search over your entire email collection.