Merge branch 'webapp22' into 'master'
Version 2.2.0 RC1 Release Candidate 1 of 2.2.0 version. See changelog for changes... See merge request !1
This commit is contained in:
commit
187b2a60f2
8
.idea/calendarimporter.iml
Normal file
8
.idea/calendarimporter.iml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
3
.idea/copyright/profiles_settings.xml
Normal file
3
.idea/copyright/profiles_settings.xml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<component name="CopyrightManager">
|
||||||
|
<settings default="" />
|
||||||
|
</component>
|
4
.idea/encodings.xml
Normal file
4
.idea/encodings.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
|
||||||
|
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/calendarimporter.iml" filepath="$PROJECT_DIR$/.idea/calendarimporter.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
4
.idea/php.xml
Normal file
4
.idea/php.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="PhpProjectSharedConfiguration" php_language_level="5.5.0" />
|
||||||
|
</project>
|
5
.idea/scopes/scope_settings.xml
Normal file
5
.idea/scopes/scope_settings.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<component name="DependencyValidationManager">
|
||||||
|
<state>
|
||||||
|
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
|
||||||
|
</state>
|
||||||
|
</component>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
677
.idea/workspace.xml
Normal file
677
.idea/workspace.xml
Normal file
@ -0,0 +1,677 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<list default="true" id="e7c9c2bb-66f1-4e37-904c-d33d8c113bde" name="Default" comment="">
|
||||||
|
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/changelog.txt" afterPath="$PROJECT_DIR$/changelog.txt" />
|
||||||
|
</list>
|
||||||
|
<ignored path="calendarimporter.iws" />
|
||||||
|
<ignored path=".idea/workspace.xml" />
|
||||||
|
<ignored path=".idea/dataSources.local.xml" />
|
||||||
|
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||||
|
<option name="TRACKING_ENABLED" value="true" />
|
||||||
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
|
</component>
|
||||||
|
<component name="CreatePatchCommitExecutor">
|
||||||
|
<option name="PATCH_PATH" value="" />
|
||||||
|
</component>
|
||||||
|
<component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
|
||||||
|
<component name="FavoritesManager">
|
||||||
|
<favorites_list name="calendarimporter" />
|
||||||
|
</component>
|
||||||
|
<component name="FileEditorManager">
|
||||||
|
<leaf>
|
||||||
|
<file leaf-file-name="CalSyncEditPanel.js" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/js/settings/dialogs/CalSyncEditPanel.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="1480">
|
||||||
|
<caret line="101" column="30" selection-start-line="101" selection-start-column="30" selection-end-line="101" selection-end-column="30" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="CalSyncGrid.js" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/js/settings/ui/CalSyncGrid.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="504">
|
||||||
|
<caret line="85" column="59" selection-start-line="85" selection-start-column="59" selection-end-line="85" selection-end-column="59" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="SettingsCalSyncWidget.js" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/js/settings/SettingsCalSyncWidget.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="729">
|
||||||
|
<caret line="104" column="16" selection-start-line="104" selection-start-column="16" selection-end-line="104" selection-end-column="142" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="sync.php" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/backend/sync.php">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="360">
|
||||||
|
<caret line="24" column="47" selection-start-line="24" selection-start-column="47" selection-end-line="24" selection-end-column="47" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#21#926#0#PHP" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="changelog.txt" pinned="false" current-in-tab="true">
|
||||||
|
<entry file="file://$PROJECT_DIR$/changelog.txt">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="75">
|
||||||
|
<caret line="5" column="19" selection-start-line="5" selection-start-column="19" selection-end-line="5" selection-end-column="19" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="manifest.xml" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/manifest.xml">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="functions.php" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/backend/functions.php">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="75">
|
||||||
|
<caret line="5" column="26" selection-start-line="5" selection-start-column="26" selection-end-line="5" selection-end-column="26" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="README.txt" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/backend/README.txt">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="config.php" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/backend/config.php">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="CalSyncEditContentPanel.js" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/js/settings/dialogs/CalSyncEditContentPanel.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="63" selection-start-line="0" selection-start-column="63" selection-end-line="0" selection-end-column="63" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
</leaf>
|
||||||
|
</component>
|
||||||
|
<component name="FileTemplateManagerImpl">
|
||||||
|
<option name="RECENT_TEMPLATES">
|
||||||
|
<list>
|
||||||
|
<option value="JavaScript File" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="Git.Settings">
|
||||||
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
|
<component name="IdeDocumentHistory">
|
||||||
|
<option name="CHANGED_PATHS">
|
||||||
|
<list>
|
||||||
|
<option value="$PROJECT_DIR$/php/plugin.calendarimporter.php" />
|
||||||
|
<option value="$PROJECT_DIR$/config.php" />
|
||||||
|
<option value="$PROJECT_DIR$/js/plugin.calendarimporter.js" />
|
||||||
|
<option value="$PROJECT_DIR$/php/module.calendar.php" />
|
||||||
|
<option value="$PROJECT_DIR$/js/data/CalendarHelper.js" />
|
||||||
|
<option value="$PROJECT_DIR$/js/data/Actions.js" />
|
||||||
|
<option value="$PROJECT_DIR$/js/dialogs/ImportPanel.js" />
|
||||||
|
<option value="$PROJECT_DIR$/js/settings/dialogs/CalSyncEditContentPanel.js" />
|
||||||
|
<option value="$PROJECT_DIR$/js/settings/SettingsWidget.js" />
|
||||||
|
<option value="$PROJECT_DIR$/js/settings/SettingsCalSyncWidget.js" />
|
||||||
|
<option value="$PROJECT_DIR$/js/settings/ui/CalSyncGrid.js" />
|
||||||
|
<option value="$PROJECT_DIR$/js/settings/dialogs/CalSyncEditPanel.js" />
|
||||||
|
<option value="$PROJECT_DIR$/backend/sync.php" />
|
||||||
|
<option value="$PROJECT_DIR$/backend/functions.php" />
|
||||||
|
<option value="$PROJECT_DIR$/changelog.txt" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||||
|
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||||
|
<component name="JsGulpfileManager">
|
||||||
|
<detection-done>true</detection-done>
|
||||||
|
<sorting>DEFINITION_ORDER</sorting>
|
||||||
|
</component>
|
||||||
|
<component name="PhpWorkspaceProjectConfiguration" backward_compatibility_performed="true" />
|
||||||
|
<component name="ProjectFrameBounds">
|
||||||
|
<option name="x" value="65" />
|
||||||
|
<option name="y" value="24" />
|
||||||
|
<option name="width" value="1792" />
|
||||||
|
<option name="height" value="999" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||||
|
<OptionsSetting value="true" id="Add" />
|
||||||
|
<OptionsSetting value="true" id="Remove" />
|
||||||
|
<OptionsSetting value="true" id="Checkout" />
|
||||||
|
<OptionsSetting value="true" id="Update" />
|
||||||
|
<OptionsSetting value="true" id="Status" />
|
||||||
|
<OptionsSetting value="true" id="Edit" />
|
||||||
|
<ConfirmationsSetting value="0" id="Add" />
|
||||||
|
<ConfirmationsSetting value="0" id="Remove" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectView">
|
||||||
|
<navigator currentView="ProjectPane" proportions="" version="1">
|
||||||
|
<flattenPackages />
|
||||||
|
<showMembers />
|
||||||
|
<showModules />
|
||||||
|
<showLibraryContents />
|
||||||
|
<hideEmptyPackages />
|
||||||
|
<abbreviatePackageNames />
|
||||||
|
<autoscrollToSource />
|
||||||
|
<autoscrollFromSource />
|
||||||
|
<sortByType />
|
||||||
|
<manualOrder />
|
||||||
|
<foldersAlwaysOnTop value="true" />
|
||||||
|
</navigator>
|
||||||
|
<panes>
|
||||||
|
<pane id="Scratches" />
|
||||||
|
<pane id="ProjectPane">
|
||||||
|
<subPane>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="js" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="js" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="ui" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="js" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="settings" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="js" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="settings" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="ui" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="js" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="settings" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="dialogs" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="js" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="dialogs" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="js" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="data" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="calendarimporter" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="backend" />
|
||||||
|
<option name="myItemType" value="com.jetbrains.php.projectView.PhpTreeStructureProvider$1" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
</subPane>
|
||||||
|
</pane>
|
||||||
|
<pane id="Scope" />
|
||||||
|
</panes>
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent">
|
||||||
|
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
||||||
|
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||||
|
<property name="js-jscs-nodeInterpreter" value="/usr/bin/node" />
|
||||||
|
</component>
|
||||||
|
<component name="RunManager">
|
||||||
|
<configuration default="true" type="JavascriptDebugType" factoryName="JavaScript Debug">
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="NodeJSConfigurationType" factoryName="Node.js" path-to-node="project" working-dir="">
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="PHPUnitRunConfigurationType" factoryName="PHPUnit">
|
||||||
|
<TestRunner />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="PhpBehatConfigurationType" factoryName="Behat">
|
||||||
|
<BehatRunner />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="PhpLocalRunConfigurationType" factoryName="PHP Console">
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="js.build_tools.gulp" factoryName="Gulp.js">
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="js.build_tools.npm" factoryName="npm">
|
||||||
|
<command value="run-script" />
|
||||||
|
<scripts />
|
||||||
|
<node-interpreter value="project" />
|
||||||
|
<envs />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="mocha-javascript-test-runner" factoryName="Mocha">
|
||||||
|
<node-interpreter>project</node-interpreter>
|
||||||
|
<node-options />
|
||||||
|
<working-directory />
|
||||||
|
<pass-parent-env>true</pass-parent-env>
|
||||||
|
<envs />
|
||||||
|
<ui />
|
||||||
|
<extra-mocha-options />
|
||||||
|
<test-kind>DIRECTORY</test-kind>
|
||||||
|
<test-directory />
|
||||||
|
<recursive>false</recursive>
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
|
<component name="ShelveChangesManager" show_recycled="false">
|
||||||
|
<option name="remove_strategy" value="false" />
|
||||||
|
</component>
|
||||||
|
<component name="TaskManager">
|
||||||
|
<task active="true" id="Default" summary="Default task">
|
||||||
|
<changelist id="e7c9c2bb-66f1-4e37-904c-d33d8c113bde" name="Default" comment="" />
|
||||||
|
<created>1477949602474</created>
|
||||||
|
<option name="number" value="Default" />
|
||||||
|
<option name="presentableId" value="Default" />
|
||||||
|
<updated>1477949602474</updated>
|
||||||
|
<workItem from="1477949603566" duration="8606000" />
|
||||||
|
</task>
|
||||||
|
<servers />
|
||||||
|
</component>
|
||||||
|
<component name="TimeTrackingManager">
|
||||||
|
<option name="totallyTimeSpent" value="8606000" />
|
||||||
|
</component>
|
||||||
|
<component name="ToolWindowManager">
|
||||||
|
<frame x="65" y="24" width="1792" height="999" extended-state="6" />
|
||||||
|
<editor active="true" />
|
||||||
|
<layout>
|
||||||
|
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
|
||||||
|
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
|
||||||
|
<window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32900432" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32900432" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
|
||||||
|
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
|
||||||
|
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||||
|
</layout>
|
||||||
|
</component>
|
||||||
|
<component name="Vcs.Log.UiProperties">
|
||||||
|
<option name="RECENTLY_FILTERED_USER_GROUPS">
|
||||||
|
<collection />
|
||||||
|
</option>
|
||||||
|
<option name="RECENTLY_FILTERED_BRANCH_GROUPS">
|
||||||
|
<collection />
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="VcsContentAnnotationSettings">
|
||||||
|
<option name="myLimit" value="2678400000" />
|
||||||
|
</component>
|
||||||
|
<component name="XDebuggerManager">
|
||||||
|
<breakpoint-manager>
|
||||||
|
<option name="time" value="1" />
|
||||||
|
</breakpoint-manager>
|
||||||
|
<watches-manager />
|
||||||
|
</component>
|
||||||
|
<component name="editorHistoryManager">
|
||||||
|
<entry file="file://$PROJECT_DIR$/Makefile">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/php/composer.json">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/php/upload.php">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/js/data/ResponseHandler.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="-456">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<element signature="n#!!doc" expanded="false" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/php/module.calendar.php">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="1057">
|
||||||
|
<caret line="467" column="64" selection-start-line="467" selection-start-column="64" selection-end-line="467" selection-end-column="64" />
|
||||||
|
<folding>
|
||||||
|
<element signature="n#__construct#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||||
|
<element signature="n#execute#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||||
|
<element signature="n#randomstring#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||||
|
<element signature="n#getDurationStringFromMintues#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||||
|
<element signature="n#exportCalendar#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||||
|
<element signature="n#importCalendar#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||||
|
<element signature="n#getAttachmentPath#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||||
|
<element signature="n#loadCalendar#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||||
|
<element signature="n#parseCalendarToArray#0;n#CalendarModule#0;n#!!top" expanded="false" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/config.php">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="60">
|
||||||
|
<caret line="4" column="60" selection-start-line="4" selection-start-column="12" selection-end-line="4" selection-end-column="60" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/php/plugin.calendarimporter.php">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="569">
|
||||||
|
<caret line="82" column="40" selection-start-line="82" selection-start-column="29" selection-end-line="82" selection-end-column="40" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/js/dialogs/ImportContentPanel.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="-171">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<element signature="n#!!doc" expanded="false" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/js/data/CalendarHelper.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/js/dialogs/ImportPanel.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="332">
|
||||||
|
<caret line="245" column="12" selection-start-line="245" selection-start-column="12" selection-end-line="245" selection-end-column="226" />
|
||||||
|
<folding>
|
||||||
|
<element signature="n#!!doc" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/js/data/Actions.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="144">
|
||||||
|
<caret line="133" column="67" selection-start-line="133" selection-start-column="22" selection-end-line="133" selection-end-column="67" />
|
||||||
|
<folding>
|
||||||
|
<element signature="n#!!doc" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/js/settings/SettingsWidget.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="340">
|
||||||
|
<caret line="83" column="82" selection-start-line="83" selection-start-column="82" selection-end-line="83" selection-end-column="82" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/js/plugin.calendarimporter.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="-51">
|
||||||
|
<caret line="262" column="12" selection-start-line="262" selection-start-column="12" selection-end-line="262" selection-end-column="12" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/js/settings/ui/CalSyncGrid.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="504">
|
||||||
|
<caret line="85" column="59" selection-start-line="85" selection-start-column="59" selection-end-line="85" selection-end-column="59" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/js/settings/SettingsCalSyncWidget.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="729">
|
||||||
|
<caret line="104" column="16" selection-start-line="104" selection-start-column="16" selection-end-line="104" selection-end-column="142" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/js/settings/dialogs/CalSyncEditContentPanel.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="63" selection-start-line="0" selection-start-column="63" selection-end-line="0" selection-end-column="63" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/js/settings/dialogs/CalSyncEditPanel.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="1480">
|
||||||
|
<caret line="101" column="30" selection-start-line="101" selection-start-column="30" selection-end-line="101" selection-end-column="30" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/backend/functions.php">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="75">
|
||||||
|
<caret line="5" column="26" selection-start-line="5" selection-start-column="26" selection-end-line="5" selection-end-column="26" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/backend/config.php">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/backend/README.txt">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/backend/sync.php">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="360">
|
||||||
|
<caret line="24" column="47" selection-start-line="24" selection-start-column="47" selection-end-line="24" selection-end-column="47" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#21#926#0#PHP" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/manifest.xml">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/changelog.txt">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="75">
|
||||||
|
<caret line="5" column="19" selection-start-line="5" selection-start-column="19" selection-end-line="5" selection-end-column="19" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</component>
|
||||||
|
</project>
|
2
Makefile
Normal file
2
Makefile
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
default:
|
||||||
|
ant deploy; cp -r /home/osboxes/Documents/kopano-webapp-3.2.0.285/deploy/plugins/calendarimporter /usr/share/kopano-webapp/plugins/
|
@ -3,7 +3,7 @@
|
|||||||
* functions.php, zarafa calender to ics im/exporter backend
|
* functions.php, zarafa calender to ics im/exporter backend
|
||||||
*
|
*
|
||||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||||
* Copyright (C) 2012-2014 Christoph Haas
|
* Copyright (C) 2012-2016 Christoph Haas
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* sync.php, zarafa calender to ics im/exporter backend
|
* sync.php, zarafa calender to ics im/exporter backend
|
||||||
*
|
*
|
||||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||||
* Copyright (C) 2012-2014 Christoph Haas
|
* Copyright (C) 2012-2016 Christoph Haas
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@ -129,7 +129,7 @@ foreach($userList as $userName => $userData) {
|
|||||||
if($icsData != NULL) {
|
if($icsData != NULL) {
|
||||||
file_put_contents($tmpFilename, $icsData);
|
file_put_contents($tmpFilename, $icsData);
|
||||||
echo "Got valid data for " . $syncItem["icsurl"] . " stored in " . $tmpFilename . "\n";
|
echo "Got valid data for " . $syncItem["icsurl"] . " stored in " . $tmpFilename . "\n";
|
||||||
$result = upload_ics_to_caldav($tmpFilename, $CALDAVURL, $userName, $syncItem["calendar"], $ADMINUSERNAME, $ADMINPASSWORD);
|
$result = upload_ics_to_caldav($tmpFilename, $CALDAVURL, $userName, $syncItem["calendarname"], $ADMINUSERNAME, $ADMINPASSWORD);
|
||||||
if(intval($result) == 200) {
|
if(intval($result) == 200) {
|
||||||
echo "Import completed: $result\n";
|
echo "Import completed: $result\n";
|
||||||
$result = update_last_sync_date($userStore, $syncItemName);
|
$result = update_last_sync_date($userStore, $syncItemName);
|
||||||
|
206
build.xml
206
build.xml
@ -1,18 +1,15 @@
|
|||||||
<project default="all">
|
<project default="all">
|
||||||
<!--############# CONFIGURE ALL PROPERTIES FOR THE REPLACER HERE ################-->
|
<property environment="env"/>
|
||||||
<property name="plugin_version" value="2.1.0"/>
|
<property name="root-folder" value="${basedir}/../../"/>
|
||||||
<!-- EOC -->
|
<property name="tools-folder" value="${root-folder}/tools/"/>
|
||||||
|
<property name="target-folder" value="${root-folder}/deploy/plugins"/>
|
||||||
<property name="root-folder" value="${basedir}/../"/>
|
<property name="server-folder" value="${root-folder}/server"/>
|
||||||
<property name="tools-folder" value="${root-folder}/TOOLS/"/>
|
|
||||||
<property name="target-folder" value="${root-folder}/DEPLOY/plugins"/>
|
|
||||||
|
|
||||||
<import file="${tools-folder}/antutil.xml"/>
|
<import file="${tools-folder}/antutil.xml"/>
|
||||||
|
|
||||||
<typedef file="${tools-folder}/antlib.xml">
|
<typedef file="${tools-folder}/antlib.xml">
|
||||||
<classpath>
|
<classpath>
|
||||||
<pathelement location="${tools-folder}/tools.jar"/>
|
<pathelement location="${tools-folder}/tools.jar"/>
|
||||||
<pathelement location="${tools-folder}/lib/compiler.jar"/>
|
|
||||||
</classpath>
|
</classpath>
|
||||||
</typedef>
|
</typedef>
|
||||||
|
|
||||||
@ -22,29 +19,7 @@
|
|||||||
</classpath>
|
</classpath>
|
||||||
</taskdef>
|
</taskdef>
|
||||||
|
|
||||||
<!-- os checks for xmllint... -->
|
|
||||||
<condition property="isWindows" value="true">
|
|
||||||
<os family="windows" />
|
|
||||||
</condition>
|
|
||||||
|
|
||||||
<!-- define nicknames for libraries -->
|
|
||||||
<property name="yui-compressor" location="${tools-folder}/lib/yuicompressor-2.4.2.jar" />
|
|
||||||
<property name="yui-compressor-ant-task" location="${tools-folder}/lib/yui-compressor-ant-task-0.5.jar" />
|
|
||||||
|
|
||||||
<!-- adds libraries to the classpath -->
|
|
||||||
<path id="yui.classpath">
|
|
||||||
<pathelement location="${yui-compressor}" />
|
|
||||||
<pathelement location="${yui-compressor-ant-task}" />
|
|
||||||
</path>
|
|
||||||
|
|
||||||
<!-- define tasks -->
|
|
||||||
<taskdef name="yui-compressor" classname="net.noha.tools.ant.yuicompressor.tasks.YuiCompressorTask">
|
|
||||||
<classpath refid="yui.classpath" />
|
|
||||||
</taskdef>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Determine plugin name -->
|
<!-- Determine plugin name -->
|
||||||
<var name="plugin" unset="true"/>
|
|
||||||
<basename file="${basedir}" property="plugin"/>
|
<basename file="${basedir}" property="plugin"/>
|
||||||
|
|
||||||
<!-- The Plugin distribution files -->
|
<!-- The Plugin distribution files -->
|
||||||
@ -54,8 +29,7 @@
|
|||||||
|
|
||||||
<!-- The Plugin CSS files -->
|
<!-- The Plugin CSS files -->
|
||||||
<property name="plugin-css-folder" value="resources/css"/>
|
<property name="plugin-css-folder" value="resources/css"/>
|
||||||
<property name="plugin-css-file" value="${plugin}-min.css"/>
|
<property name="plugin-css-file" value="${plugin}.css"/>
|
||||||
<property name="plugin-css-debug-file" value="${plugin}.css"/>
|
|
||||||
|
|
||||||
<!-- Meta target -->
|
<!-- Meta target -->
|
||||||
<target name="all" depends="concat, compress"/>
|
<target name="all" depends="concat, compress"/>
|
||||||
@ -68,16 +42,6 @@
|
|||||||
<include name="${plugin-file}"/>
|
<include name="${plugin-file}"/>
|
||||||
<include name="${plugin-debugfile}"/>
|
<include name="${plugin-debugfile}"/>
|
||||||
</fileset>
|
</fileset>
|
||||||
<fileset dir="${target-folder}/${plugin-folder}/php">
|
|
||||||
<include name="**/*.php"/>
|
|
||||||
</fileset>
|
|
||||||
<fileset dir="${target-folder}/${plugin-folder}/resources">
|
|
||||||
<include name="**/*"/>
|
|
||||||
</fileset>
|
|
||||||
<fileset dir="${target-folder}/${plugin-folder}/${plugin-css-folder}">
|
|
||||||
<include name="${plugin-css-debug-file}"/>
|
|
||||||
<include name="${plugin-css-file}"/>
|
|
||||||
</fileset>
|
|
||||||
</delete>
|
</delete>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
@ -89,27 +53,11 @@
|
|||||||
<then>
|
<then>
|
||||||
<mkdir dir="${target-folder}/${plugin-folder}/js"/>
|
<mkdir dir="${target-folder}/${plugin-folder}/js"/>
|
||||||
<echo message="Concatenating: ${plugin-debugfile}"/>
|
<echo message="Concatenating: ${plugin-debugfile}"/>
|
||||||
<!-- TODO: fix JS files for zConcat -->
|
<zConcat outputFolder="${target-folder}/${plugin-folder}/js" outputFile="${plugin-debugfile}" prioritize="\w+">
|
||||||
<!--zConcat outputFolder="${target-folder}/${plugin-folder}/js" outputFile="${plugin-debugfile}" prioritize="\w+">
|
|
||||||
<concatfiles>
|
<concatfiles>
|
||||||
<fileset dir="js" includes="**/*.js" />
|
<fileset dir="js" includes="**/*.js" />
|
||||||
</concatfiles>
|
</concatfiles>
|
||||||
</zConcat-->
|
</zConcat>
|
||||||
<concat destfile="${target-folder}/${plugin-folder}/js/${plugin-debugfile}">
|
|
||||||
<fileset file="js/ABOUT.js" />
|
|
||||||
<fileset file="js/external/Ext.util.base64.js" />
|
|
||||||
<fileset file="js/data/timezones.js" />
|
|
||||||
<fileset file="js/plugin.calendarimporter.js" />
|
|
||||||
<fileset file="js/data/ResponseHandler.js" />
|
|
||||||
<fileset file="js/dialogs/ImportContentPanel.js" />
|
|
||||||
<fileset file="js/dialogs/ImportPanel.js" />
|
|
||||||
<fileset file="js/settings/SettingsWidget.js" />
|
|
||||||
<fileset file="js/settings/SettingsCalSyncWidget.js" />
|
|
||||||
<fileset file="js/settings/ui/CalSyncPanel.js" />
|
|
||||||
<fileset file="js/settings/ui/CalSyncGrid.js" />
|
|
||||||
<fileset file="js/settings/dialogs/CalSyncEditContentPanel.js" />
|
|
||||||
<fileset file="js/settings/dialogs/CalSyncEditPanel.js" />
|
|
||||||
</concat>
|
|
||||||
</then>
|
</then>
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
@ -118,8 +66,8 @@
|
|||||||
<available file="${plugin-css-folder}" type="dir" />
|
<available file="${plugin-css-folder}" type="dir" />
|
||||||
<then>
|
<then>
|
||||||
<mkdir dir="${target-folder}/${plugin-folder}/${plugin-css-folder}"/>
|
<mkdir dir="${target-folder}/${plugin-folder}/${plugin-css-folder}"/>
|
||||||
<echo message="Concatenating: ${plugin-css-debug-file}"/>
|
<echo message="Concatenating: ${plugin-css-file}"/>
|
||||||
<zConcat outputFolder="${target-folder}/${plugin-folder}/${plugin-css-folder}" outputFile="${plugin-css-debug-file}">
|
<zConcat outputFolder="${target-folder}/${plugin-folder}/${plugin-css-folder}" outputFile="${plugin-css-file}">
|
||||||
<concatfiles>
|
<concatfiles>
|
||||||
<fileset dir="${plugin-css-folder}" includes="**/*.css" />
|
<fileset dir="${plugin-css-folder}" includes="**/*.css" />
|
||||||
</concatfiles>
|
</concatfiles>
|
||||||
@ -164,15 +112,6 @@
|
|||||||
var pgettext = function(msgctxt, msgid) {};
|
var pgettext = function(msgctxt, msgid) {};
|
||||||
</externs>
|
</externs>
|
||||||
</zCompile>
|
</zCompile>
|
||||||
<!--yui-compressor
|
|
||||||
warn="false"
|
|
||||||
munge="true"
|
|
||||||
preserveallsemicolons="false"
|
|
||||||
fromdir="${target-folder}/${plugin-folder}/js"
|
|
||||||
todir="${target-folder}/${plugin-folder}/js">
|
|
||||||
|
|
||||||
<include name="${plugin-debugfile}" />
|
|
||||||
</yui-compressor-->
|
|
||||||
</then>
|
</then>
|
||||||
</if>
|
</if>
|
||||||
</target>
|
</target>
|
||||||
@ -180,105 +119,82 @@
|
|||||||
<!-- syntax check all PHP files -->
|
<!-- syntax check all PHP files -->
|
||||||
<target name="validate">
|
<target name="validate">
|
||||||
<if>
|
<if>
|
||||||
<available file="config.php" type="file" />
|
<available file="php" filepath="${env.PATH}" />
|
||||||
<then>
|
<then>
|
||||||
<antcall target="syntax-check">
|
<if>
|
||||||
<param name="file" value="config.php"/>
|
<available file="config.php" type="file" />
|
||||||
</antcall>
|
<then>
|
||||||
</then>
|
<antcall target="syntax-check">
|
||||||
</if>
|
<param name="file" value="config.php"/>
|
||||||
<if>
|
</antcall>
|
||||||
<available file="php" type="dir" />
|
</then>
|
||||||
<then>
|
</if>
|
||||||
<foreach target="syntax-check" param="file">
|
<if>
|
||||||
<path>
|
<available file="php" type="dir" />
|
||||||
<fileset dir=".">
|
<then>
|
||||||
<include name="**/*.php"/>
|
<foreach target="syntax-check" param="file">
|
||||||
</fileset>
|
<path>
|
||||||
</path>
|
<fileset dir=".">
|
||||||
</foreach>
|
<exclude name="php/vendor/**" />
|
||||||
|
<include name="**/*.php"/>
|
||||||
|
</fileset>
|
||||||
|
</path>
|
||||||
|
</foreach>
|
||||||
|
</then>
|
||||||
|
</if>
|
||||||
</then>
|
</then>
|
||||||
|
<else>
|
||||||
|
<echo message="WARNING: PHP not available, not performing syntax-check on php files"/>
|
||||||
|
</else>
|
||||||
</if>
|
</if>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="syntax-check">
|
<target name="syntax-check">
|
||||||
<echo message="validating ${file}"/>
|
<echo message="validating ${file}"/>
|
||||||
<exec executable="php" failonerror="true" failifexecutionfails="false">
|
<exec executable="php" failonerror="true">
|
||||||
<arg value="-l"/>
|
<arg value="-l"/>
|
||||||
<arg value="${file}"/>
|
<arg value="${file}"/>
|
||||||
</exec>
|
</exec>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<!-- on windows we do not check the xml file -->
|
|
||||||
<target name="xml-os-sel" depends="xml-check,xml-copy">
|
|
||||||
<echo>Processing manifest.xml</echo>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<!-- check manifest.xml if we are on windows... -->
|
|
||||||
<target name="xml-check" unless="isWindows">
|
|
||||||
<echo message="Checking xml: manifest.xml" />
|
|
||||||
<!-- Copy (and validate) manifest.xml -->
|
|
||||||
<exec executable="xmllint" output="${target-folder}/${plugin-folder}/manifest.xml" failonerror="true" error="/dev/stdout" failifexecutionfails="false">
|
|
||||||
<arg value="--valid"/>
|
|
||||||
<arg value="--path"/>
|
|
||||||
<arg value="${root-folder}/server"/>
|
|
||||||
<arg value="manifest.xml"/>
|
|
||||||
</exec>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<!-- check manifest.xml if we are on windows... -->
|
|
||||||
<target name="xml-copy" if="isWindows">
|
|
||||||
<echo message="Copying xml: manifest.xml" />
|
|
||||||
<!-- Copy manifest.xml -->
|
|
||||||
<copy todir="${target-folder}/${plugin-folder}">
|
|
||||||
<fileset dir=".">
|
|
||||||
<include name="manifest.xml"/>
|
|
||||||
</fileset>
|
|
||||||
</copy>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<!-- Install all files into the target folder -->
|
<!-- Install all files into the target folder -->
|
||||||
<target name="deploy" depends="clean, compress, compresscss, validate, xml-os-sel">
|
<target name="deploy" depends="compress, validate">
|
||||||
<mkdir dir="${target-folder}/${plugin-folder}"/>
|
<mkdir dir="${target-folder}/${plugin-folder}"/>
|
||||||
|
|
||||||
|
<!-- Copy (and validate) manifest.xml -->
|
||||||
|
<if>
|
||||||
|
<available file="xmllint" filepath="${env.PATH}" />
|
||||||
|
<then>
|
||||||
|
<exec executable="xmllint" output="${target-folder}/${plugin-folder}/manifest.xml" failonerror="true">
|
||||||
|
<arg value="--valid"/>
|
||||||
|
<arg value="--path"/>
|
||||||
|
<arg value="${server-folder}"/>
|
||||||
|
<arg value="manifest.xml"/>
|
||||||
|
</exec>
|
||||||
|
</then>
|
||||||
|
<else>
|
||||||
|
<echo message="WARNING: xmllint not available, not performing syntax-check on manifest.xml"/>
|
||||||
|
<!-- xmllint is not available, so we must copy the file manually -->
|
||||||
|
<copy todir="${target-folder}/${plugin-folder}">
|
||||||
|
<fileset dir=".">
|
||||||
|
<include name="manifest.xml"/>
|
||||||
|
</fileset>
|
||||||
|
</copy>
|
||||||
|
</else>
|
||||||
|
</if>
|
||||||
|
|
||||||
<!-- copy files -->
|
<!-- copy files -->
|
||||||
<copy todir="${target-folder}/${plugin-folder}">
|
<copy todir="${target-folder}/${plugin-folder}">
|
||||||
<fileset dir=".">
|
<fileset dir=".">
|
||||||
<include name="resources/**/*"/>
|
<include name="resources/**/*.*"/>
|
||||||
|
<include name="external/**/*.*"/>
|
||||||
<include name="php/**/*.php"/>
|
<include name="php/**/*.php"/>
|
||||||
<include name="config.php"/>
|
<include name="config.php"/>
|
||||||
<include name="changelog.txt"/>
|
|
||||||
<!-- exclude the ant script -->
|
<!-- exclude the ant script -->
|
||||||
<exclude name="build.xml"/>
|
<exclude name="build.xml"/>
|
||||||
<!-- CSS is generated during build -->
|
<!-- CSS is generated during build -->
|
||||||
<exclude name="resources/css/*.*"/>
|
<exclude name="resources/css/*.*"/>
|
||||||
</fileset>
|
</fileset>
|
||||||
</copy>
|
</copy>
|
||||||
|
|
||||||
<!-- replace all variables... -->
|
|
||||||
<replace file="${target-folder}/${plugin-folder}/manifest.xml" token="@_@PLUGIN_VERSION@_@" value="${plugin_version}" />
|
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<!-- compresses each CSS file -->
|
|
||||||
<target name="compresscss" depends="concat">
|
|
||||||
|
|
||||||
<available file="${tools-folder}/lib/yui-compressor-ant-task-0.5.jar" property="YUIANT_AVAILABLE" />
|
|
||||||
<fail unless="YUIANT_AVAILABLE" message="yui-compressor-ant-task-0.5.jar not found" />
|
|
||||||
|
|
||||||
<if>
|
|
||||||
<available file="${target-folder}/${plugin-folder}/${plugin-css-folder}/${plugin-css-debug-file}" type="file" />
|
|
||||||
<then>
|
|
||||||
<yui-compressor
|
|
||||||
warn="false"
|
|
||||||
munge="true"
|
|
||||||
preserveallsemicolons="false"
|
|
||||||
fromdir="${target-folder}/${plugin-folder}/${plugin-css-folder}"
|
|
||||||
todir="${target-folder}/${plugin-folder}/${plugin-css-folder}">
|
|
||||||
|
|
||||||
<include name="${plugin-css-debug-file}" />
|
|
||||||
</yui-compressor>
|
|
||||||
</then>
|
|
||||||
</if>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -1,3 +1,10 @@
|
|||||||
|
calendarimporter 2.2.0:
|
||||||
|
- support for Kopano Webapp 3.1.1
|
||||||
|
- Code rework
|
||||||
|
- Calendar export improved
|
||||||
|
- Calendar import improved
|
||||||
|
- GUI improvements
|
||||||
|
|
||||||
calendarimporter 2.1.0:
|
calendarimporter 2.1.0:
|
||||||
- ics sync is now implemented
|
- ics sync is now implemented
|
||||||
|
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
/** Disable the import plugin for all clients */
|
/** Disable the import plugin for all clients */
|
||||||
define('PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE', false);
|
define('PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE', true);
|
||||||
/** Disable the export feature for all clients */
|
|
||||||
define('PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE_EXPORT', false);
|
|
||||||
/** Disable the sync feature for all clients */
|
/** Disable the sync feature for all clients */
|
||||||
define('PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE_SYNC', true); // not yet implemented
|
define('PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE_SYNC', true); // not yet implemented
|
||||||
|
|
||||||
/** The default calendar to import to*/
|
/** The default calendar to import to*/
|
||||||
define('PLUGIN_CALENDARIMPORTER_DEFAULT', "calendar");
|
define('PLUGIN_CALENDARIMPORTER_DEFAULT', "Kalender");
|
||||||
define('PLUGIN_CALENDARIMPORTER_DEFAULT_TIMEZONE', "Europe/Vienna");
|
define('PLUGIN_CALENDARIMPORTER_DEFAULT_TIMEZONE', "Europe/Vienna");
|
||||||
|
|
||||||
/** Tempory path for uploaded files... */
|
/** Tempory path for uploaded files... */
|
||||||
define('PLUGIN_CALENDARIMPORTER_TMP_UPLOAD', "/var/lib/zarafa-webapp/tmp/");
|
define('PLUGIN_CALENDARIMPORTER_TMP_UPLOAD', "/var/lib/kopano-webapp/tmp/");
|
||||||
?>
|
?>
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
/**
|
|
||||||
* A small tool to create our timezone mappings list =)
|
|
||||||
*/
|
|
||||||
import java.util.TimeZone;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
static String map[] = new String[51]; // one field = 30 minutes step
|
|
||||||
|
|
||||||
private static void initMap() {
|
|
||||||
map[0] = "Pacific/Midway";
|
|
||||||
map[1] = "";
|
|
||||||
map[2] = "Pacific/Fakaofo";
|
|
||||||
map[3] = "Pacific/Marquesas";
|
|
||||||
map[4] = "America/Anchorage";
|
|
||||||
map[5] = "";
|
|
||||||
map[6] = "America/Dawson";
|
|
||||||
map[7] = "";
|
|
||||||
map[8] = "America/Dawson_Creek";
|
|
||||||
map[9] = "";
|
|
||||||
map[10] = "America/Chicago";
|
|
||||||
map[11] = "America/Caracas";
|
|
||||||
map[12] = "America/Detroit";
|
|
||||||
map[13] = "America/Caracas";
|
|
||||||
map[14] = "America/Santiago";
|
|
||||||
map[15] = "America/St_Johns";
|
|
||||||
map[16] = "America/Sao_Paulo";
|
|
||||||
map[17] = "";
|
|
||||||
map[18] = "America/Noronha";
|
|
||||||
map[19] = "";
|
|
||||||
map[20] = "Atlantic/Cape_Verde";
|
|
||||||
map[21] = "";
|
|
||||||
map[22] = "Africa/Abidjan";
|
|
||||||
map[23] = "";
|
|
||||||
map[24] = "Europe/Vienna";
|
|
||||||
map[25] = "";
|
|
||||||
map[26] = "Asia/Jerusalem";
|
|
||||||
map[27] = "";
|
|
||||||
map[28] = "Africa/Addis_Ababa";
|
|
||||||
map[29] = "Asia/Tehran";
|
|
||||||
map[30] = "Asia/Dubai";
|
|
||||||
map[31] = "Asia/Kabul";
|
|
||||||
map[32] = "Antarctica/Mawson";
|
|
||||||
map[33] = "Asia/Colombo";
|
|
||||||
map[34] = "Antarctica/Vostok";
|
|
||||||
map[35] = "Asia/Rangoon";
|
|
||||||
map[36] = "Antarctica/Davis";
|
|
||||||
map[37] = "";
|
|
||||||
map[38] = "Antarctica/Casey";
|
|
||||||
map[39] = "";
|
|
||||||
map[40] = "Asia/Dili";
|
|
||||||
map[41] = "Australia/Darwin";
|
|
||||||
map[42] = "Australia/Currie";
|
|
||||||
map[43] = "Australia/Lord_Howe";
|
|
||||||
map[44] = "Antarctica/Macquarie";
|
|
||||||
map[45] = "Pacific/Norfolk";
|
|
||||||
map[46] = "Antarctica/McMurdo";
|
|
||||||
map[47] = "";
|
|
||||||
map[48] = "Pacific/Enderbury";
|
|
||||||
map[49] = "";
|
|
||||||
map[50] = "Pacific/Kiritimati";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param args
|
|
||||||
*/
|
|
||||||
public static void main(String[] args) {
|
|
||||||
initMap();
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for(int time = -660; time < 900; time += 30) {
|
|
||||||
|
|
||||||
int hours = time / 60;
|
|
||||||
int minutes = Math.abs(time) % 60;
|
|
||||||
|
|
||||||
String[] avaiId = TimeZone.getAvailableIDs(time*60*1000);
|
|
||||||
|
|
||||||
if(avaiId.length > 0) {
|
|
||||||
System.out.printf("\t\t/*%+d:%02d*/\n", hours, minutes);
|
|
||||||
for (String string : avaiId) {
|
|
||||||
System.out.println("\t\t'" + string + "' : '" + map[i] + "',");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,7 @@
|
|||||||
* ABOUT.js zarafa calender to ics im/exporter
|
* ABOUT.js zarafa calender to ics im/exporter
|
||||||
*
|
*
|
||||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||||
* Copyright (C) 2012-2013 Christoph Haas
|
* Copyright (C) 2012-2016 Christoph Haas
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@ -29,7 +29,7 @@ Ext.namespace('Zarafa.plugins.calendarimporter');
|
|||||||
* The copyright string holding the copyright notice for the Zarafa calendarimporter Plugin.
|
* The copyright string holding the copyright notice for the Zarafa calendarimporter Plugin.
|
||||||
*/
|
*/
|
||||||
Zarafa.plugins.calendarimporter.ABOUT = ""
|
Zarafa.plugins.calendarimporter.ABOUT = ""
|
||||||
+ "<p>Copyright (C) 2012-2013 Christoph Haas <christoph.h@sprinternet.at></p>"
|
+ "<p>Copyright (C) 2012-2016 Christoph Haas <christoph.h@sprinternet.at></p>"
|
||||||
|
|
||||||
+ "<p>This program is free software; you can redistribute it and/or "
|
+ "<p>This program is free software; you can redistribute it and/or "
|
||||||
+ "modify it under the terms of the GNU Lesser General Public "
|
+ "modify it under the terms of the GNU Lesser General Public "
|
||||||
|
178
js/data/Actions.js
Normal file
178
js/data/Actions.js
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
/**
|
||||||
|
* Actions.js zarafa calender to ics im/exporter
|
||||||
|
*
|
||||||
|
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||||
|
* Copyright (C) 2012-2016 Christoph Haas
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ResponseHandler
|
||||||
|
*
|
||||||
|
* This class handles all responses from the php backend
|
||||||
|
*/
|
||||||
|
Ext.namespace('Zarafa.plugins.calendarimporter.data');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Zarafa.plugins.calendarimporter.data.Actions
|
||||||
|
* Common actions which can be used within {@link Ext.Button buttons}
|
||||||
|
* or other {@link Ext.Component components} with action handlers.
|
||||||
|
* @singleton
|
||||||
|
*/
|
||||||
|
Zarafa.plugins.calendarimporter.data.Actions = {
|
||||||
|
/**
|
||||||
|
* Callback for the export request.
|
||||||
|
* @param {Object} response
|
||||||
|
*/
|
||||||
|
downloadICS: function (response) {
|
||||||
|
if (response.status == false) {
|
||||||
|
Zarafa.common.dialogs.MessageBox.show({
|
||||||
|
title : dgettext('plugin_files', 'Warning'),
|
||||||
|
msg : dgettext('plugin_files', response.message),
|
||||||
|
icon : Zarafa.common.dialogs.MessageBox.WARNING,
|
||||||
|
buttons: Zarafa.common.dialogs.MessageBox.OK
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
var downloadFrame = Ext.getBody().createChild({
|
||||||
|
tag: 'iframe',
|
||||||
|
cls: 'x-hidden'
|
||||||
|
});
|
||||||
|
|
||||||
|
var url = document.URL;
|
||||||
|
var link = url.substring(0, url.lastIndexOf('/') + 1);
|
||||||
|
|
||||||
|
link += "index.php?sessionid=" + container.getUser().getSessionId() + "&load=custom&name=download_ics";
|
||||||
|
link = Ext.urlAppend(link, "token=" + encodeURIComponent(response.download_token));
|
||||||
|
link = Ext.urlAppend(link, "filename=" + encodeURIComponent(response.filename));
|
||||||
|
|
||||||
|
downloadFrame.dom.contentWindow.location = link;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all calendar folders.
|
||||||
|
* @param {boolean} asDropdownStore If true, a simple array store will be returned.
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
getAllCalendarFolders: function (asDropdownStore) {
|
||||||
|
asDropdownStore = Ext.isEmpty(asDropdownStore) ? false : asDropdownStore;
|
||||||
|
|
||||||
|
var allFolders = [];
|
||||||
|
|
||||||
|
var inbox = container.getHierarchyStore().getDefaultStore();
|
||||||
|
var pub = container.getHierarchyStore().getPublicStore();
|
||||||
|
|
||||||
|
if (!Ext.isEmpty(inbox.subStores) && inbox.subStores.folders.totalLength > 0) {
|
||||||
|
for (var i = 0; i < inbox.subStores.folders.totalLength; i++) {
|
||||||
|
var folder = inbox.subStores.folders.getAt(i);
|
||||||
|
if (folder.get("container_class") == "IPF.Appointment") {
|
||||||
|
if (asDropdownStore) {
|
||||||
|
allFolders.push([
|
||||||
|
folder.get("entryid"),
|
||||||
|
folder.get("display_name")
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
allFolders.push({
|
||||||
|
display_name : folder.get("display_name"),
|
||||||
|
entryid : folder.get("entryid"),
|
||||||
|
store_entryid: folder.get("store_entryid"),
|
||||||
|
is_public : false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Ext.isEmpty(pub.subStores) && pub.subStores.folders.totalLength > 0) {
|
||||||
|
for (var j = 0; j < pub.subStores.folders.totalLength; j++) {
|
||||||
|
var folder = pub.subStores.folders.getAt(j);
|
||||||
|
if (folder.get("container_class") == "IPF.Appointment") {
|
||||||
|
if (asDropdownStore) {
|
||||||
|
allFolders.push([
|
||||||
|
folder.get("entryid"),
|
||||||
|
folder.get("display_name") + " (Public)"
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
allFolders.push({
|
||||||
|
display_name : folder.get("display_name"),
|
||||||
|
entryid : folder.get("entryid"),
|
||||||
|
store_entryid: folder.get("store_entryid"),
|
||||||
|
is_public : true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asDropdownStore) {
|
||||||
|
return allFolders.sort(Zarafa.plugins.calendarimporter.data.Actions.dynamicSort(1));
|
||||||
|
} else {
|
||||||
|
return allFolders;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a calendar folder element by name.
|
||||||
|
* @param {string} name
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
getCalendarFolderByName: function (name) {
|
||||||
|
var folders = Zarafa.plugins.calendarimporter.data.Actions.getAllCalendarFolders(false);
|
||||||
|
|
||||||
|
for (var i = 0; i < folders.length; i++) {
|
||||||
|
if (folders[i].display_name == name) {
|
||||||
|
return folders[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return container.getHierarchyStore().getDefaultFolder('calendar');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a calendar folder element by entryid.
|
||||||
|
* @param {string} entryid
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
getCalendarFolderByEntryid: function (entryid) {
|
||||||
|
var folders = Zarafa.plugins.calendarimporter.data.Actions.getAllCalendarFolders(false);
|
||||||
|
|
||||||
|
for (var i = 0; i < folders.length; i++) {
|
||||||
|
if (folders[i].entryid == entryid) {
|
||||||
|
return folders[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return container.getHierarchyStore().getDefaultFolder('calendar');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamic sort function, sorts by property name.
|
||||||
|
* @param {string|int} property
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
dynamicSort: function (property) {
|
||||||
|
var sortOrder = 1;
|
||||||
|
if (property[0] === "-") {
|
||||||
|
sortOrder = -1;
|
||||||
|
property = property.substr(1);
|
||||||
|
}
|
||||||
|
return function (a, b) {
|
||||||
|
var result = (a[property].toLowerCase() < b[property].toLowerCase()) ? -1 : (a[property].toLowerCase() > b[property].toLowerCase()) ? 1 : 0;
|
||||||
|
return result * sortOrder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -2,7 +2,7 @@
|
|||||||
* ResponseHandler.js zarafa calender to ics im/exporter
|
* ResponseHandler.js zarafa calender to ics im/exporter
|
||||||
*
|
*
|
||||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||||
* Copyright (C) 2012-2013 Christoph Haas
|
* Copyright (C) 2012-2016 Christoph Haas
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@ -38,13 +38,13 @@ Zarafa.plugins.calendarimporter.data.ResponseHandler = Ext.extend(Zarafa.core.da
|
|||||||
* @cfg {Function} successCallback The function which
|
* @cfg {Function} successCallback The function which
|
||||||
* will be called after success request.
|
* will be called after success request.
|
||||||
*/
|
*/
|
||||||
successCallback : null,
|
successCallback: null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call the successCallback callback function.
|
* Call the successCallback callback function.
|
||||||
* @param {Object} response Object contained the response data.
|
* @param {Object} response Object contained the response data.
|
||||||
*/
|
*/
|
||||||
doExport : function(response) {
|
doExport: function (response) {
|
||||||
this.successCallback(response);
|
this.successCallback(response);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ Zarafa.plugins.calendarimporter.data.ResponseHandler = Ext.extend(Zarafa.core.da
|
|||||||
* Call the successCallback callback function.
|
* Call the successCallback callback function.
|
||||||
* @param {Object} response Object contained the response data.
|
* @param {Object} response Object contained the response data.
|
||||||
*/
|
*/
|
||||||
doList : function(response) {
|
doLoad: function (response) {
|
||||||
this.successCallback(response);
|
this.successCallback(response);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ Zarafa.plugins.calendarimporter.data.ResponseHandler = Ext.extend(Zarafa.core.da
|
|||||||
* Call the successCallback callback function.
|
* Call the successCallback callback function.
|
||||||
* @param {Object} response Object contained the response data.
|
* @param {Object} response Object contained the response data.
|
||||||
*/
|
*/
|
||||||
doImport : function(response) {
|
doImport: function (response) {
|
||||||
this.successCallback(response);
|
this.successCallback(response);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ Zarafa.plugins.calendarimporter.data.ResponseHandler = Ext.extend(Zarafa.core.da
|
|||||||
* Call the successCallback callback function.
|
* Call the successCallback callback function.
|
||||||
* @param {Object} response Object contained the response data.
|
* @param {Object} response Object contained the response data.
|
||||||
*/
|
*/
|
||||||
doAttachmentpath : function(response) {
|
doImportattachment: function (response) {
|
||||||
this.successCallback(response);
|
this.successCallback(response);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ Zarafa.plugins.calendarimporter.data.ResponseHandler = Ext.extend(Zarafa.core.da
|
|||||||
* exception response with the code of exception.
|
* exception response with the code of exception.
|
||||||
* @param {Object} response Object contained the response data.
|
* @param {Object} response Object contained the response data.
|
||||||
*/
|
*/
|
||||||
doError: function(response) {
|
doError: function (response) {
|
||||||
alert("error response code: " + response.error.info.code);
|
alert("error response code: " + response.error.info.code);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
1360
js/data/timezones.js
1360
js/data/timezones.js
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
|||||||
* ImportContentPanel.js zarafa calender to ics im/exporter
|
* ImportContentPanel.js zarafa calender to ics im/exporter
|
||||||
*
|
*
|
||||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||||
* Copyright (C) 2012-2013 Christoph Haas
|
* Copyright (C) 2012-2016 Christoph Haas
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@ -42,13 +42,9 @@ Zarafa.plugins.calendarimporter.dialogs.ImportContentPanel = Ext.extend(Zarafa.c
|
|||||||
*/
|
*/
|
||||||
constructor : function(config) {
|
constructor : function(config) {
|
||||||
config = config || {};
|
config = config || {};
|
||||||
var title = _('Import Calendar File');
|
|
||||||
if(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/enable_export")){
|
|
||||||
title = _('Import/Export Calendar File');
|
|
||||||
}
|
|
||||||
Ext.applyIf(config, {
|
Ext.applyIf(config, {
|
||||||
layout : 'fit',
|
layout : 'fit',
|
||||||
title : title,
|
title : _('Import Calendar File'),
|
||||||
closeOnSave : true,
|
closeOnSave : true,
|
||||||
width : 800,
|
width : 800,
|
||||||
height : 700,
|
height : 700,
|
||||||
@ -56,7 +52,8 @@ Zarafa.plugins.calendarimporter.dialogs.ImportContentPanel = Ext.extend(Zarafa.c
|
|||||||
items : [
|
items : [
|
||||||
{
|
{
|
||||||
xtype : 'calendarimporter.importpanel',
|
xtype : 'calendarimporter.importpanel',
|
||||||
filename : config.filename
|
filename : config.filename,
|
||||||
|
folder : config.folder
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* ImportPanel.js zarafa calender to ics im/exporter
|
* ImportPanel.js zarafa calender to ics im/exporter
|
||||||
*
|
*
|
||||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||||
* Copyright (C) 2012-2013 Christoph Haas
|
* Copyright (C) 2012-2016 Christoph Haas
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@ -29,7 +29,7 @@ Ext.namespace("Zarafa.plugins.calendarimporter.dialogs");
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Zarafa.plugins.calendarimporter.dialogs.ImportPanel
|
* @class Zarafa.plugins.calendarimporter.dialogs.ImportPanel
|
||||||
* @extends Ext.form.FormPanel
|
* @extends Ext.Panel
|
||||||
*/
|
*/
|
||||||
Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
loadMask: null,
|
loadMask: null,
|
||||||
|
|
||||||
/* export event buffer */
|
/* export event buffer */
|
||||||
exportResponse: new Array(),
|
exportResponse: [],
|
||||||
|
|
||||||
/* how many requests are still running? */
|
/* how many requests are still running? */
|
||||||
runningRequests: null,
|
runningRequests: null,
|
||||||
@ -54,13 +54,8 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
/* The store for the selection grid */
|
/* The store for the selection grid */
|
||||||
store: null,
|
store: null,
|
||||||
|
|
||||||
/**
|
/* selected folder */
|
||||||
* The internal 'iframe' which is hidden from the user, which is used for downloading
|
folder : null,
|
||||||
* attachments. See {@link #doOpen}.
|
|
||||||
* @property
|
|
||||||
* @type Ext.Element
|
|
||||||
*/
|
|
||||||
downloadFrame : undefined,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
@ -71,24 +66,30 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
var self = this;
|
var self = this;
|
||||||
this.timezone = container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_timezone");
|
this.timezone = container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_timezone");
|
||||||
|
|
||||||
if(typeof config.filename !== "undefined") {
|
if (!Ext.isEmpty(config.filename)) {
|
||||||
this.icsfile = config.filename;
|
this.icsfile = config.filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Ext.isEmpty(config.folder)) {
|
||||||
|
this.folder = config.folder;
|
||||||
|
}
|
||||||
|
|
||||||
// create the data store
|
// create the data store
|
||||||
this.store = new Ext.data.ArrayStore({
|
this.store = new Ext.data.ArrayStore({
|
||||||
fields: [
|
fields: [
|
||||||
{name: 'title'},
|
{name: 'subject'},
|
||||||
{name: 'start'},
|
{name: 'startdate'},
|
||||||
{name: 'end'},
|
{name: 'enddate'},
|
||||||
{name: 'location'},
|
{name: 'location'},
|
||||||
{name: 'description'},
|
{name: 'body'},
|
||||||
{name: 'priority'},
|
{name: 'priority'},
|
||||||
{name: 'label'},
|
{name: 'label'},
|
||||||
{name: 'busy'},
|
{name: 'busy'},
|
||||||
{name: 'privatestate'},
|
{name: 'class'},
|
||||||
{name: 'organizer'},
|
{name: 'organizer'},
|
||||||
{name: 'trigger'}
|
{name: 'alarms'},
|
||||||
|
{name: 'timezone'},
|
||||||
|
{name: 'record'}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -114,29 +115,19 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
this.createGrid()
|
this.createGrid()
|
||||||
],
|
],
|
||||||
buttons: [
|
buttons: [
|
||||||
this.createExportAllButton(),
|
|
||||||
this.createSubmitAllButton(),
|
this.createSubmitAllButton(),
|
||||||
this.createSubmitButton(),
|
this.createSubmitButton(),
|
||||||
this.createCancelButton()
|
this.createCancelButton()
|
||||||
],
|
],
|
||||||
listeners: {
|
listeners: {
|
||||||
afterrender: function (cmp) {
|
afterrender: function (cmp) {
|
||||||
Ext.getCmp('importbutton').disable();
|
this.loadMask = new Ext.LoadMask(this.getEl(), {msg:'Loading...'});
|
||||||
this.loadMask = new Ext.LoadMask(Ext.getCmp("importpanel").getEl(), {msg:'Loading...'});
|
|
||||||
|
|
||||||
if(this.icsfile != null) { // if we have got the filename from an attachment
|
if(this.icsfile != null) { // if we have got the filename from an attachment
|
||||||
this.parseCalendar(this.icsfile, this.timezone, this.ignoredst);
|
this.parseCalendar(this.icsfile, this.timezone, this.ignoredst);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
close: function (cmp) {
|
scope: this
|
||||||
Ext.getCmp('importbutton').enable();
|
|
||||||
},
|
|
||||||
hide: function (cmp) {
|
|
||||||
Ext.getCmp('importbutton').enable();
|
|
||||||
},
|
|
||||||
destroy: function (cmp) {
|
|
||||||
Ext.getCmp('importbutton').enable();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -174,22 +165,25 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
reloadGridStore: function(eventdata) {
|
reloadGridStore: function(eventdata) {
|
||||||
var parsedData = [];
|
var parsedData = [];
|
||||||
|
|
||||||
// this is done to get rid of the local browser timezone....
|
|
||||||
// because all timezone specific stuff is done via php
|
|
||||||
var local_tz_offset = new Date().getTimezoneOffset() * 60000; // getTimezoneOffset returns minutes... we need milliseconds
|
|
||||||
|
|
||||||
|
|
||||||
if(eventdata !== null) {
|
if(eventdata !== null) {
|
||||||
parsedData = new Array(eventdata.events.length);
|
parsedData = new Array(eventdata.events.length);
|
||||||
var i = 0;
|
var i = 0;
|
||||||
for(i = 0; i < eventdata.events.length; i++) {
|
for(i = 0; i < eventdata.events.length; i++) {
|
||||||
var trigger = null;
|
parsedData[i] = [
|
||||||
|
eventdata.events[i]["subject"],
|
||||||
if(eventdata.events[i]["VALARM"]) {
|
new Date(parseInt(eventdata.events[i]["startdate"]) * 1000),
|
||||||
trigger = eventdata.events[i]["VALARM"]["TRIGGER"];
|
new Date(parseInt(eventdata.events[i]["duedate"]) * 1000),
|
||||||
trigger = new Date(parseInt(trigger) + local_tz_offset);
|
eventdata.events[i]["location"],
|
||||||
}
|
eventdata.events[i]["body"],
|
||||||
parsedData[i] = new Array(eventdata.events[i]["SUMMARY"], new Date(parseInt(eventdata.events[i]["DTSTART"]) + local_tz_offset), new Date(parseInt(eventdata.events[i]["DTEND"]) + local_tz_offset), eventdata.events[i]["LOCATION"], eventdata.events[i]["DESCRIPTION"],eventdata.events[i]["PRIORITY"],eventdata.events[i]["X-ZARAFA-LABEL"],eventdata.events[i]["X-MICROSOFT-CDO-BUSYSTATUS"],eventdata.events[i]["CLASS"],eventdata.events[i]["ORGANIZER"],trigger);
|
eventdata.events[i]["priority"],
|
||||||
|
eventdata.events[i]["label"],
|
||||||
|
eventdata.events[i]["busystatus"],
|
||||||
|
eventdata.events[i]["private"],
|
||||||
|
eventdata.events[i]["organizer"],
|
||||||
|
eventdata.events[i]["alarms"],
|
||||||
|
eventdata.events[i]["timezone"],
|
||||||
|
eventdata.events[i]
|
||||||
|
];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
@ -223,17 +217,18 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
columns: [
|
columns: [
|
||||||
{id: 'Summary', header: 'Title', width: 200, sortable: true, dataIndex: 'title'},
|
{id: 'Summary', header: 'Title', width: 200, sortable: true, dataIndex: 'subject'},
|
||||||
{header: 'Start', width: 200, sortable: true, dataIndex: 'start', renderer : Zarafa.common.ui.grid.Renderers.datetime},
|
{header: 'Start', width: 200, sortable: true, dataIndex: 'startdate', renderer : Zarafa.common.ui.grid.Renderers.datetime},
|
||||||
{header: 'End', width: 200, sortable: true, dataIndex: 'end', renderer : Zarafa.common.ui.grid.Renderers.datetime},
|
{header: 'End', width: 200, sortable: true, dataIndex: 'enddate', renderer : Zarafa.common.ui.grid.Renderers.datetime},
|
||||||
{header: 'Location', width: 150, sortable: true, dataIndex: 'location'},
|
{header: 'Location', width: 150, sortable: true, dataIndex: 'location'},
|
||||||
{header: 'Description', sortable: true, dataIndex: 'description'},
|
{header: 'Description', sortable: true, dataIndex: 'body'},
|
||||||
{header: "Priority", dataIndex: 'priority', hidden: true},
|
{header: "Priority", dataIndex: 'priority', hidden: true},
|
||||||
{header: "Label", dataIndex: 'label', hidden: true},
|
{header: "Label", dataIndex: 'label', hidden: true},
|
||||||
{header: "Busystatus", dataIndex: 'busy', hidden: true},
|
{header: "Busystatus", dataIndex: 'busy', hidden: true},
|
||||||
{header: "Privacystatus", dataIndex: 'privatestate', hidden: true},
|
{header: "Privacystatus", dataIndex: 'class', hidden: true},
|
||||||
{header: "Organizer", dataIndex: 'organizer', hidden: true},
|
{header: "Organizer", dataIndex: 'organizer', hidden: true},
|
||||||
{header: "Alarm", dataIndex: 'trigger', hidden: true, renderer : Zarafa.common.ui.grid.Renderers.datetime}
|
{header: "Alarm", dataIndex: 'alarms', hidden: true, renderer : Zarafa.common.ui.grid.Renderers.datetime},
|
||||||
|
{header: "Timezone", dataIndex: 'timezone', hidden: true}
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
sm: new Ext.grid.RowSelectionModel({multiSelect:true})
|
sm: new Ext.grid.RowSelectionModel({multiSelect:true})
|
||||||
@ -241,52 +236,23 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
createSelectBox: function() {
|
createSelectBox: function() {
|
||||||
var defaultFolder = container.getHierarchyStore().getDefaultFolder('calendar'); // @type: Zarafa.hierarchy.data.MAPIFolderRecord
|
var myStore = Zarafa.plugins.calendarimporter.data.Actions.getAllCalendarFolders(true);
|
||||||
var subFolders = defaultFolder.getChildren();
|
|
||||||
var myStore = [];
|
|
||||||
|
|
||||||
/* add all local calendar folders */
|
|
||||||
var i = 0;
|
|
||||||
myStore.push(new Array(defaultFolder.getDefaultFolderKey(), defaultFolder.getDisplayName()));
|
|
||||||
for(i = 0; i < subFolders.length; i++) {
|
|
||||||
/* Store all subfolders */
|
|
||||||
myStore.push(new Array(subFolders[i].getDisplayName(), subFolders[i].getDisplayName(), false)); // 3rd field = isPublicfolder
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add all shared calendar folders */
|
|
||||||
var pubStore = container.getHierarchyStore().getPublicStore();
|
|
||||||
|
|
||||||
if(typeof pubStore !== "undefined") {
|
|
||||||
try {
|
|
||||||
var pubFolder = pubStore.getDefaultFolder("publicfolders");
|
|
||||||
var pubSubFolders = pubFolder.getChildren();
|
|
||||||
|
|
||||||
for(i = 0; i < pubSubFolders.length; i++) {
|
|
||||||
if(pubSubFolders[i].isContainerClass("IPF.Appointment")){
|
|
||||||
myStore.push(new Array(pubSubFolders[i].getDisplayName(), pubSubFolders[i].getDisplayName() + " [Shared]", true)); // 3rd field = isPublicfolder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Error opening the shared folder...");
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
xtype: "selectbox",
|
xtype: "selectbox",
|
||||||
ref: 'calendarselector',
|
ref: 'calendarselector',
|
||||||
id: 'calendarselector',
|
|
||||||
editable: false,
|
editable: false,
|
||||||
name: "choosen_calendar",
|
name: "choosen_calendar",
|
||||||
value: container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_calendar"),
|
value: Ext.isEmpty(this.folder) ? Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByName(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_calendar")).entryid : this.folder,
|
||||||
width: 100,
|
width: 100,
|
||||||
fieldLabel: "Select a calender",
|
fieldLabel: "Select folder",
|
||||||
store: myStore,
|
store: myStore,
|
||||||
mode: 'local',
|
mode: 'local',
|
||||||
labelSeperator: ":",
|
labelSeperator: ":",
|
||||||
border: false,
|
border: false,
|
||||||
anchor: "100%",
|
anchor: "100%",
|
||||||
scope: this,
|
scope: this,
|
||||||
|
hidden : Ext.isEmpty(this.folder) ? false : true,
|
||||||
allowBlank: false
|
allowBlank: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -295,12 +261,11 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
return {
|
return {
|
||||||
xtype: "selectbox",
|
xtype: "selectbox",
|
||||||
ref: 'timezoneselector',
|
ref: 'timezoneselector',
|
||||||
id: 'timezoneselector',
|
|
||||||
editable: false,
|
editable: false,
|
||||||
name: "choosen_timezone",
|
name: "choosen_timezone",
|
||||||
value: Zarafa.plugins.calendarimporter.data.Timezones.unMap(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_timezone")),
|
value: Zarafa.plugins.calendarimporter.data.Timezones.unMap(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_timezone")),
|
||||||
width: 100,
|
width: 100,
|
||||||
fieldLabel: "Select a timezone (optional)",
|
fieldLabel: "Timezone",
|
||||||
store: Zarafa.plugins.calendarimporter.data.Timezones.store,
|
store: Zarafa.plugins.calendarimporter.data.Timezones.store,
|
||||||
labelSeperator: ":",
|
labelSeperator: ":",
|
||||||
mode: 'local',
|
mode: 'local',
|
||||||
@ -309,7 +274,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
scope: this,
|
scope: this,
|
||||||
allowBlank: true,
|
allowBlank: true,
|
||||||
listeners: {
|
listeners: {
|
||||||
'select': this.onTimezoneSelected,
|
select: this.onTimezoneSelected,
|
||||||
scope: this
|
scope: this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -319,10 +284,9 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
return {
|
return {
|
||||||
xtype: "checkbox",
|
xtype: "checkbox",
|
||||||
ref: 'dstcheck',
|
ref: 'dstcheck',
|
||||||
id: 'dstcheck',
|
|
||||||
name: "dst_check",
|
name: "dst_check",
|
||||||
width: 100,
|
width: 100,
|
||||||
fieldLabel: "Ignore DST (optional)",
|
fieldLabel: "Ignore DST",
|
||||||
boxLabel: 'This will ignore "Daylight saving time" offsets.',
|
boxLabel: 'This will ignore "Daylight saving time" offsets.',
|
||||||
labelSeperator: ":",
|
labelSeperator: ":",
|
||||||
border: false,
|
border: false,
|
||||||
@ -330,7 +294,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
scope: this,
|
scope: this,
|
||||||
allowBlank: true,
|
allowBlank: true,
|
||||||
listeners: {
|
listeners: {
|
||||||
'check': this.onDstChecked,
|
check: this.onDstChecked,
|
||||||
scope: this
|
scope: this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -346,10 +310,11 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
emptyText: 'Select an .ics calendar',
|
emptyText: 'Select an .ics calendar',
|
||||||
border: false,
|
border: false,
|
||||||
anchor: "100%",
|
anchor: "100%",
|
||||||
|
height : "30",
|
||||||
scope: this,
|
scope: this,
|
||||||
allowBlank: false,
|
allowBlank: false,
|
||||||
listeners: {
|
listeners: {
|
||||||
'fileselected': this.onFileSelected,
|
fileselected: this.onFileSelected,
|
||||||
scope: this
|
scope: this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -358,48 +323,28 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
createSubmitButton: function() {
|
createSubmitButton: function() {
|
||||||
return {
|
return {
|
||||||
xtype: "button",
|
xtype: "button",
|
||||||
ref: "submitButton",
|
ref: "../submitButton",
|
||||||
id: "submitButton",
|
|
||||||
disabled: true,
|
disabled: true,
|
||||||
width: 100,
|
width: 100,
|
||||||
border: false,
|
border: false,
|
||||||
text: _("Import"),
|
text: _("Import"),
|
||||||
anchor: "100%",
|
anchor: "100%",
|
||||||
handler: this.importCheckedEvents,
|
handler: this.importCheckedEvents,
|
||||||
scope: this,
|
scope: this
|
||||||
allowBlank: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
createSubmitAllButton: function() {
|
createSubmitAllButton: function() {
|
||||||
return {
|
return {
|
||||||
xtype: "button",
|
xtype: "button",
|
||||||
ref: "submitAllButton",
|
ref: "../submitAllButton",
|
||||||
id: "submitAllButton",
|
|
||||||
disabled: true,
|
disabled: true,
|
||||||
width: 100,
|
width: 100,
|
||||||
border: false,
|
border: false,
|
||||||
text: _("Import All"),
|
text: _("Import All"),
|
||||||
anchor: "100%",
|
anchor: "100%",
|
||||||
handler: this.importAllEvents,
|
handler: this.importAllEvents,
|
||||||
scope: this,
|
scope: this
|
||||||
allowBlank: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
createExportAllButton: function() {
|
|
||||||
return {
|
|
||||||
xtype: "button",
|
|
||||||
ref: "exportAllButton",
|
|
||||||
id: "exportAllButton",
|
|
||||||
hidden: !container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/enable_export"),
|
|
||||||
width: 100,
|
|
||||||
border: false,
|
|
||||||
text: _("Export All"),
|
|
||||||
anchor: "100%",
|
|
||||||
handler: this.exportAllEvents,
|
|
||||||
scope: this,
|
|
||||||
allowBlank: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -411,8 +356,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
text: _("Cancel"),
|
text: _("Cancel"),
|
||||||
anchor: "100%",
|
anchor: "100%",
|
||||||
handler: this.close,
|
handler: this.close,
|
||||||
scope: this,
|
scope: this
|
||||||
allowBlank: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -432,7 +376,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This is called when the dst checkbox has been selected
|
* This is called when the dst checkbox has been selected
|
||||||
* @param {Ext.form.CheckBox} combo
|
* @param {Ext.form.CheckBox} checkbox
|
||||||
* @param {boolean} checked
|
* @param {boolean} checked
|
||||||
*/
|
*/
|
||||||
onDstChecked : function(checkbox, checked) {
|
onDstChecked : function(checkbox, checked) {
|
||||||
@ -456,8 +400,8 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
waitMsg: 'Uploading and parsing calendar...',
|
waitMsg: 'Uploading and parsing calendar...',
|
||||||
url: 'plugins/calendarimporter/php/upload.php',
|
url: 'plugins/calendarimporter/php/upload.php',
|
||||||
failure: function(file, action) {
|
failure: function(file, action) {
|
||||||
Ext.getCmp('submitButton').disable();
|
this.submitButton.disable();
|
||||||
Ext.getCmp('submitAllButton').disable();
|
this.submitAllButton.disable();
|
||||||
Zarafa.common.dialogs.MessageBox.show({
|
Zarafa.common.dialogs.MessageBox.show({
|
||||||
title : _('Error'),
|
title : _('Error'),
|
||||||
msg : _(action.result.error),
|
msg : _(action.result.error),
|
||||||
@ -478,14 +422,15 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
|
|
||||||
parseCalendar: function (icsPath, timezone, ignoredst) {
|
parseCalendar: function (icsPath, timezone, ignoredst) {
|
||||||
this.loadMask.show();
|
this.loadMask.show();
|
||||||
// call export function here!
|
|
||||||
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
||||||
successCallback: this.handleParsingResult.createDelegate(this)
|
successCallback: this.handleParsingResult,
|
||||||
|
scope: this
|
||||||
});
|
});
|
||||||
|
|
||||||
container.getRequest().singleRequest(
|
container.getRequest().singleRequest(
|
||||||
'calendarmodule',
|
'calendarmodule',
|
||||||
'import',
|
'load',
|
||||||
{
|
{
|
||||||
ics_filepath: icsPath,
|
ics_filepath: icsPath,
|
||||||
timezone: timezone,
|
timezone: timezone,
|
||||||
@ -496,20 +441,22 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleParsingResult: function(response) {
|
handleParsingResult: function(response) {
|
||||||
this.loadMask.hide();
|
var self = this.scope;
|
||||||
|
|
||||||
|
self.loadMask.hide();
|
||||||
|
|
||||||
if(response["status"] == true) {
|
if(response["status"] == true) {
|
||||||
Ext.getCmp('submitButton').enable();
|
self.submitButton.enable();
|
||||||
Ext.getCmp('submitAllButton').enable();
|
self.submitAllButton.enable();
|
||||||
|
|
||||||
if(typeof response.parsed.calendar["X-WR-TIMEZONE"] !== "undefined") {;
|
if(typeof response.parsed.calendar["X-WR-TIMEZONE"] !== "undefined") {
|
||||||
this.timezone = response.parsed.calendar["X-WR-TIMEZONE"];
|
self.timezone = response.parsed.calendar["X-WR-TIMEZONE"];
|
||||||
this.timezoneselector.setValue(Zarafa.plugins.calendarimporter.data.Timezones.unMap(this.timezone));
|
self.timezoneselector.setValue(Zarafa.plugins.calendarimporter.data.Timezones.unMap(this.timezone));
|
||||||
}
|
}
|
||||||
this.reloadGridStore(response.parsed);
|
self.reloadGridStore(response.parsed);
|
||||||
} else {
|
} else {
|
||||||
Ext.getCmp('submitButton').disable();
|
self.submitButton.disable();
|
||||||
Ext.getCmp('submitAllButton').disable();
|
self.submitAllButton.disable();
|
||||||
Zarafa.common.dialogs.MessageBox.show({
|
Zarafa.common.dialogs.MessageBox.show({
|
||||||
title : _('Parser Error'),
|
title : _('Parser Error'),
|
||||||
msg : _(response["message"]),
|
msg : _(response["message"]),
|
||||||
@ -524,54 +471,6 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
this.dialog.close()
|
this.dialog.close()
|
||||||
},
|
},
|
||||||
|
|
||||||
convertToAppointmentRecord: function (calendarFolder,entry) {
|
|
||||||
var newRecord = Zarafa.core.data.RecordFactory.createRecordObjectByMessageClass('IPM.Appointment', {
|
|
||||||
startdate: new Date(entry.start),
|
|
||||||
duedate: (entry.end != null) ?
|
|
||||||
new Date(entry.end) :
|
|
||||||
new Date(entry.start).add(Date.HOUR, 1),
|
|
||||||
location: entry.location,
|
|
||||||
subject: entry.title,
|
|
||||||
body: entry.description,
|
|
||||||
commonstart: new Date(entry.start),
|
|
||||||
commonend: (entry.end != null) ?
|
|
||||||
new Date(entry.end) :
|
|
||||||
new Date(entry.start).add(Date.HOUR, 1),
|
|
||||||
timezone: this.timezone,
|
|
||||||
parent_entryid: calendarFolder.get('entryid'),
|
|
||||||
store_entryid: calendarFolder.get('store_entryid')
|
|
||||||
});
|
|
||||||
|
|
||||||
var busystate = new Array("FREE", "TENTATIVE", "BUSY", "OOF");
|
|
||||||
var zlabel = new Array("NONE", "IMPORTANT", "WORK", "PERSONAL", "HOLIDAY", "REQUIRED", "TRAVEL REQUIRED", "PREPARATION REQUIERED", "BIRTHDAY", "SPECIAL DATE", "PHONE INTERVIEW");
|
|
||||||
|
|
||||||
/* optional fields */
|
|
||||||
if(entry.priority !== "") {
|
|
||||||
newRecord.data.importance = entry.priority;
|
|
||||||
}
|
|
||||||
if(entry.label !== "") {
|
|
||||||
newRecord.data.label = zlabel.indexOf(entry.label);
|
|
||||||
}
|
|
||||||
if(entry.busy !== "") {
|
|
||||||
newRecord.data.busystatus = busystate.indexOf(entry.busy);
|
|
||||||
}
|
|
||||||
if(entry.privatestate !== "") {
|
|
||||||
newRecord.data["private"] = entry.privatestate == "PUBLIC" ? false : true;
|
|
||||||
}
|
|
||||||
if(entry.organizer !== "") {
|
|
||||||
newRecord.data.sent_representing_email_address = entry.organizer;
|
|
||||||
}
|
|
||||||
if(entry.trigger != null) {
|
|
||||||
newRecord.data.reminder = true;
|
|
||||||
newRecord.data.reminder_minutes = new Date((entry.start - entry.trigger)/60);
|
|
||||||
newRecord.data.reminder_time = new Date(entry.trigger);
|
|
||||||
} else {
|
|
||||||
newRecord.data.reminder = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return newRecord;
|
|
||||||
},
|
|
||||||
|
|
||||||
importCheckedEvents: function () {
|
importCheckedEvents: function () {
|
||||||
var newRecords = this.eventgrid.selModel.getSelections();
|
var newRecords = this.eventgrid.selModel.getSelections();
|
||||||
this.importEvents(newRecords);
|
this.importEvents(newRecords);
|
||||||
@ -584,295 +483,15 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
this.importEvents(newRecords);
|
this.importEvents(newRecords);
|
||||||
},
|
},
|
||||||
|
|
||||||
exportAllEvents: function () {
|
|
||||||
//receive existing calendar store
|
|
||||||
var calValue = this.calendarselector.value;
|
|
||||||
|
|
||||||
if(calValue == undefined) { // no calendar choosen
|
|
||||||
Zarafa.common.dialogs.MessageBox.show({
|
|
||||||
title : _('Error'),
|
|
||||||
msg : _('You have to choose a calendar!'),
|
|
||||||
icon : Zarafa.common.dialogs.MessageBox.ERROR,
|
|
||||||
buttons : Zarafa.common.dialogs.MessageBox.OK
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
var calexist = true;
|
|
||||||
var calendarFolder = container.getHierarchyStore().getDefaultFolder('calendar');
|
|
||||||
var pubStore = container.getHierarchyStore().getPublicStore();
|
|
||||||
var pubSubFolders = [];
|
|
||||||
var pubFolder;
|
|
||||||
|
|
||||||
if(typeof pubStore !== "undefined") {
|
|
||||||
try {
|
|
||||||
pubFolder = pubStore.getDefaultFolder("publicfolders");
|
|
||||||
pubSubFolders = pubFolder.getChildren();
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Error opening the shared folder...");
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(calValue != "calendar") {
|
|
||||||
var subFolders = calendarFolder.getChildren();
|
|
||||||
var i = 0;
|
|
||||||
|
|
||||||
/* add public folders if any exist */
|
|
||||||
for(i = 0; i < pubSubFolders.length; i++) {
|
|
||||||
if(pubSubFolders[i].isContainerClass("IPF.Appointment")){
|
|
||||||
subFolders.push(pubSubFolders[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i=0;i<subFolders.length;i++) {
|
|
||||||
// loo up right folder
|
|
||||||
// TODO: improve!!
|
|
||||||
if(subFolders[i].getDisplayName() == calValue) {
|
|
||||||
calendarFolder = subFolders[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(calendarFolder.isDefaultFolder()) {
|
|
||||||
Zarafa.common.dialogs.MessageBox.show({
|
|
||||||
title : _('Error'),
|
|
||||||
msg : _('Selected calendar does not exist!'),
|
|
||||||
icon : Zarafa.common.dialogs.MessageBox.ERROR,
|
|
||||||
buttons : Zarafa.common.dialogs.MessageBox.OK
|
|
||||||
});
|
|
||||||
calexist = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(calexist) {
|
|
||||||
Zarafa.common.dialogs.MessageBox.show({
|
|
||||||
title: 'Please wait',
|
|
||||||
msg: 'Generating ical file...',
|
|
||||||
progressText: 'Exporting...',
|
|
||||||
width:300,
|
|
||||||
progress:true,
|
|
||||||
closable:false
|
|
||||||
});
|
|
||||||
|
|
||||||
// progress bar... ;)
|
|
||||||
var updateProgressBar = function(v){
|
|
||||||
return function(){
|
|
||||||
if(v == 100){
|
|
||||||
if(Zarafa.common.dialogs.MessageBox.isVisible()) {
|
|
||||||
updateTimer();
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
Zarafa.common.dialogs.MessageBox.updateProgress(v/100, 'Exporting...');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
var updateTimer = function() {
|
|
||||||
for(var i = 1; i < 101; i++){
|
|
||||||
setTimeout(updateProgressBar(i), 20*i);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
updateTimer();
|
|
||||||
|
|
||||||
// call export function here!
|
|
||||||
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
|
||||||
successCallback: this.exportPagedEvents.createDelegate(this)
|
|
||||||
});
|
|
||||||
|
|
||||||
container.getRequest().singleRequest(
|
|
||||||
'appointmentlistmodule',
|
|
||||||
'list',
|
|
||||||
{
|
|
||||||
groupDir: "ASC",
|
|
||||||
restriction: {
|
|
||||||
//start: 0,
|
|
||||||
//limit: 500, // limit to 500 events.... not working because of hardcoded limit in listmodule
|
|
||||||
//startdate: 0,
|
|
||||||
//duedate: 2145826800 // 2037... nearly highest unix timestamp
|
|
||||||
},
|
|
||||||
sort: [{
|
|
||||||
"field": "startdate",
|
|
||||||
"direction": "DESC"
|
|
||||||
}],
|
|
||||||
store_entryid : calendarFolder.data.store_entryid,
|
|
||||||
entryid : calendarFolder.data.entryid
|
|
||||||
},
|
|
||||||
responseHandler
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate needed Requests for all events
|
|
||||||
* Needed because the listmodule has hardcoded pageing setting -.-
|
|
||||||
* @param {Object} response
|
|
||||||
*/
|
|
||||||
exportPagedEvents:function(response) {
|
|
||||||
|
|
||||||
if(response.page.start = 0 && response.item.length <= 0) {
|
|
||||||
container.getNotifier().notify('info', 'Export Failed', 'There were no items to export!');
|
|
||||||
Zarafa.common.dialogs.MessageBox.hide();
|
|
||||||
} else {
|
|
||||||
this.exportResponse = response.item;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.totalExportCount == null) {
|
|
||||||
this.totalExportCount = response.page.totalrowcount;
|
|
||||||
}
|
|
||||||
|
|
||||||
var requests = Math.ceil(response.page.totalrowcount / response.page.rowcount);
|
|
||||||
this.runningRequests = requests;
|
|
||||||
|
|
||||||
var i = 0;
|
|
||||||
|
|
||||||
//receive existing calendar store
|
|
||||||
var calValue = this.calendarselector.value;
|
|
||||||
var calendarFolder = container.getHierarchyStore().getDefaultFolder('calendar');
|
|
||||||
var pubStore = container.getHierarchyStore().getPublicStore();
|
|
||||||
var pubSubFolders = [];
|
|
||||||
var pubFolder;
|
|
||||||
|
|
||||||
if(typeof pubStore !== "undefined") {
|
|
||||||
try {
|
|
||||||
pubFolder = pubStore.getDefaultFolder("publicfolders");
|
|
||||||
pubSubFolders = pubFolder.getChildren();
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Error opening the shared folder...");
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(calValue != "calendar") {
|
|
||||||
var subFolders = calendarFolder.getChildren();
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
/* add public folders if any exist */
|
|
||||||
for(i = 0; i < pubSubFolders.length; i++) {
|
|
||||||
if(pubSubFolders[i].isContainerClass("IPF.Appointment")){
|
|
||||||
subFolders.push(pubSubFolders[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i=0;i<subFolders.length;i++) {
|
|
||||||
// loo up right folder
|
|
||||||
// TODO: improve!!
|
|
||||||
if(subFolders[i].getDisplayName() == calValue) {
|
|
||||||
calendarFolder = subFolders[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(calendarFolder.isDefaultFolder()) {
|
|
||||||
Zarafa.common.dialogs.MessageBox.show({
|
|
||||||
title : _('Error'),
|
|
||||||
msg : _('Selected calendar does not exist!'),
|
|
||||||
icon : Zarafa.common.dialogs.MessageBox.ERROR,
|
|
||||||
buttons : Zarafa.common.dialogs.MessageBox.OK
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; i < requests; i++) {
|
|
||||||
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
|
||||||
successCallback: this.storeResult.createDelegate(this)
|
|
||||||
});
|
|
||||||
this.requestNext(calendarFolder, responseHandler, response.page.rowcount *(i+1), response.page.rowcount);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Responsehandler for the single requests... will merge all events into one array
|
|
||||||
* @param {Object} response
|
|
||||||
*/
|
|
||||||
storeResult: function(response) {
|
|
||||||
var tmp = this.exportResponse;
|
|
||||||
|
|
||||||
this.exportResponse = tmp.concat(response.item);
|
|
||||||
|
|
||||||
if(this.runningRequests <= 1) {
|
|
||||||
// final request =)
|
|
||||||
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
|
||||||
successCallback: this.downLoadICS.createDelegate(this)
|
|
||||||
});
|
|
||||||
|
|
||||||
container.getRequest().singleRequest(
|
|
||||||
'calendarmodule',
|
|
||||||
'export',
|
|
||||||
{
|
|
||||||
data: this.exportResponse,
|
|
||||||
calendar: this.calendarselector.value
|
|
||||||
},
|
|
||||||
responseHandler
|
|
||||||
);
|
|
||||||
container.getNotifier().notify('info', 'Exported', 'Found ' + this.exportResponse.length + ' entries to export. Preparing download...');
|
|
||||||
this.dialog.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.runningRequests--;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* build a new event request for the listmodule
|
|
||||||
* @param {Object} calendarFolder the calendarFolder to export
|
|
||||||
* @param {Object} responseHandler (should be storeResult)
|
|
||||||
* @param {int} start
|
|
||||||
* @param {int} limit
|
|
||||||
*/
|
|
||||||
requestNext: function(calendarFolder, responseHandler, start, limit) {
|
|
||||||
|
|
||||||
container.getRequest().singleRequest(
|
|
||||||
'appointmentlistmodule',
|
|
||||||
'list',
|
|
||||||
{
|
|
||||||
groupDir: "ASC",
|
|
||||||
restriction: {
|
|
||||||
start: start,
|
|
||||||
limit: limit
|
|
||||||
//startdate: 0,
|
|
||||||
//duedate: 2145826800 // 2037... nearly highest unix timestamp
|
|
||||||
},
|
|
||||||
sort: [{
|
|
||||||
"field": "startdate",
|
|
||||||
"direction": "DESC"
|
|
||||||
}],
|
|
||||||
store_entryid : calendarFolder.data.store_entryid,
|
|
||||||
entryid : calendarFolder.data.entryid
|
|
||||||
},
|
|
||||||
responseHandler
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* download ics file =)
|
|
||||||
* @param {Object} response
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
downLoadICS : function(response) {
|
|
||||||
Zarafa.common.dialogs.MessageBox.hide();
|
|
||||||
if(response.status === true) {
|
|
||||||
if(!this.downloadFrame){
|
|
||||||
this.downloadFrame = Ext.getBody().createChild({
|
|
||||||
tag: 'iframe',
|
|
||||||
cls: 'x-hidden'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var url = 'plugins/calendarimporter/php/download.php?fileid='+response.fileid+'&basedir='+response.basedir+'&secid='+response.secid+'&realname='+response.realname;
|
|
||||||
this.downloadFrame.dom.contentWindow.location = url;
|
|
||||||
} else {
|
|
||||||
container.getNotifier().notify('error', 'Export Failed', 'ICal File creation failed!');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function stores all given events to the appointmentstore
|
* This function stores all given events to the appointmentstore
|
||||||
* @param events
|
* @param events
|
||||||
*/
|
*/
|
||||||
importEvents: function (events) {
|
importEvents: function (events) {
|
||||||
//receive existing calendar store
|
//receive existing calendar store
|
||||||
var calValue = this.calendarselector.value;
|
var calValue = this.calendarselector.getValue();
|
||||||
|
|
||||||
if(calValue == undefined) { // no calendar choosen
|
if(Ext.isEmpty(calValue)) { // no calendar choosen
|
||||||
Zarafa.common.dialogs.MessageBox.show({
|
Zarafa.common.dialogs.MessageBox.show({
|
||||||
title : _('Error'),
|
title : _('Error'),
|
||||||
msg : _('You have to choose a calendar!'),
|
msg : _('You have to choose a calendar!'),
|
||||||
@ -880,7 +499,6 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
buttons : Zarafa.common.dialogs.MessageBox.OK
|
buttons : Zarafa.common.dialogs.MessageBox.OK
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
var calexist = true;
|
|
||||||
if(this.eventgrid.selModel.getCount() < 1) {
|
if(this.eventgrid.selModel.getCount() < 1) {
|
||||||
Zarafa.common.dialogs.MessageBox.show({
|
Zarafa.common.dialogs.MessageBox.show({
|
||||||
title : _('Error'),
|
title : _('Error'),
|
||||||
@ -889,54 +507,55 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
|
|||||||
buttons : Zarafa.common.dialogs.MessageBox.OK
|
buttons : Zarafa.common.dialogs.MessageBox.OK
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
var calendarStore = new Zarafa.calendar.AppointmentStore();
|
var calendarFolder = Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(calValue);
|
||||||
var calendarFolder = container.getHierarchyStore().getDefaultFolder('calendar');
|
|
||||||
var pubStore = container.getHierarchyStore().getPublicStore();
|
|
||||||
var pubFolder = pubStore.getDefaultFolder("publicfolders");
|
|
||||||
var pubSubFolders = pubFolder.getChildren();
|
|
||||||
|
|
||||||
if(calValue != "calendar") {
|
this.loadMask.show();
|
||||||
var subFolders = calendarFolder.getChildren();
|
var uids = [];
|
||||||
var i = 0;
|
|
||||||
for(i = 0; i < pubSubFolders.length; i++) {
|
|
||||||
if(pubSubFolders[i].isContainerClass("IPF.Appointment")){
|
|
||||||
subFolders.push(pubSubFolders[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(i=0;i<subFolders.length;i++) {
|
|
||||||
// look up right folder
|
|
||||||
// TODO: improve!!
|
|
||||||
if(subFolders[i].getDisplayName() == calValue) {
|
|
||||||
calendarFolder = subFolders[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(calendarFolder.isDefaultFolder()) {
|
//receive Records from grid rows
|
||||||
Zarafa.common.dialogs.MessageBox.show({
|
Ext.each(events, function(newRecord) {
|
||||||
title : _('Error'),
|
uids.push(newRecord.data.record.internal_fields.event_uid);
|
||||||
msg : _('Selected calendar does not exist!'),
|
}, this);
|
||||||
icon : Zarafa.common.dialogs.MessageBox.ERROR,
|
|
||||||
buttons : Zarafa.common.dialogs.MessageBox.OK
|
|
||||||
});
|
|
||||||
calexist = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(calexist) {
|
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
||||||
this.loadMask.show();
|
successCallback: this.importEventsDone,
|
||||||
//receive Records from grid rows
|
scope: this
|
||||||
Ext.each(events, function(newRecord) {
|
});
|
||||||
var record = this.convertToAppointmentRecord(calendarFolder,newRecord.data);
|
|
||||||
calendarStore.add(record);
|
container.getRequest().singleRequest(
|
||||||
}, this);
|
'calendarmodule',
|
||||||
calendarStore.save();
|
'import',
|
||||||
this.loadMask.hide();
|
{
|
||||||
this.dialog.close();
|
storeid : calendarFolder.store_entryid,
|
||||||
container.getNotifier().notify('info', 'Imported', 'Imported ' + events.length + ' events. Please reload your calendar!');
|
folderid : calendarFolder.entryid,
|
||||||
}
|
uids : uids,
|
||||||
|
ics_filepath: this.icsfile
|
||||||
|
},
|
||||||
|
responseHandler
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for the import request.
|
||||||
|
* @param {Object} response
|
||||||
|
*/
|
||||||
|
importEventsDone: function (response) {
|
||||||
|
var self = this.scope;
|
||||||
|
|
||||||
|
self.loadMask.hide();
|
||||||
|
self.dialog.close();
|
||||||
|
if (response.status == true) {
|
||||||
|
container.getNotifier().notify('info', 'Imported', 'Imported ' + response.count + ' events. Please reload your calendar!');
|
||||||
|
} else {
|
||||||
|
Zarafa.common.dialogs.MessageBox.show({
|
||||||
|
title : _('Error'),
|
||||||
|
msg : _('Import failed: ') + response.message,
|
||||||
|
icon : Zarafa.common.dialogs.MessageBox.ERROR,
|
||||||
|
buttons: Zarafa.common.dialogs.MessageBox.OK
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* plugin.calendarimporter.js zarafa calender to ics im/exporter
|
* plugin.calendarimporter.js zarafa calender to ics im/exporter
|
||||||
*
|
*
|
||||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||||
* Copyright (C) 2012-2013 Christoph Haas
|
* Copyright (C) 2012-2016 Christoph Haas
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@ -24,11 +24,11 @@ Ext.namespace("Zarafa.plugins.calendarimporter"); // Assign the right na
|
|||||||
|
|
||||||
Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { // create new import plugin
|
Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { // create new import plugin
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {Object} config Configuration object
|
* @param {Object} config Configuration object
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
constructor: function (config) {
|
constructor: function (config) {
|
||||||
config = config || {};
|
config = config || {};
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
|
|||||||
* initialises insertion point for plugin
|
* initialises insertion point for plugin
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
initPlugin : function() {
|
initPlugin: function () {
|
||||||
Zarafa.plugins.calendarimporter.ImportPlugin.superclass.initPlugin.apply(this, arguments);
|
Zarafa.plugins.calendarimporter.ImportPlugin.superclass.initPlugin.apply(this, arguments);
|
||||||
|
|
||||||
/* our panel */
|
/* our panel */
|
||||||
@ -47,67 +47,92 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
|
|||||||
|
|
||||||
/* directly import received icals */
|
/* directly import received icals */
|
||||||
this.registerInsertionPoint('common.contextmenu.attachment.actions', this.createAttachmentImportButton);
|
this.registerInsertionPoint('common.contextmenu.attachment.actions', this.createAttachmentImportButton);
|
||||||
/* add import button to south navigation */
|
|
||||||
this.registerInsertionPoint("navigation.south", this.createImportButton, this);
|
|
||||||
/* add settings widget */
|
/* add settings widget */
|
||||||
this.registerInsertionPoint('context.settings.category.calendar', this.createSettingsWidget);
|
this.registerInsertionPoint('context.settings.category.calendar', this.createSettingsWidget);
|
||||||
|
|
||||||
|
/* export a calendar entry via rightclick */
|
||||||
|
this.registerInsertionPoint('context.calendar.contextmenu.actions', this.createItemExportInsertionPoint, this);
|
||||||
|
|
||||||
/* ical sync stuff */
|
/* ical sync stuff */
|
||||||
if(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/enable_sync") === true) {
|
if (container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/enable_sync") === true) {
|
||||||
/* edit panel */
|
/* edit panel */
|
||||||
Zarafa.core.data.SharedComponentType.addProperty('plugins.calendarimporter.settings.dialogs.calsyncedit');
|
Zarafa.core.data.SharedComponentType.addProperty('plugins.calendarimporter.settings.dialogs.calsyncedit');
|
||||||
|
|
||||||
/* enable the settings widget */
|
/* enable the settings widget */
|
||||||
this.registerInsertionPoint('context.settings.category.calendar', this.createSettingsCalSyncWidget);
|
this.registerInsertionPoint('context.settings.category.calendar', this.createSettingsCalSyncWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the button
|
|
||||||
*
|
|
||||||
* @return {Object} Configuration object for a {@link Ext.Button button}
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
createImportButton: function () {
|
|
||||||
var button = {
|
|
||||||
xtype : 'button',
|
|
||||||
ref : "importbutton",
|
|
||||||
id : "importbutton",
|
|
||||||
text : _('Import Calendar'),
|
|
||||||
iconCls : 'icon_calendarimporter_button',
|
|
||||||
navigationContext : container.getContextByName('calendar'),
|
|
||||||
handler : this.onImportButtonClick,
|
|
||||||
scope : this
|
|
||||||
};
|
|
||||||
|
|
||||||
if(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/enable_export")) {
|
|
||||||
button.text = _('Import/Export Calendar');
|
|
||||||
}
|
|
||||||
|
|
||||||
return button;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the button
|
* This method hooks to the contact context menu and allows users to export users to vcf.
|
||||||
*
|
*
|
||||||
* @return {Object} Configuration object for a {@link Ext.Button button}
|
* @param include
|
||||||
*
|
* @param btn
|
||||||
*/
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
createItemExportInsertionPoint: function (include, btn) {
|
||||||
|
return {
|
||||||
|
text : dgettext('plugin_files', 'Export Event'),
|
||||||
|
handler: this.exportToICS.createDelegate(this, [btn]),
|
||||||
|
scope : this,
|
||||||
|
iconCls: 'icon_calendarimporter_export'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a request to download the selected records as vCard.
|
||||||
|
* @param {Ext.Button} btn
|
||||||
|
*/
|
||||||
|
exportToICS: function (btn) {
|
||||||
|
if (btn.records.length == 0) {
|
||||||
|
return; // skip if no records where given!
|
||||||
|
}
|
||||||
|
|
||||||
|
var recordIds = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < btn.records.length; i++) {
|
||||||
|
recordIds.push(btn.records[i].get("entryid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
||||||
|
successCallback: Zarafa.plugins.calendarimporter.data.Actions.downloadICS,
|
||||||
|
scope : this
|
||||||
|
});
|
||||||
|
|
||||||
|
// request attachment preperation
|
||||||
|
container.getRequest().singleRequest(
|
||||||
|
'calendarmodule',
|
||||||
|
'export',
|
||||||
|
{
|
||||||
|
storeid: btn.records[0].get("store_entryid"),
|
||||||
|
records: recordIds
|
||||||
|
},
|
||||||
|
responseHandler
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the button
|
||||||
|
*
|
||||||
|
* @return {Object} Configuration object for a {@link Ext.Button button}
|
||||||
|
*
|
||||||
|
*/
|
||||||
createSettingsWidget: function () {
|
createSettingsWidget: function () {
|
||||||
return [{
|
return [{
|
||||||
xtype : 'calendarimporter.settingswidget'
|
xtype: 'calendarimporter.settingswidget'
|
||||||
}];
|
}];
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the button
|
* Creates the button
|
||||||
*
|
*
|
||||||
* @return {Object} Configuration object for a {@link Ext.Button button}
|
* @return {Object} Configuration object for a {@link Ext.Button button}
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
createSettingsCalSyncWidget: function () {
|
createSettingsCalSyncWidget: function () {
|
||||||
return [{
|
return [{
|
||||||
xtype : 'calendarimporter.settingscalsyncwidget'
|
xtype: 'calendarimporter.settingscalsyncwidget'
|
||||||
}];
|
}];
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -116,19 +141,19 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
|
|||||||
|
|
||||||
* @return {Object} Configuration object for a {@link Ext.Button button}
|
* @return {Object} Configuration object for a {@link Ext.Button button}
|
||||||
*/
|
*/
|
||||||
createAttachmentImportButton : function(include, btn) {
|
createAttachmentImportButton: function (include, btn) {
|
||||||
return {
|
return {
|
||||||
text : _('Import Calendar'),
|
text : _('Import to Calendar'),
|
||||||
handler : this.getAttachmentFileName.createDelegate(this, [btn, this.gotAttachmentFileName]),
|
handler : this.getAttachmentFileName.createDelegate(this, [btn]),
|
||||||
scope : this,
|
scope : this,
|
||||||
iconCls : 'icon_calendarimporter_button',
|
iconCls : 'icon_calendarimporter_button',
|
||||||
beforeShow : function(item, record) {
|
beforeShow: function (item, record) {
|
||||||
var extension = record.data.name.split('.').pop().toLowerCase();
|
var extension = record.data.name.split('.').pop().toLowerCase();
|
||||||
|
|
||||||
if(record.data.filetype == "text/calendar" || extension == "ics" || extension == "ifb" || extension == "ical" || extension == "ifbf") {
|
if (record.data.filetype == "text/calendar" || extension == "ics" || extension == "ifb" || extension == "ical" || extension == "ifbf") {
|
||||||
item.setDisabled(false);
|
item.setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
item.setDisabled(true);
|
item.setVisible(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -137,18 +162,15 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
|
|||||||
/**
|
/**
|
||||||
* Callback for getAttachmentFileName
|
* Callback for getAttachmentFileName
|
||||||
*/
|
*/
|
||||||
gotAttachmentFileName: function(response) {
|
gotAttachmentFileName: function (response) {
|
||||||
if(response.status == true) {
|
if (response.status == true) {
|
||||||
Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents'], undefined, {
|
this.scope.openImportDialog(response.tmpname);
|
||||||
manager : Ext.WindowMgr,
|
|
||||||
filename : response.tmpname
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
Zarafa.common.dialogs.MessageBox.show({
|
Zarafa.common.dialogs.MessageBox.show({
|
||||||
title : _('Error'),
|
title : _('Error'),
|
||||||
msg : _(response["message"]),
|
msg : _(response["message"]),
|
||||||
icon : Zarafa.common.dialogs.MessageBox.ERROR,
|
icon : Zarafa.common.dialogs.MessageBox.ERROR,
|
||||||
buttons : Zarafa.common.dialogs.MessageBox.OK
|
buttons: Zarafa.common.dialogs.MessageBox.OK
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -158,27 +180,27 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
|
|||||||
*/
|
*/
|
||||||
getAttachmentFileName: function (btn, callback) {
|
getAttachmentFileName: function (btn, callback) {
|
||||||
Zarafa.common.dialogs.MessageBox.show({
|
Zarafa.common.dialogs.MessageBox.show({
|
||||||
title: 'Please wait',
|
title : 'Please wait',
|
||||||
msg: 'Loading attachment...',
|
msg : 'Loading attachment...',
|
||||||
progressText: 'Initializing...',
|
progressText: 'Initializing...',
|
||||||
width:300,
|
width : 300,
|
||||||
progress:true,
|
progress : true,
|
||||||
closable:false
|
closable : false
|
||||||
});
|
});
|
||||||
|
|
||||||
// progress bar... ;)
|
// progress bar... ;)
|
||||||
var f = function(v){
|
var f = function (v) {
|
||||||
return function(){
|
return function () {
|
||||||
if(v == 100){
|
if (v == 100) {
|
||||||
Zarafa.common.dialogs.MessageBox.hide();
|
Zarafa.common.dialogs.MessageBox.hide();
|
||||||
}else{
|
} else {
|
||||||
Zarafa.common.dialogs.MessageBox.updateProgress(v/100, Math.round(v)+'% loaded');
|
Zarafa.common.dialogs.MessageBox.updateProgress(v / 100, Math.round(v) + '% loaded');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
for(var i = 1; i < 101; i++){
|
for (var i = 1; i < 101; i++) {
|
||||||
setTimeout(f(i), 20*i);
|
setTimeout(f(i), 20 * i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* store the attachment to a temporary folder and prepare it for uploading */
|
/* store the attachment to a temporary folder and prepare it for uploading */
|
||||||
@ -188,39 +210,46 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
|
|||||||
var store = attachmentStore.getParentRecord().get('store_entryid');
|
var store = attachmentStore.getParentRecord().get('store_entryid');
|
||||||
var entryid = attachmentStore.getAttachmentParentRecordEntryId();
|
var entryid = attachmentStore.getAttachmentParentRecordEntryId();
|
||||||
var attachNum = new Array(1);
|
var attachNum = new Array(1);
|
||||||
if (attachmentRecord.get('attach_num') != -1)
|
if (attachmentRecord.get('attach_num') != -1) {
|
||||||
attachNum[0] = attachmentRecord.get('attach_num');
|
attachNum[0] = attachmentRecord.get('attach_num');
|
||||||
else
|
} else {
|
||||||
attachNum[0] = attachmentRecord.get('tmpname');
|
attachNum[0] = attachmentRecord.get('tmpname');
|
||||||
|
}
|
||||||
var dialog_attachments = attachmentStore.getId();
|
var dialog_attachments = attachmentStore.getId();
|
||||||
var filename = attachmentRecord.data.name;
|
var filename = attachmentRecord.data.name;
|
||||||
|
|
||||||
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
||||||
successCallback: callback
|
successCallback: this.gotAttachmentFileName,
|
||||||
|
scope : this
|
||||||
});
|
});
|
||||||
|
|
||||||
// request attachment preperation
|
// request attachment preperation
|
||||||
container.getRequest().singleRequest(
|
container.getRequest().singleRequest(
|
||||||
'calendarmodule',
|
'calendarmodule',
|
||||||
'attachmentpath',
|
'importattachment',
|
||||||
{
|
{
|
||||||
entryid : entryid,
|
entryid : entryid,
|
||||||
store: store,
|
store : store,
|
||||||
attachNum: attachNum,
|
attachNum : attachNum,
|
||||||
dialog_attachments: dialog_attachments,
|
dialog_attachments: dialog_attachments,
|
||||||
filename: filename
|
filename : filename
|
||||||
},
|
},
|
||||||
responseHandler
|
responseHandler
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clickhandler for the button
|
* Open the import dialog.
|
||||||
|
* @param {String} filename
|
||||||
*/
|
*/
|
||||||
onImportButtonClick: function () {
|
openImportDialog: function (filename) {
|
||||||
Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents'], undefined, {
|
var componentType = Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents'];
|
||||||
manager : Ext.WindowMgr
|
var config = {
|
||||||
});
|
filename: filename,
|
||||||
|
modal : true
|
||||||
|
};
|
||||||
|
|
||||||
|
Zarafa.core.data.UIFactory.openLayerComponent(componentType, undefined, config);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -231,15 +260,22 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
|
|||||||
* @param {Ext.data.Record} record Optionally passed record.
|
* @param {Ext.data.Record} record Optionally passed record.
|
||||||
* @return {Number} The bid for the shared component
|
* @return {Number} The bid for the shared component
|
||||||
*/
|
*/
|
||||||
bidSharedComponent : function(type, record) {
|
bidSharedComponent: function (type, record) {
|
||||||
var bid = -1;
|
var bid = -1;
|
||||||
switch(type) {
|
switch (type) {
|
||||||
case Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents']:
|
case Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents']:
|
||||||
bid = 2;
|
bid = 2;
|
||||||
break;
|
break;
|
||||||
case Zarafa.core.data.SharedComponentType['plugins.calendarimporter.settings.dialogs.calsyncedit']:
|
case Zarafa.core.data.SharedComponentType['plugins.calendarimporter.settings.dialogs.calsyncedit']:
|
||||||
bid = 2;
|
bid = 2;
|
||||||
break;
|
break;
|
||||||
|
case Zarafa.core.data.SharedComponentType['common.contextmenu']:
|
||||||
|
if (record instanceof Zarafa.core.data.MAPIRecord) {
|
||||||
|
if (record.get('object_type') == Zarafa.core.mapi.ObjectType.MAPI_FOLDER && record.get('container_class') == "IPF.Appointment") {
|
||||||
|
bid = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return bid;
|
return bid;
|
||||||
},
|
},
|
||||||
@ -251,15 +287,18 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
|
|||||||
* @param {Ext.data.Record} record Optionally passed record.
|
* @param {Ext.data.Record} record Optionally passed record.
|
||||||
* @return {Ext.Component} Component
|
* @return {Ext.Component} Component
|
||||||
*/
|
*/
|
||||||
getSharedComponent : function(type, record) {
|
getSharedComponent: function (type, record) {
|
||||||
var component;
|
var component;
|
||||||
switch(type) {
|
switch (type) {
|
||||||
case Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents']:
|
case Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents']:
|
||||||
component = Zarafa.plugins.calendarimporter.dialogs.ImportContentPanel;
|
component = Zarafa.plugins.calendarimporter.dialogs.ImportContentPanel;
|
||||||
break;
|
break;
|
||||||
case Zarafa.core.data.SharedComponentType['plugins.calendarimporter.settings.dialogs.calsyncedit']:
|
case Zarafa.core.data.SharedComponentType['plugins.calendarimporter.settings.dialogs.calsyncedit']:
|
||||||
component = Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditContentPanel;
|
component = Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditContentPanel;
|
||||||
break;
|
break;
|
||||||
|
case Zarafa.core.data.SharedComponentType['common.contextmenu']:
|
||||||
|
component = Zarafa.plugins.calendarimporter.ui.ContextMenu;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return component;
|
return component;
|
||||||
@ -270,11 +309,11 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
|
|||||||
/*############################################################################################################################*
|
/*############################################################################################################################*
|
||||||
* STARTUP
|
* STARTUP
|
||||||
*############################################################################################################################*/
|
*############################################################################################################################*/
|
||||||
Zarafa.onReady(function() {
|
Zarafa.onReady(function () {
|
||||||
container.registerPlugin(new Zarafa.core.PluginMetaData({
|
container.registerPlugin(new Zarafa.core.PluginMetaData({
|
||||||
name : 'calendarimporter',
|
name : 'calendarimporter',
|
||||||
displayName : _('Calendarimporter Plugin'),
|
displayName : _('Calendarimporter Plugin'),
|
||||||
about : Zarafa.plugins.calendarimporter.ABOUT,
|
about : Zarafa.plugins.calendarimporter.ABOUT,
|
||||||
pluginConstructor : Zarafa.plugins.calendarimporter.ImportPlugin
|
pluginConstructor: Zarafa.plugins.calendarimporter.ImportPlugin
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
@ -27,6 +27,7 @@ Zarafa.plugins.calendarimporter.settings.SettingsCalSyncWidget = Ext.extend(Zara
|
|||||||
{ name : 'pass' },
|
{ name : 'pass' },
|
||||||
{ name : 'intervall', type : 'int' },
|
{ name : 'intervall', type : 'int' },
|
||||||
{ name : 'calendar' },
|
{ name : 'calendar' },
|
||||||
|
{ name : 'calendarname' },
|
||||||
{ name : 'lastsync' }
|
{ name : 'lastsync' }
|
||||||
],
|
],
|
||||||
sortInfo : {
|
sortInfo : {
|
||||||
@ -68,7 +69,9 @@ Zarafa.plugins.calendarimporter.settings.SettingsCalSyncWidget = Ext.extend(Zara
|
|||||||
var icslinks = settingsModel.get('zarafa/v1/contexts/calendar/icssync', true);
|
var icslinks = settingsModel.get('zarafa/v1/contexts/calendar/icssync', true);
|
||||||
var syncArray = [];
|
var syncArray = [];
|
||||||
for (var key in icslinks) {
|
for (var key in icslinks) {
|
||||||
syncArray.push(Ext.apply({}, icslinks[key], { id : key }));
|
if(icslinks.hasOwnProperty(key)) { // skip inherited props
|
||||||
|
syncArray.push(Ext.apply({}, icslinks[key], {id: key}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load all icslinks into the GridPanel
|
// Load all icslinks into the GridPanel
|
||||||
@ -98,7 +101,8 @@ Zarafa.plugins.calendarimporter.settings.SettingsCalSyncWidget = Ext.extend(Zara
|
|||||||
'user' : icslink.get('user'),
|
'user' : icslink.get('user'),
|
||||||
'pass' : icslink.get('pass'),
|
'pass' : icslink.get('pass'),
|
||||||
'lastsync' : icslink.get('lastsync'),
|
'lastsync' : icslink.get('lastsync'),
|
||||||
'calendar' : icslink.get('calendar')
|
'calendar' : icslink.get('calendar'),
|
||||||
|
'calendarname' : Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(icslink.get('calendar')).display_name
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
settingsModel.set('zarafa/v1/contexts/calendar/icssync', icslinkData);
|
settingsModel.set('zarafa/v1/contexts/calendar/icssync', icslinkData);
|
||||||
|
@ -24,13 +24,6 @@ Zarafa.plugins.calendarimporter.settings.SettingsWidget = Ext.extend(Zarafa.sett
|
|||||||
title : _('Calendar Import/Export plugin settings'),
|
title : _('Calendar Import/Export plugin settings'),
|
||||||
xtype : 'calendarimporter.settingswidget',
|
xtype : 'calendarimporter.settingswidget',
|
||||||
items : [
|
items : [
|
||||||
{
|
|
||||||
xtype : 'checkbox',
|
|
||||||
name : 'zarafa/v1/plugins/calendarimporter/enable_export',
|
|
||||||
ref : 'enableExport',
|
|
||||||
fieldLabel : 'Enable exporter',
|
|
||||||
lazyInit : false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
xtype : 'checkbox',
|
xtype : 'checkbox',
|
||||||
name : 'zarafa/v1/plugins/calendarimporter/enable_sync',
|
name : 'zarafa/v1/plugins/calendarimporter/enable_sync',
|
||||||
@ -47,43 +40,14 @@ Zarafa.plugins.calendarimporter.settings.SettingsWidget = Ext.extend(Zarafa.sett
|
|||||||
},
|
},
|
||||||
|
|
||||||
createSelectBox: function() {
|
createSelectBox: function() {
|
||||||
var defaultFolder = container.getHierarchyStore().getDefaultFolder('calendar'); // @type: Zarafa.hierarchy.data.MAPIFolderRecord
|
var myStore = Zarafa.plugins.calendarimporter.data.Actions.getAllCalendarFolders(true);
|
||||||
var subFolders = defaultFolder.getChildren();
|
|
||||||
var myStore = [];
|
|
||||||
|
|
||||||
/* add all local calendar folders */
|
|
||||||
var i = 0;
|
|
||||||
myStore.push(new Array(defaultFolder.getDefaultFolderKey(), defaultFolder.getDisplayName()));
|
|
||||||
for(i = 0; i < subFolders.length; i++) {
|
|
||||||
/* Store all subfolders */
|
|
||||||
myStore.push(new Array(subFolders[i].getDisplayName(), subFolders[i].getDisplayName(), false)); // 3rd field = isPublicfolder
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add all shared calendar folders */
|
|
||||||
var pubStore = container.getHierarchyStore().getPublicStore();
|
|
||||||
|
|
||||||
if(typeof pubStore !== "undefined") {
|
|
||||||
try {
|
|
||||||
var pubFolder = pubStore.getDefaultFolder("publicfolders");
|
|
||||||
var pubSubFolders = pubFolder.getChildren();
|
|
||||||
|
|
||||||
for(i = 0; i < pubSubFolders.length; i++) {
|
|
||||||
if(pubSubFolders[i].isContainerClass("IPF.Appointment")){
|
|
||||||
myStore.push(new Array(pubSubFolders[i].getDisplayName(), pubSubFolders[i].getDisplayName() + " [Shared]", true)); // 3rd field = isPublicfolder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Error opening the shared folder...");
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
xtype: "selectbox",
|
xtype: "selectbox",
|
||||||
ref : 'defaultCalendar',
|
ref : 'defaultCalendar',
|
||||||
editable: false,
|
editable: false,
|
||||||
name: "zarafa/v1/plugins/calendarimporter/default_calendar",
|
name: "zarafa/v1/plugins/calendarimporter/default_calendar",
|
||||||
value: container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_calendar"),
|
value: Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByName(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_calendar")).entryid,
|
||||||
width: 100,
|
width: 100,
|
||||||
fieldLabel: "Default calender",
|
fieldLabel: "Default calender",
|
||||||
store: myStore,
|
store: myStore,
|
||||||
@ -123,9 +87,8 @@ Zarafa.plugins.calendarimporter.settings.SettingsWidget = Ext.extend(Zarafa.sett
|
|||||||
* @param {Zarafa.settings.SettingsModel} settingsModel The settings to load
|
* @param {Zarafa.settings.SettingsModel} settingsModel The settings to load
|
||||||
*/
|
*/
|
||||||
update : function(settingsModel) {
|
update : function(settingsModel) {
|
||||||
this.enableExport.setValue(settingsModel.get(this.enableExport.name));
|
|
||||||
this.enableSync.setValue(settingsModel.get(this.enableSync.name));
|
this.enableSync.setValue(settingsModel.get(this.enableSync.name));
|
||||||
this.defaultCalendar.setValue(settingsModel.get(this.defaultCalendar.name));
|
this.defaultCalendar.setValue(Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByName(settingsModel.get(this.defaultCalendar.name)).entryid);
|
||||||
this.defaultTimezone.setValue(settingsModel.get(this.defaultTimezone.name));
|
this.defaultTimezone.setValue(settingsModel.get(this.defaultTimezone.name));
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -136,11 +99,115 @@ Zarafa.plugins.calendarimporter.settings.SettingsWidget = Ext.extend(Zarafa.sett
|
|||||||
* @param {Zarafa.settings.SettingsModel} settingsModel The settings to update
|
* @param {Zarafa.settings.SettingsModel} settingsModel The settings to update
|
||||||
*/
|
*/
|
||||||
updateSettings : function(settingsModel) {
|
updateSettings : function(settingsModel) {
|
||||||
settingsModel.set(this.enableExport.name, this.enableExport.getValue());
|
// check if the user changed a value
|
||||||
settingsModel.set(this.enableSync.name, this.enableSync.getValue());
|
var changed = false;
|
||||||
settingsModel.set(this.defaultCalendar.name, this.defaultCalendar.getValue());
|
|
||||||
settingsModel.set(this.defaultTimezone.name, this.defaultTimezone.getValue());
|
if(settingsModel.get(this.enableSync.name) != this.enableSync.getValue()) {
|
||||||
}
|
changed = true;
|
||||||
|
} else if(settingsModel.get(this.defaultCalendar.name) != Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(this.defaultCalendar.getValue()).display_name) {
|
||||||
|
changed = true;
|
||||||
|
} else if(settingsModel.get(this.defaultTimezone.name) != this.defaultTimezone.getValue()) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(changed) {
|
||||||
|
// Really save changes
|
||||||
|
settingsModel.set(this.enableSync.name, this.enableSync.getValue());
|
||||||
|
settingsModel.set(this.defaultCalendar.name, Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(this.defaultCalendar.getValue()).display_name); // store name
|
||||||
|
settingsModel.set(this.defaultTimezone.name, this.defaultTimezone.getValue());
|
||||||
|
|
||||||
|
this.onUpdateSettings();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after the {@link Zarafa.settings.SettingsModel} fires the {@link Zarafa.settings.SettingsModel#save save}
|
||||||
|
* event to indicate the settings were successfully saved and it will forcefully realod the webapp.
|
||||||
|
* settings which were saved to the server.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
onUpdateSettings : function()
|
||||||
|
{
|
||||||
|
var message = _('Your WebApp needs to be reloaded to make the changes visible!');
|
||||||
|
message += '<br/><br/>';
|
||||||
|
message += _('WebApp will automatically restart in order for these changes to take effect');
|
||||||
|
message += '<br/>';
|
||||||
|
|
||||||
|
Zarafa.common.dialogs.MessageBox.addCustomButtons({
|
||||||
|
title: _('Restart WebApp'),
|
||||||
|
msg : message,
|
||||||
|
icon: Ext.MessageBox.QUESTION,
|
||||||
|
fn : this.restartWebapp,
|
||||||
|
customButton : [{
|
||||||
|
text : _('Restart'),
|
||||||
|
name : 'restart'
|
||||||
|
}, {
|
||||||
|
text : _('Cancel'),
|
||||||
|
name : 'cancel'
|
||||||
|
}],
|
||||||
|
scope : this
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for {@link #onResetSettings}. This will check if the user
|
||||||
|
* wishes to reset the default settings or not.
|
||||||
|
* @param {String} button The button which user pressed.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
restartWebapp : function(button)
|
||||||
|
{
|
||||||
|
if (button === 'restart') {
|
||||||
|
var contextModel = this.ownerCt.settingsContext.getModel();
|
||||||
|
var realModel = contextModel.getRealSettingsModel();
|
||||||
|
|
||||||
|
realModel.save();
|
||||||
|
|
||||||
|
this.loadMask = new Zarafa.common.ui.LoadMask(Ext.getBody(), {
|
||||||
|
msg : '<b>' + _('Webapp is reloading, Please wait.') + '</b>'
|
||||||
|
});
|
||||||
|
this.loadMask.show();
|
||||||
|
|
||||||
|
this.mon(realModel, 'save', this.onSettingsSave, this);
|
||||||
|
this.mon(realModel, 'exception', this.onSettingsException, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the {@link Zarafa.settings.} fires the {@link Zarafa.settings.SettingsModel#save save}
|
||||||
|
* event to indicate the settings were successfully saved and it will forcefully realod the webapp.
|
||||||
|
* @param {Zarafa.settings.SettingsModel} model The model which fired the event.
|
||||||
|
* @param {Object} parameters The key-value object containing the action and the corresponding
|
||||||
|
* settings which were saved to the server.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
onSettingsSave : function(model, parameters)
|
||||||
|
{
|
||||||
|
this.mun(model, 'save', this.onSettingsSave, this);
|
||||||
|
Zarafa.core.Util.reloadWebapp();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the {@link Zarafa.settings.SettingsModel} fires the {@link Zarafa.settings.SettingsModel#exception exception}
|
||||||
|
* event to indicate the settings were not successfully saved.
|
||||||
|
* @param {Zarafa.settings.SettingsModel} model The settings model which fired the event
|
||||||
|
* @param {String} type The value of this parameter will be either 'response' or 'remote'.
|
||||||
|
* @param {String} action Name of the action (see {@link Ext.data.Api#actions}).
|
||||||
|
* @param {Object} options The object containing a 'path' and 'value' field indicating
|
||||||
|
* respectively the Setting and corresponding value for the setting which was being saved.
|
||||||
|
* @param {Object} response The response object as received from the PHP-side
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
onSettingsException : function(model, type, action, options, response)
|
||||||
|
{
|
||||||
|
this.loadMask.hide();
|
||||||
|
|
||||||
|
// Remove event handlers
|
||||||
|
this.mun(model, 'save', this.onSettingsSave, this);
|
||||||
|
this.mun(model, 'exception', this.onSettingsException, this);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Ext.reg('calendarimporter.settingswidget', Zarafa.plugins.calendarimporter.settings.SettingsWidget);
|
Ext.reg('calendarimporter.settingswidget', Zarafa.plugins.calendarimporter.settings.SettingsWidget);
|
||||||
|
@ -23,7 +23,7 @@ Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditContentPanel = Ext.e
|
|||||||
model : true,
|
model : true,
|
||||||
autoSave : false,
|
autoSave : false,
|
||||||
width : 400,
|
width : 400,
|
||||||
height : 350,
|
height : 400,
|
||||||
title : _('ICAL Sync'),
|
title : _('ICAL Sync'),
|
||||||
items : [{
|
items : [{
|
||||||
xtype : 'calendarimporter.calsynceditpanel',
|
xtype : 'calendarimporter.calsynceditpanel',
|
||||||
|
@ -60,7 +60,6 @@ Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditPanel = Ext.extend(E
|
|||||||
var id = 0;
|
var id = 0;
|
||||||
var record = undefined;
|
var record = undefined;
|
||||||
|
|
||||||
console.log(this);
|
|
||||||
if(!this.currentItem) {
|
if(!this.currentItem) {
|
||||||
record = new store.recordType({
|
record = new store.recordType({
|
||||||
id: this.hashCode(this.icsurl.getValue()),
|
id: this.hashCode(this.icsurl.getValue()),
|
||||||
@ -69,6 +68,7 @@ Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditPanel = Ext.extend(E
|
|||||||
user: this.user.getValue(),
|
user: this.user.getValue(),
|
||||||
pass: Ext.util.base64.encode(this.pass.getValue()),
|
pass: Ext.util.base64.encode(this.pass.getValue()),
|
||||||
calendar: this.calendar.getValue(),
|
calendar: this.calendar.getValue(),
|
||||||
|
calendarname : Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(this.calendar.getValue()).display_name,
|
||||||
lastsync: "never"
|
lastsync: "never"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -82,6 +82,7 @@ Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditPanel = Ext.extend(E
|
|||||||
this.currentItem.set('user', this.user.getValue());
|
this.currentItem.set('user', this.user.getValue());
|
||||||
this.currentItem.set('pass', Ext.util.base64.encode(this.pass.getValue()));
|
this.currentItem.set('pass', Ext.util.base64.encode(this.pass.getValue()));
|
||||||
this.currentItem.set('calendar', this.calendar.getValue());
|
this.currentItem.set('calendar', this.calendar.getValue());
|
||||||
|
this.currentItem.set('calendarname', Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(this.calendar.getValue()).display_name);
|
||||||
}
|
}
|
||||||
this.dialog.close();
|
this.dialog.close();
|
||||||
}
|
}
|
||||||
@ -95,48 +96,20 @@ Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditPanel = Ext.extend(E
|
|||||||
createPanelItems : function(config)
|
createPanelItems : function(config)
|
||||||
{
|
{
|
||||||
var icsurl = "";
|
var icsurl = "";
|
||||||
var intervall = "";
|
var intervall = "15";
|
||||||
var user = "";
|
var user = "";
|
||||||
var pass = "";
|
var pass = "";
|
||||||
var calendar = "";
|
var calendarname = "";
|
||||||
|
var calendar = Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByName(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_calendar")).entryid;
|
||||||
|
var myStore = Zarafa.plugins.calendarimporter.data.Actions.getAllCalendarFolders(true);
|
||||||
|
|
||||||
var defaultFolder = container.getHierarchyStore().getDefaultFolder('calendar'); // @type: Zarafa.hierarchy.data.MAPIFolderRecord
|
if(config.item){
|
||||||
var subFolders = defaultFolder.getChildren();
|
|
||||||
var myStore = [];
|
|
||||||
|
|
||||||
if(config.item){
|
|
||||||
icsurl = config.item.get('icsurl');
|
icsurl = config.item.get('icsurl');
|
||||||
intervall = config.item.get('intervall');
|
intervall = config.item.get('intervall');
|
||||||
user = config.item.get('user');
|
user = config.item.get('user');
|
||||||
pass = Ext.util.base64.decode(config.item.get('pass'));
|
pass = Ext.util.base64.decode(config.item.get('pass'));
|
||||||
calendar = config.item.get('calendar');
|
calendar = config.item.get('calendar');
|
||||||
}
|
calendarname = config.item.get('calendarname');
|
||||||
|
|
||||||
/* add all local calendar folders */
|
|
||||||
var i = 0;
|
|
||||||
myStore.push(new Array(defaultFolder.getDefaultFolderKey(), defaultFolder.getDisplayName()));
|
|
||||||
for(i = 0; i < subFolders.length; i++) {
|
|
||||||
/* Store all subfolders */
|
|
||||||
myStore.push(new Array(subFolders[i].getDisplayName(), subFolders[i].getDisplayName(), false)); // 3rd field = isPublicfolder
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add all shared calendar folders */
|
|
||||||
var pubStore = container.getHierarchyStore().getPublicStore();
|
|
||||||
|
|
||||||
if(typeof pubStore !== "undefined") {
|
|
||||||
try {
|
|
||||||
var pubFolder = pubStore.getDefaultFolder("publicfolders");
|
|
||||||
var pubSubFolders = pubFolder.getChildren();
|
|
||||||
|
|
||||||
for(i = 0; i < pubSubFolders.length; i++) {
|
|
||||||
if(pubSubFolders[i].isContainerClass("IPF.Appointment")){
|
|
||||||
myStore.push(new Array(pubSubFolders[i].getDisplayName(), pubSubFolders[i].getDisplayName() + " [Shared]", true)); // 3rd field = isPublicfolder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Error opening the shared folder...");
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,6 +58,16 @@ Zarafa.plugins.calendarimporter.settings.ui.CalSyncGrid = Ext.extend(Ext.grid.Gr
|
|||||||
return value ? "true" : "false";
|
return value ? "true" : "false";
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render function
|
||||||
|
* @return {String}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
renderCalendarColumn : function(value, p, record)
|
||||||
|
{
|
||||||
|
return Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(value).display_name;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a column model object, used in {@link #colModel} config
|
* Creates a column model object, used in {@link #colModel} config
|
||||||
* @return {Ext.grid.ColumnModel} column model object
|
* @return {Ext.grid.ColumnModel} column model object
|
||||||
@ -71,7 +81,7 @@ Zarafa.plugins.calendarimporter.settings.ui.CalSyncGrid = Ext.extend(Ext.grid.Gr
|
|||||||
renderer : Zarafa.common.ui.grid.Renderers.text
|
renderer : Zarafa.common.ui.grid.Renderers.text
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
dataIndex : 'calendar',
|
dataIndex : 'calendarname',
|
||||||
header : _('Destination Calender'),
|
header : _('Destination Calender'),
|
||||||
renderer : Zarafa.common.ui.grid.Renderers.text
|
renderer : Zarafa.common.ui.grid.Renderers.text
|
||||||
},
|
},
|
||||||
|
129
js/ui/ContextMenu.js
Normal file
129
js/ui/ContextMenu.js
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/**
|
||||||
|
* ContectMenu.js zarafa calender to ics im/exporter
|
||||||
|
*
|
||||||
|
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||||
|
* Copyright (C) 2012-2016 Christoph Haas
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
Ext.namespace('Zarafa.plugins.calendarimporter.ui');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Zarafa.plugins.calendarimporter.ui.ContextMenu
|
||||||
|
* @extends Zarafa.hierarchy.ui.ContextMenu
|
||||||
|
* @xtype calendarimporter.hierarchycontextmenu
|
||||||
|
*/
|
||||||
|
Zarafa.plugins.calendarimporter.ui.ContextMenu = Ext.extend(Zarafa.hierarchy.ui.ContextMenu, {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @param {Object} config Configuration object
|
||||||
|
*/
|
||||||
|
constructor: function (config) {
|
||||||
|
config = config || {};
|
||||||
|
|
||||||
|
if (config.contextNode) {
|
||||||
|
config.contextTree = config.contextNode.getOwnerTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
Zarafa.plugins.calendarimporter.ui.ContextMenu.superclass.constructor.call(this, config);
|
||||||
|
|
||||||
|
// add item to menu
|
||||||
|
var additionalItems = this.createAdditionalContextMenuItems(config);
|
||||||
|
for (var i = 0; i < additionalItems.length; i++) {
|
||||||
|
config.items[0].push(additionalItems[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Zarafa.plugins.calendarimporter.ui.ContextMenu.superclass.constructor.call(this, config); // redo ... otherwise menu does not get published
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the Action context menu items.
|
||||||
|
* @param {Object} config Configuration object for the {@link Zarafa.plugins.calendarimporter.ui.ContextMenu ContextMenu}
|
||||||
|
* @return {Zarafa.core.ui.menu.ConditionalItem[]} The list of Action context menu items
|
||||||
|
* @private
|
||||||
|
*
|
||||||
|
* Note: All handlers are called within the scope of {@link Zarafa.plugins.calendarimporter.ui.ContextMenu HierarchyContextMenu}
|
||||||
|
*/
|
||||||
|
createAdditionalContextMenuItems: function (config) {
|
||||||
|
return [{
|
||||||
|
xtype: 'menuseparator'
|
||||||
|
}, {
|
||||||
|
text : _('Import Calendar'),
|
||||||
|
iconCls : 'icon_calendarimporter_import',
|
||||||
|
handler : this.onContextItemImport,
|
||||||
|
beforeShow: function (item, record) {
|
||||||
|
var access = record.get('access') & Zarafa.core.mapi.Access.ACCESS_MODIFY;
|
||||||
|
if (!access || (record.isIPMSubTree() && !record.getMAPIStore().isDefaultStore())) {
|
||||||
|
item.setDisabled(true);
|
||||||
|
} else {
|
||||||
|
item.setDisabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
text : _('Export Calendar'),
|
||||||
|
iconCls : 'icon_calendarimporter_export',
|
||||||
|
handler : this.onContextItemExport,
|
||||||
|
beforeShow: function (item, record) {
|
||||||
|
var access = record.get('access') & Zarafa.core.mapi.Access.ACCESS_READ;
|
||||||
|
if (!access || (record.isIPMSubTree() && !record.getMAPIStore().isDefaultStore())) {
|
||||||
|
item.setDisabled(true);
|
||||||
|
} else {
|
||||||
|
item.setDisabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires on selecting 'Open' menu option from {@link Zarafa.plugins.calendarimporter.ui.ContextMenu ContextMenu}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
onContextItemExport: function () {
|
||||||
|
var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({
|
||||||
|
successCallback: Zarafa.plugins.calendarimporter.data.Actions.downloadICS,
|
||||||
|
scope : this
|
||||||
|
});
|
||||||
|
|
||||||
|
// request attachment preperation
|
||||||
|
container.getRequest().singleRequest(
|
||||||
|
'calendarmodule',
|
||||||
|
'export',
|
||||||
|
{
|
||||||
|
storeid: this.records.get("store_entryid"),
|
||||||
|
folder : this.records.get("entryid")
|
||||||
|
},
|
||||||
|
responseHandler
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires on selecting 'Open' menu option from {@link Zarafa.plugins.calendarimporter.ui.ContextMenu ContextMenu}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
onContextItemImport: function () {
|
||||||
|
var componentType = Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents'];
|
||||||
|
var config = {
|
||||||
|
modal : true,
|
||||||
|
folder: this.records.get("entryid")
|
||||||
|
};
|
||||||
|
|
||||||
|
Zarafa.core.data.UIFactory.openLayerComponent(componentType, undefined, config);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ext.reg('calendarimporter.hierarchycontextmenu', Zarafa.plugins.calendarimporter.ui.ContextMenu);
|
12
manifest.xml
12
manifest.xml
@ -2,7 +2,7 @@
|
|||||||
<!DOCTYPE plugin SYSTEM "manifest.dtd">
|
<!DOCTYPE plugin SYSTEM "manifest.dtd">
|
||||||
<plugin version="2">
|
<plugin version="2">
|
||||||
<info>
|
<info>
|
||||||
<version>@_@PLUGIN_VERSION@_@</version>
|
<version>2.2.0</version>
|
||||||
<name>calendarimporter</name>
|
<name>calendarimporter</name>
|
||||||
<title>ICS Calendar Importer/Exporter</title>
|
<title>ICS Calendar Importer/Exporter</title>
|
||||||
<author>Christoph Haas</author>
|
<author>Christoph Haas</author>
|
||||||
@ -20,13 +20,14 @@
|
|||||||
<serverfile type="module" module="calendarmodule">php/module.calendar.php</serverfile>
|
<serverfile type="module" module="calendarmodule">php/module.calendar.php</serverfile>
|
||||||
</server>
|
</server>
|
||||||
<client>
|
<client>
|
||||||
<clientfile load="release">js/calendarimporter.js</clientfile>
|
<clientfile load="release">js/calendarimporter-debug.js</clientfile>
|
||||||
<clientfile load="debug">js/calendarimporter-debug.js</clientfile>
|
<clientfile load="debug">js/calendarimporter-debug.js</clientfile>
|
||||||
|
|
||||||
<clientfile load="source">js/data/timezones.js</clientfile>
|
<clientfile load="source">js/data/timezones.js</clientfile>
|
||||||
<clientfile load="source">js/external/Ext.util.base64.js</clientfile>
|
<clientfile load="source">js/data/Actions.js</clientfile>
|
||||||
<clientfile load="source">js/plugin.calendarimporter.js</clientfile>
|
|
||||||
<clientfile load="source">js/data/ResponseHandler.js</clientfile>
|
<clientfile load="source">js/data/ResponseHandler.js</clientfile>
|
||||||
|
<clientfile load="source">js/external/Ext.util.base64.js</clientfile>
|
||||||
|
<clientfile load="source">js/ui/ContextMenu.js</clientfile>
|
||||||
<clientfile load="source">js/dialogs/ImportContentPanel.js</clientfile>
|
<clientfile load="source">js/dialogs/ImportContentPanel.js</clientfile>
|
||||||
<clientfile load="source">js/dialogs/ImportPanel.js</clientfile>
|
<clientfile load="source">js/dialogs/ImportPanel.js</clientfile>
|
||||||
<clientfile load="source">js/dialogs/settings/SettingsWidget.js</clientfile>
|
<clientfile load="source">js/dialogs/settings/SettingsWidget.js</clientfile>
|
||||||
@ -35,9 +36,10 @@
|
|||||||
<clientfile load="source">js/dialogs/settings/ui/CalSyncPanel.js</clientfile>
|
<clientfile load="source">js/dialogs/settings/ui/CalSyncPanel.js</clientfile>
|
||||||
<clientfile load="source">js/dialogs/settings/dialogs/CalSyncEditContentPanel.js</clientfile>
|
<clientfile load="source">js/dialogs/settings/dialogs/CalSyncEditContentPanel.js</clientfile>
|
||||||
<clientfile load="source">js/dialogs/settings/dialogs/CalSyncEditPanel.js</clientfile>
|
<clientfile load="source">js/dialogs/settings/dialogs/CalSyncEditPanel.js</clientfile>
|
||||||
|
<clientfile load="source">js/plugin.calendarimporter.js</clientfile>
|
||||||
</client>
|
</client>
|
||||||
<resources>
|
<resources>
|
||||||
<resourcefile load="release">resources/css/calendarimporter-min.css</resourcefile>
|
<resourcefile load="release">resources/css/calendarimporter.css</resourcefile>
|
||||||
<resourcefile load="debug">resources/css/calendarimporter.css</resourcefile>
|
<resourcefile load="debug">resources/css/calendarimporter.css</resourcefile>
|
||||||
<resourcefile load="source">resources/css/calendarimporter-main.css</resourcefile>
|
<resourcefile load="source">resources/css/calendarimporter-main.css</resourcefile>
|
||||||
</resources>
|
</resources>
|
||||||
|
5
php/.gitignore
vendored
Normal file
5
php/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
composer.phar
|
||||||
|
.composer.lock
|
||||||
|
composer.lock
|
||||||
|
vendor
|
||||||
|
vendor/*
|
5
php/composer.json
Normal file
5
php/composer.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"require": {
|
||||||
|
"sabre/vobject": "4.1"
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* download.php, zarafa calender to ics im/exporter
|
* download.php, zarafa calendar to ics im/exporter
|
||||||
*
|
*
|
||||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||||
* Copyright (C) 2012-2014 Christoph Haas
|
* Copyright (C) 2012-2016 Christoph Haas
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@ -20,25 +21,54 @@
|
|||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
$basedir = $_GET["basedir"];
|
namespace calendarimporter;
|
||||||
$secid = $_GET["secid"];
|
|
||||||
$fileid = $_GET["fileid"];
|
|
||||||
$realname = $_GET["realname"];
|
|
||||||
|
|
||||||
$secfile = $basedir . "/secid." . $secid;
|
class DownloadHandler
|
||||||
$icsfile = $basedir . "/" . $fileid . "." . $secid;
|
{
|
||||||
|
/**
|
||||||
|
* Download the given vcf file.
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function doDownload()
|
||||||
|
{
|
||||||
|
if (isset($_GET["token"])) {
|
||||||
|
$token = $_GET["token"];
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// if the secid file exists -> download!
|
if (isset($_GET["filename"])) {
|
||||||
if(file_exists($secfile)) {
|
$filename = $_GET["filename"];
|
||||||
@header("Last-Modified: " . @gmdate("D, d M Y H:i:s",time()) . " GMT");
|
} else {
|
||||||
@header("Content-type: text/calendar");
|
return false;
|
||||||
header("Content-Length: " . filesize($icsfile));
|
}
|
||||||
header("Content-Disposition: attachment; filename=" . $realname . ".ics");
|
|
||||||
|
|
||||||
//write ics
|
// validate token
|
||||||
readfile($icsfile);
|
if (!ctype_alnum($token)) { // token is a md5 hash
|
||||||
unlink($secfile);
|
return false;
|
||||||
unlink($icsfile);
|
}
|
||||||
|
|
||||||
|
$file = PLUGIN_CALENDARIMPORTER_TMP_UPLOAD . "ics_" . $token . ".ics";
|
||||||
|
|
||||||
|
if (!file_exists($file)) { // invalid token
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set headers here
|
||||||
|
header('Content-Disposition: attachment; filename="' . $filename . '"');
|
||||||
|
|
||||||
|
// no caching
|
||||||
|
header('Expires: 0'); // set expiration time
|
||||||
|
header('Content-Description: File Transfer');
|
||||||
|
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
||||||
|
header('Content-Length: ' . filesize($file));
|
||||||
|
header('Content-Type: application/octet-stream');
|
||||||
|
header('Pragma: public');
|
||||||
|
flush();
|
||||||
|
|
||||||
|
// print the downloaded file
|
||||||
|
readfile($file);
|
||||||
|
ignore_user_abort(true);
|
||||||
|
unlink($file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
|
File diff suppressed because it is too large
Load Diff
@ -1,552 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* class.icalparser.php zarafa calender to ics im/exporter
|
|
||||||
* http://code.google.com/p/ics-parser/
|
|
||||||
*
|
|
||||||
* Author: Martin Thoma , Christoph Haas <christoph.h@sprinternet.at>
|
|
||||||
* Copyright (C) 2012-2014 Christoph Haas
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library 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
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the iCal-class
|
|
||||||
* Parse ics file content to array.
|
|
||||||
*
|
|
||||||
* @param {string} filename The name of the file which should be parsed
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
class ICal {
|
|
||||||
/* How many ToDos are in this ical? */
|
|
||||||
public /** @type {int} */ $todo_count = 0;
|
|
||||||
|
|
||||||
/* How many events are in this ical? */
|
|
||||||
public /** @type {int} */ $event_count = 0;
|
|
||||||
|
|
||||||
/* Currently editing an alarm? */
|
|
||||||
private /** @type {boolean} */ $isalarm = false;
|
|
||||||
|
|
||||||
/* The parsed calendar */
|
|
||||||
public /** @type {Array} */ $cal;
|
|
||||||
|
|
||||||
/* Error message store... null default */
|
|
||||||
public /** @type {String} */ $errors;
|
|
||||||
|
|
||||||
/* Which keyword has been added to cal at last? */
|
|
||||||
private /** @type {string} */ $_lastKeyWord;
|
|
||||||
|
|
||||||
/* The default timezone, used to convert UTC Time */
|
|
||||||
private /** @type {string} */ $default_timezone = "Europe/Vienna";
|
|
||||||
|
|
||||||
/* The default timezone, used to convert UTC Time */
|
|
||||||
private /** @type {boolean} */ $timezone_set = false;
|
|
||||||
|
|
||||||
/* Ignore Daylight Saving Time */
|
|
||||||
private /** @type {boolean} */ $ignore_dst = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the iCal-Object
|
|
||||||
*
|
|
||||||
* @param {string} $filename The path to the iCal-file
|
|
||||||
*
|
|
||||||
* @return Object The iCal-Object
|
|
||||||
*/
|
|
||||||
public function __construct($filename, $default_timezone, $timezone = false, $igndst = false) {
|
|
||||||
if (!$filename) {
|
|
||||||
$this->errors = "No filename specified";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->default_timezone = $default_timezone;
|
|
||||||
|
|
||||||
if(isset($timezone) && $timezone != false) {
|
|
||||||
$this->default_timezone = $timezone;
|
|
||||||
$this->timezone_set = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($igndst) && $igndst != false) {
|
|
||||||
$this->ignore_dst = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
|
||||||
if (stristr($lines[0], 'BEGIN:VCALENDAR') === false) {
|
|
||||||
$this->errors = "Not a valid ical file";
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
foreach ($lines as $line) {
|
|
||||||
$line = trim($line);
|
|
||||||
$add = $this->keyValueFromString($line);
|
|
||||||
if ($add === false) {
|
|
||||||
$this->addCalendarComponentWithKeyAndValue($type, false, $line);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
list($keyword, $dummy, $prop, $propvalue, $value) = $add;
|
|
||||||
|
|
||||||
switch ($line) {
|
|
||||||
// http://www.kanzaki.com/docs/ical/vtodo.html
|
|
||||||
case "BEGIN:VTODO":
|
|
||||||
$this->todo_count++;
|
|
||||||
$type = "VTODO";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "BEGIN:VALARM":
|
|
||||||
//echo "vevent gematcht";
|
|
||||||
$this->isalarm=true;
|
|
||||||
$type = "VEVENT";
|
|
||||||
break;
|
|
||||||
// http://www.kanzaki.com/docs/ical/vevent.html
|
|
||||||
case "BEGIN:VEVENT":
|
|
||||||
//echo "vevent gematcht";
|
|
||||||
$this->event_count++;
|
|
||||||
$type = "VEVENT";
|
|
||||||
break;
|
|
||||||
|
|
||||||
//all other special strings
|
|
||||||
case "BEGIN:VCALENDAR":
|
|
||||||
case "BEGIN:DAYLIGHT":
|
|
||||||
// http://www.kanzaki.com/docs/ical/vtimezone.html
|
|
||||||
case "BEGIN:VTIMEZONE":
|
|
||||||
case "BEGIN:STANDARD":
|
|
||||||
$type = $value;
|
|
||||||
break;
|
|
||||||
case "END:VTODO": // end special text - goto VCALENDAR key
|
|
||||||
case "END:VEVENT":
|
|
||||||
case "END:VCALENDAR":
|
|
||||||
case "END:DAYLIGHT":
|
|
||||||
case "END:VTIMEZONE":
|
|
||||||
case "END:STANDARD":
|
|
||||||
$type = "VCALENDAR";
|
|
||||||
break;
|
|
||||||
case "END:VALARM":
|
|
||||||
$this->isalarm=false;
|
|
||||||
$type = "VEVENT";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$this->addCalendarComponentWithKeyAndValue($type, $keyword, $value, $prop, $propvalue);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $this->cal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add to $this->ical array one value and key.
|
|
||||||
*
|
|
||||||
* @param {string} $component This could be VTODO, VEVENT, VCALENDAR, ...
|
|
||||||
* @param {string} $keyword The keyword, for example DTSTART
|
|
||||||
* @param {string} $value The value, for example 20110105T090000Z
|
|
||||||
*
|
|
||||||
* @return {None}
|
|
||||||
*/
|
|
||||||
public function addCalendarComponentWithKeyAndValue($component, $keyword, $value, $prop = false, $propvalue = false) {
|
|
||||||
if ($keyword == false) { // multiline value
|
|
||||||
$keyword = $this->last_keyword;
|
|
||||||
|
|
||||||
switch ($component) {
|
|
||||||
case 'VEVENT':
|
|
||||||
if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND") or stristr($keyword, "TRIGGER")) {
|
|
||||||
$ts = $this->iCalDateToUnixTimestamp($value, $prop, $propvalue);
|
|
||||||
$value = $ts * 1000;
|
|
||||||
}
|
|
||||||
$value = str_replace("\\n", "\n", $value);
|
|
||||||
|
|
||||||
$value = $this->customFilters($keyword, $value);
|
|
||||||
|
|
||||||
if(!$this->isalarm) {
|
|
||||||
$value = $this->cal[$component][$this->event_count - 1][$keyword].$value;
|
|
||||||
} else {
|
|
||||||
$value = $this->cal[$component][$this->event_count - 1]["VALARM"][$keyword].$value;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'VTODO' :
|
|
||||||
$value = $this->cal[$component][$this->todo_count - 1]
|
|
||||||
[$keyword].$value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This should not be neccesary anymore*/
|
|
||||||
//always strip additional content....
|
|
||||||
//if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) {
|
|
||||||
//$keyword = explode(";", $keyword);
|
|
||||||
//$keyword = $keyword[0]; // remove additional content like VALUE=DATE
|
|
||||||
//}
|
|
||||||
|
|
||||||
if ((stristr($keyword, "TIMEZONE") || stristr($keyword, "TZID")) && !$this->timezone_set) { // check if timezone already set...
|
|
||||||
$this->default_timezone = $this->trimTimeZone($value); // store the calendertimezone
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($component) {
|
|
||||||
case "VTODO":
|
|
||||||
$this->cal[$component][$this->todo_count - 1][$keyword] = $value;
|
|
||||||
//$this->cal[$component][$this->todo_count]['Unix'] = $unixtime;
|
|
||||||
break;
|
|
||||||
case "VEVENT":
|
|
||||||
if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND") or stristr($keyword, "TRIGGER")) {
|
|
||||||
$ts = $this->iCalDateToUnixTimestamp($value, $prop, $propvalue);
|
|
||||||
$value = $ts * 1000;
|
|
||||||
}
|
|
||||||
$value = str_replace("\\n", "\n", $value);
|
|
||||||
|
|
||||||
$value = $this->customFilters($keyword, $value);
|
|
||||||
|
|
||||||
if(!$this->isalarm) {
|
|
||||||
$this->cal[$component][$this->event_count - 1][$keyword] = $value;
|
|
||||||
} else {
|
|
||||||
$this->cal[$component][$this->event_count - 1]["VALARM"][$keyword] = $value;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$this->cal[$component][$keyword] = $value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$this->last_keyword = $keyword;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter some chars out of the value.
|
|
||||||
*
|
|
||||||
* @param {string} $keyword keyword to which the filter is applied
|
|
||||||
* @param {string} $value to filter
|
|
||||||
* @return {string} filtered value
|
|
||||||
*/
|
|
||||||
private function customFilters($keyword, $value) {
|
|
||||||
if (stristr($keyword, "SUMMARY")) {
|
|
||||||
$value = str_replace("\n", " ", $value); // we don't need linebreaks in the summary...
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stristr($keyword, "SUMMARY")) {
|
|
||||||
$value = str_replace("\,", ",", $value); // strange escaped comma
|
|
||||||
}
|
|
||||||
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trim a Timezone String
|
|
||||||
*
|
|
||||||
* @param {string} $timezone timezone string which should be trimmed
|
|
||||||
* @return {string} trimmed value
|
|
||||||
*/
|
|
||||||
private function trimTimeZone($timezone) {
|
|
||||||
if(preg_match('~([?<=/]*)([^/]*[/|-][^/]*$)~', $timezone, $matches)) { // detects tzurls in tzids
|
|
||||||
if ($matches[2] != "") {
|
|
||||||
return $matches[2]; // 2 = extracted timezone
|
|
||||||
} else {
|
|
||||||
return $timezone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $timezone;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a key-value pair of a string.
|
|
||||||
*
|
|
||||||
* @param {string} $text which is like "VCALENDAR:Begin" or "LOCATION:"
|
|
||||||
*
|
|
||||||
* @return {array} array("Argument", "Optional Arg/Val", "Optional Arg", "Optional Value", "Value")
|
|
||||||
*/
|
|
||||||
public function keyValueFromString($text) {
|
|
||||||
|
|
||||||
preg_match('/(^[^a-z:;]+)([;]+([a-zA-Z]*)[=]*([^:"]*|"[\w\W]*"))?[:]([\w\W]*)/', $text, $matches);
|
|
||||||
|
|
||||||
// this regex has problems with multiple attributes... ATTENDEE;RSVP=TRUE;ROLE=REQ-PARTICIPANT:mailto:jsmith@example.com
|
|
||||||
// TODO: fix this
|
|
||||||
|
|
||||||
if (count($matches) == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$matches = array_splice($matches, 1, 5); // 0 = Arg, 1 = Complete Optional Arg/Val, 2 = Optional Arg, 3 = Optional Val, 4 = Value
|
|
||||||
return $matches;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return UTC Unix timestamp from ical date time format
|
|
||||||
*
|
|
||||||
* @param {string} $icalDate A Date in the format YYYYMMDD[T]HHMMSS[Z] or
|
|
||||||
* YYYYMMDD[T]HHMMSS
|
|
||||||
*
|
|
||||||
* @return {int}
|
|
||||||
*/
|
|
||||||
private function iCalDateToUTCUnixTimestamp($icalDate, $prop, $propvalue) {
|
|
||||||
|
|
||||||
$timezone = false;
|
|
||||||
$allday = false;
|
|
||||||
|
|
||||||
if($prop) {
|
|
||||||
$pos = strpos("TZIDtzid", $prop);
|
|
||||||
if($pos !== false && $propvalue != false) {
|
|
||||||
$timezone = str_replace('"', '', $propvalue);
|
|
||||||
$timezone = str_replace('\'', '', $timezone);
|
|
||||||
$timezone = $this->trimTimeZone($timezone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* timestring format */
|
|
||||||
$utc = strpos("zZ",substr($icalDate, -1)) === false ? false : true;
|
|
||||||
|
|
||||||
$icalDate = str_replace('T', '', $icalDate);
|
|
||||||
$icalDate = str_replace('Z', '', $icalDate);
|
|
||||||
|
|
||||||
$pattern = '/([0-9]{4})'; // 1: YYYY
|
|
||||||
$pattern .= '([0-9]{2})'; // 2: MM
|
|
||||||
$pattern .= '([0-9]{2})'; // 3: DD
|
|
||||||
$pattern .= '([0-9]{0,2})'; // 4: HH
|
|
||||||
$pattern .= '([0-9]{0,2})'; // 5: MM
|
|
||||||
$pattern .= '([0-9]{0,2})/'; // 6: SS
|
|
||||||
preg_match($pattern, $icalDate, $date);
|
|
||||||
|
|
||||||
// Unix timestamp can't represent dates before 1970
|
|
||||||
if ($date[1] <= 1970) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if we have a allday event
|
|
||||||
if((!$date[6] || $date[6] === "") || (!$date[5] || $date[5] === "") || (!$date[4] || $date[4] === "")) {
|
|
||||||
$date[6] = 0;
|
|
||||||
$date[5] = 0;
|
|
||||||
$date[4] = 0;
|
|
||||||
$allday = true;
|
|
||||||
|
|
||||||
$dtz = date_default_timezone_get();
|
|
||||||
date_default_timezone_set('UTC');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unix timestamps after 03:14:07 UTC 2038-01-19 might cause an overflow
|
|
||||||
// if 32 bit integers are used.
|
|
||||||
$timestamp = mktime((int)$date[4],
|
|
||||||
(int)$date[5],
|
|
||||||
(int)$date[6],
|
|
||||||
(int)$date[2],
|
|
||||||
(int)$date[3],
|
|
||||||
(int)$date[1]);
|
|
||||||
|
|
||||||
if($allday) {
|
|
||||||
date_default_timezone_set($dtz);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!$utc && !$allday) {
|
|
||||||
$tz = $this->default_timezone;
|
|
||||||
if($timezone != false) {
|
|
||||||
$tz = $timezone;
|
|
||||||
}
|
|
||||||
|
|
||||||
$error = false;
|
|
||||||
$this_tz = false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this_tz = new DateTimeZone($tz);
|
|
||||||
} catch(Exception $e) {
|
|
||||||
error_log($e->getMessage());
|
|
||||||
$error = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($error) {
|
|
||||||
try { // Try using the default calendar timezone
|
|
||||||
$this_tz = new DateTimeZone($this->default_timezone);
|
|
||||||
} catch(Exception $e) {
|
|
||||||
error_log($e->getMessage());
|
|
||||||
$timestamp_utc = $timestamp; // if that fails, we cannot do anymore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if($this_tz != false) {
|
|
||||||
$tz_now = new DateTime("now", $this_tz);
|
|
||||||
$tz_offset = $this_tz->getOffset($tz_now);
|
|
||||||
$timestamp_utc = $timestamp - $tz_offset;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$timestamp_utc = $timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return array($timestamp_utc,$allday);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a timezone specific timestamp
|
|
||||||
* @param {int} $timestamp_utc UTC Timestamp to convert
|
|
||||||
* @param {string} $timezone Timezone
|
|
||||||
* @return {int}
|
|
||||||
*/
|
|
||||||
private function UTCTimestampToTZTimestamp($timestamp_utc, $timezone, $ignore_dst = false) {
|
|
||||||
$this_tz = false;
|
|
||||||
try { // Try using the default calendar timezone
|
|
||||||
$this_tz = new DateTimeZone($this->default_timezone);
|
|
||||||
} catch(Exception $e) {
|
|
||||||
error_log($e->getMessage());
|
|
||||||
$timestamp_utc = $timestamp; // if that fails, we cannot do anymore
|
|
||||||
}
|
|
||||||
if($this_tz != false) {
|
|
||||||
$transition = $this_tz->getTransitions($timestamp_utc,$timestamp_utc);
|
|
||||||
$trans_offset = $transition[0]['offset'];
|
|
||||||
$isdst = $transition[0]['isdst'];
|
|
||||||
|
|
||||||
$tz_now = new DateTime("now", $this_tz);
|
|
||||||
$tz_offset = $this_tz->getOffset($tz_now);
|
|
||||||
|
|
||||||
if(!$ignore_dst) {
|
|
||||||
$tz_offset = $trans_offset; // normaly use dst
|
|
||||||
}
|
|
||||||
|
|
||||||
return $timestamp_utc + $tz_offset;
|
|
||||||
}
|
|
||||||
return $timestamp_utc; // maybe timezone conversion will fail...
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return Timezone specific Unix timestamp from ical date time format
|
|
||||||
*
|
|
||||||
* @param {string} $icalDate A Date in the format YYYYMMDD[T]HHMMSS[Z] or
|
|
||||||
* YYYYMMDD[T]HHMMSS
|
|
||||||
*
|
|
||||||
* @return {int}
|
|
||||||
*/
|
|
||||||
public function iCalDateToUnixTimestamp($icalDate, $prop, $propvalue) {
|
|
||||||
list($timestamp, $allday) = $this->iCalDateToUTCUnixTimestamp($icalDate, $prop, $propvalue);
|
|
||||||
|
|
||||||
if(!$allday) {
|
|
||||||
$timestamp = $this->UTCTimestampToTZTimestamp($timestamp, $this->default_timezone, $this->ignore_dst, $allday);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an array of arrays with all events. Every event is an associative
|
|
||||||
* array and each property is an element it.
|
|
||||||
*
|
|
||||||
* @return {array}
|
|
||||||
*/
|
|
||||||
public function events() {
|
|
||||||
$array = $this->cal;
|
|
||||||
return $array['VEVENT'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an array of calendar types.
|
|
||||||
*
|
|
||||||
* @return {array}
|
|
||||||
*/
|
|
||||||
public function calendar() {
|
|
||||||
$array = $this->cal;
|
|
||||||
return $array['VCALENDAR'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the default or set timezone
|
|
||||||
*
|
|
||||||
* @return {string}
|
|
||||||
*/
|
|
||||||
public function timezone() {
|
|
||||||
return $this->default_timezone;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a boolean value whether thr current calendar has events or not
|
|
||||||
*
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
public function hasEvents() {
|
|
||||||
return ( count($this->events()) > 0 ? true : false );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns false when the current calendar has no events in range, else the
|
|
||||||
* events.
|
|
||||||
*
|
|
||||||
* Note that this function makes use of a UNIX timestamp. This might be a
|
|
||||||
* problem on January the 29th, 2038.
|
|
||||||
* See http://en.wikipedia.org/wiki/Unix_time#Representing_the_number
|
|
||||||
*
|
|
||||||
* @param {boolean} $rangeStart Either true or false
|
|
||||||
* @param {boolean} $rangeEnd Either true or false
|
|
||||||
*
|
|
||||||
* @return {mixed}
|
|
||||||
*/
|
|
||||||
public function eventsFromRange($rangeStart = false, $rangeEnd = false) {
|
|
||||||
$events = $this->sortEventsWithOrder($this->events(), SORT_ASC);
|
|
||||||
|
|
||||||
if (!$events) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$extendedEvents = array();
|
|
||||||
|
|
||||||
if ($rangeStart !== false) {
|
|
||||||
$rangeStart = new DateTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($rangeEnd !== false or $rangeEnd <= 0) {
|
|
||||||
$rangeEnd = new DateTime('2038/01/18');
|
|
||||||
} else {
|
|
||||||
$rangeEnd = new DateTime($rangeEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
$rangeStart = $rangeStart->format('U');
|
|
||||||
$rangeEnd = $rangeEnd->format('U');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// loop through all events by adding two new elements
|
|
||||||
foreach ($events as $anEvent) {
|
|
||||||
$timestamp = $this->iCalDateToUnixTimestamp($anEvent['DTSTART']);
|
|
||||||
if ($timestamp >= $rangeStart && $timestamp <= $rangeEnd) {
|
|
||||||
$extendedEvents[] = $anEvent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $extendedEvents;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns sorted events
|
|
||||||
*
|
|
||||||
* @param {array} $events An array with events.
|
|
||||||
* @param {array} $sortOrder Either SORT_ASC, SORT_DESC, SORT_REGULAR,
|
|
||||||
* SORT_NUMERIC, SORT_STRING
|
|
||||||
*
|
|
||||||
* @return {array}
|
|
||||||
*/
|
|
||||||
public function sortEventsWithOrder($events, $sortOrder = SORT_ASC) {
|
|
||||||
$extendedEvents = array();
|
|
||||||
|
|
||||||
// loop through all events by adding two new elements
|
|
||||||
foreach ($events as $anEvent) {
|
|
||||||
if (!array_key_exists('UNIX_TIMESTAMP', $anEvent)) {
|
|
||||||
$anEvent['UNIX_TIMESTAMP'] = $this->iCalDateToUnixTimestamp($anEvent['DTSTART']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!array_key_exists('REAL_DATETIME', $anEvent)) {
|
|
||||||
$anEvent['REAL_DATETIME'] = date("d.m.Y", $anEvent['UNIX_TIMESTAMP']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$extendedEvents[] = $anEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($extendedEvents as $key => $value) {
|
|
||||||
$timestamp[$key] = $value['UNIX_TIMESTAMP'];
|
|
||||||
}
|
|
||||||
array_multisort($timestamp, $sortOrder, $extendedEvents);
|
|
||||||
|
|
||||||
return $extendedEvents;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
@ -21,21 +21,61 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
include_once('mapi/class.recurrence.php');
|
include_once('vendor/autoload.php');
|
||||||
include_once('plugins/calendarimporter/php/ical/class.icalcreator.php');
|
|
||||||
include_once('plugins/calendarimporter/php/ical/class.icalparser.php');
|
|
||||||
|
|
||||||
class CalendarModule extends Module {
|
use Sabre\VObject;
|
||||||
|
|
||||||
private $DEBUG = false; // enable error_log debugging
|
class CalendarModule extends Module
|
||||||
|
{
|
||||||
|
|
||||||
|
private $DEBUG = true; // enable error_log debugging
|
||||||
|
|
||||||
|
private $busystates = null;
|
||||||
|
|
||||||
|
private $labels = null;
|
||||||
|
|
||||||
|
private $attendeetype = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param $id
|
* @param $id
|
||||||
* @param $data
|
* @param $data
|
||||||
*/
|
*/
|
||||||
public function __construct($id, $data) {
|
public function __construct($id, $data)
|
||||||
parent::Module($id, $data);
|
{
|
||||||
|
parent::__construct($id, $data);
|
||||||
|
|
||||||
|
// init default timezone
|
||||||
|
date_default_timezone_set(PLUGIN_CALENDARIMPORTER_DEFAULT_TIMEZONE);
|
||||||
|
|
||||||
|
// init mappings
|
||||||
|
$this->busystates = array(
|
||||||
|
"FREE",
|
||||||
|
"TENTATIVE",
|
||||||
|
"BUSY",
|
||||||
|
"OOF"
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->labels = array(
|
||||||
|
"NONE",
|
||||||
|
"IMPORTANT",
|
||||||
|
"WORK",
|
||||||
|
"PERSONAL",
|
||||||
|
"HOLIDAY",
|
||||||
|
"REQUIRED",
|
||||||
|
"TRAVEL REQUIRED",
|
||||||
|
"PREPARATION REQUIERED",
|
||||||
|
"BIRTHDAY",
|
||||||
|
"SPECIAL DATE",
|
||||||
|
"PHONE INTERVIEW"
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->attendeetype = array(
|
||||||
|
"NON-PARTICIPANT", // needed as zarafa starts counting at 1
|
||||||
|
"REQ-PARTICIPANT",
|
||||||
|
"OPT-PARTICIPANT",
|
||||||
|
"NON-PARTICIPANT"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,28 +83,32 @@ class CalendarModule extends Module {
|
|||||||
* Exception part is used for authentication errors also
|
* Exception part is used for authentication errors also
|
||||||
* @return boolean true on success or false on failure.
|
* @return boolean true on success or false on failure.
|
||||||
*/
|
*/
|
||||||
public function execute() {
|
public function execute()
|
||||||
|
{
|
||||||
$result = false;
|
$result = false;
|
||||||
|
|
||||||
if(!$this->DEBUG) {
|
if (!$this->DEBUG) {
|
||||||
/* disable error printing - otherwise json communication might break... */
|
/* disable error printing - otherwise json communication might break... */
|
||||||
ini_set('display_errors', '0');
|
ini_set('display_errors', '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($this->data as $actionType => $actionData) {
|
foreach ($this->data as $actionType => $actionData) {
|
||||||
if(isset($actionType)) {
|
if (isset($actionType)) {
|
||||||
try {
|
try {
|
||||||
if($this->DEBUG) {
|
if ($this->DEBUG) {
|
||||||
error_log("exec: " . $actionType);
|
error_log("exec: " . $actionType);
|
||||||
}
|
}
|
||||||
switch($actionType) {
|
switch ($actionType) {
|
||||||
|
case "load":
|
||||||
|
$result = $this->loadCalendar($actionType, $actionData);
|
||||||
|
break;
|
||||||
case "export":
|
case "export":
|
||||||
$result = $this->exportCalendar($actionType, $actionData);
|
$result = $this->exportCalendar($actionType, $actionData);
|
||||||
break;
|
break;
|
||||||
case "import":
|
case "import":
|
||||||
$result = $this->importCalendar($actionType, $actionData);
|
$result = $this->importCalendar($actionType, $actionData);
|
||||||
break;
|
break;
|
||||||
case "attachmentpath":
|
case "importattachment":
|
||||||
$result = $this->getAttachmentPath($actionType, $actionData);
|
$result = $this->getAttachmentPath($actionType, $actionData);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -72,11 +116,11 @@ class CalendarModule extends Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (MAPIException $e) {
|
} catch (MAPIException $e) {
|
||||||
if($this->DEBUG) {
|
if ($this->DEBUG) {
|
||||||
error_log("mapi exception: " . $e->getMessage());
|
error_log("mapi exception: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
if($this->DEBUG) {
|
if ($this->DEBUG) {
|
||||||
error_log("exception: " . $e->getMessage());
|
error_log("exception: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,11 +135,12 @@ class CalendarModule extends Module {
|
|||||||
* @param $length the lenght of the generated string
|
* @param $length the lenght of the generated string
|
||||||
* @return string a random string
|
* @return string a random string
|
||||||
*/
|
*/
|
||||||
private function randomstring($length = 6) {
|
private function randomstring($length = 6)
|
||||||
|
{
|
||||||
// $chars - all allowed charakters
|
// $chars - all allowed charakters
|
||||||
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
||||||
|
|
||||||
srand((double)microtime()*1000000);
|
srand((double)microtime() * 1000000);
|
||||||
$i = 0;
|
$i = 0;
|
||||||
$pass = "";
|
$pass = "";
|
||||||
while ($i < $length) {
|
while ($i < $length) {
|
||||||
@ -108,224 +153,60 @@ class CalendarModule extends Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the secid file (used to verify the download path)
|
* Get a property from the array.
|
||||||
* @param $secid the secid, a random security token
|
* @param $props
|
||||||
|
* @param $propname
|
||||||
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function createSecIDFile($secid) {
|
private function getProp($props, $propname)
|
||||||
$lockFile = TMP_PATH . "/secid." . $secid;
|
{
|
||||||
$fh = fopen($lockFile, 'w') or die("can't open secid file");
|
if (isset($props["props"][$propname])) {
|
||||||
$stringData = date(DATE_RFC822);
|
return $props["props"][$propname];
|
||||||
fwrite($fh, $stringData);
|
}
|
||||||
fclose($fh);
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function getDurationStringFromMintues($minutes, $pos = false) {
|
||||||
* Generates the secid file (used to verify the download path)
|
$pos = $pos === true ? "+" : "-";
|
||||||
* @param $time a timestamp
|
$str = $pos . "P";
|
||||||
* @param $incl_time true if date should include time
|
|
||||||
* @ return date object
|
|
||||||
*/
|
|
||||||
private function getIcalDate($time, $incl_time = true) {
|
|
||||||
return $incl_time ? date('Ymd\THis', $time) : date('Ymd', $time);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* adds an event to the exported calendar)
|
|
||||||
* @param $vevent pointer to the eventstore
|
|
||||||
* @param $event the event to add
|
|
||||||
*/
|
|
||||||
private function addEvent(&$vevent, $event) {
|
|
||||||
|
|
||||||
$busystate = array("FREE", "TENTATIVE", "BUSY", "OOF");
|
|
||||||
$zlabel = array("NONE", "IMPORTANT", "WORK", "PERSONAL", "HOLIDAY", "REQUIRED", "TRAVEL REQUIRED", "PREPARATION REQUIERED", "BIRTHDAY", "SPECIAL DATE", "PHONE INTERVIEW");
|
|
||||||
|
|
||||||
$vevent->setProperty("LOCATION", $event["location"]); // property name - case independent
|
// variables for holding values
|
||||||
$vevent->setProperty("SUMMARY", $event["subject"]);
|
$mins = intval($minutes);
|
||||||
$vevent->setProperty("DESCRIPTION", str_replace("\n", "\\n",$event["description"]));
|
$hours = 0;
|
||||||
$vevent->setProperty("COMMENT", "Exported from Zarafa" );
|
$days = 0;
|
||||||
$vevent->setProperty("ORGANIZER", $event["sent_representing_email_address"]);
|
$weeks = 0;
|
||||||
$vevent->setProperty("DTSTART", $this->getIcalDate($event["commonstart"]) . "Z");
|
|
||||||
$vevent->setProperty("DTEND", $this->getIcalDate($event["commonend"]) . "Z");
|
|
||||||
$vevent->setProperty("DTSTAMP", $this->getIcalDate($event["creation_time"]) . "Z");
|
|
||||||
$vevent->setProperty("CREATED", $this->getIcalDate($event["creation_time"]) . "Z");
|
|
||||||
$vevent->setProperty("LAST-MODIFIED", $this->getIcalDate($event["last_modification_time"]) . "Z");
|
|
||||||
$vevent->setProperty("X-MICROSOFT-CDO-BUSYSTATUS", $busystate[$event["busystatus"]]);
|
|
||||||
$vevent->setProperty("X-ZARAFA-LABEL", $zlabel[$event["label"]]);
|
|
||||||
$vevent->setProperty("PRIORITY", $event["importance"]);
|
|
||||||
$vevent->setProperty("CLASS", $event["private"] ? "PRIVATE" : "PUBLIC");
|
|
||||||
|
|
||||||
// ATTENDEES
|
// calculations
|
||||||
if(count($event["attendees"]) > 0) {
|
if ( $mins >= 60 ) {
|
||||||
foreach($event["attendees"] as $attendee) {
|
$hours = (int)($mins / 60);
|
||||||
$vevent->setProperty("ATTENDEE", $attendee["props"]["smtp_address"]);
|
$mins = $mins % 60;
|
||||||
}
|
}
|
||||||
|
if ( $hours >= 24 ) {
|
||||||
|
$days = (int)($hours / 24);
|
||||||
|
$hours = $hours % 60;
|
||||||
|
}
|
||||||
|
if ( $days >= 7 ) {
|
||||||
|
$weeks = (int)($days / 7);
|
||||||
|
$days = $days % 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
// REMINDERS
|
// format result
|
||||||
if($event["reminder"]) {
|
if ( $weeks ) {
|
||||||
$valarm = & $vevent->newComponent("valarm"); // create an event alarm
|
$str .= "{$weeks}W";
|
||||||
$valarm->setProperty("action", "DISPLAY" );
|
|
||||||
$valarm->setProperty("description", $vevent->getProperty("SUMMARY")); // reuse the event summary
|
|
||||||
$valarm->setProperty("trigger", $this->getIcalDate($event["reminder_time"]) . "Z"); // create alarm trigger (in UTC datetime)
|
|
||||||
}
|
}
|
||||||
}
|
if ( $days ) {
|
||||||
|
$str .= "{$days}D";
|
||||||
/**
|
}
|
||||||
* Loads the descriptiontext of an event
|
if ( $hours ) {
|
||||||
* @param $event
|
$str .= "{$hours}H";
|
||||||
* @return array with event description/body
|
}
|
||||||
*/
|
if ( $mins ) {
|
||||||
private function loadEventDescription($event) {
|
$str .= "{$mins}M";
|
||||||
$entryid = $this->getActionEntryID($event);
|
|
||||||
$store = $this->getActionStore($event);
|
|
||||||
|
|
||||||
$basedate = null;
|
|
||||||
|
|
||||||
$properties = $GLOBALS['properties']->getAppointmentProperties();
|
|
||||||
$plaintext = true;
|
|
||||||
|
|
||||||
$data = array();
|
|
||||||
|
|
||||||
if($store && $entryid) {
|
|
||||||
$message = $GLOBALS['operations']->openMessage($store, $entryid);
|
|
||||||
|
|
||||||
|
|
||||||
// add all standard properties from the series/normal message
|
|
||||||
$data['item'] = $GLOBALS['operations']->getMessageProps($store, $message, $properties, (isset($plaintext) && $plaintext));
|
|
||||||
|
|
||||||
// if appointment is recurring then only we should get properties of occurence if basedate is supplied
|
|
||||||
if($data['item']['props']['recurring'] === true) {
|
|
||||||
if(isset($basedate) && $basedate) {
|
|
||||||
$recur = new Recurrence($store, $message);
|
|
||||||
|
|
||||||
$exceptionatt = $recur->getExceptionAttachment($basedate);
|
|
||||||
|
|
||||||
// Single occurences are never recurring
|
|
||||||
$data['item']['props']['recurring'] = false;
|
|
||||||
|
|
||||||
if($exceptionatt) {
|
|
||||||
// Existing exception (open existing item, which includes basedate)
|
|
||||||
$exceptionattProps = mapi_getprops($exceptionatt, array(PR_ATTACH_NUM));
|
|
||||||
$exception = mapi_attach_openobj($exceptionatt, 0);
|
|
||||||
|
|
||||||
// overwrite properties with the ones from the exception
|
|
||||||
$exceptionProps = $GLOBALS['operations']->getMessageProps($store, $exception, $properties, (isset($plaintext) && $plaintext));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If recurring item has set reminder to true then
|
|
||||||
* all occurrences before the 'flagdueby' value(of recurring item)
|
|
||||||
* should not show that reminder is set.
|
|
||||||
*/
|
|
||||||
if (isset($exceptionProps['props']['reminder']) && $data['item']['props']['reminder'] == true) {
|
|
||||||
$flagDueByDay = $recur->dayStartOf($data['item']['props']['flagdueby']);
|
|
||||||
|
|
||||||
if ($flagDueByDay > $basedate) {
|
|
||||||
$exceptionProps['props']['reminder'] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The properties must be merged, if the recipients or attachments are present in the exception
|
|
||||||
// then that list should be used. Otherwise the list from the series must be applied (this
|
|
||||||
// corresponds with OL2007).
|
|
||||||
// @FIXME getMessageProps should not return empty string if exception doesn't contain body
|
|
||||||
// by this change we can handle a situation where user has set empty string in the body explicitly
|
|
||||||
if (!empty($exceptionProps['props']['body']) || !empty($exceptionProps['props']['html_body'])) {
|
|
||||||
if(!empty($exceptionProps['props']['body'])) {
|
|
||||||
$data['item']['props']['body'] = $exceptionProps['props']['body'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!empty($exceptionProps['props']['html_body'])) {
|
|
||||||
$data['item']['props']['html_body'] = $exceptionProps['props']['html_body'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$data['item']['props']['isHTML'] = $exceptionProps['props']['isHTML'];
|
|
||||||
}
|
|
||||||
// remove properties from $exceptionProps so array_merge will not overwrite it
|
|
||||||
unset($exceptionProps['props']['html_body']);
|
|
||||||
unset($exceptionProps['props']['body']);
|
|
||||||
unset($exceptionProps['props']['isHTML']);
|
|
||||||
|
|
||||||
$data['item']['props'] = array_merge($data['item']['props'], $exceptionProps['props']);
|
|
||||||
if (isset($exceptionProps['recipients'])) {
|
|
||||||
$data['item']['recipients'] = $exceptionProps['recipients'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($exceptionProps['attachments'])) {
|
|
||||||
$data['item']['attachments'] = $exceptionProps['attachments'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we are using the passed basedate and not something wrong in the opened item
|
|
||||||
$data['item']['props']['basedate'] = $basedate;
|
|
||||||
} else {
|
|
||||||
// opening an occurence of a recurring series (same as normal open, but add basedate, startdate and enddate)
|
|
||||||
$data['item']['props']['basedate'] = $basedate;
|
|
||||||
$data['item']['props']['startdate'] = $recur->getOccurrenceStart($basedate);
|
|
||||||
$data['item']['props']['duedate'] = $recur->getOccurrenceEnd($basedate);
|
|
||||||
$data['item']['props']['commonstart'] = $data['item']['props']['startdate'];
|
|
||||||
$data['item']['props']['commonend'] = $data['item']['props']['duedate'];
|
|
||||||
unset($data['item']['props']['reminder_time']);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If recurring item has set reminder to true then
|
|
||||||
* all occurrences before the 'flagdueby' value(of recurring item)
|
|
||||||
* should not show that reminder is set.
|
|
||||||
*/
|
|
||||||
if (isset($exceptionProps['props']['reminder']) && $data['item']['props']['reminder'] == true) {
|
|
||||||
$flagDueByDay = $recur->dayStartOf($data['item']['props']['flagdueby']);
|
|
||||||
|
|
||||||
if ($flagDueByDay > $basedate) {
|
|
||||||
$exceptionProps['props']['reminder'] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Opening a recurring series, get the recurrence information
|
|
||||||
$recur = new Recurrence($store, $message);
|
|
||||||
$recurpattern = $recur->getRecurrence();
|
|
||||||
$tz = $recur->tz; // no function to do this at the moment
|
|
||||||
|
|
||||||
// Add the recurrence pattern to the data
|
|
||||||
if(isset($recurpattern) && is_array($recurpattern)) {
|
|
||||||
$data['item']['props'] += $recurpattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the timezone information to the data
|
|
||||||
if(isset($tz) && is_array($tz)) {
|
|
||||||
$data['item']['props'] += $tz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data['item']['props']['body'];
|
return $str;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the attendees of an event
|
|
||||||
* @param $event
|
|
||||||
* @return array with event attendees
|
|
||||||
*/
|
|
||||||
private function loadAttendees($event) {
|
|
||||||
$entryid = $this->getActionEntryID($event);
|
|
||||||
$store = $this->getActionStore($event);
|
|
||||||
|
|
||||||
$basedate = null;
|
|
||||||
|
|
||||||
$properties = $GLOBALS['properties']->getAppointmentProperties();
|
|
||||||
$plaintext = true;
|
|
||||||
|
|
||||||
$data = array();
|
|
||||||
|
|
||||||
if($store && $entryid) {
|
|
||||||
$message = $GLOBALS['operations']->openMessage($store, $entryid);
|
|
||||||
|
|
||||||
|
|
||||||
// add all standard properties from the series/normal message
|
|
||||||
$data['item'] = $GLOBALS['operations']->getMessageProps($store, $message, $properties, (isset($plaintext) && $plaintext));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data['item']['recipients']['item'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -333,61 +214,137 @@ class CalendarModule extends Module {
|
|||||||
* @param $actionType
|
* @param $actionType
|
||||||
* @param $actionData
|
* @param $actionData
|
||||||
*/
|
*/
|
||||||
private function exportCalendar($actionType, $actionData) {
|
private function exportCalendar($actionType, $actionData)
|
||||||
$secid = $this->randomstring();
|
{
|
||||||
$this->createSecIDFile($secid);
|
// Get store id
|
||||||
$tmpname = stripslashes($actionData["calendar"] . ".ics." . $this->randomstring(8));
|
$storeid = false;
|
||||||
$filename = TMP_PATH . "/" . $tmpname . "." . $secid;
|
if (isset($actionData["storeid"])) {
|
||||||
|
$storeid = $actionData["storeid"];
|
||||||
if(!is_writable(TMP_PATH . "/")) {
|
|
||||||
error_log("could not write to export tmp directory!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$tz = date("e"); // use php timezone (maybe set up in php.ini, date.timezone)
|
// Get records
|
||||||
|
$records = array();
|
||||||
if($this->DEBUG) {
|
if (isset($actionData["records"])) {
|
||||||
error_log("PHP Timezone: " . $tz);
|
$records = $actionData["records"];
|
||||||
}
|
}
|
||||||
|
|
||||||
$config = array(
|
// Get folders
|
||||||
"language" => substr($GLOBALS["settings"]->get("zarafa/v1/main/language"),0,2),
|
$folder = false;
|
||||||
"directory" => TMP_PATH . "/",
|
if (isset($actionData["folder"])) {
|
||||||
"filename" => $tmpname . "." . $secid,
|
$folder = $actionData["folder"];
|
||||||
"unique_id" => "zarafa-export-plugin",
|
|
||||||
"TZID" => $tz
|
|
||||||
);
|
|
||||||
|
|
||||||
$v = new vcalendar($config);
|
|
||||||
$v->setProperty("method", "PUBLISH"); // required of some calendar software
|
|
||||||
$v->setProperty("x-wr-calname", $actionData["calendar"]); // required of some calendar software
|
|
||||||
$v->setProperty("X-WR-CALDESC", "Exported Zarafa Calendar"); // required of some calendar software
|
|
||||||
$v->setProperty("X-WR-TIMEZONE", $tz);
|
|
||||||
|
|
||||||
$xprops = array("X-LIC-LOCATION" => $tz); // required of some calendar software
|
|
||||||
iCalUtilityFunctions::createTimezone($v, $tz, $xprops); // create timezone object in calendar
|
|
||||||
|
|
||||||
|
|
||||||
foreach($actionData["data"] as $event) {
|
|
||||||
$event["props"]["description"] = $this->loadEventDescription($event);
|
|
||||||
$event["props"]["attendees"] = $this->loadAttendees($event);
|
|
||||||
|
|
||||||
$vevent = & $v->newComponent("vevent"); // create a new event object
|
|
||||||
$this->addEvent($vevent, $event["props"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$v->saveCalendar();
|
$response = array();
|
||||||
|
$error = false;
|
||||||
|
$error_msg = "";
|
||||||
|
|
||||||
|
// write csv
|
||||||
|
$token = $this->randomstring(16);
|
||||||
|
$file = PLUGIN_CALENDARIMPORTER_TMP_UPLOAD . "ics_" . $token . ".ics";
|
||||||
|
file_put_contents($file, "");
|
||||||
|
|
||||||
|
$store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid));
|
||||||
|
if ($store) {
|
||||||
|
// load folder first
|
||||||
|
if ($folder !== false) {
|
||||||
|
$mapifolder = mapi_msgstore_openentry($store, hex2bin($folder));
|
||||||
|
|
||||||
|
$table = mapi_folder_getcontentstable($mapifolder);
|
||||||
|
$list = mapi_table_queryallrows($table, array(PR_ENTRYID));
|
||||||
|
|
||||||
|
foreach ($list as $item) {
|
||||||
|
$records[] = bin2hex($item[PR_ENTRYID]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$vcalendar = new VObject\Component\VCalendar();
|
||||||
|
|
||||||
|
// Add static stuff to vcalendar
|
||||||
|
$vcalendar->add('METHOD', 'PUBLISH');
|
||||||
|
$vcalendar->add('X-WR-CALDESC', 'Exported Zarafa Calendar');
|
||||||
|
$vcalendar->add('X-WR-TIMEZONE', date_default_timezone_get());
|
||||||
|
|
||||||
|
// TODO: add VTIMEZONE object to ical.
|
||||||
|
|
||||||
|
for ($index = 0, $count = count($records); $index < $count; $index++) {
|
||||||
|
$message = mapi_msgstore_openentry($store, hex2bin($records[$index]));
|
||||||
|
|
||||||
|
// get message properties.
|
||||||
|
$properties = $GLOBALS['properties']->getAppointmentProperties();
|
||||||
|
$plaintext = true;
|
||||||
|
$messageProps = $GLOBALS['operations']->getMessageProps($store, $message, $properties, $plaintext);
|
||||||
|
|
||||||
|
$vevent = $vcalendar->add('VEVENT', [
|
||||||
|
'SUMMARY' => $this->getProp($messageProps, "subject"),
|
||||||
|
'DTSTART' => date_timestamp_set(new DateTime(), $this->getProp($messageProps, "startdate")),
|
||||||
|
'DTEND' => date_timestamp_set(new DateTime(), $this->getProp($messageProps, "duedate")),
|
||||||
|
'CREATED' => date_timestamp_set(new DateTime(), $this->getProp($messageProps, "creation_time")),
|
||||||
|
'LAST-MODIFIED' => date_timestamp_set(new DateTime(), $this->getProp($messageProps, "last_modification_time")),
|
||||||
|
'PRIORITY' => $this->getProp($messageProps, "importance"),
|
||||||
|
'X-MICROSOFT-CDO-INTENDEDSTATUS' => $this->busystates[intval($this->getProp($messageProps, "busystatus"))], // both seem to be valid...
|
||||||
|
'X-MICROSOFT-CDO-BUSYSTATUS' => $this->busystates[intval($this->getProp($messageProps, "busystatus"))], // both seem to be valid...
|
||||||
|
'X-ZARAFA-LABEL' => $this->labels[intval($this->getProp($messageProps, "label"))],
|
||||||
|
'CLASS' => $this->getProp($messageProps, "private") ? "PRIVATE" : "PUBLIC",
|
||||||
|
'COMMENT' => "eid:" . $records[$index]
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Add organizer
|
||||||
|
$vevent->add('ORGANIZER','mailto:' . $this->getProp($messageProps, "sender_email_address"));
|
||||||
|
$vevent->ORGANIZER['CN'] = $this->getProp($messageProps, "sender_name");
|
||||||
|
|
||||||
|
// Add Attendees
|
||||||
|
if(isset($messageProps["recipients"]) && count($messageProps["recipients"]["item"]) > 0) {
|
||||||
|
foreach($messageProps["recipients"]["item"] as $attendee) {
|
||||||
|
$att = $vevent->add('ATTENDEE', "mailto:" . $this->getProp($attendee, "email_address"));
|
||||||
|
$att["CN"] = $this->getProp($attendee, "display_name");
|
||||||
|
$att["ROLE"] = $this->attendeetype[intval($this->getProp($attendee, "recipient_type"))];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add alarms
|
||||||
|
if(!empty($this->getProp($messageProps, "reminder")) && $this->getProp($messageProps, "reminder") == 1) {
|
||||||
|
$valarm = $vevent->add('VALARM', [
|
||||||
|
'ACTION' => 'DISPLAY',
|
||||||
|
'DESCRIPTION' => $this->getProp($messageProps, "subject") // reuse the event summary
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Add trigger
|
||||||
|
$durationValue = $this->getDurationStringFromMintues($this->getProp($messageProps, "reminder_minutes"), false);
|
||||||
|
$valarm->add('TRIGGER', $durationValue); // default trigger type is duration (see 4.8.6.3)
|
||||||
|
|
||||||
|
/*
|
||||||
|
$valarm->add('TRIGGER', date_timestamp_set(new DateTime(), $this->getProp($messageProps, "reminder_time"))); // trigger type "DATE-TIME"
|
||||||
|
$valarm->TRIGGER['VALUE'] = 'DATE-TIME';
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add location
|
||||||
|
if(!empty($this->getProp($messageProps, "location"))) {
|
||||||
|
$vevent->add('LOCATION',$this->getProp($messageProps, "location"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add description
|
||||||
|
$body = $this->getProp($messageProps, "isHTML") ? $this->getProp($messageProps, "html_body") : $this->getProp($messageProps, "body");
|
||||||
|
if(!empty($body)) {
|
||||||
|
$vevent->add('DESCRIPTION',$body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write combined ics file
|
||||||
|
file_put_contents($file, file_get_contents($file) . $vcalendar->serialize());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($records) > 0) {
|
||||||
|
$response['status'] = true;
|
||||||
|
$response['download_token'] = $token;
|
||||||
|
$response['filename'] = count($records) . "events.ics";
|
||||||
|
} else {
|
||||||
|
$response['status'] = false;
|
||||||
|
$response['message'] = "No events found. Export skipped!";
|
||||||
|
}
|
||||||
|
|
||||||
$response['status'] = true;
|
|
||||||
$response['fileid'] = $tmpname; // number of entries that will be exported
|
|
||||||
$response['basedir'] = TMP_PATH;
|
|
||||||
$response['secid'] = $secid;
|
|
||||||
$response['realname'] = $actionData["calendar"];
|
|
||||||
$this->addActionData($actionType, $response);
|
$this->addActionData($actionType, $response);
|
||||||
$GLOBALS["bus"]->addData($this->getResponseData());
|
$GLOBALS["bus"]->addData($this->getResponseData());
|
||||||
|
|
||||||
if($this->DEBUG) {
|
|
||||||
error_log("export done, bus data written!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -395,40 +352,111 @@ class CalendarModule extends Module {
|
|||||||
* @param $actionType
|
* @param $actionType
|
||||||
* @param $actionData
|
* @param $actionData
|
||||||
*/
|
*/
|
||||||
private function importCalendar($actionType, $actionData) {
|
private function importCalendar($actionType, $actionData)
|
||||||
if($this->DEBUG) {
|
{
|
||||||
error_log("PHP Timezone: " . $tz);
|
// Get uploaded vcf path
|
||||||
|
$icsfile = false;
|
||||||
|
if (isset($actionData["ics_filepath"])) {
|
||||||
|
$icsfile = $actionData["ics_filepath"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_readable ($actionData["ics_filepath"])) {
|
// Get store id
|
||||||
$ical = new ICal($actionData["ics_filepath"], $GLOBALS["settings"]->get("zarafa/v1/plugins/calendarimporter/default_timezone"), $actionData["timezone"], $actionData["ignore_dst"]); // Parse it!
|
$storeid = false;
|
||||||
|
if (isset($actionData["storeid"])) {
|
||||||
|
$storeid = $actionData["storeid"];
|
||||||
|
}
|
||||||
|
|
||||||
if(isset($ical->errors)) {
|
// Get folder entryid
|
||||||
$response['status'] = false;
|
$folderid = false;
|
||||||
$response['message']= $ical->errors;
|
if (isset($actionData["folderid"])) {
|
||||||
} else if(!$ical->hasEvents()) {
|
$folderid = $actionData["folderid"];
|
||||||
$response['status'] = false;
|
}
|
||||||
$response['message']= "No events in ics file";
|
|
||||||
} else {
|
// Get uids
|
||||||
$response['status'] = true;
|
$uids = array();
|
||||||
$response['parsed_file']= $actionData["ics_filepath"];
|
if (isset($actionData["uids"])) {
|
||||||
$response['parsed'] = array (
|
$uids = $actionData["uids"];
|
||||||
'timezone' => $ical->timezone(),
|
}
|
||||||
'calendar' => $ical->calendar(),
|
|
||||||
'events' => $ical->events()
|
$response = array();
|
||||||
);
|
$error = false;
|
||||||
|
$error_msg = "";
|
||||||
|
|
||||||
|
// parse the ics file a last time...
|
||||||
|
$parser = null;
|
||||||
|
try {
|
||||||
|
$parser = VObject\Reader::read(
|
||||||
|
fopen($icsfile,'r')
|
||||||
|
);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$error = true;
|
||||||
|
$error_msg = $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
$events = array();
|
||||||
|
if (count($parser->VEVENT) > 0) {
|
||||||
|
$events = $this->parseCalendarToArray($parser);
|
||||||
|
$store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid));
|
||||||
|
$folder = mapi_msgstore_openentry($store, hex2bin($folderid));
|
||||||
|
|
||||||
|
$importall = false;
|
||||||
|
if (count($uids) == count($events)) {
|
||||||
|
$importall = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$propValuesMAPI = array();
|
||||||
|
$properties = $GLOBALS['properties']->getAppointmentProperties();
|
||||||
|
// extend properties...
|
||||||
|
$properties["body"] = PR_BODY;
|
||||||
|
|
||||||
|
$count = 0;
|
||||||
|
|
||||||
|
// iterate through all events and import them :)
|
||||||
|
foreach ($events as $event) {
|
||||||
|
if (isset($event["startdate"]) && ($importall || in_array($event["internal_fields"]["event_uid"], $uids))) {
|
||||||
|
|
||||||
|
$message = mapi_folder_createmessage($folder);
|
||||||
|
|
||||||
|
// parse the arraykeys
|
||||||
|
foreach ($event as $key => $value) {
|
||||||
|
if ($key !== "internal_fields") {
|
||||||
|
if(isset($properties[$key])) {
|
||||||
|
$propValuesMAPI[$properties[$key]] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$propValuesMAPI[$properties["commonstart"]] = $propValuesMAPI[$properties["startdate"]];
|
||||||
|
$propValuesMAPI[$properties["commonend"]] = $propValuesMAPI[$properties["duedate"]];
|
||||||
|
$propValuesMAPI[$properties["duration"]] = ($propValuesMAPI[$properties["duedate"]] - $propValuesMAPI[$properties["startdate"]]) / 60; // Minutes needed
|
||||||
|
$propValuesMAPI[$properties["reminder"]] = false; // needed, overwritten if there is a timer
|
||||||
|
|
||||||
|
$propValuesMAPI[$properties["message_class"]] = "IPM.Appointment";
|
||||||
|
$propValuesMAPI[$properties["icon_index"]] = "1024";
|
||||||
|
|
||||||
|
// TODO: set attendees and alarms
|
||||||
|
|
||||||
|
mapi_setprops($message, $propValuesMAPI);
|
||||||
|
mapi_savechanges($message);
|
||||||
|
if ($this->DEBUG) {
|
||||||
|
error_log("New event added: \"" . $event["subject"] . "\".\n");
|
||||||
|
}
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$response['status'] = true;
|
||||||
|
$response['count'] = $count;
|
||||||
|
$response['message'] = "";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$response['status'] = false;
|
$response['status'] = false;
|
||||||
$response['message']= "File could not be read by server";
|
$response['count'] = 0;
|
||||||
|
$response['message'] = $error ? $error_msg : "ICS file empty!";
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->addActionData($actionType, $response);
|
$this->addActionData($actionType, $response);
|
||||||
$GLOBALS["bus"]->addData($this->getResponseData());
|
$GLOBALS["bus"]->addData($this->getResponseData());
|
||||||
|
|
||||||
if($this->DEBUG) {
|
|
||||||
error_log("parsing done, bus data written!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -437,16 +465,17 @@ class CalendarModule extends Module {
|
|||||||
* @param $actionData
|
* @param $actionData
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private function getAttachmentPath($actionType, $actionData) {
|
private function getAttachmentPath($actionType, $actionData)
|
||||||
|
{
|
||||||
// Get store id
|
// Get store id
|
||||||
$storeid = false;
|
$storeid = false;
|
||||||
if(isset($actionData["store"])) {
|
if (isset($actionData["store"])) {
|
||||||
$storeid = $actionData["store"];
|
$storeid = $actionData["store"];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get message entryid
|
// Get message entryid
|
||||||
$entryid = false;
|
$entryid = false;
|
||||||
if(isset($actionData["entryid"])) {
|
if (isset($actionData["entryid"])) {
|
||||||
$entryid = $actionData["entryid"];
|
$entryid = $actionData["entryid"];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,41 +484,40 @@ class CalendarModule extends Module {
|
|||||||
|
|
||||||
// Get number of attachment which should be opened.
|
// Get number of attachment which should be opened.
|
||||||
$attachNum = false;
|
$attachNum = false;
|
||||||
if(isset($actionData["attachNum"])) {
|
if (isset($actionData["attachNum"])) {
|
||||||
$attachNum = $actionData["attachNum"];
|
$attachNum = $actionData["attachNum"];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if storeid and entryid isset
|
// Check if storeid and entryid isset
|
||||||
if($storeid && $entryid) {
|
if ($storeid && $entryid) {
|
||||||
// Open the store
|
// Open the store
|
||||||
$store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid));
|
$store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid));
|
||||||
|
|
||||||
if($store) {
|
if ($store) {
|
||||||
// Open the message
|
// Open the message
|
||||||
$message = mapi_msgstore_openentry($store, hex2bin($entryid));
|
$message = mapi_msgstore_openentry($store, hex2bin($entryid));
|
||||||
|
|
||||||
if($message) {
|
if ($message) {
|
||||||
$attachment = false;
|
$attachment = false;
|
||||||
|
|
||||||
// Check if attachNum isset
|
// Check if attachNum isset
|
||||||
if($attachNum) {
|
if ($attachNum) {
|
||||||
// Loop through the attachNums, message in message in message ...
|
// Loop through the attachNums, message in message in message ...
|
||||||
for($i = 0; $i < (count($attachNum) - 1); $i++)
|
for ($i = 0; $i < (count($attachNum) - 1); $i++) {
|
||||||
{
|
|
||||||
// Open the attachment
|
// Open the attachment
|
||||||
$tempattach = mapi_message_openattach($message, (int) $attachNum[$i]);
|
$tempattach = mapi_message_openattach($message, (int)$attachNum[$i]);
|
||||||
if($tempattach) {
|
if ($tempattach) {
|
||||||
// Open the object in the attachment
|
// Open the object in the attachment
|
||||||
$message = mapi_attach_openobj($tempattach);
|
$message = mapi_attach_openobj($tempattach);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the attachment
|
// Open the attachment
|
||||||
$attachment = mapi_message_openattach($message, (int) $attachNum[(count($attachNum) - 1)]);
|
$attachment = mapi_message_openattach($message, (int)$attachNum[(count($attachNum) - 1)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the attachment is opened
|
// Check if the attachment is opened
|
||||||
if($attachment) {
|
if ($attachment) {
|
||||||
|
|
||||||
// Get the props of the attachment
|
// Get the props of the attachment
|
||||||
$props = mapi_attach_getprops($attachment, array(PR_ATTACH_LONG_FILENAME, PR_ATTACH_MIME_TAG, PR_DISPLAY_NAME, PR_ATTACH_METHOD));
|
$props = mapi_attach_getprops($attachment, array(PR_ATTACH_LONG_FILENAME, PR_ATTACH_MIME_TAG, PR_DISPLAY_NAME, PR_ATTACH_METHOD));
|
||||||
@ -499,29 +527,33 @@ class CalendarModule extends Module {
|
|||||||
$filename = "ERROR";
|
$filename = "ERROR";
|
||||||
|
|
||||||
// Set filename
|
// Set filename
|
||||||
if(isset($props[PR_ATTACH_LONG_FILENAME])) {
|
if (isset($props[PR_ATTACH_LONG_FILENAME])) {
|
||||||
$filename = $props[PR_ATTACH_LONG_FILENAME];
|
$filename = $props[PR_ATTACH_LONG_FILENAME];
|
||||||
} else if(isset($props[PR_ATTACH_FILENAME])) {
|
} else {
|
||||||
$filename = $props[PR_ATTACH_FILENAME];
|
if (isset($props[PR_ATTACH_FILENAME])) {
|
||||||
} else if(isset($props[PR_DISPLAY_NAME])) {
|
$filename = $props[PR_ATTACH_FILENAME];
|
||||||
$filename = $props[PR_DISPLAY_NAME];
|
} else {
|
||||||
|
if (isset($props[PR_DISPLAY_NAME])) {
|
||||||
|
$filename = $props[PR_DISPLAY_NAME];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set content type
|
// Set content type
|
||||||
if(isset($props[PR_ATTACH_MIME_TAG])) {
|
if (isset($props[PR_ATTACH_MIME_TAG])) {
|
||||||
$contentType = $props[PR_ATTACH_MIME_TAG];
|
$contentType = $props[PR_ATTACH_MIME_TAG];
|
||||||
} else {
|
} else {
|
||||||
// Parse the extension of the filename to get the content type
|
// Parse the extension of the filename to get the content type
|
||||||
if(strrpos($filename, ".") !== false) {
|
if (strrpos($filename, ".") !== false) {
|
||||||
$extension = strtolower(substr($filename, strrpos($filename, ".")));
|
$extension = strtolower(substr($filename, strrpos($filename, ".")));
|
||||||
$contentType = "application/octet-stream";
|
$contentType = "application/octet-stream";
|
||||||
if (is_readable("mimetypes.dat")){
|
if (is_readable("mimetypes.dat")) {
|
||||||
$fh = fopen("mimetypes.dat","r");
|
$fh = fopen("mimetypes.dat", "r");
|
||||||
$ext_found = false;
|
$ext_found = false;
|
||||||
while (!feof($fh) && !$ext_found){
|
while (!feof($fh) && !$ext_found) {
|
||||||
$line = fgets($fh);
|
$line = fgets($fh);
|
||||||
preg_match("/(\.[a-z0-9]+)[ \t]+([^ \t\n\r]*)/i", $line, $result);
|
preg_match("/(\.[a-z0-9]+)[ \t]+([^ \t\n\r]*)/i", $line, $result);
|
||||||
if ($extension == $result[1]){
|
if ($extension == $result[1]) {
|
||||||
$ext_found = true;
|
$ext_found = true;
|
||||||
$contentType = $result[2];
|
$contentType = $result[2];
|
||||||
}
|
}
|
||||||
@ -539,12 +571,12 @@ class CalendarModule extends Module {
|
|||||||
$stat = mapi_stream_stat($stream);
|
$stat = mapi_stream_stat($stream);
|
||||||
// File length = $stat["cb"]
|
// File length = $stat["cb"]
|
||||||
|
|
||||||
$fhandle = fopen($tmpname,'w');
|
$fhandle = fopen($tmpname, 'w');
|
||||||
$buffer = null;
|
$buffer = null;
|
||||||
for($i = 0; $i < $stat["cb"]; $i += BLOCK_SIZE) {
|
for ($i = 0; $i < $stat["cb"]; $i += BLOCK_SIZE) {
|
||||||
// Write stream
|
// Write stream
|
||||||
$buffer = mapi_stream_read($stream, BLOCK_SIZE);
|
$buffer = mapi_stream_read($stream, BLOCK_SIZE);
|
||||||
fwrite($fhandle,$buffer,strlen($buffer));
|
fwrite($fhandle, $buffer, strlen($buffer));
|
||||||
}
|
}
|
||||||
fclose($fhandle);
|
fclose($fhandle);
|
||||||
|
|
||||||
@ -569,6 +601,129 @@ class CalendarModule extends Module {
|
|||||||
$GLOBALS["bus"]->addData($this->getResponseData());
|
$GLOBALS["bus"]->addData($this->getResponseData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
/**
|
||||||
|
* Function that parses the uploaded ics file and posts it via json
|
||||||
|
* @param $actionType
|
||||||
|
* @param $actionData
|
||||||
|
*/
|
||||||
|
private function loadCalendar($actionType, $actionData)
|
||||||
|
{
|
||||||
|
$error = false;
|
||||||
|
$error_msg = "";
|
||||||
|
|
||||||
|
if (is_readable($actionData["ics_filepath"])) {
|
||||||
|
$parser = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$parser = VObject\Reader::read(
|
||||||
|
fopen($actionData["ics_filepath"],'r')
|
||||||
|
);
|
||||||
|
//error_log(print_r($parser->VTIMEZONE, true));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$error = true;
|
||||||
|
$error_msg = $e->getMessage();
|
||||||
|
}
|
||||||
|
if ($error) {
|
||||||
|
$response['status'] = false;
|
||||||
|
$response['message'] = $error_msg;
|
||||||
|
} else {
|
||||||
|
if (count($parser->VEVENT) == 0) {
|
||||||
|
$response['status'] = false;
|
||||||
|
$response['message'] = "No event in ics file";
|
||||||
|
} else {
|
||||||
|
$response['status'] = true;
|
||||||
|
$response['parsed_file'] = $actionData["ics_filepath"];
|
||||||
|
$response['parsed'] = array(
|
||||||
|
'events' => $this->parseCalendarToArray($parser),
|
||||||
|
'timezone' => isset($parser->VTIMEZONE->TZID) ? (string)$parser->VTIMEZONE->TZID : (string)$parser->{'X-WR-TIMEZONE'},
|
||||||
|
'calendar' => (string)$parser->PRODID
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$response['status'] = false;
|
||||||
|
$response['message'] = "File could not be read by server";
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addActionData($actionType, $response);
|
||||||
|
$GLOBALS["bus"]->addData($this->getResponseData());
|
||||||
|
|
||||||
|
if ($this->DEBUG) {
|
||||||
|
error_log("parsing done, bus data written!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a array with contacts
|
||||||
|
*
|
||||||
|
* @param {VObject} $calendar ics parser object
|
||||||
|
* @return array parsed events
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private function parseCalendarToArray($calendar)
|
||||||
|
{
|
||||||
|
$events = array();
|
||||||
|
foreach ($calendar->VEVENT as $Index => $vEvent) {
|
||||||
|
// Sabre\VObject\Parser\XML\Element\VEvent
|
||||||
|
$properties = array();
|
||||||
|
|
||||||
|
//uid - used for front/backend communication
|
||||||
|
$properties["internal_fields"] = array();
|
||||||
|
$properties["internal_fields"]["event_uid"] = base64_encode($Index . $vEvent->UID);
|
||||||
|
|
||||||
|
$properties["startdate"] = (string)$vEvent->DTSTART->getDateTime()->getTimestamp();
|
||||||
|
$properties["duedate"] = (string)$vEvent->DTEND->getDateTime()->getTimestamp();
|
||||||
|
$properties["location"] = (string)$vEvent->LOCATION;
|
||||||
|
$properties["subject"] = (string)$vEvent->SUMMARY;
|
||||||
|
$properties["body"] = (string)$vEvent->DESCRIPTION;
|
||||||
|
$properties["comment"] = (string)$vEvent->COMMENT;
|
||||||
|
$properties["timezone"] = (string)$vEvent->DTSTART["TZID"];
|
||||||
|
$properties["organizer"] = (string)$vEvent->ORGANIZER;
|
||||||
|
$properties["busystatus"] = array_search((string)$vEvent->{'X-MICROSOFT-CDO-INTENDEDSTATUS'}, $this->busystates); // X-MICROSOFT-CDO-BUSYSTATUS
|
||||||
|
$properties["transp"] = (string)$vEvent->TRANSP;
|
||||||
|
//$properties["trigger"] = (string)$vEvent->COMMENT;
|
||||||
|
$properties["priority"] = (string)$vEvent->PRIORITY;
|
||||||
|
$properties["private"] = ((string)$vEvent->CLASS) == "PRIVATE" ? true : false;
|
||||||
|
if(!empty((string)$vEvent->{'X-ZARAFA-LABEL'})) {
|
||||||
|
$properties["label"] = array_search((string)$vEvent->{'X-ZARAFA-LABEL'}, $this->labels);
|
||||||
|
}
|
||||||
|
$properties["last_modification_time"] = (string)$vEvent->{'LAST-MODIFIED'}->getDateTime()->getTimestamp();
|
||||||
|
$properties["creation_time"] = (string)$vEvent->CREATED->getDateTime()->getTimestamp();
|
||||||
|
$properties["rrule"] = (string)$vEvent->RRULE;
|
||||||
|
|
||||||
|
// Attendees
|
||||||
|
$properties["attendees"] = array();
|
||||||
|
if(isset($vEvent->ATTENDEE) && count($vEvent->ATTENDEE) > 0) {
|
||||||
|
foreach($vEvent->ATTENDEE as $attendee) {
|
||||||
|
$properties["attendees"][] = array(
|
||||||
|
"name" => (string)$attendee["CN"],
|
||||||
|
"mail" => (string)$attendee,
|
||||||
|
"status" => (string)$attendee["PARTSTAT"],
|
||||||
|
"role" => (string)$attendee["ROLE"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alarms
|
||||||
|
$properties["alarms"] = array();
|
||||||
|
if(isset($vEvent->VALARM) && count($vEvent->VALARM) > 0) {
|
||||||
|
foreach($vEvent->VALARM as $alarm) {
|
||||||
|
$properties["alarms"][] = array(
|
||||||
|
"description" => (string)$alarm->DESCRIPTION,
|
||||||
|
"trigger" => (string)$alarm->TRIGGER,
|
||||||
|
"type" => (string)$alarm->TRIGGER["VALUE"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
array_push($events, $properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $events;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
@ -19,25 +19,31 @@
|
|||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*
|
*
|
||||||
*
|
*/
|
||||||
|
require_once __DIR__ . "/download.php";
|
||||||
|
|
||||||
|
/**
|
||||||
* calendarimporter Plugin
|
* calendarimporter Plugin
|
||||||
*
|
*
|
||||||
* With this plugin you can import a ics file to your zarafa calendar
|
* With this plugin you can import a ics file to your zarafa calendar
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class Plugincalendarimporter extends Plugin {
|
class Plugincalendarimporter extends Plugin
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
function Plugincalendarimporter() {}
|
function __construct() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function initializes the Plugin and registers all hooks
|
* Function initializes the Plugin and registers all hooks
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function init() {
|
function init()
|
||||||
|
{
|
||||||
$this->registerHook('server.core.settings.init.before');
|
$this->registerHook('server.core.settings.init.before');
|
||||||
|
$this->registerHook('server.index.load.custom');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,11 +53,17 @@ class Plugincalendarimporter extends Plugin {
|
|||||||
* @param mixed $data object(s) related to the hook
|
* @param mixed $data object(s) related to the hook
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function execute($eventID, &$data) {
|
function execute($eventID, &$data)
|
||||||
switch($eventID) {
|
{
|
||||||
|
switch ($eventID) {
|
||||||
case 'server.core.settings.init.before' :
|
case 'server.core.settings.init.before' :
|
||||||
$this->injectPluginSettings($data);
|
$this->injectPluginSettings($data);
|
||||||
break;
|
break;
|
||||||
|
case 'server.index.load.custom':
|
||||||
|
if ($data['name'] == 'download_ics') {
|
||||||
|
calendarimporter\DownloadHandler::doDownload();
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,17 +72,17 @@ class Plugincalendarimporter extends Plugin {
|
|||||||
* settings.
|
* settings.
|
||||||
* @param Array $data Reference to the data of the triggered hook
|
* @param Array $data Reference to the data of the triggered hook
|
||||||
*/
|
*/
|
||||||
function injectPluginSettings(&$data) {
|
function injectPluginSettings(&$data)
|
||||||
|
{
|
||||||
$data['settingsObj']->addSysAdminDefaults(Array(
|
$data['settingsObj']->addSysAdminDefaults(Array(
|
||||||
'zarafa' => Array(
|
'zarafa' => Array(
|
||||||
'v1' => Array(
|
'v1' => Array(
|
||||||
'plugins' => Array(
|
'plugins' => Array(
|
||||||
'calendarimporter' => Array(
|
'calendarimporter' => Array(
|
||||||
'enable' => PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE,
|
'enable' => PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE,
|
||||||
'enable_export' => PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE_EXPORT,
|
|
||||||
'enable_sync' => PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE_SYNC,
|
'enable_sync' => PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE_SYNC,
|
||||||
'default_calendar' => PLUGIN_CALENDARIMPORTER_DEFAULT,
|
'default_calendar' => PLUGIN_CALENDARIMPORTER_DEFAULT,
|
||||||
'default_timezone' => PLUGIN_CALENDARIMPORTER_DEFAULT_TIMEZONE
|
'default_timezone' => PLUGIN_CALENDARIMPORTER_DEFAULT_TIMEZONE
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -78,4 +90,5 @@ class Plugincalendarimporter extends Plugin {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
@ -2,5 +2,29 @@
|
|||||||
background: url(../images/import_icon.png) no-repeat !important;
|
background: url(../images/import_icon.png) no-repeat !important;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-size: 18px!important;
|
}
|
||||||
|
|
||||||
|
.icon_calendarimporter_export {
|
||||||
|
background: url(../images/download.png) no-repeat;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_calendarimporter_import {
|
||||||
|
background: url(../images/upload.png) no-repeat;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.zarafa-caiplg-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.zarafa-caiplg-button .x-btn-small {
|
||||||
|
width: 80%;
|
||||||
|
height: 30px;
|
||||||
|
margin-left: 10%;
|
||||||
|
margin-right: 10%;
|
||||||
|
margin-top: 10px;
|
||||||
}
|
}
|
BIN
resources/images/download.png
Executable file
BIN
resources/images/download.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 224 B |
BIN
resources/images/download.xcf
Executable file
BIN
resources/images/download.xcf
Executable file
Binary file not shown.
BIN
resources/images/upload.png
Normal file
BIN
resources/images/upload.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 213 B |
BIN
resources/images/upload.xcf
Executable file
BIN
resources/images/upload.xcf
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user