mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged HEAD-BUG-FIX (5.1/Cloud) to HEAD (5.1/Cloud)
92231: Merged 5.0.N (5.0.1) to HEAD-BUG-FIX (5.1/Cloud) 91995: MNT-12925: Merged V4.2-BUG-FIX (4.2.5) to 5.0.N (5.0.1) 91709 : MNT-12896: Merged V4.2.1 (4.2.1.17) to V4.2-BUG-FIX (4.2.5) 89881: Merged DEV to PATCHES/V4.2.1 (4.2.1.16) 89858 : MNT-12584 : Files are multiplying themselves when do a move out and move in - UIDPLUS extension implemented : UID EXPUNGE command and APPENDUID and COPYUID response codes 88997,89016 : MNT-12584 : Files are multiplying themselves when do a move out and move in - UID SEARCH HEADER Message-Id implemented 88824 : MNT-12585 : All files disappear from a folder if one file is moved out + one file is deleted - greenmail-1.3-patched.jar was patched again to implement DELETED flag search. - Updated source files and diff file for greenmail-1.3-patched.jar library. 88774 : MNT-12546: Deleting a file in Share may not be reflected in IMAP Outlook 2011, then sync may create EML attachments in Share - Removed force change of UID validity as it is not required. 88585 : MNT-12518 : Outlook 2013: moving files to a folder and back to original leads to view discrepancies - Test changed according to new delete/append behavior 88360 : Merged DEV to DEV (V4.2.1-IMAP) 88280: MNT-12575: IMAP Needs to RETRY - Incremented MAX-RETRIS parameter up to 20, wrapped Timer to RetryingTransactionHelper. 88294,88343,88345 : MNT-12546: Deleting a file in Share may not be reflected in IMAP Outlook 2011, then sync may create EML attachments in Share - Fixed IMAP caching of deleted files via Share. 88291 : MNT-12518 : Outlook 2013: moving files to a folder and back to original leads to view discrepancies - Implement Outlook 2013 move shuffle as copy 90106: Merged DEV to PATCHES/V4.2.1 (4.2.1.16) 89996 : MNT-12584 : Files are multiplying themselves when do a move out and move in - Green mail source files have been updated 90109: Merged DEV to PATCHES/V4.2.1 (4.2.1.16) 90105 : MNT-12518 : Outlook 2013: moving files to a folder and back to original leads to view discrepancies - Do not use APPENDUID response code to avoid usage of cached messages in Outlook 2013 90307: Merged DEV to PATCHES/V4.2.1 (4.2.1.16) 90268,90271 : MNT-12585 : All files disappear from a folder if one file is moved out + one file is deleted - Squeeze UIDVALIDITY. Implement untagged EXPUNGE response 91371: MNT-12856 : User cannot see document in repository if content was not checked by admin from IMAP - AccessDeniedException should not break IMAP response 91708: MNT-12585 : All files disappear from a folder if one file is moved out + one file is deleted - Change reference to greenmail in the pom file. Should have been when the jar changed, however this is not used in the build used to create the artefacts. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@94859 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -197,6 +197,16 @@
|
||||
</associations>
|
||||
</aspect>
|
||||
|
||||
<aspect name="imap:messageHeaders">
|
||||
<title>IMAP Message Headers</title>
|
||||
<properties>
|
||||
<property name="imap:messageHeaders">
|
||||
<title>Message Headers</title>
|
||||
<type>d:text</type>
|
||||
<multiple>true</multiple>
|
||||
</property>
|
||||
</properties>
|
||||
</aspect>
|
||||
</aspects>
|
||||
|
||||
</model>
|
@@ -184,6 +184,11 @@
|
||||
<property name="imapServerEnabled">
|
||||
<value>${imap.server.enabled}</value>
|
||||
</property>
|
||||
<property name="messageHeadersToPersist">
|
||||
<list>
|
||||
<value>Message-Id</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Public Imap Service -->
|
||||
|
2
pom.xml
2
pom.xml
@@ -38,7 +38,7 @@
|
||||
<dependency>
|
||||
<groupId>com.icegreen</groupId>
|
||||
<artifactId>greenmail</artifactId>
|
||||
<version>1.3-alfresco-20130711</version>
|
||||
<version>1.3-alfresco-20141112</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-dbcp</groupId>
|
||||
|
@@ -66,4 +66,9 @@ public interface ImapModel
|
||||
static final QName ASPECT_IMAP_PREFERENCES = QName.createQName(IMAP_MODEL_1_0_URI, "imapPreferences");
|
||||
static final QName ASSOC_IMAP_UNSUBSCRIBED = QName.createQName(IMAP_MODEL_1_0_URI, "imapUnsubscribed");
|
||||
|
||||
static final QName ASPECT_IMAP_MESSAGE_HEADERS = QName.createQName(IMAP_MODEL_1_0_URI, "messageHeaders");
|
||||
static final QName PROP_MESSAGE_HEADERS = QName.createQName(IMAP_MODEL_1_0_URI, "messageHeaders");
|
||||
|
||||
static final String MESSAGE_HEADER_TO_PERSIST_SPLITTER = ":";
|
||||
|
||||
}
|
||||
|
@@ -49,7 +49,7 @@ public abstract class AbstractImapFolder implements MailFolder
|
||||
private List<FolderListener> listeners = new LinkedList<FolderListener>();
|
||||
|
||||
protected ServiceRegistry serviceRegistry;
|
||||
protected static int MAX_RETRIES = 1;
|
||||
protected static int MAX_RETRIES = 20;
|
||||
|
||||
|
||||
public AbstractImapFolder(ServiceRegistry serviceRegistry)
|
||||
@@ -103,7 +103,7 @@ public abstract class AbstractImapFolder implements MailFolder
|
||||
* @param uid - UID of the message
|
||||
* @param toFolder - reference to the destination folder.
|
||||
*/
|
||||
public void copyMessage(final long uid, final MailFolder toFolder) throws FolderException
|
||||
public long copyMessage(final long uid, final MailFolder toFolder) throws FolderException
|
||||
{
|
||||
AbstractImapFolder toImapMailFolder = (AbstractImapFolder) toFolder;
|
||||
|
||||
@@ -112,15 +112,14 @@ public abstract class AbstractImapFolder implements MailFolder
|
||||
throw new FolderException(AlfrescoImapFolderException.PERMISSION_DENIED);
|
||||
}
|
||||
|
||||
CommandCallback<Object> command = new CommandCallback<Object>()
|
||||
CommandCallback<Long> command = new CommandCallback<Long>()
|
||||
{
|
||||
public Object command() throws Throwable
|
||||
public Long command() throws Throwable
|
||||
{
|
||||
copyMessageInternal(uid, toFolder);
|
||||
return null;
|
||||
return copyMessageInternal(uid, toFolder);
|
||||
}
|
||||
};
|
||||
command.runFeedback();
|
||||
return command.runFeedback();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,6 +160,25 @@ public abstract class AbstractImapFolder implements MailFolder
|
||||
command.runFeedback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes messages marked with {@link Flags.Flag#DELETED}. Note that this message deletes the messages with current uid
|
||||
*/
|
||||
public void expunge(final long uid) throws FolderException
|
||||
{
|
||||
if (isReadOnly())
|
||||
{
|
||||
throw new FolderException("Can't expunge - Permission denied");
|
||||
}
|
||||
CommandCallback<Object> command = new CommandCallback<Object>()
|
||||
{
|
||||
public Object command() throws Throwable
|
||||
{
|
||||
expungeInternal(uid);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
command.runFeedback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns message by its UID.
|
||||
@@ -258,14 +276,21 @@ public abstract class AbstractImapFolder implements MailFolder
|
||||
|
||||
|
||||
/**
|
||||
* Simply returns UIDs of all messages in the folder.
|
||||
* Searches the mailbox for messages that match the given searching criteria
|
||||
*
|
||||
* @param searchTerm - not used
|
||||
* @param searchTerm - search term that contains search criteria.
|
||||
* @return UIDs of the messages
|
||||
*/
|
||||
public long[] search(SearchTerm searchTerm)
|
||||
public long[] search(final SearchTerm searchTerm)
|
||||
{
|
||||
return getMessageUids();
|
||||
CommandCallback<long[]> command = new CommandCallback<long[]>()
|
||||
{
|
||||
public long[] command() throws Throwable
|
||||
{
|
||||
return searchInternal(searchTerm);
|
||||
}
|
||||
};
|
||||
return command.run();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -377,12 +402,14 @@ public abstract class AbstractImapFolder implements MailFolder
|
||||
|
||||
protected abstract long appendMessageInternal(MimeMessage message, Flags flags, Date internalDate) throws Exception;
|
||||
|
||||
protected abstract void copyMessageInternal(long uid, MailFolder toFolder) throws Exception;
|
||||
protected abstract long copyMessageInternal(long uid, MailFolder toFolder) throws Exception;
|
||||
|
||||
protected abstract void deleteAllMessagesInternal() throws Exception;
|
||||
|
||||
protected abstract void expungeInternal() throws Exception;
|
||||
|
||||
protected abstract void expungeInternal(long uid) throws Exception;
|
||||
|
||||
protected abstract SimpleStoredMessage getMessageInternal(long uid) throws Exception;
|
||||
|
||||
protected abstract List<SimpleStoredMessage> getMessagesInternal();
|
||||
@@ -393,6 +420,8 @@ public abstract class AbstractImapFolder implements MailFolder
|
||||
|
||||
protected abstract void replaceFlagsInternal(Flags flags, long uid, FolderListener silentListener, boolean addUid) throws Exception;
|
||||
|
||||
protected abstract long[] searchInternal(SearchTerm searchTerm);
|
||||
|
||||
protected abstract void setFlagsInternal(Flags flags, boolean value, long uid, FolderListener silentListener, boolean addUid) throws Exception;
|
||||
|
||||
protected abstract class CommandCallback<T>
|
||||
|
@@ -23,6 +23,7 @@ import static org.alfresco.repo.imap.AlfrescoImapConst.X_ALF_NODEREF_ID;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
@@ -31,6 +32,7 @@ import javax.mail.MessagingException;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import org.alfresco.model.ImapModel;
|
||||
import org.alfresco.repo.imap.ImapService.EmailBodyFormat;
|
||||
import org.alfresco.repo.template.TemplateNode;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
@@ -38,6 +40,7 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransacti
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
@@ -119,6 +122,31 @@ public abstract class AbstractMimeMessage extends MimeMessage
|
||||
// Optional headers for further implementation of multiple Alfresco server support.
|
||||
setHeader(X_ALF_NODEREF_ID, messageFileInfo.getNodeRef().getId());
|
||||
// setHeader(X_ALF_SERVER_UID, imapService.getAlfrescoServerUID());
|
||||
|
||||
setPersistedHeaders();
|
||||
}
|
||||
|
||||
private void setPersistedHeaders() throws MessagingException
|
||||
{
|
||||
NodeService nodeService = serviceRegistry.getNodeService();
|
||||
if (nodeService.hasAspect(messageFileInfo.getNodeRef(), ImapModel.ASPECT_IMAP_MESSAGE_HEADERS))
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> messageHeaders = (List<String>)nodeService.getProperty(messageFileInfo.getNodeRef(), ImapModel.PROP_MESSAGE_HEADERS);
|
||||
|
||||
if (messageHeaders == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (String header : messageHeaders)
|
||||
{
|
||||
String headerValue = header.substring(header.indexOf(ImapModel.MESSAGE_HEADER_TO_PERSIST_SPLITTER) + 1);
|
||||
String headerName = header.substring(0, header.indexOf(ImapModel.MESSAGE_HEADER_TO_PERSIST_SPLITTER));
|
||||
|
||||
setHeader(headerName, headerValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -21,6 +21,7 @@ package org.alfresco.repo.imap;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
@@ -33,21 +34,23 @@ import javax.mail.Flags;
|
||||
import javax.mail.Flags.Flag;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.search.SearchTerm;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.ImapModel;
|
||||
import org.alfresco.repo.imap.AlfrescoImapConst.ImapViewMode;
|
||||
import org.alfresco.repo.imap.ImapService.FolderStatus;
|
||||
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.model.FileExistsException;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.model.FileNotFoundException;
|
||||
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.security.AccessStatus;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.FileFilterMode;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.alfresco.util.Utf7;
|
||||
@@ -284,8 +287,6 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
|
||||
}
|
||||
|
||||
protected FolderStatus getFolderStatus()
|
||||
{
|
||||
if (this.folderStatus == null)
|
||||
{
|
||||
CommandCallback<FolderStatus> command = new CommandCallback<FolderStatus>()
|
||||
{
|
||||
@@ -294,9 +295,7 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
|
||||
return imapService.getFolderStatus(userName, folderInfo.getNodeRef(), viewMode);
|
||||
}
|
||||
};
|
||||
this.folderStatus = command.run();
|
||||
}
|
||||
return this.folderStatus;
|
||||
return this.folderStatus = command.run();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,13 +314,9 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
|
||||
{
|
||||
long uid;
|
||||
NodeRef sourceNodeRef = extractNodeRef(message);
|
||||
if (isMoveOperation(sourceNodeRef))
|
||||
if (sourceNodeRef != null)
|
||||
{
|
||||
uid = copyOrmoveNode(this.folderInfo, message, flags, sourceNodeRef, true);
|
||||
}
|
||||
else if (sourceNodeRef != null)
|
||||
{
|
||||
uid = copyOrmoveNode(this.folderInfo, message, flags, sourceNodeRef, false);
|
||||
uid = copyOrMoveNode(this.folderInfo, message, flags, sourceNodeRef, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -345,24 +340,33 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private long copyOrmoveNode(FileInfo folderInfo, MimeMessage message, Flags flags, NodeRef sourceNodeRef, boolean move)
|
||||
private long copyOrMoveNode(FileInfo folderInfo, MimeMessage message, Flags flags, NodeRef sourceNodeRef, boolean move)
|
||||
throws FileExistsException, FileNotFoundException
|
||||
{
|
||||
FileFolderService fileFolderService = serviceRegistry.getFileFolderService();
|
||||
FileFilterMode.setClient(FileFilterMode.Client.imap);
|
||||
fileFolderService.setHidden(sourceNodeRef, false);
|
||||
FileInfo messageFile = null;
|
||||
if (move)
|
||||
{
|
||||
fileFolderService.setHidden(sourceNodeRef, false);
|
||||
messageFile = fileFolderService.move(sourceNodeRef, folderInfo.getNodeRef(), null);
|
||||
}
|
||||
else
|
||||
{
|
||||
messageFile = fileFolderService.copy(sourceNodeRef, folderInfo.getNodeRef(), null);
|
||||
NodeRef newNodeRef = serviceRegistry.getCopyService().copyAndRename(sourceNodeRef, folderInfo.getNodeRef(), ContentModel.ASSOC_CONTAINS, null, false);
|
||||
fileFolderService.setHidden(newNodeRef, false);
|
||||
messageFile = fileFolderService.getFileInfo(newNodeRef);
|
||||
}
|
||||
final long newMessageUid = (Long) messageFile.getProperties().get(ContentModel.PROP_NODE_DBID);
|
||||
imapService.setFlag(messageFile, Flag.RECENT, true);
|
||||
|
||||
imapService.persistMessageHeaders(messageFile.getNodeRef(), message);
|
||||
|
||||
Flags newFlags = new Flags(flags);
|
||||
newFlags.add(Flag.RECENT);
|
||||
|
||||
imapService.setFlags(messageFile, newFlags, true);
|
||||
imapService.setFlag(messageFile, Flag.DELETED, false);
|
||||
|
||||
return newMessageUid;
|
||||
}
|
||||
|
||||
@@ -472,7 +476,7 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
|
||||
* @throws FileExistsException
|
||||
*/
|
||||
@Override
|
||||
protected void copyMessageInternal(
|
||||
protected long copyMessageInternal(
|
||||
long uid, MailFolder toFolder)
|
||||
throws MessagingException, FileExistsException, FileNotFoundException, IOException
|
||||
{
|
||||
@@ -486,13 +490,14 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
|
||||
{
|
||||
//Generate body of message
|
||||
MimeMessage newMessage = new ImapModelMessage(sourceMessageFileInfo, serviceRegistry, true);
|
||||
toImapMailFolder.appendMessageInternal(newMessage, imapService.getFlags(sourceMessageFileInfo), new Date());
|
||||
return toImapMailFolder.appendMessageInternal(newMessage, imapService.getFlags(sourceMessageFileInfo), new Date());
|
||||
}
|
||||
else
|
||||
{
|
||||
String fileName = (String) serviceRegistry.getNodeService().getProperty(sourceMessageFileInfo.getNodeRef(), ContentModel.PROP_NAME);
|
||||
String newFileName = imapService.generateUniqueFilename(destFolderNodeRef, fileName);
|
||||
serviceRegistry.getFileFolderService().copy(sourceMessageFileInfo.getNodeRef(), destFolderNodeRef, newFileName);
|
||||
FileInfo messageFileInfo = serviceRegistry.getFileFolderService().copy(sourceMessageFileInfo.getNodeRef(), destFolderNodeRef, newFileName);
|
||||
return (Long)messageFileInfo.getProperties().get(ContentModel.PROP_NODE_DBID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,6 +537,22 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes messages marked with {@link Flags.Flag#DELETED}. Note that this message deletes the message with current uid
|
||||
*/
|
||||
@Override
|
||||
protected void expungeInternal(long uid) throws Exception
|
||||
{
|
||||
if (isReadOnly())
|
||||
{
|
||||
throw new FolderException("Can't expunge - Permission denied");
|
||||
}
|
||||
|
||||
FileInfo messageFileInfo = searchMails().get(uid);
|
||||
|
||||
imapService.expungeMessage(messageFileInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MSN number of the first unseen message.
|
||||
*
|
||||
@@ -630,7 +651,7 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
|
||||
{
|
||||
try
|
||||
{
|
||||
result.add(imapService.createImapMessage(fileInfo, false));
|
||||
result.add(imapService.createImapMessage(fileInfo, true));
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("[convertToMessages] Message added: " + fileInfo.getName());
|
||||
@@ -744,8 +765,18 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
|
||||
return null;
|
||||
}
|
||||
};
|
||||
try
|
||||
{
|
||||
command.run();
|
||||
}
|
||||
catch (AccessDeniedException ade)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Access denied to reset RECENT FLAG");
|
||||
}
|
||||
}
|
||||
}
|
||||
return recent;
|
||||
}
|
||||
|
||||
@@ -769,7 +800,7 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
|
||||
@Override
|
||||
public long getUidValidity()
|
||||
{
|
||||
return getFolderStatus().uidValidity + mountPointId;
|
||||
return getFolderStatus().uidValidity / 1000L + mountPointId;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -812,6 +843,24 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
|
||||
notifyFlagUpdate(msn, flags, uidNotification, silentListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long[] searchInternal(SearchTerm searchTerm)
|
||||
{
|
||||
List<SimpleStoredMessage> messages = getMessages();
|
||||
long[] result = new long[messages.size()];
|
||||
int i = 0;
|
||||
|
||||
for (SimpleStoredMessage message : messages)
|
||||
{
|
||||
if (searchTerm.match(message.getMimeMessage()))
|
||||
{
|
||||
result[i] = message.getUid();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return Arrays.copyOfRange(result, 0, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets flags for the message with the given UID. If {@code addUid} is set to {@code true}
|
||||
* {@link FolderListener} objects defined for this folder will be notified.
|
||||
|
@@ -311,6 +311,8 @@ public interface ImapService
|
||||
|
||||
public String generateUniqueFilename(NodeRef destFolderNodeRef, String fileName);
|
||||
|
||||
public void persistMessageHeaders(NodeRef nodeRef, MimeMessage message);
|
||||
|
||||
static class FolderStatus
|
||||
{
|
||||
public final int messageCount;
|
||||
|
@@ -22,10 +22,12 @@ import static org.alfresco.repo.imap.AlfrescoImapConst.DICTIONARY_TEMPLATE_PREFI
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -40,6 +42,7 @@ import java.util.TreeMap;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import javax.mail.Flags;
|
||||
import javax.mail.Header;
|
||||
import javax.mail.Flags.Flag;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.AddressException;
|
||||
@@ -166,6 +169,8 @@ public class ImapServiceImpl implements ImapService, OnRestoreNodePolicy, OnCrea
|
||||
|
||||
private boolean imapServerEnabled = false;
|
||||
|
||||
private List<String> messageHeadersToPersist = Collections.<String>emptyList();
|
||||
|
||||
static
|
||||
{
|
||||
qNameToFlag = new HashMap<QName, Flags.Flag>();
|
||||
@@ -343,6 +348,11 @@ public class ImapServiceImpl implements ImapService, OnRestoreNodePolicy, OnCrea
|
||||
this.imapServerEnabled = enabled;
|
||||
}
|
||||
|
||||
public void setMessageHeadersToPersist(List<String> headers)
|
||||
{
|
||||
this.messageHeadersToPersist = headers;
|
||||
}
|
||||
|
||||
public boolean getImapServerEnabled()
|
||||
{
|
||||
return this.imapServerEnabled;
|
||||
@@ -573,6 +583,11 @@ public class ImapServiceImpl implements ImapService, OnRestoreNodePolicy, OnCrea
|
||||
{
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
return serviceRegistry.getTransactionService().getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
// Ignore if it is NOT hidden: the shuffle may have finished; the operation may have failed
|
||||
if (!nodeService.exists(nodeRef) || !fileFolderService.isHidden(nodeRef))
|
||||
@@ -589,8 +604,11 @@ public class ImapServiceImpl implements ImapService, OnRestoreNodePolicy, OnCrea
|
||||
|
||||
// This is the transaction-aware service
|
||||
fileFolderService.delete(nodeRef);
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
try
|
||||
{
|
||||
@@ -2030,6 +2048,50 @@ public class ImapServiceImpl implements ImapService, OnRestoreNodePolicy, OnCrea
|
||||
return fileName;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void persistMessageHeaders(NodeRef messageRef, MimeMessage message)
|
||||
{
|
||||
try
|
||||
{
|
||||
Enumeration<Header> headers = message.getAllHeaders();
|
||||
List<String> messaheHeadersProperties = new ArrayList<String>();
|
||||
while(headers.hasMoreElements())
|
||||
{
|
||||
Header header = headers.nextElement();
|
||||
if (isPersistableHeader(header))
|
||||
{
|
||||
messaheHeadersProperties.add(header.getName() + ImapModel.MESSAGE_HEADER_TO_PERSIST_SPLITTER + header.getValue());
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("[persistHeaders] Persisting Header " + header.getName() + " : " + header.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
|
||||
props.put(ImapModel.PROP_MESSAGE_HEADERS, (Serializable)messaheHeadersProperties);
|
||||
|
||||
serviceRegistry.getNodeService().addAspect(messageRef, ImapModel.ASPECT_IMAP_MESSAGE_HEADERS, props);
|
||||
}
|
||||
catch(MessagingException me)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPersistableHeader(Header header)
|
||||
{
|
||||
for (String headerToPersist : messageHeadersToPersist)
|
||||
{
|
||||
if (headerToPersist.equalsIgnoreCase(header.getName()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static class CacheItem
|
||||
{
|
||||
private Date modified;
|
||||
|
@@ -54,6 +54,7 @@ import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.model.FileNotFoundException;
|
||||
import org.alfresco.service.cmr.repository.AssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
@@ -912,13 +913,18 @@ public class ImapServiceImplTest extends TestCase
|
||||
AlfrescoImapFolder destinationMailbox = imapService.getOrCreateMailbox(poweredUser, destinationPath, true, false);
|
||||
destinationMailbox.appendMessage(origMessage.getMimeMessage(), flags, null);
|
||||
|
||||
// Check the destination has the original file and only this file
|
||||
FileInfo movedNode = fileFolderService.getFileInfo(origFile.getNodeRef());
|
||||
assertNotNull("The file should exist.", movedNode);
|
||||
assertEquals("The file name should not change.", fileName, movedNode.getName());
|
||||
NodeRef newParentNodeRef = nodeService.getPrimaryParent(origFile.getNodeRef()).getParentRef();
|
||||
assertEquals("The parent should change to destination.", destinationNode.getNodeRef(), newParentNodeRef);
|
||||
// original message should be deleted or about to
|
||||
assertTrue(!nodeService.exists(origFile.getNodeRef()) || imapService.getFlags(origFile).contains(Flags.Flag.DELETED));
|
||||
|
||||
// new file should be in destination
|
||||
assertEquals("There should be only one node in the destination folder", 1, nodeService.getChildAssocs(destinationNode.getNodeRef()).size());
|
||||
NodeRef newNodeRef = nodeService.getChildAssocs(destinationNode.getNodeRef()).get(0).getChildRef();
|
||||
FileInfo newNodeFileInfo = fileFolderService.getFileInfo(newNodeRef);
|
||||
assertEquals("The file name should not change.", fileName, newNodeFileInfo.getName());
|
||||
ContentReader reader = contentService.getReader(newNodeRef, ContentModel.PROP_CONTENT);
|
||||
String contentString = reader.getContentString();
|
||||
// new file content should be the same as original one
|
||||
assertEquals(contentString, nodeContent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user