From f3823333d7c3bc6bcf4005b62e3716e1390786e2 Mon Sep 17 00:00:00 2001 From: RainLoop Team Date: Mon, 5 May 2014 23:10:37 +0400 Subject: [PATCH] Fixed contacts search (suggestions) --- package.json | 2 +- .../RainLoop/Providers/AddressBook.php | 2 +- .../Providers/AddressBook/PdoAddressBook.php | 31 +- .../Providers/PersonalAddressBook.php | 341 ---- .../PersonalAddressBook/Classes/Contact.php | 580 ------- .../PersonalAddressBook/Classes/Property.php | 114 -- .../Enumerations/PropertyType.php | 46 - .../Enumerations/ScopeType.php | 9 - .../PdoPersonalAddressBook.php | 1381 ----------------- .../PersonalAddressBookInterface.php | 65 - 10 files changed, 29 insertions(+), 2542 deletions(-) delete mode 100644 rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook.php delete mode 100644 rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Classes/Contact.php delete mode 100644 rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Classes/Property.php delete mode 100644 rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Enumerations/PropertyType.php delete mode 100644 rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Enumerations/ScopeType.php delete mode 100644 rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/PdoPersonalAddressBook.php delete mode 100644 rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/PersonalAddressBookInterface.php diff --git a/package.json b/package.json index 7779893ef..ea8d69ffd 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "RainLoop", "title": "RainLoop Webmail", "version": "1.6.6", - "release": "916", + "release": "919", "description": "Simple, modern & fast web-based email client", "homepage": "http://rainloop.net", "main": "Gruntfile.js", diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook.php index 657133293..42ac2c3a3 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook.php @@ -58,7 +58,7 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider */ public function IsSharingAllowed() { - return $this->oDriver instanceof \RainLoop\Providers\PersonalAddressBook\AddressBookInterface && + return $this->oDriver instanceof \RainLoop\Providers\AddressBook\AddressBookInterface && $this->oDriver->IsSharingAllowed(); } diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php index 9d041ac7e..9376bfecb 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php @@ -640,10 +640,15 @@ class PdoAddressBook // TODO fix this $sCustomSearch = ''; } + + $sSearchTypes = implode(',', array( + PropertyType::EMAIl, PropertyType::FIRST_NAME, PropertyType::LAST_NAME, PropertyType::NICK_NAME, + PropertyType::PHONE, PropertyType::WEB_PAGE + )); $sSql = 'SELECT id_user, id_prop, id_contact FROM rainloop_ab_properties '. - 'WHERE (id_user = :id_user) AND (prop_value LIKE :search ESCAPE \'=\''. - (0 < \strlen($sCustomSearch) ? ' OR prop_type = '.PropertyType::PHONE.' AND prop_value_custom <> \'\' AND prop_value_custom LIKE :search_custom_phone)' : ''). + 'WHERE (id_user = :id_user) AND prop_type IN ('.$sSearchTypes.') AND (prop_value LIKE :search ESCAPE \'=\''. + (0 < \strlen($sCustomSearch) ? ' OR (prop_type = '.PropertyType::PHONE.' AND prop_value_custom <> \'\' AND prop_value_custom LIKE :search_custom_phone)' : ''). ') GROUP BY id_contact, id_prop'; $aParams = array( @@ -995,7 +1000,6 @@ class PdoAddressBook if (\is_array($aFetch) && 0 < \count($aFetch)) { $aNames = array(); - $aNicks = array(); $aEmails = array(); foreach ($aFetch as $aItem) @@ -1017,7 +1021,7 @@ class PdoAddressBook $aNames[$iIdContact] = array('', ''); } - $aNames[$iIdContact][PropertyType::LAST_NAME === $iType ? 0 : 1] = $aItem['prop_value']; + $aNames[$iIdContact][PropertyType::FIRST_NAME === $iType ? 0 : 1] = $aItem['prop_value']; } else if ((isset($aIdProps[$iIdProp]) || isset($aContactAllAccess[$iIdContact])) && PropertyType::EMAIl === $iType) @@ -1055,6 +1059,25 @@ class PdoAddressBook { $aResult[] = array($sEmail, $sNickItem); } + + if (!$bName && !$bNick) + { + $aResult[] = array($sEmail, ''); + } + } + } + else + { + $aNameItem = isset($aNames[$iId]) && \is_array($aNames[$iId]) ? $aNames[$iId] : array('', ''); + $sNameItem = \trim($aNameItem[0].' '.$aNameItem[1]); + if (0 === \strlen($sNameItem)) + { + $sNameItem = isset($aNicks[$iId]) ? $aNicks[$iId] : ''; + } + + foreach ($aItems as $sEmail) + { + $aResult[] = array($sEmail, $sNameItem); } } } diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook.php deleted file mode 100644 index b3a6b61eb..000000000 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook.php +++ /dev/null @@ -1,341 +0,0 @@ -oDriver = null; - if ($oDriver instanceof \RainLoop\Providers\PersonalAddressBook\PersonalAddressBookInterface) - { - $this->oDriver = $oDriver; - } - } - - /** - * @return string - */ - public function Test() - { - \sleep(1); - return $this->oDriver instanceof \RainLoop\Providers\PersonalAddressBook\PersonalAddressBookInterface ? - $this->oDriver->Test() : 'Personal address book driver is not allowed'; - } - - /** - * @return bool - */ - public function IsActive() - { - return $this->oDriver instanceof \RainLoop\Providers\PersonalAddressBook\PersonalAddressBookInterface && - $this->oDriver->IsSupported(); - } - - /** - * @return bool - */ - public function IsSharingAllowed() - { - return $this->oDriver instanceof \RainLoop\Providers\PersonalAddressBook\PersonalAddressBookInterface && - $this->oDriver->IsSharingAllowed(); - } - - /** - * @return bool - */ - public function IsSupported() - { - return $this->oDriver instanceof \RainLoop\Providers\PersonalAddressBook\PersonalAddressBookInterface && - $this->oDriver->IsSupported(); - } - - /** - * @param string $sEmail - * - * @return string - */ - public function GetUserUidByEmail($sEmail) - { - return $this->oDriver instanceof \RainLoop\Providers\PersonalAddressBook\PersonalAddressBookInterface ? - $this->oDriver->GetUserUidByEmail($sEmail) : ''; - } - - /** - * @param string $sEmail - * - * @return int - */ - public function GetCtagByEmail($sEmail) - { - return $this->oDriver instanceof \RainLoop\Providers\PersonalAddressBook\PersonalAddressBookInterface ? - $this->oDriver->GetCtagByEmail($sEmail) : 0; - } - - /** - * @param string $sEmail - * @param bool $bCreate = false - * - * @return string - */ - public function GetUserHashByEmail($sEmail, $bCreate = false) - { - return $this->oDriver instanceof \RainLoop\Providers\PersonalAddressBook\PersonalAddressBookInterface ? - $this->oDriver->GetUserHashByEmail($sEmail, $bCreate) : ''; - } - - /** - * @param bool $bConsiderShare = true - */ - public function ConsiderShare($bConsiderShare = true) - { - if ($this->oDriver) - { - $this->oDriver->ConsiderShare($bConsiderShare); - } - - return $this; - } - - /** - * @param string $sEmail - * @param \RainLoop\Providers\PersonalAddressBook\Classes\Contact $oContact - * - * @return bool - */ - public function ContactSave($sEmail, &$oContact) - { - return $this->IsActive() ? $this->oDriver->ContactSave($sEmail, $oContact) : false; - } - - /** - * @param string $sEmail - * @param array $aContactIds - * - * @return bool - */ - public function DeleteContacts($sEmail, $aContactIds) - { - return $this->IsActive() ? $this->oDriver->DeleteContacts($sEmail, $aContactIds) : false; - } - - /** - * @param string $sEmail - * @param int $iOffset = 0 - * @param type $iLimit = 20 - * @param string $sSearch = '' - * @param int $iResultCount = 0 - * - * @return array - */ - public function GetContacts($sEmail, $iOffset = 0, $iLimit = 20, $sSearch = '', &$iResultCount = 0) - { - return $this->IsActive() ? $this->oDriver->GetContacts($sEmail, - $iOffset, $iLimit, $sSearch, $iResultCount) : array(); - } - - /** - * @param string $sEmail - * @param string $sID - * @param bool $bIsStrID = false - * - * @return \RainLoop\Providers\PersonalAddressBook\Classes\Contact|null - */ - public function GetContactByID($sEmail, $mID, $bIsStrID = false) - { - return $this->IsActive() ? $this->oDriver->GetContactByID($sEmail, $mID, $bIsStrID) : null; - } - - /** - * @param string $sEmail - * @param string $sSearch - * @param int $iLimit = 20 - * - * @return array - * - * @throws \InvalidArgumentException - */ - public function GetSuggestions($sEmail, $sSearch, $iLimit = 20) - { - return $this->IsActive() ? $this->oDriver->GetSuggestions($sEmail, $sSearch, $iLimit) : array(); - } - - /** - * @param string $sEmail - * @param array $aEmails - * @param bool $bCreateAuto = true - * - * @return bool - */ - public function IncFrec($sEmail, $aEmails, $bCreateAuto = true) - { - return $this->IsActive() ? $this->oDriver->IncFrec($sEmail, $aEmails, $bCreateAuto) : false; - } - - /** - * @param string $sCsvName - * - * @return int - */ - private function csvNameToTypeConvertor($sCsvName) - { - static $aMap = null; - if (null === $aMap) - { - $aMap = array( - 'Title' => PropertyType::FULLNAME, - 'First Name' => PropertyType::FIRST_NAME, - 'Middle Name' => PropertyType::MIDDLE_NAME, - 'Last Name' => PropertyType::LAST_NAME, - 'Suffix' => PropertyType::NAME_SUFFIX, - 'Business Fax' => PropertyType::FAX_BUSSINES, - 'Business Phone' => PropertyType::PHONE_BUSSINES, - 'Business Phone 2' => PropertyType::PHONE_BUSSINES, - 'Company Main Phone' => PropertyType::PHONE_BUSSINES, - 'Home Fax' => PropertyType::FAX_PERSONAL, - 'Home Phone' => PropertyType::PHONE_PERSONAL, - 'Home Phone 2' => PropertyType::PHONE_PERSONAL, - 'Mobile Phone' => PropertyType::MOBILE_PERSONAL, - 'Other Fax' => PropertyType::FAX_OTHER, - 'Other Phone' => PropertyType::PHONE_OTHER, -// 'Primary Phone' => PropertyType::PHONE_PERSONAL, - 'E-mail Address' => PropertyType::EMAIl_PERSONAL, - 'E-mail 2 Address' => PropertyType::EMAIl_OTHER, - 'E-mail 3 Address' => PropertyType::EMAIl_OTHER, - 'E-mail Display Name' => PropertyType::FULLNAME, - 'E-mail 2 Display Name' => PropertyType::FULLNAME, - 'E-mail 3 Display Name' => PropertyType::FULLNAME, - 'Notes' => PropertyType::NOTE, - 'Web Page' => PropertyType::WEB_PAGE_PERSONAL, - 'WebPage' => PropertyType::WEB_PAGE_PERSONAL, - ); - - $aMap = array_change_key_case($aMap, CASE_LOWER); - } - - $sCsvNameLower = \MailSo\Base\Utils::IsAscii($sCsvName) ? \strtolower($sCsvName) : ''; - return isset($aMap[$sCsvNameLower]) ? $aMap[$sCsvNameLower] : PropertyType::UNKNOWN; - } - - /** - * @param string $sEmail - * @param array $aCsvData - * - * @return int - */ - public function ImportCsvArray($sEmail, $aCsvData) - { - $iCount = 0; - if ($this->IsActive() && \is_array($aCsvData) && 0 < \count($aCsvData)) - { - $oContact = new \RainLoop\Providers\PersonalAddressBook\Classes\Contact(); - foreach ($aCsvData as $aItem) - { - foreach ($aItem as $sItemName => $sItemValue) - { - $sItemName = \trim($sItemName); - $sItemValue = \trim($sItemValue); - - if (!empty($sItemName) && !empty($sItemValue)) - { - $iType = $this->csvNameToTypeConvertor($sItemName); - if (PropertyType::UNKNOWN !== $iType) - { - $oProp = new \RainLoop\Providers\PersonalAddressBook\Classes\Property(); - $oProp->Type = $iType; - $oProp->Value = $sItemValue; - - $oContact->Properties[] = $oProp; - } - } - } - - if ($oContact && 0 < \count($oContact->Properties)) - { - if ($this->ContactSave($sEmail, $oContact)) - { - $iCount++; - } - } - - $oContact->Clear(); - } - - unset($oContact); - } - - return $iCount; - } - - /** - * @param string $sEmail - * @param string $sVcfData - * - * @return int - */ - public function ImportVcfFile($sEmail, $sVcfData) - { - $iCount = 0; - if ($this->IsActive() && \is_string($sVcfData)) - { - $sVcfData = \trim($sVcfData); - if ("\xef\xbb\xbf" === \substr($sVcfData, 0, 3)) - { - $sVcfData = \substr($sVcfData, 3); - } - - $oVCardSplitter = null; - try - { - $oVCardSplitter = new \Sabre\VObject\Splitter\VCard($sVcfData); - } - catch (\Exception $oExc) - { - $this->Logger()->WriteException($oExc); - } - - if ($oVCardSplitter) - { - $oContact = new \RainLoop\Providers\PersonalAddressBook\Classes\Contact(); - - $oVCard = null; - - while ($oVCard = $oVCardSplitter->getNext()) - { - if ($oVCard instanceof \Sabre\VObject\Component\VCard) - { - if (empty($oVCard->UID)) - { - $oVCard->UID = \Sabre\DAV\UUIDUtil::getUUID(); - } - - $oContact->ParseVCard($oVCard, $oVCard->serialize()); - if (0 < \count($oContact->Properties)) - { - if ($this->ContactSave($sEmail, $oContact)) - { - $iCount++; - } - } - - $oContact->Clear(); - } - } - } - } - - return $iCount; - } -} 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 deleted file mode 100644 index 44fffacf4..000000000 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Classes/Contact.php +++ /dev/null @@ -1,580 +0,0 @@ -Clear(); - } - - public function Clear() - { - $this->IdContact = ''; - $this->IdContactStr = ''; - $this->IdUser = 0; - $this->Display = ''; - $this->ScopeType = \RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_; - $this->Changed = \time(); - $this->IdPropertyFromSearch = 0; - $this->Properties = array(); - $this->ReadOnly = false; - - $this->CardDavData = ''; - $this->CardDavHash = ''; - $this->CardDavSize = 0; - } - - public function UpdateDependentValues($bReparseVcard = true) - { - $sLastName = ''; - $sFirstName = ''; - $sEmail = ''; - $sOther = ''; - - $oFullNameProperty = null; - - foreach ($this->Properties as /* @var $oProperty \RainLoop\Providers\PersonalAddressBook\Classes\Property */ &$oProperty) - { - if ($oProperty) - { - $oProperty->ScopeType = $this->ScopeType; - $oProperty->UpdateDependentValues(); - - if (!$oFullNameProperty && PropertyType::FULLNAME === $oProperty->Type) - { - $oFullNameProperty =& $oProperty; - } - - if (0 < \strlen($oProperty->Value)) - { - if ('' === $sEmail && $oProperty->IsEmail()) - { - $sEmail = $oProperty->Value; - } - else if ('' === $sLastName && PropertyType::LAST_NAME === $oProperty->Type) - { - $sLastName = $oProperty->Value; - } - else if ('' === $sFirstName && PropertyType::FIRST_NAME === $oProperty->Type) - { - $sFirstName = $oProperty->Value; - } - else if (\in_array($oProperty->Type, array(PropertyType::FULLNAME, - PropertyType::PHONE_PERSONAL, PropertyType::PHONE_BUSSINES, PropertyType::PHONE_OTHER, - PropertyType::MOBILE_PERSONAL, PropertyType::MOBILE_BUSSINES, PropertyType::MOBILE_OTHER - ))) - { - $sOther = $oProperty->Value; - } - } - } - } - - if (empty($this->IdContactStr)) - { - $this->IdContactStr = \Sabre\DAV\UUIDUtil::getUUID(); - } - - $sDisplay = ''; - if (0 < \strlen($sLastName) || 0 < \strlen($sFirstName)) - { - $sDisplay = \trim($sFirstName.' '.$sLastName); - } - - if ('' === $sDisplay && 0 < \strlen($sEmail)) - { - $sDisplay = \trim($sEmail); - } - - if ('' === $sDisplay) - { - $sDisplay = $sOther; - } - - $this->Display = \trim($sDisplay); - - $bNewFull = false; - if (!$oFullNameProperty) - { - $oFullNameProperty = new \RainLoop\Providers\PersonalAddressBook\Classes\Property(PropertyType::FULLNAME, $this->Display); - $bNewFull = true; - } - - $oFullNameProperty->Value = $this->Display; - $oFullNameProperty->UpdateDependentValues(); - - if ($bNewFull) - { - $this->Properties[] = $oFullNameProperty; - } - - if ($bReparseVcard || '' === $this->CardDavData) - { - $oVCard = $this->ToVCardObject($this->CardDavData); - $this->CardDavData = $oVCard ? $oVCard->serialize() : $this->CardDavData; - unset($oVCard); - } - - if (!empty($this->CardDavData)) - { - $this->CardDavHash = \md5($this->CardDavData); - $this->CardDavSize = \strlen($this->CardDavData); - } - else - { - $this->CardDavHash = ''; - $this->CardDavSize = 0; - } - } - - /** - * @return array - */ - public function GetEmails() - { - $aResult = array(); - foreach ($this->Properties as /* @var $oProperty \RainLoop\Providers\PersonalAddressBook\Classes\Property */ &$oProperty) - { - if ($oProperty && $oProperty->IsEmail()) - { - $aResult[] = $oProperty->Value; - } - } - - return \array_unique($aResult); - } - - /** - * @param \Sabre\VObject\Document $oVCard - * @param string $sCardData - */ - public function ParseVCard($oVCard, $sVCard) - { - $bNew = empty($this->IdContact); - - if (!$bNew) - { - $this->Properties = array(); - } - - $aProperties = array(); - if ($oVCard) - { - $bOldVersion = empty($oVCard->VERSION) ? false : - \in_array((string) $oVCard->VERSION, array('2.1', '2.0', '1.0')); - - $this->IdContactStr = $oVCard->UID ? (string) $oVCard->UID : \Sabre\DAV\UUIDUtil::getUUID(); - - if (isset($oVCard->FN) && '' !== \trim($oVCard->FN)) - { - $sValue = \trim($oVCard->FN); - if ($bOldVersion && !isset($oVCard->FN->parameters['CHARSET'])) - { - if (0 < \strlen($sValue)) - { - $sEncValue = @\utf8_encode($sValue); - if (0 === \strlen($sEncValue)) - { - $sEncValue = $sValue; - } - - $sValue = $sEncValue; - } - } - - $sValue = \MailSo\Base\Utils::Utf8Clear($sValue); - $aProperties[] = new Property(PropertyType::FULLNAME, $sValue); - } - - if (isset($oVCard->NICKNAME) && '' !== \trim($oVCard->NICKNAME)) - { - $sValue = \trim($oVCard->NICKNAME); - if ($bOldVersion && !isset($oVCard->NICKNAME->parameters['CHARSET'])) - { - if (0 < \strlen($sValue)) - { - $sEncValue = @\utf8_encode($sValue); - if (0 === \strlen($sEncValue)) - { - $sEncValue = $sValue; - } - - $sValue = $sEncValue; - } - } - - $sValue = \MailSo\Base\Utils::Utf8Clear($sValue); - $aProperties[] = new Property(PropertyType::NICK_NAME, $sValue); - } - -// if (isset($oVCard->NOTE) && '' !== \trim($oVCard->NOTE)) -// { -// $sValue = \trim($oVCard->NOTE); -// if ($bOldVersion) -// { -// if (0 < \strlen($sValue)) -// { -// $sEncValue = @\utf8_encode($sValue); -// if (0 === \strlen($sEncValue)) -// { -// $sEncValue = $sValue; -// } -// -// $sValue = $sEncValue; -// } -// } -// -// $sValue = \MailSo\Base\Utils::Utf8Clear($sValue); -// $aProperties[] = new Property(PropertyType::NOTE, $sValue); -// } - - if (isset($oVCard->N)) - { - $aNames = $oVCard->N->getParts(); - foreach ($aNames as $iIndex => $sValue) - { - $sValue = \trim($sValue); - if ($bOldVersion && !isset($oVCard->N->parameters['CHARSET'])) - { - if (0 < \strlen($sValue)) - { - $sEncValue = @\utf8_encode($sValue); - if (0 === \strlen($sEncValue)) - { - $sEncValue = $sValue; - } - - $sValue = $sEncValue; - } - } - - $sValue = \MailSo\Base\Utils::Utf8Clear($sValue); - switch ($iIndex) { - case 0: - $aProperties[] = new Property(PropertyType::LAST_NAME, $sValue); - break; - case 1: - $aProperties[] = new Property(PropertyType::FIRST_NAME, $sValue); - break; - case 2: - $aProperties[] = new Property(PropertyType::MIDDLE_NAME, $sValue); - break; - case 3: - $aProperties[] = new Property(PropertyType::NAME_PREFIX, $sValue); - break; - case 4: - $aProperties[] = new Property(PropertyType::NAME_SUFFIX, $sValue); - break; - } - } - } - - if (isset($oVCard->EMAIL)) - { - $bPref = false; - foreach($oVCard->EMAIL as $oEmail) - { - $oTypes = $oEmail ? $oEmail['TYPE'] : null; - $sEmail = $oEmail ? \trim($oEmail->getValue()) : ''; - - if (0 < \strlen($sEmail)) - { - if ($oTypes) - { - $oProp = new Property($oTypes->has('WORK') ? PropertyType::EMAIl_BUSSINES : PropertyType::EMAIl_PERSONAL, $sEmail); - if (!$bPref && $oTypes->has('pref')) - { - $bPref = true; - \array_unshift($aProperties, $oProp); - } - else - { - \array_push($aProperties, $oProp); - } - } - else - { - \array_unshift($aProperties, - new Property(PropertyType::EMAIl_PERSONAL, $sEmail)); - } - } - } - } - - if (isset($oVCard->URL)) - { - foreach($oVCard->URL as $oUrl) - { - $oTypes = $oUrl ? $oUrl['TYPE'] : null; - $sUrl = $oUrl ? \trim((string) $oUrl) : ''; - - if (0 < \strlen($sUrl)) - { - \array_push($aProperties, - new Property($oTypes && $oTypes->has('WORK') ? - PropertyType::WEB_PAGE_BUSSINES : PropertyType::WEB_PAGE_PERSONAL, $sUrl)); - } - } - } - - if (isset($oVCard->TEL)) - { - $bPref = false; - foreach($oVCard->TEL as $oTel) - { - $oTypes = $oTel ? $oTel['TYPE'] : null; - $sTel = $oTypes ? \trim((string) $oTel) : ''; - - if (0 < \strlen($sTel)) - { - if ($oTypes) - { - $oProp = null; - $bWork = $oTypes->has('WORK'); - - switch (true) - { - case $oTypes->has('VOICE'): - $oProp = new Property($bWork ? PropertyType::PHONE_BUSSINES : PropertyType::PHONE_PERSONAL, $sTel); - break; - case $oTypes->has('CELL'): - $oProp = new Property($bWork ? PropertyType::MOBILE_BUSSINES : PropertyType::MOBILE_PERSONAL, $sTel); - break; - case $oTypes->has('FAX'): - $oProp = new Property($bWork ? PropertyType::FAX_BUSSINES : PropertyType::FAX_PERSONAL, $sTel); - break; - case $oTypes->has('WORK'): - $oProp = new Property(PropertyType::MOBILE_BUSSINES, $sTel); - break; - default: - $oProp = new Property(PropertyType::MOBILE_PERSONAL, $sTel); - break; - } - - if ($oProp) - { - if (!$bPref && $oTypes->has('pref')) - { - $bPref = true; - \array_unshift($aProperties, $oProp); - } - else - { - \array_push($aProperties, $oProp); - } - } - } - else - { - \array_unshift($aProperties, - new Property(PropertyType::MOBILE_PERSONAL, $sTel)); - } - } - } - } - - $this->Properties = $aProperties; - - $this->CardDavData = \MailSo\Base\Utils::Utf8Clear($sVCard); - } - - $this->UpdateDependentValues(false); - } - - /** - * @return string - */ - public function ToVCardObject($sPreVCard = '') - { -// $this->UpdateDependentValues(); - - $oVCard = null; - if (0 < \strlen($sPreVCard)) - { - try - { - $oVCard = \Sabre\VObject\Reader::read($sPreVCard); - } - catch (\Exception $oExc) {}; - } - - if (!$oVCard) - { - $oVCard = new \Sabre\VObject\Component\VCard(); - } - - $oVCard->VERSION = '3.0'; - $oVCard->PRODID = '-//RainLoop//'.APP_VERSION.'//EN'; - - unset($oVCard->FN, $oVCard->EMAIL, $oVCard->TEL); - - $bPrefEmail = $bPrefPhone = false; - $sFirstName = $sLastName = $sMiddleName = $sSuffix = $sPrefix = ''; - foreach ($this->Properties as /* @var $oProperty \RainLoop\Providers\PersonalAddressBook\Classes\Property */ &$oProperty) - { - if ($oProperty) - { - switch ($oProperty->Type) - { - case PropertyType::FULLNAME: - $oVCard->FN = $oProperty->Value; - break; - case PropertyType::NICK_NAME: - $oVCard->NICKNAME = $oProperty->Value; - break; - case PropertyType::FIRST_NAME: - $sFirstName = $oProperty->Value; - break; - case PropertyType::LAST_NAME: - $sLastName = $oProperty->Value; - break; - case PropertyType::MIDDLE_NAME: - $sMiddleName = $oProperty->Value; - break; - case PropertyType::NAME_SUFFIX: - $sSuffix = $oProperty->Value; - break; - case PropertyType::NAME_PREFIX: - $sPrefix = $oProperty->Value; - break; - case PropertyType::EMAIl_PERSONAL: - case PropertyType::EMAIl_BUSSINES: - case PropertyType::EMAIl_OTHER: - $aParams = array('TYPE' => array('INTERNET')); - $aParams['TYPE'][] = PropertyType::EMAIl_BUSSINES === $oProperty->Type ? 'WORK' : 'HOME'; - - if (!$bPrefEmail) - { - $bPrefEmail = true; - $aParams['TYPE'][] = 'pref'; - } - $oVCard->add('EMAIL', $oProperty->Value, $aParams); - break; - case PropertyType::WEB_PAGE_PERSONAL: - case PropertyType::WEB_PAGE_BUSSINES: - case PropertyType::WEB_PAGE_OTHER: - $aParams = array('TYPE' => array()); - $aParams['TYPE'][] = PropertyType::WEB_PAGE_BUSSINES === $oProperty->Type ? 'WORK' : 'HOME'; - $oVCard->add('URL', $oProperty->Value, $aParams); - break; - case PropertyType::PHONE_PERSONAL: - case PropertyType::PHONE_BUSSINES: - case PropertyType::PHONE_OTHER: - case PropertyType::MOBILE_PERSONAL: - case PropertyType::MOBILE_BUSSINES: - case PropertyType::MOBILE_OTHER: - case PropertyType::FAX_PERSONAL: - case PropertyType::FAX_BUSSINES: - case PropertyType::FAX_OTHER: - $aParams = array('TYPE' => array()); - $sType = ''; - if (\in_array($oProperty->Type, array(PropertyType::PHONE_PERSONAL, PropertyType::PHONE_BUSSINES, PropertyType::PHONE_OTHER))) - { - $sType = 'VOICE'; - } - else if (\in_array($oProperty->Type, array(PropertyType::MOBILE_PERSONAL, PropertyType::MOBILE_BUSSINES, PropertyType::MOBILE_OTHER))) - { - $sType = 'CELL'; - } - else if (\in_array($oProperty->Type, array(PropertyType::FAX_PERSONAL, PropertyType::FAX_BUSSINES, PropertyType::FAX_OTHER))) - { - $sType = 'FAX'; - } - - if (!empty($sType)) - { - $aParams['TYPE'][] = $sType; - } - - $aParams['TYPE'][] = \in_array($oProperty->Type, array( - PropertyType::PHONE_BUSSINES, PropertyType::MOBILE_BUSSINES, PropertyType::FAX_BUSSINES)) ? 'WORK' : 'HOME'; - - if (!$bPrefPhone) - { - $bPrefPhone = true; - $aParams['TYPE'][] = 'pref'; - } - - $oVCard->add('TEL', $oProperty->Value, $aParams); - break; - } - } - } - - $oVCard->UID = $this->IdContactStr; - $oVCard->N = array($sLastName, $sFirstName, $sMiddleName, $sPrefix, $sSuffix); - $oVCard->REV = \gmdate('Ymd', $this->Changed).'T'.\gmdate('His', $this->Changed).'Z'; - - return $oVCard; - } - - /** - * @return string - */ - public function VCardUri() - { - return $this->IdContactStr.'.vcf'; - } -} 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 deleted file mode 100644 index b0aa97c98..000000000 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Classes/Property.php +++ /dev/null @@ -1,114 +0,0 @@ -Clear(); - - $this->Type = $iType; - $this->Value = $sValue; - } - - public function Clear() - { - $this->IdProperty = 0; - - $this->Type = PropertyType::UNKNOWN; - $this->ScopeType = \RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_; - $this->TypeCustom = ''; - - $this->Value = ''; - $this->ValueCustom = ''; - - $this->Frec = 0; - } - - /** - * @return bool - */ - public function IsEmail() - { - return \in_array($this->Type, array( - PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER - )); - } - - /** - * @return bool - */ - public function IsPhone() - { - return \in_array($this->Type, array( - PropertyType::PHONE_PERSONAL, PropertyType::PHONE_BUSSINES, PropertyType::PHONE_OTHER, - PropertyType::MOBILE_PERSONAL, PropertyType::MOBILE_BUSSINES, PropertyType::MOBILE_OTHER, - PropertyType::FAX_PERSONAL, PropertyType::FAX_BUSSINES, PropertyType::FAX_OTHER - )); - } - - public function UpdateDependentValues() - { - // trimer - $this->Value = \trim($this->Value); - $this->ValueCustom = \trim($this->ValueCustom); - $this->TypeCustom = \trim($this->TypeCustom); - - if (0 < \strlen($this->Value)) - { - // lower - if ($this->IsEmail()) - { - $this->Value = \strtolower($this->Value); - } - - // phones clear value for searching - if ($this->IsPhone()) - { - $sPhone = $this->Value; - $sPhone = \preg_replace('/^[+]+/', '', $sPhone); - $sPhone = \preg_replace('/[^\d]/', '', $sPhone); - $this->ValueCustom = $sPhone; - } - } - } -} diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Enumerations/PropertyType.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Enumerations/PropertyType.php deleted file mode 100644 index 1428e6ff7..000000000 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/Enumerations/PropertyType.php +++ /dev/null @@ -1,46 +0,0 @@ -sDsn = $sDsn; - $this->sUser = $sUser; - $this->sPassword = $sPassword; - $this->sDsnType = $sDsnType; - - $this->bConsiderShare = true; - - $this->bExplain = false; - } - - /** - * @param bool $bConsiderShare - * - * @return \RainLoop\Providers\PersonalAddressBook\PdoPersonalAddressBook - */ - public function ConsiderShare($bConsiderShare = true) - { - $this->bConsiderShare = !!$bConsiderShare; - - return $this; - } - - /** - * @return bool - */ - public function IsSupported() - { - $aDrivers = \class_exists('PDO') ? \PDO::getAvailableDrivers() : array(); - return \is_array($aDrivers) ? \in_array($this->sDsnType, $aDrivers) : false; - } - - /** - * @return bool - */ - public function IsConsiderShare() - { - return $this->bConsiderShare; - } - - /** - * @return bool - */ - public function IsSharingAllowed() - { - return $this->IsConsiderShare() && $this->IsSupported(); - } - - /** - * @param string $sEmail - * @return mixed - */ - public function GetUserUidByEmail($sEmail) - { - $this->Sync(); - - $iId = $this->getUserId($sEmail); - return 0 < $iId ? (string) $iId : ''; - } - - /** - * @param string $sEmail - * @return string - */ - public function GetCtagByEmail($sEmail) - { - $this->Sync(); - - $sResult = '0'; - $iUserID = $this->getUserId($sEmail); - if (0 < $iUserID) - { - $oStmt = $this->prepareAndExecute('SELECT MAX(id_prop) as max_value FROM rainloop_pab_properties WHERE id_user = :id_user', - array(':id_user' => array($iUserID, \PDO::PARAM_INT))); - - if ($oStmt) - { - $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); - if ($aFetch && !empty($aFetch[0]['max_value'])) - { - $sResult = 'RL-CTAG-'.((string) $aFetch[0]['max_value']); - } - } - } - - return $sResult; - } - - /** - * @param string $sEmail - * @param bool $bCreate = false - * - * @return string - */ - 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 WHERE id_user = :id_user LIMIT 1', - array(':id_user' => array($iUserID, \PDO::PARAM_INT))); - - if ($oStmt) - { - $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); - if ($aFetch && !empty($aFetch[0]['pass_hash'])) - { - $sHash = \rtrim(\base_convert(\md5(\md5($sEmail.'-'.\trim($aFetch[0]['pass_hash']).'-rainloop')), 16, 32), '0'); - } - else if ($bCreate) - { - $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) - ) - ); - - $sHash = $this->GetUserHashByEmail($sEmail, false); - } - } - } - - return $sHash; - } - - /** - * @param string $sEmail - * @param \RainLoop\Providers\PersonalAddressBook\Classes\Contact $oContact - * - * @return bool - */ - public function ContactSave($sEmail, &$oContact) - { - $this->Sync(); - $iUserID = $this->getUserId($sEmail); - - $iIdContact = 0 < \strlen($oContact->IdContact) && \is_numeric($oContact->IdContact) ? (int) $oContact->IdContact : 0; - - $bUpdate = 0 < $iIdContact; - - if (!$this->bConsiderShare) - { - $oContact->ScopeType = \RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_; - } - - $oContact->UpdateDependentValues(); - $oContact->Changed = \time(); - - try - { - if ($this->isTransactionSupported()) - { - $this->beginTransaction(); - } - - $aFreq = array(); - if ($bUpdate) - { - $aFreq = $this->getContactFreq($iUserID, $iIdContact); - - $sSql = 'UPDATE rainloop_pab_contacts SET id_contact_str = :id_contact_str, display = :display, '. - 'scope_type = :scope_type, changed = :changed, '. - 'carddav_data = :carddav_data, carddav_hash = :carddav_hash, carddav_size = :carddav_size '. - 'WHERE id_user = :id_user AND id_contact = :id_contact'; - - $this->prepareAndExecute($sSql, - array( - ':id_user' => array($iUserID, \PDO::PARAM_INT), - ':id_contact' => array($iIdContact, \PDO::PARAM_INT), - ':id_contact_str' => array($oContact->IdContactStr, \PDO::PARAM_STR), - ':display' => array($oContact->Display, \PDO::PARAM_STR), - ':scope_type' => array($oContact->ScopeType, \PDO::PARAM_INT), - ':changed' => array($oContact->Changed, \PDO::PARAM_INT), - - ':carddav_data' => array($oContact->CardDavData, \PDO::PARAM_STR), - ':carddav_hash' => array($oContact->CardDavHash, \PDO::PARAM_STR), - ':carddav_size' => array($oContact->CardDavSize, \PDO::PARAM_INT) - ) - ); - - // clear previos props - $this->prepareAndExecute( - 'DELETE FROM rainloop_pab_properties WHERE id_user = :id_user AND id_contact = :id_contact', - array( - ':id_user' => array($iUserID, \PDO::PARAM_INT), - ':id_contact' => array($iIdContact, \PDO::PARAM_INT) - ) - ); - } - else - { - $sSql = 'INSERT INTO rainloop_pab_contacts '. - '( id_user, id_contact_str, display, scope_type, changed, carddav_data, carddav_hash, carddav_size) VALUES '. - '(:id_user, :id_contact_str, :display, :scope_type, :changed, :carddav_data, :carddav_hash, :carddav_size)'; - - $this->prepareAndExecute($sSql, - array( - ':id_user' => array($iUserID, \PDO::PARAM_INT), - ':id_contact_str' => array($oContact->IdContactStr, \PDO::PARAM_STR), - ':display' => array($oContact->Display, \PDO::PARAM_STR), - ':scope_type' => array($oContact->ScopeType, \PDO::PARAM_INT), - ':changed' => array($oContact->Changed, \PDO::PARAM_INT), - - ':carddav_data' => array($oContact->CardDavData, \PDO::PARAM_STR), - ':carddav_hash' => array($oContact->CardDavHash, \PDO::PARAM_STR), - ':carddav_size' => array($oContact->CardDavSize, \PDO::PARAM_INT) - ) - ); - - $sLast = $this->lastInsertId('id_contact'); - if (\is_numeric($sLast) && 0 < (int) $sLast) - { - $iIdContact = (int) $sLast; - $oContact->IdContact = (string) $iIdContact; - } - } - - if (0 < $iIdContact) - { - $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($iIdContact, \PDO::PARAM_INT), - ':id_user' => array($iUserID, \PDO::PARAM_INT), - ':scope_type' => array($oContact->ScopeType, \PDO::PARAM_INT), - ':prop_type' => array($oProp->Type, \PDO::PARAM_INT), - ':prop_type_custom' => array($oProp->TypeCustom, \PDO::PARAM_STR), - ':prop_value' => array($oProp->Value, \PDO::PARAM_STR), - ':prop_value_custom' => array($oProp->ValueCustom, \PDO::PARAM_STR), - ':prop_frec' => array($iFreq, \PDO::PARAM_INT), - ); - } - - $sSql = 'INSERT INTO rainloop_pab_properties '. - '( id_contact, id_user, prop_type, prop_type_custom, prop_value, prop_value_custom, scope_type, prop_frec) VALUES '. - '(:id_contact, :id_user, :prop_type, :prop_type_custom, :prop_value, :prop_value_custom, :scope_type, :prop_frec)'; - - $this->prepareAndExecute($sSql, $aParams, true); - } - } - catch (\Exception $oException) - { - if ($this->isTransactionSupported()) - { - $this->rollBack(); - } - - throw $oException; - } - - if ($this->isTransactionSupported()) - { - $this->commit(); - } - - return 0 < $iIdContact; - } - - /** - * @param string $sEmail - * @param array $aContactIds - * - * @return bool - */ - public function DeleteContacts($sEmail, $aContactIds) - { - $this->Sync(); - $iUserID = $this->getUserId($sEmail); - - $aContactIds = \array_filter($aContactIds, function (&$mItem) { - $mItem = (int) \trim($mItem); - return 0 < $mItem; - }); - - if (0 === \count($aContactIds)) - { - return false; - } - - $sIDs = \implode(',', $aContactIds); - $aParams = array(':id_user' => array($iUserID, \PDO::PARAM_INT)); - - $this->prepareAndExecute('DELETE FROM rainloop_pab_tags_contacts WHERE id_contact IN ('.$sIDs.')'); - $this->prepareAndExecute('DELETE FROM rainloop_pab_properties WHERE id_user = :id_user AND id_contact IN ('.$sIDs.')', $aParams); - $this->prepareAndExecute('DELETE FROM rainloop_pab_contacts WHERE id_user = :id_user AND id_contact IN ('.$sIDs.')', $aParams); - - return true; - } - - /** - * @param string $sEmail - * @param array $aTagsIds - * - * @return bool - */ - public function DeleteTags($sEmail, $aTagsIds) - { - $this->Sync(); - $iUserID = $this->getUserId($sEmail); - - $aTagsIds = \array_filter($aTagsIds, function (&$mItem) { - $mItem = (int) \trim($mItem); - return 0 < $mItem; - }); - - if (0 === \count($aTagsIds)) - { - return false; - } - - $sIDs = \implode(',', $aTagsIds); - $aParams = array(':id_user' => array($iUserID, \PDO::PARAM_INT)); - - $this->prepareAndExecute('DELETE FROM rainloop_pab_tags_contacts WHERE id_tag IN ('.$sIDs.')'); - $this->prepareAndExecute('DELETE FROM rainloop_pab_tags WHERE id_user = :id_user AND id_tag IN ('.$sIDs.')', $aParams); - - return true; - } - - /** - * @param string $sEmail - * @param int $iOffset = 0 - * @param int $iLimit = 20 - * @param string $sSearch = '' - * @param int $iResultCount = 0 - * - * @return array - */ - public function GetContacts($sEmail, $iOffset = 0, $iLimit = 20, $sSearch = '', &$iResultCount = 0) - { - $this->Sync(); - - $iOffset = 0 <= $iOffset ? $iOffset : 0; - $iLimit = 0 < $iLimit ? (int) $iLimit : 20; - $sSearch = \trim($sSearch); - - $iUserID = $this->getUserId($sEmail); - - $iCount = 0; - $aSearchIds = array(); - $aPropertyFromSearchIds = array(); - - if (0 < \strlen($sSearch)) - { - $sCustomSearch = $this->specialConvertSearchValueCustomPhone($sSearch); - if ('%%' === $sCustomSearch) - { - // TODO fix this - $sCustomSearch = ''; - } - - $sSql = 'SELECT id_user, id_prop, id_contact FROM rainloop_pab_properties '. - 'WHERE ('. - 'id_user = :id_user'. - ($this->bConsiderShare ? ' OR scope_type = :scope_type_share_all' : ''). - ') AND (prop_value LIKE :search ESCAPE \'=\''. - (0 < \strlen($sCustomSearch) ? ' OR (prop_type IN ('.\implode(',', array( - PropertyType::PHONE_PERSONAL, PropertyType::PHONE_BUSSINES, PropertyType::PHONE_OTHER, - PropertyType::MOBILE_PERSONAL, PropertyType::MOBILE_BUSSINES, PropertyType::MOBILE_OTHER, - PropertyType::FAX_PERSONAL, PropertyType::FAX_BUSSINES, PropertyType::FAX_OTHER - )).') AND prop_value_custom <> \'\' AND prop_value_custom LIKE :search_custom_phone)' : ''). - ') GROUP BY id_contact, id_prop'; - - $aParams = array( - ':id_user' => array($iUserID, \PDO::PARAM_INT), - ':search' => array($this->specialConvertSearchValue($sSearch, '='), \PDO::PARAM_STR) - ); - - if (0 < \strlen($sCustomSearch)) - { - $aParams[':search_custom_phone'] = array($sCustomSearch, \PDO::PARAM_STR); - } - - if ($this->bConsiderShare) - { - $aParams[':scope_type_share_all'] = array(\RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::SHARE_ALL, \PDO::PARAM_INT); - } - - $oStmt = $this->prepareAndExecute($sSql, $aParams); - if ($oStmt) - { - $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); - if (\is_array($aFetch) && 0 < \count($aFetch)) - { - foreach ($aFetch as $aItem) - { - $iIdContact = $aItem && isset($aItem['id_contact']) ? (int) $aItem['id_contact'] : 0; - if (0 < $iIdContact) - { - $aSearchIds[] = $iIdContact; - $aPropertyFromSearchIds[$iIdContact] = isset($aItem['id_prop']) ? (int) $aItem['id_prop'] : 0; - } - } - } - - $aSearchIds = \array_unique($aSearchIds); - $iCount = \count($aSearchIds); - } - } - else - { - $sSql = 'SELECT COUNT(DISTINCT id_contact) as contact_count FROM rainloop_pab_properties '. - 'WHERE id_user = :id_user'. - ($this->bConsiderShare ? ' OR scope_type = :scope_type_share_all' : '') - ; - - $aParams = array( - ':id_user' => array($iUserID, \PDO::PARAM_INT) - ); - - if ($this->bConsiderShare) - { - $aParams[':scope_type_share_all'] = array(\RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::SHARE_ALL, \PDO::PARAM_INT); - } - - $oStmt = $this->prepareAndExecute($sSql, $aParams); - if ($oStmt) - { - $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); - if ($aFetch && isset($aFetch[0]['contact_count']) && is_numeric($aFetch[0]['contact_count']) && 0 < (int) $aFetch[0]['contact_count']) - { - $iCount = (int) $aFetch[0]['contact_count']; - } - } - } - - $iResultCount = $iCount; - - if (0 < $iCount) - { - $sSql = 'SELECT * FROM rainloop_pab_contacts '. - 'WHERE (id_user = :id_user'. - ($this->bConsiderShare ? ' OR scope_type = :scope_type_share_all)' : ')') - ; - - $aParams = array( - ':id_user' => array($iUserID, \PDO::PARAM_INT) - ); - - if ($this->bConsiderShare) - { - $aParams[':scope_type_share_all'] = array(\RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::SHARE_ALL, \PDO::PARAM_INT); - } - - if (0 < \count($aSearchIds)) - { - $sSql .= ' AND id_contact IN ('.implode(',', $aSearchIds).')'; - } - - $sSql .= ' ORDER BY display ASC LIMIT :limit OFFSET :offset'; - $aParams[':limit'] = array($iLimit, \PDO::PARAM_INT); - $aParams[':offset'] = array($iOffset, \PDO::PARAM_INT); - - $oStmt = $this->prepareAndExecute($sSql, $aParams); - if ($oStmt) - { - $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); - - $aContacts = array(); - $aIdContacts = array(); - if (\is_array($aFetch) && 0 < \count($aFetch)) - { - foreach ($aFetch as $aItem) - { - $iIdContact = $aItem && isset($aItem['id_contact']) ? (int) $aItem['id_contact'] : 0; - if (0 < $iIdContact) - { - $aIdContacts[] = $iIdContact; - $oContact = new \RainLoop\Providers\PersonalAddressBook\Classes\Contact(); - - $oContact->IdContact = (string) $iIdContact; - $oContact->IdContactStr = isset($aItem['id_contact_str']) ? (string) $aItem['id_contact_str'] : ''; - $oContact->Display = isset($aItem['display']) ? (string) $aItem['display'] : ''; - $oContact->ScopeType = isset($aItem['scope_type']) ? (int) $aItem['scope_type'] : - \RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_; - $oContact->Changed = isset($aItem['changed']) ? (int) $aItem['changed'] : 0; - $oContact->ReadOnly = $iUserID !== (isset($aItem['id_user']) ? (int) $aItem['id_user'] : 0); - - $oContact->IdPropertyFromSearch = isset($aPropertyFromSearchIds[$iIdContact]) && - 0 < $aPropertyFromSearchIds[$iIdContact] ? $aPropertyFromSearchIds[$iIdContact] : 0; - - $aContacts[$iIdContact] = $oContact; - } - } - } - - unset($aFetch); - - if (0 < count($aIdContacts)) - { - $oStmt->closeCursor(); - - $sSql = 'SELECT * FROM rainloop_pab_properties WHERE id_contact IN ('.\implode(',', $aIdContacts).')'; - $oStmt = $this->prepareAndExecute($sSql); - - if ($oStmt) - { - $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); - if (\is_array($aFetch) && 0 < \count($aFetch)) - { - foreach ($aFetch as $aItem) - { - if ($aItem && isset($aItem['id_prop'], $aItem['id_contact'], $aItem['prop_type'], $aItem['prop_value'])) - { - $iId = (int) $aItem['id_contact']; - if (0 < $iId && isset($aContacts[$iId])) - { - $oProperty = new \RainLoop\Providers\PersonalAddressBook\Classes\Property(); - $oProperty->IdProperty = (int) $aItem['id_prop']; - $oProperty->ScopeType = isset($aItem['scope_type']) ? (int) $aItem['scope_type'] : - \RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_; - $oProperty->Type = (int) $aItem['prop_type']; - $oProperty->TypeCustom = isset($aItem['prop_type_custom']) ? (string) $aItem['prop_type_custom'] : ''; - $oProperty->Value = (string) $aItem['prop_value']; - $oProperty->ValueCustom = isset($aItem['prop_value_custom']) ? (string) $aItem['prop_value_custom'] : ''; - $oProperty->Frec = isset($aItem['prop_frec']) ? (int) $aItem['prop_frec'] : 0; - - $aContacts[$iId]->Properties[] = $oProperty; - } - } - } - } - - unset($aFetch); - - foreach ($aContacts as &$oItem) - { - $oItem->UpdateDependentValues(); - } - - return \array_values($aContacts); - } - } - } - } - - return array(); - } - - /** - * @param string $sEmail - * @param string $sID - * @param bool $bIsStrID = false - * - * @return \RainLoop\Providers\PersonalAddressBook\Classes\Contact|null - */ - public function GetContactByID($sEmail, $mID, $bIsStrID = false) - { - $this->Sync(); - - $mID = \trim($mID); - - $iUserID = $this->getUserId($sEmail); - - $sSql = 'SELECT * FROM rainloop_pab_contacts '. - 'WHERE ('. - 'id_user = :id_user'. - ($this->bConsiderShare ? ' OR scope_type = :scope_type_share_all' : ''). - ')' - ; - - $aParams = array( - ':id_user' => array($iUserID, \PDO::PARAM_INT) - ); - - if ($this->bConsiderShare) - { - $aParams[':scope_type_share_all'] = array(\RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::SHARE_ALL, \PDO::PARAM_INT); - } - - if ($bIsStrID) - { - $sSql .= ' AND id_contact_str = :id_contact_str'; - $aParams[':id_contact_str'] = array($mID, \PDO::PARAM_STR); - } - else - { - $sSql .= ' AND id_contact = :id_contact'; - $aParams[':id_contact'] = array($mID, \PDO::PARAM_INT); - } - - $sSql .= ' LIMIT 1'; - - $oContact = null; - $iIdContact = 0; - - $oStmt = $this->prepareAndExecute($sSql, $aParams); - if ($oStmt) - { - $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); - - if (\is_array($aFetch) && 0 < \count($aFetch)) - { - foreach ($aFetch as $aItem) - { - $iIdContact = $aItem && isset($aItem['id_contact']) ? (int) $aItem['id_contact'] : 0; - if (0 < $iIdContact) - { - $oContact = new \RainLoop\Providers\PersonalAddressBook\Classes\Contact(); - - $oContact->IdContact = (string) $iIdContact; - $oContact->IdContactStr = isset($aItem['id_contact_str']) ? (string) $aItem['id_contact_str'] : ''; - $oContact->Display = isset($aItem['display']) ? (string) $aItem['display'] : ''; - $oContact->ScopeType = isset($aItem['scope_type']) ? (int) $aItem['scope_type'] : - \RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_; - $oContact->Changed = isset($aItem['changed']) ? (int) $aItem['changed'] : 0; - $oContact->ReadOnly = $iUserID !== (isset($aItem['id_user']) ? (int) $aItem['id_user'] : 0); - - $oContact->CardDavData = empty($aItem['carddav_data']) ? '' : (string) $aItem['carddav_data']; - $oContact->CardDavHash = empty($aItem['carddav_hash']) ? \md5($oContact->CardDavData) : (string) $aItem['carddav_hash']; - $oContact->CardDavSize = empty($aItem['carddav_size']) ? \strlen($oContact->CardDavData) : (int) $aItem['carddav_size']; - } - } - } - - unset($aFetch); - - if (0 < $iIdContact && $oContact) - { - $oStmt->closeCursor(); - - $sSql = 'SELECT * FROM rainloop_pab_properties WHERE id_contact = '.$iIdContact; - $oStmt = $this->prepareAndExecute($sSql); - - if ($oStmt) - { - $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); - if (\is_array($aFetch) && 0 < \count($aFetch)) - { - foreach ($aFetch as $aItem) - { - if ($aItem && isset($aItem['id_prop'], $aItem['id_contact'], $aItem['prop_type'], $aItem['prop_value'])) - { - if ((string) $oContact->IdContact === (string) $aItem['id_contact']) - { - $oProperty = new \RainLoop\Providers\PersonalAddressBook\Classes\Property(); - $oProperty->IdProperty = (int) $aItem['id_prop']; - $oProperty->ScopeType = isset($aItem['scope_type']) ? (int) $aItem['scope_type'] : - \RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_; - $oProperty->Type = (int) $aItem['prop_type']; - $oProperty->TypeCustom = isset($aItem['prop_type_custom']) ? (string) $aItem['prop_type_custom'] : ''; - $oProperty->Value = (string) $aItem['prop_value']; - $oProperty->ValueCustom = isset($aItem['prop_value_custom']) ? (string) $aItem['prop_value_custom'] : ''; - $oProperty->Frec = isset($aItem['prop_frec']) ? (int) $aItem['prop_frec'] : 0; - - $oContact->Properties[] = $oProperty; - } - } - } - } - - unset($aFetch); - - $oContact->UpdateDependentValues(); - } - } - } - - return $oContact; - } - - /** - * @param string $sEmail - * @param string $sSearch - * @param int $iLimit = 20 - * - * @return array - * - * @throws \InvalidArgumentException - */ - public function GetSuggestions($sEmail, $sSearch, $iLimit = 20) - { - $sSearch = \trim($sSearch); - if (0 === \strlen($sSearch)) - { - throw new \InvalidArgumentException('Empty Search argument'); - } - - $this->Sync(); - - $iUserID = $this->getUserId($sEmail); - - $sTypes = implode(',', array( - PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER, PropertyType::FIRST_NAME, PropertyType::LAST_NAME - )); - - $sSql = 'SELECT id_contact, id_prop, prop_type, prop_value FROM rainloop_pab_properties '. - 'WHERE ('. - 'id_user = :id_user'. - ($this->bConsiderShare ? ' OR scope_type = :scope_type_share_all' : ''). - ') AND prop_type IN ('.$sTypes.') AND prop_value LIKE :search ESCAPE \'=\''; - - $aParams = array( - ':id_user' => array($iUserID, \PDO::PARAM_INT), - ':limit' => array($iLimit, \PDO::PARAM_INT), - ':search' => array($this->specialConvertSearchValue($sSearch, '='), \PDO::PARAM_STR) - ); - - if ($this->bConsiderShare) - { - $aParams[':scope_type_share_all'] = array(\RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::SHARE_ALL, \PDO::PARAM_INT); - } - - $sSql .= ' ORDER BY prop_frec DESC'; - $sSql .= ' LIMIT :limit'; - - $aResult = array(); - - $oStmt = $this->prepareAndExecute($sSql, $aParams); - if ($oStmt) - { - $aIdContacts = array(); - $aIdProps = array(); - $aContactAllAccess = array(); - - $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); - if (\is_array($aFetch) && 0 < \count($aFetch)) - { - foreach ($aFetch as $aItem) - { - $iIdContact = $aItem && isset($aItem['id_contact']) ? (int) $aItem['id_contact'] : 0; - $iIdProp = $aItem && isset($aItem['id_prop']) ? (int) $aItem['id_prop'] : 0; - $iType = $aItem && isset($aItem['prop_type']) ? (int) $aItem['prop_type'] : 0; - - if (0 < $iIdContact && 0 < $iIdProp) - { - $aIdContacts[$iIdContact] = $iIdContact; - $aIdProps[$iIdProp] = $iIdProp; - - if (\in_array($iType, array(PropertyType::LAST_NAME, PropertyType::FIRST_NAME))) - { - $aContactAllAccess[$iIdContact] = $iIdContact; - } - } - } - } - - unset($aFetch); - - $aIdContacts = \array_values($aIdContacts); - if (0 < count($aIdContacts)) - { - $oStmt->closeCursor(); - - $sTypes = \implode(',', array( - PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER, PropertyType::FIRST_NAME, PropertyType::LAST_NAME - )); - - $sSql = 'SELECT id_prop, id_contact, prop_type, prop_value FROM rainloop_pab_properties '. - 'WHERE prop_type IN ('.$sTypes.') AND id_contact IN ('.\implode(',', $aIdContacts).')'; - - $oStmt = $this->prepareAndExecute($sSql); - if ($oStmt) - { - $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); - if (\is_array($aFetch) && 0 < \count($aFetch)) - { - $aNames = array(); - $aEmails = array(); - - foreach ($aFetch as $aItem) - { - if ($aItem && isset($aItem['id_prop'], $aItem['id_contact'], $aItem['prop_type'], $aItem['prop_value'])) - { - $iIdContact = (int) $aItem['id_contact']; - $iIdProp = (int) $aItem['id_prop']; - $iType = (int) $aItem['prop_type']; - - if (\in_array($iType, array(PropertyType::LAST_NAME, PropertyType::FIRST_NAME))) - { - if (!isset($aNames[$iIdContact])) - { - $aNames[$iIdContact] = array('', ''); - } - - $aNames[$iIdContact][PropertyType::LAST_NAME === $iType ? 0 : 1] = $aItem['prop_value']; - } - else if ((isset($aIdProps[$iIdProp]) || isset($aContactAllAccess[$iIdContact]))&& - \in_array($iType, array(PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES))) - { - if (!isset($aEmails[$iIdContact])) - { - $aEmails[$iIdContact] = array(); - } - - $aEmails[$iIdContact][] = $aItem['prop_value']; - } - } - } - -// $this->writeLog($aNames); -// $this->writeLog($aEmails); - - foreach ($aEmails as $iId => $aItems) - { - $aNameItem = isset($aNames[$iId]) && \is_array($aNames[$iId]) ? $aNames[$iId] : array('', ''); - $sNameItem = \trim($aNameItem[0].' '.$aNameItem[1]); - - foreach ($aItems as $sEmail) - { - $aResult[] = array($sEmail, $sNameItem); - } - } - } - - unset($aFetch); - - if ($iLimit < \count($aResult)) - { - $aResult = \array_slice($aResult, 0, $iLimit); - } - - return $aResult; - } - } - } - - return array(); - } - - /** - * @param string $sEmail - * @param array $aEmails - * @param bool $bCreateAuto = true - * - * @return bool - */ - public function IncFrec($sEmail, $aEmails, $bCreateAuto = true) - { - $self = $this; - $aEmailsObjects = \array_map(function ($mItem) { - $oResult = null; - try - { - $oResult = \MailSo\Mime\Email::Parse(\trim($mItem)); - } - catch (\Exception $oException) {} - return $oResult; - }, $aEmails); - - if (0 === \count($aEmailsObjects)) - { - throw new \InvalidArgumentException('Empty Emails argument'); - } - - $this->Sync(); - $iUserID = $this->getUserId($sEmail); - - $sTypes = \implode(',', array( - PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER - )); - - $aExists = array(); - $aEmailsToCreate = array(); - $aEmailsToUpdate = array(); - - if ($bCreateAuto) - { - $sSql = 'SELECT prop_value FROM rainloop_pab_properties WHERE id_user = :id_user AND prop_type IN ('.$sTypes.')'; - $oStmt = $this->prepareAndExecute($sSql, array( - ':id_user' => array($iUserID, \PDO::PARAM_INT) - )); - - if ($oStmt) - { - $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); - if (\is_array($aFetch) && 0 < \count($aFetch)) - { - foreach ($aFetch as $aItem) - { - if ($aItem && !empty($aItem['prop_value'])) - { - $aExists[] = \strtolower(\trim($aItem['prop_value'])); - } - } - } - } - - $aEmailsToCreate = \array_filter($aEmailsObjects, function ($oItem) use ($aExists, &$aEmailsToUpdate) { - if ($oItem) - { - $sEmail = \strtolower(\trim($oItem->GetEmail())); - if (0 < \strlen($sEmail)) - { - $aEmailsToUpdate[] = $sEmail; - return !\in_array($sEmail, $aExists); - } - } - - return false; - }); - } - else - { - foreach ($aEmailsObjects as $oItem) - { - if ($oItem) - { - $sEmailUpdate = \strtolower(\trim($oItem->GetEmail())); - if (0 < \strlen($sEmailUpdate)) - { - $aEmailsToUpdate[] = $sEmailUpdate; - } - } - } - } - - unset($aEmails, $aEmailsObjects); - - if (0 < \count($aEmailsToCreate)) - { - $oContact = new \RainLoop\Providers\PersonalAddressBook\Classes\Contact(); - foreach ($aEmailsToCreate as $oEmail) - { - $oContact->ScopeType = \RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_; - - if ('' !== \trim($oEmail->GetEmail())) - { - $oPropEmail = new \RainLoop\Providers\PersonalAddressBook\Classes\Property(); - $oPropEmail->ScopeType = $oContact->ScopeType; - $oPropEmail->Type = \RainLoop\Providers\PersonalAddressBook\Enumerations\PropertyType::EMAIl_PERSONAL; - $oPropEmail->Value = \strtolower(\trim($oEmail->GetEmail())); - - $oContact->Properties[] = $oPropEmail; - } - - if ('' !== \trim($oEmail->GetDisplayName())) - { - $sFirst = $sLast = ''; - $sFullName = $oEmail->GetDisplayName(); - if (false !== \strpos($sFullName, ' ')) - { - $aNames = explode(' ', $sFullName, 2); - $sFirst = isset($aNames[0]) ? $aNames[0] : ''; - $sLast = isset($aNames[1]) ? $aNames[1] : ''; - } - else - { - $sFirst = $sFullName; - } - - if (0 < \strlen($sFirst)) - { - $oPropName = new \RainLoop\Providers\PersonalAddressBook\Classes\Property(); - $oPropName->ScopeType = $oContact->ScopeType; - $oPropName->Type = \RainLoop\Providers\PersonalAddressBook\Enumerations\PropertyType::FIRST_NAME; - $oPropName->Value = \trim($sFirst); - - $oContact->Properties[] = $oPropName; - } - - if (0 < \strlen($sLast)) - { - $oPropName = new \RainLoop\Providers\PersonalAddressBook\Classes\Property(); - $oPropName->ScopeType = $oContact->ScopeType; - $oPropName->Type = \RainLoop\Providers\PersonalAddressBook\Enumerations\PropertyType::LAST_NAME; - $oPropName->Value = \trim($sLast); - - $oContact->Properties[] = $oPropName; - } - } - - if (0 < \count($oContact->Properties)) - { - $this->ContactSave($sEmail, $oContact); - } - - $oContact->Clear(); - } - } - - $sSql = 'UPDATE rainloop_pab_properties SET prop_frec = prop_frec + 1 WHERE id_user = :id_user AND prop_type IN ('.$sTypes; - - $aEmailsQuoted = \array_map(function ($mItem) use ($self) { - return $self->quoteValue($mItem); - }, $aEmailsToUpdate); - - if (1 === \count($aEmailsQuoted)) - { - $sSql .= ') AND prop_value = '.$aEmailsQuoted[0]; - } - else - { - $sSql .= ') AND prop_value IN ('.\implode(',', $aEmailsQuoted).')'; - } - - return !!$this->prepareAndExecute($sSql, array( - ':id_user' => array($iUserID, \PDO::PARAM_INT), - )); - } - - /** - * @return string - */ - public function Test() - { - $sResult = ''; - try - { - $this->Sync(); - if (0 >= $this->getVersion($this->sDsnType.'-pab-version')) - { - $sResult = 'Unknown database error'; - } - } - catch (\Exception $oException) - { - $sResult = $oException->getMessage(); - if (!empty($sResult) && !\MailSo\Base\Utils::IsAscii($sResult) && !\MailSo\Base\Utils::IsUtf8($sResult)) - { - $sResult = @\utf8_encode($sResult); - } - - if (!\is_string($sResult) || empty($sResult)) - { - $sResult = 'Unknown database error'; - } - } - - return $sResult; - } - - private function getInitialTablesArray($sDbType) - { - $sInitial = ''; - $aResult = array(); - - switch ($sDbType) - { - case 'mysql': - $sInitial = <<sDsnType) - { - case 'mysql': - return $this->dataBaseUpgrade($this->sDsnType.'-pab-version', array( - 1 => $this->getInitialTablesArray($this->sDsnType), - 2 => array( -'ALTER TABLE rainloop_pab_contacts ADD id_contact_str varchar(128) NOT NULL DEFAULT \'\' AFTER id_contact;', -'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 ( - id_user int UNSIGNED NOT NULL, - email varchar(128) NOT NULL, - pass_hash varchar(128) NOT NULL -)/*!40000 ENGINE=INNODB */;' - ) - )); - case 'pgsql': - return $this->dataBaseUpgrade($this->sDsnType.'-pab-version', array( - 1 => $this->getInitialTablesArray($this->sDsnType), - 2 => array( -'ALTER TABLE rainloop_pab_contacts ADD id_contact_str varchar(128) NOT NULL DEFAULT \'\';', -'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 ( - id_user integer NOT NULL, - email varchar(128) NOT NULL, - pass_hash varchar(128) NOT NULL -);' - ) - )); - case 'sqlite': - return $this->dataBaseUpgrade($this->sDsnType.'-pab-version', array( - 1 => $this->getInitialTablesArray($this->sDsnType), - 2 => array( -'ALTER TABLE rainloop_pab_contacts ADD id_contact_str text NOT NULL DEFAULT \'\';', -'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 ( - id_user integer NOT NULL, - email text NOT NULL, - pass_hash text NOT NULL -);' - ) - )); - } - - return false; - } - - /** - * @param int $iUserID - * @param int $iIdContact - * @return array - */ - private function getContactFreq($iUserID, $iIdContact) - { - $aResult = array(); - - $sTypes = \implode(',', array( - PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES - )); - - $sSql = 'SELECT prop_value, prop_frec FROM rainloop_pab_properties WHERE id_user = :id_user AND id_contact = :id_contact AND prop_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['prop_value']) && !empty($aItem['prop_frec'])) - { - $aResult[$aItem['prop_value']] = (int) $aItem['prop_frec']; - } - } - } - } - - return $aResult; - } - - /** - * @param string $sSearch - * @param string $sEscapeSign = '=' - * - * @return string - */ - private function specialConvertSearchValue($sSearch, $sEscapeSign = '=') - { - return '%'.\str_replace(array($sEscapeSign, '_', '%'), - array($sEscapeSign.$sEscapeSign, $sEscapeSign.'_', $sEscapeSign.'%'), $sSearch).'%'; - } - - /** - * @param string $sSearch - * - * @return string - */ - private function specialConvertSearchValueCustomPhone($sSearch) - { - return '%'.\preg_replace('/[^\d]/', '', $sSearch).'%'; - } - - /** - * @return array - */ - protected function getPdoAccessData() - { - return array($this->sDsnType, $this->sDsn, $this->sUser, $this->sPassword); - } -} \ No newline at end of file diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/PersonalAddressBookInterface.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/PersonalAddressBookInterface.php deleted file mode 100644 index 74a1413e9..000000000 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/PersonalAddressBook/PersonalAddressBookInterface.php +++ /dev/null @@ -1,65 +0,0 @@ -