runger_email_reply_trimmer 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +72 -0
- data/LICENSE +9 -0
- data/README.md +21 -0
- data/Rakefile +17 -0
- data/bin/release +27 -0
- data/lib/runger_email_reply_trimmer/delimiter_matcher.rb +12 -0
- data/lib/runger_email_reply_trimmer/email_header_matcher.rb +72 -0
- data/lib/runger_email_reply_trimmer/embedded_email_matcher.rb +158 -0
- data/lib/runger_email_reply_trimmer/empty_line_matcher.rb +9 -0
- data/lib/runger_email_reply_trimmer/quote_matcher.rb +9 -0
- data/lib/runger_email_reply_trimmer/signature_matcher.rb +52 -0
- data/lib/runger_email_reply_trimmer/version.rb +5 -0
- data/lib/runger_email_reply_trimmer.rb +226 -0
- data/runger_email_reply_trimmer.gemspec +21 -0
- data/test/before/email_headers_1.txt +1 -0
- data/test/before/email_headers_2.txt +1 -0
- data/test/before/email_headers_3.txt +1 -0
- data/test/before/email_headers_4.txt +1 -0
- data/test/before/embedded_email_10.txt +25 -0
- data/test/before/embedded_email_german_3.txt +1 -0
- data/test/before/embedded_email_spanish_2.txt +1 -0
- data/test/before/forwarded_apple.txt +1 -0
- data/test/before/forwarded_gmail.txt +1 -0
- data/test/before/forwarded_message.txt +0 -0
- data/test/elided/delimiters.txt +10 -0
- data/test/elided/dual_embedded.txt +10 -0
- data/test/elided/email_headers_1.txt +14 -0
- data/test/elided/email_headers_2.txt +9 -0
- data/test/elided/email_headers_3.txt +16 -0
- data/test/elided/email_headers_4.txt +15 -0
- data/test/elided/email_headers_5.txt +23 -0
- data/test/elided/embedded_ception.txt +38 -0
- data/test/elided/embedded_email_1.txt +6 -0
- data/test/elided/embedded_email_10.txt +40 -0
- data/test/elided/embedded_email_11.txt +3 -0
- data/test/elided/embedded_email_12.txt +8 -0
- data/test/elided/embedded_email_13.txt +9 -0
- data/test/elided/embedded_email_14.txt +11 -0
- data/test/elided/embedded_email_15.txt +4 -0
- data/test/elided/embedded_email_16.txt +4 -0
- data/test/elided/embedded_email_17.txt +2 -0
- data/test/elided/embedded_email_18.txt +1 -0
- data/test/elided/embedded_email_19.txt +0 -0
- data/test/elided/embedded_email_2.txt +9 -0
- data/test/elided/embedded_email_3.txt +14 -0
- data/test/elided/embedded_email_4.txt +15 -0
- data/test/elided/embedded_email_5.txt +3 -0
- data/test/elided/embedded_email_6.txt +3 -0
- data/test/elided/embedded_email_7.txt +10 -0
- data/test/elided/embedded_email_8.txt +3 -0
- data/test/elided/embedded_email_9.txt +3 -0
- data/test/elided/embedded_email_chinese.txt +4 -0
- data/test/elided/embedded_email_dutch_1.txt +10 -0
- data/test/elided/embedded_email_dutch_2.txt +59 -0
- data/test/elided/embedded_email_french_1.txt +9 -0
- data/test/elided/embedded_email_french_2.txt +19 -0
- data/test/elided/embedded_email_german_1.txt +22 -0
- data/test/elided/embedded_email_german_2.txt +3 -0
- data/test/elided/embedded_email_german_3.txt +7 -0
- data/test/elided/embedded_email_german_4.txt +15 -0
- data/test/elided/embedded_email_german_5.txt +20 -0
- data/test/elided/embedded_email_german_6.txt +8 -0
- data/test/elided/embedded_email_italian.txt +28 -0
- data/test/elided/embedded_email_norwegian.txt +9 -0
- data/test/elided/embedded_email_polish_1.txt +32 -0
- data/test/elided/embedded_email_polish_2.txt +7 -0
- data/test/elided/embedded_email_portuguese.txt +14 -0
- data/test/elided/embedded_email_quote_text.txt +6 -0
- data/test/elided/embedded_email_russian_1.txt +25 -0
- data/test/elided/embedded_email_russian_2.txt +23 -0
- data/test/elided/embedded_email_spanish_1.txt +32 -0
- data/test/elided/embedded_email_spanish_2.txt +10 -0
- data/test/elided/embedded_email_swedish.txt +8 -0
- data/test/elided/embedded_email_ukrainian.txt +17 -0
- data/test/elided/forwarded_apple.txt +15 -0
- data/test/elided/forwarded_gmail.txt +15 -0
- data/test/elided/forwarded_message.txt +6 -0
- data/test/elided/normalize_line_endings.txt +0 -0
- data/test/elided/quote_and_text.txt +0 -0
- data/test/elided/quote_only.txt +0 -0
- data/test/elided/retains_spaces_and_formatting.txt +0 -0
- data/test/elided/signatures.txt +31 -0
- data/test/elided/spam_1.txt +75 -0
- data/test/elided/spam_2.txt +152 -0
- data/test/elided/strip.txt +0 -0
- data/test/elided/text_only.txt +0 -0
- data/test/elided/usenet.txt +7 -0
- data/test/emails/delimiters.txt +14 -0
- data/test/emails/dual_embedded.txt +13 -0
- data/test/emails/email_headers_1.txt +17 -0
- data/test/emails/email_headers_2.txt +10 -0
- data/test/emails/email_headers_3.txt +18 -0
- data/test/emails/email_headers_4.txt +17 -0
- data/test/emails/email_headers_5.txt +37 -0
- data/test/emails/embedded_ception.txt +47 -0
- data/test/emails/embedded_email_1.txt +8 -0
- data/test/emails/embedded_email_10.txt +42 -0
- data/test/emails/embedded_email_11.txt +5 -0
- data/test/emails/embedded_email_12.txt +18 -0
- data/test/emails/embedded_email_13.txt +14 -0
- data/test/emails/embedded_email_14.txt +16 -0
- data/test/emails/embedded_email_15.txt +9 -0
- data/test/emails/embedded_email_16.txt +16 -0
- data/test/emails/embedded_email_17.txt +38 -0
- data/test/emails/embedded_email_18.txt +7 -0
- data/test/emails/embedded_email_19.txt +13 -0
- data/test/emails/embedded_email_2.txt +16 -0
- data/test/emails/embedded_email_3.txt +24 -0
- data/test/emails/embedded_email_4.txt +19 -0
- data/test/emails/embedded_email_5.txt +5 -0
- data/test/emails/embedded_email_6.txt +11 -0
- data/test/emails/embedded_email_7.txt +20 -0
- data/test/emails/embedded_email_8.txt +5 -0
- data/test/emails/embedded_email_9.txt +5 -0
- data/test/emails/embedded_email_chinese.txt +7 -0
- data/test/emails/embedded_email_dutch_1.txt +13 -0
- data/test/emails/embedded_email_dutch_2.txt +62 -0
- data/test/emails/embedded_email_french_1.txt +12 -0
- data/test/emails/embedded_email_french_2.txt +21 -0
- data/test/emails/embedded_email_german_1.txt +26 -0
- data/test/emails/embedded_email_german_2.txt +6 -0
- data/test/emails/embedded_email_german_3.txt +10 -0
- data/test/emails/embedded_email_german_4.txt +18 -0
- data/test/emails/embedded_email_german_5.txt +23 -0
- data/test/emails/embedded_email_german_6.txt +14 -0
- data/test/emails/embedded_email_italian.txt +31 -0
- data/test/emails/embedded_email_norwegian.txt +11 -0
- data/test/emails/embedded_email_polish_1.txt +34 -0
- data/test/emails/embedded_email_polish_2.txt +11 -0
- data/test/emails/embedded_email_portuguese.txt +18 -0
- data/test/emails/embedded_email_quote_text.txt +10 -0
- data/test/emails/embedded_email_russian_1.txt +27 -0
- data/test/emails/embedded_email_russian_2.txt +26 -0
- data/test/emails/embedded_email_spanish_1.txt +41 -0
- data/test/emails/embedded_email_spanish_2.txt +12 -0
- data/test/emails/embedded_email_swedish.txt +20 -0
- data/test/emails/embedded_email_ukrainian.txt +19 -0
- data/test/emails/forwarded_apple.txt +17 -0
- data/test/emails/forwarded_gmail.txt +17 -0
- data/test/emails/forwarded_message.txt +9 -0
- data/test/emails/normalize_line_endings.txt +4 -0
- data/test/emails/quote_and_text.txt +3 -0
- data/test/emails/quote_only.txt +1 -0
- data/test/emails/retains_spaces_and_formatting.txt +14 -0
- data/test/emails/signatures.txt +33 -0
- data/test/emails/spam_1.txt +75 -0
- data/test/emails/spam_2.txt +174 -0
- data/test/emails/strip.txt +10 -0
- data/test/emails/text_only.txt +1 -0
- data/test/emails/usenet.txt +9 -0
- data/test/embedded/email_headers_1.txt +12 -0
- data/test/embedded/email_headers_2.txt +8 -0
- data/test/embedded/email_headers_3.txt +16 -0
- data/test/embedded/email_headers_4.txt +15 -0
- data/test/embedded/embedded_email_10.txt +15 -0
- data/test/embedded/embedded_email_german_3.txt +6 -0
- data/test/embedded/embedded_email_spanish_2.txt +9 -0
- data/test/embedded/forwarded_apple.txt +13 -0
- data/test/embedded/forwarded_gmail.txt +14 -0
- data/test/embedded/forwarded_message.txt +8 -0
- data/test/matchers/does_not_contain_embedded_email.txt +5 -0
- data/test/test_email_matcher.rb +17 -0
- data/test/test_email_reply_trimmer.rb +87 -0
- data/test/trimmed/delimiters.txt +3 -0
- data/test/trimmed/dual_embedded.txt +1 -0
- data/test/trimmed/email_headers_1.txt +1 -0
- data/test/trimmed/email_headers_2.txt +1 -0
- data/test/trimmed/email_headers_3.txt +1 -0
- data/test/trimmed/email_headers_4.txt +1 -0
- data/test/trimmed/email_headers_5.txt +11 -0
- data/test/trimmed/embedded_ception.txt +4 -0
- data/test/trimmed/embedded_email_1.txt +1 -0
- data/test/trimmed/embedded_email_10.txt +1 -0
- data/test/trimmed/embedded_email_11.txt +1 -0
- data/test/trimmed/embedded_email_12.txt +1 -0
- data/test/trimmed/embedded_email_13.txt +3 -0
- data/test/trimmed/embedded_email_14.txt +3 -0
- data/test/trimmed/embedded_email_15.txt +3 -0
- data/test/trimmed/embedded_email_16.txt +11 -0
- data/test/trimmed/embedded_email_17.txt +35 -0
- data/test/trimmed/embedded_email_18.txt +5 -0
- data/test/trimmed/embedded_email_19.txt +13 -0
- data/test/trimmed/embedded_email_2.txt +3 -0
- data/test/trimmed/embedded_email_3.txt +7 -0
- data/test/trimmed/embedded_email_4.txt +2 -0
- data/test/trimmed/embedded_email_5.txt +1 -0
- data/test/trimmed/embedded_email_6.txt +7 -0
- data/test/trimmed/embedded_email_7.txt +10 -0
- data/test/trimmed/embedded_email_8.txt +1 -0
- data/test/trimmed/embedded_email_9.txt +1 -0
- data/test/trimmed/embedded_email_chinese.txt +2 -0
- data/test/trimmed/embedded_email_dutch_1.txt +1 -0
- data/test/trimmed/embedded_email_dutch_2.txt +2 -0
- data/test/trimmed/embedded_email_french_1.txt +1 -0
- data/test/trimmed/embedded_email_french_2.txt +1 -0
- data/test/trimmed/embedded_email_german_1.txt +1 -0
- data/test/trimmed/embedded_email_german_2.txt +1 -0
- data/test/trimmed/embedded_email_german_3.txt +1 -0
- data/test/trimmed/embedded_email_german_4.txt +1 -0
- data/test/trimmed/embedded_email_german_5.txt +1 -0
- data/test/trimmed/embedded_email_german_6.txt +4 -0
- data/test/trimmed/embedded_email_italian.txt +1 -0
- data/test/trimmed/embedded_email_norwegian.txt +1 -0
- data/test/trimmed/embedded_email_polish_1.txt +1 -0
- data/test/trimmed/embedded_email_polish_2.txt +2 -0
- data/test/trimmed/embedded_email_portuguese.txt +2 -0
- data/test/trimmed/embedded_email_quote_text.txt +2 -0
- data/test/trimmed/embedded_email_russian_1.txt +1 -0
- data/test/trimmed/embedded_email_russian_2.txt +1 -0
- data/test/trimmed/embedded_email_spanish_1.txt +6 -0
- data/test/trimmed/embedded_email_spanish_2.txt +1 -0
- data/test/trimmed/embedded_email_swedish.txt +9 -0
- data/test/trimmed/embedded_email_ukrainian.txt +1 -0
- data/test/trimmed/forwarded_apple.txt +1 -0
- data/test/trimmed/forwarded_gmail.txt +1 -0
- data/test/trimmed/forwarded_message.txt +1 -0
- data/test/trimmed/normalize_line_endings.txt +4 -0
- data/test/trimmed/quote_and_text.txt +3 -0
- data/test/trimmed/quote_only.txt +1 -0
- data/test/trimmed/retains_spaces_and_formatting.txt +14 -0
- data/test/trimmed/signatures.txt +1 -0
- data/test/trimmed/spam_1.txt +0 -0
- data/test/trimmed/spam_2.txt +21 -0
- data/test/trimmed/strip.txt +1 -0
- data/test/trimmed/text_only.txt +1 -0
- data/test/trimmed/usenet.txt +1 -0
- metadata +275 -0
@@ -0,0 +1,226 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'runger_email_reply_trimmer/delimiter_matcher'
|
4
|
+
|
5
|
+
require_relative 'runger_email_reply_trimmer/email_header_matcher'
|
6
|
+
require_relative 'runger_email_reply_trimmer/embedded_email_matcher'
|
7
|
+
require_relative 'runger_email_reply_trimmer/empty_line_matcher'
|
8
|
+
require_relative 'runger_email_reply_trimmer/quote_matcher'
|
9
|
+
require_relative 'runger_email_reply_trimmer/signature_matcher'
|
10
|
+
|
11
|
+
module RungerEmailReplyTrimmer
|
12
|
+
module_function
|
13
|
+
|
14
|
+
DELIMITER = 'd'
|
15
|
+
EMBEDDED = 'b'
|
16
|
+
EMPTY = 'e'
|
17
|
+
EMAIL_HEADER = 'h'
|
18
|
+
QUOTE = 'q'
|
19
|
+
SIGNATURE = 's'
|
20
|
+
TEXT = 't'
|
21
|
+
|
22
|
+
def identify_line_content(line)
|
23
|
+
return EMPTY if EmptyLineMatcher.match?(line)
|
24
|
+
return DELIMITER if DelimiterMatcher.match?(line)
|
25
|
+
return SIGNATURE if SignatureMatcher.match?(line)
|
26
|
+
return EMBEDDED if EmbeddedEmailMatcher.match?(line)
|
27
|
+
return EMAIL_HEADER if EmailHeaderMatcher.match?(line)
|
28
|
+
return QUOTE if QuoteMatcher.match?(line)
|
29
|
+
|
30
|
+
TEXT
|
31
|
+
end
|
32
|
+
|
33
|
+
def trim(text, split = false)
|
34
|
+
return if text.nil? || text =~ /\A[[:space:]]*\z/m
|
35
|
+
|
36
|
+
# do some cleanup
|
37
|
+
preprocess!(text)
|
38
|
+
|
39
|
+
# from now on, we'll work on a line-by-line basis
|
40
|
+
lines = text.split("\n")
|
41
|
+
lines_dup = lines.dup
|
42
|
+
|
43
|
+
# identify content of each lines
|
44
|
+
pattern = lines.map { |l| identify_line_content(l) }.join
|
45
|
+
|
46
|
+
# remove everything after the first delimiter
|
47
|
+
if pattern =~ /d/
|
48
|
+
index = pattern =~ /d/
|
49
|
+
pattern = pattern[0...index]
|
50
|
+
lines = lines[0...index]
|
51
|
+
end
|
52
|
+
|
53
|
+
# remove all mobile signatures
|
54
|
+
while pattern =~ /s/
|
55
|
+
index = pattern =~ /s/
|
56
|
+
pattern.slice!(index)
|
57
|
+
lines.slice!(index)
|
58
|
+
end
|
59
|
+
|
60
|
+
# when the reply is at the end of the email
|
61
|
+
if is_reply_at_end?(pattern)
|
62
|
+
index = pattern =~ /t[et]*$/
|
63
|
+
pattern = ''
|
64
|
+
lines = lines[index..]
|
65
|
+
end
|
66
|
+
|
67
|
+
# if there is an embedded email marker, not followed by a quote
|
68
|
+
# then take everything up to that marker
|
69
|
+
if pattern =~ /te*b[^q]*$/
|
70
|
+
index = pattern =~ /te*b[^q]*$/
|
71
|
+
pattern = pattern[0..index]
|
72
|
+
lines = lines[0..index]
|
73
|
+
end
|
74
|
+
|
75
|
+
# if there is an embedded email marker, followed by a huge quote
|
76
|
+
# then take everything up to that marker
|
77
|
+
if pattern =~ /te*b[eqbh]*([te]*)$/ && ::Regexp.last_match(1).count('t') < 7
|
78
|
+
index = pattern =~ /te*b[eqbh]*[te]*$/
|
79
|
+
pattern = pattern[0..index]
|
80
|
+
lines = lines[0..index]
|
81
|
+
end
|
82
|
+
|
83
|
+
# if there is some text before a huge quote ending the email,
|
84
|
+
# then remove the quote
|
85
|
+
if pattern =~ /t?e*[qbe]+$/
|
86
|
+
index = pattern =~ /t?e*[qbe]+$/
|
87
|
+
pattern = pattern[0..index]
|
88
|
+
lines = lines[0..index]
|
89
|
+
end
|
90
|
+
|
91
|
+
# if there still are some embedded email markers, just remove them
|
92
|
+
while pattern =~ /b/
|
93
|
+
index = pattern =~ /b/
|
94
|
+
pattern.slice!(index)
|
95
|
+
lines.slice!(index)
|
96
|
+
end
|
97
|
+
|
98
|
+
# fix email headers when they span over multiple lines
|
99
|
+
if pattern =~ /h+[hte]+h+e/
|
100
|
+
index = pattern =~ /h+[hte]+h+e/
|
101
|
+
size = pattern[/h+[hte]+h+e/].size
|
102
|
+
size.times.each { |s| pattern[index + s] = EMAIL_HEADER }
|
103
|
+
end
|
104
|
+
|
105
|
+
# if there are at least 3 consecutive email headers,
|
106
|
+
# take everything up to these headers
|
107
|
+
if pattern =~ /t[eq]*h{3,}/
|
108
|
+
index = pattern =~ /t[eq]*h{3,}/
|
109
|
+
pattern = pattern[0..index]
|
110
|
+
lines = lines[0..index]
|
111
|
+
end
|
112
|
+
|
113
|
+
# if there still are some email headers, just remove them
|
114
|
+
while pattern =~ /h/
|
115
|
+
index = pattern =~ /h/
|
116
|
+
pattern.slice!(index)
|
117
|
+
lines.slice!(index)
|
118
|
+
end
|
119
|
+
|
120
|
+
# remove trailing quotes when there's at least one line of text
|
121
|
+
if pattern =~ /t/ && pattern =~ /[eq]+$/
|
122
|
+
index = pattern =~ /[eq]+$/
|
123
|
+
pattern = pattern[0...index]
|
124
|
+
lines = lines[0...index]
|
125
|
+
end
|
126
|
+
|
127
|
+
# results
|
128
|
+
trimmed = lines.join("\n").strip
|
129
|
+
|
130
|
+
if split
|
131
|
+
[trimmed, compute_elided(lines_dup, lines)]
|
132
|
+
else
|
133
|
+
trimmed
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def extract_embedded_email(text)
|
138
|
+
return if text.nil? || text =~ /\A[[:space:]]*\z/m
|
139
|
+
|
140
|
+
# do some cleanup
|
141
|
+
preprocess!(text)
|
142
|
+
|
143
|
+
# from now on, we'll work on a line-by-line basis
|
144
|
+
lines = text.split("\n")
|
145
|
+
|
146
|
+
# identify content of each lines
|
147
|
+
pattern = lines.map { |l| identify_line_content(l) }.join
|
148
|
+
|
149
|
+
if (index = pattern =~ /(?:h[eqd]*?){3,}[tq]/)
|
150
|
+
embedded = lines[index..].join("\n").strip
|
151
|
+
elsif (index = pattern =~ /b(?:[eqd]*){3,}[tq]/)
|
152
|
+
# Exception for email clients (macOS / iOS) which embed fwd emails in quotes.
|
153
|
+
embedded = lines[index + 1..].map { |l| l.gsub(/^>\s*/, '') }.join("\n").strip
|
154
|
+
end
|
155
|
+
|
156
|
+
if index
|
157
|
+
before = lines[0...(pattern[0...index] =~ /e*(b[eqd]*|b*[ed]*)$/)].join("\n").strip
|
158
|
+
[embedded, before]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def preprocess!(text)
|
163
|
+
# normalize line endings
|
164
|
+
text.gsub!("\r\n", "\n")
|
165
|
+
|
166
|
+
# remove PGP markers
|
167
|
+
text.gsub!(/\A-----BEGIN PGP SIGNED MESSAGE-----\n(?:Hash: \w+)?\s+/i, '')
|
168
|
+
text.gsub!(/^-----BEGIN PGP SIGNATURE-----$[\s\S]+^-----END PGP SIGNATURE-----/, '')
|
169
|
+
|
170
|
+
# remove unsubscribe links
|
171
|
+
text.gsub!(/^Unsubscribe: .+@.+(\n.+http:.+)?\s*\z/i, '')
|
172
|
+
|
173
|
+
# remove alias-style quotes marker
|
174
|
+
text.gsub!(/^.*>{5} "[^"\n]+" == .+ writes:/, '')
|
175
|
+
|
176
|
+
# change enclosed-style quotes format
|
177
|
+
text.gsub!(/^>>> ?(.+) ?>>>$\n([\s\S]+?)\n^<<< ?\1 ?<<<$/) {
|
178
|
+
::Regexp.last_match(2).gsub(/^/, '> ')
|
179
|
+
}
|
180
|
+
text.gsub!(/^>{4,}[[:blank:]]*$\n([\s\S]+?)\n^<{4,}[[:blank:]]*$/) {
|
181
|
+
::Regexp.last_match(1).gsub(/^/, '> ')
|
182
|
+
}
|
183
|
+
|
184
|
+
# fix all quotes formats
|
185
|
+
text.gsub!(/^((?:[[:blank:]]*[[:alpha:]]*[>|])+)/) {
|
186
|
+
::Regexp.last_match(1).gsub(/([[:alpha:]]+>|\|)/, '>')
|
187
|
+
}
|
188
|
+
|
189
|
+
# fix embedded email markers that might span over multiple lines
|
190
|
+
(
|
191
|
+
EmbeddedEmailMatcher::ON_DATE_SOMEONE_WROTE_REGEXES +
|
192
|
+
EmbeddedEmailMatcher::SOMEONE_WROTE_ON_DATE_REGEXES +
|
193
|
+
EmbeddedEmailMatcher::DATE_SOMEONE_WROTE_REGEXES +
|
194
|
+
[EmbeddedEmailMatcher::DATE_SOMEONE_EMAIL_REGEX]
|
195
|
+
).each do |r|
|
196
|
+
text.gsub!(r) do |m|
|
197
|
+
m.count("\n") > 4 ? m : m.gsub(/\n+[[:space:]]*/, ' ')
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
# remove leading/trailing whitespaces
|
202
|
+
text.strip!
|
203
|
+
end
|
204
|
+
|
205
|
+
def compute_elided(text, lines)
|
206
|
+
elided = []
|
207
|
+
|
208
|
+
t = 0
|
209
|
+
l = 0
|
210
|
+
|
211
|
+
while t < text.size
|
212
|
+
while l < lines.size && text[t] == lines[l]
|
213
|
+
t += 1
|
214
|
+
l += 1
|
215
|
+
end
|
216
|
+
elided << text[t]
|
217
|
+
t += 1
|
218
|
+
end
|
219
|
+
|
220
|
+
elided.join("\n").strip
|
221
|
+
end
|
222
|
+
|
223
|
+
def is_reply_at_end?(pattern)
|
224
|
+
pattern =~ /^b[^t]+t[et]*$/
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/runger_email_reply_trimmer/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'runger_email_reply_trimmer'
|
7
|
+
s.version = RungerEmailReplyTrimmer::VERSION
|
8
|
+
|
9
|
+
s.summary = 'Library to trim replies from plain text email.'
|
10
|
+
s.description = 'RungerEmailReplyTrimmer is a library to trim replies from plain text email.'
|
11
|
+
|
12
|
+
s.authors = ['David Runger', 'Régis Hanol']
|
13
|
+
s.email = ['davidjrunger@gmail.com', 'regis+rubygems@hanol.fr']
|
14
|
+
|
15
|
+
s.homepage = 'https://github.com/davidrunger/runger_email_reply_trimmer'
|
16
|
+
s.license = 'MIT'
|
17
|
+
|
18
|
+
s.require_paths = ['lib']
|
19
|
+
s.files = Dir['**/*'].reject { |path| File.directory?(path) || path =~ /.*\.gem$/ }
|
20
|
+
s.metadata['rubygems_mfa_required'] = 'true'
|
21
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
This is a reply from Outlook!
|
@@ -0,0 +1 @@
|
|
1
|
+
This is a reply from Outlook!
|
@@ -0,0 +1 @@
|
|
1
|
+
This is the actual reply.
|
@@ -0,0 +1 @@
|
|
1
|
+
test
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Thank you.
|
2
|
+
|
3
|
+
Sent from Outlook Mobile<https://foo.bar>
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
On Sun, Feb 7, 2016 at 12:12 AM -0800, "Arpit Jalan" <arpit.jalan@discourse.org<mailto:arpit.jalan@discourse.org>> wrote:
|
9
|
+
|
10
|
+
Hi Some,
|
11
|
+
|
12
|
+
https://meta.discourse.org is now running on latest Discourse version!
|
13
|
+
|
14
|
+
Regards,
|
15
|
+
Arpit
|
16
|
+
|
17
|
+
On Fri, Feb 5, 2016 at 10:43 AM Arpit Jalan <arpit.jalan@discourse.org<mailto:arpit.jalan@discourse.org>> wrote:
|
18
|
+
Okay, sure!
|
19
|
+
|
20
|
+
Arpit
|
21
|
+
On Fri, 5 Feb 2016 at 10:42, Some One <foo@bar.com<mailto:foo@bar.com>> wrote:
|
22
|
+
Arpit,
|
23
|
+
Yes that sounds good.
|
24
|
+
|
25
|
+
Sent from Outlook Mobile<https://foo.bar>
|
@@ -0,0 +1 @@
|
|
1
|
+
Gruß Discourse
|
@@ -0,0 +1 @@
|
|
1
|
+
Igual que siempre (inclusive ahora), sin nada raro :/
|
@@ -0,0 +1 @@
|
|
1
|
+
This email has been forwarded from Apple Mail.
|
@@ -0,0 +1 @@
|
|
1
|
+
This email has been forwarded from Gmail.
|
File without changes
|
@@ -0,0 +1,16 @@
|
|
1
|
+
From: Some One <discuss@foo.bar<mailto:discuss@foo.bar>>
|
2
|
+
Reply-To: "For.bar" <reply+275e18486b01289e3250bebe85ef6496@members.foo.bar<mailto:reply+275e18486b01289e3250bebe85ef6496@members.foo.bar>>
|
3
|
+
Date: Monday, February 8, 2016 11:44 AM
|
4
|
+
To: Discourse <discourse@discourse.org<mailto:discourse@discourse.org>>
|
5
|
+
Subject: VIS
|
6
|
+
|
7
|
+
|
8
|
+
Here's an email with some very important stuff.
|
9
|
+
|
10
|
+
|
11
|
+
________________________________
|
12
|
+
Reply here<http://foo.bar> or hit reply from your inbox to help members by sharing your ideas.
|
13
|
+
Mute this topic<http://42.wat> to stop getting updates, we'll send you the next one.
|
14
|
+
|
15
|
+
|
16
|
+
DO NOT FORWARD THIS EMAIL!
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Da: Sally54721
|
2
|
+
Risposta: Testy McTesterson / Test
|
3
|
+
Data: giovedì 8 ottobre 2015 15:26
|
4
|
+
A: Testy McTesterson
|
5
|
+
Oggetto: Test | Issue (#3)
|
6
|
+
|
7
|
+
[@example](http://example.com/u/example)
|
8
|
+
|
9
|
+
—
|
10
|
+
Reply to this email directly or [view it on GitLab](http://git.example.com/example/Test/issues/3). {"@context":"[http://schema.org","@type":"EmailMessage","action":{"@type":"ViewAction","name":"View](http://schema.org%22,%22@type%22:%22EmailMessage%22,%22action%22:%7B%22@type%22:%22ViewAction%22,%22name%22:%22View) Issue","url":"[http://git.example.com/example/Test/issues/3"}](http://git.example.com/example/Test/issues/3%22%7D)} You're receiving this notification because you are a member of the Testy McTesterson / Test project team.
|
11
|
+
|
12
|
+
--
|
13
|
+
Questo messaggio e' stato analizzato con Libra ESVA ed e' risultato non infetto.
|
14
|
+
[Clicca qui per segnalarlo come spam.](http://esva.example.com/cgi-bin/learn-msg.cgi?id=1234567890.ABCDEF)
|
15
|
+
[Clicca qui per metterlo in blacklist](http://esva.example.com/cgi-bin/learn-msg.cgi?blacklist=1&id=1234567890.ABCDEF)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
From: Erlend Sogge Heggen <meta@discoursemail.com>
|
2
|
+
Reply-To: Erlend Sogge Heggen <meta+abcd@discoursemail.com>
|
3
|
+
Date: Wednesday, 5 April 2017 at 17:01
|
4
|
+
To: Jef <jef@bar.com>
|
5
|
+
Subject: [Discourse Meta] [PM] Discourse for Communities of Practice, educational organisation
|
6
|
+
|
7
|
+
|
8
|
+
erlend_sh<https://meta.discourse.org/u/erlend_sh> Erlend Sogge Heggen<https://meta.discourse.org/u/erlend_sh> Team
|
9
|
+
April 5
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
Hi Jef,
|
14
|
+
|
15
|
+
Is your University a legally recognised educational institution? Otherwise I'm afraid you're not eligible for this discount.
|
16
|
+
|
17
|
+
Sincerely,
|
18
|
+
|
19
|
+
Erlend
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
This email message and any attachments may contain confidential information and may be privileged. If you are not the intended recipient or otherwise not authorized to receive this message, you are prohibited to use, copy, disclose or take any action based on this email or any information contained herein. If you are not the intended recipient, please advise the sender immediately by replying to this email and permanently delete this message and any attachments from your system.
|
@@ -0,0 +1,38 @@
|
|
1
|
+
On Mon, Feb 1, 2016 at 6:32 PM, Jeff Atwood <info@discourse.org> wrote:
|
2
|
+
|
3
|
+
> This is Jeff's reply.
|
4
|
+
>
|
5
|
+
> On Mon, Feb 1, 2016 at 7:50 AM, Some One <foo@bar.com > > wrote:
|
6
|
+
>
|
7
|
+
>> Great!
|
8
|
+
>>
|
9
|
+
>> Many thanks.
|
10
|
+
>>
|
11
|
+
>> ~s
|
12
|
+
>>
|
13
|
+
>> On Mon, Feb 1, 2016 at 5:05 AM Discourse Team <team@discourse.org> wrote:
|
14
|
+
>>
|
15
|
+
>>> WAT?
|
16
|
+
>>>
|
17
|
+
>>> On Wed, Jan 27, 2016 at 10:48 PM, Some One < >>> foo@bar.com> wrote:
|
18
|
+
>>>
|
19
|
+
>>>> Hi Team,
|
20
|
+
>>>>
|
21
|
+
>>>> How is it doing?
|
22
|
+
>>>>
|
23
|
+
>>>> Some One
|
24
|
+
>>>>
|
25
|
+
>>>> On Wed, Jan 27, 2016 at 10:10 AM Discourse Team <team@discourse.org> >>>> wrote:
|
26
|
+
>>>>
|
27
|
+
>>>>> Hello :waves_hand:
|
28
|
+
>>>>>
|
29
|
+
>>>>
|
30
|
+
>>>
|
31
|
+
>
|
32
|
+
|
33
|
+
|
34
|
+
--
|
35
|
+
Some One
|
36
|
+
Community Manager
|
37
|
+
foo@bar.com
|
38
|
+
(123) 456-7890
|
@@ -0,0 +1,40 @@
|
|
1
|
+
Sent from Outlook Mobile<https://foo.bar>
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
On Sun, Feb 7, 2016 at 12:12 AM -0800, "Arpit Jalan" <arpit.jalan@discourse.org<mailto:arpit.jalan@discourse.org>> wrote:
|
7
|
+
|
8
|
+
Hi Some,
|
9
|
+
|
10
|
+
https://meta.discourse.org is now running on latest Discourse version!
|
11
|
+
|
12
|
+
Regards,
|
13
|
+
Arpit
|
14
|
+
|
15
|
+
On Fri, Feb 5, 2016 at 10:43 AM Arpit Jalan <arpit.jalan@discourse.org<mailto:arpit.jalan@discourse.org>> wrote:
|
16
|
+
Okay, sure!
|
17
|
+
|
18
|
+
Arpit
|
19
|
+
On Fri, 5 Feb 2016 at 10:42, Some One <foo@bar.com<mailto:foo@bar.com>> wrote:
|
20
|
+
Arpit,
|
21
|
+
Yes that sounds good.
|
22
|
+
|
23
|
+
Sent from Outlook Mobile<https://foo.bar>
|
24
|
+
|
25
|
+
_____________________________
|
26
|
+
From: Arpit Jalan <arpit.jalan@discourse.org<mailto:arpit.jalan@discourse.org>>
|
27
|
+
Sent: Thursday, February 4, 2016 10:05 AM
|
28
|
+
Subject: Meta Discourse update
|
29
|
+
To: Some One <foo@bar.com<mailto:foo@bar.com>>, Discourse Team <team@discourse.org<mailto:team@discourse.org>>
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
Hi Some One,
|
34
|
+
|
35
|
+
Time to update meta to the latest Discourse version!
|
36
|
+
|
37
|
+
Do you want me to take care of it?
|
38
|
+
|
39
|
+
Regards,
|
40
|
+
Arpit
|
@@ -0,0 +1,9 @@
|
|
1
|
+
At 6/16/2016 08:32 PM, you wrote:
|
2
|
+
><https://meta.discourse.org/users/codinghorror>codinghorror
|
3
|
+
><https://meta.discourse.org/users/codinghorror>Jeff Atwood co-founder
|
4
|
+
>June 17
|
5
|
+
>
|
6
|
+
>Sorry I got a little mixed up with all the incoming replies. Are you
|
7
|
+
>able to log in?
|
8
|
+
>
|
9
|
+
>Use your email address and "forgot password" if you need it reset.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
2016-10-24 15:36 GMT+02:00 Foo bar < info@foo.bar>:
|
2
|
+
|
3
|
+
> Thank you so much Erlend, very thanks!
|
4
|
+
>
|
5
|
+
> 2016-10-24 15:03 GMT+02:00 Erlend Sogge Heggen <meta@discoursemail.com>:
|
6
|
+
>
|
7
|
+
>> erlend_sh <https://meta.discourse.org/users/erlend_sh> Erlend Sogge
|
8
|
+
>> Heggen <https://meta.discourse.org/users/erlend_sh> team
|
9
|
+
>> October 24
|
10
|
+
>>
|
11
|
+
>> I received your application and I've replied with setup instructions.
|
@@ -0,0 +1 @@
|
|
1
|
+
On 8 May 2017 17:34, "Andy Jones" <Andy.Jones@jameshall.co.uk> wrote:
|
File without changes
|
@@ -0,0 +1,9 @@
|
|
1
|
+
---- On Tue, 22 Dec 2015 14:17:36 +0530 Sam Saffron<info@discourse.org> wrote ----
|
2
|
+
|
3
|
+
|
4
|
+
sam Sam Saffron co-founder
|
5
|
+
December 22
|
6
|
+
You are not using the right endpoint, go to user profile / badges, have a look at dev tools to see what it calls
|
7
|
+
There is a discrete endpoint to get all the badges a user has
|
8
|
+
|
9
|
+
To respond, reply to this email or visit the topic.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
On Thu, Jun 20, 2013 at 4:18 PM, matt2 via Discourse Meta < info@discourse.org> wrote:
|
2
|
+
|
3
|
+
> matt2 posted in 'Discourse on Ubuntu: Video Walkthrough' on Discourse Meta:
|
4
|
+
> ------------------------------
|
5
|
+
>
|
6
|
+
> Has anyone tried on AWS? a public AMI would be awesome.
|
7
|
+
> ------------------------------
|
8
|
+
>
|
9
|
+
> Please visit this link to respond:
|
10
|
+
> http://meta.discourse.org/t/discourse-on-ubuntu-video-walkthrough/7478/4
|
11
|
+
>
|
12
|
+
> To unsubscribe from these emails, visit your user preferences<http://meta.discourse.org/user_preferences>
|
13
|
+
> .
|
14
|
+
>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
2013/7/20 sam via Discourse Meta <info@discourse.org>
|
2
|
+
|
3
|
+
> sam replied to your post in 'Unable to create group' on Discourse Meta:
|
4
|
+
> ------------------------------
|
5
|
+
>
|
6
|
+
> Is this an error handling thing, if you name the group "test" and only
|
7
|
+
> place yourself in it, does it persist?
|
8
|
+
> ------------------------------
|
9
|
+
>
|
10
|
+
> To respond, reply to this email or visit
|
11
|
+
> http://meta.discourse.org/t/unable-to-create-group/8198/6 in your browser.
|
12
|
+
>
|
13
|
+
> To unsubscribe from these emails, visit your user preferences<http://meta.discourse.org/user_preferences>
|
14
|
+
> .
|
15
|
+
>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
> Op 2 feb. 2015 om 05:28 heeft VannillaSky <info@discourse.org> het volgende geschreven:
|
2
|
+
>
|
3
|
+
>
|
4
|
+
> VannillaSky
|
5
|
+
> February 2
|
6
|
+
> Solved. Going forward...
|
7
|
+
>
|
8
|
+
> To respond, reply to this email or visit https://meta.discourse.org/t/import-posts-from-facebook-group-into-discourse/6089/33 in your browser.
|
9
|
+
>
|
10
|
+
> To unsubscribe from these emails, visit your user preferences.
|