mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-06 16:07:03 +03:00
Improved #79
This commit is contained in:
parent
89107387d5
commit
910e7fbfd5
2 changed files with 58 additions and 80 deletions
|
|
@ -139,7 +139,7 @@ class PdoAddressBook
|
||||||
{
|
{
|
||||||
$aMatch = array();
|
$aMatch = array();
|
||||||
if (\preg_match('/\/([^\/?]+)$/', $sKey, $aMatch) && !empty($aMatch[1]) &&
|
if (\preg_match('/\/([^\/?]+)$/', $sKey, $aMatch) && !empty($aMatch[1]) &&
|
||||||
(!$aItem['{dav:}resourcetype'] || !$aItem['{dav:}resourcetype']->is('{DAV:}collection')))
|
(!$aItem['{dav:}resourcetype'] || !\in_array('{DAV:}collection', $aItem['{dav:}resourcetype'])))
|
||||||
{
|
{
|
||||||
$sVcfFileName = \urldecode(\urldecode($aMatch[1]));
|
$sVcfFileName = \urldecode(\urldecode($aMatch[1]));
|
||||||
$sKeyID = \preg_replace('/\.vcf$/i', '', $sVcfFileName);
|
$sKeyID = \preg_replace('/\.vcf$/i', '', $sVcfFileName);
|
||||||
|
|
@ -280,9 +280,7 @@ class PdoAddressBook
|
||||||
|
|
||||||
if (empty($sNextPath))
|
if (empty($sNextPath))
|
||||||
{
|
{
|
||||||
$oResourceType = isset($aItem['{DAV:}resourcetype']) ? $aItem['{DAV:}resourcetype'] : null;
|
if (isset($aItem['{DAV:}resourcetype']) && \in_array('{DAV:}collection', $aItem['{DAV:}resourcetype']))
|
||||||
/* @var $oResourceType \Sabre\DAV\Property\ResourceType */
|
|
||||||
if ($oResourceType && $oResourceType->is('{DAV:}collection'))
|
|
||||||
{
|
{
|
||||||
$sNextPath = $sKey;
|
$sNextPath = $sKey;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -403,15 +401,10 @@ class PdoAddressBook
|
||||||
{
|
{
|
||||||
if (!empty($sKey) && $aItem && isset($aItem['{DAV:}resourcetype']))
|
if (!empty($sKey) && $aItem && isset($aItem['{DAV:}resourcetype']))
|
||||||
{
|
{
|
||||||
$oResourceType = $aItem['{DAV:}resourcetype'];
|
if (\in_array('{DAV:}collection', $aItem['{DAV:}resourcetype'])
|
||||||
/* @var $oResourceType \Sabre\DAV\Property\ResourceType */
|
&& \in_array('{urn:ietf:params:xml:ns:carddav}addressbook', $aItem['{DAV:}resourcetype']))
|
||||||
|
|
||||||
if ($oResourceType && $oResourceType->is('{DAV:}collection'))
|
|
||||||
{
|
{
|
||||||
if ($oResourceType->is('{urn:ietf:params:xml:ns:carddav}addressbook'))
|
$aContactsPaths[$sKey] = isset($aItem['{DAV:}displayname']) ? \trim($aItem['{DAV:}displayname']) : '';
|
||||||
{
|
|
||||||
$aContactsPaths[$sKey] = isset($aItem['{DAV:}displayname']) ? \trim($aItem['{DAV:}displayname']) : '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -451,11 +444,8 @@ class PdoAddressBook
|
||||||
{
|
{
|
||||||
if (!empty($sKey) && isset($aItem['{DAV:}resourcetype']))
|
if (!empty($sKey) && isset($aItem['{DAV:}resourcetype']))
|
||||||
{
|
{
|
||||||
$oResourceType = $aItem['{DAV:}resourcetype'];
|
if (\in_array('{DAV:}collection', $aItem['{DAV:}resourcetype'])
|
||||||
/* @var $oResourceType \Sabre\DAV\Property\ResourceType */
|
&& \in_array('{urn:ietf:params:xml:ns:carddav}addressbook', $aItem['{DAV:}resourcetype']))
|
||||||
|
|
||||||
if ($oResourceType && $oResourceType->is('{DAV:}collection') &&
|
|
||||||
$oResourceType->is('{urn:ietf:params:xml:ns:carddav}addressbook'))
|
|
||||||
{
|
{
|
||||||
$bGood = true;
|
$bGood = true;
|
||||||
}
|
}
|
||||||
|
|
@ -471,7 +461,7 @@ class PdoAddressBook
|
||||||
return $bGood;
|
return $bGood;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDavClientFromUrl(string $sUrl, string $sUser, string $sPassword, string $sProxy = '') : DAVClient
|
private function getDavClientFromUrl(string $sUrl, string $sUser, string $sPassword, string $sProxy = '') : DAVClient
|
||||||
{
|
{
|
||||||
if (!\preg_match('/^http[s]?:\/\//i', $sUrl))
|
if (!\preg_match('/^http[s]?:\/\//i', $sUrl))
|
||||||
{
|
{
|
||||||
|
|
@ -515,7 +505,7 @@ class PdoAddressBook
|
||||||
return $oClient;
|
return $oClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDavClient(string $sUrl, string $sUser, string $sPassword, string $sProxy = '') : ?DAVClient
|
private function getDavClient(string $sUrl, string $sUser, string $sPassword, string $sProxy = '') : ?DAVClient
|
||||||
{
|
{
|
||||||
$aMatch = array();
|
$aMatch = array();
|
||||||
$sUserAddressBookNameName = '';
|
$sUserAddressBookNameName = '';
|
||||||
|
|
|
||||||
|
|
@ -10,21 +10,7 @@ namespace SnappyMail\DAV;
|
||||||
|
|
||||||
class Client
|
class Client
|
||||||
{
|
{
|
||||||
/**
|
// public $__UrlPath__;
|
||||||
* The propertyMap is a key-value array.
|
|
||||||
*
|
|
||||||
* If you use the propertyMap, any {DAV:}multistatus responses with the
|
|
||||||
* proeprties listed in this array, will automatically be mapped to a
|
|
||||||
* respective class.
|
|
||||||
*
|
|
||||||
* The {DAV:}resourcetype property is automatically added. This maps to
|
|
||||||
* Sabre\DAV\Property\ResourceType
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
public $propertyMap = array(
|
|
||||||
// '{DAV:}resourcetype' => 'SnappyMail\\DAV\\Property\\ResourceType'
|
|
||||||
);
|
|
||||||
|
|
||||||
protected $baseUri;
|
protected $baseUri;
|
||||||
|
|
||||||
|
|
@ -62,6 +48,40 @@ class Client
|
||||||
$this->HTTP->verify_peer = $value;
|
$this->HTTP->verify_peer = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs an actual HTTP request, and returns the result.
|
||||||
|
*
|
||||||
|
* If the specified url is relative, it will be expanded based on the base url.
|
||||||
|
*/
|
||||||
|
public function request(string $method, string $url = '', string $body = null, array $headers = array()) : \SnappyMail\HTTP\Response
|
||||||
|
{
|
||||||
|
if (!\preg_match('@^(https?:)?//@', $url)) {
|
||||||
|
// If the url starts with a slash, we must calculate the url based off
|
||||||
|
// the root of the base url.
|
||||||
|
if (0 === \strpos($url, '/')) {
|
||||||
|
$parts = \parse_url($this->baseUri);
|
||||||
|
$url = $parts['scheme'] . '://' . $parts['host'] . (isset($parts['port'])?':' . $parts['port']:'') . $url;
|
||||||
|
} else {
|
||||||
|
$url = $this->baseUri . $url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$response = $this->HTTP->doRequest('PROPFIND', $url, $body, $headers);
|
||||||
|
if (301 == $response->status) {
|
||||||
|
// Like: RewriteRule ^\.well-known/carddav /nextcloud/remote.php/dav [R=301,L]
|
||||||
|
$location = $response->getRedirectLocation();
|
||||||
|
\trigger_error("Redirect {$url} to {$location}");
|
||||||
|
$url = \preg_replace('@^(https?:)?//[^/]+[/$]@', '/', $location);
|
||||||
|
$parts = \parse_url($this->baseUri);
|
||||||
|
$url = $parts['scheme'] . '://' . $parts['host'] . (isset($parts['port'])?':' . $parts['port']:'') . $url;
|
||||||
|
$response = $this->HTTP->doRequest('PROPFIND', $url, $body, $headers);
|
||||||
|
}
|
||||||
|
if (300 <= $response->status) {
|
||||||
|
throw new \SnappyMail\HTTP\Exception("PROPFIND {$url}", $response->status, $response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does a PROPFIND request
|
* Does a PROPFIND request
|
||||||
*
|
*
|
||||||
|
|
@ -98,35 +118,10 @@ class Client
|
||||||
$body .= ' </d:prop>' . "\n";
|
$body .= ' </d:prop>' . "\n";
|
||||||
$body .= '</d:propfind>';
|
$body .= '</d:propfind>';
|
||||||
|
|
||||||
if (!\preg_match('@^(https?:)?//@', $url)) {
|
$response = $this->request('PROPFIND', $url, $body, array(
|
||||||
// If the url starts with a slash, we must calculate the url based off
|
|
||||||
// the root of the base url.
|
|
||||||
if (0 === \strpos($url, '/')) {
|
|
||||||
$parts = \parse_url($this->baseUri);
|
|
||||||
$url = $parts['scheme'] . '://' . $parts['host'] . (isset($parts['port'])?':' . $parts['port']:'') . $url;
|
|
||||||
} else {
|
|
||||||
$url = $this->baseUri . $url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$response = $this->HTTP->doRequest('PROPFIND', $url, $body, array(
|
|
||||||
"Depth: {$depth}",
|
"Depth: {$depth}",
|
||||||
'Content-Type: application/xml'
|
'Content-Type: application/xml'
|
||||||
));
|
));
|
||||||
if (301 == $response->status) {
|
|
||||||
// Like: RewriteRule ^\.well-known/carddav /nextcloud/remote.php/dav [R=301,L]
|
|
||||||
$location = $response->getRedirectLocation();
|
|
||||||
\trigger_error("Redirect {$url} to {$location}");
|
|
||||||
$url = \preg_replace('@^(https?:)?//[^/]+[/$]@', '/', $location);
|
|
||||||
$parts = \parse_url($this->baseUri);
|
|
||||||
$url = $parts['scheme'] . '://' . $parts['host'] . (isset($parts['port'])?':' . $parts['port']:'') . $url;
|
|
||||||
$response = $this->HTTP->doRequest('PROPFIND', $url, $body, array(
|
|
||||||
"Depth: {$depth}",
|
|
||||||
'Content-Type: application/xml'
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if (300 <= $response->status) {
|
|
||||||
throw new \SnappyMail\HTTP\Exception("PROPFIND {$url}", $response->status, $response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the WebDAV multistatus response body
|
* Parse the WebDAV multistatus response body
|
||||||
|
|
@ -148,26 +143,21 @@ class Client
|
||||||
throw new \InvalidArgumentException('The passed data is not valid XML');
|
throw new \InvalidArgumentException('The passed data is not valid XML');
|
||||||
}
|
}
|
||||||
|
|
||||||
$responseXML->registerXPathNamespace('d', 'urn:DAV');
|
$ns = \array_search('urn:DAV', $responseXML->getNamespaces(true));
|
||||||
|
// $ns_card = \array_search('urn:ietf:params:xml:ns:carddav', $responseXML->getNamespaces(true));
|
||||||
|
|
||||||
$result = array();
|
$result = array();
|
||||||
|
|
||||||
foreach ($responseXML->xpath('d:response') as $response) {
|
foreach ($responseXML->xpath("{$ns}:response") as $response) {
|
||||||
$response->registerXPathNamespace('d', 'urn:DAV');
|
$href = $response->xpath("{$ns}:href");
|
||||||
$href = $response->xpath('d:href');
|
|
||||||
$href = (string) $href[0];
|
$href = (string) $href[0];
|
||||||
|
|
||||||
$properties = array();
|
$properties = array();
|
||||||
|
foreach ($response->xpath("{$ns}:propstat") as $propStat) {
|
||||||
foreach ($response->xpath('d:propstat') as $propStat) {
|
$status = $propStat->xpath("{$ns}:status");
|
||||||
$propStat->registerXPathNamespace('d', 'urn:DAV');
|
|
||||||
$status = $propStat->xpath('d:status');
|
|
||||||
list($httpVersion, $statusCode, $message) = \explode(' ', (string)$status[0], 3);
|
list($httpVersion, $statusCode, $message) = \explode(' ', (string)$status[0], 3);
|
||||||
|
|
||||||
// Only using the propertymap for results with status 200.
|
$properties[$statusCode] = static::parseProperties(\dom_import_simplexml($propStat));
|
||||||
$propertyMap = $statusCode === '200' ? $this->propertyMap : array();
|
|
||||||
|
|
||||||
$properties[$statusCode] = static::parseProperties(\dom_import_simplexml($propStat), $propertyMap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$result[$href] = $properties;
|
$result[$href] = $properties;
|
||||||
|
|
@ -218,14 +208,10 @@ class Client
|
||||||
* If no value was given (self-closing element) null will be used as the
|
* If no value was given (self-closing element) null will be used as the
|
||||||
* value. This is used in for example PROPFIND requests.
|
* value. This is used in for example PROPFIND requests.
|
||||||
*
|
*
|
||||||
* Complex values are supported through the propertyMap argument. The
|
|
||||||
* propertyMap should have the clark-notation properties as it's keys, and
|
|
||||||
* classnames as values.
|
|
||||||
*
|
|
||||||
* When any of these properties are found, the fromDOMElement() method will be
|
* When any of these properties are found, the fromDOMElement() method will be
|
||||||
* (statically) called. The result of this method is used as the value.
|
* (statically) called. The result of this method is used as the value.
|
||||||
*/
|
*/
|
||||||
protected static function parseProperties(\DOMElement $parentNode, array $propertyMap = array()) : array
|
protected static function parseProperties(\DOMElement $parentNode) : array
|
||||||
{
|
{
|
||||||
$propList = array();
|
$propList = array();
|
||||||
foreach ($parentNode->childNodes as $propNode) {
|
foreach ($parentNode->childNodes as $propNode) {
|
||||||
|
|
@ -234,8 +220,11 @@ class Client
|
||||||
/* If there are no elements in here, we actually get 1 text node, this special case is dedicated to netdrive */
|
/* If there are no elements in here, we actually get 1 text node, this special case is dedicated to netdrive */
|
||||||
if (XML_ELEMENT_NODE == $propNodeData->nodeType) {
|
if (XML_ELEMENT_NODE == $propNodeData->nodeType) {
|
||||||
$propertyName = self::toClarkNotation($propNodeData);
|
$propertyName = self::toClarkNotation($propNodeData);
|
||||||
if (isset($propertyMap[$propertyName])) {
|
if ('{DAV:}resourcetype' === $propertyName) {
|
||||||
$propList[$propertyName] = \call_user_func(array($propertyMap[$propertyName], 'fromDOMElement'), $propNodeData);
|
$propList[$propertyName] = [];
|
||||||
|
foreach ($propNodeData->childNodes as $resourcetype) {
|
||||||
|
$propList[$propertyName][] = self::toClarkNotation($resourcetype);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$propList[$propertyName] = $propNodeData->textContent;
|
$propList[$propertyName] = $propNodeData->textContent;
|
||||||
}
|
}
|
||||||
|
|
@ -245,5 +234,4 @@ class Client
|
||||||
}
|
}
|
||||||
return $propList;
|
return $propList;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue