mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
Initial cut of IMAP support (disabled by default, to enable move imap sample files into extension folder)
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14279 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -473,6 +473,9 @@
|
|||||||
<property name="companyHomePath">
|
<property name="companyHomePath">
|
||||||
<value>/${spaces.company_home.childname}</value>
|
<value>/${spaces.company_home.childname}</value>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="webApplicationContextUrl">
|
||||||
|
<value>${web.application.context.url}</value>
|
||||||
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="counter" class="org.alfresco.repo.action.executer.CounterIncrementActionExecuter" parent="action-executer">
|
<bean id="counter" class="org.alfresco.repo.action.executer.CounterIncrementActionExecuter" parent="action-executer">
|
||||||
|
@@ -52,6 +52,7 @@
|
|||||||
<import resource="classpath:alfresco/form-services-context.xml"/>
|
<import resource="classpath:alfresco/form-services-context.xml"/>
|
||||||
<import resource="classpath:alfresco/invitation-service-context.xml"/>
|
<import resource="classpath:alfresco/invitation-service-context.xml"/>
|
||||||
<import resource="classpath:alfresco/cmis-api-context.xml" />
|
<import resource="classpath:alfresco/cmis-api-context.xml" />
|
||||||
|
<import resource="classpath:alfresco/imap-server-context.xml"/>
|
||||||
<import resource="classpath*:alfresco/patch/*-context.xml" />
|
<import resource="classpath*:alfresco/patch/*-context.xml" />
|
||||||
<import resource="classpath*:alfresco/domain/*-context.xml" />
|
<import resource="classpath*:alfresco/domain/*-context.xml" />
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
<view:view xmlns:view="http://www.alfresco.org/view/repository/1.0"
|
<view:view xmlns:view="http://www.alfresco.org/view/repository/1.0"
|
||||||
xmlns:cm="http://www.alfresco.org/model/content/1.0"
|
xmlns:cm="http://www.alfresco.org/model/content/1.0"
|
||||||
xmlns:app="http://www.alfresco.org/model/application/1.0">
|
xmlns:app="http://www.alfresco.org/model/application/1.0"
|
||||||
|
xmlns:emailserver="http://www.alfresco.org/model/emailserver/1.0">
|
||||||
|
|
||||||
<!-- NOTE: all replaced properties referenced from repository.properties file must also be
|
<!-- NOTE: all replaced properties referenced from repository.properties file must also be
|
||||||
mapped in the bootstrap-context.xml spacesBootstrap/configuration section -->
|
mapped in the bootstrap-context.xml spacesBootstrap/configuration section -->
|
||||||
@@ -24,34 +25,34 @@
|
|||||||
<view:permission>Consumer</view:permission>
|
<view:permission>Consumer</view:permission>
|
||||||
</view:ace>
|
</view:ace>
|
||||||
</view:acl>
|
</view:acl>
|
||||||
<app:uifacets/>
|
<app:uifacets/>
|
||||||
<cm:name>${spaces.dictionary.name}</cm:name>
|
<cm:name>${spaces.dictionary.name}</cm:name>
|
||||||
<app:icon>space-icon-default</app:icon>
|
<app:icon>space-icon-default</app:icon>
|
||||||
<cm:title>${spaces.dictionary.name}</cm:title>
|
<cm:title>${spaces.dictionary.name}</cm:title>
|
||||||
<cm:description>${spaces.dictionary.description}</cm:description>
|
<cm:description>${spaces.dictionary.description}</cm:description>
|
||||||
<cm:contains>
|
<cm:contains>
|
||||||
<cm:folder view:childName="${spaces.templates.childname}">
|
<cm:folder view:childName="${spaces.templates.childname}">
|
||||||
<app:uifacets/>
|
<app:uifacets/>
|
||||||
<cm:name>${spaces.templates.name}</cm:name>
|
<cm:name>${spaces.templates.name}</cm:name>
|
||||||
<app:icon>space-icon-default</app:icon>
|
<app:icon>space-icon-default</app:icon>
|
||||||
<cm:title>${spaces.templates.name}</cm:title>
|
<cm:title>${spaces.templates.name}</cm:title>
|
||||||
<cm:description>${spaces.templates.description}</cm:description>
|
<cm:description>${spaces.templates.description}</cm:description>
|
||||||
</cm:folder>
|
</cm:folder>
|
||||||
<cm:folder
|
<cm:folder
|
||||||
view:childName="${spaces.templates.content.childname}">
|
view:childName="${spaces.templates.content.childname}">
|
||||||
<app:uifacets/>
|
<app:uifacets/>
|
||||||
<cm:name>${spaces.templates.content.name}</cm:name>
|
<cm:name>${spaces.templates.content.name}</cm:name>
|
||||||
<app:icon>space-icon-default</app:icon>
|
<app:icon>space-icon-default</app:icon>
|
||||||
<cm:title>${spaces.templates.content.name}</cm:title>
|
<cm:title>${spaces.templates.content.name}</cm:title>
|
||||||
<cm:description>${spaces.templates.content.description}</cm:description>
|
<cm:description>${spaces.templates.content.description}</cm:description>
|
||||||
</cm:folder>
|
</cm:folder>
|
||||||
<cm:folder
|
<cm:folder
|
||||||
view:childName="${spaces.templates.email.childname}">
|
view:childName="${spaces.templates.email.childname}">
|
||||||
<app:uifacets/>
|
<app:uifacets/>
|
||||||
<cm:name>${spaces.templates.email.name}</cm:name>
|
<cm:name>${spaces.templates.email.name}</cm:name>
|
||||||
<app:icon>space-icon-default</app:icon>
|
<app:icon>space-icon-default</app:icon>
|
||||||
<cm:title>${spaces.templates.email.name}</cm:title>
|
<cm:title>${spaces.templates.email.name}</cm:title>
|
||||||
<cm:description>${spaces.templates.email.description}</cm:description>
|
<cm:description>${spaces.templates.email.description}</cm:description>
|
||||||
<cm:contains>
|
<cm:contains>
|
||||||
<cm:folder
|
<cm:folder
|
||||||
view:childName="${spaces.templates.email.invite.childname}">
|
view:childName="${spaces.templates.email.invite.childname}">
|
||||||
@@ -80,69 +81,68 @@
|
|||||||
</cm:contains>
|
</cm:contains>
|
||||||
</cm:folder>
|
</cm:folder>
|
||||||
</cm:contains>
|
</cm:contains>
|
||||||
</cm:folder>
|
</cm:folder>
|
||||||
<cm:folder
|
<cm:folder
|
||||||
view:childName="${spaces.templates.rss.childname}">
|
view:childName="${spaces.templates.rss.childname}">
|
||||||
<view:acl>
|
<view:acl>
|
||||||
<view:ace view:access="ALLOWED">
|
<view:ace view:access="ALLOWED">
|
||||||
<view:authority>${alfresco_user_store.guestusername}</view:authority>
|
<view:authority>${alfresco_user_store.guestusername}</view:authority>
|
||||||
<view:permission>Consumer</view:permission>
|
<view:permission>Consumer</view:permission>
|
||||||
</view:ace>
|
</view:ace>
|
||||||
</view:acl>
|
</view:acl>
|
||||||
<app:uifacets/>
|
<app:uifacets/>
|
||||||
<cm:name>${spaces.templates.rss.name}</cm:name>
|
<cm:name>${spaces.templates.rss.name}</cm:name>
|
||||||
<app:icon>space-icon-default</app:icon>
|
<app:icon>space-icon-default</app:icon>
|
||||||
<cm:title>${spaces.templates.rss.name}</cm:title>
|
<cm:title>${spaces.templates.rss.name}</cm:title>
|
||||||
<cm:description>${spaces.templates.rss.description}</cm:description>
|
<cm:description>${spaces.templates.rss.description}</cm:description>
|
||||||
</cm:folder>
|
</cm:folder>
|
||||||
<cm:folder
|
<cm:folder
|
||||||
view:childName="${spaces.savedsearches.childname}">
|
view:childName="${spaces.savedsearches.childname}">
|
||||||
<view:acl view:inherit="false">
|
<view:acl view:inherit="false">
|
||||||
<view:ace view:access="ALLOWED">
|
<view:ace view:access="ALLOWED">
|
||||||
<view:authority>GROUP_EVERYONE</view:authority>
|
<view:authority>GROUP_EVERYONE</view:authority>
|
||||||
<view:permission>Contributor</view:permission>
|
<view:permission>Contributor</view:permission>
|
||||||
</view:ace>
|
</view:ace>
|
||||||
</view:acl>
|
</view:acl>
|
||||||
<app:uifacets/>
|
<app:uifacets/>
|
||||||
<cm:name>${spaces.savedsearches.name}</cm:name>
|
<cm:name>${spaces.savedsearches.name}</cm:name>
|
||||||
<app:icon>space-icon-default</app:icon>
|
<app:icon>space-icon-default</app:icon>
|
||||||
<cm:title>${spaces.savedsearches.name}</cm:title>
|
<cm:title>${spaces.savedsearches.name}</cm:title>
|
||||||
<cm:description>${spaces.savedsearches.description}</cm:description>
|
<cm:description>${spaces.savedsearches.description}</cm:description>
|
||||||
</cm:folder>
|
</cm:folder>
|
||||||
<cm:folder view:childName="${spaces.scripts.childname}">
|
<cm:folder view:childName="${spaces.scripts.childname}">
|
||||||
<app:uifacets/>
|
<app:uifacets/>
|
||||||
<cm:name>${spaces.scripts.name}</cm:name>
|
<cm:name>${spaces.scripts.name}</cm:name>
|
||||||
<app:icon>space-icon-default</app:icon>
|
<app:icon>space-icon-default</app:icon>
|
||||||
<cm:title>${spaces.scripts.name}</cm:title>
|
<cm:title>${spaces.scripts.name}</cm:title>
|
||||||
<cm:description>${spaces.scripts.description}</cm:description>
|
<cm:description>${spaces.scripts.description}</cm:description>
|
||||||
</cm:folder>
|
</cm:folder>
|
||||||
</cm:contains>
|
</cm:contains>
|
||||||
</cm:folder>
|
</cm:folder>
|
||||||
<cm:folder view:childName="${spaces.guest_home.childname}">
|
<cm:folder view:childName="${spaces.guest_home.childname}">
|
||||||
<view:acl view:inherit="false">
|
<view:acl view:inherit="false">
|
||||||
<view:ace view:access="ALLOWED">
|
<view:ace view:access="ALLOWED">
|
||||||
<view:authority>${alfresco_user_store.guestusername}</view:authority>
|
<view:authority>${alfresco_user_store.guestusername}</view:authority>
|
||||||
<view:permission>Consumer</view:permission>
|
<view:permission>Consumer</view:permission>
|
||||||
</view:ace>
|
</view:ace>
|
||||||
<view:ace view:access="ALLOWED">
|
<view:ace view:access="ALLOWED">
|
||||||
<view:authority>GROUP_EVERYONE</view:authority>
|
<view:authority>GROUP_EVERYONE</view:authority>
|
||||||
<view:permission>Consumer</view:permission>
|
<view:permission>Consumer</view:permission>
|
||||||
</view:ace>
|
</view:ace>
|
||||||
</view:acl>
|
</view:acl>
|
||||||
<app:uifacets/>
|
<app:uifacets/>
|
||||||
<cm:name>${spaces.guest_home.name}</cm:name>
|
<cm:name>${spaces.guest_home.name}</cm:name>
|
||||||
<app:icon>space-icon-default</app:icon>
|
<app:icon>space-icon-default</app:icon>
|
||||||
<cm:title>${spaces.guest_home.name}</cm:title>
|
<cm:title>${spaces.guest_home.name}</cm:title>
|
||||||
<cm:description>${spaces.guest_home.description}</cm:description>
|
<cm:description>${spaces.guest_home.description}</cm:description>
|
||||||
</cm:folder>
|
</cm:folder>
|
||||||
<cm:folder view:childName="${spaces.user_homes.childname}">
|
<cm:folder view:childName="${spaces.user_homes.childname}">
|
||||||
<app:uifacets/>
|
<app:uifacets/>
|
||||||
<cm:name>${spaces.user_homes.name}</cm:name>
|
<cm:name>${spaces.user_homes.name}</cm:name>
|
||||||
<app:icon>space-icon-default</app:icon>
|
<app:icon>space-icon-default</app:icon>
|
||||||
<cm:title>${spaces.user_homes.name}</cm:title>
|
<cm:title>${spaces.user_homes.name}</cm:title>
|
||||||
<cm:description>${spaces.user_homes.description}</cm:description>
|
<cm:description>${spaces.user_homes.description}</cm:description>
|
||||||
</cm:folder>
|
</cm:folder>
|
||||||
</cm:contains>
|
</cm:contains>
|
||||||
</cm:folder>
|
</cm:folder>
|
||||||
|
|
||||||
</view:view>
|
</view:view>
|
@@ -49,7 +49,7 @@
|
|||||||
<cm:userName>${alfresco_user_store.adminusername}</cm:userName>
|
<cm:userName>${alfresco_user_store.adminusername}</cm:userName>
|
||||||
<cm:firstName>Administrator</cm:firstName>
|
<cm:firstName>Administrator</cm:firstName>
|
||||||
<cm:lastName></cm:lastName>
|
<cm:lastName></cm:lastName>
|
||||||
<cm:email></cm:email>
|
<cm:email>admin@alfresco.com</cm:email>
|
||||||
<cm:organizationId></cm:organizationId>
|
<cm:organizationId></cm:organizationId>
|
||||||
<cm:homeFolder>/${spaces.company_home.childname}</cm:homeFolder>
|
<cm:homeFolder>/${spaces.company_home.childname}</cm:homeFolder>
|
||||||
<cm:homeFolderProvider>bootstrapHomeFolderProvider</cm:homeFolderProvider>
|
<cm:homeFolderProvider>bootstrapHomeFolderProvider</cm:homeFolderProvider>
|
||||||
|
@@ -928,6 +928,7 @@
|
|||||||
<value>alfresco/model/bpmModel.xml</value>
|
<value>alfresco/model/bpmModel.xml</value>
|
||||||
<value>alfresco/model/wcmModel.xml</value>
|
<value>alfresco/model/wcmModel.xml</value>
|
||||||
<value>alfresco/model/forumModel.xml</value>
|
<value>alfresco/model/forumModel.xml</value>
|
||||||
|
<value>alfresco/model/imapModel.xml</value>
|
||||||
|
|
||||||
<!-- Content models -->
|
<!-- Content models -->
|
||||||
<value>alfresco/model/applicationModel.xml</value>
|
<value>alfresco/model/applicationModel.xml</value>
|
||||||
|
19
config/alfresco/extension/custom-imap-server-context.xml.sample
Executable file
19
config/alfresco/extension/custom-imap-server-context.xml.sample
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
<?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="imapServerConfigurationProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
|
||||||
|
<property name="ignoreUnresolvablePlaceholders">
|
||||||
|
<value>true</value>
|
||||||
|
</property>
|
||||||
|
<property name="locations">
|
||||||
|
<list>
|
||||||
|
<value>classpath:alfresco/imap-server.properties</value>
|
||||||
|
<!-- Override -->
|
||||||
|
<value>classpath:alfresco/extension/custom-imap-server.properties</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
</beans>
|
2
config/alfresco/extension/custom-imap-server.properties.sample
Executable file
2
config/alfresco/extension/custom-imap-server.properties.sample
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
imap.server.enabled=true
|
||||||
|
imap.server.port=143
|
40
config/alfresco/extension/imap-bootsrap-context.xml.sample
Executable file
40
config/alfresco/extension/imap-bootsrap-context.xml.sample
Executable file
@@ -0,0 +1,40 @@
|
|||||||
|
<?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>
|
14
config/alfresco/imap-config.xml
Executable file
14
config/alfresco/imap-config.xml
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
<alfresco-config>
|
||||||
|
<config>
|
||||||
|
<imapConfig>
|
||||||
|
<imap name="Repository_virtual" mode="virtual">
|
||||||
|
<store>workspace://SpacesStore</store>
|
||||||
|
<rootPath>/app:company_home</rootPath>
|
||||||
|
</imap>
|
||||||
|
<imap name="Repository_archive" mode="archive">
|
||||||
|
<store>workspace://SpacesStore</store>
|
||||||
|
<rootPath>/app:company_home</rootPath>
|
||||||
|
</imap>
|
||||||
|
</imapConfig>
|
||||||
|
</config>
|
||||||
|
</alfresco-config>
|
91
config/alfresco/imap-server-context.xml
Executable file
91
config/alfresco/imap-server-context.xml
Executable file
@@ -0,0 +1,91 @@
|
|||||||
|
<?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="imapResourceBundles" class="org.alfresco.i18n.ResourceBundleBootstrapComponent">
|
||||||
|
<property name="resourceBundles">
|
||||||
|
<list>
|
||||||
|
<value>alfresco.messages.imap-service</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="imapServerConfigurationProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
|
||||||
|
<property name="ignoreUnresolvablePlaceholders">
|
||||||
|
<value>true</value>
|
||||||
|
</property>
|
||||||
|
<property name="locations">
|
||||||
|
<list>
|
||||||
|
<value>classpath:alfresco/imap-server.properties</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="imapHelper" class="org.alfresco.repo.imap.ImapHelper">
|
||||||
|
<property name="nodeService" ref="NodeService" />
|
||||||
|
<property name="fileFolderService" ref="FileFolderService" />
|
||||||
|
<property name="searchService" ref="SearchService" />
|
||||||
|
<property name="namespaceService" ref="NamespaceService" />
|
||||||
|
<property name="templateService" ref="TemplateService" />
|
||||||
|
<property name="permissionService" ref="PermissionService" />
|
||||||
|
<property name="configService" ref="webClientConfigService" />
|
||||||
|
<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="defaultFromAddress">
|
||||||
|
<value>${mail.from.default}</value>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<property name="webApplicationContextUrl">
|
||||||
|
<value>${web.application.context.url}</value>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<property name="imapRoot">
|
||||||
|
<value>${spaces.store}/${spaces.company_home.childname}/${spaces.imap_home.childname}</value>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<property name="repositoryTemplatePath">
|
||||||
|
<value>${spaces.store}/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.imapConfig.childname}/${spaces.imap_templates.childname}</value>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="imapServer" class="org.alfresco.repo.imap.AlfrescoImapServer">
|
||||||
|
<property name="port">
|
||||||
|
<value>${imap.server.port}</value>
|
||||||
|
</property>
|
||||||
|
<property name="imapServerEnabled">
|
||||||
|
<value>${imap.server.enabled}</value>
|
||||||
|
</property>
|
||||||
|
<property name="imapHostManager">
|
||||||
|
<ref local="imapHostManager"/>
|
||||||
|
</property>
|
||||||
|
<property name="imapUserManager">
|
||||||
|
<ref local="imapUserManager"/>
|
||||||
|
</property>
|
||||||
|
<property name="imapHelper">
|
||||||
|
<ref local="imapHelper"/>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="imapHostManager" class="org.alfresco.repo.imap.AlfrescoImapHostManager" >
|
||||||
|
<property name="serviceRegistry" ref="ServiceRegistry" />
|
||||||
|
<property name="nodeService" ref="NodeService" />
|
||||||
|
<property name="fileFolderService" ref="FileFolderService" />
|
||||||
|
<property name="imapHelper" ref="imapHelper" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="imapUserManager" class="org.alfresco.repo.imap.AlfrescoImapUserManager">
|
||||||
|
<property name="imapHostManager">
|
||||||
|
<ref local="imapHostManager" />
|
||||||
|
</property>
|
||||||
|
<property name="authenticationService" ref="AuthenticationService" />
|
||||||
|
<property name="personService" ref="PersonService" />
|
||||||
|
<property name="nodeService" ref="NodeService" />
|
||||||
|
</bean>
|
||||||
|
</beans>
|
4
config/alfresco/imap-server.properties
Executable file
4
config/alfresco/imap-server.properties
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
imap.server.enabled=false
|
||||||
|
imap.server.port=143
|
||||||
|
|
||||||
|
#imap.server.web.application.context.url=http://localhost:8080/alfresco
|
77
config/alfresco/imap/scripts/command-processor.js
Executable file
77
config/alfresco/imap/scripts/command-processor.js
Executable file
@@ -0,0 +1,77 @@
|
|||||||
|
<import resource="/Company Home/Data Dictionary/Scripts/command-utils.js">
|
||||||
|
|
||||||
|
function processCommand()
|
||||||
|
{
|
||||||
|
var isEmailed = document.hasAspect("emailserver:emailed");
|
||||||
|
|
||||||
|
logger.log("Command Processor: isEmailed=" + isEmailed);
|
||||||
|
|
||||||
|
if (isEmailed)
|
||||||
|
{
|
||||||
|
// Delete email attachments
|
||||||
|
var attachments = document.assocs["attachments"];
|
||||||
|
if (attachments != null)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < attachments.length; i++)
|
||||||
|
{
|
||||||
|
attachments[i].remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var command = document.properties["cm:title"];
|
||||||
|
logger.log("Command Processor: command=" + command);
|
||||||
|
|
||||||
|
var parts = new Array();
|
||||||
|
var str = command;
|
||||||
|
var i = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var index = str.indexOf("-");
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
parts[i] = str;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
parts[i] = str.substring(0, index);
|
||||||
|
str = str.substr(index + 1);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// do-<commandName>-<arg1>-...-<argN>
|
||||||
|
if (parts.length < 3 || parts[0].toLowerCase() != "do")
|
||||||
|
{
|
||||||
|
var message = "Unknown command: " + command;
|
||||||
|
logger.log(message);
|
||||||
|
createEmail(message, message, message, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var commandName = parts[1].toLowerCase();
|
||||||
|
var commandFolder = space.childByNamePath(commandName);
|
||||||
|
logger.log("Found '" + commandName + "' command folder: '" + commandFolder + "'");
|
||||||
|
if (commandFolder == null)
|
||||||
|
{
|
||||||
|
var message = "Command Processor: wrong command=" + command;
|
||||||
|
createEmail(message, message, message, false);
|
||||||
|
logger.log(message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.move(commandFolder);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
processCommand();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
243
config/alfresco/imap/scripts/command-search.js
Executable file
243
config/alfresco/imap/scripts/command-search.js
Executable file
@@ -0,0 +1,243 @@
|
|||||||
|
<import resource="/Company Home/Data Dictionary/Scripts/command-utils.js">
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resources
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* var templatePath = "/Data Dictionary/Imap Configs/Templates/imap_search_response_text_html.ftl";*/
|
||||||
|
var errorParameter = "Error: The query parameter is not set!";
|
||||||
|
var errorXPathNotValid = "Error: The Xpath query is not valid.";
|
||||||
|
var unknownCommand = "Unknown command";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Globals
|
||||||
|
*/
|
||||||
|
var title;
|
||||||
|
var command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create content for e-mail in text format
|
||||||
|
*
|
||||||
|
* @nodes (Array) ScriptNodes array
|
||||||
|
* @return content for e-mail in text format
|
||||||
|
*/
|
||||||
|
function createContentTextPlain(nodes)
|
||||||
|
{
|
||||||
|
var content = "Command: " + title + "\n\n";
|
||||||
|
for (var i = 0; i < nodes.length; i++)
|
||||||
|
{
|
||||||
|
content = content + "Name: " + nodes[i].getName() + "\nUrl: " +
|
||||||
|
webApplicationContextUrl + nodes[i].getUrl();
|
||||||
|
|
||||||
|
if (nodes[i].isDocument)
|
||||||
|
{
|
||||||
|
content = content + "\nDownload Url: " +
|
||||||
|
webApplicationContextUrl + nodes[i].getDownloadUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
content = content + "\n\n";
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This for possible processing. It need to be investigated.
|
||||||
|
* The possible solution is to send a search request into FreeMarker template and let the template do search!
|
||||||
|
* @param nodes
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
function createResponseTextHtml(nodes)
|
||||||
|
{
|
||||||
|
var template = companyhome.childByNamePath(templatePath);
|
||||||
|
var result;
|
||||||
|
if (template != null)
|
||||||
|
{
|
||||||
|
var args = new Array();
|
||||||
|
args["title"] = title;
|
||||||
|
args["nodes"] = nodes; /*it does not work; need to investigate how to send this to freemarker processing*/
|
||||||
|
args["webApplicationContextUrl"] = webApplicationContextUrl;
|
||||||
|
result = document.processTemplate(template, args);
|
||||||
|
logger.log("Response template is found. Response body is created using template.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = createContentTextHtml(nodes);
|
||||||
|
logger.log("Response template is NOT found. Response is created using default function.");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create content for e-mail in html format
|
||||||
|
*
|
||||||
|
* @nodes (Array) ScriptNodes array
|
||||||
|
* @return content for e-mail in html format
|
||||||
|
*/
|
||||||
|
function createContentTextHtml(nodes)
|
||||||
|
{
|
||||||
|
var content = "Command: " + title + "\n<br/><br/>\n";
|
||||||
|
content += "<table class=\"links\">\n";
|
||||||
|
content += "<thead align=\"center\">";
|
||||||
|
content += "<tr>";
|
||||||
|
content += "<td>Name</td>";
|
||||||
|
content += "<td>Url</td>";
|
||||||
|
content += "<td>Download Url</td>";
|
||||||
|
content += "</tr>";
|
||||||
|
content += "</thead>\n"
|
||||||
|
|
||||||
|
|
||||||
|
for (var i = 0; i < nodes.length; i++)
|
||||||
|
{
|
||||||
|
content += "<tr>\n";
|
||||||
|
content += "<td>" + nodes[i].getName() + "</td>";
|
||||||
|
content += "<td><a href=\"" + webApplicationContextUrl + nodes[i].getUrl() + "\">" +
|
||||||
|
webApplicationContextUrl + nodes[i].getUrl() + "</a></td>";
|
||||||
|
content += "<td> ";
|
||||||
|
if (nodes[i].isDocument)
|
||||||
|
{
|
||||||
|
content += "<a href=\"" + webApplicationContextUrl + nodes[i].getDownloadUrl() + "\">" +
|
||||||
|
webApplicationContextUrl + nodes[i].getDownloadUrl() + "</a>";
|
||||||
|
}
|
||||||
|
content += "</td>\n";
|
||||||
|
content += "</tr>\n";
|
||||||
|
}
|
||||||
|
content += "</table>";
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute search command
|
||||||
|
*
|
||||||
|
* @params (string) command parameters
|
||||||
|
*/
|
||||||
|
function commandSearch(params)
|
||||||
|
{
|
||||||
|
var store = "workspace://SpacesStore";
|
||||||
|
var query;
|
||||||
|
var subject = "Search result";
|
||||||
|
var type = "lucene";
|
||||||
|
var paramArray = params.split(";");
|
||||||
|
for (var i = 0; i < paramArray.length; i++)
|
||||||
|
{
|
||||||
|
var param = paramArray[i].split("=");
|
||||||
|
param[0] = param[0].toLowerCase();
|
||||||
|
|
||||||
|
switch (param[0])
|
||||||
|
{
|
||||||
|
case "store": store = param[1]; break;
|
||||||
|
case "query": query = param[1]; break;
|
||||||
|
case "subject": subject = param[1]; break;
|
||||||
|
case "type": type = param[1].toLowerCase(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query == null)
|
||||||
|
{
|
||||||
|
createEmail(errorParameter, errorParameter, errorParameter, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var nodes;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case "lucene":
|
||||||
|
nodes = search.luceneSearch(store, query);
|
||||||
|
break;
|
||||||
|
case "xpath":
|
||||||
|
var isValid = search.isValidXpathQuery(query);
|
||||||
|
if (isValid == true)
|
||||||
|
{
|
||||||
|
nodes = search.xpathSearch(store, query);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
createEmail(errorXPathNotValid, errorXPathNotValid, errorXPathNotValid, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "node":
|
||||||
|
var node = search.findNode(query);
|
||||||
|
if (node == null) break;
|
||||||
|
nodes = new Array(node);
|
||||||
|
break;
|
||||||
|
case "tag":
|
||||||
|
nodes = search.tagSearch(store, query);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (exception)
|
||||||
|
{
|
||||||
|
createEmail(exception.message, exception.message, "Search Error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodes == null || nodes.length == 0)
|
||||||
|
{
|
||||||
|
var message = "Nothing was found using query: '" + subject + "'.";
|
||||||
|
createEmail(message, message, subject);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*createEmail(createResponseTextHtml(nodes), createContentTextPlain(nodes), subject, true);*/
|
||||||
|
createEmail(createContentTextHtml(nodes), createContentTextPlain(nodes), subject, false);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Decode subject
|
||||||
|
*
|
||||||
|
* @subject (string) subject
|
||||||
|
*/
|
||||||
|
function decodeSubject(subject)
|
||||||
|
{
|
||||||
|
var s = new Array();
|
||||||
|
s[0] = new Array("\\", "%5c");
|
||||||
|
s[1] = new Array("/", "%2f");
|
||||||
|
s[2] = new Array("*", "%2a");
|
||||||
|
s[3] = new Array("|", "%7c");
|
||||||
|
s[4] = new Array(":", "%3a");
|
||||||
|
s[5] = new Array("\"", "%22");
|
||||||
|
s[6] = new Array("<", "%3c");
|
||||||
|
s[7] = new Array(">", "%3e");
|
||||||
|
s[8] = new Array("?", "%3f");
|
||||||
|
|
||||||
|
for (var i = 0; i < s.length; i++)
|
||||||
|
{
|
||||||
|
var re = new RegExp(s[i][1], 'g');
|
||||||
|
subject = subject.replace(re, s[i][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return subject;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function main()
|
||||||
|
{
|
||||||
|
title = decodeSubject(document.properties["cm:title"]);
|
||||||
|
command = title.split("-");
|
||||||
|
if (command[0].toLowerCase() == "do")
|
||||||
|
{
|
||||||
|
if (command[1].toLowerCase() == "search")
|
||||||
|
{
|
||||||
|
commandSearch(title.substring(4 + command[1].length));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var message = unknownCommand + ": '" + title + "'";
|
||||||
|
createEmail(message, message, message, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var message = unknownCommand + ": '" + title + "'";
|
||||||
|
createEmail(message, message, message, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
logger.log("Start search command.");
|
||||||
|
main();
|
||||||
|
logger.log("End search command.");
|
||||||
|
|
56
config/alfresco/imap/scripts/command-utils.js
Executable file
56
config/alfresco/imap/scripts/command-utils.js
Executable file
@@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* Create e-mail
|
||||||
|
* contentTextHtml (string) html content
|
||||||
|
* contentTextPlain (string) text content
|
||||||
|
*/
|
||||||
|
function createEmail(contentTextHtml, contentTextPlain, subject, templateUsed)
|
||||||
|
{
|
||||||
|
var command = document.properties["cm:title"];
|
||||||
|
var userName = person.properties["cm:userName"];
|
||||||
|
|
||||||
|
var inboxFolder = companyhome.childByNamePath("IMAP Home/" + userName + "/INBOX");
|
||||||
|
if (inboxFolder == null)
|
||||||
|
{
|
||||||
|
logger.log("Command Processor: INBOX folder does't exists.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextMessageUID = inboxFolder.properties["imap:nextMessageUID"];
|
||||||
|
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:messageSubject"] = subject;
|
||||||
|
response.properties["imap:messageTo"] = document.properties["cm:originator"];
|
||||||
|
response.properties["imap:messageCc"] = "";
|
||||||
|
response.properties["imap:messageUID"] = nextMessageUID;
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
}
|
@@ -326,6 +326,9 @@
|
|||||||
<prop key="spaces.user_homes.childname">${spaces.user_homes.childname}</prop>
|
<prop key="spaces.user_homes.childname">${spaces.user_homes.childname}</prop>
|
||||||
<prop key="spaces.sites.childname">${spaces.sites.childname}</prop>
|
<prop key="spaces.sites.childname">${spaces.sites.childname}</prop>
|
||||||
<prop key="spaces.templates.email.invite.childname">${spaces.templates.email.invite.childname}</prop>
|
<prop key="spaces.templates.email.invite.childname">${spaces.templates.email.invite.childname}</prop>
|
||||||
|
<prop key="spaces.imap_home.childname">${spaces.imap_home.childname}</prop>
|
||||||
|
<prop key="spaces.imapConfig.childname">${spaces.imapConfig.childname}</prop>
|
||||||
|
<prop key="spaces.imap_templates.childname">${spaces.imap_templates.childname}</prop>
|
||||||
</props>
|
</props>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
@@ -516,6 +519,7 @@
|
|||||||
<prop key="location">alfresco/bootstrap/sitesSpace.xml</prop>
|
<prop key="location">alfresco/bootstrap/sitesSpace.xml</prop>
|
||||||
<prop key="messages">alfresco/messages/bootstrap-spaces</prop>
|
<prop key="messages">alfresco/messages/bootstrap-spaces</prop>
|
||||||
</props>
|
</props>
|
||||||
|
|
||||||
</list>
|
</list>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
12
config/alfresco/messages/bootstrap-imapScripts.properties
Executable file
12
config/alfresco/messages/bootstrap-imapScripts.properties
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
imap.command_processor.name=command-processor.js
|
||||||
|
imap.command_processor.title=Command Processor
|
||||||
|
imap.command_processor.description=Email Command Processor Script
|
||||||
|
|
||||||
|
imap.command_search.name=command-search.js
|
||||||
|
imap.command_search.title=Search Command
|
||||||
|
imap.command_search.description=Email Search Command Script
|
||||||
|
|
||||||
|
imap.command_utils.name=command-utils.js
|
||||||
|
imap.command_utils.title=Command Utils
|
||||||
|
imap.command_utils.description=Email Command Utils
|
||||||
|
|
@@ -6,6 +6,12 @@ spaces.company_home.description=The company root space
|
|||||||
spaces.dictionary.name=Data Dictionary
|
spaces.dictionary.name=Data Dictionary
|
||||||
spaces.dictionary.description=User managed definitions
|
spaces.dictionary.description=User managed definitions
|
||||||
|
|
||||||
|
spaces.imapConfig.name=Imap Configs
|
||||||
|
spaces.imapConfig.description=Imap Configs
|
||||||
|
|
||||||
|
spaces.imap_templates.name=Templates
|
||||||
|
spaces.imap_templates.description=Templates for IMAP generated messages
|
||||||
|
|
||||||
spaces.templates.name=Space Templates
|
spaces.templates.name=Space Templates
|
||||||
spaces.templates.description=Space folder templates
|
spaces.templates.description=Space folder templates
|
||||||
|
|
||||||
@@ -44,3 +50,6 @@ spaces.sites.description=Site Collaboration Spaces
|
|||||||
|
|
||||||
spaces.templates.email.invite.name=invite
|
spaces.templates.email.invite.name=invite
|
||||||
spaces.templates.email.invite.description=Invite email templates
|
spaces.templates.email.invite.description=Invite email templates
|
||||||
|
|
||||||
|
spaces.imap_home.name=IMAP Home
|
||||||
|
spaces.imap_home.description=IMAP Home
|
10
config/alfresco/messages/imap-service.properties
Executable file
10
config/alfresco/messages/imap-service.properties
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
#
|
||||||
|
# Imap I18N messages
|
||||||
|
#
|
||||||
|
|
||||||
|
# Information messages. prefix 'imap.server.info'
|
||||||
|
imap.server.info.message_body_not_found = "The message body parts are not found."
|
||||||
|
|
||||||
|
# Error messages. prefix 'imap.server.error'
|
||||||
|
imap.server.error.properties_dont_exist = "Appropriate properties do not exist."
|
||||||
|
|
@@ -1,4 +1,4 @@
|
|||||||
# PatchService messages
|
# PatchService messages
|
||||||
patch.service.preceeded_by_alternative=Preceeded by alternative patch ''{0}''.
|
patch.service.preceeded_by_alternative=Preceeded by alternative patch ''{0}''.
|
||||||
patch.service.not_relevant=Not relevant to schema {0}
|
patch.service.not_relevant=Not relevant to schema {0}
|
||||||
patch.executer.checking=Checking for patches to apply ...
|
patch.executer.checking=Checking for patches to apply ...
|
||||||
@@ -261,3 +261,11 @@ patch.mtShareExistingTenants.result=Update existing tenants for MT Share.
|
|||||||
patch.mtShareExistingTenants.result.not_applicable=Patch applied, although no changes made since MT is not enabled.
|
patch.mtShareExistingTenants.result.not_applicable=Patch applied, although no changes made since MT is not enabled.
|
||||||
|
|
||||||
patch.redeployInvitationProcess.description=Re-deploy Invitation Process Definitions.
|
patch.redeployInvitationProcess.description=Re-deploy Invitation Process Definitions.
|
||||||
|
|
||||||
|
patch.imapFolders.description=Creates folders tree necessary for IMAP functionality
|
||||||
|
patch.imapFolders.result.exists=The 'Imap Configs' folder already exists
|
||||||
|
patch.imapFolders.result.created=The 'Imap Configs' folder was successfully created
|
||||||
|
|
||||||
|
patch.imapUserFolders.description=Creates folders tree necessary for IMAP functionality
|
||||||
|
patch.imapUserFolders.result.exists=The 'IMAP Home' folder already exists
|
||||||
|
patch.imapUserFolders.result.created=The 'IMAP Home' folder was successfully created
|
||||||
|
100
config/alfresco/model/imapModel.xml
Executable file
100
config/alfresco/model/imapModel.xml
Executable file
@@ -0,0 +1,100 @@
|
|||||||
|
<model name="imap:imapmodel" xmlns="http://www.alfresco.org/model/dictionary/1.0">
|
||||||
|
|
||||||
|
<description>IMAP Content Model</description>
|
||||||
|
<author>Alfresco</author>
|
||||||
|
<published>2009-01-20</published>
|
||||||
|
<version>1.0</version>
|
||||||
|
|
||||||
|
<imports>
|
||||||
|
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm" />
|
||||||
|
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d" />
|
||||||
|
</imports>
|
||||||
|
|
||||||
|
<namespaces>
|
||||||
|
<namespace uri="http://www.alfresco.org/model/imap/1.0" prefix="imap" />
|
||||||
|
</namespaces>
|
||||||
|
|
||||||
|
<types>
|
||||||
|
<type name="imap:imapFolder">
|
||||||
|
<title>IMAP Folder</title>
|
||||||
|
<parent>cm:folder</parent>
|
||||||
|
<properties>
|
||||||
|
<property name="imap:subscribed">
|
||||||
|
<type>d:boolean</type>
|
||||||
|
</property>
|
||||||
|
<property name="imap:selectable">
|
||||||
|
<type>d:boolean</type>
|
||||||
|
<mandatory>true</mandatory>
|
||||||
|
<default>true</default>
|
||||||
|
</property>
|
||||||
|
</properties>
|
||||||
|
</type>
|
||||||
|
|
||||||
|
<type name="imap:imapContent">
|
||||||
|
<title>IMAP File</title>
|
||||||
|
<parent>cm:folder</parent>
|
||||||
|
<properties>
|
||||||
|
<!-- Message -->
|
||||||
|
<property name="imap:messageFrom">
|
||||||
|
<type>d:text</type>
|
||||||
|
</property>
|
||||||
|
<property name="imap:messageTo">
|
||||||
|
<type>d:text</type>
|
||||||
|
</property>
|
||||||
|
<property name="imap:messageCc">
|
||||||
|
<type>d:text</type>
|
||||||
|
</property>
|
||||||
|
<property name="imap:messageSubject">
|
||||||
|
<type>d:text</type>
|
||||||
|
</property>
|
||||||
|
</properties>
|
||||||
|
<mandatory-aspects>
|
||||||
|
<aspect>imap:flaggable</aspect>
|
||||||
|
</mandatory-aspects>
|
||||||
|
</type>
|
||||||
|
|
||||||
|
<type name="imap:imapAttach">
|
||||||
|
<title>Attachment to the IMAP message</title>
|
||||||
|
<parent>cm:content</parent>
|
||||||
|
<properties>
|
||||||
|
<property name="imap:attachID">
|
||||||
|
<type>d:text</type>
|
||||||
|
</property>
|
||||||
|
</properties>
|
||||||
|
</type>
|
||||||
|
|
||||||
|
<type name="imap:imapBody">
|
||||||
|
<title>Body of the IMAP message</title>
|
||||||
|
<parent>cm:content</parent>
|
||||||
|
</type>
|
||||||
|
</types>
|
||||||
|
|
||||||
|
<aspects>
|
||||||
|
<aspect name="imap:flaggable">
|
||||||
|
<properties>
|
||||||
|
<property name="imap:flagAnswered">
|
||||||
|
<type>d:boolean</type>
|
||||||
|
</property>
|
||||||
|
<property name="imap:flagDeleted">
|
||||||
|
<type>d:boolean</type>
|
||||||
|
</property>
|
||||||
|
<property name="imap:flagDraft">
|
||||||
|
<type>d:boolean</type>
|
||||||
|
</property>
|
||||||
|
<property name="imap:flagSeen">
|
||||||
|
<type>d:boolean</type>
|
||||||
|
</property>
|
||||||
|
<property name="imap:flagRecent">
|
||||||
|
<type>d:boolean</type>
|
||||||
|
</property>
|
||||||
|
<property name="imap:flagFlagged">
|
||||||
|
<type>d:boolean</type>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
</properties>
|
||||||
|
</aspect>
|
||||||
|
<aspect name="imap:subscribed"/>
|
||||||
|
<aspect name="imap:nonselectable"/>
|
||||||
|
</aspects>
|
||||||
|
|
||||||
|
</model>
|
@@ -6,6 +6,8 @@ repository.name=Main Repository
|
|||||||
|
|
||||||
dir.root=./alf_data
|
dir.root=./alf_data
|
||||||
|
|
||||||
|
web.application.context.url=http://localhost:8080/alfresco
|
||||||
|
|
||||||
dir.contentstore=${dir.root}/contentstore
|
dir.contentstore=${dir.root}/contentstore
|
||||||
dir.contentstore.deleted=${dir.root}/contentstore.deleted
|
dir.contentstore.deleted=${dir.root}/contentstore.deleted
|
||||||
|
|
||||||
@@ -226,6 +228,8 @@ spaces.company_home.childname=app:company_home
|
|||||||
spaces.guest_home.childname=app:guest_home
|
spaces.guest_home.childname=app:guest_home
|
||||||
spaces.dictionary.childname=app:dictionary
|
spaces.dictionary.childname=app:dictionary
|
||||||
spaces.templates.childname=app:space_templates
|
spaces.templates.childname=app:space_templates
|
||||||
|
spaces.imapConfig.childname=app:imap_configs
|
||||||
|
spaces.imap_templates.childname=app:imap_templates
|
||||||
spaces.templates.content.childname=app:content_templates
|
spaces.templates.content.childname=app:content_templates
|
||||||
spaces.templates.email.childname=app:email_templates
|
spaces.templates.email.childname=app:email_templates
|
||||||
spaces.templates.rss.childname=app:rss_templates
|
spaces.templates.rss.childname=app:rss_templates
|
||||||
@@ -235,6 +239,7 @@ spaces.wcm.childname=app:wcm
|
|||||||
spaces.wcm_content_forms.childname=app:wcm_forms
|
spaces.wcm_content_forms.childname=app:wcm_forms
|
||||||
spaces.content_forms.childname=app:forms
|
spaces.content_forms.childname=app:forms
|
||||||
spaces.user_homes.childname=app:user_homes
|
spaces.user_homes.childname=app:user_homes
|
||||||
|
spaces.imap_home.childname=imap:imap_home
|
||||||
spaces.sites.childname=st:sites
|
spaces.sites.childname=st:sites
|
||||||
spaces.templates.email.invite.childname=cm:invite
|
spaces.templates.email.invite.childname=cm:invite
|
||||||
|
|
||||||
|
BIN
config/alfresco/templates/imap/command_processor_scripts.acp
Executable file
BIN
config/alfresco/templates/imap/command_processor_scripts.acp
Executable file
Binary file not shown.
BIN
config/alfresco/templates/imap/email_actions_space.acp
Executable file
BIN
config/alfresco/templates/imap/email_actions_space.acp
Executable file
Binary file not shown.
BIN
config/alfresco/templates/imap/imap_config_space.acp
Executable file
BIN
config/alfresco/templates/imap/imap_config_space.acp
Executable file
Binary file not shown.
173
config/alfresco/templates/imap/imap_message_text_html.ftl
Executable file
173
config/alfresco/templates/imap/imap_message_text_html.ftl
Executable file
@@ -0,0 +1,173 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
|
<meta name="Generator" content="Alfresco Repository">
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
background-color:#FFFFFF;
|
||||||
|
color:#000000;
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
font-family:Verdana,Arial,sans-serif;
|
||||||
|
font-size:11px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
text-align:left;
|
||||||
|
font-size:15px;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
text-align:left;
|
||||||
|
font-size:13px;
|
||||||
|
}
|
||||||
|
fieldset {
|
||||||
|
border:1px dotted #555555;
|
||||||
|
margin:15px 5px 15px 5px;
|
||||||
|
}
|
||||||
|
fieldset legend {
|
||||||
|
font-weight:bold;
|
||||||
|
border:1px dotted #555555;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
padding:7px;
|
||||||
|
}
|
||||||
|
.links {
|
||||||
|
border:0;
|
||||||
|
border-collapse:collapse;
|
||||||
|
width:99%;
|
||||||
|
}
|
||||||
|
.links td {
|
||||||
|
border:0;
|
||||||
|
padding:5px;
|
||||||
|
}
|
||||||
|
.description {
|
||||||
|
border:0;
|
||||||
|
border-collapse:collapse;
|
||||||
|
width:99%;
|
||||||
|
}
|
||||||
|
.description td {
|
||||||
|
/*border:1px dotted #555555;*/
|
||||||
|
padding:5px;
|
||||||
|
}
|
||||||
|
#start_workflow input, #start_workflow select, #start_workflow textarea
|
||||||
|
{
|
||||||
|
border:1px solid #555555;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<hr/>
|
||||||
|
<h1> Document (name): ${document.name} </h1>
|
||||||
|
<hr/>
|
||||||
|
<fieldset>
|
||||||
|
<legend> Metadata </legend>
|
||||||
|
<table class="description">
|
||||||
|
<#if document.properties.title?exists>
|
||||||
|
<tr><td valign="top">Title:</td><td>${document.properties.title}</td></tr>
|
||||||
|
<#else>
|
||||||
|
<tr><td valign="top">Title:</td><td> </td></tr>
|
||||||
|
</#if>
|
||||||
|
<#if document.properties.description?exists>
|
||||||
|
<tr><td valign="top">Description:</td><td>${document.properties.description}</td></tr>
|
||||||
|
<#else>
|
||||||
|
<tr><td valign="top">Description:</td><td> </td></tr>
|
||||||
|
</#if>
|
||||||
|
<tr><td>Creator:</td><td>${document.properties.creator}</td></tr>
|
||||||
|
<tr><td>Created:</td><td>${document.properties.created?datetime}</td></tr>
|
||||||
|
<tr><td>Modifier:</td><td>${document.properties.modifier}</td></tr>
|
||||||
|
<tr><td>Modified:</td><td>${document.properties.modified?datetime}</td></tr>
|
||||||
|
<tr><td>Size:</td><td>${document.size / 1024} Kb</td></tr>
|
||||||
|
</table>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset>
|
||||||
|
<legend> Content links </legend>
|
||||||
|
<table class="links">
|
||||||
|
<tr>
|
||||||
|
<td>Content folder:</td><td><a href="${contextUrl}${document.displayPath}">${contextUrl}${document.displayPath}</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Content URL:</td><td><a href="${contextUrl}${document.url}">${contextUrl}${document.url}</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Download URL:</td><td><a href="${contextUrl}${document.downloadUrl}">${contextUrl}${document.downloadUrl}</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>WebDAV URL:</td><td><a href="${contextUrl}${document.webdavUrl}">${contextUrl}${document.webdavUrl}</a></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset>
|
||||||
|
<legend> Start Workflow </legend>
|
||||||
|
<form id="start_workflow"
|
||||||
|
name="start_workflow"
|
||||||
|
method="get"
|
||||||
|
action="${contextUrl}/service/imap/start-workflow"
|
||||||
|
enctype="application/x-www-form-urlencoded">
|
||||||
|
<input type="hidden" name="alfTicket" value="${alfTicket}" />
|
||||||
|
<input type="hidden" name="nodeRefId" value="${document.id}" />
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>Workflow type:</td>
|
||||||
|
<td>
|
||||||
|
<!-- Workflow list is hardcoded for now -->
|
||||||
|
<select id="workflowType" name="workflowType" style="width:134px">
|
||||||
|
<option value="adhoc">Adhoc Task</option>
|
||||||
|
<option value="review">Review & Approve</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Asign to:</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="assignTo" name="assignTo"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Priority:</td>
|
||||||
|
<td>
|
||||||
|
<select size="1" name="workflowPriority" id="workflowPriority">
|
||||||
|
<option value="1">1</option>
|
||||||
|
<option selected="selected" value="2">2</option>
|
||||||
|
<option value="3">3</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<tr>
|
||||||
|
<td>Due date:</td>
|
||||||
|
<td>
|
||||||
|
Day: <select size="1" name="workflowDueDateDay" id="workflowDueDateDay">
|
||||||
|
<option selected="selected" value="1">1</option>
|
||||||
|
<#list 2..31 as i>
|
||||||
|
<option value="${i}">${i}</option>
|
||||||
|
</#list>
|
||||||
|
</select>
|
||||||
|
</select>
|
||||||
|
Month: <select size="1" name="workflowDueDateMonth" id="workflowDueDateMonth">
|
||||||
|
<option selected="selected" value="1">1</option>
|
||||||
|
<#list 2..12 as i>
|
||||||
|
<option value="${i}">${i}</option>
|
||||||
|
</#list>
|
||||||
|
</select>
|
||||||
|
Year: <input type="text" size="5" id="workflowDueDateYear" name="workflowDueDateYear"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Description:</td><td><textarea style="width:132px" id="description" name="description"></textarea></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><center><input id="submitButton" type="submit" value="Start workflow" style="margin:20px 5px 5px 5px"/></center></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</fieldset>
|
||||||
|
<!--
|
||||||
|
JBPM ids for debug....
|
||||||
|
id=jbpm$4,name=jbpm$wcmwf:changerequest,version=1,title=Change Request
|
||||||
|
id=jbpm$3,name=jbpm$wcmwf:submit,version=1,title=Web Site Submission
|
||||||
|
id=jbpm$5,name=jbpm$wcmwf:submitdirect,version=1,title=Web Site Submission (Direct)
|
||||||
|
id=jbpm$2,name=jbpm$wf:adhoc,version=1,title=Adhoc Task
|
||||||
|
id=jbpm$6,name=jbpm$wf:invite,version=1,title=Site Invite
|
||||||
|
id=jbpm$1,name=jbpm$wf:review,version=1,title=Review & Approve
|
||||||
|
-->
|
||||||
|
</body>
|
||||||
|
</html>
|
35
config/alfresco/templates/imap/imap_message_text_plain.ftl
Executable file
35
config/alfresco/templates/imap/imap_message_text_plain.ftl
Executable file
@@ -0,0 +1,35 @@
|
|||||||
|
------------------------------------------------------------------------------
|
||||||
|
Document name: ${document.name}
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
<#if document.properties.title?exists>
|
||||||
|
Title: ${document.properties.title}
|
||||||
|
<#else>
|
||||||
|
Title: NONE
|
||||||
|
</#if>
|
||||||
|
<#if document.properties.description?exists>
|
||||||
|
Description: ${document.properties.description}
|
||||||
|
<#else>
|
||||||
|
Description: NONE
|
||||||
|
</#if>
|
||||||
|
Creator: ${document.properties.creator}
|
||||||
|
Created: ${document.properties.created?datetime}
|
||||||
|
Modifier: ${document.properties.modifier}
|
||||||
|
Modified: ${document.properties.modified?datetime}
|
||||||
|
Size: ${document.size / 1024} Kb
|
||||||
|
|
||||||
|
|
||||||
|
CONTENT LINKS
|
||||||
|
|
||||||
|
Content folder: ${contextUrl}${document.displayPath}
|
||||||
|
Content URL: ${contextUrl}${document.url}
|
||||||
|
Download URL: ${contextUrl}${document.downloadUrl}
|
||||||
|
WebDAV URL: ${contextUrl}${document.webdavUrl}
|
||||||
|
|
||||||
|
START WORKFLOW
|
||||||
|
|
||||||
|
{It is not possible to create a customizible workflow in txt format!
|
||||||
|
It is possible to create static links to IMAP Workflow Handler webscript,
|
||||||
|
But, in this case all parameters must be hardcoded in the link.
|
||||||
|
See http://localhost:8080/alfresco/service/description/org/alfresco/imap/start-workflow.get
|
||||||
|
for usage information.}
|
157
config/alfresco/templates/imap/template_test.html
Executable file
157
config/alfresco/templates/imap/template_test.html
Executable file
@@ -0,0 +1,157 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
|
<meta name="Generator" content="Alfresco Repository">
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
background-color:#FFFFFF;
|
||||||
|
color:#000000;
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
font-family:Verdana,Arial,sans-serif;
|
||||||
|
font-size:11px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
text-align:left;
|
||||||
|
font-size:15px;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
text-align:left;
|
||||||
|
font-size:13px;
|
||||||
|
}
|
||||||
|
fieldset {
|
||||||
|
border:1px dotted #555555;
|
||||||
|
margin:15px 5px 15px 5px;
|
||||||
|
}
|
||||||
|
fieldset legend {
|
||||||
|
font-weight:bold;
|
||||||
|
border:1px dotted #555555;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
padding:7px;
|
||||||
|
}
|
||||||
|
.links {
|
||||||
|
border:0;
|
||||||
|
border-collapse:collapse;
|
||||||
|
width:99%;
|
||||||
|
}
|
||||||
|
.links td {
|
||||||
|
border:0;
|
||||||
|
padding:5px;
|
||||||
|
}
|
||||||
|
.description {
|
||||||
|
border:0;
|
||||||
|
border-collapse:collapse;
|
||||||
|
width:99%;
|
||||||
|
}
|
||||||
|
.description td {
|
||||||
|
/*border:1px dotted #555555;*/
|
||||||
|
padding:5px;
|
||||||
|
}
|
||||||
|
#start_workflow input, #start_workflow select, #start_workflow textarea
|
||||||
|
{
|
||||||
|
border:1px solid #555555;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<hr/>
|
||||||
|
<h1> Document (name): ${document.name} </h1>
|
||||||
|
<hr/>
|
||||||
|
<fieldset>
|
||||||
|
<legend> Metadata </legend>
|
||||||
|
<table class="description">
|
||||||
|
<#if document.properties.title?exists>
|
||||||
|
<tr><td valign="top">Title:</td><td>${document.properties.title}</td></tr>
|
||||||
|
<#else>
|
||||||
|
<tr><td valign="top">Title:</td><td> </td></tr>
|
||||||
|
</#if>
|
||||||
|
<#if document.properties.description?exists>
|
||||||
|
<tr><td valign="top">Description:</td><td>${document.properties.description}</td></tr>
|
||||||
|
<#else>
|
||||||
|
<tr><td valign="top">Description:</td><td> </td></tr>
|
||||||
|
</#if>
|
||||||
|
<tr><td>Creator:</td><td>${document.properties.creator}</td></tr>
|
||||||
|
<tr><td>Created:</td><td>${document.properties.created?datetime}</td></tr>
|
||||||
|
<tr><td>Modifier:</td><td>${document.properties.modifier}</td></tr>
|
||||||
|
<tr><td>Modified:</td><td>${document.properties.modified?datetime}</td></tr>
|
||||||
|
<tr><td>Size:</td><td>${document.size / 1024} Kb</td></tr>
|
||||||
|
</table>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset>
|
||||||
|
<legend> Content links </legend>
|
||||||
|
<table class="links">
|
||||||
|
<tr>
|
||||||
|
<td>Content folder:</td><td><a href="${contextUrl}${document.displayPath}">${contextUrl}${document.displayPath}</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Content URL:</td><td><a href="${contextUrl}${document.url}">${contextUrl}${document.url}</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Download URL:</td><td><a href="${contextUrl}${document.downloadUrl}">${contextUrl}${document.downloadUrl}</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>WebDAV URL:</td><td><a href="${contextUrl}${document.webdavUrl}">${contextUrl}${document.webdavUrl}</a></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset>
|
||||||
|
<legend> Start Workflow </legend>
|
||||||
|
<form id="start_workflow"
|
||||||
|
name="start_workflow"
|
||||||
|
method="get"
|
||||||
|
action="${contextUrl}/service/imap/start-workflow"
|
||||||
|
enctype="application/x-www-form-urlencoded">
|
||||||
|
<input type="hidden" name="alfTicket" value="${alfTicket}" />
|
||||||
|
<input type="hidden" name="nodeRefId" value="${document.id}" />
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>Workflow type:</td>
|
||||||
|
<td>
|
||||||
|
<!-- Workflow list is hardcoded for now -->
|
||||||
|
<select id="workflowType" name="workflowType" style="width:134px">
|
||||||
|
<option value="adhoc">Adhoc Task</option>
|
||||||
|
<option value="review">Review & Approve</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Asign to:</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="assignTo" name="assignTo"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Priority:</td>
|
||||||
|
<td>
|
||||||
|
<select size="1" name="workflowPriority" id="workflowPriority">
|
||||||
|
<option value="1">1</option>
|
||||||
|
<option selected="selected" value="2">2</option>
|
||||||
|
<option value="3">3</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<tr>
|
||||||
|
<td>Due date:</td><td><input type="text" id="dueDate" name="dueDate"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Description:</td><td><textarea style="width:132px" id="description" name="description"></textarea></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><center><input id="submitButton" type="submit" value="Start workflow" style="margin:20px 5px 5px 5px"/></center></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</fieldset>
|
||||||
|
<!--
|
||||||
|
JBPM ids for debug....
|
||||||
|
id=jbpm$4,name=jbpm$wcmwf:changerequest,version=1,title=Change Request
|
||||||
|
id=jbpm$3,name=jbpm$wcmwf:submit,version=1,title=Web Site Submission
|
||||||
|
id=jbpm$5,name=jbpm$wcmwf:submitdirect,version=1,title=Web Site Submission (Direct)
|
||||||
|
id=jbpm$2,name=jbpm$wf:adhoc,version=1,title=Adhoc Task
|
||||||
|
id=jbpm$6,name=jbpm$wf:invite,version=1,title=Site Invite
|
||||||
|
id=jbpm$1,name=jbpm$wf:review,version=1,title=Review & Approve
|
||||||
|
-->
|
||||||
|
</body>
|
||||||
|
</html>
|
@@ -0,0 +1,11 @@
|
|||||||
|
<webscript>
|
||||||
|
<shortname>IMAP Server Status</shortname>
|
||||||
|
<description>
|
||||||
|
This script return status of IMAP server (enabled/diabled)
|
||||||
|
</description>
|
||||||
|
<url>/imap/servstatus</url>
|
||||||
|
<format default="html">extension</format>
|
||||||
|
<authentication>user</authentication>
|
||||||
|
<transaction>required</transaction>
|
||||||
|
<family>IMAP</family>
|
||||||
|
</webscript>
|
@@ -0,0 +1,12 @@
|
|||||||
|
<webscript>
|
||||||
|
<shortname>IMAP Workflow Handler</shortname>
|
||||||
|
<description>
|
||||||
|
This webscript starts a different workflows. It have used in the IMAP email body links.
|
||||||
|
(The optional feature is the reply email with a report.)
|
||||||
|
</description>
|
||||||
|
<url>/imap/start-workflow?alfTicket={ticket}&nodeRefId={id}&workflowType={wt}&assignTo={at}&workflowDueDateDay={ddd}&workflowDueDateMonth={ddm}&workflowDueDateYear={ddy}&description={desc}</url>
|
||||||
|
<format default="html">extension</format>
|
||||||
|
<authentication>user</authentication>
|
||||||
|
<transaction>required</transaction>
|
||||||
|
<family>IMAP</family>
|
||||||
|
</webscript>
|
@@ -0,0 +1,71 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
|
<meta name="Generator" content="Alfresco Repository">
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
background-color:#FFFFFF;
|
||||||
|
color:#000000;
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
font-family:Verdana,Arial,sans-serif;
|
||||||
|
font-size:11px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
text-align:left;
|
||||||
|
font-size:15px;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
text-align:left;
|
||||||
|
font-size:13px;
|
||||||
|
}
|
||||||
|
.links {
|
||||||
|
border:0;
|
||||||
|
border-collapse:collapse;
|
||||||
|
width:99%;
|
||||||
|
}
|
||||||
|
.links td {
|
||||||
|
border:0;
|
||||||
|
padding:5px;
|
||||||
|
}
|
||||||
|
.description {
|
||||||
|
border:0;
|
||||||
|
border-collapse:collapse;
|
||||||
|
width:99%;
|
||||||
|
}
|
||||||
|
.description td {
|
||||||
|
border:1px dotted #555555;
|
||||||
|
padding:5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Workflow has started successfully.</h1>
|
||||||
|
<table class="description">
|
||||||
|
<tr>
|
||||||
|
<td>Ticket:</td><td>${args.alfTicket}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>NodeRef id:</td><td>${args.nodeRefId}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Workflow type:</td><td>${args.workflowType}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Asign to:</td><td>${args.assignTo}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Due date:</td><td>${args.workflowDueDateDay}/${args.workflowDueDateMonth}/${args.workflowDueDateYear}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Description:</td><td>${args.description}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Result:</td><td> --- </td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
42
config/alfresco/templates/webscripts/org/alfresco/imap/start-workflow.get.js
Executable file
42
config/alfresco/templates/webscripts/org/alfresco/imap/start-workflow.get.js
Executable file
@@ -0,0 +1,42 @@
|
|||||||
|
function main()
|
||||||
|
{
|
||||||
|
logger.log("Start workflow form 'Start workflow' webscript");
|
||||||
|
var docNode = search.findNode("workspace://SpacesStore/" + args.nodeRefId);
|
||||||
|
if (docNode == undefined)
|
||||||
|
{
|
||||||
|
status.code = 404;
|
||||||
|
status.message = "Content with NodeRef id '" + args.nodeRefId + "' not found.";
|
||||||
|
status.redirect = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var workflowType = "jbpm$wf:" + args.workflowType;
|
||||||
|
var assignTo = people.getPerson(args.assignTo);
|
||||||
|
if (assignTo == undefined)
|
||||||
|
{
|
||||||
|
status.code = 404;
|
||||||
|
status.message = "Person with username '" + args.assignTo + "' not found.";
|
||||||
|
status.redirect = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var day = args.workflowDueDateDay;
|
||||||
|
var month = args.workflowDueDateMonth;
|
||||||
|
var year = args.workflowDueDateYear;
|
||||||
|
if (year != null && year.length == 2)
|
||||||
|
{
|
||||||
|
year = "20" + year;
|
||||||
|
}
|
||||||
|
var dueDate = new Date(year, month - 1, day);
|
||||||
|
var description = args.description;
|
||||||
|
|
||||||
|
var workflow = actions.create("start-workflow");
|
||||||
|
workflow.parameters.workflowName = workflowType;
|
||||||
|
workflow.parameters["bpm:workflowDescription"] = description;
|
||||||
|
workflow.parameters["bpm:assignee"] = assignTo;
|
||||||
|
workflow.parameters["bpm:workflowPriority"] = args.workflowPriority;
|
||||||
|
if (dueDate != null)
|
||||||
|
{
|
||||||
|
workflow.parameters["bpm:workflowDueDate"] = dueDate;
|
||||||
|
}
|
||||||
|
workflow.execute(docNode);
|
||||||
|
}
|
||||||
|
main();
|
@@ -40,6 +40,8 @@ import org.alfresco.model.ContentModel;
|
|||||||
import org.alfresco.repo.content.MimetypeMap;
|
import org.alfresco.repo.content.MimetypeMap;
|
||||||
import org.alfresco.service.cmr.email.EmailMessage;
|
import org.alfresco.service.cmr.email.EmailMessage;
|
||||||
import org.alfresco.service.cmr.email.EmailMessageException;
|
import org.alfresco.service.cmr.email.EmailMessageException;
|
||||||
|
import org.alfresco.service.cmr.repository.ContentService;
|
||||||
|
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||||
import org.alfresco.service.cmr.repository.MimetypeService;
|
import org.alfresco.service.cmr.repository.MimetypeService;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
@@ -120,24 +122,54 @@ public class FolderEmailMessageHandler extends AbstractEmailMessageHandler
|
|||||||
// Write the message content
|
// Write the message content
|
||||||
if (message.getBody() != null)
|
if (message.getBody() != null)
|
||||||
{
|
{
|
||||||
InputStream contentIs = message.getBody().getContent();
|
if (message.getBody().getSize() == -1)
|
||||||
// The message body is plain text, unless an extension has been provided
|
|
||||||
MimetypeService mimetypeService = getMimetypeService();
|
|
||||||
String mimetype = mimetypeService.guessMimetype(messageSubject);
|
|
||||||
if (mimetype.equals(MimetypeMap.MIMETYPE_BINARY))
|
|
||||||
{
|
{
|
||||||
mimetype= MimetypeMap.MIMETYPE_TEXT_PLAIN;
|
// If message body is empty we write space as a content
|
||||||
|
// to make possible rule processing
|
||||||
|
// (Rules don't work on empty documents)
|
||||||
|
writeSpace(contentNodeRef);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InputStream contentIs = message.getBody().getContent();
|
||||||
|
// The message body is plain text, unless an extension has been provided
|
||||||
|
MimetypeService mimetypeService = getMimetypeService();
|
||||||
|
String mimetype = mimetypeService.guessMimetype(messageSubject);
|
||||||
|
if (mimetype.equals(MimetypeMap.MIMETYPE_BINARY))
|
||||||
|
{
|
||||||
|
mimetype = MimetypeMap.MIMETYPE_TEXT_PLAIN;
|
||||||
|
}
|
||||||
|
// Use the default encoding. It will get overridden if the body is text.
|
||||||
|
String encoding = message.getBody().getEncoding();
|
||||||
|
|
||||||
|
writeContent(contentNodeRef, contentIs, mimetype, encoding);
|
||||||
}
|
}
|
||||||
// Use the default encoding. It will get overridden if the body is text.
|
|
||||||
String encoding = message.getBody().getEncoding();
|
|
||||||
|
|
||||||
writeContent(contentNodeRef, contentIs, mimetype, encoding);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add attachments
|
// Add attachments
|
||||||
addAttachments(spaceNodeRef, contentNodeRef, message);
|
addAttachments(spaceNodeRef, contentNodeRef, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method writes space as a content. We need this space because rules doesn't proceed documents with empty content. We need rule processing for command email messages with
|
||||||
|
* empty body.
|
||||||
|
*
|
||||||
|
* @param nodeRef Reference to the parent node
|
||||||
|
*/
|
||||||
|
private void writeSpace(NodeRef nodeRef)
|
||||||
|
{
|
||||||
|
if (log.isDebugEnabled())
|
||||||
|
{
|
||||||
|
log.debug("Write space string");
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentService contentService = getContentService();
|
||||||
|
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
|
||||||
|
writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
|
||||||
|
writer.setEncoding("UTF-8");
|
||||||
|
writer.putContent(" ");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds titled aspect to the specified node.
|
* Adds titled aspect to the specified node.
|
||||||
*
|
*
|
||||||
|
@@ -153,7 +153,7 @@ public class SubethaEmailMessage implements EmailMessage
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
subject = mimeMessage.getSubject();
|
subject = encodeSubject(mimeMessage.getSubject());
|
||||||
}
|
}
|
||||||
catch (MessagingException e)
|
catch (MessagingException e)
|
||||||
{
|
{
|
||||||
@@ -373,7 +373,8 @@ public class SubethaEmailMessage implements EmailMessage
|
|||||||
|
|
||||||
for (EmailMessagePart attachment : attachments)
|
for (EmailMessagePart attachment : attachments)
|
||||||
{
|
{
|
||||||
if (attachment instanceof SubethaEmailMessagePart) {
|
if (attachment instanceof SubethaEmailMessagePart)
|
||||||
|
{
|
||||||
((SubethaEmailMessagePart) attachment).setRmiRegistry(rmiRegistryHost, rmiRegistryPort);
|
((SubethaEmailMessagePart) attachment).setRmiRegistry(rmiRegistryHost, rmiRegistryPort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -410,4 +411,24 @@ public class SubethaEmailMessage implements EmailMessage
|
|||||||
return attachments;
|
return attachments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces characters \/*|:"<>? on their hex values. Subject field is used as name of the content, so we need to replace characters that are forbidden in content names.
|
||||||
|
*
|
||||||
|
* @param subject String representing subject
|
||||||
|
* @return Encoded string
|
||||||
|
*/
|
||||||
|
static private String encodeSubject(String subject)
|
||||||
|
{
|
||||||
|
String result = subject.trim();
|
||||||
|
String[][] s = new String[][] { { "\\", "%5c" }, { "/", "%2f" }, { "*", "%2a" }, { "|", "%7c" }, { ":", "%3a" }, { "\"", "%22" }, { "<", "%3c" }, { ">", "%3e" },
|
||||||
|
{ "?", "%3f" } };
|
||||||
|
|
||||||
|
for (int i = 0; i < s.length; i++)
|
||||||
|
{
|
||||||
|
result = result.replace(s[i][0], s[i][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
60
source/java/org/alfresco/model/ImapModel.java
Executable file
60
source/java/org/alfresco/model/ImapModel.java
Executable file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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.model;
|
||||||
|
|
||||||
|
import org.alfresco.service.namespace.QName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IMAP Model Constants
|
||||||
|
*
|
||||||
|
* @author Mike Shavnev
|
||||||
|
*/
|
||||||
|
public interface ImapModel
|
||||||
|
{
|
||||||
|
static final String IMAP_MODEL_1_0_URI = "http://www.alfresco.org/model/imap/1.0";
|
||||||
|
|
||||||
|
static final QName ASPECT_IMAP_FOLDER_SUBSCRIBED = QName.createQName(IMAP_MODEL_1_0_URI, "subscribed");
|
||||||
|
static final QName ASPECT_IMAP_FOLDER_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 PROP_MESSAGE_FROM = QName.createQName(IMAP_MODEL_1_0_URI, "messageFrom");
|
||||||
|
static final QName PROP_MESSAGE_TO = QName.createQName(IMAP_MODEL_1_0_URI, "messageTo");
|
||||||
|
static final QName PROP_MESSAGE_CC = QName.createQName(IMAP_MODEL_1_0_URI, "messageCc");
|
||||||
|
static final QName PROP_MESSAGE_SUBJECT = QName.createQName(IMAP_MODEL_1_0_URI, "messageSubject");
|
||||||
|
|
||||||
|
static final QName 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_DELETED = QName.createQName(IMAP_MODEL_1_0_URI, "flagDeleted");
|
||||||
|
static final QName PROP_FLAG_DRAFT = QName.createQName(IMAP_MODEL_1_0_URI, "flagDraft");
|
||||||
|
static final QName PROP_FLAG_SEEN = QName.createQName(IMAP_MODEL_1_0_URI, "flagSeen");
|
||||||
|
static final QName PROP_FLAG_RECENT = QName.createQName(IMAP_MODEL_1_0_URI, "flagRecent");
|
||||||
|
static final QName PROP_FLAG_FLAGGED = QName.createQName(IMAP_MODEL_1_0_URI, "flagFlagged");
|
||||||
|
|
||||||
|
static final QName TYPE_IMAP_BODY = QName.createQName(IMAP_MODEL_1_0_URI, "imapBody");
|
||||||
|
|
||||||
|
static final QName TYPE_IMAP_ATTACH = QName.createQName(IMAP_MODEL_1_0_URI, "imapAttach");
|
||||||
|
static final QName PROP_ATTACH_ID = QName.createQName(IMAP_MODEL_1_0_URI, "attachID");
|
||||||
|
|
||||||
|
}
|
@@ -58,7 +58,8 @@ public class ScriptActionExecuter extends ActionExecuterAbstractBase
|
|||||||
private String companyHomePath;
|
private String companyHomePath;
|
||||||
private StoreRef storeRef;
|
private StoreRef storeRef;
|
||||||
private ScriptLocation scriptLocation;
|
private ScriptLocation scriptLocation;
|
||||||
|
private String webApplicationContextUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param serviceRegistry The serviceRegistry to set.
|
* @param serviceRegistry The serviceRegistry to set.
|
||||||
*/
|
*/
|
||||||
@@ -94,7 +95,17 @@ public class ScriptActionExecuter extends ActionExecuterAbstractBase
|
|||||||
{
|
{
|
||||||
this.scriptLocation = scriptLocation;
|
this.scriptLocation = scriptLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the web application context url
|
||||||
|
*
|
||||||
|
* @param webApplicationContextUrl web application context url
|
||||||
|
*/
|
||||||
|
public void setWebApplicationContextUrl(String webApplicationContextUrl)
|
||||||
|
{
|
||||||
|
this.webApplicationContextUrl = webApplicationContextUrl;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow adhoc properties to be passed to this action
|
* Allow adhoc properties to be passed to this action
|
||||||
*
|
*
|
||||||
@@ -149,7 +160,9 @@ public class ScriptActionExecuter extends ActionExecuterAbstractBase
|
|||||||
// Add the action to the default model
|
// Add the action to the default model
|
||||||
ScriptAction scriptAction = new ScriptAction(this.serviceRegistry, action, this.actionDefinition);
|
ScriptAction scriptAction = new ScriptAction(this.serviceRegistry, action, this.actionDefinition);
|
||||||
model.put("action", scriptAction);
|
model.put("action", scriptAction);
|
||||||
|
|
||||||
|
model.put("webApplicationContextUrl", webApplicationContextUrl);
|
||||||
|
|
||||||
Object result = null;
|
Object result = null;
|
||||||
if (this.scriptLocation == null)
|
if (this.scriptLocation == null)
|
||||||
{
|
{
|
||||||
|
264
source/java/org/alfresco/repo/admin/patch/impl/ImapFoldersPatch.java
Executable file
264
source/java/org/alfresco/repo/admin/patch/impl/ImapFoldersPatch.java
Executable file
@@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* 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.admin.patch.impl;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.alfresco.i18n.I18NUtil;
|
||||||
|
import org.alfresco.repo.admin.patch.AbstractPatch;
|
||||||
|
import org.alfresco.repo.importer.ACPImportPackageHandler;
|
||||||
|
import org.alfresco.repo.importer.ImporterBootstrap;
|
||||||
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
|
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||||
|
import org.alfresco.service.cmr.admin.PatchException;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
|
import org.alfresco.service.cmr.view.ImporterService;
|
||||||
|
import org.alfresco.service.cmr.view.Location;
|
||||||
|
import org.springframework.context.MessageSource;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
/**
|
||||||
|
* Builds folders tree necessary for IMAP functionality and imports email action scripts.
|
||||||
|
*
|
||||||
|
* 1. Company Home > Data Dictionary > Imap Config > Templates
|
||||||
|
* 2. Company Home > Data Dictionary > Email Actions > search
|
||||||
|
* 3. Company Home > Data Dictionary > Scripts > command-processor.js, command-search.js
|
||||||
|
*
|
||||||
|
* @author Arseny Kovalchuk
|
||||||
|
*/
|
||||||
|
public class ImapFoldersPatch extends AbstractPatch
|
||||||
|
{
|
||||||
|
// messages' ids
|
||||||
|
private static final String MSG_EXISTS = "patch.imapFolders.result.exists";
|
||||||
|
private static final String MSG_CREATED = "patch.imapFolders.result.created";
|
||||||
|
|
||||||
|
// folders' names for path building
|
||||||
|
private static final String PROPERTY_COMPANY_HOME_CHILDNAME = "spaces.company_home.childname";
|
||||||
|
private static final String PROPERTY_DICTIONARY_CHILDNAME = "spaces.dictionary.childname";
|
||||||
|
private static final String PROPERTY_SCRIPTS_CHILDNAME = "spaces.scripts.childname";
|
||||||
|
private static final String PROPERTY_IMAP_CONFIG_CHILDNAME = "spaces.imapConfig.childname";
|
||||||
|
|
||||||
|
private ImporterBootstrap importerBootstrap;
|
||||||
|
private MessageSource messageSource;
|
||||||
|
protected Properties configuration;
|
||||||
|
private ImporterService importerService;
|
||||||
|
|
||||||
|
private NodeRef companyHomeNodeRef;
|
||||||
|
private NodeRef dictionaryNodeRef;
|
||||||
|
private NodeRef scriptsNodeRef;
|
||||||
|
private NodeRef imapConfigFolderNodeRef;
|
||||||
|
private String configFoldersACP;
|
||||||
|
private String emailActionsACP;
|
||||||
|
private String scriptsACP;
|
||||||
|
|
||||||
|
public void setImporterBootstrap(ImporterBootstrap importerBootstrap)
|
||||||
|
{
|
||||||
|
this.importerBootstrap = importerBootstrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessageSource(MessageSource messageSource)
|
||||||
|
{
|
||||||
|
this.messageSource = messageSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImporterService(ImporterService importerService)
|
||||||
|
{
|
||||||
|
this.importerService = importerService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfigFoldersACP(String configFoldersACP)
|
||||||
|
{
|
||||||
|
this.configFoldersACP = configFoldersACP;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmailActionsACP(String emailActionsACP)
|
||||||
|
{
|
||||||
|
this.emailActionsACP = emailActionsACP;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScriptsACP(String scriptsACP)
|
||||||
|
{
|
||||||
|
this.scriptsACP = scriptsACP;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void checkCommonProperties() throws Exception
|
||||||
|
{
|
||||||
|
checkPropertyNotNull(importerBootstrap, "importerBootstrap");
|
||||||
|
checkPropertyNotNull(messageSource, "messageSource");
|
||||||
|
checkPropertyNotNull(importerService, "importerService");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setUp() throws Exception
|
||||||
|
{
|
||||||
|
// get the node store that we must work against
|
||||||
|
StoreRef storeRef = importerBootstrap.getStoreRef();
|
||||||
|
if (storeRef == null)
|
||||||
|
{
|
||||||
|
throw new PatchException("Bootstrap store has not been set");
|
||||||
|
}
|
||||||
|
NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef);
|
||||||
|
|
||||||
|
this.configuration = importerBootstrap.getConfiguration();
|
||||||
|
// get the association names that form the path
|
||||||
|
String companyHomeChildName = configuration.getProperty(PROPERTY_COMPANY_HOME_CHILDNAME);
|
||||||
|
if (companyHomeChildName == null || companyHomeChildName.length() == 0)
|
||||||
|
{
|
||||||
|
throw new PatchException("Bootstrap property '" + PROPERTY_COMPANY_HOME_CHILDNAME + "' is not present");
|
||||||
|
}
|
||||||
|
String dictionaryChildName = configuration.getProperty(PROPERTY_DICTIONARY_CHILDNAME);
|
||||||
|
if (dictionaryChildName == null || dictionaryChildName.length() == 0)
|
||||||
|
{
|
||||||
|
throw new PatchException("Bootstrap property '" + PROPERTY_DICTIONARY_CHILDNAME + "' is not present");
|
||||||
|
}
|
||||||
|
String scriptsChildName = configuration.getProperty(PROPERTY_SCRIPTS_CHILDNAME);
|
||||||
|
if (scriptsChildName == null || scriptsChildName.length() == 0)
|
||||||
|
{
|
||||||
|
throw new PatchException("Bootstrap property '" + PROPERTY_SCRIPTS_CHILDNAME + "' is not present");
|
||||||
|
}
|
||||||
|
|
||||||
|
String imapConfigChildName = configuration.getProperty(PROPERTY_IMAP_CONFIG_CHILDNAME);
|
||||||
|
if (imapConfigChildName == null || imapConfigChildName.length() == 0)
|
||||||
|
{
|
||||||
|
throw new PatchException("Bootstrap property '" + PROPERTY_IMAP_CONFIG_CHILDNAME + "' is not present");
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the search string to get the company home node
|
||||||
|
StringBuilder sb = new StringBuilder(256);
|
||||||
|
sb.append("/").append(companyHomeChildName);
|
||||||
|
String xpath = sb.toString();
|
||||||
|
// get the company home
|
||||||
|
List<NodeRef> nodeRefs = searchService.selectNodes(storeRootNodeRef, xpath, null, namespaceService, false);
|
||||||
|
if (nodeRefs.size() == 0)
|
||||||
|
{
|
||||||
|
throw new PatchException("XPath didn't return any results: \n" + " root: " + storeRootNodeRef + "\n" + " xpath: " + xpath);
|
||||||
|
}
|
||||||
|
else if (nodeRefs.size() > 1)
|
||||||
|
{
|
||||||
|
throw new PatchException("XPath returned too many results: \n" + " root: " + storeRootNodeRef + "\n" + " xpath: " + xpath + "\n" + " results: " + nodeRefs);
|
||||||
|
}
|
||||||
|
this.companyHomeNodeRef = nodeRefs.get(0);
|
||||||
|
|
||||||
|
// build the search string to get the dictionary node
|
||||||
|
sb.append("/").append(dictionaryChildName);
|
||||||
|
xpath = sb.toString();
|
||||||
|
// get the dictionary node
|
||||||
|
nodeRefs = searchService.selectNodes(storeRootNodeRef, xpath, null, namespaceService, false);
|
||||||
|
if (nodeRefs.size() == 0)
|
||||||
|
{
|
||||||
|
throw new PatchException("XPath didn't return any results: \n" + " root: " + storeRootNodeRef + "\n" + " xpath: " + xpath);
|
||||||
|
}
|
||||||
|
else if (nodeRefs.size() > 1)
|
||||||
|
{
|
||||||
|
throw new PatchException("XPath returned too many results: \n" + " root: " + storeRootNodeRef + "\n" + " xpath: " + xpath + "\n" + " results: " + nodeRefs);
|
||||||
|
}
|
||||||
|
this.dictionaryNodeRef = nodeRefs.get(0);
|
||||||
|
sb.append("/").append(scriptsChildName);
|
||||||
|
xpath = sb.toString();
|
||||||
|
nodeRefs = searchService.selectNodes(storeRootNodeRef, xpath, null, namespaceService, false);
|
||||||
|
if (nodeRefs.size() == 0)
|
||||||
|
{
|
||||||
|
throw new PatchException("XPath didn't return any results: \n" + " root: " + storeRootNodeRef + "\n" + " xpath: " + xpath);
|
||||||
|
}
|
||||||
|
else if (nodeRefs.size() > 1)
|
||||||
|
{
|
||||||
|
throw new PatchException("XPath returned too many results: \n" + " root: " + storeRootNodeRef + "\n" + " xpath: " + xpath + "\n" + " results: " + nodeRefs);
|
||||||
|
}
|
||||||
|
this.scriptsNodeRef = nodeRefs.get(0);
|
||||||
|
// get the ImapConfig node
|
||||||
|
sb.delete((sb.length() - (scriptsChildName.length() + 1)), sb.length());
|
||||||
|
sb.append("/").append(imapConfigChildName);
|
||||||
|
xpath = sb.toString();
|
||||||
|
nodeRefs = searchService.selectNodes(storeRootNodeRef, xpath, null, namespaceService, false);
|
||||||
|
if (nodeRefs.size() > 1)
|
||||||
|
{
|
||||||
|
throw new PatchException("XPath returned too many results: \n" + " root: " + storeRootNodeRef + "\n" + " xpath: " + xpath + "\n" + " results: " + nodeRefs);
|
||||||
|
}
|
||||||
|
else if (nodeRefs.size() == 0)
|
||||||
|
{
|
||||||
|
this.imapConfigFolderNodeRef = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.imapConfigFolderNodeRef = nodeRefs.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String applyInternal() throws Exception
|
||||||
|
{
|
||||||
|
checkCommonProperties();
|
||||||
|
setUp();
|
||||||
|
String msg = null;
|
||||||
|
if (imapConfigFolderNodeRef == null)
|
||||||
|
{
|
||||||
|
// import the content
|
||||||
|
RunAsWork<Object> importRunAs = new RunAsWork<Object>()
|
||||||
|
{
|
||||||
|
public Object doWork() throws Exception
|
||||||
|
{
|
||||||
|
importImapConfig();
|
||||||
|
importScripts();
|
||||||
|
importEmailActions();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
AuthenticationUtil.runAs(importRunAs, authenticationContext.getSystemUserName());
|
||||||
|
msg = I18NUtil.getMessage(MSG_CREATED);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg = I18NUtil.getMessage(MSG_EXISTS, imapConfigFolderNodeRef);
|
||||||
|
}
|
||||||
|
return msg;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void importImapConfig() throws IOException
|
||||||
|
{
|
||||||
|
importInternal(this.configFoldersACP, this.dictionaryNodeRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void importEmailActions() throws IOException
|
||||||
|
{
|
||||||
|
importInternal(this.emailActionsACP, this.dictionaryNodeRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void importScripts() throws IOException
|
||||||
|
{
|
||||||
|
importInternal(this.scriptsACP, this.scriptsNodeRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
257
source/java/org/alfresco/repo/admin/patch/impl/ImapUsersPatch.java
Executable file
257
source/java/org/alfresco/repo/admin/patch/impl/ImapUsersPatch.java
Executable file
@@ -0,0 +1,257 @@
|
|||||||
|
/*
|
||||||
|
* 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.admin.patch.impl;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import org.alfresco.i18n.I18NUtil;
|
||||||
|
import org.alfresco.model.ApplicationModel;
|
||||||
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.repo.admin.patch.AbstractPatch;
|
||||||
|
import org.alfresco.repo.importer.ImporterBootstrap;
|
||||||
|
import org.alfresco.service.cmr.admin.PatchException;
|
||||||
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
|
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.cmr.search.SearchParameters;
|
||||||
|
import org.alfresco.service.cmr.search.SearchService;
|
||||||
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.springframework.context.MessageSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Dmitry Vaserin
|
||||||
|
*/
|
||||||
|
public class ImapUsersPatch extends AbstractPatch
|
||||||
|
{
|
||||||
|
// messages' ids
|
||||||
|
private static final String MSG_EXISTS = "patch.imapUserFolders.result.exists";
|
||||||
|
private static final String MSG_CREATED = "patch.imapUserFolders.result.created";
|
||||||
|
|
||||||
|
// folders' names for path building
|
||||||
|
private static final String PROPERTY_COMPANY_HOME_CHILDNAME = "spaces.company_home.childname";
|
||||||
|
private static final String PROPERTY_IMAP_HOME_FOLDER_CHILDNAME = "spaces.imap_home.childname";
|
||||||
|
|
||||||
|
private static final String PROPERTY_ICON = "space-icon-default";
|
||||||
|
private static final String MSG_IMAP_HOME_FOLDER_NAME = "spaces.imap_home.name";
|
||||||
|
private static final String MSG_IMAP_HOME_FOLDER_DESCRIPTION = "spaces.imap_home.description";
|
||||||
|
|
||||||
|
private static final String INBOX_NAME = "INBOX";
|
||||||
|
private static final String INBOX_DECSRIPTION = "INBOX mail box";
|
||||||
|
|
||||||
|
private ImporterBootstrap importerBootstrap;
|
||||||
|
private MessageSource messageSource;
|
||||||
|
|
||||||
|
protected NodeRef companyHomeNodeRef;
|
||||||
|
protected Properties configuration;
|
||||||
|
protected NodeRef imapHomeNodeRef;
|
||||||
|
|
||||||
|
public void setImporterBootstrap(ImporterBootstrap importerBootstrap)
|
||||||
|
{
|
||||||
|
this.importerBootstrap = importerBootstrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessageSource(MessageSource messageSource)
|
||||||
|
{
|
||||||
|
this.messageSource = messageSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure that required common properties have been set
|
||||||
|
*/
|
||||||
|
protected void checkCommonProperties() throws Exception
|
||||||
|
{
|
||||||
|
checkPropertyNotNull(importerBootstrap, "importerBootstrap");
|
||||||
|
checkPropertyNotNull(namespaceService, "namespaceService");
|
||||||
|
checkPropertyNotNull(searchService, "searchService");
|
||||||
|
checkPropertyNotNull(nodeService, "nodeService");
|
||||||
|
checkPropertyNotNull(messageSource, "messageSource");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts pertinent references and properties that are common to execution of this and derived patches.
|
||||||
|
*/
|
||||||
|
protected void setUp() throws Exception
|
||||||
|
{
|
||||||
|
// get the node store that we must work against
|
||||||
|
StoreRef storeRef = importerBootstrap.getStoreRef();
|
||||||
|
if (storeRef == null)
|
||||||
|
{
|
||||||
|
throw new PatchException("Bootstrap store has not been set");
|
||||||
|
}
|
||||||
|
NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef);
|
||||||
|
|
||||||
|
this.configuration = importerBootstrap.getConfiguration();
|
||||||
|
// get the association names that form the path
|
||||||
|
String companyHomeChildName = configuration.getProperty(PROPERTY_COMPANY_HOME_CHILDNAME);
|
||||||
|
if (companyHomeChildName == null || companyHomeChildName.length() == 0)
|
||||||
|
{
|
||||||
|
throw new PatchException("Bootstrap property '" + PROPERTY_COMPANY_HOME_CHILDNAME + "' is not present");
|
||||||
|
}
|
||||||
|
String imapHomeChildName = configuration.getProperty(PROPERTY_IMAP_HOME_FOLDER_CHILDNAME);
|
||||||
|
if (imapHomeChildName == null || imapHomeChildName.length() == 0)
|
||||||
|
{
|
||||||
|
throw new PatchException("Bootstrap property '" + PROPERTY_IMAP_HOME_FOLDER_CHILDNAME + "' is not present");
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the search string to get the company home node
|
||||||
|
StringBuilder sb = new StringBuilder(256);
|
||||||
|
sb.append("/").append(companyHomeChildName);
|
||||||
|
String xpath = sb.toString();
|
||||||
|
// get the company home
|
||||||
|
List<NodeRef> nodeRefs = searchService.selectNodes(storeRootNodeRef, xpath, null, namespaceService, false);
|
||||||
|
if (nodeRefs.size() == 0)
|
||||||
|
{
|
||||||
|
throw new PatchException("XPath didn't return any results: \n" + " root: " + storeRootNodeRef + "\n" + " xpath: " + xpath);
|
||||||
|
}
|
||||||
|
else if (nodeRefs.size() > 1)
|
||||||
|
{
|
||||||
|
throw new PatchException("XPath returned too many results: \n" + " root: " + storeRootNodeRef + "\n" + " xpath: " + xpath + "\n" + " results: " + nodeRefs);
|
||||||
|
}
|
||||||
|
this.companyHomeNodeRef = nodeRefs.get(0);
|
||||||
|
|
||||||
|
xpath = imapHomeChildName;
|
||||||
|
nodeRefs = searchService.selectNodes(companyHomeNodeRef, xpath, null, namespaceService, false);
|
||||||
|
if (nodeRefs.size() > 1)
|
||||||
|
{
|
||||||
|
throw new PatchException("XPath returned too many results: \n" + " dictionary node: " + companyHomeNodeRef + "\n" + " xpath: " + xpath + "\n" + " results: "
|
||||||
|
+ nodeRefs);
|
||||||
|
}
|
||||||
|
else if (nodeRefs.size() == 0)
|
||||||
|
{
|
||||||
|
// the node does not exist
|
||||||
|
this.imapHomeNodeRef = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.imapHomeNodeRef = nodeRefs.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String applyInternal() throws Exception
|
||||||
|
{
|
||||||
|
// properties must be set
|
||||||
|
checkCommonProperties();
|
||||||
|
// get useful values
|
||||||
|
setUp();
|
||||||
|
|
||||||
|
String msg = null;
|
||||||
|
|
||||||
|
if (imapHomeNodeRef == null)
|
||||||
|
{
|
||||||
|
// create it
|
||||||
|
createImapHomeFolders();
|
||||||
|
msg = I18NUtil.getMessage(MSG_CREATED, imapHomeNodeRef);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// it already exists
|
||||||
|
msg = I18NUtil.getMessage(MSG_EXISTS, imapHomeNodeRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
// done
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createImapHomeFolders()
|
||||||
|
{
|
||||||
|
// get required properties
|
||||||
|
String imapHomeChildName = configuration.getProperty(PROPERTY_IMAP_HOME_FOLDER_CHILDNAME);
|
||||||
|
if (imapHomeChildName == null)
|
||||||
|
{
|
||||||
|
throw new PatchException("Bootstrap property '" + PROPERTY_IMAP_HOME_FOLDER_CHILDNAME + "' is not present");
|
||||||
|
}
|
||||||
|
|
||||||
|
String name = messageSource.getMessage(MSG_IMAP_HOME_FOLDER_NAME, null, I18NUtil.getLocale());
|
||||||
|
if (name == null || name.length() == 0)
|
||||||
|
{
|
||||||
|
throw new PatchException("Bootstrap property '" + MSG_IMAP_HOME_FOLDER_NAME + "' is not present");
|
||||||
|
}
|
||||||
|
|
||||||
|
String description = messageSource.getMessage(MSG_IMAP_HOME_FOLDER_DESCRIPTION, null, I18NUtil.getLocale());
|
||||||
|
if (description == null || description.length() == 0)
|
||||||
|
{
|
||||||
|
throw new PatchException("Bootstrap property '" + MSG_IMAP_HOME_FOLDER_DESCRIPTION + "' is not present");
|
||||||
|
}
|
||||||
|
|
||||||
|
imapHomeNodeRef = createSpace(companyHomeNodeRef, name, description, imapHomeChildName);
|
||||||
|
|
||||||
|
// Create IMAP Home and "INBOX" for each user
|
||||||
|
createImapUserHomes();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createImapUserHomes()
|
||||||
|
{
|
||||||
|
StringBuilder query = new StringBuilder(128);
|
||||||
|
query.append("@").append(NamespaceService.CONTENT_MODEL_PREFIX).append("\\:userName:*");
|
||||||
|
|
||||||
|
SearchParameters params = new SearchParameters();
|
||||||
|
params.setLanguage(SearchService.LANGUAGE_LUCENE);
|
||||||
|
params.addStore(importerBootstrap.getStoreRef());
|
||||||
|
params.setQuery(query.toString());
|
||||||
|
|
||||||
|
ResultSet results = searchService.query(params);
|
||||||
|
List<NodeRef> people;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
people = results.getNodeRefs();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
results.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (NodeRef nodeRef : people)
|
||||||
|
{
|
||||||
|
String userName = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_USERNAME);
|
||||||
|
String desc = userName + " " + messageSource.getMessage(MSG_IMAP_HOME_FOLDER_NAME, null, I18NUtil.getLocale());
|
||||||
|
NodeRef userHome = createSpace(imapHomeNodeRef, userName, desc, userName);
|
||||||
|
// Create Inbox
|
||||||
|
createSpace(userHome, INBOX_NAME, INBOX_DECSRIPTION, INBOX_NAME);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private NodeRef createSpace(NodeRef parent, String name, String desc, String childName)
|
||||||
|
{
|
||||||
|
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(7);
|
||||||
|
properties.put(ContentModel.PROP_NAME, name);
|
||||||
|
properties.put(ContentModel.PROP_TITLE, name);
|
||||||
|
properties.put(ContentModel.PROP_DESCRIPTION, desc);
|
||||||
|
properties.put(ApplicationModel.PROP_ICON, PROPERTY_ICON);
|
||||||
|
// create the node
|
||||||
|
ChildAssociationRef childAssocRef = nodeService.createNode(parent, ContentModel.ASSOC_CONTAINS, QName.resolveToQName(namespaceService, childName),
|
||||||
|
ContentModel.TYPE_FOLDER, properties);
|
||||||
|
NodeRef result = childAssocRef.getChildRef();
|
||||||
|
|
||||||
|
// add the required aspects
|
||||||
|
nodeService.addAspect(result, ApplicationModel.ASPECT_UIFACETS, null);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
72
source/java/org/alfresco/repo/imap/AlfrescoImapConst.java
Executable file
72
source/java/org/alfresco/repo/imap/AlfrescoImapConst.java
Executable file
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Mike Shavnev
|
||||||
|
*/
|
||||||
|
public interface AlfrescoImapConst
|
||||||
|
{
|
||||||
|
|
||||||
|
public static final char HIERARCHY_DELIMITER = '.';
|
||||||
|
public static final String NAMESPACE_PREFIX = "#";
|
||||||
|
public static final String USER_NAMESPACE = "#mail";
|
||||||
|
public static final String INBOX_NAME = "INBOX";
|
||||||
|
|
||||||
|
public static final String BODY_TEXT_PLAIN_NAME = "Body.txt";
|
||||||
|
public static final String BODY_TEXT_HTML_NAME = "Body.html";
|
||||||
|
public static final String MESSAGE_PREFIX = "Message_";
|
||||||
|
// Separator for user enties in flag and subscribe properties
|
||||||
|
public static final String USER_SEPARATOR = ";";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines {@link AlfrescoImapMailFolder} view mode as archive mode. Used for Email Archive View.
|
||||||
|
*/
|
||||||
|
public static final String MODE_ARCHIVE = "archive";
|
||||||
|
/**
|
||||||
|
* Defines {@link AlfrescoImapMailFolder} view mode as virtual mode. Used for IMAP Virtualised View.
|
||||||
|
*/
|
||||||
|
public static final String MODE_VIRTUAL = "virtual";
|
||||||
|
|
||||||
|
// 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_HTML_TEMPLATE = "/alfresco/templates/imap/imap_message_text_html.ftl";
|
||||||
|
|
||||||
|
public static final String DICTIONARY_TEMPLATE_PREFIX = "emailbody";
|
||||||
|
public static final String PREF_IMAP_FAVOURITE_SITES = "org.alfresco.share.sites.imap.favourites";
|
||||||
|
|
||||||
|
// AlfrescoImapMessage constants
|
||||||
|
public static final String MIME_VERSION = "MIME-Version";
|
||||||
|
public static final String CONTENT_TYPE = "Content-Type";
|
||||||
|
public static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
|
||||||
|
public static final String MULTIPART_MIXED = "mixed";
|
||||||
|
public static final String CONTENT_ID = "Content-ID";
|
||||||
|
public static final String X_ALF_NODEREF_ID = "X-Alfresco-NodeRef-ID"; // The NodeRef id header
|
||||||
|
public static final String X_ALF_SERVER_UID = "X-Alfresco-Server-UID"; // The unique identifier of Alfresco server
|
||||||
|
public static final String EIGHT_BIT_ENCODING = "8bit";
|
||||||
|
public static final String BASE_64_ENCODING = "base64";
|
||||||
|
public static final String UTF_8 = "UTF-8";
|
||||||
|
|
||||||
|
}
|
958
source/java/org/alfresco/repo/imap/AlfrescoImapHostManager.java
Executable file
958
source/java/org/alfresco/repo/imap/AlfrescoImapHostManager.java
Executable file
@@ -0,0 +1,958 @@
|
|||||||
|
/*
|
||||||
|
* 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.Serializable;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.model.ImapModel;
|
||||||
|
import org.alfresco.repo.imap.config.ImapConfigElement.ImapConfig;
|
||||||
|
import org.alfresco.repo.imap.exception.AlfrescoImapFolderException;
|
||||||
|
import org.alfresco.repo.model.filefolder.FileFolderServiceImpl;
|
||||||
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
|
import org.alfresco.service.ServiceRegistry;
|
||||||
|
import org.alfresco.service.cmr.model.FileExistsException;
|
||||||
|
import org.alfresco.service.cmr.model.FileFolderService;
|
||||||
|
import org.alfresco.service.cmr.model.FileInfo;
|
||||||
|
import org.alfresco.service.cmr.model.FileNotFoundException;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
|
import org.alfresco.service.cmr.security.AccessStatus;
|
||||||
|
import org.alfresco.service.cmr.security.PermissionService;
|
||||||
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import com.icegreen.greenmail.imap.AuthorizationException;
|
||||||
|
import com.icegreen.greenmail.imap.ImapHostManager;
|
||||||
|
import com.icegreen.greenmail.store.FolderException;
|
||||||
|
import com.icegreen.greenmail.store.MailFolder;
|
||||||
|
import com.icegreen.greenmail.user.GreenMailUser;
|
||||||
|
import com.icegreen.greenmail.util.GreenMailUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Mike Shavnev
|
||||||
|
*/
|
||||||
|
public class AlfrescoImapHostManager implements ImapHostManager
|
||||||
|
{
|
||||||
|
|
||||||
|
private Log logger = LogFactory.getLog(AlfrescoImapHostManager.class);
|
||||||
|
|
||||||
|
private ServiceRegistry serviceRegistry;
|
||||||
|
|
||||||
|
private NodeService nodeService;
|
||||||
|
private FileFolderService fileFolderService;
|
||||||
|
private ImapHelper imapHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hierarchy delimiter for mailboxes on this host.
|
||||||
|
*
|
||||||
|
* @return The hierarchy delimiter character.
|
||||||
|
*/
|
||||||
|
public char getHierarchyDelimiter()
|
||||||
|
{
|
||||||
|
return AlfrescoImapConst.HIERARCHY_DELIMITER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an collection of mailboxes. Method searches mailboxes under mount points defined for a specific user. Mount points include user's IMAP Virtualised Views and Email
|
||||||
|
* Archive Views. This method serves LIST command of the IMAP protocol.
|
||||||
|
*
|
||||||
|
* @param user User making the request
|
||||||
|
* @param mailboxPattern String name of a mailbox possible including a wildcard.
|
||||||
|
* @return Collection of mailboxes matching the pattern.
|
||||||
|
* @throws com.icegreen.greenmail.store.FolderException
|
||||||
|
*/
|
||||||
|
public Collection<MailFolder> listMailboxes(GreenMailUser user, String mailboxPattern) throws FolderException
|
||||||
|
{
|
||||||
|
mailboxPattern = GreenMailUtil.convertFromUtf7(mailboxPattern);
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Listing mailboxes: mailboxPattern=" + mailboxPattern);
|
||||||
|
}
|
||||||
|
mailboxPattern = imapHelper.getMailPathInRepo(mailboxPattern);
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Listing mailboxes: mailboxPattern in alfresco=" + mailboxPattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<MailFolder> result = new LinkedList<MailFolder>();
|
||||||
|
|
||||||
|
Map<String, NodeRef> mountPoints = imapHelper.getMountPoints();
|
||||||
|
Map<String, ImapConfig> imapConfigs = imapHelper.getImapConfigs();
|
||||||
|
|
||||||
|
NodeRef mountPoint;
|
||||||
|
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 mode = imapConfigs.get(mountPointName).getMode();
|
||||||
|
|
||||||
|
if (!mailboxPattern.equals("*"))
|
||||||
|
{
|
||||||
|
mountPoint = mountParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isVirtualView = imapConfigs.get(mountPointName).getMode().equals(AlfrescoImapConst.MODE_VIRTUAL);
|
||||||
|
Collection<FileInfo> folders = listFolder(mountPoint, user, mailboxPattern, isVirtualView);
|
||||||
|
if (folders != null)
|
||||||
|
{
|
||||||
|
for (FileInfo folder : folders)
|
||||||
|
{
|
||||||
|
result.add(new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), folder, folder.getName(), mode, mountParent, mountPointName, imapHelper));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mailboxPattern.equals("*"))
|
||||||
|
{
|
||||||
|
result.add(new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), mountPointFileInfo, mountPointName, mode, mountParent, mountPointName, imapHelper));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mountPoint = imapHelper.getUserImapHomeRef(user.getLogin());
|
||||||
|
Collection<FileInfo> imapFolders = listFolder(mountPoint, user, mailboxPattern, false);
|
||||||
|
if (imapFolders != null)
|
||||||
|
{
|
||||||
|
for (FileInfo imapFolder : imapFolders)
|
||||||
|
{
|
||||||
|
result.add(new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), imapFolder, imapFolder.getName(), AlfrescoImapConst.MODE_ARCHIVE, mountPoint, null,
|
||||||
|
imapHelper));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<FileInfo> listFolder(NodeRef root, GreenMailUser user, String mailboxPattern, boolean isVirtualView) throws FolderException
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Listing mailboxes: mailboxPattern=" + mailboxPattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<FileInfo> result = new LinkedList<FileInfo>();
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
List<FileInfo> list = imapHelper.searchFolders(root, name, true, isVirtualView);
|
||||||
|
if (list.size() > 0)
|
||||||
|
{
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else if (name.endsWith("*"))
|
||||||
|
{
|
||||||
|
List<FileInfo> list = imapHelper.searchFolders(root, name.replace('%', '*'), false, isVirtualView);
|
||||||
|
if (list.size() > 0)
|
||||||
|
{
|
||||||
|
result.addAll(list);
|
||||||
|
for (FileInfo fileInfo : list)
|
||||||
|
{
|
||||||
|
List<FileInfo> childList = imapHelper.searchFolders(fileInfo.getNodeRef(), "*", true, isVirtualView);
|
||||||
|
result.addAll(childList);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else if (name.contains("%") || name.contains("*"))
|
||||||
|
{
|
||||||
|
List<FileInfo> list = imapHelper.searchFolders(root, name.replace('%', '*'), false, isVirtualView);
|
||||||
|
if (list.size() > 0)
|
||||||
|
{
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<FileInfo> list = imapHelper.searchFolders(root, name, false, isVirtualView);
|
||||||
|
if (list.size() > 0)
|
||||||
|
{
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<FileInfo> list = imapHelper.searchFolders(root, name.replace('%', '*'), false, isVirtualView);
|
||||||
|
for (FileInfo folder : list)
|
||||||
|
{
|
||||||
|
Collection<FileInfo> childFolders = listFolder(folder.getNodeRef(), user, remainName, isVirtualView);
|
||||||
|
if (childFolders != null)
|
||||||
|
{
|
||||||
|
result.addAll(childFolders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.isEmpty())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an collection of subscribed mailboxes. To appear in search result mailboxes should have {http://www.alfresco.org/model/imap/1.0}subscribed property specified for
|
||||||
|
* user. Method searches subscribed mailboxes under mount points defined for a specific user. Mount points include user's IMAP Virtualised Views and Email Archive Views. This
|
||||||
|
* method serves LSUB command of the IMAP protocol.
|
||||||
|
*
|
||||||
|
* @param user User making the request
|
||||||
|
* @param mailboxPattern String name of a mailbox possible including a wildcard.
|
||||||
|
* @return Collection of mailboxes matching the pattern.
|
||||||
|
* @throws com.icegreen.greenmail.store.FolderException
|
||||||
|
*/
|
||||||
|
public Collection<MailFolder> listSubscribedMailboxes(GreenMailUser user, String mailboxPattern) throws FolderException
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Listing subscribed mailboxes: mailboxPattern=" + mailboxPattern);
|
||||||
|
}
|
||||||
|
mailboxPattern = imapHelper.getMailPathInRepo(mailboxPattern);
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Listing subscribed mailboxes: mailboxPattern in alfresco=" + mailboxPattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<MailFolder> result = new LinkedList<MailFolder>();
|
||||||
|
|
||||||
|
Map<String, NodeRef> mountPoints = imapHelper.getMountPoints();
|
||||||
|
Map<String, ImapConfig> imapConfigs = imapHelper.getImapConfigs();
|
||||||
|
|
||||||
|
NodeRef mountPoint;
|
||||||
|
|
||||||
|
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 = listSubscribedFolder(mountPoint, mountPoint, user, mailboxPattern, isVirtualView);
|
||||||
|
if (folders != null)
|
||||||
|
{
|
||||||
|
for (MailFolder mailFolder : folders)
|
||||||
|
{
|
||||||
|
AlfrescoImapMailFolder folder = (AlfrescoImapMailFolder) mailFolder;
|
||||||
|
folder.setMountPointName(mountPointName);
|
||||||
|
folder.setViewMode(viewMode);
|
||||||
|
folder.setMountParent(mountParent);
|
||||||
|
}
|
||||||
|
result.addAll(folders);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mailboxPattern.equals("*"))
|
||||||
|
{
|
||||||
|
if (isSubscribed(mountPointFileInfo, user.getLogin()))
|
||||||
|
{
|
||||||
|
result.add(new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), mountPointFileInfo, mountPointName, viewMode, mountParent, mountPointName, imapHelper));
|
||||||
|
}
|
||||||
|
// \NoSelect
|
||||||
|
else if (hasSubscribedChild(mountPointFileInfo, user.getLogin(), isVirtualView))
|
||||||
|
{
|
||||||
|
result.add(new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), mountPointFileInfo, mountPointName, viewMode, mountParent, mountPointName, imapHelper,
|
||||||
|
false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeRef root = imapHelper.getSpacesStoreNodeRef();
|
||||||
|
|
||||||
|
root = imapHelper.getUserImapHomeRef(user.getLogin());
|
||||||
|
Collection<MailFolder> imapFolders = listSubscribedFolder(root, root, user, mailboxPattern, false);
|
||||||
|
|
||||||
|
if (imapFolders != null)
|
||||||
|
{
|
||||||
|
result.addAll(imapFolders);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<MailFolder> listSubscribedFolder(NodeRef mailboxRoot, NodeRef root, GreenMailUser user, String mailboxPattern, 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))
|
||||||
|
{
|
||||||
|
List<FileInfo> list = imapHelper.searchFolders(root, name, true, isVirtualView);
|
||||||
|
Collection<FileInfo> subscribedList = getSubscribed(list, user.getLogin());
|
||||||
|
|
||||||
|
if (subscribedList.size() > 0)
|
||||||
|
{
|
||||||
|
return createMailFolderList(user, subscribedList, 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 = getSubscribed(list, user.getLogin());
|
||||||
|
|
||||||
|
if (list.size() > 0)
|
||||||
|
{
|
||||||
|
fullList.addAll(subscribedList);
|
||||||
|
for (FileInfo fileInfo : list)
|
||||||
|
{
|
||||||
|
List<FileInfo> childList = imapHelper.searchFolders(fileInfo.getNodeRef(), "*", true, isVirtualView);
|
||||||
|
fullList.addAll(getSubscribed(childList, user.getLogin()));
|
||||||
|
}
|
||||||
|
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>();
|
||||||
|
|
||||||
|
for (FileInfo fileInfo : list)
|
||||||
|
{
|
||||||
|
if (isSubscribed(fileInfo, user.getLogin()))
|
||||||
|
{
|
||||||
|
// folderName, viewMode, mountPointName will be setted in listSubscribedMailboxes() 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 listSubscribedMailboxes() method
|
||||||
|
subscribedList.add(new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), fileInfo, null, null, mailboxRoot, null, imapHelper, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return subscribedList;
|
||||||
|
}
|
||||||
|
else if (name.contains("%") || name.contains("*"))
|
||||||
|
{
|
||||||
|
List<FileInfo> list = imapHelper.searchFolders(root, name.replace('%', '*'), false, isVirtualView);
|
||||||
|
Collection<FileInfo> 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 = 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 = listSubscribedFolder(mailboxRoot, folder.getNodeRef(), user, remainName, isVirtualView);
|
||||||
|
|
||||||
|
if (childFolders != null)
|
||||||
|
{
|
||||||
|
result.addAll(childFolders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.isEmpty())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renames an existing mailbox. The specified mailbox must already exist, the requested name must not exist already but must be able to be created and the user must have rights
|
||||||
|
* to delete the existing mailbox and create a mailbox with the new name. Any inferior hierarchical names must also be renamed. If INBOX is renamed, the contents of INBOX are
|
||||||
|
* transferred to a new mailbox with the new name, but INBOX is not deleted. If INBOX has inferior mailbox these are not renamed. This method serves RENAME command of the IMAP
|
||||||
|
* protocol. <p/> Method searches mailbox under mount points defined for a specific user. Mount points include user's IMAP Virtualised Views and Email Archive Views.
|
||||||
|
*
|
||||||
|
* @param user User making the request.
|
||||||
|
* @param oldMailboxName String name of the existing folder
|
||||||
|
* @param newMailboxName String target 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public void renameMailbox(GreenMailUser user, String oldMailboxName, String newMailboxName) throws FolderException, AuthorizationException
|
||||||
|
{
|
||||||
|
oldMailboxName = GreenMailUtil.convertFromUtf7(oldMailboxName);
|
||||||
|
newMailboxName = GreenMailUtil.convertFromUtf7(newMailboxName);
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Renaming folder: oldMailboxName=" + oldMailboxName + " newMailboxName=" + newMailboxName);
|
||||||
|
}
|
||||||
|
|
||||||
|
AlfrescoImapMailFolder sourceNode = (AlfrescoImapMailFolder) getFolder(user, GreenMailUtil.convertInUtf7(oldMailboxName));
|
||||||
|
|
||||||
|
NodeRef root = imapHelper.getMailboxRootRef(oldMailboxName, user.getLogin());
|
||||||
|
String mailboxRepoName = imapHelper.getMailPathInRepo(newMailboxName);
|
||||||
|
|
||||||
|
StringTokenizer tokenizer = new StringTokenizer(mailboxRepoName, String.valueOf(AlfrescoImapConst.HIERARCHY_DELIMITER));
|
||||||
|
|
||||||
|
NodeRef parentNodeRef = root;
|
||||||
|
while (tokenizer.hasMoreTokens())
|
||||||
|
{
|
||||||
|
String folderName = tokenizer.nextToken();
|
||||||
|
|
||||||
|
if (!tokenizer.hasMoreTokens())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (oldMailboxName.equalsIgnoreCase(AlfrescoImapConst.INBOX_NAME))
|
||||||
|
{
|
||||||
|
// If you trying to rename INBOX
|
||||||
|
// - just copy it to another folder with new name
|
||||||
|
// and leave INBOX (with children) intact.
|
||||||
|
fileFolderService.copy(sourceNode.getFolderInfo().getNodeRef(), parentNodeRef, folderName);
|
||||||
|
List<FileInfo> itemsForRemove = fileFolderService.list(sourceNode.getFolderInfo().getNodeRef());
|
||||||
|
for (FileInfo fileInfo : itemsForRemove)
|
||||||
|
{
|
||||||
|
fileFolderService.delete(fileInfo.getNodeRef());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileFolderService.move(sourceNode.getFolderInfo().getNodeRef(), parentNodeRef, folderName);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (FileExistsException e)
|
||||||
|
{
|
||||||
|
throw new FolderException(FolderException.ALREADY_EXISTS_LOCALLY);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException e)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<FileInfo> folders = imapHelper.searchFolders(parentNodeRef, folderName, false, true);
|
||||||
|
|
||||||
|
if (folders.size() == 0)
|
||||||
|
{
|
||||||
|
AccessStatus status = imapHelper.hasPermission(parentNodeRef, PermissionService.WRITE);
|
||||||
|
if (status == AccessStatus.DENIED)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Creating folder: Cant't create folder - Permission denied");
|
||||||
|
}
|
||||||
|
throw new AlfrescoImapFolderException(AlfrescoImapFolderException.PERMISSION_DENIED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Create mailBox: " + folderName);
|
||||||
|
}
|
||||||
|
FileFolderServiceImpl.makeFolders(fileFolderService, parentNodeRef, Arrays.asList(folderName), ContentModel.TYPE_FOLDER);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parentNodeRef = folders.get(0).getNodeRef();
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("MailBox: " + folderName + " already exists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to a newly created mailbox. The request should specify a mailbox that does not already exist on this server, that could exist on this server and that the
|
||||||
|
* user has rights to create. This method serves CREATE command of the IMAP protocol.
|
||||||
|
*
|
||||||
|
* @param user User making the request.
|
||||||
|
* @param mailboxName String name of the target
|
||||||
|
* @return an Mailbox reference.
|
||||||
|
* @throws com.icegreen.greenmail.store.FolderException if mailbox already exists
|
||||||
|
* @throws AlfrescoImapFolderException if user does not have rights to create the new mailbox.
|
||||||
|
*/
|
||||||
|
public MailFolder createMailbox(GreenMailUser user, String mailboxName) throws AuthorizationException, FolderException
|
||||||
|
{
|
||||||
|
mailboxName = GreenMailUtil.convertFromUtf7(mailboxName);
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Creating folder: " + mailboxName);
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeRef root = imapHelper.getMailboxRootRef(mailboxName, user.getLogin());
|
||||||
|
|
||||||
|
String mountPointName = imapHelper.getMountPointName(mailboxName);
|
||||||
|
String mailboxRepoNam = imapHelper.getMailPathInRepo(mailboxName);
|
||||||
|
StringTokenizer tokenizer = new StringTokenizer(mailboxRepoNam, String.valueOf(AlfrescoImapConst.HIERARCHY_DELIMITER));
|
||||||
|
|
||||||
|
NodeRef parentNodeRef = root;
|
||||||
|
|
||||||
|
while (tokenizer.hasMoreTokens())
|
||||||
|
{
|
||||||
|
String folderName = tokenizer.nextToken();
|
||||||
|
|
||||||
|
List<FileInfo> folders = imapHelper.searchFolders(parentNodeRef, folderName, false, true);
|
||||||
|
|
||||||
|
if (folders.size() == 0)
|
||||||
|
{
|
||||||
|
AccessStatus status = imapHelper.hasPermission(parentNodeRef, PermissionService.WRITE);
|
||||||
|
if (status == AccessStatus.DENIED)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Creating folder: Cant't create folder - Permission denied");
|
||||||
|
}
|
||||||
|
throw new AlfrescoImapFolderException(AlfrescoImapFolderException.PERMISSION_DENIED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Create mailBox: " + mailboxName);
|
||||||
|
}
|
||||||
|
FileInfo mailFolder = FileFolderServiceImpl.makeFolders(fileFolderService, parentNodeRef, Arrays.asList(folderName), ContentModel.TYPE_FOLDER);
|
||||||
|
|
||||||
|
|
||||||
|
return new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), mailFolder, folderName, imapHelper.getViewMode(mailboxName), root, mountPointName, imapHelper);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parentNodeRef = folders.get(0).getNodeRef();
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("MailBox: " + folderName + " already exists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FolderException(FolderException.ALREADY_EXISTS_LOCALLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an existing MailBox. Specified mailbox must already exist on this server, and the user must have rights to delete it. <p/> This method serves DELETE command of the
|
||||||
|
* IMAP protocol.
|
||||||
|
*
|
||||||
|
* @param user User making the request.
|
||||||
|
* @param mailboxName String name of the target
|
||||||
|
* @throws com.icegreen.greenmail.store.FolderException if mailbox has a non-selectable store with children
|
||||||
|
*/
|
||||||
|
public void deleteMailbox(GreenMailUser user, String mailboxName) throws FolderException, AuthorizationException
|
||||||
|
{
|
||||||
|
AlfrescoImapMailFolder folder = (AlfrescoImapMailFolder) getFolder(user, mailboxName);
|
||||||
|
NodeRef nodeRef = folder.getFolderInfo().getNodeRef();
|
||||||
|
|
||||||
|
List<FileInfo> childFolders = imapHelper.searchFolders(nodeRef, "*", false, false);
|
||||||
|
|
||||||
|
if (childFolders.isEmpty())
|
||||||
|
{
|
||||||
|
folder.signalDeletion();
|
||||||
|
// Delete child folders and messages
|
||||||
|
fileFolderService.delete(nodeRef);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (folder.isSelectable())
|
||||||
|
{
|
||||||
|
// Delete all messages for this folder
|
||||||
|
// Don't delete subfolders and their messages
|
||||||
|
List<FileInfo> messages = imapHelper.searchFiles(nodeRef, "*", ImapModel.TYPE_IMAP_CONTENT, false);
|
||||||
|
for (FileInfo message : messages)
|
||||||
|
{
|
||||||
|
fileFolderService.delete(message.getNodeRef());
|
||||||
|
}
|
||||||
|
nodeService.addAspect(nodeRef, ImapModel.ASPECT_IMAP_FOLDER_NONSELECTABLE, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new FolderException(mailboxName + " - Can't delete a non-selectable store with children.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to an existing Mailbox. The requested mailbox must already exists on this server and the requesting user must have at least lookup rights. <p/> It is
|
||||||
|
* also can be used by to obtain hierarchy delimiter by the LIST command: <p/> C: 2 list "" "" <p/> S: * LIST () "." "" <p/> S: 2 OK LIST completed. <p/> Method searches
|
||||||
|
* mailbox under mount points defined for a specific user. Mount points include user's IMAP Virtualised Views and Email Archive Views.
|
||||||
|
*
|
||||||
|
* @param user User making the request.
|
||||||
|
* @param mailboxName String name of the target.
|
||||||
|
* @return an Mailbox reference.
|
||||||
|
*/
|
||||||
|
public MailFolder getFolder(GreenMailUser user, String mailboxName)
|
||||||
|
{
|
||||||
|
mailboxName = GreenMailUtil.convertFromUtf7(mailboxName);
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Getting folder: " + mailboxName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If MailFolder object is used to obtain hierarchy delimiter by LIST command:
|
||||||
|
// Example:
|
||||||
|
// C: 2 list "" ""
|
||||||
|
// S: * LIST () "." ""
|
||||||
|
// S: 2 OK LIST completed.
|
||||||
|
if ("".equals(mailboxName))
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Request for the hierarchy delimiter");
|
||||||
|
}
|
||||||
|
return new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), null, null, null, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeRef root = imapHelper.getMailboxRootRef(mailboxName, user.getLogin());
|
||||||
|
String mountPointName = imapHelper.getMountPointName(mailboxName);
|
||||||
|
String mailboxRepoName = imapHelper.getMailPathInRepo(mailboxName);
|
||||||
|
|
||||||
|
StringTokenizer tokenizer = new StringTokenizer(mailboxRepoName, String.valueOf(AlfrescoImapConst.HIERARCHY_DELIMITER));
|
||||||
|
int count = tokenizer.countTokens();
|
||||||
|
NodeRef nodeRef = root;
|
||||||
|
|
||||||
|
while (tokenizer.hasMoreTokens())
|
||||||
|
{
|
||||||
|
String t = tokenizer.nextToken();
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("token=" + t);
|
||||||
|
}
|
||||||
|
count--;
|
||||||
|
|
||||||
|
List<FileInfo> list = imapHelper.searchFolders(nodeRef, t, false, true);
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
if (!list.isEmpty())
|
||||||
|
{
|
||||||
|
|
||||||
|
return new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), list.get(0), list.get(0).getName(), imapHelper.getViewMode(mailboxName), root,
|
||||||
|
mountPointName, imapHelper);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), null, null, null, null, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!list.isEmpty())
|
||||||
|
{
|
||||||
|
nodeRef = list.get(0).getNodeRef();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), null, null, null, null, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Error state");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simply calls {@link #getFolder(GreenMailUser, String)}. <p/> Added to implement {@link ImapHostManager}.
|
||||||
|
*/
|
||||||
|
public MailFolder getFolder(GreenMailUser user, String mailboxName, boolean mustExist) throws FolderException
|
||||||
|
{
|
||||||
|
return getFolder(user, mailboxName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the user's INBOX.
|
||||||
|
*
|
||||||
|
* @param user The user making the request.
|
||||||
|
* @return The user's Inbox.
|
||||||
|
*/
|
||||||
|
public MailFolder getInbox(GreenMailUser user) throws FolderException
|
||||||
|
{
|
||||||
|
return getFolder(user, AlfrescoImapConst.INBOX_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not supported. May be used by GreenMailUser.create() method. <p/> Added to implement {@link ImapHostManager}.
|
||||||
|
*/
|
||||||
|
public void createPrivateMailAccount(GreenMailUser user) throws FolderException
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribes a user to a mailbox. The mailbox must exist locally and the user must have rights to modify it. <p/> This method serves SUBSCRIBE command of the IMAP protocol.
|
||||||
|
*
|
||||||
|
* @param user User making the request
|
||||||
|
* @param mailbox String representation of a mailbox name.
|
||||||
|
*/
|
||||||
|
public void subscribe(final GreenMailUser user, final String mailbox) throws FolderException
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Subscribing: " + mailbox);
|
||||||
|
}
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribes from a given mailbox. <p/> This method serves UNSUBSCRIBE command of the IMAP protocol.
|
||||||
|
*
|
||||||
|
* @param user User making the request
|
||||||
|
* @param mailbox String representation of a mailbox name.
|
||||||
|
*/
|
||||||
|
public void unsubscribe(final GreenMailUser user, final String mailbox) throws FolderException
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Unsubscribing: " + mailbox);
|
||||||
|
}
|
||||||
|
AlfrescoImapMailFolder mailFolder = (AlfrescoImapMailFolder) getFolder(user, mailbox);
|
||||||
|
nodeService.removeAspect(mailFolder.getFolderInfo().getNodeRef(), ImapModel.ASPECT_IMAP_FOLDER_SUBSCRIBED);
|
||||||
|
|
||||||
|
// This is a multiuser support. Commented due new requirements
|
||||||
|
// AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Void>()
|
||||||
|
// {
|
||||||
|
// public Void doWork() throws Exception
|
||||||
|
// {
|
||||||
|
// AlfrescoImapMailFolder mailFolder = (AlfrescoImapMailFolder) getFolder(user, mailbox);
|
||||||
|
// if (mailFolder.getFolderInfo() != null)
|
||||||
|
// {
|
||||||
|
// FileInfo fileInfo = mailFolder.getFolderInfo();
|
||||||
|
// String subscribedList = (String) nodeService.getProperty(fileInfo.getNodeRef(), ImapModel.PROP_IMAP_FOLDER_SUBSCRIBED);
|
||||||
|
// if (subscribedList == null)
|
||||||
|
// {
|
||||||
|
// subscribedList = "";
|
||||||
|
// }
|
||||||
|
// subscribedList = subscribedList.replaceAll(imapHelper.formatUserEntry(user.getLogin()), "");
|
||||||
|
// nodeService.setProperty(fileInfo.getNodeRef(), ImapModel.PROP_IMAP_FOLDER_SUBSCRIBED, subscribedList);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// logger.debug("MailBox: " + mailbox + " doesn't exsist. Maybe it was deleted earlier.");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// }, AuthenticationUtil.getSystemUserName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not supported. Used by GreenMail class.
|
||||||
|
*/
|
||||||
|
public List getAllMessages()
|
||||||
|
{
|
||||||
|
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(List<FileInfo> list, String userName)
|
||||||
|
{
|
||||||
|
Collection<FileInfo> result = new LinkedList<FileInfo>();
|
||||||
|
|
||||||
|
for (FileInfo folderInfo : list)
|
||||||
|
{
|
||||||
|
if (isSubscribed(folderInfo, userName))
|
||||||
|
{
|
||||||
|
result.add(folderInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasSubscribedChild(FileInfo parent, String userName, boolean isVirtualView)
|
||||||
|
{
|
||||||
|
List<FileInfo> list = imapHelper.searchFolders(parent.getNodeRef(), "*", true, isVirtualView);
|
||||||
|
|
||||||
|
for (FileInfo fileInfo : list)
|
||||||
|
{
|
||||||
|
if (isSubscribed(fileInfo, userName))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<MailFolder> createMailFolderList(GreenMailUser user, Collection<FileInfo> list, NodeRef imapUserHomeRef)
|
||||||
|
{
|
||||||
|
Collection<MailFolder> result = new LinkedList<MailFolder>();
|
||||||
|
|
||||||
|
for (FileInfo folderInfo : list)
|
||||||
|
{
|
||||||
|
// folderName, viewMode, mountPointName will be setted in listSubscribedMailboxes() method
|
||||||
|
result.add(new AlfrescoImapMailFolder(user.getQualifiedMailboxName(), folderInfo, null, null, imapUserHomeRef, null, imapHelper));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------Getters and Setters----------------------------
|
||||||
|
|
||||||
|
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||||
|
{
|
||||||
|
this.serviceRegistry = serviceRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceRegistry getServiceRegistry()
|
||||||
|
{
|
||||||
|
return serviceRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNodeService(NodeService nodeService)
|
||||||
|
{
|
||||||
|
this.nodeService = nodeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileFolderService(FileFolderService fileFolderService)
|
||||||
|
{
|
||||||
|
this.fileFolderService = fileFolderService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImapHelper(ImapHelper imapHelper)
|
||||||
|
{
|
||||||
|
this.imapHelper = imapHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1084
source/java/org/alfresco/repo/imap/AlfrescoImapMailFolder.java
Executable file
1084
source/java/org/alfresco/repo/imap/AlfrescoImapMailFolder.java
Executable file
File diff suppressed because it is too large
Load Diff
508
source/java/org/alfresco/repo/imap/AlfrescoImapMessage.java
Executable file
508
source/java/org/alfresco/repo/imap/AlfrescoImapMessage.java
Executable file
@@ -0,0 +1,508 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
123
source/java/org/alfresco/repo/imap/AlfrescoImapServer.java
Executable file
123
source/java/org/alfresco/repo/imap/AlfrescoImapServer.java
Executable file
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.alfresco.util.AbstractLifecycleBean;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
import com.icegreen.greenmail.Managers;
|
||||||
|
import com.icegreen.greenmail.imap.ImapHostManager;
|
||||||
|
import com.icegreen.greenmail.imap.ImapServer;
|
||||||
|
import com.icegreen.greenmail.user.UserManager;
|
||||||
|
import com.icegreen.greenmail.util.ServerSetup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Mike Shavnev
|
||||||
|
*/
|
||||||
|
public class AlfrescoImapServer extends AbstractLifecycleBean
|
||||||
|
{
|
||||||
|
|
||||||
|
private static Log logger = LogFactory.getLog(AlfrescoImapServer.class);
|
||||||
|
|
||||||
|
private ImapServer serverImpl;
|
||||||
|
|
||||||
|
private int port = 143;
|
||||||
|
|
||||||
|
private ImapHostManager imapHostManager;
|
||||||
|
|
||||||
|
private UserManager imapUserManager;
|
||||||
|
|
||||||
|
private boolean imapServerEnabled;
|
||||||
|
|
||||||
|
private ImapHelper imapHelper;
|
||||||
|
|
||||||
|
public void setImapServerEnabled(boolean imapServerEnabled)
|
||||||
|
{
|
||||||
|
this.imapServerEnabled = imapServerEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(int port)
|
||||||
|
{
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImapHostManager(ImapHostManager imapHostManager)
|
||||||
|
{
|
||||||
|
this.imapHostManager = imapHostManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImapUserManager(UserManager imapUserManager)
|
||||||
|
{
|
||||||
|
this.imapUserManager = imapUserManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImapHelper(ImapHelper imapHelper)
|
||||||
|
{
|
||||||
|
this.imapHelper = imapHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onBootstrap(ApplicationEvent event)
|
||||||
|
{
|
||||||
|
if (imapServerEnabled && imapHelper.isPatchApplied())
|
||||||
|
{
|
||||||
|
Managers imapManagers = new Managers()
|
||||||
|
{
|
||||||
|
public ImapHostManager getImapHostManager()
|
||||||
|
{
|
||||||
|
return imapHostManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserManager getUserManager()
|
||||||
|
{
|
||||||
|
return imapUserManager;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
serverImpl = new ImapServer(new ServerSetup(port, null, ServerSetup.PROTOCOL_IMAP), imapManagers);
|
||||||
|
serverImpl.startService(null);
|
||||||
|
if (logger.isInfoEnabled())
|
||||||
|
{
|
||||||
|
logger.info("IMAP service started on port " + this.port + ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("IMAP service is disabled.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onShutdown(ApplicationEvent event)
|
||||||
|
{
|
||||||
|
if (serverImpl != null)
|
||||||
|
{
|
||||||
|
serverImpl.stopService(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
107
source/java/org/alfresco/repo/imap/AlfrescoImapUser.java
Executable file
107
source/java/org/alfresco/repo/imap/AlfrescoImapUser.java
Executable file
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* 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 javax.mail.internet.MimeMessage;
|
||||||
|
|
||||||
|
import com.icegreen.greenmail.imap.ImapHostManager;
|
||||||
|
import com.icegreen.greenmail.mail.MovingMessage;
|
||||||
|
import com.icegreen.greenmail.user.GreenMailUser;
|
||||||
|
import com.icegreen.greenmail.user.UserException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alfresco implementation of the GreenMailUser interface.
|
||||||
|
*
|
||||||
|
* @author Arseny Kovalchuk
|
||||||
|
*/
|
||||||
|
public class AlfrescoImapUser implements GreenMailUser
|
||||||
|
{
|
||||||
|
private String userName;
|
||||||
|
private char[] password;
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
private ImapHostManager imapHostManager;
|
||||||
|
|
||||||
|
public AlfrescoImapUser(String email, String login, String password, ImapHostManager imapHostManager)
|
||||||
|
{
|
||||||
|
this.email = email;
|
||||||
|
this.userName = login;
|
||||||
|
this.password = password.toCharArray();
|
||||||
|
this.imapHostManager = imapHostManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void authenticate(String password) throws UserException
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
// This method is used in the POP3 greenmail implementation, so it is disabled for IMAP
|
||||||
|
// See AlfrescoImapUserManager.test() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public void create() throws UserException
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() throws UserException
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deliver(MovingMessage msg) throws UserException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deliver(MimeMessage msg) throws UserException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail()
|
||||||
|
{
|
||||||
|
return this.email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLogin()
|
||||||
|
{
|
||||||
|
return this.userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword()
|
||||||
|
{
|
||||||
|
return new String(this.password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQualifiedMailboxName()
|
||||||
|
{
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password)
|
||||||
|
{
|
||||||
|
this.password = password.toCharArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
168
source/java/org/alfresco/repo/imap/AlfrescoImapUserManager.java
Executable file
168
source/java/org/alfresco/repo/imap/AlfrescoImapUserManager.java
Executable file
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* 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.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.repo.security.authentication.AuthenticationException;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
|
import org.alfresco.service.cmr.security.AuthenticationService;
|
||||||
|
import org.alfresco.service.cmr.security.PersonService;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import com.icegreen.greenmail.imap.ImapHostManager;
|
||||||
|
import com.icegreen.greenmail.user.GreenMailUser;
|
||||||
|
import com.icegreen.greenmail.user.UserException;
|
||||||
|
import com.icegreen.greenmail.user.UserManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Arseny Kovalchuk
|
||||||
|
*/
|
||||||
|
public class AlfrescoImapUserManager extends UserManager
|
||||||
|
{
|
||||||
|
private Log logger = LogFactory.getLog(AlfrescoImapUserManager.class);
|
||||||
|
|
||||||
|
protected Map<String, GreenMailUser> userMap = Collections.synchronizedMap(new HashMap<String, GreenMailUser>());
|
||||||
|
protected ImapHostManager imapHostManager;
|
||||||
|
|
||||||
|
protected AuthenticationService authenticationService;
|
||||||
|
protected PersonService personService;
|
||||||
|
protected NodeService nodeService;
|
||||||
|
|
||||||
|
public AlfrescoImapUserManager()
|
||||||
|
{
|
||||||
|
super(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlfrescoImapUserManager(ImapHostManager imapHostManager)
|
||||||
|
{
|
||||||
|
this();
|
||||||
|
this.imapHostManager = imapHostManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GreenMailUser createUser(String email, String login, String password) throws UserException
|
||||||
|
{
|
||||||
|
// TODO: User creation/addition code should be implemented here (in the AlfrescoImapUserManager).
|
||||||
|
// Following code is not need and not used in the current implementation.
|
||||||
|
GreenMailUser user = new AlfrescoImapUser(email, login, password, imapHostManager);
|
||||||
|
user.create();
|
||||||
|
addUser(user);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addUser(GreenMailUser user)
|
||||||
|
{
|
||||||
|
userMap.put(user.getLogin(), user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GreenMailUser getUser(String login)
|
||||||
|
{
|
||||||
|
return (GreenMailUser) userMap.get(login);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GreenMailUser getUserByEmail(String email)
|
||||||
|
{
|
||||||
|
GreenMailUser ret = getUser(email);
|
||||||
|
if (null == ret)
|
||||||
|
{
|
||||||
|
for (GreenMailUser user : userMap.values())
|
||||||
|
{
|
||||||
|
// TODO: NPE!
|
||||||
|
if (user.getEmail().trim().equalsIgnoreCase(email.trim()))
|
||||||
|
{
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteUser(GreenMailUser user) throws UserException
|
||||||
|
{
|
||||||
|
user = (GreenMailUser) userMap.remove(user.getLogin());
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
user.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The login method.
|
||||||
|
*
|
||||||
|
* @see com.icegreen.greenmail.imap.commands.LoginCommand#doProcess()
|
||||||
|
*/
|
||||||
|
public boolean test(String userid, String password)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
authenticationService.authenticate(userid, password.toCharArray());
|
||||||
|
String email = null;
|
||||||
|
if (personService.personExists(userid))
|
||||||
|
{
|
||||||
|
NodeRef personNodeRef = personService.getPerson(userid);
|
||||||
|
email = (String) nodeService.getProperty(personNodeRef, ContentModel.PROP_EMAIL);
|
||||||
|
}
|
||||||
|
GreenMailUser user = new AlfrescoImapUser(email, userid, password, imapHostManager);
|
||||||
|
addUser(user);
|
||||||
|
}
|
||||||
|
catch (AuthenticationException ex)
|
||||||
|
{
|
||||||
|
logger.error("IMAP authentication failed for userid: " + userid);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImapHostManager getImapHostManager()
|
||||||
|
{
|
||||||
|
return this.imapHostManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImapHostManager(ImapHostManager imapHostManager)
|
||||||
|
{
|
||||||
|
this.imapHostManager = imapHostManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthenticationService(AuthenticationService authenticationService)
|
||||||
|
{
|
||||||
|
this.authenticationService = authenticationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPersonService(PersonService personService)
|
||||||
|
{
|
||||||
|
this.personService = personService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNodeService(NodeService nodeService)
|
||||||
|
{
|
||||||
|
this.nodeService = nodeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
980
source/java/org/alfresco/repo/imap/ImapHelper.java
Executable file
980
source/java/org/alfresco/repo/imap/ImapHelper.java
Executable file
@@ -0,0 +1,980 @@
|
|||||||
|
/*
|
||||||
|
* 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.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.mail.Flags;
|
||||||
|
import javax.mail.Flags.Flag;
|
||||||
|
|
||||||
|
import org.alfresco.config.Config;
|
||||||
|
import org.alfresco.config.ConfigService;
|
||||||
|
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.ImapConfigElement;
|
||||||
|
import org.alfresco.repo.imap.config.ImapConfigElement.ImapConfig;
|
||||||
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
|
import org.alfresco.service.cmr.site.SiteInfo;
|
||||||
|
import org.alfresco.service.cmr.site.SiteService;
|
||||||
|
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.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
|
||||||
|
*/
|
||||||
|
public 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 ConfigService configService;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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, ImapConfig> imapConfigs = getImapConfigs();
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
public NodeRef getUserImapHomeRef(String userName)
|
||||||
|
{
|
||||||
|
return fileFolderService.searchSimple(imapRootNodeRef, userName);
|
||||||
|
}
|
||||||
|
|
||||||
|
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, ImapConfig> imapConfigs = getImapConfigs();
|
||||||
|
Map<String, NodeRef> mountPoints = new HashMap<String, NodeRef>();
|
||||||
|
|
||||||
|
for (ImapConfig 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return map of imap configs. Name of config == key in the map
|
||||||
|
*
|
||||||
|
* @return map of imap configs.
|
||||||
|
*/
|
||||||
|
public Map<String, ImapConfig> getImapConfigs()
|
||||||
|
{
|
||||||
|
Config imapConfig = configService.getConfig("imapConfig");
|
||||||
|
ImapConfigElement imapConfigElement = (ImapConfigElement) imapConfig.getConfigElement(ImapConfigElement.CONFIG_ELEMENT_ID);
|
||||||
|
return imapConfigElement.getImapConfigs();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, ImapConfig> imapConfigs = getImapConfigs();
|
||||||
|
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, ImapConfig> imapConfigs = getImapConfigs();
|
||||||
|
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, ImapConfig> imapConfigs = getImapConfigs();
|
||||||
|
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 ConfigService getConfigService()
|
||||||
|
{
|
||||||
|
return configService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfigService(ConfigService configService)
|
||||||
|
{
|
||||||
|
this.configService = configService;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
143
source/java/org/alfresco/repo/imap/config/ImapConfigElement.java
Executable file
143
source/java/org/alfresco/repo/imap/config/ImapConfigElement.java
Executable file
@@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* 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.config;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.config.ConfigElement;
|
||||||
|
import org.alfresco.config.element.ConfigElementAdapter;
|
||||||
|
|
||||||
|
public class ImapConfigElement extends ConfigElementAdapter
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = -6911139959296875159L;
|
||||||
|
|
||||||
|
public static final String CONFIG_ELEMENT_ID = "imapConfig";
|
||||||
|
|
||||||
|
private Map<String, ImapConfig> imapConfigs = new LinkedHashMap<String, ImapConfig>(8, 10f);
|
||||||
|
|
||||||
|
public ImapConfigElement()
|
||||||
|
{
|
||||||
|
super(CONFIG_ELEMENT_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImapConfigElement(String name)
|
||||||
|
{
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigElement combine(ConfigElement configElement)
|
||||||
|
{
|
||||||
|
ImapConfigElement combined = new ImapConfigElement();
|
||||||
|
|
||||||
|
// add all the imapConfigs from this element
|
||||||
|
for (ImapConfig imapConfig : getImapConfigs().values())
|
||||||
|
{
|
||||||
|
combined.addImapConfig(imapConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add all the imapConfigs from the given element
|
||||||
|
for (ImapConfig imapConfig : ((ImapConfigElement) configElement).getImapConfigs().values())
|
||||||
|
{
|
||||||
|
combined.addImapConfig(imapConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
return combined;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, ImapConfig> getImapConfigs()
|
||||||
|
{
|
||||||
|
return imapConfigs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImapConfig getImapConfig(String name)
|
||||||
|
{
|
||||||
|
return imapConfigs.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addImapConfig(ImapConfig imapConfig)
|
||||||
|
{
|
||||||
|
imapConfigs.put(imapConfig.getName(), imapConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ImapConfig implements Serializable
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 424330549937129149L;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String mode;
|
||||||
|
private String store;
|
||||||
|
private String rootPath;
|
||||||
|
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMode()
|
||||||
|
{
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMode(String mode)
|
||||||
|
{
|
||||||
|
this.mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStore()
|
||||||
|
{
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStore(String store)
|
||||||
|
{
|
||||||
|
this.store = store;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRootPath()
|
||||||
|
{
|
||||||
|
return rootPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRootPath(String rootPath)
|
||||||
|
{
|
||||||
|
this.rootPath = rootPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getSerialVersionUID()
|
||||||
|
{
|
||||||
|
return serialVersionUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
81
source/java/org/alfresco/repo/imap/config/ImapElementReader.java
Executable file
81
source/java/org/alfresco/repo/imap/config/ImapElementReader.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.repo.imap.config;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.alfresco.config.ConfigElement;
|
||||||
|
import org.alfresco.config.ConfigException;
|
||||||
|
import org.alfresco.config.xml.elementreader.ConfigElementReader;
|
||||||
|
import org.alfresco.repo.imap.config.ImapConfigElement.ImapConfig;
|
||||||
|
import org.dom4j.Element;
|
||||||
|
|
||||||
|
public class ImapElementReader implements ConfigElementReader
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final String ELEMENT_IMAP_CONFIG = "imapConfig";
|
||||||
|
private static final String ELEMENT_IMAP = "imap";
|
||||||
|
private static final String ELEMENT_STORE = "store";
|
||||||
|
private static final String ELEMENT_ROOTPATH = "rootPath";
|
||||||
|
|
||||||
|
private static final String ATTR_NAME = "name";
|
||||||
|
private static final String ATTR_MODE = "mode";
|
||||||
|
|
||||||
|
public ConfigElement parse(Element element)
|
||||||
|
{
|
||||||
|
ImapConfigElement configElement = null;
|
||||||
|
|
||||||
|
if (element != null)
|
||||||
|
{
|
||||||
|
String elementName = element.getName();
|
||||||
|
if (elementName.equals(ELEMENT_IMAP_CONFIG) == false)
|
||||||
|
{
|
||||||
|
throw new ConfigException("ImapElementReader can parse '" + ELEMENT_IMAP_CONFIG + "' elements only, the element passed is '" + elementName + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
configElement = new ImapConfigElement();
|
||||||
|
|
||||||
|
for (Iterator<Element> items = element.elementIterator(ELEMENT_IMAP); items.hasNext();)
|
||||||
|
{
|
||||||
|
Element item = items.next();
|
||||||
|
|
||||||
|
String name = item.attributeValue(ATTR_NAME);
|
||||||
|
String mode = item.attributeValue(ATTR_MODE);
|
||||||
|
String store = item.element(ELEMENT_STORE).getStringValue();
|
||||||
|
String rootPath = item.element(ELEMENT_ROOTPATH).getStringValue();
|
||||||
|
|
||||||
|
ImapConfig imapConfig = new ImapConfig();
|
||||||
|
imapConfig.setName(name);
|
||||||
|
imapConfig.setMode(mode);
|
||||||
|
imapConfig.setStore(store);
|
||||||
|
imapConfig.setRootPath(rootPath);
|
||||||
|
|
||||||
|
configElement.addImapConfig(imapConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return configElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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.exception;
|
||||||
|
|
||||||
|
import com.icegreen.greenmail.store.FolderException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown on an inappropriate attempt to modify a folder.
|
||||||
|
*
|
||||||
|
* @author Ivan Rybnikov
|
||||||
|
*/
|
||||||
|
public class AlfrescoImapFolderException extends FolderException
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -2721708848846740336L;
|
||||||
|
|
||||||
|
public final static String PERMISSION_DENIED = "Can't create folder - Permission denied";
|
||||||
|
|
||||||
|
public AlfrescoImapFolderException(String message)
|
||||||
|
{
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -48,6 +48,8 @@ import org.dom4j.io.SAXReader;
|
|||||||
import org.mozilla.javascript.Context;
|
import org.mozilla.javascript.Context;
|
||||||
import org.mozilla.javascript.Scriptable;
|
import org.mozilla.javascript.Scriptable;
|
||||||
|
|
||||||
|
import com.werken.saxpath.XPathReader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search component for use by the ScriptService.
|
* Search component for use by the ScriptService.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -215,6 +217,26 @@ public final class Search extends BaseScopableProcessorExtension
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validation Xpath query
|
||||||
|
*
|
||||||
|
* @param query xpath query
|
||||||
|
* @return true if xpath query valid
|
||||||
|
*/
|
||||||
|
public boolean isValidXpathQuery(String query)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
XPathReader reader = new XPathReader();
|
||||||
|
reader.parse(query);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a Lucene search
|
* Execute a Lucene search
|
||||||
*
|
*
|
||||||
|
Reference in New Issue
Block a user