X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=lib%2Fsup%2Fmodes%2Fedit-message-mode.rb;h=3df3176f924ac0b0ccf525adc41b6ce2acdcd059;hb=3ef5e2e01079b557432ad57cabadee36a02b9cf4;hp=e04fc3033dfc4f80f6a9012bba5769cc4625a3fb;hpb=881bac62392d86edf46bcb0d269a7195e41ff8c1;p=sup diff --git a/lib/sup/modes/edit-message-mode.rb b/lib/sup/modes/edit-message-mode.rb index e04fc30..3df3176 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={} @@ -57,10 +61,24 @@ EOS @body = opts.delete(:body) || [] @body += sig_lines if $config[:edit_signature] - @attachments = [] + if opts[:attachments] + @attachments = opts[:attachments].values + @attachment_names = opts[:attachments].keys + else + @attachments = [] + @attachment_names = [] + end + @message_id = "<#{Time.now.to_i}-sup-#{rand 10000}@#{Socket.gethostname}>" @edited = false - @skip_top_rows = opts[:skip_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 +86,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 + "" + 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 @@ -116,20 +146,39 @@ EOS def attach_file fn = BufferManager.ask_for_filename :attachment, "File name (enter for browser): " return unless fn - @attachments << Pathname.new(fn) + @attachments << RMail::Message.make_file_attachment(fn) + @attachment_names << fn update end def delete_attachment - i = (curpos - @skip_top_rows) - @attachment_lines_offset - if i >= 0 && i < @attachments.size && BufferManager.ask_yes_or_no("Delete attachment #{@attachments[i]}?") + i = curpos - @attachment_lines_offset - DECORATION_LINES - 1 + if i >= 0 && i < @attachments.size && BufferManager.ask_yes_or_no("Delete attachment #{@attachment_names[i]}?") @attachments.delete_at i + @attachment_names.delete_at i update end end 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 @@ -145,7 +194,7 @@ protected unless @attachments.empty? @text += [""] @attachment_lines_offset = @text.length - @text += @attachments.map { |f| [[:attachment_color, "+ Attachment: #{f} (#{f.human_size})"]] } + @text += (0 ... @attachments.size).map { |i| [[:attachment_color, "+ Attachment: #{@attachment_names[i]} (#{@attachments[i].body.size.to_human_size})"]] } end end @@ -208,7 +257,6 @@ protected return false if $config[:confirm_no_attachments] && mentions_attachments? && @attachments.size == 0 && !BufferManager.ask_yes_or_no("You haven't added any attachments. Really send?")#" stupid ruby-mode return false if $config[:confirm_top_posting] && top_posting? && !BufferManager.ask_yes_or_no("You're top-posting. That makes you a bad person. Really send?") #" stupid ruby-mode - date = Time.now from_email = if @header["From"] =~ /?$/ $1 @@ -220,13 +268,15 @@ protected BufferManager.flash "Sending..." begin - IO.popen(acct.sendmail, "w") { |p| write_full_message_to p, date, false } + date = Time.now + m = build_message date + IO.popen(acct.sendmail, "w") { |p| p.puts m } raise SendmailCommandFailed, "Couldn't execute #{acct.sendmail}" unless $? == 0 - SentManager.write_sent_message(date, from_email) { |f| write_full_message_to f, date, true } + SentManager.write_sent_message(date, from_email) { |f| f.puts sanitize_body(m.to_s) } BufferManager.kill_buffer buffer BufferManager.flash "Message sent!" true - rescue SystemCallError, SendmailCommandFailed => e + rescue SystemCallError, SendmailCommandFailed, CryptoManager::Error => e Redwood::log "Problem sending mail: #{e.message}" BufferManager.flash "Problem sending mail: #{e.message}" false @@ -239,8 +289,32 @@ protected BufferManager.flash "Saved for later editing." end - def write_full_message_to f, date=Time.now, escape=false + def build_message date m = RMail::Message.new + m.header["Content-Type"] = "text/plain; charset=#{$encoding}" + m.body = @body.join + m.body = m.body + m.body += sig_lines.join("\n") unless $config[:edit_signature] + + ## there are attachments, so wrap body in an attachment of its own + unless @attachments.empty? + body_m = m + body_m.header["Content-Disposition"] = "inline" + m = RMail::Message.new + + m.add_part body_m + @attachments.each { |a| m.add_part a } + end + + ## 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"]).map { |p| PersonManager.person_for(p).email } + + m = CryptoManager.send @crypto_selector.val, from_email, to_email, m + end + + ## finally, set the top-level headers @header.each do |k, v| next if v.nil? || v.empty? m.header[k] = @@ -251,28 +325,10 @@ protected v.join ", " end end - m.header["Date"] = date.rfc2822 m.header["Message-Id"] = @message_id m.header["User-Agent"] = "Sup/#{Redwood::VERSION}" - - if @attachments.empty? - m.header["Content-Type"] = "text/plain; charset=#{$encoding}" - m.body = @body.join - m.body = sanitize_body m.body if escape - m.body += sig_lines.join("\n") unless $config[:edit_signature] - else - body_m = RMail::Message.new - body_m.body = @body.join - body_m.body = sanitize_body body_m.body if escape - body_m.body += sig_lines.join("\n") unless $config[:edit_signature] - body_m.header["Content-Type"] = "text/plain; charset=#{$encoding}" - body_m.header["Content-Disposition"] = "inline" - - m.add_part body_m - @attachments.each { |fn| m.add_file_attachment fn.to_s } - end - f.puts m.to_s + m end ## TODO: remove this. redundant with write_full_message_to.