1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.james.transport.mailets;
21
22 import org.apache.mailet.base.StringUtils;
23 import org.apache.mailet.base.GenericMailet;
24 import org.apache.mailet.Mail;
25 import org.apache.mailet.MailetException;
26
27 import javax.mail.MessagingException;
28 import javax.mail.internet.ContentType;
29
30 import java.io.BufferedReader;
31 import java.io.File;
32 import java.io.FileInputStream;
33 import java.io.FileNotFoundException;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.io.InputStreamReader;
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.regex.Pattern;
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 public class ReplaceContent extends GenericMailet {
91 private static final String PARAMETER_NAME_SUBJECT_PATTERN = "subjectPattern";
92 private static final String PARAMETER_NAME_BODY_PATTERN = "bodyPattern";
93 private static final String PARAMETER_NAME_SUBJECT_PATTERNFILE = "subjectPatternFile";
94 private static final String PARAMETER_NAME_BODY_PATTERNFILE = "bodyPatternFile";
95 private static final String PARAMETER_NAME_CHARSET = "charset";
96
97 public static final int FLAG_REPEAT = 1;
98
99 private static class ReplaceConfig {
100 private Pattern[] subjectPatterns;
101 private String[] subjectSubstitutions;
102 private Integer[] subjectFlags;
103 private Pattern[] bodyPatterns;
104 private String[] bodySubstitutions;
105 private Integer[] bodyFlags;
106 }
107
108 private String charset;
109 private int debug = 0;
110
111
112
113
114
115
116 public String getMailetInfo() {
117 return "ReplaceContent";
118 }
119
120
121
122
123
124 protected static Object[] getPattern(String line) throws MailetException {
125 String[] pieces = StringUtils.split(line, "/");
126 if (pieces.length < 3) throw new MailetException("Invalid expression: " + line);
127 int options = 0;
128
129 if (pieces[2].indexOf('i') >= 0) options += Pattern.CASE_INSENSITIVE;
130 if (pieces[2].indexOf('m') >= 0) options += Pattern.MULTILINE;
131 if (pieces[2].indexOf('s') >= 0) options += Pattern.DOTALL;
132
133 int flags = 0;
134 if (pieces[2].indexOf('r') >= 0) flags += FLAG_REPEAT;
135
136 if (pieces[1].indexOf("\\r") >= 0) pieces[1] = pieces[1].replaceAll("\\\\r", "\r");
137 if (pieces[1].indexOf("\\n") >= 0) pieces[1] = pieces[1].replaceAll("\\\\n", "\n");
138 if (pieces[1].indexOf("\\t") >= 0) pieces[1] = pieces[1].replaceAll("\\\\t", "\t");
139
140 return new Object[] {Pattern.compile(pieces[0], options), pieces[1] , new Integer(flags)};
141 }
142
143 protected static List[] getPatternsFromString(String pattern) throws MailetException {
144 pattern = pattern.trim();
145 if (pattern.length() < 2 && !pattern.startsWith("/") && !pattern.endsWith("/")) throw new MailetException("Invalid parameter value: " + PARAMETER_NAME_SUBJECT_PATTERN);
146 pattern = pattern.substring(1, pattern.length() - 1);
147 String[] patternArray = StringUtils.split(pattern, "/,/");
148
149 List patterns = new ArrayList();
150 List substitutions = new ArrayList();
151 List flags = new ArrayList();
152 for (int i = 0; i < patternArray.length; i++) {
153 Object[] o = getPattern(patternArray[i]);
154 patterns.add(o[0]);
155 substitutions.add(o[1]);
156 flags.add(o[2]);
157 }
158
159 return new List[] {patterns, substitutions, flags};
160 }
161
162 protected static List[] getPatternsFromStream(InputStream stream, String charset) throws MailetException, IOException {
163 List patterns = new ArrayList();
164 List substitutions = new ArrayList();
165 List flags = new ArrayList();
166 BufferedReader reader = new BufferedReader(charset != null ? new InputStreamReader(stream, charset) : new InputStreamReader(stream));
167
168
169 String line;
170 while ((line = reader.readLine()) != null) {
171 line = line.trim();
172 if (line.length() > 0 && !line.startsWith("#")) {
173 if (line.length() < 2 && !line.startsWith("/") && !line.endsWith("/")) throw new MailetException("Invalid expression: " + line);
174 Object[] o = getPattern(line.substring(1, line.length() - 1));
175 patterns.add(o[0]);
176 substitutions.add(o[1]);
177 flags.add(o[2]);
178 }
179 }
180 reader.close();
181 return new List[] {patterns, substitutions, flags};
182 }
183
184
185
186
187 private List[] getPatternsFromFileList(String filepar) throws MailetException, IOException {
188 List patterns = new ArrayList();
189 List substitutions = new ArrayList();
190 List flags = new ArrayList();
191 String[] files = filepar.split(",");
192 for (int i = 0; i < files.length; i++) {
193 files[i] = files[i].trim();
194 if (debug > 0) log("Loading patterns from: " + files[i]);
195 String charset = null;
196 int pc = files[i].lastIndexOf('?');
197 if (pc >= 0) {
198 charset = files[i].substring(pc + 1);
199 files[i] = files[i].substring(0, pc);
200 }
201 InputStream is = null;
202 if (files[i].startsWith("#")) is = getClass().getResourceAsStream(files[i].substring(1));
203 else {
204 File f = new File(files[i]);
205 if (f.isFile()) is = new FileInputStream(f);
206 }
207 if (is != null) {
208 List[] o = getPatternsFromStream(is, charset);
209 patterns.addAll(o[0]);
210 substitutions.addAll(o[1]);
211 flags.addAll(o[2]);
212 is.close();
213 }
214 }
215 return new List[] {patterns, substitutions, flags};
216 }
217
218 protected static String applyPatterns(Pattern[] patterns, String[] substitutions, Integer[] pflags, String text, int debug, GenericMailet logOwner) {
219 for (int i = 0; i < patterns.length; i ++) {
220 int flags = pflags[i].intValue();
221 boolean changed = false;
222 do {
223 changed = false;
224 String replaced = patterns[i].matcher(text).replaceAll(substitutions[i]);
225 if (!replaced.equals(text)) {
226 if (debug > 0) logOwner.log("Subject rule match: " + patterns[i].pattern());
227 text = replaced;
228 changed = true;
229 }
230 } while ((flags & FLAG_REPEAT) > 0 && changed);
231 }
232
233 return text;
234 }
235
236
237 public void init() throws MailetException {
238 charset = getInitParameter(PARAMETER_NAME_CHARSET);
239 debug = Integer.parseInt(getInitParameter("debug", "0"));
240 }
241
242 private ReplaceConfig initPatterns() throws MailetException {
243 try {
244 List bodyPatternsList = new ArrayList();
245 List bodySubstitutionsList = new ArrayList();
246 List bodyFlagsList = new ArrayList();
247 List subjectPatternsList = new ArrayList();
248 List subjectSubstitutionsList = new ArrayList();
249 List subjectFlagsList = new ArrayList();
250
251 String pattern = getInitParameter(PARAMETER_NAME_SUBJECT_PATTERN);
252 if (pattern != null) {
253 List[] o = getPatternsFromString(pattern);
254 subjectPatternsList.addAll(o[0]);
255 subjectSubstitutionsList.addAll(o[1]);
256 subjectFlagsList.addAll(o[2]);
257 }
258
259 pattern = getInitParameter(PARAMETER_NAME_BODY_PATTERN);
260 if (pattern != null) {
261 List[] o = getPatternsFromString(pattern);
262 bodyPatternsList.addAll(o[0]);
263 bodySubstitutionsList.addAll(o[1]);
264 bodyFlagsList.addAll(o[2]);
265 }
266
267 String filepar = getInitParameter(PARAMETER_NAME_SUBJECT_PATTERNFILE);
268 if (filepar != null) {
269 List[] o = getPatternsFromFileList(filepar);
270 subjectPatternsList.addAll(o[0]);
271 subjectSubstitutionsList.addAll(o[1]);
272 subjectFlagsList.addAll(o[2]);
273 }
274
275 filepar = getInitParameter(PARAMETER_NAME_BODY_PATTERNFILE);
276 if (filepar != null) {
277 List[] o = getPatternsFromFileList(filepar);
278 bodyPatternsList.addAll(o[0]);
279 bodySubstitutionsList.addAll(o[1]);
280 bodyFlagsList.addAll(o[2]);
281 }
282
283 ReplaceConfig rConfig = new ReplaceConfig();
284 rConfig.subjectPatterns = (Pattern[]) subjectPatternsList.toArray(new Pattern[0]);
285 rConfig.subjectSubstitutions = (String[]) subjectSubstitutionsList.toArray(new String[0]);
286 rConfig.subjectFlags = (Integer[]) subjectFlagsList.toArray(new Integer[0]);
287 rConfig.bodyPatterns = (Pattern[]) bodyPatternsList.toArray(new Pattern[0]);
288 rConfig.bodySubstitutions = (String[]) bodySubstitutionsList.toArray(new String[0]);
289 rConfig.bodyFlags = (Integer[]) bodyFlagsList.toArray(new Integer[0]);
290
291 return rConfig;
292
293 } catch (FileNotFoundException e) {
294 throw new MailetException("Failed initialization", e);
295
296 } catch (MailetException e) {
297 throw new MailetException("Failed initialization", e);
298
299 } catch (IOException e) {
300 throw new MailetException("Failed initialization", e);
301
302 }
303 }
304
305 public void service(Mail mail) throws MailetException {
306 ReplaceConfig rConfig = initPatterns();
307
308 try {
309 boolean mod = false;
310 boolean contentChanged = false;
311
312 if (rConfig.subjectPatterns != null && rConfig.subjectPatterns.length > 0) {
313 String subject = mail.getMessage().getSubject();
314 if (subject == null) subject = "";
315 subject = applyPatterns(rConfig.subjectPatterns, rConfig.subjectSubstitutions, rConfig.subjectFlags, subject, debug, this);
316 if (charset != null) mail.getMessage().setSubject(subject, charset);
317 else mail.getMessage().setSubject(subject);
318 mod = true;
319 }
320
321 if (rConfig.bodyPatterns != null && rConfig.bodyPatterns.length > 0) {
322 Object bodyObj = mail.getMessage().getContent();
323 if (bodyObj == null) bodyObj = "";
324 if (bodyObj instanceof String) {
325 String body = (String) bodyObj;
326 body = applyPatterns(rConfig.bodyPatterns, rConfig.bodySubstitutions, rConfig.bodyFlags, body, debug, this);
327 String contentType = mail.getMessage().getContentType();
328 if (charset != null) {
329 ContentType ct = new ContentType(contentType);
330 ct.setParameter("charset", charset);
331 contentType = ct.toString();
332 }
333 mail.getMessage().setContent(body, contentType);
334 mod = true;
335 contentChanged = true;
336 }
337 }
338
339 if (charset != null && !contentChanged) {
340 ContentType ct = new ContentType(mail.getMessage().getContentType());
341 ct.setParameter("charset", charset);
342 String contentType = mail.getMessage().getContentType();
343 mail.getMessage().setContent(mail.getMessage().getContent(), contentType);
344 }
345
346 if (mod) mail.getMessage().saveChanges();
347
348 } catch (MessagingException e) {
349 throw new MailetException("Error in replace", e);
350
351 } catch (IOException e) {
352 throw new MailetException("Error in replace", e);
353 }
354 }
355
356 }