-
Notifications
You must be signed in to change notification settings - Fork 0
/
EmailReplyParser.cls
173 lines (153 loc) · 5.35 KB
/
EmailReplyParser.cls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/* This class is used to parse the reply of the emails */
public with sharing class EmailReplyParser {
public class EmailReplyParserException extends Exception{}
private final static String CRF = '\r\n';
private final static String NEW_LINE = '\n';
/* These are the patterns we are using to parse the reply */
private final static Pattern MULTI_QUOTE_HDR_REGEX = Pattern.compile('(?!On.*On\\s.+?wrote:)(On\\s(.+?)wrote:)');
private final static Pattern SIG_REGEX = Pattern.compile('(\u2014|--|__|-\\w)|(^Sent from my (\\w+\\s*){1,3})');
private final static Pattern QUOTED_REGEX = Pattern.compile('(>+)');
private final static Pattern QUOTE_HDR_REGEX = Pattern.compile('^:etorw.*nO');
public final String text;
private boolean foundVisible = false;
private List<Fragment> fragments = new List<Fragment>();
private Fragment fragment;
public EmailMessage(String text) {
if(String.isNotBlank(text)){
this.text = text.replace(CRF,'\n');
}else{
throw new EmailReplyParserException('Argument cannot be blank');
}
}
/* This method is use to initiate the parsing process */
public static EmailMessage read(String content) {
EmailMessage message = new EmailMessage(content);
message.read();
return message;
}
/* This method is use to get the main reply text */
public static String parseReply(String content) {
EmailMessage message = read(content);
return message.getReply();
}
public String getReply() {
String finalReply='';
List<String> lines = new List<String>();
/* we are reversing the different fragements and consider only the hidden = true ones */
for( Integer i=fragments.size(); i>0; i-- ){
Fragment fragmentObj = fragments.get(i-1);
if( !fragmentObj.isHidden() ){
finalReply = finalReply + fragmentObj.content;
}
}
System.debug('finalReply..'+finalReply);
return replyFramgment;
}
public void read() {
System.debug('In Read..'+text);
String workingText = text;
Matcher multiQuote = Pattern.compile('(?m)(?s)'+MULTI_QUOTE_HDR_REGEX.pattern())
.matcher(workingText);
if (multiQuote.find()) {
String newQuoteHeader = multiQuote.group().replace(NEW_LINE, '');
workingText = Pattern.compile('(?s)'+MULTI_QUOTE_HDR_REGEX.pattern()).matcher(workingText)
.replaceAll(newQuoteHeader);
}
List<String> splittedList = workingText.split('\n');
List<String> reverseList = new List<String>();
for( Integer i = splittedList.size(); i>0; i-- ){
String splittedStr = splittedList.get(i-1);
reverseList.add(splittedStr);
}
for(String line : reverseList){
scanLine(line);
}
finishFragment();
}
private void scanLine(String line) {
line = line.removeEnd(NEW_LINE).removeStart(NEW_LINE);
if (SIG_REGEX.matcher(line).lookingAt()) {
line = line.removeStart(NEW_LINE);
}
boolean isQuoted = QUOTED_REGEX.matcher(line).lookingAt();
if (fragment != null && String.isBlank(line.trim())) {
if (SIG_REGEX.matcher(fragment.lines.get(fragment.lines.size() - 1)).lookingAt()) {
fragment.setSignature(true);
finishFragment();
}
}
if (fragment != null &&
((fragment.isQuoted() == isQuoted) ||
(fragment.isQuoted() && (quoteHeader(line) || String.isBlank(line))))) {
fragment.lines.add(line);
}else {
finishFragment();
fragment = new Fragment(isQuoted, line);
}
}
private boolean quoteHeader(String line) {
String reversed = line.reverse();
return QUOTE_HDR_REGEX.matcher(reversed).lookingAt();
}
private void finishFragment() {
if (fragment != null) {
fragment.finish();
if (!foundVisible) {
if (fragment.isQuoted() ||
fragment.isSignature() ||
String.isBlank(fragment.getContent().trim())) {
fragment.setHidden(true);
} else {
foundVisible = true;
}
}
fragments.add(fragment);
}
fragment = null;
}
public List<Fragment> getFragments(){
return fragments;
}
/* This is the inner class that store the different fragments(Parts) of the email
ie. signature,main reply text etc
It also store the properties of the email
*/
class Fragment {
private boolean signature = false;
private boolean hidden = false;
private boolean quoted;
private String content;
private List<String> lines = new List<String>();
public Fragment(boolean quoted, String firstLine) {
this.quoted = quoted;
this.lines.add(firstLine);
}
public String getContent() {
return content;
}
public boolean isSignature() {
return signature;
}
public void setSignature(boolean signature) {
this.signature = signature;
}
public boolean isHidden() {
return hidden;
}
public void setHidden(boolean hidden) {
this.hidden = hidden;
}
public boolean isQuoted() {
return quoted;
}
public void finish() {
List<String> reverseList = new List<String>();
for(Integer i=lines.size(); i>0; i--){
String line = lines.get(i-1);
reverseList.add(line);
}
content = String.join(reverseList, '\n');
content = content.removeEnd(' ').removeStart(' '); // remove extra spaces from begining and end
}
}
}