From: wmorgan Date: Sat, 8 Dec 2007 21:20:17 +0000 (+0000) Subject: add gpg interface to all outgoing messages (but no implementation yet) X-Git-Url: https://git.cworth.org/git?a=commitdiff_plain;h=f8989bae2cf6126690b2bcb978e1950021c3cb41;p=sup add gpg interface to all outgoing messages (but no implementation yet) git-svn-id: svn://rubyforge.org/var/svn/sup/trunk@744 5c8cc53c-5e98-4d25-b20a-d8db53a31250 --- diff --git a/Manifest.txt b/Manifest.txt index d24764c..a423a6f 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -24,6 +24,7 @@ lib/sup/contact.rb lib/sup/crypto.rb lib/sup/draft.rb lib/sup/hook.rb +lib/sup/horizontal-selector.rb lib/sup/imap.rb lib/sup/index.rb lib/sup/keymap.rb diff --git a/lib/sup.rb b/lib/sup.rb index 9cd2fd7..60679ee 100644 --- a/lib/sup.rb +++ b/lib/sup.rb @@ -255,6 +255,7 @@ require "sup/tagger" require "sup/draft" require "sup/poll" require "sup/crypto" +require "sup/horizontal-selector" require "sup/modes/line-cursor-mode" require "sup/modes/help-mode" require "sup/modes/edit-message-mode" diff --git a/lib/sup/colormap.rb b/lib/sup/colormap.rb index 004df26..9c6869a 100644 --- a/lib/sup/colormap.rb +++ b/lib/sup/colormap.rb @@ -51,6 +51,8 @@ class Colormap case bg when Curses::COLOR_CYAN Curses::COLOR_YELLOW + when Curses::COLOR_YELLOW + Curses::COLOR_BLUE else Curses::COLOR_CYAN end diff --git a/lib/sup/crypto.rb b/lib/sup/crypto.rb index 148456d..5db576b 100644 --- a/lib/sup/crypto.rb +++ b/lib/sup/crypto.rb @@ -3,6 +3,12 @@ module Redwood class CryptoManager include Singleton + OUTGOING_MESSAGE_OPERATIONS = OrderedHash.new( + [:sign, "Sign"], + [:sign_and_encrypt, "Sign and encrypt"], + [:encrypt, "Encrypt only"] + ) + def initialize @mutex = Mutex.new self.class.i_am_the_instance self @@ -13,13 +19,16 @@ class CryptoManager @cmd = case bin when /\S/ + Redwood::log "crypto: detected gpg binary in #{bin}" "#{bin} --quiet --batch --no-verbose --logger-fd 1 --use-agent" else + Redwood::log "crypto: no gpg binary detected" nil end end - # returns a cryptosignature + def have_crypto?; !@cmd.nil? end + def verify payload, signature # both RubyMail::Message objects return unknown_status(cant_find_binary) unless @cmd diff --git a/lib/sup/modes/edit-message-mode.rb b/lib/sup/modes/edit-message-mode.rb index e04fc30..43bf9f0 100644 --- a/lib/sup/modes/edit-message-mode.rb +++ b/lib/sup/modes/edit-message-mode.rb @@ -8,6 +8,8 @@ module Redwood class SendmailCommandFailed < StandardError; end class EditMessageMode < LineCursorMode + DECORATION_LINES = 1 + FORCE_HEADERS = %w(From To Cc Bcc Subject) MULTI_HEADERS = %w(To Cc Bcc) NON_EDITABLE_HEADERS = %w(Message-Id Date) @@ -48,6 +50,8 @@ EOS k.add :save_as_draft, "Save as draft", 'P' k.add :attach_file, "Attach a file", 'a' k.add :delete_attachment, "Delete an attachment", 'd' + k.add :move_cursor_right, "Move selector to the right", :right + k.add :move_cursor_left, "Move selector to the left", :left end def initialize opts={} @@ -60,7 +64,15 @@ EOS @attachments = [] @message_id = "<#{Time.now.to_i}-sup-#{rand 10000}@#{Socket.gethostname}>" @edited = false - @skip_top_rows = opts[:skip_top_rows] || 0 + @reserve_top_rows = opts[:reserve_top_rows] || 0 + @selectors = [] + @selector_label_width = 0 + + @crypto_selector = + 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 HookManager.run "before-edit", :header => @header, :body => @body @@ -68,17 +80,29 @@ EOS regen_text end - def lines; @text.length end - def [] i; @text[i] end + def lines; @text.length + (@selectors.empty? ? 0 : (@selectors.length + DECORATION_LINES)) end + + def [] i + if @selectors.empty? + @text[i] + elsif i < @selectors.length + @selectors[i].line @selector_label_width + elsif i == @selectors.length + "-" * buffer.content_width + else + @text[i - @selectors.length - DECORATION_LINES] + end + end - ## a hook + ## hook for subclasses. i hate this style of programming. def handle_new_text header, body; end def edit_message_or_field - if (curpos - @skip_top_rows) >= @header_lines.length + lines = DECORATION_LINES + @selectors.size + if (curpos - lines) >= @header_lines.length edit_message else - edit_field @header_lines[curpos - @skip_top_rows] + edit_field @header_lines[curpos - lines] end end @@ -121,7 +145,7 @@ EOS end def delete_attachment - i = (curpos - @skip_top_rows) - @attachment_lines_offset + i = (curpos - @reserve_top_rows) - @attachment_lines_offset if i >= 0 && i < @attachments.size && BufferManager.ask_yes_or_no("Delete attachment #{@attachments[i]}?") @attachments.delete_at i update @@ -130,6 +154,23 @@ EOS protected + def move_cursor_left + return unless curpos < @selectors.length + @selectors[curpos].roll_left + buffer.mark_dirty + end + + def move_cursor_right + return unless curpos < @selectors.length + @selectors[curpos].roll_right + buffer.mark_dirty + end + + def add_selector s + @selectors << s + @selector_label_width = [@selector_label_width, s.label.length].max + end + def update regen_text buffer.mark_dirty if buffer diff --git a/lib/sup/modes/reply-mode.rb b/lib/sup/modes/reply-mode.rb index fb7bfd6..c95ffc0 100644 --- a/lib/sup/modes/reply-mode.rb +++ b/lib/sup/modes/reply-mode.rb @@ -3,18 +3,13 @@ module Redwood class ReplyMode < EditMessageMode REPLY_TYPES = [:sender, :recipient, :list, :all, :user] TYPE_DESCRIPTIONS = { - :sender => "Reply to sender", - :recipient => "Reply to recipient", - :all => "Reply to all", - :list => "Reply to mailing list", - :user => "Customized reply" + :sender => "Sender", + :recipient => "Recipient", + :all => "All", + :list => "Mailing list", + :user => "Customized" } - register_keymap do |k| - k.add :move_cursor_right, "Move cursor to the right", :right - k.add :move_cursor_left, "Move cursor to the left", :left - end - def initialize message @m = message @@ -41,7 +36,6 @@ class ReplyMode < EditMessageMode ## next, cc: cc = (@m.to + @m.cc - [from, to]).uniq - Redwood::log "cc = (#{@m.to.inspect} + #{@m.cc.inspect} - #{[from, to].inspect}).uniq = #{cc.inspect}" ## one potential reply type is "reply to recipient". this only happens ## in certain cases: @@ -85,36 +79,39 @@ class ReplyMode < EditMessageMode }.merge v end - @type_labels = REPLY_TYPES.select { |t| @headers.member?(t) } - @selected_type = + types = REPLY_TYPES.select { |t| @headers.member?(t) } + @type_selector = HorizontalSelector.new "Reply to:", types, types.map { |x| TYPE_DESCRIPTIONS[x] } + + @type_selector.set_to( if @m.is_list_message? :list elsif @headers.member? :sender :sender else :recipient - end + end) - super :header => @headers[@selected_type], :body => body, - :skip_top_rows => 2, :twiddles => false + super :header => @headers[@type_selector.val], :body => body, :twiddles => false + add_selector @type_selector end - def lines; super + 2; end - def [] i - case i - when 0 - @type_labels.inject([]) do |array, t| - array + [[(t == @selected_type ? :none_highlight : :none), - "#{TYPE_DESCRIPTIONS[t]}"], [:none, " "]] - end + [[:none, ""]] - when 1 - "" - else - super(i - 2) +protected + + def move_cursor_right + super + if @headers[@type_selector.val] != self.header + self.header = @headers[@type_selector.val] + update end end -protected + def move_cursor_left + super + if @headers[@type_selector.val] != self.header + self.header = @headers[@type_selector.val] + update + end + end def reply_body_lines m lines = ["Excerpts from #{@m.from.name}'s message of #{@m.date}:"] + m.quotable_body_lines.map { |l| "> #{l}" } @@ -123,9 +120,9 @@ protected end def handle_new_text new_header, new_body - old_header = @headers[@selected_type] + old_header = @headers[@type_selector.val] if new_header.size != old_header.size || old_header.any? { |k, v| new_header[k] != v } - @selected_type = :user + @type_selector.set_to :user self.header = @headers[:user] = new_header update end @@ -138,24 +135,10 @@ protected def edit_field field edited_field = super if edited_field && edited_field != "Subject" - @selected_type = :user + @type_selector.set_to :user update end end - - def move_cursor_left - i = @type_labels.index @selected_type - @selected_type = @type_labels[(i - 1) % @type_labels.length] - self.header = @headers[@selected_type] - update - end - - def move_cursor_right - i = @type_labels.index @selected_type - @selected_type = @type_labels[(i + 1) % @type_labels.length] - self.header = @headers[@selected_type] - update - end end end diff --git a/lib/sup/modes/scroll-mode.rb b/lib/sup/modes/scroll-mode.rb index 328a07d..1ff9170 100644 --- a/lib/sup/modes/scroll-mode.rb +++ b/lib/sup/modes/scroll-mode.rb @@ -176,7 +176,7 @@ protected draw_line_from_array ln, s, opts end else - raise "unknown drawable object: #{s.inspect}" # good for debugging + raise "unknown drawable object: #{s.inspect} in #{self} for line #{ln}" # good for debugging end ## speed test diff --git a/lib/sup/util.rb b/lib/sup/util.rb index cc15803..e2b82e1 100644 --- a/lib/sup/util.rb +++ b/lib/sup/util.rb @@ -577,23 +577,26 @@ end class OrderedHash < Hash alias_method :store, :[]= alias_method :each_pair, :each + attr_reader :keys - def initialize + def initialize *a @keys = [] + a.each { |k, v| self[k] = v } end - def []=(key, val) + def []= key, val @keys << key unless member?(key) super end - def delete(key) - @keys.delete(key) + def values; keys.map { |k| self[k] } end + def index key; @keys.index key end + + def delete key + @keys.delete key super end - def each - @keys.each { |k| yield k, self[k] } - end + def each; @keys.each { |k| yield k, self[k] } end end