From 639d8c58f6b7052a3e6c7e3bc03afc56e82a5823 Mon Sep 17 00:00:00 2001 From: RainLoop Team Date: Wed, 25 Dec 2013 04:05:04 +0400 Subject: [PATCH] CardDAV (pre-release) --- Gruntfile.js | 1 + dev/Boots/AbstractApp.js | 2 +- dev/Boots/RainLoopApp.js | 7 +- dev/Screens/Login.js | 2 +- dev/Settings/Contacts.js | 39 ++++ dev/Settings/General.js | 8 - .../0.0.0/app/libraries/MailSo/Base/Http.php | 12 +- .../0.0.0/app/libraries/RainLoop/Actions.php | 25 ++- .../PdoPersonalAddressBook.php | 23 +- .../Views/AdminSettingsContacts.html | 4 +- .../app/templates/Views/SettingsAccounts.html | 2 +- .../Views/SettingsChangePassword.html | 2 +- .../app/templates/Views/SettingsContacts.html | 66 ++++++ .../app/templates/Views/SettingsFolders.html | 2 +- .../app/templates/Views/SettingsGeneral.html | 16 +- .../templates/Views/SettingsIdentities.html | 2 +- .../app/templates/Views/SettingsPane.html | 2 +- .../app/templates/Views/SettingsSocial.html | 2 +- .../app/templates/Views/SettingsThemes.html | 2 +- .../app/templates/Views/SystemDropDown.html | 8 +- rainloop/v/0.0.0/langs/de.ini | 13 +- rainloop/v/0.0.0/langs/en.ini | 13 +- rainloop/v/0.0.0/langs/es.ini | 13 +- rainloop/v/0.0.0/langs/fr.ini | 13 +- rainloop/v/0.0.0/langs/is.ini | 13 +- rainloop/v/0.0.0/langs/ko-kr.ini | 13 +- rainloop/v/0.0.0/langs/lv.ini | 13 +- rainloop/v/0.0.0/langs/nl.ini | 13 +- rainloop/v/0.0.0/langs/no.ini | 13 +- rainloop/v/0.0.0/langs/pl.ini | 13 +- rainloop/v/0.0.0/langs/pt-br.ini | 13 +- rainloop/v/0.0.0/langs/pt-pt.ini | 13 +- rainloop/v/0.0.0/langs/ru.ini | 13 +- rainloop/v/0.0.0/langs/zh-cn.ini | 13 +- rainloop/v/0.0.0/static/js/admin.js | 104 ++++----- rainloop/v/0.0.0/static/js/admin.min.js | 2 +- rainloop/v/0.0.0/static/js/app.js | 201 ++++++++++-------- rainloop/v/0.0.0/static/js/app.min.js | 16 +- 38 files changed, 525 insertions(+), 207 deletions(-) create mode 100644 dev/Settings/Contacts.js create mode 100644 rainloop/v/0.0.0/app/templates/Views/SettingsContacts.html diff --git a/Gruntfile.js b/Gruntfile.js index 06bd3ffb9..eb7a20e41 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -277,6 +277,7 @@ module.exports = function (grunt) { "dev/ViewModels/SettingsPaneViewModel.js", "dev/Settings/General.js", + "dev/Settings/Contacts.js", "dev/Settings/Accounts.js", "dev/Settings/Identity.js", "dev/Settings/Identities.js", diff --git a/dev/Boots/AbstractApp.js b/dev/Boots/AbstractApp.js index b8045903c..0c2d90a2f 100644 --- a/dev/Boots/AbstractApp.js +++ b/dev/Boots/AbstractApp.js @@ -146,7 +146,7 @@ AbstractApp.prototype.settingsSet = function (sName, mValue) AbstractApp.prototype.setTitle = function (sTitle) { - sTitle = ((0 < sTitle.length) ? sTitle + ' - ' : '') + + sTitle = ((Utils.isNormal(sTitle) && 0 < sTitle.length) ? sTitle + ' - ' : '') + RL.settingsGet('Title') || ''; window.document.title = '_'; diff --git a/dev/Boots/RainLoopApp.js b/dev/Boots/RainLoopApp.js index 863cf6c16..af56f052b 100644 --- a/dev/Boots/RainLoopApp.js +++ b/dev/Boots/RainLoopApp.js @@ -719,7 +719,12 @@ RainLoopApp.prototype.bootstart = function () { Utils.removeSettingsViewModel(SettingsChangePasswordScreen); } - + + if (!RL.settingsGet('ContactsIsAllowed')) + { + Utils.removeSettingsViewModel(SettingsContacts); + } + if (!RL.settingsGet('AllowAdditionalAccounts')) { Utils.removeSettingsViewModel(SettingsAccounts); diff --git a/dev/Screens/Login.js b/dev/Screens/Login.js index 23a5cbbbe..efee34c7d 100644 --- a/dev/Screens/Login.js +++ b/dev/Screens/Login.js @@ -13,5 +13,5 @@ _.extend(LoginScreen.prototype, KnoinAbstractScreen.prototype); LoginScreen.prototype.onShow = function () { - RL.setTitle(Utils.i18n('TITLES/LOGIN')); + RL.setTitle(''); }; \ No newline at end of file diff --git a/dev/Settings/Contacts.js b/dev/Settings/Contacts.js new file mode 100644 index 000000000..df763a8fc --- /dev/null +++ b/dev/Settings/Contacts.js @@ -0,0 +1,39 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +/** + * @constructor + */ +function SettingsContacts() +{ + var oData = RL.data(); + + this.contactsAutosave = oData.contactsAutosave; + this.showPassword = ko.observable(false); + + this.allowContactsSync = !!RL.settingsGet('ContactsSyncIsAllowed'); + this.contactsSyncServer = RL.settingsGet('ContactsSyncServer'); + this.contactsSyncUser = RL.settingsGet('ContactsSyncUser'); + this.contactsSyncPass = RL.settingsGet('ContactsSyncPassword'); + this.contactsSyncPabUrl = RL.settingsGet('ContactsSyncPabUrl'); +} + +Utils.addSettingsViewModel(SettingsContacts, 'SettingsContacts', 'SETTINGS_LABELS/LABEL_CONTACTS_NAME', 'contacts'); + +SettingsContacts.prototype.toggleShowPassword = function () +{ + this.showPassword(!this.showPassword()); +}; + +SettingsContacts.prototype.onBuild = function () +{ + RL.data().contactsAutosave.subscribe(function (bValue) { + RL.remote().saveSettings(Utils.emptyFunction, { + 'ContactsAutosave': bValue ? '1' : '0' + }); + }); +}; + +SettingsContacts.prototype.onShow = function () +{ + this.showPassword(false); +}; diff --git a/dev/Settings/General.js b/dev/Settings/General.js index 7dcb34926..ee19158c6 100644 --- a/dev/Settings/General.js +++ b/dev/Settings/General.js @@ -12,7 +12,6 @@ function SettingsGeneral() this.mainMessagesPerPageArray = Consts.Defaults.MessagesPerPageArray; this.editorDefaultType = oData.editorDefaultType; this.showImages = oData.showImages; - this.contactsAutosave = oData.contactsAutosave; this.interfaceAnimation = oData.interfaceAnimation; this.useDesktopNotifications = oData.useDesktopNotifications; this.threading = oData.threading; @@ -39,7 +38,6 @@ function SettingsGeneral() this.mppTrigger = ko.observable(Enums.SaveSettingsStep.Idle); this.isAnimationSupported = Globals.bAnimationSupported; - this.allowContacts = !!RL.settingsGet('ContactsIsAllowed'); } Utils.addSettingsViewModel(SettingsGeneral, 'SettingsGeneral', 'SETTINGS_LABELS/LABEL_GENERAL_NAME', 'general', true); @@ -97,12 +95,6 @@ SettingsGeneral.prototype.onBuild = function () }); }); - oData.contactsAutosave.subscribe(function (bValue) { - RL.remote().saveSettings(Utils.emptyFunction, { - 'ContactsAutosave': bValue ? '1' : '0' - }); - }); - oData.interfaceAnimation.subscribe(function (sValue) { RL.remote().saveSettings(Utils.emptyFunction, { 'InterfaceAnimation': sValue diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Base/Http.php b/rainloop/v/0.0.0/app/libraries/MailSo/Base/Http.php index 9ffbd0b1b..3b1653b12 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Base/Http.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Base/Http.php @@ -290,11 +290,12 @@ class Http /** * @param bool $bWithRemoteUserData = false - * @param bool $bRemoveWWW = true + * @param bool $bWithoutWWW = true + * @param bool $bWithoutPort = false * * @return string */ - public function GetHost($bWithRemoteUserData = false, $bRemoveWWW = true) + public function GetHost($bWithRemoteUserData = false, $bWithoutWWW = true, $bWithoutPort = false) { $sHost = $this->GetServer('HTTP_HOST', ''); if (0 === \strlen($sHost)) @@ -307,7 +308,7 @@ class Http ? $sName : $sName.':'.$iPort; } - if ($bRemoveWWW) + if ($bWithoutWWW) { $sHost = 'www.' === \substr(\strtolower($sHost), 0, 4) ? \substr($sHost, 4) : $sHost; } @@ -318,6 +319,11 @@ class Http $sHost = (0 < \strlen($sUser) ? $sUser.'@' : '').$sHost; } + if ($bWithoutPort) + { + $sHost = \preg_replace('/:[\d]+$/', '', $sHost); + } + return $sHost; } diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php index d33ce3991..4c5c43873 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -930,14 +930,35 @@ class Actions $oAccount = $this->getAccountFromToken(false); if ($oAccount instanceof \RainLoop\Account) { + $oPab = $this->PersonalAddressBookProvider($oAccount); + + $aResult['Auth'] = true; $aResult['Email'] = $oAccount->Email(); $aResult['IncLogin'] = $oAccount->IncLogin(); $aResult['OutLogin'] = $oAccount->OutLogin(); $aResult['AccountHash'] = $oAccount->Hash(); $aResult['ChangePasswordIsAllowed'] = $this->ChangePasswordProvider()->PasswordChangePossibility($oAccount); - $aResult['ContactsIsAllowed'] = $this->PersonalAddressBookProvider($oAccount)->IsActive(); - $aResult['ContactsSharingIsAllowed'] = $this->PersonalAddressBookProvider($oAccount)->IsSharingAllowed(); + $aResult['ContactsIsAllowed'] = $oPab->IsActive(); + $aResult['ContactsSharingIsAllowed'] = $oPab->IsSharingAllowed(); + + $aResult['ContactsSyncIsAllowed'] = (bool) $oConfig->Get('contacts', 'allow_sync', false); + $aResult['ContactsSyncServer'] = ''; + $aResult['ContactsSyncUser'] = ''; + $aResult['ContactsSyncPassword'] = ''; + $aResult['ContactsSyncPabUrl'] = ''; + + if ($aResult['ContactsSyncIsAllowed']) + { + $aResult['ContactsSyncServer'] = $this->Http()->GetHost(false, true, true); + $aResult['ContactsSyncUser'] = $oAccount->ParentEmailHelper(); + $aResult['ContactsSyncPassword'] = $oPab->GetUserHashByEmail($aResult['ContactsSyncUser'], true); + + $sUrl = \rtrim(\trim($this->Http()->GetScheme().'://'.$this->Http()->GetHost(true, false).$this->Http()->GetPath()), '/\\'); + $sUrl = \preg_replace('/index\.php(.*)$/i', '', $sUrl); + + $aResult['ContactsSyncPabUrl'] = $sUrl.'/index.php/dav/addressbooks/'.$oAccount->ParentEmailHelper().'/default/'; + } $oSettings = $this->SettingsProvider()->Load($oAccount); } diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/PdoPersonalAddressBook.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/PdoPersonalAddressBook.php index d9acae8ce..d566d9450 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/PdoPersonalAddressBook.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/PdoPersonalAddressBook.php @@ -88,6 +88,8 @@ class PdoPersonalAddressBook */ public function GetUserUidByEmail($sEmail) { + $this->Sync(); + $iId = $this->getUserId($sEmail); return 0 < $iId ? (string) $iId : ''; } @@ -98,6 +100,8 @@ class PdoPersonalAddressBook */ public function GetCtagByEmail($sEmail) { + $this->Sync(); + $sResult = '0'; $iUserID = $this->getUserId($sEmail); if (0 < $iUserID) @@ -126,11 +130,13 @@ class PdoPersonalAddressBook */ public function GetUserHashByEmail($sEmail, $bCreate = false) { + $this->Sync(); + $sHash = ''; $iUserID = $this->getUserId($sEmail); if (0 < $iUserID) { - $oStmt = $this->prepareAndExecute('SELECT pass_hash FROM rainloop_pab_users_hashes WHERE id_user = :id_user LIMIT 1', + $oStmt = $this->prepareAndExecute('SELECT pass_hash FROM rainloop_pab_users WHERE id_user = :id_user LIMIT 1', array(':id_user' => array($iUserID, \PDO::PARAM_INT))); if ($oStmt) @@ -142,14 +148,15 @@ class PdoPersonalAddressBook } else if ($bCreate) { - $this->prepareAndExecute('INSERT INTO rainloop_pab_users_hashes (id_user, pass_hash) VALUES (:id_user, :pass_hash);', + $this->prepareAndExecute('INSERT INTO rainloop_pab_users (id_user, email, pass_hash) VALUES (:id_user, :email, :pass_hash);', array( ':id_user' => array($iUserID, \PDO::PARAM_INT), + ':email' => array($sEmail, \PDO::PARAM_STR), ':pass_hash' => array(\md5($sEmail.\microtime(true)), \PDO::PARAM_STR) ) ); - $this->GetUserHashByEmail($sEmail, false); + $sHash = $this->GetUserHashByEmail($sEmail, false); } } } @@ -305,6 +312,7 @@ class PdoPersonalAddressBook */ public function DeleteContacts($sEmail, $aContactIds) { + $this->Sync(); $iUserID = $this->getUserId($sEmail); $aContactIds = \array_filter($aContactIds, function (&$mItem) { @@ -1239,8 +1247,9 @@ SQLITEINITIAL; 'ALTER TABLE rainloop_pab_contacts ADD carddav_data MEDIUMTEXT;', 'ALTER TABLE rainloop_pab_contacts ADD carddav_hash varchar(128) NOT NULL DEFAULT \'\';', 'ALTER TABLE rainloop_pab_contacts ADD carddav_size int UNSIGNED NOT NULL DEFAULT 0;', -'CREATE TABLE IF NOT EXISTS rainloop_pab_users_hashes ( +'CREATE TABLE IF NOT EXISTS rainloop_pab_users ( id_user int UNSIGNED NOT NULL, + email varchar(128) NOT NULL, pass_hash varchar(128) NOT NULL )/*!40000 ENGINE=INNODB */;' ) @@ -1253,8 +1262,9 @@ SQLITEINITIAL; 'ALTER TABLE rainloop_pab_contacts ADD carddav_data TEXT;', 'ALTER TABLE rainloop_pab_contacts ADD carddav_hash varchar(128) NOT NULL DEFAULT \'\';', 'ALTER TABLE rainloop_pab_contacts ADD carddav_size integer NOT NULL DEFAULT 0;', -'CREATE TABLE rainloop_pab_users_hashes ( +'CREATE TABLE rainloop_pab_users ( id_user integer NOT NULL, + email varchar(128) NOT NULL, pass_hash varchar(128) NOT NULL );' ) @@ -1267,8 +1277,9 @@ SQLITEINITIAL; 'ALTER TABLE rainloop_pab_contacts ADD carddav_data text;', 'ALTER TABLE rainloop_pab_contacts ADD carddav_hash text NOT NULL DEFAULT \'\';', 'ALTER TABLE rainloop_pab_contacts ADD carddav_size integer NOT NULL DEFAULT 0;', -'CREATE TABLE rainloop_pab_users_hashes ( +'CREATE TABLE rainloop_pab_users ( id_user integer NOT NULL, + email text NOT NULL, pass_hash text NOT NULL );' ) diff --git a/rainloop/v/0.0.0/app/templates/Views/AdminSettingsContacts.html b/rainloop/v/0.0.0/app/templates/Views/AdminSettingsContacts.html index 590c2091a..eea16a045 100644 --- a/rainloop/v/0.0.0/app/templates/Views/AdminSettingsContacts.html +++ b/rainloop/v/0.0.0/app/templates/Views/AdminSettingsContacts.html @@ -9,7 +9,6 @@
-
Contacts
@@ -23,12 +22,15 @@ Allow contacts sharing +
+ read about web server configuration
+