sup 0.13.2.1 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sup might be problematic. Click here for more details.
- data/CONTRIBUTORS +11 -7
- data/History.txt +9 -3
- data/ReleaseNotes +13 -16
- data/bin/sup +10 -7
- data/bin/sup-psych-ify-config-files +16 -0
- data/lib/sup.rb +32 -18
- data/lib/sup/account.rb +2 -1
- data/lib/sup/buffer.rb +13 -13
- data/lib/sup/contact.rb +3 -1
- data/lib/sup/crypto.rb +44 -18
- data/lib/sup/draft.rb +5 -2
- data/lib/sup/index.rb +54 -34
- data/lib/sup/label.rb +3 -1
- data/lib/sup/message.rb +10 -4
- data/lib/sup/message_chunks.rb +13 -47
- data/lib/sup/modes/compose_mode.rb +2 -0
- data/lib/sup/modes/edit_message_mode.rb +4 -4
- data/lib/sup/modes/inbox_mode.rb +1 -1
- data/lib/sup/modes/thread_index_mode.rb +4 -4
- data/lib/sup/modes/thread_view_mode.rb +4 -0
- data/lib/sup/poll.rb +1 -1
- data/lib/sup/rfc2047.rb +1 -3
- data/lib/sup/sent.rb +7 -2
- data/lib/sup/source.rb +12 -20
- data/lib/sup/textfield.rb +10 -0
- data/lib/sup/util.rb +85 -43
- data/lib/sup/util/query.rb +14 -0
- data/lib/sup/version.rb +1 -1
- metadata +57 -141
data/CONTRIBUTORS
CHANGED
@@ -11,13 +11,14 @@ Eric Sherman <hyperbolist at the gmail dot coms>
|
|
11
11
|
Tero Tilus <tero at the tilus dot nets>
|
12
12
|
Ben Walton <bwalton at the artsci.utoronto dot cas>
|
13
13
|
Mike Stipicevic <stipim at the rpi dot edus>
|
14
|
+
Clint Byrum <clint at the ubuntu dot coms>
|
14
15
|
Marcus Williams <marcus-sup at the bar-coded dot nets>
|
15
16
|
Lionel Ott <white.magic at the gmx dot des>
|
16
17
|
Gaudenz Steinlin <gaudenz at the soziologie dot chs>
|
17
18
|
Damien Leone <damien.leone at the fensalir dot frs>
|
18
19
|
Ingmar Vanhassel <ingmar at the exherbo dot orgs>
|
19
20
|
Mark Alexander <marka at the pobox dot coms>
|
20
|
-
Eric Weikl <eric.weikl at the
|
21
|
+
Eric Weikl <eric.weikl at the gmx dot nets>
|
21
22
|
Christopher Warrington <chrisw at the rice dot edus>
|
22
23
|
W. Trevor King <wking at the drexel dot edus>
|
23
24
|
Richard Brown <rbrown at the exherbo dot orgs>
|
@@ -26,9 +27,11 @@ Marc Hartstein <marc.hartstein at the alum.vassar dot edus>
|
|
26
27
|
Israel Herraiz <israel.herraiz at the gmail dot coms>
|
27
28
|
Bo Borgerson <gigabo at the gmail dot coms>
|
28
29
|
Michael Hamann <michael at the content-space dot des>
|
30
|
+
Jonathan Lassoff <jof at the thejof dot coms>
|
29
31
|
William Erik Baxter <web at the superscript dot coms>
|
30
32
|
Grant Hollingworth <grant at the antiflux dot orgs>
|
31
33
|
Markus Klinik <markus.klinik at the gmx dot des>
|
34
|
+
Ico Doornekamp <ico at the pruts dot nls>
|
32
35
|
Adeodato Simó <dato at the net.com.org dot ess>
|
33
36
|
Daniel Schoepe <daniel.schoepe at the googlemail dot coms>
|
34
37
|
Jason Petsod <jason at the petsod dot orgs>
|
@@ -44,21 +47,22 @@ Andrew Pimlott <andrew at the pimlott dot nets>
|
|
44
47
|
Jeff Balogh <its.jeff.balogh at the gmail dot coms>
|
45
48
|
Matías Aguirre <matiasaguirre at the gmail dot coms>
|
46
49
|
Kornilios Kourtis <kkourt at the cslab.ece.ntua dot grs>
|
47
|
-
Giorgio Lando <patroclo7 at the gmail dot coms>
|
48
50
|
Kevin Riggle <kevinr at the free-dissociation dot coms>
|
51
|
+
Giorgio Lando <patroclo7 at the gmail dot coms>
|
49
52
|
Benoît PIERRE <benoit.pierre at the gmail dot coms>
|
53
|
+
Matthieu Rakotojaona <matthieu.rakotojaona at the gmail dot coms>
|
50
54
|
Alvaro Herrera <alvherre at the alvh.no-ip dot orgs>
|
51
55
|
Steven Lawrance <stl at the koffein dot nets>
|
52
56
|
Jonah <Jonah at the GoodCoffee dot cas>
|
53
57
|
ian <itaylor at the uark dot edus>
|
58
|
+
Todd Eisenberger <teisenbe at the andrew.cmu dot edus>
|
54
59
|
Adam Lloyd <adam at the alloy-d dot nets>
|
55
|
-
Gregor Hoffleit <gregor at the sam.mediasupervision dot des>
|
56
60
|
MichaelRevell <mikearevell at the gmail dot coms>
|
57
|
-
|
61
|
+
Per Andersson <avtobiff at the gmail dot coms>
|
62
|
+
Gregor Hoffleit <gregor at the sam.mediasupervision dot des>
|
58
63
|
Steven Walter <swalter at the monarch.(none)>
|
59
64
|
Jon M. Dugan <jdugan at the es dot nets>
|
60
|
-
Jonathan Lassoff <jof at the thejof dot coms>
|
61
|
-
Matthieu Rakotojaona <matthieu.rakotojaona at the gmail dot coms>
|
62
|
-
Stefan Lundström <lundst at the snabb.(none)>
|
63
65
|
Matthias Vallentin <vallentin at the icir dot orgs>
|
66
|
+
Stefan Lundström <lundst at the snabb.(none)>
|
67
|
+
Horacio Sanson <horacio at the skillupjapan.co dot jps>
|
64
68
|
Kirill Smelkov <kirr at the landau.phys.spbu dot rus>
|
data/History.txt
CHANGED
@@ -1,6 +1,12 @@
|
|
1
|
-
== 0.
|
2
|
-
|
3
|
-
*
|
1
|
+
== 0.14.0 / 2013-08-15
|
2
|
+
|
3
|
+
* CJK compatability
|
4
|
+
* Psych over Syck
|
5
|
+
* Ruby 1.8 deprecated
|
6
|
+
* Thread safety
|
7
|
+
* No more Iconv, but using built in Ruby encodings. Better UTF-8
|
8
|
+
handling.
|
9
|
+
* GPGME 2.0 support
|
4
10
|
|
5
11
|
== 0.13.2 / 2013-06-26
|
6
12
|
|
data/ReleaseNotes
CHANGED
@@ -1,24 +1,21 @@
|
|
1
|
-
Release 0.
|
1
|
+
Release 0.14.0:
|
2
2
|
|
3
|
-
|
3
|
+
CJK-compatability, Psych usage, thread safety, GPGME 2.0 support. Sup is now
|
4
|
+
Ruby 1.9 based, and apart from RMail - ready for Ruby 2.0.0.
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
incorporates these fixes. Please upgrade immediately and also ensure
|
9
|
-
that your mime-decode or mime-view hooks are secure [0], [1].
|
6
|
+
Sup now uses Psych as a YAML parser (default by Ruby) and your previous
|
7
|
+
configuration files (~/.sup/*.yaml) may need to be migrated or re-created for
|
8
|
+
them to work with the new sup. A migration script is included for this.
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
this means that the string (content_type, filename) is intended to be
|
14
|
-
used _without_ any further quotes. Please make sure that if you use
|
15
|
-
.mailcap (non OSX systems), you do not quote the string.
|
10
|
+
Check https://github.com/sup-heliotrope/sup/wiki/Migration-0.13-to-0.14 for
|
11
|
+
the latest instructions.
|
16
12
|
|
17
|
-
|
18
|
-
|
13
|
+
First back up your ~/.sup directory and index, after installing the new sup
|
14
|
+
run:
|
19
15
|
|
20
|
-
|
21
|
-
|
16
|
+
$ sup-psych-ify-config-files
|
17
|
+
|
18
|
+
to migrate your files. You should now be all set for buisness.
|
22
19
|
|
23
20
|
|
24
21
|
Release 0.13.2:
|
data/bin/sup
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
2
3
|
|
3
4
|
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
4
5
|
|
@@ -8,8 +9,6 @@ require 'ncursesw'
|
|
8
9
|
|
9
10
|
no_gpgme = false
|
10
11
|
begin
|
11
|
-
# gpgme broke its API in 2.0, so make sure we have the old version for now.
|
12
|
-
gem 'gpgme', '=1.0.8'
|
13
12
|
require 'gpgme'
|
14
13
|
rescue LoadError
|
15
14
|
no_gpgme = true
|
@@ -158,7 +157,11 @@ begin
|
|
158
157
|
|
159
158
|
$die = false
|
160
159
|
trap("TERM") { |x| $die = true }
|
161
|
-
trap("WINCH")
|
160
|
+
trap("WINCH") do |x|
|
161
|
+
::Thread.new do
|
162
|
+
BufferManager.sigwinch_happened!
|
163
|
+
end
|
164
|
+
end
|
162
165
|
|
163
166
|
if(s = Redwood::SourceManager.source_for DraftManager.source_name)
|
164
167
|
DraftManager.source = s
|
@@ -290,8 +293,8 @@ begin
|
|
290
293
|
b.mode.load_in_background if new
|
291
294
|
when :search
|
292
295
|
completions = LabelManager.all_labels.map { |l| "label:#{LabelManager.string_for l}" }
|
293
|
-
completions = completions.each { |l| l.
|
294
|
-
completions +=
|
296
|
+
completions = completions.each { |l| l.fix_encoding }
|
297
|
+
completions += Index::COMPL_PREFIXES
|
295
298
|
query = BufferManager.ask_many_with_completions :search, "Search all messages (enter for saved searches): ", completions
|
296
299
|
unless query.nil?
|
297
300
|
if query.empty?
|
@@ -304,7 +307,7 @@ begin
|
|
304
307
|
SearchResultsMode.spawn_from_query "is:unread"
|
305
308
|
when :list_labels
|
306
309
|
labels = LabelManager.all_labels.map { |l| LabelManager.string_for l }
|
307
|
-
labels = labels.each { |l| l.
|
310
|
+
labels = labels.each { |l| l.fix_encoding }
|
308
311
|
|
309
312
|
user_label = bm.ask_with_completions :label, "Show threads with label (enter for listing): ", labels
|
310
313
|
unless user_label.nil?
|
@@ -412,7 +415,7 @@ unless Redwood::exceptions.empty?
|
|
412
415
|
We are very sorry. It seems that an error occurred in Sup. Please
|
413
416
|
accept our sincere apologies. Please submit the contents of
|
414
417
|
#{BASE_DIR}/exception-log.txt and a brief report of the
|
415
|
-
circumstances to https://github.com/sup-heliotrope/sup/issues so that
|
418
|
+
circumstances to https://github.com/sup-heliotrope/sup/issues so that
|
416
419
|
we might address this problem. Thank you!
|
417
420
|
|
418
421
|
Sincerely,
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
4
|
+
|
5
|
+
require "sup"
|
6
|
+
require "fileutils"
|
7
|
+
|
8
|
+
Redwood.start
|
9
|
+
|
10
|
+
fn = Redwood::SOURCE_FN
|
11
|
+
FileUtils.cp fn, "#{fn}.syck_bak"
|
12
|
+
|
13
|
+
Redwood::SourceManager.load_sources fn
|
14
|
+
Redwood::SourceManager.save_sources fn, true
|
15
|
+
|
16
|
+
Redwood.finish
|
data/lib/sup.rb
CHANGED
@@ -1,11 +1,8 @@
|
|
1
|
-
|
1
|
+
# encoding: utf-8
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'rubygems'
|
4
4
|
require 'yaml'
|
5
|
-
|
6
|
-
YAML::ENGINE.yamler = 'syck'
|
7
|
-
end
|
8
|
-
|
5
|
+
YAML::ENGINE.yamler = 'psych'
|
9
6
|
require 'zlib'
|
10
7
|
require 'thread'
|
11
8
|
require 'fileutils'
|
@@ -28,18 +25,23 @@ end
|
|
28
25
|
class Module
|
29
26
|
def yaml_properties *props
|
30
27
|
props = props.map { |p| p.to_s }
|
31
|
-
vars = props.map { |p| "@#{p}" }
|
32
|
-
klass = self
|
33
|
-
path = klass.name.gsub(/::/, "/")
|
34
28
|
|
35
|
-
|
36
|
-
|
37
|
-
|
29
|
+
path = name.gsub(/::/, "/")
|
30
|
+
yaml_tag "!#{Redwood::YAML_DOMAIN},#{Redwood::YAML_DATE}/#{path}"
|
31
|
+
|
32
|
+
define_method :init_with do |coder|
|
33
|
+
initialize(*coder.map.values_at(*props))
|
38
34
|
end
|
39
35
|
|
40
|
-
|
41
|
-
|
36
|
+
define_method :encode_with do |coder|
|
37
|
+
coder.map = props.inject({}) do |hash, key|
|
38
|
+
hash[key] = instance_variable_get("@#{key}")
|
39
|
+
hash
|
40
|
+
end
|
42
41
|
end
|
42
|
+
|
43
|
+
# Legacy
|
44
|
+
Psych.load_tags["!#{Redwood::LEGACY_YAML_DOMAIN},#{Redwood::YAML_DATE}/#{path}"] = self
|
43
45
|
end
|
44
46
|
end
|
45
47
|
|
@@ -58,7 +60,8 @@ module Redwood
|
|
58
60
|
SEARCH_FN = File.join(BASE_DIR, "searches.txt")
|
59
61
|
LOG_FN = File.join(BASE_DIR, "log")
|
60
62
|
|
61
|
-
YAML_DOMAIN = "
|
63
|
+
YAML_DOMAIN = "supmua.org"
|
64
|
+
LEGACY_YAML_DOMAIN = "masanjin.net"
|
62
65
|
YAML_DATE = "2006-10-01"
|
63
66
|
|
64
67
|
## record exceptions thrown in threads nicely
|
@@ -268,7 +271,7 @@ EOM
|
|
268
271
|
else
|
269
272
|
require 'etc'
|
270
273
|
require 'socket'
|
271
|
-
name = Etc.getpwnam(ENV["USER"]).gecos.split(/,/).first rescue nil
|
274
|
+
name = Etc.getpwnam(ENV["USER"]).gecos.split(/,/).first.force_encoding($encoding).fix_encoding rescue nil
|
272
275
|
name ||= ENV["USER"]
|
273
276
|
email = ENV["USER"] + "@" +
|
274
277
|
begin
|
@@ -280,8 +283,8 @@ EOM
|
|
280
283
|
config = {
|
281
284
|
:accounts => {
|
282
285
|
:default => {
|
283
|
-
:name => name,
|
284
|
-
:email => email,
|
286
|
+
:name => name.fix_encoding,
|
287
|
+
:email => email.fix_encoding,
|
285
288
|
:alternates => [],
|
286
289
|
:sendmail => "/usr/sbin/sendmail -oem -ti",
|
287
290
|
:signature => File.join(ENV["HOME"], ".signature"),
|
@@ -314,6 +317,7 @@ require "sup/logger/singleton"
|
|
314
317
|
## determine encoding and character set
|
315
318
|
$encoding = Locale.current.charset
|
316
319
|
$encoding = "UTF-8" if $encoding == "utf8"
|
320
|
+
$encoding = "UTF-8" if $encoding == "UTF8"
|
317
321
|
if $encoding
|
318
322
|
debug "using character set encoding #{$encoding.inspect}"
|
319
323
|
else
|
@@ -321,6 +325,16 @@ else
|
|
321
325
|
$encoding = "UTF-8"
|
322
326
|
end
|
323
327
|
|
328
|
+
# test encoding
|
329
|
+
teststr = "test"
|
330
|
+
teststr.encode('UTF-8')
|
331
|
+
begin
|
332
|
+
teststr.encode($encoding)
|
333
|
+
rescue Encoding::ConverterNotFoundError
|
334
|
+
warn "locale encoding is invalid, defaulting to utf-8"
|
335
|
+
$encoding = "UTF-8"
|
336
|
+
end
|
337
|
+
|
324
338
|
require "sup/buffer"
|
325
339
|
require "sup/keymap"
|
326
340
|
require "sup/mode"
|
data/lib/sup/account.rb
CHANGED
@@ -50,8 +50,9 @@ class AccountManager
|
|
50
50
|
[:name, :sendmail, :signature, :gpgkey].each { |k| hash[k] ||= @default_account.send(k) }
|
51
51
|
end
|
52
52
|
hash[:alternates] ||= []
|
53
|
+
fail "alternative emails are not an array: #{hash[:alternates]}" unless hash[:alternates].kind_of? Array
|
53
54
|
|
54
|
-
[:name, :signature].each { |x| hash[x]
|
55
|
+
[:name, :signature].each { |x| hash[x] ? hash[x].fix_encoding : nil }
|
55
56
|
|
56
57
|
a = Account.new hash
|
57
58
|
@accounts[a] = true
|
data/lib/sup/buffer.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'etc'
|
2
4
|
require 'thread'
|
3
5
|
|
@@ -126,14 +128,11 @@ class Buffer
|
|
126
128
|
@w.attrset Colormap.color_for(opts[:color] || :none, opts[:highlight])
|
127
129
|
s ||= ""
|
128
130
|
maxl = @width - x # maximum display width width
|
129
|
-
stringl = maxl # string "length"
|
130
131
|
|
131
132
|
# fill up the line with blanks to overwrite old screen contents
|
132
133
|
@w.mvaddstr y, x, " " * maxl unless opts[:no_fill]
|
133
134
|
|
134
|
-
|
135
|
-
stringl += 1 while stringl < s.length && s[0 ... stringl].display_length < maxl
|
136
|
-
@w.mvaddstr y, x, s[0 ... stringl]
|
135
|
+
@w.mvaddstr y, x, s.slice_by_display_length(maxl)
|
137
136
|
end
|
138
137
|
|
139
138
|
def clear
|
@@ -450,7 +449,7 @@ EOS
|
|
450
449
|
|
451
450
|
def ask_with_completions domain, question, completions, default=nil
|
452
451
|
ask domain, question, default do |s|
|
453
|
-
s.
|
452
|
+
s.fix_encoding
|
454
453
|
completions.select { |x| x =~ /^#{Regexp::escape s}/iu }.map { |x| [x, x] }
|
455
454
|
end
|
456
455
|
end
|
@@ -467,9 +466,9 @@ EOS
|
|
467
466
|
raise "william screwed up completion: #{partial.inspect}"
|
468
467
|
end
|
469
468
|
|
470
|
-
prefix.
|
471
|
-
target.
|
472
|
-
completions.select { |x| x =~ /^#{Regexp::escape target}/
|
469
|
+
prefix.fix_encoding
|
470
|
+
target.fix_encoding
|
471
|
+
completions.select { |x| x =~ /^#{Regexp::escape target}/iu }.map { |x| [prefix + x, x] }
|
473
472
|
end
|
474
473
|
end
|
475
474
|
|
@@ -477,12 +476,12 @@ EOS
|
|
477
476
|
ask domain, question, default do |partial|
|
478
477
|
prefix, target = partial.split_on_commas_with_remainder
|
479
478
|
target ||= prefix.pop || ""
|
480
|
-
target.
|
479
|
+
target.fix_encoding
|
481
480
|
|
482
481
|
prefix = prefix.join(", ") + (prefix.empty? ? "" : ", ")
|
483
|
-
prefix.
|
482
|
+
prefix.fix_encoding
|
484
483
|
|
485
|
-
completions.select { |x| x =~ /^#{Regexp::escape target}/
|
484
|
+
completions.select { |x| x =~ /^#{Regexp::escape target}/iu }.sort_by { |c| [ContactManager.contact_for(c) ? 0 : 1, c] }.map { |x| [prefix + x, x] }
|
486
485
|
end
|
487
486
|
end
|
488
487
|
|
@@ -495,7 +494,7 @@ EOS
|
|
495
494
|
if dir
|
496
495
|
[[s.sub(full, dir), "~#{name}"]]
|
497
496
|
else
|
498
|
-
users.select { |u| u =~ /^#{Regexp::escape name}/ }.map do |u|
|
497
|
+
users.select { |u| u =~ /^#{Regexp::escape name}/u }.map do |u|
|
499
498
|
[s.sub("~#{name}", "~#{u}"), "~#{u}"]
|
500
499
|
end
|
501
500
|
end
|
@@ -554,6 +553,7 @@ EOS
|
|
554
553
|
|
555
554
|
completions = (recent + contacts).flatten.uniq
|
556
555
|
completions += HookManager.run("extra-contact-addresses") || []
|
556
|
+
|
557
557
|
answer = BufferManager.ask_many_emails_with_completions domain, question, completions, default
|
558
558
|
|
559
559
|
if answer
|
@@ -622,7 +622,7 @@ EOS
|
|
622
622
|
tf.deactivate
|
623
623
|
draw_screen :sync => false, :status => status, :title => title
|
624
624
|
end
|
625
|
-
tf.value.tap { |x| x
|
625
|
+
tf.value.tap { |x| x }
|
626
626
|
end
|
627
627
|
|
628
628
|
def ask_getch question, accept=nil
|
data/lib/sup/contact.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
module Redwood
|
2
4
|
|
3
5
|
class ContactManager
|
@@ -54,7 +56,7 @@ class ContactManager
|
|
54
56
|
def is_aliased_contact? person; !@p2a[person].nil? end
|
55
57
|
|
56
58
|
def save
|
57
|
-
File.open(@fn, "w") do |f|
|
59
|
+
File.open(@fn, "w:UTF-8") do |f|
|
58
60
|
@p2a.sort_by { |(p, a)| [p.full_address, a] }.each do |(p, a)|
|
59
61
|
f.puts "#{a || ''}: #{p.full_address}"
|
60
62
|
end
|
data/lib/sup/crypto.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
begin
|
2
|
-
# gpgme broke its API in 2.0, so make sure we have the old version for now.
|
3
|
-
gem 'gpgme', '=1.0.8'
|
4
2
|
require 'gpgme'
|
5
3
|
rescue LoadError
|
6
4
|
end
|
@@ -64,28 +62,39 @@ EOS
|
|
64
62
|
@gpgme_present =
|
65
63
|
begin
|
66
64
|
begin
|
67
|
-
|
65
|
+
begin
|
66
|
+
GPGME.check_version({:protocol => GPGME::PROTOCOL_OpenPGP})
|
67
|
+
rescue TypeError
|
68
|
+
GPGME.check_version(nil)
|
69
|
+
end
|
68
70
|
true
|
69
71
|
rescue GPGME::Error
|
70
72
|
false
|
73
|
+
rescue ArgumentError
|
74
|
+
# gpgme 2.0.0 raises this due to the hash->string conversion
|
75
|
+
false
|
71
76
|
end
|
72
77
|
rescue NameError
|
73
78
|
false
|
74
79
|
end
|
75
80
|
|
76
81
|
unless @gpgme_present
|
77
|
-
@not_working_reason = ['gpgme gem not present',
|
82
|
+
@not_working_reason = ['gpgme gem not present',
|
78
83
|
'Install the gpgme gem in order to use signed and encrypted emails']
|
79
84
|
return
|
80
85
|
end
|
81
86
|
|
82
87
|
# if gpg2 is available, it will start gpg-agent if required
|
83
88
|
if (bin = `which gpg2`.chomp) =~ /\S/
|
84
|
-
GPGME.set_engine_info
|
89
|
+
if GPGME.respond_to?('set_engine_info')
|
90
|
+
GPGME.set_engine_info GPGME::PROTOCOL_OpenPGP, bin, nil
|
91
|
+
else
|
92
|
+
GPGME.gpgme_set_engine_info GPGME::PROTOCOL_OpenPGP, bin, nil
|
93
|
+
end
|
85
94
|
else
|
86
95
|
# check if the gpg-options hook uses the passphrase_callback
|
87
96
|
# if it doesn't then check if gpg agent is present
|
88
|
-
gpg_opts = HookManager.run("gpg-options",
|
97
|
+
gpg_opts = HookManager.run("gpg-options",
|
89
98
|
{:operation => "sign", :options => {}}) || {}
|
90
99
|
if gpg_opts[:passphrase_callback].nil?
|
91
100
|
if ENV['GPG_AGENT_INFO'].nil?
|
@@ -110,22 +119,29 @@ EOS
|
|
110
119
|
end
|
111
120
|
|
112
121
|
def have_crypto?; @not_working_reason.nil? end
|
122
|
+
def not_working_reason; @not_working_reason end
|
113
123
|
|
114
124
|
def sign from, to, payload
|
115
125
|
return unknown_status(@not_working_reason) unless @not_working_reason.nil?
|
116
126
|
|
117
127
|
gpg_opts = {:protocol => GPGME::PROTOCOL_OpenPGP, :armor => true, :textmode => true}
|
118
128
|
gpg_opts.merge!(gen_sign_user_opts(from))
|
119
|
-
gpg_opts = HookManager.run("gpg-options",
|
129
|
+
gpg_opts = HookManager.run("gpg-options",
|
120
130
|
{:operation => "sign", :options => gpg_opts}) || gpg_opts
|
121
131
|
|
122
132
|
begin
|
123
|
-
|
133
|
+
if GPGME.respond_to?('detach_sign')
|
134
|
+
sig = GPGME.detach_sign(format_payload(payload), gpg_opts)
|
135
|
+
else
|
136
|
+
crypto = GPGME::Crypto.new
|
137
|
+
gpg_opts[:mode] = GPGME::SIG_MODE_DETACH
|
138
|
+
sig = crypto.sign(format_payload(payload), gpg_opts).read
|
139
|
+
end
|
124
140
|
rescue GPGME::Error => exc
|
125
141
|
raise Error, gpgme_exc_msg(exc.message)
|
126
142
|
end
|
127
143
|
|
128
|
-
# if the key (or gpg-agent) is not available GPGME does not complain
|
144
|
+
# if the key (or gpg-agent) is not available GPGME does not complain
|
129
145
|
# but just returns a zero length string. Let's catch that
|
130
146
|
if sig.length == 0
|
131
147
|
raise Error, gpgme_exc_msg("GPG failed to generate signature: check that gpg-agent is running and your key is available.")
|
@@ -145,7 +161,7 @@ EOS
|
|
145
161
|
|
146
162
|
gpg_opts = {:protocol => GPGME::PROTOCOL_OpenPGP, :armor => true, :textmode => true}
|
147
163
|
if sign
|
148
|
-
gpg_opts.merge!(gen_sign_user_opts(from))
|
164
|
+
gpg_opts.merge!(gen_sign_user_opts(from))
|
149
165
|
gpg_opts.merge!({:sign => true})
|
150
166
|
end
|
151
167
|
gpg_opts = HookManager.run("gpg-options",
|
@@ -153,12 +169,18 @@ EOS
|
|
153
169
|
recipients = to + [from]
|
154
170
|
recipients = HookManager.run("gpg-expand-keys", { :recipients => recipients }) || recipients
|
155
171
|
begin
|
156
|
-
|
172
|
+
if GPGME.respond_to?('encrypt')
|
173
|
+
cipher = GPGME.encrypt(recipients, format_payload(payload), gpg_opts)
|
174
|
+
else
|
175
|
+
crypto = GPGME::Crypto.new
|
176
|
+
gpg_opts[:recipients] = recipients
|
177
|
+
cipher = crypto.encrypt(format_payload(payload), gpg_opts).read
|
178
|
+
end
|
157
179
|
rescue GPGME::Error => exc
|
158
180
|
raise Error, gpgme_exc_msg(exc.message)
|
159
181
|
end
|
160
182
|
|
161
|
-
# if the key (or gpg-agent) is not available GPGME does not complain
|
183
|
+
# if the key (or gpg-agent) is not available GPGME does not complain
|
162
184
|
# but just returns a zero length string. Let's catch that
|
163
185
|
if cipher.length == 0
|
164
186
|
raise Error, gpgme_exc_msg("GPG failed to generate cipher text: check that gpg-agent is running and your key is available.")
|
@@ -262,7 +284,11 @@ EOS
|
|
262
284
|
{:operation => "decrypt", :options => gpg_opts}) || gpg_opts
|
263
285
|
ctx = GPGME::Ctx.new(gpg_opts)
|
264
286
|
cipher_data = GPGME::Data.from_str(format_payload(payload))
|
265
|
-
|
287
|
+
if GPGME::Data.respond_to?('empty')
|
288
|
+
plain_data = GPGME::Data.empty
|
289
|
+
else
|
290
|
+
plain_data = GPGME::Data.empty!
|
291
|
+
end
|
266
292
|
begin
|
267
293
|
ctx.decrypt_verify(cipher_data, plain_data)
|
268
294
|
rescue GPGME::Error => exc
|
@@ -275,7 +301,7 @@ EOS
|
|
275
301
|
end
|
276
302
|
plain_data.seek(0, IO::SEEK_SET)
|
277
303
|
output = plain_data.read
|
278
|
-
output.
|
304
|
+
output.transcode(Encoding::ASCII_8BIT, output.encoding)
|
279
305
|
|
280
306
|
## TODO: test to see if it is still necessary to do a 2nd run if verify
|
281
307
|
## fails.
|
@@ -290,7 +316,7 @@ EOS
|
|
290
316
|
# Look for Charset, they are put before the base64 crypted part
|
291
317
|
charsets = payload.body.split("\n").grep(/^Charset:/)
|
292
318
|
if !charsets.empty? and charsets[0] =~ /^Charset: (.+)$/
|
293
|
-
output
|
319
|
+
output.transcode($encoding, $1)
|
294
320
|
end
|
295
321
|
msg.body = output
|
296
322
|
else
|
@@ -314,7 +340,7 @@ EOS
|
|
314
340
|
msg = RMail::Parser.read output
|
315
341
|
if msg.header.content_type =~ %r{^multipart/} && !msg.multipart?
|
316
342
|
output = "MIME-Version: 1.0\n" + output
|
317
|
-
output.
|
343
|
+
output.fix_encoding
|
318
344
|
msg = RMail::Parser.read output
|
319
345
|
end
|
320
346
|
end
|
@@ -330,7 +356,7 @@ private
|
|
330
356
|
|
331
357
|
def gpgme_exc_msg msg
|
332
358
|
err_msg = "Exception in GPGME call: #{msg}"
|
333
|
-
info err_msg
|
359
|
+
#info err_msg
|
334
360
|
err_msg
|
335
361
|
end
|
336
362
|
|
@@ -362,7 +388,7 @@ private
|
|
362
388
|
else
|
363
389
|
first_sig = "Unknown error or empty signature"
|
364
390
|
end
|
365
|
-
rescue EOFError
|
391
|
+
rescue EOFError
|
366
392
|
from_key = nil
|
367
393
|
first_sig = "No public key available for #{signature.fingerprint}"
|
368
394
|
end
|