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
@@ -21,11 +21,10 @@ No options.
21
21
  EOS
22
22
  end
23
23
 
24
- index = Redwood::Index.new
24
+ index = Redwood::Index.init
25
+ Redwood::SourceManager.init
25
26
  index.load
26
27
 
27
- (1 ... index.index.reader.max_doc).each do |i|
28
- next if index.index.deleted? i
29
- d = index.index[i]
30
- puts [d[:message_id], "(" + d[:label] + ")"] * " "
28
+ index.each_message :load_spam => true, :load_deleted => true, :load_killed => true do |m|
29
+ puts "#{m.id} (#{m.labels.to_a.sort_by { |l| l.to_s } * ' '})"
31
30
  end
@@ -48,13 +48,14 @@ EOS
48
48
  end.parse(ARGV)
49
49
 
50
50
  require "sup"
51
+ Redwood::start
51
52
  puts "loading index..."
52
- index = Redwood::Index.new
53
+ index = Redwood::Index.init
53
54
  index.load
54
55
  puts "loaded index of #{index.size} messages"
55
56
 
56
57
  ARGV.each do |fn|
57
- next if index.source_for fn
58
+ next if Redwood::SourceManager.source_for fn
58
59
 
59
60
  ## TODO: merge this code with the same snippet in import
60
61
  source =
@@ -69,15 +70,14 @@ ARGV.each do |fn|
69
70
  Redwood::MBox::Loader.new(fn, nil, !$opts[:unusual], $opts[:archive])
70
71
  end
71
72
 
72
- source_ids = {}
73
+ source_ids = Hash.new 0
73
74
  count = 0
74
75
  source.each do |offset, labels|
75
76
  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
77
+ m.load_from_source!
78
+ source_id = Redwood::SourceManager.source_for_id m.id
79
+ next unless source_id
80
+ source_ids[source_id] += 1
81
81
  count += 1
82
82
  break if count == $opts[:scan_num]
83
83
  end
@@ -86,8 +86,7 @@ ARGV.each do |fn|
86
86
  id = source_ids.keys.first.to_i
87
87
  puts "assigned #{source} to #{source_ids.keys.first}"
88
88
  source.id = id
89
- source.seek_to! source.total
90
- index.add_source source
89
+ Redwood::SourceManager.add_source source
91
90
  else
92
91
  puts ">> unable to determine #{source}: #{source_ids.inspect}"
93
92
  end
@@ -9,9 +9,7 @@ PROGRESS_UPDATE_INTERVAL = 15 # seconds
9
9
 
10
10
  class Float
11
11
  def to_s; sprintf '%.2f', self; end
12
- def to_time_s
13
- infinite? ? "unknown" : super
14
- end
12
+ def to_time_s; infinite? ? "unknown" : super end
15
13
  end
16
14
 
17
15
  class Numeric
@@ -21,6 +19,10 @@ class Numeric
21
19
  end
22
20
  end
23
21
 
22
+ class Set
23
+ def to_s; to_a * ',' end
24
+ end
25
+
24
26
  def time
25
27
  startt = Time.now
26
28
  yield
@@ -54,10 +56,10 @@ by running "sup-add --help".
54
56
  Options controlling WHICH messages sup-sync operates on:
55
57
  EOS
56
58
  opt :new, "Operate on new messages only. Don't scan over the entire source. (Default.)", :short => :none
57
- opt :changed, "Scan over the entire source for messages that have been deleted, altered, or moved from another source. (In the case of mbox sources, this includes all messages AFTER an altered message.)"
59
+ opt :changed, "Scan over the entire source for messages that have been deleted, altered, or moved from another source."
58
60
  opt :restored, "Operate only on those messages included in a dump file as specified by --restore which have changed state."
59
61
  opt :all, "Operate on all messages in the source, regardless of newness or changedness."
60
- opt :start_at, "For --changed and --all, start at a particular offset.", :type => :int
62
+ opt :start_at, "For --changed, --restored and --all, start at a particular offset.", :type => :int
61
63
 
62
64
  text <<EOS
63
65
 
@@ -68,7 +70,7 @@ EOS
68
70
  opt :discard, "Discard any message state in the index and use the default source state. Dangerous!", :short => :none
69
71
  opt :archive, "When using the default source state, mark messages as archived.", :short => "-x"
70
72
  opt :read, "When using the default source state, mark messages as read."
71
- opt :extra_labels, "When using the default source state, also apply these user-defined labels. Should be a comma-separated list.", :type => String, :short => :none
73
+ opt :extra_labels, "When using the default source state, also apply these user-defined labels (a comma-separated list)", :default => "", :short => :none
72
74
 
73
75
  text <<EOS
74
76
 
@@ -86,42 +88,46 @@ end
86
88
  Trollop::die :restored, "requires --restore" if opts[:restored] unless opts[:restore]
87
89
  if opts[:start_at]
88
90
  Trollop::die :start_at, "must be non-negative" if opts[:start_at] < 0
89
- Trollop::die :start_at, "requires either --changed or --all" unless opts[:changed] || opts[:all]
91
+ Trollop::die :start_at, "requires either --changed, --restored or --all" unless opts[:changed] || opts[:restored] || opts[:all]
90
92
  end
91
93
 
92
94
  target = [:new, :changed, :all, :restored].find { |x| opts[x] } || :new
93
95
  op = [:asis, :restore, :discard].find { |x| opts[x] } || :asis
94
96
 
95
97
  Redwood::start
96
- index = Redwood::Index.new
97
-
98
- restored_state =
99
- if opts[:restore]
100
- dump = {}
101
- $stderr.puts "Loading state dump from #{opts[:restore]}..."
102
- IO.foreach opts[:restore] do |l|
103
- l =~ /^(\S+) \((.*?)\)$/ or raise "Can't read dump line: #{l.inspect}"
104
- mid, labels = $1, $2
105
- dump[mid] = labels.symbolistize
106
- end
107
- $stderr.puts "Read #{dump.size} entries from dump file."
108
- dump
109
- else
110
- {}
98
+ index = Redwood::Index.init
99
+
100
+ restored_state = if opts[:restore]
101
+ dump = {}
102
+ puts "Loading state dump from #{opts[:restore]}..."
103
+ IO.foreach opts[:restore] do |l|
104
+ l =~ /^(\S+) \((.*?)\)$/ or raise "Can't read dump line: #{l.inspect}"
105
+ mid, labels = $1, $2
106
+ dump[mid] = labels.to_set_of_symbols
111
107
  end
108
+ puts "Read #{dump.size} entries from dump file."
109
+ dump
110
+ else
111
+ {}
112
+ end
112
113
 
113
114
  seen = {}
114
- index.lock_or_die
115
+ index.lock_interactively or exit
115
116
  begin
116
117
  index.load
117
118
 
118
- sources = ARGV.map do |uri|
119
- index.source_for uri or Trollop::die "Unknown source: #{uri}. Did you add it with sup-add first?"
119
+ sources = if opts[:all_sources]
120
+ Redwood::SourceManager.sources
121
+ elsif ARGV.empty?
122
+ Redwood::SourceManager.usual_sources
123
+ else
124
+ ARGV.map do |uri|
125
+ Redwood::SourceManager.source_for uri or Trollop::die "Unknown source: #{uri}. Did you add it with sup-add first?"
126
+ end
120
127
  end
121
-
122
- sources = index.usual_sources if sources.empty?
123
- sources = index.sources if opts[:all_sources]
124
128
 
129
+ ## for all target specifications except for only-new messages, reset the
130
+ ## source to the beginning (or to the user-specified starting point.)
125
131
  unless target == :new
126
132
  if opts[:start_at]
127
133
  Trollop::die :start_at, "can only be used on one source" unless sources.size == 1
@@ -131,57 +137,88 @@ begin
131
137
  sources.each { |s| s.reset! }
132
138
  end
133
139
  end
134
-
140
+
135
141
  sources.each do |source|
136
- $stderr.puts "Scanning #{source}..."
142
+ puts "Scanning #{source}..."
137
143
  num_added = num_updated = num_scanned = num_restored = 0
138
144
  last_info_time = start_time = Time.now
139
145
 
140
- Redwood::PollManager.add_messages_from source, :force_overwrite => true do |m, offset, entry|
146
+ Redwood::PollManager.each_message_from source do |m|
141
147
  num_scanned += 1
142
148
  seen[m.id] = true
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
149
+ old_m = index.build_message m.id
150
+
151
+ case target
152
+ when :changed
153
+ ## skip this message if we're operating only on changed messages, the
154
+ ## message is in the index, and it's unchanged from what the source is
155
+ ## reporting.
156
+ next if old_m && old_m.source.id == m.source.id && old_m.source_info == m.source_info
157
+ when :restored
158
+ ## skip if we're operating on restored messages, and this one
159
+ ## ain't (or we wouldn't be making a change)
160
+ next unless old_m && restored_state[m.id] && restored_state[m.id] != old_m.labels
161
+ when :new
162
+ ## nothing to do; we'll consider all messages starting at the start offset, which
163
+ ## hasn't been changed.
164
+ when :all
165
+ ## nothing to do; we'll consider all messages starting at the start offset, which
166
+ ## was reset to the beginning above.
151
167
  end
152
168
 
153
- ## skip if we're operating only on changed messages, the message
154
- ## is in the index, and it's unchanged from what the source is
155
- ## reporting.
156
- next if target == :changed && entry && entry[:source_id].to_i == source.id && entry[:source_info].to_i == offset
157
-
158
- ## get the state currently in the index
159
- index_state = entry[:label].symbolistize if entry
160
-
161
- ## skip if we're operating on restored messages, and this one
162
- ## ain't.
163
- next if target == :restored && (!restored_state[m.id] || (index_state && restored_state[m.id].sort_by { |s| s.to_s } == index_state.sort_by { |s| s.to_s }))
164
-
165
- ## m.labels is the default source labels. tweak these according
166
- ## to default source state modification flags.
167
- m.labels -= [:inbox] if opts[:archive]
168
- m.labels -= [:unread] if opts[:read]
169
- m.labels += opts[:extra_labels].strip.split(/\s*,\s*/).map { |x| x.intern } if opts[:extra_labels]
170
-
171
- ## assign message labels based on the operation we're performing
172
- case op
173
- when :asis
174
- m.labels = ((m.labels - [:unread, :inbox]) + index_state).uniq if index_state
175
- when :restore
176
- ## if the entry exists on disk
177
- if restored_state[m.id]
178
- m.labels = restored_state[m.id]
169
+ ## tweak source labels according to commandline arguments if necessary
170
+ m.labels.delete :inbox if opts[:archive]
171
+ m.labels.delete :unread if opts[:read]
172
+ m.labels += opts[:extra_labels].to_set_of_symbols(",")
173
+
174
+ ## decide what to do based on message labels and the operation we're performing
175
+ dothis, new_labels = case
176
+ when (op == :restore) && restored_state[m.id]
177
+ if old_m && (old_m.labels != restored_state[m.id])
178
+ num_restored += 1
179
+ [:update_message_state, restored_state[m.id]]
180
+ elsif old_m.nil?
179
181
  num_restored += 1
180
- elsif index_state
181
- m.labels = index_state
182
+ m.labels = restored_state[m.id]
183
+ :add_message
184
+ else
185
+ # labels are the same; don't do anything
186
+ end
187
+ when op == :discard
188
+ if old_m && (old_m.labels != m.labels)
189
+ [:update_message_state, m.labels]
190
+ else
191
+ # labels are the same; don't do anything
192
+ end
193
+ else
194
+ ## duplicate behavior of poll mode: if index_state is non-nil, this is a newer
195
+ ## version of an older message, so merge in any new labels except :unread and
196
+ ## :inbox.
197
+ ##
198
+ ## TODO: refactor such that this isn't duplicated
199
+ if old_m
200
+ m.labels = old_m.labels + (m.labels - [:unread, :inbox])
201
+ :update_message
202
+ else
203
+ :add_message
182
204
  end
183
- when :discard
184
- ## nothin! use default source labels
205
+ end
206
+
207
+ ## now, actually do the operation
208
+ case dothis
209
+ when :add_message
210
+ puts "Adding new message #{source}##{m.source_info} with labels #{m.labels}" if opts[:verbose]
211
+ index.add_message m unless opts[:dry_run]
212
+ num_added += 1
213
+ when :update_message
214
+ puts "Updating message #{source}##{m.source_info}; labels #{old_m.labels} => #{m.labels}; offset #{old_m.source_info} => #{m.source_info}" if opts[:verbose]
215
+ index.update_message m unless opts[:dry_run]
216
+ num_updated += 1
217
+ when :update_message_state
218
+ puts "Changing flags for #{source}##{m.source_info} from #{m.labels} to #{new_labels}" if opts[:verbose]
219
+ m.labels = new_labels
220
+ index.update_message_state m unless opts[:dry_run]
221
+ num_updated += 1
185
222
  end
186
223
 
187
224
  if Time.now - last_info_time > PROGRESS_UPDATE_INTERVAL
@@ -189,56 +226,40 @@ begin
189
226
  elapsed = last_info_time - start_time
190
227
  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
191
228
  remaining = (100.0 - pctdone) * (elapsed.to_f / pctdone)
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
193
- end
194
-
195
- if index_state.nil?
196
- puts "Adding message #{source}##{offset} from #{m.from} with state {#{m.labels * ', '}}" if opts[:verbose]
197
- num_added += 1
198
- else
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]
200
- num_updated += 1
229
+ 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
201
230
  end
202
-
203
- opts[:dry_run] ? nil : m
204
231
  end
205
- $stderr.puts "Scanned #{num_scanned}, added #{num_added}, updated #{num_updated} messages from #{source}."
206
- $stderr.puts "Restored state on #{num_restored} (#{100.0 * num_restored / num_scanned}%) messages." if num_restored > 0
232
+
233
+ puts "Scanned #{num_scanned}, added #{num_added}, updated #{num_updated} messages from #{source}."
234
+ puts "Restored state on #{num_restored} (#{100.0 * num_restored / num_scanned}%) messages." if num_restored > 0
207
235
  end
208
236
 
209
237
  ## delete any messages in the index that claim they're from one of
210
238
  ## these sources, but that we didn't see.
211
- ##
212
- ## kinda crappy code here, because we delve directly into the Ferret
213
- ## API.
214
- ##
215
- ## TODO: move this to Index, i suppose.
216
- if (target == :all || target == :changed) && !opts[:start_at]
217
- $stderr.puts "Deleting missing messages from the index..."
239
+ if (target == :all || target == :changed)
240
+ puts "Deleting missing messages from the index..."
218
241
  num_del, num_scanned = 0, 0
219
242
  sources.each do |source|
220
243
  raise "no source id for #{source}" unless source.id
221
- q = "+source_id:#{source.id}"
222
- q += " +source_info: >= #{opts[:start_at]}" if opts[:start_at]
223
- index.index.search_each(q, :limit => :all) do |docid, score|
244
+ index.each_message :source_id => source.id, :load_spam => true, :load_deleted => true, :load_killed => true do |m|
224
245
  num_scanned += 1
225
- mid = index.index[docid][:message_id]
226
- unless seen[mid]
227
- puts "Deleting #{mid}" if opts[:verbose]
228
- index.index.delete docid unless opts[:dry_run]
246
+ unless seen[m.id]
247
+ next unless m.source_info >= opts[:start_at] if opts[:start_at]
248
+ puts "Deleting #{m.id}" if opts[:verbose]
249
+ index.delete m.id unless opts[:dry_run]
229
250
  num_del += 1
230
251
  end
231
252
  end
232
253
  end
233
- $stderr.puts "Deleted #{num_del} / #{num_scanned} messages"
254
+ puts "Deleted #{num_del} / #{num_scanned} messages"
234
255
  end
235
256
 
236
257
  index.save
237
258
 
238
259
  if opts[:optimize]
239
- $stderr.puts "Optimizing index..."
240
- optt = time { index.index.optimize unless opts[:dry_run] }
241
- $stderr.puts "Optimized index of size #{index.size} in #{optt}s."
260
+ puts "Optimizing index..."
261
+ optt = time { index.optimize unless opts[:dry_run] }
262
+ puts "Optimized index of size #{index.size} in #{optt}s."
242
263
  end
243
264
  rescue Redwood::FatalSourceError => e
244
265
  $stderr.puts "Sorry, I couldn't communicate with a source: #{e.message}"
@@ -4,6 +4,7 @@ require 'rubygems'
4
4
  require 'uri'
5
5
  require 'tempfile'
6
6
  require 'trollop'
7
+ require 'enumerator'
7
8
  require "sup"
8
9
 
9
10
  ## save a message 'm' to an open file pointer 'fp'
@@ -14,6 +15,10 @@ def die msg
14
15
  $stderr.puts "Error: #{msg}"
15
16
  exit(-1)
16
17
  end
18
+ def has_any_from_source_with_label? index, source, label
19
+ query = { :source_id => source.id, :label => label, :limit => 1, :load_spam => true, :load_deleted => true, :load_killed => true }
20
+ not Enumerable::Enumerator.new(index, :each_id, query).map.empty?
21
+ end
17
22
 
18
23
  opts = Trollop::options do
19
24
  version "sup-sync-back (sup #{Redwood::VERSION})"
@@ -60,8 +65,8 @@ EOS
60
65
  end
61
66
 
62
67
  Redwood::start
63
- index = Redwood::Index.new
64
- index.lock_or_die
68
+ index = Redwood::Index.init
69
+ index.lock_interactively or exit
65
70
 
66
71
  deleted_fp, spam_fp = nil
67
72
  unless opts[:dry_run]
@@ -75,13 +80,13 @@ begin
75
80
  index.load
76
81
 
77
82
  sources = ARGV.map do |uri|
78
- s = index.source_for(uri) or die "unknown source: #{uri}. Did you add it with sup-add first?"
83
+ s = Redwood::SourceManager.source_for(uri) or die "unknown source: #{uri}. Did you add it with sup-add first?"
79
84
  s.is_a?(Redwood::MBox::Loader) or die "#{uri} is not an mbox source."
80
85
  s
81
86
  end
82
87
 
83
88
  if sources.empty?
84
- sources = index.usual_sources.select { |s| s.is_a? Redwood::MBox::Loader }
89
+ sources = Redwood::SourceManager.usual_sources.select { |s| s.is_a? Redwood::MBox::Loader }
85
90
  end
86
91
 
87
92
  unless sources.all? { |s| s.file_path.nil? } || File.executable?(dotlockfile) || opts[:dont_use_dotlockfile]
@@ -96,37 +101,37 @@ EOS
96
101
  sources.each do |source|
97
102
  $stderr.puts "Scanning #{source}..."
98
103
 
99
- unless ((opts[:drop_deleted] || opts[:move_deleted]) && index.has_any_from_source_with_label?(source, :deleted)) || ((opts[:drop_spam] || opts[:move_spam]) && index.has_any_from_source_with_label?(source, :spam))
104
+ unless ((opts[:drop_deleted] || opts[:move_deleted]) && has_any_from_source_with_label?(index, source, :deleted)) || ((opts[:drop_spam] || opts[:move_spam]) && has_any_from_source_with_label?(index, source, :spam))
100
105
  $stderr.puts "Nothing to do from this source; skipping"
101
106
  next
102
107
  end
103
108
 
104
109
  source.reset!
105
110
  num_dropped = num_moved = num_scanned = 0
106
-
111
+
107
112
  out_fp = Tempfile.new "sup-sync-back-#{source.id}"
108
- Redwood::PollManager.add_messages_from source do |m, offset, entry|
113
+ Redwood::PollManager.each_message_from source do |m|
109
114
  num_scanned += 1
110
115
 
111
- if entry
112
- labels = entry[:label].symbolistize.to_boolean_h
116
+ if(m_old = index.build_message(m.id))
117
+ labels = m_old.labels
113
118
 
114
119
  if labels.member? :deleted
115
120
  if opts[:drop_deleted]
116
- puts "Dropping deleted message #{source}##{offset}" if opts[:verbose]
121
+ puts "Dropping deleted message #{source}##{m.source_info}" if opts[:verbose]
117
122
  num_dropped += 1
118
123
  elsif opts[:move_deleted] && labels.member?(:deleted)
119
- puts "Moving deleted message #{source}##{offset}" if opts[:verbose]
124
+ puts "Moving deleted message #{source}##{m.source_info}" if opts[:verbose]
120
125
  save m, deleted_fp unless opts[:dry_run]
121
126
  num_moved += 1
122
127
  end
123
128
 
124
129
  elsif labels.member? :spam
125
130
  if opts[:drop_spam]
126
- puts "Dropping spam message #{source}##{offset}" if opts[:verbose]
131
+ puts "Dropping spam message #{source}##{m.source_info}" if opts[:verbose]
127
132
  num_dropped += 1
128
133
  elsif opts[:move_spam] && labels.member?(:spam)
129
- puts "Moving spam message #{source}##{offset}" if opts[:verbose]
134
+ puts "Moving spam message #{source}##{m.source_info}" if opts[:verbose]
130
135
  save m, spam_fp unless opts[:dry_run]
131
136
  num_moved += 1
132
137
  end
@@ -136,8 +141,6 @@ EOS
136
141
  else
137
142
  save m, out_fp unless opts[:dry_run]
138
143
  end
139
-
140
- nil # don't actually add anything!
141
144
  end
142
145
  $stderr.puts "Scanned #{num_scanned}, dropped #{num_dropped}, moved #{num_moved} messages from #{source}."
143
146
  modified_sources << source if num_dropped > 0 || num_moved > 0