sup 0.22.1 → 1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/checks.yml +70 -0
  3. data/.gitignore +1 -3
  4. data/.rubocop.yml +5 -0
  5. data/CONTRIBUTORS +14 -5
  6. data/Gemfile +6 -1
  7. data/History.txt +76 -0
  8. data/Manifest.txt +149 -0
  9. data/README.md +32 -5
  10. data/Rakefile +40 -1
  11. data/bin/sup +7 -5
  12. data/bin/sup-add +16 -20
  13. data/bin/sup-config +30 -44
  14. data/bin/sup-dump +2 -2
  15. data/bin/sup-import-dump +4 -4
  16. data/bin/sup-sync +3 -3
  17. data/bin/sup-sync-back-maildir +2 -2
  18. data/bin/sup-tweak-labels +5 -5
  19. data/ext/mkrf_conf_xapian.rb +10 -4
  20. data/lib/sup/colormap.rb +1 -1
  21. data/lib/sup/crypto.rb +17 -8
  22. data/lib/sup/hook.rb +9 -9
  23. data/lib/sup/index.rb +20 -7
  24. data/lib/sup/keymap.rb +1 -1
  25. data/lib/sup/logger.rb +1 -1
  26. data/lib/sup/maildir.rb +4 -4
  27. data/lib/sup/mbox.rb +4 -4
  28. data/lib/sup/message.rb +26 -15
  29. data/lib/sup/message_chunks.rb +29 -20
  30. data/lib/sup/mode.rb +1 -0
  31. data/lib/sup/modes/completion_mode.rb +0 -1
  32. data/lib/sup/modes/contact_list_mode.rb +1 -0
  33. data/lib/sup/modes/file_browser_mode.rb +2 -2
  34. data/lib/sup/modes/label_list_mode.rb +1 -1
  35. data/lib/sup/modes/reply_mode.rb +3 -1
  36. data/lib/sup/modes/search_list_mode.rb +2 -2
  37. data/lib/sup/modes/thread_index_mode.rb +1 -1
  38. data/lib/sup/modes/thread_view_mode.rb +15 -13
  39. data/lib/sup/rfc2047.rb +21 -6
  40. data/lib/sup/source.rb +9 -3
  41. data/lib/sup/textfield.rb +0 -1
  42. data/lib/sup/thread.rb +0 -1
  43. data/lib/sup/util/axe.rb +17 -0
  44. data/lib/sup/util/ncurses.rb +3 -3
  45. data/lib/sup/util.rb +42 -67
  46. data/lib/sup/version.rb +10 -1
  47. data/lib/sup.rb +13 -8
  48. data/man/sup-add.1 +34 -55
  49. data/man/sup-config.1 +23 -36
  50. data/man/sup-dump.1 +25 -35
  51. data/man/sup-import-dump.1 +33 -54
  52. data/man/sup-psych-ify-config-files.1 +25 -34
  53. data/man/sup-recover-sources.1 +34 -49
  54. data/man/sup-sync-back-maildir.1 +39 -60
  55. data/man/sup-sync.1 +49 -79
  56. data/man/sup-tweak-labels.1 +35 -58
  57. data/man/sup.1 +50 -62
  58. data/sup.gemspec +12 -9
  59. data/test/dummy_source.rb +21 -15
  60. data/test/fixtures/embedded-message.eml +34 -0
  61. data/test/fixtures/mailing-list-header.eml +80 -0
  62. data/test/fixtures/non-ascii-header-in-nested-message.eml +36 -0
  63. data/test/fixtures/non-ascii-header.eml +8 -0
  64. data/test/fixtures/rfc2047-header-encoding.eml +15 -0
  65. data/test/fixtures/text-attachments-with-charset.eml +60 -0
  66. data/test/fixtures/utf8-header.eml +17 -0
  67. data/test/fixtures/zimbra-quote-with-bottom-post.eml +27 -0
  68. data/test/gnupg_test_home/gpg.conf +2 -1
  69. data/test/gnupg_test_home/private-keys-v1.d/306D2EE90FF0014B5B9FD07E265C751791674140.key +0 -0
  70. data/test/gnupg_test_home/pubring.gpg +0 -0
  71. data/test/gnupg_test_home/receiver_pubring.gpg +0 -0
  72. data/test/gnupg_test_home/receiver_secring.gpg +0 -0
  73. data/test/gnupg_test_home/regen_keys.sh +69 -18
  74. data/test/gnupg_test_home/secring.gpg +0 -0
  75. data/test/gnupg_test_home/sup-test-2@foo.bar.asc +20 -22
  76. data/test/integration/test_mbox.rb +1 -1
  77. data/test/integration/test_sup-add.rb +83 -0
  78. data/test/test_crypto.rb +46 -0
  79. data/test/test_header_parsing.rb +9 -1
  80. data/test/test_helper.rb +7 -4
  81. data/test/test_message.rb +188 -22
  82. data/test/test_messages_dir.rb +13 -15
  83. data/test/unit/test_horizontal_selector.rb +4 -4
  84. data/test/unit/test_locale_fiddler.rb +1 -1
  85. data/test/unit/util/test_query.rb +10 -4
  86. data/test/unit/util/test_string.rb +9 -3
  87. data/test/unit/util/test_uri.rb +2 -2
  88. metadata +93 -51
  89. data/.travis.yml +0 -13
  90. data/bin/sup-psych-ify-config-files +0 -21
  91. data/test/gnupg_test_home/key1.gen +0 -15
  92. data/test/gnupg_test_home/key2.gen +0 -15
  93. data/test/gnupg_test_home/key_ecc.gen +0 -13
  94. data/test/gnupg_test_home/private-keys-v1.d/719C7455A7169C6EE8819C6E91002E4F9DD00A65.key +0 -1
  95. data/test/gnupg_test_home/private-keys-v1.d/8A130806A754AA29D59487D76BD355040D9F26C0.key +0 -0
  96. data/test/gnupg_test_home/private-keys-v1.d/B7AA46B22BD8A6AD1B4F266C19A3B124A32DDD71.key +0 -0
  97. data/test/gnupg_test_home/private-keys-v1.d/FA64ACD7CC871371BDF57285A6CDF0E618827783.key +0 -0
  98. data/test/integration/test_label_service.rb +0 -18
  99. data/test/test_yaml_migration.rb +0 -85
data/bin/sup-config CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
4
4
 
5
- require 'highline/import'
6
- require 'trollop'
5
+ require 'optimist'
7
6
  require "sup"
7
+ require 'sup/util/axe'
8
8
 
9
- $opts = Trollop::options do
9
+ $opts = Optimist::options do
10
10
  version "sup-config (sup #{Redwood::VERSION})"
11
11
  banner <<EOS
12
12
  Interactive configuration tool for Sup. Won't destroy existing
@@ -19,20 +19,6 @@ No options.
19
19
  EOS
20
20
  end
21
21
 
22
- def axe q, default=nil
23
- question = if default && !default.empty?
24
- "#{q} (enter for \"#{default}\"): "
25
- else
26
- "#{q}: "
27
- end
28
- ans = ask question
29
- ans.empty? ? default : ans.to_s
30
- end
31
-
32
- def axe_yes q, default="n"
33
- axe(q, default) =~ /^y|yes$/i
34
- end
35
-
36
22
  def build_cmd cmd
37
23
  (ENV["RUBY_INVOCATION"] ? ENV["RUBY_INVOCATION"] + " " : "") + File.join(File.dirname($0), cmd)
38
24
  end
@@ -42,8 +28,8 @@ def add_source
42
28
 
43
29
  type = nil
44
30
 
45
- say "Ok, adding a new source."
46
- choose do |menu|
31
+ @cli.say "Ok, adding a new source."
32
+ @cli.choose do |menu|
47
33
  menu.prompt = "What type of mail source is it? "
48
34
  menu.choice("mbox file") { type = :mbox }
49
35
  menu.choice("maildir directory") { type = :maildir }
@@ -51,7 +37,7 @@ def add_source
51
37
  end
52
38
 
53
39
  while true do
54
- say "Ok, now for the details."
40
+ @cli.say "Ok, now for the details."
55
41
 
56
42
  default_labels, components = case type
57
43
  when :mbox
@@ -75,11 +61,11 @@ def add_source
75
61
  uri = begin
76
62
  Redwood::Util::Uri.build components
77
63
  rescue URI::Error => e
78
- 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}"
79
65
  if axe_yes("Try again?") then next else return end
80
66
  end
81
67
 
82
- say "I'm going to add this source: #{uri}"
68
+ @cli.say "I'm going to add this source: #{uri}"
83
69
  unless axe("Does that look right?", "y") =~ /^y|yes$/i
84
70
  if axe_yes("Try again?") then next else return end
85
71
  end
@@ -108,21 +94,21 @@ def add_source
108
94
 
109
95
  system cmd
110
96
  if $?.success?
111
- say "Great! Added!"
97
+ @cli.say "Great! Added!"
112
98
  break
113
99
  else
114
- say "Rats, that failed. You may have to do it manually."
100
+ @cli.say "Rats, that failed. You may have to do it manually."
115
101
  if axe_yes("Try again?") then next else return end
116
102
  end
117
103
  end
118
104
  end
119
105
 
120
- $terminal.wrap_at = :auto
106
+ @cli.wrap_at = :auto
121
107
  Redwood::start
122
108
  index = Redwood::Index.init
123
109
  Redwood::SourceManager.load_sources
124
110
 
125
- say <<EOS
111
+ @cli.say <<EOS
126
112
  Howdy neighbor! This here's sup-config, ready to help you jack in to
127
113
  the next generation of digital cyberspace: the text-based email
128
114
  program. Get ready to be the envy of everyone in your internets
@@ -138,11 +124,11 @@ account = $config[:accounts][:default]
138
124
  name = axe "What's your name?", account[:name]
139
125
  email = axe "What's your (primary) email address?", account[:email]
140
126
 
141
- say "Ok, your from header will look like this:"
142
- say " From: #{name} <#{email}>"
127
+ @cli.say "Ok, your from header will look like this:"
128
+ @cli.say " From: #{name} <#{email}>"
143
129
 
144
- say "\nDo you have any alternate email addresses that also receive email?"
145
- 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."
146
132
  alts = axe("Alternate email addresses", account[:alternates].join(" ")).split(/\s+/)
147
133
 
148
134
  sigfn = axe "What file contains your signature?", account[:signature]
@@ -159,36 +145,36 @@ $config[:time_mode] = time_mode
159
145
 
160
146
  done = false
161
147
  until done
162
- 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."
163
149
  Redwood::SourceManager.load_sources
164
- say "Current sources:"
150
+ @cli.say "Current sources:"
165
151
  if Redwood::SourceManager.sources.empty?
166
- say " No sources!"
152
+ @cli.say " No sources!"
167
153
  else
168
154
  Redwood::SourceManager.sources.each { |s| puts "* #{s}" }
169
155
  end
170
156
 
171
- say "\n"
172
- choose do |menu|
157
+ @cli.say "\n"
158
+ @cli.choose do |menu|
173
159
  menu.prompt = "Your wish? "
174
160
  menu.choice("Add a new source.") { add_source }
175
161
  menu.choice("Done adding sources!") { done = true }
176
162
  end
177
163
  end
178
164
 
179
- say "\nSup needs to know where to store your sent messages."
180
- 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"
181
167
 
182
168
  Redwood::SourceManager.load_sources
183
169
  if Redwood::SourceManager.sources.empty?
184
- 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."
185
171
  $config[:sent_source] = 'sup://sent'
186
172
  else
187
173
  # this handles the event that source.yaml already contains the SentLoader
188
174
  # source.
189
175
  have_sup_sent = false
190
176
 
191
- choose do |menu|
177
+ @cli.choose do |menu|
192
178
  menu.prompt = "Store my sent mail in? "
193
179
 
194
180
  menu.choice('Default (an mbox in ~/.sup, aka sup://sent)') { $config[:sent_source] = 'sup://sent'} unless have_sup_sent
@@ -202,9 +188,9 @@ end
202
188
 
203
189
  Redwood::save_yaml_obj $config, Redwood::CONFIG_FN, false, true
204
190
 
205
- 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}."
206
192
 
207
- say <<EOS
193
+ @cli.say <<EOS
208
194
 
209
195
  The final step is to import all your messages into the Sup index.
210
196
  Depending on how many messages are in the sources, this could take
@@ -218,10 +204,10 @@ if axe_yes "Run sup-sync to import all messages now?"
218
204
  puts "Ok, trying to run \"#{cmd}\"..."
219
205
  system cmd
220
206
  if $?.success?
221
- say "Great! It worked!"
207
+ @cli.say "Great! It worked!"
222
208
  break
223
209
  else
224
- say "Rats, that failed. You may have to do it manually."
210
+ @cli.say "Rats, that failed. You may have to do it manually."
225
211
  if axe_yes("Try again?") then next else break end
226
212
  end
227
213
  end
@@ -229,7 +215,7 @@ end
229
215
 
230
216
  index.load
231
217
 
232
- say <<EOS
218
+ @cli.say <<EOS
233
219
 
234
220
  Okee doke, you've got yourself an index of #{index.size} messages. Looks
235
221
  like you're ready to jack in to cyberspace there, cowboy.
data/bin/sup-dump CHANGED
@@ -3,12 +3,12 @@
3
3
  $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
4
4
 
5
5
  require 'xapian'
6
- require 'trollop'
6
+ require 'optimist'
7
7
  require 'set'
8
8
 
9
9
  BASE_DIR = ENV["SUP_BASE"] || File.join(ENV["HOME"], ".sup")
10
10
 
11
- $opts = Trollop::options do
11
+ $opts = Optimist::options do
12
12
  version "sup-dump"
13
13
  banner <<EOS
14
14
  Dumps all message state from the sup index to standard out. You can
data/bin/sup-import-dump CHANGED
@@ -3,7 +3,7 @@
3
3
  $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
4
4
 
5
5
  require 'uri'
6
- require 'trollop'
6
+ require 'optimist'
7
7
  require "sup"
8
8
 
9
9
  PROGRESS_UPDATE_INTERVAL = 15 # seconds
@@ -11,7 +11,7 @@ PROGRESS_UPDATE_INTERVAL = 15 # seconds
11
11
  class AbortExecution < SystemExit
12
12
  end
13
13
 
14
- opts = Trollop::options do
14
+ opts = Optimist::options do
15
15
  version "sup-import-dump (sup #{Redwood::VERSION})"
16
16
  banner <<EOS
17
17
  Imports message state previously exported by sup-dump into the index.
@@ -36,8 +36,8 @@ EOS
36
36
 
37
37
  conflicts :ignore_missing, :warn_missing, :abort_missing
38
38
  end
39
- Trollop::die "No dump file given" if ARGV.empty?
40
- Trollop::die "Extra arguments given" if ARGV.length > 1
39
+ Optimist::die "No dump file given" if ARGV.empty?
40
+ Optimist::die "Extra arguments given" if ARGV.length > 1
41
41
  dump_name = ARGV.shift
42
42
  missing_action = [:ignore_missing, :warn_missing, :abort_missing].find { |x| opts[x] } || :abort_missing
43
43
 
data/bin/sup-sync CHANGED
@@ -3,7 +3,7 @@
3
3
  $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
4
4
 
5
5
  require 'uri'
6
- require 'trollop'
6
+ require 'optimist'
7
7
  require "sup"
8
8
 
9
9
  PROGRESS_UPDATE_INTERVAL = 15 # seconds
@@ -30,7 +30,7 @@ def time
30
30
  Time.now - startt
31
31
  end
32
32
 
33
- opts = Trollop::options do
33
+ opts = Optimist::options do
34
34
  version "sup-sync (sup #{Redwood::VERSION})"
35
35
  banner <<EOS
36
36
  Synchronizes the Sup index with one or more message sources by adding
@@ -112,7 +112,7 @@ begin
112
112
  Redwood::SourceManager.usual_sources
113
113
  else
114
114
  ARGV.map do |uri|
115
- Redwood::SourceManager.source_for uri or Trollop::die "Unknown source: #{uri}. Did you add it with sup-add first?"
115
+ Redwood::SourceManager.source_for uri or Optimist::die "Unknown source: #{uri}. Did you add it with sup-add first?"
116
116
  end
117
117
  end
118
118
 
@@ -3,10 +3,10 @@
3
3
 
4
4
  $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
5
5
 
6
- require 'trollop'
6
+ require 'optimist'
7
7
  require "sup"
8
8
 
9
- opts = Trollop::options do
9
+ opts = Optimist::options do
10
10
  version "sup-sync-back-maildir (sup #{Redwood::VERSION})"
11
11
  banner <<EOS
12
12
  Export Xapian entries to Maildir sources on disk.
data/bin/sup-tweak-labels CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
4
4
 
5
- require 'trollop'
5
+ require 'optimist'
6
6
  require "sup"
7
7
 
8
8
  class Float
@@ -25,7 +25,7 @@ def time
25
25
  Time.now - startt
26
26
  end
27
27
 
28
- opts = Trollop::options do
28
+ opts = Optimist::options do
29
29
  version "sup-tweak-labels (sup #{Redwood::VERSION})"
30
30
  banner <<EOS
31
31
  Batch modification of message state for messages already in the index.
@@ -58,7 +58,7 @@ opts[:verbose] = true if opts[:very_verbose]
58
58
  add_labels = opts[:add].to_set_of_symbols ","
59
59
  remove_labels = opts[:remove].to_set_of_symbols ","
60
60
 
61
- Trollop::die "nothing to do: no labels to add or remove" if add_labels.empty? && remove_labels.empty?
61
+ Optimist::die "nothing to do: no labels to add or remove" if add_labels.empty? && remove_labels.empty?
62
62
 
63
63
  Redwood::start
64
64
  index = Redwood::Index.init
@@ -71,10 +71,10 @@ begin
71
71
  Redwood::SourceManager.sources
72
72
  else
73
73
  ARGV.map do |uri|
74
- Redwood::SourceManager.source_for uri or Trollop::die "Unknown source: #{uri}. Did you add it with sup-add first?"
74
+ Redwood::SourceManager.source_for uri or Optimist::die "Unknown source: #{uri}. Did you add it with sup-add first?"
75
75
  end
76
76
  end.map { |s| s.id }
77
- Trollop::die "nothing to do: no sources" if source_ids.empty?
77
+ Optimist::die "nothing to do: no sources" if source_ids.empty?
78
78
 
79
79
  query = "(" + source_ids.map { |id| "source_id:#{id}" }.join(" OR ") + ")"
80
80
  if add_labels.empty?
@@ -10,13 +10,19 @@ end
10
10
 
11
11
  puts "xapian: platform specific dependencies.."
12
12
 
13
- inst = Gem::DependencyInstaller.new
13
+ destination = File.writable?(Gem.dir) ? Gem.dir : Gem.user_dir
14
+ inst = Gem::DependencyInstaller.new(:install_dir => destination)
14
15
  begin
15
16
 
16
17
  if !RbConfig::CONFIG['arch'].include?('openbsd')
17
18
  # update version in Gemfile as well
18
19
  name = "xapian-ruby"
19
- version = "~> 1.2.15"
20
+ version =
21
+ if /^2\.0\./ =~ RUBY_VERSION
22
+ ["~> 1.2", "< 1.3.6"]
23
+ else
24
+ "~> 1.2"
25
+ end
20
26
 
21
27
  begin
22
28
  # try to load gem
@@ -34,8 +40,8 @@ begin
34
40
  STDERR.puts "xapian: openbsd: you have to install xapian-core and xapian-bindings manually, have a look at: https://github.com/sup-heliotrope/sup/wiki/Installation%3A-OpenBSD"
35
41
  end
36
42
 
37
- rescue
38
-
43
+ rescue StandardError => e
44
+ STDERR.puts "Unable to install #{name} gem: #{e.inspect}"
39
45
  exit(1)
40
46
 
41
47
  end
data/lib/sup/colormap.rb CHANGED
@@ -236,7 +236,7 @@ class Colormap
236
236
  @@instance.send meth, *a
237
237
  end
238
238
  # Performance shortcut
239
- def self.color_for *a; @@instance.color_for *a; end
239
+ def self.color_for(*a); @@instance.color_for(*a); end
240
240
  end
241
241
 
242
242
  end
data/lib/sup/crypto.rb CHANGED
@@ -127,18 +127,27 @@ EOS
127
127
  def sign from, to, payload
128
128
  return unknown_status(@not_working_reason) unless @not_working_reason.nil?
129
129
 
130
+ # We grab this from the GPG::Ctx below after signing, so that we can set
131
+ # micalg in Content-Type to match the hash algorithm GPG decided to use.
132
+ hash_algo = nil
133
+
130
134
  gpg_opts = {:protocol => GPGME::PROTOCOL_OpenPGP, :armor => true, :textmode => true}
131
135
  gpg_opts.merge!(gen_sign_user_opts(from))
132
136
  gpg_opts = HookManager.run("gpg-options",
133
137
  {:operation => "sign", :options => gpg_opts}) || gpg_opts
134
138
  begin
135
- if GPGME.respond_to?('detach_sign')
136
- sig = GPGME.detach_sign(format_payload(payload), gpg_opts)
137
- else
138
- crypto = GPGME::Crypto.new
139
- gpg_opts[:mode] = GPGME::SIG_MODE_DETACH
140
- sig = crypto.sign(format_payload(payload), gpg_opts).read
139
+ input = GPGME::Data.new(format_payload(payload))
140
+ output = GPGME::Data.new()
141
+ GPGME::Ctx.new(gpg_opts) do |ctx|
142
+ if gpg_opts[:signer]
143
+ signers = GPGME::Key.find(:secret, gpg_opts[:signer], :sign)
144
+ ctx.add_signer(*signers)
145
+ end
146
+ ctx.sign(input, output, GPGME::SIG_MODE_DETACH)
147
+ hash_algo = GPGME::hash_algo_name(ctx.sign_result.signatures[0].hash_algo)
141
148
  end
149
+ output.seek(0)
150
+ sig = output.read
142
151
  rescue GPGME::Error => exc
143
152
  raise Error, gpgme_exc_msg(exc.message)
144
153
  end
@@ -150,7 +159,7 @@ EOS
150
159
  end
151
160
 
152
161
  envelope = RMail::Message.new
153
- envelope.header["Content-Type"] = 'multipart/signed; protocol=application/pgp-signature'
162
+ envelope.header["Content-Type"] = "multipart/signed; protocol=application/pgp-signature; micalg=pgp-#{hash_algo.downcase}"
154
163
 
155
164
  envelope.add_part payload
156
165
  signature = RMail::Message.make_attachment sig, "application/pgp-signature", nil, "signature.asc"
@@ -233,7 +242,7 @@ EOS
233
242
  end
234
243
 
235
244
  if valid || !unknown
236
- summary_line = simplify_sig_line(verify_result.signatures[0].to_s, all_trusted)
245
+ summary_line = simplify_sig_line(verify_result.signatures[0].to_s.dup, all_trusted)
237
246
  end
238
247
 
239
248
  if all_output_lines.length == 0
data/lib/sup/hook.rb CHANGED
@@ -109,20 +109,20 @@ class HookManager
109
109
  @descs[name] = desc
110
110
  end
111
111
 
112
- def print_hooks f=$stdout
113
- puts <<EOS
114
- Have #{HookManager.descs.size} registered hooks:
115
-
116
- EOS
117
-
118
- HookManager.descs.sort.each do |name, desc|
119
- f.puts <<EOS
112
+ def print_hooks pattern="", f=$stdout
113
+ matching_hooks = HookManager.descs.sort.keep_if {|name, desc| pattern.empty? or name.match(pattern)}.map do |name, desc|
114
+ <<EOS
120
115
  #{name}
121
116
  #{"-" * name.length}
122
117
  File: #{fn_for name}
123
118
  #{desc}
124
119
  EOS
125
120
  end
121
+
122
+ showing_str = matching_hooks.size == HookManager.descs.size ? "" : " (showing #{matching_hooks.size})"
123
+ f.puts "Have #{HookManager.descs.size} registered hooks#{showing_str}:"
124
+ f.puts
125
+ matching_hooks.each { |text| f.puts text }
126
126
  end
127
127
 
128
128
  def enabled? name; !hook_for(name).nil? end
@@ -138,7 +138,7 @@ private
138
138
  returning IO.read(fn_for(name)) do
139
139
  debug "read '#{name}' from #{fn_for(name)}"
140
140
  end
141
- rescue SystemCallError => e
141
+ rescue SystemCallError
142
142
  #debug "disabled hook for '#{name}': #{e.message}"
143
143
  nil
144
144
  end
data/lib/sup/index.rb CHANGED
@@ -425,7 +425,7 @@ EOS
425
425
 
426
426
  ## gmail style "is" operator
427
427
  subs = subs.gsub(/\b(is|has):(\S+)\b/) do
428
- field, label = $1, $2
428
+ _field, label = $1, $2
429
429
  case label
430
430
  when "read"
431
431
  "-label:unread"
@@ -516,19 +516,32 @@ EOS
516
516
  qp.stemmer = Xapian::Stem.new($config[:stem_language])
517
517
  qp.stemming_strategy = Xapian::QueryParser::STEM_SOME
518
518
  qp.default_op = Xapian::Query::OP_AND
519
- qp.add_valuerangeprocessor(Xapian::NumberValueRangeProcessor.new(DATE_VALUENO, 'date:', true))
520
- NORMAL_PREFIX.each { |k,info| info[:prefix].each { |v| qp.add_prefix k, v } }
521
- BOOLEAN_PREFIX.each { |k,info| info[:prefix].each { |v| qp.add_boolean_prefix k, v, info[:exclusive] } }
519
+ valuerangeprocessor = Xapian::NumberValueRangeProcessor.new(DATE_VALUENO,
520
+ 'date:', true)
521
+ qp.add_valuerangeprocessor(valuerangeprocessor)
522
+ NORMAL_PREFIX.each { |k,info| info[:prefix].each {
523
+ |v| qp.add_prefix k, v }
524
+ }
525
+ BOOLEAN_PREFIX.each { |k,info| info[:prefix].each {
526
+ |v| qp.add_boolean_prefix k, v, info[:exclusive] }
527
+ }
522
528
 
523
529
  begin
524
- xapian_query = qp.parse_query(subs, Xapian::QueryParser::FLAG_PHRASE|Xapian::QueryParser::FLAG_BOOLEAN|Xapian::QueryParser::FLAG_LOVEHATE|Xapian::QueryParser::FLAG_WILDCARD)
530
+ xapian_query = qp.parse_query(subs, Xapian::QueryParser::FLAG_PHRASE |
531
+ Xapian::QueryParser::FLAG_BOOLEAN |
532
+ Xapian::QueryParser::FLAG_LOVEHATE |
533
+ Xapian::QueryParser::FLAG_WILDCARD)
525
534
  rescue RuntimeError => e
526
535
  raise ParseError, "xapian query parser error: #{e}"
527
536
  end
528
537
 
529
538
  debug "parsed xapian query: #{Util::Query.describe(xapian_query, subs)}"
530
539
 
531
- raise ParseError if xapian_query.nil? or xapian_query.empty?
540
+ if xapian_query.nil? or xapian_query.empty?
541
+ raise ParseError, "couldn't parse \"#{s}\" as xapian query " \
542
+ "(special characters aren't indexed)"
543
+ end
544
+
532
545
  query[:qobj] = xapian_query
533
546
  query[:text] = s
534
547
  query
@@ -636,7 +649,7 @@ EOS
636
649
  end
637
650
 
638
651
  def synchronize &b
639
- @index_mutex.synchronize &b
652
+ @index_mutex.synchronize(&b)
640
653
  end
641
654
 
642
655
  def run_query xapian_query, offset, limit, checkatleast=0
data/lib/sup/keymap.rb CHANGED
@@ -98,7 +98,7 @@ EOS
98
98
  end
99
99
 
100
100
  def action_for kc
101
- action, help, keys = @map[kc.code]
101
+ action, help, _keys = @map[kc.code]
102
102
  [action, help]
103
103
  end
104
104
 
data/lib/sup/logger.rb CHANGED
@@ -71,7 +71,7 @@ end
71
71
 
72
72
  ## include me to have top-level #debug, #info, etc. methods.
73
73
  module LogsStuff
74
- Logger::LEVELS.each { |l| define_method(l) { |s| Logger.instance.send(l, s) } }
74
+ Logger::LEVELS.each { |l| define_method(l) { |s, uplevel = 0| Logger.instance.send(l, s) } }
75
75
  end
76
76
 
77
77
  end
data/lib/sup/maildir.rb CHANGED
@@ -12,13 +12,13 @@ class Maildir < Source
12
12
  def initialize uri, usual=true, archived=false, sync_back=true, id=nil, labels=[]
13
13
  super uri, usual, archived, id
14
14
  @expanded_uri = Source.expand_filesystem_uri(uri)
15
- parts = @expanded_uri.match /^([a-zA-Z0-9]*:(\/\/)?)(.*)/
15
+ parts = /^([a-zA-Z0-9]*:(\/\/)?)(.*)/.match @expanded_uri
16
16
  if parts
17
17
  prefix = parts[1]
18
18
  @path = parts[3]
19
- uri = URI(prefix + URI.encode(@path, URI_ENCODE_CHARS))
19
+ uri = URI(prefix + Source.encode_path_for_uri(@path))
20
20
  else
21
- uri = URI(URI.encode @expanded_uri, URI_ENCODE_CHARS)
21
+ uri = URI(Source.encode_path_for_uri @path)
22
22
  @path = uri.path
23
23
  end
24
24
 
@@ -30,7 +30,7 @@ class Maildir < Source
30
30
  # sync by default if not specified
31
31
  @sync_back = true if @sync_back.nil?
32
32
 
33
- @dir = URI.decode uri.path
33
+ @dir = URI.decode_www_form_component uri.path
34
34
  @labels = Set.new(labels || [])
35
35
  @mutex = Mutex.new
36
36
  @ctimes = { 'cur' => Time.at(0), 'new' => Time.at(0) }
data/lib/sup/mbox.rb CHANGED
@@ -19,13 +19,13 @@ class MBox < Source
19
19
  case uri_or_fp
20
20
  when String
21
21
  @expanded_uri = Source.expand_filesystem_uri(uri_or_fp)
22
- parts = @expanded_uri.match /^([a-zA-Z0-9]*:(\/\/)?)(.*)/
22
+ parts = /^([a-zA-Z0-9]*:(\/\/)?)(.*)/.match @expanded_uri
23
23
  if parts
24
24
  prefix = parts[1]
25
25
  @path = parts[3]
26
- uri = URI(prefix + URI.encode(@path, URI_ENCODE_CHARS))
26
+ uri = URI(prefix + Source.encode_path_for_uri(@path))
27
27
  else
28
- uri = URI(URI.encode @expanded_uri, URI_ENCODE_CHARS)
28
+ uri = URI(Source.encode_path_for_uri @expanded_uri)
29
29
  @path = uri.path
30
30
  end
31
31
 
@@ -36,7 +36,7 @@ class MBox < Source
36
36
  else
37
37
  @f = uri_or_fp
38
38
  @path = uri_or_fp.path
39
- @expanded_uri = "mbox://#{URI.encode @path, URI_ENCODE_CHARS}"
39
+ @expanded_uri = "mbox://#{Source.encode_path_for_uri @path}"
40
40
  end
41
41
 
42
42
  super uri_or_fp, usual, archived, id