sup 0.19.0 → 0.23
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +4 -1
- data/.gitmodules +3 -0
- data/.travis.yml +12 -6
- data/CONTRIBUTORS +28 -14
- data/Gemfile +5 -0
- data/History.txt +92 -0
- data/README.md +26 -5
- data/Rakefile +41 -1
- data/ReleaseNotes +17 -0
- data/bin/sup +12 -23
- data/bin/sup-add +15 -16
- data/bin/sup-config +30 -45
- data/bin/sup-dump +2 -3
- data/bin/sup-import-dump +5 -6
- data/bin/sup-sync +3 -4
- data/bin/sup-sync-back-maildir +3 -4
- data/bin/sup-tweak-labels +6 -7
- data/contrib/colorpicker.rb +0 -2
- data/contrib/completion/_sup.bash +102 -0
- data/devel/profile.rb +0 -1
- data/ext/mkrf_conf_xapian.rb +47 -0
- data/lib/sup.rb +10 -8
- data/lib/sup/buffer.rb +12 -0
- data/lib/sup/colormap.rb +5 -2
- data/lib/sup/contact.rb +4 -2
- data/lib/sup/crypto.rb +58 -16
- data/lib/sup/draft.rb +8 -8
- data/lib/sup/hook.rb +9 -9
- data/lib/sup/index.rb +20 -7
- data/lib/sup/label.rb +1 -1
- data/lib/sup/logger.rb +1 -1
- data/lib/sup/maildir.rb +16 -5
- data/lib/sup/mbox.rb +13 -5
- data/lib/sup/message.rb +36 -12
- data/lib/sup/message_chunks.rb +13 -4
- data/lib/sup/mode.rb +34 -28
- data/lib/sup/modes/contact_list_mode.rb +1 -0
- data/lib/sup/modes/edit_message_mode.rb +3 -2
- data/lib/sup/modes/forward_mode.rb +22 -3
- data/lib/sup/modes/line_cursor_mode.rb +1 -1
- data/lib/sup/modes/reply_mode.rb +3 -1
- data/lib/sup/modes/text_mode.rb +6 -1
- data/lib/sup/modes/thread_index_mode.rb +12 -2
- data/lib/sup/modes/thread_view_mode.rb +111 -14
- data/lib/sup/person.rb +68 -61
- data/lib/sup/search.rb +1 -1
- data/lib/sup/sent.rb +1 -1
- data/lib/sup/source.rb +1 -1
- data/lib/sup/util.rb +15 -94
- data/lib/sup/util/axe.rb +17 -0
- data/lib/sup/util/locale_fiddler.rb +24 -0
- data/lib/sup/util/ncurses.rb +3 -3
- data/lib/sup/version.rb +10 -1
- data/sup.gemspec +29 -11
- data/test/{messages → fixtures}/bad-content-transfer-encoding-1.eml +0 -0
- data/test/{messages → fixtures}/binary-content-transfer-encoding-2.eml +0 -0
- data/test/fixtures/blank-header-fields.eml +71 -0
- data/test/fixtures/contacts.txt +1 -0
- data/test/fixtures/mailing-list-header.eml +80 -0
- data/test/fixtures/malicious-attachment-names.eml +55 -0
- data/test/fixtures/missing-from-to.eml +18 -0
- data/test/{messages → fixtures}/missing-line.eml +0 -0
- data/test/fixtures/multi-part-2.eml +72 -0
- data/test/fixtures/multi-part.eml +61 -0
- data/test/fixtures/no-body.eml +18 -0
- data/test/fixtures/simple-message.eml +29 -0
- data/test/fixtures/text-attachments-with-charset.eml +46 -0
- data/test/fixtures/zimbra-quote-with-bottom-post.eml +27 -0
- data/test/gnupg_test_home/gpg.conf +3 -1
- data/test/gnupg_test_home/private-keys-v1.d/306D2EE90FF0014B5B9FD07E265C751791674140.key +0 -0
- data/test/gnupg_test_home/pubring.gpg +0 -0
- data/test/gnupg_test_home/receiver_pubring.gpg +0 -0
- data/test/gnupg_test_home/receiver_secring.gpg +0 -0
- data/test/gnupg_test_home/regen_keys.sh +89 -0
- data/test/gnupg_test_home/secring.gpg +0 -0
- data/test/gnupg_test_home/sup-test-2@foo.bar.asc +20 -17
- data/test/integration/test_maildir.rb +75 -0
- data/test/integration/test_mbox.rb +69 -0
- data/test/test_crypto.rb +14 -2
- data/test/test_header_parsing.rb +1 -1
- data/test/test_helper.rb +6 -3
- data/test/test_message.rb +115 -341
- data/test/test_messages_dir.rb +4 -28
- data/test/test_yaml_regressions.rb +1 -1
- data/test/unit/test_contact.rb +33 -0
- data/test/unit/test_locale_fiddler.rb +15 -0
- data/test/unit/test_person.rb +37 -0
- data/test/unit/util/test_query.rb +10 -4
- data/test/unit/util/test_string.rb +6 -0
- metadata +137 -53
- data/test/gnupg_test_home/receiver_trustdb.gpg +0 -0
- data/test/gnupg_test_home/trustdb.gpg +0 -0
data/bin/sup-add
CHANGED
@@ -3,12 +3,11 @@
|
|
3
3
|
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
4
4
|
|
5
5
|
require 'uri'
|
6
|
-
require '
|
7
|
-
require 'highline/import'
|
8
|
-
require 'trollop'
|
6
|
+
require 'optimist'
|
9
7
|
require "sup"
|
8
|
+
require 'sup/util/axe'
|
10
9
|
|
11
|
-
$opts =
|
10
|
+
$opts = Optimist::options do
|
12
11
|
version "sup-add (sup #{Redwood::VERSION})"
|
13
12
|
banner <<EOS
|
14
13
|
Adds a source to the Sup source list.
|
@@ -36,7 +35,7 @@ EOS
|
|
36
35
|
opt :force_account, "Reuse previously defined account user@hostname.", :type => String
|
37
36
|
end
|
38
37
|
|
39
|
-
|
38
|
+
Optimist::die "require one or more sources" if ARGV.empty?
|
40
39
|
|
41
40
|
## for sources that require login information, prompt the user for
|
42
41
|
## that. also provide a list of previously-defined login info to
|
@@ -54,11 +53,11 @@ def get_login_info uri, sources
|
|
54
53
|
if $opts[:force_account]
|
55
54
|
host, username, password = accounts.find { |h, u, p| $opts[:force_account] == "#{u}@#{h}" }
|
56
55
|
unless username && password
|
57
|
-
say "No previous account #{$opts[:force_account].inspect} found."
|
56
|
+
@cli.say "No previous account #{$opts[:force_account].inspect} found."
|
58
57
|
end
|
59
58
|
else
|
60
|
-
say "Would you like to use the same account as for a previous source for #{uri}?"
|
61
|
-
choose do |menu|
|
59
|
+
@cli.say "Would you like to use the same account as for a previous source for #{uri}?"
|
60
|
+
@cli.choose do |menu|
|
62
61
|
accounts.each do |host, olduser, oldpw|
|
63
62
|
menu.choice("Use the account info for #{olduser}@#{host}") { username, password = olduser, oldpw }
|
64
63
|
end
|
@@ -69,15 +68,15 @@ def get_login_info uri, sources
|
|
69
68
|
end
|
70
69
|
|
71
70
|
unless username && password
|
72
|
-
username = ask("Username for #{uri.host}: ");
|
73
|
-
password = ask("Password for #{uri.host}: ") { |q| q.echo = false }
|
71
|
+
username = @cli.ask("Username for #{uri.host}: ");
|
72
|
+
password = @cli.ask("Password for #{uri.host}: ") { |q| q.echo = false }
|
74
73
|
puts # why?
|
75
74
|
end
|
76
75
|
|
77
76
|
[username, password]
|
78
77
|
end
|
79
78
|
|
80
|
-
|
79
|
+
@cli.wrap_at = :auto
|
81
80
|
Redwood::start
|
82
81
|
index = Redwood::Index.init
|
83
82
|
index.load
|
@@ -91,11 +90,11 @@ begin
|
|
91
90
|
labels = $opts[:labels] ? $opts[:labels].split(/\s*,\s*/).uniq : []
|
92
91
|
|
93
92
|
if !$opts[:force_new] && Redwood::SourceManager.source_for(uri)
|
94
|
-
say "Already know about #{uri}; skipping."
|
93
|
+
@cli.say "Already know about #{uri}; skipping."
|
95
94
|
next
|
96
95
|
end
|
97
96
|
|
98
|
-
parsed_uri = URI(uri)
|
97
|
+
parsed_uri = URI(URI.escape(uri))
|
99
98
|
|
100
99
|
source =
|
101
100
|
case parsed_uri.scheme
|
@@ -104,11 +103,11 @@ begin
|
|
104
103
|
when "mbox"
|
105
104
|
Redwood::MBox.new uri, !$opts[:unusual], $opts[:archive], nil, labels
|
106
105
|
when nil
|
107
|
-
|
106
|
+
Optimist::die "Sources must be specified with an URI"
|
108
107
|
else
|
109
|
-
|
108
|
+
Optimist::die "Unknown source type #{parsed_uri.scheme.inspect}"
|
110
109
|
end
|
111
|
-
say "Adding #{source}..."
|
110
|
+
@cli.say "Adding #{source}..."
|
112
111
|
Redwood::SourceManager.add_source source
|
113
112
|
end
|
114
113
|
ensure
|
data/bin/sup-config
CHANGED
@@ -2,12 +2,11 @@
|
|
2
2
|
|
3
3
|
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
4
4
|
|
5
|
-
require '
|
6
|
-
require 'highline/import'
|
7
|
-
require 'trollop'
|
5
|
+
require 'optimist'
|
8
6
|
require "sup"
|
7
|
+
require 'sup/util/axe'
|
9
8
|
|
10
|
-
$opts =
|
9
|
+
$opts = Optimist::options do
|
11
10
|
version "sup-config (sup #{Redwood::VERSION})"
|
12
11
|
banner <<EOS
|
13
12
|
Interactive configuration tool for Sup. Won't destroy existing
|
@@ -20,20 +19,6 @@ No options.
|
|
20
19
|
EOS
|
21
20
|
end
|
22
21
|
|
23
|
-
def axe q, default=nil
|
24
|
-
question = if default && !default.empty?
|
25
|
-
"#{q} (enter for \"#{default}\"): "
|
26
|
-
else
|
27
|
-
"#{q}: "
|
28
|
-
end
|
29
|
-
ans = ask question
|
30
|
-
ans.empty? ? default : ans.to_s
|
31
|
-
end
|
32
|
-
|
33
|
-
def axe_yes q, default="n"
|
34
|
-
axe(q, default) =~ /^y|yes$/i
|
35
|
-
end
|
36
|
-
|
37
22
|
def build_cmd cmd
|
38
23
|
(ENV["RUBY_INVOCATION"] ? ENV["RUBY_INVOCATION"] + " " : "") + File.join(File.dirname($0), cmd)
|
39
24
|
end
|
@@ -43,8 +28,8 @@ def add_source
|
|
43
28
|
|
44
29
|
type = nil
|
45
30
|
|
46
|
-
say "Ok, adding a new source."
|
47
|
-
choose do |menu|
|
31
|
+
@cli.say "Ok, adding a new source."
|
32
|
+
@cli.choose do |menu|
|
48
33
|
menu.prompt = "What type of mail source is it? "
|
49
34
|
menu.choice("mbox file") { type = :mbox }
|
50
35
|
menu.choice("maildir directory") { type = :maildir }
|
@@ -52,7 +37,7 @@ def add_source
|
|
52
37
|
end
|
53
38
|
|
54
39
|
while true do
|
55
|
-
say "Ok, now for the details."
|
40
|
+
@cli.say "Ok, now for the details."
|
56
41
|
|
57
42
|
default_labels, components = case type
|
58
43
|
when :mbox
|
@@ -76,11 +61,11 @@ def add_source
|
|
76
61
|
uri = begin
|
77
62
|
Redwood::Util::Uri.build components
|
78
63
|
rescue URI::Error => e
|
79
|
-
say "Whoopsie! I couldn't build a URI from that: #{e.message}"
|
64
|
+
@cli.say "Whoopsie! I couldn't build a URI from that: #{e.message}"
|
80
65
|
if axe_yes("Try again?") then next else return end
|
81
66
|
end
|
82
67
|
|
83
|
-
say "I'm going to add this source: #{uri}"
|
68
|
+
@cli.say "I'm going to add this source: #{uri}"
|
84
69
|
unless axe("Does that look right?", "y") =~ /^y|yes$/i
|
85
70
|
if axe_yes("Try again?") then next else return end
|
86
71
|
end
|
@@ -109,21 +94,21 @@ def add_source
|
|
109
94
|
|
110
95
|
system cmd
|
111
96
|
if $?.success?
|
112
|
-
say "Great! Added!"
|
97
|
+
@cli.say "Great! Added!"
|
113
98
|
break
|
114
99
|
else
|
115
|
-
say "Rats, that failed. You may have to do it manually."
|
100
|
+
@cli.say "Rats, that failed. You may have to do it manually."
|
116
101
|
if axe_yes("Try again?") then next else return end
|
117
102
|
end
|
118
103
|
end
|
119
104
|
end
|
120
105
|
|
121
|
-
|
106
|
+
@cli.wrap_at = :auto
|
122
107
|
Redwood::start
|
123
108
|
index = Redwood::Index.init
|
124
109
|
Redwood::SourceManager.load_sources
|
125
110
|
|
126
|
-
say <<EOS
|
111
|
+
@cli.say <<EOS
|
127
112
|
Howdy neighbor! This here's sup-config, ready to help you jack in to
|
128
113
|
the next generation of digital cyberspace: the text-based email
|
129
114
|
program. Get ready to be the envy of everyone in your internets
|
@@ -139,11 +124,11 @@ account = $config[:accounts][:default]
|
|
139
124
|
name = axe "What's your name?", account[:name]
|
140
125
|
email = axe "What's your (primary) email address?", account[:email]
|
141
126
|
|
142
|
-
say "Ok, your from header will look like this:"
|
143
|
-
say " From: #{name} <#{email}>"
|
127
|
+
@cli.say "Ok, your from header will look like this:"
|
128
|
+
@cli.say " From: #{name} <#{email}>"
|
144
129
|
|
145
|
-
say "\nDo you have any alternate email addresses that also receive email?"
|
146
|
-
say "If so, enter them now, separated by spaces."
|
130
|
+
@cli.say "\nDo you have any alternate email addresses that also receive email?"
|
131
|
+
@cli.say "If so, enter them now, separated by spaces."
|
147
132
|
alts = axe("Alternate email addresses", account[:alternates].join(" ")).split(/\s+/)
|
148
133
|
|
149
134
|
sigfn = axe "What file contains your signature?", account[:signature]
|
@@ -160,36 +145,36 @@ $config[:time_mode] = time_mode
|
|
160
145
|
|
161
146
|
done = false
|
162
147
|
until done
|
163
|
-
say "\nNow, we'll tell Sup where to find all your email."
|
148
|
+
@cli.say "\nNow, we'll tell Sup where to find all your email."
|
164
149
|
Redwood::SourceManager.load_sources
|
165
|
-
say "Current sources:"
|
150
|
+
@cli.say "Current sources:"
|
166
151
|
if Redwood::SourceManager.sources.empty?
|
167
|
-
say " No sources!"
|
152
|
+
@cli.say " No sources!"
|
168
153
|
else
|
169
154
|
Redwood::SourceManager.sources.each { |s| puts "* #{s}" }
|
170
155
|
end
|
171
156
|
|
172
|
-
say "\n"
|
173
|
-
choose do |menu|
|
157
|
+
@cli.say "\n"
|
158
|
+
@cli.choose do |menu|
|
174
159
|
menu.prompt = "Your wish? "
|
175
160
|
menu.choice("Add a new source.") { add_source }
|
176
161
|
menu.choice("Done adding sources!") { done = true }
|
177
162
|
end
|
178
163
|
end
|
179
164
|
|
180
|
-
say "\nSup needs to know where to store your sent messages."
|
181
|
-
say "Only sources capable of storing mail will be listed.\n\n"
|
165
|
+
@cli.say "\nSup needs to know where to store your sent messages."
|
166
|
+
@cli.say "Only sources capable of storing mail will be listed.\n\n"
|
182
167
|
|
183
168
|
Redwood::SourceManager.load_sources
|
184
169
|
if Redwood::SourceManager.sources.empty?
|
185
|
-
say "\nUsing the default sup://sent, since you haven't configured other sources yet."
|
170
|
+
@cli.say "\nUsing the default sup://sent, since you haven't configured other sources yet."
|
186
171
|
$config[:sent_source] = 'sup://sent'
|
187
172
|
else
|
188
173
|
# this handles the event that source.yaml already contains the SentLoader
|
189
174
|
# source.
|
190
175
|
have_sup_sent = false
|
191
176
|
|
192
|
-
choose do |menu|
|
177
|
+
@cli.choose do |menu|
|
193
178
|
menu.prompt = "Store my sent mail in? "
|
194
179
|
|
195
180
|
menu.choice('Default (an mbox in ~/.sup, aka sup://sent)') { $config[:sent_source] = 'sup://sent'} unless have_sup_sent
|
@@ -203,9 +188,9 @@ end
|
|
203
188
|
|
204
189
|
Redwood::save_yaml_obj $config, Redwood::CONFIG_FN, false, true
|
205
190
|
|
206
|
-
say "Ok, I've saved you up a nice lil' #{Redwood::CONFIG_FN}."
|
191
|
+
@cli.say "Ok, I've saved you up a nice lil' #{Redwood::CONFIG_FN}."
|
207
192
|
|
208
|
-
say <<EOS
|
193
|
+
@cli.say <<EOS
|
209
194
|
|
210
195
|
The final step is to import all your messages into the Sup index.
|
211
196
|
Depending on how many messages are in the sources, this could take
|
@@ -219,10 +204,10 @@ if axe_yes "Run sup-sync to import all messages now?"
|
|
219
204
|
puts "Ok, trying to run \"#{cmd}\"..."
|
220
205
|
system cmd
|
221
206
|
if $?.success?
|
222
|
-
say "Great! It worked!"
|
207
|
+
@cli.say "Great! It worked!"
|
223
208
|
break
|
224
209
|
else
|
225
|
-
say "Rats, that failed. You may have to do it manually."
|
210
|
+
@cli.say "Rats, that failed. You may have to do it manually."
|
226
211
|
if axe_yes("Try again?") then next else break end
|
227
212
|
end
|
228
213
|
end
|
@@ -230,7 +215,7 @@ end
|
|
230
215
|
|
231
216
|
index.load
|
232
217
|
|
233
|
-
say <<EOS
|
218
|
+
@cli.say <<EOS
|
234
219
|
|
235
220
|
Okee doke, you've got yourself an index of #{index.size} messages. Looks
|
236
221
|
like you're ready to jack in to cyberspace there, cowboy.
|
data/bin/sup-dump
CHANGED
@@ -2,14 +2,13 @@
|
|
2
2
|
|
3
3
|
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
4
4
|
|
5
|
-
require 'rubygems'
|
6
5
|
require 'xapian'
|
7
|
-
require '
|
6
|
+
require 'optimist'
|
8
7
|
require 'set'
|
9
8
|
|
10
9
|
BASE_DIR = ENV["SUP_BASE"] || File.join(ENV["HOME"], ".sup")
|
11
10
|
|
12
|
-
$opts =
|
11
|
+
$opts = Optimist::options do
|
13
12
|
version "sup-dump"
|
14
13
|
banner <<EOS
|
15
14
|
Dumps all message state from the sup index to standard out. You can
|
data/bin/sup-import-dump
CHANGED
@@ -3,8 +3,7 @@
|
|
3
3
|
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
4
4
|
|
5
5
|
require 'uri'
|
6
|
-
require '
|
7
|
-
require 'trollop'
|
6
|
+
require 'optimist'
|
8
7
|
require "sup"
|
9
8
|
|
10
9
|
PROGRESS_UPDATE_INTERVAL = 15 # seconds
|
@@ -12,7 +11,7 @@ PROGRESS_UPDATE_INTERVAL = 15 # seconds
|
|
12
11
|
class AbortExecution < SystemExit
|
13
12
|
end
|
14
13
|
|
15
|
-
opts =
|
14
|
+
opts = Optimist::options do
|
16
15
|
version "sup-import-dump (sup #{Redwood::VERSION})"
|
17
16
|
banner <<EOS
|
18
17
|
Imports message state previously exported by sup-dump into the index.
|
@@ -37,8 +36,8 @@ EOS
|
|
37
36
|
|
38
37
|
conflicts :ignore_missing, :warn_missing, :abort_missing
|
39
38
|
end
|
40
|
-
|
41
|
-
|
39
|
+
Optimist::die "No dump file given" if ARGV.empty?
|
40
|
+
Optimist::die "Extra arguments given" if ARGV.length > 1
|
42
41
|
dump_name = ARGV.shift
|
43
42
|
missing_action = [:ignore_missing, :warn_missing, :abort_missing].find { |x| opts[x] } || :abort_missing
|
44
43
|
|
@@ -82,7 +81,7 @@ begin
|
|
82
81
|
next if opts[:dry_run]
|
83
82
|
|
84
83
|
m.labels = new_labels
|
85
|
-
index.update_message_state m
|
84
|
+
index.update_message_state [m, false]
|
86
85
|
end
|
87
86
|
|
88
87
|
index.commit_transaction if opts[:atomic]
|
data/bin/sup-sync
CHANGED
@@ -3,8 +3,7 @@
|
|
3
3
|
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
4
4
|
|
5
5
|
require 'uri'
|
6
|
-
require '
|
7
|
-
require 'trollop'
|
6
|
+
require 'optimist'
|
8
7
|
require "sup"
|
9
8
|
|
10
9
|
PROGRESS_UPDATE_INTERVAL = 15 # seconds
|
@@ -31,7 +30,7 @@ def time
|
|
31
30
|
Time.now - startt
|
32
31
|
end
|
33
32
|
|
34
|
-
opts =
|
33
|
+
opts = Optimist::options do
|
35
34
|
version "sup-sync (sup #{Redwood::VERSION})"
|
36
35
|
banner <<EOS
|
37
36
|
Synchronizes the Sup index with one or more message sources by adding
|
@@ -113,7 +112,7 @@ begin
|
|
113
112
|
Redwood::SourceManager.usual_sources
|
114
113
|
else
|
115
114
|
ARGV.map do |uri|
|
116
|
-
Redwood::SourceManager.source_for uri or
|
115
|
+
Redwood::SourceManager.source_for uri or Optimist::die "Unknown source: #{uri}. Did you add it with sup-add first?"
|
117
116
|
end
|
118
117
|
end
|
119
118
|
|
data/bin/sup-sync-back-maildir
CHANGED
@@ -3,11 +3,10 @@
|
|
3
3
|
|
4
4
|
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
5
5
|
|
6
|
-
require '
|
7
|
-
require 'trollop'
|
6
|
+
require 'optimist'
|
8
7
|
require "sup"
|
9
8
|
|
10
|
-
opts =
|
9
|
+
opts = Optimist::options do
|
11
10
|
version "sup-sync-back-maildir (sup #{Redwood::VERSION})"
|
12
11
|
banner <<EOS
|
13
12
|
Export Xapian entries to Maildir sources on disk.
|
@@ -60,7 +59,7 @@ $config[:sync_back_to_maildir] = true
|
|
60
59
|
|
61
60
|
begin
|
62
61
|
sync_performed = []
|
63
|
-
sync_performed = File.readlines(Redwood::SYNC_OK_FN).collect { |e| e.strip }.find_all { |e| not e.empty? } if File.
|
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
|
64
63
|
sources = []
|
65
64
|
|
66
65
|
## Try to find out sources given in parameters
|
data/bin/sup-tweak-labels
CHANGED
@@ -2,8 +2,7 @@
|
|
2
2
|
|
3
3
|
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
4
4
|
|
5
|
-
require '
|
6
|
-
require 'trollop'
|
5
|
+
require 'optimist'
|
7
6
|
require "sup"
|
8
7
|
|
9
8
|
class Float
|
@@ -26,7 +25,7 @@ def time
|
|
26
25
|
Time.now - startt
|
27
26
|
end
|
28
27
|
|
29
|
-
opts =
|
28
|
+
opts = Optimist::options do
|
30
29
|
version "sup-tweak-labels (sup #{Redwood::VERSION})"
|
31
30
|
banner <<EOS
|
32
31
|
Batch modification of message state for messages already in the index.
|
@@ -59,7 +58,7 @@ opts[:verbose] = true if opts[:very_verbose]
|
|
59
58
|
add_labels = opts[:add].to_set_of_symbols ","
|
60
59
|
remove_labels = opts[:remove].to_set_of_symbols ","
|
61
60
|
|
62
|
-
|
61
|
+
Optimist::die "nothing to do: no labels to add or remove" if add_labels.empty? && remove_labels.empty?
|
63
62
|
|
64
63
|
Redwood::start
|
65
64
|
index = Redwood::Index.init
|
@@ -72,10 +71,10 @@ begin
|
|
72
71
|
Redwood::SourceManager.sources
|
73
72
|
else
|
74
73
|
ARGV.map do |uri|
|
75
|
-
Redwood::SourceManager.source_for uri or
|
74
|
+
Redwood::SourceManager.source_for uri or Optimist::die "Unknown source: #{uri}. Did you add it with sup-add first?"
|
76
75
|
end
|
77
76
|
end.map { |s| s.id }
|
78
|
-
|
77
|
+
Optimist::die "nothing to do: no sources" if source_ids.empty?
|
79
78
|
|
80
79
|
query = "(" + source_ids.map { |id| "source_id:#{id}" }.join(" OR ") + ")"
|
81
80
|
if add_labels.empty?
|
@@ -83,7 +82,7 @@ begin
|
|
83
82
|
## query to only messages with those labels
|
84
83
|
query += " (" + remove_labels.map { |l| "label:#{l}" }.join(" OR ") + ")"
|
85
84
|
end
|
86
|
-
query += ' ' + opts[:query] if opts[:query]
|
85
|
+
query += ' AND ' + opts[:query] if opts[:query]
|
87
86
|
|
88
87
|
parsed_query = index.parse_query query
|
89
88
|
parsed_query.merge! :load_spam => true, :load_deleted => true, :load_killed => true
|
data/contrib/colorpicker.rb
CHANGED
@@ -0,0 +1,102 @@
|
|
1
|
+
# Sup Bash completion
|
2
|
+
#
|
3
|
+
# * Complete options for all Sup commands.
|
4
|
+
# * Disable completion for next option when current option takes an argument.
|
5
|
+
# * Complete sources, directories, and files, where applicable.
|
6
|
+
|
7
|
+
_sup_cmds() {
|
8
|
+
local cur prev opts sources
|
9
|
+
COMPREPLY=()
|
10
|
+
cur="${COMP_WORDS[COMP_CWORD]}"
|
11
|
+
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
12
|
+
sources="$(sed -n '/uri:/ {s/.*uri:\s*//p}' $HOME/.sup/sources.yaml)"
|
13
|
+
|
14
|
+
case "${1##/*}" in
|
15
|
+
sup-add)
|
16
|
+
opts="--archive -a --unusual -u --sync-back --no-sync-back -s
|
17
|
+
--labels -l --force-new -f --force-account -o --version -v
|
18
|
+
--help -h mbox: maildir:"
|
19
|
+
|
20
|
+
case $prev in
|
21
|
+
--labels|-l|--force-account|-o)
|
22
|
+
COMPREPLY=()
|
23
|
+
return 0
|
24
|
+
;;
|
25
|
+
esac
|
26
|
+
;;
|
27
|
+
sup-config|sup-dump)
|
28
|
+
opts="--version -v --help -h"
|
29
|
+
;;
|
30
|
+
sup-import-dump)
|
31
|
+
opts="--verbose -v --ignore-missing -i --warn-missing -w
|
32
|
+
--abort-missing -a --atomic -t --dry-run -n --version --help
|
33
|
+
-h"
|
34
|
+
;;
|
35
|
+
sup)
|
36
|
+
opts="--list-hooks -l --no-threads -n --no-initial-poll -o --search
|
37
|
+
-s --compose -c --subject -j --version -v --help -h"
|
38
|
+
|
39
|
+
case $prev in
|
40
|
+
--search|-s|--compose|-c|--subject|-j)
|
41
|
+
COMPREPLY=()
|
42
|
+
return 0
|
43
|
+
;;
|
44
|
+
esac
|
45
|
+
;;
|
46
|
+
sup-recover-sources)
|
47
|
+
opts="--unusual --archive --scan-num --help -h $sources"
|
48
|
+
|
49
|
+
case $prev in
|
50
|
+
--scan-num)
|
51
|
+
COMPREPLY=()
|
52
|
+
return 0
|
53
|
+
;;
|
54
|
+
esac
|
55
|
+
;;
|
56
|
+
sup-sync)
|
57
|
+
opts="--asis --restore --discard --archive -x --read -r
|
58
|
+
--extra-labels --verbose -v --optimize -o --all-sources
|
59
|
+
--dry-run -n --version --help -h ${sources}"
|
60
|
+
|
61
|
+
|
62
|
+
case $prev in
|
63
|
+
--restore|--extra-labels)
|
64
|
+
COMPREPLY=()
|
65
|
+
return 0
|
66
|
+
;;
|
67
|
+
esac
|
68
|
+
;;
|
69
|
+
sup-sync-back-maildir)
|
70
|
+
maildir_sources="$(echo $sources | tr ' ' '\n' | grep maildir)"
|
71
|
+
opts="--no-confirm -n --no-merge -m --list-sources -l
|
72
|
+
--unusual-sources-too -u --version -v --help -h
|
73
|
+
$maildir_sources"
|
74
|
+
;;
|
75
|
+
sup-tweak-labels)
|
76
|
+
opts="--add -a --remove -r --query -q --verbose -v --very-verbose
|
77
|
+
-e --all-sources --dry-run -n --no-sync-back -o --version
|
78
|
+
--help -h $sources"
|
79
|
+
|
80
|
+
case $prev in
|
81
|
+
--add|-a|--remove|-r|--query|-q)
|
82
|
+
COMPREPLY=()
|
83
|
+
return 0
|
84
|
+
;;
|
85
|
+
esac
|
86
|
+
;;
|
87
|
+
esac
|
88
|
+
|
89
|
+
COMPREPLY=( $(compgen -W "$opts" -- ${cur}) )
|
90
|
+
return 0
|
91
|
+
}
|
92
|
+
|
93
|
+
complete -F _sup_cmds sup \
|
94
|
+
sup-add \
|
95
|
+
sup-config \
|
96
|
+
sup-dump \
|
97
|
+
sup-recover-sources \
|
98
|
+
sup-sync \
|
99
|
+
sup-sync-back-maildir \
|
100
|
+
sup-tweak-labels
|
101
|
+
|
102
|
+
complete -F _sup_cmds -o filenames -o plusdirs sup-import-dump
|