Hi All,
I spoke briefly with William yesterday about this, but didn't get a
chance to package it until just now...
I've recently discovered sup and am looking to try it out to see if it
will work for my needs (or can be made to). It seems to combine the
things I love about mutt and gmail into a great package (and ruby is a
plus too!). Right off the bat, I wanted support for maildir or imap
storage of sent mail (I live in nfs land so I tend to have a natural
distaste for mbox). I've implemented the basic functionality for this
although there is more room to work (the mbox version is implemented
in SentLoader as I didn't want to get into refactoring mbox code yet).
Also, this is my first exposure to working with git, so I apologize if
the attached patch isn't up to snuff...Comments welcome, and I'll
certainly update the patch and resubmit.
I hope you'll find this useful...It's working for me currently, but
there are likely some things that could be improved.
Thanks
-Ben
--
---------------------------------------------------------------------------------------------------------------------------
Ben Walton <[EMAIL PROTECTED]>
When one person suffers from a delusion, it is called insanity. When
many people suffer from a delusion it is called Religion.
Robert M. Pirsig, Zen and the Art of Motorcycle Maintenance
---------------------------------------------------------------------------------------------------------------------------
From 6b402377b1049f8fe9482b83b912566a34854b79 Mon Sep 17 00:00:00 2001
From: Ben Walton <[EMAIL PROTECTED]>
Date: Tue, 29 Apr 2008 09:34:00 -0400
Subject: [PATCH] flexible sent source
* Added a configuration item named sent_source that holds the uri of the source
that the user wishes to place sent mail in.
* If the user selects a sent source type that doesn't honour the store_message
method, the default is to use the old sent.mbox (now mbox:///path/to/sent.mbox
instead of sup://sent
* sup-config asks about using each added source as the sent source during
config. If none is chosen, it presents all of them at them end (including
mbox:///path/to/sent on [at least] the first run)
* imap and maildir sources now honour the store_message method and will place
a new mail item into the destination they represent.
* mbox store_message has not been genericized yet.
---
bin/sup | 9 +++++++--
bin/sup-config | 34 +++++++++++++++++++++++++++++++---
lib/sup.rb | 5 +++--
lib/sup/imap.rb | 8 ++++++++
lib/sup/maildir.rb | 36 +++++++++++++++++++++++++++++++++++-
lib/sup/sent.rb | 45 +++++++++++++++++++++++++++++----------------
lib/sup/source.rb | 4 +++-
7 files changed, 116 insertions(+), 25 deletions(-)
diff --git a/bin/sup b/bin/sup
index 6360cde..8567baa 100644
--- a/bin/sup
+++ b/bin/sup
@@ -128,10 +128,15 @@ begin
end
if(s = Index.source_for SentManager.source_name)
- SentManager.source = s
+ if s.respond_to? :store_message
+ SentManager.source = s
+ else
+ Redwood::log "configured sent mail source doesn't handle storing mail. reverting to default."
+ Index.add_source SentManager.new_source
+ end
else
Redwood::log "no sent mail source, auto-adding..."
- Index.add_source SentManager.new_source
+ Index.add_source SentManager.new_source #use the default mbox source
end
HookManager.run "startup"
diff --git a/bin/sup-config b/bin/sup-config
index f978a6b..972c92f 100644
--- a/bin/sup-config
+++ b/bin/sup-config
@@ -121,19 +121,27 @@ def add_source
usual = axe_yes "Does this source ever receive new messages?", "y"
archive = usual ? axe_yes("Should new messages be automatically archived? (I.e. not appear in your inbox, though still be accessible via search.)") : false
+ issent = axe_yes "Is this your sent box?", "n"
+
labels_str = axe("Enter any labels to be automatically added to all messages from this source, separated by spaces (or 'none')", default_labels.join(","))
labels =
if labels_str =~ /^\s*none\s*$/i
- nil
+ []
else
labels_str.split(/\s+/)
end
-
+
+ if issent
+ labels.push 'sent'
+ $have_sent = true
+ $config[:sent_source] = uri.to_s
+ end
+
cmd = build_cmd "sup-add"
cmd += " --unusual" unless usual
cmd += " --archive" if archive
- cmd += " --labels=#{labels.join(',')}" if labels && !labels.empty?
+ cmd += " --labels=#{labels.join(',')}" if !labels.empty?
cmd += " #{uri}"
puts "Ok, trying to run \"#{cmd}\"..."
@@ -210,6 +218,26 @@ until done
end
end
+unless $have_sent
+ index.load_sources
+ say "\n"
+ choose do |menu|
+ menu.prompt = "Which mail source is your sent box?"
+ #on first run, we'll present the ~/.sup/sent.mbox option. that option
+ #will be lost if they choose a different mailbox and then re-run this
+ menu.choice("#{$config[:sent_source]} (default)") { }
+ unless index.sources.empty?
+ index.sources.each do |s|
+ menu.choice(s) { $config[:sent_source] = s.uri } unless $config[:sent_source].eql? s.uri
+ end
+ end
+end
+end
+
+Redwood::save_yaml_obj $config, Redwood::CONFIG_FN
+
+say "#{Redwood::CONFIG_FN} updated with Sent source."
+
say <<EOS
Ok. The final step is to import all your messages into the Sup index.
diff --git a/lib/sup.rb b/lib/sup.rb
index 9e90267..592085e 100644
--- a/lib/sup.rb
+++ b/lib/sup.rb
@@ -42,7 +42,7 @@ module Redwood
PERSON_FN = File.join(BASE_DIR, "people.txt")
CONTACT_FN = File.join(BASE_DIR, "contacts.txt")
DRAFT_DIR = File.join(BASE_DIR, "drafts")
- SENT_FN = File.join(BASE_DIR, "sent.mbox")
+ SENT_FN = File.join(BASE_DIR, "sent.mbox") #now used as a fallback
LOCK_FN = File.join(BASE_DIR, "lock")
SUICIDE_FN = File.join(BASE_DIR, "please-kill-yourself")
HOOK_DIR = File.join(BASE_DIR, "hooks")
@@ -92,7 +92,7 @@ module Redwood
def start
Redwood::PersonManager.new Redwood::PERSON_FN
- Redwood::SentManager.new Redwood::SENT_FN
+ Redwood::SentManager.new $config[:sent_source]
Redwood::ContactManager.new Redwood::CONTACT_FN
Redwood::LabelManager.new Redwood::LABEL_FN
Redwood::AccountManager.new $config[:accounts]
@@ -197,6 +197,7 @@ else
:confirm_no_attachments => true,
:confirm_top_posting => true,
:discard_snippets_from_encrypted_messages => false,
+ :sent_source => 'mbox://' + Redwood::SENT_FN,
}
begin
FileUtils.mkdir_p Redwood::BASE_DIR
diff --git a/lib/sup/imap.rb b/lib/sup/imap.rb
index 1d36976..dfb7091 100644
--- a/lib/sup/imap.rb
+++ b/lib/sup/imap.rb
@@ -114,6 +114,14 @@ class IMAP < Source
end
synchronized :raw_message
+ def store_message date, from_email, &block
+ message = StringIO.new
+ yield message
+ message.string.gsub! /\n/, "\r\n"
+
+ safely { @imap.append mailbox, message.string, [:Seen], Time.now }
+ end
+
def connect
return if @imap
safely { } # do nothing!
diff --git a/lib/sup/maildir.rb b/lib/sup/maildir.rb
index 620e8e2..e07761b 100644
--- a/lib/sup/maildir.rb
+++ b/lib/sup/maildir.rb
@@ -19,7 +19,7 @@ class Maildir < Source
raise ArgumentError, "not a maildir URI" unless uri.scheme == "maildir"
raise ArgumentError, "maildir URI cannot have a host: #{uri.host}" if uri.host
- raise ArgumentError, "mbox URI must have a path component" unless uri.path
+ raise ArgumentError, "maildir URI must have a path component" unless uri.path
@dir = uri.path
@labels = (labels || []).freeze
@@ -59,6 +59,35 @@ class Maildir < Source
with_file_for(id) { |f| RMail::Parser.read f }
end
+ def store_message date, from_email, &block
+ stored = false
+ new_fn = new_maildir_basefn + ":2,S"
+ Dir.chdir(@dir) do |d|
+ tmp_path = File.join(@dir, 'tmp', new_fn)
+ new_path = File.join(@dir, 'new', new_fn)
+ begin
+ sleep 2 if File.stat(tmp_path)
+
+ #give the previous tmp file a chance to go away
+ #this is kind of silly anyway, but that's what the standard says
+ #(of course it also suggests giving up to 24 hours to complete this)
+ File.stat(tmp_path)
+ rescue Errno::ENOENT #this is what we want!
+ begin
+ File.open(tmp_path, 'w') do |f|
+ yield f #caller stores the data...
+ f.fsync
+ end
+ File.link tmp_path, new_path
+ stored = true
+ ensure
+ File.unlink tmp_path if File.exists? tmp_path
+ end
+ end #rescue
+ end #dir.chdir
+ stored
+ end
+
def raw_header id
scan_mailbox
ret = ""
@@ -164,6 +193,11 @@ private
[($1 || fn), ($2 || "2"), ($3 || "")]
end
+ def new_maildir_basefn
+ Kernel::srand()
+ "#{Time.now.to_i.to_s}.#{$$}#{Kernel.rand(1000000)}.#{Socket.gethostname}"
+ end
+
## not thread-safe on msg
def maildir_mark_file msg, flag
orig_path = @ids_to_fns[msg]
diff --git a/lib/sup/sent.rb b/lib/sup/sent.rb
index ee843c7..8a366be 100644
--- a/lib/sup/sent.rb
+++ b/lib/sup/sent.rb
@@ -3,26 +3,27 @@ module Redwood
class SentManager
include Singleton
- attr_accessor :source
- def initialize fn
- @fn = fn
- @source = nil
+ def initialize src_name
+ @@src_name = src_name
+ @@source = nil
self.class.i_am_the_instance self
end
- def self.source_name; "sup://sent"; end
- def self.source_id; 9998; end
- def new_source; @source = Recoverable.new SentLoader.new; end
+ def source= source; @@source = source; end
+ def source; @@source; end
- def write_sent_message date, from_email
- need_blank = File.exists?(@fn) && !File.zero?(@fn)
- File.open(@fn, "a") do |f|
- f.puts if need_blank
- f.puts "From #{from_email} #{date}"
- yield f
- end
+ def self.source_name; @@src_name; end
+ def self.source_id; @@source.is_a?(SentLoader) ? 9998 : @@source.id; end
+
+ def new_source
+ @@src_name = "mbox://" + Redwood::SENT_FN
+ @@source = Recoverable.new SentLoader.new
+ end
+
+ def write_sent_message date, from_email, &block
+ @@source.store_message date, from_email, &block
- PollManager.add_messages_from(@source) do |m, o, e|
+ PollManager.add_messages_from(@@source) do |m, o, e|
m.remove_label :unread
m
end
@@ -38,11 +39,23 @@ class SentLoader < MBox::Loader
super "mbox://" + @filename, cur_offset, true, true
end
+ def id; 9998; end
+
+ # i don't like putting this here, but the mbox stuff needs a refactor and
+ # i'm not up to that yet.
+ def store_message date, from_email, &block
+ need_blank = File.exists?(@filename) && !File.zero?(@filename)
+ File.open(@filename, "a") do |f|
+ f.puts if need_blank
+ f.puts "From #{from_email} #{date}"
+ yield f
+ end
+ end
+
def file_path; @filename end
def uri; SentManager.source_name; end
def to_s; SentManager.source_name; end
- def id; SentManager.source_id; end
def labels; [:sent, :inbox]; end
end
diff --git a/lib/sup/source.rb b/lib/sup/source.rb
index 6510aae..96321c9 100644
--- a/lib/sup/source.rb
+++ b/lib/sup/source.rb
@@ -15,6 +15,7 @@ class Source
## 1. See how many messages it contains
## 2. Get an arbitrary message
## 3. (optional) see whether the source has marked it read or not
+ ## 4. (optional) store a sent message
##
## In particular, Sup doesn't need to move messages, mark them as
## read, delete them, or anything else. (Well, it's nice to be able
@@ -35,6 +36,7 @@ class Source
## - end_offset (exclusive!)
## - load_header offset
## - load_message offset
+ ## - store_message date, from_email, &block [append the message to source]
## - raw_header offset
## - raw_message offset
## - check
@@ -100,7 +102,7 @@ class Source
end
protected
-
+
def Source.expand_filesystem_uri uri
uri.gsub "~", File.expand_path("~")
end
--
1.5.5.1
_______________________________________________
sup-talk mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/sup-talk