sup 0.7 → 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.

Files changed (46) hide show
  1. data/CONTRIBUTORS +8 -3
  2. data/History.txt +19 -0
  3. data/README.txt +45 -44
  4. data/ReleaseNotes +6 -0
  5. data/bin/sup +36 -5
  6. data/bin/sup-add +0 -0
  7. data/bin/sup-config +0 -0
  8. data/bin/sup-dump +0 -0
  9. data/bin/sup-recover-sources +8 -12
  10. data/bin/sup-sync +22 -16
  11. data/bin/sup-sync-back +1 -1
  12. data/bin/sup-tweak-labels +8 -8
  13. data/lib/sup.rb +3 -17
  14. data/lib/sup/account.rb +2 -3
  15. data/lib/sup/buffer.rb +21 -10
  16. data/lib/sup/colormap.rb +30 -27
  17. data/lib/sup/contact.rb +1 -1
  18. data/lib/sup/draft.rb +1 -3
  19. data/lib/sup/imap.rb +1 -1
  20. data/lib/sup/index.rb +70 -48
  21. data/lib/sup/label.rb +12 -10
  22. data/lib/sup/logger.rb +1 -1
  23. data/lib/sup/maildir.rb +1 -1
  24. data/lib/sup/mbox.rb +13 -70
  25. data/lib/sup/mbox/loader.rb +26 -15
  26. data/lib/sup/message-chunks.rb +18 -6
  27. data/lib/sup/message.rb +56 -67
  28. data/lib/sup/mode.rb +2 -1
  29. data/lib/sup/modes/buffer-list-mode.rb +6 -2
  30. data/lib/sup/modes/compose-mode.rb +0 -1
  31. data/lib/sup/modes/contact-list-mode.rb +1 -1
  32. data/lib/sup/modes/edit-message-mode.rb +37 -9
  33. data/lib/sup/modes/inbox-mode.rb +34 -0
  34. data/lib/sup/modes/label-list-mode.rb +10 -3
  35. data/lib/sup/modes/reply-mode.rb +24 -13
  36. data/lib/sup/modes/resume-mode.rb +2 -0
  37. data/lib/sup/modes/scroll-mode.rb +10 -9
  38. data/lib/sup/modes/search-results-mode.rb +2 -2
  39. data/lib/sup/modes/thread-index-mode.rb +157 -38
  40. data/lib/sup/modes/thread-view-mode.rb +27 -11
  41. data/lib/sup/person.rb +22 -73
  42. data/lib/sup/poll.rb +18 -20
  43. data/lib/sup/source.rb +44 -0
  44. data/lib/sup/undo.rb +39 -0
  45. data/lib/sup/util.rb +25 -16
  46. metadata +46 -45
@@ -1,17 +1,22 @@
1
- William Morgan <wmorgan-sup at the masanjin dot nets>
2
- Ismo Puustinen <ismo at the iki dot fis>
3
1
  Nicolas Pouillard <nicolas.pouillard at the gmail dot coms>
2
+ Mike Stipicevic <stipim at the rpi dot edus>
4
3
  Marcus Williams <marcus-sup at the bar-coded dot nets>
5
4
  Lionel Ott <white.magic at the gmx dot des>
5
+ Ingmar Vanhassel <ingmar at the exherbo dot orgs>
6
6
  Mark Alexander <marka at the pobox dot coms>
7
7
  Christopher Warrington <chrisw at the rice dot edus>
8
- Marc Hartstein <marc.hartstein at the alum.vassar dot edus>
8
+ Richard Brown <rbrown at the exherbo dot orgs>
9
9
  Ben Walton <bwalton at the artsci.utoronto dot cas>
10
+ Marc Hartstein <marc.hartstein at the alum.vassar dot edus>
10
11
  Grant Hollingworth <grant at the antiflux dot orgs>
11
12
  Steve Goldman <sgoldman at the tower-research dot coms>
12
13
  Decklin Foster <decklin at the red-bean dot coms>
14
+ Ismo Puustinen <ismo at the iki dot fis>
13
15
  Jeff Balogh <its.jeff.balogh at the gmail dot coms>
16
+ Alex Vandiver <alexmv at the mit dot edus>
14
17
  Giorgio Lando <patroclo7 at the gmail dot coms>
15
18
  Israel Herraiz <israel.herraiz at the gmail dot coms>
16
19
  Ian Taylor <ian at the lorf dot orgs>
20
+ Stefan Lundström <lundst at the snabb.(none)>
17
21
  Rich Lane <rlane at the club.cc.cmu dot edus>
22
+ Kirill Smelkov <kirr at the landau.phys.spbu dot rus>
@@ -1,3 +1,22 @@
1
+ == 0.8 / 2009-06-05
2
+ * Undo support on many operations. Yay!
3
+ * Mbox splitting fixes. No more "From "-line problems.
4
+ * Mail parsing speedups.
5
+ * Many utf8 and widechar fixes. Display of crazy characters should be pretty
6
+ close.
7
+ * Outgoing email with non-ASCII headers is now properly encoded.
8
+ * Email addresses are no longer permanently attached to names. This was
9
+ causing problems with automated email systems that used different names
10
+ with the same address.
11
+ * Curses background now retains the terminal default color. This also makes
12
+ Sup work better on transparent terminals.
13
+ * Improve dynamic loading of setlocale for Cygwin and BSD systems.
14
+ * Labels can now be removed from multiple tagged threads.
15
+ * Applying operations to tagged threads is now invoked with '='.
16
+ * Buffer list is betterified and is now invoked with ';'.
17
+ * Zsh autocompletion support.
18
+ * As always, many bugfixes and tweaks.
19
+
1
20
  == 0.7 / 2009-03-16
2
21
  * Ferret index corruption issues fixed (hopefully!)
3
22
  * Text entry now scrolls to the right on overflow, i.e. is actually usable
data/README.txt CHANGED
@@ -13,22 +13,20 @@ Sup makes it easy to:
13
13
  - Handle massive amounts of email.
14
14
 
15
15
  - Mix email from different sources: mbox files (even across different
16
- machines), Maildir directories, IMAP folders, POP accounts, and
17
- GMail accounts.
16
+ machines), Maildir directories, IMAP folders, and GMail accounts.
18
17
 
19
- - Instantaneously search over your entire email collection. Search
20
- over body text, or use a query language to combine search
21
- predicates in any way.
18
+ - Instantaneously search over your entire email collection. Search over
19
+ body text, or use a query language to combine search predicates in any
20
+ way.
22
21
 
23
22
  - Handle multiple accounts. Replying to email sent to a particular
24
- account will use the correct SMTP server, signature, and from
25
- address.
23
+ account will use the correct SMTP server, signature, and from address.
26
24
 
27
- - Add custom code to handle certain types of messages or to handle
28
- certain types of text within messages.
25
+ - Add custom code to customize Sup to whatever particular and bizarre
26
+ needs you may have.
29
27
 
30
- - Organize email with user-defined labels, automatically track
31
- recent contacts, and much more!
28
+ - Organize email with user-defined labels, automatically track recent
29
+ contacts, and much more!
32
30
 
33
31
  The goal of Sup is to become the email client of choice for nerds
34
32
  everywhere.
@@ -48,40 +46,41 @@ Features:
48
46
  message level. Entire threads are manipulated and viewed (with
49
47
  redundancies removed) at a time.
50
48
 
51
- - Labels instead of folders. Drop that tired old metaphor and you'll
52
- see how much easier it is to organize email.
49
+ - Labels instead of folders. Drop that tired old metaphor and you'll see
50
+ how much easier it is to organize email.
53
51
 
54
- - GMail-style thread management (but better!). Archive a thread, and
55
- it will disappear from your inbox until someone replies. Kill a
56
- thread, and it will never come back to your inbox (but will still
57
- show up in searches.) Mark a thread as spam and you'll never again
58
- see it unless explicitly searching for spam.
52
+ - GMail-style thread management. Archive a thread, and it will disappear
53
+ from your inbox until someone replies. Kill a thread, and it will
54
+ never come back to your inbox (but will still show up in searches.)
55
+ Mark a thread as spam and you'll never again see it unless explicitly
56
+ searching for spam.
59
57
 
60
58
  - Console based interface. No mouse clicking required!
61
59
 
62
- - Programmability. It's in Ruby. The code is good. It's easy to
63
- extend.
60
+ - Programmability. It's in Ruby. The code is good. It has an extensive
61
+ hook system that makes it easy to extend and customize.
64
62
 
65
- - Multiple buffer support. Why be limited to viewing one thread at a
63
+ - Multiple buffer support. Why be limited to viewing one thing at a
66
64
  time?
67
65
 
68
- - Tons of other little features, like automatic context-sensitive
69
- help, multi-message operations, MIME attachment viewing, recent
70
- contact list generation, etc.
66
+ - Tons of other little features, like automatic context-sensitive help,
67
+ multi-message operations, MIME attachment viewing, recent contact list
68
+ generation, etc.
71
69
 
72
70
  Current limitations which will be fixed:
73
71
 
74
- - Support for mbox, remote mbox, and IMAP only at this point. No
75
- support for POP, mh, or GMail mailstores.
72
+ - Sup doesn't play nicely with other mail clients. If you alter a mail
73
+ source (read, move, delete, etc) with another client Sup will punish
74
+ you with a lengthy reindexing process.
76
75
 
77
- - No internationalization support. No wide characters, no subject
78
- demangling.
76
+ - Support for mbox, Maildir, and IMAP only at this point. No support for
77
+ POP or mh.
79
78
 
80
- - Unix-centrism in MIME attachment handling and in sendmail
81
- invocation.
79
+ - IMAP support is very slow due mostly to Ruby's IMAP library. You may
80
+ consider something like offlineimap to mirror your IMAP folders with
81
+ local Maildir ones.
82
82
 
83
- - Several obvious missing features, like undo, filters / saved
84
- searches, message annotations, etc.
83
+ - Unix-centrism in MIME attachment handling and in sendmail invocation.
85
84
 
86
85
  == SYNOPSYS:
87
86
 
@@ -90,21 +89,23 @@ Current limitations which will be fixed:
90
89
 
91
90
  Note that Sup never changes the contents of any mailboxes; it only
92
91
  indexes in to them. So it shouldn't ever corrupt your mail. The flip
93
- side is that if you change a mailbox (e.g. delete messages, or, in
94
- the case of mbox files, read an unread message) then Sup will be
95
- unable to load messages from that source and will ask you to run
96
- sup-sync --changed.
92
+ side is that if you change a mailbox (e.g. delete messages, or, in the
93
+ case of mbox files, read an unread message) then Sup will be unable to
94
+ load messages from that source and will ask you to run sup-sync
95
+ --changed.
97
96
 
98
97
  == REQUIREMENTS:
99
98
 
100
- * ferret >= 0.10.13
101
- * ncurses
102
- * rmail
103
- * highline
104
- * net-ssh
105
- * trollop >= 1.7
106
- * lockfile
107
- * mime-types
99
+ - ferret >= 0.11.6
100
+ - ncurses >= 0.9.1
101
+ - rmail >= 0.17
102
+ - highline
103
+ - net-ssh
104
+ - trollop >= 1.12
105
+ - lockfile
106
+ - mime-types
107
+ - gettext
108
+ - fastthread
108
109
 
109
110
  == INSTALL:
110
111
 
@@ -1,3 +1,9 @@
1
+ Release 0.8:
2
+
3
+ The big wins are undo support, mbox splitting fixes, and the various UI
4
+ speedups and bugfixes. Parsing new email should also be faster, although
5
+ IMAP remains tragically slow, as usual.
6
+
1
7
  Release 0.7:
2
8
 
3
9
  The big win in this release is that Ferret index corruption issues should now
data/bin/sup CHANGED
@@ -8,7 +8,7 @@ require 'trollop'
8
8
  require 'fastthread'
9
9
  require "sup"
10
10
 
11
- BIN_VERSION = "0.7"
11
+ BIN_VERSION = "0.8"
12
12
 
13
13
  unless Redwood::VERSION == BIN_VERSION
14
14
  $stderr.puts <<EOS
@@ -67,9 +67,9 @@ global_keymap = Keymap.new do |k|
67
67
  k.add :quit_now, "Quit Sup immediately", 'Q'
68
68
  k.add :help, "Show help", '?'
69
69
  k.add :roll_buffers, "Switch to next buffer", 'b'
70
- # k.add :roll_buffers_backwards, "Switch to previous buffer", 'B'
70
+ k.add :roll_buffers_backwards, "Switch to previous buffer", 'B'
71
71
  k.add :kill_buffer, "Kill the current buffer", 'x'
72
- k.add :list_buffers, "List all buffers", 'B'
72
+ k.add :list_buffers, "List all buffers", ';'
73
73
  k.add :list_contacts, "List contacts", 'C'
74
74
  k.add :redraw, "Redraw screen", :ctrl_l
75
75
  k.add :search, "Search all messages", '\\', 'F'
@@ -81,11 +81,42 @@ global_keymap = Keymap.new do |k|
81
81
  k.add :recall_draft, "Edit most recent draft message", 'R'
82
82
  end
83
83
 
84
+ ## the following magic enables wide characters when used with a ruby
85
+ ## ncurses.so that's been compiled against libncursesw. (note the w.) why
86
+ ## this works, i have no idea. much like pretty much every aspect of
87
+ ## dealing with curses. cargo cult programming at its best.
88
+ ##
89
+ ## BSD users: if libc.so.6 is not found, try installing compat6x.
90
+ require 'dl/import'
91
+ module LibC
92
+ extend DL::Importable
93
+ setlocale_lib = case Config::CONFIG['arch']
94
+ when /darwin/; "libc.dylib"
95
+ when /cygwin/; "cygwin1.dll"
96
+ else; "libc.so.6"
97
+ end
98
+
99
+ Redwood::log "dynamically loading setlocale() from #{setlocale_lib}"
100
+ begin
101
+ dlload setlocale_lib
102
+ extern "void setlocale(int, const char *)"
103
+ Redwood::log "setting locale..."
104
+ LibC.setlocale(6, "") # LC_ALL == 6
105
+ 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
+ if Config::CONFIG['arch'] =~ /bsd/
109
+ Redwood::log "BSD variant detected. You may have to install a compat6x package to acquire libc."
110
+ end
111
+ end
112
+ end
113
+
84
114
  def start_cursing
85
115
  Ncurses.initscr
86
116
  Ncurses.noecho
87
117
  Ncurses.cbreak
88
118
  Ncurses.stdscr.keypad 1
119
+ Ncurses.use_default_colors
89
120
  Ncurses.curs_set 0
90
121
  Ncurses.start_color
91
122
  $cursing = true
@@ -229,7 +260,7 @@ begin
229
260
  when :kill_buffer
230
261
  bm.kill_buffer_safely bm.focus_buf
231
262
  when :list_buffers
232
- bm.spawn_unless_exists("Buffer List") { BufferListMode.new }
263
+ bm.spawn_unless_exists("buffer list", :system => true) { BufferListMode.new }
233
264
  when :list_contacts
234
265
  b, new = bm.spawn_unless_exists("Contact List") { ContactListMode.new }
235
266
  b.mode.load_in_background if new
@@ -240,7 +271,7 @@ begin
240
271
  when :search_unread
241
272
  SearchResultsMode.spawn_from_query "is:unread"
242
273
  when :list_labels
243
- labels = LabelManager.listable_labels.map { |l| LabelManager.string_for l }
274
+ labels = LabelManager.all_labels.map { |l| LabelManager.string_for l }
244
275
  user_label = bm.ask_with_completions :label, "Show threads with label (enter for listing): ", labels
245
276
  unless user_label.nil?
246
277
  if user_label.empty?
File without changes
File without changes
File without changes
@@ -72,18 +72,14 @@ ARGV.each do |fn|
72
72
  source_ids = {}
73
73
  count = 0
74
74
  source.each do |offset, labels|
75
- begin
76
- m = Redwood::Message.new :source => source, :source_info => offset
77
- docid, entry = index.load_entry_for_id m.id
78
- next unless entry
79
- #puts "# #{source} #{offset} #{entry[:source_id]}"
80
-
81
- source_ids[entry[:source_id]] = (source_ids[entry[:source_id]] || 0) + 1
82
- count += 1
83
- break if count == $opts[:scan_num]
84
- rescue Redwood::MessageFormatError => e
85
- puts "# #{e.message}"
86
- end
75
+ m = Redwood::Message.new :source => source, :source_info => offset
76
+ docid, entry = index.load_entry_for_id m.id
77
+ next unless entry
78
+ #puts "# #{source} #{offset} #{entry[:source_id]}"
79
+
80
+ source_ids[entry[:source_id]] = (source_ids[entry[:source_id]] || 0) + 1
81
+ count += 1
82
+ break if count == $opts[:scan_num]
87
83
  end
88
84
 
89
85
  if source_ids.size == 1
@@ -5,6 +5,8 @@ require 'rubygems'
5
5
  require 'trollop'
6
6
  require "sup"
7
7
 
8
+ PROGRESS_UPDATE_INTERVAL = 15 # seconds
9
+
8
10
  class Float
9
11
  def to_s; sprintf '%.2f', self; end
10
12
  def to_time_s
@@ -100,7 +102,7 @@ restored_state =
100
102
  IO.foreach opts[:restore] do |l|
101
103
  l =~ /^(\S+) \((.*?)\)$/ or raise "Can't read dump line: #{l.inspect}"
102
104
  mid, labels = $1, $2
103
- dump[mid] = labels.split(" ").map { |x| x.intern }
105
+ dump[mid] = labels.symbolistize
104
106
  end
105
107
  $stderr.puts "Read #{dump.size} entries from dump file."
106
108
  dump
@@ -122,7 +124,9 @@ begin
122
124
 
123
125
  unless target == :new
124
126
  if opts[:start_at]
125
- sources.each { |s| s.seek_to! opts[:start_at] }
127
+ Trollop::die :start_at, "can only be used on one source" unless sources.size == 1
128
+ sources.first.seek_to! opts[:start_at]
129
+ sources.first.correct_offset! if sources.first.respond_to?(:correct_offset!)
126
130
  else
127
131
  sources.each { |s| s.reset! }
128
132
  end
@@ -137,18 +141,22 @@ begin
137
141
  num_scanned += 1
138
142
  seen[m.id] = true
139
143
 
144
+ if Time.now - last_info_time > PROGRESS_UPDATE_INTERVAL
145
+ last_info_time = Time.now
146
+ elapsed = last_info_time - start_time
147
+ start = opts[:start_at] || source.start_offset
148
+ pctdone = 100.0 * (source.cur_offset - start).to_f / (source.end_offset - start).to_f
149
+ remaining = (100.0 - pctdone) * (elapsed.to_f / pctdone)
150
+ $stderr.printf "## read %dm (about %.0f%%) @ %.1fm/s. %s elapsed, about %s remaining\n", num_scanned, pctdone, num_scanned / elapsed, elapsed.to_time_s, remaining.to_time_s
151
+ end
152
+
140
153
  ## skip if we're operating only on changed messages, the message
141
154
  ## is in the index, and it's unchanged from what the source is
142
155
  ## reporting.
143
156
  next if target == :changed && entry && entry[:source_id].to_i == source.id && entry[:source_info].to_i == offset
144
157
 
145
158
  ## get the state currently in the index
146
- index_state =
147
- if entry
148
- entry[:label].split(/\s+/).map { |x| x.intern }
149
- else
150
- nil
151
- end
159
+ index_state = entry[:label].symbolistize if entry
152
160
 
153
161
  ## skip if we're operating on restored messages, and this one
154
162
  ## ain't.
@@ -158,12 +166,12 @@ begin
158
166
  ## to default source state modification flags.
159
167
  m.labels -= [:inbox] if opts[:archive]
160
168
  m.labels -= [:unread] if opts[:read]
161
- m.labels += opts[:extra_labels].split(/\s*,\s*/).map { |x| x.intern } if opts[:extra_labels]
169
+ m.labels += opts[:extra_labels].strip.split(/\s*,\s*/).map { |x| x.intern } if opts[:extra_labels]
162
170
 
163
171
  ## assign message labels based on the operation we're performing
164
172
  case op
165
173
  when :asis
166
- m.labels = index_state if index_state
174
+ m.labels = ((m.labels - [:unread, :inbox]) + index_state).uniq if index_state
167
175
  when :restore
168
176
  ## if the entry exists on disk
169
177
  if restored_state[m.id]
@@ -176,16 +184,16 @@ begin
176
184
  ## nothin! use default source labels
177
185
  end
178
186
 
179
- if Time.now - last_info_time > 60
187
+ if Time.now - last_info_time > PROGRESS_UPDATE_INTERVAL
180
188
  last_info_time = Time.now
181
189
  elapsed = last_info_time - start_time
182
190
  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
183
191
  remaining = (100.0 - pctdone) * (elapsed.to_f / pctdone)
184
- $stderr.puts "## #{num_scanned} (#{pctdone}%) read; #{elapsed.to_time_s} elapsed; #{remaining.to_time_s} remaining"
192
+ $stderr.printf "## read %dm (about %.0f%%) @ %.1fm/s. %s elapsed, about %s remaining\n", num_scanned, pctdone, num_scanned / elapsed, elapsed.to_time_s, remaining.to_time_s
185
193
  end
186
194
 
187
195
  if index_state.nil?
188
- puts "Adding message #{source}##{offset} with state {#{m.labels * ', '}}" if opts[:verbose]
196
+ puts "Adding message #{source}##{offset} from #{m.from} with state {#{m.labels * ', '}}" if opts[:verbose]
189
197
  num_added += 1
190
198
  else
191
199
  puts "Updating message #{source}##{offset}, source #{entry[:source_id]} => #{source.id}, offset #{entry[:source_info]} => #{offset}, state {#{index_state * ', '}} => {#{m.labels * ', '}}" if opts[:verbose]
@@ -205,9 +213,7 @@ begin
205
213
  ## API.
206
214
  ##
207
215
  ## TODO: move this to Index, i suppose.
208
-
209
-
210
- if target == :all || target == :changed
216
+ if (target == :all || target == :changed) && !opts[:start_at]
211
217
  $stderr.puts "Deleting missing messages from the index..."
212
218
  num_del, num_scanned = 0, 0
213
219
  sources.each do |source|
@@ -109,7 +109,7 @@ EOS
109
109
  num_scanned += 1
110
110
 
111
111
  if entry
112
- labels = entry[:label].split.map { |x| x.intern }.to_boolean_h
112
+ labels = entry[:label].symbolistize.to_boolean_h
113
113
 
114
114
  if labels.member? :deleted
115
115
  if opts[:drop_deleted]
@@ -46,10 +46,12 @@ EOS
46
46
  Other options:
47
47
  EOS
48
48
  opt :verbose, "Print message ids as they're processed."
49
+ opt :very_verbose, "Print message names and subjects as they're processed."
49
50
  opt :all_sources, "Scan over all sources.", :short => :none
50
51
  opt :dry_run, "Don't actually modify the index. Probably only useful with --verbose.", :short => "-n"
51
52
  opt :version, "Show version information", :short => :none
52
53
  end
54
+ opts[:verbose] = true if opts[:very_verbose]
53
55
 
54
56
  add_labels = (opts[:add] || "").split(",").map { |l| l.intern }.uniq
55
57
  remove_labels = (opts[:remove] || "").split(",").map { |l| l.intern }.uniq
@@ -71,7 +73,7 @@ begin
71
73
  end.map { |s| s.id }
72
74
  Trollop::die "nothing to do: no sources" if source_ids.empty?
73
75
 
74
- query = "+(" + source_ids.map { |id| "source_id:#{id}" }.join(" ") + ")"
76
+ query = "+(" + source_ids.map { |id| "source_id:#{id}" }.join(" OR ") + ")"
75
77
  if add_labels.empty?
76
78
  ## if all we're doing is removing labels, we can further restrict the
77
79
  ## query to only messages with those labels
@@ -79,19 +81,15 @@ begin
79
81
  end
80
82
  query += ' ' + opts[:query] if opts[:query]
81
83
 
82
- qobj, opts = Redwood::Index.parse_user_query_string query
83
- query = Redwood::Index.build_query opts.merge(:qobj => qobj)
84
-
85
- results = index.ferret.search query, :limit => :all
86
- num_total = results.total_hits
84
+ docs = Redwood::Index.run_query query
85
+ num_total = docs.size
87
86
 
88
87
  $stderr.puts "Found #{num_total} documents across #{source_ids.length} sources. Scanning..."
89
88
 
90
89
  num_changed = num_scanned = 0
91
90
  last_info_time = start_time = Time.now
92
- results.hits.each do |hit|
91
+ docs.each do |id|
93
92
  num_scanned += 1
94
- id = hit.doc
95
93
 
96
94
  m = index.build_message id
97
95
  old_labels = m.labels.clone
@@ -102,7 +100,9 @@ begin
102
100
 
103
101
  unless m.labels.sort_by { |s| s.to_s } == old_labels.sort_by { |s| s.to_s }
104
102
  num_changed += 1
103
+ puts "From #{m.from}, subject: #{m.subj}" if opts[:very_verbose]
105
104
  puts "#{m.id}: {#{old_labels.join ','}} => {#{m.labels.join ','}}" if opts[:verbose]
105
+ puts if opts[:very_verbose]
106
106
  index.sync_message m unless opts[:dry_run]
107
107
  end
108
108