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">
|
<property name="compositePropertyTypes">
|
||||||
<map>
|
<map>
|
||||||
<entry key="imap.server.mountPoints">
|
<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>
|
<value>org.alfresco.repo.imap.config.ImapConfigBean</value>
|
||||||
</entry>
|
</entry>
|
||||||
</map>
|
</map>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</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">
|
<bean id="fileServerConfiguration" class="org.alfresco.repo.management.subsystems.SubsystemProxyFactory">
|
||||||
<property name="sourceApplicationContextFactory">
|
<property name="sourceApplicationContextFactory">
|
||||||
<ref bean="fileServers" />
|
<ref bean="fileServers" />
|
||||||
|
@@ -437,6 +437,10 @@
|
|||||||
class="org.alfresco.repo.content.transform.MailContentTransformer"
|
class="org.alfresco.repo.content.transform.MailContentTransformer"
|
||||||
parent="baseContentTransformer" />
|
parent="baseContentTransformer" />
|
||||||
|
|
||||||
|
<bean id="transformer.RFC822"
|
||||||
|
class="org.alfresco.repo.content.transform.EMLTransformer"
|
||||||
|
parent="baseContentTransformer" />
|
||||||
|
|
||||||
<!-- Import the ImageMagick transformer from the third party subsystem -->
|
<!-- Import the ImageMagick transformer from the third party subsystem -->
|
||||||
<bean id="transformer.worker.ImageMagick" class="org.alfresco.repo.management.subsystems.SubsystemProxyFactory">
|
<bean id="transformer.worker.ImageMagick" class="org.alfresco.repo.management.subsystems.SubsystemProxyFactory">
|
||||||
<property name="sourceApplicationContextFactory">
|
<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;
|
var message = "Unknown command: " + command;
|
||||||
logger.log(message);
|
logger.log(message);
|
||||||
createEmail(message, message, message, false);
|
createEmail(message, message, message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ function processCommand()
|
|||||||
if (commandFolder == null)
|
if (commandFolder == null)
|
||||||
{
|
{
|
||||||
var message = "Command Processor: wrong command=" + command;
|
var message = "Command Processor: wrong command=" + command;
|
||||||
createEmail(message, message, message, false);
|
createEmail(message, message, message);
|
||||||
logger.log(message);
|
logger.log(message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -75,7 +75,17 @@ function createResponseTextHtml(nodes)
|
|||||||
*/
|
*/
|
||||||
function createContentTextHtml(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 += "<table class=\"links\">\n";
|
||||||
content += "<thead align=\"center\">";
|
content += "<thead align=\"center\">";
|
||||||
content += "<tr>";
|
content += "<tr>";
|
||||||
@@ -83,7 +93,7 @@ function createContentTextHtml(nodes)
|
|||||||
content += "<td>Url</td>";
|
content += "<td>Url</td>";
|
||||||
content += "<td>Download Url</td>";
|
content += "<td>Download Url</td>";
|
||||||
content += "</tr>";
|
content += "</tr>";
|
||||||
content += "</thead>\n"
|
content += "</thead>\n" + "</div></body></html>";
|
||||||
|
|
||||||
|
|
||||||
for (var i = 0; i < nodes.length; i++)
|
for (var i = 0; i < nodes.length; i++)
|
||||||
@@ -133,7 +143,7 @@ function commandSearch(params)
|
|||||||
|
|
||||||
if (query == null)
|
if (query == null)
|
||||||
{
|
{
|
||||||
createEmail(errorParameter, errorParameter, errorParameter, false);
|
createEmail(errorParameter, errorParameter, errorParameter);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +164,7 @@ function commandSearch(params)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
createEmail(errorXPathNotValid, errorXPathNotValid, errorXPathNotValid, false);
|
createEmail(errorXPathNotValid, errorXPathNotValid, errorXPathNotValid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -180,8 +190,8 @@ function commandSearch(params)
|
|||||||
createEmail(message, message, subject);
|
createEmail(message, message, subject);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*createEmail(createResponseTextHtml(nodes), createContentTextPlain(nodes), subject, true);*/
|
/*createEmail(createContentTextPlain(nodes), createResponseTextHtml(nodes), subject);*/
|
||||||
createEmail(createContentTextHtml(nodes), createContentTextPlain(nodes), subject, false);
|
createEmail(createContentTextPlain(nodes), createContentTextHtml(nodes), subject);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Decode subject
|
* Decode subject
|
||||||
@@ -224,13 +234,13 @@ function main()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var message = unknownCommand + ": '" + title + "'";
|
var message = unknownCommand + ": '" + title + "'";
|
||||||
createEmail(message, message, message, false);
|
createEmail(message, message, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var message = unknownCommand + ": '" + title + "'";
|
var message = unknownCommand + ": '" + title + "'";
|
||||||
createEmail(message, message, message, false);
|
createEmail(message, message, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.remove();
|
document.remove();
|
||||||
|
@@ -1,9 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Create e-mail
|
* Create e-mail
|
||||||
* contentTextHtml (string) html content
|
* contentEML (string) content message
|
||||||
* contentTextPlain (string) text content
|
|
||||||
*/
|
*/
|
||||||
function createEmail(contentTextHtml, contentTextPlain, subject, templateUsed)
|
function createEmail(messageTXT, messageHTML, subject)
|
||||||
{
|
{
|
||||||
var command = document.properties["cm:title"];
|
var command = document.properties["cm:title"];
|
||||||
var userName = person.properties["cm:userName"];
|
var userName = person.properties["cm:userName"];
|
||||||
@@ -15,42 +14,42 @@ function createEmail(contentTextHtml, contentTextPlain, subject, templateUsed)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var nextMessageUID = inboxFolder.properties["imap:nextMessageUID"];
|
var response = inboxFolder.createNode("response" + Date.now() + ".eml", "cm:content");
|
||||||
inboxFolder.properties["imap:nextMessageUID"] = nextMessageUID + 1;
|
|
||||||
inboxFolder.save();
|
|
||||||
|
|
||||||
var response = inboxFolder.createNode("response" + Date.now(), "imap:imapContent");
|
|
||||||
response.properties["imap:messageFrom"] = "command@alfresco.com";
|
response.properties["imap:messageFrom"] = "command@alfresco.com";
|
||||||
response.properties["imap:messageSubject"] = subject;
|
response.properties["imap:messageSubject"] = subject;
|
||||||
response.properties["imap:messageTo"] = document.properties["cm:originator"];
|
response.properties["imap:messageTo"] = document.properties["cm:originator"];
|
||||||
response.properties["imap:messageCc"] = "";
|
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();
|
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'
|
# Error messages. prefix 'imap.server.error'
|
||||||
imap.server.error.properties_dont_exist = "Appropriate properties do not exist."
|
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 mimetype="image/x-dwt" display="AutoCAD Template">
|
<mimetype mimetype="image/x-dwt" display="AutoCAD Template">
|
||||||
<extension>dwt</extension>
|
<extension>dwt</extension>
|
||||||
|
</mimetype>
|
||||||
|
<mimetype mimetype="message/rfc822" display="EMail">
|
||||||
|
<extension>eml</extension>
|
||||||
</mimetype>
|
</mimetype>
|
||||||
<mimetype mimetype="application/vnd.ms-outlook" display="Outlook MSG">
|
<mimetype mimetype="application/vnd.ms-outlook" display="Outlook MSG">
|
||||||
<extension>msg</extension>
|
<extension>msg</extension>
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
<title>IMAP Folder</title>
|
<title>IMAP Folder</title>
|
||||||
<parent>cm:folder</parent>
|
<parent>cm:folder</parent>
|
||||||
<properties>
|
<properties>
|
||||||
<property name="imap:subscribed">
|
<property name="imap:nonSubscribed">
|
||||||
<type>d:boolean</type>
|
<type>d:boolean</type>
|
||||||
</property>
|
</property>
|
||||||
<property name="imap:selectable">
|
<property name="imap:selectable">
|
||||||
@@ -30,29 +30,6 @@
|
|||||||
</properties>
|
</properties>
|
||||||
</type>
|
</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">
|
<type name="imap:imapAttach">
|
||||||
<title>Attachment to the IMAP message</title>
|
<title>Attachment to the IMAP message</title>
|
||||||
<parent>cm:content</parent>
|
<parent>cm:content</parent>
|
||||||
@@ -69,11 +46,63 @@
|
|||||||
</type>
|
</type>
|
||||||
</types>
|
</types>
|
||||||
|
|
||||||
<aspects>
|
<aspects>
|
||||||
<aspect name="imap:flaggable">
|
<aspect name="imap:imapContent">
|
||||||
<properties>
|
<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">
|
<property name="imap:flagAnswered">
|
||||||
<type>d:boolean</type>
|
<type>d:boolean</type>
|
||||||
</property>
|
</property>
|
||||||
<property name="imap:flagDeleted">
|
<property name="imap:flagDeleted">
|
||||||
<type>d:boolean</type>
|
<type>d:boolean</type>
|
||||||
@@ -90,11 +119,10 @@
|
|||||||
<property name="imap:flagFlagged">
|
<property name="imap:flagFlagged">
|
||||||
<type>d:boolean</type>
|
<type>d:boolean</type>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
</properties>
|
</properties>
|
||||||
</aspect>
|
</aspect>
|
||||||
<aspect name="imap:subscribed"/>
|
<aspect name="imap:nonSubscribed"/>
|
||||||
<aspect name="imap:nonselectable"/>
|
<aspect name="imap:nonselectable"/>
|
||||||
</aspects>
|
</aspects>
|
||||||
|
|
||||||
</model>
|
</model>
|
@@ -1808,4 +1808,40 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</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>
|
</beans>
|
||||||
|
@@ -338,14 +338,22 @@ nfs.user.mappings.default.gid=0
|
|||||||
# IMAP
|
# IMAP
|
||||||
imap.server.enabled=false
|
imap.server.enabled=false
|
||||||
imap.server.port=143
|
imap.server.port=143
|
||||||
|
imap.server.host=localhost
|
||||||
|
imap.server.attachments.extraction.enabled=true
|
||||||
|
|
||||||
# Default IMAP mount points
|
# 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.store=${spaces.store}
|
||||||
imap.server.mountPoints.default.rootPath=/${spaces.company_home.childname}
|
imap.server.mountPoints.default.rootPath=/${spaces.company_home.childname}
|
||||||
imap.server.mountPoints.default.mode=virtual
|
imap.server.mountPoints.default.mode=virtual
|
||||||
imap.server.mountPoints.value.Repository_virtual.mode=virtual
|
imap.server.mountPoints.value.Repository_virtual.mode=virtual
|
||||||
imap.server.mountPoints.value.Repository_archive.mode=archive
|
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)
|
# Activity feed max size and max age (eg. 44640 mins = 31 days)
|
||||||
activities.feed.max.size=100
|
activities.feed.max.size=100
|
||||||
|
@@ -11,41 +11,10 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</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">
|
<bean id="imapServer" class="org.alfresco.repo.imap.AlfrescoImapServer">
|
||||||
|
<property name="host">
|
||||||
|
<value>${imap.server.host}</value>
|
||||||
|
</property>
|
||||||
<property name="port">
|
<property name="port">
|
||||||
<value>${imap.server.port}</value>
|
<value>${imap.server.port}</value>
|
||||||
</property>
|
</property>
|
||||||
@@ -58,16 +27,13 @@
|
|||||||
<property name="imapUserManager">
|
<property name="imapUserManager">
|
||||||
<ref local="imapUserManager" />
|
<ref local="imapUserManager" />
|
||||||
</property>
|
</property>
|
||||||
<property name="imapHelper">
|
|
||||||
<ref local="imapHelper" />
|
|
||||||
</property>
|
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<!--The configurable list of mount points - actually a post-processed composite property! -->
|
<!--The configurable list of mount points - actually a post-processed composite property! -->
|
||||||
<bean id="imap.server.mountPoints" class="org.springframework.beans.factory.config.ListFactoryBean">
|
<bean id="imap.server.mountPoints" class="org.springframework.beans.factory.config.ListFactoryBean">
|
||||||
<property name="sourceList">
|
<property name="sourceList">
|
||||||
<list>
|
<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">
|
<property name="mode">
|
||||||
<value>virtual</value>
|
<value>virtual</value>
|
||||||
</property>
|
</property>
|
||||||
@@ -78,7 +44,7 @@
|
|||||||
<value>/${spaces.company_home.childname}</value>
|
<value>/${spaces.company_home.childname}</value>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</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">
|
<property name="mode">
|
||||||
<value>archive</value>
|
<value>archive</value>
|
||||||
</property>
|
</property>
|
||||||
@@ -93,17 +59,101 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</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">
|
<bean id="imapHostManager" class="org.alfresco.repo.imap.AlfrescoImapHostManager">
|
||||||
<property name="serviceRegistry" ref="ServiceRegistry" />
|
<property name="imapService">
|
||||||
<property name="nodeService" ref="NodeService" />
|
<ref bean="ImapService" />
|
||||||
<property name="fileFolderService" ref="FileFolderService" />
|
</property>
|
||||||
<property name="imapHelper" ref="imapHelper" />
|
<property name="transactionService">
|
||||||
|
<ref bean="transactionService" />
|
||||||
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="imapUserManager" class="org.alfresco.repo.imap.AlfrescoImapUserManager">
|
<bean id="imapUserManager" class="org.alfresco.repo.imap.AlfrescoImapUserManager">
|
||||||
<property name="imapHostManager">
|
|
||||||
<ref local="imapHostManager" />
|
|
||||||
</property>
|
|
||||||
<property name="authenticationService" ref="AuthenticationService" />
|
<property name="authenticationService" ref="AuthenticationService" />
|
||||||
<property name="personService" ref="PersonService" />
|
<property name="personService" ref="PersonService" />
|
||||||
<property name="nodeService" ref="NodeService" />
|
<property name="nodeService" ref="NodeService" />
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
imap.server.enabled=false
|
imap.server.enabled=false
|
||||||
|
imap.server.host=localhost
|
||||||
imap.server.port=143
|
imap.server.port=143
|
||||||
|
|
||||||
#imap.server.web.application.context.url=http://localhost:8080/alfresco
|
#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>
|
<legend> Content links </legend>
|
||||||
<table class="links">
|
<table class="links">
|
||||||
<tr>
|
<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>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Content URL:</td><td><a href="${contextUrl}${document.url}">${contextUrl}${document.url}</a></td>
|
<td>Content URL:</td><td><a href="${contextUrl}${document.url}">${contextUrl}${document.url}</a></td>
|
||||||
@@ -101,7 +101,7 @@
|
|||||||
<legend> Start Workflow </legend>
|
<legend> Start Workflow </legend>
|
||||||
<form id="start_workflow"
|
<form id="start_workflow"
|
||||||
name="start_workflow"
|
name="start_workflow"
|
||||||
method="get"
|
method="post"
|
||||||
action="${contextUrl}/service/imap/start-workflow"
|
action="${contextUrl}/service/imap/start-workflow"
|
||||||
enctype="application/x-www-form-urlencoded">
|
enctype="application/x-www-form-urlencoded">
|
||||||
<input type="hidden" name="alfTicket" value="${alfTicket}" />
|
<input type="hidden" name="alfTicket" value="${alfTicket}" />
|
||||||
|
@@ -21,7 +21,7 @@ Size: ${document.size / 1024} Kb
|
|||||||
|
|
||||||
CONTENT LINKS
|
CONTENT LINKS
|
||||||
|
|
||||||
Content folder: ${contextUrl}${document.displayPath}
|
Content folder: ${contextUrl}/navigate/browse${document.displayPath}
|
||||||
Content URL: ${contextUrl}${document.url}
|
Content URL: ${contextUrl}${document.url}
|
||||||
Download URL: ${contextUrl}${document.downloadUrl}
|
Download URL: ${contextUrl}${document.downloadUrl}
|
||||||
WebDAV URL: ${contextUrl}${document.webdavUrl}
|
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
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* 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
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* 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.
|
* Concrete representation of an email message as implemented for the SubEtha mail server.
|
||||||
*
|
*
|
||||||
|
* @author Mike Shavnev
|
||||||
|
*
|
||||||
* @since 2.2
|
* @since 2.2
|
||||||
*/
|
*/
|
||||||
public class SubethaEmailMessage implements EmailMessage
|
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 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 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_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_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_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_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 ASPECT_FLAGGABLE = QName.createQName(IMAP_MODEL_1_0_URI, "flaggable");
|
||||||
static final QName PROP_FLAG_ANSWERED = QName.createQName(IMAP_MODEL_1_0_URI, "flagAnswered");
|
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
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* 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.alfresco.service.cmr.view.Location;
|
||||||
import org.springframework.context.MessageSource;
|
import org.springframework.context.MessageSource;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds folders tree necessary for IMAP functionality and imports email action scripts.
|
* 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);
|
throw new PatchException("XPath returned too many results: \n" + " root: " + storeRootNodeRef + "\n" + " xpath: " + xpath + "\n" + " results: " + nodeRefs);
|
||||||
}
|
}
|
||||||
this.dictionaryNodeRef = nodeRefs.get(0);
|
this.dictionaryNodeRef = nodeRefs.get(0);
|
||||||
|
|
||||||
sb.append("/").append(scriptsChildName);
|
sb.append("/").append(scriptsChildName);
|
||||||
xpath = sb.toString();
|
xpath = sb.toString();
|
||||||
nodeRefs = searchService.selectNodes(storeRootNodeRef, xpath, null, namespaceService, false);
|
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);
|
throw new PatchException("XPath returned too many results: \n" + " root: " + storeRootNodeRef + "\n" + " xpath: " + xpath + "\n" + " results: " + nodeRefs);
|
||||||
}
|
}
|
||||||
this.scriptsNodeRef = nodeRefs.get(0);
|
this.scriptsNodeRef = nodeRefs.get(0);
|
||||||
|
|
||||||
// get the ImapConfig node
|
// get the ImapConfig node
|
||||||
sb.delete((sb.length() - (scriptsChildName.length() + 1)), sb.length());
|
sb.delete((sb.length() - (scriptsChildName.length() + 1)), sb.length());
|
||||||
sb.append("/").append(imapConfigChildName);
|
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_ATOM = "application/atom+xml";
|
||||||
public static final String MIMETYPE_RSS = "application/rss+xml";
|
public static final String MIMETYPE_RSS = "application/rss+xml";
|
||||||
public static final String MIMETYPE_RFC822 = "message/rfc822";
|
public static final String MIMETYPE_RFC822 = "message/rfc822";
|
||||||
|
public static final String MIMETYPE_OUTLOOK_MSG = "application/vnd.ms-outlook";
|
||||||
// Open Document
|
// Open Document
|
||||||
public static final String MIMETYPE_OPENDOCUMENT_TEXT = "application/vnd.oasis.opendocument.text";
|
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";
|
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)
|
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))
|
!MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(targetMimetype))
|
||||||
{
|
{
|
||||||
// only support MSG -> TEXT
|
// 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 interface AlfrescoImapConst
|
||||||
{
|
{
|
||||||
|
|
||||||
public static final char HIERARCHY_DELIMITER = '.';
|
public static final char HIERARCHY_DELIMITER = '/';
|
||||||
public static final String NAMESPACE_PREFIX = "#";
|
public static final String NAMESPACE_PREFIX = "#";
|
||||||
public static final String USER_NAMESPACE = "#mail";
|
public static final String USER_NAMESPACE = "#mail";
|
||||||
public static final String INBOX_NAME = "INBOX";
|
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_PLAIN_NAME = "Body.txt";
|
||||||
public static final String BODY_TEXT_HTML_NAME = "Body.html";
|
public static final String BODY_TEXT_HTML_NAME = "Body.html";
|
||||||
public static final String MESSAGE_PREFIX = "Message_";
|
public static final String MESSAGE_PREFIX = "Message_";
|
||||||
|
public static final String EML_EXTENSION = ".eml";
|
||||||
// Separator for user enties in flag and subscribe properties
|
// Separator for user enties in flag and subscribe properties
|
||||||
public static final String USER_SEPARATOR = ";";
|
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";
|
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";
|
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
|
// Default content model email message templates
|
||||||
public static final String CLASSPATH_TEXT_PLAIN_TEMPLATE = "/alfresco/templates/imap/imap_message_text_plain.ftl";
|
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;
|
package org.alfresco.repo.imap;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
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.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
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.FolderException;
|
||||||
import com.icegreen.greenmail.store.MailFolder;
|
import com.icegreen.greenmail.store.MailFolder;
|
||||||
import com.icegreen.greenmail.user.GreenMailUser;
|
import com.icegreen.greenmail.user.GreenMailUser;
|
||||||
import com.icegreen.greenmail.util.GreenMailUtil;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Mike Shavnev
|
* @author Mike Shavnev
|
||||||
@@ -63,11 +46,8 @@ public class AlfrescoImapHostManager implements ImapHostManager
|
|||||||
|
|
||||||
private Log logger = LogFactory.getLog(AlfrescoImapHostManager.class);
|
private Log logger = LogFactory.getLog(AlfrescoImapHostManager.class);
|
||||||
|
|
||||||
private ServiceRegistry serviceRegistry;
|
private ImapService imapService;
|
||||||
|
private TransactionService transactionService;
|
||||||
private NodeService nodeService;
|
|
||||||
private FileFolderService fileFolderService;
|
|
||||||
private ImapHelper imapHelper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the hierarchy delimiter for mailboxes on this host.
|
* 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
|
public Collection<MailFolder> listMailboxes(GreenMailUser user, String mailboxPattern) throws FolderException
|
||||||
{
|
{
|
||||||
mailboxPattern = GreenMailUtil.convertFromUtf7(mailboxPattern);
|
try
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
{
|
||||||
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);
|
catch (Throwable e)
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
{
|
||||||
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
|
public Collection<MailFolder> listSubscribedMailboxes(GreenMailUser user, String mailboxPattern) throws FolderException
|
||||||
{
|
{
|
||||||
mailboxPattern = GreenMailUtil.convertFromUtf7(mailboxPattern);
|
try
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
{
|
||||||
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);
|
catch (Throwable e)
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
{
|
||||||
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 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.
|
* @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
|
public void renameMailbox(GreenMailUser user, String oldMailboxName, String newMailboxName) throws FolderException, AuthorizationException
|
||||||
{
|
{
|
||||||
oldMailboxName = GreenMailUtil.convertFromUtf7(oldMailboxName);
|
try
|
||||||
newMailboxName = GreenMailUtil.convertFromUtf7(newMailboxName);
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
{
|
||||||
logger.debug("Renaming folder: oldMailboxName=" + oldMailboxName + " newMailboxName=" + newMailboxName);
|
imapService.renameMailbox(new AlfrescoImapUser(user.getEmail(), user.getLogin(), user.getPassword()), oldMailboxName, newMailboxName);
|
||||||
}
|
}
|
||||||
|
catch (Throwable e)
|
||||||
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())
|
|
||||||
{
|
{
|
||||||
String folderName = tokenizer.nextToken();
|
throw new FolderException(e.getMessage());
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -480,58 +138,14 @@ public class AlfrescoImapHostManager implements ImapHostManager
|
|||||||
*/
|
*/
|
||||||
public MailFolder createMailbox(GreenMailUser user, String mailboxName) throws AuthorizationException, FolderException
|
public MailFolder createMailbox(GreenMailUser user, String mailboxName) throws AuthorizationException, FolderException
|
||||||
{
|
{
|
||||||
mailboxName = GreenMailUtil.convertFromUtf7(mailboxName);
|
try
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
{
|
||||||
logger.debug("Creating folder: " + mailboxName);
|
return imapService.createMailbox(new AlfrescoImapUser(user.getEmail(), user.getLogin(), user.getPassword()), mailboxName);
|
||||||
}
|
}
|
||||||
|
catch (Throwable e)
|
||||||
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())
|
|
||||||
{
|
{
|
||||||
String folderName = tokenizer.nextToken();
|
throw new FolderException(e.getMessage());
|
||||||
|
|
||||||
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(FolderException.ALREADY_EXISTS_LOCALLY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -544,34 +158,13 @@ public class AlfrescoImapHostManager implements ImapHostManager
|
|||||||
*/
|
*/
|
||||||
public void deleteMailbox(GreenMailUser user, String mailboxName) throws FolderException, AuthorizationException
|
public void deleteMailbox(GreenMailUser user, String mailboxName) throws FolderException, AuthorizationException
|
||||||
{
|
{
|
||||||
AlfrescoImapMailFolder folder = (AlfrescoImapMailFolder) getFolder(user, mailboxName);
|
try
|
||||||
NodeRef nodeRef = folder.getFolderInfo().getNodeRef();
|
|
||||||
|
|
||||||
List<FileInfo> childFolders = imapHelper.searchFolders(nodeRef, "*", false, false);
|
|
||||||
|
|
||||||
if (childFolders.isEmpty())
|
|
||||||
{
|
{
|
||||||
folder.signalDeletion();
|
imapService.deleteMailbox(new AlfrescoImapUser(user.getEmail(), user.getLogin(), user.getPassword()), mailboxName);
|
||||||
// Delete child folders and messages
|
|
||||||
fileFolderService.delete(nodeRef);
|
|
||||||
}
|
}
|
||||||
else
|
catch (Throwable e)
|
||||||
{
|
{
|
||||||
if (folder.isSelectable())
|
throw new FolderException(e.getMessage());
|
||||||
{
|
|
||||||
// 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.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,80 +179,22 @@ public class AlfrescoImapHostManager implements ImapHostManager
|
|||||||
*/
|
*/
|
||||||
public MailFolder getFolder(GreenMailUser user, String mailboxName)
|
public MailFolder getFolder(GreenMailUser user, String mailboxName)
|
||||||
{
|
{
|
||||||
mailboxName = GreenMailUtil.convertFromUtf7(mailboxName);
|
return imapService.getFolder(new AlfrescoImapUser(user.getEmail(), user.getLogin(), user.getPassword()), 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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simply calls {@link #getFolder(GreenMailUser, String)}. <p/> Added to implement {@link ImapHostManager}.
|
* 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
|
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 user User making the request
|
||||||
* @param mailbox String representation of a mailbox name.
|
* @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 user User making the request
|
||||||
* @param mailbox String representation of a mailbox name.
|
* @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.
|
* Not supported. Used by GreenMail class.
|
||||||
*/
|
*/
|
||||||
public List getAllMessages()
|
public List<?> getAllMessages()
|
||||||
{
|
{
|
||||||
throw new UnsupportedOperationException();
|
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----------------------------
|
// ----------------------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;
|
this.transactionService = transactionService;
|
||||||
}
|
|
||||||
|
|
||||||
public void setImapHelper(ImapHelper imapHelper)
|
|
||||||
{
|
|
||||||
this.imapHelper = imapHelper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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 int port = 143;
|
||||||
|
|
||||||
|
private String host = "localhost";
|
||||||
|
|
||||||
private ImapHostManager imapHostManager;
|
private ImapHostManager imapHostManager;
|
||||||
|
|
||||||
private UserManager imapUserManager;
|
private UserManager imapUserManager;
|
||||||
|
|
||||||
private boolean imapServerEnabled;
|
private boolean imapServerEnabled;
|
||||||
|
|
||||||
private ImapHelper imapHelper;
|
|
||||||
|
|
||||||
public void setImapServerEnabled(boolean imapServerEnabled)
|
public void setImapServerEnabled(boolean imapServerEnabled)
|
||||||
{
|
{
|
||||||
this.imapServerEnabled = imapServerEnabled;
|
this.imapServerEnabled = imapServerEnabled;
|
||||||
@@ -65,6 +65,11 @@ public class AlfrescoImapServer extends AbstractLifecycleBean
|
|||||||
this.port = port;
|
this.port = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setHost(String host)
|
||||||
|
{
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
public void setImapHostManager(ImapHostManager imapHostManager)
|
public void setImapHostManager(ImapHostManager imapHostManager)
|
||||||
{
|
{
|
||||||
this.imapHostManager = imapHostManager;
|
this.imapHostManager = imapHostManager;
|
||||||
@@ -75,14 +80,9 @@ public class AlfrescoImapServer extends AbstractLifecycleBean
|
|||||||
this.imapUserManager = imapUserManager;
|
this.imapUserManager = imapUserManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setImapHelper(ImapHelper imapHelper)
|
|
||||||
{
|
|
||||||
this.imapHelper = imapHelper;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onBootstrap(ApplicationEvent event)
|
protected void onBootstrap(ApplicationEvent event)
|
||||||
{
|
{
|
||||||
if (imapServerEnabled && imapHelper.isPatchApplied())
|
if (imapServerEnabled)
|
||||||
{
|
{
|
||||||
Managers imapManagers = new Managers()
|
Managers imapManagers = new Managers()
|
||||||
{
|
{
|
||||||
@@ -96,11 +96,11 @@ public class AlfrescoImapServer extends AbstractLifecycleBean
|
|||||||
return imapUserManager;
|
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);
|
serverImpl.startService(null);
|
||||||
if (logger.isInfoEnabled())
|
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
|
else
|
||||||
|
@@ -26,7 +26,6 @@ package org.alfresco.repo.imap;
|
|||||||
|
|
||||||
import javax.mail.internet.MimeMessage;
|
import javax.mail.internet.MimeMessage;
|
||||||
|
|
||||||
import com.icegreen.greenmail.imap.ImapHostManager;
|
|
||||||
import com.icegreen.greenmail.mail.MovingMessage;
|
import com.icegreen.greenmail.mail.MovingMessage;
|
||||||
import com.icegreen.greenmail.user.GreenMailUser;
|
import com.icegreen.greenmail.user.GreenMailUser;
|
||||||
import com.icegreen.greenmail.user.UserException;
|
import com.icegreen.greenmail.user.UserException;
|
||||||
@@ -42,14 +41,11 @@ public class AlfrescoImapUser implements GreenMailUser
|
|||||||
private char[] password;
|
private char[] password;
|
||||||
private String email;
|
private String email;
|
||||||
|
|
||||||
private ImapHostManager imapHostManager;
|
public AlfrescoImapUser(String email, String login, String password)
|
||||||
|
|
||||||
public AlfrescoImapUser(String email, String login, String password, ImapHostManager imapHostManager)
|
|
||||||
{
|
{
|
||||||
this.email = email;
|
this.email = email;
|
||||||
this.userName = login;
|
this.userName = login;
|
||||||
this.password = password.toCharArray();
|
this.password = password.toCharArray();
|
||||||
this.imapHostManager = imapHostManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void authenticate(String password) throws UserException
|
public void authenticate(String password) throws UserException
|
||||||
@@ -71,12 +67,12 @@ public class AlfrescoImapUser implements GreenMailUser
|
|||||||
|
|
||||||
public void deliver(MovingMessage msg) throws UserException
|
public void deliver(MovingMessage msg) throws UserException
|
||||||
{
|
{
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deliver(MimeMessage msg) throws UserException
|
public void deliver(MimeMessage msg) throws UserException
|
||||||
{
|
{
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEmail()
|
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.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import com.icegreen.greenmail.imap.ImapHostManager;
|
|
||||||
import com.icegreen.greenmail.user.GreenMailUser;
|
import com.icegreen.greenmail.user.GreenMailUser;
|
||||||
import com.icegreen.greenmail.user.UserException;
|
import com.icegreen.greenmail.user.UserException;
|
||||||
import com.icegreen.greenmail.user.UserManager;
|
import com.icegreen.greenmail.user.UserManager;
|
||||||
@@ -50,7 +49,6 @@ public class AlfrescoImapUserManager extends UserManager
|
|||||||
private Log logger = LogFactory.getLog(AlfrescoImapUserManager.class);
|
private Log logger = LogFactory.getLog(AlfrescoImapUserManager.class);
|
||||||
|
|
||||||
protected Map<String, GreenMailUser> userMap = Collections.synchronizedMap(new HashMap<String, GreenMailUser>());
|
protected Map<String, GreenMailUser> userMap = Collections.synchronizedMap(new HashMap<String, GreenMailUser>());
|
||||||
protected ImapHostManager imapHostManager;
|
|
||||||
|
|
||||||
protected AuthenticationService authenticationService;
|
protected AuthenticationService authenticationService;
|
||||||
protected PersonService personService;
|
protected PersonService personService;
|
||||||
@@ -61,17 +59,11 @@ public class AlfrescoImapUserManager extends UserManager
|
|||||||
super(null);
|
super(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AlfrescoImapUserManager(ImapHostManager imapHostManager)
|
|
||||||
{
|
|
||||||
this();
|
|
||||||
this.imapHostManager = imapHostManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GreenMailUser createUser(String email, String login, String password) throws UserException
|
public GreenMailUser createUser(String email, String login, String password) throws UserException
|
||||||
{
|
{
|
||||||
// TODO: User creation/addition code should be implemented here (in the AlfrescoImapUserManager).
|
// TODO: User creation/addition code should be implemented here (in the AlfrescoImapUserManager).
|
||||||
// Following code is not need and not used in the current implementation.
|
// 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();
|
user.create();
|
||||||
addUser(user);
|
addUser(user);
|
||||||
return user;
|
return user;
|
||||||
@@ -129,7 +121,7 @@ public class AlfrescoImapUserManager extends UserManager
|
|||||||
NodeRef personNodeRef = personService.getPerson(userid);
|
NodeRef personNodeRef = personService.getPerson(userid);
|
||||||
email = (String) nodeService.getProperty(personNodeRef, ContentModel.PROP_EMAIL);
|
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);
|
addUser(user);
|
||||||
}
|
}
|
||||||
catch (AuthenticationException ex)
|
catch (AuthenticationException ex)
|
||||||
@@ -140,16 +132,6 @@ public class AlfrescoImapUserManager extends UserManager
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImapHostManager getImapHostManager()
|
|
||||||
{
|
|
||||||
return this.imapHostManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setImapHostManager(ImapHostManager imapHostManager)
|
|
||||||
{
|
|
||||||
this.imapHostManager = imapHostManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAuthenticationService(AuthenticationService authenticationService)
|
public void setAuthenticationService(AuthenticationService authenticationService)
|
||||||
{
|
{
|
||||||
this.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;
|
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
|
public class ImapConfigBean implements BeanNameAware
|
||||||
{
|
{
|
||||||
@@ -35,9 +35,6 @@ public class ImapConfigBean implements BeanNameAware
|
|||||||
/** The IMAP folder name. */
|
/** The IMAP folder name. */
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
/** The mode (virtual or archive). */
|
|
||||||
private String mode;
|
|
||||||
|
|
||||||
/** The Alfresco store name. */
|
/** The Alfresco store name. */
|
||||||
private String store;
|
private String store;
|
||||||
|
|
||||||
@@ -63,27 +60,6 @@ public class ImapConfigBean implements BeanNameAware
|
|||||||
this.name = name;
|
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.
|
* 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.cmis.CMISServices;
|
||||||
import org.alfresco.mbeans.VirtServerRegistry;
|
import org.alfresco.mbeans.VirtServerRegistry;
|
||||||
import org.alfresco.repo.forms.FormService;
|
import org.alfresco.repo.forms.FormService;
|
||||||
|
import org.alfresco.repo.imap.ImapService;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
import org.alfresco.service.ServiceRegistry;
|
import org.alfresco.service.ServiceRegistry;
|
||||||
import org.alfresco.service.cmr.action.ActionService;
|
import org.alfresco.service.cmr.action.ActionService;
|
||||||
@@ -544,4 +545,13 @@ public class ServiceDescriptorRegistry
|
|||||||
{
|
{
|
||||||
return (CMISQueryService)getService(CMIS_QUERY_SERVICE);
|
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.cmis.CMISServices;
|
||||||
import org.alfresco.mbeans.VirtServerRegistry;
|
import org.alfresco.mbeans.VirtServerRegistry;
|
||||||
import org.alfresco.repo.forms.FormService;
|
import org.alfresco.repo.forms.FormService;
|
||||||
|
import org.alfresco.repo.imap.ImapService;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
import org.alfresco.service.cmr.action.ActionService;
|
import org.alfresco.service.cmr.action.ActionService;
|
||||||
import org.alfresco.service.cmr.attributes.AttributeService;
|
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_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CMISService");
|
||||||
static final QName CMIS_DICTIONARY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CMISDictionaryService");
|
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 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
|
@NotAuditable
|
||||||
CMISQueryService getCMISQueryService();
|
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