sup

A curses threads-with-tags style email client

sup.git

git clone https://supmua.dev/git/sup/

bin/sup-sync-back-maildir (4490B) - raw

      1 #!/usr/bin/env ruby
      2 # encoding: utf-8
      3 
      4 $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
      5 
      6 require 'optimist'
      7 require "sup"
      8 
      9 opts = Optimist::options do
     10   version "sup-sync-back-maildir (sup #{Redwood::VERSION})"
     11   banner <<EOS
     12 Export Xapian entries to Maildir sources on disk.
     13 
     14 This script parses the Xapian entries for a given Maildir source and renames
     15 (changes maildir flags) e-mail files on disk according to the labels stored in
     16 the index. It will export all the changes you made in Sup to your
     17 Maildirs so that they can be propagated to your IMAP server with e.g. offlineimap.
     18 
     19 The script also merges some Maildir flags into Sup such
     20 as R (replied) and P (passed, forwarded), for instance suppose you
     21 have an e-mail file like this: foo_bar:2,FRS (flags are favorite,
     22 replied, seen) and its Xapian entry has labels 'starred', the merge
     23 operation will add the 'replied' label to the Xapian entry.
     24 
     25 If you choose not to merge (-m) you will lose information ('replied'), and in
     26 the previous example the file will be renamed to foo_bar:2,FS.
     27 
     28 Running this script is *strongly* recommended when setting the
     29 "sync_back_to_maildir" option from false to true in config.yaml or changing the
     30 "sync_back" flag to true for a source in sources.yaml.
     31 
     32 Usage:
     33   sup-sync-back-maildir [options] <source>*
     34 
     35 where <source>* is source URIs. If no source is given, the default behavior is
     36 to sync back all Maildir sources marked as usual and that have not disabled
     37 sync back using the configuration parameter sync_back = false in sources.yaml.
     38 
     39 Options include:
     40 EOS
     41   opt :no_confirm, "Don't ask for confirmation before synchronizing", :default => false, :short => "n"
     42   opt :no_merge, "Don't merge new supported Maildir flags (R and P)", :default => false, :short => "m"
     43   opt :list_sources, "List your Maildir sources and exit", :default => false, :short => "l"
     44   opt :unusual_sources_too, "Sync unusual sources too if no specific source information is given", :default => false, :short => "u"
     45 end
     46 
     47 def die msg
     48   $stderr.puts "Error: #{msg}"
     49   exit(-1)
     50 end
     51 
     52 Redwood::start true
     53 index = Redwood::Index.init
     54 index.lock_interactively or exit
     55 index.load
     56 
     57 ## Force sync_back_to_maildir option otherwise nothing will happen
     58 $config[:sync_back_to_maildir] = true
     59 
     60 begin
     61   sync_performed = []
     62   sync_performed = File.readlines(Redwood::SYNC_OK_FN).collect { |e| e.strip }.find_all { |e| not e.empty? } if File.exist? Redwood::SYNC_OK_FN
     63   sources = []
     64 
     65   ## Try to find out sources given in parameters
     66   sources = ARGV.map do |uri|
     67     s = Redwood::SourceManager.source_for(uri) or die "unknown source: #{uri}. Did you add it with sup-add first?"
     68     s.is_a?(Redwood::Maildir) or die "#{uri} is not a Maildir source."
     69     s.sync_back_enabled? or die "#{uri} has disabled sync back - check your configuration."
     70     s
     71   end unless opts[:list_sources]
     72 
     73   ## Otherwise, check all sources in sources.yaml
     74   if sources.empty? or opts[:list_sources] == true
     75     if opts[:unusual_sources_too]
     76       sources = Redwood::SourceManager.sources.select do |s|
     77         s.is_a? Redwood::Maildir and s.sync_back_enabled?
     78       end
     79     else
     80       sources = Redwood::SourceManager.usual_sources.select do |s|
     81         s.is_a? Redwood::Maildir and s.sync_back_enabled?
     82       end
     83     end
     84   end
     85 
     86   if opts[:list_sources] == true
     87     sources.each do |s|
     88       puts "id: #{s.id}, uri: #{s.uri}"
     89     end
     90   else
     91     sources.each do |s|
     92       if opts[:no_confirm] == false
     93         print "Are you sure you want to synchronize '#{s.uri}'? (Y/n) "
     94         next if STDIN.gets.chomp.downcase == 'n'
     95       end
     96 
     97       infos = index.enum_for(:each_source_info, s.id).to_a
     98       counter = 0
     99       infos.each do |info|
    100         print "\rSynchronizing '#{s.uri}'... #{((counter += 1)/infos.size.to_f*100).to_i}%"
    101         index.each_message({:location => [s.id, info]}, false) do |m|
    102           if opts[:no_merge] == false
    103             m.merge_labels_from_locations [:replied, :forwarded]
    104           end
    105 
    106           if Redwood::Index.message_joining_killed? m
    107             m.labels += [:killed]
    108           end
    109 
    110           index.save_message m
    111         end
    112       end
    113       print "\n"
    114       sync_performed << s.uri
    115     end
    116     ## Write a flag file to tell sup that the synchronization has been performed
    117     File.open(Redwood::SYNC_OK_FN, 'w') {|f| f.write(sync_performed.join("\n")) }
    118   end
    119 rescue Exception => e
    120   File.open("sup-exception-log.txt", "w") { |f| f.puts e.backtrace }
    121   raise
    122 ensure
    123   index.save_index
    124   Redwood::finish
    125   index.unlock
    126 end