sup 0.8.1 → 0.9

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.

Files changed (67) hide show
  1. data/CONTRIBUTORS +13 -6
  2. data/History.txt +19 -0
  3. data/ReleaseNotes +35 -0
  4. data/bin/sup +82 -77
  5. data/bin/sup-add +7 -7
  6. data/bin/sup-config +104 -85
  7. data/bin/sup-dump +4 -5
  8. data/bin/sup-recover-sources +9 -10
  9. data/bin/sup-sync +121 -100
  10. data/bin/sup-sync-back +18 -15
  11. data/bin/sup-tweak-labels +24 -21
  12. data/lib/sup.rb +53 -33
  13. data/lib/sup/account.rb +0 -2
  14. data/lib/sup/buffer.rb +47 -22
  15. data/lib/sup/colormap.rb +6 -6
  16. data/lib/sup/contact.rb +0 -2
  17. data/lib/sup/crypto.rb +34 -23
  18. data/lib/sup/draft.rb +6 -14
  19. data/lib/sup/ferret_index.rb +471 -0
  20. data/lib/sup/hook.rb +30 -43
  21. data/lib/sup/hook.rb.BACKUP.8625.rb +158 -0
  22. data/lib/sup/hook.rb.BACKUP.8681.rb +158 -0
  23. data/lib/sup/hook.rb.BASE.8625.rb +155 -0
  24. data/lib/sup/hook.rb.BASE.8681.rb +155 -0
  25. data/lib/sup/hook.rb.LOCAL.8625.rb +142 -0
  26. data/lib/sup/hook.rb.LOCAL.8681.rb +142 -0
  27. data/lib/sup/hook.rb.REMOTE.8625.rb +145 -0
  28. data/lib/sup/hook.rb.REMOTE.8681.rb +145 -0
  29. data/lib/sup/imap.rb +18 -8
  30. data/lib/sup/index.rb +70 -528
  31. data/lib/sup/interactive-lock.rb +74 -0
  32. data/lib/sup/keymap.rb +26 -26
  33. data/lib/sup/label.rb +2 -4
  34. data/lib/sup/logger.rb +54 -35
  35. data/lib/sup/maildir.rb +41 -6
  36. data/lib/sup/mbox.rb +1 -1
  37. data/lib/sup/mbox/loader.rb +18 -6
  38. data/lib/sup/mbox/ssh-file.rb +1 -7
  39. data/lib/sup/message-chunks.rb +36 -23
  40. data/lib/sup/message.rb +126 -46
  41. data/lib/sup/mode.rb +3 -2
  42. data/lib/sup/modes/console-mode.rb +108 -0
  43. data/lib/sup/modes/edit-message-mode.rb +15 -5
  44. data/lib/sup/modes/inbox-mode.rb +2 -4
  45. data/lib/sup/modes/label-list-mode.rb +1 -1
  46. data/lib/sup/modes/line-cursor-mode.rb +18 -18
  47. data/lib/sup/modes/log-mode.rb +29 -16
  48. data/lib/sup/modes/poll-mode.rb +7 -9
  49. data/lib/sup/modes/reply-mode.rb +5 -3
  50. data/lib/sup/modes/scroll-mode.rb +2 -2
  51. data/lib/sup/modes/search-results-mode.rb +9 -11
  52. data/lib/sup/modes/text-mode.rb +2 -2
  53. data/lib/sup/modes/thread-index-mode.rb +26 -16
  54. data/lib/sup/modes/thread-view-mode.rb +84 -39
  55. data/lib/sup/person.rb +6 -8
  56. data/lib/sup/poll.rb +46 -47
  57. data/lib/sup/rfc2047.rb +1 -5
  58. data/lib/sup/sent.rb +27 -20
  59. data/lib/sup/source.rb +90 -13
  60. data/lib/sup/textfield.rb +4 -4
  61. data/lib/sup/thread.rb +15 -13
  62. data/lib/sup/undo.rb +0 -1
  63. data/lib/sup/update.rb +0 -1
  64. data/lib/sup/util.rb +51 -43
  65. data/lib/sup/xapian_index.rb +566 -0
  66. metadata +57 -46
  67. data/lib/sup/suicide.rb +0 -36
@@ -1,4 +1,8 @@
1
+ William Morgan <wmorgan-sup at the masanjin dot nets>
2
+ Rich Lane <rlane at the club.cc.cmu dot edus>
3
+ Ismo Puustinen <ismo at the iki dot fis>
1
4
  Nicolas Pouillard <nicolas.pouillard at the gmail dot coms>
5
+ Ben Walton <bwalton at the artsci.utoronto dot cas>
2
6
  Mike Stipicevic <stipim at the rpi dot edus>
3
7
  Marcus Williams <marcus-sup at the bar-coded dot nets>
4
8
  Lionel Ott <white.magic at the gmx dot des>
@@ -6,17 +10,20 @@ Ingmar Vanhassel <ingmar at the exherbo dot orgs>
6
10
  Mark Alexander <marka at the pobox dot coms>
7
11
  Christopher Warrington <chrisw at the rice dot edus>
8
12
  Richard Brown <rbrown at the exherbo dot orgs>
9
- Ben Walton <bwalton at the artsci.utoronto dot cas>
10
13
  Marc Hartstein <marc.hartstein at the alum.vassar dot edus>
14
+ Israel Herraiz <israel.herraiz at the gmail dot coms>
11
15
  Grant Hollingworth <grant at the antiflux dot orgs>
16
+ Adeodato Simó <dato at the net.com.org dot ess>
12
17
  Steve Goldman <sgoldman at the tower-research dot coms>
18
+ Edward Z. Yang <ezyang at the mit dot edus>
13
19
  Decklin Foster <decklin at the red-bean dot coms>
14
- Ismo Puustinen <ismo at the iki dot fis>
20
+ Alex Vandiver <alex at the chmrr dot nets>
15
21
  Jeff Balogh <its.jeff.balogh at the gmail dot coms>
16
- Alex Vandiver <alexmv at the mit dot edus>
22
+ Carl Worth <cworth at the cworth dot orgs>
23
+ Kornilios Kourtis <kkourt at the cslab.ece.ntua dot grs>
17
24
  Giorgio Lando <patroclo7 at the gmail dot coms>
18
- Israel Herraiz <israel.herraiz at the gmail dot coms>
25
+ Benoît PIERRE <benoit.pierre at the gmail dot coms>
19
26
  Ian Taylor <ian at the lorf dot orgs>
20
- Stefan Lundström <lundst at the snabb.(none)>
21
- Rich Lane <rlane at the club.cc.cmu dot edus>
27
+ Stefan Lundström
28
+ Michael Hamann <michael at the content-space dot des>
22
29
  Kirill Smelkov <kirr at the landau.phys.spbu dot rus>
@@ -1,3 +1,22 @@
1
+ == 0.9 / 2009-10-01
2
+ * Experimental Xapian backend to replace Ferret. Not everything works with it,
3
+ but it's fast and less likely to barf. See release notes.
4
+ * New keybinding: "G" for reply-all.
5
+ * New hook: custom-search, for adding your own query expansions.
6
+ * Better preemptive thread loading.
7
+ * Random UI tweaks: display labels before subjects, change thread-view-mode's
8
+ 'n' and 'p' commands slightly
9
+ * Better killing of other Sup processes.
10
+ * Die gracefully upon SIGKILL.
11
+ * Finally figure out the curses+ruby magic to make SIGWINCH (i.e. xterm
12
+ resizing) work correctly.
13
+ * Add a console mode (press ~) for interactively playing with the index.
14
+ * Finally figure out the curses magic to stop the weird keyboard behavior after
15
+ leaving the editor.
16
+ * Improved logging. Logging now supports SUP_LOG_LEVEL environment variable.
17
+ Set this to "debug" for verbiage.
18
+ * As always, many bugfixes and tweaks.
19
+
1
20
  == 0.8.1 / 2009-06-15
2
21
  * make multibyte display "work" for non-utf8 locales
3
22
  * fix reply-mode always selecting "Customized"
@@ -1,3 +1,38 @@
1
+ Release 0.9:
2
+
3
+ There's a new Xapian backend as an alternative to the Ferret one. It's still in
4
+ a beta stage. It's much faster and much less prone to the random crashes than
5
+ Ferret, but certain things don't work yet, most noticeably the unread message
6
+ counts in label-list-mode.
7
+
8
+ You can switch back and forth between both indexes without harm, *except* any
9
+ new messages added to the one index won't be picked up by the other. Follow
10
+ these instructions:
11
+
12
+ To TRY the Xapian index, without screwing Ferret up:
13
+
14
+ 1. sup-dump > dump # takes a while
15
+ 2. export SUP_INDEX=xapian # or however you do it in your shell
16
+ 3. sup-sync --all --all-sources --restore dump # takes a long time
17
+ 4. sup -n # -n ensures that no polling is done. don't hit 'P' either
18
+
19
+ Step 1 will take a long time, and step 3 will take a very long time.
20
+
21
+ At this point, whenever you run Sup, the SUP_INDEX environment variable will
22
+ determine which index you use. If it's unset, or "ferret", you will use the
23
+ ferret index. If it's "xapian", the Xapian index. Make sure when you run sup
24
+ with the Xapian index, you use -n and don't hit 'P', to avoid loading new
25
+ messages into it.
26
+
27
+ If you want to switch to Xapian permanently, you can then:
28
+
29
+ 1. rm -rf ~/.sup/ferret
30
+ 2. permanently set SUP_INDEX=xapian according to your shell
31
+ 3. Run sup as normal, i.e. without -n.
32
+
33
+ If you want to go back to Ferret, you can just rm -rf ~/.sup/xapian and make
34
+ sure your SUP_INDEX environment variable is unset.
35
+
1
36
  Release 0.8.1:
2
37
 
3
38
  A bugfix release with fixes for quote parsing (bad behavior in certain long
data/bin/sup CHANGED
@@ -5,10 +5,9 @@ require 'ncurses'
5
5
  require 'curses'
6
6
  require 'fileutils'
7
7
  require 'trollop'
8
- require 'fastthread'
9
8
  require "sup"
10
9
 
11
- BIN_VERSION = "0.8.1"
10
+ BIN_VERSION = "0.9"
12
11
 
13
12
  unless Redwood::VERSION == BIN_VERSION
14
13
  $stderr.puts <<EOS
@@ -59,6 +58,7 @@ if $opts[:list_hooks]
59
58
  end
60
59
 
61
60
  Thread.abort_on_exception = true # make debugging possible
61
+ Thread.current.priority = 1 # keep ui responsive
62
62
 
63
63
  module Redwood
64
64
 
@@ -79,6 +79,8 @@ global_keymap = Keymap.new do |k|
79
79
  k.add :compose, "Compose new message", 'm', 'c'
80
80
  k.add :nothing, "Do nothing", :ctrl_g
81
81
  k.add :recall_draft, "Edit most recent draft message", 'R'
82
+ k.add :show_inbox, "Show the Inbox buffer", 'I'
83
+ k.add :show_console, "Show the Console buffer", '~'
82
84
  end
83
85
 
84
86
  ## the following magic enables wide characters when used with a ruby
@@ -89,24 +91,24 @@ end
89
91
  ## BSD users: if libc.so.6 is not found, try installing compat6x.
90
92
  require 'dl/import'
91
93
  module LibC
92
- extend DL::Importable
94
+ extend DL.const_defined?(:Importer) ? DL::Importer : DL::Importable
93
95
  setlocale_lib = case Config::CONFIG['arch']
94
96
  when /darwin/; "libc.dylib"
95
97
  when /cygwin/; "cygwin1.dll"
96
98
  else; "libc.so.6"
97
99
  end
98
100
 
99
- Redwood::log "dynamically loading setlocale() from #{setlocale_lib}"
101
+ debug "dynamically loading setlocale() from #{setlocale_lib}"
100
102
  begin
101
103
  dlload setlocale_lib
102
104
  extern "void setlocale(int, const char *)"
103
- Redwood::log "setting locale..."
105
+ debug "setting locale..."
104
106
  LibC.setlocale(6, "") # LC_ALL == 6
105
107
  rescue RuntimeError => e
106
- Redwood::log "cannot dlload setlocale(); ncurses wide character support probably broken."
107
- Redwood::log "dlload error was #{e.class}: #{e.message}"
108
+ warn "cannot dlload setlocale(); ncurses wide character support probably broken."
109
+ warn "dlload error was #{e.class}: #{e.message}"
108
110
  if Config::CONFIG['arch'] =~ /bsd/
109
- Redwood::log "BSD variant detected. You may have to install a compat6x package to acquire libc."
111
+ warn "BSD variant detected. You may have to install a compat6x package to acquire libc."
110
112
  end
111
113
  end
112
114
  end
@@ -130,80 +132,68 @@ def stop_cursing
130
132
  end
131
133
  module_function :start_cursing, :stop_cursing
132
134
 
133
- Index.new
134
- begin
135
- Index.lock
136
- rescue Index::LockError => e
137
- require 'highline'
138
-
139
- h = HighLine.new
140
- h.wrap_at = :auto
141
- h.say Index.fancy_lock_error_message_for(e)
142
-
143
- case h.ask("Should I ask that process to kill itself? ")
144
- when /^\s*y(es)?\s*$/i
145
- h.say "Ok, suggesting seppuku..."
146
- FileUtils.touch Redwood::SUICIDE_FN
147
- sleep SuicideManager::DELAY * 2
148
- FileUtils.rm_f Redwood::SUICIDE_FN
149
- h.say "Let's try that again."
150
- retry
151
- else
152
- h.say <<EOS
153
- Ok, giving up. If the process crashed and left a stale lockfile, you
154
- can fix this by manually deleting #{Index.lockfile}.
155
- EOS
156
- exit
157
- end
158
- end
135
+ Index.init
136
+ Index.lock_interactively or exit
159
137
 
160
138
  begin
161
139
  Redwood::start
162
140
  Index.load
163
141
 
164
- if(s = Index.source_for DraftManager.source_name)
142
+ $die = false
143
+ trap("TERM") { |x| $die = true }
144
+ trap("WINCH") { |x| BufferManager.sigwinch_happened! }
145
+
146
+ if(s = Redwood::SourceManager.source_for DraftManager.source_name)
165
147
  DraftManager.source = s
166
148
  else
167
- Redwood::log "no draft source, auto-adding..."
168
- Index.add_source DraftManager.new_source
149
+ debug "no draft source, auto-adding..."
150
+ Redwood::SourceManager.add_source DraftManager.new_source
169
151
  end
170
152
 
171
- if(s = Index.source_for SentManager.source_name)
153
+ if(s = Redwood::SourceManager.source_for SentManager.source_uri)
172
154
  SentManager.source = s
173
155
  else
174
- Redwood::log "no sent mail source, auto-adding..."
175
- Index.add_source SentManager.new_source
156
+ Redwood::SourceManager.add_source SentManager.default_source
176
157
  end
177
158
 
178
159
  HookManager.run "startup"
179
160
 
180
- log "starting curses"
161
+ debug "starting curses"
162
+ Redwood::Logger.remove_sink $stderr
181
163
  start_cursing
182
164
 
183
- bm = BufferManager.new
165
+ bm = BufferManager.init
184
166
  Colormap.new.populate_colormap
185
167
 
186
- log "initializing mail index buffer"
168
+ debug "initializing log buffer"
169
+ lmode = Redwood::LogMode.new "system log"
170
+ lmode.on_kill { Logger.clear! }
171
+ Logger.add_sink lmode
172
+ Logger.force_message "Welcome to Sup! Log level is set to #{Logger.level}."
173
+ if Logger::LEVELS.index(Logger.level) > 0
174
+ Logger.force_message "For more verbose logging, restart with SUP_LOG_LEVEL=#{Logger::LEVELS[Logger::LEVELS.index(Logger.level)-1]}."
175
+ end
176
+
177
+ debug "initializing inbox buffer"
187
178
  imode = InboxMode.new
188
179
  ibuf = bm.spawn "Inbox", imode
189
180
 
190
- log "ready for interaction!"
191
- Logger.make_buf
181
+ debug "ready for interaction!"
192
182
 
193
183
  bm.draw_screen
194
184
 
195
- Index.usual_sources.each do |s|
185
+ Redwood::SourceManager.usual_sources.each do |s|
196
186
  next unless s.respond_to? :connect
197
187
  reporting_thread("call #connect on #{s}") do
198
188
  begin
199
189
  s.connect
200
190
  rescue SourceError => e
201
- Redwood::log "fatal error loading from #{s}: #{e.message}"
191
+ error "fatal error loading from #{s}: #{e.message}"
202
192
  end
203
193
  end
204
194
  end unless $opts[:no_initial_poll]
205
-
206
- imode.load_threads :num => ibuf.content_height, :when_done => lambda { reporting_thread("poll after loading inbox") { sleep 1; PollManager.poll } unless $opts[:no_threads] || $opts[:no_initial_poll] }
195
+
196
+ imode.load_threads :num => ibuf.content_height, :when_done => lambda { |num| reporting_thread("poll after loading inbox") { sleep 1; PollManager.poll } unless $opts[:no_threads] || $opts[:no_initial_poll] }
207
197
 
208
198
  if $opts[:compose]
209
199
  ComposeMode.spawn_nicely :to_default => $opts[:compose]
@@ -211,7 +201,6 @@ begin
211
201
 
212
202
  unless $opts[:no_threads]
213
203
  PollManager.start
214
- SuicideManager.start
215
204
  Index.start_lock_update_thread
216
205
  end
217
206
 
@@ -219,30 +208,40 @@ begin
219
208
  SearchResultsMode.spawn_from_query $opts[:search]
220
209
  end
221
210
 
222
- until Redwood::exceptions.nonempty? || SuicideManager.die?
223
- c =
224
- begin
225
- Ncurses.nonblocking_getch
226
- rescue Exception => e
227
- if e.is_a?(Interrupt)
228
- raise if BufferManager.ask_yes_or_no("Die ungracefully now?")
229
- bm.draw_screen
230
- nil
231
- end
232
- end
233
- next unless c
211
+ until Redwood::exceptions.nonempty? || $die
212
+ c = begin
213
+ Ncurses.nonblocking_getch
214
+ rescue Interrupt
215
+ raise if BufferManager.ask_yes_or_no "Die ungracefully now?"
216
+ BufferManager.draw_screen
217
+ nil
218
+ end
219
+
220
+ if c.nil?
221
+ if BufferManager.sigwinch_happened?
222
+ debug "redrawing screen on sigwinch"
223
+ BufferManager.completely_redraw_screen
224
+ end
225
+ next
226
+ end
227
+
228
+ if c == 410
229
+ ## this is ncurses's way of telling us it's detected a refresh.
230
+ ## since we have our own sigwinch handler, we don't do anything.
231
+ next
232
+ end
233
+
234
234
  bm.erase_flash
235
235
 
236
- action =
237
- begin
238
- if bm.handle_input c
239
- :nothing
240
- else
241
- bm.resolve_input_with_keymap c, global_keymap
242
- end
243
- rescue InputSequenceAborted
236
+ action = begin
237
+ if bm.handle_input c
244
238
  :nothing
239
+ else
240
+ bm.resolve_input_with_keymap c, global_keymap
245
241
  end
242
+ rescue InputSequenceAborted
243
+ :nothing
244
+ end
246
245
  case action
247
246
  when :quit_now
248
247
  break if bm.kill_all_buffers_safely
@@ -298,6 +297,11 @@ begin
298
297
  b, new = BufferManager.spawn_unless_exists("All drafts") { LabelSearchResultsMode.new [:draft] }
299
298
  b.mode.load_threads :num => b.content_height if new
300
299
  end
300
+ when :show_inbox
301
+ BufferManager.raise_to_front ibuf
302
+ when :show_console
303
+ b, new = bm.spawn_unless_exists("Console", :system => true) { ConsoleMode.new }
304
+ b.mode.run
301
305
  when :nothing, InputSequenceAborted
302
306
  when :redraw
303
307
  bm.completely_redraw_screen
@@ -308,13 +312,12 @@ begin
308
312
  bm.draw_screen
309
313
  end
310
314
 
311
- bm.kill_all_buffers if SuicideManager.die?
315
+ bm.kill_all_buffers if $die
312
316
  rescue Exception => e
313
317
  Redwood::record_exception e, "main"
314
318
  ensure
315
319
  unless $opts[:no_threads]
316
320
  PollManager.stop if PollManager.instantiated?
317
- SuicideManager.stop if PollManager.instantiated?
318
321
  Index.stop_lock_update_thread
319
322
  end
320
323
 
@@ -322,17 +325,19 @@ ensure
322
325
 
323
326
  Redwood::finish
324
327
  stop_cursing
325
- Redwood::log "stopped cursing"
328
+ Redwood::Logger.remove_all_sinks!
329
+ Redwood::Logger.add_sink $stderr, false
330
+ debug "stopped cursing"
326
331
 
327
- if SuicideManager.instantiated? && SuicideManager.die?
328
- Redwood::log "I've been ordered to commit seppuku. I obey!"
332
+ if $die
333
+ info "I've been ordered to commit seppuku. I obey!"
329
334
  end
330
335
 
331
336
  if Redwood::exceptions.empty?
332
- Redwood::log "no fatal errors. good job, william."
337
+ debug "no fatal errors. good job, william."
333
338
  Index.save
334
339
  else
335
- Redwood::log "oh crap, an exception"
340
+ error "oh crap, an exception"
336
341
  end
337
342
 
338
343
  Index.unlock
@@ -77,17 +77,17 @@ end
77
77
 
78
78
  $terminal.wrap_at = :auto
79
79
  Redwood::start
80
- index = Redwood::Index.new
80
+ index = Redwood::Index.init
81
81
 
82
- index.lock_or_die
82
+ index.lock_interactively or exit
83
83
 
84
84
  begin
85
- index.load_sources
85
+ Redwood::SourceManager.load_sources
86
86
 
87
87
  ARGV.each do |uri|
88
88
  labels = $opts[:labels] ? $opts[:labels].split(/\s*,\s*/).uniq : []
89
89
 
90
- if !$opts[:force_new] && index.source_for(uri)
90
+ if !$opts[:force_new] && Redwood::SourceManager.source_for(uri)
91
91
  say "Already know about #{uri}; skipping."
92
92
  next
93
93
  end
@@ -99,10 +99,10 @@ begin
99
99
  when "mbox+ssh"
100
100
  say "For SSH connections, if you will use public key authentication, you may leave the username and password blank."
101
101
  say ""
102
- username, password = get_login_info uri, index.sources
102
+ username, password = get_login_info uri, Redwood::SourceManager.sources
103
103
  Redwood::MBox::SSHLoader.new uri, username, password, nil, !$opts[:unusual], $opts[:archive], nil, labels
104
104
  when "imap", "imaps"
105
- username, password = get_login_info uri, index.sources
105
+ username, password = get_login_info uri, Redwood::SourceManager.sources
106
106
  Redwood::IMAP.new uri, username, password, nil, !$opts[:unusual], $opts[:archive], nil, labels
107
107
  when "maildir"
108
108
  Redwood::Maildir.new uri, nil, !$opts[:unusual], $opts[:archive], nil, labels
@@ -114,7 +114,7 @@ begin
114
114
  Trollop::die "Unknown source type #{parsed_uri.scheme.inspect}"
115
115
  end
116
116
  say "Adding #{source}..."
117
- index.add_source source
117
+ Redwood::SourceManager.add_source source
118
118
  end
119
119
  ensure
120
120
  index.save
@@ -17,15 +17,14 @@ Usage:
17
17
 
18
18
  Options:
19
19
  EOS
20
- end #' stupid ruby-mode
20
+ end
21
21
 
22
22
  def axe q, default=nil
23
- ans =
24
- if default && !default.empty?
25
- ask "#{q} (enter for \"#{default}\"): "
26
- else
27
- ask "#{q}: "
28
- end
23
+ ans = if default && !default.empty?
24
+ ask "#{q} (enter for \"#{default}\"): "
25
+ else
26
+ ask "#{q}: "
27
+ end
29
28
  ans.empty? ? default : ans
30
29
  end
31
30
 
@@ -54,64 +53,62 @@ def add_source
54
53
  while true do
55
54
  say "Ok, now for the details."
56
55
 
57
- default_labels, components =
58
- case type
59
- when :mbox
60
- $last_fn ||= ENV["MAIL"]
61
- fn = axe "What's the full path to the mbox file?", $last_fn #"srm
62
- return if fn.nil? || fn.empty?
63
-
64
- $last_fn = fn
65
- [Redwood::MBox::Loader.suggest_labels_for(fn),
66
- { :scheme => "mbox", :path => fn }]
67
- when :maildir
68
- $last_fn ||= ENV["MAIL"]
69
- fn = axe "What's the full path to the maildir directory?", $last_fn #"srm
70
- return if fn.nil? || fn.empty?
71
-
72
- $last_fn = fn
73
- [Redwood::Maildir.suggest_labels_for(fn),
74
- { :scheme => "maildir", :path => fn }]
75
- when :mboxssh
76
- $last_server ||= "localhost"
77
- srv = axe "What machine is the mbox file located on?", $last_server
78
- return if srv.nil? || srv.empty?
79
- $last_server = srv
80
-
81
- fn = axe "What's the path to the mbox file?", $last_fn #" stupid ruby-mode
82
- return if fn.nil? || fn.empty?
83
- $last_fn = fn
84
- fn = "/#{fn}" # lame
85
- [Redwood::MBox::SSHLoader.suggest_labels_for(fn),
86
- { :scheme => "mbox+ssh", :host => srv, :path => fn }]
87
- when :imap, :imaps
88
- $last_server ||= "localhost"
89
- srv = axe "What is the IMAP server (host, or host:port notation)?", $last_server
90
- return if srv.nil? || srv.empty?
91
- $last_server = srv
92
-
93
- $last_folder ||= "INBOX"
94
- fn = axe "What's the folder path?", $last_folder #"srm
95
- return if fn.nil? || fn.empty?
96
- $last_folder = fn
97
-
98
- fn = "/#{fn}" # lame
99
- if srv =~ /^(\S+):(\d+)$/
100
- host, port = $1, $2.to_i
101
- else
102
- host, port = srv, nil
103
- end
104
- [Redwood::IMAP.suggest_labels_for(fn),
105
- { :scheme => type.to_s, :host => host, :port => port, :path => fn }]
106
- end
107
-
108
- uri =
109
- begin
110
- URI::Generic.build components
111
- rescue URI::Error => e
112
- say "Whoopsie! I couldn't build a URI from that: #{e.message}"
113
- if axe_yes("Try again?") then next else return end
56
+ default_labels, components = case type
57
+ when :mbox
58
+ $last_fn ||= ENV["MAIL"]
59
+ fn = axe "What's the full path to the mbox file?", $last_fn
60
+ return if fn.nil? || fn.empty?
61
+
62
+ $last_fn = fn
63
+ [Redwood::MBox::Loader.suggest_labels_for(fn),
64
+ { :scheme => "mbox", :path => fn }]
65
+ when :maildir
66
+ $last_fn ||= ENV["MAIL"]
67
+ fn = axe "What's the full path to the maildir directory?", $last_fn
68
+ return if fn.nil? || fn.empty?
69
+
70
+ $last_fn = fn
71
+ [Redwood::Maildir.suggest_labels_for(fn),
72
+ { :scheme => "maildir", :path => fn }]
73
+ when :mboxssh
74
+ $last_server ||= "localhost"
75
+ srv = axe "What machine is the mbox file located on?", $last_server
76
+ return if srv.nil? || srv.empty?
77
+ $last_server = srv
78
+
79
+ fn = axe "What's the path to the mbox file?", $last_fn
80
+ return if fn.nil? || fn.empty?
81
+ $last_fn = fn
82
+ fn = "/#{fn}" # lame
83
+ [Redwood::MBox::SSHLoader.suggest_labels_for(fn),
84
+ { :scheme => "mbox+ssh", :host => srv, :path => fn }]
85
+ when :imap, :imaps
86
+ $last_server ||= "localhost"
87
+ srv = axe "What is the IMAP server (host, or host:port notation)?", $last_server
88
+ return if srv.nil? || srv.empty?
89
+ $last_server = srv
90
+
91
+ $last_folder ||= "INBOX"
92
+ fn = axe "What's the folder path?", $last_folder
93
+ return if fn.nil? || fn.empty?
94
+ $last_folder = fn
95
+
96
+ fn = "/#{fn}"
97
+ if srv =~ /^(\S+):(\d+)$/
98
+ host, port = $1, $2.to_i
99
+ else
100
+ host, port = srv, nil
114
101
  end
102
+ [Redwood::IMAP.suggest_labels_for(fn),
103
+ { :scheme => type.to_s, :host => host, :port => port, :path => fn }]
104
+ end
105
+
106
+ uri = begin
107
+ URI::Generic.build components
108
+ rescue URI::Error => e
109
+ say "Whoopsie! I couldn't build a URI from that: #{e.message}"
110
+ if axe_yes("Try again?") then next else return end
111
+ end
115
112
 
116
113
  say "I'm going to add this source: #{uri}"
117
114
  unless axe("Does that look right?", "y") =~ /^y|yes$/i
@@ -123,13 +120,12 @@ def add_source
123
120
 
124
121
  labels_str = axe("Enter any labels to be automatically added to all messages from this source, separated by spaces (or 'none')", default_labels.join(","))
125
122
 
126
- labels =
127
- if labels_str =~ /^\s*none\s*$/i
128
- nil
129
- else
130
- labels_str.split(/\s+/)
131
- end
132
-
123
+ labels = if labels_str =~ /^\s*none\s*$/i
124
+ nil
125
+ else
126
+ labels_str.split(/\s+/)
127
+ end
128
+
133
129
  cmd = build_cmd "sup-add"
134
130
  cmd += " --unusual" unless usual
135
131
  cmd += " --archive" if archive
@@ -151,8 +147,8 @@ end
151
147
 
152
148
  $terminal.wrap_at = :auto
153
149
  Redwood::start
154
- index = Redwood::Index.new
155
- index.load_sources
150
+ index = Redwood::Index.init
151
+ Redwood::SourceManager.load_sources
156
152
 
157
153
  say <<EOS
158
154
  Howdy neighbor! This here's sup-config, ready to help you jack in to
@@ -164,14 +160,13 @@ nary a click of the mouse!
164
160
  Just answer these simple questions and you'll be on your way.
165
161
 
166
162
  EOS
167
- #' stupid ruby-mode
168
163
 
169
164
  account = $config[:accounts][:default]
170
165
 
171
166
  name = axe "What's your name?", account[:name]
172
- email = axe "What's your (primary) email address?", account[:email] #'srm
167
+ email = axe "What's your (primary) email address?", account[:email]
173
168
 
174
- say "Ok, your header will look like this:"
169
+ say "Ok, your from header will look like this:"
175
170
  say " From: #{name} <#{email}>"
176
171
 
177
172
  say "\nDo you have any alternate email addresses that also receive email?"
@@ -187,19 +182,15 @@ $config[:accounts][:default][:alternates] = alts
187
182
  $config[:accounts][:default][:signature] = sigfn
188
183
  $config[:editor] = editor
189
184
 
190
- Redwood::save_yaml_obj $config, Redwood::CONFIG_FN
191
-
192
- say "Ok, I've saved you up a nice lil' #{Redwood::CONFIG_FN}."
193
-
194
185
  done = false
195
186
  until done
196
187
  say "\nNow, we'll tell Sup where to find all your email."
197
- index.load_sources
188
+ Redwood::SourceManager.load_sources
198
189
  say "Current sources:"
199
- if index.sources.empty?
190
+ if Redwood::SourceManager.sources.empty?
200
191
  say " No sources!"
201
192
  else
202
- index.sources.each { |s| puts "* #{s}" }
193
+ Redwood::SourceManager.sources.each { |s| puts "* #{s}" }
203
194
  end
204
195
 
205
196
  say "\n"
@@ -210,14 +201,42 @@ until done
210
201
  end
211
202
  end
212
203
 
204
+ say "\nSup needs to know where to store your sent messages."
205
+ say "Only sources capable of storing mail will be listed.\n\n"
206
+
207
+ Redwood::SourceManager.load_sources
208
+ if Redwood::SourceManager.sources.empty?
209
+ say "\nUsing the default sup://sent, since you haven't configured other sources yet."
210
+ $config[:sent_source] = 'sup://sent'
211
+ else
212
+ # this handles the event that source.yaml already contains the SentLoader
213
+ # source.
214
+ have_sup_sent = false
215
+
216
+ choose do |menu|
217
+ menu.prompt = "Store my sent mail in? "
218
+
219
+ menu.choice('Default (an mbox in ~/.sup, aka sup://sent)') { $config[:sent_source] = 'sup://sent'} unless have_sup_sent
220
+
221
+ valid_sents = Redwood::SourceManager.sources.each do |s|
222
+ have_sup_sent = true if s.to_s.eql?('sup://sent')
223
+ menu.choice(s.to_s) { $config[:sent_source] = s.to_s } if s.respond_to? :store_message
224
+ end
225
+ end
226
+ end
227
+
228
+ Redwood::save_yaml_obj $config, Redwood::CONFIG_FN
229
+
230
+ say "Ok, I've saved you up a nice lil' #{Redwood::CONFIG_FN}."
231
+
213
232
  say <<EOS
214
233
 
215
- Ok. The final step is to import all your messages into the Sup index.
234
+ The final step is to import all your messages into the Sup index.
216
235
  Depending on how many messages are in the sources, this could take
217
236
  quite a while.
218
237
 
219
238
  EOS
220
- #'
239
+
221
240
  if axe_yes "Run sup-sync to import all messages now?"
222
241
  while true
223
242
  cmd = build_cmd("sup-sync") + " --all-sources"