commit 87b0fcd5b3d230777e1c76aa74bc77651185898a
Author: Mikel Lindsaar <mikel@rubyx.com>
Date:   Tue Mar 6 18:59:38 2012 +1100

    Fix security vulnerability allowing command line exploit when using exim or sendmail from the command line
    
    Conflicts:
    
    	lib/mail/network/delivery_methods/exim.rb
    	lib/mail/network/delivery_methods/sendmail.rb
    	spec/mail/network/delivery_methods/sendmail_spec.rb

diff --git a/lib/mail.rb b/lib/mail.rb
index 65f872e..758de74 100644
--- a/lib/mail.rb
+++ b/lib/mail.rb
@@ -29,7 +29,7 @@ module Mail # :doc:
   require 'mail/core_extensions/nil'
   require 'mail/core_extensions/object'
   require 'mail/core_extensions/string'
-  require 'mail/core_extensions/shellwords' unless String.new.respond_to?(:shellescape)
+  require 'mail/core_extensions/shell_escape'
   require 'mail/core_extensions/smtp' if RUBY_VERSION < '1.9.3'
   require 'mail/indifferent_hash'
 
diff --git a/lib/mail/core_extensions/shell_escape.rb b/lib/mail/core_extensions/shell_escape.rb
new file mode 100644
index 0000000..8972698
--- /dev/null
+++ b/lib/mail/core_extensions/shell_escape.rb
@@ -0,0 +1,56 @@
+# encoding: utf-8
+
+# The following is an adaptation of ruby 1.9.2's shellwords.rb file,
+# it is modified to include '+' in the allowed list to allow for
+# sendmail to accept email addresses as the sender with a + in them
+#
+module Mail
+  module ShellEscape
+    # Escapes a string so that it can be safely used in a Bourne shell
+    # command line.
+    #
+    # Note that a resulted string should be used unquoted and is not
+    # intended for use in double quotes nor in single quotes.
+    #
+    #   open("| grep #{Shellwords.escape(pattern)} file") { |pipe|
+    #     # ...
+    #   }
+    #
+    # +String#shellescape+ is a shorthand for this function.
+    #
+    #   open("| grep #{pattern.shellescape} file") { |pipe|
+    #     # ...
+    #   }
+    #
+    def escape_for_shell(str)
+      # An empty argument will be skipped, so return empty quotes.
+      return "''" if str.empty?
+
+      str = str.dup
+
+      # Process as a single byte sequence because not all shell
+      # implementations are multibyte aware.
+      str.gsub!(/([^A-Za-z0-9_\s\+\-.,:\/@\n])/n, "\\\\\\1")
+
+      # A LF cannot be escaped with a backslash because a backslash + LF
+      # combo is regarded as line continuation and simply ignored.
+      str.gsub!(/\n/, "'\n'")
+
+      return str
+    end
+
+    module_function :escape_for_shell
+  end
+end
+
+class String
+  # call-seq:
+  #   str.shellescape => string
+  #
+  # Escapes +str+ so that it can be safely used in a Bourne shell
+  # command line.  See +Shellwords::shellescape+ for details.
+  #
+  def escape_for_shell
+    Mail::ShellEscape.escape_for_shell(self)
+  end
+end
\ No newline at end of file
diff --git a/lib/mail/core_extensions/shellwords.rb b/lib/mail/core_extensions/shellwords.rb
deleted file mode 100644
index bd433e4..0000000
--- a/lib/mail/core_extensions/shellwords.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# encoding: utf-8
-
-# The following is imported from ruby 1.9.2 shellwords.rb
-#
-module Shellwords
-  # Escapes a string so that it can be safely used in a Bourne shell
-  # command line.
-  #
-  # Note that a resulted string should be used unquoted and is not
-  # intended for use in double quotes nor in single quotes.
-  #
-  #   open("| grep #{Shellwords.escape(pattern)} file") { |pipe|
-  #     # ...
-  #   }
-  #
-  # +String#shellescape+ is a shorthand for this function.
-  #
-  #   open("| grep #{pattern.shellescape} file") { |pipe|
-  #     # ...
-  #   }
-  #
-  def shellescape(str)
-    # An empty argument will be skipped, so return empty quotes.
-    return "''" if str.empty?
-
-    str = str.dup
-
-    # Process as a single byte sequence because not all shell
-    # implementations are multibyte aware.
-    str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/n, "\\\\\\1")
-
-    # A LF cannot be escaped with a backslash because a backslash + LF
-    # combo is regarded as line continuation and simply ignored.
-    str.gsub!(/\n/, "'\n'")
-
-    return str
-  end
-
-  module_function :shellescape
-
-  class << self
-    alias escape shellescape
-  end
-
-end
-
-class String
-  # call-seq:
-  #   str.shellescape => string
-  #
-  # Escapes +str+ so that it can be safely used in a Bourne shell
-  # command line.  See +Shellwords::shellescape+ for details.
-  #
-  def shellescape
-    Shellwords.escape(self)
-  end
-end
\ No newline at end of file
diff --git a/lib/mail/network/delivery_methods/exim.rb b/lib/mail/network/delivery_methods/exim.rb
new file mode 100644
index 0000000..c5762ab
--- /dev/null
+++ b/lib/mail/network/delivery_methods/exim.rb
@@ -0,0 +1,53 @@
+module Mail
+
+  # A delivery method implementation which sends via exim.
+  #
+  # To use this, first find out where the exim binary is on your computer,
+  # if you are on a mac or unix box, it is usually in /usr/sbin/exim, this will
+  # be your exim location.
+  #
+  #   Mail.defaults do
+  #     delivery_method :exim
+  #   end
+  #
+  # Or if your exim binary is not at '/usr/sbin/exim'
+  #
+  #   Mail.defaults do
+  #     delivery_method :exim, :location => '/absolute/path/to/your/exim'
+  #   end
+  #
+  # Then just deliver the email as normal:
+  #
+  #   Mail.deliver do
+  #     to 'mikel@test.lindsaar.net'
+  #     from 'ada@test.lindsaar.net'
+  #     subject 'testing exim'
+  #     body 'testing exim'
+  #   end
+  #
+  # Or by calling deliver on a Mail message
+  #
+  #   mail = Mail.new do
+  #     to 'mikel@test.lindsaar.net'
+  #     from 'ada@test.lindsaar.net'
+  #     subject 'testing exim'
+  #     body 'testing exim'
+  #   end
+  #
+  #   mail.deliver!
+  class Exim < Sendmail
+
+    def initialize(values)
+      self.settings = { :location       => '/usr/sbin/exim',
+                        :arguments      => '-i -t' }.merge(values)
+    end
+
+    def self.call(path, arguments, mail)
+      IO.popen("#{path} #{arguments}", "w+") do |io|
+        io.puts mail.encoded.to_lf
+        io.flush
+      end
+    end
+
+  end
+end
diff --git a/lib/mail/network/delivery_methods/sendmail.rb b/lib/mail/network/delivery_methods/sendmail.rb
index 29f1876..73ef921 100644
--- a/lib/mail/network/delivery_methods/sendmail.rb
+++ b/lib/mail/network/delivery_methods/sendmail.rb
@@ -45,14 +45,14 @@ module Mail
 
     def deliver!(mail)
       envelope_from = mail.return_path || mail.sender || mail.from_addrs.first
-      return_path = "-f \"#{envelope_from.to_s.shellescape}\"" if envelope_from
+      return_path = "-f " + '"' + envelope_from.escape_for_shell + '"' if envelope_from
 
       arguments = [settings[:arguments], return_path].compact.join(" ")
 
-      Sendmail.call(settings[:location], arguments, mail.destinations.collect(&:shellescape).join(" "), mail)
+      self.class.call(settings[:location], arguments, mail.destinations.collect(&:escape_for_shell).join(" "), mail)
     end
 
-    def Sendmail.call(path, arguments, destinations, mail)
+    def self.call(path, arguments, destinations, mail)
       IO.popen("#{path} #{arguments} #{destinations}", "w+") do |io|
         io.puts mail.encoded.to_lf
         io.flush
