| 1: | <?php |
| 2: | |
| 3: | |
| 4: | |
| 5: | |
| 6: | |
| 7: | |
| 8: | namespace Aurora\Modules\Dav; |
| 9: | |
| 10: | use Afterlogic\DAV\CalDAV\Plugin; |
| 11: | use Aurora\Modules\Calendar\Enums\Permission; |
| 12: | |
| 13: | use function Sabre\Uri\split; |
| 14: | |
| 15: | |
| 16: | |
| 17: | |
| 18: | |
| 19: | |
| 20: | |
| 21: | |
| 22: | |
| 23: | if (!defined('DAV_ROOT')) { |
| 24: | define('DAV_ROOT', 'dav/server.php/'); |
| 25: | } |
| 26: | if (!defined('DAV_EMAIL_DEV')) { |
| 27: | define('DAV_EMAIL_DEV', '@'); |
| 28: | } |
| 29: | |
| 30: | class Client |
| 31: | { |
| 32: | public const PROP_RESOURCETYPE = '{DAV:}resourcetype'; |
| 33: | public const PROP_DISPLAYNAME = '{DAV:}displayname'; |
| 34: | public const PROP_CALENDAR_DESCRIPTION = '{urn:ietf:params:xml:ns:caldav}calendar-description'; |
| 35: | public const PROP_CALENDAR_ORDER = '{http://apple.com/ns/ical/}calendar-order'; |
| 36: | public const PROP_CALENDAR_COLOR = '{http://apple.com/ns/ical/}calendar-color'; |
| 37: | public const PROP_CALENDAR_DATA = '{urn:ietf:params:xml:ns:caldav}calendar-data'; |
| 38: | public const PROP_ADDRESSBOOK_DATA = '{urn:ietf:params:xml:ns:carddav}address-data'; |
| 39: | public const PROP_OWNER = '{DAV:}owner'; |
| 40: | public const PROP_CTAG = '{http://calendarserver.org/ns/}getctag'; |
| 41: | public const PROP_ETAG = '{DAV:}getetag'; |
| 42: | public const PROP_CURRENT_USER_PRINCIPAL = '{DAV:}current-user-principal'; |
| 43: | public const PROP_CALENDAR_HOME_SET = '{urn:ietf:params:xml:ns:caldav}calendar-home-set'; |
| 44: | public const PROP_CALENDAR_INVITE = '{' . Plugin::NS_CALENDARSERVER . '}invite'; |
| 45: | public const PROP_ADDRESSBOOK_HOME_SET = '{urn:ietf:params:xml:ns:carddav}addressbook-home-set'; |
| 46: | public const PROP_GROUP_MEMBERSHIP = '{DAV:}group-membership'; |
| 47: | public const PROP_GROUP_MEMBER_SET = '{DAV:}group-member-set'; |
| 48: | |
| 49: | |
| 50: | |
| 51: | |
| 52: | |
| 53: | public $baseUrl; |
| 54: | |
| 55: | |
| 56: | |
| 57: | |
| 58: | protected $user; |
| 59: | |
| 60: | |
| 61: | |
| 62: | |
| 63: | protected $connected; |
| 64: | |
| 65: | |
| 66: | |
| 67: | |
| 68: | protected $protocol = 'http'; |
| 69: | |
| 70: | |
| 71: | |
| 72: | |
| 73: | protected $port = 80; |
| 74: | |
| 75: | |
| 76: | |
| 77: | |
| 78: | protected $server; |
| 79: | |
| 80: | |
| 81: | |
| 82: | |
| 83: | public $isCustomServer = false; |
| 84: | |
| 85: | |
| 86: | |
| 87: | |
| 88: | public $client; |
| 89: | |
| 90: | |
| 91: | |
| 92: | |
| 93: | |
| 94: | |
| 95: | public function __construct($baseUrl, $user, $pass) |
| 96: | { |
| 97: | $this->client = new \Afterlogic\DAV\Client( |
| 98: | array( |
| 99: | 'baseUri' => $baseUrl, |
| 100: | 'userName' => $user, |
| 101: | 'password' => $pass |
| 102: | ) |
| 103: | ); |
| 104: | |
| 105: | $this->user = $user; |
| 106: | |
| 107: | $aUrlParts = parse_url($baseUrl); |
| 108: | |
| 109: | if (isset($aUrlParts['port'])) { |
| 110: | $this->port = $aUrlParts['port']; |
| 111: | } |
| 112: | |
| 113: | $matches = array(); |
| 114: | if (preg_match('#^(https?)://([a-z0-9.-]+)(:([0-9]+))?(/.*)$#', $baseUrl, $matches)) { |
| 115: | $this->protocol = $matches[1]; |
| 116: | $this->server = $matches[2]; |
| 117: | $this->baseUrl = $matches[5]; |
| 118: | } |
| 119: | |
| 120: | $this->connected = false; |
| 121: | } |
| 122: | |
| 123: | |
| 124: | |
| 125: | |
| 126: | public function Connect() |
| 127: | { |
| 128: | if ($this->connected === false) { |
| 129: | $this->connected = $this->testConnection(); |
| 130: | } |
| 131: | return $this->connected; |
| 132: | } |
| 133: | |
| 134: | |
| 135: | |
| 136: | |
| 137: | public function testConnection() |
| 138: | { |
| 139: | $res = $this->client->options_ex(); |
| 140: | $this->isCustomServer = $res['custom-server']; |
| 141: | |
| 142: | return true; |
| 143: | } |
| 144: | |
| 145: | |
| 146: | |
| 147: | |
| 148: | public function GetBaseUrl() |
| 149: | { |
| 150: | return $this->baseUrl; |
| 151: | } |
| 152: | |
| 153: | |
| 154: | |
| 155: | |
| 156: | public function GetRootUrl($url) |
| 157: | { |
| 158: | $urlParts = parse_url($url); |
| 159: | $path = '/'; |
| 160: | if (isset($urlParts['path'])) { |
| 161: | $path = $urlParts['path']; |
| 162: | } |
| 163: | return $path; |
| 164: | } |
| 165: | |
| 166: | |
| 167: | |
| 168: | |
| 169: | public function GetUser() |
| 170: | { |
| 171: | return $this->user; |
| 172: | } |
| 173: | |
| 174: | |
| 175: | |
| 176: | |
| 177: | public function GetServer() |
| 178: | { |
| 179: | return $this->server; |
| 180: | } |
| 181: | |
| 182: | |
| 183: | |
| 184: | |
| 185: | public function GetServerUrl() |
| 186: | { |
| 187: | $sPort = ''; |
| 188: | if ((int)$this->port != 80) { |
| 189: | $sPort = ':' . $this->port; |
| 190: | } |
| 191: | return $this->protocol . '://' . $_SERVER['SERVER_NAME'] . $sPort; |
| 192: | } |
| 193: | |
| 194: | |
| 195: | |
| 196: | |
| 197: | |
| 198: | |
| 199: | |
| 200: | public function CreateItem($sUrl, $sData) |
| 201: | { |
| 202: | return $this->client->request( |
| 203: | 'PUT', |
| 204: | $sUrl, |
| 205: | $sData, |
| 206: | array( |
| 207: | 'If-None-Match' => '*' |
| 208: | ) |
| 209: | ); |
| 210: | } |
| 211: | |
| 212: | |
| 213: | |
| 214: | |
| 215: | |
| 216: | |
| 217: | |
| 218: | public function UpdateItem($sUrl, $sData, $sEtag = '*') |
| 219: | { |
| 220: | return $this->client->request( |
| 221: | 'PUT', |
| 222: | $sUrl, |
| 223: | $sData, |
| 224: | array( |
| 225: | |
| 226: | ) |
| 227: | ); |
| 228: | } |
| 229: | |
| 230: | |
| 231: | |
| 232: | |
| 233: | |
| 234: | |
| 235: | |
| 236: | public function MoveItem($url, $newUrl) |
| 237: | { |
| 238: | return $this->client->request( |
| 239: | 'MOVE', |
| 240: | $url, |
| 241: | '', |
| 242: | array( |
| 243: | 'destination' => $newUrl |
| 244: | ) |
| 245: | ); |
| 246: | } |
| 247: | |
| 248: | |
| 249: | |
| 250: | |
| 251: | |
| 252: | |
| 253: | |
| 254: | |
| 255: | |
| 256: | |
| 257: | |
| 258: | public function createCalendar( |
| 259: | $sSystemName, |
| 260: | $sDisplayName, |
| 261: | $sDescription, |
| 262: | $iOrder, |
| 263: | $sColor, |
| 264: | $sCalendarHome |
| 265: | ) |
| 266: | { |
| 267: | $xml = |
| 268: | '<?xml version="1.0" encoding="UTF-8" ?> |
| 269: | <c:mkcalendar xmlns:c="'.\Sabre\CalDAV\Plugin::NS_CALDAV.'" xmlns:d="DAV:" xmlns:ic="http://apple.com/ns/ical/"> |
| 270: | <d:set> |
| 271: | <d:prop> |
| 272: | <d:displayname>'.$sDisplayName.'</d:displayname> |
| 273: | <c:calendar-description>'.$sDescription.'</c:calendar-description> |
| 274: | <ic:calendar-order>'.$iOrder.'</ic:calendar-order> |
| 275: | <ic:calendar-color>'.$sColor.'</ic:calendar-color> |
| 276: | </d:prop> |
| 277: | </d:set> |
| 278: | </c:mkcalendar>'; |
| 279: | |
| 280: | return $this->client->request( |
| 281: | 'MKCALENDAR', |
| 282: | $sCalendarHome.$sSystemName, |
| 283: | $xml, |
| 284: | array( |
| 285: | 'Content-Type' => 'application/xml', |
| 286: | 'Depth' => '1' |
| 287: | ) |
| 288: | ); |
| 289: | } |
| 290: | |
| 291: | |
| 292: | |
| 293: | |
| 294: | |
| 295: | |
| 296: | |
| 297: | |
| 298: | |
| 299: | |
| 300: | public function updateCalendar($sCalendarId, $sDisplayName, $sDescription, $iOrder, $sColor) |
| 301: | { |
| 302: | return $this->client->propPatch( |
| 303: | $sCalendarId, |
| 304: | array( |
| 305: | self::PROP_DISPLAYNAME => $sDisplayName, |
| 306: | self::PROP_CALENDAR_DESCRIPTION => $sDescription, |
| 307: | self::PROP_CALENDAR_ORDER => $iOrder, |
| 308: | self::PROP_CALENDAR_COLOR => $sColor |
| 309: | ) |
| 310: | ); |
| 311: | } |
| 312: | |
| 313: | |
| 314: | |
| 315: | |
| 316: | |
| 317: | |
| 318: | |
| 319: | public function updateCalendarColor($sCalendarId, $sColor) |
| 320: | { |
| 321: | return $this->client->propPatch( |
| 322: | $sCalendarId, |
| 323: | array( |
| 324: | self::PROP_CALENDAR_COLOR => $sColor |
| 325: | ) |
| 326: | ); |
| 327: | } |
| 328: | |
| 329: | |
| 330: | |
| 331: | |
| 332: | public function DeleteItem($url) |
| 333: | { |
| 334: | return $this->client->request('DELETE', $url); |
| 335: | } |
| 336: | |
| 337: | |
| 338: | |
| 339: | |
| 340: | |
| 341: | |
| 342: | |
| 343: | public function QueryCal($filter, $url = '') |
| 344: | { |
| 345: | $xml = |
| 346: | '<?xml version="1.0" encoding="utf-8" ?> |
| 347: | <c:calendar-query xmlns:d="DAV:" xmlns:c="'.\Sabre\CalDAV\Plugin::NS_CALDAV.'"> |
| 348: | <d:prop> |
| 349: | <d:getetag/> |
| 350: | <c:calendar-data/> |
| 351: | </d:prop> |
| 352: | '.$filter.' |
| 353: | </c:calendar-query>'; |
| 354: | |
| 355: | $res = array(); |
| 356: | try { |
| 357: | $res = $this->client->request( |
| 358: | 'REPORT', |
| 359: | $url, |
| 360: | $xml, |
| 361: | array( |
| 362: | 'Content-Type' => 'application/xml', |
| 363: | 'Depth' => '1' |
| 364: | ) |
| 365: | ); |
| 366: | } catch(\Sabre\DAV\Exception $ex) { |
| 367: | return false; |
| 368: | } |
| 369: | |
| 370: | $aStatus = $this->client->parseMultiStatus($res['body']); |
| 371: | |
| 372: | $report = array(); |
| 373: | foreach ($aStatus as $key => $props) { |
| 374: | $response = array(); |
| 375: | if (count($props) > 0) { |
| 376: | $response['url'] = $url; |
| 377: | $response['href'] = basename($key); |
| 378: | $response['etag'] = isset($props[200]) ? preg_replace('/^"?([^"]+)"?/', '$1', $props[200][self::PROP_ETAG]) : ''; |
| 379: | $response['data'] = isset($props[200]) ? $props[200][self::PROP_CALENDAR_DATA] : ''; |
| 380: | |
| 381: | $report[] = $response; |
| 382: | } |
| 383: | } |
| 384: | return $report; |
| 385: | } |
| 386: | |
| 387: | |
| 388: | |
| 389: | |
| 390: | |
| 391: | |
| 392: | |
| 393: | public function QueryCardsInfo($filter, $url = '') |
| 394: | { |
| 395: | $xml = |
| 396: | '<?xml version="1.0" encoding="utf-8" ?> |
| 397: | <c:addressbook-query xmlns:d="DAV:" xmlns:c="'.\Sabre\CardDAV\Plugin::NS_CARDDAV.'"> |
| 398: | <d:prop> |
| 399: | <d:getetag/> |
| 400: | </d:prop> |
| 401: | '.$filter.' |
| 402: | </c:addressbook-query>'; |
| 403: | |
| 404: | $res = array(); |
| 405: | try { |
| 406: | $res = $this->client->request( |
| 407: | 'REPORT', |
| 408: | $url, |
| 409: | $xml, |
| 410: | array( |
| 411: | 'Content-Type' => 'application/xml', |
| 412: | 'Depth' => '1' |
| 413: | ) |
| 414: | ); |
| 415: | } catch(\Sabre\DAV\Exception $ex) { |
| 416: | return false; |
| 417: | } |
| 418: | |
| 419: | $aStatus = $this->client->parseMultiStatus($res['body']); |
| 420: | |
| 421: | $report = array(); |
| 422: | foreach ($aStatus as $key => $props) { |
| 423: | $response = array(); |
| 424: | $response['href'] = basename($key); |
| 425: | $response['etag'] = isset($props[200]) ? preg_replace('/^"?([^"]+)"?/', '$1', $props[200][self::PROP_ETAG]) : ''; |
| 426: | $response['data'] = isset($props[200]) && isset($props[200][self::PROP_ADDRESSBOOK_DATA]) ? $props[200][self::PROP_ADDRESSBOOK_DATA] : ''; |
| 427: | |
| 428: | $report[] = $response; |
| 429: | } |
| 430: | return $report; |
| 431: | } |
| 432: | |
| 433: | |
| 434: | |
| 435: | |
| 436: | |
| 437: | |
| 438: | |
| 439: | public function QueryCards($calendar_url, $urls = []) |
| 440: | { |
| 441: | $aHrefs = []; |
| 442: | foreach ($urls as $url) { |
| 443: | $aHrefs[] = ' <d:href>' . $url . '</d:href>'; |
| 444: | } |
| 445: | $sHrefs = implode("\n", $aHrefs); |
| 446: | $xml = |
| 447: | '<?xml version="1.0" encoding="utf-8" ?> |
| 448: | <c:addressbook-multiget xmlns:d="DAV:" xmlns:c="'.\Sabre\CardDAV\Plugin::NS_CARDDAV.'"> |
| 449: | <d:prop> |
| 450: | <d:getetag /> |
| 451: | <c:address-data /> |
| 452: | </d:prop> |
| 453: | ' . $sHrefs . ' |
| 454: | </c:addressbook-multiget>'; |
| 455: | |
| 456: | $res = array(); |
| 457: | try { |
| 458: | $res = $this->client->request( |
| 459: | 'REPORT', |
| 460: | $calendar_url, |
| 461: | $xml, |
| 462: | array( |
| 463: | 'Content-Type' => 'application/xml', |
| 464: | 'Depth' => '1' |
| 465: | ) |
| 466: | ); |
| 467: | } catch(\Sabre\DAV\Exception $ex) { |
| 468: | return false; |
| 469: | } |
| 470: | |
| 471: | $aStatus = $this->client->parseMultiStatus($res['body']); |
| 472: | |
| 473: | $report = array(); |
| 474: | foreach ($aStatus as $key => $props) { |
| 475: | $response = array(); |
| 476: | $response['href'] = basename($key); |
| 477: | $response['etag'] = isset($props[200]) ? preg_replace('/^"?([^"]+)"?/', '$1', $props[200][self::PROP_ETAG]) : ''; |
| 478: | $response['data'] = isset($props[200]) && isset($props[200][self::PROP_ADDRESSBOOK_DATA]) ? $props[200][self::PROP_ADDRESSBOOK_DATA] : ''; |
| 479: | |
| 480: | $report[] = $response; |
| 481: | } |
| 482: | return $report; |
| 483: | } |
| 484: | |
| 485: | public function GetVcardsInfo($url = '', $sSearch = '', $sGroupId = '') |
| 486: | { |
| 487: | $sFilter = ''; |
| 488: | $sGroupFilter = ''; |
| 489: | $sSearchFilter = ''; |
| 490: | |
| 491: | if (!empty($sGroupId)) { |
| 492: | $sGroupFilter = |
| 493: | ' <c:prop-filter name="CATEGORIES"> |
| 494: | <c:text-match icollation="i;octet" match-type="contains">'.$sGroupId.'</c:text-match> |
| 495: | </c:prop-filter>'; |
| 496: | } |
| 497: | |
| 498: | if (!empty($sSearch)) { |
| 499: | $sSearchFilter = |
| 500: | ' <c:prop-filter name="FN"> |
| 501: | <c:text-match icollation="i;octet" match-type="contains">'.$sSearch.'</c:text-match> |
| 502: | </c:prop-filter> |
| 503: | <c:prop-filter name="N"> |
| 504: | <c:text-match icollation="i;octet" match-type="contains">'.$sSearch.'</c:text-match> |
| 505: | </c:prop-filter> |
| 506: | <c:prop-filter name="EMAIL"> |
| 507: | <c:text-match icollation="i;octet" match-type="contains">'.$sSearch.'</c:text-match> |
| 508: | </c:prop-filter> |
| 509: | <c:prop-filter name="NICKNAME"> |
| 510: | <c:text-match icollation="i;octet" match-type="contains">'.$sSearch.'</c:text-match> |
| 511: | </c:prop-filter>'; |
| 512: | } |
| 513: | |
| 514: | if (!empty($sSearch) || !empty($sGroupId)) { |
| 515: | $sFilter = |
| 516: | ' <c:filter> |
| 517: | ' . $sSearchFilter |
| 518: | . $sGroupFilter . ' |
| 519: | </c:filter>'; |
| 520: | } |
| 521: | |
| 522: | return $this->QueryCardsInfo($sFilter, $url); |
| 523: | } |
| 524: | |
| 525: | public function GetVcards($url, $urls = []) |
| 526: | { |
| 527: | list($path, $name) = split($url); |
| 528: | $url = $path . '/' . rawurlencode($name); |
| 529: | |
| 530: | return $this->QueryCards($url, $urls); |
| 531: | } |
| 532: | |
| 533: | |
| 534: | |
| 535: | |
| 536: | |
| 537: | |
| 538: | |
| 539: | public function GetTimeRange($start = null, $end = null) |
| 540: | { |
| 541: | $timeRange = ''; |
| 542: | $startRange = ''; |
| 543: | $endRange = ''; |
| 544: | if (isset($start) || isset($end)) { |
| 545: | if (isset($start)) { |
| 546: | $startRange = 'start="'.$start.'"'; |
| 547: | } |
| 548: | if (isset($end)) { |
| 549: | $endRange = 'end="'.$end.'"'; |
| 550: | } |
| 551: | $timeRange = sprintf('<c:time-range %s %s/>', $startRange, $endRange); |
| 552: | } |
| 553: | return $timeRange; |
| 554: | } |
| 555: | |
| 556: | |
| 557: | |
| 558: | |
| 559: | |
| 560: | |
| 561: | |
| 562: | |
| 563: | public function getEvents($url = '', $start = null, $finish = null) |
| 564: | { |
| 565: | $timeRange = $this->GetTimeRange($start, $finish); |
| 566: | $url = rtrim($url, '/') . '/'; |
| 567: | list($path, $name) = split($url); |
| 568: | $url = $path . '/' . rawurlencode($name); |
| 569: | $filter = |
| 570: | '<c:filter> |
| 571: | <c:comp-filter name="VCALENDAR"> |
| 572: | <c:comp-filter name="VEVENT"> |
| 573: | '.$timeRange.' |
| 574: | </c:comp-filter> |
| 575: | </c:comp-filter> |
| 576: | </c:filter>'; |
| 577: | return $this->QueryCal($filter, $url); |
| 578: | } |
| 579: | |
| 580: | |
| 581: | |
| 582: | |
| 583: | |
| 584: | |
| 585: | |
| 586: | public function GetEventByUid($sCalendarUrl, $sUid) |
| 587: | { |
| 588: | $filter = |
| 589: | ' <c:filter> |
| 590: | <c:comp-filter name="VCALENDAR"> |
| 591: | <c:comp-filter name="VEVENT"> |
| 592: | <c:prop-filter name="UID"> |
| 593: | <c:text-match icollation="i;octet">'.$sUid.'</c:text-match> |
| 594: | </c:prop-filter> |
| 595: | </c:comp-filter> |
| 596: | </c:comp-filter> |
| 597: | </c:filter>'; |
| 598: | $result = $this->QueryCal($filter, $sCalendarUrl); |
| 599: | if ($result !== false) { |
| 600: | return current($result); |
| 601: | } else { |
| 602: | return false; |
| 603: | } |
| 604: | } |
| 605: | |
| 606: | |
| 607: | |
| 608: | |
| 609: | |
| 610: | |
| 611: | public function GetItem($url = '') |
| 612: | { |
| 613: | $res = $this->client->request('GET', $url); |
| 614: | if ($res !== false) { |
| 615: | return $res['body']; |
| 616: | } |
| 617: | return $res; |
| 618: | } |
| 619: | |
| 620: | |
| 621: | |
| 622: | |
| 623: | |
| 624: | |
| 625: | |
| 626: | |
| 627: | public function GetAlarms($url = '', $start = null, $finish = null) |
| 628: | { |
| 629: | $timeRange = $this->GetTimeRange($start, $finish); |
| 630: | $url = rtrim($url, '/') . '/'; |
| 631: | |
| 632: | $filter = |
| 633: | '<c:filter> |
| 634: | <c:comp-filter name="VCALENDAR"> |
| 635: | <c:comp-filter name="VEVENT"> |
| 636: | <c:comp-filter name="VALARM"> |
| 637: | '.$timeRange.' |
| 638: | </c:comp-filter> |
| 639: | </c:comp-filter> |
| 640: | </c:comp-filter> |
| 641: | </c:filter>'; |
| 642: | |
| 643: | |
| 644: | return $this->QueryCal($filter, $url); |
| 645: | } |
| 646: | |
| 647: | |
| 648: | |
| 649: | |
| 650: | |
| 651: | |
| 652: | |
| 653: | |
| 654: | |
| 655: | |
| 656: | |
| 657: | public function GetTodos($start, $finish, $completed = false, $cancelled = false, $url = '') |
| 658: | { |
| 659: | $timeRange = $this->GetTimeRange($start, $finish); |
| 660: | |
| 661: | |
| 662: | $negateCancelled = ($cancelled === true ? 'no' : 'yes'); |
| 663: | $negateCompleted = ($cancelled === true ? 'no' : 'yes'); |
| 664: | |
| 665: | $filter = |
| 666: | '<c:filter> |
| 667: | <c:comp-filter name="VCALENDAR"> |
| 668: | <c:comp-filter name="VTODO"> |
| 669: | <c:prop-filter name="STATUS"> |
| 670: | <c:text-match negate-condition="'.$negateCompleted.'">COMPLETED</c:text-match> |
| 671: | </c:prop-filter> |
| 672: | <c:prop-filter name="STATUS"> |
| 673: | <C:text-match negate-condition="'.$negateCancelled.'">CANCELLED</c:text-match> |
| 674: | </c:prop-filter> |
| 675: | ' . $timeRange . ' |
| 676: | </c:comp-filter> |
| 677: | </c:comp-filter> |
| 678: | </c:filter>'; |
| 679: | |
| 680: | return $this->QueryCal($filter, $url); |
| 681: | } |
| 682: | |
| 683: | |
| 684: | |
| 685: | |
| 686: | |
| 687: | |
| 688: | public function getCalendar($url = '') |
| 689: | { |
| 690: | $filter = |
| 691: | '<c:filter> |
| 692: | <c:comp-filter name="VCALENDAR"></c:comp-filter> |
| 693: | </c:filter>'; |
| 694: | |
| 695: | return $this->QueryCal($filter, $url); |
| 696: | } |
| 697: | |
| 698: | public function GetCurrentPrincipal() |
| 699: | { |
| 700: | $res = $this->client->propFind('', array(self::PROP_CURRENT_USER_PRINCIPAL)); |
| 701: | |
| 702: | return $res[self::PROP_CURRENT_USER_PRINCIPAL]; |
| 703: | } |
| 704: | |
| 705: | |
| 706: | |
| 707: | |
| 708: | public function GetPrincipalMembers($principal = '') |
| 709: | { |
| 710: | $res = array(); |
| 711: | try { |
| 712: | $res = $this->client->propFind( |
| 713: | $principal, |
| 714: | array( |
| 715: | self::PROP_GROUP_MEMBERSHIP |
| 716: | ), |
| 717: | 1 |
| 718: | ); |
| 719: | } catch(\Exception $ex) { |
| 720: | return []; |
| 721: | } |
| 722: | |
| 723: | return $res[self::PROP_GROUP_MEMBERSHIP]; |
| 724: | } |
| 725: | |
| 726: | |
| 727: | |
| 728: | |
| 729: | public function GetCalendarHomeSet($principalUrl = '') |
| 730: | { |
| 731: | $props = $this->client->propFind( |
| 732: | $principalUrl, |
| 733: | array( |
| 734: | self::PROP_CALENDAR_HOME_SET |
| 735: | ) |
| 736: | ); |
| 737: | return $props[self::PROP_CALENDAR_HOME_SET]; |
| 738: | } |
| 739: | |
| 740: | |
| 741: | |
| 742: | |
| 743: | public function GetAddressBookHomeSet($principalUrl = '') |
| 744: | { |
| 745: | $props = $this->client->propFind( |
| 746: | $principalUrl, |
| 747: | array( |
| 748: | self::PROP_ADDRESSBOOK_HOME_SET |
| 749: | ) |
| 750: | ); |
| 751: | return $props[self::PROP_ADDRESSBOOK_HOME_SET]; |
| 752: | } |
| 753: | |
| 754: | public function GetAddressBooks($url = '') |
| 755: | { |
| 756: | $aProps = $this->client->propFind( |
| 757: | $url, |
| 758: | array( |
| 759: | self::PROP_RESOURCETYPE, |
| 760: | self::PROP_DISPLAYNAME |
| 761: | ), |
| 762: | 1 |
| 763: | ); |
| 764: | return $aProps; |
| 765: | } |
| 766: | |
| 767: | public function getCalendars($url = '') |
| 768: | { |
| 769: | $calendars = array(); |
| 770: | |
| 771: | if (class_exists('\Aurora\Modules\Calendar\Classes\Calendar')) { |
| 772: | $aProps = $this->client->propFind( |
| 773: | $url, |
| 774: | array( |
| 775: | self::PROP_RESOURCETYPE, |
| 776: | self::PROP_DISPLAYNAME, |
| 777: | self::PROP_OWNER, |
| 778: | self::PROP_CTAG, |
| 779: | self::PROP_CALENDAR_DESCRIPTION, |
| 780: | self::PROP_CALENDAR_COLOR, |
| 781: | self::PROP_CALENDAR_ORDER, |
| 782: | self::PROP_CALENDAR_INVITE |
| 783: | ), |
| 784: | 1 |
| 785: | ); |
| 786: | |
| 787: | foreach ($aProps as $key => $props) { |
| 788: | if ($props['{DAV:}resourcetype']->is('{'.\Sabre\CalDAV\Plugin::NS_CALDAV.'}calendar') && |
| 789: | !$props['{DAV:}resourcetype']->is('{'.\Sabre\CalDAV\Plugin::NS_CALENDARSERVER.'}shared')) { |
| 790: | $calendar = new \Aurora\Modules\Calendar\Classes\Calendar($key); |
| 791: | |
| 792: | $calendar->CTag = $props[self::PROP_CTAG]; |
| 793: | $calendar->DisplayName = $props[self::PROP_DISPLAYNAME]; |
| 794: | $calendar->Principals[] = isset($props[self::PROP_OWNER]) ? $props[self::PROP_OWNER] : ''; |
| 795: | $calendar->Description = isset($props[self::PROP_CALENDAR_DESCRIPTION]) ? $props[self::PROP_CALENDAR_DESCRIPTION] : ''; |
| 796: | $calendar->Color = isset($props[self::PROP_CALENDAR_COLOR]) ? $props[self::PROP_CALENDAR_COLOR] : ''; |
| 797: | if (strlen($calendar->Color) > 7) { |
| 798: | $calendar->Color = substr($calendar->Color, 0, 7); |
| 799: | } |
| 800: | |
| 801: | if (isset($props[self::PROP_CALENDAR_ORDER])) { |
| 802: | $calendar->Order = $props[self::PROP_CALENDAR_ORDER]; |
| 803: | } |
| 804: | if (isset($props[self::PROP_CALENDAR_INVITE])) { |
| 805: | $aInvitesProp = $props[self::PROP_CALENDAR_INVITE]; |
| 806: | |
| 807: | foreach ($aInvitesProp as $aInviteProp) { |
| 808: | if ($aInviteProp['name'] === '{' . Plugin::NS_CALENDARSERVER . '}user') { |
| 809: | $aShare = []; |
| 810: | |
| 811: | foreach ($aInviteProp['value'] as $aValue) { |
| 812: | switch ($aValue['name']) { |
| 813: | case '{DAV:}href': |
| 814: | list(, $aShare['email']) = split($aValue['value']); |
| 815: | |
| 816: | break; |
| 817: | case '{http://calendarserver.org/ns/}access': |
| 818: | if (isset($aValue['value'][0])) { |
| 819: | $aShare['access'] = $aValue['value'][0]['name'] === '{' . Plugin::NS_CALENDARSERVER . '}read-write' |
| 820: | ? \Afterlogic\DAV\Permission::Write |
| 821: | : \Afterlogic\DAV\Permission::Read; |
| 822: | } |
| 823: | break; |
| 824: | } |
| 825: | } |
| 826: | if (!empty($aShare)) { |
| 827: | $calendar->Shares[] = $aShare; |
| 828: | } |
| 829: | } |
| 830: | } |
| 831: | } |
| 832: | |
| 833: | $calendars[$calendar->Id] = $calendar; |
| 834: | } |
| 835: | } |
| 836: | } |
| 837: | return $calendars; |
| 838: | } |
| 839: | |
| 840: | public function GetVcardByUid($uid, $url = '') |
| 841: | { |
| 842: | $filter = ""; |
| 843: | |
| 844: | if ($uid) { |
| 845: | $filter = |
| 846: | '<c:filter> |
| 847: | <c:prop-filter name="UID"> |
| 848: | <c:text-match collation="i;unicode-casemap" match-type="equals">'.$uid.'</c:text-match> |
| 849: | </c:prop-filter> |
| 850: | </c:filter>'; |
| 851: | } |
| 852: | |
| 853: | return $this->QueryCardsInfo($filter, $url); |
| 854: | } |
| 855: | |
| 856: | public function GetProxies($sProxy) |
| 857: | { |
| 858: | $res = array(); |
| 859: | try { |
| 860: | $res = $this->client->propFind( |
| 861: | $sProxy, |
| 862: | array( |
| 863: | self::PROP_GROUP_MEMBER_SET |
| 864: | ), |
| 865: | 1 |
| 866: | ); |
| 867: | } catch(\Exception $ex) { |
| 868: | return []; |
| 869: | } |
| 870: | |
| 871: | return $res[self::PROP_GROUP_MEMBER_SET]; |
| 872: | } |
| 873: | |
| 874: | public function AddProxy($proxy, $to) |
| 875: | { |
| 876: | $sProxyStr = ''; |
| 877: | $aCurrentProxies = array(); |
| 878: | $duplicate = false; |
| 879: | |
| 880: | $aCurrentProxies = $this->GetProxies($proxy); |
| 881: | |
| 882: | if ($aCurrentProxies) { |
| 883: | foreach ($aCurrentProxies as $sCurrentProxy => $val) { |
| 884: | $sCurrentProxy = ltrim($sCurrentProxy, DAV_ROOT); |
| 885: | if ($sCurrentProxy == $proxy) { |
| 886: | $duplicate = true; |
| 887: | } |
| 888: | $sProxyStr .= '<d:href>' . $sCurrentProxy . '</d:href>'; |
| 889: | } |
| 890: | } |
| 891: | if ($duplicate) { |
| 892: | return false; |
| 893: | } |
| 894: | |
| 895: | $sProxyStr .= '<d:href>' . \Afterlogic\DAV\Constants::PRINCIPALS_PREFIX . $to . '</d:href>'; |
| 896: | |
| 897: | return $this->client->propPatch($proxy, array('group-member-set'=>$sProxyStr)); |
| 898: | } |
| 899: | |
| 900: | public function DeleteProxy($proxy, $to) |
| 901: | { |
| 902: | $aCurrentProxies = $this->GetProxies($proxy); |
| 903: | |
| 904: | $sProxyStr = ""; |
| 905: | |
| 906: | if ($aCurrentProxies) { |
| 907: | foreach ($aCurrentProxies as $sCurrentProxy => $val) { |
| 908: | $sCurrentProxy = ltrim($sCurrentProxy, DAV_ROOT); |
| 909: | $sProxyStr .= '<d:href>' . $sCurrentProxy . '</d:href>'; |
| 910: | } |
| 911: | } |
| 912: | |
| 913: | $sProxyStr = str_replace('<d:href>' . \Afterlogic\DAV\Constants::PRINCIPALS_PREFIX . $to . '</d:href>', '', $sProxyStr); |
| 914: | |
| 915: | return $this->client->propPatch( |
| 916: | $proxy, |
| 917: | array( |
| 918: | 'group-member-set'=>$sProxyStr |
| 919: | ) |
| 920: | ); |
| 921: | } |
| 922: | |
| 923: | |
| 924: | |
| 925: | |
| 926: | |
| 927: | |
| 928: | |
| 929: | public function GetCalendarProxiedFor($principalUrl) |
| 930: | { |
| 931: | $body = |
| 932: | '<?xml version="1.0"?> |
| 933: | <d:expand-property xmlns:d="DAV:"> |
| 934: | <d:property name="calendar-proxy-read-for" namespace="'.\Sabre\CalDAV\Plugin::NS_CALENDARSERVER.'"> |
| 935: | <d:property name="calendar-home-set" namespace="'.\Sabre\CalDAV\Plugin::NS_CALDAV.'" /> |
| 936: | </d:property> |
| 937: | <d:property name="calendar-proxy-write-for" namespace="'.\Sabre\CalDAV\Plugin::NS_CALENDARSERVER.'"> |
| 938: | <d:property name="calendar-home-set" namespace="'.\Sabre\CalDAV\Plugin::NS_CALDAV.'" /> |
| 939: | </d:property> |
| 940: | </d:expand-property>'; |
| 941: | |
| 942: | $res = $this->client->request( |
| 943: | 'REPORT', |
| 944: | $principalUrl, |
| 945: | $body, |
| 946: | array( |
| 947: | 'Content-Type' => 'application/xml', |
| 948: | 'Depth' => '1' |
| 949: | ) |
| 950: | ); |
| 951: | |
| 952: | if (isset($res['body'])) { |
| 953: | $data = new \DOMDocument(); |
| 954: | |
| 955: | $data->loadXML($res['body'], LIBXML_NOERROR | LIBXML_NOWARNING | LIBXML_NSCLEAN); |
| 956: | $xp = new \DOMXPath($data); |
| 957: | |
| 958: | $xp->registerNamespace('c', \Sabre\CalDAV\Plugin::NS_CALDAV); |
| 959: | $xp->registerNamespace('cs', \Sabre\CalDAV\Plugin::NS_CALENDARSERVER); |
| 960: | $xp->registerNamespace('d', 'urn:dav'); |
| 961: | $values = array(); |
| 962: | |
| 963: | $result = $xp->query("/d:multistatus/d:response/d:propstat/d:prop/cs:calendar-proxy-read-for/d:response/d:propstat/d:prop/c:calendar-home-set/d:href"); |
| 964: | foreach ($result as $elem) { |
| 965: | $values[] = array( |
| 966: | 'href' => $elem->nodeValue, |
| 967: | 'mode' => 'read' |
| 968: | ); |
| 969: | } |
| 970: | |
| 971: | $result = $xp->query("/d:multistatus/d:response/d:propstat/d:prop/cs:calendar-proxy-write-for/d:response/d:propstat/d:prop/c:calendar-home-set/d:href"); |
| 972: | foreach ($result as $elem) { |
| 973: | $values[] = array( |
| 974: | 'href' => $elem->nodeValue, |
| 975: | 'mode' => 'write' |
| 976: | ); |
| 977: | } |
| 978: | |
| 979: | return $values; |
| 980: | } |
| 981: | return array(); |
| 982: | } |
| 983: | } |
| 984: | |