From: wmorgan Date: Wed, 21 Feb 2007 03:58:16 +0000 (+0000) Subject: added maildir support (finally!) X-Git-Url: https://git.notmuchmail.org/git?a=commitdiff_plain;h=3206b4b3d29a3df3d32f70aa3258d43b6cece346;p=sup added maildir support (finally!) git-svn-id: svn://rubyforge.org/var/svn/sup/trunk@339 5c8cc53c-5e98-4d25-b20a-d8db53a31250 --- diff --git a/History.txt b/History.txt index ac5e1ba..723b6d8 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,7 @@ +== 0.0.8 / XXXX +* Maildir support. +* More bugfixes. Will they ever end? + == 0.0.7 / 2007-02-12 * Split sup-import into two bits: sup-import and sup-add. * Command-line arguments now handled by trollop. diff --git a/Manifest.txt b/Manifest.txt index c4b9da6..0f33838 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -23,6 +23,7 @@ lib/sup/index.rb lib/sup/keymap.rb lib/sup/label.rb lib/sup/logger.rb +lib/sup/maildir.rb lib/sup/mbox.rb lib/sup/mbox/loader.rb lib/sup/mbox/ssh-file.rb diff --git a/README.txt b/README.txt index bc271fa..748cb91 100644 --- a/README.txt +++ b/README.txt @@ -11,9 +11,9 @@ with the speed and simplicity of a console interface. Sup makes it easy to: - Handle massive amounts of email. -- Mix email from different sources: mbox files (even across - different machines), IMAP folders, POP accounts, and GMail - accounts. +- 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 @@ -40,7 +40,7 @@ Features: operability, regardless of how much amount of email you have. - Immediate full-text search of your entire email archive, using the - Ferret query langauge. Search over message bodies, labels, from: and + Ferret query language. Search over message bodies, labels, from: and to: fields, or any combination thereof. - Thread-centrism. Operations are performed at the thread, not the @@ -109,21 +109,24 @@ Current limitations which will be fixed: * ncurses * rmail * highline +* trollop +* net-ssh == INSTALL: * gem install sup -y == KNOWN BUGS IN OTHER PACKAGES: + * If you get an error about frozen strings in RubyMail when importing certain messages with attachments, in rmail, change line 159 of multipart.rb to: chunk = chunk[0..start] + This is because RubyMail hasn't been updated since like Ruby 1.8.2. + Please bug Matt Lickey. * Occasionally Ferret produces something the Ruby GC doesn't like (particularly when importing messages from very large sources). No worries, just re-run sup-import. (This is unresolved atm.) -* There are a couple other Ferret issues with outstanding patches but - they are pretty rare. * If you are using IMAP or Maildir and see this error: /usr/local/lib/ruby/1.8/yaml.rb:133:in `transfer': allocator undefined for Bignum (TypeError) then you need to upgrade to Ruby 1.8.5. YAML in earlier versions diff --git a/bin/sup-add b/bin/sup-add index 69749bb..b0d8457 100644 --- a/bin/sup-add +++ b/bin/sup-add @@ -6,8 +6,6 @@ require 'highline/import' require 'trollop' require "sup" -Thread.abort_on_exception = true # make debugging possible - $opts = Trollop::options do version "sup-add (sup #{Redwood::VERSION})" banner </ # secure, "INBOX" folder imaps:/// # secure, arbitrary folder +For Maildir folders, use the form: + maildir:// + Options are: EOS opt :archive, "Automatically archive all new messages from these sources." @@ -80,22 +81,30 @@ index.load ARGV.each do |uri| uri = "mbox://#{uri}" unless uri =~ %r!://! + if !$opts[:force_new] && index.source_for(uri) say "Already know about #{uri}; skipping." next end + + parsed_uri = URI(uri) + source = - case uri - when %r!^mbox\+ssh://! + case parsed_uri.scheme + when "mbox+ssh" say "For SSH connections, if you will use public key authentication, you may leave the username and password blank." say "" username, password = get_login_info uri, index.sources - Redwood::MBox::SSHLoader.new(uri, username, password, nil, !$opts[:unusual], $opts[:archive]) - when %r!^imaps?://! + Redwood::MBox::SSHLoader.new uri, username, password, nil, !$opts[:unusual], $opts[:archive] + when "imap", "imaps" username, password = get_login_info uri, index.sources - Redwood::IMAP.new(uri, username, password, nil, !$opts[:unusual], $opts[:archive]) + Redwood::IMAP.new uri, username, password, nil, !$opts[:unusual], $opts[:archive] + when "maildir" + Redwood::Maildir.new uri, nil, !$opts[:unusual], $opts[:archive] + when "mbox" + Redwood::MBox::Loader.new uri, nil, !$opts[:unusual], $opts[:archive] else - Redwood::MBox::Loader.new(uri, nil, !$opts[:unusual], $opts[:archive]) + Trollop::die "Unknown source type #{parsed_uri.scheme.inspect}" end say "Adding #{source}..." index.add_source source diff --git a/bin/sup-import b/bin/sup-import index cf2b41a..c0c635c 100644 --- a/bin/sup-import +++ b/bin/sup-import @@ -5,8 +5,6 @@ require 'rubygems' require 'trollop' require "sup" -Thread.abort_on_exception = true # make debugging possible - class Float def to_s; sprintf '%.2f', self; end end diff --git a/doc/TODO b/doc/TODO index db9b7d5..e2bda88 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,13 +1,13 @@ for 0.0.8 --------- -bugfix: when one new message comes into an imap folder, we don't catch - it until a restart -bugfix: triggering a pageup when cursor scrolling up jumps to the bottom of the - page rather than the next line -create attachments -forward attachments -warnings: top-posting, missing attachment -maildir +x maildir +_ bugfix: when one new message comes into an imap folder, we don't + catch it until a restart +_ bugfix: triggering a pageup when cursor scrolling up jumps to the + bottom of the page rather than the next line +_ create attachments +_ forward attachments +_ warnings: top-posting, missing attachment for 0.0.9 --------- diff --git a/lib/sup.rb b/lib/sup.rb index 2df5e52..76b435d 100644 --- a/lib/sup.rb +++ b/lib/sup.rb @@ -127,6 +127,7 @@ require "sup/update" require "sup/message" require "sup/source" require "sup/mbox" +require "sup/maildir" require "sup/imap" require "sup/person" require "sup/account" diff --git a/lib/sup/maildir.rb b/lib/sup/maildir.rb new file mode 100644 index 0000000..f15befc --- /dev/null +++ b/lib/sup/maildir.rb @@ -0,0 +1,124 @@ +require 'rmail' +require 'uri' + +module Redwood + +## Maildir doesn't provide an ordered unique id, which is what Sup +## requires to be really useful. So we must maintain, in memory, a +## mapping between Sup "ids" (timestamps, essentially) and the +## pathnames on disk. + +class Maildir < Source + SCAN_INTERVAL = 30 # seconds + + def initialize uri, last_date=nil, usual=true, archived=false, id=nil + super + + @dir = URI(uri).path + @ids = [] + @ids_to_fns = {} + @labels = [:unread] + @last_scan = nil + @mutex = Mutex.new + end + + def load_header id + scan_mailbox + with_file_for(id) { |f| MBox::read_header f } + end + + def load_message id + scan_mailbox + with_file_for(id) { |f| RMail::Parser.read f } + end + + def raw_header id + scan_mailbox + ret = "" + with_file_for(id) do |f| + until f.eof? || (l = f.gets) =~ /^$/ + ret += l + end + end + ret + end + + def raw_full_message id + scan_mailbox + with_file_for(id) { |f| f.readlines.join } + end + + def scan_mailbox + return if @last_scan && (Time.now - @last_scan) < SCAN_INTERVAL + + cdir = File.join(@dir, 'cur') + ndir = File.join(@dir, 'cur') + + begin + @ids, @ids_to_fns = @mutex.synchronize do + ids, ids_to_fns = [], {} + (Dir[File.join(cdir, "*")] + Dir[File.join(ndir, "*")]).map do |fn| + id = make_id fn + ids << id + ids_to_fns[id] = fn + end + [ids.sort, ids_to_fns] + end + rescue SystemCallError => e + die "Problem scanning Maildir directories: #{e.message}." + end + + @last_scan = Time.now + end + + def each + scan_mailbox + start = @ids.index(cur_offset || start_offset) or die "Unknown message id #{cur_offset || start_offset}.", :suggest_rebuild => true # couldn't find the most recent email + + start.upto(@ids.length - 1) do |i| + id = @ids[i] + self.cur_offset = id + yield id, @labels.clone + end + end + + def start_offset + scan_mailbox + @ids.first + end + + def end_offset + scan_mailbox + @ids.last + end + + def pct_done; 100.0 * (@ids.index(cur_offset) || 0).to_f / (@ids.length - 1).to_f; end + +private + + def die message, opts={} + message += " It is likely that messages have been deleted from this Maildir mailbox. Please run sup-import --rebuild #{to_s} to correct this problem." if opts[:suggest_rebuild] + self.broken_msg = message + Redwood::log message + BufferManager.flash "Error communicating with Maildir. See log for details." if BufferManager.instantiated? + raise SourceError, message + end + + def make_id fn + # use 7 digits for the size. why 7? seems nice. + sprintf("%d%07d", File.ctime(fn), File.size(fn)).to_i + end + + def with_file_for id + fn = @ids_to_fns[id] or die "No such id: #{id.inspect}.", :suggest_rebuild => true + begin + File.open(fn) { |f| yield f } + rescue SystemCallError => e + die "Problem reading file for id #{id.inspect}: #{fn.inspect}: #{e.message}." + end + end +end + +Redwood::register_yaml(Maildir, %w(uri cur_offset usual archived id)) + +end diff --git a/www/index.html b/www/index.html index 1d590bb..8aba073 100644 --- a/www/index.html +++ b/www/index.html @@ -56,10 +56,11 @@ the philosophical statement.

Status

-

The current version of Sup is 0.0.7, released February 12th, 2007. +

The current version of Sup is 0.0.8, released XXXX. This is a beta release. It is unix-centric and has no i18n - support. It supports only mbox, mbox+ssh, and IMAP, not POP, - GMail or Maildir. I plan to fix all of these problems.

+ support. It supports mbox, mbox over ssh, IMAP, and Maildir. It + does not support POP or GMail. I plan to fix all of these + problems.

Other than those limitations, it works great! I use it for my everyday email, and it makes dealing with 85,000 messages a