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.
- data/CONTRIBUTORS +13 -6
- data/History.txt +19 -0
- data/ReleaseNotes +35 -0
- data/bin/sup +82 -77
- data/bin/sup-add +7 -7
- data/bin/sup-config +104 -85
- data/bin/sup-dump +4 -5
- data/bin/sup-recover-sources +9 -10
- data/bin/sup-sync +121 -100
- data/bin/sup-sync-back +18 -15
- data/bin/sup-tweak-labels +24 -21
- data/lib/sup.rb +53 -33
- data/lib/sup/account.rb +0 -2
- data/lib/sup/buffer.rb +47 -22
- data/lib/sup/colormap.rb +6 -6
- data/lib/sup/contact.rb +0 -2
- data/lib/sup/crypto.rb +34 -23
- data/lib/sup/draft.rb +6 -14
- data/lib/sup/ferret_index.rb +471 -0
- data/lib/sup/hook.rb +30 -43
- data/lib/sup/hook.rb.BACKUP.8625.rb +158 -0
- data/lib/sup/hook.rb.BACKUP.8681.rb +158 -0
- data/lib/sup/hook.rb.BASE.8625.rb +155 -0
- data/lib/sup/hook.rb.BASE.8681.rb +155 -0
- data/lib/sup/hook.rb.LOCAL.8625.rb +142 -0
- data/lib/sup/hook.rb.LOCAL.8681.rb +142 -0
- data/lib/sup/hook.rb.REMOTE.8625.rb +145 -0
- data/lib/sup/hook.rb.REMOTE.8681.rb +145 -0
- data/lib/sup/imap.rb +18 -8
- data/lib/sup/index.rb +70 -528
- data/lib/sup/interactive-lock.rb +74 -0
- data/lib/sup/keymap.rb +26 -26
- data/lib/sup/label.rb +2 -4
- data/lib/sup/logger.rb +54 -35
- data/lib/sup/maildir.rb +41 -6
- data/lib/sup/mbox.rb +1 -1
- data/lib/sup/mbox/loader.rb +18 -6
- data/lib/sup/mbox/ssh-file.rb +1 -7
- data/lib/sup/message-chunks.rb +36 -23
- data/lib/sup/message.rb +126 -46
- data/lib/sup/mode.rb +3 -2
- data/lib/sup/modes/console-mode.rb +108 -0
- data/lib/sup/modes/edit-message-mode.rb +15 -5
- data/lib/sup/modes/inbox-mode.rb +2 -4
- data/lib/sup/modes/label-list-mode.rb +1 -1
- data/lib/sup/modes/line-cursor-mode.rb +18 -18
- data/lib/sup/modes/log-mode.rb +29 -16
- data/lib/sup/modes/poll-mode.rb +7 -9
- data/lib/sup/modes/reply-mode.rb +5 -3
- data/lib/sup/modes/scroll-mode.rb +2 -2
- data/lib/sup/modes/search-results-mode.rb +9 -11
- data/lib/sup/modes/text-mode.rb +2 -2
- data/lib/sup/modes/thread-index-mode.rb +26 -16
- data/lib/sup/modes/thread-view-mode.rb +84 -39
- data/lib/sup/person.rb +6 -8
- data/lib/sup/poll.rb +46 -47
- data/lib/sup/rfc2047.rb +1 -5
- data/lib/sup/sent.rb +27 -20
- data/lib/sup/source.rb +90 -13
- data/lib/sup/textfield.rb +4 -4
- data/lib/sup/thread.rb +15 -13
- data/lib/sup/undo.rb +0 -1
- data/lib/sup/update.rb +0 -1
- data/lib/sup/util.rb +51 -43
- data/lib/sup/xapian_index.rb +566 -0
- metadata +57 -46
- data/lib/sup/suicide.rb +0 -36
data/bin/sup-dump
CHANGED
@@ -21,11 +21,10 @@ No options.
|
|
21
21
|
EOS
|
22
22
|
end
|
23
23
|
|
24
|
-
index = Redwood::Index.
|
24
|
+
index = Redwood::Index.init
|
25
|
+
Redwood::SourceManager.init
|
25
26
|
index.load
|
26
27
|
|
27
|
-
|
28
|
-
|
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
|
data/bin/sup-recover-sources
CHANGED
@@ -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.
|
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
|
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
|
-
|
77
|
-
|
78
|
-
|
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
|
-
|
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
|
data/bin/sup-sync
CHANGED
@@ -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
|
-
|
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.
|
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
|
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.
|
97
|
-
|
98
|
-
restored_state =
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
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.
|
115
|
+
index.lock_interactively or exit
|
115
116
|
begin
|
116
117
|
index.load
|
117
118
|
|
118
|
-
sources =
|
119
|
-
|
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
|
-
|
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.
|
146
|
+
Redwood::PollManager.each_message_from source do |m|
|
141
147
|
num_scanned += 1
|
142
148
|
seen[m.id] = true
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
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
|
-
##
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
##
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
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
|
-
|
181
|
-
|
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
|
-
|
184
|
-
|
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
|
-
|
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
|
-
|
206
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
226
|
-
|
227
|
-
puts "Deleting #{
|
228
|
-
index.
|
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
|
-
|
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
|
-
|
240
|
-
optt = time { index.
|
241
|
-
|
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}"
|
data/bin/sup-sync-back
CHANGED
@@ -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.
|
64
|
-
index.
|
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 =
|
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 =
|
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]) &&
|
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.
|
113
|
+
Redwood::PollManager.each_message_from source do |m|
|
109
114
|
num_scanned += 1
|
110
115
|
|
111
|
-
if
|
112
|
-
labels =
|
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}##{
|
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}##{
|
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}##{
|
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}##{
|
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
|