diff --git a/lib/email/receiver.rb b/lib/email/receiver.rb index f8fb71f5bd8..142e83d4e19 100644 --- a/lib/email/receiver.rb +++ b/lib/email/receiver.rb @@ -162,28 +162,38 @@ module Email REPLYING_HEADER_LABELS = ['From', 'Sent', 'To', 'Subject', 'Reply To', 'Cc', 'Bcc', 'Date'] REPLYING_HEADER_REGEX = Regexp.union(REPLYING_HEADER_LABELS.map { |lbl| "#{lbl}:" }) + def line_is_quote?(l) + l =~ /\A\s*\-{3,80}\s*\z/ || + l =~ Regexp.new("\\A\\s*" + I18n.t('user_notifications.previous_discussion') + "\\s*\\Z") || + (l =~ /via #{SiteSetting.title}(.*)\:$/) || + # This one might be controversial but so many reply lines have years, times and end with a colon. + # Let's try it and see how well it works. + (l =~ /\d{4}/ && l =~ /\d:\d\d/ && l =~ /\:$/) || + (l =~ /On [\w, ]+\d+.*wrote:/) + end + def discourse_email_trimmer(body) lines = body.scrub.lines.to_a + range_start = 0 range_end = 0 + # If we started with a quote, skip it lines.each_with_index do |l, idx| - break if l =~ /\A\s*\-{3,80}\s*\z/ || - l =~ Regexp.new("\\A\\s*" + I18n.t('user_notifications.previous_discussion') + "\\s*\\Z") || - (l =~ /via #{SiteSetting.title}(.*)\:$/) || - # This one might be controversial but so many reply lines have years, times and end with a colon. - # Let's try it and see how well it works. - (l =~ /\d{4}/ && l =~ /\d:\d\d/ && l =~ /\:$/) || - (l =~ /On \w+ \d+,? \d+,?.*wrote:/) + break unless line_is_quote?(l) or l =~ /^>/ or l.blank? + range_start = idx + 1 + end + + lines[range_start..-1].each_with_index do |l, idx| + break if line_is_quote?(l) # Headers on subsequent lines break if (0..2).all? { |off| lines[idx+off] =~ REPLYING_HEADER_REGEX } # Headers on the same line break if REPLYING_HEADER_LABELS.count { |lbl| l.include? lbl } >= 3 - - range_end = idx + range_end = range_start + idx end - lines[0..range_end].join.strip + lines[range_start..range_end].join.strip end def wrap_body_in_quote(user_email) diff --git a/spec/components/email/receiver_spec.rb b/spec/components/email/receiver_spec.rb index 4b460b3ada4..82533078990 100644 --- a/spec/components/email/receiver_spec.rb +++ b/spec/components/email/receiver_spec.rb @@ -42,15 +42,13 @@ describe Email::Receiver do end it "supports a Hebrew reply" do - I18n.expects(:t).with('user_notifications.previous_discussion').returns('כלטוב') + I18n.stubs(:t).with('user_notifications.previous_discussion').returns('כלטוב') # The force_encoding call is only needed for the test - it is passed on fine to the cooked post expect(test_parse_body(fixture_file("emails/hebrew.eml"))).to eq("שלום") end it "supports a BIG5-encoded reply" do - I18n.expects(:t).with('user_notifications.previous_discussion').returns('媽!我上電視了!') - # The force_encoding call is only needed for the test - it is passed on fine to the cooked post expect(test_parse_body(fixture_file("emails/big5.eml"))).to eq("媽!我上電視了!") end @@ -149,12 +147,30 @@ the lazy dog. The quick brown fox jumps over the lazy dog." ) end + it "can retrieve the first part of multiple replies" do + expect(test_parse_body(fixture_file("emails/inline_mixed.eml"))).to eq( +"The quick brown fox jumps over the lazy dog. The quick brown fox jumps over +the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown +fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. +The quick brown fox jumps over the lazy dog. The quick brown fox jumps over +the lazy dog. The quick brown fox jumps over the lazy dog. + +> First paragraph. +> +> Second paragraph. + +The quick brown fox jumps over the lazy dog. The quick brown fox jumps over +the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown" + ) + + end + it "should not include previous replies" do - expect(test_parse_body(fixture_file("emails/previous_replies.eml"))).not_to match /Previous Replies/ + expect(test_parse_body(fixture_file("emails/previous_replies.eml"))).not_to match(/Previous Replies/) end it "strips iPhone signature" do - expect(test_parse_body(fixture_file("emails/iphone_signature.eml"))).not_to match /Sent from my iPhone/ + expect(test_parse_body(fixture_file("emails/iphone_signature.eml"))).not_to match(/Sent from my iPhone/) end it "properly renders email reply from gmail web client" do @@ -288,7 +304,7 @@ This is a link http://example.com" expect(topic.posts.count).to eq(start_count + 1) expect(topic.posts.last.cooked.strip).to eq(fixture_file("emails/paragraphs.cooked").strip) - expect(topic.posts.last.cooked).not_to match /
/ + expect(topic.posts.last.cooked).to match(//) expect(Upload.find_by(sha1: upload_sha)).not_to eq(nil) end diff --git a/spec/fixtures/emails/inline_mixed.eml b/spec/fixtures/emails/inline_mixed.eml new file mode 100644 index 00000000000..f8be9c7a548 --- /dev/null +++ b/spec/fixtures/emails/inline_mixed.eml @@ -0,0 +1,37 @@ +In-Reply-To: +References: + <5434ced4ee0f9_663fb0b5f76070593b@discourse-app.mail> +Date: Mon, 1 Dec 2014 20:48:40 +0530 +Delivered-To: someone@googlemail.com +Subject: Re: [Discourse] [Meta] Testing reply via email +From: Walter White +To: Discourse +Content-Type: multipart/alternative; boundary=20cf30363f8522466905092920a6 + +--20cf30363f8522466905092920a6 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: quoted-printable + +On Wed, Oct 8, 2014 at 11:12 AM, techAPJ wrote: + +> techAPJ +> November 28 +> +> Test reply. +> +> First paragraph. +> +> Second paragraph. + +The quick brown fox jumps over the lazy dog. The quick brown fox jumps over +the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown +fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. +The quick brown fox jumps over the lazy dog. The quick brown fox jumps over +the lazy dog. The quick brown fox jumps over the lazy dog. + +> First paragraph. +> +> Second paragraph. + +The quick brown fox jumps over the lazy dog. The quick brown fox jumps over +the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown