mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-07 16:37:02 +03:00
+ Updated contacts sql shema (breaking changes) + Fixes - Removed SabreDAV Server - Removed Contacts Sharing (awhile, code refactoring)
This commit is contained in:
parent
54a4c2657a
commit
d29f20789f
78 changed files with 2024 additions and 2317 deletions
|
|
@ -53,6 +53,28 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
|
|||
$this->oDriver->IsSupported();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function IsSharingAllowed()
|
||||
{
|
||||
return $this->oDriver instanceof \RainLoop\Providers\PersonalAddressBook\AddressBookInterface &&
|
||||
$this->oDriver->IsSharingAllowed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sEmail
|
||||
* @param string $sUrl
|
||||
* @param string $sUser
|
||||
* @param string $sPassword
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function Sync($sEmail, $sUrl, $sUser, $sPassword)
|
||||
{
|
||||
return $this->IsActive() ? $this->oDriver->Sync($sEmail, $sUrl, $sUser, $sPassword) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sEmail
|
||||
* @param \RainLoop\Providers\AddressBook\Classes\Contact $oContact
|
||||
|
|
@ -140,37 +162,64 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
|
|||
{
|
||||
$aMap = array(
|
||||
'Title' => PropertyType::FULLNAME,
|
||||
'First Name' => PropertyType::FIRST_NAME,
|
||||
'Middle Name' => PropertyType::MIDDLE_NAME,
|
||||
'Last Name' => PropertyType::LAST_NAME,
|
||||
'Name' => PropertyType::FULLNAME,
|
||||
'FullName' => PropertyType::FULLNAME,
|
||||
'DisplayName' => PropertyType::FULLNAME,
|
||||
'First' => PropertyType::FIRST_NAME,
|
||||
'FirstName' => PropertyType::FIRST_NAME,
|
||||
'Middle' => PropertyType::MIDDLE_NAME,
|
||||
'MiddleName' => PropertyType::MIDDLE_NAME,
|
||||
'Last' => PropertyType::LAST_NAME,
|
||||
'LastName' => 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,
|
||||
'NickName' => PropertyType::NICK_NAME,
|
||||
'BusinessFax' => array(PropertyType::PHONE, 'Work,Fax'),
|
||||
'BusinessFax2' => array(PropertyType::PHONE, 'Work,Fax'),
|
||||
'BusinessPhone' => array(PropertyType::PHONE, 'Work'),
|
||||
'BusinessPhone2' => array(PropertyType::PHONE, 'Work'),
|
||||
'BusinessPhone3' => array(PropertyType::PHONE, 'Work'),
|
||||
'CompanyPhone' => array(PropertyType::PHONE, 'Work'),
|
||||
'CompanyMainPhone' => array(PropertyType::PHONE, 'Work'),
|
||||
'HomeFax' => array(PropertyType::PHONE, 'Home,Fax'),
|
||||
'HomeFax2' => array(PropertyType::PHONE, 'Home,Fax'),
|
||||
'HomePhone' => array(PropertyType::PHONE, 'Home'),
|
||||
'HomePhone2' => array(PropertyType::PHONE, 'Home'),
|
||||
'HomePhone3' => array(PropertyType::PHONE, 'Home'),
|
||||
'Mobile' => array(PropertyType::PHONE, 'Mobile'),
|
||||
'MobilePhone' => array(PropertyType::PHONE, 'Mobile'),
|
||||
'BusinessMobile' => array(PropertyType::PHONE, 'Work,Mobile'),
|
||||
'BusinessMobilePhone' => array(PropertyType::PHONE, 'Work,Mobile'),
|
||||
'OtherFax' => array(PropertyType::PHONE, 'Other,Fax'),
|
||||
'OtherPhone' => array(PropertyType::PHONE, 'Other'),
|
||||
'PrimaryPhone' => array(PropertyType::PHONE, 'Pref,Home'),
|
||||
'Email' => array(PropertyType::EMAIl, 'Home'),
|
||||
'Email2' => array(PropertyType::EMAIl, 'Home'),
|
||||
'Email3' => array(PropertyType::EMAIl, 'Home'),
|
||||
'EmailAddress' => array(PropertyType::EMAIl, 'Home'),
|
||||
'Email2Address' => array(PropertyType::EMAIl, 'Home'),
|
||||
'Email3Address' => array(PropertyType::EMAIl, 'Home'),
|
||||
'OtherEmail' => array(PropertyType::EMAIl, 'Other'),
|
||||
'BusinessEmail' => array(PropertyType::EMAIl, 'Work'),
|
||||
'BusinessEmail2' => array(PropertyType::EMAIl, 'Work'),
|
||||
'BusinessEmail3' => array(PropertyType::EMAIl, 'Work'),
|
||||
'PersonalEmail' => array(PropertyType::EMAIl, 'Home'),
|
||||
'PersonalEmail2' => array(PropertyType::EMAIl, 'Home'),
|
||||
'PersonalEmail3' => array(PropertyType::EMAIl, 'Home'),
|
||||
'Notes' => PropertyType::NOTE,
|
||||
'Web Page' => PropertyType::WEB_PAGE_PERSONAL,
|
||||
'WebPage' => PropertyType::WEB_PAGE_PERSONAL,
|
||||
'Web' => PropertyType::WEB_PAGE,
|
||||
'BusinessWeb' => array(PropertyType::WEB_PAGE, 'Work'),
|
||||
'WebPage' => PropertyType::WEB_PAGE,
|
||||
'BusinessWebPage' => array(PropertyType::WEB_PAGE, 'Work'),
|
||||
'WebSite' => PropertyType::WEB_PAGE,
|
||||
'BusinessWebSite' => array(PropertyType::WEB_PAGE, 'Work'),
|
||||
'PersonalWebSite' => PropertyType::WEB_PAGE
|
||||
);
|
||||
|
||||
$aMap = \array_change_key_case($aMap, CASE_LOWER);
|
||||
}
|
||||
|
||||
$sCsvNameLower = \MailSo\Base\Utils::IsAscii($sCsvName) ? \strtolower($sCsvName) : '';
|
||||
return isset($aMap[$sCsvNameLower]) ? $aMap[$sCsvNameLower] : PropertyType::UNKNOWN;
|
||||
$sCsvNameLower = \MailSo\Base\Utils::IsAscii($sCsvName) ? \preg_replace('/[\s\-]+/', '', \strtolower($sCsvName)) : '';
|
||||
return !empty($sCsvNameLower) && isset($aMap[$sCsvNameLower]) ? $aMap[$sCsvNameLower] : PropertyType::UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -182,11 +231,15 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
|
|||
public function ImportCsvArray($sEmail, $aCsvData)
|
||||
{
|
||||
$iCount = 0;
|
||||
$iResetTimer = 0;
|
||||
|
||||
if ($this->IsActive() && \is_array($aCsvData) && 0 < \count($aCsvData))
|
||||
{
|
||||
$oContact = new \RainLoop\Providers\AddressBook\Classes\Contact();
|
||||
foreach ($aCsvData as $aItem)
|
||||
{
|
||||
\MailSo\Base\Utils::ResetTimeLimit($iResetTimer);
|
||||
|
||||
foreach ($aItem as $sItemName => $sItemValue)
|
||||
{
|
||||
$sItemName = \trim($sItemName);
|
||||
|
|
@ -194,12 +247,15 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
|
|||
|
||||
if (!empty($sItemName) && !empty($sItemValue))
|
||||
{
|
||||
$iType = $this->csvNameToTypeConvertor($sItemName);
|
||||
$mData = $this->csvNameToTypeConvertor($sItemName);
|
||||
$iType = \is_array($mData) ? $mData[0] : $mData;
|
||||
|
||||
if (PropertyType::UNKNOWN !== $iType)
|
||||
{
|
||||
$oProp = new \RainLoop\Providers\AddressBook\Classes\Property();
|
||||
$oProp->Type = $iType;
|
||||
$oProp->Value = $sItemValue;
|
||||
$oProp->TypeStr = \is_array($mData) && !empty($mData[1]) ? $mData[1] : '';
|
||||
|
||||
$oContact->Properties[] = $oProp;
|
||||
}
|
||||
|
|
@ -232,6 +288,8 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
|
|||
public function ImportVcfFile($sEmail, $sVcfData)
|
||||
{
|
||||
$iCount = 0;
|
||||
$iResetTimer = 0;
|
||||
|
||||
if ($this->IsActive() && \is_string($sVcfData))
|
||||
{
|
||||
$sVcfData = \trim($sVcfData);
|
||||
|
|
@ -260,12 +318,15 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
|
|||
{
|
||||
if ($oVCard instanceof \Sabre\VObject\Component\VCard)
|
||||
{
|
||||
\MailSo\Base\Utils::ResetTimeLimit($iResetTimer);
|
||||
|
||||
if (empty($oVCard->UID))
|
||||
{
|
||||
$oVCard->UID = \Sabre\DAV\UUIDUtil::getUUID();
|
||||
}
|
||||
|
||||
$oContact->ParseVCard($oVCard, $oVCard->serialize());
|
||||
$oContact->PopulateByVCard($oVCard->serialize());
|
||||
|
||||
if (0 < \count($oContact->Properties))
|
||||
{
|
||||
if ($this->ContactSave($sEmail, $oContact))
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class Contact
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $Hash;
|
||||
public $Etag;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
|
@ -64,7 +64,7 @@ class Contact
|
|||
$this->Properties = array();
|
||||
$this->ReadOnly = false;
|
||||
$this->IdPropertyFromSearch = 0;
|
||||
$this->Hash = '';
|
||||
$this->Etag = '';
|
||||
}
|
||||
|
||||
public function UpdateDependentValues()
|
||||
|
|
@ -101,9 +101,8 @@ class Contact
|
|||
{
|
||||
$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
|
||||
else if (\in_array($oProperty->Type, array(
|
||||
PropertyType::FULLNAME, PropertyType::PHONE
|
||||
)))
|
||||
{
|
||||
$sOther = $oProperty->Value;
|
||||
|
|
@ -134,20 +133,16 @@ class Contact
|
|||
}
|
||||
|
||||
$this->Display = \trim($sDisplay);
|
||||
|
||||
$bNewFull = false;
|
||||
if (!$oFullNameProperty)
|
||||
|
||||
if ($oFullNameProperty)
|
||||
{
|
||||
$oFullNameProperty = new \RainLoop\Providers\AddressBook\Classes\Property(PropertyType::FULLNAME, $this->Display);
|
||||
$bNewFull = true;
|
||||
$oFullNameProperty->Value = $this->Display;
|
||||
$oFullNameProperty->UpdateDependentValues();
|
||||
}
|
||||
|
||||
$oFullNameProperty->Value = $this->Display;
|
||||
$oFullNameProperty->UpdateDependentValues();
|
||||
|
||||
if ($bNewFull)
|
||||
if (!$oFullNameProperty)
|
||||
{
|
||||
$this->Properties[] = $oFullNameProperty;
|
||||
$this->Properties[] = new \RainLoop\Providers\AddressBook\Classes\Property(PropertyType::FULLNAME, $this->Display);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -177,85 +172,189 @@ class Contact
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \Sabre\VObject\Document $oVCard
|
||||
* @return string
|
||||
*/
|
||||
public function ParseVCard($oVCard)
|
||||
public function CardDavNameUri()
|
||||
{
|
||||
$bNew = empty($this->IdContact);
|
||||
return $this->IdContactStr.'.vcf';
|
||||
}
|
||||
|
||||
if (!$bNew)
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function ToVCard($sPreVCard = '')
|
||||
{
|
||||
$this->UpdateDependentValues();
|
||||
|
||||
$oVCard = null;
|
||||
if (0 < \strlen($sPreVCard))
|
||||
{
|
||||
$this->Properties = array();
|
||||
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, $oVCard->URL);
|
||||
|
||||
$sFirstName = $sLastName = $sMiddleName = $sSuffix = $sPrefix = '';
|
||||
foreach ($this->Properties as /* @var $oProperty \RainLoop\Providers\AddressBook\Classes\Property */ &$oProperty)
|
||||
{
|
||||
if ($oProperty)
|
||||
{
|
||||
$sAddKey = '';
|
||||
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:
|
||||
if (empty($sAddKey))
|
||||
{
|
||||
$sAddKey = 'EMAIL';
|
||||
}
|
||||
case PropertyType::WEB_PAGE:
|
||||
if (empty($sAddKey))
|
||||
{
|
||||
$sAddKey = 'URL';
|
||||
}
|
||||
case PropertyType::PHONE:
|
||||
if (empty($sAddKey))
|
||||
{
|
||||
$sAddKey = 'TEL';
|
||||
}
|
||||
|
||||
$aTypes = $oProperty->TypesAsArray();
|
||||
$oVCard->add($sAddKey, $oProperty->Value, \is_array($aTypes) && 0 < \count($aTypes) ? array('TYPE' => $aTypes) : null);
|
||||
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 (string) $oVCard->serialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $oProp
|
||||
* @param bool $bOldVersion
|
||||
* @return string
|
||||
*/
|
||||
private function getPropertyValueHelper($oProp, $bOldVersion)
|
||||
{
|
||||
$sValue = \trim($oProp);
|
||||
if ($bOldVersion && !isset($oProp->parameters['CHARSET']))
|
||||
{
|
||||
if (0 < \strlen($sValue))
|
||||
{
|
||||
$sEncValue = @\utf8_encode($sValue);
|
||||
if (0 === \strlen($sEncValue))
|
||||
{
|
||||
$sEncValue = $sValue;
|
||||
}
|
||||
|
||||
$sValue = $sEncValue;
|
||||
}
|
||||
}
|
||||
|
||||
return \MailSo\Base\Utils::Utf8Clear($sValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $oProp
|
||||
* @param bool $bOldVersion
|
||||
* @return string
|
||||
*/
|
||||
private function addArrayPropertyHelper(&$aProperties, $oArrayProp, $iType)
|
||||
{
|
||||
foreach ($oArrayProp as $oProp)
|
||||
{
|
||||
$oTypes = $oProp ? $oProp['TYPE'] : null;
|
||||
$aTypes = $oTypes ? $oTypes->getParts() : array();
|
||||
$sValue = $oProp ? \trim($oProp->getValue()) : '';
|
||||
|
||||
if (0 < \strlen($sValue))
|
||||
{
|
||||
if (!$oTypes || $oTypes->has('PREF'))
|
||||
{
|
||||
\array_unshift($aProperties, new Property($iType, $sValue, \implode(',', $aTypes)));
|
||||
}
|
||||
else
|
||||
{
|
||||
\array_push($aProperties, new Property($iType, $sValue, \implode(',', $aTypes)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function PopulateByVCard($sVCard, $sEtag = '')
|
||||
{
|
||||
$this->Properties = array();
|
||||
|
||||
if (!empty($sEtag))
|
||||
{
|
||||
$this->Etag = $sEtag;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$oVCard = \Sabre\VObject\Reader::read($sVCard);
|
||||
}
|
||||
catch (\Exception $oExc) {};
|
||||
|
||||
$aProperties = array();
|
||||
if ($oVCard)
|
||||
{
|
||||
$bOldVersion = empty($oVCard->VERSION) ? false :
|
||||
$bOldVersion = empty($oVCard->VERSION) ? false :
|
||||
\in_array((string) $oVCard->VERSION, array('2.1', '2.0', '1.0'));
|
||||
|
||||
$this->IdContactStr = !empty($oVCard->UID) ? (string) $oVCard->UID : \Sabre\DAV\UUIDUtil::getUUID();
|
||||
$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);
|
||||
$sValue = $this->getPropertyValueHelper($oVCard->FN, $bOldVersion);
|
||||
$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);
|
||||
$sValue = $sValue = $this->getPropertyValueHelper($oVCard->NICKNAME, $bOldVersion);
|
||||
$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);
|
||||
// $sValue = $this->getPropertyValueHelper($oVCard->NOTE, $bOldVersion);
|
||||
// $aProperties[] = new Property(PropertyType::NOTE, $sValue);
|
||||
// }
|
||||
|
||||
|
|
@ -302,244 +401,22 @@ class Contact
|
|||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->addArrayPropertyHelper(&$aProperties, $oVCard->EMAIL, PropertyType::EMAIl);
|
||||
}
|
||||
|
||||
if (isset($oVCard->URL))
|
||||
{
|
||||
$this->addArrayPropertyHelper(&$aProperties, $oVCard->URL, PropertyType::WEB_PAGE);
|
||||
}
|
||||
|
||||
// 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->addArrayPropertyHelper(&$aProperties, $oVCard->TEL, PropertyType::PHONE);
|
||||
}
|
||||
|
||||
|
||||
$this->Properties = $aProperties;
|
||||
}
|
||||
|
||||
$this->UpdateDependentValues(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function ToVCardObject($sPreVCard = '')
|
||||
{
|
||||
$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\AddressBook\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';
|
||||
$this->UpdateDependentValues();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class Property
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $TypeCustom;
|
||||
public $TypeStr;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
|
|
@ -37,12 +37,13 @@ class Property
|
|||
public $Frec;
|
||||
|
||||
public function __construct(
|
||||
$iType = \RainLoop\Providers\AddressBook\Enumerations\PropertyType::UNKNOWN, $sValue = '')
|
||||
$iType = \RainLoop\Providers\AddressBook\Enumerations\PropertyType::UNKNOWN, $sValue = '', $sTypeStr = '')
|
||||
{
|
||||
$this->Clear();
|
||||
|
||||
$this->Type = $iType;
|
||||
$this->Value = $sValue;
|
||||
$this->TypeStr = $sTypeStr;
|
||||
}
|
||||
|
||||
public function Clear()
|
||||
|
|
@ -50,7 +51,7 @@ class Property
|
|||
$this->IdProperty = 0;
|
||||
|
||||
$this->Type = PropertyType::UNKNOWN;
|
||||
$this->TypeCustom = '';
|
||||
$this->TypeStr = '';
|
||||
|
||||
$this->Value = '';
|
||||
$this->ValueCustom = '';
|
||||
|
|
@ -63,9 +64,7 @@ class Property
|
|||
*/
|
||||
public function IsEmail()
|
||||
{
|
||||
return \in_array($this->Type, array(
|
||||
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER
|
||||
));
|
||||
return PropertyType::EMAIl === $this->Type;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -73,18 +72,29 @@ class Property
|
|||
*/
|
||||
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
|
||||
));
|
||||
return PropertyType::PHONE === $this->Type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function TypesAsArray()
|
||||
{
|
||||
$aResult = array();
|
||||
if (!empty($this->TypeStr))
|
||||
{
|
||||
$sTypeStr = \preg_replace('/[\s]+/', '', $this->TypeStr);
|
||||
$aResult = \explode(',', $sTypeStr);
|
||||
}
|
||||
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
public function UpdateDependentValues()
|
||||
{
|
||||
$this->Value = \trim($this->Value);
|
||||
$this->ValueCustom = \trim($this->ValueCustom);
|
||||
$this->TypeCustom = \trim($this->TypeCustom);
|
||||
$this->TypeStr = \trim($this->TypeStr);
|
||||
|
||||
if (0 < \strlen($this->Value))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,21 +16,11 @@ class PropertyType
|
|||
const NAME_PREFIX = 20;
|
||||
const NAME_SUFFIX = 21;
|
||||
|
||||
const EMAIl_PERSONAL = 30;
|
||||
const EMAIl_BUSSINES = 31;
|
||||
const EMAIl_OTHER = 32;
|
||||
|
||||
const PHONE_PERSONAL = 50;
|
||||
const PHONE_BUSSINES = 51;
|
||||
const PHONE_OTHER = 52;
|
||||
|
||||
const MOBILE_PERSONAL = 60;
|
||||
const MOBILE_BUSSINES = 61;
|
||||
const MOBILE_OTHER = 62;
|
||||
|
||||
const FAX_PERSONAL = 70;
|
||||
const FAX_BUSSINES = 71;
|
||||
const FAX_OTHER = 72;
|
||||
const EMAIl = 30;
|
||||
const PHONE = 31;
|
||||
// const MOBILE = 32;
|
||||
// const FAX = 33;
|
||||
const WEB_PAGE = 32;
|
||||
|
||||
const FACEBOOK = 90;
|
||||
const SKYPE = 91;
|
||||
|
|
@ -38,9 +28,5 @@ class PropertyType
|
|||
|
||||
const NOTE = 110;
|
||||
|
||||
const WEB_PAGE_PERSONAL = 220;
|
||||
const WEB_PAGE_BUSSINES = 221;
|
||||
const WEB_PAGE_OTHER = 222;
|
||||
|
||||
const CUSTOM = 250;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\Providers\AddressBook\Enumerations;
|
||||
|
||||
class ScopeType
|
||||
{
|
||||
const DEFAULT_ = 0;
|
||||
const SHARE_ALL = 2;
|
||||
}
|
||||
|
|
@ -47,15 +47,335 @@ class PdoAddressBook
|
|||
return \is_array($aDrivers) ? \in_array($this->sDsnType, $aDrivers) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function IsSharingAllowed()
|
||||
{
|
||||
return $this->IsSupported() && false; // TODO
|
||||
}
|
||||
|
||||
private function flushDeletedContacts($iUserID)
|
||||
{
|
||||
return !!$this->prepareAndExecute('DELETE FROM rainloop_ab_contacts WHERE id_user = :id_user AND deleted = 1', array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT)
|
||||
));
|
||||
}
|
||||
|
||||
private function updateContactEtagAndTime($iUserID, $mID, $sEtag, $iChanged)
|
||||
{
|
||||
return !!$this->prepareAndExecute('UPDATE rainloop_ab_contacts SET changed = :changed, etag = :etag '.
|
||||
'WHERE id_user = :id_user AND id_contact = :id_contact', array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT),
|
||||
':id_contact' => array($mID, \PDO::PARAM_INT),
|
||||
':changed' => array($iChanged, \PDO::PARAM_INT),
|
||||
':etag' => array($sEtag, \PDO::PARAM_STR)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function prepearDatabaseSyncData($iUserID)
|
||||
{
|
||||
$aResult = array();
|
||||
$oStmt = $this->prepareAndExecute('SELECT id_contact, id_contact_str, changed, deleted, etag FROM rainloop_ab_contacts WHERE id_user = :id_user', 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 && isset($aItem['id_contact'], $aItem['id_contact_str'], $aItem['changed'], $aItem['deleted'], $aItem['etag']) &&
|
||||
!empty($aItem['id_contact_str']))
|
||||
{
|
||||
$aResult[$aItem['id_contact_str']] = array(
|
||||
'id_contact' => $aItem['id_contact'],
|
||||
'etag' => $aItem['etag'],
|
||||
'changed' => (int) $aItem['changed'],
|
||||
'deleted' => '1' === (string) $aItem['deleted']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
private function prepearRemoteSyncData($oClient, $sPath)
|
||||
{
|
||||
$mResult = false;
|
||||
$aResponse = null;
|
||||
try
|
||||
{
|
||||
$this->oLogger->Write('PROPFIND '.$sPath, \MailSo\Log\Enumerations\Type::INFO, 'DAV');
|
||||
$aResponse = $oClient->propFind($sPath, array(
|
||||
'{DAV:}getlastmodified',
|
||||
'{DAV:}getetag'
|
||||
), 1);
|
||||
|
||||
}
|
||||
catch (\Exception $oException)
|
||||
{
|
||||
$this->oLogger->WriteException($oException);
|
||||
}
|
||||
|
||||
if (\is_array($aResponse))
|
||||
{
|
||||
$mResult = array();
|
||||
foreach ($aResponse as $sKey => $aItem)
|
||||
{
|
||||
$sKey = \rtrim(\trim($sKey), '\\/');
|
||||
if (!empty($sKey) && is_array($aItem))
|
||||
{
|
||||
$aItem = \array_change_key_case($aItem, \CASE_LOWER);
|
||||
if (isset($aItem['{dav:}getetag'], $aItem['{dav:}getlastmodified']))
|
||||
{
|
||||
$aMatch = array();
|
||||
if (\preg_match('/\/([^\/?]+)$/', $sKey, $aMatch) && !empty($aMatch[1]))
|
||||
{
|
||||
$sVcfFileName = $aMatch[1];
|
||||
$sKeyID = \preg_replace('/\.vcf$/i', '', $sVcfFileName);
|
||||
|
||||
$mResult[$sKeyID] = array(
|
||||
'vcf' => $sVcfFileName,
|
||||
'etag' => \trim(\trim($aItem['{dav:}getetag']), '"\''),
|
||||
'lastmodified' => $aItem['{dav:}getlastmodified'],
|
||||
'changed' => \MailSo\Base\DateTimeHelper::ParseRFC2822DateString($aItem['{dav:}getlastmodified']),
|
||||
'deleted' => false
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $mResult;
|
||||
}
|
||||
|
||||
private function davClientRequest($oClient, $sCmd, $sUrl, $mData = null)
|
||||
{
|
||||
\MailSo\Base\Utils::ResetTimeLimit($this->iResetTimer);
|
||||
|
||||
$this->oLogger->Write($sCmd.' '.$sUrl.('PUT' === $sCmd && null !== $mData ? ' ('.\strlen($mData).')' : ''),
|
||||
\MailSo\Log\Enumerations\Type::INFO, 'DAV');
|
||||
|
||||
if ('PUT' === $sCmd)
|
||||
{
|
||||
$this->oLogger->Write($mData, \MailSo\Log\Enumerations\Type::INFO, 'DAV');
|
||||
}
|
||||
|
||||
$oResponse = false;
|
||||
try
|
||||
{
|
||||
$oResponse = 'PUT' === $sCmd && null !== $mData ?
|
||||
$oClient->request($sCmd, $sUrl, $mData) : $oClient->request($sCmd, $sUrl);
|
||||
|
||||
if ('GET' === $sCmd || false)
|
||||
{
|
||||
$this->oLogger->WriteDump($oResponse, \MailSo\Log\Enumerations\Type::INFO, 'DAV');
|
||||
}
|
||||
}
|
||||
catch (\Exception $oException)
|
||||
{
|
||||
$this->oLogger->WriteException($oException);
|
||||
}
|
||||
|
||||
return $oResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sEmail
|
||||
* @param \RainLoop\Providers\AddressBook\Classes\Contact $oContact
|
||||
* @param string $sUrl
|
||||
* @param string $sUser
|
||||
* @param string $sPassword
|
||||
* @param string $sProxy = ''
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ContactSave($sEmail, &$oContact)
|
||||
public function Sync($sEmail, $sUrl, $sUser, $sPassword, $sProxy = '')
|
||||
{
|
||||
$this->Sync();
|
||||
$this->SyncDatabase();
|
||||
|
||||
$iUserID = $this->getUserId($sEmail);
|
||||
if (0 >= $iUserID)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$aUrl = \parse_url($sUrl);
|
||||
if (!\is_array($aUrl))
|
||||
{
|
||||
$aUrl = array();
|
||||
}
|
||||
|
||||
$aUrl['scheme'] = isset($aUrl['scheme']) ? $aUrl['scheme'] : 'http';
|
||||
$aUrl['host'] = isset($aUrl['host']) ? $aUrl['host'] : 'localhost';
|
||||
$aUrl['port'] = isset($aUrl['port']) ? $aUrl['port'] : 80;
|
||||
$aUrl['path'] = isset($aUrl['path']) ? \rtrim($aUrl['path'], '\\/').'/' : '/';
|
||||
|
||||
$aSettings = array(
|
||||
'baseUri' => $aUrl['scheme'].'://'.$aUrl['host'].('80' === (string) $aUrl['port'] ? '' : ':'.$aUrl['port']),
|
||||
'userName' => $sUser,
|
||||
'password' => $sPassword
|
||||
);
|
||||
|
||||
if (!empty($sProxy))
|
||||
{
|
||||
$aSettings['proxy'] = $sProxy;
|
||||
}
|
||||
|
||||
$sPath = $aUrl['path'];
|
||||
|
||||
$oClient = new \Sabre\DAV\Client($aSettings);
|
||||
$oClient->setVerifyPeer(false);
|
||||
|
||||
$aRemoteSyncData = $this->prepearRemoteSyncData($oClient, $sPath);
|
||||
if (false === $aRemoteSyncData)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$aDatabaseSyncData = $this->prepearDatabaseSyncData($iUserID);
|
||||
|
||||
// $this->oLogger->WriteDump($aDatabaseSyncData);
|
||||
// $this->oLogger->WriteDump($aRemoteSyncData);
|
||||
|
||||
//+++del (from carddav)
|
||||
foreach ($aDatabaseSyncData as $sKey => $aData)
|
||||
{
|
||||
if ($aData['deleted'] &&
|
||||
isset($aRemoteSyncData[$sKey], $aRemoteSyncData[$sKey]['vcf']))
|
||||
{
|
||||
$this->davClientRequest($oClient, 'DELETE', $sPath.$aRemoteSyncData[$sKey]['vcf']);
|
||||
}
|
||||
}
|
||||
//---del
|
||||
|
||||
//+++del (from db)
|
||||
$aIdsForDeletedion = array();
|
||||
foreach ($aDatabaseSyncData as $sKey => $aData)
|
||||
{
|
||||
if (!$aData['deleted'] && !empty($aData['etag']) && !isset($aRemoteSyncData[$sKey]))
|
||||
{
|
||||
$aIdsForDeletedion[] = $aData['id_contact'];
|
||||
}
|
||||
}
|
||||
|
||||
if (0 < \count($aIdsForDeletedion))
|
||||
{
|
||||
$this->DeleteContacts($sEmail, $aIdsForDeletedion, false);
|
||||
}
|
||||
//---del
|
||||
|
||||
$this->flushDeletedContacts($iUserID);
|
||||
|
||||
//+++new or newer (from db)
|
||||
foreach ($aDatabaseSyncData as $sKey => $aData)
|
||||
{
|
||||
if (!$aData['deleted'] &&
|
||||
(empty($aData['etag']) && !isset($aRemoteSyncData[$sKey])) // new
|
||||
||
|
||||
(!empty($aData['etag']) && isset($aRemoteSyncData[$sKey]) && // newer
|
||||
$aRemoteSyncData[$sKey]['etag'] !== $aData['etag'] &&
|
||||
$aRemoteSyncData[$sKey]['changed'] < $aData['changed']
|
||||
)
|
||||
)
|
||||
{
|
||||
$mID = $aData['id_contact'];
|
||||
$oContact = $this->GetContactByID($sEmail, $mID, false);
|
||||
if ($oContact)
|
||||
{
|
||||
$sExsistensBody = '';
|
||||
$mExsistenRemoteID = isset($aRemoteSyncData[$sKey]['vcf']) && !empty($aData['etag']) ? $aRemoteSyncData[$sKey]['vcf'] : '';
|
||||
if (0 < \strlen($mExsistenRemoteID))
|
||||
{
|
||||
$oResponse = $this->davClientRequest($oClient, 'GET', $sPath.$mExsistenRemoteID);
|
||||
if ($oResponse && isset($oResponse['headers'], $oResponse['body']))
|
||||
{
|
||||
$sExsistensBody = \trim($oResponse['body']);
|
||||
}
|
||||
}
|
||||
|
||||
$oResponse = $this->davClientRequest($oClient, 'PUT',
|
||||
$sPath.$oContact->CardDavNameUri(), $oContact->ToVCard($sExsistensBody));
|
||||
|
||||
if ($oResponse && isset($oResponse['headers'], $oResponse['headers']['etag']))
|
||||
{
|
||||
$sEtag = \trim(\trim($oResponse['headers']['etag']), '"\'');
|
||||
$sDate = !empty($oResponse['headers']['date']) ? \trim($oResponse['headers']['date']) : '';
|
||||
if (!empty($sEtag))
|
||||
{
|
||||
$iChanged = empty($sDate) ? \time() : \MailSo\Base\DateTimeHelper::ParseRFC2822DateString($sDate);
|
||||
$this->updateContactEtagAndTime($iUserID, $mID, $sEtag, $iChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unset($oContact);
|
||||
}
|
||||
}
|
||||
//---new
|
||||
|
||||
//+++new or newer (from carddav)
|
||||
foreach ($aRemoteSyncData as $sKey => $aData)
|
||||
{
|
||||
if (!isset($aDatabaseSyncData[$sKey]) // new
|
||||
||
|
||||
($aDatabaseSyncData[$sKey]['etag'] !== $aData['etag'] && // newer
|
||||
$aDatabaseSyncData[$sKey]['changed'] < $aData['changed'])
|
||||
)
|
||||
{
|
||||
$mExsistenContactID = isset($aDatabaseSyncData[$sKey]['id_contact']) ?
|
||||
$aDatabaseSyncData[$sKey]['id_contact'] : '';
|
||||
|
||||
$oResponse = $this->davClientRequest($oClient, 'GET', $sPath.$aData['vcf']);
|
||||
if ($oResponse && isset($oResponse['headers'], $oResponse['body']))
|
||||
{
|
||||
$sBody = \trim($oResponse['body']);
|
||||
if (!empty($sBody))
|
||||
{
|
||||
$oContact = null;
|
||||
if ($mExsistenContactID)
|
||||
{
|
||||
$oContact = $this->GetContactByID($sEmail, $mExsistenContactID);
|
||||
}
|
||||
|
||||
if (!$oContact)
|
||||
{
|
||||
$oContact = new \RainLoop\Providers\AddressBook\Classes\Contact();
|
||||
}
|
||||
|
||||
$oContact->PopulateByVCard($sBody,
|
||||
!empty($oResponse['headers']['etag']) ? \trim(\trim($oResponse['headers']['etag']), '"\'') : '');
|
||||
|
||||
$this->ContactSave($sEmail, $oContact);
|
||||
unset($oContact);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sEmail
|
||||
* @param \RainLoop\Providers\AddressBook\Classes\Contact $oContact
|
||||
* @param bool $bSyncDb = true
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ContactSave($sEmail, &$oContact, $bSyncDb = true)
|
||||
{
|
||||
if ($bSyncDb)
|
||||
{
|
||||
$this->SyncDatabase();
|
||||
}
|
||||
|
||||
$iUserID = $this->getUserId($sEmail);
|
||||
|
||||
$iIdContact = 0 < \strlen($oContact->IdContact) && \is_numeric($oContact->IdContact) ? (int) $oContact->IdContact : 0;
|
||||
|
|
@ -77,7 +397,7 @@ class PdoAddressBook
|
|||
{
|
||||
$aFreq = $this->getContactFreq($iUserID, $iIdContact);
|
||||
|
||||
$sSql = 'UPDATE rainloop_ab_contacts SET id_contact_str = :id_contact_str, display = :display, changed = :changed, hash = :hash '.
|
||||
$sSql = 'UPDATE rainloop_ab_contacts SET id_contact_str = :id_contact_str, display = :display, changed = :changed, etag = :etag '.
|
||||
'WHERE id_user = :id_user AND id_contact = :id_contact';
|
||||
|
||||
$this->prepareAndExecute($sSql,
|
||||
|
|
@ -87,7 +407,7 @@ class PdoAddressBook
|
|||
':id_contact_str' => array($oContact->IdContactStr, \PDO::PARAM_STR),
|
||||
':display' => array($oContact->Display, \PDO::PARAM_STR),
|
||||
':changed' => array($oContact->Changed, \PDO::PARAM_INT),
|
||||
':hash' => array($oContact->Hash, \PDO::PARAM_STR)
|
||||
':etag' => array($oContact->Etag, \PDO::PARAM_STR)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
@ -103,8 +423,8 @@ class PdoAddressBook
|
|||
else
|
||||
{
|
||||
$sSql = 'INSERT INTO rainloop_ab_contacts '.
|
||||
'( id_user, id_contact_str, display, changed, hash) VALUES '.
|
||||
'(:id_user, :id_contact_str, :display, :changed, :hash)';
|
||||
'( id_user, id_contact_str, display, changed, etag) VALUES '.
|
||||
'(:id_user, :id_contact_str, :display, :changed, :etag)';
|
||||
|
||||
$this->prepareAndExecute($sSql,
|
||||
array(
|
||||
|
|
@ -112,11 +432,11 @@ class PdoAddressBook
|
|||
':id_contact_str' => array($oContact->IdContactStr, \PDO::PARAM_STR),
|
||||
':display' => array($oContact->Display, \PDO::PARAM_STR),
|
||||
':changed' => array($oContact->Changed, \PDO::PARAM_INT),
|
||||
':hash' => array($oContact->Hash, \PDO::PARAM_STR)
|
||||
':etag' => array($oContact->Etag, \PDO::PARAM_STR)
|
||||
)
|
||||
);
|
||||
|
||||
$sLast = $this->lastInsertId('id_contact');
|
||||
$sLast = $this->lastInsertId('rainloop_ab_contacts', 'id_contact');
|
||||
if (\is_numeric($sLast) && 0 < (int) $sLast)
|
||||
{
|
||||
$iIdContact = (int) $sLast;
|
||||
|
|
@ -139,7 +459,7 @@ class PdoAddressBook
|
|||
':id_contact' => array($iIdContact, \PDO::PARAM_INT),
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT),
|
||||
':prop_type' => array($oProp->Type, \PDO::PARAM_INT),
|
||||
':prop_type_custom' => array($oProp->TypeCustom, \PDO::PARAM_STR),
|
||||
':prop_type_str' => array($oProp->TypeStr, \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),
|
||||
|
|
@ -147,8 +467,8 @@ class PdoAddressBook
|
|||
}
|
||||
|
||||
$sSql = 'INSERT INTO rainloop_ab_properties '.
|
||||
'( id_contact, id_user, prop_type, prop_type_custom, prop_value, prop_value_custom, prop_frec) VALUES '.
|
||||
'(:id_contact, :id_user, :prop_type, :prop_type_custom, :prop_value, :prop_value_custom, :prop_frec)';
|
||||
'( id_contact, id_user, prop_type, prop_type_str, prop_value, prop_value_custom, prop_frec) VALUES '.
|
||||
'(:id_contact, :id_user, :prop_type, :prop_type_str, :prop_value, :prop_value_custom, :prop_frec)';
|
||||
|
||||
$this->prepareAndExecute($sSql, $aParams, true);
|
||||
}
|
||||
|
|
@ -174,12 +494,17 @@ class PdoAddressBook
|
|||
/**
|
||||
* @param string $sEmail
|
||||
* @param array $aContactIds
|
||||
* @param bool $bSyncDb = true
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function DeleteContacts($sEmail, $aContactIds)
|
||||
public function DeleteContacts($sEmail, $aContactIds, $bSyncDb = true)
|
||||
{
|
||||
$this->Sync();
|
||||
if ($bSyncDb)
|
||||
{
|
||||
$this->SyncDatabase();
|
||||
}
|
||||
|
||||
$iUserID = $this->getUserId($sEmail);
|
||||
|
||||
$aContactIds = \array_filter($aContactIds, function (&$mItem) {
|
||||
|
|
@ -196,7 +521,44 @@ class PdoAddressBook
|
|||
$aParams = array(':id_user' => array($iUserID, \PDO::PARAM_INT));
|
||||
|
||||
$this->prepareAndExecute('DELETE FROM rainloop_ab_properties WHERE id_user = :id_user AND id_contact IN ('.$sIDs.')', $aParams);
|
||||
$this->prepareAndExecute('DELETE FROM rainloop_ab_contacts WHERE id_user = :id_user AND id_contact IN ('.$sIDs.')', $aParams);
|
||||
|
||||
$aParams = array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT),
|
||||
':changed' => array(\time(), \PDO::PARAM_INT)
|
||||
);
|
||||
|
||||
$this->prepareAndExecute('UPDATE rainloop_ab_contacts SET deleted = 1, changed = :changed '.
|
||||
'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->SyncDatabase();
|
||||
$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;
|
||||
}
|
||||
|
|
@ -212,7 +574,7 @@ class PdoAddressBook
|
|||
*/
|
||||
public function GetContacts($sEmail, $iOffset = 0, $iLimit = 20, $sSearch = '', &$iResultCount = 0)
|
||||
{
|
||||
$this->Sync();
|
||||
$this->SyncDatabase();
|
||||
|
||||
$iOffset = 0 <= $iOffset ? $iOffset : 0;
|
||||
$iLimit = 0 < $iLimit ? (int) $iLimit : 20;
|
||||
|
|
@ -235,11 +597,7 @@ class PdoAddressBook
|
|||
|
||||
$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 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)' : '').
|
||||
(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(
|
||||
|
|
@ -297,7 +655,7 @@ class PdoAddressBook
|
|||
|
||||
if (0 < $iCount)
|
||||
{
|
||||
$sSql = 'SELECT * FROM rainloop_ab_contacts WHERE id_user = :id_user';
|
||||
$sSql = 'SELECT * FROM rainloop_ab_contacts WHERE deleted = 0 AND id_user = :id_user';
|
||||
|
||||
$aParams = array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT)
|
||||
|
|
@ -367,7 +725,7 @@ class PdoAddressBook
|
|||
$oProperty = new \RainLoop\Providers\AddressBook\Classes\Property();
|
||||
$oProperty->IdProperty = (int) $aItem['id_prop'];
|
||||
$oProperty->Type = (int) $aItem['prop_type'];
|
||||
$oProperty->TypeCustom = isset($aItem['prop_type_custom']) ? (string) $aItem['prop_type_custom'] : '';
|
||||
$oProperty->TypeStr = isset($aItem['prop_type_str']) ? (string) $aItem['prop_type_str'] : '';
|
||||
$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;
|
||||
|
|
@ -403,13 +761,11 @@ class PdoAddressBook
|
|||
*/
|
||||
public function GetContactByID($sEmail, $mID, $bIsStrID = false)
|
||||
{
|
||||
$this->Sync();
|
||||
|
||||
$mID = \trim($mID);
|
||||
|
||||
$iUserID = $this->getUserId($sEmail);
|
||||
|
||||
$sSql = 'SELECT * FROM rainloop_ab_contacts WHERE id_user = :id_user';
|
||||
$sSql = 'SELECT * FROM rainloop_ab_contacts WHERE deleted = 0 AND id_user = :id_user';
|
||||
|
||||
$aParams = array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT)
|
||||
|
|
@ -450,7 +806,7 @@ class PdoAddressBook
|
|||
$oContact->Display = isset($aItem['display']) ? (string) $aItem['display'] : '';
|
||||
$oContact->Changed = isset($aItem['changed']) ? (int) $aItem['changed'] : 0;
|
||||
$oContact->ReadOnly = $iUserID !== (isset($aItem['id_user']) ? (int) $aItem['id_user'] : 0);
|
||||
$oContact->Hash = empty($aItem['hash']) ? '' : (string) $aItem['hash'];
|
||||
$oContact->Etag = empty($aItem['etag']) ? '' : (string) $aItem['etag'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -478,7 +834,7 @@ class PdoAddressBook
|
|||
$oProperty = new \RainLoop\Providers\AddressBook\Classes\Property();
|
||||
$oProperty->IdProperty = (int) $aItem['id_prop'];
|
||||
$oProperty->Type = (int) $aItem['prop_type'];
|
||||
$oProperty->TypeCustom = isset($aItem['prop_type_custom']) ? (string) $aItem['prop_type_custom'] : '';
|
||||
$oProperty->TypeStr = isset($aItem['prop_type_str']) ? (string) $aItem['prop_type_str'] : '';
|
||||
$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;
|
||||
|
|
@ -516,12 +872,12 @@ class PdoAddressBook
|
|||
throw new \InvalidArgumentException('Empty Search argument');
|
||||
}
|
||||
|
||||
$this->Sync();
|
||||
$this->SyncDatabase();
|
||||
|
||||
$iUserID = $this->getUserId($sEmail);
|
||||
|
||||
$sTypes = implode(',', array(
|
||||
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER, PropertyType::FIRST_NAME, PropertyType::LAST_NAME
|
||||
PropertyType::EMAIl, PropertyType::FIRST_NAME, PropertyType::LAST_NAME
|
||||
));
|
||||
|
||||
$sSql = 'SELECT id_contact, id_prop, prop_type, prop_value FROM rainloop_ab_properties '.
|
||||
|
|
@ -575,7 +931,7 @@ class PdoAddressBook
|
|||
$oStmt->closeCursor();
|
||||
|
||||
$sTypes = \implode(',', array(
|
||||
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER, PropertyType::FIRST_NAME, PropertyType::LAST_NAME
|
||||
PropertyType::EMAIl, PropertyType::FIRST_NAME, PropertyType::LAST_NAME
|
||||
));
|
||||
|
||||
$sSql = 'SELECT id_prop, id_contact, prop_type, prop_value FROM rainloop_ab_properties '.
|
||||
|
|
@ -607,8 +963,8 @@ class PdoAddressBook
|
|||
|
||||
$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)))
|
||||
else if ((isset($aIdProps[$iIdProp]) || isset($aContactAllAccess[$iIdContact])) &&
|
||||
PropertyType::EMAIl === $iType)
|
||||
{
|
||||
if (!isset($aEmails[$iIdContact]))
|
||||
{
|
||||
|
|
@ -676,22 +1032,19 @@ class PdoAddressBook
|
|||
throw new \InvalidArgumentException('Empty Emails argument');
|
||||
}
|
||||
|
||||
$this->Sync();
|
||||
$this->SyncDatabase();
|
||||
$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_ab_properties WHERE id_user = :id_user AND prop_type IN ('.$sTypes.')';
|
||||
$sSql = 'SELECT prop_value FROM rainloop_ab_properties WHERE id_user = :id_user AND prop_type = :prop_type';
|
||||
$oStmt = $this->prepareAndExecute($sSql, array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT)
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT),
|
||||
':prop_type' => array(PropertyType::EMAIl, \PDO::PARAM_INT)
|
||||
));
|
||||
|
||||
if ($oStmt)
|
||||
|
|
@ -748,7 +1101,7 @@ class PdoAddressBook
|
|||
if ('' !== \trim($oEmail->GetEmail()))
|
||||
{
|
||||
$oPropEmail = new \RainLoop\Providers\AddressBook\Classes\Property();
|
||||
$oPropEmail->Type = \RainLoop\Providers\AddressBook\Enumerations\PropertyType::EMAIl_PERSONAL;
|
||||
$oPropEmail->Type = \RainLoop\Providers\AddressBook\Enumerations\PropertyType::EMAIl;
|
||||
$oPropEmail->Value = \strtolower(\trim($oEmail->GetEmail()));
|
||||
|
||||
$oContact->Properties[] = $oPropEmail;
|
||||
|
|
@ -797,7 +1150,7 @@ class PdoAddressBook
|
|||
}
|
||||
}
|
||||
|
||||
$sSql = 'UPDATE rainloop_ab_properties SET prop_frec = prop_frec + 1 WHERE id_user = :id_user AND prop_type IN ('.$sTypes;
|
||||
$sSql = 'UPDATE rainloop_ab_properties SET prop_frec = prop_frec + 1 WHERE id_user = :id_user AND prop_type = :prop_type';
|
||||
|
||||
$aEmailsQuoted = \array_map(function ($mItem) use ($self) {
|
||||
return $self->quoteValue($mItem);
|
||||
|
|
@ -805,15 +1158,16 @@ class PdoAddressBook
|
|||
|
||||
if (1 === \count($aEmailsQuoted))
|
||||
{
|
||||
$sSql .= ') AND prop_value = '.$aEmailsQuoted[0];
|
||||
$sSql .= ' AND prop_value = '.$aEmailsQuoted[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSql .= ') AND prop_value IN ('.\implode(',', $aEmailsQuoted).')';
|
||||
$sSql .= ' AND prop_value IN ('.\implode(',', $aEmailsQuoted).')';
|
||||
}
|
||||
|
||||
|
||||
return !!$this->prepareAndExecute($sSql, array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT),
|
||||
':prop_type' => array(PropertyType::EMAIl, \PDO::PARAM_INT)
|
||||
));
|
||||
}
|
||||
|
||||
|
|
@ -825,7 +1179,7 @@ class PdoAddressBook
|
|||
$sResult = '';
|
||||
try
|
||||
{
|
||||
$this->Sync();
|
||||
$this->SyncDatabase();
|
||||
if (0 >= $this->getVersion($this->sDsnType.'-ab-version'))
|
||||
{
|
||||
$sResult = 'Unknown database error';
|
||||
|
|
@ -857,14 +1211,13 @@ class PdoAddressBook
|
|||
|
||||
CREATE TABLE IF NOT EXISTS rainloop_ab_contacts (
|
||||
|
||||
id_contact bigint UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
id_contact_str varchar(128) NOT NULL DEFAULT \'\',
|
||||
id_user int UNSIGNED NOT NULL,
|
||||
display_name varchar(255) NOT NULL DEFAULT '',
|
||||
display_email varchar(255) NOT NULL DEFAULT '',
|
||||
display varchar(255) NOT NULL DEFAULT '',
|
||||
changed int UNSIGNED NOT NULL DEFAULT 0,
|
||||
hash varchar(128) NOT NULL DEFAULT \'\',
|
||||
id_contact bigint UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
id_contact_str varchar(128) NOT NULL DEFAULT '',
|
||||
id_user int UNSIGNED NOT NULL,
|
||||
display varchar(255) NOT NULL DEFAULT '',
|
||||
changed int UNSIGNED NOT NULL DEFAULT 0,
|
||||
deleted tinyint UNSIGNED NOT NULL DEFAULT 0,
|
||||
etag varchar(128) /*!40101 CHARACTER SET ascii COLLATE ascii_general_ci */ NOT NULL DEFAULT '',
|
||||
|
||||
PRIMARY KEY(id_contact),
|
||||
INDEX id_user_rainloop_ab_contacts_index (id_user)
|
||||
|
|
@ -873,20 +1226,42 @@ CREATE TABLE IF NOT EXISTS rainloop_ab_contacts (
|
|||
|
||||
CREATE TABLE IF NOT EXISTS rainloop_ab_properties (
|
||||
|
||||
id_prop bigint UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
id_contact bigint UNSIGNED NOT NULL,
|
||||
id_user int UNSIGNED NOT NULL,
|
||||
prop_type tinyint UNSIGNED NOT NULL,
|
||||
prop_type_custom varchar(50) /*!40101 CHARACTER SET ascii COLLATE ascii_general_ci */ NOT NULL DEFAULT '',
|
||||
prop_value varchar(255) NOT NULL DEFAULT '',
|
||||
prop_value_custom varchar(255) NOT NULL DEFAULT '',
|
||||
prop_frec int UNSIGNED NOT NULL DEFAULT 0,
|
||||
id_prop bigint UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
id_contact bigint UNSIGNED NOT NULL,
|
||||
id_user int UNSIGNED NOT NULL,
|
||||
prop_type tinyint UNSIGNED NOT NULL,
|
||||
prop_type_str varchar(255) /*!40101 CHARACTER SET ascii COLLATE ascii_general_ci */ NOT NULL DEFAULT '',
|
||||
prop_value varchar(255) NOT NULL DEFAULT '',
|
||||
prop_value_custom varchar(255) NOT NULL DEFAULT '',
|
||||
prop_frec int UNSIGNED NOT NULL DEFAULT 0,
|
||||
|
||||
PRIMARY KEY(id_prop),
|
||||
INDEX id_user_rainloop_ab_properties_index (id_user),
|
||||
INDEX id_user_id_contact_rainloop_ab_properties_index (id_user, id_contact)
|
||||
|
||||
)/*!40000 ENGINE=INNODB *//*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS rainloop_ab_tags (
|
||||
|
||||
id_tag int UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
id_user int UNSIGNED NOT NULL,
|
||||
tag_name varchar(255) NOT NULL,
|
||||
|
||||
PRIMARY KEY(id_tag),
|
||||
INDEX id_user_rainloop_ab_tags_index (id_user),
|
||||
INDEX id_user_name_rainloop_ab_tags_index (id_user, tag_name)
|
||||
|
||||
)/*!40000 ENGINE=INNODB *//*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS rainloop_ab_tags_contacts (
|
||||
|
||||
id_tag int UNSIGNED NOT NULL,
|
||||
id_contact bigint UNSIGNED NOT NULL,
|
||||
|
||||
INDEX id_tag_rainloop_ab_tags_contacts_index (id_tag),
|
||||
INDEX id_contact_rainloop_ab_tags_contacts_index (id_contact)
|
||||
|
||||
)/*!40000 ENGINE=INNODB */;
|
||||
MYSQLINITIAL;
|
||||
break;
|
||||
|
||||
|
|
@ -894,31 +1269,48 @@ MYSQLINITIAL;
|
|||
$sInitial = <<<POSTGRESINITIAL
|
||||
|
||||
CREATE TABLE rainloop_ab_contacts (
|
||||
id_contact bigserial PRIMARY KEY,
|
||||
id_user integer NOT NULL,
|
||||
display_name varchar(128) NOT NULL DEFAULT '',
|
||||
display_email varchar(128) NOT NULL DEFAULT '',
|
||||
display varchar(128) NOT NULL DEFAULT '',
|
||||
changed integer NOT NULL default 0.
|
||||
hash varchar(128) NOT NULL DEFAULT ''
|
||||
id_contact bigserial PRIMARY KEY,
|
||||
id_contact_str varchar(128) NOT NULL DEFAULT '',
|
||||
id_user integer NOT NULL,
|
||||
display varchar(255) NOT NULL DEFAULT '',
|
||||
changed integer NOT NULL default 0,
|
||||
deleted integer NOT NULL default 0,
|
||||
etag varchar(128) NOT NULL DEFAULT ''
|
||||
);
|
||||
|
||||
CREATE INDEX id_user_rainloop_ab_contacts_index ON rainloop_ab_contacts (id_user);
|
||||
|
||||
CREATE TABLE rainloop_ab_properties (
|
||||
id_prop bigserial PRIMARY KEY,
|
||||
id_contact integer NOT NULL,
|
||||
id_user integer NOT NULL,
|
||||
prop_type integer NOT NULL,
|
||||
prop_type_custom varchar(50) NOT NULL DEFAULT '',
|
||||
prop_value varchar(128) NOT NULL DEFAULT '',
|
||||
prop_value_custom varchar(128) NOT NULL DEFAULT '',
|
||||
prop_frec integer NOT NULL default 0
|
||||
id_prop bigserial PRIMARY KEY,
|
||||
id_contact integer NOT NULL,
|
||||
id_user integer NOT NULL,
|
||||
prop_type integer NOT NULL,
|
||||
prop_type_str varchar(255) NOT NULL DEFAULT '',
|
||||
prop_value text NOT NULL DEFAULT '',
|
||||
prop_value_custom text NOT NULL DEFAULT '',
|
||||
prop_frec integer NOT NULL default 0
|
||||
);
|
||||
|
||||
CREATE INDEX id_user_rainloop_ab_properties_index ON rainloop_ab_properties (id_user);
|
||||
CREATE INDEX id_user_id_contact_rainloop_ab_properties_index ON rainloop_ab_properties (id_user, id_contact);
|
||||
|
||||
CREATE TABLE rainloop_ab_tags (
|
||||
id_tag serial PRIMARY KEY,
|
||||
id_user integer NOT NULL,
|
||||
tag_name varchar(255) NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX id_user_rainloop_ab_tags_index ON rainloop_ab_tags (id_user);
|
||||
CREATE INDEX id_user_name_rainloop_ab_tags_index ON rainloop_ab_tags (id_user, tag_name);
|
||||
|
||||
CREATE TABLE rainloop_ab_tags_contacts (
|
||||
id_tag integer NOT NULL,
|
||||
id_contact integer NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX id_tag_rainloop_ab_tags_index ON rainloop_ab_tags_contacts (id_tag);
|
||||
CREATE INDEX id_contact_rainloop_ab_tags_index ON rainloop_ab_tags_contacts (id_contact);
|
||||
|
||||
POSTGRESINITIAL;
|
||||
break;
|
||||
|
||||
|
|
@ -926,31 +1318,48 @@ POSTGRESINITIAL;
|
|||
$sInitial = <<<SQLITEINITIAL
|
||||
|
||||
CREATE TABLE rainloop_ab_contacts (
|
||||
id_contact integer NOT NULL PRIMARY KEY,
|
||||
id_user integer NOT NULL,
|
||||
display_name text NOT NULL DEFAULT '',
|
||||
display_email text NOT NULL DEFAULT '',
|
||||
display text NOT NULL DEFAULT '',
|
||||
changed integer NOT NULL DEFAULT 0,
|
||||
hash text NOT NULL DEFAULT ''
|
||||
id_contact integer NOT NULL PRIMARY KEY,
|
||||
id_contact_str text NOT NULL DEFAULT '',
|
||||
id_user integer NOT NULL,
|
||||
display text NOT NULL DEFAULT '',
|
||||
changed integer NOT NULL DEFAULT 0,
|
||||
deleted integer NOT NULL DEFAULT 0,
|
||||
etag text NOT NULL DEFAULT ''
|
||||
);
|
||||
|
||||
CREATE INDEX id_user_rainloop_ab_contacts_index ON rainloop_ab_contacts (id_user);
|
||||
|
||||
CREATE TABLE rainloop_ab_properties (
|
||||
id_prop integer NOT NULL PRIMARY KEY,
|
||||
id_contact integer NOT NULL,
|
||||
id_user integer NOT NULL,
|
||||
prop_type integer NOT NULL,
|
||||
prop_type_custom text NOT NULL DEFAULT '',
|
||||
prop_value text NOT NULL DEFAULT '',
|
||||
prop_value_custom text NOT NULL DEFAULT '',
|
||||
prop_frec integer NOT NULL DEFAULT 0
|
||||
id_prop integer NOT NULL PRIMARY KEY,
|
||||
id_contact integer NOT NULL,
|
||||
id_user integer NOT NULL,
|
||||
prop_type integer NOT NULL,
|
||||
prop_type_str text NOT NULL DEFAULT '',
|
||||
prop_value text NOT NULL DEFAULT '',
|
||||
prop_value_custom text NOT NULL DEFAULT '',
|
||||
prop_frec integer NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX id_user_rainloop_ab_properties_index ON rainloop_ab_properties (id_user);
|
||||
CREATE INDEX id_user_id_contact_rainloop_ab_properties_index ON rainloop_ab_properties (id_user, id_contact);
|
||||
|
||||
CREATE TABLE rainloop_ab_tags (
|
||||
id_tag integer NOT NULL PRIMARY KEY,
|
||||
id_user integer NOT NULL,
|
||||
tag_name text NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX id_user_rainloop_ab_tags_index ON rainloop_ab_tags (id_user);
|
||||
CREATE INDEX id_user_name_rainloop_ab_tags_index ON rainloop_ab_tags (id_user, tag_name);
|
||||
|
||||
CREATE TABLE rainloop_ab_tags_contacts (
|
||||
id_tag integer NOT NULL,
|
||||
id_contact integer NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX id_tag_rainloop_ab_tags_index ON rainloop_ab_tags_contacts (id_tag);
|
||||
CREATE INDEX id_contact_rainloop_ab_tags_index ON rainloop_ab_tags_contacts (id_contact);
|
||||
|
||||
SQLITEINITIAL;
|
||||
break;
|
||||
}
|
||||
|
|
@ -974,22 +1383,32 @@ SQLITEINITIAL;
|
|||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Sync()
|
||||
public function SyncDatabase()
|
||||
{
|
||||
static $mCache = null;
|
||||
if (null !== $mCache)
|
||||
{
|
||||
return $mCache;
|
||||
}
|
||||
|
||||
$mCache = false;
|
||||
switch ($this->sDsnType)
|
||||
{
|
||||
case 'mysql':
|
||||
return $this->dataBaseUpgrade($this->sDsnType.'-ab-version', array(
|
||||
$mCache = $this->dataBaseUpgrade($this->sDsnType.'-ab-version', array(
|
||||
1 => $this->getInitialTablesArray($this->sDsnType)
|
||||
));
|
||||
break;
|
||||
case 'pgsql':
|
||||
return $this->dataBaseUpgrade($this->sDsnType.'-ab-version', array(
|
||||
$mCache = $this->dataBaseUpgrade($this->sDsnType.'-ab-version', array(
|
||||
1 => $this->getInitialTablesArray($this->sDsnType)
|
||||
));
|
||||
break;
|
||||
case 'sqlite':
|
||||
return $this->dataBaseUpgrade($this->sDsnType.'-ab-version', array(
|
||||
$mCache = $this->dataBaseUpgrade($this->sDsnType.'-ab-version', array(
|
||||
1 => $this->getInitialTablesArray($this->sDsnType)
|
||||
));
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -1004,14 +1423,11 @@ SQLITEINITIAL;
|
|||
{
|
||||
$aResult = array();
|
||||
|
||||
$sTypes = \implode(',', array(
|
||||
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES
|
||||
));
|
||||
|
||||
$sSql = 'SELECT prop_value, prop_frec FROM rainloop_ab_properties WHERE id_user = :id_user AND id_contact = :id_contact AND prop_type IN ('.$sTypes.')';
|
||||
$sSql = 'SELECT prop_value, prop_frec FROM rainloop_ab_properties WHERE id_user = :id_user AND id_contact = :id_contact AND prop_type = :type';
|
||||
$aParams = array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT),
|
||||
':id_contact' => array($iIdContact, \PDO::PARAM_INT)
|
||||
':id_contact' => array($iIdContact, \PDO::PARAM_INT),
|
||||
':type' => array(PropertyType::EMAIl, \PDO::PARAM_INT)
|
||||
);
|
||||
|
||||
$oStmt = $this->prepareAndExecute($sSql, $aParams);
|
||||
|
|
|
|||
|
|
@ -18,16 +18,33 @@ class Storage extends \RainLoop\Providers\AbstractProvider
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account|null $oAccount
|
||||
* @param \RainLoop\Account|string|null $oAccount
|
||||
* @param int $iStorageType
|
||||
* @param string $iStorageType
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function verifyAccount($oAccount, $iStorageType)
|
||||
{
|
||||
if (\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY !== $iStorageType &&
|
||||
!($oAccount instanceof \RainLoop\Account || \is_string($oAccount)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account|string|null $oAccount
|
||||
* @param int $iStorageType
|
||||
* @param string $sKey
|
||||
* @param string $sValue
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function Put($oAccount, $iStorageType, $sKey, $sValue)
|
||||
{
|
||||
if (\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY !== $iStorageType && !($oAccount instanceof \RainLoop\Account))
|
||||
if (!$this->verifyAccount($oAccount, $iStorageType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -36,7 +53,7 @@ class Storage extends \RainLoop\Providers\AbstractProvider
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account|null $oAccount
|
||||
* @param \RainLoop\Account|string|null $oAccount
|
||||
* @param int $iStorageType
|
||||
* @param string $sKey
|
||||
* @param mixed $mDefault = false
|
||||
|
|
@ -45,7 +62,7 @@ class Storage extends \RainLoop\Providers\AbstractProvider
|
|||
*/
|
||||
public function Get($oAccount, $iStorageType, $sKey, $mDefault = false)
|
||||
{
|
||||
if (\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY !== $iStorageType && !($oAccount instanceof \RainLoop\Account))
|
||||
if (!$this->verifyAccount($oAccount, $iStorageType))
|
||||
{
|
||||
return $mDefault;
|
||||
}
|
||||
|
|
@ -54,7 +71,7 @@ class Storage extends \RainLoop\Providers\AbstractProvider
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account|null $oAccount
|
||||
* @param \RainLoop\Account|string|null $oAccount
|
||||
* @param int $iStorageType
|
||||
* @param string $sKey
|
||||
*
|
||||
|
|
@ -62,7 +79,7 @@ class Storage extends \RainLoop\Providers\AbstractProvider
|
|||
*/
|
||||
public function Clear($oAccount, $iStorageType, $sKey)
|
||||
{
|
||||
if (\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY !== $iStorageType && !($oAccount instanceof \RainLoop\Account))
|
||||
if (!$this->verifyAccount($oAccount, $iStorageType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class DefaultStorage implements \RainLoop\Providers\Storage\StorageInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account|null $oAccount
|
||||
* @param \RainLoop\Account|string|null $oAccount
|
||||
* @param int $iStorageType
|
||||
* @param string $sKey
|
||||
* @param string $sValue
|
||||
|
|
@ -34,7 +34,7 @@ class DefaultStorage implements \RainLoop\Providers\Storage\StorageInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account|null $oAccount
|
||||
* @param \RainLoop\Account|string|null $oAccount
|
||||
* @param int $iStorageType
|
||||
* @param string $sKey
|
||||
* @param mixed $mDefault = false
|
||||
|
|
@ -54,7 +54,7 @@ class DefaultStorage implements \RainLoop\Providers\Storage\StorageInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account|null $oAccount
|
||||
* @param \RainLoop\Account|string|null $oAccount
|
||||
* @param int $iStorageType
|
||||
* @param string $sKey
|
||||
*
|
||||
|
|
@ -73,22 +73,27 @@ class DefaultStorage implements \RainLoop\Providers\Storage\StorageInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account|null $oAccount
|
||||
* @param \RainLoop\Account|string|null $mAccount
|
||||
* @param int $iStorageType
|
||||
* @param string $sKey
|
||||
* @param bool $bMkDir = false
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function generateFileName($oAccount, $iStorageType, $sKey, $bMkDir = false)
|
||||
private function generateFileName($mAccount, $iStorageType, $sKey, $bMkDir = false)
|
||||
{
|
||||
if (!$oAccount)
|
||||
if (null === $mAccount)
|
||||
{
|
||||
$iStorageType = \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY;
|
||||
}
|
||||
|
||||
$sEmail = $oAccount ? \preg_replace('/[^a-z0-9\-\.@]+/', '_',
|
||||
('' === $oAccount->ParentEmail() ? '' : $oAccount->ParentEmail().'/').$oAccount->Email()) : '';
|
||||
$sEmail = $mAccount instanceof \RainLoop\Account ? \preg_replace('/[^a-z0-9\-\.@]+/', '_',
|
||||
('' === $mAccount->ParentEmail() ? '' : $mAccount->ParentEmail().'/').$mAccount->Email()) : '';
|
||||
|
||||
if (\is_string($mAccount) && empty($sEmail))
|
||||
{
|
||||
$sEmail = \preg_replace('/[^a-z0-9\-\.@]+/', '_', $mAccount);
|
||||
}
|
||||
|
||||
$sTypePath = $sKeyPath = '';
|
||||
switch ($iStorageType)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue