mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
Merged DEV/IMAP3 to HEAD
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14654 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -414,12 +414,30 @@
|
||||
<property name="compositePropertyTypes">
|
||||
<map>
|
||||
<entry key="imap.server.mountPoints">
|
||||
<value>org.alfresco.repo.imap.config.ImapConfigMountPointsBean</value>
|
||||
</entry>
|
||||
<entry key="imap.ignore.extraction">
|
||||
<value>org.alfresco.repo.imap.config.ImapConfigBean</value>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="ImapService" class="org.alfresco.repo.management.subsystems.SubsystemProxyFactory">
|
||||
<property name="sourceApplicationContextFactory">
|
||||
<ref bean="imap" />
|
||||
</property>
|
||||
<property name="sourceBeanName">
|
||||
<value>ImapService</value>
|
||||
</property>
|
||||
<property name="interfaces">
|
||||
<list>
|
||||
<value>org.alfresco.repo.imap.ImapService</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="fileServerConfiguration" class="org.alfresco.repo.management.subsystems.SubsystemProxyFactory">
|
||||
<property name="sourceApplicationContextFactory">
|
||||
<ref bean="fileServers" />
|
||||
|
@@ -437,6 +437,10 @@
|
||||
class="org.alfresco.repo.content.transform.MailContentTransformer"
|
||||
parent="baseContentTransformer" />
|
||||
|
||||
<bean id="transformer.RFC822"
|
||||
class="org.alfresco.repo.content.transform.EMLTransformer"
|
||||
parent="baseContentTransformer" />
|
||||
|
||||
<!-- Import the ImageMagick transformer from the third party subsystem -->
|
||||
<bean id="transformer.worker.ImageMagick" class="org.alfresco.repo.management.subsystems.SubsystemProxyFactory">
|
||||
<property name="sourceApplicationContextFactory">
|
||||
|
@@ -1,40 +0,0 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
|
||||
|
||||
<beans>
|
||||
<bean id="patch.imapFolders" class="org.alfresco.repo.admin.patch.impl.ImapFoldersPatch" parent="basePatch" >
|
||||
<property name="id"><value>patch.imapFolders</value></property>
|
||||
<property name="description"><value>patch.imapFolders.description</value></property>
|
||||
<property name="fixesFromSchema"><value>0</value></property>
|
||||
<property name="fixesToSchema"><value>${version.schema}</value></property>
|
||||
<property name="targetSchema"><value>10000</value></property>
|
||||
<property name="importerBootstrap">
|
||||
<ref bean="spacesBootstrap" />
|
||||
</property>
|
||||
<property name="messageSource">
|
||||
<ref bean="bootstrapSpacesMessageSource" />
|
||||
</property>
|
||||
<property name="importerService">
|
||||
<ref bean="importerComponent" />
|
||||
</property>
|
||||
<property name="configFoldersACP"><value>alfresco/templates/imap/imap_config_space.acp</value></property>
|
||||
<property name="emailActionsACP"><value>alfresco/templates/imap/email_actions_space.acp</value></property>
|
||||
<property name="scriptsACP"><value>alfresco/templates/imap/command_processor_scripts.acp</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="patch.imapUserFolders" class="org.alfresco.repo.admin.patch.impl.ImapUsersPatch" parent="basePatch" >
|
||||
<property name="id"><value>patch.imapUserFolders</value></property>
|
||||
<property name="description"><value>patch.imapUserFolders.description</value></property>
|
||||
<property name="fixesFromSchema"><value>0</value></property>
|
||||
<property name="fixesToSchema"><value>${version.schema}</value></property>
|
||||
<property name="targetSchema"><value>10000</value></property>
|
||||
<!-- helper beans for execution -->
|
||||
<property name="messageSource">
|
||||
<ref bean="bootstrapSpacesMessageSource" />
|
||||
</property>
|
||||
<property name="importerBootstrap">
|
||||
<ref bean="spacesBootstrap" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
@@ -44,7 +44,7 @@ function processCommand()
|
||||
{
|
||||
var message = "Unknown command: " + command;
|
||||
logger.log(message);
|
||||
createEmail(message, message, message, false);
|
||||
createEmail(message, message, message);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ function processCommand()
|
||||
if (commandFolder == null)
|
||||
{
|
||||
var message = "Command Processor: wrong command=" + command;
|
||||
createEmail(message, message, message, false);
|
||||
createEmail(message, message, message);
|
||||
logger.log(message);
|
||||
return;
|
||||
}
|
||||
|
@@ -75,7 +75,17 @@ function createResponseTextHtml(nodes)
|
||||
*/
|
||||
function createContentTextHtml(nodes)
|
||||
{
|
||||
var content = "Command: " + title + "\n<br/><br/>\n";
|
||||
var content ="<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">" +
|
||||
"<html><head>" +
|
||||
"<meta http-equiv=Content-Type content=\"text/html; charset=UTF-8\">" +
|
||||
"<style type=\"text/css\">" +
|
||||
"* {font-family:Verdana,Arial,sans-serif;font-size:11px;}" +
|
||||
".links {border:1px dotted #555555;border-collapse:collapse;width:99%;}" +
|
||||
".links td {border:1px dotted #555555;padding:5px;}" +
|
||||
"</style>" +
|
||||
"</head>" +
|
||||
"<body>" +
|
||||
"<div>" + "Command: " + title + "\n<br/><br/>\n";
|
||||
content += "<table class=\"links\">\n";
|
||||
content += "<thead align=\"center\">";
|
||||
content += "<tr>";
|
||||
@@ -83,7 +93,7 @@ function createContentTextHtml(nodes)
|
||||
content += "<td>Url</td>";
|
||||
content += "<td>Download Url</td>";
|
||||
content += "</tr>";
|
||||
content += "</thead>\n"
|
||||
content += "</thead>\n" + "</div></body></html>";
|
||||
|
||||
|
||||
for (var i = 0; i < nodes.length; i++)
|
||||
@@ -133,7 +143,7 @@ function commandSearch(params)
|
||||
|
||||
if (query == null)
|
||||
{
|
||||
createEmail(errorParameter, errorParameter, errorParameter, false);
|
||||
createEmail(errorParameter, errorParameter, errorParameter);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -154,7 +164,7 @@ function commandSearch(params)
|
||||
}
|
||||
else
|
||||
{
|
||||
createEmail(errorXPathNotValid, errorXPathNotValid, errorXPathNotValid, false);
|
||||
createEmail(errorXPathNotValid, errorXPathNotValid, errorXPathNotValid);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -180,8 +190,8 @@ function commandSearch(params)
|
||||
createEmail(message, message, subject);
|
||||
return;
|
||||
}
|
||||
/*createEmail(createResponseTextHtml(nodes), createContentTextPlain(nodes), subject, true);*/
|
||||
createEmail(createContentTextHtml(nodes), createContentTextPlain(nodes), subject, false);
|
||||
/*createEmail(createContentTextPlain(nodes), createResponseTextHtml(nodes), subject);*/
|
||||
createEmail(createContentTextPlain(nodes), createContentTextHtml(nodes), subject);
|
||||
}
|
||||
/**
|
||||
* Decode subject
|
||||
@@ -224,13 +234,13 @@ function main()
|
||||
else
|
||||
{
|
||||
var message = unknownCommand + ": '" + title + "'";
|
||||
createEmail(message, message, message, false);
|
||||
createEmail(message, message, message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var message = unknownCommand + ": '" + title + "'";
|
||||
createEmail(message, message, message, false);
|
||||
createEmail(message, message, message);
|
||||
}
|
||||
|
||||
document.remove();
|
||||
|
@@ -1,9 +1,8 @@
|
||||
/**
|
||||
* Create e-mail
|
||||
* contentTextHtml (string) html content
|
||||
* contentTextPlain (string) text content
|
||||
* contentEML (string) content message
|
||||
*/
|
||||
function createEmail(contentTextHtml, contentTextPlain, subject, templateUsed)
|
||||
function createEmail(messageTXT, messageHTML, subject)
|
||||
{
|
||||
var command = document.properties["cm:title"];
|
||||
var userName = person.properties["cm:userName"];
|
||||
@@ -15,42 +14,42 @@ function createEmail(contentTextHtml, contentTextPlain, subject, templateUsed)
|
||||
return;
|
||||
}
|
||||
|
||||
var nextMessageUID = inboxFolder.properties["imap:nextMessageUID"];
|
||||
inboxFolder.properties["imap:nextMessageUID"] = nextMessageUID + 1;
|
||||
inboxFolder.save();
|
||||
|
||||
var response = inboxFolder.createNode("response" + Date.now(), "imap:imapContent");
|
||||
var response = inboxFolder.createNode("response" + Date.now() + ".eml", "cm:content");
|
||||
response.properties["imap:messageFrom"] = "command@alfresco.com";
|
||||
response.properties["imap:messageSubject"] = subject;
|
||||
response.properties["imap:messageTo"] = document.properties["cm:originator"];
|
||||
response.properties["imap:messageCc"] = "";
|
||||
response.properties["imap:messageUID"] = nextMessageUID;
|
||||
response.addAspect("imap:imapContent", null);
|
||||
|
||||
response.content = createRFC822Message("command@alfresco.com", document.properties["cm:originator"], subject, messageTXT, messageHTML);
|
||||
response.save();
|
||||
|
||||
var textBody = response.createNode("Body.txt", "imap:imapBody");
|
||||
textBody.content = contentTextPlain;
|
||||
textBody.save();
|
||||
|
||||
var htmlBody = response.createNode("Body.html", "imap:imapBody");
|
||||
if (templateUsed == true)
|
||||
{
|
||||
htmlBody.content = contentTextHtml;
|
||||
}
|
||||
else
|
||||
{
|
||||
htmlBody.content = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">" +
|
||||
"<html><head>" +
|
||||
"<meta http-equiv=Content-Type content=\"text/html; charset=UTF-8\">" +
|
||||
"<style type=\"text/css\">" +
|
||||
"* {font-family:Verdana,Arial,sans-serif;font-size:11px;}" +
|
||||
".links {border:1px dotted #555555;border-collapse:collapse;width:99%;}" +
|
||||
".links td {border:1px dotted #555555;padding:5px;}" +
|
||||
"</style>" +
|
||||
"</head>" +
|
||||
"<body>" +
|
||||
"<div>" + contentTextHtml + "</div></body></html>";
|
||||
}
|
||||
htmlBody.save();
|
||||
|
||||
function createRFC822Message(from, to, subject, textPart, htmlPart)
|
||||
{
|
||||
var id = new Number(Date.now()).toString(16);
|
||||
var boundary = "----------" + id;
|
||||
var date = new Date().toGMTString();
|
||||
var messageHeaders = "MIME-Version: 1.0\r\n" +
|
||||
"Date: " + date + "\r\n" +
|
||||
"From: " + from + "\r\n" +
|
||||
"To: " + to + "\r\n" +
|
||||
"Subject: " + subject + "\r\n" +
|
||||
"Message-ID: " + id + "\r\n" +
|
||||
"X-Priority: 3 (Normal)\r\n" +
|
||||
"Content-Type: multipart/alternative; boundary=\"" + boundary + "\"\r\n\r\n";
|
||||
var messageBody = "";
|
||||
messageBody += messageHeaders;
|
||||
messageBody += "--" + boundary + "\r\n";
|
||||
messageBody += "Content-Type: text/plain; charset=utf-8\r\n";
|
||||
//TODO Content-Transfer-Encoding
|
||||
messageBody += "\r\n";
|
||||
messageBody += textPart + "\r\n\r\n";
|
||||
messageBody += "--" + boundary + "\r\n";
|
||||
messageBody += "Content-Type: text/html; charset=utf-8\r\n";
|
||||
//TODO Content-Transfer-Encoding
|
||||
messageBody += "\r\n";
|
||||
messageBody += htmlPart + "\r\n\r\n";
|
||||
messageBody += "--" + boundary + "--\r\n\r\n";
|
||||
return messageBody;
|
||||
}
|
@@ -7,4 +7,8 @@ imap.server.info.message_body_not_found = "The message body parts are not found.
|
||||
|
||||
# Error messages. prefix 'imap.server.error'
|
||||
imap.server.error.properties_dont_exist = "Appropriate properties do not exist."
|
||||
imap.server.error.permission_denied = "Cannot create folder - Permission denied."
|
||||
imap.server.error.folder_already_exist = "Folder already exists."
|
||||
imap.server.error.mailbox_name_is_mandatory = "Mailbox name is mandatory parameter."
|
||||
imap.server.error.cannot_get_a_folder = "Cannot get a folder with name ''{0}''."
|
||||
|
||||
|
@@ -353,6 +353,9 @@
|
||||
</mimetype>
|
||||
<mimetype mimetype="image/x-dwt" display="AutoCAD Template">
|
||||
<extension>dwt</extension>
|
||||
</mimetype>
|
||||
<mimetype mimetype="message/rfc822" display="EMail">
|
||||
<extension>eml</extension>
|
||||
</mimetype>
|
||||
<mimetype mimetype="application/vnd.ms-outlook" display="Outlook MSG">
|
||||
<extension>msg</extension>
|
||||
|
@@ -19,7 +19,7 @@
|
||||
<title>IMAP Folder</title>
|
||||
<parent>cm:folder</parent>
|
||||
<properties>
|
||||
<property name="imap:subscribed">
|
||||
<property name="imap:nonSubscribed">
|
||||
<type>d:boolean</type>
|
||||
</property>
|
||||
<property name="imap:selectable">
|
||||
@@ -30,29 +30,6 @@
|
||||
</properties>
|
||||
</type>
|
||||
|
||||
<type name="imap:imapContent">
|
||||
<title>IMAP File</title>
|
||||
<parent>cm:folder</parent>
|
||||
<properties>
|
||||
<!-- Message -->
|
||||
<property name="imap:messageFrom">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
<property name="imap:messageTo">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
<property name="imap:messageCc">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
<property name="imap:messageSubject">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
</properties>
|
||||
<mandatory-aspects>
|
||||
<aspect>imap:flaggable</aspect>
|
||||
</mandatory-aspects>
|
||||
</type>
|
||||
|
||||
<type name="imap:imapAttach">
|
||||
<title>Attachment to the IMAP message</title>
|
||||
<parent>cm:content</parent>
|
||||
@@ -69,11 +46,63 @@
|
||||
</type>
|
||||
</types>
|
||||
|
||||
<aspects>
|
||||
<aspect name="imap:flaggable">
|
||||
<properties>
|
||||
<aspects>
|
||||
<aspect name="imap:imapContent">
|
||||
<title>IMAP File</title>
|
||||
<parent>imap:flaggable</parent>
|
||||
<properties>
|
||||
<!-- Message -->
|
||||
<property name="imap:messageFrom">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
<property name="imap:messageTo">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
<property name="imap:messageCc">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
<property name="imap:messageSubject">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
<property name="imap:messageId">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
<property name="imap:threadIndex">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
</properties>
|
||||
<associations>
|
||||
<association name="imap:attachment">
|
||||
<title>Attachment</title>
|
||||
<source>
|
||||
<mandatory>false</mandatory>
|
||||
<many>false</many>
|
||||
</source>
|
||||
<target>
|
||||
<class>cm:cmobject</class>
|
||||
<mandatory>false</mandatory>
|
||||
<many>true</many>
|
||||
</target>
|
||||
</association>
|
||||
<association name="imap:attachmentsFolder">
|
||||
<title>Attachments Folder</title>
|
||||
<source>
|
||||
<mandatory>false</mandatory>
|
||||
<many>false</many>
|
||||
</source>
|
||||
<target>
|
||||
<class>cm:cmobject</class>
|
||||
<mandatory>false</mandatory>
|
||||
<many>false</many>
|
||||
</target>
|
||||
</association>
|
||||
</associations>
|
||||
</aspect>
|
||||
|
||||
<aspect name="imap:flaggable">
|
||||
<properties>
|
||||
<property name="imap:flagAnswered">
|
||||
<type>d:boolean</type>
|
||||
<type>d:boolean</type>
|
||||
</property>
|
||||
<property name="imap:flagDeleted">
|
||||
<type>d:boolean</type>
|
||||
@@ -90,11 +119,10 @@
|
||||
<property name="imap:flagFlagged">
|
||||
<type>d:boolean</type>
|
||||
</property>
|
||||
|
||||
</properties>
|
||||
</aspect>
|
||||
<aspect name="imap:subscribed"/>
|
||||
<aspect name="imap:nonselectable"/>
|
||||
</aspect>
|
||||
<aspect name="imap:nonSubscribed"/>
|
||||
<aspect name="imap:nonselectable"/>
|
||||
</aspects>
|
||||
|
||||
</model>
|
@@ -1808,4 +1808,40 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="patch.imapFolders" class="org.alfresco.repo.admin.patch.impl.ImapFoldersPatch" parent="basePatch" >
|
||||
<property name="id"><value>patch.imapFolders</value></property>
|
||||
<property name="description"><value>patch.imapFolders.description</value></property>
|
||||
<property name="fixesFromSchema"><value>0</value></property>
|
||||
<property name="fixesToSchema"><value>2012</value></property>
|
||||
<property name="targetSchema"><value>2013</value></property>
|
||||
<property name="importerBootstrap">
|
||||
<ref bean="spacesBootstrap" />
|
||||
</property>
|
||||
<property name="messageSource">
|
||||
<ref bean="bootstrapSpacesMessageSource" />
|
||||
</property>
|
||||
<property name="importerService">
|
||||
<ref bean="importerComponent" />
|
||||
</property>
|
||||
<property name="configFoldersACP"><value>alfresco/templates/imap/imap_config_space.acp</value></property>
|
||||
<property name="emailActionsACP"><value>alfresco/templates/imap/email_actions_space.acp</value></property>
|
||||
<property name="scriptsACP"><value>alfresco/templates/imap/command_processor_scripts.acp</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="patch.imapUserFolders" class="org.alfresco.repo.admin.patch.impl.ImapUsersPatch" parent="basePatch" >
|
||||
<property name="id"><value>patch.imapUserFolders</value></property>
|
||||
<property name="description"><value>patch.imapUserFolders.description</value></property>
|
||||
<property name="fixesFromSchema"><value>0</value></property>
|
||||
<property name="fixesToSchema"><value>2012</value></property>
|
||||
<property name="targetSchema"><value>2013</value></property>
|
||||
<!-- helper beans for execution -->
|
||||
<property name="messageSource">
|
||||
<ref bean="bootstrapSpacesMessageSource" />
|
||||
</property>
|
||||
<property name="importerBootstrap">
|
||||
<ref bean="spacesBootstrap" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
</beans>
|
||||
|
@@ -338,14 +338,22 @@ nfs.user.mappings.default.gid=0
|
||||
# IMAP
|
||||
imap.server.enabled=false
|
||||
imap.server.port=143
|
||||
imap.server.host=localhost
|
||||
imap.server.attachments.extraction.enabled=true
|
||||
|
||||
# Default IMAP mount points
|
||||
imap.server.mountPoints=Repository_virtual,Repository_archive
|
||||
imap.server.mountPoints=Repository_virtual,Repository_archive,Repository_mixed
|
||||
imap.server.mountPoints.default.store=${spaces.store}
|
||||
imap.server.mountPoints.default.rootPath=/${spaces.company_home.childname}
|
||||
imap.server.mountPoints.default.mode=virtual
|
||||
imap.server.mountPoints.value.Repository_virtual.mode=virtual
|
||||
imap.server.mountPoints.value.Repository_archive.mode=archive
|
||||
imap.server.mountPoints.value.Repository_mixed.mode=mixed
|
||||
|
||||
# Folders that will be excluded from the automatic extraction capability
|
||||
#imap.ignore.extraction=adminInbox
|
||||
#imap.ignore.extraction.value.adminInbox.store=${spaces.store}
|
||||
#imap.ignore.extraction.value.adminInbox.rootPath=/${spaces.company_home.childname}/imap:imap_home/cm:admin/cm:INBOX
|
||||
|
||||
# Activity feed max size and max age (eg. 44640 mins = 31 days)
|
||||
activities.feed.max.size=100
|
||||
|
@@ -11,41 +11,10 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="imapHelper" class="org.alfresco.repo.imap.ImapHelper">
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
<property name="fileFolderService" ref="FileFolderService" />
|
||||
<property name="searchService" ref="SearchService" />
|
||||
<property name="namespaceService" ref="NamespaceService" />
|
||||
<property name="templateService" ref="TemplateService" />
|
||||
<property name="permissionService" ref="PermissionService" />
|
||||
<property name="dictionaryService" ref="DictionaryService" />
|
||||
<property name="preferenceService" ref="PreferenceService" />
|
||||
<property name="siteService" ref="SiteService" />
|
||||
<property name="patchService" ref="patchComponent" />
|
||||
<property name="serviceRegistry" ref="ServiceRegistry" />
|
||||
|
||||
<property name="imapConfigBeans">
|
||||
<ref bean="imap.server.mountPoints" />
|
||||
</property>
|
||||
|
||||
<property name="defaultFromAddress">
|
||||
<value>${mail.from.default}</value>
|
||||
</property>
|
||||
|
||||
<property name="webApplicationContextUrl">
|
||||
<value>${web.application.context.url}</value>
|
||||
</property>
|
||||
|
||||
<property name="imapRoot">
|
||||
<value>${spaces.store}/${spaces.company_home.childname}/${spaces.imap_home.childname}</value>
|
||||
</property>
|
||||
|
||||
<property name="repositoryTemplatePath">
|
||||
<value>${spaces.store}/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.imapConfig.childname}/${spaces.imap_templates.childname}</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="imapServer" class="org.alfresco.repo.imap.AlfrescoImapServer">
|
||||
<property name="host">
|
||||
<value>${imap.server.host}</value>
|
||||
</property>
|
||||
<property name="port">
|
||||
<value>${imap.server.port}</value>
|
||||
</property>
|
||||
@@ -58,16 +27,13 @@
|
||||
<property name="imapUserManager">
|
||||
<ref local="imapUserManager" />
|
||||
</property>
|
||||
<property name="imapHelper">
|
||||
<ref local="imapHelper" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!--The configurable list of mount points - actually a post-processed composite property! -->
|
||||
<bean id="imap.server.mountPoints" class="org.springframework.beans.factory.config.ListFactoryBean">
|
||||
<property name="sourceList">
|
||||
<list>
|
||||
<bean id="Repository_virtual" class="org.alfresco.repo.imap.config.ImapConfigBean">
|
||||
<bean id="Repository_virtual" class="org.alfresco.repo.imap.config.ImapConfigMountPointsBean">
|
||||
<property name="mode">
|
||||
<value>virtual</value>
|
||||
</property>
|
||||
@@ -78,7 +44,7 @@
|
||||
<value>/${spaces.company_home.childname}</value>
|
||||
</property>
|
||||
</bean>
|
||||
<bean id="Repository_archive" class="org.alfresco.repo.imap.config.ImapConfigBean">
|
||||
<bean id="Repository_archive" class="org.alfresco.repo.imap.config.ImapConfigMountPointsBean">
|
||||
<property name="mode">
|
||||
<value>archive</value>
|
||||
</property>
|
||||
@@ -93,17 +59,101 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!--The configurable list of folders that ignore attachment extraction - actually a post-processed composite property! -->
|
||||
<bean id="imap.ignore.extraction" class="org.springframework.beans.factory.config.ListFactoryBean">
|
||||
<property name="sourceList">
|
||||
<list>
|
||||
<bean id="ignored" class="org.alfresco.repo.imap.config.ImapConfigBean">
|
||||
<property name="store">
|
||||
<value>${spaces.store}</value>
|
||||
</property>
|
||||
<property name="rootPath">
|
||||
<value>/${spaces.company_home.childname}</value>
|
||||
</property>
|
||||
</bean>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="ImapService_transaction" class="org.springframework.transaction.interceptor.TransactionInterceptor">
|
||||
<property name="transactionManager">
|
||||
<ref bean="transactionManager"/>
|
||||
</property>
|
||||
<property name="transactionAttributes">
|
||||
<props>
|
||||
<prop key="search*">${server.transaction.mode.readOnly}</prop>
|
||||
<prop key="getFolder">${server.transaction.mode.default}</prop>
|
||||
<prop key="getFlags">${server.transaction.mode.default}</prop>
|
||||
<prop key="get*">${server.transaction.mode.readOnly}</prop>
|
||||
<prop key="*">${server.transaction.mode.default}</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="imapService" class="org.alfresco.repo.imap.ImapServiceImpl" init-method="init">
|
||||
<property name="fileFolderService">
|
||||
<ref bean="FileFolderService"/>
|
||||
</property>
|
||||
<property name="nodeService">
|
||||
<ref bean="NodeService"/>
|
||||
</property>
|
||||
<property name="serviceRegistry">
|
||||
<ref bean="ServiceRegistry"/>
|
||||
</property>
|
||||
|
||||
<property name="imapConfigMountPointsBeans">
|
||||
<ref bean="imap.server.mountPoints" />
|
||||
</property>
|
||||
<property name="ignoreExtractionFolders">
|
||||
<ref bean="imap.ignore.extraction" />
|
||||
</property>
|
||||
<property name="imapRoot">
|
||||
<value>${spaces.store}/${spaces.company_home.childname}/${spaces.imap_home.childname}</value>
|
||||
</property>
|
||||
<property name="defaultFromAddress">
|
||||
<value>${mail.from.default}</value>
|
||||
</property>
|
||||
<property name="webApplicationContextUrl">
|
||||
<value>${web.application.context.url}</value>
|
||||
</property>
|
||||
<property name="repositoryTemplatePath">
|
||||
<value>${spaces.store}/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.imapConfig.childname}/${spaces.imap_templates.childname}</value>
|
||||
</property>
|
||||
<property name="extractAttachmentsEnabled">
|
||||
<value>${imap.server.attachments.extraction.enabled}</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Public Imap Service -->
|
||||
|
||||
<bean id="ImapService" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="proxyInterfaces">
|
||||
<list>
|
||||
<value>org.alfresco.repo.imap.ImapService</value>
|
||||
</list>
|
||||
</property>
|
||||
<property name="target">
|
||||
<ref bean="imapService"/>
|
||||
</property>
|
||||
<property name="interceptorNames">
|
||||
<list>
|
||||
<idref local="ImapService_transaction"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="imapHostManager" class="org.alfresco.repo.imap.AlfrescoImapHostManager">
|
||||
<property name="serviceRegistry" ref="ServiceRegistry" />
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
<property name="fileFolderService" ref="FileFolderService" />
|
||||
<property name="imapHelper" ref="imapHelper" />
|
||||
<property name="imapService">
|
||||
<ref bean="ImapService" />
|
||||
</property>
|
||||
<property name="transactionService">
|
||||
<ref bean="transactionService" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="imapUserManager" class="org.alfresco.repo.imap.AlfrescoImapUserManager">
|
||||
<property name="imapHostManager">
|
||||
<ref local="imapHostManager" />
|
||||
</property>
|
||||
<property name="authenticationService" ref="AuthenticationService" />
|
||||
<property name="personService" ref="PersonService" />
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
|
@@ -1,4 +1,5 @@
|
||||
imap.server.enabled=false
|
||||
imap.server.host=localhost
|
||||
imap.server.port=143
|
||||
|
||||
#imap.server.web.application.context.url=http://localhost:8080/alfresco
|
||||
|
Binary file not shown.
Binary file not shown.
@@ -84,7 +84,7 @@
|
||||
<legend> Content links </legend>
|
||||
<table class="links">
|
||||
<tr>
|
||||
<td>Content folder:</td><td><a href="${contextUrl}${document.displayPath}">${contextUrl}${document.displayPath}</a></td>
|
||||
<td>Content folder:</td><td><a href="${contextUrl}/navigate/browse${document.displayPath}">${contextUrl}/navigate/browse${document.displayPath}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Content URL:</td><td><a href="${contextUrl}${document.url}">${contextUrl}${document.url}</a></td>
|
||||
@@ -101,7 +101,7 @@
|
||||
<legend> Start Workflow </legend>
|
||||
<form id="start_workflow"
|
||||
name="start_workflow"
|
||||
method="get"
|
||||
method="post"
|
||||
action="${contextUrl}/service/imap/start-workflow"
|
||||
enctype="application/x-www-form-urlencoded">
|
||||
<input type="hidden" name="alfTicket" value="${alfTicket}" />
|
||||
|
@@ -21,7 +21,7 @@ Size: ${document.size / 1024} Kb
|
||||
|
||||
CONTENT LINKS
|
||||
|
||||
Content folder: ${contextUrl}${document.displayPath}
|
||||
Content folder: ${contextUrl}/navigate/browse${document.displayPath}
|
||||
Content URL: ${contextUrl}${document.url}
|
||||
Download URL: ${contextUrl}${document.downloadUrl}
|
||||
WebDAV URL: ${contextUrl}${document.webdavUrl}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -49,6 +49,8 @@ import org.apache.commons.logging.LogFactory;
|
||||
/**
|
||||
* Concrete representation of an email message as implemented for the SubEtha mail server.
|
||||
*
|
||||
* @author Mike Shavnev
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public class SubethaEmailMessage implements EmailMessage
|
||||
|
@@ -35,14 +35,18 @@ public interface ImapModel
|
||||
{
|
||||
static final String IMAP_MODEL_1_0_URI = "http://www.alfresco.org/model/imap/1.0";
|
||||
|
||||
static final QName ASPECT_IMAP_FOLDER_SUBSCRIBED = QName.createQName(IMAP_MODEL_1_0_URI, "subscribed");
|
||||
static final QName ASPECT_IMAP_FOLDER_NONSUBSCRIBED = QName.createQName(IMAP_MODEL_1_0_URI, "nonSubscribed");
|
||||
static final QName ASPECT_IMAP_FOLDER_NONSELECTABLE = QName.createQName(IMAP_MODEL_1_0_URI, "nonselectable");
|
||||
|
||||
static final QName TYPE_IMAP_CONTENT = QName.createQName(IMAP_MODEL_1_0_URI, "imapContent");
|
||||
static final QName ASPECT_IMAP_CONTENT = QName.createQName(IMAP_MODEL_1_0_URI, "imapContent");
|
||||
static final QName PROP_MESSAGE_FROM = QName.createQName(IMAP_MODEL_1_0_URI, "messageFrom");
|
||||
static final QName PROP_MESSAGE_TO = QName.createQName(IMAP_MODEL_1_0_URI, "messageTo");
|
||||
static final QName PROP_MESSAGE_CC = QName.createQName(IMAP_MODEL_1_0_URI, "messageCc");
|
||||
static final QName PROP_MESSAGE_SUBJECT = QName.createQName(IMAP_MODEL_1_0_URI, "messageSubject");
|
||||
static final QName PROP_MESSAGE_ID = QName.createQName(IMAP_MODEL_1_0_URI, "messageId");
|
||||
static final QName PROP_THREAD_INDEX = QName.createQName(IMAP_MODEL_1_0_URI, "threadIndex");
|
||||
static final QName ASSOC_IMAP_ATTACHMENT = QName.createQName(IMAP_MODEL_1_0_URI, "attachment");
|
||||
static final QName ASSOC_IMAP_ATTACHMENTS_FOLDER = QName.createQName(IMAP_MODEL_1_0_URI, "attachmentsFolder");
|
||||
|
||||
static final QName ASPECT_FLAGGABLE = QName.createQName(IMAP_MODEL_1_0_URI, "flaggable");
|
||||
static final QName PROP_FLAG_ANSWERED = QName.createQName(IMAP_MODEL_1_0_URI, "flagAnswered");
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@@ -41,6 +41,7 @@ import org.alfresco.service.cmr.view.ImporterService;
|
||||
import org.alfresco.service.cmr.view.Location;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
/**
|
||||
* Builds folders tree necessary for IMAP functionality and imports email action scripts.
|
||||
*
|
||||
@@ -176,6 +177,7 @@ public class ImapFoldersPatch extends AbstractPatch
|
||||
throw new PatchException("XPath returned too many results: \n" + " root: " + storeRootNodeRef + "\n" + " xpath: " + xpath + "\n" + " results: " + nodeRefs);
|
||||
}
|
||||
this.dictionaryNodeRef = nodeRefs.get(0);
|
||||
|
||||
sb.append("/").append(scriptsChildName);
|
||||
xpath = sb.toString();
|
||||
nodeRefs = searchService.selectNodes(storeRootNodeRef, xpath, null, namespaceService, false);
|
||||
@@ -188,6 +190,7 @@ public class ImapFoldersPatch extends AbstractPatch
|
||||
throw new PatchException("XPath returned too many results: \n" + " root: " + storeRootNodeRef + "\n" + " xpath: " + xpath + "\n" + " results: " + nodeRefs);
|
||||
}
|
||||
this.scriptsNodeRef = nodeRefs.get(0);
|
||||
|
||||
// get the ImapConfig node
|
||||
sb.delete((sb.length() - (scriptsChildName.length() + 1)), sb.length());
|
||||
sb.append("/").append(imapConfigChildName);
|
||||
|
@@ -79,6 +79,7 @@ public class MimetypeMap implements MimetypeService
|
||||
public static final String MIMETYPE_ATOM = "application/atom+xml";
|
||||
public static final String MIMETYPE_RSS = "application/rss+xml";
|
||||
public static final String MIMETYPE_RFC822 = "message/rfc822";
|
||||
public static final String MIMETYPE_OUTLOOK_MSG = "application/vnd.ms-outlook";
|
||||
// Open Document
|
||||
public static final String MIMETYPE_OPENDOCUMENT_TEXT = "application/vnd.oasis.opendocument.text";
|
||||
public static final String MIMETYPE_OPENDOCUMENT_TEXT_TEMPLATE = "application/vnd.oasis.opendocument.text-template";
|
||||
|
118
source/java/org/alfresco/repo/content/transform/EMLTransformer.java
Executable file
118
source/java/org/alfresco/repo/content/transform/EMLTransformer.java
Executable file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.content.transform;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.Part;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.TransformationOptions;
|
||||
|
||||
public class EMLTransformer extends AbstractContentTransformer2
|
||||
{
|
||||
public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
if (!MimetypeMap.MIMETYPE_RFC822.equals(sourceMimetype) || !MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(targetMimetype))
|
||||
{
|
||||
// only support RFC822 -> TEXT
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void transformInternal(ContentReader reader, ContentWriter writer, TransformationOptions options) throws Exception
|
||||
{
|
||||
InputStream is = null;
|
||||
try
|
||||
{
|
||||
is = reader.getContentInputStream();
|
||||
|
||||
MimeMessage mimeMessage = new MimeMessage(Session.getDefaultInstance(new Properties()), is);
|
||||
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
Object content = mimeMessage.getContent();
|
||||
if (content instanceof Multipart)
|
||||
{
|
||||
Multipart multipart = (Multipart) content;
|
||||
Part part = multipart.getBodyPart(0);
|
||||
|
||||
if (part.getContent() instanceof Multipart)
|
||||
{
|
||||
multipart = (Multipart) part.getContent();
|
||||
for (int i = 0, n = multipart.getCount(); i < n; i++)
|
||||
{
|
||||
part = multipart.getBodyPart(i);
|
||||
if (part.getContentType().contains("text"))
|
||||
{
|
||||
sb.append(part.getContent().toString()).append("\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else if (part.getContentType().contains("text"))
|
||||
{
|
||||
sb.append(part.getContent().toString());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(content.toString());
|
||||
}
|
||||
|
||||
writer.putContent(sb.toString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (is != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
is.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -56,7 +56,7 @@ public class MailContentTransformer extends AbstractContentTransformer2
|
||||
*/
|
||||
public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
if (!MimetypeMap.MIMETYPE_RFC822.equals(sourceMimetype) ||
|
||||
if (!MimetypeMap.MIMETYPE_OUTLOOK_MSG.equals(sourceMimetype) ||
|
||||
!MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(targetMimetype))
|
||||
{
|
||||
// only support MSG -> TEXT
|
||||
|
694
source/java/org/alfresco/repo/imap/AbstractImapFolder.java
Executable file
694
source/java/org/alfresco/repo/imap/AbstractImapFolder.java
Executable file
@@ -0,0 +1,694 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.imap;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.mail.Flags;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.search.SearchTerm;
|
||||
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.icegreen.greenmail.foedus.util.MsgRangeFilter;
|
||||
import com.icegreen.greenmail.mail.MovingMessage;
|
||||
import com.icegreen.greenmail.store.FolderException;
|
||||
import com.icegreen.greenmail.store.FolderListener;
|
||||
import com.icegreen.greenmail.store.MailFolder;
|
||||
import com.icegreen.greenmail.store.SimpleStoredMessage;
|
||||
|
||||
/**
|
||||
* Implementation of greenmail MailFolder. It represents an Alfresco content folder and handles appendMessage, copyMessage, expunge (delete), getMessages, getMessage and so
|
||||
* requests.
|
||||
*
|
||||
* @author Ivan Rybnikov
|
||||
*/
|
||||
public abstract class AbstractImapFolder implements MailFolder
|
||||
{
|
||||
|
||||
private static Log logger = LogFactory.getLog(AbstractImapFolder.class);
|
||||
|
||||
private List<FolderListener> listeners = new LinkedList<FolderListener>();
|
||||
|
||||
protected ServiceRegistry serviceRegistry;
|
||||
protected static int MAX_RETRIES = 1;
|
||||
|
||||
|
||||
public AbstractImapFolder(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that checks mandatory parameter.
|
||||
* @param The parameter instance to check.
|
||||
* @param The name of the parameter.
|
||||
*/
|
||||
protected void checkParameter(Object parameter, String name)
|
||||
{
|
||||
if (parameter == null)
|
||||
{
|
||||
throw new IllegalArgumentException(name + " parameter is null.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Appends message to the folder.
|
||||
*
|
||||
* @param message - message.
|
||||
* @param flags - message flags.
|
||||
* @param internalDate - not used. Current date used instead.
|
||||
* @return
|
||||
*/
|
||||
public long appendMessage(final MimeMessage message, final Flags flags, final Date internalDate) throws FolderException
|
||||
{
|
||||
if (isReadOnly())
|
||||
{
|
||||
throw new FolderException("Can't append message - Permission denied");
|
||||
}
|
||||
|
||||
CommandCallback<Long> command = new CommandCallback<Long>()
|
||||
{
|
||||
public Long command() throws Throwable
|
||||
{
|
||||
return appendMessageInternal(message, flags, internalDate);
|
||||
}
|
||||
};
|
||||
return command.runFeedback();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copies message with the given UID to the specified {@link 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
|
||||
{
|
||||
AbstractImapFolder toImapMailFolder = (AbstractImapFolder) toFolder;
|
||||
|
||||
if (toImapMailFolder.isReadOnly())
|
||||
{
|
||||
throw new FolderException("Can't create folder - Permission denied");
|
||||
}
|
||||
|
||||
CommandCallback<Object> command = new CommandCallback<Object>()
|
||||
{
|
||||
public Object command() throws Throwable
|
||||
{
|
||||
copyMessageInternal(uid, toFolder);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
command.runFeedback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks all messages in the folder as deleted using {@link Flags.Flag#DELETED} flag.
|
||||
*/
|
||||
public void deleteAllMessages() throws FolderException
|
||||
{
|
||||
CommandCallback<Object> command = new CommandCallback<Object>()
|
||||
{
|
||||
public Object command() throws Throwable
|
||||
{
|
||||
deleteAllMessagesInternal();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
command.runFeedback();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Deletes messages marked with {@link Flags.Flag#DELETED}. Note that this message deletes all messages with this flag.
|
||||
*/
|
||||
public void expunge() throws FolderException
|
||||
{
|
||||
if (isReadOnly())
|
||||
{
|
||||
throw new FolderException("Can't expunge - Permission denied");
|
||||
}
|
||||
CommandCallback<Object> command = new CommandCallback<Object>()
|
||||
{
|
||||
public Object command() throws Throwable
|
||||
{
|
||||
expungeInternal();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
command.runFeedback();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of the first unseen message.
|
||||
*
|
||||
* @return Number of the first unseen message.
|
||||
*/
|
||||
public int getFirstUnseen()
|
||||
{
|
||||
return getFirstUnseenInternal();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns full name of the folder with namespace and full path delimited with the hierarchy delimiter (see {@link AlfrescoImapConst#HIERARCHY_DELIMITER}) <p/> E.g.: <p/>
|
||||
* #mail.admin."Repository_archive.Data Dictionary.Space Templates.Software Engineering Project" <p/> This is required by GreenMail implementation.
|
||||
*/
|
||||
public String getFullName()
|
||||
{
|
||||
CommandCallback<String> command = new CommandCallback<String>()
|
||||
{
|
||||
public String command() throws Throwable
|
||||
{
|
||||
return getFullNameInternal();
|
||||
}
|
||||
};
|
||||
return command.run();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns message by its UID.
|
||||
*
|
||||
* @param uid - UID of the message.
|
||||
* @return message.
|
||||
*/
|
||||
public SimpleStoredMessage getMessage(final long uid)
|
||||
{
|
||||
CommandCallback<SimpleStoredMessage> command = new CommandCallback<SimpleStoredMessage>()
|
||||
{
|
||||
public SimpleStoredMessage command() throws Throwable
|
||||
{
|
||||
return getMessageInternal(uid);
|
||||
}
|
||||
};
|
||||
return command.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns count of the messages in the folder.
|
||||
*
|
||||
* @return Count of the messages.
|
||||
*/
|
||||
public int getMessageCount()
|
||||
{
|
||||
CommandCallback<Integer> command = new CommandCallback<Integer>()
|
||||
{
|
||||
public Integer command() throws Throwable
|
||||
{
|
||||
return getMessageCountInternal();
|
||||
}
|
||||
};
|
||||
return command.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of all messages in the folder.
|
||||
*
|
||||
* @return list of {@link SimpleStoredMessage} objects.
|
||||
*/
|
||||
public List<SimpleStoredMessage> getMessages()
|
||||
{
|
||||
CommandCallback<List<SimpleStoredMessage>> command = new CommandCallback<List<SimpleStoredMessage>>()
|
||||
{
|
||||
public List<SimpleStoredMessage> command() throws Throwable
|
||||
{
|
||||
return getMessagesInternal();
|
||||
}
|
||||
};
|
||||
return command.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of messages by filter.
|
||||
*
|
||||
* @param msgRangeFilter - {@link MsgRangeFilter} object representing filter.
|
||||
* @return list of filtered messages.
|
||||
*/
|
||||
public List<SimpleStoredMessage> getMessages(final MsgRangeFilter msgRangeFilter)
|
||||
{
|
||||
CommandCallback <List<SimpleStoredMessage>> command = new CommandCallback <List<SimpleStoredMessage>>()
|
||||
{
|
||||
public List<SimpleStoredMessage> command() throws Throwable
|
||||
{
|
||||
return getMessagesInternal(msgRangeFilter);
|
||||
}
|
||||
};
|
||||
return command.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns message sequence number in the folder by its UID.
|
||||
*
|
||||
* @param uid - message UID.
|
||||
* @return message sequence number.
|
||||
* @throws FolderException if no message with given UID.
|
||||
*/
|
||||
public int getMsn(final long uid) throws FolderException
|
||||
{
|
||||
CommandCallback<Integer> command = new CommandCallback<Integer>()
|
||||
{
|
||||
public Integer command() throws Throwable
|
||||
{
|
||||
return getMsnInternal(uid);
|
||||
}
|
||||
};
|
||||
return command.runFeedback(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns folder name.
|
||||
*
|
||||
* @return folder name.
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
CommandCallback<String> command = new CommandCallback<String>()
|
||||
{
|
||||
public String command() throws Throwable
|
||||
{
|
||||
return getNameInternal();
|
||||
}
|
||||
};
|
||||
return command.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns UIDs of all messages in the folder.
|
||||
*
|
||||
* @return UIDS of the messages.
|
||||
*/
|
||||
public long[] getMessageUids()
|
||||
{
|
||||
CommandCallback<Object> command = new CommandCallback<Object>()
|
||||
{
|
||||
public Object command() throws Throwable
|
||||
{
|
||||
return getMessageUidsInternal();
|
||||
}
|
||||
};
|
||||
return (long[])command.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of messages that have no {@link Flags.Flag#DELETED} flag set for current user.
|
||||
*
|
||||
* @return the list of non-deleted messages.
|
||||
*/
|
||||
public List<SimpleStoredMessage> getNonDeletedMessages()
|
||||
{
|
||||
CommandCallback <List<SimpleStoredMessage>> command = new CommandCallback<List<SimpleStoredMessage>>()
|
||||
{
|
||||
public List<SimpleStoredMessage> command() throws Throwable
|
||||
{
|
||||
return getNonDeletedMessagesInternal();
|
||||
}
|
||||
};
|
||||
List<SimpleStoredMessage> result = (List<SimpleStoredMessage>)command.run();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns permanent flags.
|
||||
*
|
||||
* @return {@link Flags} object containing flags.
|
||||
*/
|
||||
public Flags getPermanentFlags()
|
||||
{
|
||||
CommandCallback<Flags> command = new CommandCallback<Flags>()
|
||||
{
|
||||
public Flags command() throws Throwable
|
||||
{
|
||||
return getPermanentFlagsInternal();
|
||||
}
|
||||
};
|
||||
return command.run(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns count of messages with {@link Flags.Flag#RECENT} flag. If {@code reset} parameter is {@code true} - removes {@link Flags.Flag#RECENT} flag from the message for
|
||||
* current user.
|
||||
*
|
||||
* @param reset - if true the {@link Flags.Flag#RECENT} will be deleted for current user if exists.
|
||||
* @return returns count of recent messages.
|
||||
*/
|
||||
public int getRecentCount(final boolean reset)
|
||||
{
|
||||
CommandCallback<Integer> command = new CommandCallback<Integer>()
|
||||
{
|
||||
public Integer command() throws Throwable
|
||||
{
|
||||
return getRecentCountInternal(reset);
|
||||
}
|
||||
};
|
||||
return command.run(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns UIDNEXT value of the folder.
|
||||
*
|
||||
* @return UIDNEXT value.
|
||||
*/
|
||||
public long getUidNext()
|
||||
{
|
||||
CommandCallback<Long> command = new CommandCallback<Long>()
|
||||
{
|
||||
public Long command() throws Throwable
|
||||
{
|
||||
return getUidNextInternal();
|
||||
}
|
||||
};
|
||||
return command.run(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns UIDVALIDITY value of the folder.
|
||||
*
|
||||
* @return UIDVALIDITY value.
|
||||
*/
|
||||
public long getUidValidity()
|
||||
{
|
||||
CommandCallback<Long> command = new CommandCallback<Long>()
|
||||
{
|
||||
public Long command() throws Throwable
|
||||
{
|
||||
return getUidValidityInternal();
|
||||
}
|
||||
};
|
||||
return command.run(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns count of the messages with {@link Flags.Flag#SEEN} in the folder for the current user.
|
||||
*
|
||||
* @return Count of the unseen messages for current user.
|
||||
*/
|
||||
public int getUnseenCount()
|
||||
{
|
||||
CommandCallback<Integer> command = new CommandCallback<Integer>()
|
||||
{
|
||||
public Integer command() throws Throwable
|
||||
{
|
||||
return getUnseenCountInternal();
|
||||
}
|
||||
};
|
||||
return command.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the folder is selectable.
|
||||
*
|
||||
* @return {@code boolean}.
|
||||
*/
|
||||
public boolean isSelectable()
|
||||
{
|
||||
CommandCallback<Boolean> command = new CommandCallback<Boolean>()
|
||||
{
|
||||
public Boolean command() throws Throwable
|
||||
{
|
||||
return isSelectableInternal();
|
||||
}
|
||||
};
|
||||
return command.run(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces 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.
|
||||
* {@code silentListener} can be provided - this listener wouldn't be notified.
|
||||
*
|
||||
* @param flags - new flags.
|
||||
* @param uid - message UID.
|
||||
* @param silentListener - listener that shouldn't be notified.
|
||||
* @param addUid - defines whether or not listeners be notified.
|
||||
*/
|
||||
public void replaceFlags(final Flags flags, final long uid, final FolderListener silentListener, final boolean addUid) throws FolderException
|
||||
{
|
||||
CommandCallback<Object> command = new CommandCallback<Object>()
|
||||
{
|
||||
public Object command() throws Throwable
|
||||
{
|
||||
replaceFlagsInternal(flags, uid, silentListener, addUid);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
command.runFeedback(true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simply returns UIDs of all messages in the folder.
|
||||
*
|
||||
* @param searchTerm - not used
|
||||
* @return UIDs of the messages
|
||||
*/
|
||||
public long[] search(SearchTerm searchTerm)
|
||||
{
|
||||
return getMessageUids();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* {@code silentListener} can be provided - this listener wouldn't be notified.
|
||||
*
|
||||
* @param flags - new flags.
|
||||
* @param value - flags value.
|
||||
* @param uid - message UID.
|
||||
* @param silentListener - listener that shouldn't be notified.
|
||||
* @param addUid - defines whether or not listeners be notified.
|
||||
*/
|
||||
public void setFlags(final Flags flags, final boolean value, final long uid, final FolderListener silentListener, final boolean addUid) throws FolderException
|
||||
{
|
||||
CommandCallback<Object> command = new CommandCallback<Object>()
|
||||
{
|
||||
public Object command() throws Throwable
|
||||
{
|
||||
setFlagsInternal(flags, value, uid, silentListener, addUid);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
command.runFeedback();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Not supported. Added to implement {@link MailFolder#store(MovingMessage)}.
|
||||
*/
|
||||
public void store(MovingMessage mail) throws Exception
|
||||
{
|
||||
throw new UnsupportedOperationException("Method store(MovingMessage) is not suppoted.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported. Added to implement {@link MailFolder#store(MimeMessage)}.
|
||||
*/
|
||||
public void store(MimeMessage message) throws Exception
|
||||
{
|
||||
throw new UnsupportedOperationException("Method store(MimeMessage) is not suppoted.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds {@link FolderListener} to the folder.
|
||||
*
|
||||
* @param listener - new listener.
|
||||
*/
|
||||
public void addListener(FolderListener listener)
|
||||
{
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Removes {@link FolderListener} from the folder.
|
||||
*
|
||||
* @param listener - Listener to remove.
|
||||
*/
|
||||
public void removeListener(FolderListener listener)
|
||||
{
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method is called before the deletion of the folder. Notifies {@link FolderListener} objects with {@link FolderListener#mailboxDeleted()} method calls.
|
||||
*/
|
||||
public void signalDeletion()
|
||||
{
|
||||
synchronized (listeners)
|
||||
{
|
||||
for (int i = 0; i < listeners.size(); i++)
|
||||
{
|
||||
FolderListener listener = (FolderListener) listeners.get(i);
|
||||
listener.mailboxDeleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void notifyFlagUpdate(int msn, Flags flags, Long uidNotification, FolderListener silentListener)
|
||||
{
|
||||
synchronized (listeners)
|
||||
{
|
||||
for (FolderListener listener : listeners)
|
||||
{
|
||||
if (listener == silentListener)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
listener.flagsUpdated(msn, flags, uidNotification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected abstract boolean isReadOnly();
|
||||
|
||||
protected abstract long appendMessageInternal(MimeMessage message, Flags flags, Date internalDate) throws Exception;
|
||||
|
||||
protected abstract void copyMessageInternal(long uid, MailFolder toFolder) throws Exception;
|
||||
|
||||
protected abstract void deleteAllMessagesInternal() throws Exception;
|
||||
|
||||
protected abstract void expungeInternal() throws Exception;
|
||||
|
||||
protected abstract int getFirstUnseenInternal();
|
||||
|
||||
protected abstract String getFullNameInternal() throws Exception;
|
||||
|
||||
protected abstract SimpleStoredMessage getMessageInternal(long uid) throws Exception;
|
||||
|
||||
protected abstract int getMessageCountInternal();
|
||||
|
||||
protected abstract List<SimpleStoredMessage> getMessagesInternal();
|
||||
|
||||
protected abstract List<SimpleStoredMessage> getMessagesInternal(MsgRangeFilter msgRangeFilter);
|
||||
|
||||
protected abstract int getMsnInternal(long uid) throws Exception;
|
||||
|
||||
protected abstract String getNameInternal();
|
||||
|
||||
protected abstract long[] getMessageUidsInternal();
|
||||
|
||||
protected abstract List<SimpleStoredMessage> getNonDeletedMessagesInternal();
|
||||
|
||||
protected abstract Flags getPermanentFlagsInternal();
|
||||
|
||||
protected abstract int getRecentCountInternal(boolean reset);
|
||||
|
||||
protected abstract long getUidNextInternal();
|
||||
|
||||
protected abstract long getUidValidityInternal();
|
||||
|
||||
protected abstract int getUnseenCountInternal();
|
||||
|
||||
protected abstract boolean isSelectableInternal();
|
||||
|
||||
protected abstract void replaceFlagsInternal(Flags flags, long uid, FolderListener silentListener, boolean addUid) throws Exception;
|
||||
|
||||
protected abstract void setFlagsInternal(Flags flags, boolean value, long uid, FolderListener silentListener, boolean addUid) throws Exception;
|
||||
|
||||
|
||||
|
||||
|
||||
protected abstract class CommandCallback<T>
|
||||
{
|
||||
public abstract T command() throws Throwable;
|
||||
|
||||
public T runFeedback() throws FolderException
|
||||
{
|
||||
return this.runFeedback(false);
|
||||
}
|
||||
|
||||
public T runFeedback(boolean readOnly) throws FolderException
|
||||
{
|
||||
try
|
||||
{
|
||||
RetryingTransactionHelper txHelper = serviceRegistry.getTransactionService().getRetryingTransactionHelper();
|
||||
txHelper.setMaxRetries(MAX_RETRIES);
|
||||
txHelper.setReadOnly(readOnly);
|
||||
T result = txHelper.doInTransaction(new RetryingTransactionCallback<T>() {
|
||||
public T execute() throws Throwable
|
||||
{
|
||||
return command();
|
||||
}
|
||||
}, readOnly);
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Throwable cause = e.getCause();
|
||||
String message;
|
||||
if (cause != null)
|
||||
{
|
||||
message = cause.getMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
message = e.getMessage();
|
||||
}
|
||||
throw new FolderException(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public T run()
|
||||
{
|
||||
return this.run(false);
|
||||
}
|
||||
|
||||
|
||||
public T run(boolean readOnly)
|
||||
{
|
||||
RetryingTransactionHelper txHelper = serviceRegistry.getTransactionService().getRetryingTransactionHelper();
|
||||
txHelper.setMaxRetries(MAX_RETRIES);
|
||||
txHelper.setReadOnly(readOnly);
|
||||
T result = txHelper.doInTransaction(new RetryingTransactionCallback<T>() {
|
||||
public T execute() throws Throwable
|
||||
{
|
||||
return command();
|
||||
}
|
||||
}, readOnly);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
368
source/java/org/alfresco/repo/imap/AbstractMimeMessage.java
Executable file
368
source/java/org/alfresco/repo/imap/AbstractMimeMessage.java
Executable file
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.imap;
|
||||
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.CLASSPATH_TEXT_HTML_TEMPLATE;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.CLASSPATH_TEXT_PLAIN_TEMPLATE;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.DICTIONARY_TEMPLATE_PREFIX;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.MIME_VERSION;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.X_ALF_NODEREF_ID;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.mail.Address;
|
||||
import javax.mail.Flags;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.AddressException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import org.alfresco.i18n.I18NUtil;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.template.TemplateNode;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
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.StoreRef;
|
||||
import org.alfresco.service.cmr.search.ResultSet;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* @author Arseny Kovalchuk
|
||||
*/
|
||||
public abstract class AbstractMimeMessage extends MimeMessage
|
||||
{
|
||||
/** Used if imapHelper.getDefaultFromAddress is not set */
|
||||
protected static final String DEFAULT_EMAIL_FROM = "alfresco@alfresco.org";
|
||||
protected static final String DEFAULT_EMAIL_TO = DEFAULT_EMAIL_FROM;
|
||||
protected static final String KOI8R_CHARSET = "koi8-r";
|
||||
|
||||
protected static int MAX_RETRIES = 1;
|
||||
|
||||
private Log logger = LogFactory.getLog(AbstractMimeMessage.class);
|
||||
|
||||
protected boolean generateBody = true;
|
||||
|
||||
protected ServiceRegistry serviceRegistry;
|
||||
protected ImapService imapService;
|
||||
protected FileInfo messageFileInfo;
|
||||
protected MimeMessage wrappedMessage;
|
||||
|
||||
protected AbstractMimeMessage(Session session)
|
||||
{
|
||||
super(session);
|
||||
}
|
||||
|
||||
protected AbstractMimeMessage(FileInfo fileInfo, ServiceRegistry serviceRegistry, boolean generateBody) throws MessagingException
|
||||
{
|
||||
super(Session.getDefaultInstance(new Properties()));
|
||||
this.generateBody = generateBody;
|
||||
buildMessage(fileInfo, serviceRegistry);
|
||||
}
|
||||
|
||||
public static enum EmailBodyType
|
||||
{
|
||||
TEXT_PLAIN, TEXT_HTML;
|
||||
|
||||
public String getSubtype()
|
||||
{
|
||||
return name().toLowerCase().substring(5);
|
||||
}
|
||||
|
||||
public String getTypeSubtype()
|
||||
{
|
||||
return name().toLowerCase().replaceAll("_", "");
|
||||
}
|
||||
|
||||
public String getMimeType()
|
||||
{
|
||||
return name().toLowerCase().replaceAll("_", "/");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void buildMessage(FileInfo fileInfo, ServiceRegistry serviceRegistry) throws MessagingException
|
||||
{
|
||||
checkParameter(serviceRegistry, "ServiceRegistry");
|
||||
this.content = null;
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
this.imapService = serviceRegistry.getImapService();
|
||||
this.messageFileInfo = fileInfo;
|
||||
RetryingTransactionHelper txHelper = serviceRegistry.getTransactionService().getRetryingTransactionHelper();
|
||||
txHelper.setMaxRetries(MAX_RETRIES);
|
||||
txHelper.doInTransaction(new RetryingTransactionCallback<Object>() {
|
||||
public Object execute() throws Throwable
|
||||
{
|
||||
buildMessageInternal();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Method must be implemented in subclasses. It usually should be used to generate message body.
|
||||
*
|
||||
* @throws MessagingException
|
||||
*/
|
||||
public abstract void buildMessageInternal() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Method that checks mandatory parameter.
|
||||
* @param The parameter instance to check.
|
||||
* @param The name of the parameter.
|
||||
*/
|
||||
protected void checkParameter(Object parameter, String name)
|
||||
{
|
||||
if (parameter == null)
|
||||
{
|
||||
throw new IllegalArgumentException(name + " parameter is null.");
|
||||
}
|
||||
}
|
||||
|
||||
protected void setMessageHeaders() throws MessagingException
|
||||
{
|
||||
setHeader(MIME_VERSION, "1.0");
|
||||
// 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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the InternetAddress from the Content Author name if provided. If name not specified, it takes Content Creator name. If content creator does not exists, the default
|
||||
* from address will be returned.
|
||||
*
|
||||
* @param contentAuthor The content author full name.
|
||||
* @return Generated InternetAddress[] array.
|
||||
* @throws AddressException
|
||||
*/
|
||||
protected InternetAddress[] buildSenderFromAddress() throws AddressException
|
||||
{
|
||||
// Generate FROM address (Content author)
|
||||
InternetAddress[] addressList = null;
|
||||
Map<QName, Serializable> properties = messageFileInfo.getProperties();
|
||||
String prop = (String) properties.get(ContentModel.PROP_AUTHOR);
|
||||
String defaultFromAddress = imapService.getDefaultFromAddress();
|
||||
defaultFromAddress = defaultFromAddress == null ? DEFAULT_EMAIL_FROM : defaultFromAddress;
|
||||
try
|
||||
{
|
||||
|
||||
if (prop != null)
|
||||
{
|
||||
StringBuilder contentAuthor = new StringBuilder();
|
||||
contentAuthor.append("\"").append(prop).append("\" <").append(defaultFromAddress).append(">");
|
||||
addressList = InternetAddress.parse(contentAuthor.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
prop = (String) properties.get(ContentModel.PROP_CREATOR);
|
||||
if (prop != null)
|
||||
{
|
||||
StringBuilder creator = new StringBuilder();
|
||||
creator.append("\"").append(prop).append("\" <").append(defaultFromAddress).append(">");
|
||||
addressList = InternetAddress.parse(creator.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new AddressException(I18NUtil.getMessage("imap.server.error.properties_dont_exist"));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (AddressException e)
|
||||
{
|
||||
addressList = InternetAddress.parse(DEFAULT_EMAIL_FROM);
|
||||
}
|
||||
return addressList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link FileInfo} object representing message in Alfresco.
|
||||
*
|
||||
* @return reference to the {@link FileInfo} object.
|
||||
*/
|
||||
public FileInfo getMessageInfo()
|
||||
{
|
||||
return messageFileInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns message flags.
|
||||
*
|
||||
* @return {@link Flags}
|
||||
*/
|
||||
@Override
|
||||
public Flags getFlags()
|
||||
{
|
||||
return imapService.getFlags(messageFileInfo);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets message flags.
|
||||
*
|
||||
* @param flags - {@link Flags} object.
|
||||
* @param value - flags value.
|
||||
*/
|
||||
@Override
|
||||
public void setFlags(Flags flags, boolean value) throws MessagingException
|
||||
{
|
||||
imapService.setFlags(messageFileInfo, flags, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text representing email body for ContentModel node.
|
||||
*
|
||||
* @param nodeRef NodeRef of the target content.
|
||||
* @param type The type of the returned body. May be the one of {@link EmailBodyType}.
|
||||
* @return Text representing email body for ContentModel node.
|
||||
*/
|
||||
public String getEmailBodyText(EmailBodyType type)
|
||||
{
|
||||
return serviceRegistry.getTemplateService().processTemplate(getDefaultEmailBodyTemplate(type), createEmailTemplateModel(messageFileInfo.getNodeRef()));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO USE CASE 2: "The To/addressee will be the first email alias found in the parent folders or a default one (TBD)". It seems to be more informative as alike
|
||||
* {@code <user>@<current.domain>}...
|
||||
*
|
||||
* @return Generated TO address {@code <user>@<current.domain>}
|
||||
* @throws AddressException
|
||||
*/
|
||||
protected InternetAddress[] buildRecipientToAddress() throws AddressException
|
||||
{
|
||||
InternetAddress[] result = null;
|
||||
String defaultEmailTo = null;
|
||||
final String escapedUserName = AuthenticationUtil.getFullyAuthenticatedUser().replaceAll("[/,\\,@]", ".");
|
||||
final String userDomain = DEFAULT_EMAIL_TO.split("@")[1];
|
||||
defaultEmailTo = escapedUserName + "@" + userDomain;
|
||||
try
|
||||
{
|
||||
result = InternetAddress.parse(defaultEmailTo);
|
||||
}
|
||||
catch (AddressException e)
|
||||
{
|
||||
logger.error(String.format("Wrong email address '%s'.", defaultEmailTo), e);
|
||||
result = InternetAddress.parse(DEFAULT_EMAIL_TO);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void addFromInternal(String addressesString) throws MessagingException
|
||||
{
|
||||
if (addressesString != null)
|
||||
{
|
||||
addFrom(InternetAddress.parse(addressesString));
|
||||
}
|
||||
else
|
||||
{
|
||||
addFrom(new Address[] { new InternetAddress(DEFAULT_EMAIL_FROM) });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns default email body template. This method trying to find a template on the path in the repository first e.g. {@code "Data Dictionary > IMAP Templates >"}. This path
|
||||
* should be set as the property of the "imapHelper" bean. In this case it returns {@code NodeRef.toString()} of the template. If there are no template in the repository it
|
||||
* returns a default template on the classpath.
|
||||
*
|
||||
* @param type One of the {@link EmailBodyType}.
|
||||
* @return String representing template classpath path or NodeRef.toString().
|
||||
*/
|
||||
private String getDefaultEmailBodyTemplate(EmailBodyType type)
|
||||
{
|
||||
String result = null;
|
||||
switch (type)
|
||||
{
|
||||
case TEXT_HTML:
|
||||
result = CLASSPATH_TEXT_HTML_TEMPLATE;
|
||||
break;
|
||||
case TEXT_PLAIN:
|
||||
result = CLASSPATH_TEXT_PLAIN_TEMPLATE;
|
||||
break;
|
||||
}
|
||||
final StringBuilder templateName = new StringBuilder(DICTIONARY_TEMPLATE_PREFIX).append("-").append(type.getTypeSubtype()).append(".ftl");
|
||||
final String repositoryTemplatePath = imapService.getRepositoryTemplatePath();
|
||||
int indexOfStoreDelim = repositoryTemplatePath.indexOf(StoreRef.URI_FILLER);
|
||||
if (indexOfStoreDelim == -1)
|
||||
{
|
||||
logger.error("Bad path format, " + StoreRef.URI_FILLER + " not found");
|
||||
return result;
|
||||
}
|
||||
indexOfStoreDelim += StoreRef.URI_FILLER.length();
|
||||
int indexOfPathDelim = repositoryTemplatePath.indexOf("/", indexOfStoreDelim);
|
||||
if (indexOfPathDelim == -1)
|
||||
{
|
||||
logger.error("Bad path format, / not found");
|
||||
return result;
|
||||
}
|
||||
final String storePath = repositoryTemplatePath.substring(0, indexOfPathDelim);
|
||||
final String rootPathInStore = repositoryTemplatePath.substring(indexOfPathDelim);
|
||||
final String query = String.format("+PATH:\"%1$s/*\" +@cm\\:name:\"%2$s\"", rootPathInStore, templateName.toString());
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Using template path :" + repositoryTemplatePath + "/" + templateName);
|
||||
logger.debug("Query: " + query);
|
||||
}
|
||||
StoreRef storeRef = new StoreRef(storePath);
|
||||
ResultSet resultSet = serviceRegistry.getSearchService().query(storeRef, "lucene", query);
|
||||
if (resultSet == null || resultSet.length() == 0)
|
||||
{
|
||||
logger.error(String.format("IMAP message template '%1$s' does not exist in the path '%2$s'.", templateName, repositoryTemplatePath));
|
||||
return result;
|
||||
}
|
||||
result = resultSet.getNodeRef(0).toString();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds default email template model for TemplateProcessor
|
||||
*
|
||||
* @param ref NodeRef of the target content.
|
||||
* @return Map that includes template model objects.
|
||||
*/
|
||||
private Map<String, Object> createEmailTemplateModel(NodeRef ref)
|
||||
{
|
||||
Map<String, Object> model = new HashMap<String, Object>(8, 1.0f);
|
||||
TemplateNode tn = new TemplateNode(ref, serviceRegistry, null);
|
||||
model.put("document", tn);
|
||||
NodeRef parent = serviceRegistry.getNodeService().getPrimaryParent(ref).getParentRef();
|
||||
model.put("space", new TemplateNode(parent, serviceRegistry, null));
|
||||
model.put("date", new Date());
|
||||
model.put("contextUrl", new String(imapService.getWebApplicationContextUrl()));
|
||||
model.put("alfTicket", new String(serviceRegistry.getAuthenticationService().getCurrentTicket()));
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@@ -30,7 +30,7 @@ package org.alfresco.repo.imap;
|
||||
public interface AlfrescoImapConst
|
||||
{
|
||||
|
||||
public static final char HIERARCHY_DELIMITER = '.';
|
||||
public static final char HIERARCHY_DELIMITER = '/';
|
||||
public static final String NAMESPACE_PREFIX = "#";
|
||||
public static final String USER_NAMESPACE = "#mail";
|
||||
public static final String INBOX_NAME = "INBOX";
|
||||
@@ -38,17 +38,23 @@ public interface AlfrescoImapConst
|
||||
public static final String BODY_TEXT_PLAIN_NAME = "Body.txt";
|
||||
public static final String BODY_TEXT_HTML_NAME = "Body.html";
|
||||
public static final String MESSAGE_PREFIX = "Message_";
|
||||
public static final String EML_EXTENSION = ".eml";
|
||||
// Separator for user enties in flag and subscribe properties
|
||||
public static final String USER_SEPARATOR = ";";
|
||||
|
||||
/**
|
||||
* Defines {@link AlfrescoImapMailFolder} view mode as archive mode. Used for Email Archive View.
|
||||
* Defines {@link AlfrescoImapFolder} view mode as archive mode. Used for Email Archive View.
|
||||
*/
|
||||
public static final String MODE_ARCHIVE = "archive";
|
||||
/**
|
||||
* Defines {@link AlfrescoImapMailFolder} view mode as virtual mode. Used for IMAP Virtualised View.
|
||||
* Defines {@link AlfrescoImapFolder} view mode as virtual mode. Used for IMAP Virtualised View.
|
||||
*/
|
||||
public static final String MODE_VIRTUAL = "virtual";
|
||||
/**
|
||||
* Defines {@link AlfrescoImapFolder} view mode as mixed mode. Used for IMAP Mixed View.
|
||||
*/
|
||||
public static final String MODE_MIXED = "mixed";
|
||||
|
||||
|
||||
// Default content model email message templates
|
||||
public static final String CLASSPATH_TEXT_PLAIN_TEMPLATE = "/alfresco/templates/imap/imap_message_text_plain.ftl";
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -24,27 +24,11 @@
|
||||
*/
|
||||
package org.alfresco.repo.imap;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.ImapModel;
|
||||
import org.alfresco.repo.imap.config.ImapConfigBean;
|
||||
import org.alfresco.repo.imap.exception.AlfrescoImapFolderException;
|
||||
import org.alfresco.repo.model.filefolder.FileFolderServiceImpl;
|
||||
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.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.security.AccessStatus;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
@@ -53,7 +37,6 @@ import com.icegreen.greenmail.imap.ImapHostManager;
|
||||
import com.icegreen.greenmail.store.FolderException;
|
||||
import com.icegreen.greenmail.store.MailFolder;
|
||||
import com.icegreen.greenmail.user.GreenMailUser;
|
||||
import com.icegreen.greenmail.util.GreenMailUtil;
|
||||
|
||||
/**
|
||||
* @author Mike Shavnev
|
||||
@@ -63,11 +46,8 @@ public class AlfrescoImapHostManager implements ImapHostManager
|
||||
|
||||
private Log logger = LogFactory.getLog(AlfrescoImapHostManager.class);
|
||||
|
||||
private ServiceRegistry serviceRegistry;
|
||||
|
||||
private NodeService nodeService;
|
||||
private FileFolderService fileFolderService;
|
||||
private ImapHelper imapHelper;
|
||||
private ImapService imapService;
|
||||
private TransactionService transactionService;
|
||||
|
||||
/**
|
||||
* Returns the hierarchy delimiter for mailboxes on this host.
|
||||
@@ -90,18 +70,14 @@ public class AlfrescoImapHostManager implements ImapHostManager
|
||||
*/
|
||||
public Collection<MailFolder> listMailboxes(GreenMailUser user, String mailboxPattern) throws FolderException
|
||||
{
|
||||
mailboxPattern = GreenMailUtil.convertFromUtf7(mailboxPattern);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
try
|
||||
{
|
||||
logger.debug("Listing mailboxes: mailboxPattern=" + mailboxPattern);
|
||||
return new ArrayList<MailFolder>(imapService.listMailboxes(new AlfrescoImapUser(user.getEmail(), user.getLogin(), user.getPassword()), mailboxPattern));
|
||||
}
|
||||
mailboxPattern = imapHelper.getMailPathInRepo(mailboxPattern);
|
||||
if (logger.isDebugEnabled())
|
||||
catch (Throwable e)
|
||||
{
|
||||
logger.debug("Listing mailboxes: mailboxPattern in alfresco=" + mailboxPattern);
|
||||
throw new FolderException(e.getMessage());
|
||||
}
|
||||
return listMailboxes(user, mailboxPattern, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,251 +92,14 @@ public class AlfrescoImapHostManager implements ImapHostManager
|
||||
*/
|
||||
public Collection<MailFolder> listSubscribedMailboxes(GreenMailUser user, String mailboxPattern) throws FolderException
|
||||
{
|
||||
mailboxPattern = GreenMailUtil.convertFromUtf7(mailboxPattern);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
try
|
||||
{
|
||||
logger.debug("Listing subscribed mailboxes: mailboxPattern=" + mailboxPattern);
|
||||
return new ArrayList<MailFolder>(imapService.listSubscribedMailboxes(new AlfrescoImapUser(user.getEmail(), user.getLogin(), user.getPassword()), mailboxPattern));
|
||||
}
|
||||
mailboxPattern = imapHelper.getMailPathInRepo(mailboxPattern);
|
||||
if (logger.isDebugEnabled())
|
||||
catch (Throwable e)
|
||||
{
|
||||
logger.debug("Listing subscribed mailboxes: mailboxPattern in alfresco=" + mailboxPattern);
|
||||
throw new FolderException(e.getMessage());
|
||||
}
|
||||
|
||||
return listMailboxes(user, mailboxPattern, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Depend on listSubscribed param, list Mailboxes or list subscribed Mailboxes
|
||||
*/
|
||||
private Collection<MailFolder> listMailboxes(GreenMailUser user, String mailboxPattern, boolean listSubscribed) throws FolderException
|
||||
{
|
||||
Collection<MailFolder> result = new LinkedList<MailFolder>();
|
||||
|
||||
Map<String, NodeRef> mountPoints = imapHelper.getMountPoints();
|
||||
Map<String, ImapConfigBean> imapConfigs = imapHelper.getImapConfig();
|
||||
|
||||
NodeRef mountPoint;
|
||||
|
||||
// List mailboxes that are in mount points
|
||||
for (String mountPointName : mountPoints.keySet())
|
||||
{
|
||||
|
||||
mountPoint = mountPoints.get(mountPointName);
|
||||
FileInfo mountPointFileInfo = imapHelper.getFileFolderService().getFileInfo(mountPoint);
|
||||
NodeRef mountParent = imapHelper.getNodeService().getParentAssocs(mountPoint).get(0).getParentRef();
|
||||
String viewMode = imapConfigs.get(mountPointName).getMode();
|
||||
|
||||
if (!mailboxPattern.equals("*"))
|
||||
{
|
||||
mountPoint = mountParent;
|
||||
}
|
||||
|
||||
boolean isVirtualView = imapConfigs.get(mountPointName).getMode().equals(AlfrescoImapConst.MODE_VIRTUAL);
|
||||
Collection<MailFolder> folders = listFolder(mountPoint, mountPoint, user, mailboxPattern, listSubscribed, isVirtualView);
|
||||
if (folders != null)
|
||||
{
|
||||
for (MailFolder mailFolder : folders)
|
||||
{
|
||||
AlfrescoImapMailFolder folder = (AlfrescoImapMailFolder) mailFolder;
|
||||
folder.setMountPointName(mountPointName);
|
||||
folder.setViewMode(viewMode);
|
||||
folder.setMountParent(mountParent);
|
||||
}
|
||||
result.addAll(folders);
|
||||
}
|
||||
|
||||
// Add mount point to the result list
|
||||
if (mailboxPattern.equals("*"))
|
||||
{
|
||||
if ((listSubscribed && isSubscribed(mountPointFileInfo, user.getLogin())) || (!listSubscribed))
|
||||
{
|
||||
result.add(new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), mountPointFileInfo, mountPointName, viewMode, mountParent, mountPointName, imapHelper));
|
||||
}
|
||||
// \NoSelect
|
||||
else if (listSubscribed && hasSubscribedChild(mountPointFileInfo, user.getLogin(), isVirtualView))
|
||||
{
|
||||
result.add(new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), mountPointFileInfo, mountPointName, viewMode, mountParent, mountPointName, imapHelper,
|
||||
false));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// List mailboxes that are in user IMAP Home
|
||||
NodeRef root = imapHelper.getUserImapHomeRef(user.getLogin());
|
||||
Collection<MailFolder> imapFolders = listFolder(root, root, user, mailboxPattern, listSubscribed, false);
|
||||
|
||||
if (imapFolders != null)
|
||||
{
|
||||
for (MailFolder mailFolder : imapFolders)
|
||||
{
|
||||
AlfrescoImapMailFolder folder = (AlfrescoImapMailFolder) mailFolder;
|
||||
folder.setViewMode(AlfrescoImapConst.MODE_ARCHIVE);
|
||||
folder.setMountParent(root);
|
||||
}
|
||||
result.addAll(imapFolders);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
private Collection<MailFolder> listFolder(NodeRef mailboxRoot, NodeRef root, GreenMailUser user, String mailboxPattern, boolean listSubscribed, boolean isVirtualView)
|
||||
throws FolderException
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Listing mailboxes: mailboxPattern=" + mailboxPattern);
|
||||
}
|
||||
|
||||
int index = mailboxPattern.indexOf(AlfrescoImapConst.HIERARCHY_DELIMITER);
|
||||
|
||||
String name = null;
|
||||
String remainName = null;
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
name = mailboxPattern;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = mailboxPattern.substring(0, index);
|
||||
remainName = mailboxPattern.substring(index + 1);
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Listing mailboxes: name=" + name);
|
||||
}
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
if ("*".equals(name))
|
||||
{
|
||||
Collection<FileInfo> list = imapHelper.searchFolders(root, name, true, isVirtualView);
|
||||
if (listSubscribed)
|
||||
{
|
||||
list = getSubscribed(list, user.getLogin());
|
||||
}
|
||||
|
||||
if (list.size() > 0)
|
||||
{
|
||||
return createMailFolderList(user, list, mailboxRoot);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else if (name.endsWith("*"))
|
||||
{
|
||||
List<FileInfo> fullList = new LinkedList<FileInfo>();
|
||||
List<FileInfo> list = imapHelper.searchFolders(root, name.replace('%', '*'), false, isVirtualView);
|
||||
Collection<FileInfo> subscribedList = list;
|
||||
if (listSubscribed)
|
||||
{
|
||||
subscribedList = getSubscribed(list, user.getLogin());
|
||||
}
|
||||
|
||||
if (list.size() > 0)
|
||||
{
|
||||
fullList.addAll(subscribedList);
|
||||
for (FileInfo fileInfo : list)
|
||||
{
|
||||
List<FileInfo> childList = imapHelper.searchFolders(fileInfo.getNodeRef(), "*", true, isVirtualView);
|
||||
if (listSubscribed)
|
||||
{
|
||||
fullList.addAll(getSubscribed(childList, user.getLogin()));
|
||||
}
|
||||
else
|
||||
{
|
||||
fullList.addAll(childList);
|
||||
}
|
||||
}
|
||||
return createMailFolderList(user, fullList, mailboxRoot);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else if ("%".equals(name))
|
||||
{
|
||||
List<FileInfo> list = imapHelper.searchFolders(root, "*", false, isVirtualView);
|
||||
LinkedList<MailFolder> subscribedList = new LinkedList<MailFolder>();
|
||||
|
||||
if (listSubscribed)
|
||||
{
|
||||
for (FileInfo fileInfo : list)
|
||||
{
|
||||
if (isSubscribed(fileInfo, user.getLogin()))
|
||||
{
|
||||
// folderName, viewMode, mountPointName will be setted in listMailboxes() method
|
||||
subscribedList.add(new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), fileInfo, null, null, mailboxRoot, null, imapHelper));
|
||||
}
|
||||
// \NoSelect
|
||||
else if (hasSubscribedChild(fileInfo, user.getLogin(), isVirtualView))
|
||||
{
|
||||
// folderName, viewMode, mountPointName will be setted in listMailboxes() method
|
||||
subscribedList.add(new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), fileInfo, null, null, mailboxRoot, null, imapHelper, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return createMailFolderList(user, list, mailboxRoot);
|
||||
}
|
||||
|
||||
return subscribedList;
|
||||
}
|
||||
else if (name.contains("%") || name.contains("*"))
|
||||
{
|
||||
List<FileInfo> list = imapHelper.searchFolders(root, name.replace('%', '*'), false, isVirtualView);
|
||||
Collection<FileInfo> subscribedList = list;
|
||||
if (listSubscribed)
|
||||
{
|
||||
subscribedList = getSubscribed(list, user.getLogin());
|
||||
}
|
||||
|
||||
if (subscribedList.size() > 0)
|
||||
{
|
||||
return createMailFolderList(user, subscribedList, mailboxRoot);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
List<FileInfo> list = imapHelper.searchFolders(root, name, false, isVirtualView);
|
||||
Collection<FileInfo> subscribedList = list;
|
||||
if (listSubscribed)
|
||||
{
|
||||
subscribedList = getSubscribed(list, user.getLogin());
|
||||
}
|
||||
|
||||
if (subscribedList.size() > 0)
|
||||
{
|
||||
return createMailFolderList(user, subscribedList, mailboxRoot);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// If (index != -1) this is not the last level
|
||||
Collection<MailFolder> result = new LinkedList<MailFolder>();
|
||||
|
||||
List<FileInfo> list = imapHelper.searchFolders(root, name.replace('%', '*'), false, isVirtualView);
|
||||
for (FileInfo folder : list)
|
||||
{
|
||||
Collection<MailFolder> childFolders = listFolder(mailboxRoot, folder.getNodeRef(), user, remainName, listSubscribed, isVirtualView);
|
||||
|
||||
if (childFolders != null)
|
||||
{
|
||||
result.addAll(childFolders);
|
||||
}
|
||||
}
|
||||
|
||||
if (result.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -375,97 +114,16 @@ public class AlfrescoImapHostManager implements ImapHostManager
|
||||
* @throws com.icegreen.greenmail.store.FolderException if an existing folder with the new name.
|
||||
* @throws AlfrescoImapFolderException if user does not have rights to create the new mailbox.
|
||||
*/
|
||||
|
||||
public void renameMailbox(GreenMailUser user, String oldMailboxName, String newMailboxName) throws FolderException, AuthorizationException
|
||||
{
|
||||
oldMailboxName = GreenMailUtil.convertFromUtf7(oldMailboxName);
|
||||
newMailboxName = GreenMailUtil.convertFromUtf7(newMailboxName);
|
||||
if (logger.isDebugEnabled())
|
||||
try
|
||||
{
|
||||
logger.debug("Renaming folder: oldMailboxName=" + oldMailboxName + " newMailboxName=" + newMailboxName);
|
||||
imapService.renameMailbox(new AlfrescoImapUser(user.getEmail(), user.getLogin(), user.getPassword()), oldMailboxName, newMailboxName);
|
||||
}
|
||||
|
||||
AlfrescoImapMailFolder sourceNode = (AlfrescoImapMailFolder) getFolder(user, GreenMailUtil.convertInUtf7(oldMailboxName));
|
||||
|
||||
NodeRef root = imapHelper.getMailboxRootRef(oldMailboxName, user.getLogin());
|
||||
String mailboxRepoName = imapHelper.getMailPathInRepo(newMailboxName);
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(mailboxRepoName, String.valueOf(AlfrescoImapConst.HIERARCHY_DELIMITER));
|
||||
|
||||
NodeRef parentNodeRef = root;
|
||||
while (tokenizer.hasMoreTokens())
|
||||
catch (Throwable e)
|
||||
{
|
||||
String folderName = tokenizer.nextToken();
|
||||
|
||||
if (!tokenizer.hasMoreTokens())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (oldMailboxName.equalsIgnoreCase(AlfrescoImapConst.INBOX_NAME))
|
||||
{
|
||||
// If you trying to rename INBOX
|
||||
// - just copy it to another folder with new name
|
||||
// and leave INBOX (with children) intact.
|
||||
fileFolderService.copy(sourceNode.getFolderInfo().getNodeRef(), parentNodeRef, folderName);
|
||||
List<FileInfo> itemsForRemove = fileFolderService.list(sourceNode.getFolderInfo().getNodeRef());
|
||||
for (FileInfo fileInfo : itemsForRemove)
|
||||
{
|
||||
fileFolderService.delete(fileInfo.getNodeRef());
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
fileFolderService.move(sourceNode.getFolderInfo().getNodeRef(), parentNodeRef, folderName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
catch (FileExistsException e)
|
||||
{
|
||||
throw new FolderException(FolderException.ALREADY_EXISTS_LOCALLY);
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
List<FileInfo> folders = imapHelper.searchFolders(parentNodeRef, folderName, false, true);
|
||||
|
||||
if (folders.size() == 0)
|
||||
{
|
||||
AccessStatus status = imapHelper.hasPermission(parentNodeRef, PermissionService.WRITE);
|
||||
if (status == AccessStatus.DENIED)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Creating folder: Cant't create folder - Permission denied");
|
||||
}
|
||||
throw new AlfrescoImapFolderException(AlfrescoImapFolderException.PERMISSION_DENIED);
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Create mailBox: " + folderName);
|
||||
}
|
||||
FileFolderServiceImpl.makeFolders(fileFolderService, parentNodeRef, Arrays.asList(folderName), ContentModel.TYPE_FOLDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
parentNodeRef = folders.get(0).getNodeRef();
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("MailBox: " + folderName + " already exists");
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new FolderException(e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -480,58 +138,14 @@ public class AlfrescoImapHostManager implements ImapHostManager
|
||||
*/
|
||||
public MailFolder createMailbox(GreenMailUser user, String mailboxName) throws AuthorizationException, FolderException
|
||||
{
|
||||
mailboxName = GreenMailUtil.convertFromUtf7(mailboxName);
|
||||
if (logger.isDebugEnabled())
|
||||
try
|
||||
{
|
||||
logger.debug("Creating folder: " + mailboxName);
|
||||
return imapService.createMailbox(new AlfrescoImapUser(user.getEmail(), user.getLogin(), user.getPassword()), mailboxName);
|
||||
}
|
||||
|
||||
NodeRef root = imapHelper.getMailboxRootRef(mailboxName, user.getLogin());
|
||||
|
||||
String mountPointName = imapHelper.getMountPointName(mailboxName);
|
||||
String mailboxRepoNam = imapHelper.getMailPathInRepo(mailboxName);
|
||||
StringTokenizer tokenizer = new StringTokenizer(mailboxRepoNam, String.valueOf(AlfrescoImapConst.HIERARCHY_DELIMITER));
|
||||
|
||||
NodeRef parentNodeRef = root;
|
||||
|
||||
while (tokenizer.hasMoreTokens())
|
||||
catch (Throwable e)
|
||||
{
|
||||
String folderName = tokenizer.nextToken();
|
||||
|
||||
List<FileInfo> folders = imapHelper.searchFolders(parentNodeRef, folderName, false, true);
|
||||
|
||||
if (folders.size() == 0)
|
||||
{
|
||||
AccessStatus status = imapHelper.hasPermission(parentNodeRef, PermissionService.WRITE);
|
||||
if (status == AccessStatus.DENIED)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Creating folder: Cant't create folder - Permission denied");
|
||||
}
|
||||
throw new AlfrescoImapFolderException(AlfrescoImapFolderException.PERMISSION_DENIED);
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Create mailBox: " + mailboxName);
|
||||
}
|
||||
FileInfo mailFolder = FileFolderServiceImpl.makeFolders(fileFolderService, parentNodeRef, Arrays.asList(folderName), ContentModel.TYPE_FOLDER);
|
||||
|
||||
return new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), mailFolder, folderName, imapHelper.getViewMode(mailboxName), root, mountPointName, imapHelper);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
parentNodeRef = folders.get(0).getNodeRef();
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("MailBox: " + folderName + " already exists");
|
||||
}
|
||||
}
|
||||
throw new FolderException(e.getMessage());
|
||||
}
|
||||
|
||||
throw new FolderException(FolderException.ALREADY_EXISTS_LOCALLY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -544,34 +158,13 @@ public class AlfrescoImapHostManager implements ImapHostManager
|
||||
*/
|
||||
public void deleteMailbox(GreenMailUser user, String mailboxName) throws FolderException, AuthorizationException
|
||||
{
|
||||
AlfrescoImapMailFolder folder = (AlfrescoImapMailFolder) getFolder(user, mailboxName);
|
||||
NodeRef nodeRef = folder.getFolderInfo().getNodeRef();
|
||||
|
||||
List<FileInfo> childFolders = imapHelper.searchFolders(nodeRef, "*", false, false);
|
||||
|
||||
if (childFolders.isEmpty())
|
||||
try
|
||||
{
|
||||
folder.signalDeletion();
|
||||
// Delete child folders and messages
|
||||
fileFolderService.delete(nodeRef);
|
||||
imapService.deleteMailbox(new AlfrescoImapUser(user.getEmail(), user.getLogin(), user.getPassword()), mailboxName);
|
||||
}
|
||||
else
|
||||
catch (Throwable e)
|
||||
{
|
||||
if (folder.isSelectable())
|
||||
{
|
||||
// Delete all messages for this folder
|
||||
// Don't delete subfolders and their messages
|
||||
List<FileInfo> messages = imapHelper.searchFiles(nodeRef, "*", ImapModel.TYPE_IMAP_CONTENT, false);
|
||||
for (FileInfo message : messages)
|
||||
{
|
||||
fileFolderService.delete(message.getNodeRef());
|
||||
}
|
||||
nodeService.addAspect(nodeRef, ImapModel.ASPECT_IMAP_FOLDER_NONSELECTABLE, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FolderException(mailboxName + " - Can't delete a non-selectable store with children.");
|
||||
}
|
||||
throw new FolderException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,80 +179,22 @@ public class AlfrescoImapHostManager implements ImapHostManager
|
||||
*/
|
||||
public MailFolder getFolder(GreenMailUser user, String mailboxName)
|
||||
{
|
||||
mailboxName = GreenMailUtil.convertFromUtf7(mailboxName);
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Getting folder: " + mailboxName);
|
||||
}
|
||||
|
||||
// If MailFolder object is used to obtain hierarchy delimiter by LIST command:
|
||||
// Example:
|
||||
// C: 2 list "" ""
|
||||
// S: * LIST () "." ""
|
||||
// S: 2 OK LIST completed.
|
||||
if ("".equals(mailboxName))
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Request for the hierarchy delimiter");
|
||||
}
|
||||
return new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
NodeRef root = imapHelper.getMailboxRootRef(mailboxName, user.getLogin());
|
||||
String mountPointName = imapHelper.getMountPointName(mailboxName);
|
||||
String mailboxRepoName = imapHelper.getMailPathInRepo(mailboxName);
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(mailboxRepoName, String.valueOf(AlfrescoImapConst.HIERARCHY_DELIMITER));
|
||||
int count = tokenizer.countTokens();
|
||||
NodeRef nodeRef = root;
|
||||
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
String t = tokenizer.nextToken();
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("token=" + t);
|
||||
}
|
||||
count--;
|
||||
|
||||
List<FileInfo> list = imapHelper.searchFolders(nodeRef, t, false, true);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
if (!list.isEmpty())
|
||||
{
|
||||
|
||||
return new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), list.get(0), list.get(0).getName(), imapHelper.getViewMode(mailboxName), root,
|
||||
mountPointName, imapHelper);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), null, null, null, null, null, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!list.isEmpty())
|
||||
{
|
||||
nodeRef = list.get(0).getNodeRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), null, null, null, null, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Error state");
|
||||
return imapService.getFolder(new AlfrescoImapUser(user.getEmail(), user.getLogin(), user.getPassword()), mailboxName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply calls {@link #getFolder(GreenMailUser, String)}. <p/> Added to implement {@link ImapHostManager}.
|
||||
*/
|
||||
public MailFolder getFolder(GreenMailUser user, String mailboxName, boolean mustExist) throws FolderException
|
||||
public MailFolder getFolder(final GreenMailUser user, final String mailboxName, boolean mustExist) throws FolderException
|
||||
{
|
||||
return getFolder(user, mailboxName);
|
||||
try
|
||||
{
|
||||
return getFolder(new AlfrescoImapUser(user.getEmail(), user.getLogin(), user.getPassword()), mailboxName);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
throw new FolderException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -670,7 +205,14 @@ public class AlfrescoImapHostManager implements ImapHostManager
|
||||
*/
|
||||
public MailFolder getInbox(GreenMailUser user) throws FolderException
|
||||
{
|
||||
return getFolder(user, AlfrescoImapConst.INBOX_NAME);
|
||||
try
|
||||
{
|
||||
return getFolder(new AlfrescoImapUser(user.getEmail(), user.getLogin(), user.getPassword()), AlfrescoImapConst.INBOX_NAME);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
throw new FolderException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -687,39 +229,16 @@ public class AlfrescoImapHostManager implements ImapHostManager
|
||||
* @param user User making the request
|
||||
* @param mailbox String representation of a mailbox name.
|
||||
*/
|
||||
public void subscribe(final GreenMailUser user, final String mailbox) throws FolderException
|
||||
public void subscribe(GreenMailUser user, String mailbox) throws FolderException
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
try
|
||||
{
|
||||
logger.debug("Subscribing: " + mailbox);
|
||||
imapService.subscribe(new AlfrescoImapUser(user.getEmail(), user.getLogin(), user.getPassword()), mailbox);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
throw new FolderException(e.getMessage());
|
||||
}
|
||||
AlfrescoImapMailFolder mailFolder = (AlfrescoImapMailFolder) getFolder(user, mailbox);
|
||||
nodeService.addAspect(mailFolder.getFolderInfo().getNodeRef(), ImapModel.ASPECT_IMAP_FOLDER_SUBSCRIBED, null);
|
||||
// This is a multiuser support. Commented due new requirements
|
||||
// AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Void>()
|
||||
// {
|
||||
// public Void doWork() throws Exception
|
||||
// {
|
||||
// AlfrescoImapMailFolder mailFolder = (AlfrescoImapMailFolder) getFolder(user, mailbox);
|
||||
// FileInfo fileInfo = mailFolder.getFolderInfo();
|
||||
// if (fileInfo != null)
|
||||
// {
|
||||
// String subscribedList = (String) nodeService.getProperty(fileInfo.getNodeRef(), ImapModel.PROP_IMAP_FOLDER_SUBSCRIBED);
|
||||
// if (subscribedList == null)
|
||||
// {
|
||||
// subscribedList = "";
|
||||
// }
|
||||
// subscribedList = subscribedList.replaceAll(imapHelper.formatUserEntry(user.getLogin()), "");
|
||||
// subscribedList += imapHelper.formatUserEntry(user.getLogin());
|
||||
// nodeService.setProperty(fileInfo.getNodeRef(), ImapModel.PROP_IMAP_FOLDER_SUBSCRIBED, subscribedList);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// logger.debug("MailBox: " + mailbox + "doesn't exsist. Maybe it was deleted earlier.");
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
// }, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -728,137 +247,46 @@ public class AlfrescoImapHostManager implements ImapHostManager
|
||||
* @param user User making the request
|
||||
* @param mailbox String representation of a mailbox name.
|
||||
*/
|
||||
public void unsubscribe(final GreenMailUser user, final String mailbox) throws FolderException
|
||||
public void unsubscribe(GreenMailUser user, String mailbox) throws FolderException
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
try
|
||||
{
|
||||
logger.debug("Unsubscribing: " + mailbox);
|
||||
imapService.unsubscribe(new AlfrescoImapUser(user.getEmail(), user.getLogin(), user.getPassword()), mailbox);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
throw new FolderException(e.getMessage());
|
||||
}
|
||||
AlfrescoImapMailFolder mailFolder = (AlfrescoImapMailFolder) getFolder(user, mailbox);
|
||||
nodeService.removeAspect(mailFolder.getFolderInfo().getNodeRef(), ImapModel.ASPECT_IMAP_FOLDER_SUBSCRIBED);
|
||||
|
||||
// This is a multiuser support. Commented due new requirements
|
||||
// AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Void>()
|
||||
// {
|
||||
// public Void doWork() throws Exception
|
||||
// {
|
||||
// AlfrescoImapMailFolder mailFolder = (AlfrescoImapMailFolder) getFolder(user, mailbox);
|
||||
// if (mailFolder.getFolderInfo() != null)
|
||||
// {
|
||||
// FileInfo fileInfo = mailFolder.getFolderInfo();
|
||||
// String subscribedList = (String) nodeService.getProperty(fileInfo.getNodeRef(), ImapModel.PROP_IMAP_FOLDER_SUBSCRIBED);
|
||||
// if (subscribedList == null)
|
||||
// {
|
||||
// subscribedList = "";
|
||||
// }
|
||||
// subscribedList = subscribedList.replaceAll(imapHelper.formatUserEntry(user.getLogin()), "");
|
||||
// nodeService.setProperty(fileInfo.getNodeRef(), ImapModel.PROP_IMAP_FOLDER_SUBSCRIBED, subscribedList);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// logger.debug("MailBox: " + mailbox + " doesn't exsist. Maybe it was deleted earlier.");
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
// }, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported. Used by GreenMail class.
|
||||
*/
|
||||
public List getAllMessages()
|
||||
public List<?> getAllMessages()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private boolean isSubscribed(FileInfo fileInfo, String userName)
|
||||
{
|
||||
return nodeService.hasAspect(fileInfo.getNodeRef(), ImapModel.ASPECT_IMAP_FOLDER_SUBSCRIBED);
|
||||
// This is a multiuser support. Commented due new requirements
|
||||
|
||||
// Map<QName, Serializable> properties = fileInfo.getProperties();
|
||||
// String subscribedList = (String) properties.get(ImapModel.PROP_IMAP_FOLDER_SUBSCRIBED);
|
||||
// if (subscribedList == null)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return subscribedList.contains(imapHelper.formatUserEntry(userName));
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
private Collection<FileInfo> getSubscribed(Collection<FileInfo> list, String userName)
|
||||
{
|
||||
Collection<FileInfo> result = new LinkedList<FileInfo>();
|
||||
|
||||
for (FileInfo folderInfo : list)
|
||||
{
|
||||
if (isSubscribed(folderInfo, userName))
|
||||
{
|
||||
result.add(folderInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean hasSubscribedChild(FileInfo parent, String userName, boolean isVirtualView)
|
||||
{
|
||||
List<FileInfo> list = imapHelper.searchFolders(parent.getNodeRef(), "*", true, isVirtualView);
|
||||
|
||||
for (FileInfo fileInfo : list)
|
||||
{
|
||||
if (isSubscribed(fileInfo, userName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private Collection<MailFolder> createMailFolderList(GreenMailUser user, Collection<FileInfo> list, NodeRef imapUserHomeRef)
|
||||
{
|
||||
Collection<MailFolder> result = new LinkedList<MailFolder>();
|
||||
|
||||
for (FileInfo folderInfo : list)
|
||||
{
|
||||
// folderName, viewMode, mountPointName will be setted in listSubscribedMailboxes() method
|
||||
result.add(new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), folderInfo, null, null, imapUserHomeRef, null, imapHelper));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
// ----------------------Getters and Setters----------------------------
|
||||
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
public ImapService getImapService()
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
return imapService;
|
||||
}
|
||||
|
||||
public ServiceRegistry getServiceRegistry()
|
||||
public void setImapService(ImapService imapService)
|
||||
{
|
||||
return serviceRegistry;
|
||||
this.imapService = imapService;
|
||||
}
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
public TransactionService getTransactionService()
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
return transactionService;
|
||||
}
|
||||
|
||||
public void setFileFolderService(FileFolderService fileFolderService)
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
this.fileFolderService = fileFolderService;
|
||||
}
|
||||
|
||||
public void setImapHelper(ImapHelper imapHelper)
|
||||
{
|
||||
this.imapHelper = imapHelper;
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,508 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.imap;
|
||||
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.BASE_64_ENCODING;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.CONTENT_ID;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.CONTENT_TRANSFER_ENCODING;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.CONTENT_TYPE;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.MIME_VERSION;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.UTF_8;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.X_ALF_NODEREF_ID;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.X_ALF_SERVER_UID;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.activation.DataHandler;
|
||||
import javax.activation.DataSource;
|
||||
import javax.mail.Address;
|
||||
import javax.mail.Flags;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.AddressException;
|
||||
import javax.mail.internet.ContentType;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
import javax.mail.internet.MimeUtility;
|
||||
import javax.mail.util.ByteArrayDataSource;
|
||||
|
||||
import org.alfresco.i18n.I18NUtil;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.ImapModel;
|
||||
import org.alfresco.repo.imap.ImapHelper.EmailBodyType;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Extended MimeMessage to represent a content stored in the Alfresco repository.
|
||||
*
|
||||
* @author Arseny Kovalchuk
|
||||
*/
|
||||
public class AlfrescoImapMessage extends MimeMessage
|
||||
{
|
||||
/** Used if imapHelper.getDefaultFromAddress is not set */
|
||||
private static final String DEFAULT_EMAIL_FROM = "alfresco@alfresco.org";
|
||||
private static final String DEFAULT_EMAIL_TO = DEFAULT_EMAIL_FROM;
|
||||
private static final String KOI8R_CHARSET = "koi8-r";
|
||||
|
||||
private static Log logger = LogFactory.getLog(AlfrescoImapMessage.class);
|
||||
|
||||
private ImapHelper imapHelper;
|
||||
private FileInfo messageInfo;
|
||||
|
||||
/**
|
||||
* Constructs {@link AlfrescoImapMessage} object.
|
||||
*
|
||||
* @param fileInfo - reference to the {@link FileInfo} object representing the message.
|
||||
* @param imapHelper - reference to the {@link ImapHelper} object.
|
||||
* @param generateBody - if {@code true} message body will be generated.
|
||||
*
|
||||
* @throws MessagingException if generation of the body fails.
|
||||
*/
|
||||
public AlfrescoImapMessage(FileInfo fileInfo, ImapHelper imapHelper, boolean generateBody) throws MessagingException
|
||||
{
|
||||
super(Session.getDefaultInstance(new Properties()));
|
||||
this.messageInfo = fileInfo;
|
||||
this.imapHelper = imapHelper;
|
||||
if (generateBody)
|
||||
{
|
||||
setMessageHeaders();
|
||||
buildMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs {@link AlfrescoImapMessage} object.
|
||||
*
|
||||
* @param fileInfo - reference to the {@link FileInfo} object representing the message.
|
||||
* @param imapHelper - reference to the {@link ImapHelper} object.
|
||||
* @param message - {@link MimeMessage}
|
||||
* @throws MessagingException
|
||||
*/
|
||||
public AlfrescoImapMessage(FileInfo fileInfo, ImapHelper imapHelper, MimeMessage message) throws MessagingException
|
||||
{
|
||||
super(message);
|
||||
this.messageInfo = fileInfo;
|
||||
this.imapHelper = imapHelper;
|
||||
|
||||
setMessageHeaders();
|
||||
final NodeRef nodeRef = fileInfo.getNodeRef();
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
|
||||
props.put(ImapModel.PROP_MESSAGE_FROM, InternetAddress.toString(message.getFrom()));
|
||||
props.put(ImapModel.PROP_MESSAGE_TO, InternetAddress.toString(message.getRecipients(RecipientType.TO)));
|
||||
props.put(ImapModel.PROP_MESSAGE_CC, InternetAddress.toString(message.getRecipients(RecipientType.CC)));
|
||||
|
||||
String[] subj = message.getHeader("Subject");
|
||||
if (subj.length > 0)
|
||||
{
|
||||
props.put(ImapModel.PROP_MESSAGE_SUBJECT, subj[0]);
|
||||
imapHelper.getNodeService().setProperty(nodeRef, ContentModel.PROP_DESCRIPTION, subj[0]);
|
||||
}
|
||||
|
||||
Map<QName, Serializable> allprops = imapHelper.getNodeService().getProperties(fileInfo.getNodeRef());
|
||||
allprops.putAll(props);
|
||||
imapHelper.getNodeService().setProperties(nodeRef, allprops);
|
||||
// setContent(buildMultipart(fileInfo)); - disabled for better performance.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns message flags.
|
||||
*
|
||||
* @return {@link Flags}
|
||||
*/
|
||||
@Override
|
||||
public synchronized Flags getFlags()
|
||||
{
|
||||
return imapHelper.getFlags(messageInfo);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets message flags.
|
||||
*
|
||||
* @param flags - {@link Flags} object.
|
||||
* @param value - flags value.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void setFlags(Flags flags, boolean value) throws MessagingException
|
||||
{
|
||||
imapHelper.setFlags(messageInfo, flags, value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns {@link FileInfo} object representing message in Alfresco.
|
||||
*
|
||||
* @return reference to the {@link FileInfo} object.
|
||||
*/
|
||||
public FileInfo getMessageInfo()
|
||||
{
|
||||
return messageInfo;
|
||||
}
|
||||
|
||||
private void setMessageHeaders() throws MessagingException
|
||||
{
|
||||
setHeader(MIME_VERSION, "1.0");
|
||||
// Optional headers for further implementation of multiple Alfresco server support.
|
||||
setHeader(X_ALF_NODEREF_ID, messageInfo.getNodeRef().getId());
|
||||
setHeader(X_ALF_SERVER_UID, imapHelper.getAlfrescoServerUID());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method builds MimeMessage based on either ImapModel or ContentModel type.
|
||||
*
|
||||
* @param fileInfo - Source file information {@link FileInfo}
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private void buildMessage() throws MessagingException
|
||||
{
|
||||
final NodeRef nodeRef = messageInfo.getNodeRef();
|
||||
if (ImapModel.TYPE_IMAP_CONTENT.equals(imapHelper.getNodeService().getType(nodeRef)))
|
||||
{
|
||||
buildImapModelMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
buildContentModelMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method builds MimeMessage based on {@link ImapModel}
|
||||
*
|
||||
* @param fileInfo - Source file information {@link FileInfo}
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private void buildImapModelMessage() throws MessagingException
|
||||
{
|
||||
Map<QName, Serializable> properties = messageInfo.getProperties();
|
||||
setSentDate(messageInfo.getModifiedDate());
|
||||
String prop = (String) properties.get(ImapModel.PROP_MESSAGE_FROM);
|
||||
addFromInternal(prop);
|
||||
prop = (String) properties.get(ImapModel.PROP_MESSAGE_TO);
|
||||
|
||||
if (prop != null && prop.length() > 0)
|
||||
{
|
||||
addRecipients(RecipientType.TO, InternetAddress.parse(prop));
|
||||
}
|
||||
else
|
||||
{
|
||||
addRecipients(RecipientType.TO, DEFAULT_EMAIL_TO);
|
||||
}
|
||||
|
||||
prop = (String) properties.get(ImapModel.PROP_MESSAGE_CC);
|
||||
if (prop != null && prop.length() > 0)
|
||||
{
|
||||
addRecipients(RecipientType.CC, InternetAddress.parse(prop));
|
||||
}
|
||||
|
||||
prop = (String) properties.get(ImapModel.PROP_MESSAGE_SUBJECT);
|
||||
setSubject(prop == null ? messageInfo.getName() : prop);
|
||||
|
||||
setContent(buildImapModelMultipart());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method builds {@link MimeMessage} based on {@link ContentModel}
|
||||
*
|
||||
* @param fileInfo - Source file information {@link FileInfo}
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private void buildContentModelMessage() throws MessagingException
|
||||
{
|
||||
Map<QName, Serializable> properties = messageInfo.getProperties();
|
||||
String prop = null;
|
||||
setSentDate(messageInfo.getModifiedDate());
|
||||
// Add FROM address
|
||||
Address[] addressList = buildSenderFromAddress(properties);
|
||||
addFrom(addressList);
|
||||
// Add TO address
|
||||
addressList = buildRecipientToAddress();
|
||||
addRecipients(RecipientType.TO, addressList);
|
||||
prop = (String) properties.get(ContentModel.PROP_TITLE);
|
||||
try
|
||||
{
|
||||
prop = (prop == null) ? MimeUtility.encodeText(messageInfo.getName(), KOI8R_CHARSET, null) : MimeUtility.encodeText(prop, KOI8R_CHARSET, null);
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
setSubject(prop);
|
||||
setContent(buildContentModelMultipart());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method builds {@link Multipart} based on {@link ContentModel}
|
||||
*
|
||||
* @param fileInfo - Source file information {@link FileInfo}
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private Multipart buildContentModelMultipart() throws MessagingException
|
||||
{
|
||||
MimeMultipart rootMultipart = new MimeMultipart("alternative");
|
||||
// Cite MOB-395: "email agent will be used to select an appropriate template" - we are not able to
|
||||
// detect an email agent so we use a default template for all messages.
|
||||
// See AlfrescoImapConst to see the possible templates to use.
|
||||
String bodyTxt = imapHelper.getEmailBodyText(messageInfo.getNodeRef(), EmailBodyType.TEXT_PLAIN);
|
||||
rootMultipart.addBodyPart(getTextBodyPart(bodyTxt, EmailBodyType.TEXT_PLAIN.getSubtype()));
|
||||
String bodyHtml = imapHelper.getEmailBodyText(messageInfo.getNodeRef(), EmailBodyType.TEXT_HTML);
|
||||
rootMultipart.addBodyPart(getTextBodyPart(bodyHtml, EmailBodyType.TEXT_HTML.getSubtype()));
|
||||
return rootMultipart;
|
||||
}
|
||||
|
||||
private MimeBodyPart getTextBodyPart(String bodyText, String subtype) throws MessagingException
|
||||
{
|
||||
MimeBodyPart result = new MimeBodyPart();
|
||||
result.setText(bodyText, UTF_8, subtype);
|
||||
result.addHeader(CONTENT_TRANSFER_ENCODING, BASE_64_ENCODING);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method builds {@link Multipart} based on {@link ImapModel}
|
||||
*
|
||||
* @param fileInfo - Source file information {@link FileInfo}
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private Multipart buildImapModelMultipart() throws MessagingException
|
||||
{
|
||||
DataSource source = null;
|
||||
String errorMessage = null;
|
||||
|
||||
// Root multipart - multipart/mixed
|
||||
MimeMultipart rootMultipart = new MimeMultipart("mixed");
|
||||
// Message body - multipart/alternative - consists of two parts: text/plain and text/html
|
||||
MimeMultipart messageBody = new MimeMultipart("alternative");
|
||||
// <------------------------ text html body part ------------------------>
|
||||
List<FileInfo> bodyHtmls = imapHelper.searchFiles(messageInfo.getNodeRef(), "*.html", ImapModel.TYPE_IMAP_BODY, false);
|
||||
ContentType contentType = null;
|
||||
MimeBodyPart textHtmlBodyPart = null;
|
||||
if (bodyHtmls != null && bodyHtmls.size() > 0)
|
||||
{
|
||||
textHtmlBodyPart = new MimeBodyPart();
|
||||
FileInfo bodyHtml = bodyHtmls.get(0);
|
||||
contentType = new ContentType(bodyHtml.getContentData().getMimetype());
|
||||
ContentReader reader = imapHelper.getFileFolderService().getReader(bodyHtml.getNodeRef());
|
||||
try
|
||||
{
|
||||
source = new ByteArrayDataSource(reader.getContentInputStream(), contentType.toString());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
logger.error(e);
|
||||
errorMessage = e.getMessage();
|
||||
}
|
||||
if (source != null)
|
||||
{
|
||||
textHtmlBodyPart.setDataHandler(new DataHandler(source));
|
||||
textHtmlBodyPart.addHeader(CONTENT_TYPE, bodyHtml.getContentData().getMimetype());
|
||||
// textHtmlBodyPart.addHeader(CONTENT_TRANSFER_ENCODING, EIGHT_BIT_ENCODING);
|
||||
textHtmlBodyPart.addHeader(CONTENT_TRANSFER_ENCODING, BASE_64_ENCODING);
|
||||
}
|
||||
else
|
||||
{
|
||||
textHtmlBodyPart.setText(errorMessage, UTF_8);
|
||||
}
|
||||
messageBody.addBodyPart(textHtmlBodyPart);
|
||||
}
|
||||
// </------------------------ text html body part ------------------------>
|
||||
// <------------------------ text plain body part ------------------------>
|
||||
List<FileInfo> results = imapHelper.searchFiles(messageInfo.getNodeRef(), "*.txt", ImapModel.TYPE_IMAP_BODY, false);
|
||||
MimeBodyPart textPlainBodyPart = null;
|
||||
String text = null;
|
||||
if (results != null && results.size() > 0)
|
||||
{
|
||||
textPlainBodyPart = new MimeBodyPart();
|
||||
FileInfo bodyTxt = results.get(0);
|
||||
text = imapHelper.getFileFolderService().getReader(bodyTxt.getNodeRef()).getContentString();
|
||||
contentType = new ContentType(bodyTxt.getContentData().getMimetype());
|
||||
}
|
||||
else if (textHtmlBodyPart == null)
|
||||
{
|
||||
text = I18NUtil.getMessage("imap.server.info.message_body_not_found");
|
||||
contentType = new ContentType(EmailBodyType.TEXT_PLAIN.getMimeType() + "; charset=UTF-8");
|
||||
}
|
||||
|
||||
textPlainBodyPart.setText(text, contentType.getParameter("charset"), contentType.getSubType());
|
||||
textPlainBodyPart.addHeader(CONTENT_TYPE, contentType.toString());
|
||||
messageBody.addBodyPart(textPlainBodyPart);
|
||||
// </------------------------ text plain body part ------------------------>
|
||||
|
||||
// Body part for multipart/alternative
|
||||
MimeBodyPart messageBodyPart = new MimeBodyPart();
|
||||
messageBodyPart.setContent(messageBody);
|
||||
// Add multipart/alternative into root multipart/mixed...
|
||||
rootMultipart.addBodyPart(messageBodyPart);
|
||||
|
||||
// Process attachments
|
||||
List<FileInfo> attaches = imapHelper.searchFiles(messageInfo.getNodeRef(), "*", ImapModel.TYPE_IMAP_ATTACH, false);
|
||||
|
||||
for (FileInfo attach : attaches)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
errorMessage = null;
|
||||
messageBodyPart = new MimeBodyPart();
|
||||
ContentReader reader = imapHelper.getFileFolderService().getReader(attach.getNodeRef());
|
||||
source = new ByteArrayDataSource(reader.getContentInputStream(), attach.getContentData().getMimetype());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
logger.error(e);
|
||||
errorMessage = e.getMessage();
|
||||
}
|
||||
if (source != null)
|
||||
{
|
||||
String attachID = (String) imapHelper.getNodeService().getProperty(attach.getNodeRef(), ImapModel.PROP_ATTACH_ID);
|
||||
if (attachID != null)
|
||||
{
|
||||
messageBodyPart.addHeader(CONTENT_ID, attachID);
|
||||
}
|
||||
StringBuilder ct = new StringBuilder(attach.getContentData().getMimetype()).append("; name=\"").append(attach.getName()).append("\"");
|
||||
messageBodyPart.addHeader(CONTENT_TYPE, ct.toString());
|
||||
messageBodyPart.addHeader(CONTENT_TRANSFER_ENCODING, BASE_64_ENCODING);
|
||||
messageBodyPart.setDataHandler(new DataHandler(source));
|
||||
try
|
||||
{
|
||||
messageBodyPart.setFileName(MimeUtility.encodeText(attach.getName(), KOI8R_CHARSET, null));
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
messageBodyPart.setText(errorMessage, UTF_8);
|
||||
}
|
||||
rootMultipart.addBodyPart(messageBodyPart);
|
||||
}
|
||||
return rootMultipart;
|
||||
}
|
||||
|
||||
private void addFromInternal(String addressesString) throws MessagingException
|
||||
{
|
||||
if (addressesString != null)
|
||||
{
|
||||
addFrom(InternetAddress.parse(addressesString));
|
||||
}
|
||||
else
|
||||
{
|
||||
addFrom(new Address[] { new InternetAddress(DEFAULT_EMAIL_FROM) });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO USE CASE 2: "The To/addressee will be the first email alias found in the parent folders or a default one (TBD)". It seems to be more informative as alike
|
||||
* {@code <user>@<current.domain>}...
|
||||
*
|
||||
* @return Generated TO address {@code <user>@<current.domain>}
|
||||
* @throws AddressException
|
||||
*/
|
||||
private InternetAddress[] buildRecipientToAddress() throws AddressException
|
||||
{
|
||||
InternetAddress[] result = null;
|
||||
String defaultEmailTo = null;
|
||||
// TODO : search first email alias found in the parent folders
|
||||
// if (found) defaultEmailTo = foundAlias
|
||||
// else
|
||||
final String escapedUserName = imapHelper.getCurrentUser().replaceAll("[/,\\,@]", ".");
|
||||
final String userDomain = DEFAULT_EMAIL_TO.split("@")[1];
|
||||
defaultEmailTo = escapedUserName + "@" + userDomain;
|
||||
try
|
||||
{
|
||||
result = InternetAddress.parse(defaultEmailTo);
|
||||
}
|
||||
catch (AddressException e)
|
||||
{
|
||||
logger.error(String.format("Wrong email address '%s'.", defaultEmailTo), e);
|
||||
result = InternetAddress.parse(DEFAULT_EMAIL_TO);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the InternetAddress from the Content Author name if provided. If name not specified, it takes Content Creator name. If content creator does not exists, the default
|
||||
* from address will be returned.
|
||||
*
|
||||
* @param contentAuthor The content author full name.
|
||||
* @return Generated InternetAddress[] array.
|
||||
* @throws AddressException
|
||||
*/
|
||||
private InternetAddress[] buildSenderFromAddress(Map<QName, Serializable> properties) throws AddressException
|
||||
{
|
||||
// Generate FROM address (Content author)
|
||||
InternetAddress[] addressList = null;
|
||||
String prop = (String) properties.get(ContentModel.PROP_AUTHOR);
|
||||
String defaultFromAddress = imapHelper.getDefaultFromAddress();
|
||||
defaultFromAddress = defaultFromAddress == null ? DEFAULT_EMAIL_FROM : defaultFromAddress;
|
||||
try
|
||||
{
|
||||
|
||||
if (prop != null)
|
||||
{
|
||||
StringBuilder contentAuthor = new StringBuilder();
|
||||
contentAuthor.append("\"").append(prop).append("\" <").append(defaultFromAddress).append(">");
|
||||
addressList = InternetAddress.parse(contentAuthor.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
prop = (String) properties.get(ContentModel.PROP_CREATOR);
|
||||
if (prop != null)
|
||||
{
|
||||
StringBuilder creator = new StringBuilder();
|
||||
creator.append("\"").append(prop).append("\" <").append(defaultFromAddress).append(">");
|
||||
addressList = InternetAddress.parse(creator.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new AddressException(I18NUtil.getMessage("imap.server.error.properties_dont_exist"));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (AddressException e)
|
||||
{
|
||||
addressList = InternetAddress.parse(DEFAULT_EMAIL_FROM);
|
||||
}
|
||||
return addressList;
|
||||
}
|
||||
|
||||
}
|
@@ -47,14 +47,14 @@ public class AlfrescoImapServer extends AbstractLifecycleBean
|
||||
|
||||
private int port = 143;
|
||||
|
||||
private String host = "localhost";
|
||||
|
||||
private ImapHostManager imapHostManager;
|
||||
|
||||
private UserManager imapUserManager;
|
||||
|
||||
private boolean imapServerEnabled;
|
||||
|
||||
private ImapHelper imapHelper;
|
||||
|
||||
public void setImapServerEnabled(boolean imapServerEnabled)
|
||||
{
|
||||
this.imapServerEnabled = imapServerEnabled;
|
||||
@@ -65,6 +65,11 @@ public class AlfrescoImapServer extends AbstractLifecycleBean
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public void setHost(String host)
|
||||
{
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public void setImapHostManager(ImapHostManager imapHostManager)
|
||||
{
|
||||
this.imapHostManager = imapHostManager;
|
||||
@@ -75,14 +80,9 @@ public class AlfrescoImapServer extends AbstractLifecycleBean
|
||||
this.imapUserManager = imapUserManager;
|
||||
}
|
||||
|
||||
public void setImapHelper(ImapHelper imapHelper)
|
||||
{
|
||||
this.imapHelper = imapHelper;
|
||||
}
|
||||
|
||||
protected void onBootstrap(ApplicationEvent event)
|
||||
{
|
||||
if (imapServerEnabled && imapHelper.isPatchApplied())
|
||||
if (imapServerEnabled)
|
||||
{
|
||||
Managers imapManagers = new Managers()
|
||||
{
|
||||
@@ -96,11 +96,11 @@ public class AlfrescoImapServer extends AbstractLifecycleBean
|
||||
return imapUserManager;
|
||||
}
|
||||
};
|
||||
serverImpl = new ImapServer(new ServerSetup(port, null, ServerSetup.PROTOCOL_IMAP), imapManagers);
|
||||
serverImpl = new ImapServer(new ServerSetup(port, host, ServerSetup.PROTOCOL_IMAP), imapManagers);
|
||||
serverImpl.startService(null);
|
||||
if (logger.isInfoEnabled())
|
||||
{
|
||||
logger.info("IMAP service started on port " + this.port + ".");
|
||||
logger.info("IMAP service started on host:port " + this.host + ":" + this.port + ".");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@@ -26,7 +26,6 @@ package org.alfresco.repo.imap;
|
||||
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import com.icegreen.greenmail.imap.ImapHostManager;
|
||||
import com.icegreen.greenmail.mail.MovingMessage;
|
||||
import com.icegreen.greenmail.user.GreenMailUser;
|
||||
import com.icegreen.greenmail.user.UserException;
|
||||
@@ -42,14 +41,11 @@ public class AlfrescoImapUser implements GreenMailUser
|
||||
private char[] password;
|
||||
private String email;
|
||||
|
||||
private ImapHostManager imapHostManager;
|
||||
|
||||
public AlfrescoImapUser(String email, String login, String password, ImapHostManager imapHostManager)
|
||||
public AlfrescoImapUser(String email, String login, String password)
|
||||
{
|
||||
this.email = email;
|
||||
this.userName = login;
|
||||
this.password = password.toCharArray();
|
||||
this.imapHostManager = imapHostManager;
|
||||
}
|
||||
|
||||
public void authenticate(String password) throws UserException
|
||||
@@ -71,12 +67,12 @@ public class AlfrescoImapUser implements GreenMailUser
|
||||
|
||||
public void deliver(MovingMessage msg) throws UserException
|
||||
{
|
||||
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void deliver(MimeMessage msg) throws UserException
|
||||
{
|
||||
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String getEmail()
|
||||
|
@@ -37,7 +37,6 @@ import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.icegreen.greenmail.imap.ImapHostManager;
|
||||
import com.icegreen.greenmail.user.GreenMailUser;
|
||||
import com.icegreen.greenmail.user.UserException;
|
||||
import com.icegreen.greenmail.user.UserManager;
|
||||
@@ -50,7 +49,6 @@ public class AlfrescoImapUserManager extends UserManager
|
||||
private Log logger = LogFactory.getLog(AlfrescoImapUserManager.class);
|
||||
|
||||
protected Map<String, GreenMailUser> userMap = Collections.synchronizedMap(new HashMap<String, GreenMailUser>());
|
||||
protected ImapHostManager imapHostManager;
|
||||
|
||||
protected AuthenticationService authenticationService;
|
||||
protected PersonService personService;
|
||||
@@ -61,17 +59,11 @@ public class AlfrescoImapUserManager extends UserManager
|
||||
super(null);
|
||||
}
|
||||
|
||||
public AlfrescoImapUserManager(ImapHostManager imapHostManager)
|
||||
{
|
||||
this();
|
||||
this.imapHostManager = imapHostManager;
|
||||
}
|
||||
|
||||
public GreenMailUser createUser(String email, String login, String password) throws UserException
|
||||
{
|
||||
// TODO: User creation/addition code should be implemented here (in the AlfrescoImapUserManager).
|
||||
// Following code is not need and not used in the current implementation.
|
||||
GreenMailUser user = new AlfrescoImapUser(email, login, password, imapHostManager);
|
||||
GreenMailUser user = new AlfrescoImapUser(email, login, password);
|
||||
user.create();
|
||||
addUser(user);
|
||||
return user;
|
||||
@@ -129,7 +121,7 @@ public class AlfrescoImapUserManager extends UserManager
|
||||
NodeRef personNodeRef = personService.getPerson(userid);
|
||||
email = (String) nodeService.getProperty(personNodeRef, ContentModel.PROP_EMAIL);
|
||||
}
|
||||
GreenMailUser user = new AlfrescoImapUser(email, userid, password, imapHostManager);
|
||||
GreenMailUser user = new AlfrescoImapUser(email, userid, password);
|
||||
addUser(user);
|
||||
}
|
||||
catch (AuthenticationException ex)
|
||||
@@ -140,16 +132,6 @@ public class AlfrescoImapUserManager extends UserManager
|
||||
return true;
|
||||
}
|
||||
|
||||
public ImapHostManager getImapHostManager()
|
||||
{
|
||||
return this.imapHostManager;
|
||||
}
|
||||
|
||||
public void setImapHostManager(ImapHostManager imapHostManager)
|
||||
{
|
||||
this.imapHostManager = imapHostManager;
|
||||
}
|
||||
|
||||
public void setAuthenticationService(AuthenticationService authenticationService)
|
||||
{
|
||||
this.authenticationService = authenticationService;
|
||||
|
99
source/java/org/alfresco/repo/imap/ContentModelMessage.java
Executable file
99
source/java/org/alfresco/repo/imap/ContentModelMessage.java
Executable file
@@ -0,0 +1,99 @@
|
||||
package org.alfresco.repo.imap;
|
||||
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.BASE_64_ENCODING;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.CONTENT_TRANSFER_ENCODING;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.UTF_8;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.mail.Address;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
import javax.mail.internet.MimeUtility;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
public class ContentModelMessage extends AbstractMimeMessage
|
||||
{
|
||||
|
||||
public ContentModelMessage(FileInfo fileInfo, ServiceRegistry serviceRegistry, boolean generateBody) throws MessagingException
|
||||
{
|
||||
super(fileInfo, serviceRegistry, generateBody);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildMessageInternal() throws MessagingException
|
||||
{
|
||||
if (generateBody != false)
|
||||
{
|
||||
setMessageHeaders();
|
||||
buildContentModelMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method builds {@link MimeMessage} based on {@link ContentModel}
|
||||
*
|
||||
* @param fileInfo - Source file information {@link FileInfo}
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private void buildContentModelMessage() throws MessagingException
|
||||
{
|
||||
Map<QName, Serializable> properties = messageFileInfo.getProperties();
|
||||
String prop = null;
|
||||
setSentDate(messageFileInfo.getModifiedDate());
|
||||
// Add FROM address
|
||||
Address[] addressList = buildSenderFromAddress();
|
||||
addFrom(addressList);
|
||||
// Add TO address
|
||||
addressList = buildRecipientToAddress();
|
||||
addRecipients(RecipientType.TO, addressList);
|
||||
prop = (String) properties.get(ContentModel.PROP_TITLE);
|
||||
try
|
||||
{
|
||||
prop = (prop == null) ? MimeUtility.encodeText(messageFileInfo.getName(), KOI8R_CHARSET, null) : MimeUtility.encodeText(prop, KOI8R_CHARSET, null);
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
setSubject(prop);
|
||||
setContent(buildContentModelMultipart());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method builds {@link Multipart} based on {@link ContentModel}
|
||||
*
|
||||
* @param fileInfo - Source file information {@link FileInfo}
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private Multipart buildContentModelMultipart() throws MessagingException
|
||||
{
|
||||
MimeMultipart rootMultipart = new MimeMultipart("alternative");
|
||||
// Cite MOB-395: "email agent will be used to select an appropriate template" - we are not able to
|
||||
// detect an email agent so we use a default template for all messages.
|
||||
// See AlfrescoImapConst to see the possible templates to use.
|
||||
String bodyTxt = getEmailBodyText(EmailBodyType.TEXT_PLAIN);
|
||||
rootMultipart.addBodyPart(getTextBodyPart(bodyTxt, EmailBodyType.TEXT_PLAIN.getSubtype()));
|
||||
String bodyHtml = getEmailBodyText(EmailBodyType.TEXT_HTML);
|
||||
rootMultipart.addBodyPart(getTextBodyPart(bodyHtml, EmailBodyType.TEXT_HTML.getSubtype()));
|
||||
return rootMultipart;
|
||||
}
|
||||
|
||||
private MimeBodyPart getTextBodyPart(String bodyText, String subtype) throws MessagingException
|
||||
{
|
||||
MimeBodyPart result = new MimeBodyPart();
|
||||
result.setText(bodyText, UTF_8, subtype);
|
||||
result.addHeader(CONTENT_TRANSFER_ENCODING, BASE_64_ENCODING);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@@ -1,994 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.imap;
|
||||
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.CLASSPATH_TEXT_HTML_TEMPLATE;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.CLASSPATH_TEXT_PLAIN_TEMPLATE;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.DICTIONARY_TEMPLATE_PREFIX;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.mail.Flags;
|
||||
import javax.mail.Flags.Flag;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.ImapModel;
|
||||
import org.alfresco.repo.admin.patch.PatchInfo;
|
||||
import org.alfresco.repo.admin.patch.PatchService;
|
||||
import org.alfresco.repo.imap.config.ImapConfigBean;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.template.TemplateNode;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.preference.PreferenceService;
|
||||
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.repository.TemplateService;
|
||||
import org.alfresco.service.cmr.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.cmr.security.AccessStatus;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.cmr.site.SiteInfo;
|
||||
import org.alfresco.service.cmr.site.SiteService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.AbstractLifecycleBean;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* Helper class to access repository services by IMAP components. Also contains a common helper methods to search and
|
||||
* manage IMAP content and other usefull methods. Configured as {@code <bean id="imapHelper"
|
||||
* class="org.alfresco.repo.imap.ImapHelper">} in the {@code imap-server-context.xml} file.
|
||||
*
|
||||
* @author Dmitry Vaserin
|
||||
*/
|
||||
/*package*/class ImapHelper extends AbstractLifecycleBean
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(ImapHelper.class);
|
||||
|
||||
private static String PATCH_ID = "patch.imapFolders";
|
||||
|
||||
private NodeService nodeService;
|
||||
private SearchService searchService;
|
||||
private FileFolderService fileFolderService;
|
||||
private TemplateService templateService;
|
||||
private NamespaceService namespaceService;
|
||||
private PermissionService permissionService;
|
||||
private DictionaryService dictionaryService;
|
||||
private PreferenceService preferenceService;
|
||||
private SiteService siteService;
|
||||
|
||||
private ServiceRegistry serviceRegistry;
|
||||
|
||||
private PatchService patchService;
|
||||
|
||||
private String defaultFromAddress;
|
||||
private String webApplicationContextUrl = "http://localhost:8080/alfresco";
|
||||
private String repositoryTemplatePath;
|
||||
private String imapRoot;
|
||||
private NodeRef spacesStoreNodeRef;
|
||||
private NodeRef companyHomeNodeRef;
|
||||
private NodeRef imapRootNodeRef;
|
||||
|
||||
private boolean patchApplied = false;
|
||||
|
||||
private final static Map<QName, Flags.Flag> qNameToFlag;
|
||||
private final static Map<Flags.Flag, QName> flagToQname;
|
||||
|
||||
private Map<String, ImapConfigBean> imapConfigBeans = Collections.emptyMap();
|
||||
|
||||
static
|
||||
{
|
||||
qNameToFlag = new HashMap<QName, Flags.Flag>();
|
||||
qNameToFlag.put(ImapModel.PROP_FLAG_ANSWERED, Flags.Flag.ANSWERED);
|
||||
qNameToFlag.put(ImapModel.PROP_FLAG_DELETED, Flags.Flag.DELETED);
|
||||
qNameToFlag.put(ImapModel.PROP_FLAG_DRAFT, Flags.Flag.DRAFT);
|
||||
qNameToFlag.put(ImapModel.PROP_FLAG_SEEN, Flags.Flag.SEEN);
|
||||
qNameToFlag.put(ImapModel.PROP_FLAG_RECENT, Flags.Flag.RECENT);
|
||||
qNameToFlag.put(ImapModel.PROP_FLAG_FLAGGED, Flags.Flag.FLAGGED);
|
||||
|
||||
flagToQname = new HashMap<Flags.Flag, QName>();
|
||||
flagToQname.put(Flags.Flag.ANSWERED, ImapModel.PROP_FLAG_ANSWERED);
|
||||
flagToQname.put(Flags.Flag.DELETED, ImapModel.PROP_FLAG_DELETED);
|
||||
flagToQname.put(Flags.Flag.DRAFT, ImapModel.PROP_FLAG_DRAFT);
|
||||
flagToQname.put(Flags.Flag.SEEN, ImapModel.PROP_FLAG_SEEN);
|
||||
flagToQname.put(Flags.Flag.RECENT, ImapModel.PROP_FLAG_RECENT);
|
||||
flagToQname.put(Flags.Flag.FLAGGED, ImapModel.PROP_FLAG_FLAGGED);
|
||||
}
|
||||
|
||||
public static enum EmailBodyType
|
||||
{
|
||||
TEXT_PLAIN, TEXT_HTML;
|
||||
|
||||
public String getSubtype()
|
||||
{
|
||||
return name().toLowerCase().substring(5);
|
||||
}
|
||||
|
||||
public String getTypeSubtype()
|
||||
{
|
||||
return name().toLowerCase().replaceAll("_", "");
|
||||
}
|
||||
|
||||
public String getMimeType()
|
||||
{
|
||||
return name().toLowerCase().replaceAll("_", "/");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onShutdown(ApplicationEvent event)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBootstrap(ApplicationEvent event)
|
||||
{
|
||||
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
List<PatchInfo> patches = getPatchService().getPatches(null, null);
|
||||
for (PatchInfo patch : patches)
|
||||
{
|
||||
if (patch.getId().equals(PATCH_ID))
|
||||
{
|
||||
patchApplied = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!patchApplied)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int indexOfStoreDelim = imapRoot.indexOf(StoreRef.URI_FILLER);
|
||||
|
||||
if (indexOfStoreDelim == -1)
|
||||
{
|
||||
throw new RuntimeException("Bad path format, " + StoreRef.URI_FILLER + " not found");
|
||||
}
|
||||
|
||||
indexOfStoreDelim += StoreRef.URI_FILLER.length();
|
||||
|
||||
int indexOfPathDelim = imapRoot.indexOf("/", indexOfStoreDelim);
|
||||
|
||||
if (indexOfPathDelim == -1)
|
||||
{
|
||||
throw new java.lang.RuntimeException("Bad path format, / not found");
|
||||
}
|
||||
|
||||
String storePath = imapRoot.substring(0, indexOfPathDelim);
|
||||
String rootPathInStore = imapRoot.substring(indexOfPathDelim);
|
||||
|
||||
StoreRef storeRef = new StoreRef(storePath);
|
||||
|
||||
if (nodeService.exists(storeRef) == false)
|
||||
{
|
||||
throw new RuntimeException("No store for path: " + storeRef);
|
||||
}
|
||||
|
||||
NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef);
|
||||
|
||||
List<NodeRef> nodeRefs = searchService.selectNodes(storeRootNodeRef, rootPathInStore, null, namespaceService, false);
|
||||
|
||||
if (nodeRefs.size() > 1)
|
||||
{
|
||||
throw new RuntimeException("Multiple possible roots for : \n" + " root path: " + rootPathInStore + "\n" + " results: " + nodeRefs);
|
||||
}
|
||||
else if (nodeRefs.size() == 0)
|
||||
{
|
||||
throw new RuntimeException("No root found for : \n" + " root path: " + rootPathInStore);
|
||||
}
|
||||
|
||||
imapRootNodeRef = nodeRefs.get(0);
|
||||
|
||||
// Get "Company Home" node reference
|
||||
StoreRef store = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");
|
||||
ResultSet rs = searchService.query(store, SearchService.LANGUAGE_XPATH, "/app:company_home");
|
||||
try
|
||||
{
|
||||
if (rs.length() == 0)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("'Company Home' space doesn't exists.");
|
||||
}
|
||||
companyHomeNodeRef = rs.getNodeRef(0);
|
||||
}
|
||||
finally
|
||||
{
|
||||
rs.close();
|
||||
}
|
||||
|
||||
spacesStoreNodeRef = nodeService.getRootNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
|
||||
|
||||
return null;
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for files in specified context
|
||||
*
|
||||
* @param contextNodeRef context folder for search
|
||||
* @param namePattern name pattern for search
|
||||
* @param searchType type for search
|
||||
* @param includeSubFolders include SubFolders
|
||||
* @return list of files with specifed type
|
||||
*/
|
||||
public List<FileInfo> searchFiles(NodeRef contextNodeRef, String namePattern, QName searchType, boolean includeSubFolders)
|
||||
{
|
||||
return search(contextNodeRef, namePattern, searchType, true, false, includeSubFolders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for mailboxes in specified context
|
||||
*
|
||||
* @param contextNodeRef context folder for search
|
||||
* @param namePattern name pattern for search
|
||||
* @param includeSubFolders include SubFolders
|
||||
* @param isVirtualView is folder in "Virtual" View
|
||||
* @return list of mailboxes
|
||||
*/
|
||||
public List<FileInfo> searchFolders(NodeRef contextNodeRef, String namePattern, boolean includeSubFolders, boolean isVirtualView)
|
||||
{
|
||||
QName searchType = ContentModel.TYPE_FOLDER;
|
||||
if (isVirtualView)
|
||||
{
|
||||
searchType = null;
|
||||
}
|
||||
|
||||
List<FileInfo> result = search(contextNodeRef, namePattern, searchType, false, true, includeSubFolders);
|
||||
if (isVirtualView)
|
||||
{
|
||||
List<SiteInfo> nonFavSites = getNonFavouriteSites(getCurrentUser());
|
||||
for (SiteInfo siteInfo : nonFavSites)
|
||||
{
|
||||
FileInfo nonFavSite = fileFolderService.getFileInfo(siteInfo.getNodeRef());
|
||||
List<FileInfo> siteChilds = search(nonFavSite.getNodeRef(), namePattern, null, false, true, true);
|
||||
result.removeAll(siteChilds);
|
||||
result.remove(nonFavSite);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove folders from Sites
|
||||
List<SiteInfo> sites = siteService.listSites(getCurrentUser());
|
||||
for (SiteInfo siteInfo : sites)
|
||||
{
|
||||
List<FileInfo> siteChilds = search(siteInfo.getNodeRef(), namePattern, null, false, true, true);
|
||||
result.removeAll(siteChilds);
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for emails in specified folder depend on view mode.
|
||||
*
|
||||
* @param contextNodeRef context folder for search
|
||||
* @param namePattern name pattern for search
|
||||
* @param viewMode context folder view mode
|
||||
* @param includeSubFolders includeSubFolders
|
||||
* @return list of emails that context folder contains.
|
||||
*/
|
||||
public List<FileInfo> searchMails(NodeRef contextNodeRef, String namePattern, String viewMode, boolean includeSubFolders)
|
||||
{
|
||||
|
||||
List<FileInfo> result = new LinkedList<FileInfo>();
|
||||
if (viewMode.equals(AlfrescoImapConst.MODE_ARCHIVE))
|
||||
{
|
||||
result = search(contextNodeRef, namePattern, ImapModel.TYPE_IMAP_CONTENT, false, true, includeSubFolders);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (viewMode.equals(AlfrescoImapConst.MODE_VIRTUAL))
|
||||
{
|
||||
result = search(contextNodeRef, namePattern, null, true, false, includeSubFolders);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<FileInfo> search(NodeRef contextNodeRef, String namePattern, QName searchType, boolean fileSearch, boolean folderSearch, boolean includeSubFolders)
|
||||
{
|
||||
List<FileInfo> result = new LinkedList<FileInfo>();
|
||||
List<FileInfo> searchResult = fileFolderService.search(contextNodeRef, namePattern, fileSearch, folderSearch, includeSubFolders);
|
||||
|
||||
if (searchType == null)
|
||||
{
|
||||
return searchResult;
|
||||
}
|
||||
|
||||
for (FileInfo fileInfo : searchResult)
|
||||
{
|
||||
if (nodeService.getType(fileInfo.getNodeRef()).equals(searchType))
|
||||
{
|
||||
result.add(fileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get root reference for the specified mailbox
|
||||
*
|
||||
* @param mailboxName mailbox name in IMAP client.
|
||||
* @param userName
|
||||
* @return
|
||||
*/
|
||||
public NodeRef getMailboxRootRef(String mailboxName, String userName)
|
||||
{
|
||||
String rootFolder;
|
||||
int index = mailboxName.indexOf(AlfrescoImapConst.HIERARCHY_DELIMITER);
|
||||
if (index > 0)
|
||||
{
|
||||
rootFolder = mailboxName.substring(0, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
rootFolder = mailboxName;
|
||||
}
|
||||
|
||||
Map<String, ImapConfigBean> imapConfigs = getImapConfig();
|
||||
if (imapConfigs.keySet().contains(rootFolder))
|
||||
{
|
||||
Map<String, NodeRef> mountPoints = getMountPoints();
|
||||
NodeRef mountRef = mountPoints.get(rootFolder);
|
||||
return nodeService.getParentAssocs(mountRef).get(0).getParentRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
return getUserImapHomeRef(userName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param userName user name
|
||||
* @return user IMAP home reference and create it if it doesn't exist.
|
||||
*/
|
||||
public NodeRef getUserImapHomeRef(final String userName)
|
||||
{
|
||||
NodeRef userHome = fileFolderService.searchSimple(imapRootNodeRef, userName);
|
||||
if (userHome == null)
|
||||
{
|
||||
// create user home
|
||||
userHome = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<NodeRef>()
|
||||
{
|
||||
public NodeRef doWork() throws Exception
|
||||
{
|
||||
NodeRef result = fileFolderService.create(imapRootNodeRef, userName, ContentModel.TYPE_FOLDER).getNodeRef();
|
||||
nodeService.setProperty(result, ContentModel.PROP_DESCRIPTION, userName);
|
||||
// create inbox
|
||||
fileFolderService.create(result, AlfrescoImapConst.INBOX_NAME, ContentModel.TYPE_FOLDER);
|
||||
return result;
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
return userHome;
|
||||
}
|
||||
|
||||
public String getCurrentUser()
|
||||
{
|
||||
return AuthenticationUtil.getFullyAuthenticatedUser();
|
||||
}
|
||||
|
||||
public String getUserImapHomeId(String userName)
|
||||
{
|
||||
return getUserImapHomeRef(userName).getId();
|
||||
}
|
||||
|
||||
public NodeRef getImapRootNodeRef()
|
||||
{
|
||||
return imapRootNodeRef;
|
||||
}
|
||||
|
||||
public NodeRef getCompanyHomeNodeRef()
|
||||
{
|
||||
return companyHomeNodeRef;
|
||||
}
|
||||
|
||||
public NodeRef getSpacesStoreNodeRef()
|
||||
{
|
||||
return spacesStoreNodeRef;
|
||||
}
|
||||
|
||||
public void setImapRoot(String imapRoot)
|
||||
{
|
||||
this.imapRoot = imapRoot;
|
||||
}
|
||||
|
||||
public String getDefaultFromAddress()
|
||||
{
|
||||
return defaultFromAddress;
|
||||
}
|
||||
|
||||
public void setDefaultFromAddress(String defaultFromAddress)
|
||||
{
|
||||
this.defaultFromAddress = defaultFromAddress;
|
||||
}
|
||||
|
||||
public String getWebApplicationContextUrl()
|
||||
{
|
||||
return this.webApplicationContextUrl;
|
||||
}
|
||||
|
||||
public void setWebApplicationContextUrl(String webApplicationContextUrl)
|
||||
{
|
||||
this.webApplicationContextUrl = webApplicationContextUrl;
|
||||
}
|
||||
|
||||
public String getRepositoryTemplatePath()
|
||||
{
|
||||
return repositoryTemplatePath;
|
||||
}
|
||||
|
||||
public void setRepositoryTemplatePath(String repositoryTemplatePath)
|
||||
{
|
||||
this.repositoryTemplatePath = repositoryTemplatePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return flags that belong to the specified imap folder.
|
||||
*
|
||||
* @param messageInfo imap folder info.
|
||||
* @return flags.
|
||||
*/
|
||||
public Flags getFlags(FileInfo messageInfo)
|
||||
{
|
||||
Flags flags = new Flags();
|
||||
checkForFlaggableAspect(messageInfo.getNodeRef());
|
||||
Map<QName, Serializable> props = nodeService.getProperties(messageInfo.getNodeRef());
|
||||
|
||||
for (QName key : qNameToFlag.keySet())
|
||||
{
|
||||
Boolean value = (Boolean) props.get(key);
|
||||
if (value != null && value)
|
||||
{
|
||||
flags.add(qNameToFlag.get(key));
|
||||
}
|
||||
}
|
||||
// This is a multiuser flag support. Commented due new requirements
|
||||
// for (QName key : qNameToFlag.keySet())
|
||||
// {
|
||||
// if (key.equals(ImapModel.PROP_FLAG_DELETED))
|
||||
// {
|
||||
// Boolean value = (Boolean) props.get(key);
|
||||
// if (value != null && value)
|
||||
// {
|
||||
// flags.add(qNameToFlag.get(key));
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// String users = (String) props.get(key);
|
||||
//
|
||||
// if (users != null && users.indexOf(formatUserEntry(getCurrentUser())) >= 0)
|
||||
// {
|
||||
// flags.add(qNameToFlag.get(key));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set flags to the specified imapFolder.
|
||||
*
|
||||
* @param messageInfo FileInfo of imap Folder.
|
||||
* @param flags flags to set.
|
||||
* @param value value to set.
|
||||
*/
|
||||
public void setFlags(FileInfo messageInfo, Flags flags, boolean value)
|
||||
{
|
||||
checkForFlaggableAspect(messageInfo.getNodeRef());
|
||||
for (Flags.Flag flag : flags.getSystemFlags())
|
||||
{
|
||||
setFlag(messageInfo, flag, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set flags to the specified imapFolder.
|
||||
*
|
||||
* @param messageInfo FileInfo of imap Folder
|
||||
* @param flag flag to set.
|
||||
* @param value value value to set.
|
||||
*/
|
||||
public void setFlag(final FileInfo messageInfo, final Flag flag, final boolean value)
|
||||
{
|
||||
checkForFlaggableAspect(messageInfo.getNodeRef());
|
||||
nodeService.setProperty(messageInfo.getNodeRef(), flagToQname.get(flag), value);
|
||||
|
||||
// This is a multiuser flag support. Commented due new requirements
|
||||
// if (flagToQname.get(flag).equals(ImapModel.PROP_FLAG_DELETED))
|
||||
// {
|
||||
// nodeService.setProperty(messageInfo.getNodeRef(), flagToQname.get(flag), value);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Void>()
|
||||
// {
|
||||
// public Void doWork() throws Exception
|
||||
// {
|
||||
//
|
||||
// String users = (String) nodeService.getProperty(messageInfo.getNodeRef(), flagToQname.get(flag));
|
||||
// if (value)
|
||||
// {
|
||||
// if (users == null)
|
||||
// {
|
||||
// users = "";
|
||||
// }
|
||||
// users += formatUserEntry(getCurrentUser());
|
||||
//
|
||||
// }
|
||||
// else if (users != null)
|
||||
// {
|
||||
// users = users.replace(formatUserEntry(getCurrentUser()), "");
|
||||
//
|
||||
// }
|
||||
// nodeService.setProperty(messageInfo.getNodeRef(), flagToQname.get(flag), users);
|
||||
// return null;
|
||||
// }
|
||||
// }, AuthenticationUtil.getSystemUserName());
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the given authentication has a particular permission for the given node.
|
||||
*
|
||||
* @param nodeRef nodeRef of the node
|
||||
* @param permission permission for check
|
||||
* @return the access status
|
||||
*/
|
||||
public AccessStatus hasPermission(NodeRef nodeRef, String permission)
|
||||
{
|
||||
return permissionService.hasPermission(nodeRef, permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change userName into following format ;userName;
|
||||
*
|
||||
* @param userName
|
||||
* @return
|
||||
*/
|
||||
public String formatUserEntry(String userName)
|
||||
{
|
||||
return AlfrescoImapConst.USER_SEPARATOR + userName + AlfrescoImapConst.USER_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should returns a unique identifier of Alfresco server. The possible UID may be calculated based on IP address, Server port, MAC address, Web Application context.
|
||||
* This UID should be parseable into initial components. This necessary for the implementation of the following case: If the message being copied (e.g. drag-and-drop) between
|
||||
* two different Alfresco accounts in the IMAP client, we must unambiguously identify from which Alfresco server this message being copied. The message itself does not contain
|
||||
* content data, so we must download it from the initial server (e.g. using download content servlet) and save it into destination repository.
|
||||
*
|
||||
* @return String representation of unique identifier of Alfresco server
|
||||
*/
|
||||
public String getAlfrescoServerUID()
|
||||
{
|
||||
// TODO Implement as javadoc says.
|
||||
return "Not-Implemented";
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of mount points. Name of mount point == key in the map.
|
||||
*
|
||||
* @return Map of mount points.
|
||||
*/
|
||||
public Map<String, NodeRef> getMountPoints()
|
||||
{
|
||||
Map<String, ImapConfigBean> imapConfigs = getImapConfig();
|
||||
Map<String, NodeRef> mountPoints = new HashMap<String, NodeRef>();
|
||||
|
||||
for (ImapConfigBean config : imapConfigs.values())
|
||||
{
|
||||
// Get node reference
|
||||
StoreRef store = new StoreRef(config.getStore());
|
||||
ResultSet rs = searchService.query(store, SearchService.LANGUAGE_XPATH, config.getRootPath());
|
||||
if (rs.length() == 0)
|
||||
{
|
||||
logger.warn("Didn't find " + config.getName());
|
||||
}
|
||||
else
|
||||
{
|
||||
NodeRef nodeRef = rs.getNodeRef(0);
|
||||
mountPoints.put(config.getName(), nodeRef);
|
||||
}
|
||||
rs.close();
|
||||
}
|
||||
return mountPoints;
|
||||
}
|
||||
|
||||
public void setImapConfigBeans(ImapConfigBean[] imapConfigBeans)
|
||||
{
|
||||
this.imapConfigBeans = new LinkedHashMap<String, ImapConfigBean>(imapConfigBeans.length * 2);
|
||||
for (ImapConfigBean bean : imapConfigBeans)
|
||||
{
|
||||
this.imapConfigBeans.put(bean.getName(), bean);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return map of imap configs. Name of config == key in the map
|
||||
*
|
||||
* @return map of imap configs.
|
||||
*/
|
||||
public Map<String, ImapConfigBean> getImapConfig()
|
||||
{
|
||||
return this.imapConfigBeans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return view mode ("virtual" or "archive") for specified mailbox.
|
||||
*
|
||||
* @param mailboxName name of the mailbox in IMAP client.
|
||||
* @return view mode of the specified mailbox.
|
||||
*/
|
||||
public String getViewMode(String mailboxName)
|
||||
{
|
||||
String rootFolder;
|
||||
int index = mailboxName.indexOf(AlfrescoImapConst.HIERARCHY_DELIMITER);
|
||||
if (index > 0)
|
||||
{
|
||||
rootFolder = mailboxName.substring(0, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
rootFolder = mailboxName;
|
||||
}
|
||||
Map<String, ImapConfigBean> imapConfigs = getImapConfig();
|
||||
if (imapConfigs.keySet().contains(rootFolder))
|
||||
{
|
||||
return imapConfigs.get(rootFolder).getMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
return AlfrescoImapConst.MODE_ARCHIVE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return mount point name, which was specified in imap-config.xml for the current mailbox.
|
||||
*
|
||||
* @param mailboxName mailbox name in IMAP client.
|
||||
* @return mount point name or null.
|
||||
*/
|
||||
public String getMountPointName(String mailboxName)
|
||||
{
|
||||
String rootFolder;
|
||||
int index = mailboxName.indexOf(AlfrescoImapConst.HIERARCHY_DELIMITER);
|
||||
if (index > 0)
|
||||
{
|
||||
rootFolder = mailboxName.substring(0, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
rootFolder = mailboxName;
|
||||
}
|
||||
Map<String, ImapConfigBean> imapConfigs = getImapConfig();
|
||||
if (imapConfigs.keySet().contains(rootFolder))
|
||||
{
|
||||
return rootFolder;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert mailpath from IMAP client representation to the alfresco representation view. (e.g. with default settings "getMailPathInRepo(Repository_virtual.Imap Home)" will
|
||||
* return "Company Home.Imap Home")
|
||||
*
|
||||
* @param mailPath mailbox path in IMAP client
|
||||
* @return mailbox path in alfresco
|
||||
*/
|
||||
public String getMailPathInRepo(String mailPath)
|
||||
{
|
||||
String rootFolder;
|
||||
String remain = "";
|
||||
int index = mailPath.indexOf(AlfrescoImapConst.HIERARCHY_DELIMITER);
|
||||
if (index > 0)
|
||||
{
|
||||
rootFolder = mailPath.substring(0, index);
|
||||
remain = mailPath.substring(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
rootFolder = mailPath;
|
||||
}
|
||||
Map<String, ImapConfigBean> imapConfigs = getImapConfig();
|
||||
if (imapConfigs.keySet().contains(rootFolder))
|
||||
{
|
||||
Map<String, NodeRef> mountPoints = getMountPoints();
|
||||
NodeRef rootRef = mountPoints.get(rootFolder);
|
||||
String rootName = nodeService.getProperty(rootRef, ContentModel.PROP_NAME).toString();
|
||||
|
||||
return rootName + remain;
|
||||
}
|
||||
else
|
||||
{
|
||||
return mailPath;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of sites, that belong to the specified user and not marked as "Imap favourite"
|
||||
*
|
||||
* @param userName name of user
|
||||
* @return List of nonFavourite sites.
|
||||
*/
|
||||
public List<SiteInfo> getNonFavouriteSites(String userName)
|
||||
{
|
||||
List<SiteInfo> nonFavSites = new LinkedList<SiteInfo>();
|
||||
Map<String, Serializable> prefs = preferenceService.getPreferences(userName, AlfrescoImapConst.PREF_IMAP_FAVOURITE_SITES);
|
||||
List<SiteInfo> sites = siteService.listSites(userName);
|
||||
for (SiteInfo siteInfo : sites)
|
||||
{
|
||||
String key = AlfrescoImapConst.PREF_IMAP_FAVOURITE_SITES + "." + siteInfo.getShortName();
|
||||
Boolean isImapFavourite = (Boolean) prefs.get(key);
|
||||
if (isImapFavourite == null || !isImapFavourite)
|
||||
{
|
||||
nonFavSites.add(siteInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return nonFavSites;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text representing email body for ContentModel node.
|
||||
*
|
||||
* @param nodeRef NodeRef of the target content.
|
||||
* @param type The type of the returned body. May be the one of {@link EmailBodyType}.
|
||||
* @return Text representing email body for ContentModel node.
|
||||
*/
|
||||
public String getEmailBodyText(NodeRef nodeRef, EmailBodyType type)
|
||||
{
|
||||
return templateService.processTemplate(getDefaultEmailBodyTemplate(type), createEmailTemplateModel(nodeRef));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns default email body template. This method trying to find a template on the path in the repository first e.g. {@code "Data Dictionary > IMAP Templates >"}. This path
|
||||
* should be set as the property of the "imapHelper" bean. In this case it returns {@code NodeRef.toString()} of the template. If there are no template in the repository it
|
||||
* returns a default template on the classpath.
|
||||
*
|
||||
* @param type One of the {@link EmailBodyType}.
|
||||
* @return String representing template classpath path or NodeRef.toString().
|
||||
*/
|
||||
public String getDefaultEmailBodyTemplate(EmailBodyType type)
|
||||
{
|
||||
String result = null;
|
||||
switch (type)
|
||||
{
|
||||
case TEXT_HTML:
|
||||
result = CLASSPATH_TEXT_HTML_TEMPLATE;
|
||||
break;
|
||||
case TEXT_PLAIN:
|
||||
result = CLASSPATH_TEXT_PLAIN_TEMPLATE;
|
||||
break;
|
||||
}
|
||||
final StringBuilder templateName = new StringBuilder(DICTIONARY_TEMPLATE_PREFIX).append("-").append(type.getTypeSubtype()).append(".ftl");
|
||||
int indexOfStoreDelim = repositoryTemplatePath.indexOf(StoreRef.URI_FILLER);
|
||||
if (indexOfStoreDelim == -1)
|
||||
{
|
||||
logger.error("Bad path format, " + StoreRef.URI_FILLER + " not found");
|
||||
return result;
|
||||
}
|
||||
indexOfStoreDelim += StoreRef.URI_FILLER.length();
|
||||
int indexOfPathDelim = repositoryTemplatePath.indexOf("/", indexOfStoreDelim);
|
||||
if (indexOfPathDelim == -1)
|
||||
{
|
||||
logger.error("Bad path format, / not found");
|
||||
return result;
|
||||
}
|
||||
final String storePath = repositoryTemplatePath.substring(0, indexOfPathDelim);
|
||||
final String rootPathInStore = repositoryTemplatePath.substring(indexOfPathDelim);
|
||||
final String query = String.format("+PATH:\"%1$s/*\" +@cm\\:name:\"%2$s\"", rootPathInStore, templateName.toString());
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Using template path :" + repositoryTemplatePath + "/" + templateName);
|
||||
logger.debug("Query: " + query);
|
||||
}
|
||||
StoreRef storeRef = new StoreRef(storePath);
|
||||
ResultSet resultSet = searchService.query(storeRef, "lucene", query);
|
||||
if (resultSet == null || resultSet.length() == 0)
|
||||
{
|
||||
logger.error(String.format("IMAP message template '%1$s' does not exist in the path '%2$s'.", templateName, repositoryTemplatePath));
|
||||
return result;
|
||||
}
|
||||
result = resultSet.getNodeRef(0).toString();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds default email template model for TemplateProcessor
|
||||
*
|
||||
* @param ref NodeRef of the target content.
|
||||
* @return Map that includes template model objects.
|
||||
*/
|
||||
private Map<String, Object> createEmailTemplateModel(NodeRef ref)
|
||||
{
|
||||
Map<String, Object> model = new HashMap<String, Object>(8, 1.0f);
|
||||
TemplateNode tn = new TemplateNode(ref, serviceRegistry, null);
|
||||
model.put("document", tn);
|
||||
NodeRef parent = nodeService.getPrimaryParent(ref).getParentRef();
|
||||
model.put("space", new TemplateNode(parent, serviceRegistry, null));
|
||||
model.put("date", new Date());
|
||||
model.put("contextUrl", new String(getWebApplicationContextUrl()));
|
||||
model.put("alfTicket", new String(serviceRegistry.getAuthenticationService().getCurrentTicket()));
|
||||
return model;
|
||||
}
|
||||
|
||||
private void checkForFlaggableAspect(NodeRef nodeRef)
|
||||
{
|
||||
if (!nodeService.hasAspect(nodeRef, ImapModel.ASPECT_FLAGGABLE))
|
||||
{
|
||||
Map<QName, Serializable> aspectProperties = new HashMap<QName, Serializable>();
|
||||
nodeService.addAspect(nodeRef, ImapModel.ASPECT_FLAGGABLE, aspectProperties);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPatchApplied()
|
||||
{
|
||||
return patchApplied;
|
||||
}
|
||||
|
||||
// ----------------------Getters and Setters----------------------------
|
||||
|
||||
public NodeService getNodeService()
|
||||
{
|
||||
return nodeService;
|
||||
}
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public SearchService getSearchService()
|
||||
{
|
||||
return searchService;
|
||||
}
|
||||
|
||||
public void setSearchService(SearchService searchService)
|
||||
{
|
||||
this.searchService = searchService;
|
||||
}
|
||||
|
||||
public FileFolderService getFileFolderService()
|
||||
{
|
||||
return fileFolderService;
|
||||
}
|
||||
|
||||
public void setFileFolderService(FileFolderService fileFolderService)
|
||||
{
|
||||
this.fileFolderService = fileFolderService;
|
||||
}
|
||||
|
||||
public TemplateService getTemplateService()
|
||||
{
|
||||
return templateService;
|
||||
}
|
||||
|
||||
public void setTemplateService(TemplateService templateService)
|
||||
{
|
||||
this.templateService = templateService;
|
||||
}
|
||||
|
||||
public NamespaceService getNamespaceService()
|
||||
{
|
||||
return namespaceService;
|
||||
}
|
||||
|
||||
public void setNamespaceService(NamespaceService namespaceService)
|
||||
{
|
||||
this.namespaceService = namespaceService;
|
||||
}
|
||||
|
||||
public PermissionService getPermissionService()
|
||||
{
|
||||
return permissionService;
|
||||
}
|
||||
|
||||
public void setPermissionService(PermissionService permissionService)
|
||||
{
|
||||
this.permissionService = permissionService;
|
||||
}
|
||||
|
||||
public DictionaryService getDictionaryService()
|
||||
{
|
||||
return dictionaryService;
|
||||
}
|
||||
|
||||
public void setDictionaryService(DictionaryService dictionaryService)
|
||||
{
|
||||
this.dictionaryService = dictionaryService;
|
||||
}
|
||||
|
||||
public PreferenceService getPreferenceService()
|
||||
{
|
||||
return preferenceService;
|
||||
}
|
||||
|
||||
public void setPreferenceService(PreferenceService preferenceService)
|
||||
{
|
||||
this.preferenceService = preferenceService;
|
||||
}
|
||||
|
||||
public SiteService getSiteService()
|
||||
{
|
||||
return siteService;
|
||||
}
|
||||
|
||||
public void setSiteService(SiteService siteService)
|
||||
{
|
||||
this.siteService = siteService;
|
||||
}
|
||||
|
||||
public ServiceRegistry getServiceRegistry()
|
||||
{
|
||||
return serviceRegistry;
|
||||
}
|
||||
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
public PatchService getPatchService()
|
||||
{
|
||||
return patchService;
|
||||
}
|
||||
|
||||
public void setPatchService(PatchService patchService)
|
||||
{
|
||||
this.patchService = patchService;
|
||||
}
|
||||
|
||||
}
|
144
source/java/org/alfresco/repo/imap/ImapModelMessage.java
Executable file
144
source/java/org/alfresco/repo/imap/ImapModelMessage.java
Executable file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.imap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.util.SharedByteArrayInputStream;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.ContentIOException;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Extended MimeMessage to represent a content stored in the Alfresco repository.
|
||||
*
|
||||
* @author Arseny Kovalchuk
|
||||
*/
|
||||
public class ImapModelMessage extends AbstractMimeMessage
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(ImapModelMessage.class);
|
||||
|
||||
/**
|
||||
* Constructs {@link ImapModelMessage} object.
|
||||
*
|
||||
* @param fileInfo - reference to the {@link FileInfo} object representing the message.
|
||||
* @param imapHelper - reference to the {@link ImapHelper} object.
|
||||
* @param generateBody - if {@code true} message body will be generated.
|
||||
*
|
||||
* @throws MessagingException if generation of the body fails.
|
||||
*/
|
||||
public ImapModelMessage(FileInfo fileInfo, ServiceRegistry serviceRegistry, boolean generateBody) throws MessagingException
|
||||
{
|
||||
super(fileInfo, serviceRegistry, generateBody);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildMessageInternal() throws MessagingException
|
||||
{
|
||||
if (generateBody != false)
|
||||
{
|
||||
setMessageHeaders();
|
||||
buildImapMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method builds MimeMessage based on either ImapModel or ContentModel type.
|
||||
*
|
||||
* @param fileInfo - Source file information {@link FileInfo}
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private void buildImapMessage() throws MessagingException
|
||||
{
|
||||
modified = false;
|
||||
saved = false;
|
||||
buildRFC822Message();
|
||||
saved = true;
|
||||
}
|
||||
|
||||
private void buildRFC822Message() throws MessagingException
|
||||
{
|
||||
ContentService contentService = serviceRegistry.getContentService();
|
||||
ContentReader reader = contentService.getReader(messageFileInfo.getNodeRef(), ContentModel.PROP_CONTENT);
|
||||
try
|
||||
{
|
||||
InputStream is = reader.getContentInputStream();
|
||||
this.parse(is);
|
||||
is.close();
|
||||
is = null;
|
||||
}
|
||||
catch (ContentIOException e)
|
||||
{
|
||||
//logger.error(e);
|
||||
throw new MessagingException("The error occured during message creation from content stream.", e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
//logger.error(e);
|
||||
throw new MessagingException("The error occured during message creation from content stream.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InputStream getContentStream() throws MessagingException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this.contentStream == null)
|
||||
{
|
||||
if (content != null)
|
||||
{
|
||||
return new SharedByteArrayInputStream(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MessagingException("No content");
|
||||
}
|
||||
}
|
||||
return this.contentStream;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new MessagingException(e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
protected void parse(InputStream inputstream) throws MessagingException
|
||||
{
|
||||
headers = createInternetHeaders(inputstream);
|
||||
contentStream = inputstream;
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
75
source/java/org/alfresco/repo/imap/ImapService.java
Executable file
75
source/java/org/alfresco/repo/imap/ImapService.java
Executable file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.imap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.mail.Flags;
|
||||
import javax.mail.Flags.Flag;
|
||||
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
|
||||
/**
|
||||
* @author Arseny Kovalchuk
|
||||
*/
|
||||
public interface ImapService
|
||||
{
|
||||
public List<AlfrescoImapFolder> listMailboxes(AlfrescoImapUser user, String mailboxPattern);
|
||||
|
||||
public List<AlfrescoImapFolder> listSubscribedMailboxes(AlfrescoImapUser user, String mailboxPattern);
|
||||
|
||||
public AlfrescoImapFolder createMailbox(AlfrescoImapUser user, String mailboxName);
|
||||
|
||||
public void deleteMailbox(AlfrescoImapUser user, String mailboxName);
|
||||
|
||||
public void renameMailbox(AlfrescoImapUser user, String oldMailboxName, String newMailboxName);
|
||||
|
||||
public AlfrescoImapFolder getFolder(AlfrescoImapUser user, String mailboxName);
|
||||
|
||||
public void subscribe(AlfrescoImapUser user, String mailbox);
|
||||
|
||||
public void unsubscribe(AlfrescoImapUser user, String mailbox);
|
||||
|
||||
public List<FileInfo> searchFiles(NodeRef contextNodeRef, String namePattern, boolean includeSubFolders);
|
||||
|
||||
public List<FileInfo> searchFolders(NodeRef contextNodeRef, String namePattern, boolean includeSubFolders, String viewMode);
|
||||
|
||||
public List<FileInfo> searchMails(NodeRef contextNodeRef, String namePattern, String viewMode, boolean includeSubFolders);
|
||||
|
||||
public Flags getFlags(FileInfo messageFileInfo);
|
||||
|
||||
public void setFlags(FileInfo messageFileInfo, Flags flags, boolean value);
|
||||
|
||||
public void setFlag(FileInfo messageFileInfo, Flag flag, boolean value);
|
||||
|
||||
public String getDefaultFromAddress();
|
||||
|
||||
public String getRepositoryTemplatePath();
|
||||
|
||||
public String getWebApplicationContextUrl();
|
||||
|
||||
}
|
1284
source/java/org/alfresco/repo/imap/ImapServiceImpl.java
Executable file
1284
source/java/org/alfresco/repo/imap/ImapServiceImpl.java
Executable file
File diff suppressed because it is too large
Load Diff
417
source/java/org/alfresco/repo/imap/ImapServiceImplTest.java
Executable file
417
source/java/org/alfresco/repo/imap/ImapServiceImplTest.java
Executable file
@@ -0,0 +1,417 @@
|
||||
package org.alfresco.repo.imap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.mail.Flags;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.ImapModel;
|
||||
import org.alfresco.repo.importer.ACPImportPackageHandler;
|
||||
import org.alfresco.repo.node.integrity.IntegrityChecker;
|
||||
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
||||
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.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.cmr.security.AuthenticationService;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.cmr.view.ImporterService;
|
||||
import org.alfresco.service.cmr.view.Location;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.alfresco.util.PropertyMap;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
public class ImapServiceImplTest extends TestCase
|
||||
{
|
||||
|
||||
private static final String USER_NAME = "admin";
|
||||
private static final String USER_PASSWORD = "admin";
|
||||
|
||||
private static final String MAILBOX_NAME_A = "mailbox_a";
|
||||
private static final String MAILBOX_NAME_B = "mailbox_b";
|
||||
private static final String MAILBOX_PATTERN = "mailbox*";
|
||||
private static final String FOLDER_PATTERN = "___-___folder*";
|
||||
private static final String FILE_PATTERN = "___-___file*";
|
||||
|
||||
private static final ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||
private TransactionService transactionService;
|
||||
private NodeService nodeService;
|
||||
private ImporterService importerService;
|
||||
private PersonService personService;
|
||||
private AuthenticationService authenticationService;
|
||||
private PermissionService permissionService;
|
||||
private SearchService searchService;
|
||||
private NamespaceService namespaceService;
|
||||
|
||||
private AlfrescoImapUser user;
|
||||
private ImapService imapService;
|
||||
private UserTransaction txn;
|
||||
|
||||
private NodeRef companyHomeNodeRef;
|
||||
|
||||
private Flags flags;
|
||||
|
||||
String anotherUserName;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean("ServiceRegistry");
|
||||
transactionService = serviceRegistry.getTransactionService();
|
||||
nodeService = serviceRegistry.getNodeService();
|
||||
importerService = serviceRegistry.getImporterService();
|
||||
personService = serviceRegistry.getPersonService();
|
||||
authenticationService = serviceRegistry.getAuthenticationService();
|
||||
permissionService = serviceRegistry.getPermissionService();
|
||||
imapService = serviceRegistry.getImapService();
|
||||
searchService = serviceRegistry.getSearchService();
|
||||
namespaceService = serviceRegistry.getNamespaceService();
|
||||
|
||||
flags = new Flags();
|
||||
flags.add(Flags.Flag.SEEN);
|
||||
flags.add(Flags.Flag.FLAGGED);
|
||||
flags.add(Flags.Flag.ANSWERED);
|
||||
flags.add(Flags.Flag.DELETED);
|
||||
|
||||
// start the transaction
|
||||
txn = transactionService.getUserTransaction();
|
||||
txn.begin();
|
||||
authenticationService.authenticate(USER_NAME, USER_PASSWORD.toCharArray());
|
||||
|
||||
// downgrade integrity
|
||||
IntegrityChecker.setWarnInTransaction();
|
||||
|
||||
anotherUserName = "user" + System.currentTimeMillis();
|
||||
|
||||
PropertyMap testUser = new PropertyMap();
|
||||
testUser.put(ContentModel.PROP_USERNAME, anotherUserName);
|
||||
testUser.put(ContentModel.PROP_FIRSTNAME, anotherUserName);
|
||||
testUser.put(ContentModel.PROP_LASTNAME, anotherUserName);
|
||||
testUser.put(ContentModel.PROP_EMAIL, anotherUserName + "@alfresco.com");
|
||||
testUser.put(ContentModel.PROP_JOBTITLE, "jobTitle");
|
||||
|
||||
personService.createPerson(testUser);
|
||||
|
||||
// create the ACEGI Authentication instance for the new user
|
||||
authenticationService.createAuthentication(anotherUserName, anotherUserName.toCharArray());
|
||||
|
||||
user = new AlfrescoImapUser(anotherUserName + "@alfresco.com", anotherUserName, anotherUserName);
|
||||
|
||||
String storePath = "workspace://SpacesStore";
|
||||
String companyHomePathInStore = "/app:company_home";
|
||||
|
||||
StoreRef storeRef = new StoreRef(storePath);
|
||||
|
||||
NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef);
|
||||
|
||||
List<NodeRef> nodeRefs = searchService.selectNodes(storeRootNodeRef, companyHomePathInStore, null, namespaceService, false);
|
||||
companyHomeNodeRef = nodeRefs.get(0);
|
||||
|
||||
/*
|
||||
* Importing test folders:
|
||||
*
|
||||
* "Company Home" contains: "___-___folder_a"
|
||||
*
|
||||
* "___-___folder_a" contains: "___-___folder_a_a",
|
||||
* "___-___file_a",
|
||||
* "Message_485.eml" (this is IMAP Message)
|
||||
*
|
||||
* "___-___folder_a_a" contains: "____-____file_a_a"
|
||||
*
|
||||
*/
|
||||
importInternal("test-resources/imapservice_test_folder_a.acp", companyHomeNodeRef);
|
||||
|
||||
reauthenticate(anotherUserName, anotherUserName);
|
||||
}
|
||||
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
txn.rollback();
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void importInternal(String acpName, NodeRef space)
|
||||
throws IOException
|
||||
{
|
||||
ClassPathResource acpResource = new ClassPathResource(acpName);
|
||||
ACPImportPackageHandler acpHandler = new ACPImportPackageHandler(acpResource.getFile(), null);
|
||||
Location importLocation = new Location(space);
|
||||
importerService.importView(acpHandler, importLocation, null, null);
|
||||
}
|
||||
|
||||
private boolean checkMailbox(AlfrescoImapUser user, String mailboxName)
|
||||
{
|
||||
AlfrescoImapFolder mailFolder = (AlfrescoImapFolder)imapService.getFolder(user, mailboxName);
|
||||
|
||||
if (mailFolder.getFolderInfo() == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkSubscribedMailbox(AlfrescoImapUser user, String mailboxName)
|
||||
{
|
||||
List<AlfrescoImapFolder> aifs = imapService.listSubscribedMailboxes(user, mailboxName);
|
||||
boolean present = false;
|
||||
for (AlfrescoImapFolder aif : aifs)
|
||||
{
|
||||
if (aif.getName().equals(mailboxName))
|
||||
{
|
||||
present = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return present;
|
||||
}
|
||||
|
||||
private void reauthenticate(String name, String password)
|
||||
{
|
||||
authenticationService.invalidateTicket(authenticationService.getCurrentTicket());
|
||||
authenticationService.clearCurrentSecurityContext();
|
||||
authenticationService.authenticate(name, password.toCharArray());
|
||||
}
|
||||
|
||||
public void testGetFolder() throws Exception
|
||||
{
|
||||
imapService.createMailbox(user, MAILBOX_NAME_A);
|
||||
assertTrue(checkMailbox(user, MAILBOX_NAME_A));
|
||||
}
|
||||
|
||||
public void testListMailbox() throws Exception
|
||||
{
|
||||
imapService.createMailbox(user, MAILBOX_NAME_A);
|
||||
imapService.createMailbox(user, MAILBOX_NAME_B);
|
||||
List<AlfrescoImapFolder> mf = imapService.listMailboxes(user, MAILBOX_PATTERN);
|
||||
assertEquals(mf.size(), 2);
|
||||
}
|
||||
|
||||
public void testListSubscribedMailbox() throws Exception
|
||||
{
|
||||
imapService.createMailbox(user, MAILBOX_NAME_A);
|
||||
imapService.createMailbox(user, MAILBOX_NAME_B);
|
||||
imapService.subscribe(user, MAILBOX_NAME_A);
|
||||
imapService.subscribe(user, MAILBOX_NAME_B);
|
||||
List<AlfrescoImapFolder> aif = imapService.listSubscribedMailboxes(user, MAILBOX_PATTERN);
|
||||
assertEquals(aif.size(), 2);
|
||||
}
|
||||
|
||||
public void testCreateMailbox() throws Exception
|
||||
{
|
||||
imapService.createMailbox(user, MAILBOX_NAME_A);
|
||||
assertTrue("Mailbox isn't created", checkMailbox(user, MAILBOX_NAME_A));
|
||||
}
|
||||
|
||||
public void testDuplicateMailboxes() throws Exception
|
||||
{
|
||||
imapService.createMailbox(user, MAILBOX_NAME_A);
|
||||
try
|
||||
{
|
||||
imapService.createMailbox(user, MAILBOX_NAME_A);
|
||||
fail("Duplicate Mailbox was created");
|
||||
}
|
||||
catch (AlfrescoRuntimeException e)
|
||||
{
|
||||
// expected
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testRenameMailbox() throws Exception
|
||||
{
|
||||
imapService.createMailbox(user, MAILBOX_NAME_A);
|
||||
imapService.renameMailbox(user, MAILBOX_NAME_A, MAILBOX_NAME_B);
|
||||
assertFalse("Can't rename mailbox", checkMailbox(user, MAILBOX_NAME_A));
|
||||
assertTrue("Can't rename mailbox", checkMailbox(user, MAILBOX_NAME_B));
|
||||
}
|
||||
|
||||
public void testRenameMailboxDuplicate() throws Exception
|
||||
{
|
||||
imapService.createMailbox(user, MAILBOX_NAME_A);
|
||||
imapService.createMailbox(user, MAILBOX_NAME_B);
|
||||
try
|
||||
{
|
||||
imapService.renameMailbox(user, MAILBOX_NAME_A, MAILBOX_NAME_B);
|
||||
fail("Mailbox was renamed to existing one but shouldn't");
|
||||
}
|
||||
catch (AlfrescoRuntimeException e)
|
||||
{
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testDeleteMailbox() throws Exception
|
||||
{
|
||||
imapService.createMailbox(user, MAILBOX_NAME_B);
|
||||
imapService.deleteMailbox(user, MAILBOX_NAME_B);
|
||||
assertFalse("Can't delete mailbox", checkMailbox(user, MAILBOX_NAME_B));
|
||||
}
|
||||
|
||||
public void testSearchFoldersInArchive() throws Exception
|
||||
{
|
||||
List<FileInfo> fi = imapService.searchFolders(companyHomeNodeRef, FOLDER_PATTERN, true, AlfrescoImapConst.MODE_ARCHIVE);
|
||||
assertNotNull("Can't find folders in Archive Mode", fi);
|
||||
assertEquals("Can't find folders in Archive Mode", fi.size(), 2);
|
||||
|
||||
fi = imapService.searchFolders(companyHomeNodeRef, FOLDER_PATTERN, false, AlfrescoImapConst.MODE_ARCHIVE);
|
||||
assertNotNull("Can't find folders in Archive Mode", fi);
|
||||
assertEquals("Can't find folders in Archive Mode", fi.size(), 1);
|
||||
}
|
||||
|
||||
public void testSearchFoldersInVirtual() throws Exception
|
||||
{
|
||||
List<FileInfo> fi = imapService.searchFolders(companyHomeNodeRef, FOLDER_PATTERN, true, AlfrescoImapConst.MODE_VIRTUAL);
|
||||
assertNotNull("Can't find folders in Virtual Mode", fi);
|
||||
assertEquals("Can't find folders in Virtual Mode", fi.size(), 2);
|
||||
|
||||
fi = imapService.searchFolders(companyHomeNodeRef, FOLDER_PATTERN, false, AlfrescoImapConst.MODE_VIRTUAL);
|
||||
assertNotNull("Can't find folders in Virtual Mode", fi);
|
||||
assertEquals("Can't find folders in Virtual Mode", fi.size(), 1);
|
||||
}
|
||||
|
||||
public void testSearchFoldersInMixed() throws Exception
|
||||
{
|
||||
List<FileInfo> fi = imapService.searchFolders(companyHomeNodeRef, FOLDER_PATTERN, true, AlfrescoImapConst.MODE_MIXED);
|
||||
assertNotNull("Can't find folders in Mixed Mode", fi);
|
||||
assertEquals("Can't find folders in Mixed Mode", fi.size(), 2);
|
||||
|
||||
fi = imapService.searchFolders(companyHomeNodeRef, FOLDER_PATTERN, false, AlfrescoImapConst.MODE_MIXED);
|
||||
assertNotNull("Can't find folders in Mixed Mode", fi);
|
||||
assertEquals("Can't find folders in Mixed Mode", fi.size(), 1);
|
||||
}
|
||||
|
||||
public void testSearchFiles() throws Exception
|
||||
{
|
||||
List<FileInfo> fi = imapService.searchFiles(companyHomeNodeRef, FILE_PATTERN, true);
|
||||
assertNotNull(fi);
|
||||
assertTrue(fi.size() > 0);
|
||||
}
|
||||
|
||||
public void testSearchMails() throws Exception
|
||||
{
|
||||
List<FileInfo> fi = imapService.searchMails(companyHomeNodeRef, "*", AlfrescoImapConst.MODE_MIXED, true);
|
||||
assertNotNull(fi);
|
||||
assertTrue(fi.size() > 0);
|
||||
}
|
||||
|
||||
public void testSubscribe() throws Exception
|
||||
{
|
||||
imapService.createMailbox(user, MAILBOX_NAME_A);
|
||||
|
||||
imapService.subscribe(user, MAILBOX_NAME_A);
|
||||
assertTrue("Can't subscribe mailbox", checkSubscribedMailbox(user, MAILBOX_NAME_A));
|
||||
}
|
||||
|
||||
public void testUnsubscribe() throws Exception
|
||||
{
|
||||
imapService.createMailbox(user, MAILBOX_NAME_A);
|
||||
imapService.subscribe(user, MAILBOX_NAME_A);
|
||||
imapService.unsubscribe(user, MAILBOX_NAME_A);
|
||||
assertFalse("Can't unsubscribe mailbox", checkSubscribedMailbox(user, MAILBOX_NAME_A));
|
||||
}
|
||||
|
||||
private void setFlags(FileInfo messageFileInfo) throws Exception
|
||||
{
|
||||
imapService.setFlags(messageFileInfo, flags, true);
|
||||
NodeRef messageNodeRef = messageFileInfo.getNodeRef();
|
||||
Map<QName, Serializable> props = nodeService.getProperties(messageNodeRef);
|
||||
|
||||
assertTrue("Can't set SEEN flag", props.containsKey(ImapModel.PROP_FLAG_SEEN));
|
||||
assertTrue("Can't set FLAGGED flag", props.containsKey(ImapModel.PROP_FLAG_FLAGGED));
|
||||
assertTrue("Can't set ANSWERED flag", props.containsKey(ImapModel.PROP_FLAG_ANSWERED));
|
||||
assertTrue("Can't set DELETED flag", props.containsKey(ImapModel.PROP_FLAG_DELETED));
|
||||
}
|
||||
|
||||
public void testSetFlags() throws Exception
|
||||
{
|
||||
List<FileInfo> fis = imapService.searchMails(companyHomeNodeRef, "*", AlfrescoImapConst.MODE_ARCHIVE, true);
|
||||
if (fis != null && fis.size() > 0)
|
||||
{
|
||||
FileInfo messageFileInfo = fis.get(0);
|
||||
try
|
||||
{
|
||||
setFlags(messageFileInfo);
|
||||
fail("Can't set flags");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e instanceof AccessDeniedException)
|
||||
{
|
||||
// expected
|
||||
}
|
||||
else
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
reauthenticate(USER_NAME, USER_PASSWORD);
|
||||
|
||||
permissionService.setPermission(companyHomeNodeRef, anotherUserName, PermissionService.WRITE, true);
|
||||
|
||||
reauthenticate(anotherUserName, anotherUserName);
|
||||
|
||||
setFlags(messageFileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public void testSetFlag() throws Exception
|
||||
{
|
||||
List<FileInfo> fis = imapService.searchMails(companyHomeNodeRef, "*", AlfrescoImapConst.MODE_ARCHIVE, true);
|
||||
if (fis != null && fis.size() > 0)
|
||||
{
|
||||
FileInfo messageFileInfo = fis.get(0);
|
||||
|
||||
reauthenticate(USER_NAME, USER_PASSWORD);
|
||||
|
||||
permissionService.setPermission(companyHomeNodeRef, anotherUserName, PermissionService.WRITE, true);
|
||||
|
||||
reauthenticate(anotherUserName, anotherUserName);
|
||||
|
||||
imapService.setFlag(messageFileInfo, Flags.Flag.RECENT, true);
|
||||
|
||||
Serializable prop = nodeService.getProperty(messageFileInfo.getNodeRef(), ImapModel.PROP_FLAG_RECENT);
|
||||
assertNotNull("Can't set RECENT flag", prop);
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetFlags() throws Exception
|
||||
{
|
||||
List<FileInfo> fis = imapService.searchMails(companyHomeNodeRef, "*", AlfrescoImapConst.MODE_ARCHIVE, true);
|
||||
if (fis != null && fis.size() > 0)
|
||||
{
|
||||
FileInfo messageFileInfo = fis.get(0);
|
||||
|
||||
reauthenticate(USER_NAME, USER_PASSWORD);
|
||||
|
||||
permissionService.setPermission(companyHomeNodeRef, anotherUserName, PermissionService.WRITE, true);
|
||||
|
||||
imapService.setFlags(messageFileInfo, flags, true);
|
||||
|
||||
reauthenticate(anotherUserName, anotherUserName);
|
||||
|
||||
Flags fl = imapService.getFlags(messageFileInfo);
|
||||
assertTrue(fl.contains(flags));
|
||||
}
|
||||
}
|
||||
}
|
166
source/java/org/alfresco/repo/imap/IncomingImapMessage.java
Executable file
166
source/java/org/alfresco/repo/imap/IncomingImapMessage.java
Executable file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.imap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeUtility;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.ImapModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.ContentIOException;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
* This class is used to serve incoming IMAP message. E.g. when message is copied /moved into some IMAP older.
|
||||
*
|
||||
* @author Arseny Kovalchuk
|
||||
*/
|
||||
public class IncomingImapMessage extends AbstractMimeMessage
|
||||
{
|
||||
private Log logger = LogFactory.getLog(IncomingImapMessage.class);
|
||||
private ContentReader contentReader;
|
||||
/**
|
||||
* Constructs {@link IncomingImapMessage} object based on {@link MimeMessage}
|
||||
*
|
||||
* @param fileInfo - reference to the {@link FileInfo} object representing the message.
|
||||
* @param imapHelper - reference to the {@link ImapHelper} object.
|
||||
* @param message - {@link MimeMessage}
|
||||
* @throws MessagingException
|
||||
*/
|
||||
public IncomingImapMessage(FileInfo fileInfo, ServiceRegistry serviceRegistry, MimeMessage message) throws MessagingException
|
||||
{
|
||||
super(Session.getDefaultInstance(new Properties()));
|
||||
this.wrappedMessage = message; // temporary save it and then destroyed in writeContent() (to avoid memory leak with byte[] MimeMessage.content field)
|
||||
this.buildMessage(fileInfo, serviceRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildMessageInternal() throws MessagingException
|
||||
{
|
||||
setMessageHeaders();
|
||||
// Add Imap Content Aspect with properties
|
||||
NodeService nodeService = serviceRegistry.getNodeService();
|
||||
nodeService.addAspect(this.messageFileInfo.getNodeRef(), ImapModel.ASPECT_IMAP_CONTENT, null);
|
||||
// Write content
|
||||
writeContent();
|
||||
imapService.setFlags(messageFileInfo, flags, true);
|
||||
|
||||
final NodeRef nodeRef = messageFileInfo.getNodeRef();
|
||||
Map<QName, Serializable> newProperties = new HashMap<QName, Serializable>();
|
||||
newProperties.put(ImapModel.PROP_MESSAGE_FROM, InternetAddress.toString(this.getFrom()));
|
||||
newProperties.put(ImapModel.PROP_MESSAGE_TO, InternetAddress.toString(this.getRecipients(RecipientType.TO)));
|
||||
newProperties.put(ImapModel.PROP_MESSAGE_CC, InternetAddress.toString(this.getRecipients(RecipientType.CC)));
|
||||
newProperties.put(ImapModel.PROP_MESSAGE_ID, this.getMessageID());
|
||||
String[] threadIndexes = this.getHeader("Thread-Index");
|
||||
String threadIndex = (threadIndexes == null || threadIndexes.length == 0) ? null : threadIndexes[0];
|
||||
newProperties.put(ImapModel.PROP_THREAD_INDEX, threadIndex);
|
||||
|
||||
String[] subj = this.getHeader("Subject");
|
||||
if (subj != null && subj.length > 0)
|
||||
{
|
||||
String decodedSubject = subj[0];
|
||||
try
|
||||
{
|
||||
decodedSubject = MimeUtility.decodeText(decodedSubject);
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
logger.warn(e.toString());
|
||||
}
|
||||
newProperties.put(ImapModel.PROP_MESSAGE_SUBJECT, decodedSubject);
|
||||
newProperties.put(ContentModel.PROP_TITLE, decodedSubject);
|
||||
newProperties.put(ContentModel.PROP_DESCRIPTION, decodedSubject);
|
||||
}
|
||||
|
||||
serviceRegistry.getNodeService().addProperties(nodeRef, newProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the content of incoming message into Alfresco repository.
|
||||
*
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private void writeContent() throws MessagingException
|
||||
{
|
||||
ContentWriter writer = serviceRegistry.getContentService().getWriter(messageFileInfo.getNodeRef(), ContentModel.PROP_CONTENT, true);
|
||||
writer.setMimetype(MimetypeMap.MIMETYPE_RFC822);
|
||||
try
|
||||
{
|
||||
OutputStream outputStream = writer.getContentOutputStream();
|
||||
wrappedMessage.writeTo(outputStream);
|
||||
outputStream.close();
|
||||
wrappedMessage = null; // it is not used any more and it is available to GC (to avoid memory leak with byte[] MimeMessage.content field)
|
||||
this.contentReader = serviceRegistry.getContentService().getReader(messageFileInfo.getNodeRef(), ContentModel.PROP_CONTENT);
|
||||
}
|
||||
catch (ContentIOException e)
|
||||
{
|
||||
throw new MessagingException(e.getMessage(), e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new MessagingException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InputStream getContentStream() throws MessagingException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this.contentStream == null)
|
||||
{
|
||||
this.contentStream = this.contentReader.getContentInputStream();
|
||||
}
|
||||
return this.contentStream;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new MessagingException(e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
154
source/java/org/alfresco/repo/imap/LoadTest.java
Executable file
154
source/java/org/alfresco/repo/imap/LoadTest.java
Executable file
@@ -0,0 +1,154 @@
|
||||
package org.alfresco.repo.imap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.mail.Flags;
|
||||
|
||||
import org.alfresco.repo.importer.ACPImportPackageHandler;
|
||||
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.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.cmr.security.AuthenticationService;
|
||||
import org.alfresco.service.cmr.view.ImporterService;
|
||||
import org.alfresco.service.cmr.view.Location;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import com.icegreen.greenmail.imap.ImapConstants;
|
||||
import com.icegreen.greenmail.store.SimpleStoredMessage;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class LoadTest extends TestCase
|
||||
{
|
||||
private Log logger = LogFactory.getLog(LoadTest.class);
|
||||
|
||||
|
||||
private static final ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||
|
||||
private ImapService imapService;
|
||||
private ImporterService importerService;
|
||||
|
||||
private AlfrescoImapUser user;
|
||||
private static final String USER_NAME = "admin";
|
||||
private static final String USER_PASSWORD = "admin";
|
||||
private static final String TEST_DATA_FOLDER_NAME = "test_data";
|
||||
private static final String TEST_FOLDER_NAME = "test_imap3";
|
||||
private static final long MESSAGE_QUANTITY = 3;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean("ServiceRegistry");
|
||||
AuthenticationService authenticationService = serviceRegistry.getAuthenticationService();
|
||||
imapService = serviceRegistry.getImapService();
|
||||
importerService = serviceRegistry.getImporterService();
|
||||
NodeService nodeService = serviceRegistry.getNodeService();
|
||||
SearchService searchService = serviceRegistry.getSearchService();
|
||||
NamespaceService namespaceService = serviceRegistry.getNamespaceService();
|
||||
|
||||
user = new AlfrescoImapUser(USER_NAME + "@alfresco.com", USER_NAME, USER_PASSWORD);
|
||||
|
||||
authenticationService.authenticate(USER_NAME, USER_PASSWORD.toCharArray());
|
||||
|
||||
StoreRef storeRef = new StoreRef("workspace://SpacesStore");
|
||||
NodeRef rootRef = nodeService.getRootNode(storeRef);
|
||||
|
||||
// Delete test folder
|
||||
List<NodeRef> nodeRefs = searchService.selectNodes(rootRef, "/app:company_home/imap:imap_home/cm:admin/cm:" + TEST_FOLDER_NAME, null, namespaceService, false);
|
||||
if (nodeRefs.size() == 1)
|
||||
{
|
||||
NodeRef ch = nodeRefs.get(0);
|
||||
nodeService.deleteNode(ch);
|
||||
}
|
||||
// Delete test data folder
|
||||
nodeRefs = searchService.selectNodes(rootRef, "/app:company_home/imap:imap_home/cm:admin/cm:" + TEST_DATA_FOLDER_NAME, null, namespaceService, false);
|
||||
if (nodeRefs.size() == 1)
|
||||
{
|
||||
NodeRef ch = nodeRefs.get(0);
|
||||
nodeService.deleteNode(ch);
|
||||
}
|
||||
|
||||
NodeRef adminNodeRef = searchService.selectNodes(rootRef, "/app:company_home/imap:imap_home/cm:admin", null, namespaceService, false).get(0);
|
||||
importTestData("test-resources/load_test_data.acp", adminNodeRef);
|
||||
|
||||
|
||||
AlfrescoImapFolder testDataFolder = imapService.getFolder(user, TEST_DATA_FOLDER_NAME);
|
||||
// FileInfo fileInfo = imapService.searchMails(drafts.getFolderInfo().getNodeRef(), "*", AlfrescoImapConst.MODE_ARCHIVE, false).get(0);
|
||||
// SimpleStoredMessage m = drafts.createImapMessage(fileInfo, (long)0, true);
|
||||
|
||||
// imapService.setExtractAttachmentsEnabled(false);
|
||||
SimpleStoredMessage m = testDataFolder.getMessages().get(0);
|
||||
m = testDataFolder.getMessage(m.getUid());
|
||||
|
||||
|
||||
|
||||
|
||||
AlfrescoImapFolder folder = imapService.createMailbox(user, TEST_FOLDER_NAME);
|
||||
|
||||
logger.info("Creating folders...");
|
||||
long t = System.currentTimeMillis();
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < MESSAGE_QUANTITY; i++)
|
||||
{
|
||||
System.out.println("i = " + i);
|
||||
// folder.appendMessageInternal(message, new Flags(), new Date());
|
||||
folder.appendMessage(m.getMimeMessage(), new Flags(), new Date());
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.error(e, e);
|
||||
}
|
||||
|
||||
t = System.currentTimeMillis() - t;
|
||||
logger.info("Create time: " + t + " ms (" + t/1000 + " s (" + t/60000 + " min))");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public void testList()
|
||||
{
|
||||
logger.info("Listing folders...");
|
||||
|
||||
long t = System.currentTimeMillis();
|
||||
List<AlfrescoImapFolder> list = imapService.listMailboxes(user, TEST_FOLDER_NAME + "*");
|
||||
t = System.currentTimeMillis() - t;
|
||||
|
||||
logger.info("List time: " + t + " ms (" + t/1000 + " s)");
|
||||
logger.info("List size: " + list.size());
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void importTestData(String acpName, NodeRef space) throws IOException
|
||||
{
|
||||
ClassPathResource acpResource = new ClassPathResource(acpName);
|
||||
ACPImportPackageHandler acpHandler = new ACPImportPackageHandler(acpResource.getFile(), null);
|
||||
Location importLocation = new Location(space);
|
||||
importerService.importView(acpHandler, importLocation, null, null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
161
source/java/org/alfresco/repo/imap/RemoteLoadTest.java
Executable file
161
source/java/org/alfresco/repo/imap/RemoteLoadTest.java
Executable file
@@ -0,0 +1,161 @@
|
||||
package org.alfresco.repo.imap;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.mail.Address;
|
||||
import javax.mail.BodyPart;
|
||||
import javax.mail.Folder;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Part;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Store;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.sun.mail.util.BASE64DecoderStream;
|
||||
|
||||
public class RemoteLoadTest extends TestCase
|
||||
{
|
||||
|
||||
private Log logger = LogFactory.getLog(LoadTest.class);
|
||||
|
||||
private static final String USER_NAME = "admin";
|
||||
private static final String USER_PASSWORD = "admin";
|
||||
private static final String TEST_FOLDER_NAME = "test_imap1000";
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void testMailbox()
|
||||
{
|
||||
logger.info("Getting folder...");
|
||||
long t = System.currentTimeMillis();
|
||||
|
||||
String host = "localhost";
|
||||
|
||||
// Create empty properties
|
||||
Properties props = new Properties();
|
||||
|
||||
// Get session
|
||||
Session session = Session.getDefaultInstance(props, null);
|
||||
|
||||
Store store = null;
|
||||
Folder folder = null;
|
||||
try
|
||||
{
|
||||
// Get the store
|
||||
store = session.getStore("imap");
|
||||
store.connect(host, USER_NAME, USER_PASSWORD);
|
||||
|
||||
// Get folder
|
||||
folder = store.getFolder(TEST_FOLDER_NAME);
|
||||
folder.open(Folder.READ_ONLY);
|
||||
|
||||
// Get directory
|
||||
Message message[] = folder.getMessages();
|
||||
|
||||
for (int i = 0, n = message.length; i < n; i++)
|
||||
{
|
||||
message[i].getAllHeaders();
|
||||
|
||||
Address[] from = message[i].getFrom();
|
||||
System.out.print(i + ": ");
|
||||
if (from != null)
|
||||
{
|
||||
System.out.print(message[i].getFrom()[0] + "\t");
|
||||
}
|
||||
System.out.println(message[i].getSubject());
|
||||
|
||||
Object content = message[i].getContent();
|
||||
if (content instanceof MimeMultipart)
|
||||
{
|
||||
for (int j = 0, m = ((MimeMultipart)content).getCount(); j < m; j++)
|
||||
{
|
||||
BodyPart part = ((MimeMultipart)content).getBodyPart(j);
|
||||
Object partContent = part.getContent();
|
||||
|
||||
if (partContent instanceof String)
|
||||
{
|
||||
String body = (String)partContent;
|
||||
}
|
||||
else if (partContent instanceof FilterInputStream)
|
||||
{
|
||||
FilterInputStream fis = (FilterInputStream)partContent;
|
||||
BufferedInputStream bis = new BufferedInputStream(fis);
|
||||
|
||||
/* while (bis.available() > 0)
|
||||
{
|
||||
bis.read();
|
||||
}*/
|
||||
byte[] bytes = new byte[524288];
|
||||
while (bis.read(bytes) != -1)
|
||||
{
|
||||
}
|
||||
bis.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nn = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
t = System.currentTimeMillis() - t;
|
||||
logger.info("Time: " + t + " ms (" + t/1000 + " s)");
|
||||
logger.info("Length: " + message.length);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.error(e.getMessage(), e);
|
||||
fail(e.getMessage());
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Close connection
|
||||
try
|
||||
{
|
||||
if (folder != null)
|
||||
{
|
||||
folder.close(false);
|
||||
}
|
||||
}
|
||||
catch (MessagingException e)
|
||||
{
|
||||
logger.error(e.getMessage(), e);
|
||||
fail(e.getMessage());
|
||||
}
|
||||
try
|
||||
{
|
||||
if (store != null)
|
||||
{
|
||||
store.close();
|
||||
}
|
||||
}
|
||||
catch (MessagingException e)
|
||||
{
|
||||
logger.error(e.getMessage(), e);
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
189
source/java/org/alfresco/repo/imap/SimpleImapMessage.java
Executable file
189
source/java/org/alfresco/repo/imap/SimpleImapMessage.java
Executable file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.imap;
|
||||
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.BASE_64_ENCODING;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.CONTENT_TRANSFER_ENCODING;
|
||||
import static org.alfresco.repo.imap.AlfrescoImapConst.UTF_8;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.mail.Address;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
import javax.mail.internet.MimeUtility;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.ImapModel;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.ContentIOException;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Extended MimeMessage to represent a content stored in the Alfresco repository.
|
||||
*
|
||||
* @author Arseny Kovalchuk
|
||||
*/
|
||||
public class SimpleImapMessage extends AbstractMimeMessage
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(SimpleImapMessage.class);
|
||||
|
||||
/**
|
||||
* Constructs {@link SimpleImapMessage} object.
|
||||
*
|
||||
* @param fileInfo - reference to the {@link FileInfo} object representing the message.
|
||||
* @param imapHelper - reference to the {@link ImapHelper} object.
|
||||
* @param generateBody - if {@code true} message body will be generated.
|
||||
*
|
||||
* @throws MessagingException if generation of the body fails.
|
||||
*/
|
||||
public SimpleImapMessage(FileInfo fileInfo, ServiceRegistry serviceRegistry, boolean generateBody) throws MessagingException
|
||||
{
|
||||
super(fileInfo, serviceRegistry, generateBody);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildMessageInternal() throws MessagingException
|
||||
{
|
||||
if (generateBody != false)
|
||||
{
|
||||
setMessageHeaders();
|
||||
buildImapMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method builds MimeMessage based on either ImapModel or ContentModel type.
|
||||
*
|
||||
* @param fileInfo - Source file information {@link FileInfo}
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private void buildImapMessage() throws MessagingException
|
||||
{
|
||||
final NodeRef nodeRef = messageFileInfo.getNodeRef();
|
||||
if (serviceRegistry.getNodeService().hasAspect(nodeRef, ImapModel.ASPECT_IMAP_CONTENT))
|
||||
{
|
||||
buildRFC822Message();
|
||||
}
|
||||
else
|
||||
{
|
||||
buildContentModelMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private void buildRFC822Message() throws MessagingException
|
||||
{
|
||||
ContentService contentService = serviceRegistry.getContentService();
|
||||
ContentReader reader = contentService.getReader(messageFileInfo.getNodeRef(), ContentModel.PROP_CONTENT);
|
||||
try
|
||||
{
|
||||
InputStream inputStream = reader.getContentInputStream();
|
||||
this.parse(inputStream);
|
||||
inputStream.close();
|
||||
}
|
||||
catch (ContentIOException e)
|
||||
{
|
||||
//logger.error(e);
|
||||
throw new MessagingException("The error occured during message creation from content stream.", e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
//logger.error(e);
|
||||
throw new MessagingException("The error occured during message creation from content stream.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method builds {@link MimeMessage} based on {@link ContentModel}
|
||||
*
|
||||
* @param fileInfo - Source file information {@link FileInfo}
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private void buildContentModelMessage() throws MessagingException
|
||||
{
|
||||
Map<QName, Serializable> properties = messageFileInfo.getProperties();
|
||||
String prop = null;
|
||||
setSentDate(messageFileInfo.getModifiedDate());
|
||||
// Add FROM address
|
||||
Address[] addressList = buildSenderFromAddress();
|
||||
addFrom(addressList);
|
||||
// Add TO address
|
||||
addressList = buildRecipientToAddress();
|
||||
addRecipients(RecipientType.TO, addressList);
|
||||
prop = (String) properties.get(ContentModel.PROP_TITLE);
|
||||
try
|
||||
{
|
||||
prop = (prop == null) ? MimeUtility.encodeText(messageFileInfo.getName(), KOI8R_CHARSET, null) : MimeUtility.encodeText(prop, KOI8R_CHARSET, null);
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
setSubject(prop);
|
||||
setContent(buildContentModelMultipart());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method builds {@link Multipart} based on {@link ContentModel}
|
||||
*
|
||||
* @param fileInfo - Source file information {@link FileInfo}
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private Multipart buildContentModelMultipart() throws MessagingException
|
||||
{
|
||||
MimeMultipart rootMultipart = new MimeMultipart("alternative");
|
||||
// Cite MOB-395: "email agent will be used to select an appropriate template" - we are not able to
|
||||
// detect an email agent so we use a default template for all messages.
|
||||
// See AlfrescoImapConst to see the possible templates to use.
|
||||
String bodyTxt = getEmailBodyText(EmailBodyType.TEXT_PLAIN);
|
||||
rootMultipart.addBodyPart(getTextBodyPart(bodyTxt, EmailBodyType.TEXT_PLAIN.getSubtype()));
|
||||
String bodyHtml = getEmailBodyText(EmailBodyType.TEXT_HTML);
|
||||
rootMultipart.addBodyPart(getTextBodyPart(bodyHtml, EmailBodyType.TEXT_HTML.getSubtype()));
|
||||
return rootMultipart;
|
||||
}
|
||||
|
||||
|
||||
private MimeBodyPart getTextBodyPart(String bodyText, String subtype) throws MessagingException
|
||||
{
|
||||
MimeBodyPart result = new MimeBodyPart();
|
||||
result.setText(bodyText, UTF_8, subtype);
|
||||
result.addHeader(CONTENT_TRANSFER_ENCODING, BASE_64_ENCODING);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@@ -27,7 +27,7 @@ package org.alfresco.repo.imap.config;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
|
||||
/**
|
||||
* Provides the parameters for an IMAP mount point (a mapping from an Alfresco node path to an IMAP folder name).
|
||||
* Standard ImapConfig bean.
|
||||
*/
|
||||
public class ImapConfigBean implements BeanNameAware
|
||||
{
|
||||
@@ -35,9 +35,6 @@ public class ImapConfigBean implements BeanNameAware
|
||||
/** The IMAP folder name. */
|
||||
private String name;
|
||||
|
||||
/** The mode (virtual or archive). */
|
||||
private String mode;
|
||||
|
||||
/** The Alfresco store name. */
|
||||
private String store;
|
||||
|
||||
@@ -63,27 +60,6 @@ public class ImapConfigBean implements BeanNameAware
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mode.
|
||||
*
|
||||
* @return the mode (virtual or archive)
|
||||
*/
|
||||
public String getMode()
|
||||
{
|
||||
return this.mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the mode.
|
||||
*
|
||||
* @param mode
|
||||
* the new mode (virtual or archive)
|
||||
*/
|
||||
public void setMode(String mode)
|
||||
{
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Alfresco store name.
|
||||
*
|
||||
|
59
source/java/org/alfresco/repo/imap/config/ImapConfigMountPointsBean.java
Executable file
59
source/java/org/alfresco/repo/imap/config/ImapConfigMountPointsBean.java
Executable file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.imap.config;
|
||||
|
||||
|
||||
/**
|
||||
* Provides the parameters for an IMAP mount point (a mapping from an Alfresco node path to an IMAP folder name).
|
||||
*/
|
||||
public class ImapConfigMountPointsBean extends ImapConfigBean
|
||||
{
|
||||
|
||||
|
||||
/** The mode (virtual, archive or mixed). */
|
||||
private String mode;
|
||||
|
||||
/**
|
||||
* Gets the mode.
|
||||
*
|
||||
* @return the mode (virtual or archive)
|
||||
*/
|
||||
public String getMode()
|
||||
{
|
||||
return this.mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the mode.
|
||||
*
|
||||
* @param mode
|
||||
* the new mode (virtual or archive)
|
||||
*/
|
||||
public void setMode(String mode)
|
||||
{
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
}
|
@@ -31,6 +31,7 @@ import org.alfresco.cmis.CMISQueryService;
|
||||
import org.alfresco.cmis.CMISServices;
|
||||
import org.alfresco.mbeans.VirtServerRegistry;
|
||||
import org.alfresco.repo.forms.FormService;
|
||||
import org.alfresco.repo.imap.ImapService;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
@@ -544,4 +545,13 @@ public class ServiceDescriptorRegistry
|
||||
{
|
||||
return (CMISQueryService)getService(CMIS_QUERY_SERVICE);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.service.ServiceRegistry#getCMISQueryService()
|
||||
*/
|
||||
public ImapService getImapService()
|
||||
{
|
||||
return (ImapService)getService(IMAP_SERVICE);
|
||||
}
|
||||
}
|
||||
|
@@ -31,6 +31,7 @@ import org.alfresco.cmis.CMISQueryService;
|
||||
import org.alfresco.cmis.CMISServices;
|
||||
import org.alfresco.mbeans.VirtServerRegistry;
|
||||
import org.alfresco.repo.forms.FormService;
|
||||
import org.alfresco.repo.imap.ImapService;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
import org.alfresco.service.cmr.attributes.AttributeService;
|
||||
@@ -149,6 +150,7 @@ public interface ServiceRegistry
|
||||
static final QName CMIS_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CMISService");
|
||||
static final QName CMIS_DICTIONARY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CMISDictionaryService");
|
||||
static final QName CMIS_QUERY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CMISQueryService");
|
||||
static final QName IMAP_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ImapService");
|
||||
|
||||
|
||||
/**
|
||||
@@ -506,4 +508,11 @@ public interface ServiceRegistry
|
||||
*/
|
||||
@NotAuditable
|
||||
CMISQueryService getCMISQueryService();
|
||||
|
||||
/**
|
||||
* Get the IMAP service (or null if one is not provided)
|
||||
* @return the IMAP service
|
||||
*/
|
||||
@NotAuditable
|
||||
ImapService getImapService();
|
||||
}
|
||||
|
81
source/java/org/alfresco/util/Utf7.java
Executable file
81
source/java/org/alfresco/util/Utf7.java
Executable file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.util;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import com.beetstra.jutf7.CharsetProvider;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Mike Shavnev
|
||||
*
|
||||
*/
|
||||
public class Utf7
|
||||
{
|
||||
public static final String UTF7 = "UTF-7";
|
||||
public static final String UTF7_OPTIONAL = "X-UTF-7-OPTIONAL";
|
||||
public static final String UTF7_MODIFIED = "X-MODIFIED-UTF-7";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert string from UTF-7 characters
|
||||
*
|
||||
* @param string Input string for decoding
|
||||
* @return Decoded string
|
||||
*/
|
||||
public static String decode(String string, String charsetName)
|
||||
{
|
||||
if (string.length() <= 1)
|
||||
{
|
||||
return string;
|
||||
}
|
||||
CharsetProvider provider = new CharsetProvider();
|
||||
Charset charset = provider.charsetForName(charsetName);
|
||||
CharBuffer charBuffer = charset.decode(ByteBuffer.wrap(string.getBytes()));
|
||||
return charBuffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert string to UTF-7 characters
|
||||
*
|
||||
* @param string Input string for decoding
|
||||
* @return Encoded string
|
||||
*/
|
||||
public static String encode(String string, String charsetName)
|
||||
{
|
||||
if (string.length() <= 1)
|
||||
{
|
||||
return string;
|
||||
}
|
||||
CharsetProvider provider = new CharsetProvider();
|
||||
Charset charset = provider.charsetForName(charsetName);
|
||||
ByteBuffer byteBuffer = charset.encode(string);
|
||||
return new String(byteBuffer.array()).substring(0, byteBuffer.limit());
|
||||
}
|
||||
}
|
BIN
source/test-resources/imapservice_test_folder_a.acp
Executable file
BIN
source/test-resources/imapservice_test_folder_a.acp
Executable file
Binary file not shown.
BIN
source/test-resources/load_test_data.acp
Executable file
BIN
source/test-resources/load_test_data.acp
Executable file
Binary file not shown.
Reference in New Issue
Block a user