9 ## save a message 'm' to an open file pointer 'fp'
11 m.source.each_raw_full_message_line(m.source_info) { |l| fp.print l }
14 opts = Trollop::options do
15 version "sup-sync-back (sup #{Redwood::VERSION})"
17 Partially synchronizes a message source with the Sup index by deleting
18 or moving any messages from the source that are marked as deleted or
19 spam in the Sup index.
21 Currently only works with mbox sources.
24 sup-sync-back [options] <source>*
26 where <source>* is zero or more source URIs. If no sources are given,
27 sync back all usual sources.
29 You probably want to run sup-sync --changed after this command.
33 opt :delete_deleted, "Delete deleted messages.", :default => false, :short => "d"
34 opt :move_deleted, "Move deleted messages to a local mbox file.", :type => String, :short => :none
35 opt :delete_spam, "Delete spam messages.", :default => false, :short => "s"
36 opt :move_spam, "Move spam messages to a local mbox file.", :type => String, :short => :none
37 opt :verbose, "Print message ids as they're processed."
38 opt :dry_run, "Don't actually modify the index. Probably only useful with --verbose.", :short => "-n"
39 opt :version, "Show version information", :short => :none
41 conflicts :delete_deleted, :move_deleted
42 conflicts :delete_spam, :move_spam
46 index = Redwood::Index.new
49 deleted_fp, spam_fp = nil
51 deleted_fp = File.open(opts[:move_deleted], "a") if opts[:move_deleted]
52 spam_fp = File.open(opts[:move_spam], "a") if opts[:move_spam]
58 sources = ARGV.map do |uri|
59 s = index.source_for(uri) or Trollop::die "Unknown source: #{uri}. Did you add it with sup-add first?"
60 s.is_a?(Redwood::MBox::Loader) or Trollop::die "#{uri} is not an mbox source."
66 sources = index.usual_sources.select { |s| s.is_a? Redwood::MBox::Loader }
74 sources.each do |source|
75 $stderr.puts "Scanning #{source}..."
77 unless ((opts[:delete_deleted] || opts[:move_deleted]) && index.has_any_from_source_with_label?(source, :deleted)) || ((opts[:delete_spam] || opts[:move_spam]) && index.has_any_from_source_with_label?(source, :spam))
78 $stderr.puts "Nothing to do from this source; skipping"
83 num_deleted = num_moved = num_scanned = 0
85 out_fp = Tempfile.new "sup-sync-back-#{source.id}"
86 Redwood::PollManager.add_messages_from source do |m, offset, entry|
90 labels = entry[:label].split.map { |x| x.intern }.to_boolean_h
92 if labels.member? :deleted
93 if opts[:delete_deleted]
94 puts "Dropping deleted message #{source}##{offset}" if opts[:verbose]
96 elsif opts[:move_deleted] && labels.member?(:deleted)
97 puts "Moving deleted message #{source}##{offset}" if opts[:verbose]
98 save m, deleted_fp unless opts[:dry_run]
102 elsif labels.member? :spam
103 if opts[:delete_spam]
104 puts "Deleting spam message #{source}##{offset}" if opts[:verbose]
106 elsif opts[:move_spam] && labels.member?(:spam)
107 puts "Moving spam message #{source}##{offset}" if opts[:verbose]
108 save m, spam_fp unless opts[:dry_run]
112 save m, out_fp unless opts[:dry_run]
115 save m, out_fp unless opts[:dry_run]
118 nil # don't actually add anything!
120 $stderr.puts "Scanned #{num_scanned}, deleted #{num_deleted}, moved #{num_moved} messages from #{source}."
121 any_modified = true if num_deleted > 0 || num_moved > 0
122 out_fp.close unless opts[:dry_run]
124 unless opts[:dry_run] || !any_modified
125 deleted_fp.flush if deleted_fp
126 spam_fp.flush if spam_fp
128 $stderr.puts "Moving #{out_fp.path} to #{source.file_path}"
129 FileUtils.mv out_fp.path, source.file_path
133 unless opts[:dry_run]
134 deleted_fp.close if deleted_fp
135 spam_fp.close if spam_fp
140 if using_usual_sources
141 $stderr.puts "You should now run: sup-sync --changed"
143 $stderr.puts "You should now run: sup-sync --changed #{sources.join(' ')}"
146 rescue Exception => e
147 File.open("sup-exception-log.txt", "w") { |f| f.puts e.backtrace }