]> git.cworth.org Git - sup/blobdiff - lib/sup/modes/edit-message-mode.rb
Add new :crypto_default configuration option.
[sup] / lib / sup / modes / edit-message-mode.rb
index cc6e7af4a482d46dfefd74f5034846c81035620d..3449503bf1d297e9ebd0bf2a03a6f780ec7bceff 100644 (file)
@@ -3,6 +3,10 @@ require 'socket' # just for gethostname!
 require 'pathname'
 require 'rmail'
 
+# from jcode.rb, not included in ruby 1.9
+PATTERN_UTF8 = '[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf]'
+RE_UTF8 = Regexp.new(PATTERN_UTF8, 0, 'n')
+
 module Redwood
 
 class SendmailCommandFailed < StandardError; end
@@ -12,7 +16,7 @@ class EditMessageMode < LineCursorMode
 
   FORCE_HEADERS = %w(From To Cc Bcc Subject)
   MULTI_HEADERS = %w(To Cc Bcc)
-  NON_EDITABLE_HEADERS = %w(Message-Id Date)
+  NON_EDITABLE_HEADERS = %w(Message-id Date)
 
   HookManager.register "signature", <<EOS
 Generates a message signature.
@@ -69,7 +73,14 @@ EOS
       @attachment_names = []
     end
 
-    @message_id = "<#{Time.now.to_i}-sup-#{rand 10000}@#{Socket.gethostname}>"
+    begin
+      hostname = File.open("/etc/mailname", "r").gets.chomp
+    rescue
+        nil
+    end
+    hostname = Socket.gethostname if hostname.nil? or hostname.empty?
+
+    @message_id = "<#{Time.now.to_i}-sup-#{rand 10000}@#{hostname}>"
     @edited = false
     @selectors = []
     @selector_label_width = 0
@@ -78,7 +89,12 @@ EOS
       if CryptoManager.have_crypto?
         HorizontalSelector.new "Crypto:", [:none] + CryptoManager::OUTGOING_MESSAGE_OPERATIONS.keys, ["None"] + CryptoManager::OUTGOING_MESSAGE_OPERATIONS.values
       end
-    add_selector @crypto_selector if @crypto_selector
+    if @crypto_selector
+      if !$config[:crypto_default].nil?
+        @crypto_selector.set_to $config[:crypto_default]
+      end
+      add_selector @crypto_selector
+    end
     
     HookManager.run "before-edit", :header => @header, :body => @body
 
@@ -145,6 +161,8 @@ EOS
     !edited? || BufferManager.ask_yes_or_no("Discard message?")
   end
 
+  def unsaved?; edited? end
+
   def attach_file
     fn = BufferManager.ask_for_filename :attachment, "File name (enter for browser): "
     return unless fn
@@ -168,6 +186,29 @@ EOS
 
 protected
 
+  def mime_encode string
+    string = [string].pack('M') # basic quoted-printable
+    string.gsub!(/=\n/,'')      # .. remove trailing newline
+    string.gsub!(/_/,'=96')     # .. encode underscores
+    string.gsub!(/\?/,'=3F')    # .. encode question marks
+    string.gsub!(/ /,'_')       # .. translate space to underscores
+    "=?utf-8?q?#{string}?="
+  end
+
+  def mime_encode_subject string
+    return string unless string.match(RE_UTF8)
+    mime_encode string
+  end
+
+  RE_ADDRESS = /(.+)( <.*@.*>)/
+
+  # Encode "bælammet mitt <user@example.com>" into
+  # "=?utf-8?q?b=C3=A6lammet_mitt?= <user@example.com>
+  def mime_encode_address string
+    return string unless string.match(RE_UTF8)
+    string.sub(RE_ADDRESS) { |match| mime_encode($1) + $2 }
+  end
+
   def move_cursor_left
     if curpos < @selectors.length
       @selectors[curpos].roll_left
@@ -212,7 +253,7 @@ protected
 
   def parse_file fn
     File.open(fn) do |f|
-      header = MBox::read_header f
+      header = Source.parse_raw_email_header(f).inject({}) { |h, (k, v)| h[k.capitalize] = v; h } # lousy HACK
       body = f.readlines.map { |l| l.chomp }
 
       header.delete_if { |k, v| NON_EDITABLE_HEADERS.member? k }
@@ -257,7 +298,7 @@ protected
           if i == 0
             header + " " + name
           else
-            (" " * (header.length + 1)) + name
+            (" " * (header.display_length + 1)) + name
           end + (i == things.length - 1 ? "" : ",")
         end
       end
@@ -289,7 +330,7 @@ protected
       BufferManager.flash "Message sent!"
       true
     rescue SystemCallError, SendmailCommandFailed, CryptoManager::Error => e
-      Redwood::log "Problem sending mail: #{e.message}"
+      warn "Problem sending mail: #{e.message}"
       BufferManager.flash "Problem sending mail: #{e.message}"
       false
     end
@@ -321,8 +362,8 @@ protected
 
     ## do whatever crypto transformation is necessary
     if @crypto_selector && @crypto_selector.val != :none
-      from_email = PersonManager.person_for(@header["From"]).email
-      to_email = [@header["To"], @header["Cc"], @header["Bcc"]].flatten.compact.map { |p| PersonManager.person_for(p).email }
+      from_email = Person.from_address(@header["From"]).email
+      to_email = [@header["To"], @header["Cc"], @header["Bcc"]].flatten.compact.map { |p| Person.from_address(p).email }
 
       m = CryptoManager.send @crypto_selector.val, from_email, to_email, m
     end
@@ -333,14 +374,16 @@ protected
       m.header[k] = 
         case v
         when String
-          v
+          k.match(/subject/i) ? mime_encode_subject(v) : mime_encode_address(v)
         when Array
-          v.join ", "
+          v.map { |v| mime_encode_address v }.join ", "
         end
     end
+
     m.header["Date"] = date.rfc2822
     m.header["Message-Id"] = @message_id
     m.header["User-Agent"] = "Sup/#{Redwood::VERSION}"
+    m.header["Content-Transfer-Encoding"] = '8bit'
     m
   end
 
@@ -390,7 +433,7 @@ protected
 
       contacts = BufferManager.ask_for_contacts :people, "#{field}: ", default
       if contacts
-        text = contacts.map { |s| s.longname }.join(", ")
+        text = contacts.map { |s| s.full_address }.join(", ")
         @header[field] = parse_header field, text
         update
       end
@@ -412,7 +455,7 @@ private
   end
 
   def sig_lines
-    p = PersonManager.person_for(@header["From"])
+    p = Person.from_address(@header["From"])
     from_email = p && p.email
 
     ## first run the hook