sup 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sup might be problematic. Click here for more details.
- data/History.txt +14 -1
- data/Manifest.txt +4 -1
- data/README.txt +13 -7
- data/Rakefile +3 -3
- data/bin/sup +17 -8
- data/bin/sup-add +20 -14
- data/bin/sup-config +222 -0
- data/bin/sup-dump +31 -0
- data/bin/sup-sync +235 -0
- data/doc/FAQ.txt +52 -25
- data/doc/Philosophy.txt +19 -19
- data/doc/TODO +37 -11
- data/doc/UserGuide.txt +42 -41
- data/lib/sup.rb +48 -4
- data/lib/sup/buffer.rb +22 -5
- data/lib/sup/draft.rb +2 -2
- data/lib/sup/imap.rb +20 -30
- data/lib/sup/index.rb +42 -54
- data/lib/sup/logger.rb +1 -1
- data/lib/sup/maildir.rb +127 -0
- data/lib/sup/mbox/loader.rb +40 -38
- data/lib/sup/mbox/ssh-file.rb +16 -25
- data/lib/sup/mbox/ssh-loader.rb +2 -11
- data/lib/sup/message.rb +14 -8
- data/lib/sup/mode.rb +1 -1
- data/lib/sup/modes/edit-message-mode.rb +1 -1
- data/lib/sup/modes/inbox-mode.rb +4 -1
- data/lib/sup/modes/line-cursor-mode.rb +3 -2
- data/lib/sup/modes/reply-mode.rb +1 -1
- data/lib/sup/modes/thread-index-mode.rb +6 -6
- data/lib/sup/modes/thread-view-mode.rb +24 -11
- data/lib/sup/poll.rb +45 -36
- data/lib/sup/sent.rb +3 -3
- data/lib/sup/source.rb +29 -47
- data/lib/sup/thread.rb +1 -1
- data/lib/sup/util.rb +30 -5
- metadata +12 -7
- data/bin/sup-import +0 -159
data/lib/sup/thread.rb
CHANGED
@@ -54,7 +54,7 @@ class Thread
|
|
54
54
|
## message can be a Message object, or :fake_root, or nil.
|
55
55
|
def each fake_root=false
|
56
56
|
adj = 0
|
57
|
-
root = @containers.find_all { |c| !Message.subj_is_reply?(c) }.argmin { |c| c.date }
|
57
|
+
root = @containers.find_all { |c| !Message.subj_is_reply?(c) }.argmin { |c| c.date || 0 }
|
58
58
|
|
59
59
|
if root
|
60
60
|
adj = 1
|
data/lib/sup/util.rb
CHANGED
@@ -8,10 +8,6 @@ class Module
|
|
8
8
|
bool_writer(*args)
|
9
9
|
end
|
10
10
|
|
11
|
-
def attr_reader_cloned *args
|
12
|
-
args.each { |sym| class_eval %{ def #{sym}; @#{sym}.clone; end } }
|
13
|
-
end
|
14
|
-
|
15
11
|
def defer_all_other_method_calls_to obj
|
16
12
|
class_eval %{ def method_missing meth, *a, &b; @#{obj}.send meth, *a, &b; end }
|
17
13
|
end
|
@@ -267,11 +263,12 @@ end
|
|
267
263
|
## allows for constructors that take arguments.
|
268
264
|
##
|
269
265
|
## You must have #initialize call "self.class.i_am_the_instance self"
|
270
|
-
## at some point or everything will fail horribly
|
266
|
+
## at some point or everything will fail horribly.
|
271
267
|
module Singleton
|
272
268
|
module ClassMethods
|
273
269
|
def instance; @instance; end
|
274
270
|
def instantiated?; defined?(@instance) && !@instance.nil?; end
|
271
|
+
def deinstantiate!; @instance = nil; end
|
275
272
|
def method_missing meth, *a, &b
|
276
273
|
raise "no instance defined!" unless defined? @instance
|
277
274
|
@instance.send meth, *a, &b
|
@@ -286,3 +283,31 @@ module Singleton
|
|
286
283
|
klass.extend ClassMethods
|
287
284
|
end
|
288
285
|
end
|
286
|
+
|
287
|
+
## wraps an object. if it throws an exception, keeps a copy, and
|
288
|
+
## rethrows it for any further method calls.
|
289
|
+
class Recoverable
|
290
|
+
def initialize o
|
291
|
+
@o = o
|
292
|
+
@e = nil
|
293
|
+
end
|
294
|
+
|
295
|
+
def clear_error!; @e = nil; end
|
296
|
+
def has_errors?; !@e.nil?; end
|
297
|
+
def error; @e; end
|
298
|
+
|
299
|
+
def method_missing m, *a, &b; __pass m, *a, &b; end
|
300
|
+
|
301
|
+
def id; __pass :id; end
|
302
|
+
def to_s; __pass :to_s; end
|
303
|
+
def to_yaml x; __pass :to_yaml, x; end
|
304
|
+
|
305
|
+
def __pass m, *a, &b
|
306
|
+
begin
|
307
|
+
@o.send(m, *a, &b)
|
308
|
+
rescue Exception => e
|
309
|
+
@e = e
|
310
|
+
raise e
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
metadata
CHANGED
@@ -3,15 +3,15 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: sup
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0.
|
7
|
-
date: 2007-
|
6
|
+
version: 0.0.8
|
7
|
+
date: 2007-04-01 00:00:00 -07:00
|
8
8
|
summary: 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.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
11
|
email: wmorgan-sup@masanjin.net
|
12
12
|
homepage: http://sup.rubyforge.org
|
13
13
|
rubyforge_project: sup
|
14
|
-
description: "Sup is a console-based email client that combines the best features of GMail, mutt, and emacs. Sup matches the power of GMail 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."
|
14
|
+
description: "Sup is a console-based email client that combines the best features of GMail, mutt, and emacs. Sup matches the power of GMail 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), 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."
|
15
15
|
autorequire:
|
16
16
|
default_executable:
|
17
17
|
bindir: bin
|
@@ -36,8 +36,10 @@ files:
|
|
36
36
|
- Rakefile
|
37
37
|
- bin/sup
|
38
38
|
- bin/sup-add
|
39
|
-
- bin/sup-
|
39
|
+
- bin/sup-config
|
40
|
+
- bin/sup-dump
|
40
41
|
- bin/sup-recover-sources
|
42
|
+
- bin/sup-sync
|
41
43
|
- doc/FAQ.txt
|
42
44
|
- doc/Philosophy.txt
|
43
45
|
- doc/TODO
|
@@ -53,6 +55,7 @@ files:
|
|
53
55
|
- lib/sup/keymap.rb
|
54
56
|
- lib/sup/label.rb
|
55
57
|
- lib/sup/logger.rb
|
58
|
+
- lib/sup/maildir.rb
|
56
59
|
- lib/sup/mbox.rb
|
57
60
|
- lib/sup/mbox/loader.rb
|
58
61
|
- lib/sup/mbox/ssh-file.rb
|
@@ -97,8 +100,10 @@ extra_rdoc_files: []
|
|
97
100
|
executables:
|
98
101
|
- sup
|
99
102
|
- sup-add
|
100
|
-
- sup-
|
103
|
+
- sup-config
|
104
|
+
- sup-dump
|
101
105
|
- sup-recover-sources
|
106
|
+
- sup-sync
|
102
107
|
extensions: []
|
103
108
|
|
104
109
|
requirements: []
|
@@ -154,7 +159,7 @@ dependencies:
|
|
154
159
|
version_requirement:
|
155
160
|
version_requirements: !ruby/object:Gem::Version::Requirement
|
156
161
|
requirements:
|
157
|
-
- - "
|
162
|
+
- - ">="
|
158
163
|
- !ruby/object:Gem::Version
|
159
|
-
version:
|
164
|
+
version: "1.5"
|
160
165
|
version:
|
data/bin/sup-import
DELETED
@@ -1,159 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'uri'
|
4
|
-
require 'rubygems'
|
5
|
-
require 'trollop'
|
6
|
-
require "sup"
|
7
|
-
|
8
|
-
Thread.abort_on_exception = true # make debugging possible
|
9
|
-
|
10
|
-
class Float
|
11
|
-
def to_s; sprintf '%.2f', self; end
|
12
|
-
end
|
13
|
-
|
14
|
-
class Numeric
|
15
|
-
def to_time_s
|
16
|
-
i = to_i
|
17
|
-
sprintf "%d:%02d:%02d", i / 3600, (i / 60) % 60, i % 60
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def time
|
22
|
-
startt = Time.now
|
23
|
-
yield
|
24
|
-
Time.now - startt
|
25
|
-
end
|
26
|
-
|
27
|
-
opts = Trollop::options do
|
28
|
-
version "sup-import (sup #{Redwood::VERSION})"
|
29
|
-
banner <<EOS
|
30
|
-
Imports messages into the Sup index from one or more sources.
|
31
|
-
|
32
|
-
Usage:
|
33
|
-
sup-import [options] <source>*
|
34
|
-
|
35
|
-
where <source>* is zero or more source URIs or mbox filenames. If no
|
36
|
-
sources are given, imports messages from all sources marked as
|
37
|
-
"usual".
|
38
|
-
|
39
|
-
Options are:
|
40
|
-
EOS
|
41
|
-
opt :archive, "Automatically archive any imported messages."
|
42
|
-
opt :read, "Automatically mark as read any imported messages."
|
43
|
-
opt :verbose, "Print message ids as they're processed."
|
44
|
-
opt :optimize, "As the last stage of the import, optimize the index."
|
45
|
-
text <<EOS
|
46
|
-
|
47
|
-
The following options allow sup-import to consider *all* messages in the
|
48
|
-
source, not just new ones:
|
49
|
-
EOS
|
50
|
-
opt :rebuild, "Scan over the entire source and update the index to account for any messages that have been deleted, altered, or moved from another source."
|
51
|
-
opt :full_rebuild, "Re-insert all messages in the source, not just ones that have changed or are new."
|
52
|
-
opt :start_at, "For rescan and rebuild, start at the given offset.", :type => :int
|
53
|
-
opt :overwrite_state, "For --full-rebuild, overwrite the message state to the default state for that source, obeying --archive and --read if given."
|
54
|
-
end
|
55
|
-
Trollop::die :start_at, "must be non-negative" if (opts[:start_at] || 0) < 0
|
56
|
-
Trollop::die :start_at, "requires either --rebuild or --full-rebuild" if opts[:start_at] && !(opts[:rebuild] || opts[:full_rebuild])
|
57
|
-
Trollop::die :overwrite_state, "requires --full-rebuild" if opts[:overwrite_state] && !opts[:full_rebuild]
|
58
|
-
Trollop::die :force_rebuild, "cannot be specified with --rebuild" if opts[:full_rebuild] && opts[:rebuild]
|
59
|
-
|
60
|
-
Redwood::start
|
61
|
-
index = Redwood::Index.new
|
62
|
-
index.load
|
63
|
-
|
64
|
-
sources = ARGV.map do |uri|
|
65
|
-
uri = "mbox://#{uri}" unless uri =~ %r!://!
|
66
|
-
index.source_for uri or raise "Unknown source: #{uri}"
|
67
|
-
end
|
68
|
-
|
69
|
-
sources = index.usual_sources if sources.empty?
|
70
|
-
|
71
|
-
if opts[:rebuild] || opts[:full_rebuild]
|
72
|
-
if opts[:start_at]
|
73
|
-
sources.each { |s| s.seek_to! opts[:start_at] }
|
74
|
-
else
|
75
|
-
sources.each { |s| s.reset! }
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
last_update = start = Time.now
|
80
|
-
found = {}
|
81
|
-
begin
|
82
|
-
sources.each do |source|
|
83
|
-
num_added = 0
|
84
|
-
num_updated = 0
|
85
|
-
puts "Scanning #{source}..."
|
86
|
-
Redwood::PollManager.add_new_messages_from source do |m, offset, entry|
|
87
|
-
## if the entry exists on disk
|
88
|
-
if entry && !opts[:overwrite_state]
|
89
|
-
m.labels = entry[:label].split(/\s+/).map { |x| x.intern }
|
90
|
-
else
|
91
|
-
## m.labels defaults to labels from the source
|
92
|
-
m.labels -= [:inbox] if opts[:archive]
|
93
|
-
m.labels -= [:unread] if opts[:read]
|
94
|
-
end
|
95
|
-
|
96
|
-
if Time.now - last_update > 60
|
97
|
-
last_update = Time.now
|
98
|
-
elapsed = last_update - start
|
99
|
-
pctdone = source.respond_to?(:pct_done) ? source.pct_done : 100.0 * (source.cur_offset.to_f - source.start_offset).to_f / (source.end_offset - source.start_offset).to_f
|
100
|
-
remaining = (100.0 - pctdone) * (elapsed.to_f / pctdone)
|
101
|
-
puts "## #{num} (#{pctdone}% done) read; #{elapsed.to_time_s} elapsed; est. #{remaining.to_time_s} remaining"
|
102
|
-
end
|
103
|
-
|
104
|
-
## update if...
|
105
|
-
if entry.nil? # it's a new message; or
|
106
|
-
puts "Adding message at #{offset}, labels: #{m.labels * ' '}" if opts[:verbose]
|
107
|
-
num_added += 1
|
108
|
-
found[m.id] = true
|
109
|
-
m
|
110
|
-
elsif opts[:full_rebuild] || # we're updating everyone; or
|
111
|
-
(opts[:rebuild] && (entry[:source_id].to_i != source.id || entry[:source_info].to_i != offset)) # we're updating just the changed ones
|
112
|
-
puts "Updating message at #{offset} (from #{m.from.longname}, subject '#{m.subj}'), source #{entry[:source_id]} => #{source.id}, offset #{entry[:source_info]} => #{offset}, labels: {#{m.labels * ', '}}" if opts[:verbose]
|
113
|
-
num_updated += 1 unless found[m.id]
|
114
|
-
found[m.id] = true
|
115
|
-
m
|
116
|
-
else
|
117
|
-
found[m.id] = true
|
118
|
-
nil
|
119
|
-
end
|
120
|
-
end
|
121
|
-
puts "Added #{num_added}, updated #{num_updated} messages from #{source}."
|
122
|
-
end
|
123
|
-
ensure
|
124
|
-
puts "Saving index and sources..."
|
125
|
-
index.save
|
126
|
-
Redwood::finish
|
127
|
-
end
|
128
|
-
|
129
|
-
## delete any messages in the index that claim they're from one of
|
130
|
-
## these sources, but that we didn't see.
|
131
|
-
##
|
132
|
-
## kinda crappy code here, because we delve directly into the Ferret
|
133
|
-
## API.
|
134
|
-
##
|
135
|
-
## TODO: move this to Index, i suppose.
|
136
|
-
if opts[:rebuild] || opts[:full_rebuild]
|
137
|
-
puts "Deleting missing messages from the index..."
|
138
|
-
numdel = num = 0
|
139
|
-
sources.each do |source|
|
140
|
-
raise "no source id for #{source}" unless source.id
|
141
|
-
q = "+source_id:#{source.id}"
|
142
|
-
q += " +source_info: >= #{opts[:start_at]}" if opts[:start_at]
|
143
|
-
num += index.index.search_each(q, :limit => :all) do |docid, score|
|
144
|
-
mid = index.index[docid][:message_id]
|
145
|
-
# puts "got #{mid}"
|
146
|
-
next if found[mid]
|
147
|
-
puts "Deleting #{mid}" if opts[:verbose]
|
148
|
-
index.index.delete docid
|
149
|
-
numdel += 1
|
150
|
-
end
|
151
|
-
end
|
152
|
-
puts "Deleted #{numdel} / #{num} messages"
|
153
|
-
end
|
154
|
-
|
155
|
-
if opts[:optimize]
|
156
|
-
puts "Optimizing index..."
|
157
|
-
optt = time { index.index.optimize }
|
158
|
-
puts "Optimized index of size #{index.size} in #{optt}s."
|
159
|
-
end
|