]> git.cworth.org Git - sup/blob - bin/sup-recover-sources
Merge commit 'bw/bw/bounce_message' into next
[sup] / bin / sup-recover-sources
1 #!/usr/bin/env ruby
2
3 require 'optparse'
4
5 $opts = {
6   :unusual => false,
7   :archive => false,
8   :scan_num => 10,
9 }
10
11
12 OPTIONPARSERSUCKS = "\n" + " " * 38
13 OptionParser.new do |opts|
14   opts.banner = <<EOS
15 Usage: sup-recover-sources [options] <source>+
16
17 Rebuilds a lost sources.yaml file by reading messages from a list of
18 sources and determining, for each source, the most prevalent
19 'source_id' field of messages from that source in the index.
20
21 The only non-deterministic component to this is that if the same
22 message appears in multiple sources, those sources may be
23 mis-diagnosed by this program.
24
25 If the first N messages (--scan-num below) all have the same source_id
26 in the index, the source will be added to sources.yaml. Otherwise, the
27 distribution will be printed, and you will have to add it by hand.
28
29 The offset pointer into the sources will be set to the end of the source,
30 so you will have to run sup-import --rebuild for each new source after
31 doing this.
32
33 Options include:
34 EOS
35
36   opts.on("--unusual", "Mark sources as 'unusual'. Only usual#{OPTIONPARSERSUCKS}sources will be polled by hand. Default:#{OPTIONPARSERSUCKS}#{$opts[:unusual]}.") { $opts[:unusual] = true }
37
38   opts.on("--archive", "Mark sources as 'archive'. New messages#{OPTIONPARSERSUCKS}from these sources will not appear in#{OPTIONPARSERSUCKS}the inbox. Default: #{$opts[:archive]}.") { $opts[:archive] = true }
39
40   opts.on("--scan-num N", Integer, "Number of messages to scan per source.#{OPTIONPARSERSUCKS}Default: #{$opts[:scan_num]}.") do |n|
41     $opts[:scan_num] = n
42   end
43
44   opts.on_tail("-h", "--help", "Show this message") do
45     puts opts
46     exit
47   end
48 end.parse(ARGV)
49
50 require "sup"
51 puts "loading index..."
52 index = Redwood::Index.new
53 index.load
54 puts "loaded index of #{index.size} messages"
55
56 ARGV.each do |fn|
57   next if index.source_for fn
58
59   ## TODO: merge this code with the same snippet in import
60   source = 
61     case fn
62     when %r!^imaps?://!
63       print "Username for #{fn}: "
64       username = $stdin.gets.chomp
65       print "Password for #{fn} (warning: cleartext): "
66       password = $stdin.gets.chomp
67       Redwood::IMAP.new(fn, username, password, nil, !$opts[:unusual], $opts[:archive])
68     else
69       Redwood::MBox::Loader.new(fn, nil, !$opts[:unusual], $opts[:archive])
70     end
71
72   source_ids = {}
73   count = 0
74   source.each do |offset, labels|
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]
83   end
84
85   if source_ids.size == 1
86     id = source_ids.keys.first.to_i
87     puts "assigned #{source} to #{source_ids.keys.first}"
88     source.id = id
89     source.seek_to! source.total
90     index.add_source source
91   else
92     puts ">> unable to determine #{source}: #{source_ids.inspect}"
93   end
94 end
95
96 index.save