commit ca5d97440fd2774475103278b6bfd7683089ef48
parent f8a5da3d272a7d835a05b683049d9ebd793266ce
Author: Gaute Hope <eg@gaute.vetsj.com>
Date: Fri, 21 Mar 2014 15:51:10 +0100
Merge branch 'develop'
Diffstat:
22 files changed, 221 insertions(+), 303 deletions(-)
diff --git a/.travis.yml b/.travis.yml
@@ -1,6 +1,8 @@
language: ruby
rvm:
+ - 2.1.1
+ - 2.1.0
- 2.0.0
- 1.9.3
@@ -9,4 +11,3 @@ before_install:
- sudo apt-get install -qq uuid-dev uuid libncursesw5-dev libncursesw5 gnupg2
script: bundle exec rake travis
-
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
@@ -18,10 +18,12 @@ Clint Byrum <clint at the ubuntu dot coms>
Marcus Williams <marcus-sup at the bar-coded dot nets>
Lionel Ott <white.magic at the gmx dot des>
Gaudenz Steinlin <gaudenz at the soziologie dot chs>
-Mark Alexander <marka at the pobox dot coms>
+Matthieu Rakotojaona <matthieu.rakotojaona at the gmail dot coms>
Ingmar Vanhassel <ingmar at the exherbo dot orgs>
+Mark Alexander <marka at the pobox dot coms>
Edward Z. Yang <ezyang at the mit dot edus>
-Matthieu Rakotojaona <matthieu.rakotojaona at the gmail dot coms>
+Timon Vonk <timonv at the gmail dot coms>
+julien@macbook <julien.stechele at the gmail dot coms>
Christopher Warrington <chrisw at the rice dot edus>
W. Trevor King <wking at the drexel dot edus>
Richard Brown <rbrown at the exherbo dot orgs>
@@ -29,13 +31,14 @@ Anthony Martinez <pi+sup at the pihost dot uss>
Marc Hartstein <marc.hartstein at the alum.vassar dot edus>
Israel Herraiz <israel.herraiz at the gmail dot coms>
Bo Borgerson <gigabo at the gmail dot coms>
+Atte Kojo <atte.kojo at the reaktor dot fis>
Michael Hamann <michael at the content-space dot des>
-Jonathan Lassoff <jof at the thejof dot coms>
William Erik Baxter <web at the superscript dot coms>
-Grant Hollingworth <grant at the antiflux dot orgs>
-Adeodato Simó <dato at the net.com.org dot ess>
+Jonathan Lassoff <jof at the thejof dot coms>
Markus Klinik <markus.klinik at the gmx dot des>
+Grant Hollingworth <grant at the antiflux dot orgs>
Ico Doornekamp <ico at the pruts dot nls>
+Adeodato Simó <dato at the net.com.org dot ess>
Daniel Schoepe <daniel.schoepe at the googlemail dot coms>
Jason Petsod <jason at the petsod dot orgs>
James Taylor <james at the jamestaylor dot orgs>
@@ -46,8 +49,8 @@ Decklin Foster <decklin at the red-bean dot coms>
Cameron Matheson <cam+sup at the cammunism dot orgs>
Carl Worth <cworth at the cworth dot orgs>
Alex Vandiver <alex at the chmrr dot nets>
-Andrew Pimlott <andrew at the pimlott dot nets>
Jeff Balogh <its.jeff.balogh at the gmail dot coms>
+Andrew Pimlott <andrew at the pimlott dot nets>
Matías Aguirre <matiasaguirre at the gmail dot coms>
Kornilios Kourtis <kkourt at the cslab.ece.ntua dot grs>
Lars Fischer <fischer at the wiwi.uni-siegen dot des>
@@ -58,18 +61,18 @@ Alvaro Herrera <alvherre at the alvh.no-ip dot orgs>
Steven Lawrance <stl at the koffein dot nets>
Jonah <Jonah at the GoodCoffee dot cas>
ian <itaylor at the uark dot edus>
-Todd Eisenberger <teisenbe at the andrew.cmu dot edus>
+MichaelRevell <mikearevell at the gmail dot coms>
Per Andersson <avtobiff at the gmail dot coms>
+Todd Eisenberger <teisenbe at the andrew.cmu dot edus>
+Gregor Hoffleit <gregor at the sam.mediasupervision dot des>
Adam Lloyd <adam at the alloy-d dot nets>
-MichaelRevell <mikearevell at the gmail dot coms>
0xACE <0xACE at the users.noreply.github dot coms>
-Gregor Hoffleit <gregor at the sam.mediasupervision dot des>
Steven Walter <swalter at the monarch.(none)>
-Atte Kojo <atte.kojo at the reaktor dot fis>
-Stefan Lundström <lundst at the snabb.(none)>
+Jon M. Dugan <jdugan at the es dot nets>
+Horacio Sanson <horacio at the skillupjapan.co dot jps>
Matthias Vallentin <vallentin at the icir dot orgs>
akojo <atte.kojo at the gmail dot coms>
-Horacio Sanson <horacio at the skillupjapan.co dot jps>
-Jon M. Dugan <jdugan at the es dot nets>
+William A. Kennington III <william at the wkennington dot coms>
+Stefan Lundström <lundst at the snabb.(none)>
Johannes Larsen <johs.a.larsen at the gmail dot coms>
Kirill Smelkov <kirr at the landau.phys.spbu dot rus>
diff --git a/History.txt b/History.txt
@@ -1,3 +1,11 @@
+== 0.16.0 / 2014-03-21
+
+* sup-sync-back-mbox removed.
+* safer mime-view attachment file name handling
+* show thread labels in thread-view-mode
+* remove lock file if there is no sup alive
+* deprecate migration script on ruby > 2.1
+
== 0.15.4 / 2014-02-06
* Various bugfixes
diff --git a/README.md b/README.md
@@ -20,9 +20,6 @@ Features:
Current limitations:
-* [Ruby 2.0 support][ruby20] is very fresh, consider it experimental. Patches
- are welcome
-
* Sup does in general not play nicely with other mail clients, not all
changes can be synced back to the mail source. Refer to [Maildir Syncback][maildir-syncback]
in the wiki for this recently included feature. Maildir Syncback
diff --git a/ReleaseNotes b/ReleaseNotes
@@ -1,3 +1,13 @@
+Release 0.16.0:
+
+Removed unfinished and abandoned sup-sync-back-mbox.
+
+Safer mime-view attachment file name handling, a temp file name is used
+while the extension is only used if it is alphanumeric.
+
+The migration script for YAML documents is now deprecated for ruby > 2.1
+and will be removed in the future.
+
Release 0.15.4:
Bugfixes.
diff --git a/bin/sup-psych-ify-config-files b/bin/sup-psych-ify-config-files
@@ -5,6 +5,11 @@ $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
require "sup"
require "fileutils"
+if RUBY_VERSION >= "2.1"
+ puts "YAML migration is deprecated by Ruby 2.1 and newer."
+ exit
+end
+
Redwood.start
fn = Redwood::SOURCE_FN
diff --git a/bin/sup-sync-back-mbox b/bin/sup-sync-back-mbox
@@ -1,181 +0,0 @@
-#!/usr/bin/env ruby
-
-$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
-
-require 'rubygems'
-require 'uri'
-require 'tempfile'
-require 'trollop'
-require "sup"
-
-fail "not working yet"
-
-## save a message 'm' to an open file pointer 'fp'
-def save m, fp
- m.source.each_raw_message_line(m.source_info) { |l| fp.print l }
-end
-def die msg
- $stderr.puts "Error: #{msg}"
- exit(-1)
-end
-def has_any_from_source_with_label? index, source, label
- query = { :source_id => source.id, :label => label, :limit => 1, :load_spam => true, :load_deleted => true, :load_killed => true }
- index.num_results_for(query) != 0
-end
-
-opts = Trollop::options do
- version "sup-sync-back-mbox (sup #{Redwood::VERSION})"
- banner <<EOS
-Drop or move messages from Sup sources that are marked as deleted or
-spam in the Sup index.
-
-Currently only works with mbox sources.
-
-Usage:
- sup-sync-back-mbox [options] <source>*
-
-where <source>* is zero or more source URIs. If no sources are given,
-sync back all usual sources.
-
-You almost certainly want to run sup-sync --changed after this command.
-Running this does not change the index.
-
-Options include:
-EOS
- opt :drop_deleted, "Drop deleted messages.", :default => false, :short => "d"
- opt :move_deleted, "Move deleted messages to a local mbox file.", :type => String, :short => :none
- opt :drop_spam, "Drop spam messages.", :default => false, :short => "s"
- opt :move_spam, "Move spam messages to a local mbox file.", :type => String, :short => :none
-
- opt :with_dotlockfile, "Specific dotlockfile location (mbox files only).", :default => "/usr/bin/dotlockfile", :short => :none
- opt :dont_use_dotlockfile, "Don't use dotlockfile to lock mbox files. Dangerous if other processes modify them concurrently.", :default => false, :short => :none
-
- opt :verbose, "Print message ids as they're processed."
- opt :dry_run, "Don't actually modify the index. Probably only useful with --verbose.", :short => "-n"
- opt :version, "Show version information", :short => :none
-
- conflicts :drop_deleted, :move_deleted
- conflicts :drop_spam, :move_spam
-end
-
-unless opts[:drop_deleted] || opts[:move_deleted] || opts[:drop_spam] || opts[:move_spam]
- puts <<EOS
-Nothing to do. Please specify at least one of --drop-deleted, --move-deleted,
---drop-spam, or --move-spam.
-EOS
-
- exit
-end
-
-Redwood::start
-index = Redwood::Index.init
-index.lock_interactively or exit
-
-deleted_fp, spam_fp = nil
-unless opts[:dry_run]
- deleted_fp = File.open(opts[:move_deleted], "a") if opts[:move_deleted]
- spam_fp = File.open(opts[:move_spam], "a") if opts[:move_spam]
-end
-
-dotlockfile = opts[:with_dotlockfile] || "/usr/bin/dotlockfile"
-
-begin
- index.load
-
- sources = ARGV.map do |uri|
- s = Redwood::SourceManager.source_for(uri) or die "unknown source: #{uri}. Did you add it with sup-add first?"
- s.is_a?(Redwood::MBox) or die "#{uri} is not an mbox source."
- s
- end
-
- if sources.empty?
- sources = Redwood::SourceManager.usual_sources.select { |s| s.is_a? Redwood::MBox }
- end
-
- unless sources.all? { |s| s.file_path.nil? } || File.executable?(dotlockfile) || opts[:dont_use_dotlockfile]
- die <<EOS
-can't execute dotlockfile binary: #{dotlockfile}. Specify --with-dotlockfile
-if it's in a nonstandard location, or, if you want to live dangerously, try
---dont-use-dotlockfile
-EOS
- end
-
- modified_sources = []
- sources.each do |source|
- $stderr.puts "Scanning #{source}..."
-
- unless ((opts[:drop_deleted] || opts[:move_deleted]) && has_any_from_source_with_label?(index, source, :deleted)) || ((opts[:drop_spam] || opts[:move_spam]) && has_any_from_source_with_label?(index, source, :spam))
- $stderr.puts "Nothing to do from this source; skipping"
- next
- end
-
- source.reset!
- num_dropped = num_moved = num_scanned = 0
-
- out_fp = Tempfile.new "sup-sync-back-mbox-#{source.id}"
- Redwood::PollManager.each_message_from source do |m|
- num_scanned += 1
-
- if(m_old = index.build_message(m.id))
- labels = m_old.labels
-
- if labels.member? :deleted
- if opts[:drop_deleted]
- puts "Dropping deleted message #{source}##{m.source_info}" if opts[:verbose]
- num_dropped += 1
- elsif opts[:move_deleted] && labels.member?(:deleted)
- puts "Moving deleted message #{source}##{m.source_info}" if opts[:verbose]
- save m, deleted_fp unless opts[:dry_run]
- num_moved += 1
- end
-
- elsif labels.member? :spam
- if opts[:drop_spam]
- puts "Dropping spam message #{source}##{m.source_info}" if opts[:verbose]
- num_dropped += 1
- elsif opts[:move_spam] && labels.member?(:spam)
- puts "Moving spam message #{source}##{m.source_info}" if opts[:verbose]
- save m, spam_fp unless opts[:dry_run]
- num_moved += 1
- end
- else
- save m, out_fp unless opts[:dry_run]
- end
- else
- save m, out_fp unless opts[:dry_run]
- end
- end
- $stderr.puts "Scanned #{num_scanned}, dropped #{num_dropped}, moved #{num_moved} messages from #{source}."
- modified_sources << source if num_dropped > 0 || num_moved > 0
- out_fp.close unless opts[:dry_run]
-
- unless opts[:dry_run] || (num_dropped == 0 && num_moved == 0)
- deleted_fp.flush if deleted_fp
- spam_fp.flush if spam_fp
- unless opts[:dont_use_dotlockfile]
- puts "Locking #{source.file_path}..."
- system "#{opts[:dotlockfile]} -l #{source.file_path}"
- puts "Writing #{source.file_path}..."
- FileUtils.cp out_fp.path, source.file_path
- puts "Unlocking #{source.file_path}..."
- system "#{opts[:dotlockfile]} -u #{source.file_path}"
- end
- end
- end
-
- unless opts[:dry_run]
- deleted_fp.close if deleted_fp
- spam_fp.close if spam_fp
- end
-
- $stderr.puts "Done."
- unless modified_sources.empty?
- $stderr.puts "You should now run: sup-sync --changed #{modified_sources.join(' ')}"
- end
-rescue Exception => e
- File.open("sup-exception-log.txt", "w") { |f| f.puts e.backtrace }
- raise
-ensure
- Redwood::finish
- index.unlock
-end
diff --git a/contrib/completion/_sup.zsh b/contrib/completion/_sup.zsh
@@ -1,8 +1,8 @@
-#compdef sup sup-add sup-config sup-dump sup-sync sup-sync-back-mbox sup-tweak-labels sup-recover-sources
+#compdef sup sup-add sup-config sup-dump sup-sync sup-tweak-labels sup-recover-sources
# vim: set et sw=2 sts=2 ts=2 ft=zsh :
# TODO: sources completion: maildir://some/dir, mbox://some/file, ...
-# for sup-add, sup-sync, sup-sync-back-mbox, sup-tweak-labels
+# for sup-add, sup-sync, sup-tweak-labels
(( ${+functions[_sup_cmd]} )) ||
_sup_cmd()
diff --git a/lib/sup/interactive_lock.rb b/lib/sup/interactive_lock.rb
@@ -25,49 +25,64 @@ module InteractiveLock
begin
Index.lock
rescue Index::LockError => e
- stream.puts <<EOS
-Error: the index is locked by another process! User '#{e.user}' on
-host '#{e.host}' is running #{e.pname} with pid #{e.pid}.
-The process was alive as of at least #{time_ago_in_words e.mtime} ago.
+ begin
+ Process.kill 0, e.pid.to_i # 0 signal test the existence of PID
+ stream.puts <<EOS
+ Error: the index is locked by another process! User '#{e.user}' on
+ host '#{e.host}' is running #{e.pname} with pid #{e.pid}.
+ The process was alive as of at least #{time_ago_in_words e.mtime} ago.
EOS
- stream.print "Should I ask that process to kill itself (y/n)? "
- stream.flush
-
- success = if $stdin.gets =~ /^\s*y(es)?\s*$/i
- stream.puts "Ok, trying to kill process..."
-
- begin
+ stream.print "Should I ask that process to kill itself (y/n)? "
+ stream.flush
+ if $stdin.gets =~ /^\s*y(es)?\s*$/i
Process.kill "TERM", e.pid.to_i
sleep DELAY
- rescue Errno::ESRCH # no such process
- stream.puts "Hm, I couldn't kill it."
+ stream.puts "Let's try that again."
+ begin
+ Index.lock
+ rescue Index::LockError => e
+ stream.puts "I couldn't lock the index. The lockfile might just be stale."
+ stream.print "Should I just remove it and continue? (y/n) "
+ stream.flush
+ if $stdin.gets =~ /^\s*y(es)?\s*$/i
+ begin
+ FileUtils.rm e.path
+ rescue Errno::ENOENT
+ stream.puts "The lockfile doesn't exists. We continue."
+ end
+ stream.puts "Let's try that one more time."
+ begin
+ Index.lock
+ rescue Index::LockError => e
+ stream.puts "I couldn't unlock the index."
+ return false
+ end
+ return true
+ end
+ end
end
-
- stream.puts "Let's try that again."
+ rescue Errno::ESRCH # no such process
+ stream.puts "I couldn't lock the index. The lockfile might just be stale."
+ begin
+ FileUtils.rm e.path
+ rescue Errno::ENOENT
+ stream.puts "The lockfile doesn't exists. We continue."
+ end
+ stream.puts "Let's try that one more time."
begin
+ sleep DELAY
Index.lock
rescue Index::LockError => e
- stream.puts "I couldn't lock the index. The lockfile might just be stale."
- stream.print "Should I just remove it and continue? (y/n) "
- stream.flush
-
- if $stdin.gets =~ /^\s*y(es)?\s*$/i
- FileUtils.rm e.path
-
- stream.puts "Let's try that one more time."
- begin
- Index.lock
- true
- rescue Index::LockError => e
- end
- end
+ stream.puts "I couldn't unlock the index."
+ return false
end
+ return true
end
-
- stream.puts "Sorry, couldn't unlock the index." unless success
- success
+ stream.puts "Sorry, couldn't unlock the index."
+ return false
end
+ return true
end
end
diff --git a/lib/sup/mbox.rb b/lib/sup/mbox.rb
@@ -119,8 +119,6 @@ class MBox < Source
## we're just moving messages around on disk, than reading things
## into memory with raw_message.
##
- ## i hoped never to have to move shit around on disk but
- ## sup-sync-back-mbox has to do it.
def each_raw_message_line offset
@mutex.synchronize do
ensure_open
diff --git a/lib/sup/message_chunks.rb b/lib/sup/message_chunks.rb
@@ -60,8 +60,6 @@ end
module Redwood
module Chunk
class Attachment
- ## please see note in write_to_disk on important usage
- ## of quotes to avoid remote command injection.
HookManager.register "mime-decode", <<EOS
Decodes a MIME attachment into text form. The text will be displayed
directly in Sup. For attachments that you wish to use a separate program
@@ -79,8 +77,6 @@ Return value:
EOS
- ## please see note in write_to_disk on important usage
- ## of quotes to avoid remote command injection.
HookManager.register "mime-view", <<EOS
Views a non-text MIME attachment. This hook allows you to run
third-party programs for attachments that require such a thing (e.g.
@@ -132,8 +128,6 @@ EOS
when /^text\/plain\b/
@raw_content
else
- ## please see note in write_to_disk on important usage
- ## of quotes to avoid remote command injection.
HookManager.run "mime-decode", :content_type => @content_type,
:filename => lambda { write_to_disk },
:charset => encoded_content.charset,
@@ -171,8 +165,6 @@ EOS
def initial_state; :open end
def viewable?; @lines.nil? end
def view_default! path
- ## please see note in write_to_disk on important usage
- ## of quotes to avoid remote command injection.
case RbConfig::CONFIG['arch']
when /darwin/
cmd = "open #{path}"
@@ -185,28 +177,32 @@ EOS
end
def view!
- ## please see note in write_to_disk on important usage
- ## of quotes to avoid remote command injection.
- write_to_disk do |file|
-
- @@view_tempfiles.push file # make sure the tempfile is not garbage collected before sup stops
-
+ write_to_disk do |path|
ret = HookManager.run "mime-view", :content_type => @content_type,
- :filename => file.path
- ret || view_default!(file.path)
+ :filename => path
+ ret || view_default!(path)
end
end
- ## note that the path returned from write_to_disk is
- ## Shellwords.escaped and is intended to be used without single
- ## or double quotes. the use of either opens sup up for remote
- ## code injection through the file name.
def write_to_disk
begin
- file = Tempfile.new(["sup", Shellwords.escape(@filename.gsub("/", "_")) || "sup-attachment"])
+ # Add the original extension to the generated tempfile name only if the
+ # extension is "safe" (won't be interpreted by the shell). Since
+ # Tempfile.new always generates safe file names this should prevent
+ # attacking the user with funny attachment file names.
+ tempname = if (File.extname @filename) =~ /^\.[[:alnum:]]+$/ then
+ ["sup-attachment", File.extname(@filename)]
+ else
+ "sup-attachment"
+ end
+
+ file = Tempfile.new(tempname)
file.print @raw_content
file.flush
- yield file if block_given?
+
+ @@view_tempfiles.push file # make sure the tempfile is not garbage collected before sup stops
+
+ yield file.path if block_given?
return file.path
ensure
file.close
diff --git a/lib/sup/modes/contact_list_mode.rb b/lib/sup/modes/contact_list_mode.rb
@@ -130,7 +130,7 @@ protected
def text_for_contact p
aalias = ContactManager.alias_for(p) || ""
[[:tagged_color, @tags.tagged?(p) ? ">" : " "],
- [:none, sprintf("%-#{@awidth}s %-#{@nwidth}s %s", aalias, p.name, p.email)]]
+ [:text_color, sprintf("%-#{@awidth}s %-#{@nwidth}s %s", aalias, p.name, p.email)]]
end
def regen_text
diff --git a/lib/sup/modes/inbox_mode.rb b/lib/sup/modes/inbox_mode.rb
@@ -6,7 +6,6 @@ class InboxMode < ThreadIndexMode
register_keymap do |k|
## overwrite toggle_archived with archive
k.add :archive, "Archive thread (remove from inbox)", 'a'
- k.add :read_and_archive, "Archive thread (remove from inbox) and mark read", 'A'
k.add :refine_search, "Refine search", '|'
end
@@ -64,47 +63,6 @@ class InboxMode < ThreadIndexMode
threads.each { |t| Index.save_thread t }
end
- def read_and_archive
- return unless cursor_thread
- thread = cursor_thread # to make sure lambda only knows about 'old' cursor_thread
-
- was_unread = thread.labels.member? :unread
- UndoManager.register "reading and archiving thread" do
- thread.apply_label :inbox
- thread.apply_label :unread if was_unread
- add_or_unhide thread.first
- Index.save_thread thread
- end
-
- cursor_thread.remove_label :unread
- cursor_thread.remove_label :inbox
- hide_thread cursor_thread
- regen_text
- Index.save_thread thread
- end
-
- def multi_read_and_archive threads
- old_labels = threads.map { |t| t.labels.dup }
-
- threads.each do |t|
- t.remove_label :unread
- t.remove_label :inbox
- hide_thread t
- end
- regen_text
-
- UndoManager.register "reading and archiving #{threads.size.pluralize 'thread'}" do
- threads.zip(old_labels).each do |t, l|
- t.labels = l
- add_or_unhide t.first
- Index.save_thread t
- end
- regen_text
- end
-
- threads.each { |t| Index.save_thread t }
- end
-
def handle_unarchived_update sender, m
add_or_unhide m
end
diff --git a/lib/sup/modes/thread_index_mode.rb b/lib/sup/modes/thread_index_mode.rb
@@ -33,6 +33,7 @@ EOS
k.add_multi "Load all threads (! to confirm) :", '!' do |kk|
kk.add :load_all_threads, "Load all threads (may list a _lot_ of threads)", '!'
end
+ k.add :read_and_archive, "Archive thread (remove from inbox) and mark read", 'A'
k.add :cancel_search, "Cancel current search", :ctrl_g
k.add :reload, "Refresh view", '@'
k.add :toggle_archived, "Toggle archived status", 'a'
@@ -732,6 +733,47 @@ EOS
end
ignore_concurrent_calls :load_threads
+ def read_and_archive
+ return unless cursor_thread
+ thread = cursor_thread # to make sure lambda only knows about 'old' cursor_thread
+
+ was_unread = thread.labels.member? :unread
+ UndoManager.register "reading and archiving thread" do
+ thread.apply_label :inbox
+ thread.apply_label :unread if was_unread
+ add_or_unhide thread.first
+ Index.save_thread thread
+ end
+
+ cursor_thread.remove_label :unread
+ cursor_thread.remove_label :inbox
+ hide_thread cursor_thread
+ regen_text
+ Index.save_thread thread
+ end
+
+ def multi_read_and_archive threads
+ old_labels = threads.map { |t| t.labels.dup }
+
+ threads.each do |t|
+ t.remove_label :unread
+ t.remove_label :inbox
+ hide_thread t
+ end
+ regen_text
+
+ UndoManager.register "reading and archiving #{threads.size.pluralize 'thread'}" do
+ threads.zip(old_labels).each do |t, l|
+ t.labels = l
+ add_or_unhide t.first
+ Index.save_thread t
+ end
+ regen_text
+ end
+
+ threads.each { |t| Index.save_thread t }
+ end
+
def resize rows, cols
regen_text
super
diff --git a/lib/sup/modes/thread_view_mode.rb b/lib/sup/modes/thread_view_mode.rb
@@ -692,6 +692,15 @@ EOS
end
end
+
+ def status
+ user_labels = @thread.labels.to_a.map do |l|
+ l.to_s if LabelManager.user_defined_labels.member?(l)
+ end.compact.join(",")
+ user_labels = (user_labels.empty? and "" or "<#{user_labels}>")
+ [user_labels, super].join(" -- ")
+ end
+
private
def initial_state_for m
diff --git a/lib/sup/person.rb b/lib/sup/person.rb
@@ -15,7 +15,7 @@ class Person
name.gsub('\\\\', '\\')
end
- @email = email.strip.gsub(/\s+/, " ").downcase
+ @email = email.strip.gsub(/\s+/, " ")
end
def to_s; "#@name <#@email>" end
diff --git a/lib/sup/source.rb b/lib/sup/source.rb
@@ -68,7 +68,7 @@ class Source
@poll_lock = Monitor.new
end
- ## overwrite me if you have a disk incarnation (currently used only for sup-sync-back-mbox)
+ ## overwrite me if you have a disk incarnation
def file_path; nil end
def to_s; @uri.to_s; end
diff --git a/lib/sup/util.rb b/lib/sup/util.rb
@@ -267,6 +267,14 @@ end
class String
def display_length
@display_length ||= Unicode.width(self.fix_encoding!, false)
+
+ # if Unicode.width fails and returns -1, fall back to
+ # regular String#length, see pull-request: #256.
+ if @display_length < 0
+ @display_length = self.length
+ end
+
+ @display_length
end
def slice_by_display_length len
diff --git a/sup.gemspec b/sup.gemspec
@@ -5,8 +5,8 @@ require 'sup/version'
# Files
SUP_EXECUTABLES = %w(sup sup-add sup-config sup-dump sup-import-dump
- sup-recover-sources sup-sync sup-sync-back-maildir sup-sync-back-mbox
- sup-tweak-labels sup-psych-ify-config-files)
+ sup-recover-sources sup-sync sup-sync-back-maildir sup-tweak-labels
+ sup-psych-ify-config-files)
SUP_EXTRA_FILES = %w(CONTRIBUTORS README.md LICENSE History.txt ReleaseNotes)
SUP_FILES =
SUP_EXTRA_FILES +
diff --git a/test/messages/missing-line.eml b/test/messages/missing-line.eml
@@ -0,0 +1,9 @@
+From: foo@aol.com
+To: foo@test.com
+Subject: Encoding bug
+Content-Type: text/plain; charset="iso-8859-1"
+Content-Transfer-Encoding: quoted-printable
+
+This is =91 a test: the first line seems to disappear from the mail body but is
+still visible in the thread view.
+
diff --git a/test/test_messages_dir.rb b/test/test_messages_dir.rb
@@ -105,6 +105,41 @@ class TestMessagesDir < ::Minitest::Unit::TestCase
# lines should contain an error message
assert (lines.join.include? "An error occurred while loading this message."), "This message should not load successfully"
end
+
+ def test_missing_line
+ message = ''
+ File.open 'test/messages/missing-line.eml' do |f|
+ message = f.read
+ end
+
+ source = DummySource.new("sup-test://test_messages")
+ source.messages = [ message ]
+ source_info = 0
+
+ sup_message = Message.build_from_source(source, source_info)
+ sup_message.load_from_source!
+
+ from = sup_message.from
+ # "from" is just a simple person item
+
+ assert_equal("foo@aol.com", from.email)
+ #assert_equal("Fake Sender", from.name)
+
+ subj = sup_message.subj
+ assert_equal("Encoding bug", subj)
+
+ chunks = sup_message.load_from_source!
+ indexable_chunks = sup_message.indexable_chunks
+
+ # there should be only one chunk
+ #assert_equal(1, chunks.length)
+
+ lines = chunks[0].lines
+
+ badline = lines[0]
+ assert (badline.display_length > 0), "The length of this line should greater than 0: #{badline}"
+
+ end
end
end
diff --git a/test/test_yaml_migration.rb b/test/test_yaml_migration.rb
@@ -3,6 +3,7 @@ require "test_helper"
require "sup"
require "psych"
+if RUBY_VERSION < "2.1"
describe "Sup's YAML util" do
describe "Module#yaml_properties" do
def build_class_with_name name, &b
@@ -78,3 +79,7 @@ id: ID
end
end
end
+
+else
+ puts "Some YAML tests are skipped on Ruby 2.1.0 and newer."
+end