diff --git a/.docker/release/files/usr/local/include/application.ini b/.docker/release/files/usr/local/include/application.ini index 1f8ab7a9e..35e0d5569 100644 --- a/.docker/release/files/usr/local/include/application.ini +++ b/.docker/release/files/usr/local/include/application.ini @@ -97,7 +97,6 @@ capath = "" client_cert = "" [capa] -contacts = On quota = On search = On search_adv = On @@ -304,7 +303,6 @@ cookie_default_secure = Off check_new_messages = On replace_env_in_configuration = "" boundary_prefix = "" -kolab_enabled = Off dev_email = "" dev_password = "" diff --git a/dev/App/User.js b/dev/App/User.js index cc7850531..8094d4268 100644 --- a/dev/App/User.js +++ b/dev/App/User.js @@ -92,6 +92,8 @@ export class AppUser extends AbstractApp { addShortcut('escape,enter', '', dropdownsDetectVisibility); addEventListener('click', dropdownsDetectVisibility); + + this.folderList = FolderUserStore.folderList; } refresh() { diff --git a/dev/Settings/User/Contacts.js b/dev/Settings/User/Contacts.js index e1059efd5..a274873e3 100644 --- a/dev/Settings/User/Contacts.js +++ b/dev/Settings/User/Contacts.js @@ -4,7 +4,6 @@ import { koComputable } from 'External/ko'; import { SettingsGet } from 'Common/Globals'; import { i18n, trigger as translatorTrigger } from 'Common/Translator'; import { ContactUserStore } from 'Stores/User/Contact'; -import { FolderUserStore } from 'Stores/User/Folder'; import Remote from 'Remote/User/Fetch'; export class UserSettingsContacts /*extends AbstractViewSettings*/ { @@ -49,33 +48,5 @@ export class UserSettingsContacts /*extends AbstractViewSettings*/ { Password: ContactUserStore.syncPass() }) ); - - this.kolabContactFolder = ko.observable(SettingsGet('KolabContactFolder')); - this.kolabContactFolder.subscribe(value => - Remote.saveSettings(null, { KolabContactFolder: value }) - ); - this.showKolab = FolderUserStore.allowKolab(); - this.folderSelectList = koComputable(() => { - const - aResult = [{ - id: '', - name: '', - }], - foldersWalk = folders => { - folders.forEach(oItem => { - if ('contact' === oItem.kolabType()) { - aResult.push({ - id: oItem.fullName, - name: oItem.fullName - }); - } - if (oItem.subFolders.length) { - foldersWalk(oItem.subFolders()); - } - }); - }; - foldersWalk(FolderUserStore.folderList()); - return aResult; - }); } } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/KolabAddressBook.php b/plugins/kolab/KolabAddressBook.php similarity index 90% rename from snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/KolabAddressBook.php rename to plugins/kolab/KolabAddressBook.php index fdf930841..e0e1b8fb0 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/KolabAddressBook.php +++ b/plugins/kolab/KolabAddressBook.php @@ -1,12 +1,12 @@ oImapClient /*&&\RainLoop\Api::Config()->Get('labs', 'kolab_enabled', false)*/) { + if (!$this->oImapClient) { $this->oImapClient = $this->MailClient()->ImapClient(); } return $this->oImapClient; @@ -78,9 +78,9 @@ class KolabAddressBook implements AddressBookInterface return $xCard; } - protected function MessageAsContact(\MailSo\Mail\Message $oMessage) : ?Classes\Contact + protected function MessageAsContact(\MailSo\Mail\Message $oMessage) : ?Contact { - $oContact = new Classes\Contact; + $oContact = new Contact; $oContact->IdContact = $oMessage->Uid(); // $oContact->Display = isset($aItem['display']) ? (string) $aItem['display'] : ''; $oContact->Changed = $oMessage->HeaderTimeStampInUTC(); @@ -88,12 +88,12 @@ class KolabAddressBook implements AddressBookInterface $oFrom = $oMessage->From(); if ($oFrom) { $oMail = $oFrom[0]; - $oProperty = new Classes\Property(PropertyType::EMAIl, $oMail->GetEmail()); + $oProperty = new Property(PropertyType::EMAIl, $oMail->GetEmail()); $oContact->Properties[] = $oProperty; - $oProperty = new Classes\Property(PropertyType::FULLNAME, $oMail->GetDisplayName()); -// $oProperty = new Classes\Property(PropertyType::FULLNAME, $oMail->ToString()); + $oProperty = new Property(PropertyType::FULLNAME, $oMail->GetDisplayName()); +// $oProperty = new Property(PropertyType::FULLNAME, $oMail->ToString()); $oContact->Properties[] = $oProperty; -// $oProperty = new Classes\Property(PropertyType::NICK_NAME, $oMail->GetDisplayName()); +// $oProperty = new Property(PropertyType::NICK_NAME, $oMail->GetDisplayName()); // $oContact->Properties[] = $oProperty; } @@ -129,7 +129,7 @@ class KolabAddressBook implements AddressBookInterface return false; } - public function ContactSave(string $sEmail, Classes\Contact $oContact) : bool + public function ContactSave(string $sEmail, Contact $oContact) : bool { // TODO // $emails = $oContact->GetEmails(); @@ -237,7 +237,7 @@ class KolabAddressBook implements AddressBookInterface if (!\strlen($oParams->sFolderName)) { // return []; - throw new ClientException(Notifications::CantGetMessageList); + throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList); } $this->ImapClient(); @@ -254,13 +254,13 @@ class KolabAddressBook implements AddressBookInterface catch (\Throwable $oException) { throw $oException; - throw new ClientException(Notifications::CantGetMessageList, $oException); + throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList, $oException); } return $aResult; } - public function GetContactByID(string $sEmail, $mID, bool $bIsStrID = false) : ?Classes\Contact + public function GetContactByID(string $sEmail, $mID, bool $bIsStrID = false) : ?Contact { if ($bIsStrID) { $oMessage = null; diff --git a/plugins/kolab/LICENSE b/plugins/kolab/LICENSE new file mode 100644 index 000000000..4aed64b3a --- /dev/null +++ b/plugins/kolab/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2015 RainLoop Team + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/kolab/index.php b/plugins/kolab/index.php new file mode 100644 index 000000000..c6dcdc0e5 --- /dev/null +++ b/plugins/kolab/index.php @@ -0,0 +1,89 @@ +Set('contacts', 'enable', true); + if (\RainLoop\Api::Config()->Get('contacts', 'enable', false)) { + $this->addHook('filter.app-data', 'FilterAppData'); + $this->addHook('main.fabrica', 'MainFabrica'); + + $this->addJs('js/settings.js'); + $this->addTemplate('templates/KolabSettings.html'); + $this->addJsonHook('KolabFolder', 'DoKolabFolder'); + } + } + + public function Supported() : string + { + return ''; + } + + private function Account() : \RainLoop\Model\Account + { + return \RainLoop\Api::Actions()->getAccountFromToken(); + } + + private function SettingsProvider() : \RainLoop\Providers\Settings + { + return \RainLoop\Api::Actions()->SettingsProvider(true); + } + + private function Settings() : \RainLoop\Settings + { + return $this->SettingsProvider()->Load($this->Account()); + } + + public function DoKolabFolder() : array + { +// \error_log(\print_r($this->Manager()->Actions()->GetActionParams(), 1)); + $sValue = $this->jsonParam('contact'); + $oSettings = $this->Settings(); + if (\is_string($sValue)) { + $oSettings->SetConf('KolabContactFolder', $sValue); + $this->SettingsProvider()->Save($this->Account(), $oSettings); + } + return $this->jsonResponse(__FUNCTION__, true); + } + + public function FilterAppData($bAdmin, &$aResult) : void + { +// if ImapClient->IsSupported('METADATA') + if (\is_array($aResult) && !empty($aResult['Auth'])) { + $aResult['Capa']['Kolab'] = true; + $aResult['KolabContactFolder'] = (string) $this->Settings()->GetConf('KolabContactFolder', ''); + } + } + + /** + * @param mixed $mResult + */ + public function MainFabrica(string $sName, &$mResult) + { +/* + if ('suggestions' === $sName) { + if (!\is_array($mResult)) { + $mResult = array(); + } +// $sFolder = \trim($this->Config()->Get('plugin', 'mailbox', '')); +// if ($sFolder) { + require_once __DIR__ . '/KolabContactsSuggestions.php'; + $mResult[] = new KolabContactsSuggestions(); +// } + } +*/ + if ('address-book' === $sName) { + require_once __DIR__ . '/KolabAddressBook.php'; + $mResult = new KolabAddressBook(); + } + } +} diff --git a/plugins/kolab/js/settings.js b/plugins/kolab/js/settings.js new file mode 100644 index 000000000..1f83fb0bd --- /dev/null +++ b/plugins/kolab/js/settings.js @@ -0,0 +1,54 @@ +(rl => { + +const getFolders = type => { + const + aResult = [{ + id: '', + name: '', + }], + foldersWalk = folders => { + folders.forEach(oItem => { + if (type === oItem.kolabType()) { + aResult.push({ + id: oItem.fullName, + name: oItem.fullName + }); + } + if (oItem.subFolders.length) { + foldersWalk(oItem.subFolders()); + } + }); + }; + foldersWalk(rl.app.folderList()); + return aResult; +}; + + +class KolabSettings /* extends AbstractViewSettings */ +{ + constructor() { + this.contactFolder = ko.observable(rl.settings.get('KolabContactFolder')); +// rl.app.FolderUserStore.hasCapability('METADATA'); + this.contactFolder.subscribe(value => { + rl.pluginRemoteRequest(()=>{}, 'KolabFolder', { + contact: value + }); + }); + this.contactFoldersList = ko.computed(() => getFolders('contact'), {'pure':true}); +// this.eventFoldersList = ko.computed(() => getFolders('event'), {'pure':true}); +// this.taskFoldersList = ko.computed(() => getFolders('task'), {'pure':true}); +// this.noteFoldersList = ko.computed(() => getFolders('note'), {'pure':true}); +// this.fileFoldersList = ko.computed(() => getFolders('file'), {'pure':true}); +// this.journalFoldersList = ko.computed(() => getFolders('journal'), {'pure':true}); +// this.configFoldersList = ko.computed(() => getFolders('configuration'), {'pure':true}); + } +} + +rl.addSettingsViewModel( + KolabSettings, + 'KolabSettings', + 'Kolab', + 'kolab' +); + +})(window.rl); diff --git a/plugins/kolab/templates/KolabSettings.html b/plugins/kolab/templates/KolabSettings.html new file mode 100644 index 000000000..71cd3cc93 --- /dev/null +++ b/plugins/kolab/templates/KolabSettings.html @@ -0,0 +1,12 @@ +