sup 0.19.0 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d330a3455ed22952d8c45fce0f6a0d69346c40f2
4
- data.tar.gz: 337b95be43bc301f6180b542b2395df025f4f1db
3
+ metadata.gz: e7b5ce3c73c1c6d194d8103bb25de84981db2529
4
+ data.tar.gz: a5d0868505c66e8c7974025d5131738d2a436ab6
5
5
  SHA512:
6
- metadata.gz: f538e3054ba742a5fadd296bcb6d29b0295e3ca807a0dfe600d908b3cfa9602697bd4e422ac5bde8facb603fe12784add4709ccc4f5ca9b7b76bf348cec3a6f3
7
- data.tar.gz: 1923d32e3cfc13998e52bc7c53b19482f6a4ed9b13d4e79880a1a6a16d926b26af2e6aaa73d1ea6556a6d2cdaf51aae1979afc51eff01697df9801dd787a45a3
6
+ metadata.gz: 8b44f362bd82be161b1d9451d805af1a9d73d962df4c54196703dec1bbca383fb7bd5f2c0bf6479c1fc57bc27b37ec17a65fc2b24abab838e7f2797bfb64687a
7
+ data.tar.gz: e3a2eaaebf74bec788b18c28be9d9a2bee2b8fa06487780f3199aa7446ec386ac5ffc731595245e40be6423dfc1708bed14fe74ada70eab06097655ccc4fd47a
data/.gitignore CHANGED
@@ -4,6 +4,7 @@
4
4
  *~
5
5
  # artifact
6
6
  pkg/
7
+ man/
7
8
  *.gem
8
9
  # i have accidently added this one one too many times
9
10
  sup-exception-log.txt
@@ -14,4 +15,5 @@ Gemfile.lock
14
15
 
15
16
  # generated file for gnupg test
16
17
  test/gnupg_test_home/random_seed
18
+ test/gnupg_test_home/trustdb.gpg
17
19
 
@@ -0,0 +1,3 @@
1
+ [submodule "doc/wiki"]
2
+ path = doc/wiki
3
+ url = https://github.com/sup-heliotrope/sup.wiki.git
@@ -7,6 +7,7 @@ rvm:
7
7
 
8
8
  before_install:
9
9
  - sudo apt-get update -qq
10
- - sudo apt-get install -qq uuid-dev uuid libncursesw5-dev libncursesw5 gnupg2
10
+ - sudo apt-get install -qq uuid-dev uuid libncursesw5-dev libncursesw5 gnupg2 pandoc
11
+ - git submodule update --init --recursive
11
12
 
12
13
  script: bundle exec rake travis
@@ -13,12 +13,13 @@ Michael Stapelberg <michael at the stapelberg dot des>
13
13
  Eric Sherman <hyperbolist at the gmail dot coms>
14
14
  Tero Tilus <tero at the tilus dot nets>
15
15
  Ben Walton <bwalton at the artsci.utoronto dot cas>
16
+ Scott Bonds <scott at the ggr dot coms>
16
17
  Mike Stipicevic <stipim at the rpi dot edus>
17
18
  Martin Bähr <mbaehr at the societyserver dot orgs>
19
+ Matthieu Rakotojaona <matthieu.rakotojaona at the gmail dot coms>
18
20
  Clint Byrum <clint at the ubuntu dot coms>
19
21
  Wael M. Nasreddine <wael.nasreddine at the gmail dot coms>
20
22
  Marcus Williams <marcus-sup at the bar-coded dot nets>
21
- Matthieu Rakotojaona <matthieu.rakotojaona at the gmail dot coms>
22
23
  Lionel Ott <white.magic at the gmx dot des>
23
24
  Gaudenz Steinlin <gaudenz at the soziologie dot chs>
24
25
  Ingmar Vanhassel <ingmar at the exherbo dot orgs>
@@ -37,25 +38,27 @@ Markus Klinik <mkl at the lambdanaut dot nets>
37
38
  Bo Borgerson <gigabo at the gmail dot coms>
38
39
  Atte Kojo <atte.kojo at the reaktor dot fis>
39
40
  Michael Hamann <michael at the content-space dot des>
40
- William Erik Baxter <web at the superscript dot coms>
41
41
  Jonathan Lassoff <jof at the thejof dot coms>
42
+ William Erik Baxter <web at the superscript dot coms>
42
43
  Grant Hollingworth <grant at the antiflux dot orgs>
43
44
  Ico Doornekamp <ico at the pruts dot nls>
44
45
  Adeodato Simó <dato at the net.com.org dot ess>
45
46
  Daniel Schoepe <daniel.schoepe at the googlemail dot coms>
46
47
  James Taylor <james at the jamestaylor dot orgs>
47
48
  Jason Petsod <jason at the petsod dot orgs>
48
- Robin Burchell <viroteck at the viroteck dot nets>
49
49
  Steve Goldman <sgoldman at the tower-research dot coms>
50
+ Robin Burchell <viroteck at the viroteck dot nets>
50
51
  Peter Harkins <ph at the malaprop dot orgs>
51
52
  Decklin Foster <decklin at the red-bean dot coms>
52
53
  Cameron Matheson <cam+sup at the cammunism dot orgs>
53
54
  Carl Worth <cworth at the cworth dot orgs>
54
55
  Alex Vandiver <alex at the chmrr dot nets>
55
- Andrew Pimlott <andrew at the pimlott dot nets>
56
56
  Jeff Balogh <its.jeff.balogh at the gmail dot coms>
57
+ Andrew Pimlott <andrew at the pimlott dot nets>
57
58
  Matías Aguirre <matiasaguirre at the gmail dot coms>
58
59
  PaulSmecker <paul.smecker at the gmail dot coms>
60
+ Per Andersson <avtobiff at the gmail dot coms>
61
+ Ruthard Baudach <rthrd at the web dot des>
59
62
  Kornilios Kourtis <kkourt at the cslab.ece.ntua dot grs>
60
63
  Lars Fischer <fischer at the wiwi.uni-siegen dot des>
61
64
  madhat2r <MaDhAt2r at the dukefoo dot coms>
@@ -67,18 +70,17 @@ Steven Lawrance <stl at the koffein dot nets>
67
70
  Jonah <Jonah at the GoodCoffee dot cas>
68
71
  ian <itaylor at the uark dot edus>
69
72
  Adam Lloyd <adam at the alloy-d dot nets>
70
- MichaelRevell <mikearevell at the gmail dot coms>
71
- Gregor Hoffleit <gregor at the sam.mediasupervision dot des>
72
73
  Todd Eisenberger <teisenbe at the andrew.cmu dot edus>
73
- Per Andersson <avtobiff at the gmail dot coms>
74
74
  0xACE <0xACE at the users.noreply.github dot coms>
75
+ MichaelRevell <mikearevell at the gmail dot coms>
76
+ Gregor Hoffleit <gregor at the sam.mediasupervision dot des>
75
77
  Steven Schmeiser <steven at the schmeiser dot orgs>
76
78
  Steven Walter <swalter at the monarch.(none)>
77
79
  Jon M. Dugan <jdugan at the es dot nets>
78
- akojo <atte.kojo at the gmail dot coms>
79
- Matthias Vallentin <vallentin at the icir dot orgs>
80
- William A. Kennington III <william at the wkennington dot coms>
81
80
  Horacio Sanson <horacio at the skillupjapan.co dot jps>
82
81
  Stefan Lundström <lundst at the snabb.(none)>
82
+ William A. Kennington III <william at the wkennington dot coms>
83
+ akojo <atte.kojo at the gmail dot coms>
84
+ Matthias Vallentin <vallentin at the icir dot orgs>
83
85
  Johannes Larsen <johs.a.larsen at the gmail dot coms>
84
86
  Kirill Smelkov <kirr at the landau.phys.spbu dot rus>
data/Gemfile CHANGED
@@ -1,3 +1,7 @@
1
1
  source 'https://rubygems.org/'
2
2
 
3
+ if !RbConfig::CONFIG['arch'].include?('openbsd')
4
+ gem 'xapian-ruby', '~> 1.2.15'
5
+ end
6
+
3
7
  gemspec
@@ -1,3 +1,16 @@
1
+ == 0.20.0 / 2014-10-06
2
+
3
+ * add man-pages (generated from wiki) (Per Andersson)!
4
+ * HTML messages or messages that are decoded with the mime-decode hook
5
+ are now indexed if the mime-decode hook is set up (Scott Bonds).
6
+ * OpenBSD support (Scott Bonds)!
7
+ * goto-hook for keybinding to open URLs.
8
+ * support special charaters in source URIs (Scott Bonds).
9
+ * output message id and locations on all load_from_source failures
10
+ * fix long-standing getlocal bug
11
+ * make new test GPG keys (old ones expired), valid for one year, script
12
+ now available in devel/ for making new ones.
13
+
1
14
  == 0.19.0 / 2014-07-05
2
15
 
3
16
  * new check-attachment hook
data/Rakefile CHANGED
@@ -9,4 +9,45 @@ Rake::TestTask.new(:test) do |test|
9
9
  end
10
10
  task :default => :test
11
11
 
12
+ task :build => [:man]
12
13
  task :travis => [:test, :build]
14
+
15
+ def test_pandoc
16
+ return system("pandoc -v > /dev/null 2>&1")
17
+ end
18
+
19
+ task :man do
20
+ puts "building manpages from wiki.."
21
+ unless test_pandoc
22
+ puts "no pandoc installed, needed for manpage generation."
23
+ return
24
+ end
25
+
26
+ # test if wiki is cloned
27
+ unless Dir.exist? 'doc/wiki/man'
28
+ puts "wiki git repository is not cloned in doc/wiki, try: git submodule update --init."
29
+ return
30
+ end
31
+
32
+ unless Dir.exist? 'man'
33
+ Dir.mkdir 'man'
34
+ end
35
+
36
+ Dir.glob("doc/wiki/man/*.md").each do |md|
37
+ m = /^.*\/(?<manpage>[^\/]*)\.md$/.match(md)[:manpage]
38
+ puts "generating manpage for: #{m}.."
39
+ r = system "pandoc -s -f markdown -t man #{md} -o man/#{m}"
40
+
41
+ unless r
42
+ puts "failed to generate manpage: #{m}."
43
+ return
44
+ end
45
+ end
46
+ end
47
+
48
+ task :clean do
49
+ ['man', 'pkg'].each do |d|
50
+ puts "cleaning #{d}.."
51
+ FileUtils.rm_r d if Dir.exist? d
52
+ end
53
+ end
@@ -1,3 +1,13 @@
1
+ Release 0.20.0:
2
+
3
+ We've got man pages (Mr. Andersson)! We've got OpenBSD support (Scott Bonds)!
4
+ It is now possible to get your HTML emails indexed by setting up a mime-decode
5
+ hook before you index (Scott Bonds)! Scott Bonds also fixed up special character handing in source URIs. It is now possible to set up a goto hook
6
+ for opening the URL below the cursor.
7
+
8
+ Also a few long standing bugs have been fixed, and new GPG keys have been made
9
+ for the tests.
10
+
1
11
  Release 0.19.0:
2
12
 
3
13
  New hook: check-attachment and a new option to shows dates in 24h format.
data/bin/sup CHANGED
@@ -106,26 +106,28 @@ end
106
106
  ## ncurses.so that's been compiled against libncursesw. (note the w.) why
107
107
  ## this works, i have no idea. much like pretty much every aspect of
108
108
  ## dealing with curses. cargo cult programming at its best.
109
- require 'dl/import'
110
109
  require 'rbconfig'
111
- module LibC
112
- extend DL.const_defined?(:Importer) ? DL::Importer : DL::Importable
113
- setlocale_lib = case RbConfig::CONFIG['arch']
114
- when /darwin/; "libc.dylib"
115
- when /cygwin/; "cygwin1.dll"
116
- when /freebsd/; "libc.so.7"
117
- else; "libc.so.6"
118
- end
110
+ unless RbConfig::CONFIG['arch'] =~ /openbsd/
111
+ require 'dl/import'
112
+ module LibC
113
+ extend DL.const_defined?(:Importer) ? DL::Importer : DL::Importable
114
+ setlocale_lib = case RbConfig::CONFIG['arch']
115
+ when /darwin/; "libc.dylib"
116
+ when /cygwin/; "cygwin1.dll"
117
+ when /freebsd/; "libc.so.7"
118
+ else; "libc.so.6"
119
+ end
119
120
 
120
- debug "dynamically loading setlocale() from #{setlocale_lib}"
121
- begin
122
- dlload setlocale_lib
123
- extern "void setlocale(int, const char *)"
124
- debug "setting locale..."
125
- LibC.setlocale(6, "") # LC_ALL == 6
126
- rescue RuntimeError => e
127
- warn "cannot dlload setlocale(); ncurses wide character support probably broken."
128
- warn "dlload error was #{e.class}: #{e.message}"
121
+ debug "dynamically loading setlocale() from #{setlocale_lib}"
122
+ begin
123
+ dlload setlocale_lib
124
+ extern "void setlocale(int, const char *)"
125
+ debug "setting locale..."
126
+ LibC.setlocale(6, "") # LC_ALL == 6
127
+ rescue RuntimeError => e
128
+ warn "cannot dlload setlocale(); ncurses wide character support probably broken."
129
+ warn "dlload error was #{e.class}: #{e.message}"
130
+ end
129
131
  end
130
132
  end
131
133
 
@@ -0,0 +1,47 @@
1
+ require 'rubygems'
2
+ require 'rubygems/command.rb'
3
+ require 'rubygems/dependency_installer.rb'
4
+ require 'rbconfig'
5
+
6
+ begin
7
+ Gem::Command.build_args = ARGV
8
+ rescue NoMethodError
9
+ end
10
+
11
+ puts "xapian: platform specific dependencies.."
12
+
13
+ inst = Gem::DependencyInstaller.new
14
+ begin
15
+
16
+ if !RbConfig::CONFIG['arch'].include?('openbsd')
17
+ # update version in Gemfile as well
18
+ name = "xapian-ruby"
19
+ version = "~> 1.2.15"
20
+
21
+ begin
22
+ # try to load gem
23
+
24
+ gem name, version
25
+ STDERR.puts "xapian: already installed."
26
+
27
+ rescue Gem::LoadError
28
+
29
+ STDERR.puts "xapian: installing xapian-ruby.."
30
+ inst.install name, version
31
+
32
+ end
33
+ else
34
+ 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
+ end
36
+
37
+ rescue
38
+
39
+ exit(1)
40
+
41
+ end
42
+
43
+ # create dummy rakefile to indicate success
44
+ f = File.open(File.join(File.dirname(__FILE__), "Rakefile"), "w")
45
+ f.write("task :default\n")
46
+ f.close
47
+
data/lib/sup.rb CHANGED
@@ -8,6 +8,7 @@ require 'fileutils'
8
8
  require 'locale'
9
9
  require 'ncursesw'
10
10
  require 'rmail'
11
+ require 'uri'
11
12
  begin
12
13
  require 'fastthread'
13
14
  rescue LoadError
@@ -64,6 +65,7 @@ module Redwood
64
65
  LEGACY_YAML_DOMAIN = "masanjin.net"
65
66
  YAML_DATE = "2006-10-01"
66
67
  MAILDIR_SYNC_CHECK_SKIPPED = 'SKIPPED'
68
+ URI_ENCODE_CHARS = "!*'();:@&=+$,?#[] " # see https://en.wikipedia.org/wiki/Percent-encoding
67
69
 
68
70
  ## record exceptions thrown in threads nicely
69
71
  @exceptions = []
@@ -396,6 +396,18 @@ EOS
396
396
  end
397
397
  end
398
398
 
399
+ ## ask* functions. these functions display a one-line text field with
400
+ ## a prompt at the bottom of the screen. answers typed or choosen by
401
+ ## tab-completion
402
+ ##
403
+ ## common arguments are:
404
+ ##
405
+ ## domain: token used as key for @textfields, which seems to be a
406
+ ## dictionary of input field objects
407
+ ## question: string used as prompt
408
+ ## completions: array of possible answers, that can be completed by using
409
+ ## the tab key
410
+ ## default: default value to return
399
411
  def ask_with_completions domain, question, completions, default=nil
400
412
  ask domain, question, default do |s|
401
413
  s.fix_encoding!
@@ -12,7 +12,15 @@ 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
- uri = URI(@expanded_uri)
15
+ parts = @expanded_uri.match /^([a-zA-Z0-9]*:(\/\/)?)(.*)/
16
+ if parts
17
+ prefix = parts[1]
18
+ @path = parts[3]
19
+ uri = URI(prefix + URI.encode(@path, URI_ENCODE_CHARS))
20
+ else
21
+ uri = URI(URI.encode @expanded_uri, URI_ENCODE_CHARS)
22
+ @path = uri.path
23
+ end
16
24
 
17
25
  raise ArgumentError, "not a maildir URI" unless uri.scheme == "maildir"
18
26
  raise ArgumentError, "maildir URI cannot have a host: #{uri.host}" if uri.host
@@ -22,7 +30,7 @@ class Maildir < Source
22
30
  # sync by default if not specified
23
31
  @sync_back = true if @sync_back.nil?
24
32
 
25
- @dir = uri.path
33
+ @dir = URI.decode uri.path
26
34
  @labels = Set.new(labels || [])
27
35
  @mutex = Mutex.new
28
36
  @ctimes = { 'cur' => Time.at(0), 'new' => Time.at(0) }
@@ -120,7 +128,10 @@ class Maildir < Source
120
128
  @ctimes[d] = ctime
121
129
 
122
130
  old_ids = benchmark(:maildir_read_index) { Index.instance.enum_for(:each_source_info, self.id, "#{d}/").to_a }
123
- new_ids = benchmark(:maildir_read_dir) { Dir.glob("#{subdir}/*").map { |x| File.join(d,File.basename(x)) }.sort }
131
+ new_ids = benchmark(:maildir_read_dir) {
132
+ Dir.open(subdir).select {
133
+ |f| !File.directory? f}.map {
134
+ |x| File.join(d,File.basename(x)) }.sort }
124
135
  added += new_ids - old_ids
125
136
  deleted += old_ids - new_ids
126
137
  debug "#{old_ids.size} in index, #{new_ids.size} in filesystem"
@@ -19,16 +19,24 @@ 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
- uri = URI(@expanded_uri)
22
+ parts = @expanded_uri.match /^([a-zA-Z0-9]*:(\/\/)?)(.*)/
23
+ if parts
24
+ prefix = parts[1]
25
+ @path = parts[3]
26
+ uri = URI(prefix + URI.encode(@path, URI_ENCODE_CHARS))
27
+ else
28
+ uri = URI(URI.encode @expanded_uri, URI_ENCODE_CHARS)
29
+ @path = uri.path
30
+ end
31
+
23
32
  raise ArgumentError, "not an mbox uri" unless uri.scheme == "mbox"
24
33
  raise ArgumentError, "mbox URI ('#{uri}') cannot have a host: #{uri.host}" if uri.host
25
34
  raise ArgumentError, "mbox URI must have a path component" unless uri.path
26
35
  @f = nil
27
- @path = uri.path
28
36
  else
29
37
  @f = uri_or_fp
30
38
  @path = uri_or_fp.path
31
- @expanded_uri = "mbox://#{@path}"
39
+ @expanded_uri = "mbox://#{URI.encode @path, URI_ENCODE_CHARS}"
32
40
  end
33
41
 
34
42
  super uri_or_fp, usual, archived, id
@@ -268,6 +268,14 @@ class Message
268
268
  debug "could not load message: #{location.inspect}, exception: #{e.inspect}"
269
269
 
270
270
  [Chunk::Text.new(error_message.split("\n"))]
271
+
272
+ rescue Exception => e
273
+
274
+ warn "problem reading message #{id}"
275
+ debug "could not load message: #{location.inspect}, exception: #{e.inspect}"
276
+
277
+ raise e
278
+
271
279
  end
272
280
  end
273
281
 
@@ -327,17 +335,17 @@ EOS
327
335
  to.map { |p| p.indexable_content },
328
336
  cc.map { |p| p.indexable_content },
329
337
  bcc.map { |p| p.indexable_content },
330
- indexable_chunks.map { |c| c.lines },
338
+ indexable_chunks.map { |c| c.lines.map { |l| l.fix_encoding! } },
331
339
  indexable_subject,
332
340
  ].flatten.compact.join " "
333
341
  end
334
342
 
335
343
  def indexable_body
336
- indexable_chunks.map { |c| c.lines }.flatten.compact.join " "
344
+ indexable_chunks.map { |c| c.lines }.flatten.compact.map { |l| l.fix_encoding! }.join " "
337
345
  end
338
346
 
339
347
  def indexable_chunks
340
- chunks.select { |c| c.is_a? Chunk::Text } || []
348
+ chunks.select { |c| c.indexable? } || []
341
349
  end
342
350
 
343
351
  def indexable_subject
@@ -164,6 +164,7 @@ EOS
164
164
  ## something we can display inline. otherwise, it's viewable.
165
165
  def inlineable?; false end
166
166
  def expandable?; !viewable? end
167
+ def indexable?; expandable? end
167
168
  def initial_state; :open end
168
169
  def viewable?; @lines.nil? end
169
170
  def view_default! path
@@ -229,6 +230,7 @@ EOS
229
230
  def inlineable?; true end
230
231
  def quotable?; true end
231
232
  def expandable?; false end
233
+ def indexable?; true end
232
234
  def viewable?; false end
233
235
  def color; :text_color end
234
236
  end
@@ -242,6 +244,7 @@ EOS
242
244
  def inlineable?; @lines.length == 1 end
243
245
  def quotable?; true end
244
246
  def expandable?; !inlineable? end
247
+ def indexable?; expandable? end
245
248
  def viewable?; false end
246
249
 
247
250
  def patina_color; :quote_patina_color end
@@ -258,6 +261,7 @@ EOS
258
261
  def inlineable?; @lines.length == 1 end
259
262
  def quotable?; false end
260
263
  def expandable?; !inlineable? end
264
+ def indexable?; expandable? end
261
265
  def viewable?; false end
262
266
 
263
267
  def patina_color; :sig_patina_color end
@@ -291,6 +295,7 @@ EOS
291
295
  def inlineable?; false end
292
296
  def quotable?; false end
293
297
  def expandable?; true end
298
+ def indexable?; true end
294
299
  def initial_state; :closed end
295
300
  def viewable?; false end
296
301
 
@@ -322,6 +327,7 @@ EOS
322
327
  def inlineable?; false end
323
328
  def quotable?; false end
324
329
  def expandable?; !@lines.empty? end
330
+ def indexable?; false end
325
331
  def viewable?; false end
326
332
  end
327
333
  end
@@ -20,6 +20,7 @@ Variables:
20
20
  to the raw headers for the message. E.g., header["From"],
21
21
  header["To"], etc.
22
22
  from_email: the email part of the From: line, or nil if empty
23
+ message_id: the unique message id of the message
23
24
  Return value:
24
25
  A string (multi-line ok) containing the text of the signature, or nil to
25
26
  use the default signature, or :none for no signature.
@@ -688,7 +689,7 @@ private
688
689
  from_email = p && p.email
689
690
 
690
691
  ## first run the hook
691
- hook_sig = HookManager.run "signature", :header => @header, :from_email => from_email
692
+ hook_sig = HookManager.run "signature", :header => @header, :from_email => from_email, :message_id => @message_id
692
693
 
693
694
  return [] if hook_sig == :none
694
695
  return ["", "-- "] + hook_sig.split("\n") if hook_sig
@@ -856,6 +856,12 @@ protected
856
856
  need_update = false
857
857
 
858
858
  @mutex.synchronize do
859
+ # and certainly not sure why this happens..
860
+ #
861
+ # probably a race condition between thread modification and updating
862
+ # going on.
863
+ return if @threads[l].empty?
864
+
859
865
  @size_widgets[l] = size_widget_for_thread @threads[l]
860
866
  @date_widgets[l] = date_widget_for_thread @threads[l]
861
867
 
@@ -42,6 +42,14 @@ Return value:
42
42
  None.
43
43
  EOS
44
44
 
45
+ HookManager.register "goto", <<EOS
46
+ Open the uri given as a parameter.
47
+ Variables:
48
+ uri: The uri
49
+ Return value:
50
+ None.
51
+ EOS
52
+
45
53
  register_keymap do |k|
46
54
  k.add :toggle_detailed_header, "Toggle detailed header", 'h'
47
55
  k.add :show_header, "Show full message header", 'H'
@@ -80,6 +88,8 @@ EOS
80
88
  k.add :kill_and_next, "Kill this thread, kill buffer, and view next", '&'
81
89
  k.add :toggle_wrap, "Toggle wrapping of text", 'w'
82
90
 
91
+ k.add :goto_uri, "Goto uri under cursor", 'g'
92
+
83
93
  k.add_multi "(a)rchive/(d)elete/mark as (s)pam/mark as u(N)read:", '.' do |kk|
84
94
  kk.add :archive_and_kill, "Archive this thread and kill buffer", 'a'
85
95
  kk.add :delete_and_kill, "Delete this thread and kill buffer", 'd'
@@ -722,6 +732,48 @@ EOS
722
732
  [user_labels, super].join(" -- ")
723
733
  end
724
734
 
735
+ def goto_uri
736
+ unless (chunk = @chunk_lines[curpos])
737
+ BufferManager.flash "No URI found."
738
+ return
739
+ end
740
+ unless HookManager.enabled? "goto"
741
+ BufferManager.flash "You must add a goto.rb hook before you can goto a URI."
742
+ return
743
+ end
744
+
745
+ # @text is a list of lines with this format:
746
+ # [
747
+ # [[:text_color, "Some text"]]
748
+ # [[:text_color, " continued here"]]
749
+ # ]
750
+
751
+ linetext = @text.slice(curpos, @text.length).flatten(1)
752
+ .take_while{|d| d[0] == :text_color and d[1].strip != ""} # Only take up to the first "" alone on its line
753
+ .map{|d| d[1].strip}.join("").strip
754
+
755
+ found = false
756
+ (linetext || "").scan(URI::regexp).each do |matches|
757
+ begin
758
+ link = $& # ruby magic: $& is the whole regexp match
759
+ u = URI.parse(link)
760
+ next unless u.absolute?
761
+ next unless ["http", "https"].include?(u.scheme)
762
+
763
+ reallink = Shellwords.escape(u.to_s)
764
+ BufferManager.flash "Going to #{reallink} ..."
765
+ HookManager.run "goto", :uri => reallink
766
+ BufferManager.completely_redraw_screen
767
+ found = true
768
+
769
+ rescue URI::InvalidURIError => e
770
+ debug "not a uri: #{e}"
771
+ # Do nothing, this is an ok flow
772
+ end
773
+ end
774
+ BufferManager.flash "No URI found." unless found
775
+ end
776
+
725
777
  private
726
778
 
727
779
  def initial_state_for m
@@ -1,3 +1,3 @@
1
1
  module Redwood
2
- VERSION = "0.19.0"
2
+ VERSION = "0.20.0"
3
3
  end
@@ -25,16 +25,31 @@ DESC
25
25
  SUP: please note that our old mailing lists have been shut down,
26
26
  re-subscribe to supmua@googlegroups.com to discuss and follow
27
27
  updates on sup (send email to: supmua+subscribe@googlegroups.com).
28
+
29
+ OpenBSD users:
30
+ If your operating system is OpenBSD you have some
31
+ additional, manual steps to do before Sup will work, see:
32
+ https://github.com/sup-heliotrope/sup/wiki/Installation%3A-OpenBSD.
28
33
  EOF
29
34
 
30
35
  s.files = `git ls-files -z`.split("\x0")
31
36
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
32
37
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
33
38
  s.require_paths = ["lib"]
39
+ s.extra_rdoc_files = Dir.glob("man/*")
34
40
 
35
41
  s.required_ruby_version = '>= 1.9.3'
36
42
 
37
- s.add_runtime_dependency "xapian-ruby", "~> 1.2.15"
43
+ # this is here to support skipping the xapian-ruby installation on OpenBSD
44
+ # because the xapian-ruby gem doesn't install on OpenBSD, you must install
45
+ # xapian-core and xapian-bindings manually on OpenBSD
46
+ # see https://github.com/sup-heliotrope/sup/wiki/Installation%3A-OpenBSD
47
+ # and https://en.wikibooks.org/wiki/Ruby_Programming/RubyGems#How_to_install_different_versions_of_gems_depending_on_which_version_of_ruby_the_installee_is_using
48
+ s.extensions = %w[ext/mkrf_conf_xapian.rb]
49
+
50
+ ## remember to update the xapian dependency in
51
+ ## ext/mkrf_conf_xapian.rb and Gemfile.
52
+
38
53
  s.add_runtime_dependency "ncursesw", "~> 1.4.0"
39
54
  s.add_runtime_dependency "rmail-sup", "~> 1.0.1"
40
55
  s.add_runtime_dependency "highline"
@@ -50,4 +65,5 @@ SUP: please note that our old mailing lists have been shut down,
50
65
  s.add_development_dependency "minitest", "~> 4.7"
51
66
  s.add_development_dependency "rr", "~> 1.0.5"
52
67
  s.add_development_dependency "gpgme", ">= 2.0.2"
68
+
53
69
  end
@@ -1 +1,2 @@
1
- default-key 789E7011
1
+ trust-model always
2
+
@@ -0,0 +1,15 @@
1
+ %echo Generating a standard key
2
+ Key-Type: DSA
3
+ Key-Length: 1024
4
+ Subkey-Type: ELG-E
5
+ Subkey-Length: 1024
6
+ Name-Real: Sup Test Sender 1
7
+ Name-Comment: Test sender key
8
+ Name-Email: sup-test-1@foo.bar
9
+ Expire-Date: 1y
10
+ %no-protection
11
+ %pubring pubring.gpg
12
+ %secring secring.gpg
13
+ # Do a commit here, so that we can later print "done" :-)
14
+ %commit
15
+ %echo done
@@ -0,0 +1,15 @@
1
+ %echo Generating a standard key
2
+ Key-Type: DSA
3
+ Key-Length: 1024
4
+ Subkey-Type: ELG-E
5
+ Subkey-Length: 1024
6
+ Name-Real: Sup Test Receiver
7
+ Name-Comment: Test receiver for Sup
8
+ Name-Email: sup-test-2@foo.bar
9
+ Expire-Date: 1y
10
+ %no-protection
11
+ %pubring pubring.gpg
12
+ %secring secring.gpg
13
+ # Do a commit here, so that we can later print "done" :-)
14
+ %commit
15
+ %echo done
@@ -0,0 +1,35 @@
1
+ #! /bin/bash
2
+ #
3
+ # re-generate test keys for the sup test base
4
+ #
5
+ # https://github.com/sup-heliotrope/sup/wiki/Development%3A-Crypto
6
+
7
+ pushd $(dirname $0)
8
+
9
+ export GNUPGHOME="$(pwd)"
10
+
11
+ echo "genrating keys in: $GNUPGHOME.."
12
+
13
+ rm *.gpg *.asc
14
+
15
+ echo "generate receiver key.."
16
+ gpg --batch --gen-key key2.gen
17
+
18
+ echo "export receiver key.."
19
+
20
+ gpg --output sup-test-2@foo.bar.asc --armor --export sup-test-2@foo.bar
21
+
22
+ mv trustdb.gpg receiver_trustdb.gpg
23
+ mv secring.gpg receiver_secring.gpg
24
+ mv pubring.gpg receiver_pubring.gpg
25
+
26
+ echo "generate sender key.."
27
+ gpg --batch --gen-key key1.gen
28
+
29
+ echo "import receiver key.."
30
+ gpg --import sup-test-2@foo.bar.asc
31
+
32
+
33
+
34
+ popd
35
+
@@ -1,20 +1,25 @@
1
1
  -----BEGIN PGP PUBLIC KEY BLOCK-----
2
- Version: GnuPG v2.0.20 (GNU/Linux)
2
+ Version: GnuPG v2
3
3
 
4
- mI0EUgi0fAEEAOLAcQW96NEUSB7YE/la8X56jGW5BMX3aAixOF8LvOwMBbUK1T+U
5
- 0H2PGIrXVcYyHcPqWRpRahbsIAldBqzffPlzMa+aqJaB1xKkNruxSoIzwPdidZMe
6
- l0Dxz2FDsoXD0KPyWnAYhGmQyz2MFpZxu2tlYqvwWVW//XGnk/KHvIXbABEBAAG0
7
- PlN1cCBUZXN0IFJlY2VpdmVyIChUZXN0IHJlY2VpdmVyIGZvciBTdXApIDxzdXAt
8
- dGVzdC0yQGZvby5iYXI+iL8EEwECACkFAlIItHwCGwMFCQHhM4AHCwkIBwMCAQYV
9
- CAIJCgsEFgIDAQIeAQIXgAAKCRAsABl+cWpykMMVBADHkQPgTz0CqKKp3k+z3dbm
10
- ocmI4tYNn1dOkDQqyfoBTfs6L3g4j5OE2UrguntRYyg5oon+uO5d18CQ5dY0sCw/
11
- o5IwyzTrxI8IocbtZvBdSb+XjLndynGuIQoqaJq9i6n1V4klFHVOna8Q9JstLfRX
12
- H1d4xPhnvKcaDDx/NV3X/biNBFIItHwBBADBpb43MpkrUWlg7HWJ1ZfOlxnOxrJ3
13
- Gz9WFNV06UbcZEuFKA/vHRjM6gWzUn5903FLuCWu3eBrq5xQfWipbp187PmocpoG
14
- skJ6gosLs1fMYRBjv2VbG9xJVKdKJMjqZw5FUpXKAaHr8P9jN6g2STQrbeQ8CVUK
15
- h7zOWRXAXSKUgwARAQABiKUEGAECAA8FAlIItHwCGwwFCQHhM4AACgkQLAAZfnFq
16
- cpDV1QQAzcxFXznEX92DjWxWRC7gRHgIsQk9WJnDzjtnDjSWCp3H85qeTZGZrn9W
17
- NoneV/S5Y7K3Mkceh4rFaANQ3zx4b05y1LFt5N/lPwIe5VB0vcPumtZum2fSGfpK
18
- nTXvzelcWcm2aGyUSaWvOkntWKEEt1kB5Oq6EtZoRZLMzAxLd7s=
19
- =aKsV
4
+ mQGiBFP3VogRBADVBEkaZQXj728C1HUIaTRDCFoKzojwC79Z1BLsD72qQYE8z1ic
5
+ 5P9CJpJU5wbhQFDTGBjw+i1nNTWy01z4q5bfFqok+KorT3XNp5IJRcRIEOkj+Twq
6
+ 7ZaSODwXGsUmdzSoOVDYmtUpVzRQe0IM0rPQQV4vGzgw55FdJBe7a63nIwCg+WvR
7
+ iQN09PlhpGG7SIEmx0psEqUEAL/t1c5oC9RC7L4a0GM+2AcgFRBMXvzpdnytrzgt
8
+ 73Ud6CcUplQp6WODrUYhX0RLzSJPO4zWDsBmkBad/iQCwbCKpFPfAFdBMArJpknx
9
+ rc6vRED4a9dLfCNTT1g86CkiElge9t36juZgOoFT3xt/XP7BxhU1fCFshZNR6VK6
10
+ tN9eA/9G4fUX6XvEGIrNiBYKyU4QvM1nyMXCBujm7vYF6KfSlYyAvVXxG4h+mvUy
11
+ ZXQ/WHMQJSbPTY3dd4hmo0p0GUMlSvXU8JLf7qienW1IccD9Pv88J1XjkbFd+wgw
12
+ feoSx1sAfc36gH+aE17lvsU+PPAP4Bc9CSiScNo0iQv7v/KZjrQ+U3VwIFRlc3Qg
13
+ UmVjZWl2ZXIgKFRlc3QgcmVjZWl2ZXIgZm9yIFN1cCkgPHN1cC10ZXN0LTJAZm9v
14
+ LmJhcj6IaQQTEQIAKQUCU/dWiAIbIwUJAeEzgAcLCQgHAwIBBhUIAgkKCwQWAgMB
15
+ Ah4BAheAAAoJEKfs+g8ACvQGPxIAnj1CSZCzjwyIFLgNEQnIhntU+b28AKDsMEVN
16
+ gf9mHqwhabN+UKgBwX0U3LkBDQRT91aIEAQAjQZEnDK++SKp/l2Oiku6H9IuCsi4
17
+ lv+MhLQP0bMuD4DrPk3mauZNc8BB+U0wgAMh/kZoCKySEdMK1mcf2iOsd5yOCrK+
18
+ sJQAMsALAnrYjCE9QA2xIQs8gHF4PrKopycF55iRHQMDNa1QWfs+j4WJaXderlGQ
19
+ S0dGfLyoqtZsFusAAwUEAIi0+aDZlAVVIdDO2cvR0lu6eDW2Mr2ExZzuwTfAI6dS
20
+ tJLoPzoA2OAVW7cFVVpCOHcVLiF2GOHvtJPw1MgpxaNjzpNdJPTiP2sYZg253dfR
21
+ v66Cw9IuWKgZcElWXmIy5vFWqWWbLyTBOuwEQxCsFnjN9UUZauSADOJSPFy1sekf
22
+ iE8EGBECAA8FAlP3VogCGwwFCQHhM4AACgkQp+z6DwAK9Ab/swCg8LWNwfMwNk+H
23
+ gLgnS1LVsesZ8D4An2Ie2P0/oYuSmPPFV44kbWySX9wW
24
+ =Jo82
20
25
  -----END PGP PUBLIC KEY BLOCK-----
@@ -0,0 +1,75 @@
1
+ require "test_helper"
2
+
3
+ class TestMaildir < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ @path = Dir.mktmpdir
7
+
8
+ @test_message_1 = <<EOS
9
+ From: Bob <bob@bob.com>
10
+ To: a dear friend
11
+
12
+ Hello there friend. How are you? Blah is blah blah.
13
+ Wow. Maildir FTW, am I right?
14
+ EOS
15
+
16
+ end
17
+
18
+ def teardown
19
+ ObjectSpace.each_object(Class).select {|a| a < Redwood::Singleton}.each do |klass|
20
+ klass.deinstantiate! unless klass == Redwood::Logger
21
+ end
22
+ FileUtils.rm_r @path
23
+ end
24
+
25
+ def create_a_maildir(extra='')
26
+ maildir = File.join @path, "test_maildir#{extra}"
27
+ ['', 'cur', 'new', 'tmp'].each do |dir|
28
+ Dir.mkdir(File.join maildir, dir)
29
+ end
30
+ maildir
31
+ end
32
+
33
+ def create_a_maildir_email(folder, content)
34
+ File.write(File.join(folder, "#{Time.now.to_f}.hostname:2,S"), content)
35
+ end
36
+
37
+ def start_sup_and_add_source(source)
38
+ start
39
+ Index.init @path
40
+ Index.load
41
+ SourceManager.instance.instance_eval '@sources = {}'
42
+ SourceManager.instance.add_source source
43
+ PollManager.poll_from source
44
+ end
45
+
46
+ # and now, let the tests begin!
47
+
48
+ def test_can_index_a_maildir_directory
49
+
50
+ maildir = create_a_maildir
51
+ create_a_maildir_email(File.join(maildir, 'cur'), @test_message_1)
52
+ start_sup_and_add_source Maildir.new "maildir:#{maildir}"
53
+
54
+ messages_in_index = []
55
+ Index.instance.each_message {|a| messages_in_index << a}
56
+ refute_empty messages_in_index, 'There are no messages in the index'
57
+ assert_equal(messages_in_index.first.raw_message, @test_message_1)
58
+
59
+ end
60
+
61
+ def test_can_index_a_maildir_directory_with_special_characters
62
+
63
+ maildir = create_a_maildir URI_ENCODE_CHARS
64
+ create_a_maildir_email(File.join(maildir, 'cur'), @test_message_1)
65
+ start_sup_and_add_source Maildir.new "maildir:#{maildir}"
66
+
67
+ messages_in_index = []
68
+ Index.instance.each_message {|a| messages_in_index << a}
69
+ refute_empty messages_in_index, 'There are no messages in the index'
70
+ assert_equal(messages_in_index.first.raw_message, @test_message_1)
71
+
72
+ end
73
+
74
+ end
75
+
@@ -0,0 +1,69 @@
1
+ require "test_helper"
2
+
3
+ class TestMbox < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ @path = Dir.mktmpdir
7
+
8
+ @test_message_1 = <<EOS
9
+ From sup-talk-bounces@rubyforge.org Mon Apr 27 12:56:18 2009
10
+ From: Bob <bob@bob.com>
11
+ To: Joe <joe@joe.com>
12
+
13
+ Hello there friend. How are you? Blah is blah blah.
14
+ I like mboxes, don't you?
15
+ EOS
16
+
17
+ end
18
+
19
+ def teardown
20
+ ObjectSpace.each_object(Class).select {|a| a < Redwood::Singleton}.each do |klass|
21
+ klass.deinstantiate! unless klass == Redwood::Logger
22
+ end
23
+ FileUtils.rm_r @path
24
+ end
25
+
26
+ def create_a_mbox(extra='')
27
+ mbox = File.join(@path, "test_mbox#{extra}.mbox")
28
+ File.write(mbox, @test_message_1)
29
+ mbox
30
+ end
31
+
32
+ def start_sup_and_add_source(source)
33
+ start
34
+ Index.init @path
35
+ Index.load
36
+ SourceManager.instance.instance_eval '@sources = {}'
37
+ SourceManager.instance.add_source source
38
+ PollManager.poll_from source
39
+ end
40
+
41
+ # and now, let the tests begin!
42
+
43
+ def test_can_index_a_mbox_directory
44
+
45
+ mbox = create_a_mbox
46
+ start_sup_and_add_source MBox.new "mbox:#{mbox}"
47
+
48
+ messages_in_index = []
49
+ Index.instance.each_message {|a| messages_in_index << a}
50
+ refute_empty messages_in_index, 'There are no messages in the index'
51
+ test_message_without_first_line = @test_message_1.sub(/^.*\n/,'')
52
+ assert_equal(messages_in_index.first.raw_message, test_message_without_first_line)
53
+
54
+ end
55
+
56
+ def test_can_index_a_mbox_directory_with_special_characters
57
+
58
+ mbox = create_a_mbox URI_ENCODE_CHARS
59
+ start_sup_and_add_source MBox.new "mbox:#{mbox}"
60
+
61
+ messages_in_index = []
62
+ Index.instance.each_message {|a| messages_in_index << a}
63
+ refute_empty messages_in_index, 'There are no messages in the index'
64
+ test_message_without_first_line = @test_message_1.sub(/^.*\n/,'')
65
+ assert_equal(messages_in_index.first.raw_message, test_message_without_first_line)
66
+
67
+ end
68
+
69
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sup
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.19.0
4
+ version: 0.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Morgan
@@ -11,22 +11,8 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2014-07-05 00:00:00.000000000 Z
14
+ date: 2014-10-06 00:00:00.000000000 Z
15
15
  dependencies:
16
- - !ruby/object:Gem::Dependency
17
- name: xapian-ruby
18
- requirement: !ruby/object:Gem::Requirement
19
- requirements:
20
- - - "~>"
21
- - !ruby/object:Gem::Version
22
- version: 1.2.15
23
- type: :runtime
24
- prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- requirements:
27
- - - "~>"
28
- - !ruby/object:Gem::Version
29
- version: 1.2.15
30
16
  - !ruby/object:Gem::Dependency
31
17
  name: ncursesw
32
18
  requirement: !ruby/object:Gem::Requirement
@@ -244,10 +230,22 @@ executables:
244
230
  - sup-sync
245
231
  - sup-sync-back-maildir
246
232
  - sup-tweak-labels
247
- extensions: []
248
- extra_rdoc_files: []
233
+ extensions:
234
+ - ext/mkrf_conf_xapian.rb
235
+ extra_rdoc_files:
236
+ - man/sup-tweak-labels.1
237
+ - man/sup-sync.1
238
+ - man/sup-psych-ify-config-files.1
239
+ - man/sup-config.1
240
+ - man/sup-import-dump.1
241
+ - man/sup-dump.1
242
+ - man/sup-sync-back-maildir.1
243
+ - man/sup-add.1
244
+ - man/sup-recover-sources.1
245
+ - man/sup.1
249
246
  files:
250
247
  - ".gitignore"
248
+ - ".gitmodules"
251
249
  - ".travis.yml"
252
250
  - CONTRIBUTORS
253
251
  - Gemfile
@@ -277,6 +275,7 @@ files:
277
275
  - doc/FAQ.txt
278
276
  - doc/Hooks.txt
279
277
  - doc/Philosophy.txt
278
+ - ext/mkrf_conf_xapian.rb
280
279
  - lib/sup.rb
281
280
  - lib/sup/account.rb
282
281
  - lib/sup/buffer.rb
@@ -342,17 +341,30 @@ files:
342
341
  - lib/sup/util/query.rb
343
342
  - lib/sup/util/uri.rb
344
343
  - lib/sup/version.rb
344
+ - man/sup-add.1
345
+ - man/sup-config.1
346
+ - man/sup-dump.1
347
+ - man/sup-import-dump.1
348
+ - man/sup-psych-ify-config-files.1
349
+ - man/sup-recover-sources.1
350
+ - man/sup-sync-back-maildir.1
351
+ - man/sup-sync.1
352
+ - man/sup-tweak-labels.1
353
+ - man/sup.1
345
354
  - sup.gemspec
346
355
  - test/dummy_source.rb
347
356
  - test/gnupg_test_home/gpg.conf
357
+ - test/gnupg_test_home/key1.gen
358
+ - test/gnupg_test_home/key2.gen
348
359
  - test/gnupg_test_home/pubring.gpg
349
360
  - test/gnupg_test_home/receiver_pubring.gpg
350
361
  - test/gnupg_test_home/receiver_secring.gpg
351
- - test/gnupg_test_home/receiver_trustdb.gpg
362
+ - test/gnupg_test_home/regen_keys.sh
352
363
  - test/gnupg_test_home/secring.gpg
353
364
  - test/gnupg_test_home/sup-test-2@foo.bar.asc
354
- - test/gnupg_test_home/trustdb.gpg
355
365
  - test/integration/test_label_service.rb
366
+ - test/integration/test_maildir.rb
367
+ - test/integration/test_mbox.rb
356
368
  - test/messages/bad-content-transfer-encoding-1.eml
357
369
  - test/messages/binary-content-transfer-encoding-2.eml
358
370
  - test/messages/missing-line.eml
@@ -376,6 +388,11 @@ post_install_message: |
376
388
  SUP: please note that our old mailing lists have been shut down,
377
389
  re-subscribe to supmua@googlegroups.com to discuss and follow
378
390
  updates on sup (send email to: supmua+subscribe@googlegroups.com).
391
+
392
+ OpenBSD users:
393
+ If your operating system is OpenBSD you have some
394
+ additional, manual steps to do before Sup will work, see:
395
+ https://github.com/sup-heliotrope/sup/wiki/Installation%3A-OpenBSD.
379
396
  rdoc_options: []
380
397
  require_paths:
381
398
  - lib
@@ -398,14 +415,17 @@ summary: A console-based email client with the best features of GMail, mutt and
398
415
  test_files:
399
416
  - test/dummy_source.rb
400
417
  - test/gnupg_test_home/gpg.conf
418
+ - test/gnupg_test_home/key1.gen
419
+ - test/gnupg_test_home/key2.gen
401
420
  - test/gnupg_test_home/pubring.gpg
402
421
  - test/gnupg_test_home/receiver_pubring.gpg
403
422
  - test/gnupg_test_home/receiver_secring.gpg
404
- - test/gnupg_test_home/receiver_trustdb.gpg
423
+ - test/gnupg_test_home/regen_keys.sh
405
424
  - test/gnupg_test_home/secring.gpg
406
425
  - test/gnupg_test_home/sup-test-2@foo.bar.asc
407
- - test/gnupg_test_home/trustdb.gpg
408
426
  - test/integration/test_label_service.rb
427
+ - test/integration/test_maildir.rb
428
+ - test/integration/test_mbox.rb
409
429
  - test/messages/bad-content-transfer-encoding-1.eml
410
430
  - test/messages/binary-content-transfer-encoding-2.eml
411
431
  - test/messages/missing-line.eml