From 3a4867abea635a83e3a5897aff855a3da24d3ad8 Mon Sep 17 00:00:00 2001 From: RainLoop Team Date: Wed, 4 Dec 2013 02:50:01 +0400 Subject: [PATCH] MySQL pab driver implementation (part 4) --- .../0.0.0/app/libraries/RainLoop/Actions.php | 9 +- .../libraries/RainLoop/Common/PdoAbstract.php | 49 +++- .../PersonalAddressBook/Classes/Contact.php | 7 +- .../PersonalAddressBook/Classes/Property.php | 19 -- .../MySqlPersonalAddressBook.php | 253 ++++++++++++++---- rainloop/v/0.0.0/static/js/app.js | 2 +- rainloop/v/0.0.0/static/js/app.min.js | 2 +- 7 files changed, 255 insertions(+), 86 deletions(-) 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 165227153..70aa23435 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -3790,10 +3790,10 @@ class Actions $this->Plugins()->RunHook('filter.smtp-credentials', array($oAccount, &$aSmtpCredentials)); - $bHookConnect = $bHookAuth = $bHookFrom = $bHookFrom = $bHookTo = $bHookData = false; + $bHookConnect = $bHookAuth = $bHookFrom = $bHookFrom = $bHookTo = $bHookData = $bHookLogoutAndDisconnect = false; $this->Plugins()->RunHook('filter.smtp-connect', array($oAccount, $aSmtpCredentials, &$oSmtpClient, $oMessage, &$oRcpt, - &$bHookConnect, &$bHookAuth, &$bHookFrom, &$bHookTo, &$bHookData)); + &$bHookConnect, &$bHookAuth, &$bHookFrom, &$bHookTo, &$bHookData, &$bHookLogoutAndDisconnect)); if (!$bHookConnect) { @@ -3839,7 +3839,10 @@ class Actions $oSmtpClient->DataWithStream($rMessageStream); } - $oSmtpClient->LogoutAndDisconnect(); + if (!$bHookLogoutAndDisconnect) + { + $oSmtpClient->LogoutAndDisconnect(); + } } catch (\MailSo\Net\Exceptions\ConnectionException $oException) { diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Common/PdoAbstract.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Common/PdoAbstract.php index a99bd252b..f35fc938c 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Common/PdoAbstract.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Common/PdoAbstract.php @@ -93,14 +93,49 @@ abstract class PdoAbstract return $oPdo; } + /** + * @param string $sName = null + * + * @return string + */ + protected function lastInsertId($sName = null) + { + return $this->getPDO()->lastInsertId($sName); + } + + /** + * @return nool + */ + protected function beginTransaction() + { + return $this->getPDO()->beginTransaction(); + } + + /** + * @return nool + */ + protected function commit() + { + return $this->getPDO()->commit(); + } + + /** + * @return nool + */ + protected function rollBack() + { + return $this->getPDO()->rollBack(); + } + /** * @param \RainLoop\Account $oAccount * @param string $sSql * @param array $aParams + * @param bool $bMultParams = false * * @return \PDOStatement|null */ - protected function prepareAndExecute($sSql, $aParams = array()) + protected function prepareAndExecute($sSql, $aParams = array(), $bMultParams = false) { $mResult = null; @@ -108,12 +143,16 @@ abstract class PdoAbstract $oStmt = $this->getPDO()->prepare($sSql); if ($oStmt) { - foreach ($aParams as $sName => $aValue) + $aRootParams = $bMultParams ? $aParams : array($aParams); + foreach ($aRootParams as $aSubParams) { - $oStmt->bindValue($sName, $aValue[0], $aValue[1]); - } + foreach ($aSubParams as $sName => $aValue) + { + $oStmt->bindValue($sName, $aValue[0], $aValue[1]); + } - $mResult = $oStmt->execute() ? $oStmt : null; + $mResult = $oStmt->execute() && !$bMultParams ? $oStmt : null; + } } return $mResult; diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Classes/Contact.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Classes/Contact.php index 82cafcbcb..4fb487503 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Classes/Contact.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Classes/Contact.php @@ -9,11 +9,6 @@ class Contact */ public $IdContact; - /** - * @var int - */ - public $IdUser; - /** * @var string */ @@ -66,7 +61,7 @@ class Contact $sDisplayName = ''; $sDisplayEmail = ''; - foreach ($this->Properties as /* @var $oProperty \RainLoop\Providers\PersonalAddressBook\Classes\Property */ $oProperty) + foreach ($this->Properties as /* @var $oProperty \RainLoop\Providers\PersonalAddressBook\Classes\Property */ &$oProperty) { if ($oProperty) { diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Classes/Property.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Classes/Property.php index 679953462..099f14040 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Classes/Property.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Classes/Property.php @@ -6,21 +6,6 @@ use RainLoop\Providers\PersonalAddressBook\Enumerations\PropertyType; class Property { - /** - * @var int - */ - public $IdProperty; - - /** - * @var int - */ - public $IdContact; - - /** - * @var int - */ - public $IdUser; - /** * @var int */ @@ -53,10 +38,6 @@ class Property public function Clear() { - $this->IdProperty = 0; - $this->IdContact = 0; - $this->IdUser = 0; - $this->Type = PropertyType::UNKNOWN; $this->TypeCustom = ''; diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/MySqlPersonalAddressBook.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/MySqlPersonalAddressBook.php index d05ef6185..edc2f3cd2 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/MySqlPersonalAddressBook.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/MySqlPersonalAddressBook.php @@ -21,14 +21,41 @@ class MySqlPersonalAddressBook } /** - * @param \RainLoop\Account $oAccount + * @param int $iUserID * @param int $iIdContact - * - * @return \RainLoop\Providers\PersonalAddressBook\Classes\Contact|null + * @return array */ - public function GetContactById($oAccount, $iIdContact) + private function getContactFreq($iUserID, $iIdContact) { - return null; + $aResult = array(); + + $sTypes = \implode(',', array( + PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER + )); + + $sSql = 'SELECT `value`, `frec` FROM `rainloop_pab_prop` WHERE id_user = :id_user AND `id_contact` = :id_contact AND `type` IN ('.$sTypes.')'; + $aParams = array( + ':id_user' => array($iUserID, \PDO::PARAM_INT), + ':id_contact' => array($iIdContact, \PDO::PARAM_INT) + ); + + $oStmt = $this->prepareAndExecute($sSql, $aParams); + if ($oStmt) + { + $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); + if (\is_array($aFetch)) + { + foreach ($aFetch as $aItem) + { + if ($aItem && !empty($aItem['value']) && !empty($aItem['frec'])) + { + $aResult[$aItem['value']] = (int) $aItem['frec']; + } + } + } + } + + return $aResult; } /** @@ -37,20 +64,105 @@ class MySqlPersonalAddressBook * * @return bool */ - public function CreateContact($oAccount, &$oContact) + public function SetContact($oAccount, &$oContact) { - return false; - } + $iUserID = $this->getUserId($oAccount->ParentEmailHelper()); + $bUpdate = 0 < $oContact->IdContact; - /** - * @param \RainLoop\Account $oAccount - * @param \RainLoop\Providers\PersonalAddressBook\Classes\Contact $oContact - * - * @return bool - */ - public function UpdateContact($oAccount, &$oContact) - { - return false; + $oContact->UpdateDependentValues(); + $oContact->Changed = \time(); + + try + { + $this->beginTransaction(); + + $aFreq = array(); + if ($bUpdate) + { + $aFreq = $this->getContactFreq($iUserID, $oContact->IdContact); + + $sSql = 'UPDATE `rainloop_pab_contacts` SET `display_in_list` = :display_in_list, '. + '`type` = :type, `changed` = :changed WHERE id_user = :id_user AND `id_contact` = :id_contact'; + + $this->prepareAndExecute($sSql, + array( + ':id_user' => array($iUserID, \PDO::PARAM_INT), + ':id_contact' => array($oContact->IdContact, \PDO::PARAM_INT), + ':display_in_list' => array($oContact->DisplayInList, \PDO::PARAM_STR), + ':type' => array($oContact->Type, \PDO::PARAM_INT), + ':changed' => array($oContact->Changed, \PDO::PARAM_INT), + ) + ); + + // clear previos props + $this->prepareAndExecute( + 'DELETE FROM `rainloop_pab_prop` WHERE `id_user` = :id_user AND `id_contact` = :id_contact', + array( + ':id_user' => array($iUserID, \PDO::PARAM_INT), + ':id_contact' => array($oContact->IdContact, \PDO::PARAM_INT) + ) + ); + } + else + { + $sSql = 'INSERT INTO `rainloop_pab_contacts` '. + '(`id_user`, `display_in_list`, `type`, `changed`) VALUES '. + '(:id_user, :display_in_list, :type, :changed)'; + + $this->prepareAndExecute($sSql, + array( + ':id_user' => array($iUserID, \PDO::PARAM_INT), + ':display_in_list' => array($oContact->DisplayInList, \PDO::PARAM_STR), + ':type' => array($oContact->Type, \PDO::PARAM_INT), + ':changed' => array($oContact->Changed, \PDO::PARAM_INT) + ) + ); + + $sLast = $this->lastInsertId('id_contact'); + if (\is_numeric($sLast) && 0 < (int) $sLast) + { + $oContact->IdContact = (int) $sLast; + } + } + + if (0 < $oContact->IdContact) + { + $aParams = array(); + foreach ($oContact->Properties as /* @var $oProp \RainLoop\Providers\PersonalAddressBook\Classes\Property */ $oProp) + { + $iFreq = $oProp->Frec; + if ($oProp->IsEmail() && isset($aFreq[$oProp->Value])) + { + $iFreq = $aFreq[$oProp->Value]; + } + + $aParams[] = array( + ':id_contact' => array($oContact->IdContact, \PDO::PARAM_INT), + ':id_user' => array($iUserID, \PDO::PARAM_INT), + ':type' => array($oProp->Type, \PDO::PARAM_INT), + ':type_custom' => array($oProp->TypeCustom, \PDO::PARAM_STR), + ':value' => array($oProp->Value, \PDO::PARAM_STR), + ':value_custom' => array($oProp->ValueClear, \PDO::PARAM_STR), + ':frec' => array($iFreq, \PDO::PARAM_INT), + ); + } + + $sSql = 'INSERT INTO `rainloop_pab_prop` '. + '(`id_contact`, `id_user`, `type`, `type_custom`, `value`, `value_custom`, `frec`) VALUES '. + '(:id_contact, :id_user, :type, :type_custom, :value, :value_custom, :frec)'; + + $this->prepareAndExecute($sSql, $aParams, true); + } + } + catch (\Exception $oException) + { + $this->rollBack(); + throw $oException; + } + + $this->commit(); + + return 0 < $oContact->IdContact; } /** @@ -139,7 +251,6 @@ class MySqlPersonalAddressBook $oContact = new \RainLoop\Providers\PersonalAddressBook\Classes\Contact(); $oContact->IdContact = $iIdContact; - $oContact->IdUser = $iUserID; $oContact->DisplayInList = isset($aItem['display_in_list']) ? (string) $aItem['display_in_list'] : ''; $oContact->Type = isset($aItem['type']) ? (int) $aItem['type'] : \RainLoop\Providers\PersonalAddressBook\Enumerations\ContactType::DEFAULT_; @@ -175,10 +286,6 @@ class MySqlPersonalAddressBook if (0 < $iId && isset($aContacts[$iIdContact])) { $oProperty = new \RainLoop\Providers\PersonalAddressBook\Classes\Property(); - - $oProperty->IdProperty = (int) $aItem['id_prop']; - $oProperty->IdContact = $iIdContact; - $oProperty->IdUser = $iUserID; $oProperty->Type = (int) $aItem['type']; $oProperty->TypeCustom = isset($aItem['type_custom']) ? (string) $aItem['type_custom'] : ''; $oProperty->Value = (string) $aItem['value']; @@ -234,8 +341,9 @@ class MySqlPersonalAddressBook ':search' => array($this->specialConvertSearchValue($sSearch, '='), \PDO::PARAM_STR) ); - $sSql .= ' ORDER BY `frec` ASC LIMIT :limit'; + $sSql .= ' ORDER BY `frec` DESC LIMIT :limit'; + $aResult = array(); $oStmt = $this->prepareAndExecute($sSql, $aParams); if ($oStmt) { @@ -249,6 +357,7 @@ class MySqlPersonalAddressBook if (0 < $iIdContact) { $aIdContacts[] = $iIdContact; + $aResult[$iIdContact] = array('', ''); } } } @@ -259,7 +368,7 @@ class MySqlPersonalAddressBook { $oStmt->closeCursor(); - $sTypes = implode(',', array( + $sTypes = \implode(',', array( PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER, PropertyType::FULLNAME )); @@ -273,7 +382,6 @@ class MySqlPersonalAddressBook if ($oStmt) { $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); - $aResult = array(); if (\is_array($aFetch) && 0 < \count($aFetch)) { foreach ($aFetch as $aItem) @@ -281,19 +389,17 @@ class MySqlPersonalAddressBook if ($aItem && isset($aItem['id_contact'], $aItem['type'], $aItem['value'])) { $iId = $aItem['id_contact']; - if (!isset($aResult[$iId])) + if (isset($aResult[$iId])) { - $aResult[$iId] = array('', ''); - } - - if ('' === $aResult[$iId][0] && \in_array((int) $aItem['type'], - array(PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER))) - { - $aResult[$iId][0] = $aItem['value']; - } - else if ('' === $aResult[$iId][1] && \in_array((int) $aItem['type'], array(PropertyType::FULLNAME))) - { - $aResult[$iId][1] = $aItem['value']; + if ('' === $aResult[$iId][0] && \in_array((int) $aItem['type'], + array(PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER))) + { + $aResult[$iId][0] = $aItem['value']; + } + else if ('' === $aResult[$iId][1] && \in_array((int) $aItem['type'], array(PropertyType::FULLNAME))) + { + $aResult[$iId][1] = $aItem['value']; + } } } } @@ -324,31 +430,76 @@ class MySqlPersonalAddressBook $iUserID = $this->getUserId($oAccount->ParentEmailHelper()); $self = $this; - $aEmails = \array_filter($aEmails, function (&$mItem) use ($self) { - $mItem = \strtolower(\trim($mItem)); - if (0 < \strlen($mItem)) - { - $mItem = $self->quoteValue($mItem); - return true; - } - return false; + $aEmails = \array_map(function ($mItem) { + return \strtolower(\trim($mItem)); + }, $aEmails); + + $aEmails = \array_filter($aEmails, function ($mItem) { + return 0 < \strlen($mItem); }); if (0 === \count($aEmails)) { throw new \InvalidArgumentException('Empty Emails argument'); } - - $sSql = 'UPDATE `rainloop_pab_prop` SET `frec` = `frec` + 1 WHERE id_user = :id_user AND `type` IN ('. - \implode(',', array(PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER)); - if (1 === \count($aEmails)) + $sTypes = \implode(',', array( + PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER + )); + + $sSql = 'SELECT `value` FROM `rainloop_pab_prop` WHERE id_user = :id_user AND `type` IN ('.$sTypes.')'; + $oStmt = $this->prepareAndExecute($sSql, array( + ':id_user' => array($iUserID, \PDO::PARAM_INT) + )); + + $aExists = array(); + if ($oStmt) { - $sSql .= ') AND `value` = '.$aEmails[0]; + $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); + if (\is_array($aFetch) && 0 < \count($aFetch)) + { + foreach ($aFetch as $aItem) + { + if ($aItem && !empty($aItem['value'])) + { + $aExists[] = \strtolower(\trim($aItem['value'])); + } + } + } + } + + $aEmailsToCreate = \array_diff($aEmails, $aExists); + if (0 < \count($aEmailsToCreate)) + { + $oContact = new \RainLoop\Providers\PersonalAddressBook\Classes\Contact(); + foreach ($aEmailsToCreate as $sEmailToCreate) + { + $oContact->Type = \RainLoop\Providers\PersonalAddressBook\Enumerations\ContactType::AUTO; + + $oProp = new \RainLoop\Providers\PersonalAddressBook\Classes\Property(); + $oProp->Type = \RainLoop\Providers\PersonalAddressBook\Enumerations\PropertyType::EMAIl_PERSONAL; + $oProp->Value = $sEmailToCreate; + + $oContact->Properties[] = $oProp; + + $this->SetContact($oAccount, $oContact); + $oContact->Clear(); + } + } + + $sSql = 'UPDATE `rainloop_pab_prop` SET `frec` = `frec` + 1 WHERE id_user = :id_user AND `type` IN ('.$sTypes; + + $aEmailsQuoted = \array_map(function ($mItem) use ($self) { + return $self->quoteValue($mItem); + }, $aEmails); + + if (1 === \count($aEmailsQuoted)) + { + $sSql .= ') AND `value` = '.$aEmailsQuoted[0]; } else { - $sSql .= ') AND `value` IN ('.\implode(',', $aEmails).')'; + $sSql .= ') AND `value` IN ('.\implode(',', $aEmailsQuoted).')'; } return !!$this->prepareAndExecute($sSql, array( diff --git a/rainloop/v/0.0.0/static/js/app.js b/rainloop/v/0.0.0/static/js/app.js index f10ad378e..256e86727 100644 --- a/rainloop/v/0.0.0/static/js/app.js +++ b/rainloop/v/0.0.0/static/js/app.js @@ -8060,7 +8060,7 @@ PopupsComposeViewModel.prototype.sendMessageResponse = function (sResult, oData) else { this.sendError(true); - window.alert(Utils.getNotification(oData.ErrorCode ? oData.ErrorCode : Enums.Notification.CantSendMessage)); + window.alert(Utils.getNotification(oData && oData.ErrorCode ? oData.ErrorCode : Enums.Notification.CantSendMessage)); } } }; diff --git a/rainloop/v/0.0.0/static/js/app.min.js b/rainloop/v/0.0.0/static/js/app.min.js index b0b8a8fae..9d41b9f57 100644 --- a/rainloop/v/0.0.0/static/js/app.min.js +++ b/rainloop/v/0.0.0/static/js/app.min.js @@ -3,6 +3,6 @@ }),this.multyForwardCommand=nb.createCommand(this,function(){sb.showScreenPopup(D,[lb.ComposeType.ForwardAsAttachment,zb.data().messageListCheckedOrSelected()])},this.canBeMoved),this.deleteWithoutMoveCommand=nb.createCommand(this,function(){this.deleteSelectedMessageFromCurrentFolder(lb.FolderType.Trash,!1)},this.canBeMoved),this.deleteCommand=nb.createCommand(this,function(){this.deleteSelectedMessageFromCurrentFolder(lb.FolderType.Trash,!0)},this.canBeMoved),this.spamCommand=nb.createCommand(this,function(){this.deleteSelectedMessageFromCurrentFolder(lb.FolderType.Spam,!0)},this.canBeMoved),this.moveCommand=nb.createCommand(this,nb.emptyFunction,this.canBeMoved),this.setCommand=nb.createCommand(this,nb.emptyFunction,this.hasCheckedLines),this.checkCommand=nb.createCommand(this,nb.emptyFunction,this.hasCheckedLines),this.reloadCommand=nb.createCommand(this,function(){zb.data().messageListCompleteLoadingThrottle()||zb.reloadMessageList(!1,!0)}),this.quotaTooltip=h.bind(this.quotaTooltip,this),this.selector=new k(this.messageList,this.currentMessage,".messageListItem .actionHandle",".messageListItem.selected",".messageListItem .checkboxMessage"),this.selector.on("onItemSelect",h.bind(function(b){b?(a.message(a.staticMessageList.populateByMessageListItem(b)),this.populateMessageBody(a.message())):a.message(null)},this)),this.selector.on("onItemGetUid",function(a){return a?a.generateUid():""}),this.selector.on("onDelete",h.bind(function(){0'),e.after(f),e.remove()),f&&f[0]&&f.attr("data-href",g).attr("data-theme",a[0]).text(a[1]),d.themeTrigger(lb.SaveSettingsStep.TrueResult))}).always(function(){d.iTimer=a.setTimeout(function(){d.themeTrigger(lb.SaveSettingsStep.Idle)},1e3),d.oLastAjax=null})),zb.remote().saveSettings(null,{Theme:c})},this)}function $(){nb.initDataConstructorBySettings(this)}function _(){$.call(this);var a=function(a){return function(){var b=zb.cache().getFolderFromCacheList(a());b&&b.type(lb.FolderType.User)}},d=function(a){return function(b){var c=zb.cache().getFolderFromCacheList(b);c&&c.type(a)}};this.devEmail="",this.devLogin="",this.devPassword="",this.accountEmail=c.observable(""),this.accountIncLogin=c.observable(""),this.accountOutLogin=c.observable(""),this.projectHash=c.observable(""),this.threading=c.observable(!1),this.lastFoldersHash="",this.remoteSuggestions=!1,this.sentFolder=c.observable(""),this.draftFolder=c.observable(""),this.spamFolder=c.observable(""),this.trashFolder=c.observable(""),this.sentFolder.subscribe(a(this.sentFolder),this,"beforeChange"),this.draftFolder.subscribe(a(this.draftFolder),this,"beforeChange"),this.spamFolder.subscribe(a(this.spamFolder),this,"beforeChange"),this.trashFolder.subscribe(a(this.trashFolder),this,"beforeChange"),this.sentFolder.subscribe(d(lb.FolderType.SentItems),this),this.draftFolder.subscribe(d(lb.FolderType.Draft),this),this.spamFolder.subscribe(d(lb.FolderType.Spam),this),this.trashFolder.subscribe(d(lb.FolderType.Trash),this),this.draftFolderNotEnabled=c.computed(function(){return""===this.draftFolder()||kb.Values.UnuseOptionValue===this.draftFolder()},this),this.displayName=c.observable(""),this.signature=c.observable(""),this.replyTo=c.observable(""),this.accounts=c.observableArray([]),this.accountsLoading=c.observable(!1).extend({throttle:100}),this.identities=c.observableArray([]),this.identitiesLoading=c.observable(!1).extend({throttle:100}),this.namespace="",this.folderList=c.observableArray([]),this.foldersListError=c.observable(""),this.foldersLoading=c.observable(!1),this.foldersCreating=c.observable(!1),this.foldersDeleting=c.observable(!1),this.foldersRenaming=c.observable(!1),this.currentFolder=c.observable(null).extend({toggleSubscribe:[null,function(a){a&&a.selected(!1)},function(a){a&&a.selected(!0)}]}),this.currentFolderFullNameRaw=c.computed(function(){return this.currentFolder()?this.currentFolder().fullNameRaw:""},this),this.currentFolderFullName=c.computed(function(){return this.currentFolder()?this.currentFolder().fullName:""},this),this.currentFolderFullNameHash=c.computed(function(){return this.currentFolder()?this.currentFolder().fullNameHash:""},this),this.currentFolderName=c.computed(function(){return this.currentFolder()?this.currentFolder().name():""},this),this.folderListSystemNames=c.computed(function(){var a=["INBOX"],b=this.folderList(),c=this.sentFolder(),d=this.draftFolder(),e=this.spamFolder(),f=this.trashFolder();return nb.isArray(b)&&00?Math.ceil(b/a*100):0},this),this.useKeyboardShortcuts=c.observable(!0),this.googleActions=c.observable(!1),this.googleLoggined=c.observable(!1),this.googleUserName=c.observable(""),this.facebookActions=c.observable(!1),this.facebookLoggined=c.observable(!1),this.facebookUserName=c.observable(""),this.twitterActions=c.observable(!1),this.twitterLoggined=c.observable(!1),this.twitterUserName=c.observable(""),this.customThemeType=c.observable(lb.CustomThemeType.Light),this.purgeMessageBodyCacheThrottle=h.throttle(this.purgeMessageBodyCache,3e4)}function ab(){this.oRequests={}}function bb(){ab.call(this),this.oRequests={}}function cb(){this.oEmailsPicsHashes={},this.oServices={}}function db(){cb.call(this),this.oFoldersCache={},this.oFoldersNamesCache={},this.oFolderHashCache={},this.oFolderUidNextCache={},this.oMessageListHashCache={},this.oMessageFlagsCache={},this.oNewMessage={},this.oRequestedMessage={}}function eb(a){q.call(this,"settings",a),this.menu=c.observableArray([]),this.oCurrentSubScreen=null,this.oViewModelPlace=null}function fb(){q.call(this,"login",[J])}function gb(){q.call(this,"mailbox",[L,N,O,P]),this.oLastRoute={}}function hb(){eb.call(this,[M,Q,R]),nb.initOnStartOrLangChange(function(){this.sSettingsTitle=nb.i18n("TITLES/SETTINGS")},this,function(){zb.setTitle(this.sSettingsTitle)})}function ib(){o.call(this),this.oSettings=null,this.oPlugins=null,this.oLink=null,this.oLocal=null,this.isLocalAutocomplete=!0,this.popupVisibility=c.observable(!1),this.iframe=b('