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