mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
CardDAV (pre-alpha/unstable)
This commit is contained in:
parent
0ec965bccb
commit
599e934b4a
76 changed files with 6984 additions and 1512 deletions
|
|
@ -251,31 +251,30 @@ Enums.ContactPropertyType = {
|
||||||
'FullName': 10,
|
'FullName': 10,
|
||||||
|
|
||||||
'FirstName': 15,
|
'FirstName': 15,
|
||||||
'SurName': 16,
|
'LastName': 16,
|
||||||
'MiddleName': 17,
|
'MiddleName': 16,
|
||||||
'Nick': 18,
|
'Nick': 18,
|
||||||
|
|
||||||
|
'NamePrefix': 20,
|
||||||
|
'NameSuffix': 21,
|
||||||
|
|
||||||
'EmailPersonal': 30,
|
'EmailPersonal': 30,
|
||||||
'EmailBussines': 31,
|
'EmailBussines': 31,
|
||||||
'EmailOther': 32,
|
|
||||||
|
|
||||||
'PhonePersonal': 50,
|
'PhonePersonal': 50,
|
||||||
'PhoneBussines': 51,
|
'PhoneBussines': 51,
|
||||||
'PhoneOther': 52,
|
|
||||||
|
|
||||||
'MobilePersonal': 60,
|
'MobilePersonal': 60,
|
||||||
'MobileBussines': 61,
|
'MobileBussines': 61,
|
||||||
'MobileOther': 62,
|
|
||||||
|
|
||||||
'FaxPesonal': 70,
|
'FaxPesonal': 70,
|
||||||
'FaxBussines': 71,
|
'FaxBussines': 71,
|
||||||
'FaxOther': 72,
|
|
||||||
|
|
||||||
'Facebook': 90,
|
'Facebook': 90,
|
||||||
'Skype': 91,
|
'Skype': 91,
|
||||||
'GitHub': 92,
|
'GitHub': 92,
|
||||||
|
|
||||||
'Description': 110,
|
'Note': 110,
|
||||||
|
|
||||||
'Custom': 250
|
'Custom': 250
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -570,13 +570,13 @@ WebMailAjaxRemoteStorage.prototype.contacts = function (fCallback, iOffset, iLim
|
||||||
/**
|
/**
|
||||||
* @param {?Function} fCallback
|
* @param {?Function} fCallback
|
||||||
*/
|
*/
|
||||||
WebMailAjaxRemoteStorage.prototype.contactSave = function (fCallback, sRequestUid, sUid, sUidStr, nScopeType, aProperties)
|
WebMailAjaxRemoteStorage.prototype.contactSave = function (fCallback, sRequestUid, sUid, sUidStr, iScopeType, aProperties)
|
||||||
{
|
{
|
||||||
this.defaultRequest(fCallback, 'ContactSave', {
|
this.defaultRequest(fCallback, 'ContactSave', {
|
||||||
'RequestUid': sRequestUid,
|
'RequestUid': sRequestUid,
|
||||||
'Uid': Utils.trim(sUid),
|
'Uid': Utils.trim(sUid),
|
||||||
'UidStr': Utils.trim(sUidStr),
|
'UidStr': Utils.trim(sUidStr),
|
||||||
'ScopeType': nScopeType,
|
'ScopeType': iScopeType,
|
||||||
'Properties': aProperties
|
'Properties': aProperties
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -284,8 +284,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.add-link {
|
.add-link {
|
||||||
padding-top: 5px;
|
margin-left: 2px;
|
||||||
padding-left: 7px;
|
padding: 5px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
}
|
}
|
||||||
|
|
@ -334,15 +334,19 @@
|
||||||
|
|
||||||
.e-share-sign {
|
.e-share-sign {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 20px;
|
top: 60px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-save-contact {
|
.button-save-contact {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 100px;
|
top: 20px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
|
|
||||||
|
&.dirty {
|
||||||
|
color: #51a351;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.read-only {
|
&.read-only {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ function PopupsContactsViewModel()
|
||||||
var
|
var
|
||||||
self = this,
|
self = this,
|
||||||
oT = Enums.ContactPropertyType,
|
oT = Enums.ContactPropertyType,
|
||||||
aNameTypes = [oT.FullName, oT.FirstName, oT.SurName, oT.MiddleName],
|
aNameTypes = [oT.FirstName, oT.LastName],
|
||||||
aEmailTypes = [oT.EmailPersonal, oT.EmailBussines, oT.EmailOther],
|
aEmailTypes = [oT.EmailPersonal, oT.EmailBussines, oT.EmailOther],
|
||||||
aPhonesTypes = [
|
aPhonesTypes = [
|
||||||
oT.PhonePersonal, oT.PhoneBussines, oT.PhoneOther,
|
oT.PhonePersonal, oT.PhoneBussines, oT.PhoneOther,
|
||||||
|
|
@ -267,6 +267,8 @@ function PopupsContactsViewModel()
|
||||||
|
|
||||||
if (bRes)
|
if (bRes)
|
||||||
{
|
{
|
||||||
|
self.watchDirty(false);
|
||||||
|
|
||||||
_.delay(function () {
|
_.delay(function () {
|
||||||
self.viewSaveTrigger(Enums.SaveSettingsStep.Idle);
|
self.viewSaveTrigger(Enums.SaveSettingsStep.Idle);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
@ -284,19 +286,21 @@ function PopupsContactsViewModel()
|
||||||
|
|
||||||
this.bDropPageAfterDelete = false;
|
this.bDropPageAfterDelete = false;
|
||||||
|
|
||||||
|
this.watchDirty = ko.observable(false);
|
||||||
this.watchHash = ko.observable(false);
|
this.watchHash = ko.observable(false);
|
||||||
|
|
||||||
this.viewHash = ko.computed(function () {
|
this.viewHash = ko.computed(function () {
|
||||||
return '' + self.viewScopeType() + ' - ' + _.map(self.viewProperties(), function (oItem) {
|
return '' + self.viewScopeType() + ' - ' + _.map(self.viewProperties(), function (oItem) {
|
||||||
return oItem.value();
|
return oItem.value();
|
||||||
}).join('');
|
}).join('');
|
||||||
});
|
});
|
||||||
|
|
||||||
this.saveCommandDebounce = _.debounce(_.bind(this.saveCommand, this), 1000);
|
// this.saveCommandDebounce = _.debounce(_.bind(this.saveCommand, this), 1000);
|
||||||
|
|
||||||
this.viewHash.subscribe(function () {
|
this.viewHash.subscribe(function () {
|
||||||
if (this.watchHash() && !this.viewReadOnly())
|
if (this.watchHash() && !this.viewReadOnly() && !this.watchDirty())
|
||||||
{
|
{
|
||||||
this.saveCommandDebounce();
|
this.watchDirty(true);
|
||||||
}
|
}
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
|
|
@ -329,7 +333,7 @@ PopupsContactsViewModel.prototype.addNewEmail = function ()
|
||||||
|
|
||||||
PopupsContactsViewModel.prototype.addNewPhone = function ()
|
PopupsContactsViewModel.prototype.addNewPhone = function ()
|
||||||
{
|
{
|
||||||
this.addNewProperty(Enums.ContactPropertyType.PhonePersonal);
|
this.addNewProperty(Enums.ContactPropertyType.MobilePersonal);
|
||||||
};
|
};
|
||||||
|
|
||||||
PopupsContactsViewModel.prototype.removeCheckedOrSelectedContactsFromList = function ()
|
PopupsContactsViewModel.prototype.removeCheckedOrSelectedContactsFromList = function ()
|
||||||
|
|
@ -417,7 +421,8 @@ PopupsContactsViewModel.prototype.populateViewContact = function (oContact)
|
||||||
var
|
var
|
||||||
sId = '',
|
sId = '',
|
||||||
sIdStr = '',
|
sIdStr = '',
|
||||||
bHasName = false,
|
sLastName = '',
|
||||||
|
sFirstName = '',
|
||||||
aList = []
|
aList = []
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
@ -437,12 +442,17 @@ PopupsContactsViewModel.prototype.populateViewContact = function (oContact)
|
||||||
_.each(oContact.properties, function (aProperty) {
|
_.each(oContact.properties, function (aProperty) {
|
||||||
if (aProperty && aProperty[0])
|
if (aProperty && aProperty[0])
|
||||||
{
|
{
|
||||||
aList.push(new ContactPropertyModel(aProperty[0], aProperty[1], false,
|
if (Enums.ContactPropertyType.LastName === aProperty[0])
|
||||||
Enums.ContactPropertyType.FullName === aProperty[0] ? 'CONTACTS/PLACEHOLDER_ENTER_DISPLAY_NAME' : ''));
|
|
||||||
|
|
||||||
if (Enums.ContactPropertyType.FullName === aProperty[0])
|
|
||||||
{
|
{
|
||||||
bHasName = true;
|
sLastName = aProperty[1];
|
||||||
|
}
|
||||||
|
else if (Enums.ContactPropertyType.FirstName === aProperty[0])
|
||||||
|
{
|
||||||
|
sFirstName = aProperty[1];
|
||||||
|
}
|
||||||
|
else if (-1 === Utils.inArray(aProperty[0], [Enums.ContactPropertyType.FullName]))
|
||||||
|
{
|
||||||
|
aList.push(new ContactPropertyModel(aProperty[0], aProperty[1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -452,16 +462,15 @@ PopupsContactsViewModel.prototype.populateViewContact = function (oContact)
|
||||||
this.viewScopeType(oContact.scopeType);
|
this.viewScopeType(oContact.scopeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bHasName)
|
aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.FirstName, sFirstName, false, 'CONTACTS/PLACEHOLDER_ENTER_FIRST_NAME'));
|
||||||
{
|
aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.LastName, sLastName, !oContact, 'CONTACTS/PLACEHOLDER_ENTER_LAST_NAME'));
|
||||||
aList.push(new ContactPropertyModel(Enums.ContactPropertyType.FullName, '', !oContact, 'CONTACTS/PLACEHOLDER_ENTER_DISPLAY_NAME'));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.viewID(sId);
|
this.viewID(sId);
|
||||||
this.viewIDStr(sIdStr);
|
this.viewIDStr(sIdStr);
|
||||||
this.viewProperties([]);
|
this.viewProperties([]);
|
||||||
this.viewProperties(aList);
|
this.viewProperties(aList);
|
||||||
|
|
||||||
|
this.watchDirty(false);
|
||||||
this.watchHash(true);
|
this.watchHash(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "RainLoop",
|
"name": "RainLoop",
|
||||||
"title": "RainLoop Webmail",
|
"title": "RainLoop Webmail",
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"release": "556",
|
"release": "557",
|
||||||
"description": "Simple, modern & fast web-based email client",
|
"description": "Simple, modern & fast web-based email client",
|
||||||
"homepage": "http://rainloop.net",
|
"homepage": "http://rainloop.net",
|
||||||
"main": "Gruntfile.js",
|
"main": "Gruntfile.js",
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ if (!\defined('RAINLOOP_APP_ROOT_PATH'))
|
||||||
}
|
}
|
||||||
else if (0 === \strpos($sClassName, 'Sabre') && false !== \strpos($sClassName, '\\'))
|
else if (0 === \strpos($sClassName, 'Sabre') && false !== \strpos($sClassName, '\\'))
|
||||||
{
|
{
|
||||||
|
include_once RAINLOOP_APP_LIBRARIES_PATH.'RainLoop/SabreDAV/MbStringFix.php';
|
||||||
return include RAINLOOP_APP_LIBRARIES_PATH.'Sabre/'.\str_replace('\\', '/', \substr($sClassName, 6)).'.php';
|
return include RAINLOOP_APP_LIBRARIES_PATH.'Sabre/'.\str_replace('\\', '/', \substr($sClassName, 6)).'.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -563,6 +563,8 @@ class Actions
|
||||||
$this->oPersonalAddressBookProvider = new \RainLoop\Providers\PersonalAddressBook(
|
$this->oPersonalAddressBookProvider = new \RainLoop\Providers\PersonalAddressBook(
|
||||||
$this->Config()->Get('contacts', 'enable', false) || $bForceEnable ? $this->fabrica('personal-address-book', $oAccount) : null);
|
$this->Config()->Get('contacts', 'enable', false) || $bForceEnable ? $this->fabrica('personal-address-book', $oAccount) : null);
|
||||||
|
|
||||||
|
$this->oPersonalAddressBookProvider->SetLogger($this->Logger());
|
||||||
|
|
||||||
$this->oPersonalAddressBookProvider->ConsiderShare(
|
$this->oPersonalAddressBookProvider->ConsiderShare(
|
||||||
!!$this->Config()->Get('contacts', 'allow_sharing', false));
|
!!$this->Config()->Get('contacts', 'allow_sharing', false));
|
||||||
}
|
}
|
||||||
|
|
@ -995,7 +997,7 @@ class Actions
|
||||||
|
|
||||||
$aResult['ContactsEnable'] = (bool) $oConfig->Get('contacts', 'enable', false);
|
$aResult['ContactsEnable'] = (bool) $oConfig->Get('contacts', 'enable', false);
|
||||||
$aResult['ContactsSharing'] = (bool) $oConfig->Get('contacts', 'allow_sharing', false);
|
$aResult['ContactsSharing'] = (bool) $oConfig->Get('contacts', 'allow_sharing', false);
|
||||||
$aResult['ContactsSync'] = (bool) $oConfig->Get('contacts', 'allow_carddav_sync', false);
|
$aResult['ContactsSync'] = (bool) $oConfig->Get('labs', 'sync_allow_dav', false);
|
||||||
$aResult['ContactsPdoType'] = $this->ValidateContactPdoType(\trim($this->Config()->Get('contacts', 'type', 'sqlite')));
|
$aResult['ContactsPdoType'] = $this->ValidateContactPdoType(\trim($this->Config()->Get('contacts', 'type', 'sqlite')));
|
||||||
$aResult['ContactsPdoDsn'] = (string) $oConfig->Get('contacts', 'pdo_dsn', '');
|
$aResult['ContactsPdoDsn'] = (string) $oConfig->Get('contacts', 'pdo_dsn', '');
|
||||||
$aResult['ContactsPdoType'] = (string) $oConfig->Get('contacts', 'type', '');
|
$aResult['ContactsPdoType'] = (string) $oConfig->Get('contacts', 'type', '');
|
||||||
|
|
@ -4267,17 +4269,28 @@ class Actions
|
||||||
$iScopeType = \RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_;
|
$iScopeType = \RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_;
|
||||||
}
|
}
|
||||||
|
|
||||||
$oContact = new \RainLoop\Providers\PersonalAddressBook\Classes\Contact();
|
$oContact = null;
|
||||||
if (0 < \strlen($sUid))
|
if (0 < \strlen($sUid))
|
||||||
{
|
{
|
||||||
$oContact->IdContact = $sUid;
|
$oContact = $oPab->GetContactByID($oAccount->ParentEmailHelper(), $sUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$oContact)
|
||||||
|
{
|
||||||
|
$oContact = new \RainLoop\Providers\PersonalAddressBook\Classes\Contact();
|
||||||
|
if (0 < \strlen($sUid))
|
||||||
|
{
|
||||||
|
$oContact->IdContact = $sUid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (0 < \strlen($sUidStr))
|
if (0 < \strlen($sUidStr))
|
||||||
{
|
{
|
||||||
$oContact->IdContactStr = $sUidStr;
|
$oContact->IdContactStr = $sUidStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
$oContact->ScopeType = $iScopeType;
|
$oContact->ScopeType = $iScopeType;
|
||||||
|
$oContact->Properties = array();
|
||||||
|
|
||||||
$aProperties = $this->GetActionParam('Properties', array());
|
$aProperties = $this->GetActionParam('Properties', array());
|
||||||
if (\is_array($aProperties))
|
if (\is_array($aProperties))
|
||||||
|
|
@ -5676,7 +5689,7 @@ class Actions
|
||||||
'{{ErrorTitle}}' => $sTitle,
|
'{{ErrorTitle}}' => $sTitle,
|
||||||
'{{ErrorHeader}}' => $sTitle,
|
'{{ErrorHeader}}' => $sTitle,
|
||||||
'{{ErrorDesc}}' => $sDesc,
|
'{{ErrorDesc}}' => $sDesc,
|
||||||
'{{BackLinkVisibility}}' => $bShowBackLink ? 'inline-block' : 'none',
|
'{{BackLinkVisibilityStyle}}' => $bShowBackLink ? 'display:inline-block' : 'display:none',
|
||||||
'{{BackLink}}' => $this->StaticI18N('STATIC/BACK_LINK'),
|
'{{BackLink}}' => $this->StaticI18N('STATIC/BACK_LINK'),
|
||||||
'{{BackHref}}' => './'
|
'{{BackHref}}' => './'
|
||||||
));
|
));
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,6 @@ class Application extends \RainLoop\Config\AbstractConfig
|
||||||
'contacts' => array(
|
'contacts' => array(
|
||||||
'enable' => array(false, 'Enable contacts'),
|
'enable' => array(false, 'Enable contacts'),
|
||||||
'allow_sharing' => array(true),
|
'allow_sharing' => array(true),
|
||||||
'allow_carddav_sync' => array(false),
|
|
||||||
'suggestions_limit' => array(30),
|
'suggestions_limit' => array(30),
|
||||||
'type' => array('sqlite', ''),
|
'type' => array('sqlite', ''),
|
||||||
'pdo_dsn' => array('mysql:host=127.0.0.1;port=3306;dbname=rainloop', ''),
|
'pdo_dsn' => array('mysql:host=127.0.0.1;port=3306;dbname=rainloop', ''),
|
||||||
|
|
@ -201,6 +200,10 @@ Enables caching in the system'),
|
||||||
'ignore_folders_subscription' => array(false,
|
'ignore_folders_subscription' => array(false,
|
||||||
'Experimental settings. Handle with care.
|
'Experimental settings. Handle with care.
|
||||||
'),
|
'),
|
||||||
|
'sync_allow_dav' => array(false),
|
||||||
|
'sync_dav_host' => array(''),
|
||||||
|
'sync_dav_digest_auth' => array(false),
|
||||||
|
|
||||||
'allow_message_append' => array(false),
|
'allow_message_append' => array(false),
|
||||||
'date_from_headers' => array(false),
|
'date_from_headers' => array(false),
|
||||||
'cache_system_data' => array(true),
|
'cache_system_data' => array(true),
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,11 @@ abstract class AbstractProvider
|
||||||
*/
|
*/
|
||||||
protected $oAccount;
|
protected $oAccount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \MailSo\Log\Logger
|
||||||
|
*/
|
||||||
|
protected $oLogger = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
|
|
@ -24,4 +29,23 @@ abstract class AbstractProvider
|
||||||
{
|
{
|
||||||
$this->oAccount = $oAccount;
|
$this->oAccount = $oAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \MailSo\Log\Logger $oLogger
|
||||||
|
*/
|
||||||
|
public function SetLogger($oLogger)
|
||||||
|
{
|
||||||
|
if ($oLogger instanceof \MailSo\Log\Logger)
|
||||||
|
{
|
||||||
|
$this->oLogger = $oLogger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \MailSo\Log\Logger|null
|
||||||
|
*/
|
||||||
|
public function Logger()
|
||||||
|
{
|
||||||
|
return $this->oLogger;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,17 @@ class PersonalAddressBook extends \RainLoop\Providers\AbstractProvider
|
||||||
$this->oDriver->GetUserUidByEmail($sEmail) : '';
|
$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 string $sEmail
|
||||||
* @param bool $bCreate = false
|
* @param bool $bCreate = false
|
||||||
|
|
@ -97,29 +108,29 @@ class PersonalAddressBook extends \RainLoop\Providers\AbstractProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \RainLoop\Account $oAccount
|
* @param string $sEmail
|
||||||
* @param \RainLoop\Providers\PersonalAddressBook\Classes\Contact $oContact
|
* @param \RainLoop\Providers\PersonalAddressBook\Classes\Contact $oContact
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function ContactSave($oAccount, &$oContact)
|
public function ContactSave($sEmail, &$oContact)
|
||||||
{
|
{
|
||||||
return $this->IsActive() ? $this->oDriver->ContactSave($oAccount, $oContact) : false;
|
return $this->IsActive() ? $this->oDriver->ContactSave($sEmail, $oContact) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \RainLoop\Account $oAccount
|
* @param string $sEmail
|
||||||
* @param array $aContactIds
|
* @param array $aContactIds
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function DeleteContacts($oAccount, $aContactIds)
|
public function DeleteContacts($sEmail, $aContactIds)
|
||||||
{
|
{
|
||||||
return $this->IsActive() ? $this->oDriver->DeleteContacts($oAccount, $aContactIds) : false;
|
return $this->IsActive() ? $this->oDriver->DeleteContacts($sEmail, $aContactIds) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \RainLoop\Account|mixed $mAccountOrId
|
* @param string $sEmail
|
||||||
* @param int $iOffset = 0
|
* @param int $iOffset = 0
|
||||||
* @param type $iLimit = 20
|
* @param type $iLimit = 20
|
||||||
* @param string $sSearch = ''
|
* @param string $sSearch = ''
|
||||||
|
|
@ -127,9 +138,9 @@ class PersonalAddressBook extends \RainLoop\Providers\AbstractProvider
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function GetContacts($mAccountOrId, $iOffset = 0, $iLimit = 20, $sSearch = '', &$iResultCount = 0)
|
public function GetContacts($sEmail, $iOffset = 0, $iLimit = 20, $sSearch = '', &$iResultCount = 0)
|
||||||
{
|
{
|
||||||
return $this->IsActive() ? $this->oDriver->GetContacts($mAccountOrId,
|
return $this->IsActive() ? $this->oDriver->GetContacts($sEmail,
|
||||||
$iOffset, $iLimit, $sSearch, $iResultCount) : array();
|
$iOffset, $iLimit, $sSearch, $iResultCount) : array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -146,7 +157,7 @@ class PersonalAddressBook extends \RainLoop\Providers\AbstractProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \RainLoop\Account $oAccount
|
* @param string $sEmail
|
||||||
* @param string $sSearch
|
* @param string $sSearch
|
||||||
* @param int $iLimit = 20
|
* @param int $iLimit = 20
|
||||||
*
|
*
|
||||||
|
|
@ -154,20 +165,20 @@ class PersonalAddressBook extends \RainLoop\Providers\AbstractProvider
|
||||||
*
|
*
|
||||||
* @throws \InvalidArgumentException
|
* @throws \InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
public function GetSuggestions($oAccount, $sSearch, $iLimit = 20)
|
public function GetSuggestions($sEmail, $sSearch, $iLimit = 20)
|
||||||
{
|
{
|
||||||
return $this->IsActive() ? $this->oDriver->GetSuggestions($oAccount, $sSearch, $iLimit) : array();
|
return $this->IsActive() ? $this->oDriver->GetSuggestions($sEmail, $sSearch, $iLimit) : array();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \RainLoop\Account $oAccount
|
* @param string $sEmail
|
||||||
* @param array $aEmails
|
* @param array $aEmails
|
||||||
* @param bool $bCreateAuto = true
|
* @param bool $bCreateAuto = true
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function IncFrec($oAccount, $aEmails, $bCreateAuto = true)
|
public function IncFrec($sEmail, $aEmails, $bCreateAuto = true)
|
||||||
{
|
{
|
||||||
return $this->IsActive() ? $this->oDriver->IncFrec($oAccount, $aEmails, $bCreateAuto) : false;
|
return $this->IsActive() ? $this->oDriver->IncFrec($sEmail, $aEmails, $bCreateAuto) : false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,10 @@
|
||||||
|
|
||||||
namespace RainLoop\Providers\PersonalAddressBook\Classes;
|
namespace RainLoop\Providers\PersonalAddressBook\Classes;
|
||||||
|
|
||||||
use RainLoop\Providers\PersonalAddressBook\Enumerations\PropertyType;
|
use
|
||||||
|
RainLoop\Providers\PersonalAddressBook\Enumerations\PropertyType,
|
||||||
|
RainLoop\Providers\PersonalAddressBook\Classes\Property
|
||||||
|
;
|
||||||
|
|
||||||
class Contact
|
class Contact
|
||||||
{
|
{
|
||||||
|
|
@ -21,16 +24,6 @@ class Contact
|
||||||
*/
|
*/
|
||||||
public $Display;
|
public $Display;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $DisplayName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $DisplayEmail;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
|
|
@ -56,6 +49,21 @@ class Contact
|
||||||
*/
|
*/
|
||||||
public $ReadOnly;
|
public $ReadOnly;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $CardDavData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $CardDavHash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $CardDavSize;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->Clear();
|
$this->Clear();
|
||||||
|
|
@ -67,19 +75,25 @@ class Contact
|
||||||
$this->IdContactStr = '';
|
$this->IdContactStr = '';
|
||||||
$this->IdUser = 0;
|
$this->IdUser = 0;
|
||||||
$this->Display = '';
|
$this->Display = '';
|
||||||
$this->DisplayName = '';
|
|
||||||
$this->DisplayEmail = '';
|
|
||||||
$this->ScopeType = \RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_;
|
$this->ScopeType = \RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_;
|
||||||
$this->Changed = \time();
|
$this->Changed = \time();
|
||||||
$this->IdPropertyFromSearch = 0;
|
$this->IdPropertyFromSearch = 0;
|
||||||
$this->Properties = array();
|
$this->Properties = array();
|
||||||
$this->ReadOnly = false;
|
$this->ReadOnly = false;
|
||||||
|
|
||||||
|
$this->CardDavData = '';
|
||||||
|
$this->CardDavHash = '';
|
||||||
|
$this->CardDavSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function UpdateDependentValues()
|
public function UpdateDependentValues($bReparseVcard = true)
|
||||||
{
|
{
|
||||||
$sDisplayName = '';
|
$sLastName = '';
|
||||||
$sDisplayEmail = '';
|
$sFirstName = '';
|
||||||
|
$sEmail = '';
|
||||||
|
$sOther = '';
|
||||||
|
|
||||||
|
$oFullNameProperty = null;
|
||||||
|
|
||||||
foreach ($this->Properties as /* @var $oProperty \RainLoop\Providers\PersonalAddressBook\Classes\Property */ &$oProperty)
|
foreach ($this->Properties as /* @var $oProperty \RainLoop\Providers\PersonalAddressBook\Classes\Property */ &$oProperty)
|
||||||
{
|
{
|
||||||
|
|
@ -88,15 +102,32 @@ class Contact
|
||||||
$oProperty->ScopeType = $this->ScopeType;
|
$oProperty->ScopeType = $this->ScopeType;
|
||||||
$oProperty->UpdateDependentValues();
|
$oProperty->UpdateDependentValues();
|
||||||
|
|
||||||
if ('' === $sDisplayName && \RainLoop\Providers\PersonalAddressBook\Enumerations\PropertyType::FULLNAME === $oProperty->Type &&
|
if (!$oFullNameProperty && PropertyType::FULLNAME === $oProperty->Type)
|
||||||
0 < \strlen($oProperty->Value))
|
|
||||||
{
|
{
|
||||||
$sDisplayName = $oProperty->Value;
|
$oFullNameProperty =& $oProperty;
|
||||||
}
|
}
|
||||||
else if ('' === $sDisplayEmail && $oProperty->IsEmail() &&
|
|
||||||
0 < \strlen($oProperty->Value))
|
if (0 < \strlen($oProperty->Value))
|
||||||
{
|
{
|
||||||
$sDisplayEmail = $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::MOBILE_PERSONAL, PropertyType::MOBILE_BUSSINES,
|
||||||
|
)))
|
||||||
|
{
|
||||||
|
$sOther = $oProperty->Value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -106,10 +137,55 @@ class Contact
|
||||||
$this->IdContactStr = \Sabre\DAV\UUIDUtil::getUUID();
|
$this->IdContactStr = \Sabre\DAV\UUIDUtil::getUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->DisplayName = $sDisplayName;
|
$sDisplay = '';
|
||||||
$this->DisplayEmail = $sDisplayEmail;
|
if (0 < \strlen($sLastName) || 0 < \strlen($sFirstName))
|
||||||
|
{
|
||||||
|
$sDisplay = \trim($sLastName.' '.$sFirstName);
|
||||||
|
}
|
||||||
|
|
||||||
$this->Display = 0 < \strlen($sDisplayName) ? $sDisplayName : (!empty($sDisplayEmail) ? $sDisplayEmail : '');
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->CardDavData))
|
||||||
|
{
|
||||||
|
$this->CardDavHash = \md5($this->CardDavData);
|
||||||
|
$this->CardDavSize = \strlen($this->CardDavData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->CardDavHash = '';
|
||||||
|
$this->CardDavSize = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -129,19 +205,183 @@ class Contact
|
||||||
return \array_unique($aResult);
|
return \array_unique($aResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $sVCard
|
||||||
|
*/
|
||||||
|
public function ParseVCard($sVCard)
|
||||||
|
{
|
||||||
|
$bNew = empty($this->IdContact);
|
||||||
|
|
||||||
|
if (!$bNew)
|
||||||
|
{
|
||||||
|
$this->Properties = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$oVCard = null;
|
||||||
|
$aProperties = array();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$oVCard = \Sabre\VObject\Reader::read($sVCard);
|
||||||
|
}
|
||||||
|
catch (\Exception $oExc) {}
|
||||||
|
|
||||||
|
if ($oVCard && $oVCard->UID)
|
||||||
|
{
|
||||||
|
$this->IdContactStr = (string) $oVCard->UID;
|
||||||
|
|
||||||
|
if (isset($oVCard->FN) && '' !== \trim($oVCard->FN))
|
||||||
|
{
|
||||||
|
$aProperties[] = new Property(PropertyType::FULLNAME, \trim($oVCard->FN));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($oVCard->NICKNAME) && '' !== \trim($oVCard->NICKNAME))
|
||||||
|
{
|
||||||
|
$aProperties[] = new Property(PropertyType::NICK_NAME, \trim($oVCard->NICKNAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (isset($oVCard->NOTE) && '' !== \trim($oVCard->NOTE))
|
||||||
|
// {
|
||||||
|
// $aProperties[] = new Property(PropertyType::NOTE, \trim($oVCard->NOTE));
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (isset($oVCard->N))
|
||||||
|
{
|
||||||
|
$aNames = $oVCard->N->getParts();
|
||||||
|
foreach ($aNames as $iIndex => $sValue)
|
||||||
|
{
|
||||||
|
$sValue = \trim($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))
|
||||||
|
{
|
||||||
|
foreach($oVCard->EMAIL as $oEmail)
|
||||||
|
{
|
||||||
|
$oTypes = $oEmail ? $oEmail['TYPE'] : null;
|
||||||
|
$sEmail = $oTypes ? \trim((string) $oEmail) : '';
|
||||||
|
|
||||||
|
if ($oTypes && 0 < \strlen($sEmail))
|
||||||
|
{
|
||||||
|
if ($oTypes->has('WORK'))
|
||||||
|
{
|
||||||
|
$aProperties[] = new Property(PropertyType::EMAIl_BUSSINES, $sEmail);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$aProperties[] = new Property(PropertyType::EMAIl_PERSONAL, $sEmail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($oVCard->TEL))
|
||||||
|
{
|
||||||
|
foreach($oVCard->TEL as $oTel)
|
||||||
|
{
|
||||||
|
$oTypes = $oTel ? $oTel['TYPE'] : null;
|
||||||
|
$sTel = $oTypes ? \trim((string) $oTel) : '';
|
||||||
|
|
||||||
|
if ($oTypes && 0 < \strlen($sTel))
|
||||||
|
{
|
||||||
|
if ($oTypes->has('VOICE'))
|
||||||
|
{
|
||||||
|
if ($oTypes->has('WORK'))
|
||||||
|
{
|
||||||
|
$aProperties[] = new Property(PropertyType::PHONE_BUSSINES, $sTel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$aProperties[] = new Property(PropertyType::PHONE_PERSONAL, $sTel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ($oTypes->has('CELL'))
|
||||||
|
{
|
||||||
|
if ($oTypes->has('WORK'))
|
||||||
|
{
|
||||||
|
$aProperties[] = new Property(PropertyType::MOBILE_BUSSINES, $sTel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$aProperties[] = new Property(PropertyType::MOBILE_PERSONAL, $sTel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ($oTypes->has('FAX'))
|
||||||
|
{
|
||||||
|
if ($oTypes->has('WORK'))
|
||||||
|
{
|
||||||
|
$aProperties[] = new Property(PropertyType::FAX_BUSSINES, $sTel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$aProperties[] = new Property(PropertyType::FAX_PERSONAL, $sTel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ($oTypes->has('WORK'))
|
||||||
|
{
|
||||||
|
$aProperties[] = new Property(PropertyType::MOBILE_BUSSINES, $sTel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$aProperties[] = new Property(PropertyType::MOBILE_PERSONAL, $sTel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->Properties = $aProperties;
|
||||||
|
|
||||||
|
$this->CardDavData = $sVCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->UpdateDependentValues(false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function ToVCardObject()
|
public function ToVCardObject($sPreVCard = '')
|
||||||
{
|
{
|
||||||
$this->UpdateDependentValues();
|
// $this->UpdateDependentValues();
|
||||||
|
|
||||||
$oVCard = new \Sabre\VObject\Component\VCard('VCARD');
|
$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->VERSION = '3.0';
|
||||||
$oVCard->PRODID = '-//RainLoop//'.APP_VERSION.'//EN';
|
$oVCard->PRODID = '-//RainLoop//'.APP_VERSION.'//EN';
|
||||||
|
|
||||||
$sFirstName = $sSurName = '';
|
unset($oVCard->FN, $oVCard->EMAIL, $oVCard->TEL);
|
||||||
|
|
||||||
|
$sFirstName = $sLastName = $sMiddleName = $sSuffix = $sPrefix = '';
|
||||||
foreach ($this->Properties as /* @var $oProperty \RainLoop\Providers\PersonalAddressBook\Classes\Property */ &$oProperty)
|
foreach ($this->Properties as /* @var $oProperty \RainLoop\Providers\PersonalAddressBook\Classes\Property */ &$oProperty)
|
||||||
{
|
{
|
||||||
if ($oProperty)
|
if ($oProperty)
|
||||||
|
|
@ -151,55 +391,55 @@ class Contact
|
||||||
case PropertyType::FULLNAME:
|
case PropertyType::FULLNAME:
|
||||||
$oVCard->FN = $oProperty->Value;
|
$oVCard->FN = $oProperty->Value;
|
||||||
break;
|
break;
|
||||||
case PropertyType::NICK:
|
case PropertyType::NICK_NAME:
|
||||||
$oVCard->NICKNAME = $oProperty->Value;
|
$oVCard->NICKNAME = $oProperty->Value;
|
||||||
break;
|
break;
|
||||||
case PropertyType::EMAIl_PERSONAL:
|
case PropertyType::EMAIl_PERSONAL:
|
||||||
case PropertyType::EMAIl_OTHER:
|
$oVCard->add('EMAIL', $oProperty->Value, array('TYPE' => array('INTERNET', 'HOME')));
|
||||||
$oVCard->add('EMAIL', $oProperty->Value, array('TYPE' => 'INTERNET', 'TYPE' => 'HOME'));
|
|
||||||
break;
|
break;
|
||||||
case PropertyType::EMAIl_BUSSINES:
|
case PropertyType::EMAIl_BUSSINES:
|
||||||
$oVCard->add('EMAIL', $oProperty->Value, array('TYPE' => 'INTERNET', 'TYPE' => 'WORK'));
|
$oVCard->add('EMAIL', $oProperty->Value, array('TYPE' => array('INTERNET', 'WORK')));
|
||||||
break;
|
break;
|
||||||
case PropertyType::PHONE_PERSONAL:
|
case PropertyType::PHONE_PERSONAL:
|
||||||
case PropertyType::PHONE_OTHER:
|
$oVCard->add('TEL', $oProperty->Value, array('TYPE' => array('VOICE', 'HOME')));
|
||||||
$oVCard->add('TEL', $oProperty->Value, array('TYPE' => 'VOICE', 'TYPE' => 'HOME'));
|
|
||||||
break;
|
break;
|
||||||
case PropertyType::PHONE_BUSSINES:
|
case PropertyType::PHONE_BUSSINES:
|
||||||
$oVCard->add('TEL', $oProperty->Value, array('TYPE' => 'VOICE', 'TYPE' => 'WORK'));
|
$oVCard->add('TEL', $oProperty->Value, array('TYPE' => array('VOICE', 'WORK')));
|
||||||
break;
|
break;
|
||||||
case PropertyType::MOBILE_PERSONAL:
|
case PropertyType::MOBILE_PERSONAL:
|
||||||
|
$oVCard->add('TEL', $oProperty->Value, array('TYPE' => array('CELL', 'HOME')));
|
||||||
|
break;
|
||||||
case PropertyType::MOBILE_BUSSINES:
|
case PropertyType::MOBILE_BUSSINES:
|
||||||
case PropertyType::MOBILE_OTHER:
|
$oVCard->add('TEL', $oProperty->Value, array('TYPE' => array('CELL', 'WORK')));
|
||||||
$oVCard->add('TEL', $oProperty->Value, array('TYPE' => 'VOICE', 'TYPE' => 'CELL'));
|
|
||||||
break;
|
break;
|
||||||
case PropertyType::FAX_PERSONAL:
|
case PropertyType::FAX_PERSONAL:
|
||||||
case PropertyType::FAX_OTHER:
|
$oVCard->add('TEL', $oProperty->Value, array('TYPE' => array('FAX', 'HOME')));
|
||||||
$oVCard->add('TEL', $oProperty->Value, array('TYPE' => 'FAX', 'TYPE' => 'HOME'));
|
|
||||||
break;
|
break;
|
||||||
case PropertyType::FAX_BUSSINES:
|
case PropertyType::FAX_BUSSINES:
|
||||||
$oVCard->add('TEL', $oProperty->Value, array('TYPE' => 'FAX', 'TYPE' => 'WORK'));
|
$oVCard->add('TEL', $oProperty->Value, array('TYPE' => array('FAX', 'WORK')));
|
||||||
break;
|
break;
|
||||||
case PropertyType::FIRST_NAME:
|
case PropertyType::FIRST_NAME:
|
||||||
$sFirstName = $oProperty->Value;
|
$sFirstName = $oProperty->Value;
|
||||||
break;
|
break;
|
||||||
case PropertyType::SUR_NAME:
|
case PropertyType::LAST_NAME:
|
||||||
$sSurName = $oProperty->Value;
|
$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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$oVCard->UID = $this->VCardUID();
|
$oVCard->UID = $this->IdContactStr;
|
||||||
|
$oVCard->N = array($sLastName, $sFirstName, $sMiddleName, $sPrefix, $sSuffix);
|
||||||
// $oVCard->N = array(
|
$oVCard->REV = gmdate('Ymd').'T'.gmdate('His').'Z';
|
||||||
// $sSurName,
|
|
||||||
// $sFirstName,
|
|
||||||
// '',
|
|
||||||
// '',
|
|
||||||
// '',
|
|
||||||
// ''
|
|
||||||
// );
|
|
||||||
|
|
||||||
return $oVCard;
|
return $oVCard;
|
||||||
}
|
}
|
||||||
|
|
@ -207,10 +447,8 @@ class Contact
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function VCardUID()
|
public function VCardUri()
|
||||||
{
|
{
|
||||||
return $this->IdContactStr.'.vcf';
|
return $this->IdContactStr.'.vcf';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,13 @@ class Property
|
||||||
*/
|
*/
|
||||||
public $Frec;
|
public $Frec;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct(
|
||||||
|
$iType = \RainLoop\Providers\PersonalAddressBook\Enumerations\PropertyType::UNKNOWN, $sValue = '')
|
||||||
{
|
{
|
||||||
$this->Clear();
|
$this->Clear();
|
||||||
|
|
||||||
|
$this->Type = $iType;
|
||||||
|
$this->Value = $sValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function Clear()
|
public function Clear()
|
||||||
|
|
@ -66,7 +70,7 @@ class Property
|
||||||
public function IsEmail()
|
public function IsEmail()
|
||||||
{
|
{
|
||||||
return \in_array($this->Type, array(
|
return \in_array($this->Type, array(
|
||||||
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER
|
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,9 +80,9 @@ class Property
|
||||||
public function IsPhone()
|
public function IsPhone()
|
||||||
{
|
{
|
||||||
return \in_array($this->Type, array(
|
return \in_array($this->Type, array(
|
||||||
PropertyType::PHONE_PERSONAL, PropertyType::PHONE_BUSSINES, PropertyType::PHONE_OTHER,
|
PropertyType::PHONE_PERSONAL, PropertyType::PHONE_BUSSINES,
|
||||||
PropertyType::MOBILE_PERSONAL, PropertyType::MOBILE_BUSSINES, PropertyType::MOBILE_OTHER,
|
PropertyType::MOBILE_PERSONAL, PropertyType::MOBILE_BUSSINES,
|
||||||
PropertyType::FAX_BUSSINES, PropertyType::FAX_OTHER
|
PropertyType::FAX_BUSSINES
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,31 +9,30 @@ class PropertyType
|
||||||
const FULLNAME = 10;
|
const FULLNAME = 10;
|
||||||
|
|
||||||
const FIRST_NAME = 15;
|
const FIRST_NAME = 15;
|
||||||
const SUR_NAME = 16;
|
const LAST_NAME = 16;
|
||||||
const MIDDLE_NAME = 17;
|
const MIDDLE_NAME = 17;
|
||||||
const NICK = 18;
|
const NICK_NAME = 18;
|
||||||
|
|
||||||
|
const NAME_PREFIX = 20;
|
||||||
|
const NAME_SUFFIX = 21;
|
||||||
|
|
||||||
const EMAIl_PERSONAL = 30;
|
const EMAIl_PERSONAL = 30;
|
||||||
const EMAIl_BUSSINES = 31;
|
const EMAIl_BUSSINES = 31;
|
||||||
const EMAIl_OTHER = 32;
|
|
||||||
|
|
||||||
const PHONE_PERSONAL = 50;
|
const PHONE_PERSONAL = 50;
|
||||||
const PHONE_BUSSINES = 51;
|
const PHONE_BUSSINES = 51;
|
||||||
const PHONE_OTHER = 52;
|
|
||||||
|
|
||||||
const MOBILE_PERSONAL = 60;
|
const MOBILE_PERSONAL = 60;
|
||||||
const MOBILE_BUSSINES = 61;
|
const MOBILE_BUSSINES = 61;
|
||||||
const MOBILE_OTHER = 62;
|
|
||||||
|
|
||||||
const FAX_PERSONAL = 70;
|
const FAX_PERSONAL = 70;
|
||||||
const FAX_BUSSINES = 71;
|
const FAX_BUSSINES = 71;
|
||||||
const FAX_OTHER = 72;
|
|
||||||
|
|
||||||
const FACEBOOK = 90;
|
const FACEBOOK = 90;
|
||||||
const SKYPE = 91;
|
const SKYPE = 91;
|
||||||
const GITHUB = 92;
|
const GITHUB = 92;
|
||||||
|
|
||||||
const DESCRIPTION = 110;
|
const NOTE = 110;
|
||||||
|
|
||||||
const CUSTOM = 250;
|
const CUSTOM = 250;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,32 @@ class PdoPersonalAddressBook
|
||||||
return 0 < $iId ? (string) $iId : '';
|
return 0 < $iId ? (string) $iId : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $sEmail
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function GetCtagByEmail($sEmail)
|
||||||
|
{
|
||||||
|
$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 string $sEmail
|
||||||
* @param bool $bCreate = false
|
* @param bool $bCreate = false
|
||||||
|
|
@ -142,7 +168,7 @@ class PdoPersonalAddressBook
|
||||||
$this->Sync();
|
$this->Sync();
|
||||||
$iUserID = $this->getUserId($sEmail);
|
$iUserID = $this->getUserId($sEmail);
|
||||||
|
|
||||||
$iIdContact = \strlen($oContact->IdContact) && \is_numeric($oContact->IdContact) ? (int) $oContact->IdContact : 0;
|
$iIdContact = 0 < \strlen($oContact->IdContact) && \is_numeric($oContact->IdContact) ? (int) $oContact->IdContact : 0;
|
||||||
|
|
||||||
$bUpdate = 0 < $iIdContact;
|
$bUpdate = 0 < $iIdContact;
|
||||||
|
|
||||||
|
|
@ -166,8 +192,10 @@ class PdoPersonalAddressBook
|
||||||
{
|
{
|
||||||
$aFreq = $this->getContactFreq($iUserID, $iIdContact);
|
$aFreq = $this->getContactFreq($iUserID, $iIdContact);
|
||||||
|
|
||||||
$sSql = 'UPDATE rainloop_pab_contacts SET id_contact_str = :id_contact_str, display = :display, display_name = :display_name, display_email = :display_email, '.
|
$sSql = 'UPDATE rainloop_pab_contacts SET id_contact_str = :id_contact_str, display = :display, '.
|
||||||
'scope_type = :scope_type, changed = :changed WHERE id_user = :id_user AND id_contact = :id_contact';
|
'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,
|
$this->prepareAndExecute($sSql,
|
||||||
array(
|
array(
|
||||||
|
|
@ -175,10 +203,12 @@ class PdoPersonalAddressBook
|
||||||
':id_contact' => array($iIdContact, \PDO::PARAM_INT),
|
':id_contact' => array($iIdContact, \PDO::PARAM_INT),
|
||||||
':id_contact_str' => array($oContact->IdContactStr, \PDO::PARAM_STR),
|
':id_contact_str' => array($oContact->IdContactStr, \PDO::PARAM_STR),
|
||||||
':display' => array($oContact->Display, \PDO::PARAM_STR),
|
':display' => array($oContact->Display, \PDO::PARAM_STR),
|
||||||
':display_name' => array($oContact->DisplayName, \PDO::PARAM_STR),
|
|
||||||
':display_email' => array($oContact->DisplayEmail, \PDO::PARAM_STR),
|
|
||||||
':scope_type' => array($oContact->ScopeType, \PDO::PARAM_INT),
|
':scope_type' => array($oContact->ScopeType, \PDO::PARAM_INT),
|
||||||
':changed' => array($oContact->Changed, \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)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -194,18 +224,20 @@ class PdoPersonalAddressBook
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$sSql = 'INSERT INTO rainloop_pab_contacts '.
|
$sSql = 'INSERT INTO rainloop_pab_contacts '.
|
||||||
'( id_user, id_contact_str, display, display_name, display_email, scope_type, changed) VALUES '.
|
'( id_user, id_contact_str, display, scope_type, changed, carddav_data, carddav_hash, carddav_size) VALUES '.
|
||||||
'(:id_user, :id_contact_str, :display, :display_name, :display_email, :scope_type, :changed)';
|
'(:id_user, :id_contact_str, :display, :scope_type, :changed, :carddav_data, :carddav_hash, :carddav_size)';
|
||||||
|
|
||||||
$this->prepareAndExecute($sSql,
|
$this->prepareAndExecute($sSql,
|
||||||
array(
|
array(
|
||||||
':id_user' => array($iUserID, \PDO::PARAM_INT),
|
':id_user' => array($iUserID, \PDO::PARAM_INT),
|
||||||
':id_contact_str' => array($oContact->IdContactStr, \PDO::PARAM_STR),
|
':id_contact_str' => array($oContact->IdContactStr, \PDO::PARAM_STR),
|
||||||
':display' => array($oContact->Display, \PDO::PARAM_STR),
|
':display' => array($oContact->Display, \PDO::PARAM_STR),
|
||||||
':display_name' => array($oContact->DisplayName, \PDO::PARAM_STR),
|
|
||||||
':display_email' => array($oContact->DisplayEmail, \PDO::PARAM_STR),
|
|
||||||
':scope_type' => array($oContact->ScopeType, \PDO::PARAM_INT),
|
':scope_type' => array($oContact->ScopeType, \PDO::PARAM_INT),
|
||||||
':changed' => array($oContact->Changed, \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)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -356,9 +388,9 @@ class PdoPersonalAddressBook
|
||||||
($this->bConsiderShare ? ' OR scope_type = :scope_type_share_all' : '').
|
($this->bConsiderShare ? ' OR scope_type = :scope_type_share_all' : '').
|
||||||
') AND (prop_value LIKE :search ESCAPE \'=\' OR ('.
|
') AND (prop_value LIKE :search ESCAPE \'=\' OR ('.
|
||||||
'prop_type IN ('.\implode(',', array(
|
'prop_type IN ('.\implode(',', array(
|
||||||
PropertyType::PHONE_PERSONAL, PropertyType::PHONE_BUSSINES, PropertyType::PHONE_OTHER,
|
PropertyType::PHONE_PERSONAL, PropertyType::PHONE_BUSSINES,
|
||||||
PropertyType::MOBILE_PERSONAL, PropertyType::MOBILE_BUSSINES, PropertyType::MOBILE_OTHER,
|
PropertyType::MOBILE_PERSONAL, PropertyType::MOBILE_BUSSINES,
|
||||||
PropertyType::FAX_PERSONAL, PropertyType::FAX_BUSSINES, PropertyType::FAX_OTHER
|
PropertyType::FAX_PERSONAL, PropertyType::FAX_BUSSINES
|
||||||
)).') AND prop_value_custom LIKE :search_custom_phone'.
|
)).') AND prop_value_custom LIKE :search_custom_phone'.
|
||||||
')) GROUP BY id_contact, id_prop';
|
')) GROUP BY id_contact, id_prop';
|
||||||
|
|
||||||
|
|
@ -467,8 +499,6 @@ class PdoPersonalAddressBook
|
||||||
$oContact->IdContact = (string) $iIdContact;
|
$oContact->IdContact = (string) $iIdContact;
|
||||||
$oContact->IdContactStr = isset($aItem['id_contact_str']) ? (string) $aItem['id_contact_str'] : '';
|
$oContact->IdContactStr = isset($aItem['id_contact_str']) ? (string) $aItem['id_contact_str'] : '';
|
||||||
$oContact->Display = isset($aItem['display']) ? (string) $aItem['display'] : '';
|
$oContact->Display = isset($aItem['display']) ? (string) $aItem['display'] : '';
|
||||||
$oContact->DisplayName = isset($aItem['display_name']) ? (string) $aItem['display_name'] : '';
|
|
||||||
$oContact->DisplayEmail = isset($aItem['display_email']) ? (string) $aItem['display_email'] : '';
|
|
||||||
$oContact->ScopeType = isset($aItem['scope_type']) ? (int) $aItem['scope_type'] :
|
$oContact->ScopeType = isset($aItem['scope_type']) ? (int) $aItem['scope_type'] :
|
||||||
\RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_;
|
\RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_;
|
||||||
$oContact->Changed = isset($aItem['changed']) ? (int) $aItem['changed'] : 0;
|
$oContact->Changed = isset($aItem['changed']) ? (int) $aItem['changed'] : 0;
|
||||||
|
|
@ -551,8 +581,10 @@ class PdoPersonalAddressBook
|
||||||
$iUserID = $this->getUserId($sEmail);
|
$iUserID = $this->getUserId($sEmail);
|
||||||
|
|
||||||
$sSql = 'SELECT * FROM rainloop_pab_contacts '.
|
$sSql = 'SELECT * FROM rainloop_pab_contacts '.
|
||||||
'WHERE id_user = :id_user'.
|
'WHERE ('.
|
||||||
($this->bConsiderShare ? ' OR scope_type = :scope_type_share_all' : '')
|
'id_user = :id_user'.
|
||||||
|
($this->bConsiderShare ? ' OR scope_type = :scope_type_share_all' : '').
|
||||||
|
')'
|
||||||
;
|
;
|
||||||
|
|
||||||
$aParams = array(
|
$aParams = array(
|
||||||
|
|
@ -584,6 +616,7 @@ class PdoPersonalAddressBook
|
||||||
if ($oStmt)
|
if ($oStmt)
|
||||||
{
|
{
|
||||||
$aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC);
|
$aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if (\is_array($aFetch) && 0 < \count($aFetch))
|
if (\is_array($aFetch) && 0 < \count($aFetch))
|
||||||
{
|
{
|
||||||
foreach ($aFetch as $aItem)
|
foreach ($aFetch as $aItem)
|
||||||
|
|
@ -596,12 +629,14 @@ class PdoPersonalAddressBook
|
||||||
$oContact->IdContact = (string) $iIdContact;
|
$oContact->IdContact = (string) $iIdContact;
|
||||||
$oContact->IdContactStr = isset($aItem['id_contact_str']) ? (string) $aItem['id_contact_str'] : '';
|
$oContact->IdContactStr = isset($aItem['id_contact_str']) ? (string) $aItem['id_contact_str'] : '';
|
||||||
$oContact->Display = isset($aItem['display']) ? (string) $aItem['display'] : '';
|
$oContact->Display = isset($aItem['display']) ? (string) $aItem['display'] : '';
|
||||||
$oContact->DisplayName = isset($aItem['display_name']) ? (string) $aItem['display_name'] : '';
|
|
||||||
$oContact->DisplayEmail = isset($aItem['display_email']) ? (string) $aItem['display_email'] : '';
|
|
||||||
$oContact->ScopeType = isset($aItem['scope_type']) ? (int) $aItem['scope_type'] :
|
$oContact->ScopeType = isset($aItem['scope_type']) ? (int) $aItem['scope_type'] :
|
||||||
\RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_;
|
\RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_;
|
||||||
$oContact->Changed = isset($aItem['changed']) ? (int) $aItem['changed'] : 0;
|
$oContact->Changed = isset($aItem['changed']) ? (int) $aItem['changed'] : 0;
|
||||||
$oContact->ReadOnly = $iUserID !== (isset($aItem['id_user']) ? (int) $aItem['id_user'] : 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'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -674,7 +709,7 @@ class PdoPersonalAddressBook
|
||||||
$iUserID = $this->getUserId($sEmail);
|
$iUserID = $this->getUserId($sEmail);
|
||||||
|
|
||||||
$sTypes = implode(',', array(
|
$sTypes = implode(',', array(
|
||||||
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER, PropertyType::FULLNAME
|
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::FULLNAME
|
||||||
));
|
));
|
||||||
|
|
||||||
$sSql = 'SELECT id_contact, id_prop, prop_type, prop_value FROM rainloop_pab_properties '.
|
$sSql = 'SELECT id_contact, id_prop, prop_type, prop_value FROM rainloop_pab_properties '.
|
||||||
|
|
@ -716,7 +751,7 @@ class PdoPersonalAddressBook
|
||||||
$aIdContacts[$iIdContact] = $iIdContact;
|
$aIdContacts[$iIdContact] = $iIdContact;
|
||||||
$iType = isset($aItem['prop_type']) ? (int) $aItem['prop_type'] : PropertyType::UNKNOWN;
|
$iType = isset($aItem['prop_type']) ? (int) $aItem['prop_type'] : PropertyType::UNKNOWN;
|
||||||
|
|
||||||
if (\in_array($iType, array(PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER, PropertyType::FULLNAME)))
|
if (\in_array($iType, array(PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::FULLNAME)))
|
||||||
{
|
{
|
||||||
if (!\in_array($iIdContact, $aSkipIds))
|
if (!\in_array($iIdContact, $aSkipIds))
|
||||||
{
|
{
|
||||||
|
|
@ -745,7 +780,7 @@ class PdoPersonalAddressBook
|
||||||
$oStmt->closeCursor();
|
$oStmt->closeCursor();
|
||||||
|
|
||||||
$sTypes = \implode(',', array(
|
$sTypes = \implode(',', array(
|
||||||
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER, PropertyType::FULLNAME
|
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::FULLNAME
|
||||||
));
|
));
|
||||||
|
|
||||||
$sSql = 'SELECT id_prop, id_contact, prop_type, prop_value FROM rainloop_pab_properties '.
|
$sSql = 'SELECT id_prop, id_contact, prop_type, prop_value FROM rainloop_pab_properties '.
|
||||||
|
|
@ -771,8 +806,7 @@ class PdoPersonalAddressBook
|
||||||
{
|
{
|
||||||
$aNames[$iIdContact] = $aItem['prop_value'];
|
$aNames[$iIdContact] = $aItem['prop_value'];
|
||||||
}
|
}
|
||||||
else if (\in_array($iType,
|
else if (\in_array($iType, array(PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES)))
|
||||||
array(PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER)))
|
|
||||||
{
|
{
|
||||||
if (!isset($aEmails[$iIdContact]))
|
if (!isset($aEmails[$iIdContact]))
|
||||||
{
|
{
|
||||||
|
|
@ -804,8 +838,7 @@ class PdoPersonalAddressBook
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (\in_array($iType,
|
else if (\in_array($iType, array(PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES)))
|
||||||
array(PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER)))
|
|
||||||
{
|
{
|
||||||
$aResult[] = array((string) $aItem['prop_value'],
|
$aResult[] = array((string) $aItem['prop_value'],
|
||||||
isset($aNames[$iIdContact]) ? (string) $aNames[$iIdContact] : '');
|
isset($aNames[$iIdContact]) ? (string) $aNames[$iIdContact] : '');
|
||||||
|
|
@ -858,7 +891,7 @@ class PdoPersonalAddressBook
|
||||||
$iUserID = $this->getUserId($sEmail);
|
$iUserID = $this->getUserId($sEmail);
|
||||||
|
|
||||||
$sTypes = \implode(',', array(
|
$sTypes = \implode(',', array(
|
||||||
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER
|
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES
|
||||||
));
|
));
|
||||||
|
|
||||||
$aExists = array();
|
$aExists = array();
|
||||||
|
|
@ -1203,6 +1236,9 @@ SQLITEINITIAL;
|
||||||
1 => $this->getInitialTablesArray($this->sDsnType),
|
1 => $this->getInitialTablesArray($this->sDsnType),
|
||||||
2 => array(
|
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 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_hashes (
|
'CREATE TABLE IF NOT EXISTS rainloop_pab_users_hashes (
|
||||||
id_user int UNSIGNED NOT NULL,
|
id_user int UNSIGNED NOT NULL,
|
||||||
pass_hash varchar(128) NOT NULL
|
pass_hash varchar(128) NOT NULL
|
||||||
|
|
@ -1214,6 +1250,9 @@ SQLITEINITIAL;
|
||||||
1 => $this->getInitialTablesArray($this->sDsnType),
|
1 => $this->getInitialTablesArray($this->sDsnType),
|
||||||
2 => array(
|
2 => array(
|
||||||
'ALTER TABLE rainloop_pab_contacts ADD id_contact_str varchar(128) NOT NULL DEFAULT \'\';',
|
'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_hashes (
|
'CREATE TABLE rainloop_pab_users_hashes (
|
||||||
id_user integer NOT NULL,
|
id_user integer NOT NULL,
|
||||||
pass_hash varchar(128) NOT NULL
|
pass_hash varchar(128) NOT NULL
|
||||||
|
|
@ -1225,6 +1264,9 @@ SQLITEINITIAL;
|
||||||
1 => $this->getInitialTablesArray($this->sDsnType),
|
1 => $this->getInitialTablesArray($this->sDsnType),
|
||||||
2 => array(
|
2 => array(
|
||||||
'ALTER TABLE rainloop_pab_contacts ADD id_contact_str text NOT NULL DEFAULT \'\';',
|
'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_hashes (
|
'CREATE TABLE rainloop_pab_users_hashes (
|
||||||
id_user integer NOT NULL,
|
id_user integer NOT NULL,
|
||||||
pass_hash text NOT NULL
|
pass_hash text NOT NULL
|
||||||
|
|
@ -1246,7 +1288,7 @@ SQLITEINITIAL;
|
||||||
$aResult = array();
|
$aResult = array();
|
||||||
|
|
||||||
$sTypes = \implode(',', array(
|
$sTypes = \implode(',', array(
|
||||||
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER
|
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.')';
|
$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.')';
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,14 @@ class CardDAV implements \Sabre\CardDAV\Backend\BackendInterface
|
||||||
$this->oAuthBackend = $oAuthBackend;
|
$this->oAuthBackend = $oAuthBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $mData
|
||||||
|
*/
|
||||||
|
private function writeLog($mData)
|
||||||
|
{
|
||||||
|
$this->oPersonalAddressBook->Logger()->WriteMixed($mData);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $sPrincipalUri
|
* @param string $sPrincipalUri
|
||||||
*
|
*
|
||||||
|
|
@ -74,6 +82,8 @@ class CardDAV implements \Sabre\CardDAV\Backend\BackendInterface
|
||||||
*/
|
*/
|
||||||
public function getAddressBooksForUser($sPrincipalUri)
|
public function getAddressBooksForUser($sPrincipalUri)
|
||||||
{
|
{
|
||||||
|
$this->writeLog('::getAddressBooksForUser('.$sPrincipalUri.')');
|
||||||
|
|
||||||
$aAddressBooks = array();
|
$aAddressBooks = array();
|
||||||
|
|
||||||
$sEmail = $this->getAuthEmail($sPrincipalUri);
|
$sEmail = $this->getAuthEmail($sPrincipalUri);
|
||||||
|
|
@ -88,7 +98,7 @@ class CardDAV implements \Sabre\CardDAV\Backend\BackendInterface
|
||||||
'principaluri' => $sPrincipalUri,
|
'principaluri' => $sPrincipalUri,
|
||||||
'{DAV:}displayname' => 'Personal Address Book',
|
'{DAV:}displayname' => 'Personal Address Book',
|
||||||
'{'.\Sabre\CardDAV\Plugin::NS_CARDDAV.'}addressbook-description' => 'Personal Address Book',
|
'{'.\Sabre\CardDAV\Plugin::NS_CARDDAV.'}addressbook-description' => 'Personal Address Book',
|
||||||
'{http://calendarserver.org/ns/}getctag' => 1,
|
'{http://calendarserver.org/ns/}getctag' => $this->oPersonalAddressBook->GetCtagByEmail($sEmail),
|
||||||
'{'.\Sabre\CardDAV\Plugin::NS_CARDDAV.'}supported-address-data' => new \Sabre\CardDAV\Property\SupportedAddressData()
|
'{'.\Sabre\CardDAV\Plugin::NS_CARDDAV.'}supported-address-data' => new \Sabre\CardDAV\Property\SupportedAddressData()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -110,6 +120,8 @@ class CardDAV implements \Sabre\CardDAV\Backend\BackendInterface
|
||||||
*/
|
*/
|
||||||
public function updateAddressBook($mAddressBookID, array $aMutations)
|
public function updateAddressBook($mAddressBookID, array $aMutations)
|
||||||
{
|
{
|
||||||
|
$this->writeLog('::updateAddressBook('.$mAddressBookID.', $aMutations)');
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,6 +136,7 @@ class CardDAV implements \Sabre\CardDAV\Backend\BackendInterface
|
||||||
*/
|
*/
|
||||||
public function createAddressBook($sPrincipalUri, $sUrl, array $aProperties)
|
public function createAddressBook($sPrincipalUri, $sUrl, array $aProperties)
|
||||||
{
|
{
|
||||||
|
$this->writeLog('::createAddressBook('.$sPrincipalUri.', '.$sUrl.', $aProperties)');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -135,6 +148,7 @@ class CardDAV implements \Sabre\CardDAV\Backend\BackendInterface
|
||||||
*/
|
*/
|
||||||
public function deleteAddressBook($mAddressBookID)
|
public function deleteAddressBook($mAddressBookID)
|
||||||
{
|
{
|
||||||
|
$this->writeLog('::deleteAddressBook('.$mAddressBookID.')');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -159,6 +173,8 @@ class CardDAV implements \Sabre\CardDAV\Backend\BackendInterface
|
||||||
*/
|
*/
|
||||||
public function getCards($mAddressBookID)
|
public function getCards($mAddressBookID)
|
||||||
{
|
{
|
||||||
|
$this->writeLog('::getCards('.$mAddressBookID.')');
|
||||||
|
|
||||||
$aResult = array();
|
$aResult = array();
|
||||||
if (!empty($mAddressBookID))
|
if (!empty($mAddressBookID))
|
||||||
{
|
{
|
||||||
|
|
@ -170,12 +186,11 @@ class CardDAV implements \Sabre\CardDAV\Backend\BackendInterface
|
||||||
{
|
{
|
||||||
if (!$oItem->ReadOnly)
|
if (!$oItem->ReadOnly)
|
||||||
{
|
{
|
||||||
$sCardData = $oItem->ToVCardObject()->serialize();
|
|
||||||
$aResult[] = array(
|
$aResult[] = array(
|
||||||
'uri' => $oItem->VCardUID(),
|
'uri' => $oItem->VCardUri(),
|
||||||
'lastmodified' => $oItem->Changed,
|
'lastmodified' => $oItem->Changed,
|
||||||
'etag' => \md5($sCardData),
|
'etag' => $oItem->CardDavHash,
|
||||||
'size' => \strlen($sCardData)
|
'size' => $oItem->CardDavSize
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -197,6 +212,8 @@ class CardDAV implements \Sabre\CardDAV\Backend\BackendInterface
|
||||||
*/
|
*/
|
||||||
public function getCard($mAddressBookID, $sCardUri)
|
public function getCard($mAddressBookID, $sCardUri)
|
||||||
{
|
{
|
||||||
|
$this->writeLog('::getCard('.$mAddressBookID.', '.$sCardUri.')');
|
||||||
|
|
||||||
$oContact = null;
|
$oContact = null;
|
||||||
if (!empty($mAddressBookID) && !empty($sCardUri) && '.vcf' === \substr($sCardUri, -4))
|
if (!empty($mAddressBookID) && !empty($sCardUri) && '.vcf' === \substr($sCardUri, -4))
|
||||||
{
|
{
|
||||||
|
|
@ -209,13 +226,12 @@ class CardDAV implements \Sabre\CardDAV\Backend\BackendInterface
|
||||||
|
|
||||||
if ($oContact)
|
if ($oContact)
|
||||||
{
|
{
|
||||||
$sCardData = $oContact->ToVCardObject()->serialize();
|
|
||||||
return array(
|
return array(
|
||||||
'uri' => $oContact->VCardUID(),
|
'uri' => $oContact->VCardUri(),
|
||||||
'lastmodified' => $oContact->Changed,
|
'lastmodified' => $oContact->Changed,
|
||||||
'etag' => \md5($sCardData),
|
'etag' => $oContact->CardDavHash,
|
||||||
'size' => \strlen($sCardData),
|
'size' => $oContact->CardDavSize,
|
||||||
'carddata' => $sCardData
|
'carddata' => $oContact->CardDavData
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -250,12 +266,18 @@ class CardDAV implements \Sabre\CardDAV\Backend\BackendInterface
|
||||||
*/
|
*/
|
||||||
public function createCard($mAddressBookID, $sCardUri, $sCardData)
|
public function createCard($mAddressBookID, $sCardUri, $sCardData)
|
||||||
{
|
{
|
||||||
|
$this->writeLog('::createCard('.$mAddressBookID.', '.$sCardUri.', $sCardData)');
|
||||||
|
$this->writeLog($sCardData);
|
||||||
|
|
||||||
if (!empty($mAddressBookID) && !empty($sCardUri) && '.vcf' === \substr($sCardUri, -4) && 0 < \strlen($sCardData))
|
if (!empty($mAddressBookID) && !empty($sCardUri) && '.vcf' === \substr($sCardUri, -4) && 0 < \strlen($sCardData))
|
||||||
{
|
{
|
||||||
$sEmail = $this->getAuthEmail('', $mAddressBookID);
|
$sEmail = $this->getAuthEmail('', $mAddressBookID);
|
||||||
if (!empty($sEmail))
|
if (!empty($sEmail))
|
||||||
{
|
{
|
||||||
// TODO
|
$oContact = new \RainLoop\Providers\PersonalAddressBook\Classes\Contact();
|
||||||
|
$oContact->ParseVCard($sCardData);
|
||||||
|
|
||||||
|
$this->oPersonalAddressBook->ContactSave($sEmail, $oContact);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -290,12 +312,25 @@ class CardDAV implements \Sabre\CardDAV\Backend\BackendInterface
|
||||||
*/
|
*/
|
||||||
public function updateCard($mAddressBookID, $sCardUri, $sCardData)
|
public function updateCard($mAddressBookID, $sCardUri, $sCardData)
|
||||||
{
|
{
|
||||||
|
$this->writeLog('::updateCard('.$mAddressBookID.', '.$sCardUri.', $sCardData)');
|
||||||
|
$this->writeLog($sCardData);
|
||||||
|
|
||||||
if (!empty($mAddressBookID) && !empty($sCardUri) && '.vcf' === \substr($sCardUri, -4) && 0 < \strlen($sCardData))
|
if (!empty($mAddressBookID) && !empty($sCardUri) && '.vcf' === \substr($sCardUri, -4) && 0 < \strlen($sCardData))
|
||||||
{
|
{
|
||||||
$sEmail = $this->getAuthEmail('', $mAddressBookID);
|
$sEmail = $this->getAuthEmail('', $mAddressBookID);
|
||||||
if (!empty($sEmail))
|
if (!empty($sEmail))
|
||||||
{
|
{
|
||||||
// TODO
|
$oContact = $this->oPersonalAddressBook->GetContactByID($sEmail, \substr($sCardUri, 0, -4), true);
|
||||||
|
if (!$oContact)
|
||||||
|
{
|
||||||
|
$oContact = new \RainLoop\Providers\PersonalAddressBook\Classes\Contact();
|
||||||
|
}
|
||||||
|
|
||||||
|
$oContact->ParseVCard($sCardData);
|
||||||
|
if ($this->oPersonalAddressBook->ContactSave($sEmail, $oContact) && !empty($oContact->CardDavHash))
|
||||||
|
{
|
||||||
|
return '"'.$oContact->CardDavHash.'"';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -312,6 +347,8 @@ class CardDAV implements \Sabre\CardDAV\Backend\BackendInterface
|
||||||
*/
|
*/
|
||||||
public function deleteCard($mAddressBookID, $sCardUri)
|
public function deleteCard($mAddressBookID, $sCardUri)
|
||||||
{
|
{
|
||||||
|
$this->writeLog('::deleteCard('.$mAddressBookID.', '.$sCardUri.')');
|
||||||
|
|
||||||
$bResult = false;
|
$bResult = false;
|
||||||
$oContact = null;
|
$oContact = null;
|
||||||
if (!empty($mAddressBookID) && !empty($sCardUri) && '.vcf' === \substr($sCardUri, -4))
|
if (!empty($mAddressBookID) && !empty($sCardUri) && '.vcf' === \substr($sCardUri, -4))
|
||||||
|
|
|
||||||
65
rainloop/v/0.0.0/app/libraries/RainLoop/SabreDAV/Logger.php
Normal file
65
rainloop/v/0.0.0/app/libraries/RainLoop/SabreDAV/Logger.php
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace RainLoop\SabreDAV;
|
||||||
|
|
||||||
|
class Logger extends \Sabre\DAV\ServerPlugin
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \MailSo\Log\Logger
|
||||||
|
*/
|
||||||
|
private $oLogger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \MailSo\Log\Logger $oLogger
|
||||||
|
*/
|
||||||
|
public function __construct($oLogger)
|
||||||
|
{
|
||||||
|
$this->oLogger = null;
|
||||||
|
if ($oLogger instanceof \MailSo\Log\Logger)
|
||||||
|
{
|
||||||
|
$this->oLogger = $oLogger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initialize(\Sabre\DAV\Server $server)
|
||||||
|
{
|
||||||
|
$this->server = $server;
|
||||||
|
$this->server->subscribeEvent('beforeMethod', array($this, 'beforeMethod'),30);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a plugin name.
|
||||||
|
*
|
||||||
|
* Using this name other plugins will be able to access other plugins
|
||||||
|
* using \Sabre\DAV\Server::getPlugin
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getPluginName()
|
||||||
|
{
|
||||||
|
return 'logger';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called before any HTTP method, but after authentication.
|
||||||
|
*
|
||||||
|
* @param string $sMethod
|
||||||
|
* @param string $sPath
|
||||||
|
* @throws \Sabre\DAV\Exception\NotAuthenticated
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function beforeMethod($sMethod, $sPath)
|
||||||
|
{
|
||||||
|
if ($this->oLogger)
|
||||||
|
{
|
||||||
|
if (true)
|
||||||
|
{
|
||||||
|
$body = $this->server->httpRequest->getBody(true);
|
||||||
|
$this->server->httpRequest->setBody($body);
|
||||||
|
$this->oLogger->Write($body, \MailSo\Log\Enumerations\Type::INFO, 'DAV');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
461
rainloop/v/0.0.0/app/libraries/RainLoop/SabreDAV/MbStringFix.php
Normal file
461
rainloop/v/0.0.0/app/libraries/RainLoop/SabreDAV/MbStringFix.php
Normal file
|
|
@ -0,0 +1,461 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
if (!function_exists('mb_strtoupper'))
|
||||||
|
{
|
||||||
|
function mb_strtoupper($s, $encoding = INF)
|
||||||
|
{
|
||||||
|
if ('' === $s .= '') return '';
|
||||||
|
|
||||||
|
if (INF === $encoding) $encoding = 'UTF-8';
|
||||||
|
else $encoding = strtoupper($encoding);
|
||||||
|
|
||||||
|
if ('UTF-8' === $encoding || 'UTF8' === $encoding) $encoding = INF;
|
||||||
|
else $s = iconv($encoding, 'UTF-8//IGNORE', $s);
|
||||||
|
|
||||||
|
static $upper;
|
||||||
|
isset($upper) || $upper = unserialize(base64_decode('YToxMDUxOntzOjE6ImEiO3M6MToiQSI7czoxOiJiIjtzOjE6IkIiO3M6MToiYyI7czoxOiJDIjtz
|
||||||
|
OjE6ImQiO3M6MToiRCI7czoxOiJlIjtzOjE6IkUiO3M6MToiZiI7czoxOiJGIjtzOjE6ImciO3M6
|
||||||
|
MToiRyI7czoxOiJoIjtzOjE6IkgiO3M6MToiaSI7czoxOiJJIjtzOjE6ImoiO3M6MToiSiI7czox
|
||||||
|
OiJrIjtzOjE6IksiO3M6MToibCI7czoxOiJMIjtzOjE6Im0iO3M6MToiTSI7czoxOiJuIjtzOjE6
|
||||||
|
Ik4iO3M6MToibyI7czoxOiJPIjtzOjE6InAiO3M6MToiUCI7czoxOiJxIjtzOjE6IlEiO3M6MToi
|
||||||
|
ciI7czoxOiJSIjtzOjE6InMiO3M6MToiUyI7czoxOiJ0IjtzOjE6IlQiO3M6MToidSI7czoxOiJV
|
||||||
|
IjtzOjE6InYiO3M6MToiViI7czoxOiJ3IjtzOjE6IlciO3M6MToieCI7czoxOiJYIjtzOjE6Inki
|
||||||
|
O3M6MToiWSI7czoxOiJ6IjtzOjE6IloiO3M6MjoiwrUiO3M6MjoizpwiO3M6Mjoiw6AiO3M6Mjoi
|
||||||
|
w4AiO3M6Mjoiw6EiO3M6Mjoiw4EiO3M6Mjoiw6IiO3M6Mjoiw4IiO3M6Mjoiw6MiO3M6Mjoiw4Mi
|
||||||
|
O3M6Mjoiw6QiO3M6Mjoiw4QiO3M6Mjoiw6UiO3M6Mjoiw4UiO3M6Mjoiw6YiO3M6Mjoiw4YiO3M6
|
||||||
|
Mjoiw6ciO3M6Mjoiw4ciO3M6Mjoiw6giO3M6Mjoiw4giO3M6Mjoiw6kiO3M6Mjoiw4kiO3M6Mjoi
|
||||||
|
w6oiO3M6Mjoiw4oiO3M6Mjoiw6siO3M6Mjoiw4siO3M6Mjoiw6wiO3M6Mjoiw4wiO3M6Mjoiw60i
|
||||||
|
O3M6Mjoiw40iO3M6Mjoiw64iO3M6Mjoiw44iO3M6Mjoiw68iO3M6Mjoiw48iO3M6Mjoiw7AiO3M6
|
||||||
|
Mjoiw5AiO3M6Mjoiw7EiO3M6Mjoiw5EiO3M6Mjoiw7IiO3M6Mjoiw5IiO3M6Mjoiw7MiO3M6Mjoi
|
||||||
|
w5MiO3M6Mjoiw7QiO3M6Mjoiw5QiO3M6Mjoiw7UiO3M6Mjoiw5UiO3M6Mjoiw7YiO3M6Mjoiw5Yi
|
||||||
|
O3M6Mjoiw7giO3M6Mjoiw5giO3M6Mjoiw7kiO3M6Mjoiw5kiO3M6Mjoiw7oiO3M6Mjoiw5oiO3M6
|
||||||
|
Mjoiw7siO3M6Mjoiw5siO3M6Mjoiw7wiO3M6Mjoiw5wiO3M6Mjoiw70iO3M6Mjoiw50iO3M6Mjoi
|
||||||
|
w74iO3M6Mjoiw54iO3M6Mjoiw78iO3M6MjoixbgiO3M6MjoixIEiO3M6MjoixIAiO3M6MjoixIMi
|
||||||
|
O3M6MjoixIIiO3M6MjoixIUiO3M6MjoixIQiO3M6MjoixIciO3M6MjoixIYiO3M6MjoixIkiO3M6
|
||||||
|
MjoixIgiO3M6MjoixIsiO3M6MjoixIoiO3M6MjoixI0iO3M6MjoixIwiO3M6MjoixI8iO3M6Mjoi
|
||||||
|
xI4iO3M6MjoixJEiO3M6MjoixJAiO3M6MjoixJMiO3M6MjoixJIiO3M6MjoixJUiO3M6MjoixJQi
|
||||||
|
O3M6MjoixJciO3M6MjoixJYiO3M6MjoixJkiO3M6MjoixJgiO3M6MjoixJsiO3M6MjoixJoiO3M6
|
||||||
|
MjoixJ0iO3M6MjoixJwiO3M6MjoixJ8iO3M6MjoixJ4iO3M6MjoixKEiO3M6MjoixKAiO3M6Mjoi
|
||||||
|
xKMiO3M6MjoixKIiO3M6MjoixKUiO3M6MjoixKQiO3M6MjoixKciO3M6MjoixKYiO3M6MjoixKki
|
||||||
|
O3M6MjoixKgiO3M6MjoixKsiO3M6MjoixKoiO3M6MjoixK0iO3M6MjoixKwiO3M6MjoixK8iO3M6
|
||||||
|
MjoixK4iO3M6MjoixLEiO3M6MToiSSI7czoyOiLEsyI7czoyOiLEsiI7czoyOiLEtSI7czoyOiLE
|
||||||
|
tCI7czoyOiLEtyI7czoyOiLEtiI7czoyOiLEuiI7czoyOiLEuSI7czoyOiLEvCI7czoyOiLEuyI7
|
||||||
|
czoyOiLEviI7czoyOiLEvSI7czoyOiLFgCI7czoyOiLEvyI7czoyOiLFgiI7czoyOiLFgSI7czoy
|
||||||
|
OiLFhCI7czoyOiLFgyI7czoyOiLFhiI7czoyOiLFhSI7czoyOiLFiCI7czoyOiLFhyI7czoyOiLF
|
||||||
|
iyI7czoyOiLFiiI7czoyOiLFjSI7czoyOiLFjCI7czoyOiLFjyI7czoyOiLFjiI7czoyOiLFkSI7
|
||||||
|
czoyOiLFkCI7czoyOiLFkyI7czoyOiLFkiI7czoyOiLFlSI7czoyOiLFlCI7czoyOiLFlyI7czoy
|
||||||
|
OiLFliI7czoyOiLFmSI7czoyOiLFmCI7czoyOiLFmyI7czoyOiLFmiI7czoyOiLFnSI7czoyOiLF
|
||||||
|
nCI7czoyOiLFnyI7czoyOiLFniI7czoyOiLFoSI7czoyOiLFoCI7czoyOiLFoyI7czoyOiLFoiI7
|
||||||
|
czoyOiLFpSI7czoyOiLFpCI7czoyOiLFpyI7czoyOiLFpiI7czoyOiLFqSI7czoyOiLFqCI7czoy
|
||||||
|
OiLFqyI7czoyOiLFqiI7czoyOiLFrSI7czoyOiLFrCI7czoyOiLFryI7czoyOiLFriI7czoyOiLF
|
||||||
|
sSI7czoyOiLFsCI7czoyOiLFsyI7czoyOiLFsiI7czoyOiLFtSI7czoyOiLFtCI7czoyOiLFtyI7
|
||||||
|
czoyOiLFtiI7czoyOiLFuiI7czoyOiLFuSI7czoyOiLFvCI7czoyOiLFuyI7czoyOiLFviI7czoy
|
||||||
|
OiLFvSI7czoyOiLFvyI7czoxOiJTIjtzOjI6IsaAIjtzOjI6IsmDIjtzOjI6IsaDIjtzOjI6IsaC
|
||||||
|
IjtzOjI6IsaFIjtzOjI6IsaEIjtzOjI6IsaIIjtzOjI6IsaHIjtzOjI6IsaMIjtzOjI6IsaLIjtz
|
||||||
|
OjI6IsaSIjtzOjI6IsaRIjtzOjI6IsaVIjtzOjI6Ise2IjtzOjI6IsaZIjtzOjI6IsaYIjtzOjI6
|
||||||
|
IsaaIjtzOjI6Isi9IjtzOjI6IsaeIjtzOjI6IsigIjtzOjI6IsahIjtzOjI6IsagIjtzOjI6Isaj
|
||||||
|
IjtzOjI6IsaiIjtzOjI6IsalIjtzOjI6IsakIjtzOjI6IsaoIjtzOjI6IsanIjtzOjI6IsatIjtz
|
||||||
|
OjI6IsasIjtzOjI6IsawIjtzOjI6IsavIjtzOjI6Isa0IjtzOjI6IsazIjtzOjI6Isa2IjtzOjI6
|
||||||
|
Isa1IjtzOjI6Isa5IjtzOjI6Isa4IjtzOjI6Isa9IjtzOjI6Isa8IjtzOjI6Isa/IjtzOjI6Ise3
|
||||||
|
IjtzOjI6IseFIjtzOjI6IseEIjtzOjI6IseGIjtzOjI6IseEIjtzOjI6IseIIjtzOjI6IseHIjtz
|
||||||
|
OjI6IseJIjtzOjI6IseHIjtzOjI6IseLIjtzOjI6IseKIjtzOjI6IseMIjtzOjI6IseKIjtzOjI6
|
||||||
|
IseOIjtzOjI6IseNIjtzOjI6IseQIjtzOjI6IsePIjtzOjI6IseSIjtzOjI6IseRIjtzOjI6IseU
|
||||||
|
IjtzOjI6IseTIjtzOjI6IseWIjtzOjI6IseVIjtzOjI6IseYIjtzOjI6IseXIjtzOjI6IseaIjtz
|
||||||
|
OjI6IseZIjtzOjI6IsecIjtzOjI6IsebIjtzOjI6IsedIjtzOjI6IsaOIjtzOjI6IsefIjtzOjI6
|
||||||
|
IseeIjtzOjI6IsehIjtzOjI6IsegIjtzOjI6IsejIjtzOjI6IseiIjtzOjI6IselIjtzOjI6Isek
|
||||||
|
IjtzOjI6IsenIjtzOjI6IsemIjtzOjI6IsepIjtzOjI6IseoIjtzOjI6IserIjtzOjI6IseqIjtz
|
||||||
|
OjI6IsetIjtzOjI6IsesIjtzOjI6IsevIjtzOjI6IseuIjtzOjI6IseyIjtzOjI6IsexIjtzOjI6
|
||||||
|
IsezIjtzOjI6IsexIjtzOjI6Ise1IjtzOjI6Ise0IjtzOjI6Ise5IjtzOjI6Ise4IjtzOjI6Ise7
|
||||||
|
IjtzOjI6Ise6IjtzOjI6Ise9IjtzOjI6Ise8IjtzOjI6Ise/IjtzOjI6Ise+IjtzOjI6IsiBIjtz
|
||||||
|
OjI6IsiAIjtzOjI6IsiDIjtzOjI6IsiCIjtzOjI6IsiFIjtzOjI6IsiEIjtzOjI6IsiHIjtzOjI6
|
||||||
|
IsiGIjtzOjI6IsiJIjtzOjI6IsiIIjtzOjI6IsiLIjtzOjI6IsiKIjtzOjI6IsiNIjtzOjI6IsiM
|
||||||
|
IjtzOjI6IsiPIjtzOjI6IsiOIjtzOjI6IsiRIjtzOjI6IsiQIjtzOjI6IsiTIjtzOjI6IsiSIjtz
|
||||||
|
OjI6IsiVIjtzOjI6IsiUIjtzOjI6IsiXIjtzOjI6IsiWIjtzOjI6IsiZIjtzOjI6IsiYIjtzOjI6
|
||||||
|
IsibIjtzOjI6IsiaIjtzOjI6IsidIjtzOjI6IsicIjtzOjI6IsifIjtzOjI6IsieIjtzOjI6Isij
|
||||||
|
IjtzOjI6IsiiIjtzOjI6IsilIjtzOjI6IsikIjtzOjI6IsinIjtzOjI6IsimIjtzOjI6IsipIjtz
|
||||||
|
OjI6IsioIjtzOjI6IsirIjtzOjI6IsiqIjtzOjI6IsitIjtzOjI6IsisIjtzOjI6IsivIjtzOjI6
|
||||||
|
IsiuIjtzOjI6IsixIjtzOjI6IsiwIjtzOjI6IsizIjtzOjI6IsiyIjtzOjI6Isi8IjtzOjI6Isi7
|
||||||
|
IjtzOjI6Isi/IjtzOjM6IuKxviI7czoyOiLJgCI7czozOiLisb8iO3M6MjoiyYIiO3M6MjoiyYEi
|
||||||
|
O3M6MjoiyYciO3M6MjoiyYYiO3M6MjoiyYkiO3M6MjoiyYgiO3M6MjoiyYsiO3M6MjoiyYoiO3M6
|
||||||
|
MjoiyY0iO3M6MjoiyYwiO3M6MjoiyY8iO3M6MjoiyY4iO3M6MjoiyZAiO3M6Mzoi4rGvIjtzOjI6
|
||||||
|
IsmRIjtzOjM6IuKxrSI7czoyOiLJkiI7czozOiLisbAiO3M6MjoiyZMiO3M6MjoixoEiO3M6Mjoi
|
||||||
|
yZQiO3M6MjoixoYiO3M6MjoiyZYiO3M6MjoixokiO3M6MjoiyZciO3M6MjoixooiO3M6MjoiyZki
|
||||||
|
O3M6Mjoixo8iO3M6MjoiyZsiO3M6MjoixpAiO3M6MjoiyaAiO3M6MjoixpMiO3M6MjoiyaMiO3M6
|
||||||
|
MjoixpQiO3M6MjoiyaUiO3M6Mzoi6p6NIjtzOjI6IsmmIjtzOjM6IuqeqiI7czoyOiLJqCI7czoy
|
||||||
|
OiLGlyI7czoyOiLJqSI7czoyOiLGliI7czoyOiLJqyI7czozOiLisaIiO3M6Mjoiya8iO3M6Mjoi
|
||||||
|
xpwiO3M6MjoiybEiO3M6Mzoi4rGuIjtzOjI6IsmyIjtzOjI6IsadIjtzOjI6Ism1IjtzOjI6Isaf
|
||||||
|
IjtzOjI6Ism9IjtzOjM6IuKxpCI7czoyOiLKgCI7czoyOiLGpiI7czoyOiLKgyI7czoyOiLGqSI7
|
||||||
|
czoyOiLKiCI7czoyOiLGriI7czoyOiLKiSI7czoyOiLJhCI7czoyOiLKiiI7czoyOiLGsSI7czoy
|
||||||
|
OiLKiyI7czoyOiLGsiI7czoyOiLKjCI7czoyOiLJhSI7czoyOiLKkiI7czoyOiLGtyI7czoyOiLN
|
||||||
|
hSI7czoyOiLOmSI7czoyOiLNsSI7czoyOiLNsCI7czoyOiLNsyI7czoyOiLNsiI7czoyOiLNtyI7
|
||||||
|
czoyOiLNtiI7czoyOiLNuyI7czoyOiLPvSI7czoyOiLNvCI7czoyOiLPviI7czoyOiLNvSI7czoy
|
||||||
|
OiLPvyI7czoyOiLOrCI7czoyOiLOhiI7czoyOiLOrSI7czoyOiLOiCI7czoyOiLOriI7czoyOiLO
|
||||||
|
iSI7czoyOiLOryI7czoyOiLOiiI7czoyOiLOsSI7czoyOiLOkSI7czoyOiLOsiI7czoyOiLOkiI7
|
||||||
|
czoyOiLOsyI7czoyOiLOkyI7czoyOiLOtCI7czoyOiLOlCI7czoyOiLOtSI7czoyOiLOlSI7czoy
|
||||||
|
OiLOtiI7czoyOiLOliI7czoyOiLOtyI7czoyOiLOlyI7czoyOiLOuCI7czoyOiLOmCI7czoyOiLO
|
||||||
|
uSI7czoyOiLOmSI7czoyOiLOuiI7czoyOiLOmiI7czoyOiLOuyI7czoyOiLOmyI7czoyOiLOvCI7
|
||||||
|
czoyOiLOnCI7czoyOiLOvSI7czoyOiLOnSI7czoyOiLOviI7czoyOiLOniI7czoyOiLOvyI7czoy
|
||||||
|
OiLOnyI7czoyOiLPgCI7czoyOiLOoCI7czoyOiLPgSI7czoyOiLOoSI7czoyOiLPgiI7czoyOiLO
|
||||||
|
oyI7czoyOiLPgyI7czoyOiLOoyI7czoyOiLPhCI7czoyOiLOpCI7czoyOiLPhSI7czoyOiLOpSI7
|
||||||
|
czoyOiLPhiI7czoyOiLOpiI7czoyOiLPhyI7czoyOiLOpyI7czoyOiLPiCI7czoyOiLOqCI7czoy
|
||||||
|
OiLPiSI7czoyOiLOqSI7czoyOiLPiiI7czoyOiLOqiI7czoyOiLPiyI7czoyOiLOqyI7czoyOiLP
|
||||||
|
jCI7czoyOiLOjCI7czoyOiLPjSI7czoyOiLOjiI7czoyOiLPjiI7czoyOiLOjyI7czoyOiLPkCI7
|
||||||
|
czoyOiLOkiI7czoyOiLPkSI7czoyOiLOmCI7czoyOiLPlSI7czoyOiLOpiI7czoyOiLPliI7czoy
|
||||||
|
OiLOoCI7czoyOiLPlyI7czoyOiLPjyI7czoyOiLPmSI7czoyOiLPmCI7czoyOiLPmyI7czoyOiLP
|
||||||
|
miI7czoyOiLPnSI7czoyOiLPnCI7czoyOiLPnyI7czoyOiLPniI7czoyOiLPoSI7czoyOiLPoCI7
|
||||||
|
czoyOiLPoyI7czoyOiLPoiI7czoyOiLPpSI7czoyOiLPpCI7czoyOiLPpyI7czoyOiLPpiI7czoy
|
||||||
|
OiLPqSI7czoyOiLPqCI7czoyOiLPqyI7czoyOiLPqiI7czoyOiLPrSI7czoyOiLPrCI7czoyOiLP
|
||||||
|
ryI7czoyOiLPriI7czoyOiLPsCI7czoyOiLOmiI7czoyOiLPsSI7czoyOiLOoSI7czoyOiLPsiI7
|
||||||
|
czoyOiLPuSI7czoyOiLPtSI7czoyOiLOlSI7czoyOiLPuCI7czoyOiLPtyI7czoyOiLPuyI7czoy
|
||||||
|
OiLPuiI7czoyOiLQsCI7czoyOiLQkCI7czoyOiLQsSI7czoyOiLQkSI7czoyOiLQsiI7czoyOiLQ
|
||||||
|
kiI7czoyOiLQsyI7czoyOiLQkyI7czoyOiLQtCI7czoyOiLQlCI7czoyOiLQtSI7czoyOiLQlSI7
|
||||||
|
czoyOiLQtiI7czoyOiLQliI7czoyOiLQtyI7czoyOiLQlyI7czoyOiLQuCI7czoyOiLQmCI7czoy
|
||||||
|
OiLQuSI7czoyOiLQmSI7czoyOiLQuiI7czoyOiLQmiI7czoyOiLQuyI7czoyOiLQmyI7czoyOiLQ
|
||||||
|
vCI7czoyOiLQnCI7czoyOiLQvSI7czoyOiLQnSI7czoyOiLQviI7czoyOiLQniI7czoyOiLQvyI7
|
||||||
|
czoyOiLQnyI7czoyOiLRgCI7czoyOiLQoCI7czoyOiLRgSI7czoyOiLQoSI7czoyOiLRgiI7czoy
|
||||||
|
OiLQoiI7czoyOiLRgyI7czoyOiLQoyI7czoyOiLRhCI7czoyOiLQpCI7czoyOiLRhSI7czoyOiLQ
|
||||||
|
pSI7czoyOiLRhiI7czoyOiLQpiI7czoyOiLRhyI7czoyOiLQpyI7czoyOiLRiCI7czoyOiLQqCI7
|
||||||
|
czoyOiLRiSI7czoyOiLQqSI7czoyOiLRiiI7czoyOiLQqiI7czoyOiLRiyI7czoyOiLQqyI7czoy
|
||||||
|
OiLRjCI7czoyOiLQrCI7czoyOiLRjSI7czoyOiLQrSI7czoyOiLRjiI7czoyOiLQriI7czoyOiLR
|
||||||
|
jyI7czoyOiLQryI7czoyOiLRkCI7czoyOiLQgCI7czoyOiLRkSI7czoyOiLQgSI7czoyOiLRkiI7
|
||||||
|
czoyOiLQgiI7czoyOiLRkyI7czoyOiLQgyI7czoyOiLRlCI7czoyOiLQhCI7czoyOiLRlSI7czoy
|
||||||
|
OiLQhSI7czoyOiLRliI7czoyOiLQhiI7czoyOiLRlyI7czoyOiLQhyI7czoyOiLRmCI7czoyOiLQ
|
||||||
|
iCI7czoyOiLRmSI7czoyOiLQiSI7czoyOiLRmiI7czoyOiLQiiI7czoyOiLRmyI7czoyOiLQiyI7
|
||||||
|
czoyOiLRnCI7czoyOiLQjCI7czoyOiLRnSI7czoyOiLQjSI7czoyOiLRniI7czoyOiLQjiI7czoy
|
||||||
|
OiLRnyI7czoyOiLQjyI7czoyOiLRoSI7czoyOiLRoCI7czoyOiLRoyI7czoyOiLRoiI7czoyOiLR
|
||||||
|
pSI7czoyOiLRpCI7czoyOiLRpyI7czoyOiLRpiI7czoyOiLRqSI7czoyOiLRqCI7czoyOiLRqyI7
|
||||||
|
czoyOiLRqiI7czoyOiLRrSI7czoyOiLRrCI7czoyOiLRryI7czoyOiLRriI7czoyOiLRsSI7czoy
|
||||||
|
OiLRsCI7czoyOiLRsyI7czoyOiLRsiI7czoyOiLRtSI7czoyOiLRtCI7czoyOiLRtyI7czoyOiLR
|
||||||
|
tiI7czoyOiLRuSI7czoyOiLRuCI7czoyOiLRuyI7czoyOiLRuiI7czoyOiLRvSI7czoyOiLRvCI7
|
||||||
|
czoyOiLRvyI7czoyOiLRviI7czoyOiLSgSI7czoyOiLSgCI7czoyOiLSiyI7czoyOiLSiiI7czoy
|
||||||
|
OiLSjSI7czoyOiLSjCI7czoyOiLSjyI7czoyOiLSjiI7czoyOiLSkSI7czoyOiLSkCI7czoyOiLS
|
||||||
|
kyI7czoyOiLSkiI7czoyOiLSlSI7czoyOiLSlCI7czoyOiLSlyI7czoyOiLSliI7czoyOiLSmSI7
|
||||||
|
czoyOiLSmCI7czoyOiLSmyI7czoyOiLSmiI7czoyOiLSnSI7czoyOiLSnCI7czoyOiLSnyI7czoy
|
||||||
|
OiLSniI7czoyOiLSoSI7czoyOiLSoCI7czoyOiLSoyI7czoyOiLSoiI7czoyOiLSpSI7czoyOiLS
|
||||||
|
pCI7czoyOiLSpyI7czoyOiLSpiI7czoyOiLSqSI7czoyOiLSqCI7czoyOiLSqyI7czoyOiLSqiI7
|
||||||
|
czoyOiLSrSI7czoyOiLSrCI7czoyOiLSryI7czoyOiLSriI7czoyOiLSsSI7czoyOiLSsCI7czoy
|
||||||
|
OiLSsyI7czoyOiLSsiI7czoyOiLStSI7czoyOiLStCI7czoyOiLStyI7czoyOiLStiI7czoyOiLS
|
||||||
|
uSI7czoyOiLSuCI7czoyOiLSuyI7czoyOiLSuiI7czoyOiLSvSI7czoyOiLSvCI7czoyOiLSvyI7
|
||||||
|
czoyOiLSviI7czoyOiLTgiI7czoyOiLTgSI7czoyOiLThCI7czoyOiLTgyI7czoyOiLThiI7czoy
|
||||||
|
OiLThSI7czoyOiLTiCI7czoyOiLThyI7czoyOiLTiiI7czoyOiLTiSI7czoyOiLTjCI7czoyOiLT
|
||||||
|
iyI7czoyOiLTjiI7czoyOiLTjSI7czoyOiLTjyI7czoyOiLTgCI7czoyOiLTkSI7czoyOiLTkCI7
|
||||||
|
czoyOiLTkyI7czoyOiLTkiI7czoyOiLTlSI7czoyOiLTlCI7czoyOiLTlyI7czoyOiLTliI7czoy
|
||||||
|
OiLTmSI7czoyOiLTmCI7czoyOiLTmyI7czoyOiLTmiI7czoyOiLTnSI7czoyOiLTnCI7czoyOiLT
|
||||||
|
nyI7czoyOiLTniI7czoyOiLToSI7czoyOiLToCI7czoyOiLToyI7czoyOiLToiI7czoyOiLTpSI7
|
||||||
|
czoyOiLTpCI7czoyOiLTpyI7czoyOiLTpiI7czoyOiLTqSI7czoyOiLTqCI7czoyOiLTqyI7czoy
|
||||||
|
OiLTqiI7czoyOiLTrSI7czoyOiLTrCI7czoyOiLTryI7czoyOiLTriI7czoyOiLTsSI7czoyOiLT
|
||||||
|
sCI7czoyOiLTsyI7czoyOiLTsiI7czoyOiLTtSI7czoyOiLTtCI7czoyOiLTtyI7czoyOiLTtiI7
|
||||||
|
czoyOiLTuSI7czoyOiLTuCI7czoyOiLTuyI7czoyOiLTuiI7czoyOiLTvSI7czoyOiLTvCI7czoy
|
||||||
|
OiLTvyI7czoyOiLTviI7czoyOiLUgSI7czoyOiLUgCI7czoyOiLUgyI7czoyOiLUgiI7czoyOiLU
|
||||||
|
hSI7czoyOiLUhCI7czoyOiLUhyI7czoyOiLUhiI7czoyOiLUiSI7czoyOiLUiCI7czoyOiLUiyI7
|
||||||
|
czoyOiLUiiI7czoyOiLUjSI7czoyOiLUjCI7czoyOiLUjyI7czoyOiLUjiI7czoyOiLUkSI7czoy
|
||||||
|
OiLUkCI7czoyOiLUkyI7czoyOiLUkiI7czoyOiLUlSI7czoyOiLUlCI7czoyOiLUlyI7czoyOiLU
|
||||||
|
liI7czoyOiLUmSI7czoyOiLUmCI7czoyOiLUmyI7czoyOiLUmiI7czoyOiLUnSI7czoyOiLUnCI7
|
||||||
|
czoyOiLUnyI7czoyOiLUniI7czoyOiLUoSI7czoyOiLUoCI7czoyOiLUoyI7czoyOiLUoiI7czoy
|
||||||
|
OiLUpSI7czoyOiLUpCI7czoyOiLUpyI7czoyOiLUpiI7czoyOiLVoSI7czoyOiLUsSI7czoyOiLV
|
||||||
|
oiI7czoyOiLUsiI7czoyOiLVoyI7czoyOiLUsyI7czoyOiLVpCI7czoyOiLUtCI7czoyOiLVpSI7
|
||||||
|
czoyOiLUtSI7czoyOiLVpiI7czoyOiLUtiI7czoyOiLVpyI7czoyOiLUtyI7czoyOiLVqCI7czoy
|
||||||
|
OiLUuCI7czoyOiLVqSI7czoyOiLUuSI7czoyOiLVqiI7czoyOiLUuiI7czoyOiLVqyI7czoyOiLU
|
||||||
|
uyI7czoyOiLVrCI7czoyOiLUvCI7czoyOiLVrSI7czoyOiLUvSI7czoyOiLVriI7czoyOiLUviI7
|
||||||
|
czoyOiLVryI7czoyOiLUvyI7czoyOiLVsCI7czoyOiLVgCI7czoyOiLVsSI7czoyOiLVgSI7czoy
|
||||||
|
OiLVsiI7czoyOiLVgiI7czoyOiLVsyI7czoyOiLVgyI7czoyOiLVtCI7czoyOiLVhCI7czoyOiLV
|
||||||
|
tSI7czoyOiLVhSI7czoyOiLVtiI7czoyOiLVhiI7czoyOiLVtyI7czoyOiLVhyI7czoyOiLVuCI7
|
||||||
|
czoyOiLViCI7czoyOiLVuSI7czoyOiLViSI7czoyOiLVuiI7czoyOiLViiI7czoyOiLVuyI7czoy
|
||||||
|
OiLViyI7czoyOiLVvCI7czoyOiLVjCI7czoyOiLVvSI7czoyOiLVjSI7czoyOiLVviI7czoyOiLV
|
||||||
|
jiI7czoyOiLVvyI7czoyOiLVjyI7czoyOiLWgCI7czoyOiLVkCI7czoyOiLWgSI7czoyOiLVkSI7
|
||||||
|
czoyOiLWgiI7czoyOiLVkiI7czoyOiLWgyI7czoyOiLVkyI7czoyOiLWhCI7czoyOiLVlCI7czoy
|
||||||
|
OiLWhSI7czoyOiLVlSI7czoyOiLWhiI7czoyOiLVliI7czozOiLhtbkiO3M6Mzoi6p29IjtzOjM6
|
||||||
|
IuG1vSI7czozOiLisaMiO3M6Mzoi4biBIjtzOjM6IuG4gCI7czozOiLhuIMiO3M6Mzoi4biCIjtz
|
||||||
|
OjM6IuG4hSI7czozOiLhuIQiO3M6Mzoi4biHIjtzOjM6IuG4hiI7czozOiLhuIkiO3M6Mzoi4biI
|
||||||
|
IjtzOjM6IuG4iyI7czozOiLhuIoiO3M6Mzoi4biNIjtzOjM6IuG4jCI7czozOiLhuI8iO3M6Mzoi
|
||||||
|
4biOIjtzOjM6IuG4kSI7czozOiLhuJAiO3M6Mzoi4biTIjtzOjM6IuG4kiI7czozOiLhuJUiO3M6
|
||||||
|
Mzoi4biUIjtzOjM6IuG4lyI7czozOiLhuJYiO3M6Mzoi4biZIjtzOjM6IuG4mCI7czozOiLhuJsi
|
||||||
|
O3M6Mzoi4biaIjtzOjM6IuG4nSI7czozOiLhuJwiO3M6Mzoi4bifIjtzOjM6IuG4niI7czozOiLh
|
||||||
|
uKEiO3M6Mzoi4bigIjtzOjM6IuG4oyI7czozOiLhuKIiO3M6Mzoi4bilIjtzOjM6IuG4pCI7czoz
|
||||||
|
OiLhuKciO3M6Mzoi4bimIjtzOjM6IuG4qSI7czozOiLhuKgiO3M6Mzoi4birIjtzOjM6IuG4qiI7
|
||||||
|
czozOiLhuK0iO3M6Mzoi4bisIjtzOjM6IuG4ryI7czozOiLhuK4iO3M6Mzoi4bixIjtzOjM6IuG4
|
||||||
|
sCI7czozOiLhuLMiO3M6Mzoi4biyIjtzOjM6IuG4tSI7czozOiLhuLQiO3M6Mzoi4bi3IjtzOjM6
|
||||||
|
IuG4tiI7czozOiLhuLkiO3M6Mzoi4bi4IjtzOjM6IuG4uyI7czozOiLhuLoiO3M6Mzoi4bi9Ijtz
|
||||||
|
OjM6IuG4vCI7czozOiLhuL8iO3M6Mzoi4bi+IjtzOjM6IuG5gSI7czozOiLhuYAiO3M6Mzoi4bmD
|
||||||
|
IjtzOjM6IuG5giI7czozOiLhuYUiO3M6Mzoi4bmEIjtzOjM6IuG5hyI7czozOiLhuYYiO3M6Mzoi
|
||||||
|
4bmJIjtzOjM6IuG5iCI7czozOiLhuYsiO3M6Mzoi4bmKIjtzOjM6IuG5jSI7czozOiLhuYwiO3M6
|
||||||
|
Mzoi4bmPIjtzOjM6IuG5jiI7czozOiLhuZEiO3M6Mzoi4bmQIjtzOjM6IuG5kyI7czozOiLhuZIi
|
||||||
|
O3M6Mzoi4bmVIjtzOjM6IuG5lCI7czozOiLhuZciO3M6Mzoi4bmWIjtzOjM6IuG5mSI7czozOiLh
|
||||||
|
uZgiO3M6Mzoi4bmbIjtzOjM6IuG5miI7czozOiLhuZ0iO3M6Mzoi4bmcIjtzOjM6IuG5nyI7czoz
|
||||||
|
OiLhuZ4iO3M6Mzoi4bmhIjtzOjM6IuG5oCI7czozOiLhuaMiO3M6Mzoi4bmiIjtzOjM6IuG5pSI7
|
||||||
|
czozOiLhuaQiO3M6Mzoi4bmnIjtzOjM6IuG5piI7czozOiLhuakiO3M6Mzoi4bmoIjtzOjM6IuG5
|
||||||
|
qyI7czozOiLhuaoiO3M6Mzoi4bmtIjtzOjM6IuG5rCI7czozOiLhua8iO3M6Mzoi4bmuIjtzOjM6
|
||||||
|
IuG5sSI7czozOiLhubAiO3M6Mzoi4bmzIjtzOjM6IuG5siI7czozOiLhubUiO3M6Mzoi4bm0Ijtz
|
||||||
|
OjM6IuG5tyI7czozOiLhubYiO3M6Mzoi4bm5IjtzOjM6IuG5uCI7czozOiLhubsiO3M6Mzoi4bm6
|
||||||
|
IjtzOjM6IuG5vSI7czozOiLhubwiO3M6Mzoi4bm/IjtzOjM6IuG5viI7czozOiLhuoEiO3M6Mzoi
|
||||||
|
4bqAIjtzOjM6IuG6gyI7czozOiLhuoIiO3M6Mzoi4bqFIjtzOjM6IuG6hCI7czozOiLhuociO3M6
|
||||||
|
Mzoi4bqGIjtzOjM6IuG6iSI7czozOiLhuogiO3M6Mzoi4bqLIjtzOjM6IuG6iiI7czozOiLhuo0i
|
||||||
|
O3M6Mzoi4bqMIjtzOjM6IuG6jyI7czozOiLhuo4iO3M6Mzoi4bqRIjtzOjM6IuG6kCI7czozOiLh
|
||||||
|
upMiO3M6Mzoi4bqSIjtzOjM6IuG6lSI7czozOiLhupQiO3M6Mzoi4bqbIjtzOjM6IuG5oCI7czoz
|
||||||
|
OiLhuqEiO3M6Mzoi4bqgIjtzOjM6IuG6oyI7czozOiLhuqIiO3M6Mzoi4bqlIjtzOjM6IuG6pCI7
|
||||||
|
czozOiLhuqciO3M6Mzoi4bqmIjtzOjM6IuG6qSI7czozOiLhuqgiO3M6Mzoi4bqrIjtzOjM6IuG6
|
||||||
|
qiI7czozOiLhuq0iO3M6Mzoi4bqsIjtzOjM6IuG6ryI7czozOiLhuq4iO3M6Mzoi4bqxIjtzOjM6
|
||||||
|
IuG6sCI7czozOiLhurMiO3M6Mzoi4bqyIjtzOjM6IuG6tSI7czozOiLhurQiO3M6Mzoi4bq3Ijtz
|
||||||
|
OjM6IuG6tiI7czozOiLhurkiO3M6Mzoi4bq4IjtzOjM6IuG6uyI7czozOiLhuroiO3M6Mzoi4bq9
|
||||||
|
IjtzOjM6IuG6vCI7czozOiLhur8iO3M6Mzoi4bq+IjtzOjM6IuG7gSI7czozOiLhu4AiO3M6Mzoi
|
||||||
|
4buDIjtzOjM6IuG7giI7czozOiLhu4UiO3M6Mzoi4buEIjtzOjM6IuG7hyI7czozOiLhu4YiO3M6
|
||||||
|
Mzoi4buJIjtzOjM6IuG7iCI7czozOiLhu4siO3M6Mzoi4buKIjtzOjM6IuG7jSI7czozOiLhu4wi
|
||||||
|
O3M6Mzoi4buPIjtzOjM6IuG7jiI7czozOiLhu5EiO3M6Mzoi4buQIjtzOjM6IuG7kyI7czozOiLh
|
||||||
|
u5IiO3M6Mzoi4buVIjtzOjM6IuG7lCI7czozOiLhu5ciO3M6Mzoi4buWIjtzOjM6IuG7mSI7czoz
|
||||||
|
OiLhu5giO3M6Mzoi4bubIjtzOjM6IuG7miI7czozOiLhu50iO3M6Mzoi4bucIjtzOjM6IuG7nyI7
|
||||||
|
czozOiLhu54iO3M6Mzoi4buhIjtzOjM6IuG7oCI7czozOiLhu6MiO3M6Mzoi4buiIjtzOjM6IuG7
|
||||||
|
pSI7czozOiLhu6QiO3M6Mzoi4bunIjtzOjM6IuG7piI7czozOiLhu6kiO3M6Mzoi4buoIjtzOjM6
|
||||||
|
IuG7qyI7czozOiLhu6oiO3M6Mzoi4butIjtzOjM6IuG7rCI7czozOiLhu68iO3M6Mzoi4buuIjtz
|
||||||
|
OjM6IuG7sSI7czozOiLhu7AiO3M6Mzoi4buzIjtzOjM6IuG7siI7czozOiLhu7UiO3M6Mzoi4bu0
|
||||||
|
IjtzOjM6IuG7tyI7czozOiLhu7YiO3M6Mzoi4bu5IjtzOjM6IuG7uCI7czozOiLhu7siO3M6Mzoi
|
||||||
|
4bu6IjtzOjM6IuG7vSI7czozOiLhu7wiO3M6Mzoi4bu/IjtzOjM6IuG7viI7czozOiLhvIAiO3M6
|
||||||
|
Mzoi4byIIjtzOjM6IuG8gSI7czozOiLhvIkiO3M6Mzoi4byCIjtzOjM6IuG8iiI7czozOiLhvIMi
|
||||||
|
O3M6Mzoi4byLIjtzOjM6IuG8hCI7czozOiLhvIwiO3M6Mzoi4byFIjtzOjM6IuG8jSI7czozOiLh
|
||||||
|
vIYiO3M6Mzoi4byOIjtzOjM6IuG8hyI7czozOiLhvI8iO3M6Mzoi4byQIjtzOjM6IuG8mCI7czoz
|
||||||
|
OiLhvJEiO3M6Mzoi4byZIjtzOjM6IuG8kiI7czozOiLhvJoiO3M6Mzoi4byTIjtzOjM6IuG8myI7
|
||||||
|
czozOiLhvJQiO3M6Mzoi4bycIjtzOjM6IuG8lSI7czozOiLhvJ0iO3M6Mzoi4bygIjtzOjM6IuG8
|
||||||
|
qCI7czozOiLhvKEiO3M6Mzoi4bypIjtzOjM6IuG8oiI7czozOiLhvKoiO3M6Mzoi4byjIjtzOjM6
|
||||||
|
IuG8qyI7czozOiLhvKQiO3M6Mzoi4bysIjtzOjM6IuG8pSI7czozOiLhvK0iO3M6Mzoi4bymIjtz
|
||||||
|
OjM6IuG8riI7czozOiLhvKciO3M6Mzoi4byvIjtzOjM6IuG8sCI7czozOiLhvLgiO3M6Mzoi4byx
|
||||||
|
IjtzOjM6IuG8uSI7czozOiLhvLIiO3M6Mzoi4by6IjtzOjM6IuG8syI7czozOiLhvLsiO3M6Mzoi
|
||||||
|
4by0IjtzOjM6IuG8vCI7czozOiLhvLUiO3M6Mzoi4by9IjtzOjM6IuG8tiI7czozOiLhvL4iO3M6
|
||||||
|
Mzoi4by3IjtzOjM6IuG8vyI7czozOiLhvYAiO3M6Mzoi4b2IIjtzOjM6IuG9gSI7czozOiLhvYki
|
||||||
|
O3M6Mzoi4b2CIjtzOjM6IuG9iiI7czozOiLhvYMiO3M6Mzoi4b2LIjtzOjM6IuG9hCI7czozOiLh
|
||||||
|
vYwiO3M6Mzoi4b2FIjtzOjM6IuG9jSI7czozOiLhvZEiO3M6Mzoi4b2ZIjtzOjM6IuG9kyI7czoz
|
||||||
|
OiLhvZsiO3M6Mzoi4b2VIjtzOjM6IuG9nSI7czozOiLhvZciO3M6Mzoi4b2fIjtzOjM6IuG9oCI7
|
||||||
|
czozOiLhvagiO3M6Mzoi4b2hIjtzOjM6IuG9qSI7czozOiLhvaIiO3M6Mzoi4b2qIjtzOjM6IuG9
|
||||||
|
oyI7czozOiLhvasiO3M6Mzoi4b2kIjtzOjM6IuG9rCI7czozOiLhvaUiO3M6Mzoi4b2tIjtzOjM6
|
||||||
|
IuG9piI7czozOiLhva4iO3M6Mzoi4b2nIjtzOjM6IuG9ryI7czozOiLhvbAiO3M6Mzoi4b66Ijtz
|
||||||
|
OjM6IuG9sSI7czozOiLhvrsiO3M6Mzoi4b2yIjtzOjM6IuG/iCI7czozOiLhvbMiO3M6Mzoi4b+J
|
||||||
|
IjtzOjM6IuG9tCI7czozOiLhv4oiO3M6Mzoi4b21IjtzOjM6IuG/iyI7czozOiLhvbYiO3M6Mzoi
|
||||||
|
4b+aIjtzOjM6IuG9tyI7czozOiLhv5siO3M6Mzoi4b24IjtzOjM6IuG/uCI7czozOiLhvbkiO3M6
|
||||||
|
Mzoi4b+5IjtzOjM6IuG9uiI7czozOiLhv6oiO3M6Mzoi4b27IjtzOjM6IuG/qyI7czozOiLhvbwi
|
||||||
|
O3M6Mzoi4b+6IjtzOjM6IuG9vSI7czozOiLhv7siO3M6Mzoi4b6AIjtzOjM6IuG+iCI7czozOiLh
|
||||||
|
voEiO3M6Mzoi4b6JIjtzOjM6IuG+giI7czozOiLhvooiO3M6Mzoi4b6DIjtzOjM6IuG+iyI7czoz
|
||||||
|
OiLhvoQiO3M6Mzoi4b6MIjtzOjM6IuG+hSI7czozOiLhvo0iO3M6Mzoi4b6GIjtzOjM6IuG+jiI7
|
||||||
|
czozOiLhvociO3M6Mzoi4b6PIjtzOjM6IuG+kCI7czozOiLhvpgiO3M6Mzoi4b6RIjtzOjM6IuG+
|
||||||
|
mSI7czozOiLhvpIiO3M6Mzoi4b6aIjtzOjM6IuG+kyI7czozOiLhvpsiO3M6Mzoi4b6UIjtzOjM6
|
||||||
|
IuG+nCI7czozOiLhvpUiO3M6Mzoi4b6dIjtzOjM6IuG+liI7czozOiLhvp4iO3M6Mzoi4b6XIjtz
|
||||||
|
OjM6IuG+nyI7czozOiLhvqAiO3M6Mzoi4b6oIjtzOjM6IuG+oSI7czozOiLhvqkiO3M6Mzoi4b6i
|
||||||
|
IjtzOjM6IuG+qiI7czozOiLhvqMiO3M6Mzoi4b6rIjtzOjM6IuG+pCI7czozOiLhvqwiO3M6Mzoi
|
||||||
|
4b6lIjtzOjM6IuG+rSI7czozOiLhvqYiO3M6Mzoi4b6uIjtzOjM6IuG+pyI7czozOiLhvq8iO3M6
|
||||||
|
Mzoi4b6wIjtzOjM6IuG+uCI7czozOiLhvrEiO3M6Mzoi4b65IjtzOjM6IuG+syI7czozOiLhvrwi
|
||||||
|
O3M6Mzoi4b6+IjtzOjI6Is6ZIjtzOjM6IuG/gyI7czozOiLhv4wiO3M6Mzoi4b+QIjtzOjM6IuG/
|
||||||
|
mCI7czozOiLhv5EiO3M6Mzoi4b+ZIjtzOjM6IuG/oCI7czozOiLhv6giO3M6Mzoi4b+hIjtzOjM6
|
||||||
|
IuG/qSI7czozOiLhv6UiO3M6Mzoi4b+sIjtzOjM6IuG/syI7czozOiLhv7wiO3M6Mzoi4oWOIjtz
|
||||||
|
OjM6IuKEsiI7czozOiLihbAiO3M6Mzoi4oWgIjtzOjM6IuKFsSI7czozOiLihaEiO3M6Mzoi4oWy
|
||||||
|
IjtzOjM6IuKFoiI7czozOiLihbMiO3M6Mzoi4oWjIjtzOjM6IuKFtCI7czozOiLihaQiO3M6Mzoi
|
||||||
|
4oW1IjtzOjM6IuKFpSI7czozOiLihbYiO3M6Mzoi4oWmIjtzOjM6IuKFtyI7czozOiLihaciO3M6
|
||||||
|
Mzoi4oW4IjtzOjM6IuKFqCI7czozOiLihbkiO3M6Mzoi4oWpIjtzOjM6IuKFuiI7czozOiLihaoi
|
||||||
|
O3M6Mzoi4oW7IjtzOjM6IuKFqyI7czozOiLihbwiO3M6Mzoi4oWsIjtzOjM6IuKFvSI7czozOiLi
|
||||||
|
ha0iO3M6Mzoi4oW+IjtzOjM6IuKFriI7czozOiLihb8iO3M6Mzoi4oWvIjtzOjM6IuKGhCI7czoz
|
||||||
|
OiLihoMiO3M6Mzoi4pOQIjtzOjM6IuKStiI7czozOiLik5EiO3M6Mzoi4pK3IjtzOjM6IuKTkiI7
|
||||||
|
czozOiLikrgiO3M6Mzoi4pOTIjtzOjM6IuKSuSI7czozOiLik5QiO3M6Mzoi4pK6IjtzOjM6IuKT
|
||||||
|
lSI7czozOiLikrsiO3M6Mzoi4pOWIjtzOjM6IuKSvCI7czozOiLik5ciO3M6Mzoi4pK9IjtzOjM6
|
||||||
|
IuKTmCI7czozOiLikr4iO3M6Mzoi4pOZIjtzOjM6IuKSvyI7czozOiLik5oiO3M6Mzoi4pOAIjtz
|
||||||
|
OjM6IuKTmyI7czozOiLik4EiO3M6Mzoi4pOcIjtzOjM6IuKTgiI7czozOiLik50iO3M6Mzoi4pOD
|
||||||
|
IjtzOjM6IuKTniI7czozOiLik4QiO3M6Mzoi4pOfIjtzOjM6IuKThSI7czozOiLik6AiO3M6Mzoi
|
||||||
|
4pOGIjtzOjM6IuKToSI7czozOiLik4ciO3M6Mzoi4pOiIjtzOjM6IuKTiCI7czozOiLik6MiO3M6
|
||||||
|
Mzoi4pOJIjtzOjM6IuKTpCI7czozOiLik4oiO3M6Mzoi4pOlIjtzOjM6IuKTiyI7czozOiLik6Yi
|
||||||
|
O3M6Mzoi4pOMIjtzOjM6IuKTpyI7czozOiLik40iO3M6Mzoi4pOoIjtzOjM6IuKTjiI7czozOiLi
|
||||||
|
k6kiO3M6Mzoi4pOPIjtzOjM6IuKwsCI7czozOiLisIAiO3M6Mzoi4rCxIjtzOjM6IuKwgSI7czoz
|
||||||
|
OiLisLIiO3M6Mzoi4rCCIjtzOjM6IuKwsyI7czozOiLisIMiO3M6Mzoi4rC0IjtzOjM6IuKwhCI7
|
||||||
|
czozOiLisLUiO3M6Mzoi4rCFIjtzOjM6IuKwtiI7czozOiLisIYiO3M6Mzoi4rC3IjtzOjM6IuKw
|
||||||
|
hyI7czozOiLisLgiO3M6Mzoi4rCIIjtzOjM6IuKwuSI7czozOiLisIkiO3M6Mzoi4rC6IjtzOjM6
|
||||||
|
IuKwiiI7czozOiLisLsiO3M6Mzoi4rCLIjtzOjM6IuKwvCI7czozOiLisIwiO3M6Mzoi4rC9Ijtz
|
||||||
|
OjM6IuKwjSI7czozOiLisL4iO3M6Mzoi4rCOIjtzOjM6IuKwvyI7czozOiLisI8iO3M6Mzoi4rGA
|
||||||
|
IjtzOjM6IuKwkCI7czozOiLisYEiO3M6Mzoi4rCRIjtzOjM6IuKxgiI7czozOiLisJIiO3M6Mzoi
|
||||||
|
4rGDIjtzOjM6IuKwkyI7czozOiLisYQiO3M6Mzoi4rCUIjtzOjM6IuKxhSI7czozOiLisJUiO3M6
|
||||||
|
Mzoi4rGGIjtzOjM6IuKwliI7czozOiLisYciO3M6Mzoi4rCXIjtzOjM6IuKxiCI7czozOiLisJgi
|
||||||
|
O3M6Mzoi4rGJIjtzOjM6IuKwmSI7czozOiLisYoiO3M6Mzoi4rCaIjtzOjM6IuKxiyI7czozOiLi
|
||||||
|
sJsiO3M6Mzoi4rGMIjtzOjM6IuKwnCI7czozOiLisY0iO3M6Mzoi4rCdIjtzOjM6IuKxjiI7czoz
|
||||||
|
OiLisJ4iO3M6Mzoi4rGPIjtzOjM6IuKwnyI7czozOiLisZAiO3M6Mzoi4rCgIjtzOjM6IuKxkSI7
|
||||||
|
czozOiLisKEiO3M6Mzoi4rGSIjtzOjM6IuKwoiI7czozOiLisZMiO3M6Mzoi4rCjIjtzOjM6IuKx
|
||||||
|
lCI7czozOiLisKQiO3M6Mzoi4rGVIjtzOjM6IuKwpSI7czozOiLisZYiO3M6Mzoi4rCmIjtzOjM6
|
||||||
|
IuKxlyI7czozOiLisKciO3M6Mzoi4rGYIjtzOjM6IuKwqCI7czozOiLisZkiO3M6Mzoi4rCpIjtz
|
||||||
|
OjM6IuKxmiI7czozOiLisKoiO3M6Mzoi4rGbIjtzOjM6IuKwqyI7czozOiLisZwiO3M6Mzoi4rCs
|
||||||
|
IjtzOjM6IuKxnSI7czozOiLisK0iO3M6Mzoi4rGeIjtzOjM6IuKwriI7czozOiLisaEiO3M6Mzoi
|
||||||
|
4rGgIjtzOjM6IuKxpSI7czoyOiLIuiI7czozOiLisaYiO3M6MjoiyL4iO3M6Mzoi4rGoIjtzOjM6
|
||||||
|
IuKxpyI7czozOiLisaoiO3M6Mzoi4rGpIjtzOjM6IuKxrCI7czozOiLisasiO3M6Mzoi4rGzIjtz
|
||||||
|
OjM6IuKxsiI7czozOiLisbYiO3M6Mzoi4rG1IjtzOjM6IuKygSI7czozOiLisoAiO3M6Mzoi4rKD
|
||||||
|
IjtzOjM6IuKygiI7czozOiLisoUiO3M6Mzoi4rKEIjtzOjM6IuKyhyI7czozOiLisoYiO3M6Mzoi
|
||||||
|
4rKJIjtzOjM6IuKyiCI7czozOiLisosiO3M6Mzoi4rKKIjtzOjM6IuKyjSI7czozOiLisowiO3M6
|
||||||
|
Mzoi4rKPIjtzOjM6IuKyjiI7czozOiLispEiO3M6Mzoi4rKQIjtzOjM6IuKykyI7czozOiLispIi
|
||||||
|
O3M6Mzoi4rKVIjtzOjM6IuKylCI7czozOiLispciO3M6Mzoi4rKWIjtzOjM6IuKymSI7czozOiLi
|
||||||
|
spgiO3M6Mzoi4rKbIjtzOjM6IuKymiI7czozOiLisp0iO3M6Mzoi4rKcIjtzOjM6IuKynyI7czoz
|
||||||
|
OiLisp4iO3M6Mzoi4rKhIjtzOjM6IuKyoCI7czozOiLisqMiO3M6Mzoi4rKiIjtzOjM6IuKypSI7
|
||||||
|
czozOiLisqQiO3M6Mzoi4rKnIjtzOjM6IuKypiI7czozOiLisqkiO3M6Mzoi4rKoIjtzOjM6IuKy
|
||||||
|
qyI7czozOiLisqoiO3M6Mzoi4rKtIjtzOjM6IuKyrCI7czozOiLisq8iO3M6Mzoi4rKuIjtzOjM6
|
||||||
|
IuKysSI7czozOiLisrAiO3M6Mzoi4rKzIjtzOjM6IuKysiI7czozOiLisrUiO3M6Mzoi4rK0Ijtz
|
||||||
|
OjM6IuKytyI7czozOiLisrYiO3M6Mzoi4rK5IjtzOjM6IuKyuCI7czozOiLisrsiO3M6Mzoi4rK6
|
||||||
|
IjtzOjM6IuKyvSI7czozOiLisrwiO3M6Mzoi4rK/IjtzOjM6IuKyviI7czozOiLis4EiO3M6Mzoi
|
||||||
|
4rOAIjtzOjM6IuKzgyI7czozOiLis4IiO3M6Mzoi4rOFIjtzOjM6IuKzhCI7czozOiLis4ciO3M6
|
||||||
|
Mzoi4rOGIjtzOjM6IuKziSI7czozOiLis4giO3M6Mzoi4rOLIjtzOjM6IuKziiI7czozOiLis40i
|
||||||
|
O3M6Mzoi4rOMIjtzOjM6IuKzjyI7czozOiLis44iO3M6Mzoi4rORIjtzOjM6IuKzkCI7czozOiLi
|
||||||
|
s5MiO3M6Mzoi4rOSIjtzOjM6IuKzlSI7czozOiLis5QiO3M6Mzoi4rOXIjtzOjM6IuKzliI7czoz
|
||||||
|
OiLis5kiO3M6Mzoi4rOYIjtzOjM6IuKzmyI7czozOiLis5oiO3M6Mzoi4rOdIjtzOjM6IuKznCI7
|
||||||
|
czozOiLis58iO3M6Mzoi4rOeIjtzOjM6IuKzoSI7czozOiLis6AiO3M6Mzoi4rOjIjtzOjM6IuKz
|
||||||
|
oiI7czozOiLis6wiO3M6Mzoi4rOrIjtzOjM6IuKzriI7czozOiLis60iO3M6Mzoi4rOzIjtzOjM6
|
||||||
|
IuKzsiI7czozOiLitIAiO3M6Mzoi4YKgIjtzOjM6IuK0gSI7czozOiLhgqEiO3M6Mzoi4rSCIjtz
|
||||||
|
OjM6IuGCoiI7czozOiLitIMiO3M6Mzoi4YKjIjtzOjM6IuK0hCI7czozOiLhgqQiO3M6Mzoi4rSF
|
||||||
|
IjtzOjM6IuGCpSI7czozOiLitIYiO3M6Mzoi4YKmIjtzOjM6IuK0hyI7czozOiLhgqciO3M6Mzoi
|
||||||
|
4rSIIjtzOjM6IuGCqCI7czozOiLitIkiO3M6Mzoi4YKpIjtzOjM6IuK0iiI7czozOiLhgqoiO3M6
|
||||||
|
Mzoi4rSLIjtzOjM6IuGCqyI7czozOiLitIwiO3M6Mzoi4YKsIjtzOjM6IuK0jSI7czozOiLhgq0i
|
||||||
|
O3M6Mzoi4rSOIjtzOjM6IuGCriI7czozOiLitI8iO3M6Mzoi4YKvIjtzOjM6IuK0kCI7czozOiLh
|
||||||
|
grAiO3M6Mzoi4rSRIjtzOjM6IuGCsSI7czozOiLitJIiO3M6Mzoi4YKyIjtzOjM6IuK0kyI7czoz
|
||||||
|
OiLhgrMiO3M6Mzoi4rSUIjtzOjM6IuGCtCI7czozOiLitJUiO3M6Mzoi4YK1IjtzOjM6IuK0liI7
|
||||||
|
czozOiLhgrYiO3M6Mzoi4rSXIjtzOjM6IuGCtyI7czozOiLitJgiO3M6Mzoi4YK4IjtzOjM6IuK0
|
||||||
|
mSI7czozOiLhgrkiO3M6Mzoi4rSaIjtzOjM6IuGCuiI7czozOiLitJsiO3M6Mzoi4YK7IjtzOjM6
|
||||||
|
IuK0nCI7czozOiLhgrwiO3M6Mzoi4rSdIjtzOjM6IuGCvSI7czozOiLitJ4iO3M6Mzoi4YK+Ijtz
|
||||||
|
OjM6IuK0nyI7czozOiLhgr8iO3M6Mzoi4rSgIjtzOjM6IuGDgCI7czozOiLitKEiO3M6Mzoi4YOB
|
||||||
|
IjtzOjM6IuK0oiI7czozOiLhg4IiO3M6Mzoi4rSjIjtzOjM6IuGDgyI7czozOiLitKQiO3M6Mzoi
|
||||||
|
4YOEIjtzOjM6IuK0pSI7czozOiLhg4UiO3M6Mzoi4rSnIjtzOjM6IuGDhyI7czozOiLitK0iO3M6
|
||||||
|
Mzoi4YONIjtzOjM6IuqZgSI7czozOiLqmYAiO3M6Mzoi6pmDIjtzOjM6IuqZgiI7czozOiLqmYUi
|
||||||
|
O3M6Mzoi6pmEIjtzOjM6IuqZhyI7czozOiLqmYYiO3M6Mzoi6pmJIjtzOjM6IuqZiCI7czozOiLq
|
||||||
|
mYsiO3M6Mzoi6pmKIjtzOjM6IuqZjSI7czozOiLqmYwiO3M6Mzoi6pmPIjtzOjM6IuqZjiI7czoz
|
||||||
|
OiLqmZEiO3M6Mzoi6pmQIjtzOjM6IuqZkyI7czozOiLqmZIiO3M6Mzoi6pmVIjtzOjM6IuqZlCI7
|
||||||
|
czozOiLqmZciO3M6Mzoi6pmWIjtzOjM6IuqZmSI7czozOiLqmZgiO3M6Mzoi6pmbIjtzOjM6IuqZ
|
||||||
|
miI7czozOiLqmZ0iO3M6Mzoi6pmcIjtzOjM6IuqZnyI7czozOiLqmZ4iO3M6Mzoi6pmhIjtzOjM6
|
||||||
|
IuqZoCI7czozOiLqmaMiO3M6Mzoi6pmiIjtzOjM6IuqZpSI7czozOiLqmaQiO3M6Mzoi6pmnIjtz
|
||||||
|
OjM6IuqZpiI7czozOiLqmakiO3M6Mzoi6pmoIjtzOjM6IuqZqyI7czozOiLqmaoiO3M6Mzoi6pmt
|
||||||
|
IjtzOjM6IuqZrCI7czozOiLqmoEiO3M6Mzoi6pqAIjtzOjM6IuqagyI7czozOiLqmoIiO3M6Mzoi
|
||||||
|
6pqFIjtzOjM6IuqahCI7czozOiLqmociO3M6Mzoi6pqGIjtzOjM6IuqaiSI7czozOiLqmogiO3M6
|
||||||
|
Mzoi6pqLIjtzOjM6IuqaiiI7czozOiLqmo0iO3M6Mzoi6pqMIjtzOjM6IuqajyI7czozOiLqmo4i
|
||||||
|
O3M6Mzoi6pqRIjtzOjM6IuqakCI7czozOiLqmpMiO3M6Mzoi6pqSIjtzOjM6IuqalSI7czozOiLq
|
||||||
|
mpQiO3M6Mzoi6pqXIjtzOjM6IuqaliI7czozOiLqnKMiO3M6Mzoi6pyiIjtzOjM6IuqcpSI7czoz
|
||||||
|
OiLqnKQiO3M6Mzoi6pynIjtzOjM6IuqcpiI7czozOiLqnKkiO3M6Mzoi6pyoIjtzOjM6IuqcqyI7
|
||||||
|
czozOiLqnKoiO3M6Mzoi6pytIjtzOjM6IuqcrCI7czozOiLqnK8iO3M6Mzoi6pyuIjtzOjM6Iuqc
|
||||||
|
syI7czozOiLqnLIiO3M6Mzoi6py1IjtzOjM6IuqctCI7czozOiLqnLciO3M6Mzoi6py2IjtzOjM6
|
||||||
|
IuqcuSI7czozOiLqnLgiO3M6Mzoi6py7IjtzOjM6IuqcuiI7czozOiLqnL0iO3M6Mzoi6py8Ijtz
|
||||||
|
OjM6IuqcvyI7czozOiLqnL4iO3M6Mzoi6p2BIjtzOjM6IuqdgCI7czozOiLqnYMiO3M6Mzoi6p2C
|
||||||
|
IjtzOjM6IuqdhSI7czozOiLqnYQiO3M6Mzoi6p2HIjtzOjM6IuqdhiI7czozOiLqnYkiO3M6Mzoi
|
||||||
|
6p2IIjtzOjM6IuqdiyI7czozOiLqnYoiO3M6Mzoi6p2NIjtzOjM6IuqdjCI7czozOiLqnY8iO3M6
|
||||||
|
Mzoi6p2OIjtzOjM6IuqdkSI7czozOiLqnZAiO3M6Mzoi6p2TIjtzOjM6IuqdkiI7czozOiLqnZUi
|
||||||
|
O3M6Mzoi6p2UIjtzOjM6IuqdlyI7czozOiLqnZYiO3M6Mzoi6p2ZIjtzOjM6IuqdmCI7czozOiLq
|
||||||
|
nZsiO3M6Mzoi6p2aIjtzOjM6IuqdnSI7czozOiLqnZwiO3M6Mzoi6p2fIjtzOjM6IuqdniI7czoz
|
||||||
|
OiLqnaEiO3M6Mzoi6p2gIjtzOjM6IuqdoyI7czozOiLqnaIiO3M6Mzoi6p2lIjtzOjM6IuqdpCI7
|
||||||
|
czozOiLqnaciO3M6Mzoi6p2mIjtzOjM6IuqdqSI7czozOiLqnagiO3M6Mzoi6p2rIjtzOjM6Iuqd
|
||||||
|
qiI7czozOiLqna0iO3M6Mzoi6p2sIjtzOjM6IuqdryI7czozOiLqna4iO3M6Mzoi6p26IjtzOjM6
|
||||||
|
IuqduSI7czozOiLqnbwiO3M6Mzoi6p27IjtzOjM6IuqdvyI7czozOiLqnb4iO3M6Mzoi6p6BIjtz
|
||||||
|
OjM6IuqegCI7czozOiLqnoMiO3M6Mzoi6p6CIjtzOjM6IuqehSI7czozOiLqnoQiO3M6Mzoi6p6H
|
||||||
|
IjtzOjM6IuqehiI7czozOiLqnowiO3M6Mzoi6p6LIjtzOjM6IuqekSI7czozOiLqnpAiO3M6Mzoi
|
||||||
|
6p6TIjtzOjM6IuqekiI7czozOiLqnqEiO3M6Mzoi6p6gIjtzOjM6IuqeoyI7czozOiLqnqIiO3M6
|
||||||
|
Mzoi6p6lIjtzOjM6IuqepCI7czozOiLqnqciO3M6Mzoi6p6mIjtzOjM6IuqeqSI7czozOiLqnqgi
|
||||||
|
O3M6Mzoi772BIjtzOjM6Iu+8oSI7czozOiLvvYIiO3M6Mzoi77yiIjtzOjM6Iu+9gyI7czozOiLv
|
||||||
|
vKMiO3M6Mzoi772EIjtzOjM6Iu+8pCI7czozOiLvvYUiO3M6Mzoi77ylIjtzOjM6Iu+9hiI7czoz
|
||||||
|
OiLvvKYiO3M6Mzoi772HIjtzOjM6Iu+8pyI7czozOiLvvYgiO3M6Mzoi77yoIjtzOjM6Iu+9iSI7
|
||||||
|
czozOiLvvKkiO3M6Mzoi772KIjtzOjM6Iu+8qiI7czozOiLvvYsiO3M6Mzoi77yrIjtzOjM6Iu+9
|
||||||
|
jCI7czozOiLvvKwiO3M6Mzoi772NIjtzOjM6Iu+8rSI7czozOiLvvY4iO3M6Mzoi77yuIjtzOjM6
|
||||||
|
Iu+9jyI7czozOiLvvK8iO3M6Mzoi772QIjtzOjM6Iu+8sCI7czozOiLvvZEiO3M6Mzoi77yxIjtz
|
||||||
|
OjM6Iu+9kiI7czozOiLvvLIiO3M6Mzoi772TIjtzOjM6Iu+8syI7czozOiLvvZQiO3M6Mzoi77y0
|
||||||
|
IjtzOjM6Iu+9lSI7czozOiLvvLUiO3M6Mzoi772WIjtzOjM6Iu+8tiI7czozOiLvvZciO3M6Mzoi
|
||||||
|
77y3IjtzOjM6Iu+9mCI7czozOiLvvLgiO3M6Mzoi772ZIjtzOjM6Iu+8uSI7czozOiLvvZoiO3M6
|
||||||
|
Mzoi77y6IjtzOjQ6IvCQkKgiO3M6NDoi8JCQgCI7czo0OiLwkJCpIjtzOjQ6IvCQkIEiO3M6NDoi
|
||||||
|
8JCQqiI7czo0OiLwkJCCIjtzOjQ6IvCQkKsiO3M6NDoi8JCQgyI7czo0OiLwkJCsIjtzOjQ6IvCQ
|
||||||
|
kIQiO3M6NDoi8JCQrSI7czo0OiLwkJCFIjtzOjQ6IvCQkK4iO3M6NDoi8JCQhiI7czo0OiLwkJCv
|
||||||
|
IjtzOjQ6IvCQkIciO3M6NDoi8JCQsCI7czo0OiLwkJCIIjtzOjQ6IvCQkLEiO3M6NDoi8JCQiSI7
|
||||||
|
czo0OiLwkJCyIjtzOjQ6IvCQkIoiO3M6NDoi8JCQsyI7czo0OiLwkJCLIjtzOjQ6IvCQkLQiO3M6
|
||||||
|
NDoi8JCQjCI7czo0OiLwkJC1IjtzOjQ6IvCQkI0iO3M6NDoi8JCQtiI7czo0OiLwkJCOIjtzOjQ6
|
||||||
|
IvCQkLciO3M6NDoi8JCQjyI7czo0OiLwkJC4IjtzOjQ6IvCQkJAiO3M6NDoi8JCQuSI7czo0OiLw
|
||||||
|
kJCRIjtzOjQ6IvCQkLoiO3M6NDoi8JCQkiI7czo0OiLwkJC7IjtzOjQ6IvCQkJMiO3M6NDoi8JCQ
|
||||||
|
vCI7czo0OiLwkJCUIjtzOjQ6IvCQkL0iO3M6NDoi8JCQlSI7czo0OiLwkJC+IjtzOjQ6IvCQkJYi
|
||||||
|
O3M6NDoi8JCQvyI7czo0OiLwkJCXIjtzOjQ6IvCQkYAiO3M6NDoi8JCQmCI7czo0OiLwkJGBIjtz
|
||||||
|
OjQ6IvCQkJkiO3M6NDoi8JCRgiI7czo0OiLwkJCaIjtzOjQ6IvCQkYMiO3M6NDoi8JCQmyI7czo0
|
||||||
|
OiLwkJGEIjtzOjQ6IvCQkJwiO3M6NDoi8JCRhSI7czo0OiLwkJCdIjtzOjQ6IvCQkYYiO3M6NDoi
|
||||||
|
8JCQniI7czo0OiLwkJGHIjtzOjQ6IvCQkJ8iO3M6NDoi8JCRiCI7czo0OiLwkJCgIjtzOjQ6IvCQ
|
||||||
|
kYkiO3M6NDoi8JCQoSI7czo0OiLwkJGKIjtzOjQ6IvCQkKIiO3M6NDoi8JCRiyI7czo0OiLwkJCj
|
||||||
|
IjtzOjQ6IvCQkYwiO3M6NDoi8JCQpCI7czo0OiLwkJGNIjtzOjQ6IvCQkKUiO3M6NDoi8JCRjiI7
|
||||||
|
czo0OiLwkJCmIjtzOjQ6IvCQkY8iO3M6NDoi8JCQpyI7fQ=='));
|
||||||
|
$map = $upper;
|
||||||
|
|
||||||
|
static $ulen_mask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
|
||||||
|
|
||||||
|
$i = 0;
|
||||||
|
$len = strlen($s);
|
||||||
|
|
||||||
|
while ($i < $len)
|
||||||
|
{
|
||||||
|
$ulen = $s[$i] < "\x80" ? 1 : $ulen_mask[$s[$i] & "\xF0"];
|
||||||
|
$uchr = substr($s, $i, $ulen);
|
||||||
|
$i += $ulen;
|
||||||
|
|
||||||
|
if (isset($map[$uchr]))
|
||||||
|
{
|
||||||
|
$uchr = $map[$uchr];
|
||||||
|
$nlen = strlen($uchr);
|
||||||
|
|
||||||
|
if ($nlen == $ulen)
|
||||||
|
{
|
||||||
|
$nlen = $i;
|
||||||
|
do $s[--$nlen] = $uchr[--$ulen];
|
||||||
|
while ($ulen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$s = substr_replace($s, $uchr, $i - $ulen, $ulen);
|
||||||
|
$len += $nlen - $ulen;
|
||||||
|
$i += $nlen - $ulen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (INF === $encoding) return $s;
|
||||||
|
else return iconv('UTF-8', $encoding, $s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('mb_strcut'))
|
||||||
|
{
|
||||||
|
function mb_strcut($str, $start, $length = null, $encoding = '')
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return \MailSo\Base\Utils::Utf8Clear(substr($str, $start, $length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('mb_detect_encoding'))
|
||||||
|
{
|
||||||
|
function mb_detect_encoding($str, $encoding_list = INF, $strict = false)
|
||||||
|
{
|
||||||
|
if (INF === $encoding_list) $encoding_list = 'UTF-8';
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (! is_array($encoding_list)) $encoding_list = array_map('trim', explode(',', $encoding_list));
|
||||||
|
$encoding_list = array_map('strtoupper', $encoding_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($encoding_list as $enc)
|
||||||
|
{
|
||||||
|
switch ($enc)
|
||||||
|
{
|
||||||
|
case 'ASCII':
|
||||||
|
if (! preg_match('/[\x80-\xFF]/', $str)) return $enc;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'UTF8':
|
||||||
|
case 'UTF-8':
|
||||||
|
if (preg_match('//u', $str)) return $enc;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return strncmp($enc, 'ISO-8859-', 9) ? false : $enc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('mb_check_encoding'))
|
||||||
|
{
|
||||||
|
function mb_check_encoding($var = INF, $encoding = INF)
|
||||||
|
{
|
||||||
|
if (INF === $encoding)
|
||||||
|
{
|
||||||
|
if (INF === $var) return false;
|
||||||
|
$encoding = 'UTF-8';
|
||||||
|
}
|
||||||
|
|
||||||
|
return false !== mb_detect_encoding($var, array($encoding), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -100,29 +100,23 @@ class Service
|
||||||
$this->oActions->KeenIO('Install');
|
$this->oActions->KeenIO('Install');
|
||||||
}
|
}
|
||||||
|
|
||||||
$bCached = false;
|
if ($this->oActions->Config()->Get('labs', 'sync_allow_dav', false))
|
||||||
$sResult = '';
|
|
||||||
$sPathInfo = \trim(\trim($this->oHttp->GetServer('PATH_INFO', '')), ' /');
|
|
||||||
if (!empty($sPathInfo))
|
|
||||||
{
|
{
|
||||||
if ('dav' !== \substr($sPathInfo, 0, 3))
|
$sDavDomain = \trim($this->oActions->Config()->Get('labs', 'sync_dav_host', ''));
|
||||||
|
if (!empty($sDavDomain) && $sDavDomain === $this->oHttp->GetHost())
|
||||||
{
|
{
|
||||||
$sPathInfo = '';
|
$this->oServiceActions->HostDav();
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($sPathInfo))
|
$bCached = false;
|
||||||
|
$sResult = '';
|
||||||
|
$sQuery = \trim(\trim($this->oHttp->GetServer('QUERY_STRING', '')), ' /');
|
||||||
|
$iPos = \strpos($sQuery, '&');
|
||||||
|
if (0 < $iPos)
|
||||||
{
|
{
|
||||||
$sQuery = \trim(\trim($this->oHttp->GetServer('QUERY_STRING', '')), ' /');
|
$sQuery = \substr($sQuery, 0, $iPos);
|
||||||
$iPos = \strpos($sQuery, '&');
|
|
||||||
if (0 < $iPos)
|
|
||||||
{
|
|
||||||
$sQuery = \substr($sQuery, 0, $iPos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$sQuery = $sPathInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->oActions->Plugins()->RunHook('filter.http-query', array(&$sQuery));
|
$this->oActions->Plugins()->RunHook('filter.http-query', array(&$sQuery));
|
||||||
|
|
|
||||||
|
|
@ -711,16 +711,8 @@ class ServiceActions
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function HostDav()
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function ServiceDav()
|
|
||||||
{
|
{
|
||||||
if (!$this->Config()->Get('contacts', 'allow_carddav_sync', false))
|
|
||||||
{
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
\set_error_handler(function ($errno, $errstr, $errfile, $errline ) {
|
\set_error_handler(function ($errno, $errstr, $errfile, $errline ) {
|
||||||
|
|
@ -730,7 +722,7 @@ class ServiceActions
|
||||||
$oPersonalAddressBookProvider = $this->oActions->PersonalAddressBookProvider();
|
$oPersonalAddressBookProvider = $this->oActions->PersonalAddressBookProvider();
|
||||||
|
|
||||||
$oAuthBackend = null;
|
$oAuthBackend = null;
|
||||||
if ($this->Config()->Get('labs', 'use_dav_digest_auth', false))
|
if ($this->Config()->Get('labs', 'sync_dav_digest_auth', false))
|
||||||
{
|
{
|
||||||
$oAuthBackend = new \RainLoop\SabreDAV\AuthDigest($oPersonalAddressBookProvider);
|
$oAuthBackend = new \RainLoop\SabreDAV\AuthDigest($oPersonalAddressBookProvider);
|
||||||
}
|
}
|
||||||
|
|
@ -751,18 +743,17 @@ class ServiceActions
|
||||||
$oPrincipalCollection, $oAddressBookRoot
|
$oPrincipalCollection, $oAddressBookRoot
|
||||||
));
|
));
|
||||||
|
|
||||||
$aPath = \trim($this->oHttp->GetPath(), '/\\ ');
|
$oServer->setBaseUri('/');
|
||||||
$oServer->setBaseUri((0 < \strlen($aPath) ? '/'.$aPath : '').'/index.php/dav/');
|
|
||||||
|
|
||||||
// Plugins
|
// Plugins
|
||||||
$oServer->addPlugin(new \Sabre\DAV\Auth\Plugin($oAuthBackend, 'RainLoop'));
|
$oServer->addPlugin(new \Sabre\DAV\Auth\Plugin($oAuthBackend, 'RainLoop'));
|
||||||
$oServer->addPlugin(new \Sabre\DAV\Browser\Plugin());
|
$oServer->addPlugin(new \Sabre\DAV\Browser\Plugin());
|
||||||
$oServer->addPlugin(new \Sabre\CardDAV\Plugin());
|
$oServer->addPlugin(new \Sabre\CardDAV\Plugin());
|
||||||
|
$oServer->addPlugin(new \Sabre\DAVACL\Plugin());
|
||||||
|
|
||||||
|
$oServer->addPlugin(new \RainLoop\SabreDAV\Logger($this->Logger()));
|
||||||
|
|
||||||
|
|
||||||
// $oAclPlugin = new \Sabre\DAVACL\Plugin();
|
|
||||||
// $oAclPlugin->hideNodesFromListings = true;
|
|
||||||
// $oAclPlugin->allowAccessToNodesWithoutACL = false;
|
|
||||||
// $oServer->addPlugin($oAclPlugin);
|
|
||||||
|
|
||||||
$oServer->exec();
|
$oServer->exec();
|
||||||
}
|
}
|
||||||
|
|
@ -770,8 +761,6 @@ class ServiceActions
|
||||||
{
|
{
|
||||||
$this->Logger()->WriteException($oException);
|
$this->Logger()->WriteException($oException);
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
735
rainloop/v/0.0.0/app/libraries/Sabre/VObject/Cli.php
Normal file
735
rainloop/v/0.0.0/app/libraries/Sabre/VObject/Cli.php
Normal file
|
|
@ -0,0 +1,735 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject;
|
||||||
|
|
||||||
|
use
|
||||||
|
InvalidArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the CLI interface for sabre-vobject.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class Cli {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No output
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $quiet = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Help display
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $showHelp = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wether to spit out 'mimedir' or 'json' format.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $format;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON pretty print
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $pretty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source file
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $inputPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destination file
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $outputPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* output stream
|
||||||
|
*
|
||||||
|
* @var resource
|
||||||
|
*/
|
||||||
|
protected $stdout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stdin
|
||||||
|
*
|
||||||
|
* @var resource
|
||||||
|
*/
|
||||||
|
protected $stdin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stderr
|
||||||
|
*
|
||||||
|
* @var resource
|
||||||
|
*/
|
||||||
|
protected $stderr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input format (one of json or mimedir)
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $inputFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the parser less strict.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $forgiving = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main function
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function main(array $argv) {
|
||||||
|
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
// We cannot easily test this, so we'll skip it. Pretty basic anyway.
|
||||||
|
|
||||||
|
if (!$this->stderr) {
|
||||||
|
$this->stderr = STDERR;
|
||||||
|
}
|
||||||
|
if (!$this->stdout) {
|
||||||
|
$this->stdout = STDOUT;
|
||||||
|
}
|
||||||
|
if (!$this->stdin) {
|
||||||
|
$this->stdin = STDIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
list($options, $positional) = $this->parseArguments($argv);
|
||||||
|
|
||||||
|
if (isset($options['q'])) {
|
||||||
|
$this->quiet = true;
|
||||||
|
}
|
||||||
|
$this->log($this->colorize('green', "sabre-vobject ") . $this->colorize('yellow', Version::VERSION));
|
||||||
|
|
||||||
|
foreach($options as $name=>$value) {
|
||||||
|
|
||||||
|
switch($name) {
|
||||||
|
|
||||||
|
case 'q' :
|
||||||
|
// Already handled earlier.
|
||||||
|
break;
|
||||||
|
case 'h' :
|
||||||
|
case 'help' :
|
||||||
|
$this->showHelp();
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case 'format' :
|
||||||
|
switch($value) {
|
||||||
|
|
||||||
|
// jcard/jcal documents
|
||||||
|
case 'jcard' :
|
||||||
|
case 'jcal' :
|
||||||
|
|
||||||
|
// specific document versions
|
||||||
|
case 'vcard21' :
|
||||||
|
case 'vcard30' :
|
||||||
|
case 'vcard40' :
|
||||||
|
case 'icalendar20' :
|
||||||
|
|
||||||
|
// specific formats
|
||||||
|
case 'json' :
|
||||||
|
case 'mimedir' :
|
||||||
|
|
||||||
|
// icalendar/vcad
|
||||||
|
case 'icalendar' :
|
||||||
|
case 'vcard' :
|
||||||
|
$this->format = $value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default :
|
||||||
|
throw new InvalidArgumentException('Unknown format: ' . $value);
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'pretty' :
|
||||||
|
if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
||||||
|
$this->pretty = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'forgiving' :
|
||||||
|
$this->forgiving = true;
|
||||||
|
break;
|
||||||
|
case 'inputformat' :
|
||||||
|
switch($value) {
|
||||||
|
// json formats
|
||||||
|
case 'jcard' :
|
||||||
|
case 'jcal' :
|
||||||
|
case 'json' :
|
||||||
|
$this->inputFormat = 'json';
|
||||||
|
break;
|
||||||
|
|
||||||
|
// mimedir formats
|
||||||
|
case 'mimedir' :
|
||||||
|
case 'icalendar' :
|
||||||
|
case 'vcard' :
|
||||||
|
case 'vcard21' :
|
||||||
|
case 'vcard30' :
|
||||||
|
case 'vcard40' :
|
||||||
|
case 'icalendar20' :
|
||||||
|
|
||||||
|
$this->inputFormat = 'mimedir';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default :
|
||||||
|
throw new InvalidArgumentException('Unknown format: ' . $value);
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
throw new InvalidArgumentException('Unknown option: ' . $name);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($positional) === 0) {
|
||||||
|
$this->showHelp();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($positional) === 1) {
|
||||||
|
throw new InvalidArgumentException('Inputfile is a required argument');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($positional) > 3) {
|
||||||
|
throw new InvalidArgumentException('Too many arguments');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!in_array($positional[0], array('validate','repair','convert','color'))) {
|
||||||
|
throw new InvalidArgumentException('Uknown command: ' . $positional[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (InvalidArgumentException $e) {
|
||||||
|
$this->showHelp();
|
||||||
|
$this->log('Error: ' . $e->getMessage(),'red');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$command = $positional[0];
|
||||||
|
|
||||||
|
$this->inputPath = $positional[1];
|
||||||
|
$this->outputPath = isset($positional[2])?$positional[2]:'-';
|
||||||
|
|
||||||
|
if ($this->outputPath !== '-') {
|
||||||
|
$this->stdout = fopen($this->outputPath,'w');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->inputFormat) {
|
||||||
|
if (substr($this->inputPath,-5)==='.json') {
|
||||||
|
$this->inputFormat = 'json';
|
||||||
|
} else {
|
||||||
|
$this->inputFormat = 'mimedir';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$this->format) {
|
||||||
|
if (substr($this->outputPath,-5)==='.json') {
|
||||||
|
$this->format = 'json';
|
||||||
|
} else {
|
||||||
|
$this->format = 'mimedir';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$realCode = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
while($input = $this->readInput()) {
|
||||||
|
|
||||||
|
$returnCode = $this->$command($input);
|
||||||
|
if ($returnCode!==0) $realCode = $returnCode;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (EofException $e) {
|
||||||
|
// end of file
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->log('Error: ' . $e->getMessage(),'red');
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $realCode;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the help message.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function showHelp() {
|
||||||
|
|
||||||
|
$this->log('Usage:', 'yellow');
|
||||||
|
$this->log(" vobject [options] command [arguments]");
|
||||||
|
$this->log('');
|
||||||
|
$this->log('Options:', 'yellow');
|
||||||
|
$this->log($this->colorize('green', ' -q ') . "Don't output anything.");
|
||||||
|
$this->log($this->colorize('green', ' -help -h ') . "Display this help message.");
|
||||||
|
$this->log($this->colorize('green', ' --format ') . "Convert to a specific format. Must be one of: vcard, vcard21,");
|
||||||
|
$this->log($this->colorize('green', ' --forgiving ') . "Makes the parser less strict.");
|
||||||
|
$this->log(" vcard30, vcard40, icalendar20, jcal, jcard, json, mimedir.");
|
||||||
|
$this->log($this->colorize('green', ' --inputformat ') . "If the input format cannot be guessed from the extension, it");
|
||||||
|
$this->log(" must be specified here.");
|
||||||
|
// Only PHP 5.4 and up
|
||||||
|
if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
||||||
|
$this->log($this->colorize('green', ' --pretty ') . "json pretty-print.");
|
||||||
|
}
|
||||||
|
$this->log('');
|
||||||
|
$this->log('Commands:', 'yellow');
|
||||||
|
$this->log($this->colorize('green', ' validate') . ' source_file Validates a file for correctness.');
|
||||||
|
$this->log($this->colorize('green', ' repair') . ' source_file [output_file] Repairs a file.');
|
||||||
|
$this->log($this->colorize('green', ' convert') . ' source_file [output_file] Converts a file.');
|
||||||
|
$this->log($this->colorize('green', ' color') . ' source_file Colorize a file, useful for debbugging.');
|
||||||
|
$this->log(<<<HELP
|
||||||
|
|
||||||
|
If source_file is set as '-', STDIN will be used.
|
||||||
|
If output_file is omitted, STDOUT will be used.
|
||||||
|
All other output is sent to STDERR.
|
||||||
|
|
||||||
|
HELP
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->log('Examples:', 'yellow');
|
||||||
|
$this->log(' vobject convert contact.vcf contact.json');
|
||||||
|
$this->log(' vobject convert --format=vcard40 old.vcf new.vcf');
|
||||||
|
$this->log(' vobject convert --inputformat=json --format=mimedir - -');
|
||||||
|
$this->log(' vobject color calendar.ics');
|
||||||
|
$this->log('');
|
||||||
|
$this->log('https://github.com/fruux/sabre-vobject','purple');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates a VObject file
|
||||||
|
*
|
||||||
|
* @param Component $vObj
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function validate($vObj) {
|
||||||
|
|
||||||
|
$returnCode = 0;
|
||||||
|
|
||||||
|
switch($vObj->name) {
|
||||||
|
case 'VCALENDAR' :
|
||||||
|
$this->log("iCalendar: " . (string)$vObj->VERSION);
|
||||||
|
break;
|
||||||
|
case 'VCARD' :
|
||||||
|
$this->log("vCard: " . (string)$vObj->VERSION);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$warnings = $vObj->validate();
|
||||||
|
if (!count($warnings)) {
|
||||||
|
$this->log(" No warnings!");
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$returnCode = 2;
|
||||||
|
foreach($warnings as $warn) {
|
||||||
|
|
||||||
|
$this->log(" " . $warn['message']);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $returnCode;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repairs a VObject file
|
||||||
|
*
|
||||||
|
* @param Component $vObj
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function repair($vObj) {
|
||||||
|
|
||||||
|
$returnCode = 0;
|
||||||
|
|
||||||
|
switch($vObj->name) {
|
||||||
|
case 'VCALENDAR' :
|
||||||
|
$this->log("iCalendar: " . (string)$vObj->VERSION);
|
||||||
|
break;
|
||||||
|
case 'VCARD' :
|
||||||
|
$this->log("vCard: " . (string)$vObj->VERSION);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$warnings = $vObj->validate(Node::REPAIR);
|
||||||
|
if (!count($warnings)) {
|
||||||
|
$this->log(" No warnings!");
|
||||||
|
} else {
|
||||||
|
foreach($warnings as $warn) {
|
||||||
|
|
||||||
|
$returnCode = 2;
|
||||||
|
$this->log(" " . $warn['message']);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
fwrite($this->stdout, $vObj->serialize());
|
||||||
|
|
||||||
|
return $returnCode;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a vObject file to a new format.
|
||||||
|
*
|
||||||
|
* @param Component $vObj
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function convert($vObj) {
|
||||||
|
|
||||||
|
$json = false;
|
||||||
|
$convertVersion = null;
|
||||||
|
$forceInput = null;
|
||||||
|
|
||||||
|
switch($this->format) {
|
||||||
|
case 'json' :
|
||||||
|
$json = true;
|
||||||
|
if ($vObj->name === 'VCARD') {
|
||||||
|
$convertVersion = Document::VCARD40;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'jcard' :
|
||||||
|
$json = true;
|
||||||
|
$forceInput = 'VCARD';
|
||||||
|
$convertVersion = Document::VCARD40;
|
||||||
|
break;
|
||||||
|
case 'jcal' :
|
||||||
|
$json = true;
|
||||||
|
$forceInput = 'VCALENDAR';
|
||||||
|
break;
|
||||||
|
case 'mimedir' :
|
||||||
|
case 'icalendar' :
|
||||||
|
case 'icalendar20' :
|
||||||
|
case 'vcard' :
|
||||||
|
break;
|
||||||
|
case 'vcard21' :
|
||||||
|
$convertVersion = Document::VCARD21;
|
||||||
|
break;
|
||||||
|
case 'vcard30' :
|
||||||
|
$convertVersion = Document::VCARD30;
|
||||||
|
break;
|
||||||
|
case 'vcard40' :
|
||||||
|
$convertVersion = Document::VCARD40;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($forceInput && $vObj->name !== $forceInput) {
|
||||||
|
throw new \Exception('You cannot convert a ' . strtolower($vObj->name) . ' to ' . $this->format);
|
||||||
|
}
|
||||||
|
if ($convertVersion) {
|
||||||
|
$vObj = $vObj->convert($convertVersion);
|
||||||
|
}
|
||||||
|
if ($json) {
|
||||||
|
$jsonOptions = 0;
|
||||||
|
if ($this->pretty) {
|
||||||
|
$jsonOptions = JSON_PRETTY_PRINT;
|
||||||
|
}
|
||||||
|
fwrite($this->stdout, json_encode($vObj->jsonSerialize(), $jsonOptions));
|
||||||
|
} else {
|
||||||
|
fwrite($this->stdout, $vObj->serialize());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colorizes a file
|
||||||
|
*
|
||||||
|
* @param Component $vObj
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function color($vObj) {
|
||||||
|
|
||||||
|
fwrite($this->stdout, $this->serializeComponent($vObj));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an ansi color string for a color name.
|
||||||
|
*
|
||||||
|
* @param string $color
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function colorize($color, $str, $resetTo = 'default') {
|
||||||
|
|
||||||
|
$colors = array(
|
||||||
|
'cyan' => '1;36',
|
||||||
|
'red' => '1;31',
|
||||||
|
'yellow' => '1;33',
|
||||||
|
'blue' => '0;34',
|
||||||
|
'green' => '0;32',
|
||||||
|
'default' => '0',
|
||||||
|
'purple' => '0;35',
|
||||||
|
);
|
||||||
|
return "\033[" . $colors[$color] . 'm' . $str . "\033[".$colors[$resetTo]."m";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes out a string in specific color.
|
||||||
|
*
|
||||||
|
* @param string $color
|
||||||
|
* @param string $str
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function cWrite($color, $str) {
|
||||||
|
|
||||||
|
fwrite($this->stdout, $this->colorize($color, $str));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function serializeComponent(Component $vObj) {
|
||||||
|
|
||||||
|
$this->cWrite('cyan', 'BEGIN');
|
||||||
|
$this->cWrite('red', ':');
|
||||||
|
$this->cWrite('yellow', $vObj->name . "\n");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives a component a 'score' for sorting purposes.
|
||||||
|
*
|
||||||
|
* This is solely used by the childrenSort method.
|
||||||
|
*
|
||||||
|
* A higher score means the item will be lower in the list.
|
||||||
|
* To avoid score collisions, each "score category" has a reasonable
|
||||||
|
* space to accomodate elements. The $key is added to the $score to
|
||||||
|
* preserve the original relative order of elements.
|
||||||
|
*
|
||||||
|
* @param int $key
|
||||||
|
* @param array $array
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
$sortScore = function($key, $array) {
|
||||||
|
|
||||||
|
if ($array[$key] instanceof Component) {
|
||||||
|
|
||||||
|
// We want to encode VTIMEZONE first, this is a personal
|
||||||
|
// preference.
|
||||||
|
if ($array[$key]->name === 'VTIMEZONE') {
|
||||||
|
$score=300000000;
|
||||||
|
return $score+$key;
|
||||||
|
} else {
|
||||||
|
$score=400000000;
|
||||||
|
return $score+$key;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Properties get encoded first
|
||||||
|
// VCARD version 4.0 wants the VERSION property to appear first
|
||||||
|
if ($array[$key] instanceof Property) {
|
||||||
|
if ($array[$key]->name === 'VERSION') {
|
||||||
|
$score=100000000;
|
||||||
|
return $score+$key;
|
||||||
|
} else {
|
||||||
|
// All other properties
|
||||||
|
$score=200000000;
|
||||||
|
return $score+$key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
$tmp = $vObj->children;
|
||||||
|
uksort($vObj->children, function($a, $b) use ($sortScore, $tmp) {
|
||||||
|
|
||||||
|
$sA = $sortScore($a, $tmp);
|
||||||
|
$sB = $sortScore($b, $tmp);
|
||||||
|
|
||||||
|
return $sA - $sB;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach($vObj->children as $child) {
|
||||||
|
if ($child instanceof Component) {
|
||||||
|
$this->serializeComponent($child);
|
||||||
|
} else {
|
||||||
|
$this->serializeProperty($child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cWrite('cyan', 'END');
|
||||||
|
$this->cWrite('red', ':');
|
||||||
|
$this->cWrite('yellow', $vObj->name . "\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colorizes a property.
|
||||||
|
*
|
||||||
|
* @param Property $property
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function serializeProperty(Property $property) {
|
||||||
|
|
||||||
|
if ($property->group) {
|
||||||
|
$this->cWrite('default', $property->group);
|
||||||
|
$this->cWrite('red', '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$str = '';
|
||||||
|
$this->cWrite('yellow', $property->name);
|
||||||
|
|
||||||
|
foreach($property->parameters as $param) {
|
||||||
|
|
||||||
|
$this->cWrite('red',';');
|
||||||
|
$this->cWrite('blue', $param->serialize());
|
||||||
|
|
||||||
|
}
|
||||||
|
$this->cWrite('red',':');
|
||||||
|
|
||||||
|
if ($property instanceof Property\Binary) {
|
||||||
|
|
||||||
|
$this->cWrite('default', 'embedded binary stripped. (' . strlen($property->getValue()) . ' bytes)');
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$parts = $property->getParts();
|
||||||
|
$first1 = true;
|
||||||
|
// Looping through property values
|
||||||
|
foreach($parts as $part) {
|
||||||
|
if ($first1) {
|
||||||
|
$first1 = false;
|
||||||
|
} else {
|
||||||
|
$this->cWrite('red', $property->delimiter);
|
||||||
|
}
|
||||||
|
$first2 = true;
|
||||||
|
// Looping through property sub-values
|
||||||
|
foreach((array)$part as $subPart) {
|
||||||
|
if ($first2) {
|
||||||
|
$first2 = false;
|
||||||
|
} else {
|
||||||
|
// The sub-value delimiter is always comma
|
||||||
|
$this->cWrite('red', ',');
|
||||||
|
}
|
||||||
|
|
||||||
|
$subPart = strtr($subPart, array(
|
||||||
|
'\\' => $this->colorize('purple', '\\\\', 'green'),
|
||||||
|
';' => $this->colorize('purple', '\;', 'green'),
|
||||||
|
',' => $this->colorize('purple', '\,', 'green'),
|
||||||
|
"\n" => $this->colorize('purple', "\\n\n\t", 'green'),
|
||||||
|
"\r" => "",
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->cWrite('green', $subPart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
$this->cWrite("default", "\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the list of arguments.
|
||||||
|
*
|
||||||
|
* @param array $argv
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function parseArguments(array $argv) {
|
||||||
|
|
||||||
|
$positional = array();
|
||||||
|
$options = array();
|
||||||
|
|
||||||
|
for($ii=0; $ii < count($argv); $ii++) {
|
||||||
|
|
||||||
|
// Skipping the first argument.
|
||||||
|
if ($ii===0) continue;
|
||||||
|
|
||||||
|
$v = $argv[$ii];
|
||||||
|
|
||||||
|
if (substr($v,0,2)==='--') {
|
||||||
|
// This is a long-form option.
|
||||||
|
$optionName = substr($v,2);
|
||||||
|
$optionValue = true;
|
||||||
|
if (strpos($optionName,'=')) {
|
||||||
|
list($optionName, $optionValue) = explode('=', $optionName);
|
||||||
|
}
|
||||||
|
$options[$optionName] = $optionValue;
|
||||||
|
} elseif (substr($v,0,1) === '-' && strlen($v)>1) {
|
||||||
|
// This is a short-form option.
|
||||||
|
foreach(str_split(substr($v,1)) as $option) {
|
||||||
|
$options[$option] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$positional[] = $v;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($options, $positional);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $parser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the input file
|
||||||
|
*
|
||||||
|
* @return Component
|
||||||
|
*/
|
||||||
|
protected function readInput() {
|
||||||
|
|
||||||
|
if (!$this->parser) {
|
||||||
|
if ($this->inputPath!=='-') {
|
||||||
|
$this->stdin = fopen($this->inputPath,'r');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->inputFormat === 'mimedir') {
|
||||||
|
$this->parser = new Parser\MimeDir($this->stdin, ($this->forgiving?Reader::OPTION_FORGIVING:0));
|
||||||
|
} else {
|
||||||
|
$this->parser = new Parser\Json($this->stdin, ($this->forgiving?Reader::OPTION_FORGIVING:0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->parser->parse();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a message to STDERR.
|
||||||
|
*
|
||||||
|
* @param string $msg
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function log($msg, $color = 'default') {
|
||||||
|
|
||||||
|
if (!$this->quiet) {
|
||||||
|
if ($color!=='default') {
|
||||||
|
$msg = $this->colorize($color, $msg);
|
||||||
|
}
|
||||||
|
fwrite($this->stderr, $msg . "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -3,82 +3,218 @@
|
||||||
namespace Sabre\VObject;
|
namespace Sabre\VObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VObject Component
|
* Component
|
||||||
*
|
*
|
||||||
* This class represents a VCALENDAR/VCARD component. A component is for example
|
* A component represents a group of properties, such as VCALENDAR, VEVENT, or
|
||||||
* VEVENT, VTODO and also VCALENDAR. It starts with BEGIN:COMPONENTNAME and
|
* VCARD.
|
||||||
* ends with END:COMPONENTNAME
|
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
*/
|
*/
|
||||||
class Component extends Node {
|
class Component extends Node {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name, for example VEVENT
|
* Component name.
|
||||||
|
*
|
||||||
|
* This will contain a string such as VEVENT, VTODO, VCALENDAR, VCARD.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
public $name;
|
public $name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Children properties and components
|
* A list of properties and/or sub-components.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public $children = array();
|
public $children = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If components are added to this map, they will be automatically mapped
|
* Creates a new component.
|
||||||
* to their respective classes, if parsed by the reader or constructed with
|
|
||||||
* the 'create' method.
|
|
||||||
*
|
*
|
||||||
* @var array
|
* You can specify the children either in key=>value syntax, in which case
|
||||||
*/
|
* properties will automatically be created, or you can just pass a list of
|
||||||
static public $classMap = array(
|
* Component and Property object.
|
||||||
'VALARM' => 'Sabre\\VObject\\Component\\VAlarm',
|
|
||||||
'VCALENDAR' => 'Sabre\\VObject\\Component\\VCalendar',
|
|
||||||
'VCARD' => 'Sabre\\VObject\\Component\\VCard',
|
|
||||||
'VEVENT' => 'Sabre\\VObject\\Component\\VEvent',
|
|
||||||
'VJOURNAL' => 'Sabre\\VObject\\Component\\VJournal',
|
|
||||||
'VTODO' => 'Sabre\\VObject\\Component\\VTodo',
|
|
||||||
'VFREEBUSY' => 'Sabre\\VObject\\Component\\VFreeBusy',
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the new component by name, but in addition will also see if
|
|
||||||
* there's a class mapped to the property name.
|
|
||||||
*
|
*
|
||||||
* @param string $name
|
* By default, a set of sensible values will be added to the component. For
|
||||||
* @param string $value
|
* an iCalendar object, this may be something like CALSCALE:GREGORIAN. To
|
||||||
* @return Component
|
* ensure that this does not happen, set $defaults to false.
|
||||||
|
*
|
||||||
|
* @param Document $root
|
||||||
|
* @param string $name such as VCALENDAR, VEVENT.
|
||||||
|
* @param array $children
|
||||||
|
* @param bool $defaults
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
static public function create($name, $value = null) {
|
public function __construct(Document $root, $name, array $children = array(), $defaults = true) {
|
||||||
|
|
||||||
$name = strtoupper($name);
|
$this->name = strtoupper($name);
|
||||||
|
$this->root = $root;
|
||||||
|
|
||||||
if (isset(self::$classMap[$name])) {
|
if ($defaults) {
|
||||||
return new self::$classMap[$name]($name, $value);
|
$children = array_merge($this->getDefaults(), $children);
|
||||||
} else {
|
}
|
||||||
return new self($name, $value);
|
|
||||||
|
foreach($children as $k=>$child) {
|
||||||
|
if ($child instanceof Node) {
|
||||||
|
|
||||||
|
// Component or Property
|
||||||
|
$this->add($child);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Property key=>value
|
||||||
|
$this->add($k, $child);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new component.
|
* Adds a new property or component, and returns the new item.
|
||||||
*
|
*
|
||||||
* By default this object will iterate over its own children, but this can
|
* This method has 3 possible signatures:
|
||||||
* be overridden with the iterator argument
|
*
|
||||||
|
* add(Component $comp) // Adds a new component
|
||||||
|
* add(Property $prop) // Adds a new property
|
||||||
|
* add($name, $value, array $parameters = array()) // Adds a new property
|
||||||
|
* add($name, array $children = array()) // Adds a new component
|
||||||
|
* by name.
|
||||||
|
*
|
||||||
|
* @return Node
|
||||||
|
*/
|
||||||
|
public function add($a1, $a2 = null, $a3 = null) {
|
||||||
|
|
||||||
|
if ($a1 instanceof Node) {
|
||||||
|
if (!is_null($a2)) {
|
||||||
|
throw new \InvalidArgumentException('The second argument must not be specified, when passing a VObject Node');
|
||||||
|
}
|
||||||
|
$a1->parent = $this;
|
||||||
|
$this->children[] = $a1;
|
||||||
|
|
||||||
|
return $a1;
|
||||||
|
|
||||||
|
} elseif(is_string($a1)) {
|
||||||
|
|
||||||
|
$item = $this->root->create($a1, $a2, $a3);
|
||||||
|
$item->parent = $this;
|
||||||
|
$this->children[] = $item;
|
||||||
|
|
||||||
|
return $item;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
throw new \InvalidArgumentException('The first argument must either be a \\Sabre\\VObject\\Node or a string');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method removes a component or property from this component.
|
||||||
|
*
|
||||||
|
* You can either specify the item by name (like DTSTART), in which case
|
||||||
|
* all properties/components with that name will be removed, or you can
|
||||||
|
* pass an instance of a property or component, in which case only that
|
||||||
|
* exact item will be removed.
|
||||||
|
*
|
||||||
|
* The removed item will be returned. In case there were more than 1 items
|
||||||
|
* removed, only the last one will be returned.
|
||||||
|
*
|
||||||
|
* @param mixed $item
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function remove($item) {
|
||||||
|
|
||||||
|
if (is_string($item)) {
|
||||||
|
$children = $this->select($item);
|
||||||
|
foreach($children as $k=>$child) {
|
||||||
|
unset($this->children[$k]);
|
||||||
|
}
|
||||||
|
return $child;
|
||||||
|
} else {
|
||||||
|
foreach($this->children as $k => $child) {
|
||||||
|
if ($child===$item) {
|
||||||
|
unset($this->children[$k]);
|
||||||
|
return $child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \InvalidArgumentException('The item you passed to remove() was not a child of this component');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable list of children
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function children() {
|
||||||
|
|
||||||
|
return $this->children;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method only returns a list of sub-components. Properties are
|
||||||
|
* ignored.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getComponents() {
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
foreach($this->children as $child) {
|
||||||
|
if ($child instanceof Component) {
|
||||||
|
$result[] = $child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array with elements that match the specified name.
|
||||||
|
*
|
||||||
|
* This function is also aware of MIME-Directory groups (as they appear in
|
||||||
|
* vcards). This means that if a property is grouped as "HOME.EMAIL", it
|
||||||
|
* will also be returned when searching for just "EMAIL". If you want to
|
||||||
|
* search for a property in a specific group, you can select on the entire
|
||||||
|
* string ("HOME.EMAIL"). If you want to search on a specific property that
|
||||||
|
* has not been assigned a group, specify ".EMAIL".
|
||||||
|
*
|
||||||
|
* Keys are retained from the 'children' array, which may be confusing in
|
||||||
|
* certain cases.
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param ElementList $iterator
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function __construct($name, ElementList $iterator = null) {
|
public function select($name) {
|
||||||
|
|
||||||
$this->name = strtoupper($name);
|
$group = null;
|
||||||
if (!is_null($iterator)) $this->iterator = $iterator;
|
$name = strtoupper($name);
|
||||||
|
if (strpos($name,'.')!==false) {
|
||||||
|
list($group,$name) = explode('.', $name, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
foreach($this->children as $key=>$child) {
|
||||||
|
|
||||||
|
if (
|
||||||
|
strtoupper($child->name) === $name &&
|
||||||
|
(is_null($group) || ( $child instanceof Property && strtoupper($child->group) === $group))
|
||||||
|
) {
|
||||||
|
|
||||||
|
$result[$key] = $child;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reset($result);
|
||||||
|
return $result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -141,9 +277,7 @@ class Component extends Node {
|
||||||
$sA = $sortScore($a, $tmp);
|
$sA = $sortScore($a, $tmp);
|
||||||
$sB = $sortScore($b, $tmp);
|
$sB = $sortScore($b, $tmp);
|
||||||
|
|
||||||
if ($sA === $sB) return 0;
|
return $sA - $sB;
|
||||||
|
|
||||||
return ($sA < $sB) ? -1 : 1;
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -155,149 +289,55 @@ class Component extends Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new component or element
|
* This method returns an array, with the representation as it should be
|
||||||
*
|
* encoded in json. This is used to create jCard or jCal documents.
|
||||||
* You can call this method with the following syntaxes:
|
|
||||||
*
|
|
||||||
* add(Node $node)
|
|
||||||
* add(string $name, $value, array $parameters = array())
|
|
||||||
*
|
|
||||||
* The first version adds an Element
|
|
||||||
* The second adds a property as a string.
|
|
||||||
*
|
|
||||||
* @param mixed $item
|
|
||||||
* @param mixed $itemValue
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function add($item, $itemValue = null, array $parameters = array()) {
|
|
||||||
|
|
||||||
if ($item instanceof Node) {
|
|
||||||
if (!is_null($itemValue)) {
|
|
||||||
throw new \InvalidArgumentException('The second argument must not be specified, when passing a VObject Node');
|
|
||||||
}
|
|
||||||
$item->parent = $this;
|
|
||||||
$this->children[] = $item;
|
|
||||||
} elseif(is_string($item)) {
|
|
||||||
|
|
||||||
$item = Property::create($item,$itemValue, $parameters);
|
|
||||||
$item->parent = $this;
|
|
||||||
$this->children[] = $item;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
throw new \InvalidArgumentException('The first argument must either be a \\Sabre\\VObject\\Node or a string');
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an iterable list of children
|
|
||||||
*
|
|
||||||
* @return ElementList
|
|
||||||
*/
|
|
||||||
public function children() {
|
|
||||||
|
|
||||||
return new ElementList($this->children);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an array with elements that match the specified name.
|
|
||||||
*
|
|
||||||
* This function is also aware of MIME-Directory groups (as they appear in
|
|
||||||
* vcards). This means that if a property is grouped as "HOME.EMAIL", it
|
|
||||||
* will also be returned when searching for just "EMAIL". If you want to
|
|
||||||
* search for a property in a specific group, you can select on the entire
|
|
||||||
* string ("HOME.EMAIL"). If you want to search on a specific property that
|
|
||||||
* has not been assigned a group, specify ".EMAIL".
|
|
||||||
*
|
|
||||||
* Keys are retained from the 'children' array, which may be confusing in
|
|
||||||
* certain cases.
|
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function select($name) {
|
|
||||||
|
|
||||||
$group = null;
|
|
||||||
$name = strtoupper($name);
|
|
||||||
if (strpos($name,'.')!==false) {
|
|
||||||
list($group,$name) = explode('.', $name, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = array();
|
|
||||||
foreach($this->children as $key=>$child) {
|
|
||||||
|
|
||||||
if (
|
|
||||||
strtoupper($child->name) === $name &&
|
|
||||||
(is_null($group) || ( $child instanceof Property && strtoupper($child->group) === $group))
|
|
||||||
) {
|
|
||||||
|
|
||||||
$result[$key] = $child;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reset($result);
|
|
||||||
return $result;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method only returns a list of sub-components. Properties are
|
|
||||||
* ignored.
|
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getComponents() {
|
public function jsonSerialize() {
|
||||||
|
|
||||||
|
$components = array();
|
||||||
|
$properties = array();
|
||||||
|
|
||||||
$result = array();
|
|
||||||
foreach($this->children as $child) {
|
foreach($this->children as $child) {
|
||||||
if ($child instanceof Component) {
|
if ($child instanceof Component) {
|
||||||
$result[] = $child;
|
$components[] = $child->jsonSerialize();
|
||||||
|
} else {
|
||||||
|
$properties[] = $child->jsonSerialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return array(
|
||||||
|
strtolower($this->name),
|
||||||
|
$properties,
|
||||||
|
$components
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the node for correctness.
|
* This method should return a list of default property values.
|
||||||
*
|
*
|
||||||
* The following options are supported:
|
|
||||||
* - Node::REPAIR - If something is broken, and automatic repair may
|
|
||||||
* be attempted.
|
|
||||||
*
|
|
||||||
* An array is returned with warnings.
|
|
||||||
*
|
|
||||||
* Every item in the array has the following properties:
|
|
||||||
* * level - (number between 1 and 3 with severity information)
|
|
||||||
* * message - (human readable message)
|
|
||||||
* * node - (reference to the offending node)
|
|
||||||
*
|
|
||||||
* @param int $options
|
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function validate($options = 0) {
|
protected function getDefaults() {
|
||||||
|
|
||||||
$result = array();
|
return array();
|
||||||
foreach($this->children as $child) {
|
|
||||||
$result = array_merge($result, $child->validate($options));
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Magic property accessors {{{ */
|
/* Magic property accessors {{{ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Using 'get' you will either get a property or component,
|
* Using 'get' you will either get a property or component.
|
||||||
*
|
*
|
||||||
* If there were no child-elements found with the specified name,
|
* If there were no child-elements found with the specified name,
|
||||||
* null is returned.
|
* null is returned.
|
||||||
*
|
*
|
||||||
|
* To use this, this may look something like this:
|
||||||
|
*
|
||||||
|
* $event = $calendar->VEVENT;
|
||||||
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @return Property
|
* @return Property
|
||||||
*/
|
*/
|
||||||
|
|
@ -353,8 +393,8 @@ class Component extends Node {
|
||||||
} else {
|
} else {
|
||||||
$this->children[] = $value;
|
$this->children[] = $value;
|
||||||
}
|
}
|
||||||
} elseif (is_scalar($value)) {
|
} elseif (is_scalar($value) || is_array($value) || is_null($value)) {
|
||||||
$property = Property::create($name,$value);
|
$property = $this->root->create($name,$value);
|
||||||
$property->parent = $this;
|
$property->parent = $this;
|
||||||
if (!is_null($overWrite)) {
|
if (!is_null($overWrite)) {
|
||||||
$this->children[$overWrite] = $property;
|
$this->children[$overWrite] = $property;
|
||||||
|
|
@ -368,7 +408,8 @@ class Component extends Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all properties and components within this component.
|
* Removes all properties and components within this component with the
|
||||||
|
* specified name.
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @return void
|
* @return void
|
||||||
|
|
@ -402,4 +443,31 @@ class Component extends Node {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the node for correctness.
|
||||||
|
*
|
||||||
|
* The following options are supported:
|
||||||
|
* - Node::REPAIR - If something is broken, an automatic repair may
|
||||||
|
* be attempted.
|
||||||
|
*
|
||||||
|
* An array is returned with warnings.
|
||||||
|
*
|
||||||
|
* Every item in the array has the following properties:
|
||||||
|
* * level - (number between 1 and 3 with severity information)
|
||||||
|
* * message - (human readable message)
|
||||||
|
* * node - (reference to the offending node)
|
||||||
|
*
|
||||||
|
* @param int $options
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function validate($options = 0) {
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
foreach($this->children as $child) {
|
||||||
|
$result = array_merge($result, $child->validate($options));
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
namespace Sabre\VObject\Component;
|
namespace Sabre\VObject\Component;
|
||||||
|
|
||||||
use Sabre\VObject;
|
use
|
||||||
|
Sabre\VObject,
|
||||||
|
Sabre\VObject\Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The VCalendar component
|
* The VCalendar component
|
||||||
|
|
@ -15,7 +17,140 @@ use Sabre\VObject;
|
||||||
*/
|
*/
|
||||||
class VCalendar extends VObject\Document {
|
class VCalendar extends VObject\Document {
|
||||||
|
|
||||||
static $defaultName = 'VCALENDAR';
|
/**
|
||||||
|
* The default name for this component.
|
||||||
|
*
|
||||||
|
* This should be 'VCALENDAR' or 'VCARD'.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
static public $defaultName = 'VCALENDAR';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a list of components, and which classes they should map to.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
static public $componentMap = array(
|
||||||
|
'VEVENT' => 'Sabre\\VObject\\Component\\VEvent',
|
||||||
|
'VFREEBUSY' => 'Sabre\\VObject\\Component\\VFreeBusy',
|
||||||
|
'VJOURNAL' => 'Sabre\\VObject\\Component\\VJournal',
|
||||||
|
'VTODO' => 'Sabre\\VObject\\Component\\VTodo',
|
||||||
|
'VALARM' => 'Sabre\\VObject\\Component\\VAlarm',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of value-types, and which classes they map to.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
static public $valueMap = array(
|
||||||
|
'BINARY' => 'Sabre\\VObject\\Property\\Binary',
|
||||||
|
'BOOLEAN' => 'Sabre\\VObject\\Property\\Boolean',
|
||||||
|
'CAL-ADDRESS' => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress',
|
||||||
|
'DATE' => 'Sabre\\VObject\\Property\\ICalendar\\Date',
|
||||||
|
'DATE-TIME' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
|
||||||
|
'DURATION' => 'Sabre\\VObject\\Property\\ICalendar\\Duration',
|
||||||
|
'FLOAT' => 'Sabre\\VObject\\Property\\Float',
|
||||||
|
'INTEGER' => 'Sabre\\VObject\\Property\\Integer',
|
||||||
|
'PERIOD' => 'Sabre\\VObject\\Property\\ICalendar\\Period',
|
||||||
|
'RECUR' => 'Sabre\\VObject\\Property\\ICalendar\\Recur',
|
||||||
|
'TEXT' => 'Sabre\\VObject\\Property\\Text',
|
||||||
|
'TIME' => 'Sabre\\VObject\\Property\\Time',
|
||||||
|
'UNKNOWN' => 'Sabre\\VObject\\Property\\Unknown', // jCard / jCal-only.
|
||||||
|
'URI' => 'Sabre\\VObject\\Property\\Uri',
|
||||||
|
'UTC-OFFSET' => 'Sabre\\VObject\\Property\\UtcOffset',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of properties, and which classes they map to.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
static public $propertyMap = array(
|
||||||
|
// Calendar properties
|
||||||
|
'CALSCALE' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'METHOD' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'PRODID' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'VERSION' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
|
||||||
|
// Component properties
|
||||||
|
'ATTACH' => 'Sabre\\VObject\\Property\\Binary',
|
||||||
|
'CATEGORIES' => 'Sabre\\VObject\\Property\\Text',
|
||||||
|
'CLASS' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'COMMENT' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'DESCRIPTION' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'GEO' => 'Sabre\\VObject\\Property\\Float',
|
||||||
|
'LOCATION' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'PERCENT-COMPLETE' => 'Sabre\\VObject\\Property\\Integer',
|
||||||
|
'PRIORITY' => 'Sabre\\VObject\\Property\\Integer',
|
||||||
|
'RESOURCES' => 'Sabre\\VObject\\Property\\Text',
|
||||||
|
'STATUS' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'SUMMARY' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
|
||||||
|
// Date and Time Component Properties
|
||||||
|
'COMPLETED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
|
||||||
|
'DTEND' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
|
||||||
|
'DUE' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
|
||||||
|
'DTSTART' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
|
||||||
|
'DURATION' => 'Sabre\\VObject\\Property\\ICalendar\\Duration',
|
||||||
|
'FREEBUSY' => 'Sabre\\VObject\\Property\\ICalendar\\Period',
|
||||||
|
'TRANSP' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
|
||||||
|
// Time Zone Component Properties
|
||||||
|
'TZID' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'TZNAME' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'TZOFFSETFROM' => 'Sabre\\VObject\\Property\\UtcOffset',
|
||||||
|
'TZOFFSETTO' => 'Sabre\\VObject\\Property\\UtcOffset',
|
||||||
|
'TZURL' => 'Sabre\\VObject\\Property\\Uri',
|
||||||
|
|
||||||
|
// Relationship Component Properties
|
||||||
|
'ATTENDEE' => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress',
|
||||||
|
'CONTACT' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'ORGANIZER' => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress',
|
||||||
|
'RECURRENCE-ID' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
|
||||||
|
'RELATED-TO' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'URL' => 'Sabre\\VObject\\Property\\Uri',
|
||||||
|
'UID' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
|
||||||
|
// Recurrence Component Properties
|
||||||
|
'EXDATE' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
|
||||||
|
'RDATE' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
|
||||||
|
'RRULE' => 'Sabre\\VObject\\Property\\ICalendar\\Recur',
|
||||||
|
'EXRULE' => 'Sabre\\VObject\\Property\\ICalendar\\Recur', // Deprecated since rfc5545
|
||||||
|
|
||||||
|
// Alarm Component Properties
|
||||||
|
'ACTION' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'REPEAT' => 'Sabre\\VObject\\Property\\Integer',
|
||||||
|
'TRIGGER' => 'Sabre\\VObject\\Property\\ICalendar\\Duration',
|
||||||
|
|
||||||
|
// Change Management Component Properties
|
||||||
|
'CREATED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
|
||||||
|
'DTSTAMP' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
|
||||||
|
'LAST-MODIFIED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
|
||||||
|
'SEQUENCE' => 'Sabre\\VObject\\Property\\Integer',
|
||||||
|
|
||||||
|
// Request Status
|
||||||
|
'REQUEST-STATUS' => 'Sabre\\VObject\\Property\\Text',
|
||||||
|
|
||||||
|
// Additions from draft-daboo-valarm-extensions-04
|
||||||
|
'ALARM-AGENT' => 'Sabre\\VObject\\Property\\Text',
|
||||||
|
'ACKNOWLEDGED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
|
||||||
|
'PROXIMITY' => 'Sabre\\VObject\\Property\\Text',
|
||||||
|
'DEFAULT-ALARM' => 'Sabre\\VObject\\Property\\Boolean',
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current document type.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function getDocumentType() {
|
||||||
|
|
||||||
|
return self::ICALENDAR20;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of all 'base components'. For instance, if an Event has
|
* Returns a list of all 'base components'. For instance, if an Event has
|
||||||
|
|
@ -115,13 +250,19 @@ class VCalendar extends VObject\Document {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setting all properties to UTC time.
|
||||||
foreach($newEvents as $newEvent) {
|
foreach($newEvents as $newEvent) {
|
||||||
|
|
||||||
foreach($newEvent->children as $child) {
|
foreach($newEvent->children as $child) {
|
||||||
if ($child instanceof VObject\Property\DateTime &&
|
if ($child instanceof VObject\Property\ICalendar\DateTime && $child->hasTime()) {
|
||||||
$child->getDateType() == VObject\Property\DateTime::LOCALTZ) {
|
$dt = $child->getDateTimes();
|
||||||
$child->setDateTime($child->getDateTime(),VObject\Property\DateTime::UTC);
|
// We only need to update the first timezone, because
|
||||||
}
|
// setDateTimes will match all other timezones to the
|
||||||
|
// first.
|
||||||
|
$dt[0]->setTimeZone(new \DateTimeZone('UTC'));
|
||||||
|
$child->setDateTimes($dt);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->add($newEvent);
|
$this->add($newEvent);
|
||||||
|
|
@ -133,6 +274,21 @@ class VCalendar extends VObject\Document {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method should return a list of default property values.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getDefaults() {
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'VERSION' => '2.0',
|
||||||
|
'PRODID' => '-//Sabre//Sabre VObject ' . VObject\Version::VERSION . '//EN',
|
||||||
|
'CALSCALE' => 'GREGORIAN',
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the node for correctness.
|
* Validates the node for correctness.
|
||||||
* An array is returned with warnings.
|
* An array is returned with warnings.
|
||||||
|
|
@ -144,8 +300,7 @@ class VCalendar extends VObject\Document {
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
/*
|
public function validate($options = 0) {
|
||||||
public function validate() {
|
|
||||||
|
|
||||||
$warnings = array();
|
$warnings = array();
|
||||||
|
|
||||||
|
|
@ -188,39 +343,10 @@ class VCalendar extends VObject\Document {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$allowedComponents = array(
|
|
||||||
'VEVENT',
|
|
||||||
'VTODO',
|
|
||||||
'VJOURNAL',
|
|
||||||
'VFREEBUSY',
|
|
||||||
'VTIMEZONE',
|
|
||||||
);
|
|
||||||
$allowedProperties = array(
|
|
||||||
'PRODID',
|
|
||||||
'VERSION',
|
|
||||||
'CALSCALE',
|
|
||||||
'METHOD',
|
|
||||||
);
|
|
||||||
$componentsFound = 0;
|
$componentsFound = 0;
|
||||||
foreach($this->children as $child) {
|
foreach($this->children as $child) {
|
||||||
if($child instanceof Component) {
|
if($child instanceof Component) {
|
||||||
$componentsFound++;
|
$componentsFound++;
|
||||||
if (!in_array($child->name, $allowedComponents)) {
|
|
||||||
$warnings[] = array(
|
|
||||||
'level' => 1,
|
|
||||||
'message' => 'The ' . $child->name . " component is not allowed in the VCALENDAR component",
|
|
||||||
'node' => $this,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($child instanceof Property) {
|
|
||||||
if (!in_array($child->name, $allowedProperties)) {
|
|
||||||
$warnings[] = array(
|
|
||||||
'level' => 2,
|
|
||||||
'message' => 'The ' . $child->name . " property is not allowed in the VCALENDAR component",
|
|
||||||
'node' => $this,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,7 +364,6 @@ class VCalendar extends VObject\Document {
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
namespace Sabre\VObject\Component;
|
namespace Sabre\VObject\Component;
|
||||||
|
|
||||||
use Sabre\VObject;
|
use
|
||||||
|
Sabre\VObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The VCard component
|
* The VCard component
|
||||||
|
|
@ -14,16 +15,164 @@ use Sabre\VObject;
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
*/
|
*/
|
||||||
class VCard extends VObject\Component {
|
class VCard extends VObject\Document {
|
||||||
|
|
||||||
static $defaultName = 'VCARD';
|
/**
|
||||||
|
* The default name for this component.
|
||||||
|
*
|
||||||
|
* This should be 'VCALENDAR' or 'VCARD'.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
static public $defaultName = 'VCARD';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caching the version number
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $version = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of value-types, and which classes they map to.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
static public $valueMap = array(
|
||||||
|
'BINARY' => 'Sabre\\VObject\\Property\\Binary',
|
||||||
|
'BOOLEAN' => 'Sabre\\VObject\\Property\\Boolean',
|
||||||
|
'CONTENT-ID' => 'Sabre\\VObject\\Property\\FlatText', // vCard 2.1 only
|
||||||
|
'DATE' => 'Sabre\\VObject\\Property\\VCard\\Date',
|
||||||
|
'DATE-TIME' => 'Sabre\\VObject\\Property\\VCard\\DateTime',
|
||||||
|
'DATE-AND-OR-TIME' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime', // vCard only
|
||||||
|
'FLOAT' => 'Sabre\\VObject\\Property\\Float',
|
||||||
|
'INTEGER' => 'Sabre\\VObject\\Property\\Integer',
|
||||||
|
'LANGUAGE-TAG' => 'Sabre\\VObject\\Property\\VCard\\LanguageTag',
|
||||||
|
'TIMESTAMP' => 'Sabre\\VObject\\Property\\VCard\\TimeStamp',
|
||||||
|
'TEXT' => 'Sabre\\VObject\\Property\\Text',
|
||||||
|
'TIME' => 'Sabre\\VObject\\Property\\Time',
|
||||||
|
'UNKNOWN' => 'Sabre\\VObject\\Property\\Unknown', // jCard / jCal-only.
|
||||||
|
'URI' => 'Sabre\\VObject\\Property\\Uri',
|
||||||
|
'URL' => 'Sabre\\VObject\\Property\\Uri', // vCard 2.1 only
|
||||||
|
'UTC-OFFSET' => 'Sabre\\VObject\\Property\\UtcOffset',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of properties, and which classes they map to.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
static public $propertyMap = array(
|
||||||
|
|
||||||
|
// vCard 2.1 properties and up
|
||||||
|
'N' => 'Sabre\\VObject\\Property\\Text',
|
||||||
|
'FN' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'PHOTO' => 'Sabre\\VObject\\Property\\Binary', // Todo: we should add a class for Binary values.
|
||||||
|
'BDAY' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
|
||||||
|
'ADR' => 'Sabre\\VObject\\Property\\Text',
|
||||||
|
'LABEL' => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
|
||||||
|
'TEL' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'EMAIL' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'MAILER' => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
|
||||||
|
'GEO' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'TITLE' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'ROLE' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'LOGO' => 'Sabre\\VObject\\Property\\Binary',
|
||||||
|
// 'AGENT' => 'Sabre\\VObject\\Property\\', // Todo: is an embedded vCard. Probably rare, so
|
||||||
|
// not supported at the moment
|
||||||
|
'ORG' => 'Sabre\\VObject\\Property\\Text',
|
||||||
|
'NOTE' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'REV' => 'Sabre\\VObject\\Property\\VCard\\TimeStamp',
|
||||||
|
'SOUND' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'URL' => 'Sabre\\VObject\\Property\\Uri',
|
||||||
|
'UID' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'VERSION' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'KEY' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'TZ' => 'Sabre\\VObject\\Property\\Text',
|
||||||
|
|
||||||
|
// vCard 3.0 properties
|
||||||
|
'CATEGORIES' => 'Sabre\\VObject\\Property\\Text',
|
||||||
|
'SORT-STRING' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'PRODID' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'NICKNAME' => 'Sabre\\VObject\\Property\\Text',
|
||||||
|
'CLASS' => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
|
||||||
|
|
||||||
|
// rfc2739 properties
|
||||||
|
'FBURL' => 'Sabre\\VObject\\Property\\Uri',
|
||||||
|
'CAPURI' => 'Sabre\\VObject\\Property\\Uri',
|
||||||
|
'CALURI' => 'Sabre\\VObject\\Property\\Uri',
|
||||||
|
|
||||||
|
// rfc4770 properties
|
||||||
|
'IMPP' => 'Sabre\\VObject\\Property\\Uri',
|
||||||
|
|
||||||
|
// vCard 4.0 properties
|
||||||
|
'XML' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
'ANNIVERSARY' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
|
||||||
|
'CLIENTPIDMAP' => 'Sabre\\VObject\\Property\\Text',
|
||||||
|
'LANG' => 'Sabre\\VObject\\Property\\VCard\\LanguageTag',
|
||||||
|
'GENDER' => 'Sabre\\VObject\\Property\\Text',
|
||||||
|
'KIND' => 'Sabre\\VObject\\Property\\FlatText',
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current document type.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function getDocumentType() {
|
||||||
|
|
||||||
|
if (!$this->version) {
|
||||||
|
$version = (string)$this->VERSION;
|
||||||
|
switch($version) {
|
||||||
|
case '2.1' :
|
||||||
|
$this->version = self::VCARD21;
|
||||||
|
break;
|
||||||
|
case '3.0' :
|
||||||
|
$this->version = self::VCARD30;
|
||||||
|
break;
|
||||||
|
case '4.0' :
|
||||||
|
$this->version = self::VCARD40;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
$this->version = self::UNKNOWN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->version;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the document to a different vcard version.
|
||||||
|
*
|
||||||
|
* Use one of the VCARD constants for the target. This method will return
|
||||||
|
* a copy of the vcard in the new version.
|
||||||
|
*
|
||||||
|
* At the moment the only supported conversion is from 3.0 to 4.0.
|
||||||
|
*
|
||||||
|
* If input and output version are identical, a clone is returned.
|
||||||
|
*
|
||||||
|
* @param int $target
|
||||||
|
* @return VCard
|
||||||
|
*/
|
||||||
|
public function convert($target) {
|
||||||
|
|
||||||
|
$converter = new VObject\VCardConverter();
|
||||||
|
return $converter->convert($this, $target);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VCards with version 2.1, 3.0 and 4.0 are found.
|
* VCards with version 2.1, 3.0 and 4.0 are found.
|
||||||
*
|
*
|
||||||
* If the VCARD doesn't know its version, 4.0 is assumed.
|
* If the VCARD doesn't know its version, 2.1 is assumed.
|
||||||
*/
|
*/
|
||||||
const DEFAULT_VERSION = '4.0';
|
const DEFAULT_VERSION = self::VCARD21;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the node for correctness.
|
* Validates the node for correctness.
|
||||||
|
|
@ -46,6 +195,12 @@ class VCard extends VObject\Component {
|
||||||
|
|
||||||
$warnings = array();
|
$warnings = array();
|
||||||
|
|
||||||
|
$versionMap = array(
|
||||||
|
self::VCARD21 => '2.1',
|
||||||
|
self::VCARD30 => '3.0',
|
||||||
|
self::VCARD40 => '4.0',
|
||||||
|
);
|
||||||
|
|
||||||
$version = $this->select('VERSION');
|
$version = $this->select('VERSION');
|
||||||
if (count($version)!==1) {
|
if (count($version)!==1) {
|
||||||
$warnings[] = array(
|
$warnings[] = array(
|
||||||
|
|
@ -54,7 +209,7 @@ class VCard extends VObject\Component {
|
||||||
'node' => $this,
|
'node' => $this,
|
||||||
);
|
);
|
||||||
if ($options & self::REPAIR) {
|
if ($options & self::REPAIR) {
|
||||||
$this->VERSION = self::DEFAULT_VERSION;
|
$this->VERSION = $versionMap[self::DEFAULT_VERSION];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$version = (string)$this->VERSION;
|
$version = (string)$this->VERSION;
|
||||||
|
|
@ -65,7 +220,7 @@ class VCard extends VObject\Component {
|
||||||
'node' => $this,
|
'node' => $this,
|
||||||
);
|
);
|
||||||
if ($options & self::REPAIR) {
|
if ($options & self::REPAIR) {
|
||||||
$this->VERSION = '4.0';
|
$this->VERSION = $versionMap[self::DEFAULT_VERSION];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,5 +258,96 @@ class VCard extends VObject\Component {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a preferred field.
|
||||||
|
*
|
||||||
|
* VCards can indicate wether a field such as ADR, TEL or EMAIL is
|
||||||
|
* preferred by specifying TYPE=PREF (vcard 2.1, 3) or PREF=x (vcard 4, x
|
||||||
|
* being a number between 1 and 100).
|
||||||
|
*
|
||||||
|
* If neither of those parameters are specified, the first is returned, if
|
||||||
|
* a field with that name does not exist, null is returned.
|
||||||
|
*
|
||||||
|
* @param string $fieldName
|
||||||
|
* @return VObject\Property|null
|
||||||
|
*/
|
||||||
|
public function preferred($propertyName) {
|
||||||
|
|
||||||
|
$preferred = null;
|
||||||
|
$lastPref = 101;
|
||||||
|
foreach($this->select($propertyName) as $field) {
|
||||||
|
|
||||||
|
$pref = 101;
|
||||||
|
if (isset($field['TYPE']) && $field['TYPE']->has('PREF')) {
|
||||||
|
$pref = 1;
|
||||||
|
} elseif (isset($field['PREF'])) {
|
||||||
|
$pref = $field['PREF']->getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($pref < $lastPref || is_null($preferred)) {
|
||||||
|
$preferred = $field;
|
||||||
|
$lastPref = $pref;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return $preferred;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method should return a list of default property values.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getDefaults() {
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'VERSION' => '3.0',
|
||||||
|
'PRODID' => '-//Sabre//Sabre VObject ' . VObject\Version::VERSION . '//EN',
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns an array, with the representation as it should be
|
||||||
|
* encoded in json. This is used to create jCard or jCal documents.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function jsonSerialize() {
|
||||||
|
|
||||||
|
// A vcard does not have sub-components, so we're overriding this
|
||||||
|
// method to remove that array element.
|
||||||
|
$properties = array();
|
||||||
|
|
||||||
|
foreach($this->children as $child) {
|
||||||
|
$properties[] = $child->jsonSerialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
strtolower($this->name),
|
||||||
|
$properties,
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the default class for a property name.
|
||||||
|
*
|
||||||
|
* @param string $propertyName
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getClassNameForPropertyName($propertyName) {
|
||||||
|
|
||||||
|
$className = parent::getClassNameForPropertyName($propertyName);
|
||||||
|
// In vCard 4, BINARY no longer exists, and we need URI instead.
|
||||||
|
|
||||||
|
if ($className == 'Sabre\\VObject\\Property\\Binary' && $this->getDocumentType()===self::VCARD40) {
|
||||||
|
return 'Sabre\\VObject\\Property\\Uri';
|
||||||
|
}
|
||||||
|
return $className;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ class VEvent extends VObject\Component {
|
||||||
} elseif (isset($this->DURATION)) {
|
} elseif (isset($this->DURATION)) {
|
||||||
$effectiveEnd = clone $effectiveStart;
|
$effectiveEnd = clone $effectiveStart;
|
||||||
$effectiveEnd->add( VObject\DateTimeParser::parseDuration($this->DURATION) );
|
$effectiveEnd->add( VObject\DateTimeParser::parseDuration($this->DURATION) );
|
||||||
} elseif ($this->DTSTART->getDateType() == VObject\Property\DateTime::DATE) {
|
} elseif (!$this->DTSTART->hasTime()) {
|
||||||
$effectiveEnd = clone $effectiveStart;
|
$effectiveEnd = clone $effectiveStart;
|
||||||
$effectiveEnd->modify('+1 day');
|
$effectiveEnd->modify('+1 day');
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ class VJournal extends VObject\Component {
|
||||||
$dtstart = isset($this->DTSTART)?$this->DTSTART->getDateTime():null;
|
$dtstart = isset($this->DTSTART)?$this->DTSTART->getDateTime():null;
|
||||||
if ($dtstart) {
|
if ($dtstart) {
|
||||||
$effectiveEnd = clone $dtstart;
|
$effectiveEnd = clone $dtstart;
|
||||||
if ($this->DTSTART->getDateType() == VObject\Property\DateTime::DATE) {
|
if (!$this->DTSTART->hasTime()) {
|
||||||
$effectiveEnd->modify('+1 day');
|
$effectiveEnd->modify('+1 day');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class DateTimeParser {
|
||||||
static public function parseDateTime($dt,\DateTimeZone $tz = null) {
|
static public function parseDateTime($dt,\DateTimeZone $tz = null) {
|
||||||
|
|
||||||
// Format is YYYYMMDD + "T" + hhmmss
|
// Format is YYYYMMDD + "T" + hhmmss
|
||||||
$result = preg_match('/^([1-4][0-9]{3})([0-1][0-9])([0-3][0-9])T([0-2][0-9])([0-5][0-9])([0-5][0-9])([Z]?)$/',$dt,$matches);
|
$result = preg_match('/^([0-9]{4})([0-1][0-9])([0-3][0-9])T([0-2][0-9])([0-5][0-9])([0-5][0-9])([Z]?)$/',$dt,$matches);
|
||||||
|
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
throw new \LogicException('The supplied iCalendar datetime value is incorrect: ' . $dt);
|
throw new \LogicException('The supplied iCalendar datetime value is incorrect: ' . $dt);
|
||||||
|
|
@ -40,7 +40,7 @@ class DateTimeParser {
|
||||||
$date = new \DateTime($matches[1] . '-' . $matches[2] . '-' . $matches[3] . ' ' . $matches[4] . ':' . $matches[5] .':' . $matches[6], $tz);
|
$date = new \DateTime($matches[1] . '-' . $matches[2] . '-' . $matches[3] . ' ' . $matches[4] . ':' . $matches[5] .':' . $matches[6], $tz);
|
||||||
|
|
||||||
// Still resetting the timezone, to normalize everything to UTC
|
// Still resetting the timezone, to normalize everything to UTC
|
||||||
$date->setTimeZone(new \DateTimeZone('UTC'));
|
// $date->setTimeZone(new \DateTimeZone('UTC'));
|
||||||
return $date;
|
return $date;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -54,7 +54,7 @@ class DateTimeParser {
|
||||||
static public function parseDate($date) {
|
static public function parseDate($date) {
|
||||||
|
|
||||||
// Format is YYYYMMDD
|
// Format is YYYYMMDD
|
||||||
$result = preg_match('/^([1-4][0-9]{3})([0-1][0-9])([0-3][0-9])$/',$date,$matches);
|
$result = preg_match('/^([0-9]{4})([0-1][0-9])([0-3][0-9])$/',$date,$matches);
|
||||||
|
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
throw new \LogicException('The supplied iCalendar date value is incorrect: ' . $date);
|
throw new \LogicException('The supplied iCalendar date value is incorrect: ' . $date);
|
||||||
|
|
@ -177,5 +177,239 @@ class DateTimeParser {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method parses a vCard date and or time value.
|
||||||
|
*
|
||||||
|
* This can be used for the DATE, DATE-TIME, TIMESTAMP and
|
||||||
|
* DATE-AND-OR-TIME value.
|
||||||
|
*
|
||||||
|
* This method returns an array, not a DateTime value.
|
||||||
|
*
|
||||||
|
* The elements in the array are in the following order:
|
||||||
|
* year, month, date, hour, minute, second, timezone
|
||||||
|
*
|
||||||
|
* Almost any part of the string may be omitted. It's for example legal to
|
||||||
|
* just specify seconds, leave out the year, etc.
|
||||||
|
*
|
||||||
|
* Timezone is either returned as 'Z' or as '+08:00'
|
||||||
|
*
|
||||||
|
* For any non-specified values null is returned.
|
||||||
|
*
|
||||||
|
* List of date formats that are supported:
|
||||||
|
* YYYY
|
||||||
|
* YYYY-MM
|
||||||
|
* YYYYMMDD
|
||||||
|
* --MMDD
|
||||||
|
* ---DD
|
||||||
|
*
|
||||||
|
* YYYY-MM-DD
|
||||||
|
* --MM-DD
|
||||||
|
* ---DD
|
||||||
|
*
|
||||||
|
* List of supported time formats:
|
||||||
|
*
|
||||||
|
* HH
|
||||||
|
* HHMM
|
||||||
|
* HHMMSS
|
||||||
|
* -MMSS
|
||||||
|
* --SS
|
||||||
|
*
|
||||||
|
* HH
|
||||||
|
* HH:MM
|
||||||
|
* HH:MM:SS
|
||||||
|
* -MM:SS
|
||||||
|
* --SS
|
||||||
|
*
|
||||||
|
* A full basic-format date-time string looks like :
|
||||||
|
* 20130603T133901
|
||||||
|
*
|
||||||
|
* A full extended-format date-time string looks like :
|
||||||
|
* 2013-06-03T13:39:01
|
||||||
|
*
|
||||||
|
* Times may be postfixed by a timezone offset. This can be either 'Z' for
|
||||||
|
* UTC, or a string like -0500 or +1100.
|
||||||
|
*
|
||||||
|
* @param string $date
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
static public function parseVCardDateTime($date) {
|
||||||
|
|
||||||
|
$regex = '/^
|
||||||
|
(?: # date part
|
||||||
|
(?:
|
||||||
|
(?: (?P<year> [0-9]{4}) (?: -)?| --)
|
||||||
|
(?P<month> [0-9]{2})?
|
||||||
|
|---)
|
||||||
|
(?P<date> [0-9]{2})?
|
||||||
|
)?
|
||||||
|
(?:T # time part
|
||||||
|
(?P<hour> [0-9]{2} | -)
|
||||||
|
(?P<minute> [0-9]{2} | -)?
|
||||||
|
(?P<second> [0-9]{2})?
|
||||||
|
|
||||||
|
(?P<timezone> # timezone offset
|
||||||
|
|
||||||
|
Z | (?: \+|-)(?: [0-9]{4})
|
||||||
|
|
||||||
|
)?
|
||||||
|
|
||||||
|
)?
|
||||||
|
$/x';
|
||||||
|
|
||||||
|
|
||||||
|
if (!preg_match($regex, $date, $matches)) {
|
||||||
|
|
||||||
|
// Attempting to parse the extended format.
|
||||||
|
$regex = '/^
|
||||||
|
(?: # date part
|
||||||
|
(?: (?P<year> [0-9]{4}) - | -- )
|
||||||
|
(?P<month> [0-9]{2}) -
|
||||||
|
(?P<date> [0-9]{2})
|
||||||
|
)?
|
||||||
|
(?:T # time part
|
||||||
|
|
||||||
|
(?: (?P<hour> [0-9]{2}) : | -)
|
||||||
|
(?: (?P<minute> [0-9]{2}) : | -)?
|
||||||
|
(?P<second> [0-9]{2})?
|
||||||
|
|
||||||
|
(?P<timezone> # timezone offset
|
||||||
|
|
||||||
|
Z | (?: \+|-)(?: [0-9]{2}:[0-9]{2})
|
||||||
|
|
||||||
|
)?
|
||||||
|
|
||||||
|
)?
|
||||||
|
$/x';
|
||||||
|
|
||||||
|
if (!preg_match($regex, $date, $matches)) {
|
||||||
|
throw new \InvalidArgumentException('Invalid vCard date-time string: ' . $date);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
$parts = array(
|
||||||
|
'year',
|
||||||
|
'month',
|
||||||
|
'date',
|
||||||
|
'hour',
|
||||||
|
'minute',
|
||||||
|
'second',
|
||||||
|
'timezone'
|
||||||
|
);
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
foreach($parts as $part) {
|
||||||
|
|
||||||
|
if (empty($matches[$part])) {
|
||||||
|
$result[$part] = null;
|
||||||
|
} elseif ($matches[$part] === '-' || $matches[$part] === '--') {
|
||||||
|
$result[$part] = null;
|
||||||
|
} else {
|
||||||
|
$result[$part] = $matches[$part];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method parses a vCard TIME value.
|
||||||
|
*
|
||||||
|
* This method returns an array, not a DateTime value.
|
||||||
|
*
|
||||||
|
* The elements in the array are in the following order:
|
||||||
|
* hour, minute, second, timezone
|
||||||
|
*
|
||||||
|
* Almost any part of the string may be omitted. It's for example legal to
|
||||||
|
* just specify seconds, leave out the hour etc.
|
||||||
|
*
|
||||||
|
* Timezone is either returned as 'Z' or as '+08:00'
|
||||||
|
*
|
||||||
|
* For any non-specified values null is returned.
|
||||||
|
*
|
||||||
|
* List of supported time formats:
|
||||||
|
*
|
||||||
|
* HH
|
||||||
|
* HHMM
|
||||||
|
* HHMMSS
|
||||||
|
* -MMSS
|
||||||
|
* --SS
|
||||||
|
*
|
||||||
|
* HH
|
||||||
|
* HH:MM
|
||||||
|
* HH:MM:SS
|
||||||
|
* -MM:SS
|
||||||
|
* --SS
|
||||||
|
*
|
||||||
|
* A full basic-format time string looks like :
|
||||||
|
* 133901
|
||||||
|
*
|
||||||
|
* A full extended-format time string looks like :
|
||||||
|
* 13:39:01
|
||||||
|
*
|
||||||
|
* Times may be postfixed by a timezone offset. This can be either 'Z' for
|
||||||
|
* UTC, or a string like -0500 or +11:00.
|
||||||
|
*
|
||||||
|
* @param string $date
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
static public function parseVCardTime($date) {
|
||||||
|
|
||||||
|
$regex = '/^
|
||||||
|
(?P<hour> [0-9]{2} | -)
|
||||||
|
(?P<minute> [0-9]{2} | -)?
|
||||||
|
(?P<second> [0-9]{2})?
|
||||||
|
|
||||||
|
(?P<timezone> # timezone offset
|
||||||
|
|
||||||
|
Z | (?: \+|-)(?: [0-9]{4})
|
||||||
|
|
||||||
|
)?
|
||||||
|
$/x';
|
||||||
|
|
||||||
|
|
||||||
|
if (!preg_match($regex, $date, $matches)) {
|
||||||
|
|
||||||
|
// Attempting to parse the extended format.
|
||||||
|
$regex = '/^
|
||||||
|
(?: (?P<hour> [0-9]{2}) : | -)
|
||||||
|
(?: (?P<minute> [0-9]{2}) : | -)?
|
||||||
|
(?P<second> [0-9]{2})?
|
||||||
|
|
||||||
|
(?P<timezone> # timezone offset
|
||||||
|
|
||||||
|
Z | (?: \+|-)(?: [0-9]{2}:[0-9]{2})
|
||||||
|
|
||||||
|
)?
|
||||||
|
$/x';
|
||||||
|
|
||||||
|
if (!preg_match($regex, $date, $matches)) {
|
||||||
|
throw new \InvalidArgumentException('Invalid vCard time string: ' . $date);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
$parts = array(
|
||||||
|
'hour',
|
||||||
|
'minute',
|
||||||
|
'second',
|
||||||
|
'timezone'
|
||||||
|
);
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
foreach($parts as $part) {
|
||||||
|
|
||||||
|
if (empty($matches[$part])) {
|
||||||
|
$result[$part] = null;
|
||||||
|
} elseif ($matches[$part] === '-') {
|
||||||
|
$result[$part] = null;
|
||||||
|
} else {
|
||||||
|
$result[$part] = $matches[$part];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,36 @@ namespace Sabre\VObject;
|
||||||
*/
|
*/
|
||||||
abstract class Document extends Component {
|
abstract class Document extends Component {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unknown document type
|
||||||
|
*/
|
||||||
|
const UNKNOWN = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vCalendar 1.0
|
||||||
|
*/
|
||||||
|
const VCALENDAR10 = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iCalendar 2.0
|
||||||
|
*/
|
||||||
|
const ICALENDAR20 = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vCard 2.1
|
||||||
|
*/
|
||||||
|
const VCARD21 = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vCard 3.0
|
||||||
|
*/
|
||||||
|
const VCARD30 = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vCard 4.0
|
||||||
|
*/
|
||||||
|
const VCARD40 = 6;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default name for this component.
|
* The default name for this component.
|
||||||
*
|
*
|
||||||
|
|
@ -25,7 +55,28 @@ abstract class Document extends Component {
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
static $defaultName;
|
static public $defaultName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of properties, and which classes they map to.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
static public $propertyMap = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of components, along with which classes they map to.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
static public $componentMap = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of value-types, and which classes they map to.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
static public $valueMap = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new document.
|
* Creates a new document.
|
||||||
|
|
@ -38,8 +89,8 @@ abstract class Document extends Component {
|
||||||
*
|
*
|
||||||
* So the two sigs:
|
* So the two sigs:
|
||||||
*
|
*
|
||||||
* new Document(array $children = array());
|
* new Document(array $children = array(), $defaults = true);
|
||||||
* new Document(string $name, array $children = array())
|
* new Document(string $name, array $children = array(), $defaults = true)
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
|
@ -47,14 +98,50 @@ abstract class Document extends Component {
|
||||||
|
|
||||||
$args = func_get_args();
|
$args = func_get_args();
|
||||||
if (count($args)===0 || is_array($args[0])) {
|
if (count($args)===0 || is_array($args[0])) {
|
||||||
array_unshift($args, static::$defaultName);
|
array_unshift($args, $this, static::$defaultName);
|
||||||
call_user_func_array(array('parent', '__construct'), $args);
|
call_user_func_array(array('parent', '__construct'), $args);
|
||||||
} else {
|
} else {
|
||||||
|
array_unshift($args, $this);
|
||||||
call_user_func_array(array('parent', '__construct'), $args);
|
call_user_func_array(array('parent', '__construct'), $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current document type.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function getDocumentType() {
|
||||||
|
|
||||||
|
return self::UNKNOWN;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new component or property.
|
||||||
|
*
|
||||||
|
* If it's a known component, we will automatically call createComponent.
|
||||||
|
* otherwise, we'll assume it's a property and call createProperty instead.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param string $arg1,... Unlimited number of args
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function create($name) {
|
||||||
|
|
||||||
|
if (isset(static::$componentMap[strtoupper($name)])) {
|
||||||
|
|
||||||
|
return call_user_func_array(array($this,'createComponent'), func_get_args());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return call_user_func_array(array($this,'createProperty'), func_get_args());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new component
|
* Creates a new component
|
||||||
*
|
*
|
||||||
|
|
@ -65,23 +152,25 @@ abstract class Document extends Component {
|
||||||
* properties will automatically be created, or you can just pass a list of
|
* properties will automatically be created, or you can just pass a list of
|
||||||
* Component and Property object.
|
* Component and Property object.
|
||||||
*
|
*
|
||||||
|
* By default, a set of sensible values will be added to the component. For
|
||||||
|
* an iCalendar object, this may be something like CALSCALE:GREGORIAN. To
|
||||||
|
* ensure that this does not happen, set $defaults to false.
|
||||||
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param array $children
|
* @param array $children
|
||||||
|
* @param bool $defaults
|
||||||
* @return Component
|
* @return Component
|
||||||
*/
|
*/
|
||||||
public function createComponent($name, array $children = array()) {
|
public function createComponent($name, array $children = null, $defaults = true) {
|
||||||
|
|
||||||
$component = Component::create($name);
|
$name = strtoupper($name);
|
||||||
foreach($children as $k=>$v) {
|
$class = 'Sabre\\VObject\\Component';
|
||||||
|
|
||||||
if ($v instanceof Node) {
|
|
||||||
$component->add($v);
|
|
||||||
} else {
|
|
||||||
$component->add($k, $v);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (isset(static::$componentMap[$name])) {
|
||||||
|
$class=static::$componentMap[$name];
|
||||||
}
|
}
|
||||||
return $component;
|
if (is_null($children)) $children = array();
|
||||||
|
return new $class($this, $name, $children, $defaults);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,11 +187,74 @@ abstract class Document extends Component {
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
* @param array $parameters
|
* @param array $parameters
|
||||||
|
* @param string $valueType Force a specific valuetype, such as URI or TEXT
|
||||||
* @return Property
|
* @return Property
|
||||||
*/
|
*/
|
||||||
public function createProperty($name, $value = null, array $parameters = array()) {
|
public function createProperty($name, $value = null, array $parameters = null, $valueType = null) {
|
||||||
|
|
||||||
return Property::create($name, $value, $parameters);
|
// If there's a . in the name, it means it's prefixed by a groupname.
|
||||||
|
if (($i=strpos($name,'.'))!==false) {
|
||||||
|
$group = substr($name, 0, $i);
|
||||||
|
$name = strtoupper(substr($name, $i+1));
|
||||||
|
} else {
|
||||||
|
$name = strtoupper($name);
|
||||||
|
$group = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$class = null;
|
||||||
|
|
||||||
|
if ($valueType) {
|
||||||
|
// The valueType argument comes first to figure out the correct
|
||||||
|
// class.
|
||||||
|
$class = $this->getClassNameForPropertyValue($valueType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($class) && isset($parameters['VALUE'])) {
|
||||||
|
// If a VALUE parameter is supplied, we should use that.
|
||||||
|
$class = $this->getClassNameForPropertyValue($parameters['VALUE']);
|
||||||
|
}
|
||||||
|
if (is_null($class)) {
|
||||||
|
$class = $this->getClassNameForPropertyName($name);
|
||||||
|
}
|
||||||
|
if (is_null($parameters)) $parameters = array();
|
||||||
|
|
||||||
|
return new $class($this, $name, $value, $parameters, $group);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns a full class-name for a value parameter.
|
||||||
|
*
|
||||||
|
* For instance, DTSTART may have VALUE=DATE. In that case we will look in
|
||||||
|
* our valueMap table and return the appropriate class name.
|
||||||
|
*
|
||||||
|
* This method returns null if we don't have a specialized class.
|
||||||
|
*
|
||||||
|
* @param string $valueParam
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function getClassNameForPropertyValue($valueParam) {
|
||||||
|
|
||||||
|
$valueParam = strtoupper($valueParam);
|
||||||
|
if (isset(static::$valueMap[$valueParam])) {
|
||||||
|
return static::$valueMap[$valueParam];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the default class for a property name.
|
||||||
|
*
|
||||||
|
* @param string $propertyName
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getClassNameForPropertyName($propertyName) {
|
||||||
|
|
||||||
|
if (isset(static::$propertyMap[$propertyName])) {
|
||||||
|
return static::$propertyMap[$propertyName];
|
||||||
|
} else {
|
||||||
|
return 'Sabre\\VObject\\Property\\Unknown';
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown by parser when the end of the stream has been reached,
|
||||||
|
* before this was expected.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class EofException extends ParseException { }
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
namespace Sabre\VObject;
|
namespace Sabre\VObject;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\Component\VCalendar;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class helps with generating FREEBUSY reports based on existing sets of
|
* This class helps with generating FREEBUSY reports based on existing sets of
|
||||||
* objects.
|
* objects.
|
||||||
|
|
@ -204,7 +207,7 @@ class FreeBusyGenerator {
|
||||||
$duration = DateTimeParser::parseDuration((string)$component->DURATION);
|
$duration = DateTimeParser::parseDuration((string)$component->DURATION);
|
||||||
$endTime = clone $startTime;
|
$endTime = clone $startTime;
|
||||||
$endTime->add($duration);
|
$endTime->add($duration);
|
||||||
} elseif ($component->DTSTART->getDateType() === Property\DateTime::DATE) {
|
} elseif (!$component->DTSTART->hasTime()) {
|
||||||
$endTime = clone $startTime;
|
$endTime = clone $startTime;
|
||||||
$endTime->modify('+1 day');
|
$endTime->modify('+1 day');
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -277,27 +280,24 @@ class FreeBusyGenerator {
|
||||||
if ($this->baseObject) {
|
if ($this->baseObject) {
|
||||||
$calendar = $this->baseObject;
|
$calendar = $this->baseObject;
|
||||||
} else {
|
} else {
|
||||||
$calendar = Component::create('VCALENDAR');
|
$calendar = new VCalendar();
|
||||||
$calendar->version = '2.0';
|
|
||||||
$calendar->prodid = '-//Sabre//Sabre VObject ' . Version::VERSION . '//EN';
|
|
||||||
$calendar->calscale = 'GREGORIAN';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$vfreebusy = Component::create('VFREEBUSY');
|
$vfreebusy = $calendar->createComponent('VFREEBUSY');
|
||||||
$calendar->add($vfreebusy);
|
$calendar->add($vfreebusy);
|
||||||
|
|
||||||
if ($this->start) {
|
if ($this->start) {
|
||||||
$dtstart = Property::create('DTSTART');
|
$dtstart = $calendar->createProperty('DTSTART');
|
||||||
$dtstart->setDateTime($this->start,Property\DateTime::UTC);
|
$dtstart->setDateTime($this->start);
|
||||||
$vfreebusy->add($dtstart);
|
$vfreebusy->add($dtstart);
|
||||||
}
|
}
|
||||||
if ($this->end) {
|
if ($this->end) {
|
||||||
$dtend = Property::create('DTEND');
|
$dtend = $calendar->createProperty('DTEND');
|
||||||
$dtend->setDateTime($this->end,Property\DateTime::UTC);
|
$dtend->setDateTime($this->end);
|
||||||
$vfreebusy->add($dtend);
|
$vfreebusy->add($dtend);
|
||||||
}
|
}
|
||||||
$dtstamp = Property::create('DTSTAMP');
|
$dtstamp = $calendar->createProperty('DTSTAMP');
|
||||||
$dtstamp->setDateTime(new \DateTime('now'), Property\DateTime::UTC);
|
$dtstamp->setDateTime(new \DateTime('now', new \DateTimeZone('UTC')));
|
||||||
$vfreebusy->add($dtstamp);
|
$vfreebusy->add($dtstamp);
|
||||||
|
|
||||||
foreach($busyTimes as $busyTime) {
|
foreach($busyTimes as $busyTime) {
|
||||||
|
|
@ -305,7 +305,7 @@ class FreeBusyGenerator {
|
||||||
$busyTime[0]->setTimeZone(new \DateTimeZone('UTC'));
|
$busyTime[0]->setTimeZone(new \DateTimeZone('UTC'));
|
||||||
$busyTime[1]->setTimeZone(new \DateTimeZone('UTC'));
|
$busyTime[1]->setTimeZone(new \DateTimeZone('UTC'));
|
||||||
|
|
||||||
$prop = Property::create(
|
$prop = $calendar->createProperty(
|
||||||
'FREEBUSY',
|
'FREEBUSY',
|
||||||
$busyTime[0]->format('Ymd\\THis\\Z') . '/' . $busyTime[1]->format('Ymd\\THis\\Z')
|
$busyTime[0]->format('Ymd\\THis\\Z') . '/' . $busyTime[1]->format('Ymd\\THis\\Z')
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@
|
||||||
namespace Sabre\VObject;
|
namespace Sabre\VObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for all nodes
|
* A node is the root class for every element in an iCalendar of vCard object.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
*/
|
*/
|
||||||
|
|
@ -17,11 +17,11 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable {
|
||||||
const REPAIR = 1;
|
const REPAIR = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turns the object back into a serialized blob.
|
* Reference to the parent object, if this is not the top object.
|
||||||
*
|
*
|
||||||
* @return string
|
* @var Node
|
||||||
*/
|
*/
|
||||||
abstract function serialize();
|
public $parent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterator override
|
* Iterator override
|
||||||
|
|
@ -31,34 +31,26 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable {
|
||||||
protected $iterator = null;
|
protected $iterator = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A link to the parent node
|
* The root document
|
||||||
*
|
*
|
||||||
* @var Node
|
* @var Component
|
||||||
*/
|
*/
|
||||||
public $parent = null;
|
protected $root;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the node for correctness.
|
* Serializes the node into a mimedir format
|
||||||
*
|
*
|
||||||
* The following options are supported:
|
* @return string
|
||||||
* - Node::REPAIR - If something is broken, and automatic repair may
|
*/
|
||||||
* be attempted.
|
abstract function serialize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns an array, with the representation as it should be
|
||||||
|
* encoded in json. This is used to create jCard or jCal documents.
|
||||||
*
|
*
|
||||||
* An array is returned with warnings.
|
|
||||||
*
|
|
||||||
* Every item in the array has the following properties:
|
|
||||||
* * level - (number between 1 and 3 with severity information)
|
|
||||||
* * message - (human readable message)
|
|
||||||
* * node - (reference to the offending node)
|
|
||||||
*
|
|
||||||
* @param int $options
|
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function validate($options = 0) {
|
abstract function jsonSerialize();
|
||||||
|
|
||||||
return array();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* {{{ IteratorAggregator interface */
|
/* {{{ IteratorAggregator interface */
|
||||||
|
|
||||||
|
|
@ -90,6 +82,29 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the node for correctness.
|
||||||
|
*
|
||||||
|
* The following options are supported:
|
||||||
|
* - Node::REPAIR - If something is broken, and automatic repair may
|
||||||
|
* be attempted.
|
||||||
|
*
|
||||||
|
* An array is returned with warnings.
|
||||||
|
*
|
||||||
|
* Every item in the array has the following properties:
|
||||||
|
* * level - (number between 1 and 3 with severity information)
|
||||||
|
* * message - (human readable message)
|
||||||
|
* * node - (reference to the offending node)
|
||||||
|
*
|
||||||
|
* @param int $options
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function validate($options = 0) {
|
||||||
|
|
||||||
|
return array();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ Countable interface */
|
/* {{{ Countable interface */
|
||||||
|
|
@ -183,5 +198,4 @@ abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable {
|
||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
namespace Sabre\VObject;
|
namespace Sabre\VObject;
|
||||||
|
|
||||||
|
use
|
||||||
|
ArrayObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VObject Parameter
|
* VObject Parameter
|
||||||
*
|
*
|
||||||
|
|
@ -23,41 +26,240 @@ class Parameter extends Node {
|
||||||
*/
|
*/
|
||||||
public $name;
|
public $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vCard 2.1 allows parameters to be encoded without a name.
|
||||||
|
*
|
||||||
|
* We can deduce the parameter name based on it's value.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $noName = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameter value
|
* Parameter value
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
public $value;
|
protected $value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up the object
|
* Sets up the object.
|
||||||
|
*
|
||||||
|
* It's recommended to use the create:: factory method instead.
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*/
|
*/
|
||||||
public function __construct($name, $value = null) {
|
public function __construct(Document $root, $name, $value = null) {
|
||||||
|
|
||||||
if (!is_scalar($value) && !is_null($value)) {
|
|
||||||
throw new \InvalidArgumentException('The value argument must be a scalar value or null');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->name = strtoupper($name);
|
$this->name = strtoupper($name);
|
||||||
|
$this->root = $root;
|
||||||
|
if (is_null($name)) {
|
||||||
|
$this->noName = true;
|
||||||
|
$this->name = static::guessParameterNameByValue($value);
|
||||||
|
}
|
||||||
|
$this->setValue($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to guess property name by value, can be used for vCard 2.1 nameless parameters.
|
||||||
|
*
|
||||||
|
* Figuring out what the name should have been. Note that a ton of
|
||||||
|
* these are rather silly in 2013 and would probably rarely be
|
||||||
|
* used, but we like to be complete.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function guessParameterNameByValue($value) {
|
||||||
|
switch(strtoupper($value)) {
|
||||||
|
|
||||||
|
// Encodings
|
||||||
|
case '7-BIT' :
|
||||||
|
case 'QUOTED-PRINTABLE' :
|
||||||
|
case 'BASE64' :
|
||||||
|
$name = 'ENCODING';
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Common types
|
||||||
|
case 'WORK' :
|
||||||
|
case 'HOME' :
|
||||||
|
case 'PREF' :
|
||||||
|
|
||||||
|
// Delivery Label Type
|
||||||
|
case 'DOM' :
|
||||||
|
case 'INTL' :
|
||||||
|
case 'POSTAL' :
|
||||||
|
case 'PARCEL' :
|
||||||
|
|
||||||
|
// Telephone types
|
||||||
|
case 'VOICE' :
|
||||||
|
case 'FAX' :
|
||||||
|
case 'MSG' :
|
||||||
|
case 'CELL' :
|
||||||
|
case 'PAGER' :
|
||||||
|
case 'BBS' :
|
||||||
|
case 'MODEM' :
|
||||||
|
case 'CAR' :
|
||||||
|
case 'ISDN' :
|
||||||
|
case 'VIDEO' :
|
||||||
|
|
||||||
|
// EMAIL types (lol)
|
||||||
|
case 'AOL' :
|
||||||
|
case 'APPLELINK' :
|
||||||
|
case 'ATTMAIL' :
|
||||||
|
case 'CIS' :
|
||||||
|
case 'EWORLD' :
|
||||||
|
case 'INTERNET' :
|
||||||
|
case 'IBMMAIL' :
|
||||||
|
case 'MCIMAIL' :
|
||||||
|
case 'POWERSHARE' :
|
||||||
|
case 'PRODIGY' :
|
||||||
|
case 'TLX' :
|
||||||
|
case 'X400' :
|
||||||
|
|
||||||
|
// Photo / Logo format types
|
||||||
|
case 'GIF' :
|
||||||
|
case 'CGM' :
|
||||||
|
case 'WMF' :
|
||||||
|
case 'BMP' :
|
||||||
|
case 'DIB' :
|
||||||
|
case 'PICT' :
|
||||||
|
case 'TIFF' :
|
||||||
|
case 'PDF ':
|
||||||
|
case 'PS' :
|
||||||
|
case 'JPEG' :
|
||||||
|
case 'MPEG' :
|
||||||
|
case 'MPEG2' :
|
||||||
|
case 'AVI' :
|
||||||
|
case 'QTIME' :
|
||||||
|
|
||||||
|
// Sound Digital Audio Type
|
||||||
|
case 'WAVE' :
|
||||||
|
case 'PCM' :
|
||||||
|
case 'AIFF' :
|
||||||
|
|
||||||
|
// Key types
|
||||||
|
case 'X509' :
|
||||||
|
case 'PGP' :
|
||||||
|
$name = 'TYPE';
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Value types
|
||||||
|
case 'INLINE' :
|
||||||
|
case 'URL' :
|
||||||
|
case 'CONTENT-ID' :
|
||||||
|
case 'CID' :
|
||||||
|
$name = 'VALUE';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$name = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the current value.
|
||||||
|
*
|
||||||
|
* This may be either a single, or multiple strings in an array.
|
||||||
|
*
|
||||||
|
* @param string|array $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setValue($value) {
|
||||||
|
|
||||||
$this->value = $value;
|
$this->value = $value;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the parameter's internal value.
|
* Returns the current value
|
||||||
*
|
*
|
||||||
* @return string
|
* This method will always return a string, or null. If there were multiple
|
||||||
|
* values, it will automatically concatinate them (separated by comma).
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getValue() {
|
public function getValue() {
|
||||||
|
|
||||||
return $this->value;
|
if (is_array($this->value)) {
|
||||||
|
return implode(',' , $this->value);
|
||||||
|
} else {
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets multiple values for this parameter.
|
||||||
|
*
|
||||||
|
* @param array $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setParts(array $value) {
|
||||||
|
|
||||||
|
$this->value = $value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all values for this parameter.
|
||||||
|
*
|
||||||
|
* If there were no values, an empty array will be returned.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getParts() {
|
||||||
|
|
||||||
|
if (is_array($this->value)) {
|
||||||
|
return $this->value;
|
||||||
|
} elseif (is_null($this->value)) {
|
||||||
|
return array();
|
||||||
|
} else {
|
||||||
|
return array($this->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a value to this parameter
|
||||||
|
*
|
||||||
|
* If the argument is specified as an array, all items will be added to the
|
||||||
|
* parameter value list.
|
||||||
|
*
|
||||||
|
* @param string|array $part
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addValue($part) {
|
||||||
|
|
||||||
|
if (is_null($this->value)) {
|
||||||
|
$this->value = $part;
|
||||||
|
} else {
|
||||||
|
$this->value = array_merge((array)$this->value, (array)$part);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this parameter contains the specified value.
|
||||||
|
*
|
||||||
|
* This is a case-insensitive match. It makes sense to call this for for
|
||||||
|
* instance the TYPE parameter, to see if it contains a keyword such as
|
||||||
|
* 'WORK' or 'FAX'.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function has($value) {
|
||||||
|
|
||||||
|
return in_array(
|
||||||
|
strtolower($value),
|
||||||
|
array_map('strtolower', (array)$this->value)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turns the object back into a serialized blob.
|
* Turns the object back into a serialized blob.
|
||||||
|
|
@ -66,27 +268,50 @@ class Parameter extends Node {
|
||||||
*/
|
*/
|
||||||
public function serialize() {
|
public function serialize() {
|
||||||
|
|
||||||
if (is_null($this->value)) {
|
$value = $this->getParts();
|
||||||
|
|
||||||
|
if (count($value)===0) {
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
$src = array(
|
|
||||||
'\\',
|
|
||||||
"\n",
|
|
||||||
';',
|
|
||||||
',',
|
|
||||||
);
|
|
||||||
$out = array(
|
|
||||||
'\\\\',
|
|
||||||
'\n',
|
|
||||||
'\;',
|
|
||||||
'\,',
|
|
||||||
);
|
|
||||||
|
|
||||||
$value = str_replace($src, $out, $this->value);
|
if ($this->root->getDocumentType() === Document::VCARD21 && $this->noName) {
|
||||||
if (strpos($value,":")!==false) {
|
|
||||||
$value = '"' . $value . '"';
|
return implode(';', $value);
|
||||||
|
|
||||||
}
|
}
|
||||||
return $this->name . '=' . $value;
|
|
||||||
|
return $this->name . '=' . array_reduce($value, function($out, $item) {
|
||||||
|
|
||||||
|
if (!is_null($out)) $out.=',';
|
||||||
|
|
||||||
|
// If there's no special characters in the string, we'll use the simple
|
||||||
|
// format
|
||||||
|
if (!preg_match('#(?: [\n":;\^,] )#x', $item)) {
|
||||||
|
return $out.$item;
|
||||||
|
} else {
|
||||||
|
// Enclosing in double-quotes, and using RFC6868 for encoding any
|
||||||
|
// special characters
|
||||||
|
$out.='"' . strtr($item, array(
|
||||||
|
'^' => '^^',
|
||||||
|
"\n" => '^n',
|
||||||
|
'"' => '^\'',
|
||||||
|
)) . '"';
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns an array, with the representation as it should be
|
||||||
|
* encoded in json. This is used to create jCard or jCal documents.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function jsonSerialize() {
|
||||||
|
|
||||||
|
return $this->value;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,7 +322,21 @@ class Parameter extends Node {
|
||||||
*/
|
*/
|
||||||
public function __toString() {
|
public function __toString() {
|
||||||
|
|
||||||
return $this->value;
|
return $this->getValue();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the iterator for this object
|
||||||
|
*
|
||||||
|
* @return ElementList
|
||||||
|
*/
|
||||||
|
public function getIterator() {
|
||||||
|
|
||||||
|
if (!is_null($this->iterator))
|
||||||
|
return $this->iterator;
|
||||||
|
|
||||||
|
return $this->iterator = new ArrayObject((array)$this->value);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
188
rainloop/v/0.0.0/app/libraries/Sabre/VObject/Parser/Json.php
Normal file
188
rainloop/v/0.0.0/app/libraries/Sabre/VObject/Parser/Json.php
Normal file
|
|
@ -0,0 +1,188 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Parser;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\Component\VCalendar,
|
||||||
|
Sabre\VObject\Component\VCard,
|
||||||
|
Sabre\VObject\ParseException,
|
||||||
|
Sabre\VObject\EofException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Json Parser.
|
||||||
|
*
|
||||||
|
* This parser parses both the jCal and jCard formats.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class Json extends Parser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The input data
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $input;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Root component
|
||||||
|
*
|
||||||
|
* @var Document
|
||||||
|
*/
|
||||||
|
protected $root;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method starts the parsing process.
|
||||||
|
*
|
||||||
|
* If the input was not supplied during construction, it's possible to pass
|
||||||
|
* it here instead.
|
||||||
|
*
|
||||||
|
* If either input or options are not supplied, the defaults will be used.
|
||||||
|
*
|
||||||
|
* @param resource|string|array|null $input
|
||||||
|
* @param int|null $options
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function parse($input = null, $options = null) {
|
||||||
|
|
||||||
|
if (!is_null($input)) {
|
||||||
|
$this->setInput($input);
|
||||||
|
}
|
||||||
|
if (is_null($this->input)) {
|
||||||
|
throw new EofException('End of input stream, or no input supplied');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($options)) {
|
||||||
|
$this->options = $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch($this->input[0]) {
|
||||||
|
case 'vcalendar' :
|
||||||
|
$this->root = new VCalendar(array(), false);
|
||||||
|
break;
|
||||||
|
case 'vcard' :
|
||||||
|
$this->root = new VCard(array(), false);
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
throw new ParseException('The root component must either be a vcalendar, or a vcard');
|
||||||
|
|
||||||
|
}
|
||||||
|
foreach($this->input[1] as $prop) {
|
||||||
|
$this->root->add($this->parseProperty($prop));
|
||||||
|
}
|
||||||
|
if (isset($this->input[2])) foreach($this->input[2] as $comp) {
|
||||||
|
$this->root->add($this->parseComponent($comp));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resetting the input so we can throw an feof exception the next time.
|
||||||
|
$this->input = null;
|
||||||
|
|
||||||
|
return $this->root;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a component
|
||||||
|
*
|
||||||
|
* @param array $jComp
|
||||||
|
* @return \Sabre\VObject\Component
|
||||||
|
*/
|
||||||
|
public function parseComponent(array $jComp) {
|
||||||
|
|
||||||
|
// We can remove $self from PHP 5.4 onward.
|
||||||
|
$self = $this;
|
||||||
|
|
||||||
|
$properties = array_map(function($jProp) use ($self) {
|
||||||
|
return $self->parseProperty($jProp);
|
||||||
|
}, $jComp[1]);
|
||||||
|
|
||||||
|
if (isset($jComp[2])) {
|
||||||
|
|
||||||
|
$components = array_map(function($jComp) use ($self) {
|
||||||
|
return $self->parseComponent($jComp);
|
||||||
|
}, $jComp[2]);
|
||||||
|
|
||||||
|
} else $components = array();
|
||||||
|
|
||||||
|
return $this->root->createComponent(
|
||||||
|
$jComp[0],
|
||||||
|
array_merge( $properties, $components),
|
||||||
|
$defaults = false
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses properties.
|
||||||
|
*
|
||||||
|
* @param array $jProp
|
||||||
|
* @return \Sabre\VObject\Property
|
||||||
|
*/
|
||||||
|
public function parseProperty(array $jProp) {
|
||||||
|
|
||||||
|
list(
|
||||||
|
$propertyName,
|
||||||
|
$parameters,
|
||||||
|
$valueType
|
||||||
|
) = $jProp;
|
||||||
|
|
||||||
|
$propertyName = strtoupper($propertyName);
|
||||||
|
|
||||||
|
// This is the default class we would be using if we didn't know the
|
||||||
|
// value type. We're using this value later in this function.
|
||||||
|
$defaultPropertyClass = $this->root->getClassNameForPropertyName($propertyName);
|
||||||
|
|
||||||
|
$parameters = (array)$parameters;
|
||||||
|
|
||||||
|
$value = array_slice($jProp, 3);
|
||||||
|
|
||||||
|
$valueType = strtoupper($valueType);
|
||||||
|
|
||||||
|
if (isset($parameters['group'])) {
|
||||||
|
$propertyName = $parameters['group'] . '.' . $propertyName;
|
||||||
|
unset($parameters['group']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$prop = $this->root->createProperty($propertyName, null, $parameters, $valueType);
|
||||||
|
$prop->setJsonValue($value);
|
||||||
|
|
||||||
|
// We have to do something awkward here. FlatText as well as Text
|
||||||
|
// represents TEXT values. We have to normalize these here. In the
|
||||||
|
// future we can get rid of FlatText once we're allowed to break BC
|
||||||
|
// again.
|
||||||
|
if ($defaultPropertyClass === 'Sabre\VObject\Property\FlatText') {
|
||||||
|
$defaultPropertyClass = 'Sabre\VObject\Property\Text';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the value type we received (e.g.: TEXT) was not the default value
|
||||||
|
// type for the given property (e.g.: BDAY), we need to add a VALUE=
|
||||||
|
// parameter.
|
||||||
|
if ($defaultPropertyClass !== get_class($prop)) {
|
||||||
|
$prop["VALUE"] = $valueType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $prop;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the input data
|
||||||
|
*
|
||||||
|
* @param resource|string|array $input
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setInput($input) {
|
||||||
|
|
||||||
|
if (is_resource($input)) {
|
||||||
|
$input = stream_get_contents($input);
|
||||||
|
}
|
||||||
|
if (is_string($input)) {
|
||||||
|
$input = json_decode($input);
|
||||||
|
}
|
||||||
|
$this->input = $input;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
602
rainloop/v/0.0.0/app/libraries/Sabre/VObject/Parser/MimeDir.php
Normal file
602
rainloop/v/0.0.0/app/libraries/Sabre/VObject/Parser/MimeDir.php
Normal file
|
|
@ -0,0 +1,602 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Parser;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\ParseException,
|
||||||
|
Sabre\VObject\EofException,
|
||||||
|
Sabre\VObject\Component,
|
||||||
|
Sabre\VObject\Property,
|
||||||
|
Sabre\VObject\Component\VCalendar,
|
||||||
|
Sabre\VObject\Component\VCard;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MimeDir parser.
|
||||||
|
*
|
||||||
|
* This class parses iCalendar/vCard files and returns an array.
|
||||||
|
*
|
||||||
|
* The array is identical to the format jCard/jCal use.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class MimeDir extends Parser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The input stream.
|
||||||
|
*
|
||||||
|
* @var resource
|
||||||
|
*/
|
||||||
|
protected $input;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Root component
|
||||||
|
*
|
||||||
|
* @var Component
|
||||||
|
*/
|
||||||
|
protected $root;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses an iCalendar or vCard file
|
||||||
|
*
|
||||||
|
* Pass a stream or a string. If null is parsed, the existing buffer is
|
||||||
|
* used.
|
||||||
|
*
|
||||||
|
* @param string|resource|null $input
|
||||||
|
* @param int|null $options
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function parse($input = null, $options = null) {
|
||||||
|
|
||||||
|
$this->root = null;
|
||||||
|
if (!is_null($input)) {
|
||||||
|
|
||||||
|
$this->setInput($input);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($options)) $this->options = $options;
|
||||||
|
|
||||||
|
$this->parseDocument();
|
||||||
|
|
||||||
|
return $this->root;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the input buffer. Must be a string or stream.
|
||||||
|
*
|
||||||
|
* @param resource|string $input
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setInput($input) {
|
||||||
|
|
||||||
|
// Resetting the parser
|
||||||
|
$this->lineIndex = 0;
|
||||||
|
$this->startLine = 0;
|
||||||
|
|
||||||
|
if (is_string($input)) {
|
||||||
|
// Convering to a stream.
|
||||||
|
$stream = fopen('php://temp', 'r+');
|
||||||
|
fwrite($stream, $input);
|
||||||
|
rewind($stream);
|
||||||
|
$this->input = $stream;
|
||||||
|
} else {
|
||||||
|
$this->input = $input;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses an entire document.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function parseDocument() {
|
||||||
|
|
||||||
|
$line = $this->readLine();
|
||||||
|
switch(strtoupper($line)) {
|
||||||
|
case 'BEGIN:VCALENDAR' :
|
||||||
|
$class = isset(VCalendar::$componentMap['VCALENDAR'])
|
||||||
|
? VCalendar::$componentMap[$name]
|
||||||
|
: 'Sabre\\VObject\\Component\\VCalendar';
|
||||||
|
break;
|
||||||
|
case 'BEGIN:VCARD' :
|
||||||
|
$class = isset(VCard::$componentMap['VCARD'])
|
||||||
|
? VCard::$componentMap['VCARD']
|
||||||
|
: 'Sabre\\VObject\\Component\\VCard';
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
throw new ParseException('This parser only supports VCARD and VCALENDAR files');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->root = new $class(array(), false);
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
|
||||||
|
// Reading until we hit END:
|
||||||
|
$line = $this->readLine();
|
||||||
|
if (strtoupper(substr($line,0,4)) === 'END:') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$result = $this->parseLine($line);
|
||||||
|
if ($result) {
|
||||||
|
$this->root->add($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = strtoupper(substr($line, 4));
|
||||||
|
if ($name!==$this->root->name) {
|
||||||
|
throw new ParseException('Invalid MimeDir file. expected: "END:' . $this->root->name . '" got: "END:' . $name . '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a line, and if it hits a component, it will also attempt to parse
|
||||||
|
* the entire component
|
||||||
|
*
|
||||||
|
* @param string $line Unfolded line
|
||||||
|
* @return Node
|
||||||
|
*/
|
||||||
|
protected function parseLine($line) {
|
||||||
|
|
||||||
|
// Start of a new component
|
||||||
|
if (strtoupper(substr($line, 0, 6)) === 'BEGIN:') {
|
||||||
|
|
||||||
|
$component = $this->root->createComponent(substr($line,6), array(), false);
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
|
||||||
|
// Reading until we hit END:
|
||||||
|
$line = $this->readLine();
|
||||||
|
if (strtoupper(substr($line,0,4)) === 'END:') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$result = $this->parseLine($line);
|
||||||
|
if ($result) {
|
||||||
|
$component->add($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = strtoupper(substr($line, 4));
|
||||||
|
if ($name!==$component->name) {
|
||||||
|
throw new ParseException('Invalid MimeDir file. expected: "END:' . $component->name . '" got: "END:' . $name . '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $component;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Property reader
|
||||||
|
$property = $this->readProperty($line);
|
||||||
|
if (!$property) {
|
||||||
|
// Ignored line
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $property;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We need to look ahead 1 line every time to see if we need to 'unfold'
|
||||||
|
* the next line.
|
||||||
|
*
|
||||||
|
* If that was not the case, we store it here.
|
||||||
|
*
|
||||||
|
* @var null|string
|
||||||
|
*/
|
||||||
|
protected $lineBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The real current line number.
|
||||||
|
*/
|
||||||
|
protected $lineIndex = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In the case of unfolded lines, this property holds the line number for
|
||||||
|
* the start of the line.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $startLine = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains a 'raw' representation of the current line.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $rawLine;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a single line from the buffer.
|
||||||
|
*
|
||||||
|
* This method strips any newlines and also takes care of unfolding.
|
||||||
|
*
|
||||||
|
* @throws \Sabre\VObject\EofException
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function readLine() {
|
||||||
|
|
||||||
|
if (!is_null($this->lineBuffer)) {
|
||||||
|
$rawLine = $this->lineBuffer;
|
||||||
|
$this->lineBuffer = null;
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
$rawLine = fgets($this->input);
|
||||||
|
if ($rawLine === false && feof($this->input)) {
|
||||||
|
throw new EofException('End of document reached prematurely');
|
||||||
|
}
|
||||||
|
$rawLine = rtrim($rawLine, "\r\n");
|
||||||
|
} while ($rawLine === ''); // Skipping empty lines
|
||||||
|
$this->lineIndex++;
|
||||||
|
}
|
||||||
|
$line = $rawLine;
|
||||||
|
|
||||||
|
$this->startLine = $this->lineIndex;
|
||||||
|
|
||||||
|
// Looking ahead for folded lines.
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
$nextLine = rtrim(fgets($this->input), "\r\n");
|
||||||
|
$this->lineIndex++;
|
||||||
|
if (!$nextLine) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ($nextLine[0] === "\t" || $nextLine[0] === " ") {
|
||||||
|
$line .= substr($nextLine, 1);
|
||||||
|
$rawLine .= "\n " . substr($nextLine, 1);
|
||||||
|
} else {
|
||||||
|
$this->lineBuffer = $nextLine;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
$this->rawLine = $rawLine;
|
||||||
|
return $line;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a property or component from a line.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function readProperty($line) {
|
||||||
|
|
||||||
|
if ($this->options & self::OPTION_FORGIVING) {
|
||||||
|
$propNameToken = 'A-Z0-9\-\._\\/';
|
||||||
|
} else {
|
||||||
|
$propNameToken = 'A-Z0-9\-\.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$paramNameToken = 'A-Z0-9\-';
|
||||||
|
$safeChar = '^";:,';
|
||||||
|
$qSafeChar = '^"';
|
||||||
|
|
||||||
|
$regex = "/
|
||||||
|
^(?P<name> [$propNameToken]+ ) (?=[;:]) # property name
|
||||||
|
|
|
||||||
|
(?<=:)(?P<propValue> .*)$ # property value
|
||||||
|
|
|
||||||
|
;(?P<paramName> [$paramNameToken]+) (?=[=;:]) # parameter name
|
||||||
|
|
|
||||||
|
(=|,)(?P<paramValue> # parameter value
|
||||||
|
(?: [$safeChar]*) |
|
||||||
|
\"(?: [$qSafeChar]+)\"
|
||||||
|
) (?=[;:,])
|
||||||
|
/xi";
|
||||||
|
|
||||||
|
//echo $regex, "\n"; die();
|
||||||
|
preg_match_all($regex, $line, $matches, PREG_SET_ORDER );
|
||||||
|
|
||||||
|
$property = array(
|
||||||
|
'name' => null,
|
||||||
|
'parameters' => array(),
|
||||||
|
'value' => null
|
||||||
|
);
|
||||||
|
|
||||||
|
$lastParam = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looping through all the tokens.
|
||||||
|
*
|
||||||
|
* Note that we are looping through them in reverse order, because if a
|
||||||
|
* sub-pattern matched, the subsequent named patterns will not show up
|
||||||
|
* in the result.
|
||||||
|
*/
|
||||||
|
foreach($matches as $match) {
|
||||||
|
|
||||||
|
if (isset($match['paramValue'])) {
|
||||||
|
if ($match['paramValue'] && $match['paramValue'][0] === '"') {
|
||||||
|
$value = substr($match['paramValue'], 1, -1);
|
||||||
|
} else {
|
||||||
|
$value = $match['paramValue'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $this->unescapeParam($value);
|
||||||
|
|
||||||
|
if (is_null($property['parameters'][$lastParam])) {
|
||||||
|
$property['parameters'][$lastParam] = $value;
|
||||||
|
} elseif (is_array($property['parameters'][$lastParam])) {
|
||||||
|
$property['parameters'][$lastParam][] = $value;
|
||||||
|
} else {
|
||||||
|
$property['parameters'][$lastParam] = array(
|
||||||
|
$property['parameters'][$lastParam],
|
||||||
|
$value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isset($match['paramName'])) {
|
||||||
|
$lastParam = strtoupper($match['paramName']);
|
||||||
|
if (!isset($property['parameters'][$lastParam])) {
|
||||||
|
$property['parameters'][$lastParam] = null;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isset($match['propValue'])) {
|
||||||
|
$property['value'] = $match['propValue'];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isset($match['name']) && $match['name']) {
|
||||||
|
$property['name'] = strtoupper($match['name']);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
throw new \LogicException('This code should not be reachable');
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($property['value']) || !$property['name']) {
|
||||||
|
if ($this->options & self::OPTION_IGNORE_INVALID_LINES) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
throw new ParseException('Invalid Mimedir file. Line starting at ' . $this->startLine . ' did not follow iCalendar/vCard conventions');
|
||||||
|
}
|
||||||
|
|
||||||
|
// vCard 2.1 states that parameters may appear without a name, and only
|
||||||
|
// a value. We can deduce the value based on it's name.
|
||||||
|
//
|
||||||
|
// Our parser will get those as parameters without a value instead, so
|
||||||
|
// we're filtering these parameters out first.
|
||||||
|
$namedParameters = array();
|
||||||
|
$namelessParameters = array();
|
||||||
|
|
||||||
|
foreach($property['parameters'] as $name=>$value) {
|
||||||
|
if (!is_null($value)) {
|
||||||
|
$namedParameters[$name] = $value;
|
||||||
|
} else {
|
||||||
|
$namelessParameters[] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$propObj = $this->root->createProperty($property['name'], null, $namedParameters);
|
||||||
|
|
||||||
|
foreach($namelessParameters as $namelessParameter) {
|
||||||
|
$propObj->add(null, $namelessParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strtoupper($propObj['ENCODING']) === 'QUOTED-PRINTABLE') {
|
||||||
|
$propObj->setQuotedPrintableValue($this->extractQuotedPrintableValue());
|
||||||
|
} else {
|
||||||
|
$propObj->setRawMimeDirValue($property['value']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $propObj;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unescapes a property value.
|
||||||
|
*
|
||||||
|
* vCard 2.1 says:
|
||||||
|
* * Semi-colons must be escaped in some property values, specifically
|
||||||
|
* ADR, ORG and N.
|
||||||
|
* * Semi-colons must be escaped in parameter values, because semi-colons
|
||||||
|
* are also use to separate values.
|
||||||
|
* * No mention of escaping backslashes with another backslash.
|
||||||
|
* * newlines are not escaped either, instead QUOTED-PRINTABLE is used to
|
||||||
|
* span values over more than 1 line.
|
||||||
|
*
|
||||||
|
* vCard 3.0 says:
|
||||||
|
* * (rfc2425) Backslashes, newlines (\n or \N) and comma's must be
|
||||||
|
* escaped, all time time.
|
||||||
|
* * Comma's are used for delimeters in multiple values
|
||||||
|
* * (rfc2426) Adds to to this that the semi-colon MUST also be escaped,
|
||||||
|
* as in some properties semi-colon is used for separators.
|
||||||
|
* * Properties using semi-colons: N, ADR, GEO, ORG
|
||||||
|
* * Both ADR and N's individual parts may be broken up further with a
|
||||||
|
* comma.
|
||||||
|
* * Properties using commas: NICKNAME, CATEGORIES
|
||||||
|
*
|
||||||
|
* vCard 4.0 (rfc6350) says:
|
||||||
|
* * Commas must be escaped.
|
||||||
|
* * Semi-colons may be escaped, an unescaped semi-colon _may_ be a
|
||||||
|
* delimiter, depending on the property.
|
||||||
|
* * Backslashes must be escaped
|
||||||
|
* * Newlines must be escaped as either \N or \n.
|
||||||
|
* * Some compound properties may contain multiple parts themselves, so a
|
||||||
|
* comma within a semi-colon delimited property may also be unescaped
|
||||||
|
* to denote multiple parts _within_ the compound property.
|
||||||
|
* * Text-properties using semi-colons: N, ADR, ORG, CLIENTPIDMAP.
|
||||||
|
* * Text-properties using commas: NICKNAME, RELATED, CATEGORIES, PID.
|
||||||
|
*
|
||||||
|
* Even though the spec says that commas must always be escaped, the
|
||||||
|
* example for GEO in Section 6.5.2 seems to violate this.
|
||||||
|
*
|
||||||
|
* iCalendar 2.0 (rfc5545) says:
|
||||||
|
* * Commas or semi-colons may be used as delimiters, depending on the
|
||||||
|
* property.
|
||||||
|
* * Commas, semi-colons, backslashes, newline (\N or \n) are always
|
||||||
|
* escaped, unless they are delimiters.
|
||||||
|
* * Colons shall not be escaped.
|
||||||
|
* * Commas can be considered the 'default delimiter' and is described as
|
||||||
|
* the delimiter in cases where the order of the multiple values is
|
||||||
|
* insignificant.
|
||||||
|
* * Semi-colons are described as the delimiter for 'structured values'.
|
||||||
|
* They are specifically used in Semi-colons are used as a delimiter in
|
||||||
|
* REQUEST-STATUS, RRULE, GEO and EXRULE. EXRULE is deprecated however.
|
||||||
|
*
|
||||||
|
* Now for the parameters
|
||||||
|
*
|
||||||
|
* If delimiter is not set (null) this method will just return a string.
|
||||||
|
* If it's a comma or a semi-colon the string will be split on those
|
||||||
|
* characters, and always return an array.
|
||||||
|
*
|
||||||
|
* @param string $input
|
||||||
|
* @param string $delimiter
|
||||||
|
* @return string|string[]
|
||||||
|
*/
|
||||||
|
static public function unescapeValue($input, $delimiter = ';') {
|
||||||
|
|
||||||
|
$regex = '# (?: (\\\\ (?: \\\\ | N | n | ; | , ) )';
|
||||||
|
if ($delimiter) {
|
||||||
|
$regex .= ' | (' . $delimiter . ')';
|
||||||
|
}
|
||||||
|
$regex .= ') #x';
|
||||||
|
|
||||||
|
$matches = preg_split($regex, $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
|
||||||
|
|
||||||
|
$resultArray = array();
|
||||||
|
$result = '';
|
||||||
|
|
||||||
|
foreach($matches as $match) {
|
||||||
|
|
||||||
|
switch ($match) {
|
||||||
|
case '\\\\' :
|
||||||
|
$result .='\\';
|
||||||
|
break;
|
||||||
|
case '\N' :
|
||||||
|
case '\n' :
|
||||||
|
$result .="\n";
|
||||||
|
break;
|
||||||
|
case '\;' :
|
||||||
|
$result .=';';
|
||||||
|
break;
|
||||||
|
case '\,' :
|
||||||
|
$result .=',';
|
||||||
|
break;
|
||||||
|
case $delimiter :
|
||||||
|
$resultArray[] = $result;
|
||||||
|
$result = '';
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
$result .= $match;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$resultArray[] = $result;
|
||||||
|
return $delimiter ? $resultArray : $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unescapes a parameter value.
|
||||||
|
*
|
||||||
|
* vCard 2.1:
|
||||||
|
* * Does not mention a mechanism for this. In addition, double quotes
|
||||||
|
* are never used to wrap values.
|
||||||
|
* * This means that parameters can simply not contain colons or
|
||||||
|
* semi-colons.
|
||||||
|
*
|
||||||
|
* vCard 3.0 (rfc2425, rfc2426):
|
||||||
|
* * Parameters _may_ be surrounded by double quotes.
|
||||||
|
* * If this is not the case, semi-colon, colon and comma may simply not
|
||||||
|
* occur (the comma used for multiple parameter values though).
|
||||||
|
* * If it is surrounded by double-quotes, it may simply not contain
|
||||||
|
* double-quotes.
|
||||||
|
* * This means that a parameter can in no case encode double-quotes, or
|
||||||
|
* newlines.
|
||||||
|
*
|
||||||
|
* vCard 4.0 (rfc6350)
|
||||||
|
* * Behavior seems to be identical to vCard 3.0
|
||||||
|
*
|
||||||
|
* iCalendar 2.0 (rfc5545)
|
||||||
|
* * Behavior seems to be identical to vCard 3.0
|
||||||
|
*
|
||||||
|
* Parameter escaping mechanism (rfc6868) :
|
||||||
|
* * This rfc describes a new way to escape parameter values.
|
||||||
|
* * New-line is encoded as ^n
|
||||||
|
* * ^ is encoded as ^^.
|
||||||
|
* * " is encoded as ^'
|
||||||
|
*
|
||||||
|
* @param string $input
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function unescapeParam($input) {
|
||||||
|
|
||||||
|
return
|
||||||
|
preg_replace_callback('#(\^(\^|n|\'))#',function($matches) {
|
||||||
|
switch($matches[2]) {
|
||||||
|
case 'n' :
|
||||||
|
return "\n";
|
||||||
|
case '^' :
|
||||||
|
return '^';
|
||||||
|
case '\'' :
|
||||||
|
return '"';
|
||||||
|
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
}
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
}, $input);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the full quoted printable value.
|
||||||
|
*
|
||||||
|
* We need a special method for this, because newlines have both a meaning
|
||||||
|
* in vCards, and in QuotedPrintable.
|
||||||
|
*
|
||||||
|
* This method does not do any decoding.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function extractQuotedPrintableValue() {
|
||||||
|
|
||||||
|
// We need to parse the raw line again to get the start of the value.
|
||||||
|
//
|
||||||
|
// We are basically looking for the first colon (:), but we need to
|
||||||
|
// skip over the parameters first, as they may contain one.
|
||||||
|
$regex = '/^
|
||||||
|
(?: [^:])+ # Anything but a colon
|
||||||
|
(?: "[^"]")* # A parameter in double quotes
|
||||||
|
: # start of the value we really care about
|
||||||
|
(.*)$
|
||||||
|
/xs';
|
||||||
|
|
||||||
|
preg_match($regex, $this->rawLine, $matches);
|
||||||
|
|
||||||
|
$value = $matches[1];
|
||||||
|
// Removing the first whitespace character from every line. Kind of
|
||||||
|
// like unfolding, but we keep the newline.
|
||||||
|
$value = str_replace("\n ", "\n", $value);
|
||||||
|
|
||||||
|
// Microsoft products don't always correctly fold lines, they may be
|
||||||
|
// missing a whitespace. So if 'forgiving' is turned on, we will take
|
||||||
|
// those as well.
|
||||||
|
if ($this->options & self::OPTION_FORGIVING) {
|
||||||
|
while(substr($value,-1) === '=') {
|
||||||
|
// Reading the line
|
||||||
|
$this->readLine();
|
||||||
|
// Grabbing the raw form
|
||||||
|
$value.="\n" . $this->rawLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Parser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract parser.
|
||||||
|
*
|
||||||
|
* This class serves as a base-class for the different parsers.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
abstract class Parser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turning on this option makes the parser more forgiving.
|
||||||
|
*
|
||||||
|
* In the case of the MimeDir parser, this means that the parser will
|
||||||
|
* accept slashes and underscores in property names, and it will also
|
||||||
|
* attempt to fix Microsoft vCard 2.1's broken line folding.
|
||||||
|
*/
|
||||||
|
const OPTION_FORGIVING = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this option is turned on, any lines we cannot parse will be ignored
|
||||||
|
* by the reader.
|
||||||
|
*/
|
||||||
|
const OPTION_IGNORE_INVALID_LINES = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bitmask of parser options
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $options;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the parser.
|
||||||
|
*
|
||||||
|
* Optionally, it's possible to parse the input stream here.
|
||||||
|
*
|
||||||
|
* @param mixed $input
|
||||||
|
* @param int $options Any parser options (OPTION constants).
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($input = null, $options = 0) {
|
||||||
|
|
||||||
|
if (!is_null($input)) {
|
||||||
|
$this->setInput($input);
|
||||||
|
}
|
||||||
|
$this->options = $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method starts the parsing process.
|
||||||
|
*
|
||||||
|
* If the input was not supplied during construction, it's possible to pass
|
||||||
|
* it here instead.
|
||||||
|
*
|
||||||
|
* If either input or options are not supplied, the defaults will be used.
|
||||||
|
*
|
||||||
|
* @param mixed $input
|
||||||
|
* @param int|null $options
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
abstract public function parse($input = null, $options = null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the input data
|
||||||
|
*
|
||||||
|
* @param mixed $input
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
abstract public function setInput($input);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -3,152 +3,92 @@
|
||||||
namespace Sabre\VObject;
|
namespace Sabre\VObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VObject Property
|
* Property
|
||||||
*
|
*
|
||||||
* A property in VObject is usually in the form PARAMNAME:paramValue.
|
* A property is always in a KEY:VALUE structure, and may optionally contain
|
||||||
* An example is : SUMMARY:Weekly meeting
|
* parameters.
|
||||||
*
|
*
|
||||||
* Properties can also have parameters:
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
* SUMMARY;LANG=en:Weekly meeting.
|
|
||||||
*
|
|
||||||
* Parameters can be accessed using the ArrayAccess interface.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
|
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
*/
|
*/
|
||||||
class Property extends Node {
|
abstract class Property extends Node {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Propertyname
|
* Property name.
|
||||||
|
*
|
||||||
|
* This will contain a string such as DTSTART, SUMMARY, FN.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
public $name;
|
public $name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Group name
|
* Property group.
|
||||||
*
|
*
|
||||||
* This may be something like 'HOME' for vcards.
|
* This is only used in vcards
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
public $group;
|
public $group;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property parameters
|
* List of parameters
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public $parameters = array();
|
public $parameters = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property value
|
* Current value
|
||||||
*
|
*
|
||||||
* @var string
|
* @var mixed
|
||||||
*/
|
*/
|
||||||
public $value;
|
protected $value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If properties are added to this map, they will be automatically mapped
|
* In case this is a multi-value property. This string will be used as a
|
||||||
* to their respective classes, if parsed by the reader or constructed with
|
* delimiter.
|
||||||
* the 'create' method.
|
|
||||||
*
|
*
|
||||||
* @var array
|
* @var string|null
|
||||||
*/
|
*/
|
||||||
static public $classMap = array(
|
public $delimiter = ';';
|
||||||
'COMPLETED' => 'Sabre\\VObject\\Property\\DateTime',
|
|
||||||
'CREATED' => 'Sabre\\VObject\\Property\\DateTime',
|
|
||||||
'DTEND' => 'Sabre\\VObject\\Property\\DateTime',
|
|
||||||
'DTSTAMP' => 'Sabre\\VObject\\Property\\DateTime',
|
|
||||||
'DTSTART' => 'Sabre\\VObject\\Property\\DateTime',
|
|
||||||
'DUE' => 'Sabre\\VObject\\Property\\DateTime',
|
|
||||||
'EXDATE' => 'Sabre\\VObject\\Property\\MultiDateTime',
|
|
||||||
'LAST-MODIFIED' => 'Sabre\\VObject\\Property\\DateTime',
|
|
||||||
'RECURRENCE-ID' => 'Sabre\\VObject\\Property\\DateTime',
|
|
||||||
'TRIGGER' => 'Sabre\\VObject\\Property\\DateTime',
|
|
||||||
'N' => 'Sabre\\VObject\\Property\\Compound',
|
|
||||||
'ORG' => 'Sabre\\VObject\\Property\\Compound',
|
|
||||||
'ADR' => 'Sabre\\VObject\\Property\\Compound',
|
|
||||||
'CATEGORIES' => 'Sabre\\VObject\\Property\\Compound',
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the new property by name, but in addition will also see if
|
* Creates the generic property.
|
||||||
* there's a class mapped to the property name.
|
|
||||||
*
|
*
|
||||||
* Parameters can be specified with the optional third argument. Parameters
|
* Parameters must be specified in key=>value syntax.
|
||||||
* must be a key->value map of the parameter name, and value. If the value
|
|
||||||
* is specified as an array, it is assumed that multiple parameters with
|
|
||||||
* the same name should be added.
|
|
||||||
*
|
*
|
||||||
|
* @param Component $root The root document
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param string $value
|
* @param string|array|null $value
|
||||||
* @param array $parameters
|
* @param array $parameters List of parameters
|
||||||
* @return Property
|
* @param string $group The vcard property group
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
static public function create($name, $value = null, array $parameters = array()) {
|
public function __construct(Component $root, $name, $value = null, array $parameters = array(), $group = null) {
|
||||||
|
|
||||||
$name = strtoupper($name);
|
|
||||||
$shortName = $name;
|
|
||||||
$group = null;
|
|
||||||
if (strpos($shortName,'.')!==false) {
|
|
||||||
list($group, $shortName) = explode('.', $shortName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset(self::$classMap[$shortName])) {
|
|
||||||
return new self::$classMap[$shortName]($name, $value, $parameters);
|
|
||||||
} else {
|
|
||||||
return new self($name, $value, $parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new property object
|
|
||||||
*
|
|
||||||
* Parameters can be specified with the optional third argument. Parameters
|
|
||||||
* must be a key->value map of the parameter name, and value. If the value
|
|
||||||
* is specified as an array, it is assumed that multiple parameters with
|
|
||||||
* the same name should be added.
|
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
* @param string $value
|
|
||||||
* @param array $parameters
|
|
||||||
*/
|
|
||||||
public function __construct($name, $value = null, array $parameters = array()) {
|
|
||||||
|
|
||||||
if (!is_scalar($value) && !is_null($value)) {
|
|
||||||
throw new \InvalidArgumentException('The value argument must be scalar or null');
|
|
||||||
}
|
|
||||||
|
|
||||||
$name = strtoupper($name);
|
|
||||||
$group = null;
|
|
||||||
if (strpos($name,'.')!==false) {
|
|
||||||
list($group, $name) = explode('.', $name);
|
|
||||||
}
|
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
$this->group = $group;
|
$this->group = $group;
|
||||||
$this->setValue($value);
|
|
||||||
|
|
||||||
foreach($parameters as $paramName => $paramValues) {
|
$this->root = $root;
|
||||||
|
|
||||||
if (!is_array($paramValues)) {
|
if (!is_null($value)) {
|
||||||
$paramValues = array($paramValues);
|
$this->setValue($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($paramValues as $paramValue) {
|
|
||||||
$this->add($paramName, $paramValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
foreach($parameters as $k=>$v) {
|
||||||
|
$this->add($k, $v);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the internal value
|
* Updates the current value.
|
||||||
*
|
*
|
||||||
* @param string $value
|
* This may be either a single, or multiple strings in an array.
|
||||||
|
*
|
||||||
|
* @param string|array $value
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setValue($value) {
|
public function setValue($value) {
|
||||||
|
|
@ -158,17 +98,131 @@ class Property extends Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the internal value
|
* Returns the current value.
|
||||||
|
*
|
||||||
|
* This method will always return a singular value. If this was a
|
||||||
|
* multi-value object, some decision will be made first on how to represent
|
||||||
|
* it as a string.
|
||||||
|
*
|
||||||
|
* To get the correct multi-value version, use getParts.
|
||||||
*
|
*
|
||||||
* @param string $value
|
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getValue() {
|
public function getValue() {
|
||||||
|
|
||||||
return $this->value;
|
if (is_array($this->value)) {
|
||||||
|
if (count($this->value)==0) {
|
||||||
|
return null;
|
||||||
|
} elseif (count($this->value)===1) {
|
||||||
|
return $this->value[0];
|
||||||
|
} else {
|
||||||
|
return $this->getRawMimeDirValue($this->value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a multi-valued property.
|
||||||
|
*
|
||||||
|
* @param array $parts
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setParts(array $parts) {
|
||||||
|
|
||||||
|
$this->value = $parts;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a multi-valued property.
|
||||||
|
*
|
||||||
|
* This method always returns an array, if there was only a single value,
|
||||||
|
* it will still be wrapped in an array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getParts() {
|
||||||
|
|
||||||
|
if (is_null($this->value)) {
|
||||||
|
return array();
|
||||||
|
} elseif (is_array($this->value)) {
|
||||||
|
return $this->value;
|
||||||
|
} else {
|
||||||
|
return array($this->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new parameter, and returns the new item.
|
||||||
|
*
|
||||||
|
* If a parameter with same name already existed, the values will be
|
||||||
|
* combined.
|
||||||
|
* If nameless parameter is added, we try to guess it's name.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param string|null|array $value
|
||||||
|
* @return Node
|
||||||
|
*/
|
||||||
|
public function add($name, $value = null) {
|
||||||
|
$noName = false;
|
||||||
|
if ($name === null) {
|
||||||
|
$name = Parameter::guessParameterNameByValue($value);
|
||||||
|
$noName = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->parameters[strtoupper($name)])) {
|
||||||
|
$this->parameters[strtoupper($name)]->addValue($value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$param = new Parameter($this->root, $name, $value);
|
||||||
|
$param->noName = $noName;
|
||||||
|
$this->parameters[$param->name] = $param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable list of children
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function parameters() {
|
||||||
|
|
||||||
|
return $this->parameters;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
abstract public function getValueType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a raw value coming from a mimedir (iCalendar/vCard) file.
|
||||||
|
*
|
||||||
|
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||||
|
* not yet done, but parameters are not included.
|
||||||
|
*
|
||||||
|
* @param string $val
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
abstract public function setRawMimeDirValue($val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a raw mime-dir representation of the value.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
abstract public function getRawMimeDirValue();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turns the object back into a serialized blob.
|
* Turns the object back into a serialized blob.
|
||||||
*
|
*
|
||||||
|
|
@ -185,17 +239,7 @@ class Property extends Node {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$src = array(
|
$str.=':' . $this->getRawMimeDirValue();
|
||||||
'\\',
|
|
||||||
"\n",
|
|
||||||
"\r",
|
|
||||||
);
|
|
||||||
$out = array(
|
|
||||||
'\\\\',
|
|
||||||
'\n',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
$str.=':' . str_replace($src, $out, $this->value);
|
|
||||||
|
|
||||||
$out = '';
|
$out = '';
|
||||||
while(strlen($str)>0) {
|
while(strlen($str)>0) {
|
||||||
|
|
@ -214,42 +258,84 @@ class Property extends Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new componenten or element
|
* Returns the value, in the format it should be encoded for json.
|
||||||
*
|
*
|
||||||
* You can call this method with the following syntaxes:
|
* This method must always return an array.
|
||||||
*
|
*
|
||||||
* add(Parameter $element)
|
* @return array
|
||||||
* add(string $name, $value)
|
*/
|
||||||
|
public function getJsonValue() {
|
||||||
|
|
||||||
|
return $this->getParts();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the json value, as it would appear in a jCard or jCal object.
|
||||||
*
|
*
|
||||||
* The first version adds an Parameter
|
* The value must always be an array.
|
||||||
* The second adds a property as a string.
|
|
||||||
*
|
*
|
||||||
* @param mixed $item
|
* @param array $value
|
||||||
* @param mixed $itemValue
|
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function add($item, $itemValue = null) {
|
public function setJsonValue(array $value) {
|
||||||
|
|
||||||
if ($item instanceof Parameter) {
|
|
||||||
if (!is_null($itemValue)) {
|
|
||||||
throw new \InvalidArgumentException('The second argument must not be specified, when passing a VObject');
|
|
||||||
}
|
|
||||||
$item->parent = $this;
|
|
||||||
$this->parameters[] = $item;
|
|
||||||
} elseif(is_string($item)) {
|
|
||||||
|
|
||||||
$parameter = new Parameter($item,$itemValue);
|
|
||||||
$parameter->parent = $this;
|
|
||||||
$this->parameters[] = $parameter;
|
|
||||||
|
|
||||||
|
if (count($value)===1) {
|
||||||
|
$this->setValue(reset($value));
|
||||||
} else {
|
} else {
|
||||||
|
$this->setValue($value);
|
||||||
throw new \InvalidArgumentException('The first argument must either be a Node a string');
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns an array, with the representation as it should be
|
||||||
|
* encoded in json. This is used to create jCard or jCal documents.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function jsonSerialize() {
|
||||||
|
|
||||||
|
$parameters = array();
|
||||||
|
|
||||||
|
foreach($this->parameters as $parameter) {
|
||||||
|
if ($parameter->name === 'VALUE') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$parameters[strtolower($parameter->name)] = $parameter->jsonSerialize();
|
||||||
|
}
|
||||||
|
// In jCard, we need to encode the property-group as a separate 'group'
|
||||||
|
// parameter.
|
||||||
|
if ($this->group) {
|
||||||
|
$parameters['group'] = $this->group;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_merge(
|
||||||
|
array(
|
||||||
|
strtolower($this->name),
|
||||||
|
(object)$parameters,
|
||||||
|
strtolower($this->getValueType()),
|
||||||
|
),
|
||||||
|
$this->getJsonValue()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when this object is being cast to a string.
|
||||||
|
*
|
||||||
|
* If the property only had a single value, you will get just that. In the
|
||||||
|
* case the property had multiple values, the contents will be escaped and
|
||||||
|
* combined with ,.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString() {
|
||||||
|
|
||||||
|
return (string)$this->getValue();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* ArrayAccess interface {{{ */
|
/* ArrayAccess interface {{{ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -272,7 +358,9 @@ class Property extends Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a parameter, or parameter list.
|
* Returns a parameter.
|
||||||
|
*
|
||||||
|
* If the parameter does not exist, null is returned.
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @return Node
|
* @return Node
|
||||||
|
|
@ -282,20 +370,11 @@ class Property extends Node {
|
||||||
if (is_int($name)) return parent::offsetGet($name);
|
if (is_int($name)) return parent::offsetGet($name);
|
||||||
$name = strtoupper($name);
|
$name = strtoupper($name);
|
||||||
|
|
||||||
$result = array();
|
if (!isset($this->parameters[$name])) {
|
||||||
foreach($this->parameters as $parameter) {
|
return null;
|
||||||
if ($parameter->name == $name)
|
|
||||||
$result[] = $parameter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($result)===0) {
|
return $this->parameters[$name];
|
||||||
return null;
|
|
||||||
} elseif (count($result)===1) {
|
|
||||||
return $result[0];
|
|
||||||
} else {
|
|
||||||
$result[0]->setIterator(new ElementList($result));
|
|
||||||
return $result[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -308,27 +387,18 @@ class Property extends Node {
|
||||||
*/
|
*/
|
||||||
public function offsetSet($name, $value) {
|
public function offsetSet($name, $value) {
|
||||||
|
|
||||||
if (is_int($name)) parent::offsetSet($name, $value);
|
if (is_int($name)) {
|
||||||
|
parent::offsetSet($name, $value);
|
||||||
if (is_scalar($value)) {
|
// @codeCoverageIgnoreStart
|
||||||
if (!is_string($name))
|
// This will never be reached, because an exception is always
|
||||||
throw new \InvalidArgumentException('A parameter name must be specified. This means you cannot use the $array[]="string" to add parameters.');
|
// thrown.
|
||||||
|
return;
|
||||||
$this->offsetUnset($name);
|
// @codeCoverageIgnoreEnd
|
||||||
$parameter = new Parameter($name, $value);
|
|
||||||
$parameter->parent = $this;
|
|
||||||
$this->parameters[] = $parameter;
|
|
||||||
|
|
||||||
} elseif ($value instanceof Parameter) {
|
|
||||||
if (!is_null($name))
|
|
||||||
throw new \InvalidArgumentException('Don\'t specify a parameter name if you\'re passing a \\Sabre\\VObject\\Parameter. Add using $array[]=$parameterObject.');
|
|
||||||
|
|
||||||
$value->parent = $this;
|
|
||||||
$this->parameters[] = $value;
|
|
||||||
} else {
|
|
||||||
throw new \InvalidArgumentException('You can only add parameters to the property object');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$param = new Parameter($this->root, $name, $value);
|
||||||
|
$this->parameters[$param->name] = $param;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -339,32 +409,20 @@ class Property extends Node {
|
||||||
*/
|
*/
|
||||||
public function offsetUnset($name) {
|
public function offsetUnset($name) {
|
||||||
|
|
||||||
if (is_int($name)) parent::offsetUnset($name);
|
if (is_int($name)) {
|
||||||
$name = strtoupper($name);
|
parent::offsetUnset($name);
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
foreach($this->parameters as $key=>$parameter) {
|
// This will never be reached, because an exception is always
|
||||||
if ($parameter->name == $name) {
|
// thrown.
|
||||||
$parameter->parent = null;
|
return;
|
||||||
unset($this->parameters[$key]);
|
// @codeCoverageIgnoreEnd
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
unset($this->parameters[strtoupper($name)]);
|
||||||
|
|
||||||
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when this object is being cast to a string
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString() {
|
|
||||||
|
|
||||||
return (string)$this->value;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is automatically called when the object is cloned.
|
* This method is automatically called when the object is cloned.
|
||||||
* Specifically, this will ensure all child elements are also cloned.
|
* Specifically, this will ensure all child elements are also cloned.
|
||||||
|
|
@ -402,14 +460,14 @@ class Property extends Node {
|
||||||
$warnings = array();
|
$warnings = array();
|
||||||
|
|
||||||
// Checking if our value is UTF-8
|
// Checking if our value is UTF-8
|
||||||
if (!StringUtil::isUTF8($this->value)) {
|
if (!StringUtil::isUTF8($this->getRawMimeDirValue())) {
|
||||||
$warnings[] = array(
|
$warnings[] = array(
|
||||||
'level' => 1,
|
'level' => 1,
|
||||||
'message' => 'Property is not valid UTF-8!',
|
'message' => 'Property is not valid UTF-8!',
|
||||||
'node' => $this,
|
'node' => $this,
|
||||||
);
|
);
|
||||||
if ($options & self::REPAIR) {
|
if ($options & self::REPAIR) {
|
||||||
$this->value = StringUtil::convertToUTF8($this->value);
|
$this->setRawMimeDirValue(StringUtil::convertToUTF8($this->getRawMimeDirValue()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
127
rainloop/v/0.0.0/app/libraries/Sabre/VObject/Property/Binary.php
Normal file
127
rainloop/v/0.0.0/app/libraries/Sabre/VObject/Property/Binary.php
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property;
|
||||||
|
|
||||||
|
use
|
||||||
|
LogicException,
|
||||||
|
Sabre\VObject\Property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BINARY property
|
||||||
|
*
|
||||||
|
* This object represents BINARY values.
|
||||||
|
*
|
||||||
|
* Binary values are most commonly used by the iCalendar ATTACH property, and
|
||||||
|
* the vCard PHOTO property.
|
||||||
|
*
|
||||||
|
* This property will transparently encode and decode to base64.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class Binary extends Property {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case this is a multi-value property. This string will be used as a
|
||||||
|
* delimiter.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $delimiter = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the current value.
|
||||||
|
*
|
||||||
|
* This may be either a single, or multiple strings in an array.
|
||||||
|
*
|
||||||
|
* @param string|array $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setValue($value) {
|
||||||
|
|
||||||
|
if(is_array($value)) {
|
||||||
|
|
||||||
|
if(count($value) === 1) {
|
||||||
|
$this->value = $value[0];
|
||||||
|
} else {
|
||||||
|
throw new \InvalidArgumentException('The argument must either be a string or an array with only one child');
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$this->value = $value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a raw value coming from a mimedir (iCalendar/vCard) file.
|
||||||
|
*
|
||||||
|
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||||
|
* not yet done, but parameters are not included.
|
||||||
|
*
|
||||||
|
* @param string $val
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setRawMimeDirValue($val) {
|
||||||
|
|
||||||
|
$this->value = base64_decode($val);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a raw mime-dir representation of the value.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRawMimeDirValue() {
|
||||||
|
|
||||||
|
return base64_encode($this->value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return 'BINARY';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value, in the format it should be encoded for json.
|
||||||
|
*
|
||||||
|
* This method must always return an array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getJsonValue() {
|
||||||
|
|
||||||
|
return array(base64_encode($this->getValue()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the json value, as it would appear in a jCard or jCal object.
|
||||||
|
*
|
||||||
|
* The value must always be an array.
|
||||||
|
*
|
||||||
|
* @param array $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setJsonValue(array $value) {
|
||||||
|
|
||||||
|
$value = array_map('base64_decode', $value);
|
||||||
|
parent::setJsonValue($value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\Property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boolean property
|
||||||
|
*
|
||||||
|
* This object represents BOOLEAN values. These are always the case-insenstive
|
||||||
|
* string TRUE or FALSE.
|
||||||
|
*
|
||||||
|
* Automatic conversion to PHP's true and false are done.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class Boolean extends Property {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a raw value coming from a mimedir (iCalendar/vCard) file.
|
||||||
|
*
|
||||||
|
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||||
|
* not yet done, but parameters are not included.
|
||||||
|
*
|
||||||
|
* @param string $val
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setRawMimeDirValue($val) {
|
||||||
|
|
||||||
|
$val = strtoupper($val)==='TRUE'?true:false;
|
||||||
|
$this->setValue($val);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a raw mime-dir representation of the value.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRawMimeDirValue() {
|
||||||
|
|
||||||
|
return $this->value?'TRUE':'FALSE';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return 'BOOLEAN';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,125 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Sabre\VObject\Property;
|
|
||||||
|
|
||||||
use Sabre\VObject;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compound property.
|
|
||||||
*
|
|
||||||
* This class adds (de)serialization of compound properties to/from arrays.
|
|
||||||
*
|
|
||||||
* Currently the following properties from RFC 6350 are mapped to use this
|
|
||||||
* class:
|
|
||||||
*
|
|
||||||
* N: Section 6.2.2
|
|
||||||
* ADR: Section 6.3.1
|
|
||||||
* ORG: Section 6.6.4
|
|
||||||
* CATEGORIES: Section 6.7.1
|
|
||||||
*
|
|
||||||
* In order to use this correctly, you must call setParts and getParts to
|
|
||||||
* retrieve and modify dates respectively.
|
|
||||||
*
|
|
||||||
* @author Thomas Tanghus (http://tanghus.net/)
|
|
||||||
* @author Lars Kneschke
|
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
|
||||||
* @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
|
|
||||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
|
||||||
*/
|
|
||||||
class Compound extends VObject\Property {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If property names are added to this map, they will be (de)serialised as arrays
|
|
||||||
* using the getParts() and setParts() methods.
|
|
||||||
* The keys are the property names, values are delimiter chars.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
static public $delimiterMap = array(
|
|
||||||
'N' => ';',
|
|
||||||
'ADR' => ';',
|
|
||||||
'ORG' => ';',
|
|
||||||
'CATEGORIES' => ',',
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The currently used delimiter.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $delimiter = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a compound value as an array.
|
|
||||||
*
|
|
||||||
* @param $name string
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getParts() {
|
|
||||||
|
|
||||||
if (is_null($this->value)) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
$delimiter = $this->getDelimiter();
|
|
||||||
|
|
||||||
// split by any $delimiter which is NOT prefixed by a slash.
|
|
||||||
// Note that this is not a a perfect solution. If a value is prefixed
|
|
||||||
// by two slashes, it should actually be split anyway.
|
|
||||||
//
|
|
||||||
// Hopefully we can fix this better in a future version, where we can
|
|
||||||
// break compatibility a bit.
|
|
||||||
$compoundValues = preg_split("/(?<!\\\)$delimiter/", $this->value);
|
|
||||||
|
|
||||||
// remove slashes from any semicolon and comma left escaped in the single values
|
|
||||||
$compoundValues = array_map(
|
|
||||||
function($val) {
|
|
||||||
return strtr($val, array('\,' => ',', '\;' => ';'));
|
|
||||||
}, $compoundValues);
|
|
||||||
|
|
||||||
return $compoundValues;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the delimiter for this property.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getDelimiter() {
|
|
||||||
|
|
||||||
if (!$this->delimiter) {
|
|
||||||
if (isset(self::$delimiterMap[$this->name])) {
|
|
||||||
$this->delimiter = self::$delimiterMap[$this->name];
|
|
||||||
} else {
|
|
||||||
// To be a bit future proof, we are going to default the
|
|
||||||
// delimiter to ;
|
|
||||||
$this->delimiter = ';';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $this->delimiter;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a compound value as an array.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param $name string
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function setParts(array $values) {
|
|
||||||
|
|
||||||
// add slashes to all semicolons and commas in the single values
|
|
||||||
$values = array_map(
|
|
||||||
function($val) {
|
|
||||||
return strtr($val, array(',' => '\,', ';' => '\;'));
|
|
||||||
}, $values);
|
|
||||||
|
|
||||||
$this->setValue(
|
|
||||||
implode($this->getDelimiter(), $values)
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,245 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Sabre\VObject\Property;
|
|
||||||
|
|
||||||
use Sabre\VObject;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DateTime property
|
|
||||||
*
|
|
||||||
* This element is used for iCalendar properties such as the DTSTART property.
|
|
||||||
* It basically provides a few helper functions that make it easier to deal
|
|
||||||
* with these. It supports both DATE-TIME and DATE values.
|
|
||||||
*
|
|
||||||
* In order to use this correctly, you must call setDateTime and getDateTime to
|
|
||||||
* retrieve and modify dates respectively.
|
|
||||||
*
|
|
||||||
* If you use the 'value' or properties directly, this object does not keep
|
|
||||||
* reference and results might appear incorrectly.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
|
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
|
||||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
|
||||||
*/
|
|
||||||
class DateTime extends VObject\Property {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Local 'floating' time
|
|
||||||
*/
|
|
||||||
const LOCAL = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UTC-based time
|
|
||||||
*/
|
|
||||||
const UTC = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Local time plus timezone
|
|
||||||
*/
|
|
||||||
const LOCALTZ = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only a date, time is ignored
|
|
||||||
*/
|
|
||||||
const DATE = 4;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DateTime representation
|
|
||||||
*
|
|
||||||
* @var \DateTime
|
|
||||||
*/
|
|
||||||
protected $dateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* dateType
|
|
||||||
*
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
protected $dateType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the Date and Time.
|
|
||||||
*
|
|
||||||
* @param \DateTime $dt
|
|
||||||
* @param int $dateType
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function setDateTime(\DateTime $dt, $dateType = self::LOCALTZ) {
|
|
||||||
|
|
||||||
switch($dateType) {
|
|
||||||
|
|
||||||
case self::LOCAL :
|
|
||||||
$this->setValue($dt->format('Ymd\\THis'));
|
|
||||||
$this->offsetUnset('VALUE');
|
|
||||||
$this->offsetUnset('TZID');
|
|
||||||
$this->offsetSet('VALUE','DATE-TIME');
|
|
||||||
break;
|
|
||||||
case self::UTC :
|
|
||||||
$dt->setTimeZone(new \DateTimeZone('UTC'));
|
|
||||||
$this->setValue($dt->format('Ymd\\THis\\Z'));
|
|
||||||
$this->offsetUnset('VALUE');
|
|
||||||
$this->offsetUnset('TZID');
|
|
||||||
$this->offsetSet('VALUE','DATE-TIME');
|
|
||||||
break;
|
|
||||||
case self::LOCALTZ :
|
|
||||||
$this->setValue($dt->format('Ymd\\THis'));
|
|
||||||
$this->offsetUnset('VALUE');
|
|
||||||
$this->offsetUnset('TZID');
|
|
||||||
$this->offsetSet('VALUE','DATE-TIME');
|
|
||||||
$this->offsetSet('TZID', $dt->getTimeZone()->getName());
|
|
||||||
break;
|
|
||||||
case self::DATE :
|
|
||||||
$this->setValue($dt->format('Ymd'));
|
|
||||||
$this->offsetUnset('VALUE');
|
|
||||||
$this->offsetUnset('TZID');
|
|
||||||
$this->offsetSet('VALUE','DATE');
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
throw new \InvalidArgumentException('You must pass a valid dateType constant');
|
|
||||||
|
|
||||||
}
|
|
||||||
$this->dateTime = $dt;
|
|
||||||
$this->dateType = $dateType;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current DateTime value.
|
|
||||||
*
|
|
||||||
* If no value was set, this method returns null.
|
|
||||||
*
|
|
||||||
* @return \DateTime|null
|
|
||||||
*/
|
|
||||||
public function getDateTime() {
|
|
||||||
|
|
||||||
if ($this->dateTime)
|
|
||||||
return $this->dateTime;
|
|
||||||
|
|
||||||
list(
|
|
||||||
$this->dateType,
|
|
||||||
$this->dateTime
|
|
||||||
) = self::parseData($this->value, $this);
|
|
||||||
return $this->dateTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the type of Date format.
|
|
||||||
*
|
|
||||||
* This method returns one of the format constants. If no date was set,
|
|
||||||
* this method will return null.
|
|
||||||
*
|
|
||||||
* @return int|null
|
|
||||||
*/
|
|
||||||
public function getDateType() {
|
|
||||||
|
|
||||||
if ($this->dateType)
|
|
||||||
return $this->dateType;
|
|
||||||
|
|
||||||
list(
|
|
||||||
$this->dateType,
|
|
||||||
$this->dateTime,
|
|
||||||
) = self::parseData($this->value, $this);
|
|
||||||
return $this->dateType;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method will return true, if the property had a date and a time, as
|
|
||||||
* opposed to only a date.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function hasTime() {
|
|
||||||
|
|
||||||
return $this->getDateType()!==self::DATE;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the internal data structure to figure out what the current date
|
|
||||||
* and time is.
|
|
||||||
*
|
|
||||||
* The returned array contains two elements:
|
|
||||||
* 1. A 'DateType' constant (as defined on this class), or null.
|
|
||||||
* 2. A DateTime object (or null)
|
|
||||||
*
|
|
||||||
* @param string|null $propertyValue The string to parse (yymmdd or
|
|
||||||
* ymmddThhmmss, etc..)
|
|
||||||
* @param \Sabre\VObject\Property|null $property The instance of the
|
|
||||||
* property we're parsing.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
static public function parseData($propertyValue, VObject\Property $property = null) {
|
|
||||||
|
|
||||||
if (is_null($propertyValue)) {
|
|
||||||
return array(null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
$date = '(?P<year>[1-2][0-9]{3})(?P<month>[0-1][0-9])(?P<date>[0-3][0-9])';
|
|
||||||
$time = '(?P<hour>[0-2][0-9])(?P<minute>[0-5][0-9])(?P<second>[0-5][0-9])';
|
|
||||||
$regex = "/^$date(T$time(?P<isutc>Z)?)?$/";
|
|
||||||
|
|
||||||
if (!preg_match($regex, $propertyValue, $matches)) {
|
|
||||||
throw new \InvalidArgumentException($propertyValue . ' is not a valid \DateTime or Date string');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($matches['hour'])) {
|
|
||||||
// Date-only
|
|
||||||
return array(
|
|
||||||
self::DATE,
|
|
||||||
new \DateTime($matches['year'] . '-' . $matches['month'] . '-' . $matches['date'] . ' 00:00:00', new \DateTimeZone('UTC')),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$dateStr =
|
|
||||||
$matches['year'] .'-' .
|
|
||||||
$matches['month'] . '-' .
|
|
||||||
$matches['date'] . ' ' .
|
|
||||||
$matches['hour'] . ':' .
|
|
||||||
$matches['minute'] . ':' .
|
|
||||||
$matches['second'];
|
|
||||||
|
|
||||||
if (isset($matches['isutc'])) {
|
|
||||||
$dt = new \DateTime($dateStr,new \DateTimeZone('UTC'));
|
|
||||||
$dt->setTimeZone(new \DateTimeZone('UTC'));
|
|
||||||
return array(
|
|
||||||
self::UTC,
|
|
||||||
$dt
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finding the timezone.
|
|
||||||
$tzid = $property['TZID'];
|
|
||||||
if (!$tzid) {
|
|
||||||
// This was a floating time string. This implies we use the
|
|
||||||
// timezone from date_default_timezone_set / date.timezone ini
|
|
||||||
// setting.
|
|
||||||
return array(
|
|
||||||
self::LOCAL,
|
|
||||||
new \DateTime($dateStr)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// To look up the timezone, we must first find the VCALENDAR component.
|
|
||||||
$root = $property;
|
|
||||||
while($root->parent) {
|
|
||||||
$root = $root->parent;
|
|
||||||
}
|
|
||||||
if ($root->name === 'VCALENDAR') {
|
|
||||||
$tz = VObject\TimeZoneUtil::getTimeZone((string)$tzid, $root);
|
|
||||||
} else {
|
|
||||||
$tz = VObject\TimeZoneUtil::getTimeZone((string)$tzid);
|
|
||||||
}
|
|
||||||
|
|
||||||
$dt = new \DateTime($dateStr, $tz);
|
|
||||||
$dt->setTimeZone($tz);
|
|
||||||
|
|
||||||
return array(
|
|
||||||
self::LOCALTZ,
|
|
||||||
$dt
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FlatText property
|
||||||
|
*
|
||||||
|
* This object represents certain TEXT values.
|
||||||
|
*
|
||||||
|
* Specifically, this property is used for text values where there is only 1
|
||||||
|
* part. Semi-colons and colons will be de-escaped when deserializing, but if
|
||||||
|
* any semi-colons or commas appear without a backslash, we will not assume
|
||||||
|
* that they are delimiters.
|
||||||
|
*
|
||||||
|
* vCard 2.1 specifically has a whole bunch of properties where this may
|
||||||
|
* happen, as it only defines a delimiter for a few properties.
|
||||||
|
*
|
||||||
|
* vCard 4.0 states something similar. An unescaped semi-colon _may_ be a
|
||||||
|
* delimiter, depending on the property.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class FlatText extends Text {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Field separator
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $delimiter = ',';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value as a quoted-printable encoded string.
|
||||||
|
*
|
||||||
|
* Overriding this so we're not splitting on a ; delimiter.
|
||||||
|
*
|
||||||
|
* @param string $val
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setQuotedPrintableValue($val) {
|
||||||
|
|
||||||
|
$val = quoted_printable_decode($val);
|
||||||
|
$this->setValue($val);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
101
rainloop/v/0.0.0/app/libraries/Sabre/VObject/Property/Float.php
Normal file
101
rainloop/v/0.0.0/app/libraries/Sabre/VObject/Property/Float.php
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\Property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Float property
|
||||||
|
*
|
||||||
|
* This object represents FLOAT values. These can be 1 or more floating-point
|
||||||
|
* numbers.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class Float extends Property {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case this is a multi-value property. This string will be used as a
|
||||||
|
* delimiter.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $delimiter = ';';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a raw value coming from a mimedir (iCalendar/vCard) file.
|
||||||
|
*
|
||||||
|
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||||
|
* not yet done, but parameters are not included.
|
||||||
|
*
|
||||||
|
* @param string $val
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setRawMimeDirValue($val) {
|
||||||
|
|
||||||
|
$val = explode($this->delimiter, $val);
|
||||||
|
foreach($val as &$item) {
|
||||||
|
$item = (float)$item;
|
||||||
|
}
|
||||||
|
$this->setParts($val);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a raw mime-dir representation of the value.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRawMimeDirValue() {
|
||||||
|
|
||||||
|
return implode(
|
||||||
|
$this->delimiter,
|
||||||
|
$this->getParts()
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return "FLOAT";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value, in the format it should be encoded for json.
|
||||||
|
*
|
||||||
|
* This method must always return an array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getJsonValue() {
|
||||||
|
|
||||||
|
$val = array_map(function($item) {
|
||||||
|
|
||||||
|
return (float)$item;
|
||||||
|
|
||||||
|
}, $this->getParts());
|
||||||
|
|
||||||
|
// Special-casing the GEO property.
|
||||||
|
//
|
||||||
|
// See:
|
||||||
|
// http://tools.ietf.org/html/draft-ietf-jcardcal-jcal-04#section-3.4.1.2
|
||||||
|
if ($this->name==='GEO') {
|
||||||
|
return array($val);
|
||||||
|
} else {
|
||||||
|
return $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property\ICalendar;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\Property\Text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CalAddress property
|
||||||
|
*
|
||||||
|
* This object encodes CAL-ADDRESS values, as defined in rfc5545
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class CalAddress extends Text {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case this is a multi-value property. This string will be used as a
|
||||||
|
* delimiter.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $delimiter = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return 'CAL-ADDRESS';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property\ICalendar;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\Property,
|
||||||
|
Sabre\VObject\Parser\MimeDir,
|
||||||
|
Sabre\VObject\DateTimeParser,
|
||||||
|
Sabre\VObject\TimeZoneUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DateTime property
|
||||||
|
*
|
||||||
|
* This object represents DATE values, as defined here:
|
||||||
|
*
|
||||||
|
* http://tools.ietf.org/html/rfc5545#section-3.3.5
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class Date extends DateTime {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,308 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property\ICalendar;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\Property,
|
||||||
|
Sabre\VObject\Parser\MimeDir,
|
||||||
|
Sabre\VObject\DateTimeParser,
|
||||||
|
Sabre\VObject\TimeZoneUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DateTime property
|
||||||
|
*
|
||||||
|
* This object represents DATE-TIME values, as defined here:
|
||||||
|
*
|
||||||
|
* http://tools.ietf.org/html/rfc5545#section-3.3.4
|
||||||
|
*
|
||||||
|
* This particular object has a bit of hackish magic that it may also in some
|
||||||
|
* cases represent a DATE value. This is because it's a common usecase to be
|
||||||
|
* able to change a DATE-TIME into a DATE.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class DateTime extends Property {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case this is a multi-value property. This string will be used as a
|
||||||
|
* delimiter.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $delimiter = ',';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a multi-valued property.
|
||||||
|
*
|
||||||
|
* You may also specify DateTime objects here.
|
||||||
|
*
|
||||||
|
* @param array $parts
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setParts(array $parts) {
|
||||||
|
|
||||||
|
if (isset($parts[0]) && $parts[0] instanceof \DateTime) {
|
||||||
|
$this->setDateTimes($parts);
|
||||||
|
} else {
|
||||||
|
parent::setParts($parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the current value.
|
||||||
|
*
|
||||||
|
* This may be either a single, or multiple strings in an array.
|
||||||
|
*
|
||||||
|
* Instead of strings, you may also use DateTime here.
|
||||||
|
*
|
||||||
|
* @param string|array|\DateTime $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setValue($value) {
|
||||||
|
|
||||||
|
if (is_array($value) && isset($value[0]) && $value[0] instanceof \DateTime) {
|
||||||
|
$this->setDateTimes($value);
|
||||||
|
} elseif ($value instanceof \DateTime) {
|
||||||
|
$this->setDateTimes(array($value));
|
||||||
|
} else {
|
||||||
|
parent::setValue($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a raw value coming from a mimedir (iCalendar/vCard) file.
|
||||||
|
*
|
||||||
|
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||||
|
* not yet done, but parameters are not included.
|
||||||
|
*
|
||||||
|
* @param string $val
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setRawMimeDirValue($val) {
|
||||||
|
|
||||||
|
$this->setValue(explode($this->delimiter, $val));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a raw mime-dir representation of the value.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRawMimeDirValue() {
|
||||||
|
|
||||||
|
return implode($this->delimiter, $this->getParts());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this is a DATE-TIME value, false if it's a DATE.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasTime() {
|
||||||
|
|
||||||
|
return strtoupper((string)$this['VALUE']) !== 'DATE';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a date-time value.
|
||||||
|
*
|
||||||
|
* Note that if this property contained more than 1 date-time, only the
|
||||||
|
* first will be returned. To get an array with multiple values, call
|
||||||
|
* getDateTimes.
|
||||||
|
*
|
||||||
|
* @return \DateTime
|
||||||
|
*/
|
||||||
|
public function getDateTime() {
|
||||||
|
|
||||||
|
$dt = $this->getDateTimes();
|
||||||
|
if (!$dt) return null;
|
||||||
|
|
||||||
|
return $dt[0];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns multiple date-time values.
|
||||||
|
*
|
||||||
|
* @return \DateTime[]
|
||||||
|
*/
|
||||||
|
public function getDateTimes() {
|
||||||
|
|
||||||
|
// Finding the timezone.
|
||||||
|
$tz = $this['TZID'];
|
||||||
|
|
||||||
|
if ($tz) {
|
||||||
|
$tz = TimeZoneUtil::getTimeZone((string)$tz, $this->root);
|
||||||
|
}
|
||||||
|
|
||||||
|
$dts = array();
|
||||||
|
foreach($this->getParts() as $part) {
|
||||||
|
$dts[] = DateTimeParser::parse($part, $tz);
|
||||||
|
}
|
||||||
|
return $dts;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the property as a DateTime object.
|
||||||
|
*
|
||||||
|
* @param \DateTime $dt
|
||||||
|
* @param bool isFloating If set to true, timezones will be ignored.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setDateTime(\DateTime $dt, $isFloating = false) {
|
||||||
|
|
||||||
|
$this->setDateTimes(array($dt), $isFloating);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the property as multiple date-time objects.
|
||||||
|
*
|
||||||
|
* The first value will be used as a reference for the timezones, and all
|
||||||
|
* the otehr values will be adjusted for that timezone
|
||||||
|
*
|
||||||
|
* @param \DateTime[] $dt
|
||||||
|
* @param bool isFloating If set to true, timezones will be ignored.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setDateTimes(array $dt, $isFloating = false) {
|
||||||
|
|
||||||
|
$values = array();
|
||||||
|
|
||||||
|
if($this->hasTime()) {
|
||||||
|
|
||||||
|
$tz = null;
|
||||||
|
$isUtc = false;
|
||||||
|
|
||||||
|
foreach($dt as $d) {
|
||||||
|
|
||||||
|
if ($isFloating) {
|
||||||
|
$values[] = $d->format('Ymd\\THis');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (is_null($tz)) {
|
||||||
|
$tz = $d->getTimeZone();
|
||||||
|
$isUtc = in_array($tz->getName() , array('UTC', 'GMT', 'Z'));
|
||||||
|
if (!$isUtc) {
|
||||||
|
$this->offsetSet('TZID', $tz->getName());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$d->setTimeZone($tz);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($isUtc) {
|
||||||
|
$values[] = $d->format('Ymd\\THis\\Z');
|
||||||
|
} else {
|
||||||
|
$values[] = $d->format('Ymd\\THis');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if ($isUtc || $isFloating) {
|
||||||
|
$this->offsetUnset('TZID');
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
foreach($dt as $d) {
|
||||||
|
|
||||||
|
$values[] = $d->format('Ymd');
|
||||||
|
|
||||||
|
}
|
||||||
|
$this->offsetUnset('TZID');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->value = $values;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return $this->hasTime()?'DATE-TIME':'DATE';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value, in the format it should be encoded for json.
|
||||||
|
*
|
||||||
|
* This method must always return an array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getJsonValue() {
|
||||||
|
|
||||||
|
$dts = $this->getDateTimes();
|
||||||
|
$hasTime = $this->hasTime();
|
||||||
|
|
||||||
|
$tz = $dts[0]->getTimeZone();
|
||||||
|
$isUtc = in_array($tz->getName() , array('UTC', 'GMT', 'Z'));
|
||||||
|
|
||||||
|
return array_map(function($dt) use ($hasTime, $isUtc) {
|
||||||
|
|
||||||
|
if ($hasTime) {
|
||||||
|
return $dt->format('Y-m-d\\TH:i:s') . ($isUtc?'Z':'');
|
||||||
|
} else {
|
||||||
|
return $dt->format('Y-m-d');
|
||||||
|
}
|
||||||
|
|
||||||
|
}, $dts);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the json value, as it would appear in a jCard or jCal object.
|
||||||
|
*
|
||||||
|
* The value must always be an array.
|
||||||
|
*
|
||||||
|
* @param array $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setJsonValue(array $value) {
|
||||||
|
|
||||||
|
// dates and times in jCal have one difference to dates and times in
|
||||||
|
// iCalendar. In jCal date-parts are separated by dashes, and
|
||||||
|
// time-parts are separated by colons. It makes sense to just remove
|
||||||
|
// those.
|
||||||
|
$this->setValue(array_map(function($item) {
|
||||||
|
|
||||||
|
return strtr($item, array(':'=>'', '-'=>''));
|
||||||
|
|
||||||
|
}, $value));
|
||||||
|
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* We need to intercept offsetSet, because it may be used to alter the
|
||||||
|
* VALUE from DATE-TIME to DATE or vice-versa.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param mixed $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function offsetSet($name, $value) {
|
||||||
|
|
||||||
|
parent::offsetSet($name, $value);
|
||||||
|
if (strtoupper($name)!=='VALUE') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will ensure that dates are correctly encoded.
|
||||||
|
$this->setDateTimes($this->getDateTimes());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property\ICalendar;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\Property,
|
||||||
|
Sabre\VObject\Parser\MimeDir,
|
||||||
|
Sabre\VObject\DateTimeParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duration property
|
||||||
|
*
|
||||||
|
* This object represents DURATION values, as defined here:
|
||||||
|
*
|
||||||
|
* http://tools.ietf.org/html/rfc5545#section-3.3.6
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class Duration extends Property {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case this is a multi-value property. This string will be used as a
|
||||||
|
* delimiter.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $delimiter = ',';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a raw value coming from a mimedir (iCalendar/vCard) file.
|
||||||
|
*
|
||||||
|
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||||
|
* not yet done, but parameters are not included.
|
||||||
|
*
|
||||||
|
* @param string $val
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setRawMimeDirValue($val) {
|
||||||
|
|
||||||
|
$this->setValue(explode($this->delimiter, $val));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a raw mime-dir representation of the value.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRawMimeDirValue() {
|
||||||
|
|
||||||
|
return implode($this->delimiter, $this->getParts());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return 'DURATION';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a DateInterval representation of the Duration property.
|
||||||
|
*
|
||||||
|
* If the property has more than one value, only the first is returned.
|
||||||
|
*
|
||||||
|
* @return \DateInterval
|
||||||
|
*/
|
||||||
|
public function getDateInterval() {
|
||||||
|
|
||||||
|
$parts = $this->getParts();
|
||||||
|
$value = $parts[0];
|
||||||
|
return DateTimeParser::parseDuration($value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property\ICalendar;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\Property,
|
||||||
|
Sabre\VObject\Parser\MimeDir,
|
||||||
|
Sabre\VObject\DateTimeParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Period property
|
||||||
|
*
|
||||||
|
* This object represents PERIOD values, as defined here:
|
||||||
|
*
|
||||||
|
* http://tools.ietf.org/html/rfc5545#section-3.8.2.6
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class Period extends Property {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case this is a multi-value property. This string will be used as a
|
||||||
|
* delimiter.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $delimiter = ',';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a raw value coming from a mimedir (iCalendar/vCard) file.
|
||||||
|
*
|
||||||
|
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||||
|
* not yet done, but parameters are not included.
|
||||||
|
*
|
||||||
|
* @param string $val
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setRawMimeDirValue($val) {
|
||||||
|
|
||||||
|
$this->setValue(explode($this->delimiter, $val));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a raw mime-dir representation of the value.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRawMimeDirValue() {
|
||||||
|
|
||||||
|
return implode($this->delimiter, $this->getParts());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return "PERIOD";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the json value, as it would appear in a jCard or jCal object.
|
||||||
|
*
|
||||||
|
* The value must always be an array.
|
||||||
|
*
|
||||||
|
* @param array $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setJsonValue(array $value) {
|
||||||
|
|
||||||
|
$value = array_map(function($item) {
|
||||||
|
|
||||||
|
return strtr(implode('/', $item), array(':' => '', '-' => ''));
|
||||||
|
|
||||||
|
}, $value);
|
||||||
|
parent::setJsonValue($value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value, in the format it should be encoded for json.
|
||||||
|
*
|
||||||
|
* This method must always return an array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getJsonValue() {
|
||||||
|
|
||||||
|
$return = array();
|
||||||
|
foreach($this->getParts() as $item) {
|
||||||
|
|
||||||
|
list($start, $end) = explode('/', $item, 2);
|
||||||
|
|
||||||
|
$start = DateTimeParser::parseDateTime($start);
|
||||||
|
|
||||||
|
// This is a duration value.
|
||||||
|
if ($end[0]==='P') {
|
||||||
|
$return[] = array(
|
||||||
|
$start->format('Y-m-d\\TH:i:s'),
|
||||||
|
$end
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$end = DateTimeParser::parseDateTime($end);
|
||||||
|
$return[] = array(
|
||||||
|
$start->format('Y-m-d\\TH:i:s'),
|
||||||
|
$end->format('Y-m-d\\TH:i:s'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,189 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property\ICalendar;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\Property,
|
||||||
|
Sabre\VObject\Parser\MimeDir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recur property
|
||||||
|
*
|
||||||
|
* This object represents RECUR properties.
|
||||||
|
* These values are just used for RRULE and the now deprecated EXRULE.
|
||||||
|
*
|
||||||
|
* The RRULE property may look something like this:
|
||||||
|
*
|
||||||
|
* RRULE:FREQ=MONTHLY;BYDAY=1,2,3;BYHOUR=5.
|
||||||
|
*
|
||||||
|
* This property exposes this as a key=>value array that is accessible using
|
||||||
|
* getParts, and may be set using setParts.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class Recur extends Property {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the current value.
|
||||||
|
*
|
||||||
|
* This may be either a single, or multiple strings in an array.
|
||||||
|
*
|
||||||
|
* @param string|array $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setValue($value) {
|
||||||
|
|
||||||
|
// If we're getting the data from json, we'll be receiving an object
|
||||||
|
if ($value instanceof \StdClass) {
|
||||||
|
$value = (array)$value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($value)) {
|
||||||
|
$newVal = array();
|
||||||
|
foreach($value as $k=>$v) {
|
||||||
|
|
||||||
|
if (is_string($v)) {
|
||||||
|
$v = strtoupper($v);
|
||||||
|
|
||||||
|
// The value had multiple sub-values
|
||||||
|
if (strpos($v,',')!==false) {
|
||||||
|
$v = explode(',', $v);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$v = array_map('strtoupper', $v);
|
||||||
|
}
|
||||||
|
|
||||||
|
$newVal[strtoupper($k)] = $v;
|
||||||
|
}
|
||||||
|
$this->value = $newVal;
|
||||||
|
} elseif (is_string($value)) {
|
||||||
|
$value = strtoupper($value);
|
||||||
|
$newValue = array();
|
||||||
|
foreach(explode(';', $value) as $part) {
|
||||||
|
|
||||||
|
// Skipping empty parts.
|
||||||
|
if (empty($part)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
list($partName, $partValue) = explode('=', $part);
|
||||||
|
|
||||||
|
// The value itself had multiple values..
|
||||||
|
if (strpos($partValue,',')!==false) {
|
||||||
|
$partValue=explode(',', $partValue);
|
||||||
|
}
|
||||||
|
$newValue[$partName] = $partValue;
|
||||||
|
|
||||||
|
}
|
||||||
|
$this->value = $newValue;
|
||||||
|
} else {
|
||||||
|
throw new \InvalidArgumentException('You must either pass a string, or a key=>value array');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current value.
|
||||||
|
*
|
||||||
|
* This method will always return a singular value. If this was a
|
||||||
|
* multi-value object, some decision will be made first on how to represent
|
||||||
|
* it as a string.
|
||||||
|
*
|
||||||
|
* To get the correct multi-value version, use getParts.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValue() {
|
||||||
|
|
||||||
|
$out = array();
|
||||||
|
foreach($this->value as $key=>$value) {
|
||||||
|
$out[] = $key . '=' . (is_array($value)?implode(',', $value):$value);
|
||||||
|
}
|
||||||
|
return strtoupper(implode(';',$out));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a multi-valued property.
|
||||||
|
*
|
||||||
|
* @param array $parts
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setParts(array $parts) {
|
||||||
|
|
||||||
|
$this->setValue($parts);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a multi-valued property.
|
||||||
|
*
|
||||||
|
* This method always returns an array, if there was only a single value,
|
||||||
|
* it will still be wrapped in an array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getParts() {
|
||||||
|
|
||||||
|
return $this->value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a raw value coming from a mimedir (iCalendar/vCard) file.
|
||||||
|
*
|
||||||
|
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||||
|
* not yet done, but parameters are not included.
|
||||||
|
*
|
||||||
|
* @param string $val
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setRawMimeDirValue($val) {
|
||||||
|
|
||||||
|
$this->setValue($val);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a raw mime-dir representation of the value.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRawMimeDirValue() {
|
||||||
|
|
||||||
|
return $this->getValue();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return "RECUR";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value, in the format it should be encoded for json.
|
||||||
|
*
|
||||||
|
* This method must always return an array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getJsonValue() {
|
||||||
|
|
||||||
|
$values = array();
|
||||||
|
foreach($this->getParts() as $k=>$v) {
|
||||||
|
$values[strtolower($k)] = $v;
|
||||||
|
}
|
||||||
|
return array($values);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\Property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integer property
|
||||||
|
*
|
||||||
|
* This object represents INTEGER values. These are always a single integer.
|
||||||
|
* They may be preceeded by either + or -.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class Integer extends Property {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a raw value coming from a mimedir (iCalendar/vCard) file.
|
||||||
|
*
|
||||||
|
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||||
|
* not yet done, but parameters are not included.
|
||||||
|
*
|
||||||
|
* @param string $val
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setRawMimeDirValue($val) {
|
||||||
|
|
||||||
|
$this->setValue((int)$val);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a raw mime-dir representation of the value.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRawMimeDirValue() {
|
||||||
|
|
||||||
|
return $this->value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return "INTEGER";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value, in the format it should be encoded for json.
|
||||||
|
*
|
||||||
|
* This method must always return an array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getJsonValue() {
|
||||||
|
|
||||||
|
return array((int)$this->getValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,180 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Sabre\VObject\Property;
|
|
||||||
|
|
||||||
use Sabre\VObject;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Multi-DateTime property
|
|
||||||
*
|
|
||||||
* This element is used for iCalendar properties such as the EXDATE property.
|
|
||||||
* It basically provides a few helper functions that make it easier to deal
|
|
||||||
* with these. It supports both DATE-TIME and DATE values.
|
|
||||||
*
|
|
||||||
* In order to use this correctly, you must call setDateTimes and getDateTimes
|
|
||||||
* to retrieve and modify dates respectively.
|
|
||||||
*
|
|
||||||
* If you use the 'value' or properties directly, this object does not keep
|
|
||||||
* reference and results might appear incorrectly.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
|
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
|
||||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
|
||||||
*/
|
|
||||||
class MultiDateTime extends VObject\Property {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DateTime representation
|
|
||||||
*
|
|
||||||
* @var DateTime[]
|
|
||||||
*/
|
|
||||||
protected $dateTimes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* dateType
|
|
||||||
*
|
|
||||||
* This is one of the Sabre\VObject\Property\DateTime constants.
|
|
||||||
*
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
protected $dateType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the value
|
|
||||||
*
|
|
||||||
* @param array $dt Must be an array of DateTime objects.
|
|
||||||
* @param int $dateType
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function setDateTimes(array $dt, $dateType = VObject\Property\DateTime::LOCALTZ) {
|
|
||||||
|
|
||||||
foreach($dt as $i)
|
|
||||||
if (!$i instanceof \DateTime)
|
|
||||||
throw new \InvalidArgumentException('You must pass an array of DateTime objects');
|
|
||||||
|
|
||||||
$this->offsetUnset('VALUE');
|
|
||||||
$this->offsetUnset('TZID');
|
|
||||||
switch($dateType) {
|
|
||||||
|
|
||||||
case DateTime::LOCAL :
|
|
||||||
$val = array();
|
|
||||||
foreach($dt as $i) {
|
|
||||||
$val[] = $i->format('Ymd\\THis');
|
|
||||||
}
|
|
||||||
$this->setValue(implode(',',$val));
|
|
||||||
$this->offsetSet('VALUE','DATE-TIME');
|
|
||||||
break;
|
|
||||||
case DateTime::UTC :
|
|
||||||
$val = array();
|
|
||||||
foreach($dt as $i) {
|
|
||||||
$i->setTimeZone(new \DateTimeZone('UTC'));
|
|
||||||
$val[] = $i->format('Ymd\\THis\\Z');
|
|
||||||
}
|
|
||||||
$this->setValue(implode(',',$val));
|
|
||||||
$this->offsetSet('VALUE','DATE-TIME');
|
|
||||||
break;
|
|
||||||
case DateTime::LOCALTZ :
|
|
||||||
$val = array();
|
|
||||||
foreach($dt as $i) {
|
|
||||||
$val[] = $i->format('Ymd\\THis');
|
|
||||||
}
|
|
||||||
$this->setValue(implode(',',$val));
|
|
||||||
$this->offsetSet('VALUE','DATE-TIME');
|
|
||||||
$this->offsetSet('TZID', $dt[0]->getTimeZone()->getName());
|
|
||||||
break;
|
|
||||||
case DateTime::DATE :
|
|
||||||
$val = array();
|
|
||||||
foreach($dt as $i) {
|
|
||||||
$val[] = $i->format('Ymd');
|
|
||||||
}
|
|
||||||
$this->setValue(implode(',',$val));
|
|
||||||
$this->offsetSet('VALUE','DATE');
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
throw new \InvalidArgumentException('You must pass a valid dateType constant');
|
|
||||||
|
|
||||||
}
|
|
||||||
$this->dateTimes = $dt;
|
|
||||||
$this->dateType = $dateType;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current DateTime value.
|
|
||||||
*
|
|
||||||
* If no value was set, this method returns null.
|
|
||||||
*
|
|
||||||
* @return array|null
|
|
||||||
*/
|
|
||||||
public function getDateTimes() {
|
|
||||||
|
|
||||||
if ($this->dateTimes)
|
|
||||||
return $this->dateTimes;
|
|
||||||
|
|
||||||
$dts = array();
|
|
||||||
|
|
||||||
if (!$this->value) {
|
|
||||||
$this->dateTimes = null;
|
|
||||||
$this->dateType = null;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach(explode(',',$this->value) as $val) {
|
|
||||||
list(
|
|
||||||
$type,
|
|
||||||
$dt
|
|
||||||
) = DateTime::parseData($val, $this);
|
|
||||||
$dts[] = $dt;
|
|
||||||
$this->dateType = $type;
|
|
||||||
}
|
|
||||||
$this->dateTimes = $dts;
|
|
||||||
return $this->dateTimes;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the type of Date format.
|
|
||||||
*
|
|
||||||
* This method returns one of the format constants. If no date was set,
|
|
||||||
* this method will return null.
|
|
||||||
*
|
|
||||||
* @return int|null
|
|
||||||
*/
|
|
||||||
public function getDateType() {
|
|
||||||
|
|
||||||
if ($this->dateType)
|
|
||||||
return $this->dateType;
|
|
||||||
|
|
||||||
if (!$this->value) {
|
|
||||||
$this->dateTimes = null;
|
|
||||||
$this->dateType = null;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$dts = array();
|
|
||||||
foreach(explode(',',$this->value) as $val) {
|
|
||||||
list(
|
|
||||||
$type,
|
|
||||||
$dt
|
|
||||||
) = DateTime::parseData($val, $this);
|
|
||||||
$dts[] = $dt;
|
|
||||||
$this->dateType = $type;
|
|
||||||
}
|
|
||||||
$this->dateTimes = $dts;
|
|
||||||
return $this->dateType;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method will return true, if the property had a date and a time, as
|
|
||||||
* opposed to only a date.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function hasTime() {
|
|
||||||
|
|
||||||
return $this->getDateType()!==DateTime::DATE;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
330
rainloop/v/0.0.0/app/libraries/Sabre/VObject/Property/Text.php
Normal file
330
rainloop/v/0.0.0/app/libraries/Sabre/VObject/Property/Text.php
Normal file
|
|
@ -0,0 +1,330 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\Property,
|
||||||
|
Sabre\VObject\Component,
|
||||||
|
Sabre\VObject\Parser\MimeDir,
|
||||||
|
Sabre\VObject\Document;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text property
|
||||||
|
*
|
||||||
|
* This object represents TEXT values.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class Text extends Property {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case this is a multi-value property. This string will be used as a
|
||||||
|
* delimiter.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $delimiter = ',';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of properties that are considered 'structured'.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $structuredValues = array(
|
||||||
|
// vCard
|
||||||
|
'N',
|
||||||
|
'ADR',
|
||||||
|
'ORG',
|
||||||
|
'GENDER',
|
||||||
|
|
||||||
|
// iCalendar
|
||||||
|
'REQUEST-STATUS',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some text components have a minimum number of components.
|
||||||
|
*
|
||||||
|
* N must for instance be represented as 5 components, separated by ;, even
|
||||||
|
* if the last few components are unused.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $minimumPropertyValues = array(
|
||||||
|
'N' => 5,
|
||||||
|
'ADR' => 7,
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the property.
|
||||||
|
*
|
||||||
|
* You can specify the parameters either in key=>value syntax, in which case
|
||||||
|
* parameters will automatically be created, or you can just pass a list of
|
||||||
|
* Parameter objects.
|
||||||
|
*
|
||||||
|
* @param Component $root The root document
|
||||||
|
* @param string $name
|
||||||
|
* @param string|array|null $value
|
||||||
|
* @param array $parameters List of parameters
|
||||||
|
* @param string $group The vcard property group
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Component $root, $name, $value = null, array $parameters = array(), $group = null) {
|
||||||
|
|
||||||
|
// There's two types of multi-valued text properties:
|
||||||
|
// 1. multivalue properties.
|
||||||
|
// 2. structured value properties
|
||||||
|
//
|
||||||
|
// The former is always separated by a comma, the latter by semi-colon.
|
||||||
|
if (in_array($name, $this->structuredValues)) {
|
||||||
|
$this->delimiter = ';';
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($root, $name, $value, $parameters, $group);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a raw value coming from a mimedir (iCalendar/vCard) file.
|
||||||
|
*
|
||||||
|
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||||
|
* not yet done, but parameters are not included.
|
||||||
|
*
|
||||||
|
* @param string $val
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setRawMimeDirValue($val) {
|
||||||
|
|
||||||
|
$this->setValue(MimeDir::unescapeValue($val, $this->delimiter));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value as a quoted-printable encoded string.
|
||||||
|
*
|
||||||
|
* @param string $val
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setQuotedPrintableValue($val) {
|
||||||
|
|
||||||
|
$val = quoted_printable_decode($val);
|
||||||
|
|
||||||
|
// Quoted printable only appears in vCard 2.1, and the only character
|
||||||
|
// that may be escaped there is ;. So we are simply splitting on just
|
||||||
|
// that.
|
||||||
|
//
|
||||||
|
// We also don't have to unescape \\, so all we need to look for is a ;
|
||||||
|
// that's not preceeded with a \.
|
||||||
|
$regex = '# (?<!\\\\) ; #x';
|
||||||
|
$matches = preg_split($regex, $val);
|
||||||
|
$this->setValue($matches);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a raw mime-dir representation of the value.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRawMimeDirValue() {
|
||||||
|
|
||||||
|
$val = $this->getParts();
|
||||||
|
|
||||||
|
if (isset($this->minimumPropertyValues[$this->name])) {
|
||||||
|
$val = array_pad($val, $this->minimumPropertyValues[$this->name], '');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($val as &$item) {
|
||||||
|
|
||||||
|
if (!is_array($item)) {
|
||||||
|
$item = array($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($item as &$subItem) {
|
||||||
|
$subItem = strtr($subItem, array(
|
||||||
|
'\\' => '\\\\',
|
||||||
|
';' => '\;',
|
||||||
|
',' => '\,',
|
||||||
|
"\n" => '\n',
|
||||||
|
"\r" => "",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
$item = implode(',', $item);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode($this->delimiter, $val);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value, in the format it should be encoded for json.
|
||||||
|
*
|
||||||
|
* This method must always return an array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getJsonValue() {
|
||||||
|
|
||||||
|
// Structured text values should always be returned as a single
|
||||||
|
// array-item. Multi-value text should be returned as multiple items in
|
||||||
|
// the top-array.
|
||||||
|
if (in_array($this->name, $this->structuredValues)) {
|
||||||
|
return array($this->getParts());
|
||||||
|
} else {
|
||||||
|
return $this->getParts();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return "TEXT";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns the object back into a serialized blob.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function serialize() {
|
||||||
|
|
||||||
|
// We need to kick in a special type of encoding, if it's a 2.1 vcard.
|
||||||
|
if ($this->root->getDocumentType() !== Document::VCARD21) {
|
||||||
|
return parent::serialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
$val = $this->getParts();
|
||||||
|
|
||||||
|
if (isset($this->minimumPropertyValues[$this->name])) {
|
||||||
|
$val = array_pad($val, $this->minimumPropertyValues[$this->name], '');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Imploding multiple parts into a single value, and splitting the
|
||||||
|
// values with ;.
|
||||||
|
if (count($val)>1) {
|
||||||
|
foreach($val as $k=>$v) {
|
||||||
|
$val[$k] = str_replace(';','\;', $v);
|
||||||
|
}
|
||||||
|
$val = implode(';', $val);
|
||||||
|
} else {
|
||||||
|
$val = $val[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$str = $this->name;
|
||||||
|
if ($this->group) $str = $this->group . '.' . $this->name;
|
||||||
|
foreach($this->parameters as $param) {
|
||||||
|
|
||||||
|
if ($param->getValue() === 'QUOTED-PRINTABLE') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$str.=';' . $param->serialize();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// If the resulting value contains a \n, we must encode it as
|
||||||
|
// quoted-printable.
|
||||||
|
if (strpos($val,"\n") !== false) {
|
||||||
|
|
||||||
|
$str.=';ENCODING=QUOTED-PRINTABLE:';
|
||||||
|
$lastLine=$str;
|
||||||
|
$out = null;
|
||||||
|
|
||||||
|
// The PHP built-in quoted-printable-encode does not correctly
|
||||||
|
// encode newlines for us. Specifically, the \r\n sequence must in
|
||||||
|
// vcards be encoded as =0D=OA and we must insert soft-newlines
|
||||||
|
// every 75 bytes.
|
||||||
|
for($ii=0;$ii<strlen($val);$ii++) {
|
||||||
|
$ord = ord($val[$ii]);
|
||||||
|
// These characters are encoded as themselves.
|
||||||
|
if ($ord >= 32 && $ord <=126) {
|
||||||
|
$lastLine.=$val[$ii];
|
||||||
|
} else {
|
||||||
|
$lastLine.='=' . strtoupper(bin2hex($val[$ii]));
|
||||||
|
}
|
||||||
|
if (strlen($lastLine)>=75) {
|
||||||
|
// Soft line break
|
||||||
|
$out.=$lastLine. "=\r\n ";
|
||||||
|
$lastLine = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!is_null($lastLine)) $out.= $lastLine . "\r\n";
|
||||||
|
return $out;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$str.=':' . $val;
|
||||||
|
$out = '';
|
||||||
|
while(strlen($str)>0) {
|
||||||
|
if (strlen($str)>75) {
|
||||||
|
$out.= mb_strcut($str,0,75,'utf-8') . "\r\n";
|
||||||
|
$str = ' ' . mb_strcut($str,75,strlen($str),'utf-8');
|
||||||
|
} else {
|
||||||
|
$out.=$str . "\r\n";
|
||||||
|
$str='';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the node for correctness.
|
||||||
|
*
|
||||||
|
* The following options are supported:
|
||||||
|
* - Node::REPAIR - If something is broken, and automatic repair may
|
||||||
|
* be attempted.
|
||||||
|
*
|
||||||
|
* An array is returned with warnings.
|
||||||
|
*
|
||||||
|
* Every item in the array has the following properties:
|
||||||
|
* * level - (number between 1 and 3 with severity information)
|
||||||
|
* * message - (human readable message)
|
||||||
|
* * node - (reference to the offending node)
|
||||||
|
*
|
||||||
|
* @param int $options
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function validate($options = 0) {
|
||||||
|
|
||||||
|
$warnings = parent::validate($options);
|
||||||
|
|
||||||
|
if (isset($this->minimumPropertyValues[$this->name])) {
|
||||||
|
|
||||||
|
$minimum = $this->minimumPropertyValues[$this->name];
|
||||||
|
$parts = $this->getParts();
|
||||||
|
if (count($parts) < $minimum) {
|
||||||
|
$warnings[] = array(
|
||||||
|
'level' => 1,
|
||||||
|
'message' => 'This property must have at least ' . $minimum . ' components. It only has ' . count($parts),
|
||||||
|
'node' => $this,
|
||||||
|
);
|
||||||
|
if ($options & self::REPAIR) {
|
||||||
|
$parts = array_pad($parts, $minimum, '');
|
||||||
|
$this->setParts($parts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return $warnings;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property;
|
||||||
|
|
||||||
|
use Sabre\VObject\DateTimeParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time property
|
||||||
|
*
|
||||||
|
* This object encodes TIME values.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class Time extends Text {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case this is a multi-value property. This string will be used as a
|
||||||
|
* delimiter.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $delimiter = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return "TIME";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value, in the format it should be encoded for json.
|
||||||
|
*
|
||||||
|
* This method must always return an array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getJsonValue() {
|
||||||
|
|
||||||
|
$parts = DateTimeParser::parseVCardTime($this->getValue());
|
||||||
|
|
||||||
|
$timeStr = '';
|
||||||
|
|
||||||
|
// Hour
|
||||||
|
if (!is_null($parts['hour'])) {
|
||||||
|
$timeStr.=$parts['hour'];
|
||||||
|
|
||||||
|
if (!is_null($parts['minute'])) {
|
||||||
|
$timeStr.=':';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We know either minute or second _must_ be set, so we insert a
|
||||||
|
// dash for an empty value.
|
||||||
|
$timeStr.='-';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minute
|
||||||
|
if (!is_null($parts['minute'])) {
|
||||||
|
$timeStr.=$parts['minute'];
|
||||||
|
|
||||||
|
if (!is_null($parts['second'])) {
|
||||||
|
$timeStr.=':';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isset($parts['second'])) {
|
||||||
|
// Dash for empty minute
|
||||||
|
$timeStr.='-';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second
|
||||||
|
if (!is_null($parts['second'])) {
|
||||||
|
$timeStr.=$parts['second'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timezone
|
||||||
|
if (!is_null($parts['timezone'])) {
|
||||||
|
$timeStr.=$parts['timezone'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($timeStr);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\Property,
|
||||||
|
Sabre\VObject\Component,
|
||||||
|
Sabre\VObject\Parser\MimeDir,
|
||||||
|
Sabre\VObject\Document;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unknown property
|
||||||
|
*
|
||||||
|
* This object represents any properties not recognized by the parser.
|
||||||
|
* This type of value has been introduced by the jCal, jCard specs.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class Unknown extends Text {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value, in the format it should be encoded for json.
|
||||||
|
*
|
||||||
|
* This method must always return an array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getJsonValue() {
|
||||||
|
|
||||||
|
return array($this->getRawMimeDirValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return "UNKNOWN";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property;
|
||||||
|
|
||||||
|
use Sabre\VObject\Property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URI property
|
||||||
|
*
|
||||||
|
* This object encodes URI values. vCard 2.1 calls these URL.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class Uri extends Property {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case this is a multi-value property. This string will be used as a
|
||||||
|
* delimiter.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $delimiter = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return "URI";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a raw value coming from a mimedir (iCalendar/vCard) file.
|
||||||
|
*
|
||||||
|
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||||
|
* not yet done, but parameters are not included.
|
||||||
|
*
|
||||||
|
* @param string $val
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setRawMimeDirValue($val) {
|
||||||
|
|
||||||
|
$this->value = $val;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a raw mime-dir representation of the value.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRawMimeDirValue() {
|
||||||
|
|
||||||
|
if (is_array($this->value)) {
|
||||||
|
return $this->value[0];
|
||||||
|
} else {
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UtcOffset property
|
||||||
|
*
|
||||||
|
* This object encodes UTC-OFFSET values.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class UtcOffset extends Text {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case this is a multi-value property. This string will be used as a
|
||||||
|
* delimiter.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $delimiter = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return "UTC-OFFSET";
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property\VCard;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\DateTimeParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date property
|
||||||
|
*
|
||||||
|
* This object encodes vCard DATE values.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class Date extends DateAndOrTime {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return "DATE";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,144 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property\VCard;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\DateTimeParser,
|
||||||
|
Sabre\VObject\Property\Text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DateAndOrTime property
|
||||||
|
*
|
||||||
|
* This object encodes DATE-AND-OR-TIME values.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class DateAndOrTime extends Text {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Field separator
|
||||||
|
*
|
||||||
|
* @var null|string
|
||||||
|
*/
|
||||||
|
public $delimiter = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return "DATE-AND-OR-TIME";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value, in the format it should be encoded for json.
|
||||||
|
*
|
||||||
|
* This method must always return an array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getJsonValue() {
|
||||||
|
|
||||||
|
$parts = DateTimeParser::parseVCardDateTime($this->getValue());
|
||||||
|
|
||||||
|
$dateStr = '';
|
||||||
|
|
||||||
|
// Year
|
||||||
|
if (!is_null($parts['year'])) {
|
||||||
|
$dateStr.=$parts['year'];
|
||||||
|
|
||||||
|
if (!is_null($parts['month'])) {
|
||||||
|
// If a year and a month is set, we need to insert a separator
|
||||||
|
// dash.
|
||||||
|
$dateStr.='-';
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (!is_null($parts['month']) || !is_null($parts['date'])) {
|
||||||
|
// Inserting two dashes
|
||||||
|
$dateStr.='--';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Month
|
||||||
|
|
||||||
|
if (!is_null($parts['month'])) {
|
||||||
|
$dateStr.=$parts['month'];
|
||||||
|
|
||||||
|
if (isset($parts['date'])) {
|
||||||
|
// If month and date are set, we need the separator dash.
|
||||||
|
$dateStr.='-';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isset($parts['date'])) {
|
||||||
|
// If the month is empty, and a date is set, we need a 'empty
|
||||||
|
// dash'
|
||||||
|
$dateStr.='-';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Date
|
||||||
|
if (!is_null($parts['date'])) {
|
||||||
|
$dateStr.=$parts['date'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Early exit if we don't have a time string.
|
||||||
|
if (is_null($parts['hour']) && is_null($parts['minute']) && is_null($parts['second'])) {
|
||||||
|
return array($dateStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
$dateStr.='T';
|
||||||
|
|
||||||
|
// Hour
|
||||||
|
if (!is_null($parts['hour'])) {
|
||||||
|
$dateStr.=$parts['hour'];
|
||||||
|
|
||||||
|
if (!is_null($parts['minute'])) {
|
||||||
|
$dateStr.=':';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We know either minute or second _must_ be set, so we insert a
|
||||||
|
// dash for an empty value.
|
||||||
|
$dateStr.='-';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minute
|
||||||
|
if (!is_null($parts['minute'])) {
|
||||||
|
$dateStr.=$parts['minute'];
|
||||||
|
|
||||||
|
if (!is_null($parts['second'])) {
|
||||||
|
$dateStr.=':';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isset($parts['second'])) {
|
||||||
|
// Dash for empty minute
|
||||||
|
$dateStr.='-';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second
|
||||||
|
if (!is_null($parts['second'])) {
|
||||||
|
$dateStr.=$parts['second'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timezone
|
||||||
|
if (!is_null($parts['timezone'])) {
|
||||||
|
$dateStr.=$parts['timezone'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($dateStr);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property\VCard;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\DateTimeParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DateTime property
|
||||||
|
*
|
||||||
|
* This object encodes DATE-TIME values for vCards.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class DateTime extends DateAndOrTime {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return "DATE-TIME";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property\VCard;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\Property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LanguageTag property
|
||||||
|
*
|
||||||
|
* This object represents LANGUAGE-TAG values as used in vCards.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class LanguageTag extends Property {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a raw value coming from a mimedir (iCalendar/vCard) file.
|
||||||
|
*
|
||||||
|
* This has been 'unfolded', so only 1 line will be passed. Unescaping is
|
||||||
|
* not yet done, but parameters are not included.
|
||||||
|
*
|
||||||
|
* @param string $val
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setRawMimeDirValue($val) {
|
||||||
|
|
||||||
|
$this->setValue($val);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a raw mime-dir representation of the value.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRawMimeDirValue() {
|
||||||
|
|
||||||
|
return $this->value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return "LANGUAGE-TAG";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject\Property\VCard;
|
||||||
|
|
||||||
|
use
|
||||||
|
Sabre\VObject\DateTimeParser,
|
||||||
|
Sabre\VObject\Property\Text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TimeStamp property
|
||||||
|
*
|
||||||
|
* This object encodes TIMESTAMP values.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class TimeStamp extends Text {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case this is a multi-value property. This string will be used as a
|
||||||
|
* delimiter.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $delimiter = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of value.
|
||||||
|
*
|
||||||
|
* This corresponds to the VALUE= parameter. Every property also has a
|
||||||
|
* 'default' valueType.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValueType() {
|
||||||
|
|
||||||
|
return "TIMESTAMP";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value, in the format it should be encoded for json.
|
||||||
|
*
|
||||||
|
* This method must always return an array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getJsonValue() {
|
||||||
|
|
||||||
|
$parts = DateTimeParser::parseVCardDateTime($this->getValue());
|
||||||
|
|
||||||
|
$dateStr =
|
||||||
|
$parts['year'] . '-' .
|
||||||
|
$parts['month'] . '-' .
|
||||||
|
$parts['date'] . 'T' .
|
||||||
|
$parts['hour'] . ':' .
|
||||||
|
$parts['minute'] . ':' .
|
||||||
|
$parts['second'];
|
||||||
|
|
||||||
|
// Timezone
|
||||||
|
if (!is_null($parts['timezone'])) {
|
||||||
|
$dateStr.=$parts['timezone'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($dateStr);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,12 +3,10 @@
|
||||||
namespace Sabre\VObject;
|
namespace Sabre\VObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VCALENDAR/VCARD reader
|
* iCalendar/vCard/jCal/jCard reader object.
|
||||||
*
|
*
|
||||||
* This class reads the vobject file, and returns a full element tree.
|
* This object provides a few (static) convenience methods to quickly access
|
||||||
*
|
* the parsers.
|
||||||
* TODO: this class currently completely works 'statically'. This is pointless,
|
|
||||||
* and defeats OOP principals. Needs refactoring in a future version.
|
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
|
@ -19,9 +17,6 @@ class Reader {
|
||||||
/**
|
/**
|
||||||
* If this option is passed to the reader, it will be less strict about the
|
* If this option is passed to the reader, it will be less strict about the
|
||||||
* validity of the lines.
|
* validity of the lines.
|
||||||
*
|
|
||||||
* Currently using this option just means, that it will accept underscores
|
|
||||||
* in property names.
|
|
||||||
*/
|
*/
|
||||||
const OPTION_FORGIVING = 1;
|
const OPTION_FORGIVING = 1;
|
||||||
|
|
||||||
|
|
@ -32,192 +27,47 @@ class Reader {
|
||||||
const OPTION_IGNORE_INVALID_LINES = 2;
|
const OPTION_IGNORE_INVALID_LINES = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the file and returns the top component
|
* Parses a vCard or iCalendar object, and returns the top component.
|
||||||
*
|
*
|
||||||
* The options argument is a bitfield. Pass any of the OPTIONS constant to
|
* The options argument is a bitfield. Pass any of the OPTIONS constant to
|
||||||
* alter the parsers' behaviour.
|
* alter the parsers' behaviour.
|
||||||
*
|
*
|
||||||
* @param string $data
|
* You can either supply a string, or a readable stream for input.
|
||||||
|
*
|
||||||
|
* @param string|resource $data
|
||||||
* @param int $options
|
* @param int $options
|
||||||
* @return Node
|
* @return Document
|
||||||
*/
|
*/
|
||||||
static function read($data, $options = 0) {
|
static function read($data, $options = 0) {
|
||||||
|
|
||||||
// Normalizing newlines
|
$parser = new Parser\MimeDir();
|
||||||
$data = str_replace(array("\r","\n\n"), array("\n","\n"), $data);
|
$result = $parser->parse($data, $options);
|
||||||
|
|
||||||
$lines = explode("\n", $data);
|
return $result;
|
||||||
|
|
||||||
// Unfolding lines
|
|
||||||
$lines2 = array();
|
|
||||||
foreach($lines as $line) {
|
|
||||||
|
|
||||||
// Skipping empty lines
|
|
||||||
if (!$line) continue;
|
|
||||||
|
|
||||||
if ($line[0]===" " || $line[0]==="\t") {
|
|
||||||
$lines2[count($lines2)-1].=substr($line,1);
|
|
||||||
} else {
|
|
||||||
$lines2[] = $line;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
unset($lines);
|
|
||||||
|
|
||||||
reset($lines2);
|
|
||||||
|
|
||||||
return self::readLine($lines2, $options);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads and parses a single line.
|
* Parses a jCard or jCal object, and returns the top component.
|
||||||
*
|
*
|
||||||
* This method receives the full array of lines. The array pointer is used
|
* The options argument is a bitfield. Pass any of the OPTIONS constant to
|
||||||
* to traverse.
|
* alter the parsers' behaviour.
|
||||||
*
|
*
|
||||||
* This method returns null if an invalid line was encountered, and the
|
* You can either a string, a readable stream, or an array for it's input.
|
||||||
* IGNORE_INVALID_LINES option was turned on.
|
* Specifying the array is useful if json_decode was already called on the
|
||||||
|
* input.
|
||||||
*
|
*
|
||||||
* @param array $lines
|
* @param string|resource|array $data
|
||||||
* @param int $options See the OPTIONS constants.
|
* @param int $options
|
||||||
* @return Node
|
* @return Node
|
||||||
*/
|
*/
|
||||||
static private function readLine(&$lines, $options = 0) {
|
static function readJson($data, $options = 0) {
|
||||||
|
|
||||||
$line = current($lines);
|
$parser = new Parser\Json();
|
||||||
$lineNr = key($lines);
|
$result = $parser->parse($data, $options);
|
||||||
next($lines);
|
|
||||||
|
|
||||||
// Components
|
|
||||||
if (strtoupper(substr($line,0,6)) === "BEGIN:") {
|
|
||||||
|
|
||||||
$componentName = strtoupper(substr($line,6));
|
|
||||||
$obj = Component::create($componentName);
|
|
||||||
|
|
||||||
$nextLine = current($lines);
|
|
||||||
|
|
||||||
while(strtoupper(substr($nextLine,0,4))!=="END:") {
|
|
||||||
|
|
||||||
$parsedLine = self::readLine($lines, $options);
|
|
||||||
$nextLine = current($lines);
|
|
||||||
|
|
||||||
if (is_null($parsedLine)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$obj->add($parsedLine);
|
|
||||||
|
|
||||||
if ($nextLine===false)
|
|
||||||
throw new ParseException('Invalid VObject. Document ended prematurely.');
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checking component name of the 'END:' line.
|
|
||||||
if (substr($nextLine,4)!==$obj->name) {
|
|
||||||
throw new ParseException('Invalid VObject, expected: "END:' . $obj->name . '" got: "' . $nextLine . '"');
|
|
||||||
}
|
|
||||||
next($lines);
|
|
||||||
|
|
||||||
return $obj;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Properties
|
|
||||||
//$result = preg_match('/(?P<name>[A-Z0-9-]+)(?:;(?P<parameters>^(?<!:):))(.*)$/',$line,$matches);
|
|
||||||
|
|
||||||
if ($options & self::OPTION_FORGIVING) {
|
|
||||||
$token = '[A-Z0-9-\._]+';
|
|
||||||
} else {
|
|
||||||
$token = '[A-Z0-9-\.]+';
|
|
||||||
}
|
|
||||||
$parameters = "(?:;(?P<parameters>([^:^\"]|\"([^\"]*)\")*))?";
|
|
||||||
$regex = "/^(?P<name>$token)$parameters:(?P<value>.*)$/i";
|
|
||||||
|
|
||||||
$result = preg_match($regex,$line,$matches);
|
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
if ($options & self::OPTION_IGNORE_INVALID_LINES) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
throw new ParseException('Invalid VObject, line ' . ($lineNr+1) . ' did not follow the icalendar/vcard format');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$propertyName = strtoupper($matches['name']);
|
|
||||||
$propertyValue = preg_replace_callback('#(\\\\(\\\\|N|n))#',function($matches) {
|
|
||||||
if ($matches[2]==='n' || $matches[2]==='N') {
|
|
||||||
return "\n";
|
|
||||||
} else {
|
|
||||||
return $matches[2];
|
|
||||||
}
|
|
||||||
}, $matches['value']);
|
|
||||||
|
|
||||||
$obj = Property::create($propertyName, $propertyValue);
|
|
||||||
|
|
||||||
if ($matches['parameters']) {
|
|
||||||
|
|
||||||
foreach(self::readParameters($matches['parameters']) as $param) {
|
|
||||||
$obj->add($param);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return $obj;
|
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a parameter list from a property
|
|
||||||
*
|
|
||||||
* This method returns an array of Parameter
|
|
||||||
*
|
|
||||||
* @param string $parameters
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
static private function readParameters($parameters) {
|
|
||||||
|
|
||||||
$token = '[A-Z0-9-]+';
|
|
||||||
|
|
||||||
$paramValue = '(?P<paramValue>[^\"^;]*|"[^"]*")';
|
|
||||||
|
|
||||||
$regex = "/(?<=^|;)(?P<paramName>$token)(=$paramValue(?=$|;))?/i";
|
|
||||||
preg_match_all($regex, $parameters, $matches, PREG_SET_ORDER);
|
|
||||||
|
|
||||||
$params = array();
|
|
||||||
foreach($matches as $match) {
|
|
||||||
|
|
||||||
if (!isset($match['paramValue'])) {
|
|
||||||
|
|
||||||
$value = null;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
$value = $match['paramValue'];
|
|
||||||
|
|
||||||
if (isset($value[0]) && $value[0]==='"') {
|
|
||||||
// Stripping quotes, if needed
|
|
||||||
$value = substr($value,1,strlen($value)-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
$value = preg_replace_callback('#(\\\\(\\\\|N|n|;|,))#',function($matches) {
|
|
||||||
if ($matches[2]==='n' || $matches[2]==='N') {
|
|
||||||
return "\n";
|
|
||||||
} else {
|
|
||||||
return $matches[2];
|
|
||||||
}
|
|
||||||
}, $value);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$params[] = new Parameter($match['paramName'], $value);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return $params;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ namespace Sabre\VObject;
|
||||||
* you may get unexpected results. The effect is that in some applications the
|
* you may get unexpected results. The effect is that in some applications the
|
||||||
* specified recurrence may look incorrect, or is missing.
|
* specified recurrence may look incorrect, or is missing.
|
||||||
*
|
*
|
||||||
|
* The recurrence iterator also does not yet support THISANDFUTURE.
|
||||||
|
*
|
||||||
* @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
|
@ -70,7 +72,6 @@ class RecurrenceIterator implements \Iterator {
|
||||||
*/
|
*/
|
||||||
public $currentDate;
|
public $currentDate;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of dates that are excluded from the rules.
|
* List of dates that are excluded from the rules.
|
||||||
*
|
*
|
||||||
|
|
@ -314,7 +315,7 @@ class RecurrenceIterator implements \Iterator {
|
||||||
public function __construct(Component $vcal, $uid=null) {
|
public function __construct(Component $vcal, $uid=null) {
|
||||||
|
|
||||||
if (is_null($uid)) {
|
if (is_null($uid)) {
|
||||||
if ($vcal->name === 'VCALENDAR') {
|
if ($vcal instanceof Component\VCalendar) {
|
||||||
throw new \InvalidArgumentException('If you pass a VCALENDAR object, you must pass a uid argument as well');
|
throw new \InvalidArgumentException('If you pass a VCALENDAR object, you must pass a uid argument as well');
|
||||||
}
|
}
|
||||||
$components = array($vcal);
|
$components = array($vcal);
|
||||||
|
|
@ -336,7 +337,17 @@ class RecurrenceIterator implements \Iterator {
|
||||||
ksort($this->overriddenEvents);
|
ksort($this->overriddenEvents);
|
||||||
|
|
||||||
if (!$this->baseEvent) {
|
if (!$this->baseEvent) {
|
||||||
throw new \InvalidArgumentException('Could not find a base event with uid: ' . $uid);
|
// No base event was found. CalDAV does allow cases where only
|
||||||
|
// overridden instances are stored.
|
||||||
|
//
|
||||||
|
// In this barticular case, we're just going to grab the first
|
||||||
|
// event and use that instead. This may not always give the
|
||||||
|
// desired result.
|
||||||
|
if (!count($this->overriddenEvents)) {
|
||||||
|
throw new \InvalidArgumentException('Could not find an event with uid: ' . $uid);
|
||||||
|
}
|
||||||
|
ksort($this->overriddenEvents, SORT_NUMERIC);
|
||||||
|
$this->baseEvent = array_shift($this->overriddenEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->startDate = clone $this->baseEvent->DTSTART->getDateTime();
|
$this->startDate = clone $this->baseEvent->DTSTART->getDateTime();
|
||||||
|
|
@ -347,26 +358,22 @@ class RecurrenceIterator implements \Iterator {
|
||||||
} else {
|
} else {
|
||||||
$this->endDate = clone $this->startDate;
|
$this->endDate = clone $this->startDate;
|
||||||
if (isset($this->baseEvent->DURATION)) {
|
if (isset($this->baseEvent->DURATION)) {
|
||||||
$this->endDate->add(DateTimeParser::parse($this->baseEvent->DURATION->value));
|
$this->endDate->add(DateTimeParser::parse((string)$this->baseEvent->DURATION));
|
||||||
} elseif ($this->baseEvent->DTSTART->getDateType()===Property\DateTime::DATE) {
|
} elseif (!$this->baseEvent->DTSTART->hasTime()) {
|
||||||
$this->endDate->modify('+1 day');
|
$this->endDate->modify('+1 day');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->currentDate = clone $this->startDate;
|
$this->currentDate = clone $this->startDate;
|
||||||
|
|
||||||
$rrule = (string)$this->baseEvent->RRULE;
|
$rrule = $this->baseEvent->RRULE;
|
||||||
|
|
||||||
$parts = explode(';', $rrule);
|
|
||||||
|
|
||||||
// If no rrule was specified, we create a default setting
|
// If no rrule was specified, we create a default setting
|
||||||
if (!$rrule) {
|
if (!$rrule) {
|
||||||
$this->frequency = 'daily';
|
$this->frequency = 'daily';
|
||||||
$this->count = 1;
|
$this->count = 1;
|
||||||
} else foreach($parts as $part) {
|
} else foreach($rrule->getParts() as $key=>$value) {
|
||||||
|
|
||||||
list($key, $value) = explode('=', $part, 2);
|
switch($key) {
|
||||||
|
|
||||||
switch(strtoupper($key)) {
|
|
||||||
|
|
||||||
case 'FREQ' :
|
case 'FREQ' :
|
||||||
if (!in_array(
|
if (!in_array(
|
||||||
|
|
@ -407,39 +414,39 @@ class RecurrenceIterator implements \Iterator {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'BYSECOND' :
|
case 'BYSECOND' :
|
||||||
$this->bySecond = explode(',', $value);
|
$this->bySecond = (array)$value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'BYMINUTE' :
|
case 'BYMINUTE' :
|
||||||
$this->byMinute = explode(',', $value);
|
$this->byMinute = (array)$value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'BYHOUR' :
|
case 'BYHOUR' :
|
||||||
$this->byHour = explode(',', $value);
|
$this->byHour = (array)$value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'BYDAY' :
|
case 'BYDAY' :
|
||||||
$this->byDay = explode(',', strtoupper($value));
|
$this->byDay = (array)$value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'BYMONTHDAY' :
|
case 'BYMONTHDAY' :
|
||||||
$this->byMonthDay = explode(',', $value);
|
$this->byMonthDay = (array)$value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'BYYEARDAY' :
|
case 'BYYEARDAY' :
|
||||||
$this->byYearDay = explode(',', $value);
|
$this->byYearDay = (array)$value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'BYWEEKNO' :
|
case 'BYWEEKNO' :
|
||||||
$this->byWeekNo = explode(',', $value);
|
$this->byWeekNo = (array)$value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'BYMONTH' :
|
case 'BYMONTH' :
|
||||||
$this->byMonth = explode(',', $value);
|
$this->byMonth = (array)$value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'BYSETPOS' :
|
case 'BYSETPOS' :
|
||||||
$this->bySetPos = explode(',', $value);
|
$this->bySetPos = (array)$value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'WKST' :
|
case 'WKST' :
|
||||||
|
|
@ -528,9 +535,9 @@ class RecurrenceIterator implements \Iterator {
|
||||||
unset($event->RDATE);
|
unset($event->RDATE);
|
||||||
unset($event->EXRULE);
|
unset($event->EXRULE);
|
||||||
|
|
||||||
$event->DTSTART->setDateTime($this->getDTStart(), $event->DTSTART->getDateType());
|
$event->DTSTART->setDateTime($this->getDTStart());
|
||||||
if (isset($event->DTEND)) {
|
if (isset($event->DTEND)) {
|
||||||
$event->DTEND->setDateTime($this->getDtEnd(), $event->DTSTART->getDateType());
|
$event->DTEND->setDateTime($this->getDtEnd());
|
||||||
}
|
}
|
||||||
if ($this->counter > 0) {
|
if ($this->counter > 0) {
|
||||||
$event->{'RECURRENCE-ID'} = (string)$event->DTSTART;
|
$event->{'RECURRENCE-ID'} = (string)$event->DTSTART;
|
||||||
|
|
@ -740,7 +747,9 @@ class RecurrenceIterator implements \Iterator {
|
||||||
$this->currentDate->modify('+' . $this->interval . ' hours');
|
$this->currentDate->modify('+' . $this->interval . ' hours');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
}
|
}
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does the processing for advancing the iterator for daily frequency.
|
* Does the processing for advancing the iterator for daily frequency.
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
namespace Sabre\VObject\Splitter;
|
namespace Sabre\VObject\Splitter;
|
||||||
|
|
||||||
use Sabre\VObject;
|
use
|
||||||
|
Sabre\VObject,
|
||||||
|
Sabre\VObject\Component\VCalendar;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Splitter
|
* Splitter
|
||||||
|
|
@ -40,14 +42,15 @@ class ICalendar implements SplitterInterface {
|
||||||
* The splitter should receive an readable file stream as it's input.
|
* The splitter should receive an readable file stream as it's input.
|
||||||
*
|
*
|
||||||
* @param resource $input
|
* @param resource $input
|
||||||
|
* @param int $options Parser options, see the OPTIONS constants.
|
||||||
*/
|
*/
|
||||||
public function __construct($input) {
|
public function __construct($input, $options = 0) {
|
||||||
|
|
||||||
$data = VObject\Reader::read(stream_get_contents($input));
|
$data = VObject\Reader::read($input, $options);
|
||||||
$vtimezones = array();
|
$vtimezones = array();
|
||||||
$components = array();
|
$components = array();
|
||||||
|
|
||||||
foreach($data->children as $component) {
|
foreach($data->children() as $component) {
|
||||||
if (!$component instanceof VObject\Component) {
|
if (!$component instanceof VObject\Component) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -68,7 +71,7 @@ class ICalendar implements SplitterInterface {
|
||||||
|
|
||||||
// Take care of recurring events
|
// Take care of recurring events
|
||||||
if (!array_key_exists($uid, $this->objects)) {
|
if (!array_key_exists($uid, $this->objects)) {
|
||||||
$this->objects[$uid] = VObject\Component::create('VCALENDAR');
|
$this->objects[$uid] = new VCalendar();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->objects[$uid]->add(clone $component);
|
$this->objects[$uid]->add(clone $component);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
namespace Sabre\VObject\Splitter;
|
namespace Sabre\VObject\Splitter;
|
||||||
|
|
||||||
use Sabre\VObject;
|
use
|
||||||
|
Sabre\VObject,
|
||||||
|
Sabre\VObject\Parser\MimeDir;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Splitter
|
* Splitter
|
||||||
|
|
@ -27,16 +29,25 @@ class VCard implements SplitterInterface {
|
||||||
*/
|
*/
|
||||||
protected $input;
|
protected $input;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persistent parser
|
||||||
|
*
|
||||||
|
* @var MimeDir
|
||||||
|
*/
|
||||||
|
protected $parser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* The splitter should receive an readable file stream as it's input.
|
* The splitter should receive an readable file stream as it's input.
|
||||||
*
|
*
|
||||||
* @param resource $input
|
* @param resource $input
|
||||||
|
* @param int $options Parser options, see the OPTIONS constants.
|
||||||
*/
|
*/
|
||||||
public function __construct($input) {
|
public function __construct($input, $options = 0) {
|
||||||
|
|
||||||
$this->input = $input;
|
$this->input = $input;
|
||||||
|
$this->parser = new MimeDir($input, $options);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,23 +61,10 @@ class VCard implements SplitterInterface {
|
||||||
*/
|
*/
|
||||||
public function getNext() {
|
public function getNext() {
|
||||||
|
|
||||||
$vcard = '';
|
try {
|
||||||
|
$object = $this->parser->parse();
|
||||||
do {
|
} catch (VObject\EofException $e) {
|
||||||
|
return null;
|
||||||
if (feof($this->input)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$line = fgets($this->input);
|
|
||||||
$vcard .= $line;
|
|
||||||
|
|
||||||
} while(strtoupper(substr($line,0,4))!=="END:");
|
|
||||||
|
|
||||||
$object = VObject\Reader::read($vcard);
|
|
||||||
|
|
||||||
if($object->name !== 'VCARD') {
|
|
||||||
throw new \InvalidArgumentException("Thats no vCard!", 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $object;
|
return $object;
|
||||||
|
|
|
||||||
|
|
@ -452,7 +452,7 @@ class TimeZoneUtil {
|
||||||
// Microsoft may add a magic number, which we also have an
|
// Microsoft may add a magic number, which we also have an
|
||||||
// answer for.
|
// answer for.
|
||||||
if (isset($vtimezone->{'X-MICROSOFT-CDO-TZID'})) {
|
if (isset($vtimezone->{'X-MICROSOFT-CDO-TZID'})) {
|
||||||
$cdoId = (int)$vtimezone->{'X-MICROSOFT-CDO-TZID'}->value;
|
$cdoId = (int)$vtimezone->{'X-MICROSOFT-CDO-TZID'}->getValue();
|
||||||
|
|
||||||
// 2 can mean both Europe/Lisbon and Europe/Sarajevo.
|
// 2 can mean both Europe/Lisbon and Europe/Sarajevo.
|
||||||
if ($cdoId===2 && strpos((string)$vtimezone->TZID, 'Sarajevo')!==false) {
|
if ($cdoId===2 && strpos((string)$vtimezone->TZID, 'Sarajevo')!==false) {
|
||||||
|
|
|
||||||
382
rainloop/v/0.0.0/app/libraries/Sabre/VObject/VCardConverter.php
Normal file
382
rainloop/v/0.0.0/app/libraries/Sabre/VObject/VCardConverter.php
Normal file
|
|
@ -0,0 +1,382 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\VObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This utility converts vcards from one version to another.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||||
|
*/
|
||||||
|
class VCardConverter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a vCard object to a new version.
|
||||||
|
*
|
||||||
|
* targetVersion must be one of:
|
||||||
|
* Document::VCARD21
|
||||||
|
* Document::VCARD30
|
||||||
|
* Document::VCARD40
|
||||||
|
*
|
||||||
|
* Currently only 3.0 and 4.0 as input and output versions.
|
||||||
|
*
|
||||||
|
* 2.1 has some minor support for the input version, it's incomplete at the
|
||||||
|
* moment though.
|
||||||
|
*
|
||||||
|
* If input and output version are identical, a clone is returned.
|
||||||
|
*
|
||||||
|
* @param Component\VCard $input
|
||||||
|
* @param int $targetVersion
|
||||||
|
*/
|
||||||
|
public function convert(Component\VCard $input, $targetVersion) {
|
||||||
|
|
||||||
|
$inputVersion = $input->getDocumentType();
|
||||||
|
if ($inputVersion===$targetVersion) {
|
||||||
|
return clone $input;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!in_array($inputVersion, array(Document::VCARD21, Document::VCARD30, Document::VCARD40))) {
|
||||||
|
throw new \InvalidArgumentException('Only vCard 2.1, 3.0 and 4.0 are supported for the input data');
|
||||||
|
}
|
||||||
|
if (!in_array($targetVersion, array(Document::VCARD30, Document::VCARD40))) {
|
||||||
|
throw new \InvalidArgumentException('You can only use vCard 3.0 or 4.0 for the target version');
|
||||||
|
}
|
||||||
|
|
||||||
|
$newVersion = $targetVersion===Document::VCARD40?'4.0':'3.0';
|
||||||
|
|
||||||
|
$output = new Component\VCard(array(
|
||||||
|
'VERSION' => $newVersion,
|
||||||
|
));
|
||||||
|
|
||||||
|
foreach($input->children as $property) {
|
||||||
|
|
||||||
|
$this->convertProperty($input, $output, $property, $targetVersion);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles conversion of a single property.
|
||||||
|
*
|
||||||
|
* @param Component\VCard $input
|
||||||
|
* @param Component\VCard $output
|
||||||
|
* @param Property $property
|
||||||
|
* @param int $targetVersion
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function convertProperty(Component\VCard $input, Component\VCard $output, Property $property, $targetVersion) {
|
||||||
|
|
||||||
|
// Skipping these, those are automatically added.
|
||||||
|
if (in_array($property->name, array('VERSION', 'PRODID'))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parameters = $property->parameters();
|
||||||
|
|
||||||
|
$valueType = null;
|
||||||
|
if (isset($parameters['VALUE'])) {
|
||||||
|
$valueType = $parameters['VALUE']->getValue();
|
||||||
|
unset($parameters['VALUE']);
|
||||||
|
}
|
||||||
|
if (!$valueType) {
|
||||||
|
$valueType = $property->getValueType();
|
||||||
|
}
|
||||||
|
|
||||||
|
$newProperty = null;
|
||||||
|
|
||||||
|
if ($targetVersion===Document::VCARD30) {
|
||||||
|
|
||||||
|
if ($property instanceof Property\Uri && in_array($property->name, array('PHOTO','LOGO','SOUND'))) {
|
||||||
|
|
||||||
|
$newProperty = $this->convertUriToBinary($output, $property, $parameters);
|
||||||
|
|
||||||
|
} elseif ($property->name === 'KIND') {
|
||||||
|
|
||||||
|
switch(strtolower($property->getValue())) {
|
||||||
|
case 'org' :
|
||||||
|
// OS X addressbook property.
|
||||||
|
$newProperty = $output->createProperty('X-ABSHOWAS','COMPANY');
|
||||||
|
break;
|
||||||
|
case 'individual' :
|
||||||
|
// Individual is implied, so we can just skip it.
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 'group' :
|
||||||
|
// OS X addressbook property
|
||||||
|
$newProperty = $output->createProperty('X-ADDRESSBOOKSERVER-KIND','GROUP');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} elseif ($targetVersion===Document::VCARD40) {
|
||||||
|
|
||||||
|
// These properties were removed in vCard 4.0
|
||||||
|
if (in_array($property->name, array('NAME', 'MAILER', 'LABEL', 'CLASS'))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($property instanceOf Property\Binary) {
|
||||||
|
|
||||||
|
$newProperty = $this->convertBinaryToUri($output, $property, $parameters);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
switch($property->name) {
|
||||||
|
case 'X-ABSHOWAS' :
|
||||||
|
if (strtoupper($property->getValue()) === 'COMPANY') {
|
||||||
|
$newProperty = $output->createProperty('KIND','org');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'X-ADDRESSBOOKSERVER-KIND' :
|
||||||
|
if (strtoupper($property->getValue()) === 'GROUP') {
|
||||||
|
$newProperty = $output->createProperty('KIND','group');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (is_null($newProperty)) {
|
||||||
|
|
||||||
|
$newProperty = $output->createProperty(
|
||||||
|
$property->name,
|
||||||
|
$property->getParts(),
|
||||||
|
array(), // no parameters yet
|
||||||
|
$valueType
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// set property group
|
||||||
|
$newProperty->group = $property->group;
|
||||||
|
|
||||||
|
if ($targetVersion===Document::VCARD40) {
|
||||||
|
$this->convertParameters40($newProperty, $parameters);
|
||||||
|
} else {
|
||||||
|
$this->convertParameters30($newProperty, $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lastly, we need to see if there's a need for a VALUE parameter.
|
||||||
|
//
|
||||||
|
// We can do that by instantating a empty property with that name, and
|
||||||
|
// seeing if the default valueType is identical to the current one.
|
||||||
|
$tempProperty = $output->createProperty($newProperty->name);
|
||||||
|
if ($tempProperty->getValueType() !== $newProperty->getValueType()) {
|
||||||
|
$newProperty['VALUE'] = $newProperty->getValueType();
|
||||||
|
}
|
||||||
|
|
||||||
|
$output->add($newProperty);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a BINARY property to a URI property.
|
||||||
|
*
|
||||||
|
* vCard 4.0 no longer supports BINARY properties.
|
||||||
|
*
|
||||||
|
* @param Component\VCard $output
|
||||||
|
* @param Property\Uri $property The input property.
|
||||||
|
* @param $parameters List of parameters that will eventually be added to
|
||||||
|
* the new property.
|
||||||
|
* @return Property\Uri
|
||||||
|
*/
|
||||||
|
protected function convertBinaryToUri(Component\VCard $output, Property\Binary $property, array &$parameters) {
|
||||||
|
|
||||||
|
$newProperty = $output->createProperty(
|
||||||
|
$property->name,
|
||||||
|
null, // no value
|
||||||
|
array(), // no parameters yet
|
||||||
|
'URI' // Forcing the BINARY type
|
||||||
|
);
|
||||||
|
|
||||||
|
$mimeType = 'application/octet-stream';
|
||||||
|
|
||||||
|
// See if we can find a better mimetype.
|
||||||
|
if (isset($parameters['TYPE'])) {
|
||||||
|
|
||||||
|
$newTypes = array();
|
||||||
|
foreach($parameters['TYPE']->getParts() as $typePart) {
|
||||||
|
if (in_array(
|
||||||
|
strtoupper($typePart),
|
||||||
|
array('JPEG','PNG','GIF')
|
||||||
|
)) {
|
||||||
|
$mimeType = 'image/' . strtolower($typePart);
|
||||||
|
} else {
|
||||||
|
$newTypes[] = $typePart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there were any parameters we're not converting to a
|
||||||
|
// mime-type, we need to keep them.
|
||||||
|
if ($newTypes) {
|
||||||
|
$parameters['TYPE']->setParts($newTypes);
|
||||||
|
} else {
|
||||||
|
unset($parameters['TYPE']);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$newProperty->setValue('data:' . $mimeType . ';base64,' . base64_encode($property->getValue()));
|
||||||
|
|
||||||
|
return $newProperty;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a URI property to a BINARY property.
|
||||||
|
*
|
||||||
|
* In vCard 4.0 attachments are encoded as data: uri. Even though these may
|
||||||
|
* be valid in vCard 3.0 as well, we should convert those to BINARY if
|
||||||
|
* possible, to improve compatibility.
|
||||||
|
*
|
||||||
|
* @param Component\VCard $output
|
||||||
|
* @param Property\Uri $property The input property.
|
||||||
|
* @param $parameters List of parameters that will eventually be added to
|
||||||
|
* the new property.
|
||||||
|
* @return Property\Binary|null
|
||||||
|
*/
|
||||||
|
protected function convertUriToBinary(Component\VCard $output, Property\Uri $property, array &$parameters) {
|
||||||
|
|
||||||
|
$value = $property->getValue();
|
||||||
|
|
||||||
|
// Only converting data: uris
|
||||||
|
if (substr($value, 0, 5)!=='data:') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$newProperty = $output->createProperty(
|
||||||
|
$property->name,
|
||||||
|
null, // no value
|
||||||
|
array(), // no parameters yet
|
||||||
|
'BINARY'
|
||||||
|
);
|
||||||
|
|
||||||
|
$mimeType = substr($value, 5, strpos($value, ',')-5);
|
||||||
|
if (strpos($mimeType, ';')) {
|
||||||
|
$mimeType = substr($mimeType,0,strpos($mimeType, ';'));
|
||||||
|
$newProperty->setValue(base64_decode(substr($value, strpos($value,',')+1)));
|
||||||
|
} else {
|
||||||
|
$newProperty->setValue(substr($value, strpos($value,',')+1));
|
||||||
|
}
|
||||||
|
unset($value);
|
||||||
|
|
||||||
|
$newProperty['ENCODING'] = 'b';
|
||||||
|
switch($mimeType) {
|
||||||
|
|
||||||
|
case 'image/jpeg' :
|
||||||
|
$newProperty['TYPE'] = 'JPEG';
|
||||||
|
break;
|
||||||
|
case 'image/png' :
|
||||||
|
$newProperty['TYPE'] = 'PNG';
|
||||||
|
break;
|
||||||
|
case 'image/gif' :
|
||||||
|
$newProperty['TYPE'] = 'GIF';
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return $newProperty;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds parameters to a new property for vCard 4.0
|
||||||
|
*
|
||||||
|
* @param Property $newProperty
|
||||||
|
* @param array $parameters
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function convertParameters40(Property $newProperty, array $parameters) {
|
||||||
|
|
||||||
|
// Adding all parameters.
|
||||||
|
foreach($parameters as $param) {
|
||||||
|
|
||||||
|
// vCard 2.1 allowed parameters with no name
|
||||||
|
if ($param->noName) $param->noName = false;
|
||||||
|
|
||||||
|
switch($param->name) {
|
||||||
|
|
||||||
|
// We need to see if there's any TYPE=PREF, because in vCard 4
|
||||||
|
// that's now PREF=1.
|
||||||
|
case 'TYPE' :
|
||||||
|
foreach($param->getParts() as $paramPart) {
|
||||||
|
|
||||||
|
if (strtoupper($paramPart)==='PREF') {
|
||||||
|
$newProperty->add('PREF','1');
|
||||||
|
} else {
|
||||||
|
$newProperty->add($param->name, $paramPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// These no longer exist in vCard 4
|
||||||
|
case 'ENCODING' :
|
||||||
|
case 'CHARSET' :
|
||||||
|
break;
|
||||||
|
|
||||||
|
default :
|
||||||
|
$newProperty->add($param->name, $param->getParts());
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds parameters to a new property for vCard 3.0
|
||||||
|
*
|
||||||
|
* @param Property $newProperty
|
||||||
|
* @param array $parameters
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function convertParameters30(Property $newProperty, array $parameters) {
|
||||||
|
|
||||||
|
// Adding all parameters.
|
||||||
|
foreach($parameters as $param) {
|
||||||
|
|
||||||
|
// vCard 2.1 allowed parameters with no name
|
||||||
|
if ($param->noName) $param->noName = false;
|
||||||
|
|
||||||
|
switch($param->name) {
|
||||||
|
|
||||||
|
case 'ENCODING' :
|
||||||
|
// This value only existed in vCard 2.1, and should be
|
||||||
|
// removed for anything else.
|
||||||
|
if (strtoupper($param->getValue())!=='QUOTED-PRINTABLE') {
|
||||||
|
$newProperty->add($param->name, $param->getParts());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Converting PREF=1 to TYPE=PREF.
|
||||||
|
*
|
||||||
|
* Any other PREF numbers we'll drop.
|
||||||
|
*/
|
||||||
|
case 'PREF' :
|
||||||
|
if ($param->getValue()=='1') {
|
||||||
|
$newProperty->add('TYPE','PREF');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default :
|
||||||
|
$newProperty->add($param->name, $param->getParts());
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,11 +14,6 @@ class Version {
|
||||||
/**
|
/**
|
||||||
* Full version number
|
* Full version number
|
||||||
*/
|
*/
|
||||||
const VERSION = '2.1.3';
|
const VERSION = '3.1.3';
|
||||||
|
|
||||||
/**
|
|
||||||
* Stability : alpha, beta, stable
|
|
||||||
*/
|
|
||||||
const STABILITY = 'stable';
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,30 +12,55 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Begin includes
|
// Begin includes
|
||||||
|
include __DIR__ . '/Cli.php';
|
||||||
include __DIR__ . '/DateTimeParser.php';
|
include __DIR__ . '/DateTimeParser.php';
|
||||||
include __DIR__ . '/ElementList.php';
|
include __DIR__ . '/ElementList.php';
|
||||||
include __DIR__ . '/FreeBusyGenerator.php';
|
include __DIR__ . '/FreeBusyGenerator.php';
|
||||||
include __DIR__ . '/Node.php';
|
include __DIR__ . '/Node.php';
|
||||||
include __DIR__ . '/Parameter.php';
|
include __DIR__ . '/Parameter.php';
|
||||||
include __DIR__ . '/ParseException.php';
|
include __DIR__ . '/ParseException.php';
|
||||||
|
include __DIR__ . '/Parser/Parser.php';
|
||||||
include __DIR__ . '/Property.php';
|
include __DIR__ . '/Property.php';
|
||||||
include __DIR__ . '/Reader.php';
|
include __DIR__ . '/Reader.php';
|
||||||
include __DIR__ . '/RecurrenceIterator.php';
|
include __DIR__ . '/RecurrenceIterator.php';
|
||||||
include __DIR__ . '/Splitter/SplitterInterface.php';
|
include __DIR__ . '/Splitter/SplitterInterface.php';
|
||||||
|
include __DIR__ . '/Splitter/VCard.php';
|
||||||
include __DIR__ . '/StringUtil.php';
|
include __DIR__ . '/StringUtil.php';
|
||||||
include __DIR__ . '/TimeZoneUtil.php';
|
include __DIR__ . '/TimeZoneUtil.php';
|
||||||
|
include __DIR__ . '/VCardConverter.php';
|
||||||
include __DIR__ . '/Version.php';
|
include __DIR__ . '/Version.php';
|
||||||
include __DIR__ . '/Splitter/VCard.php';
|
|
||||||
include __DIR__ . '/Component.php';
|
include __DIR__ . '/Component.php';
|
||||||
include __DIR__ . '/Document.php';
|
include __DIR__ . '/Document.php';
|
||||||
include __DIR__ . '/Property/Compound.php';
|
include __DIR__ . '/EofException.php';
|
||||||
include __DIR__ . '/Property/DateTime.php';
|
include __DIR__ . '/Parser/Json.php';
|
||||||
include __DIR__ . '/Property/MultiDateTime.php';
|
include __DIR__ . '/Parser/MimeDir.php';
|
||||||
|
include __DIR__ . '/Property/Binary.php';
|
||||||
|
include __DIR__ . '/Property/Boolean.php';
|
||||||
|
include __DIR__ . '/Property/Float.php';
|
||||||
|
include __DIR__ . '/Property/ICalendar/DateTime.php';
|
||||||
|
include __DIR__ . '/Property/ICalendar/Duration.php';
|
||||||
|
include __DIR__ . '/Property/ICalendar/Period.php';
|
||||||
|
include __DIR__ . '/Property/ICalendar/Recur.php';
|
||||||
|
include __DIR__ . '/Property/Integer.php';
|
||||||
|
include __DIR__ . '/Property/Text.php';
|
||||||
|
include __DIR__ . '/Property/Time.php';
|
||||||
|
include __DIR__ . '/Property/Unknown.php';
|
||||||
|
include __DIR__ . '/Property/Uri.php';
|
||||||
|
include __DIR__ . '/Property/UtcOffset.php';
|
||||||
|
include __DIR__ . '/Property/VCard/DateAndOrTime.php';
|
||||||
|
include __DIR__ . '/Property/VCard/DateTime.php';
|
||||||
|
include __DIR__ . '/Property/VCard/LanguageTag.php';
|
||||||
|
include __DIR__ . '/Property/VCard/TimeStamp.php';
|
||||||
include __DIR__ . '/Splitter/ICalendar.php';
|
include __DIR__ . '/Splitter/ICalendar.php';
|
||||||
include __DIR__ . '/Component/VAlarm.php';
|
include __DIR__ . '/Component/VAlarm.php';
|
||||||
include __DIR__ . '/Component/VCalendar.php';
|
include __DIR__ . '/Component/VCalendar.php';
|
||||||
|
include __DIR__ . '/Component/VCard.php';
|
||||||
include __DIR__ . '/Component/VEvent.php';
|
include __DIR__ . '/Component/VEvent.php';
|
||||||
include __DIR__ . '/Component/VFreeBusy.php';
|
include __DIR__ . '/Component/VFreeBusy.php';
|
||||||
include __DIR__ . '/Component/VJournal.php';
|
include __DIR__ . '/Component/VJournal.php';
|
||||||
include __DIR__ . '/Component/VTodo.php';
|
include __DIR__ . '/Component/VTodo.php';
|
||||||
|
include __DIR__ . '/Property/FlatText.php';
|
||||||
|
include __DIR__ . '/Property/ICalendar/CalAddress.php';
|
||||||
|
include __DIR__ . '/Property/ICalendar/Date.php';
|
||||||
|
include __DIR__ . '/Property/VCard/Date.php';
|
||||||
// End includes
|
// End includes
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@
|
||||||
{{ErrorDesc}}
|
{{ErrorDesc}}
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<div style="display: {{BackLinkVisibility}}">
|
<div style="{{BackLinkVisibilityStyle}}">
|
||||||
<br />
|
<br />
|
||||||
<a href="{{BackHref}}">{{BackLink}}</a>
|
<a href="{{BackHref}}">{{BackLink}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -96,8 +96,7 @@
|
||||||
<div class="form-horizontal top-part">
|
<div class="form-horizontal top-part">
|
||||||
<div class="control-group" data-bind="visible: !viewReadOnly() || 0 < viewPropertiesEmailsNonEmpty().length">
|
<div class="control-group" data-bind="visible: !viewReadOnly() || 0 < viewPropertiesEmailsNonEmpty().length">
|
||||||
<label class="control-label remove-padding-top fix-width">
|
<label class="control-label remove-padding-top fix-width">
|
||||||
|
<i class="icon-user iconsize24"></i>
|
||||||
<i class="icon-user iconsize24" data-placement="left" data-bind="tooltip: 'CONTACTS/LABEL_DISPLAY_NAME'"></i>
|
|
||||||
</label>
|
</label>
|
||||||
<div class="controls fix-width" data-bind="foreach: viewPropertiesNames">
|
<div class="controls fix-width" data-bind="foreach: viewPropertiesNames">
|
||||||
<div class="property-line">
|
<div class="property-line">
|
||||||
|
|
@ -153,9 +152,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="e-save-trigger">
|
<!-- <div class="e-save-trigger">
|
||||||
<div data-bind="saveTrigger: viewSaveTrigger"></div>
|
<div data-bind="saveTrigger: viewSaveTrigger"></div>
|
||||||
</div>
|
</div>-->
|
||||||
|
|
||||||
<div class="e-read-only-sign">
|
<div class="e-read-only-sign">
|
||||||
<i class="icon-lock iconsize24" data-placement="left" data-bind="tooltip: 'CONTACTS/LABEL_READ_ONLY'"></i>
|
<i class="icon-lock iconsize24" data-placement="left" data-bind="tooltip: 'CONTACTS/LABEL_READ_ONLY'"></i>
|
||||||
|
|
@ -187,12 +186,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <button class="btn button-save-contact" data-bind="command: saveCommand">
|
<button class="btn button-save-contact" data-bind="command: saveCommand, css: {'dirty': watchDirty}">
|
||||||
<i data-bind="css: {'icon-ok': !viewSaving(), 'icon-spinner animated': viewSaving()}"></i>
|
<i data-bind="css: {'icon-ok': !viewSaving(), 'icon-spinner animated': viewSaving()}"></i>
|
||||||
|
|
||||||
<span class="i18n" data-i18n-text="CONTACTS/BUTTON_CREATE_CONTACT" data-bind="visible: '' === viewID()"></span>
|
<span class="i18n" data-i18n-text="CONTACTS/BUTTON_CREATE_CONTACT" data-bind="visible: '' === viewID()"></span>
|
||||||
<span class="i18n" data-i18n-text="CONTACTS/BUTTON_UPDATE_CONTACT" data-bind="visible: '' !== viewID()"></span>
|
<span class="i18n" data-i18n-text="CONTACTS/BUTTON_UPDATE_CONTACT" data-bind="visible: '' !== viewID()"></span>
|
||||||
</button>-->
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,8 @@ LABEL_PHONE = "Phone"
|
||||||
LINK_ADD_EMAIL = "Add an email address"
|
LINK_ADD_EMAIL = "Add an email address"
|
||||||
LINK_ADD_PHONE = "Add a phone"
|
LINK_ADD_PHONE = "Add a phone"
|
||||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Enter display name"
|
PLACEHOLDER_ENTER_DISPLAY_NAME = "Enter display name"
|
||||||
|
PLACEHOLDER_ENTER_LAST_NAME = "Enter last name"
|
||||||
|
PLACEHOLDER_ENTER_FIRST_NAME = "Enter first name"
|
||||||
LABEL_READ_ONLY = "Read only"
|
LABEL_READ_ONLY = "Read only"
|
||||||
LABEL_SHARE = "Share"
|
LABEL_SHARE = "Share"
|
||||||
BUTTON_SHARE_NONE = "None"
|
BUTTON_SHARE_NONE = "None"
|
||||||
|
|
|
||||||
|
|
@ -7345,8 +7345,8 @@ html.rl-message-fullscreen .messageView .b-content .buttonFull {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
.b-contacts-content.modal .b-view-content .add-link {
|
.b-contacts-content.modal .b-view-content .add-link {
|
||||||
padding-top: 5px;
|
margin-left: 2px;
|
||||||
padding-left: 7px;
|
padding: 5px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
}
|
}
|
||||||
|
|
@ -7391,15 +7391,18 @@ html.rl-message-fullscreen .messageView .b-content .buttonFull {
|
||||||
}
|
}
|
||||||
.b-contacts-content.modal .b-view-content .e-share-sign {
|
.b-contacts-content.modal .b-view-content .e-share-sign {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 20px;
|
top: 60px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.b-contacts-content.modal .b-view-content .button-save-contact {
|
.b-contacts-content.modal .b-view-content .button-save-contact {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 100px;
|
top: 20px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
}
|
}
|
||||||
|
.b-contacts-content.modal .b-view-content .button-save-contact.dirty {
|
||||||
|
color: #51a351;
|
||||||
|
}
|
||||||
.b-contacts-content.modal .b-view-content.read-only .e-read-only-sign {
|
.b-contacts-content.modal .b-view-content.read-only .e-read-only-sign {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
rainloop/v/0.0.0/static/css/app.min.css
vendored
2
rainloop/v/0.0.0/static/css/app.min.css
vendored
File diff suppressed because one or more lines are too long
|
|
@ -508,31 +508,30 @@ Enums.ContactPropertyType = {
|
||||||
'FullName': 10,
|
'FullName': 10,
|
||||||
|
|
||||||
'FirstName': 15,
|
'FirstName': 15,
|
||||||
'SurName': 16,
|
'LastName': 16,
|
||||||
'MiddleName': 17,
|
'MiddleName': 16,
|
||||||
'Nick': 18,
|
'Nick': 18,
|
||||||
|
|
||||||
|
'NamePrefix': 20,
|
||||||
|
'NameSuffix': 21,
|
||||||
|
|
||||||
'EmailPersonal': 30,
|
'EmailPersonal': 30,
|
||||||
'EmailBussines': 31,
|
'EmailBussines': 31,
|
||||||
'EmailOther': 32,
|
|
||||||
|
|
||||||
'PhonePersonal': 50,
|
'PhonePersonal': 50,
|
||||||
'PhoneBussines': 51,
|
'PhoneBussines': 51,
|
||||||
'PhoneOther': 52,
|
|
||||||
|
|
||||||
'MobilePersonal': 60,
|
'MobilePersonal': 60,
|
||||||
'MobileBussines': 61,
|
'MobileBussines': 61,
|
||||||
'MobileOther': 62,
|
|
||||||
|
|
||||||
'FaxPesonal': 70,
|
'FaxPesonal': 70,
|
||||||
'FaxBussines': 71,
|
'FaxBussines': 71,
|
||||||
'FaxOther': 72,
|
|
||||||
|
|
||||||
'Facebook': 90,
|
'Facebook': 90,
|
||||||
'Skype': 91,
|
'Skype': 91,
|
||||||
'GitHub': 92,
|
'GitHub': 92,
|
||||||
|
|
||||||
'Description': 110,
|
'Note': 110,
|
||||||
|
|
||||||
'Custom': 250
|
'Custom': 250
|
||||||
};
|
};
|
||||||
|
|
|
||||||
2
rainloop/v/0.0.0/static/js/admin.min.js
vendored
2
rainloop/v/0.0.0/static/js/admin.min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -508,31 +508,30 @@ Enums.ContactPropertyType = {
|
||||||
'FullName': 10,
|
'FullName': 10,
|
||||||
|
|
||||||
'FirstName': 15,
|
'FirstName': 15,
|
||||||
'SurName': 16,
|
'LastName': 16,
|
||||||
'MiddleName': 17,
|
'MiddleName': 16,
|
||||||
'Nick': 18,
|
'Nick': 18,
|
||||||
|
|
||||||
|
'NamePrefix': 20,
|
||||||
|
'NameSuffix': 21,
|
||||||
|
|
||||||
'EmailPersonal': 30,
|
'EmailPersonal': 30,
|
||||||
'EmailBussines': 31,
|
'EmailBussines': 31,
|
||||||
'EmailOther': 32,
|
|
||||||
|
|
||||||
'PhonePersonal': 50,
|
'PhonePersonal': 50,
|
||||||
'PhoneBussines': 51,
|
'PhoneBussines': 51,
|
||||||
'PhoneOther': 52,
|
|
||||||
|
|
||||||
'MobilePersonal': 60,
|
'MobilePersonal': 60,
|
||||||
'MobileBussines': 61,
|
'MobileBussines': 61,
|
||||||
'MobileOther': 62,
|
|
||||||
|
|
||||||
'FaxPesonal': 70,
|
'FaxPesonal': 70,
|
||||||
'FaxBussines': 71,
|
'FaxBussines': 71,
|
||||||
'FaxOther': 72,
|
|
||||||
|
|
||||||
'Facebook': 90,
|
'Facebook': 90,
|
||||||
'Skype': 91,
|
'Skype': 91,
|
||||||
'GitHub': 92,
|
'GitHub': 92,
|
||||||
|
|
||||||
'Description': 110,
|
'Note': 110,
|
||||||
|
|
||||||
'Custom': 250
|
'Custom': 250
|
||||||
};
|
};
|
||||||
|
|
@ -9311,7 +9310,7 @@ function PopupsContactsViewModel()
|
||||||
var
|
var
|
||||||
self = this,
|
self = this,
|
||||||
oT = Enums.ContactPropertyType,
|
oT = Enums.ContactPropertyType,
|
||||||
aNameTypes = [oT.FullName, oT.FirstName, oT.SurName, oT.MiddleName],
|
aNameTypes = [oT.FirstName, oT.LastName],
|
||||||
aEmailTypes = [oT.EmailPersonal, oT.EmailBussines, oT.EmailOther],
|
aEmailTypes = [oT.EmailPersonal, oT.EmailBussines, oT.EmailOther],
|
||||||
aPhonesTypes = [
|
aPhonesTypes = [
|
||||||
oT.PhonePersonal, oT.PhoneBussines, oT.PhoneOther,
|
oT.PhonePersonal, oT.PhoneBussines, oT.PhoneOther,
|
||||||
|
|
@ -9567,6 +9566,8 @@ function PopupsContactsViewModel()
|
||||||
|
|
||||||
if (bRes)
|
if (bRes)
|
||||||
{
|
{
|
||||||
|
self.watchDirty(false);
|
||||||
|
|
||||||
_.delay(function () {
|
_.delay(function () {
|
||||||
self.viewSaveTrigger(Enums.SaveSettingsStep.Idle);
|
self.viewSaveTrigger(Enums.SaveSettingsStep.Idle);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
@ -9584,19 +9585,21 @@ function PopupsContactsViewModel()
|
||||||
|
|
||||||
this.bDropPageAfterDelete = false;
|
this.bDropPageAfterDelete = false;
|
||||||
|
|
||||||
|
this.watchDirty = ko.observable(false);
|
||||||
this.watchHash = ko.observable(false);
|
this.watchHash = ko.observable(false);
|
||||||
|
|
||||||
this.viewHash = ko.computed(function () {
|
this.viewHash = ko.computed(function () {
|
||||||
return '' + self.viewScopeType() + ' - ' + _.map(self.viewProperties(), function (oItem) {
|
return '' + self.viewScopeType() + ' - ' + _.map(self.viewProperties(), function (oItem) {
|
||||||
return oItem.value();
|
return oItem.value();
|
||||||
}).join('');
|
}).join('');
|
||||||
});
|
});
|
||||||
|
|
||||||
this.saveCommandDebounce = _.debounce(_.bind(this.saveCommand, this), 1000);
|
// this.saveCommandDebounce = _.debounce(_.bind(this.saveCommand, this), 1000);
|
||||||
|
|
||||||
this.viewHash.subscribe(function () {
|
this.viewHash.subscribe(function () {
|
||||||
if (this.watchHash() && !this.viewReadOnly())
|
if (this.watchHash() && !this.viewReadOnly() && !this.watchDirty())
|
||||||
{
|
{
|
||||||
this.saveCommandDebounce();
|
this.watchDirty(true);
|
||||||
}
|
}
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
|
|
@ -9629,7 +9632,7 @@ PopupsContactsViewModel.prototype.addNewEmail = function ()
|
||||||
|
|
||||||
PopupsContactsViewModel.prototype.addNewPhone = function ()
|
PopupsContactsViewModel.prototype.addNewPhone = function ()
|
||||||
{
|
{
|
||||||
this.addNewProperty(Enums.ContactPropertyType.PhonePersonal);
|
this.addNewProperty(Enums.ContactPropertyType.MobilePersonal);
|
||||||
};
|
};
|
||||||
|
|
||||||
PopupsContactsViewModel.prototype.removeCheckedOrSelectedContactsFromList = function ()
|
PopupsContactsViewModel.prototype.removeCheckedOrSelectedContactsFromList = function ()
|
||||||
|
|
@ -9717,7 +9720,8 @@ PopupsContactsViewModel.prototype.populateViewContact = function (oContact)
|
||||||
var
|
var
|
||||||
sId = '',
|
sId = '',
|
||||||
sIdStr = '',
|
sIdStr = '',
|
||||||
bHasName = false,
|
sLastName = '',
|
||||||
|
sFirstName = '',
|
||||||
aList = []
|
aList = []
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
@ -9737,12 +9741,17 @@ PopupsContactsViewModel.prototype.populateViewContact = function (oContact)
|
||||||
_.each(oContact.properties, function (aProperty) {
|
_.each(oContact.properties, function (aProperty) {
|
||||||
if (aProperty && aProperty[0])
|
if (aProperty && aProperty[0])
|
||||||
{
|
{
|
||||||
aList.push(new ContactPropertyModel(aProperty[0], aProperty[1], false,
|
if (Enums.ContactPropertyType.LastName === aProperty[0])
|
||||||
Enums.ContactPropertyType.FullName === aProperty[0] ? 'CONTACTS/PLACEHOLDER_ENTER_DISPLAY_NAME' : ''));
|
|
||||||
|
|
||||||
if (Enums.ContactPropertyType.FullName === aProperty[0])
|
|
||||||
{
|
{
|
||||||
bHasName = true;
|
sLastName = aProperty[1];
|
||||||
|
}
|
||||||
|
else if (Enums.ContactPropertyType.FirstName === aProperty[0])
|
||||||
|
{
|
||||||
|
sFirstName = aProperty[1];
|
||||||
|
}
|
||||||
|
else if (-1 === Utils.inArray(aProperty[0], [Enums.ContactPropertyType.FullName]))
|
||||||
|
{
|
||||||
|
aList.push(new ContactPropertyModel(aProperty[0], aProperty[1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -9752,16 +9761,15 @@ PopupsContactsViewModel.prototype.populateViewContact = function (oContact)
|
||||||
this.viewScopeType(oContact.scopeType);
|
this.viewScopeType(oContact.scopeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bHasName)
|
aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.FirstName, sFirstName, false, 'CONTACTS/PLACEHOLDER_ENTER_FIRST_NAME'));
|
||||||
{
|
aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.LastName, sLastName, !oContact, 'CONTACTS/PLACEHOLDER_ENTER_LAST_NAME'));
|
||||||
aList.push(new ContactPropertyModel(Enums.ContactPropertyType.FullName, '', !oContact, 'CONTACTS/PLACEHOLDER_ENTER_DISPLAY_NAME'));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.viewID(sId);
|
this.viewID(sId);
|
||||||
this.viewIDStr(sIdStr);
|
this.viewIDStr(sIdStr);
|
||||||
this.viewProperties([]);
|
this.viewProperties([]);
|
||||||
this.viewProperties(aList);
|
this.viewProperties(aList);
|
||||||
|
|
||||||
|
this.watchDirty(false);
|
||||||
this.watchHash(true);
|
this.watchHash(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -15028,13 +15036,13 @@ WebMailAjaxRemoteStorage.prototype.contacts = function (fCallback, iOffset, iLim
|
||||||
/**
|
/**
|
||||||
* @param {?Function} fCallback
|
* @param {?Function} fCallback
|
||||||
*/
|
*/
|
||||||
WebMailAjaxRemoteStorage.prototype.contactSave = function (fCallback, sRequestUid, sUid, sUidStr, nScopeType, aProperties)
|
WebMailAjaxRemoteStorage.prototype.contactSave = function (fCallback, sRequestUid, sUid, sUidStr, iScopeType, aProperties)
|
||||||
{
|
{
|
||||||
this.defaultRequest(fCallback, 'ContactSave', {
|
this.defaultRequest(fCallback, 'ContactSave', {
|
||||||
'RequestUid': sRequestUid,
|
'RequestUid': sRequestUid,
|
||||||
'Uid': Utils.trim(sUid),
|
'Uid': Utils.trim(sUid),
|
||||||
'UidStr': Utils.trim(sUidStr),
|
'UidStr': Utils.trim(sUidStr),
|
||||||
'ScopeType': nScopeType,
|
'ScopeType': iScopeType,
|
||||||
'Properties': aProperties
|
'Properties': aProperties
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
12
rainloop/v/0.0.0/static/js/app.min.js
vendored
12
rainloop/v/0.0.0/static/js/app.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue