commit 4d7b7c7ba91568d8001ba369c379c57cc8608892
parent d65aef0766c3da83e2cb7fe2198ea5d6461d855e
Author: Eric Weikl <eric.weikl@gmx.net>
Date: Thu, 9 May 2013 20:34:31 +0200
Merge branch 'sup-heliotrope/develop' into maildir-sync
Diffstat:
30 files changed, 78 insertions(+), 1227 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,7 +1,13 @@
# i use vi
*.swp
-.ditz-config
# i use emacs
*~
-# i use rake package task
+# artifact
pkg/
+*.gem
+# i have accidently added this one one too many times
+sup-exception-log.txt
+
+# bundler stuff
+Gemfile.lock
+.bundle
diff --git a/.travis.yml b/.travis.yml
@@ -9,8 +9,6 @@ before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq uuid-dev uuid libncursesw5-dev libncursesw5
-gemfile: Gemfile.ci
-
script: bundle exec rake travis
matrix:
diff --git a/Gemfile b/Gemfile
@@ -0,0 +1,3 @@
+source 'http://rubygems.org/'
+
+gemspec
diff --git a/Gemfile.ci b/Gemfile.ci
@@ -1,19 +0,0 @@
-# Until we figure out how to install deps in Travis env in a modern, DRY
-# way, just use this.
-
-source :rubygems
-
-# Original runtime deps
-gem "xapian-full-alaveteli", "~> 1.2"
-gem "ncursesw"
-gem "rmail", ">= 0.17"
-gem "highline"
-gem "trollop", ">= 1.12"
-gem "lockfile"
-gem "mime-types", "~> 1"
-gem "gettext"
-
-# required by Travis
-group :development, :test do
- gem "rake"
-end
diff --git a/README.txt b/README.txt
@@ -88,16 +88,14 @@ Current limitations which will be fixed:
== REQUIREMENTS:
- - xapian-full >= 1.1.3.2
- - ncurses >= 0.9.1
+ - xapian-full-alaveteli >= 1.2
+ - ncursesw-sup >= 1.3.1
- rmail >= 0.17
- highline
- - net-ssh
- trollop >= 1.12
- lockfile
- mime-types
- gettext
- - fastthread
== INSTALL:
diff --git a/Rakefile b/Rakefile
@@ -1,78 +1,16 @@
-## is there really no way to make a rule for this?
-WWW_FILES = %w(www/index.html README.txt doc/Philosophy.txt doc/FAQ.txt doc/NewUserGuide.txt www/main.css)
-
-rule 'ss?.png' => 'ss?-small.png' do |t|
-end
-SCREENSHOTS = FileList["www/ss?.png"]
-SCREENSHOTS_SMALL = []
-SCREENSHOTS.each do |fn|
- fn =~ /ss(\d+)\.png/
- sfn = "www/ss#{$1}-small.png"
- file sfn => [fn] do |t|
- sh "cat #{fn} | pngtopnm | pnmscale -xysize 320 240 | pnmtopng > #{sfn}"
- end
- SCREENSHOTS_SMALL << sfn
-end
-
-task :upload_webpage => WWW_FILES do |t|
- sh "rsync -essh -cavz #{t.prerequisites * ' '} wmorgan@rubyforge.org:/var/www/gforge-projects/sup/"
-end
-
-task :upload_webpage_images => (SCREENSHOTS + SCREENSHOTS_SMALL) do |t|
- sh "rsync -essh -cavz #{t.prerequisites * ' '} wmorgan@rubyforge.org:/var/www/gforge-projects/sup/"
-end
-
-# vim: syntax=ruby
-# -*- ruby -*-
-task :upload_report do |t|
- sh "ditz html ditz"
- sh "rsync -essh -cavz ditz wmorgan@rubyforge.org:/var/www/gforge-projects/sup/"
-end
-
require 'rubygems'
require 'rake/testtask'
Rake::TestTask.new(:test) do |test|
test.libs << 'test'
- test.test_files = FileList.new('test/test_*.rb').exclude(/test\/test_server.rb/)
+ test.test_files = FileList.new('test/test_*.rb')
test.verbose = true
end
-$:.push "lib"
require 'rubygems/package_task'
-unless Kernel.respond_to?(:require_relative)
- require "./sup-files"
- require "./sup-version"
-else
- require_relative "sup-files"
- require_relative "sup-version"
-end
-
-spec = Gem::Specification.new do |s|
- s.name = %q{sup}
- s.version = SUP_VERSION
- s.date = Time.now.strftime "%Y-%m-%d"
- s.authors = ["William Morgan"]
- 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{https://github.com/sup-heliotrope/sup/wiki}
- 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
-
- s.add_dependency "xapian-full-alaveteli", "~> 1.2"
- s.add_dependency "ncursesw"
- s.add_dependency "rmail", ">= 0.17"
- s.add_dependency "highline"
- s.add_dependency "trollop", ">= 1.12"
- s.add_dependency "lockfile"
- s.add_dependency "mime-types", "~> 1"
- s.add_dependency "gettext"
-end
-
-Gem::PackageTask.new(spec) do |pkg|
- pkg.need_tar = true
+Gem::PackageTask.new(Redwood::Gemspec) do |pkg|
+ pkg.need_tar = true
end
-task :tarball => ["pkg/sup-#{SUP_VERSION}.tgz"]
task :travis => [:test, :gem]
diff --git a/bin/sup b/bin/sup
@@ -2,13 +2,7 @@
require 'rubygems'
-no_ncursesw = false
-begin
- require 'ncursesw'
-rescue LoadError
- require 'ncurses'
- no_ncursesw = true
-end
+require 'ncursesw'
no_gpgme = false
begin
@@ -28,10 +22,6 @@ if ENV['SUP_PROFILE']
RubyProf.start
end
-if no_ncursesw
- info "No 'ncursesw' gem detected. Install it for wide character support."
-end
-
if no_gpgme
info "No 'gpgme' gem detected. Install it for email encryption, decryption and signatures."
end
diff --git a/bin/sup-cmd b/bin/sup-cmd
@@ -1,138 +0,0 @@
-#!/usr/bin/env ruby
-require 'rubygems'
-require 'trollop'
-require 'sup'
-require 'sup/client'
-require 'pp'
-require 'yaml'
-include Redwood
-
-SUB_COMMANDS = %w(query count label add)
-global_opts = Trollop::options do
- #version = "sup-cmd (sup #{Redwood::VERSION})"
- banner <<EOS
-Connect to a running sup-server.
-
-Usage:
- sup-cmd [global options] command [options]
-
- Valid commands: #{SUB_COMMANDS * ', '}
-
- Global options:
-EOS
-
- opt :host, "server address", :type => :string, :default => 'localhost', :short => 'o'
- opt :port, "server port", :type => :int, :default => 4300
- opt :socket, "unix domain socket path", :type => :string, :default => nil
- opt :verbose
-
- conflicts :host, :socket
- conflicts :port, :socket
-
- stop_on SUB_COMMANDS
-end
-
-cmd = ARGV.shift
-cmd_opts = case cmd
-when "query"
- Trollop.options do
- opt :offset, "Offset", :default => 0, :type => :int
- opt :limit, "Limit", :type => :int
- opt :raw, "Retrieve raw message text", :default => false
- end
-when "count"
- Trollop.options do
- end
-when "label"
- Trollop.options do
- opt :add_labels, "Labels to add", :default => ""
- opt :remove_labels, "Labels to remove", :default => ""
- end
-when "add"
- Trollop.options do
- opt :labels, "Labels separated by commas", :default => ""
- opt :mbox, "Treat input files as mboxes", :default => false
- end
-else
- Trollop::die "unrecognized command #{cmd.inspect}"
-end
-
-class SupCmd < Redwood::Client
- def initialize cmd, args, opts
- @cmd = cmd
- @opts = opts
- @args = args
- super()
- end
-
- def get_query
- @args.first or fail "query argument required"
- end
-
- def connection_established
- case @cmd
- when "query"
- query get_query, @opts[:offset], @opts[:limit], @opts[:raw] do |result|
- if result
- puts YAML.dump(result['summary'])
- puts YAML.dump(result['raw']) if @opts[:raw]
- else
- close_connection
- end
- end
- when "count"
- count(get_query) do |x|
- puts x
- close_connection
- end
- when "label"
- label get_query, @opts[:remove_labels].split(','), @opts[:add_labels].split(',') do
- close_connection
- end
- when "add"
- ARGF.binmode
- labels = @opts[:labels].split(',')
- get_message = lambda do
- return ARGF.gets(nil) unless @opts[:mbox]
- str = ""
- l = ARGF.gets
- str << l until ARGF.closed? || ARGF.eof? || MBox::is_break_line?(l = ARGF.gets)
- str.empty? ? nil : str
- end
- i_s = i = 0
- t = Time.now
- while raw = get_message[]
- i += 1
- t_d = Time.now - t
- if t_d >= 5
- i_d = i - i_s
- puts "indexed #{i} messages (#{i_d/t_d} m/s)" if global_opts[:verbose]
- t = Time.now
- i_s = i
- end
- add raw, labels do
- close_connection
- end
- end
- else
- fail "#{@cmd} command unimplemented"
- close_connection
- end
- end
-
- def unbind
- EM.stop
- end
-end
-
-
-EM.run do
- if global_opts[:socket]
- EM.connect global_opts[:socket], SupCmd, cmd, ARGV, cmd_opts.merge(global_opts)
- else
- EM.connect global_opts[:host], global_opts[:port], SupCmd, cmd, ARGV, cmd_opts.merge(global_opts)
- end
-end
-
-exit 0
-
diff --git a/bin/sup-server b/bin/sup-server
@@ -1,44 +0,0 @@
-#!/usr/bin/env ruby
-require 'rubygems'
-require 'trollop'
-require 'sup'
-require 'sup/server'
-require 'pp'
-require 'yaml'
-include Redwood
-
-global_opts = Trollop::options do
- #version = "sup-cmd (sup #{Redwood::VERSION})"
- banner <<EOS
-Interact with a Sup index.
-
-Usage:
- sup-server [options]
-EOS
-
- opt :host, "address to listen on", :type => :string, :default => 'localhost', :short => 'o'
- opt :port, "port to listen on", :type => :int, :default => 4300
- opt :verbose
-end
-
-Redwood.start
-Index.init
-Index.lock_interactively or exit
-begin
- if(s = Redwood::SourceManager.source_for SentManager.source_uri)
- SentManager.source = s
- else
- Redwood::SourceManager.add_source SentManager.default_source
- end
-
- Index.load
-
- EM.run do
- EM.start_server global_opts[:host], global_opts[:port],
- Redwood::Server, Index.instance
- EM.next_tick { puts "ready" }
- end
-
-ensure
- Index.unlock
-end
diff --git a/contrib/colorpicker.rb b/contrib/colorpicker.rb
@@ -1,10 +1,6 @@
require 'rubygems'
-begin
- require 'ncursesw'
-rescue LoadError
- require 'ncurses'
-end
+require 'ncursesw'
Ncurses.initscr
Ncurses.noecho
diff --git a/lib/sup.rb b/lib/sup.rb
@@ -2,7 +2,9 @@ require 'rubygems'
require 'syck'
require 'yaml'
-YAML::ENGINE.yamler = 'syck'
+if YAML.const_defined? :ENGINE
+ YAML::ENGINE.yamler = 'syck'
+end
require 'zlib'
require 'thread'
@@ -42,8 +44,6 @@ class Module
end
module Redwood
- VERSION = "git"
-
BASE_DIR = ENV["SUP_BASE"] || File.join(ENV["HOME"], ".sup")
CONFIG_FN = File.join(BASE_DIR, "config.yaml")
COLOR_FN = File.join(BASE_DIR, "colors.yaml")
@@ -367,6 +367,7 @@ EOS
:load_config, :managers
end
+require 'sup/version'
require "sup/util"
require "sup/hook"
require "sup/time"
diff --git a/lib/sup/buffer.rb b/lib/sup/buffer.rb
@@ -1,11 +1,7 @@
require 'etc'
require 'thread'
-begin
- require 'ncursesw'
-rescue LoadError
- require 'ncurses'
-end
+require 'ncursesw'
if defined? Ncurses
module Ncurses
diff --git a/lib/sup/client.rb b/lib/sup/client.rb
@@ -1,92 +0,0 @@
-require 'sup/protocol'
-
-module Redwood
-
-class Client < EM::P::RedwoodClient
- def initialize *a
- @next_tag = 1
- @cbs = {}
- super *a
- end
-
- def mktag &b
- @next_tag.tap do |x|
- @cbs[x] = b
- @next_tag += 1
- end
- end
-
- def rmtag tag
- @cbs.delete tag
- end
-
- def query qstr, offset, limit, raw, &b
- tag = mktag do |type,tag,args|
- if type == 'message'
- b.call args
- else
- fail unless type == 'done'
- b.call nil
- rmtag tag
- end
- end
- send_message 'query', tag,
- 'query' => qstr,
- 'offset' => offset,
- 'limit' => limit,
- 'raw' => raw
- end
-
- def count qstr, &b
- tag = mktag do |type,tag,args|
- b.call args['count']
- rmtag tag
- end
- send_message 'count', tag,
- 'query' => qstr
- end
-
- def label qstr, add, remove, &b
- tag = mktag do |type,tag,args|
- b.call
- rmtag tag
- end
- send_message 'label', tag,
- 'query' => qstr,
- 'add' => add,
- 'remove' => remove
- end
-
- def add raw, labels, &b
- tag = mktag do |type,tag,args|
- b.call
- rmtag tag
- end
- send_message 'add', tag,
- 'raw' => raw,
- 'labels' => labels
- end
-
- def thread msg_id, raw, &b
- tag = mktag do |type,tag,args|
- if type == 'message'
- b.call args
- else
- fail unless type == 'done'
- b.call nil
- rmtag tag
- end
- end
-
- send_message 'thread', tag,
- 'message_id' => msg_id,
- 'raw' => raw
- end
-
- def receive_message type, tag, args
- cb = @cbs[tag] or fail "invalid tag #{tag.inspect}"
- cb[type, tag, args]
- end
-end
-
-end
diff --git a/lib/sup/protocol.rb b/lib/sup/protocol.rb
@@ -1,161 +0,0 @@
-require 'eventmachine'
-require 'socket'
-require 'stringio'
-require 'yajl'
-
-class EM::P::Redwood < EM::Connection
- VERSION = 1
- ENCODINGS = %w(marshal json)
-
- attr_reader :debug
-
- def initialize *args
- @state = :negotiating
- @version_buf = ""
- @debug = false
- super
- end
-
- def receive_data data
- if @state == :negotiating
- @version_buf << data
- if i = @version_buf.index("\n")
- l = @version_buf.slice!(0..i)
- receive_version *parse_version(l.strip)
- x = @version_buf
- @version_buf = nil
- @state = :established
- connection_established
- receive_data x
- end
- else
- @filter.decode(data).each do |msg|
- puts "#{self.class.name} received: #{msg.inspect}" if @debug
- validate_message *msg
- receive_message *msg
- end
- end
- end
-
- def connection_established
- end
-
- def send_version encodings, extensions
- fail if encodings.empty?
- send_data "Redwood #{VERSION} #{encodings * ','} #{extensions.empty? ? :none : (extensions * ',')}\n"
- end
-
- def send_message type, tag, params={}
- fail "attempted to send message during negotiation" unless @state == :established
- puts "#{self.class.name} sent: #{[type, tag, params].inspect}" if @debug
- validate_message type, tag, params
- send_data @filter.encode([type,tag,params])
- end
-
- def receive_version l
- fail "unimplemented"
- end
-
- def receive_message type, tag, params
- fail "unimplemented"
- end
-
-private
-
- def validate_message type, tag, params
- fail unless type.is_a? String or type.is_a? Symbol
- fail unless tag.is_a? String or tag.is_a? Integer
- fail unless params.is_a? Hash
- end
-
- def parse_version l
- l =~ /^Redwood\s+(\d+)\s+([\w,]+)\s+([\w,]+)$/ or fail "unexpected banner #{l.inspect}"
- version, encodings, extensions = $1.to_i, $2, $3
- encodings = encodings.split ','
- extensions = extensions.split ','
- extensions = [] if extensions == ['none']
- fail unless version == VERSION
- fail if encodings.empty?
- [encodings, extensions]
- end
-
- def create_filter encoding
- case encoding
- when 'json' then JSONFilter.new
- when 'marshal' then MarshalFilter.new
- else fail "unknown encoding #{encoding.inspect}"
- end
- end
-
- class JSONFilter
- def initialize
- @parser = Yajl::Parser.new :check_utf8 => false
- end
-
- def decode chunk
- parsed = []
- @parser.on_parse_complete = lambda { |o| parsed << o }
- @parser << chunk
- parsed
- end
-
- def encode *os
- os.inject('') { |s, o| s << Yajl::Encoder.encode(o) }
- end
- end
-
- class MarshalFilter
- def initialize
- @buf = ''
- @state = :prefix
- @size = 0
- end
-
- def decode chunk
- received = []
- @buf << chunk
-
- begin
- if @state == :prefix
- break unless @buf.size >= 4
- prefix = @buf.slice!(0...4)
- @size = prefix.unpack('N')[0]
- @state = :data
- end
-
- fail unless @state == :data
- break if @buf.size < @size
- received << Marshal.load(@buf.slice!(0...@size))
- @state = :prefix
- end until @buf.empty?
-
- received
- end
-
- def encode o
- data = Marshal.dump o
- [data.size].pack('N') + data
- end
- end
-end
-
-class EM::P::RedwoodServer < EM::P::Redwood
- def post_init
- send_version ENCODINGS, []
- end
-
- def receive_version encodings, extensions
- fail unless encodings.size == 1
- fail unless ENCODINGS.member? encodings.first
- @filter = create_filter encodings.first
- end
-end
-
-class EM::P::RedwoodClient < EM::P::Redwood
- def receive_version encodings, extensions
- encoding = (ENCODINGS & encodings).first
- fail unless encoding
- @filter = create_filter encoding
- send_version [encoding], []
- end
-end
diff --git a/lib/sup/server.rb b/lib/sup/server.rb
@@ -1,116 +0,0 @@
-require 'sup/protocol'
-
-module Redwood
-
-class Server < EM::P::RedwoodServer
- def initialize index
- super
- @index = index
- end
-
- def receive_message type, tag, params
- if respond_to? :"request_#{type}"
- send :"request_#{type}", tag, params
- else
- send_message 'error', tag, 'description' => "invalid request type #{type.inspect}"
- end
- end
-
- def request_query tag, a
- q = @index.parse_query a['query']
- query q, a['offset'], a['limit'], a['raw'] do |r|
- send_message 'message', tag, r
- end
- send_message 'done', tag
- end
-
- def request_count tag, a
- q = @index.parse_query a['query']
- c = count q
- send_message 'count', tag, 'count' => c
- end
-
- def request_label tag, a
- q = @index.parse_query a['query']
- label q, a['add'], a['remove']
- send_message 'done', tag
- end
-
- def request_add tag, a
- add a['raw'], a['labels']
- send_message 'done', tag
- end
-
- def request_thread tag, a
- thread a['message_id'], a['raw'] do |r|
- send_message 'message', tag, r
- end
- send_message 'done', tag
- end
-
-private
-
- def result_from_message m, raw
- mkperson = lambda { |p| { :email => p.email, :name => p.name } }
- {
- 'summary' => {
- 'message_id' => m.id,
- 'date' => m.date,
- 'from' => mkperson[m.from],
- 'to' => m.to.map(&mkperson),
- 'cc' => m.cc.map(&mkperson),
- 'bcc' => m.bcc.map(&mkperson),
- 'subject' => m.subj,
- 'refs' => m.refs,
- 'replytos' => m.replytos,
- 'labels' => m.labels.map(&:to_s),
- },
- 'raw' => raw ? m.raw_message : nil,
- }
- end
-
- def query query, offset, limit, raw
- c = 0
- @index.each_message query do |m|
- next if c < offset
- break if c >= offset + limit if limit
- yield result_from_message(m, raw)
- c += 1
- end
- nil
- end
-
- def count query
- @index.num_results_for query
- end
-
- def label query, remove_labels, add_labels
- @index.each_message query do |m|
- remove_labels.each { |l| m.remove_label l }
- add_labels.each { |l| m.add_label l }
- @index.update_message_state m
- end
- nil
- end
-
- def add raw, labels
- SentManager.source.store_message Time.now, "test@example.com" do |io|
- io.write raw
- end
- PollManager.poll_from SentManager.source do |sym,m,old_m,progress|
- next unless sym == :add
- m.labels = labels
- end
- nil
- end
-
- def thread msg_id, raw
- msg = @index.build_message msg_id
- @index.each_message_in_thread_for msg do |id, builder|
- m = builder.call
- yield result_from_message(m, raw)
- end
- end
-end
-
-end
diff --git a/lib/sup/source.rb b/lib/sup/source.rb
@@ -168,7 +168,7 @@ module SerializeLabelsNicely
end
def after_unmarshal!
- @labels = Set.new(@labels.map { |s| s.to_sym })
+ @labels = Set.new(@labels.to_a.map { |s| s.to_sym })
end
end
diff --git a/lib/sup/version.rb b/lib/sup/version.rb
@@ -0,0 +1,3 @@
+module Redwood
+ VERSION = "git"
+end
diff --git a/protocol.md b/protocol.md
@@ -1,168 +0,0 @@
-Redwood Protocol
-================
-
-The server begins by sending a line of the form `Redwood <ver> <encodings>
-<extensions>`, where `ver` is the major protocol version (1), encodings is a
-comma-separated list of supported message encodings (e.g. `json,bert,marshal`),
-and `extensions` is a comma-separated list of protocol extensions. The server
-must advertise at least one encoding. A zero-length list of extensions is
-represented by `none`. The client replies in the same format, with the
-restrictions that the protocol version must match, `encodings` and `extensions`
-must be subsets of what the server advertised, and there must be exactly 1
-encoding specified.
-
-Requests and responses are represented as `[type, params]`, where `type`
-is a lowercase string corresponding to one of the message types specified
-below and `params` is a dictionary with string keys.
-
-Requests
---------
-
-There may be zero or more replies to a request. Multiple requests may be
-issued concurrently. There is an implicit, optional, opaque `tag` parameter to
-every request which will be returned in all replies to the request to
-aid clients in keeping multiple requests in flight. `tag` may be an
-arbitrary datastructure and for the purposes of Cancel defaults to nil.
-
-### Query
-Send a Message response for each hit on `query` starting at `offset`
-and sending a maximum of `limit` Messages responses. `raw` controls
-whether the raw message text is included in the response.
-
-#### Parameters
-* `query`: Query
-* `offset`: int
-* `limit`: int
-* `raw`: boolean
-
-#### Responses
-* multiple Message
-* one Done after all Messages
-
-
-### Count
-Send a count reply with the number of hits for `query`.
-
-#### Parameters
-* `query`: Query
-
-#### Responses
-* one Count
-
-
-### Label
-Modify the labels on all messages matching `query`. First removes the
-labels in `remove` then adds those in `add`.
-
-#### Parameters
-* `query`: Query
-* `add`: string list
-* `remove`: string list
-
-#### Responses
-* one Done
-
-
-### Add
-Add a message to the database. `raw` is the normal RFC 2822 message text.
-
-#### Parameters
-* `raw`: string
-* `labels`: string list
-
-#### Responses
-* one Done
-
-
-### Stream
-Sends a Message response whenever a new message that matches `query` is
-added with the Add request. This request will not terminate until a
-corresponding Cancel request is sent.
-
-#### Parameters
-* `query`: Query
-
-#### Responses
-multiple Message
-
-
-### Cancel
-Cancels all active requests with tag `target`. This is only required to
-be implemented for the Stream request.
-
-#### Parameters
-* `target`: string
-
-#### Responses
-one Done
-
-
-
-Responses
----------
-
-### Done
-Signifies that a request has completed successfully.
-
-
-### Message
-Represents a query result. If `raw` is present it is the raw message
-text that was previously a parameter to the Add request.
-
-#### Parameters
-* `summary`: Summary
-* `raw`: optional string
-
-
-### Count
-`count` is the number of messages matched.
-
-#### Parameters
-* `count`: int
-
-
-### Error
-
-#### Parameters
-* `type`: string
-* `message`: string
-
-
-
-Datatypes
----------
-
-### Query
-Recursive prefix-notation datastructure describing a boolean condition.
-Where `a` and `b` are Queries and `field` and `value` are strings, a
-Query can be any of the following:
-
-* `[:and, a, b, ...]`
-* `[:or, a, b, ...]`
-* `[:not, a, b]`
-* `[:term, field, value]`
-
-
-### Summary
-* `message_id`: string
-* `date`: time
-* `from`: Person
-* `to`, `cc`, `bcc`: Person list
-* `subject`: string
-* `refs`: string list
-* `replytos`: string list
-* `labels`: string list
-
-
-### Person
-* `name`: string
-* `email`: string
-
-
-TODO
-----
-
-* Protocol negotiation
- - Version
- - Compression (none, gzip, ...)
-* Specify string encodings
diff --git a/sup-files.rb b/sup-files.rb
@@ -1,11 +0,0 @@
-SUP_LIB_DIRS = %w(lib lib/sup lib/sup/modes)
-SUP_EXECUTABLES = %w(sup sup-add sup-cmd sup-config sup-dump sup-import-dump sup-recover-sources sup-server sup-sync sup-sync-back sup-tweak-labels)
-SUP_EXTRA_FILES = %w(CONTRIBUTORS README.txt LICENSE History.txt ReleaseNotes)
-SUP_FILES =
- SUP_EXTRA_FILES +
- SUP_EXECUTABLES.map { |f| "bin/#{f}" } +
- SUP_LIB_DIRS.map { |d| Dir["#{d}/*.rb"] }.flatten
-
-if $0 == __FILE__ # if executed from commandline
- puts SUP_FILES
-end
diff --git a/sup-version.rb b/sup-version.rb
@@ -1,15 +0,0 @@
-## allow people who use development versions by running "rake gem"
-## and installing the resulting gem it to be able to do this. (gem
-## versions must be in dotted-digit notation only and can be passed
-## with the REL environment variable to "rake gem").
-SUP_VERSION = if ENV['REL']
- ENV['REL']
-else
- $:.unshift 'lib' # force loading from ./lib/ if it exists
- require 'sup'
- if Redwood::VERSION == "git"
- "999"
- else
- Redwood::VERSION
- end
-end
diff --git a/sup.gemspec b/sup.gemspec
@@ -0,0 +1,51 @@
+lib = File.expand_path("../lib", __FILE__)
+$:.unshift(lib) unless $:.include?(lib)
+
+require 'sup/version'
+
+# Files
+SUP_EXECUTABLES = %w(sup sup-add sup-config sup-dump sup-import-dump
+ sup-recover-sources sup-sync sup-sync-back sup-tweak-labels)
+SUP_EXTRA_FILES = %w(CONTRIBUTORS README.txt LICENSE History.txt ReleaseNotes)
+SUP_FILES =
+ SUP_EXTRA_FILES +
+ SUP_EXECUTABLES.map { |f| "bin/#{f}" } +
+ Dir["lib/**/*.rb"]
+
+
+module Redwood
+ Gemspec = Gem::Specification.new do |s|
+ s.name = "sup"
+ s.version = ENV["REL"] || (::Redwood::VERSION == "git" ? "999" : ::Redwood::VERSION)
+ s.date = Time.now.strftime "%Y-%m-%d"
+ s.authors = ["William Morgan", "Gaute Hope", "Hamish Downer", "Matthieu Rakotojaona"]
+ s.email = "sup-talk@rubyforge.org"
+ s.summary = "A console-based email client with the best features of GMail, mutt and Emacs"
+ s.homepage = "https://github.com/sup-heliotrope/sup/wiki"
+ s.description = <<-DESC
+ Sup is a console-based email client for people with a lot of email.
+
+ - Handling mail from multiple mbox and Maildir sources
+ - GMail-like archiving and tagging
+ - Blazing fast full-text search with a rich query language
+ - Multiple accounts - pick the right one when sending mail
+ - Ruby-programmable hooks
+ - Automatically tracking recent contacts
+DESC
+ s.license = 'GPL-2'
+ s.files = SUP_FILES
+ s.executables = SUP_EXECUTABLES
+
+ s.add_dependency "xapian-full-alaveteli", "~> 1.2"
+ s.add_dependency "ncursesw-sup", "~> 1.3", ">= 1.3.1"
+ s.add_dependency "rmail", ">= 0.17"
+ s.add_dependency "highline"
+ s.add_dependency "trollop", ">= 1.12"
+ s.add_dependency "lockfile"
+ s.add_dependency "mime-types", "~> 1"
+ s.add_dependency "gettext"
+
+ s.add_development_dependency "bundler", "~> 1.3"
+ s.add_development_dependency "rake"
+ end
+end
diff --git a/test/test_server.rb b/test/test_server.rb
@@ -1,106 +0,0 @@
-#!/usr/bin/ruby
-# encoding: utf-8
-
-require 'test/unit'
-require 'iconv'
-require 'stringio'
-require 'tmpdir'
-require 'fileutils'
-require 'thread'
-require 'eventmachine'
-require 'sup'
-require 'sup/server'
-
-Thread.abort_on_exception = true
-
-module EM
- # Run the reactor in a new thread. This is useful for using EventMachine
- # alongside synchronous code. It is recommended to use EM.error_handler to
- # detect when an exception terminates the reactor thread.
- def self.spawn_reactor_thread
- fail "reactor already started" if EM.reactor_running?
- q = ::Queue.new
- Thread.new { EM.run { q << nil } }
- q.pop
- end
-
- # Stop the reactor and wait for it to finish. This is the counterpart to #spawn_reactor_thread.
- def self.kill_reactor_thread
- fail "reactor is not running" unless EM.reactor_running?
- fail "current thread is running the reactor" if EM.reactor_thread?
- EM.stop
- EM.reactor_thread.join
- end
-end
-
-class QueueingClient < EM::P::RedwoodClient
- def initialize
- super
- @q = Queue.new
- @readyq = Queue.new
- end
-
- def receive_message type, tag, params
- @q << [type, tag, params]
- end
-
- def connection_established
- @readyq << nil
- end
-
- def wait_until_ready
- @readyq.pop
- end
-
- def read
- @q.pop
- end
-
- alias write send_message
-end
-
-class TestServer < Test::Unit::TestCase
- def setup
- port = rand(1000) + 30000
- EM.spawn_reactor_thread
- @path = Dir.mktmpdir
- socket_path = File.join(@path, 'socket')
- Redwood::HookManager.init File.join(@path, 'hooks')
- Redwood::SourceManager.init
- Redwood::SourceManager.load_sources File.join(@path, 'sources.yaml')
- Redwood::Index.init @path
- Redwood::SearchManager.init File.join(@path, 'searches')
- Redwood::Index.load
- @server = EM.start_server socket_path,
- Redwood::Server, Redwood::Index.instance
- @client = EM.connect socket_path, QueueingClient
- @client.wait_until_ready
- end
-
- def teardown
- FileUtils.rm_r @path if passed?
- puts "not cleaning up #{@path}" unless passed?
- %w(Index SearchManager SourceManager HookManager).each do |x|
- Redwood.const_get(x.to_sym).deinstantiate!
- end
- EM.kill_reactor_thread
- end
-
- def test_invalid_request
- @client.write 'foo', '1'
- check @client.read, 'error', '1'
- end
-
- def test_query
- @client.write 'query', '1', 'query' => 'type:mail'
- check @client.read, 'done', '1'
- end
-
- def check resp, type, tag, args={}
- assert_equal type.to_s, resp[0]
- assert_equal tag.to_s, resp[1]
- args.each do |k,v|
- assert_equal v, resp[2][k.to_s]
- end
- end
-end
diff --git a/www/index.html b/www/index.html
@@ -1,223 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
- <head>
- <title>Sup</title>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <link rel="stylesheet" href="main.css" type="text/css" />
- </head>
-
- <body>
- <h1>Sup</h1>
-
- <blockquote>
- “Finally a mail client that does what we want, how we want it.”
- </blockquote>
-
- <blockquote>
- “Every other client we've tried is intolerable.”
- </blockquote>
-
- <blockquote>
- “It's just what I wanted, but I hadn't realized what I wanted until I saw it.”
- </blockquote>
-
- <blockquote>
- “Sup is almost to the point where I could jump ship from mutt.”
- </blockquote>
-
- <blockquote>
- “I was previously intrigued by a gmail-styled
- mutt-killer written in Ruby, but having actually spent a few
- hours reading the docs, and trying out all the keys, and
- reading the docs again, and trying the keys out again, and then
- actually engaging in a bunch of practice usage runs, I now
- officially can't fucking wait for the future of this thing; it
- has my full attention.”
- </blockquote>
-
- <p>
- 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, custom code insertion via a hook system, and more.
- If you're the type of person who treats email as an extension of your
- long-term memory, Sup is for you.
- </p>
-
- <p>
- Sup makes it easy to:
- </p>
-
- <ul>
- <li>
- Handle massive amounts of email.
- </li>
-
- <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.
- Search over body text, or use a query language to combine
- search predicates in any way.
- </li>
-
- <li>
- Handle multiple accounts. Replying to email sent to a
- particular account will use the correct SMTP server, signature,
- and from address.
- </li>
-
- <li>
- Add custom code to handle certain types of messages or to
- handle certain types of text within messages.
- </li>
-
- <li>
- Organize email with user-defined labels, automatically track
- recent contacts, and much more!
- </li>
- </ul>
-
- <p>
- The goal of Sup is to become the email client of choice for nerds
- everywhere.
- </p>
-
- <h2>Screenshots</h2>
-
- <ul id="screenshots">
- <li><a href="ss1.png"><img src="ss1-small.png" alt="Sup screenshot 1" /></a></li>
- <li><a href="ss2.png"><img src="ss2-small.png" alt="Sup screenshot 2" /></a></li>
- <li><a href="ss3.png"><img src="ss3-small.png" alt="Sup screenshot 3" /></a></li>
- <li><a href="ss4.png"><img src="ss4-small.png" alt="Sup screenshot 4" /></a></li>
- <li><a href="ss5.png"><img src="ss5-small.png" alt="Sup screenshot 5" /></a></li>
- <li><a href="ss6.png"><img src="ss6-small.png" alt="Sup screenshot 6" /></a></li>
- </ul>
-
- <h2>Documentation</h2>
-
- <p>
- Please read the <a href="README.txt">README</a>, the <a
- href="FAQ.txt">FAQ</a>, the <a href="NewUserGuide.txt">new user guide</a>
- and the <a href="Philosophy.txt">philosophical statement</a>.
- </p>
-
- <p> Please also read and contribute to the <a href="http://www.foobacca.co.uk/sup/">Sup wiki</a>. </p>
-
- <h2>Status</h2>
-
- <p>
- The current version of Sup is 0.12.1, released 2011-01-23. This is a
- beta release. It supports mbox and Maildir mailstores.
- </p>
-
- <p>To be notified by email of Sup releases, subscribe to the
- <a href="http://rubyforge.org/mailman/listinfo/sup-announce">sup-announce mailing list</a>. One email per release.
- </p>
-
- <!-- <p>Issue and release status is available on the <a href="ditz/">Sup ditz page</a>.</p> -->
- <p>Sup news can often be see on <a href="http://all-thing.net/label/sup/">William's blog</a>.</p>
-
- <h2>Bug reports</h2>
- <p>Find a problem with Sup? Or have a feature you'd like to see? <a href="https://github.com/sup-heliotrope/sup/issues/new">Submit
- it</a> to the <a href="https://github.com/sup-heliotrope/sup/issues">official Sup issue tracker</a>.
-
- <h2>Getting it</h2>
-
- <p>
- You can download Sup releases from the <a
- href="http://rubyforge.org/projects/sup/">Sup RubyForge page</a>.
- If you have RubyGems installed, simply command your computer to "gem
- install sup".
- </p>
-
- <p>
- If you're interested in development, you can clone the git repository like so: <code>git clone git://github.com/sup-heliotrope/sup.git</code>. You can also browse the <a
- href="http://github.com/sup-heliotrope/sup">Sup GitHub
- repository</a>. You may consider subscribing to the sup-devel list (below).
- </p>
-
- <h2>Make some new friends</h2>
-
- <p> If you'd like to meet hot single Sup users in your area, try the <a
- href="http://rubyforge.org/mailman/listinfo/sup-talk">sup-talk mailing list</a> (<a href="http://rubyforge.org/pipermail/sup-talk/">archives</a>).
- </p>
-
- <p> If you'd like to meet some grumpy old programmers to talk about Sup internals with, try the <a
- href="http://rubyforge.org/mailman/listinfo/sup-devel">sup-devel mailing list</a> (<a href="http://rubyforge.org/pipermail/sup-devel/">archives</a>).
-
-
- <h2>Credit</h2>
-
- <p>
- Sup is brought to you by <a href="http://masanjin.net/">William Morgan</a> and the following honorable contributors:
- <ul>
- <li> William Morgan </li>
- <li> Rich Lane </li>
- <li> Ismo Puustinen </li>
- <li> Nicolas Pouillard </li>
- <li> Eric Sherman </li>
- <li> Michael Stapelberg </li>
- <li> Ben Walton </li>
- <li> Mike Stipicevic </li>
- <li> Marcus Williams </li>
- <li> Lionel Ott </li>
- <li> Tero Tilus </li>
- <li> Ingmar Vanhassel </li>
- <li> Mark Alexander </li>
- <li> Gaute Hope </li>
- <li> Christopher Warrington </li>
- <li> W. Trevor King </li>
- <li> Gaudenz Steinlin </li>
- <li> Richard Brown </li>
- <li> Marc Hartstein </li>
- <li> Sascha Silbe </li>
- <li> Israel Herraiz </li>
- <li> Anthony Martinez </li>
- <li> Hamish Downer </li>
- <li> Bo Borgerson </li>
- <li> William Erik Baxter </li>
- <li> Michael Hamann </li>
- <li> Grant Hollingworth </li>
- <li> Adeodato Simó </li>
- <li> Daniel Schoepe </li>
- <li> Jason Petsod </li>
- <li> Steve Goldman </li>
- <li> Edward Z. Yang </li>
- <li> Decklin Foster </li>
- <li> Cameron Matheson </li>
- <li> Carl Worth </li>
- <li> Jeff Balogh </li>
- <li> Andrew Pimlott </li>
- <li> Alex Vandiver </li>
- <li> Peter Harkins </li>
- <li> Kornilios Kourtis </li>
- <li> Giorgio Lando </li>
- <li> Damien Leone </li>
- <li> Benoît PIERRE </li>
- <li> Alvaro Herrera </li>
- <li> Jonah </li>
- <li> Adam Lloyd </li>
- <li> Todd Eisenberger </li>
- <li> ian </li>
- <li> Steven Walter </li>
- <li> ian </li>
- <li> Jon M. Dugan </li>
- <li> Gregor Hoffleit </li>
- <li> Stefan Lundström </li>
- <li> Kirill Smelkov </li>
- </ul>
- </p>
-
- <p>
- Sup is made possible by the <a href="http://xapian.org">Xapian</a> search engine,
- and by <a href="http://www.lickey.com/">Matt Armstrong</a> and his
- tragically abandoned <a href="http://www.rfc20.org/rubymail/">RubyMail</a>
- package.
- </p>
- </body>
-</html>
diff --git a/www/main.css b/www/main.css
@@ -1,36 +0,0 @@
-body
-{
- background: white;
- color: #404040;
- margin-bottom: 2em;
- margin-left: auto;
- margin-right: auto;
- width: 90%;
-}
-
-a, a:visited
-{
- border-bottom: 1px dotted #03c;
- background: inherit;
- color: #03c;
- text-decoration: none;
-}
-
-#screenshots
-{
- margin: 0;
- padding: 0;
-}
-#screenshots li
-{
- display: inline;
- list-style: none;
-}
-#screenshots a
-{
- border-bottom: none;
-}
-#screenshots img
-{
- border: 0;
-}
diff --git a/www/ss1.png b/www/ss1.png
Binary files differ.
diff --git a/www/ss2.png b/www/ss2.png
Binary files differ.
diff --git a/www/ss3.png b/www/ss3.png
Binary files differ.
diff --git a/www/ss4.png b/www/ss4.png
Binary files differ.
diff --git a/www/ss5.png b/www/ss5.png
Binary files differ.
diff --git a/www/ss6.png b/www/ss6.png
Binary files differ.