This file is indexed.

/usr/bin/sup-sync is in sup-mail 0.22.1-2.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#!/usr/bin/ruby

$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])

require 'uri'
require 'trollop'
require "sup"

PROGRESS_UPDATE_INTERVAL = 15 # seconds

class Float
  def to_s; sprintf '%.2f', self; end
  def to_time_s; infinite? ? "unknown" : super end
end

class Numeric
  def to_time_s
    i = to_i
    sprintf "%d:%02d:%02d", i / 3600, (i / 60) % 60, i % 60
  end
end

class Set
  def to_s; to_a * ',' end
end

def time
  startt = Time.now
  yield
  Time.now - startt
end

opts = Trollop::options do
  version "sup-sync (sup #{Redwood::VERSION})"
  banner <<EOS
Synchronizes the Sup index with one or more message sources by adding
messages, deleting messages, or changing message state in the index as
appropriate.

"Message state" means read/unread, archived/inbox, starred/unstarred,
and all user-defined labels on each message.

"Default source state" refers to any state that a source itself has
keeps about a message. Sup-sync uses this information when adding a
new message to the index. The source state is typically limited to
read/unread, archived/inbox status and a single label based on the
source name. Messages using the default source state are placed in
the inbox (i.e. not archived) and unstarred.

Usage:
  sup-sync [options] <source>*

where <source>* is zero or more source URIs. If no sources are given,
sync from all usual sources. Supported source URI schemes can be seen
by running "sup-add --help".

Options controlling HOW message state is altered:
EOS
  opt :asis, "If the message is already in the index, preserve its state. Otherwise, use default source state. (Default.)", :short => :none
  opt :restore, "Restore message state from a dump file created with sup-dump. If a message is not in this dumpfile, act as --asis.", :type => String, :short => :none
  opt :discard, "Discard any message state in the index and use the default source state. Dangerous!", :short => :none
  opt :archive, "When using the default source state, mark messages as archived.", :short => "-x"
  opt :read, "When using the default source state, mark messages as read."
  opt :extra_labels, "When using the default source state, also apply these user-defined labels (a comma-separated list)", :default => "", :short => :none

text <<EOS

Other options:
EOS
  opt :verbose, "Print message ids as they're processed."
  opt :optimize, "As the final operation, optimize the index."
  opt :all_sources, "Scan over all sources.", :short => :none
  opt :dry_run, "Don't actually modify the index. Probably only useful with --verbose.", :short => "-n"
  opt :version, "Show version information", :short => :none

  conflicts :asis, :restore, :discard
end

op = [:asis, :restore, :discard].find { |x| opts[x] } || :asis

Redwood::start
index = Redwood::Index.init

restored_state = if opts[:restore]
  dump = {}
  puts "Loading state dump from #{opts[:restore]}..."
  IO.foreach opts[:restore] do |l|
    l =~ /^(\S+) \((.*?)\)$/ or raise "Can't read dump line: #{l.inspect}"
    mid, labels = $1, $2
    dump[mid] = labels.to_set_of_symbols
  end
  puts "Read #{dump.size} entries from dump file."
  dump
else
  {}
end

seen = {}
index.lock_interactively or exit
begin
  index.load

  if(s = Redwood::SourceManager.source_for Redwood::SentManager.source_uri)
    Redwood::SentManager.source = s
  else
    Redwood::SourceManager.add_source Redwood::SentManager.default_source
  end

  sources = if opts[:all_sources]
    Redwood::SourceManager.sources
  elsif ARGV.empty?
    Redwood::SourceManager.usual_sources
  else
    ARGV.map do |uri|
      Redwood::SourceManager.source_for uri or Trollop::die "Unknown source: #{uri}. Did you add it with sup-add first?"
    end
  end

  sources.each do |source|
    puts "Scanning #{source}..."
    num_added = num_updated = num_deleted = num_scanned = num_restored = 0
    last_info_time = start_time = Time.now

    Redwood::PollManager.poll_from source do |action,m,old_m,progress|
      num_scanned += 1
      if action == :delete
        num_deleted += 1
        puts "Deleting #{m.id}" if opts[:verbose]
      elsif action == :add
        seen[m.id] = true

        ## tweak source labels according to commandline arguments if necessary
        m.labels.delete :inbox if opts[:archive]
        m.labels.delete :unread if opts[:read]
        m.labels += opts[:extra_labels].to_set_of_symbols(",")

        ## decide what to do based on message labels and the operation we're performing
        dothis = case
        when (op == :restore) && restored_state[m.id]
          if old_m && (old_m.labels != restored_state[m.id])
            num_restored += 1
            m.labels = restored_state[m.id]
            :update_message_state
          elsif old_m.nil?
            num_restored += 1
            m.labels = restored_state[m.id]
            :add_message
          else
            # labels are the same; don't do anything
          end
        when op == :discard
          if old_m && (old_m.labels != m.labels)
            :update_message_state
          else
            # labels are the same; don't do anything
          end
        else
          if old_m
            :update_message
          else
            :add_message
          end
        end

        ## now, actually do the operation
        case dothis
        when :add_message
          puts "Adding new message #{source}##{m.source_info} with labels #{m.labels}" if opts[:verbose]
          num_added += 1
        when :update_message
          puts "Updating message #{source}##{m.source_info}; labels #{old_m.labels} => #{m.labels}; offset #{old_m.source_info} => #{m.source_info}" if opts[:verbose]
          num_updated += 1
        when :update_message_state
          puts "Changing flags for #{source}##{m.source_info} from #{old_m.labels} to #{m.labels}" if opts[:verbose]
          num_updated += 1
        end
      else fail "sup-sync cannot handle :update's"
      end

      if Time.now - last_info_time > PROGRESS_UPDATE_INTERVAL
        last_info_time = Time.now
        elapsed = last_info_time - start_time
        pctdone = progress * 100.0
        remaining = (100.0 - pctdone) * (elapsed.to_f / pctdone)
        printf "## scanned %dm (~%.0f%%) @ %.1fm/s. %s elapsed, ~%s remaining\n", num_scanned, pctdone, num_scanned / elapsed, elapsed.to_time_s, remaining.to_time_s
      end
      next if opts[:dry_run]
    end

    puts "Scanned #{num_scanned}, added #{num_added}, updated #{num_updated}, deleted #{num_deleted} messages from #{source}."
    puts "Restored state on #{num_restored} (#{100.0 * num_restored / num_scanned}%) messages." if num_restored > 0
  end

  index.save

  if opts[:optimize]
    puts "Optimizing index..."
    optt = time { index.optimize unless opts[:dry_run] }
    puts "Optimized index of size #{index.size} in #{optt}s."
  end
rescue Redwood::FatalSourceError => e
  $stderr.puts "Sorry, I couldn't communicate with a source: #{e.message}"
rescue Exception => e
  File.open("sup-exception-log.txt", "w") { |f| f.puts e.backtrace }
  raise
ensure
  Redwood::finish
  index.unlock
end