Browse code

[mapi] BM-15002 Fix: read forward as attachment email in public folder

David Phan authored on 01/07/2019 13:44:31 • Nicolas Lascombes committed on 09/09/2019 08:27:19
Showing 4 changed files
... ...
@@ -27,6 +27,7 @@ Require-Bundle: net.bluemind.authentication.api;bundle-version="1.0.0";visibilit
27 27
  net.bluemind.role.service,
28 28
  net.bluemind.role.api,
29 29
  net.bluemind.core.container.service,
30
- net.bluemind.system.api
30
+ net.bluemind.system.api,
31
+ net.bluemind.directory.hollow.datamodel.consumer
31 32
 Export-Package: net.bluemind.authentication.service
32 33
 
... ...
@@ -260,7 +260,6 @@ public class Authentication implements IAuthentication, IInCoreAuthentication {
260 260
 
261 261
 		String domainPart = splitted.hasNext() ? splitted.next() : "global.virt";
262 262
 		boolean isStandardDomain = !domainPart.equals("global.virt");
263
-
264 263
 		ServerSideServiceProvider sp = ServerSideServiceProvider.getProvider(SecurityContext.SYSTEM);
265 264
 		IDomains domainService = sp.instance(IDomains.class);
266 265
 		ItemValue<Domain> theDomain = domainService.findByNameOrAliases(domainPart);
... ...
@@ -102,6 +102,8 @@ public class MessageBody {
102 102
 		@JsonInclude(Include.NON_NULL)
103 103
 		public DispositionType dispositionType;
104 104
 
105
+		public byte[] content;
106
+
105 107
 		public static Part create(String file, String mime, String addr) {
106 108
 			Part p = new Part();
107 109
 			p.mime = mime;
... ...
@@ -61,7 +61,9 @@ import com.google.common.collect.Lists;
61 61
 import com.google.common.collect.Multimap;
62 62
 import com.google.common.collect.MultimapBuilder;
63 63
 import com.google.common.collect.Sets;
64
+import com.google.common.io.ByteStreams;
64 65
 import com.google.common.io.CharStreams;
66
+import com.google.common.io.CountingInputStream;
65 67
 
66 68
 import net.bluemind.backend.mail.api.DispositionType;
67 69
 import net.bluemind.backend.mail.api.MessageBody;
... ...
@@ -119,65 +121,73 @@ public class BodyStreamProcessor {
119 121
 	public static CompletableFuture<MessageBodyData> processBody(Stream eml) {
120 122
 		return EZInputStreamAdapter.consume(eml, emlInput -> {
121 123
 			logger.debug("Consuming wrapped stream {}", emlInput);
122
-			long time = System.currentTimeMillis();
123
-			MessageBody mb = new MessageBody();
124
-			mb.bodyVersion = BODY_VERSION;
125
-			Message parsed = Mime4JHelper.parse(emlInput, new OffloadedBodyFactory());
126
-			String subject = parsed.getSubject();
127
-			if (subject != null) {
128
-				mb.subject = subject.replace("\u0000", "");
129
-			}
130
-			mb.date = parsed.getDate();
131
-			mb.size = (int) emlInput.getCount();
132
-			Multimap<String, String> mmapHeaders = MultimapBuilder.hashKeys().linkedListValues().build();
133
-			parsed.getHeader().forEach(field -> mmapHeaders.put(field.getName(), field.getBody()));
134
-			mb.headers = processHeaders(mmapHeaders);
135
-			mb.messageId = parsed.getMessageId();
136
-			mb.references = processReferences(mmapHeaders);
124
+			return parseBody(emlInput, false);
125
+		});
126
+	}
137 127
 
138
-			processRecipients(mb, parsed);
128
+	public static MessageBodyData parseBodyGetFullContent(CountingInputStream emlInput) {
129
+		return parseBody(emlInput, true);
130
+	}
139 131
 
140
-			if (logger.isDebugEnabled()) {
141
-				logger.debug("Got {} unique header(s)", mb.headers.size());
142
-			}
143
-			List<String> filenames = new ArrayList<>();
144
-			StringBuilder bodyTxt = new StringBuilder();
145
-			if (!parsed.isMultipart()) {
146
-				Part p = new Part();
147
-				p.mime = parsed.getMimeType();
148
-				p.address = "1";
149
-				p.size = mb.size;
150
-				mb.structure = p;
151
-				p.charset = parsed.getCharset();
152
-				p.encoding = parsed.getContentTransferEncoding();
153
-			} else {
154
-				Multipart mpBody = (Multipart) parsed.getBody();
155
-				processMultipart(mb, mpBody, filenames, bodyTxt);
156
-			}
157
-			String extractedBody = extractBody(parsed);
158
-			bodyTxt.append(extractedBody);
159
-			mb.preview = CharMatcher.whitespace()
160
-					.collapseFrom(extractedBody.substring(0, Math.min(160, extractedBody.length())), ' ');
161
-
162
-			List<String> with = new LinkedList<>();
163
-			if (parsed.getFrom() != null && !parsed.getFrom().isEmpty()) {
164
-				with.add(toString(parsed.getFrom().get(0)));
165
-			}
166
-			with.addAll(toString(parsed.getTo()));
167
-			with.addAll(toString(parsed.getCc()));
168
-
169
-			parsed.dispose();
170
-			mb.structure.size = mb.size;
171
-			time = System.currentTimeMillis() - time;
172
-			if (time > 10) {
173
-				logger.info("Body processed in {}ms.", time);
174
-			}
132
+	private static MessageBodyData parseBody(CountingInputStream emlInput, boolean fetchContent) {
133
+		long time = System.currentTimeMillis();
175 134
 
176
-			MessageBodyData bodyData = new MessageBodyData(mb, bodyTxt.toString(), filenames, with,
177
-					mapHeaders(mb.headers));
178
-			logger.debug("Processed {}", bodyData);
179
-			return bodyData;
180
-		});
135
+		MessageBody mb = new MessageBody();
136
+		mb.bodyVersion = BODY_VERSION;
137
+		Message parsed = Mime4JHelper.parse(emlInput, new OffloadedBodyFactory());
138
+		String subject = parsed.getSubject();
139
+		if (subject != null) {
140
+			mb.subject = subject.replace("\u0000", "");
141
+		}
142
+		mb.date = parsed.getDate();
143
+		mb.size = (int) emlInput.getCount();
144
+		Multimap<String, String> mmapHeaders = MultimapBuilder.hashKeys().linkedListValues().build();
145
+		parsed.getHeader().forEach(field -> mmapHeaders.put(field.getName(), field.getBody()));
146
+		mb.headers = processHeaders(mmapHeaders);
147
+		mb.messageId = parsed.getMessageId();
148
+		mb.references = processReferences(mmapHeaders);
149
+
150
+		processRecipients(mb, parsed);
151
+
152
+		if (logger.isDebugEnabled()) {
153
+			logger.debug("Got {} unique header(s)", mb.headers.size());
154
+		}
155
+		List<String> filenames = new ArrayList<>();
156
+		StringBuilder bodyTxt = new StringBuilder();
157
+		if (!parsed.isMultipart()) {
158
+			Part p = new Part();
159
+			p.mime = parsed.getMimeType();
160
+			p.address = "1";
161
+			p.size = mb.size;
162
+			mb.structure = p;
163
+			p.charset = parsed.getCharset();
164
+			p.encoding = parsed.getContentTransferEncoding();
165
+		} else {
166
+			Multipart mpBody = (Multipart) parsed.getBody();
167
+			processMultipart(mb, mpBody, filenames, bodyTxt, fetchContent);
168
+		}
169
+
170
+		String extractedBody = extractBody(parsed);
171
+		bodyTxt.append(extractedBody);
172
+		mb.preview = extractedBody.substring(0, Math.min(160, extractedBody.length()));
173
+
174
+		List<String> with = new LinkedList<>();
175
+		if (parsed.getFrom() != null && !parsed.getFrom().isEmpty()) {
176
+			with.add(toString(parsed.getFrom().get(0)));
177
+		}
178
+		with.addAll(toString(parsed.getTo()));
179
+		with.addAll(toString(parsed.getCc()));
180
+
181
+		parsed.dispose();
182
+		mb.structure.size = mb.size;
183
+		time = System.currentTimeMillis() - time;
184
+		if (time > 10) {
185
+			logger.info("Body processed in {}ms.", time);
186
+		}
187
+
188
+		MessageBodyData bodyData = new MessageBodyData(mb, bodyTxt.toString(), filenames, with, mapHeaders(mb.headers));
189
+		logger.debug("Processed {}", bodyData);
190
+		return bodyData;
181 191
 	}
182 192
 
183 193
 	private static List<String> processReferences(Multimap<String, String> mmapHeaders) {
... ...
@@ -343,20 +353,21 @@ public class BodyStreamProcessor {
343 353
 	}
344 354
 
345 355
 	private static void processMultipart(MessageBody mb, Multipart mpBody, List<String> filenames,
346
-			StringBuilder bodyTxt) {
356
+			StringBuilder bodyTxt, boolean fetchContent) {
347 357
 		Part root = new Part();
348 358
 		root.mime = "multipart/" + mpBody.getSubType();
349 359
 		root.address = "TEXT";
350 360
 		List<Entity> subParts = mpBody.getBodyParts();
351 361
 		int idx = 1;
352 362
 		for (Entity sub : subParts) {
353
-			Part child = subPart(root, idx++, sub, filenames, bodyTxt);
363
+			Part child = subPart(root, idx++, sub, filenames, bodyTxt, fetchContent);
354 364
 			root.children.add(child);
355 365
 		}
356 366
 		mb.structure = root;
357 367
 	}
358 368
 
359
-	private static Part subPart(Part parent, int i, Entity sub, List<String> filenames, StringBuilder bodyTxt) {
369
+	private static Part subPart(Part parent, int i, Entity sub, List<String> filenames, StringBuilder bodyTxt,
370
+			boolean fetchContent) {
360 371
 		String curAddr = "TEXT".equals(parent.address) ? "" + i : parent.address + "." + i;
361 372
 		Part p = new Part();
362 373
 		p.address = curAddr;
... ...
@@ -373,7 +384,7 @@ public class BodyStreamProcessor {
373 384
 			List<Entity> subParts = mult.getBodyParts();
374 385
 			int idx = 1;
375 386
 			for (Entity subsub : subParts) {
376
-				Part child = subPart(p, idx++, subsub, filenames, bodyTxt);
387
+				Part child = subPart(p, idx++, subsub, filenames, bodyTxt, fetchContent);
377 388
 				p.children.add(child);
378 389
 			}
379 390
 		} else if (sub.getBody() instanceof SingleBody) {
... ...
@@ -413,9 +424,20 @@ public class BodyStreamProcessor {
413 424
 			if ("multipart/report".equals(parent.mime) && p.dispositionType == null && p.fileName == null) {
414 425
 				handleReportPart(sub, filenames, bodyTxt, p);
415 426
 			}
427
+
428
+			if (fetchContent) {
429
+				SingleBody body = (SingleBody) sub.getBody();
430
+				try {
431
+					p.content = ByteStreams.toByteArray(body.getInputStream());
432
+				} catch (IOException e) {
433
+					logger.warn("Failed to fetch content", e.getMessage());
434
+				}
435
+			}
436
+
416 437
 		} else {
417 438
 			logger.warn("Don't know how to process {}", p.mime);
418 439
 		}
440
+
419 441
 		return p;
420 442
 	}
421 443