diff --git a/dev/Settings/User/Contacts.js b/dev/Settings/User/Contacts.js index a274873e3..e1059efd5 100644 --- a/dev/Settings/User/Contacts.js +++ b/dev/Settings/User/Contacts.js @@ -4,6 +4,7 @@ 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*/ { @@ -48,5 +49,33 @@ 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/dev/Settings/User/Folders.js b/dev/Settings/User/Folders.js index d5e2b9aa2..914b3abc6 100644 --- a/dev/Settings/User/Folders.js +++ b/dev/Settings/User/Folders.js @@ -3,7 +3,6 @@ import { koComputable } from 'External/ko'; import { Notification } from 'Common/Enums'; import { FolderMetadataKeys } from 'Common/EnumsUser'; -import { SettingsCapa } from 'Common/Globals'; import { getNotification } from 'Common/Translator'; import { setFolder, getFolderFromCacheList, removeFolderFromCacheList } from 'Common/Cache'; @@ -26,7 +25,7 @@ const folderForDeletion = ko.observable(null).askDeleteHelper(); export class UserSettingsFolders /*extends AbstractViewSettings*/ { constructor() { - this.showKolab = koComputable(() => FolderUserStore.hasCapability('METADATA') && SettingsCapa('Kolab')); + this.showKolab = FolderUserStore.allowKolab(); this.defaultOptionsAfterRender = defaultOptionsAfterRender; this.kolabTypeOptions = ko.observableArray(); let i18nFilter = key => i18n('SETTINGS_FOLDERS/TYPE_' + key); diff --git a/dev/Stores/User/Folder.js b/dev/Stores/User/Folder.js index d1c51862b..5b5d2c1b9 100644 --- a/dev/Stores/User/Folder.js +++ b/dev/Stores/User/Folder.js @@ -6,7 +6,7 @@ import { UNUSED_OPTION_VALUE } from 'Common/Consts'; import { forEachObjectEntry } from 'Common/Utils'; import { addObservablesTo, addSubscribablesTo, addComputablesTo } from 'External/ko'; import { getFolderInboxName, getFolderFromCacheList } from 'Common/Cache'; -import { Settings } from 'Common/Globals'; +import { Settings, SettingsCapa } from 'Common/Globals'; //import Remote from 'Remote/User/Fetch'; // Circular dependency export const FolderUserStore = new class { @@ -117,6 +117,10 @@ export const FolderUserStore = new class { return this.capabilities().includes(name); } + allowKolab() { + return FolderUserStore.hasCapability('METADATA') && SettingsCapa('Kolab'); + } + /** * @returns {Array} */ diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php index 0b965c78a..c18da492f 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -248,26 +248,8 @@ class Actions break; case 'address-book': // Providers\AddressBook\AddressBookInterface - $sDsn = \trim($this->oConfig->Get('contacts', 'pdo_dsn', '')); - $sUser = \trim($this->oConfig->Get('contacts', 'pdo_user', '')); - $sPassword = (string)$this->oConfig->Get('contacts', 'pdo_password', ''); - $sDsnType = Providers\AddressBook\PdoAddressBook::validPdoType($this->oConfig->Get('contacts', 'type', 'sqlite')); - if ('sqlite' === $sDsnType) { - $sUser = $sPassword = ''; - $sDsn = 'sqlite:' . APP_PRIVATE_DATA . 'AddressBook.sqlite'; -/* - // TODO: use local db? - $homedir = $this->StorageProvider()->GenerateFilePath( - $oAccount, - \RainLoop\Providers\Storage\Enumerations\StorageType::ROOT - ); - $sDsn = 'sqlite:' . $homedir . '/AddressBook.sqlite'; -*/ - } else { - $sDsn = $sDsnType . ':' . \preg_replace('/^[a-z]+:/', '', $sDsn); - } - $mResult = new Providers\AddressBook\PdoAddressBook($sDsn, $sUser, $sPassword, $sDsnType); -// $mResult = new Providers\AddressBook\KolabAddressBook($this->MailClient()->ImapClient()); + $mResult = new Providers\AddressBook\PdoAddressBook(); +// $mResult = new Providers\AddressBook\KolabAddressBook(); break; case 'identities': case 'suggestions': @@ -750,7 +732,7 @@ class Actions 'ContactsAutosave' => (bool) $oConfig->Get('defaults', 'contacts_autosave', true), 'HideUnsubscribed' => false, 'MainEmail' => '', - 'InterfaceAnimation' => true, + 'KolabContactFolder' => '', 'UserBackgroundName' => '', 'UserBackgroundHash' => '' ); @@ -838,6 +820,7 @@ class Actions $aResult['HideUnsubscribed'] = (bool)$oSettingsLocal->GetConf('HideUnsubscribed', $aResult['HideUnsubscribed']); $aResult['UseThreads'] = (bool)$oSettingsLocal->GetConf('UseThreads', $aResult['UseThreads']); $aResult['ReplySameFolder'] = (bool)$oSettingsLocal->GetConf('ReplySameFolder', $aResult['ReplySameFolder']); + $aResult['KolabContactFolder'] = (string)$oSettingsLocal->GetConf('KolabContactFolder', $aResult['KolabContactFolder']); } if ($oConfig->Get('login', 'determine_user_language', true)) { @@ -1166,7 +1149,7 @@ class Actions 'DangerousActions' => (bool) $oConfig->Get('capa', 'dangerous_actions', true), 'GnuPG' => (bool) $oConfig->Get('security', 'openpgp', false) && \SnappyMail\PGP\GnuPG::isSupported(), 'Identities' => (bool) $oConfig->Get('webmail', 'allow_additional_identities', false), - 'Kolab' => (bool) $oConfig->Get('labs', 'kolab_enabled', false), + 'Kolab' => (bool) $oConfig->Get('labs', 'kolab_enabled', false) /* && ImapClient->IsSupported('METADATA')*/, 'MessageActions' => (bool) $oConfig->Get('capa', 'message_actions', true), 'OpenPGP' => (bool) $oConfig->Get('security', 'openpgp', false), 'Prefetch' => (bool) $oConfig->Get('labs', 'allow_prefetch', false), diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php index 6f2c4ae14..218da3690 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php @@ -345,6 +345,7 @@ trait User $this->setSettingsFromParams($oSettingsLocal, 'UseThreads', 'bool'); $this->setSettingsFromParams($oSettingsLocal, 'ReplySameFolder', 'bool'); $this->setSettingsFromParams($oSettingsLocal, 'HideUnsubscribed', 'bool'); + $this->setSettingsFromParams($oSettingsLocal, 'KolabContactFolder', 'string'); return $this->DefaultResponse(__FUNCTION__, $this->SettingsProvider()->Save($oAccount, $oSettings) && diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/KolabAddressBook.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/KolabAddressBook.php index 916cbdcf7..27514e392 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/KolabAddressBook.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/KolabAddressBook.php @@ -4,7 +4,7 @@ namespace RainLoop\Providers\AddressBook; use RainLoop\Providers\AddressBook\Enumerations\PropertyType; -class KolabAddressBook implements \RainLoop\Providers\AddressBook\AddressBookInterface +class KolabAddressBook implements AddressBookInterface { use CardDAV; @@ -12,27 +12,54 @@ class KolabAddressBook implements \RainLoop\Providers\AddressBook\AddressBookInt $oImapClient, $sFolderName; - function __construct(\MailSo\Imap\ImapClient $oImapClient) + protected function ImapClient() : \MailSo\Imap\ImapClient { - $this->oImapClient = $oImapClient; + if (!$this->oImapClient /*&&\RainLoop\Api::Config()->Get('labs', 'kolab_enabled', false)*/) { + $oActions = \RainLoop\Api::Actions(); + $oMailClient = $oActions->MailClient(); + if (!$oMailClient->IsLoggined()) { + $oActions->getAccountFromToken()->IncConnectAndLoginHelper($oActions->Plugins(), $oMailClient, $oActions->Config()); + } + $this->oImapClient = $oMailClient->ImapClient(); + } + return $this->oImapClient; } - public function SetFolder(string $sFolderName) : bool + public function FolderName() : string { - $metadata = $this->oImapClient->FolderGetMetadata($sFolderName, [\MailSo\Imap\Enumerations\MetadataKeys::KOLAB_CTYPE]); - if ($metadata && 'contact' !== \array_shift($metadata)) { - // Throw error -// $this->oImapClient->FolderList() : array - return false; + if (!\is_string($this->sFolderName)) { + $oActions = \RainLoop\Api::Actions(); + $oAccount = $oActions->getAccountFromToken(); + $this->sFolderName = (string) $oActions->SettingsProvider(true)->Load($oAccount)->GetConf('KolabContactFolder', ''); } - $this->oImapClient->FolderSelect($sFolderName); - $this->sFolderName = $sFolderName; - return true; + return $this->sFolderName; + } + + public function SelectFolder() : bool + { + try { + $sFolderName = $this->FolderName(); + if (!$sFolderName) { + return false; + } + + $metadata = $this->ImapClient()->FolderGetMetadata($sFolderName, [\MailSo\Imap\Enumerations\MetadataKeys::KOLAB_CTYPE]); + if (!$metadata || 'contact' !== \array_shift($metadata)) { + throw new \Exception("Invalid kolab contact folder: {$sFolderName}"); + } + + $this->ImapClient()->FolderSelect($sFolderName); + $this->sFolderName = $sFolderName; + return true; + } catch (\Throwable $e) { + \trigger_error("KolabAddressBook {$sFolderName} error: {$e->getMessage()}"); + } + return false; } public function IsSupported() : bool { - // Check $this->oImapClient->IsSupported('METADATA') + // Check $this->ImapClient()->IsSupported('METADATA') return true; } @@ -58,6 +85,10 @@ class KolabAddressBook implements \RainLoop\Providers\AddressBook\AddressBookInt // TODO // $emails = $oContact->GetEmails(); + if (!$this->SelectFolder()) { + return false; + } + $oContact->PopulateDisplayAndFullNameValue(); $sUID = $oContact->GetUID(); @@ -88,27 +119,27 @@ class KolabAddressBook implements \RainLoop\Providers\AddressBook\AddressBookInt $oMessage->SubParts->append($oPart); // Search in IMAP folder: - $aUids = $this->oImapClient->MessageSimpleSearch("SUBJECT {$sUID}"); + $aUids = $this->ImapClient()->MessageSimpleSearch("SUBJECT {$sUID}"); /* - $email = \MailSo\Imap\SearchCriterias::escapeSearchString($this->oImapClient, $sEmail); - $aUids = $this->oImapClient->MessageSimpleSearch("OR SUBJECT {$sUID} FROM {$email}"); - $aUids = $this->oImapClient->MessageSimpleSearch("OR SUBJECT {$sUID} FROM {$email} BODY {$email}"); + $email = \MailSo\Imap\SearchCriterias::escapeSearchString($this->ImapClient(), $sEmail); + $aUids = $this->ImapClient()->MessageSimpleSearch("OR SUBJECT {$sUID} FROM {$email}"); + $aUids = $this->ImapClient()->MessageSimpleSearch("OR SUBJECT {$sUID} FROM {$email} BODY {$email}"); - $aUids = $this->oImapClient->MessageSimpleSearch('HEADER Subject '.$sUID); + $aUids = $this->ImapClient()->MessageSimpleSearch('HEADER Subject '.$sUID); return 1 === \count($aUids) && \is_numeric($aUids[0]) ? (int) $aUids[0] : null; */ if ($aUids) { // Replace Message - if (false && $this->oImapClient->IsSupported('REPLACE')) { + if (false && $this->ImapClient()->IsSupported('REPLACE')) { // UID REPLACE } else { $oRange = new \MailSo\Imap\SequenceSet($aUids[0]); - $this->oImapClient->MessageStoreFlag($oRange, + $this->ImapClient()->MessageStoreFlag($oRange, array(\MailSo\Imap\Enumerations\MessageFlag::DELETED), \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT ); - $this->oImapClient->FolderExpunge($oRange); + $this->ImapClient()->FolderExpunge($oRange); } } @@ -118,7 +149,7 @@ class KolabAddressBook implements \RainLoop\Providers\AddressBook\AddressBookInt $oMessage->ToStream(false), array($rMessageStream), 8192, true, true); if (false !== $iMessageStreamSize) { \rewind($rMessageStream); - $this->oImapClient->MessageAppendStream($this->sFolderName, $rMessageStream, $iMessageStreamSize); + $this->ImapClient()->MessageAppendStream($this->sFolderName, $rMessageStream, $iMessageStreamSize); } return true; @@ -138,8 +169,76 @@ class KolabAddressBook implements \RainLoop\Providers\AddressBook\AddressBookInt public function GetContacts(string $sEmail, int $iOffset = 0, int $iLimit = 20, string $sSearch = '', int &$iResultCount = 0) : array { - // TODO - return []; + $oParams = new \MailSo\Mail\MessageListParams; + $oParams->sFolderName = $this->FolderName(); + $oParams->iOffset = $iOffset; + $oParams->iLimit = $iLimit; + if ($sSearch) { + $oParams->sSearch = 'from='.$sSearch; + } + $oParams->sSort = 'FROM'; +// $oParams->iPrevUidNext = $this->GetActionParam('UidNext', 0); +// $oParams->bUseThreads = false; + + if (!\strlen($oParams->sFolderName)) { +// return []; + throw new ClientException(Notifications::CantGetMessageList); + } + + $this->ImapClient(); + + $aResult = []; + + try + { + $oMessageList = \RainLoop\Api::Actions()->MailClient()->MessageList($oParams); + foreach ($oMessageList as $oMessage) { + $oContact = new Classes\Contact; + $oContact->IdContact = $oMessage->Uid(); + $oContact->IdContactStr = $oMessage->Subject(); +// $oContact->Display = isset($aItem['display']) ? (string) $aItem['display'] : ''; + $oContact->Changed = $oMessage->HeaderTimeStampInUTC(); + + $oFrom = $oMessage->From(); + if ($oFrom) { + $oMail = $oFrom[0]; + $oProperty = new Classes\Property(PropertyType::EMAIl, $oMail->GetEmail()); + $oContact->Properties[] = $oProperty; + $oProperty = new Classes\Property(PropertyType::FULLNAME, $oMail->GetDisplayName()); +// $oProperty = new Classes\Property(PropertyType::FULLNAME, $oMail->ToString()); + $oContact->Properties[] = $oProperty; +// $oProperty = new Classes\Property(PropertyType::NICK_NAME, $oMail->GetDisplayName()); +// $oContact->Properties[] = $oProperty; + + $oContact->UpdateDependentValues(); + $aResult[] = $oContact; + /* + // TODO extract xCard attachment + $oMessage->ContentType() = multipart/mixed + $oMessage->Attachments() : ?AttachmentCollection + [0] => MailSo\Mail\Attachment( + [oBodyStructure:MailSo\Mail\Attachment:private] => MailSo\Imap\BodyStructure( + [sContentType:MailSo\Imap\BodyStructure:private] => application/vcard+xml + [sCharset:MailSo\Imap\BodyStructure:private] => + [aBodyParams:MailSo\Imap\BodyStructure:private] => Array( + [name] => kolab.xml + ) + [sMailEncodingName:MailSo\Imap\BodyStructure:private] => quoted-printable + [sDisposition:MailSo\Imap\BodyStructure:private] => attachment + [sFileName:MailSo\Imap\BodyStructure:private] => kolab.xml + [iSize:MailSo\Imap\BodyStructure:private] => 1043 + [sPartID:MailSo\Imap\BodyStructure:private] => 2 + */ + } + } + } + catch (\Throwable $oException) + { + throw $oException; + throw new ClientException(Notifications::CantGetMessageList, $oException); + } + + return $aResult; } public function GetContactByID(string $sEmail, $mID, bool $bIsStrID = false) : ?Classes\Contact @@ -151,18 +250,18 @@ class KolabAddressBook implements \RainLoop\Providers\AddressBook\AddressBookInt public function GetSuggestions(string $sEmail, string $sSearch, int $iLimit = 20) : array { $sSearch = \trim($sSearch); - if (2 > \strlen($sSearch) || !$this->SetFolder(/*TODO 'Contacts'*/)) { + if (2 > \strlen($sSearch) || !$this->SelectFolder()) { return []; } - $sSearch = \MailSo\Imap\SearchCriterias::escapeSearchString($this->oImapClient, $sSearch); + $sSearch = \MailSo\Imap\SearchCriterias::escapeSearchString($this->ImapClient(), $sSearch); $aUids = \array_slice( - $this->oImapClient->MessageSimpleSearch("FROM {$sSearch}"), + $this->ImapClient()->MessageSimpleSearch("FROM {$sSearch}"), 0, $iLimit ); $aResult = []; - foreach ($this->oImapClient->Fetch(['BODY.PEEK[HEADER.FIELDS (FROM)]'], \implode(',', $aUids), true) as $oFetchResponse) { + foreach ($this->ImapClient()->Fetch(['BODY.PEEK[HEADER.FIELDS (FROM)]'], \implode(',', $aUids), true) as $oFetchResponse) { $oHeaders = new \MailSo\Mime\HeaderCollection($oFetchResponse->GetHeaderFieldsValue()); $oFrom = $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::FROM_, true); foreach ($oFrom as $oMail) { diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php index 2bb52fbc5..ba4426062 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php @@ -30,8 +30,28 @@ class PdoAddressBook */ private $sPassword; - public function __construct(string $sDsn, string $sUser = '', string $sPassword = '', string $sDsnType = 'mysql') + public function __construct() { + $oConfig = \RainLoop\Api::Config(); + $sDsnType = static::validPdoType($oConfig->Get('contacts', 'type', 'sqlite')); + if ('sqlite' === $sDsnType) { + $sUser = $sPassword = ''; + $sDsn = 'sqlite:' . APP_PRIVATE_DATA . 'AddressBook.sqlite'; +/* + // TODO: use local db? + $homedir = \RainLoop\Api::Actions()->StorageProvider()->GenerateFilePath( + $oAccount, + \RainLoop\Providers\Storage\Enumerations\StorageType::ROOT + ); + $sDsn = 'sqlite:' . $homedir . '/AddressBook.sqlite'; +*/ + } else { + $sDsn = \trim($oConfig->Get('contacts', 'pdo_dsn', '')); + $sUser = \trim($oConfig->Get('contacts', 'pdo_user', '')); + $sPassword = (string)$oConfig->Get('contacts', 'pdo_password', ''); + $sDsn = $sDsnType . ':' . \preg_replace('/^[a-z]+:/', '', $sDsn); + } + $this->sDsn = $sDsn; $this->sUser = $sUser; $this->sPassword = $sPassword; diff --git a/snappymail/v/0.0.0/app/localization/ar-SA/user.json b/snappymail/v/0.0.0/app/localization/ar-SA/user.json index 53412e63f..b5f6bd243 100644 --- a/snappymail/v/0.0.0/app/localization/ar-SA/user.json +++ b/snappymail/v/0.0.0/app/localization/ar-SA/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "إرسال الرسالة", "LABEL_CLOSE_COMPOSE": "إغلاق الرسالة" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "خاطىء token", "AUTH_ERROR": "خطأ في كلمة السر \\اسم المستخدم", diff --git a/snappymail/v/0.0.0/app/localization/bg-BG/user.json b/snappymail/v/0.0.0/app/localization/bg-BG/user.json index ad3f7235b..f9ec04b11 100644 --- a/snappymail/v/0.0.0/app/localization/bg-BG/user.json +++ b/snappymail/v/0.0.0/app/localization/bg-BG/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Изпрати съобщението", "LABEL_CLOSE_COMPOSE": "Затвори създаването" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Невалиден токен", "AUTH_ERROR": "Неуспешно удостоверяване", diff --git a/snappymail/v/0.0.0/app/localization/cs-CZ/user.json b/snappymail/v/0.0.0/app/localization/cs-CZ/user.json index 4a33ed5d0..04ce66ca9 100644 --- a/snappymail/v/0.0.0/app/localization/cs-CZ/user.json +++ b/snappymail/v/0.0.0/app/localization/cs-CZ/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Odeslat zprávu", "LABEL_CLOSE_COMPOSE": "Zavřít okno se zprávou" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Neplatný token", "AUTH_ERROR": "Ověření selhalo", diff --git a/snappymail/v/0.0.0/app/localization/da-DK/user.json b/snappymail/v/0.0.0/app/localization/da-DK/user.json index 19a757574..bf1fd96c2 100644 --- a/snappymail/v/0.0.0/app/localization/da-DK/user.json +++ b/snappymail/v/0.0.0/app/localization/da-DK/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Send meddelelse", "LABEL_CLOSE_COMPOSE": "Luk forfatter mode" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Ugyldigt tegn", "AUTH_ERROR": "Godkendelse fejlede", diff --git a/snappymail/v/0.0.0/app/localization/de-DE/user.json b/snappymail/v/0.0.0/app/localization/de-DE/user.json index c4c481b41..32d593f22 100644 --- a/snappymail/v/0.0.0/app/localization/de-DE/user.json +++ b/snappymail/v/0.0.0/app/localization/de-DE/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Nachricht senden", "LABEL_CLOSE_COMPOSE": "Popup schließen" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Ungültiger Token", "AUTH_ERROR": "Authentifizierung fehlgeschlagen", diff --git a/snappymail/v/0.0.0/app/localization/el-GR/user.json b/snappymail/v/0.0.0/app/localization/el-GR/user.json index 77b2cd940..f4ca380eb 100644 --- a/snappymail/v/0.0.0/app/localization/el-GR/user.json +++ b/snappymail/v/0.0.0/app/localization/el-GR/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Send message", "LABEL_CLOSE_COMPOSE": "Close compose" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Invalid token", "AUTH_ERROR": "Authentication failed", diff --git a/snappymail/v/0.0.0/app/localization/en/user.json b/snappymail/v/0.0.0/app/localization/en/user.json index 19c2df5d7..539fbdcab 100644 --- a/snappymail/v/0.0.0/app/localization/en/user.json +++ b/snappymail/v/0.0.0/app/localization/en/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Send message", "LABEL_CLOSE_COMPOSE": "Close compose" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Invalid token", "AUTH_ERROR": "Authentication failed", diff --git a/snappymail/v/0.0.0/app/localization/es-ES/user.json b/snappymail/v/0.0.0/app/localization/es-ES/user.json index 30045482e..9a7c9a1ab 100644 --- a/snappymail/v/0.0.0/app/localization/es-ES/user.json +++ b/snappymail/v/0.0.0/app/localization/es-ES/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Enviar mensaje", "LABEL_CLOSE_COMPOSE": "Cerrar componer" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Elemento no válido", "AUTH_ERROR": "Autentificación fallida", diff --git a/snappymail/v/0.0.0/app/localization/et-EE/user.json b/snappymail/v/0.0.0/app/localization/et-EE/user.json index b00c471c3..dd92f3e3a 100644 --- a/snappymail/v/0.0.0/app/localization/et-EE/user.json +++ b/snappymail/v/0.0.0/app/localization/et-EE/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Saada kiri", "LABEL_CLOSE_COMPOSE": "Sulge kirja koostamise aken" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Puudulik tõend", "AUTH_ERROR": "Autentimine ebaõnnestus", diff --git a/snappymail/v/0.0.0/app/localization/fa-IR/user.json b/snappymail/v/0.0.0/app/localization/fa-IR/user.json index 172d9c85e..3c270cb44 100644 --- a/snappymail/v/0.0.0/app/localization/fa-IR/user.json +++ b/snappymail/v/0.0.0/app/localization/fa-IR/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "فرستادن پیام", "LABEL_CLOSE_COMPOSE": "بستن صفحه ایجاد" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "توکن نامعتبر", "AUTH_ERROR": "احراز هویت با موفقیت همراه نبود", diff --git a/snappymail/v/0.0.0/app/localization/fi-FI/user.json b/snappymail/v/0.0.0/app/localization/fi-FI/user.json index 99d434e83..8f6120294 100644 --- a/snappymail/v/0.0.0/app/localization/fi-FI/user.json +++ b/snappymail/v/0.0.0/app/localization/fi-FI/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Lähetä viesti", "LABEL_CLOSE_COMPOSE": "Sule luo viesti" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Väärä suojaustunnus", "AUTH_ERROR": "Tunnistusvirhe", diff --git a/snappymail/v/0.0.0/app/localization/fr-FR/user.json b/snappymail/v/0.0.0/app/localization/fr-FR/user.json index 4a7b76f9e..a0f3779c7 100644 --- a/snappymail/v/0.0.0/app/localization/fr-FR/user.json +++ b/snappymail/v/0.0.0/app/localization/fr-FR/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Envoyer le message", "LABEL_CLOSE_COMPOSE": "Fermer la fenêtre d'édition" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Jeton invalide", "AUTH_ERROR": "L'authentification a échoué", diff --git a/snappymail/v/0.0.0/app/localization/hu-HU/user.json b/snappymail/v/0.0.0/app/localization/hu-HU/user.json index 5da7b4321..d3b8a4ee5 100644 --- a/snappymail/v/0.0.0/app/localization/hu-HU/user.json +++ b/snappymail/v/0.0.0/app/localization/hu-HU/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Üzenet küldés", "LABEL_CLOSE_COMPOSE": "Levélírás bezárása" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Érvénytelen kulcs", "AUTH_ERROR": "Érvénytelen hitelesítés", diff --git a/snappymail/v/0.0.0/app/localization/id-ID/user.json b/snappymail/v/0.0.0/app/localization/id-ID/user.json index d93eb6c03..d647f69e8 100644 --- a/snappymail/v/0.0.0/app/localization/id-ID/user.json +++ b/snappymail/v/0.0.0/app/localization/id-ID/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Kirim pesan", "LABEL_CLOSE_COMPOSE": "Tutup buat pesan" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Token tidak sah", "AUTH_ERROR": "Otentikasi gagal", diff --git a/snappymail/v/0.0.0/app/localization/is-IS/user.json b/snappymail/v/0.0.0/app/localization/is-IS/user.json index fa8d19478..77f2e5c0a 100644 --- a/snappymail/v/0.0.0/app/localization/is-IS/user.json +++ b/snappymail/v/0.0.0/app/localization/is-IS/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Senda skilaboð", "LABEL_CLOSE_COMPOSE": "Loka ritli" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Rangt tákn", "AUTH_ERROR": "Auðkenning mistókst", diff --git a/snappymail/v/0.0.0/app/localization/it-IT/user.json b/snappymail/v/0.0.0/app/localization/it-IT/user.json index 5dbcfa530..5f984b3d2 100644 --- a/snappymail/v/0.0.0/app/localization/it-IT/user.json +++ b/snappymail/v/0.0.0/app/localization/it-IT/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Invia messaggio", "LABEL_CLOSE_COMPOSE": "Chiudi finestra di scrittura" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Token invalido", "AUTH_ERROR": "Autenticazione fallita", diff --git a/snappymail/v/0.0.0/app/localization/ja-JP/user.json b/snappymail/v/0.0.0/app/localization/ja-JP/user.json index 158be02ae..596f496d5 100644 --- a/snappymail/v/0.0.0/app/localization/ja-JP/user.json +++ b/snappymail/v/0.0.0/app/localization/ja-JP/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "メッセージを送信", "LABEL_CLOSE_COMPOSE": "作成画面を閉じる" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "無効なトークン", "AUTH_ERROR": "認証に失敗しました", diff --git a/snappymail/v/0.0.0/app/localization/ko-KR/user.json b/snappymail/v/0.0.0/app/localization/ko-KR/user.json index 01a9d2818..60e2abfe2 100644 --- a/snappymail/v/0.0.0/app/localization/ko-KR/user.json +++ b/snappymail/v/0.0.0/app/localization/ko-KR/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "메시지 보내기", "LABEL_CLOSE_COMPOSE": "쓰기 창 닫기" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "잘못된 토큰입니다.", "AUTH_ERROR": "인증에 실패했습니다", diff --git a/snappymail/v/0.0.0/app/localization/lt-LT/user.json b/snappymail/v/0.0.0/app/localization/lt-LT/user.json index 6a60e1a3b..f889d2be4 100644 --- a/snappymail/v/0.0.0/app/localization/lt-LT/user.json +++ b/snappymail/v/0.0.0/app/localization/lt-LT/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Siųsti laišką", "LABEL_CLOSE_COMPOSE": "Uždaryti laišką" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Neteisingas raktas", "AUTH_ERROR": "Autorizacija nepavyko", diff --git a/snappymail/v/0.0.0/app/localization/lv-LV/user.json b/snappymail/v/0.0.0/app/localization/lv-LV/user.json index 8491a560d..7509de54b 100644 --- a/snappymail/v/0.0.0/app/localization/lv-LV/user.json +++ b/snappymail/v/0.0.0/app/localization/lv-LV/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Send message", "LABEL_CLOSE_COMPOSE": "Close compose" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Nepareizs tokens", "AUTH_ERROR": "Autorizācija neizdevās", diff --git a/snappymail/v/0.0.0/app/localization/nb-NO/user.json b/snappymail/v/0.0.0/app/localization/nb-NO/user.json index 67126114e..40daf6bbe 100644 --- a/snappymail/v/0.0.0/app/localization/nb-NO/user.json +++ b/snappymail/v/0.0.0/app/localization/nb-NO/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Send melding", "LABEL_CLOSE_COMPOSE": "Lukk ny melding" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Ugyldig info", "AUTH_ERROR": "Autentisering mislyktes", diff --git a/snappymail/v/0.0.0/app/localization/nl-NL/user.json b/snappymail/v/0.0.0/app/localization/nl-NL/user.json index 864ab2198..90874cc41 100644 --- a/snappymail/v/0.0.0/app/localization/nl-NL/user.json +++ b/snappymail/v/0.0.0/app/localization/nl-NL/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Bericht versturen", "LABEL_CLOSE_COMPOSE": "Nieuw bericht venster sluiten" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Ongeldige token", "AUTH_ERROR": "Authenticatie mislukt", diff --git a/snappymail/v/0.0.0/app/localization/pl-PL/user.json b/snappymail/v/0.0.0/app/localization/pl-PL/user.json index f85b2d2c3..eab50610d 100644 --- a/snappymail/v/0.0.0/app/localization/pl-PL/user.json +++ b/snappymail/v/0.0.0/app/localization/pl-PL/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Wyślij wiadomość", "LABEL_CLOSE_COMPOSE": "Zamknij okno tworzenia wiadomości" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Nieprawidłowy token", "AUTH_ERROR": "Błąd autoryzacji", diff --git a/snappymail/v/0.0.0/app/localization/pt-BR/user.json b/snappymail/v/0.0.0/app/localization/pt-BR/user.json index 395aa7cf3..10b649319 100644 --- a/snappymail/v/0.0.0/app/localization/pt-BR/user.json +++ b/snappymail/v/0.0.0/app/localization/pt-BR/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Enviar mensagem", "LABEL_CLOSE_COMPOSE": "Fechar composição" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Senha inválida", "AUTH_ERROR": "Falha na autenticação", diff --git a/snappymail/v/0.0.0/app/localization/pt-PT/user.json b/snappymail/v/0.0.0/app/localization/pt-PT/user.json index 739f98cff..5323b4a2c 100644 --- a/snappymail/v/0.0.0/app/localization/pt-PT/user.json +++ b/snappymail/v/0.0.0/app/localization/pt-PT/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Enviar mensagem", "LABEL_CLOSE_COMPOSE": "Fechar janela de composição" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Token inválido", "AUTH_ERROR": "Falha na autenticação", diff --git a/snappymail/v/0.0.0/app/localization/ro-RO/user.json b/snappymail/v/0.0.0/app/localization/ro-RO/user.json index 4fa687d1d..e7c84a8fd 100644 --- a/snappymail/v/0.0.0/app/localization/ro-RO/user.json +++ b/snappymail/v/0.0.0/app/localization/ro-RO/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Send message", "LABEL_CLOSE_COMPOSE": "Close compose" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Semn invalid", "AUTH_ERROR": "Nu se poate realiza conectarea", diff --git a/snappymail/v/0.0.0/app/localization/ru-RU/user.json b/snappymail/v/0.0.0/app/localization/ru-RU/user.json index 6f0261417..7ca1547b7 100644 --- a/snappymail/v/0.0.0/app/localization/ru-RU/user.json +++ b/snappymail/v/0.0.0/app/localization/ru-RU/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Отправить сообщение", "LABEL_CLOSE_COMPOSE": "Закрыть сообщение" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Неверный токен запроса", "AUTH_ERROR": "Не удалось авторизоваться", diff --git a/snappymail/v/0.0.0/app/localization/sk-SK/user.json b/snappymail/v/0.0.0/app/localization/sk-SK/user.json index 7b6b0fe5c..925d315e8 100644 --- a/snappymail/v/0.0.0/app/localization/sk-SK/user.json +++ b/snappymail/v/0.0.0/app/localization/sk-SK/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Send message", "LABEL_CLOSE_COMPOSE": "Close compose" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Neplatný token", "AUTH_ERROR": "Overenie zlyhalo", diff --git a/snappymail/v/0.0.0/app/localization/sl-SI/user.json b/snappymail/v/0.0.0/app/localization/sl-SI/user.json index 191a699ca..e1e58ce0f 100644 --- a/snappymail/v/0.0.0/app/localization/sl-SI/user.json +++ b/snappymail/v/0.0.0/app/localization/sl-SI/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Pošlji sporočilo", "LABEL_CLOSE_COMPOSE": "Zapri sestavljanje" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Neveljaven žeton", "AUTH_ERROR": "Spodletelo overjanje", diff --git a/snappymail/v/0.0.0/app/localization/sv-SE/user.json b/snappymail/v/0.0.0/app/localization/sv-SE/user.json index 21dde9186..35b84232b 100644 --- a/snappymail/v/0.0.0/app/localization/sv-SE/user.json +++ b/snappymail/v/0.0.0/app/localization/sv-SE/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Skicka meddelande", "LABEL_CLOSE_COMPOSE": "Stäng fönster" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Ogiltigt tecken", "AUTH_ERROR": "Autentisering misslyckades", diff --git a/snappymail/v/0.0.0/app/localization/tr-TR/user.json b/snappymail/v/0.0.0/app/localization/tr-TR/user.json index a270389d8..c61010b06 100644 --- a/snappymail/v/0.0.0/app/localization/tr-TR/user.json +++ b/snappymail/v/0.0.0/app/localization/tr-TR/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Mesajı Gönder", "LABEL_CLOSE_COMPOSE": "Oluşturulanı Kapat" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Geçersiz token", "AUTH_ERROR": "Kimlik doğrulama başarısız oldu", diff --git a/snappymail/v/0.0.0/app/localization/uk-UA/user.json b/snappymail/v/0.0.0/app/localization/uk-UA/user.json index d4ac75a09..5be2bdf29 100644 --- a/snappymail/v/0.0.0/app/localization/uk-UA/user.json +++ b/snappymail/v/0.0.0/app/localization/uk-UA/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Надіслати повідомлення", "LABEL_CLOSE_COMPOSE": "Закрити повідомлення" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "Невірний токен запиту", "AUTH_ERROR": "Не вдалося авторизуватися", diff --git a/snappymail/v/0.0.0/app/localization/zh-CN/user.json b/snappymail/v/0.0.0/app/localization/zh-CN/user.json index aea25e676..6d0c8ffbc 100644 --- a/snappymail/v/0.0.0/app/localization/zh-CN/user.json +++ b/snappymail/v/0.0.0/app/localization/zh-CN/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "发送邮件", "LABEL_CLOSE_COMPOSE": "退出新邮件" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "无效标记", "AUTH_ERROR": "认证失败", diff --git a/snappymail/v/0.0.0/app/localization/zh-TW/user.json b/snappymail/v/0.0.0/app/localization/zh-TW/user.json index cee9c40db..6efd2595c 100644 --- a/snappymail/v/0.0.0/app/localization/zh-TW/user.json +++ b/snappymail/v/0.0.0/app/localization/zh-TW/user.json @@ -500,6 +500,9 @@ "LABEL_SEND_MESSAGE": "Send message", "LABEL_CLOSE_COMPOSE": "Close compose" }, + "KOLAB": { + "CONTACTS_FOLDER": "Contacts Folder" + }, "NOTIFICATIONS": { "INVALID_TOKEN": "無效標記", "AUTH_ERROR": "認證失敗", diff --git a/snappymail/v/0.0.0/app/templates/Views/User/SettingsContacts.html b/snappymail/v/0.0.0/app/templates/Views/User/SettingsContacts.html index 16519ca2f..8f8f3a426 100644 --- a/snappymail/v/0.0.0/app/templates/Views/User/SettingsContacts.html +++ b/snappymail/v/0.0.0/app/templates/Views/User/SettingsContacts.html @@ -40,3 +40,11 @@ spellcheck="false" data-bind="value: syncPass"> +
+
Kolab
+
+ + +
+