Skip to content

Commit 04ffaff

Browse files
committed
Created ImapProtocolUtil. Fixed parse attachment info. | #107.
1 parent 26cbf36 commit 04ffaff

File tree

3 files changed

+100
-18
lines changed

3 files changed

+100
-18
lines changed

FlowCrypt/src/main/java/com/flowcrypt/email/api/email/JavaEmailConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,6 @@ public class JavaEmailConstants {
4646
public static final String FOLDER_ATTRIBUTE_NO_SELECT = "\\Noselect";
4747

4848
public static final String HEADER_X_ATTACHMENT_ID = "X-Attachment-Id";
49+
public static final String HEADER_CONTENT_ID = "Content-ID";
4950
public static final String FOLDER_INBOX = "INBOX";
5051
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Business Source License 1.0 © 2017 FlowCrypt Limited ([email protected]).
3+
* Use limitations apply. See https://github.com/FlowCrypt/flowcrypt-android/blob/master/LICENSE
4+
* Contributors: DenBond7
5+
*/
6+
7+
package com.flowcrypt.email.api.email.protocol;
8+
9+
import com.sun.mail.iap.ProtocolException;
10+
import com.sun.mail.imap.IMAPFolder;
11+
import com.sun.mail.imap.protocol.BODY;
12+
import com.sun.mail.imap.protocol.IMAPProtocol;
13+
14+
import java.io.InputStream;
15+
16+
import javax.mail.MessagingException;
17+
import javax.mail.Part;
18+
19+
/**
20+
* This class describes custom realization of some IMAP futures, which not found in JavaMail implementation.
21+
*
22+
* @author Denis Bondarenko
23+
* Date: 29.09.2017
24+
* Time: 14:57
25+
26+
*/
27+
28+
public class ImapProtocolUtil {
29+
/**
30+
* Return the MIME format stream of headers for this body part.
31+
*
32+
* @param imapFolder The {@link IMAPFolder} which contains the parent message;
33+
* @param messageNumber This number will be used for fetching {@link Part} details;
34+
* @param sectionId The {@link Part} section id.
35+
* @return
36+
* @throws MessagingException
37+
*/
38+
public static InputStream getHeaderStream(IMAPFolder imapFolder, final int messageNumber, final int sectionId)
39+
throws MessagingException {
40+
41+
return (InputStream) imapFolder.doCommand(new IMAPFolder.ProtocolCommand() {
42+
public Object doCommand(IMAPProtocol imapProtocol)
43+
throws ProtocolException {
44+
45+
BODY body = imapProtocol.peekBody(messageNumber, sectionId + ".HEADER");
46+
if (body != null) {
47+
return body.getByteArrayInputStream();
48+
} else return null;
49+
}
50+
});
51+
}
52+
}

FlowCrypt/src/main/java/com/flowcrypt/email/service/EmailSyncService.java

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.flowcrypt.email.api.email.JavaEmailConstants;
2424
import com.flowcrypt.email.api.email.model.AttachmentInfo;
2525
import com.flowcrypt.email.api.email.model.OutgoingMessageInfo;
26+
import com.flowcrypt.email.api.email.protocol.ImapProtocolUtil;
2627
import com.flowcrypt.email.api.email.sync.EmailSyncManager;
2728
import com.flowcrypt.email.api.email.sync.SyncListener;
2829
import com.flowcrypt.email.database.dao.source.AccountDao;
@@ -34,6 +35,7 @@
3435
import com.sun.mail.imap.IMAPFolder;
3536

3637
import java.io.IOException;
38+
import java.io.InputStream;
3739
import java.lang.ref.WeakReference;
3840
import java.util.ArrayList;
3941
import java.util.Arrays;
@@ -49,6 +51,7 @@
4951
import javax.mail.Part;
5052
import javax.mail.internet.ContentType;
5153
import javax.mail.internet.InternetAddress;
54+
import javax.mail.internet.InternetHeaders;
5255

5356
/**
5457
* This the email synchronization service. This class is responsible for the logic of
@@ -310,18 +313,25 @@ public void onError(AccountDao accountDao, int errorType, Exception e, String ke
310313
* @param folder The local reflection of the remote folder.
311314
* @param imapFolder The folder where the new messages exist.
312315
* @param messages The new messages.
313-
* @throws MessagingException
314-
* @throws IOException
316+
* @throws MessagingException This exception meybe happen when we try to call {@code
317+
* {@link IMAPFolder#getUID(javax.mail.Message)}}
315318
*/
316319
private void updateAttachmentTable(AccountDao accountDao, com.flowcrypt.email.api.email.Folder folder,
317320
IMAPFolder imapFolder, javax.mail.Message[] messages)
318-
throws MessagingException, IOException {
321+
throws MessagingException {
319322
AttachmentDaoSource attachmentDaoSource = new AttachmentDaoSource();
320323
ArrayList<ContentValues> contentValuesList = new ArrayList<>();
321324

322325
for (javax.mail.Message message : messages) {
323-
ArrayList<AttachmentInfo> attachmentInfoList = getAttachmentsInfo(message);
324-
if (!attachmentInfoList.isEmpty()) {
326+
ArrayList<AttachmentInfo> attachmentInfoList = null;
327+
328+
try {
329+
attachmentInfoList = getAttachmentsInfoFromPart(imapFolder, message.getMessageNumber(), message);
330+
} catch (IOException e) {
331+
e.printStackTrace();
332+
}
333+
334+
if (attachmentInfoList != null && !attachmentInfoList.isEmpty()) {
325335
for (AttachmentInfo attachmentInfo : attachmentInfoList) {
326336
contentValuesList.add(AttachmentDaoSource.prepareContentValues(accountDao.getEmail(),
327337
folder.getFolderAlias(), imapFolder.getUID(message), attachmentInfo));
@@ -335,13 +345,16 @@ private void updateAttachmentTable(AccountDao accountDao, com.flowcrypt.email.ap
335345
/**
336346
* Find attachments in the {@link Part}.
337347
*
338-
* @param part The parent part.
348+
* @param imapFolder The {@link IMAPFolder} which contains the parent message;
349+
* @param messageNumber This number will be used for fetching {@link Part} details;
350+
* @param part The parent part.
339351
* @return The list of created {@link AttachmentInfo}
340352
* @throws MessagingException
341353
* @throws IOException
342354
*/
343355
@NonNull
344-
private ArrayList<AttachmentInfo> getAttachmentsInfo(Part part) throws MessagingException, IOException {
356+
private ArrayList<AttachmentInfo> getAttachmentsInfoFromPart(IMAPFolder imapFolder, int messageNumber, Part part)
357+
throws MessagingException, IOException {
345358
ArrayList<AttachmentInfo> attachmentInfoList = new ArrayList<>();
346359

347360
if (part.isMimeType(JavaEmailConstants.MIME_TYPE_MULTIPART)) {
@@ -351,19 +364,35 @@ private ArrayList<AttachmentInfo> getAttachmentsInfo(Part part) throws Messaging
351364
for (int partCount = 0; partCount < numberOfParts; partCount++) {
352365
BodyPart bodyPart = multiPart.getBodyPart(partCount);
353366
if (bodyPart.isMimeType(JavaEmailConstants.MIME_TYPE_MULTIPART)) {
354-
ArrayList<AttachmentInfo> attachmentInfoLists = getAttachmentsInfo(bodyPart);
355-
if (attachmentInfoLists.isEmpty()) {
367+
ArrayList<AttachmentInfo> attachmentInfoLists = getAttachmentsInfoFromPart(imapFolder,
368+
messageNumber, bodyPart);
369+
if (!attachmentInfoLists.isEmpty()) {
356370
attachmentInfoList.addAll(attachmentInfoLists);
357371
}
358-
} else if (Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())
359-
&& (headers = bodyPart.getHeader(JavaEmailConstants.HEADER_X_ATTACHMENT_ID)) != null
360-
&& headers.length > 0) {
361-
AttachmentInfo attachmentInfo = new AttachmentInfo();
362-
attachmentInfo.setName(bodyPart.getFileName());
363-
attachmentInfo.setEncodedSize(bodyPart.getSize());
364-
attachmentInfo.setType(new ContentType(bodyPart.getContentType()).getPrimaryType());
365-
attachmentInfo.setId(headers[0]);
366-
attachmentInfoList.add(attachmentInfo);
372+
} else if (Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())) {
373+
InputStream inputStream = ImapProtocolUtil.getHeaderStream(imapFolder, messageNumber,
374+
partCount + 1);
375+
376+
if (inputStream == null) {
377+
throw new MessagingException("Failed to fetch headers");
378+
}
379+
380+
InternetHeaders internetHeaders = new InternetHeaders(inputStream);
381+
headers = internetHeaders.getHeader(JavaEmailConstants.HEADER_CONTENT_ID);
382+
383+
if (headers == null) {
384+
//try to receive custom Gmail attachments header X-Attachment-Id
385+
headers = internetHeaders.getHeader(JavaEmailConstants.HEADER_X_ATTACHMENT_ID);
386+
}
387+
388+
if (headers != null && headers.length > 0) {
389+
AttachmentInfo attachmentInfo = new AttachmentInfo();
390+
attachmentInfo.setName(bodyPart.getFileName());
391+
attachmentInfo.setEncodedSize(bodyPart.getSize());
392+
attachmentInfo.setType(new ContentType(bodyPart.getContentType()).getPrimaryType());
393+
attachmentInfo.setId(headers[0]);
394+
attachmentInfoList.add(attachmentInfo);
395+
}
367396
}
368397
}
369398
}

0 commit comments

Comments
 (0)