sup 0.0.1
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 +5 -0
- data/LICENSE +280 -0
- data/Manifest.txt +52 -0
- data/README.txt +119 -0
- data/Rakefile +45 -0
- data/bin/sup +229 -0
- data/bin/sup-import +162 -0
- data/doc/FAQ.txt +38 -0
- data/doc/Philosophy.txt +59 -0
- data/doc/TODO +31 -0
- data/lib/sup.rb +141 -0
- data/lib/sup/account.rb +53 -0
- data/lib/sup/buffer.rb +391 -0
- data/lib/sup/colormap.rb +118 -0
- data/lib/sup/contact.rb +40 -0
- data/lib/sup/draft.rb +105 -0
- data/lib/sup/index.rb +353 -0
- data/lib/sup/keymap.rb +89 -0
- data/lib/sup/label.rb +41 -0
- data/lib/sup/logger.rb +42 -0
- data/lib/sup/mbox.rb +51 -0
- data/lib/sup/mbox/loader.rb +116 -0
- data/lib/sup/message.rb +302 -0
- data/lib/sup/mode.rb +79 -0
- data/lib/sup/modes/buffer-list-mode.rb +37 -0
- data/lib/sup/modes/compose-mode.rb +33 -0
- data/lib/sup/modes/contact-list-mode.rb +121 -0
- data/lib/sup/modes/edit-message-mode.rb +162 -0
- data/lib/sup/modes/forward-mode.rb +38 -0
- data/lib/sup/modes/help-mode.rb +19 -0
- data/lib/sup/modes/inbox-mode.rb +45 -0
- data/lib/sup/modes/label-list-mode.rb +89 -0
- data/lib/sup/modes/label-search-results-mode.rb +29 -0
- data/lib/sup/modes/line-cursor-mode.rb +133 -0
- data/lib/sup/modes/log-mode.rb +44 -0
- data/lib/sup/modes/person-search-results-mode.rb +29 -0
- data/lib/sup/modes/poll-mode.rb +24 -0
- data/lib/sup/modes/reply-mode.rb +136 -0
- data/lib/sup/modes/resume-mode.rb +18 -0
- data/lib/sup/modes/scroll-mode.rb +106 -0
- data/lib/sup/modes/search-results-mode.rb +31 -0
- data/lib/sup/modes/text-mode.rb +51 -0
- data/lib/sup/modes/thread-index-mode.rb +389 -0
- data/lib/sup/modes/thread-view-mode.rb +338 -0
- data/lib/sup/person.rb +120 -0
- data/lib/sup/poll.rb +80 -0
- data/lib/sup/sent.rb +46 -0
- data/lib/sup/tagger.rb +40 -0
- data/lib/sup/textfield.rb +83 -0
- data/lib/sup/thread.rb +358 -0
- data/lib/sup/update.rb +21 -0
- data/lib/sup/util.rb +260 -0
- metadata +123 -0
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/sup.rb'
|
6
|
+
|
7
|
+
Hoe.new('sup', Redwood::VERSION) do |p|
|
8
|
+
p.rubyforge_name = 'sup'
|
9
|
+
p.author = "William Morgan"
|
10
|
+
p.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.'
|
11
|
+
p.description = p.paragraphs_of('README.txt', 2..4).join("\n\n")
|
12
|
+
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[2].gsub(/^\s+/, "")
|
13
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
14
|
+
p.email = "wmorgan-sup@masanjin.net"
|
15
|
+
p.extra_deps = [['ferret', '>= 0.10.13'], ['ncurses', '>= 0.9.1'], ['rmail', '>= 0.17']]
|
16
|
+
end
|
17
|
+
|
18
|
+
rule 'ss?.png' => 'ss?-small.png' do |t|
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
## is there really no way to make a rule for this?
|
24
|
+
WWW_FILES = %w(www/index.html README.txt doc/Philosophy.txt doc/FAQ.txt)
|
25
|
+
|
26
|
+
SCREENSHOTS = FileList["www/ss?.png"]
|
27
|
+
SCREENSHOTS_SMALL = []
|
28
|
+
SCREENSHOTS.each do |fn|
|
29
|
+
fn =~ /ss(\d+)\.png/
|
30
|
+
sfn = "www/ss#{$1}-small.png"
|
31
|
+
file sfn => [fn] do |t|
|
32
|
+
sh "cat #{fn} | pngtopnm | pnmscale -xysize 320 240 | pnmtopng > #{sfn}"
|
33
|
+
end
|
34
|
+
SCREENSHOTS_SMALL << sfn
|
35
|
+
end
|
36
|
+
|
37
|
+
task :upload_webpage => WWW_FILES do |t|
|
38
|
+
sh "scp -C #{t.prerequisites * ' '} wmorgan@rubyforge.org:/var/www/gforge-projects/sup/"
|
39
|
+
end
|
40
|
+
|
41
|
+
task :upload_webpage_images => (SCREENSHOTS + SCREENSHOTS_SMALL) do |t|
|
42
|
+
sh "scp -C #{t.prerequisites * ' '} wmorgan@rubyforge.org:/var/www/gforge-projects/sup/"
|
43
|
+
end
|
44
|
+
|
45
|
+
# vim: syntax=Ruby
|
data/bin/sup
ADDED
@@ -0,0 +1,229 @@
|
|
1
|
+
#!/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'ncurses'
|
5
|
+
require "sup"
|
6
|
+
|
7
|
+
module Redwood
|
8
|
+
|
9
|
+
$exception = nil
|
10
|
+
|
11
|
+
global_keymap = Keymap.new do |k|
|
12
|
+
k.add :quit, "Quit Redwood", 'q'
|
13
|
+
k.add :help, "Show help", 'H', '?'
|
14
|
+
k.add :roll_buffers, "Switch to next buffer", 'b'
|
15
|
+
k.add :roll_buffers_backwards, "Switch to previous buffer", 'B'
|
16
|
+
k.add :kill_buffer, "Kill the current buffer", 'x'
|
17
|
+
k.add :list_buffers, "List all buffers", 'A'
|
18
|
+
k.add :list_contacts, "List contacts", 'C'
|
19
|
+
k.add :redraw, "Redraw screen", :ctrl_l
|
20
|
+
k.add :search, "Search messages", '/'
|
21
|
+
k.add :list_labels, "List labels", 'L'
|
22
|
+
k.add :poll, "Poll for new messages", 'P'
|
23
|
+
k.add :compose, "Compose new message", 'm'
|
24
|
+
end
|
25
|
+
|
26
|
+
def start_cursing
|
27
|
+
Ncurses.initscr
|
28
|
+
Ncurses.noecho
|
29
|
+
Ncurses.cbreak
|
30
|
+
Ncurses.stdscr.keypad 1
|
31
|
+
Ncurses.curs_set 0
|
32
|
+
Ncurses.start_color
|
33
|
+
end
|
34
|
+
|
35
|
+
def stop_cursing
|
36
|
+
Ncurses.curs_set 1
|
37
|
+
Ncurses.echo
|
38
|
+
Ncurses.endwin
|
39
|
+
end
|
40
|
+
module_function :start_cursing, :stop_cursing
|
41
|
+
|
42
|
+
Redwood::SentManager.new Redwood::SENT_FN
|
43
|
+
Redwood::ContactManager.new Redwood::CONTACT_FN
|
44
|
+
Redwood::LabelManager.new Redwood::LABEL_FN
|
45
|
+
Redwood::AccountManager.new $config[:accounts]
|
46
|
+
Redwood::DraftManager.new Redwood::DRAFT_DIR
|
47
|
+
Redwood::UpdateManager.new
|
48
|
+
Redwood::PollManager.new
|
49
|
+
|
50
|
+
Index.new.load
|
51
|
+
log "loaded #{Index.size} messages from index"
|
52
|
+
|
53
|
+
if(s = Index.source_for DraftManager.source_name)
|
54
|
+
DraftManager.source = s
|
55
|
+
else
|
56
|
+
Index.add_source DraftManager.new_source
|
57
|
+
end
|
58
|
+
|
59
|
+
if(s = Index.source_for SentManager.source_name)
|
60
|
+
SentManager.source = s
|
61
|
+
else
|
62
|
+
Index.add_source SentManager.new_source
|
63
|
+
end
|
64
|
+
|
65
|
+
begin
|
66
|
+
log "starting curses"
|
67
|
+
start_cursing
|
68
|
+
|
69
|
+
log "initializing colormap"
|
70
|
+
Colormap.new do |c|
|
71
|
+
c.add :status_color, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLUE, Ncurses::A_BOLD
|
72
|
+
c.add :index_old_color, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLACK
|
73
|
+
c.add :index_new_color, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLACK,
|
74
|
+
Ncurses::A_BOLD
|
75
|
+
c.add :labellist_old_color, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLACK
|
76
|
+
c.add :labellist_new_color, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLACK,
|
77
|
+
Ncurses::A_BOLD
|
78
|
+
c.add :twiddle_color, Ncurses::COLOR_BLUE, Ncurses::COLOR_BLACK
|
79
|
+
c.add :label_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK
|
80
|
+
c.add :message_patina_color, Ncurses::COLOR_BLACK, Ncurses::COLOR_GREEN
|
81
|
+
c.add :mime_color, Ncurses::COLOR_CYAN, Ncurses::COLOR_BLACK
|
82
|
+
c.add :quote_patina_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK
|
83
|
+
c.add :sig_patina_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK
|
84
|
+
c.add :quote_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK
|
85
|
+
c.add :sig_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK
|
86
|
+
c.add :to_me_color, Ncurses::COLOR_GREEN, Ncurses::COLOR_BLACK
|
87
|
+
c.add :starred_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK,
|
88
|
+
Ncurses::A_BOLD
|
89
|
+
c.add :starred_patina_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_GREEN,
|
90
|
+
Ncurses::A_BOLD
|
91
|
+
c.add :snippet_color, Ncurses::COLOR_CYAN, Ncurses::COLOR_BLACK
|
92
|
+
c.add :option_color, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLACK
|
93
|
+
c.add :tagged_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK,
|
94
|
+
Ncurses::A_BOLD
|
95
|
+
c.add :draft_notification_color, Ncurses::COLOR_RED, Ncurses::COLOR_BLACK,
|
96
|
+
Ncurses::A_BOLD
|
97
|
+
end
|
98
|
+
|
99
|
+
log "initializing buffer manager"
|
100
|
+
bm = BufferManager.new
|
101
|
+
|
102
|
+
if Index.usual_sources.any? { |s| !s.done? }
|
103
|
+
log "polling for new mail"
|
104
|
+
pmode = PollMode.new
|
105
|
+
pbuf = bm.spawn "load new messages", pmode
|
106
|
+
pmode.poll
|
107
|
+
# sleep 1
|
108
|
+
# bm.kill_buffer pbuf
|
109
|
+
end
|
110
|
+
|
111
|
+
log "initializing mail index buffer"
|
112
|
+
imode = InboxMode.new
|
113
|
+
ibuf = bm.spawn "inbox", imode
|
114
|
+
|
115
|
+
log "ready for (inter)action!"
|
116
|
+
Logger.make_buf
|
117
|
+
|
118
|
+
bm.draw_screen
|
119
|
+
imode.load_more_threads ibuf.content_height
|
120
|
+
|
121
|
+
until $exception
|
122
|
+
bm.draw_screen
|
123
|
+
c = Ncurses.nonblocking_getch
|
124
|
+
bm.erase_flash
|
125
|
+
|
126
|
+
if c == Ncurses::KEY_RESIZE
|
127
|
+
bm.handle_resize
|
128
|
+
elsif c
|
129
|
+
unless bm.handle_input(c)
|
130
|
+
x = global_keymap.action_for c
|
131
|
+
case x
|
132
|
+
when :quit
|
133
|
+
break
|
134
|
+
when :help
|
135
|
+
curmode = bm.focus_buf.mode
|
136
|
+
bm.spawn_unless_exists("<help for #{curmode.name}>") { HelpMode.new curmode, global_keymap }
|
137
|
+
when :roll_buffers
|
138
|
+
bm.roll_buffers
|
139
|
+
when :roll_buffers_backwards
|
140
|
+
bm.roll_buffers_backwards
|
141
|
+
when :kill_buffer
|
142
|
+
bm.kill_buffer bm.focus_buf unless bm.focus_buf.mode.is_a? InboxMode
|
143
|
+
when :list_buffers
|
144
|
+
bm.spawn_unless_exists("Buffer List") { BufferListMode.new }
|
145
|
+
when :list_contacts
|
146
|
+
mode = ContactListMode.new
|
147
|
+
bm.spawn "compose to contacts", mode
|
148
|
+
when :search
|
149
|
+
text = bm.ask :search, "query: "
|
150
|
+
next unless text && text !~ /^\s*$/
|
151
|
+
mode = SearchResultsMode.new text
|
152
|
+
short_text =
|
153
|
+
if text.length < 20
|
154
|
+
text
|
155
|
+
else
|
156
|
+
text[0 ... 20] + "..."
|
157
|
+
end
|
158
|
+
bm.spawn "search: \"#{short_text}\"", mode
|
159
|
+
bm.draw_screen
|
160
|
+
mode.load_more_threads mode.buffer.content_height
|
161
|
+
when :list_labels
|
162
|
+
b = BufferManager.spawn_unless_exists("all labels") do
|
163
|
+
LabelListMode.new
|
164
|
+
end
|
165
|
+
b.mode.load_in_background
|
166
|
+
when :compose
|
167
|
+
mode = ComposeMode.new
|
168
|
+
bm.spawn "new message", mode
|
169
|
+
mode.edit
|
170
|
+
when :poll
|
171
|
+
b = BufferManager.spawn_unless_exists("load new messages") do
|
172
|
+
PollMode.new
|
173
|
+
end
|
174
|
+
b.mode.poll
|
175
|
+
when :nothing
|
176
|
+
when :redraw
|
177
|
+
bm.completely_redraw_screen
|
178
|
+
else
|
179
|
+
BufferManager.flash "Unknown key press '#{c.to_character}' for #{bm.focus_buf.mode.name}."
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
bm.kill_all_buffers
|
185
|
+
Redwood::LabelManager.save
|
186
|
+
Redwood::ContactManager.save
|
187
|
+
rescue Exception => e
|
188
|
+
$exception ||= e
|
189
|
+
ensure
|
190
|
+
stop_cursing
|
191
|
+
end
|
192
|
+
|
193
|
+
Index.save unless $exception # TODO: think about this
|
194
|
+
|
195
|
+
if $exception
|
196
|
+
if $exception.is_a? IndexError
|
197
|
+
$stderr.puts <<EOS
|
198
|
+
An error occurred while loading a message from source "#{$exception.source}".
|
199
|
+
Typically, this means that the source has been modified in some
|
200
|
+
way which has rendered the messages invalid.
|
201
|
+
|
202
|
+
You must rebuild the index for this source. Please run:
|
203
|
+
sup-import --rebuild #{$exception.source}
|
204
|
+
to correct this error.
|
205
|
+
EOS
|
206
|
+
raise $exception
|
207
|
+
else
|
208
|
+
$stderr.puts <<EOS
|
209
|
+
-----------------------------------------------------------------
|
210
|
+
I'm very sorry, but it seems that an error occurred in Redwood.
|
211
|
+
Please accept my sincere apologies. If you don't mind, please
|
212
|
+
send the backtrace below and a brief report of the circumstances
|
213
|
+
to user wmorgan-sup at site masanjin dot net so that I might
|
214
|
+
address this problem. Thank you!
|
215
|
+
|
216
|
+
Sincerely,
|
217
|
+
William
|
218
|
+
-----------------------------------------------------------------
|
219
|
+
|
220
|
+
The problem was: #{$exception.message} (error type #{$exception.class.name})
|
221
|
+
A backtrace follows:
|
222
|
+
EOS
|
223
|
+
raise $exception
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
end
|
229
|
+
|
data/bin/sup-import
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
#!/bin/env ruby
|
2
|
+
|
3
|
+
require "sup"
|
4
|
+
|
5
|
+
class Float
|
6
|
+
def to_s; sprintf '%.2f', self; end
|
7
|
+
end
|
8
|
+
|
9
|
+
class Numeric
|
10
|
+
def to_time_s
|
11
|
+
i = to_i
|
12
|
+
sprintf "%d:%02d:%02d", i / 3600, (i / 60) % 60, i % 60
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def time
|
17
|
+
startt = Time.now
|
18
|
+
yield
|
19
|
+
Time.now - startt
|
20
|
+
end
|
21
|
+
|
22
|
+
def educate_user
|
23
|
+
$stderr.puts <<EOS
|
24
|
+
Loads messages into the Sup index, adding sources as needed to the
|
25
|
+
source list.
|
26
|
+
|
27
|
+
Usage:
|
28
|
+
sup-import [options] <source>*
|
29
|
+
where <source>* is zero or more source descriptions (e.g., mbox
|
30
|
+
filenames on disk).
|
31
|
+
|
32
|
+
If the sources listed are not already in the Sup source list,
|
33
|
+
they will be added to it, as parameterized by the following options:
|
34
|
+
--archive: messages from these sources will not appear in the inbox
|
35
|
+
--unusual: these sources will not be polled when the flag --the-usual
|
36
|
+
is called
|
37
|
+
|
38
|
+
Regardless of whether the sources are new or not, they will be polled,
|
39
|
+
and any new messages will be added to the index, as parameterized by
|
40
|
+
the following options:
|
41
|
+
--force-archive: regardless of the source "archive" flag, any new
|
42
|
+
messages found will not appear in the inbox.
|
43
|
+
--force-read: any messages found will not be marked as new.
|
44
|
+
|
45
|
+
The following options can also be specified:
|
46
|
+
--the-usual: import new messages from all usual sources
|
47
|
+
--rebuild: rebuild the index for the specified sources rather than
|
48
|
+
just adding new messages. Useful if the sources
|
49
|
+
have changed in any way *other* than new messages
|
50
|
+
being added.
|
51
|
+
--force-rebuild: force a rebuild of all messages in the inbox, not just
|
52
|
+
ones that have changed. You probably won't need this
|
53
|
+
unless William changes the index format.
|
54
|
+
--optimize: optimize the index after adding any new messages.
|
55
|
+
--help: don't do anything, just show this message.
|
56
|
+
EOS
|
57
|
+
#' stupid ruby-mode
|
58
|
+
exit
|
59
|
+
end
|
60
|
+
|
61
|
+
educate_user if ARGV.member? '--help'
|
62
|
+
|
63
|
+
archive = ARGV.delete "--archive"
|
64
|
+
unusual = ARGV.delete "--unusual"
|
65
|
+
force_archive = ARGV.delete "--force-archive"
|
66
|
+
force_read = ARGV.delete "--force-read"
|
67
|
+
the_usual = ARGV.delete "--the-usual"
|
68
|
+
rebuild = ARGV.delete "--rebuild"
|
69
|
+
force_rebuild = ARGV.delete "--force-rebuild"
|
70
|
+
optimize = ARGV.delete "--optimize"
|
71
|
+
|
72
|
+
if(o = ARGV.find { |x| x =~ /^--/ })
|
73
|
+
$stderr.puts "error: unknown option #{o}"
|
74
|
+
educate_user
|
75
|
+
end
|
76
|
+
|
77
|
+
puts "loading index..."
|
78
|
+
index = Redwood::Index.new
|
79
|
+
index.load
|
80
|
+
pre_nm = index.size
|
81
|
+
puts "loaded index of #{index.size} messages"
|
82
|
+
|
83
|
+
sources = ARGV.map do |fn|
|
84
|
+
source = index.source_for fn
|
85
|
+
unless source
|
86
|
+
source = Redwood::MBox::Loader.new(fn, 0, !unusual, !!archive)
|
87
|
+
index.add_source source
|
88
|
+
end
|
89
|
+
source
|
90
|
+
end
|
91
|
+
sources = (sources + index.usual_sources).uniq if the_usual
|
92
|
+
sources.each { |s| s.reset! } if rebuild || force_rebuild
|
93
|
+
|
94
|
+
found = {}
|
95
|
+
start = Time.now
|
96
|
+
begin
|
97
|
+
sources.each do |source|
|
98
|
+
next if source.done?
|
99
|
+
puts "loading from #{source}... "
|
100
|
+
num = 0
|
101
|
+
start_offset = nil
|
102
|
+
source.each do |offset, labels|
|
103
|
+
start_offset ||= offset
|
104
|
+
labels -= [:inbox] if force_archive
|
105
|
+
labels -= [:unread] if force_read
|
106
|
+
begin
|
107
|
+
m = Redwood::Message.new source, offset, labels
|
108
|
+
if found[m.id]
|
109
|
+
puts "skipping duplicate message #{m.id}"
|
110
|
+
next
|
111
|
+
else
|
112
|
+
found[m.id] = true
|
113
|
+
end
|
114
|
+
|
115
|
+
m.remove_label :unread if m.mbox_status == "RO" unless force_read
|
116
|
+
if (rebuild || force_rebuild) &&
|
117
|
+
(docid, entry = index.load_entry_for_id(m.id)) && entry
|
118
|
+
if force_rebuild || entry[:source_info].to_i != offset
|
119
|
+
puts "replacing message #{m.id} labels #{entry[:label].inspect} (offset #{entry[:source_info]} => #{offset})"
|
120
|
+
m.labels = entry[:label].split.map { |l| l.intern }
|
121
|
+
num += 1 if index.update_message m, source, offset
|
122
|
+
end
|
123
|
+
else
|
124
|
+
num += 1 if index.add_message m
|
125
|
+
end
|
126
|
+
rescue Redwood::MessageFormatError => e
|
127
|
+
$stderr.puts "ignoring erroneous message at #{source}##{offset}: #{e.message}"
|
128
|
+
end
|
129
|
+
if num % 1000 == 0 && num > 0
|
130
|
+
elapsed = Time.now - start
|
131
|
+
pctdone = (offset.to_f - start_offset) / (source.total.to_f - start_offset)
|
132
|
+
remaining = (source.total.to_f - offset.to_f) * (elapsed.to_f / (offset.to_f - start_offset))
|
133
|
+
puts "## #{num} (#{(pctdone * 100.0)}% done) read; #{elapsed.to_time_s} elapsed; est. #{remaining.to_time_s} remaining"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
puts "loaded #{num} messages" unless num == 0
|
137
|
+
end
|
138
|
+
ensure
|
139
|
+
index.save
|
140
|
+
end
|
141
|
+
|
142
|
+
if rebuild || force_rebuild
|
143
|
+
puts "deleting missing messages from the index..."
|
144
|
+
numdel = 0
|
145
|
+
sources.each do |source|
|
146
|
+
raise "no source id for #{source}" unless source.id
|
147
|
+
index.index.search_each("source_id:#{source.id}", :limit => :all) do |docid, score|
|
148
|
+
mid = index.index[docid][:message_id]
|
149
|
+
next if found[mid]
|
150
|
+
puts "deleting #{mid}"
|
151
|
+
index.index.delete docid
|
152
|
+
numdel += 1
|
153
|
+
end
|
154
|
+
end
|
155
|
+
puts "deleted #{numdel} messages"
|
156
|
+
end
|
157
|
+
|
158
|
+
if optimize
|
159
|
+
puts "optimizing index..."
|
160
|
+
optt = time { index.index.optimize }
|
161
|
+
puts "optimized index of size #{index.size} in #{optt}s."
|
162
|
+
end
|
data/doc/FAQ.txt
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
Sup FAQ
|
2
|
+
-------
|
3
|
+
|
4
|
+
Q: How is Sup even possible?
|
5
|
+
A: Sup is only possible through the hard work of Dave Balmain, the
|
6
|
+
author of ferret.
|
7
|
+
|
8
|
+
I started using Ferret when it was still slightly buggy, and it
|
9
|
+
seemed like every week Dave released a bugfix or a speed
|
10
|
+
improvement that directly affected sup. Ferret has become a
|
11
|
+
first-class piece of software, and it's almost entirely due to him.
|
12
|
+
It amazes me just how much time and effort he has put into it.
|
13
|
+
|
14
|
+
Q: Why the console?
|
15
|
+
A: As the millions (ok, hundreds) of mutt users will tell you, there are
|
16
|
+
many advantages to the console:
|
17
|
+
- You don't need a bulky web browser.
|
18
|
+
- You can ssh and check your mail on another machine.
|
19
|
+
- Instantaneous interaction.
|
20
|
+
- A few keystrokes are worth a hundred mouse clicks.
|
21
|
+
|
22
|
+
Q: If you love GMail so much, why not just use it?
|
23
|
+
A: I hate using a mouse, and I hate ads, and I hate non-programmability.
|
24
|
+
|
25
|
+
Q: How does Sup deal with spam?
|
26
|
+
A: You can manually mark messages as spam, which prevents them from
|
27
|
+
showing up in future searches, but that's all that Sup does. Spam
|
28
|
+
filtering should be done by a dedicated tool like SpamAssassin.
|
29
|
+
|
30
|
+
Q: What are all these "Redwood" references I see in the code?
|
31
|
+
A: That was Sup's original name. (Think pine, elm. Although I am a
|
32
|
+
Mutt user, I couldn't think of a good progression there.) But it was
|
33
|
+
taken by another project on RubyForge, and wasn't that original,
|
34
|
+
and was too long to type anyways.
|
35
|
+
|
36
|
+
Maybe one day I'll do a huge search-and-replace on the code, but it
|
37
|
+
doesn't seem that important at this point.
|
38
|
+
|