forked from friendica/deprecated-addons
377 lines
10 KiB
PHP
377 lines
10 KiB
PHP
<?php
|
|
|
|
use Friendica\Util\DateTimeFormat;
|
|
|
|
define("DAV_ACL_READ", "{DAV:}read");
|
|
define("DAV_ACL_WRITE", "{DAV:}write");
|
|
define("DAV_DISPLAYNAME", "{DAV:}displayname");
|
|
define("DAV_CALENDARCOLOR", "{http://apple.com/ns/ical/}calendar-color");
|
|
|
|
|
|
class DAVVersionMismatchException extends Exception
|
|
{
|
|
}
|
|
|
|
|
|
class vcard_source_data_email
|
|
{
|
|
public $email, $type;
|
|
|
|
function __construct($type, $email)
|
|
{
|
|
$this->email = $email;
|
|
$this->type = $type;
|
|
}
|
|
}
|
|
|
|
class vcard_source_data_homepage
|
|
{
|
|
public $homepage, $type;
|
|
|
|
function __construct($type, $homepage)
|
|
{
|
|
$this->homepage = $homepage;
|
|
$this->type = $type;
|
|
}
|
|
}
|
|
|
|
class vcard_source_data_telephone
|
|
{
|
|
public $telephone, $type;
|
|
|
|
function __construct($type, $telephone)
|
|
{
|
|
$this->telephone = $telephone;
|
|
$this->type = $type;
|
|
}
|
|
}
|
|
|
|
class vcard_source_data_socialnetwork
|
|
{
|
|
public $nick, $type, $url;
|
|
|
|
function __construct($type, $nick, $url)
|
|
{
|
|
$this->nick = $nick;
|
|
$this->type = $type;
|
|
$this->url = $url;
|
|
}
|
|
}
|
|
|
|
class vcard_source_data_address
|
|
{
|
|
public $street, $street2, $zip, $city, $country, $type;
|
|
}
|
|
|
|
class vcard_source_data_photo
|
|
{
|
|
public $binarydata;
|
|
public $width, $height;
|
|
public $type;
|
|
}
|
|
|
|
class vcard_source_data
|
|
{
|
|
function __construct($name_first, $name_middle, $name_last)
|
|
{
|
|
$this->name_first = $name_first;
|
|
$this->name_middle = $name_middle;
|
|
$this->name_last = $name_last;
|
|
}
|
|
|
|
public $name_first, $name_middle, $name_last;
|
|
public $last_update;
|
|
public $picture_data;
|
|
|
|
/** @var array|vcard_source_data_telephone[] $telephones */
|
|
public $telephones;
|
|
|
|
/** @var array|vcard_source_data_homepage[] $homepages */
|
|
public $homepages;
|
|
|
|
/** @var array|vcard_source_data_socialnetwork[] $socialnetworks */
|
|
public $socialnetworks;
|
|
|
|
/** @var array|vcard_source_data_email[] $email */
|
|
public $emails;
|
|
|
|
/** @var array|vcard_source_data_address[] $addresses */
|
|
public $addresses;
|
|
|
|
/** @var vcard_source_data_photo */
|
|
public $photo;
|
|
}
|
|
|
|
/**
|
|
* @param vcard_source_data $vcardsource
|
|
* @return string
|
|
*/
|
|
function vcard_source_compile($vcardsource)
|
|
{
|
|
$str = "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Friendica//DAV-Plugin//EN\r\n";
|
|
$str .= "N:" . str_replace(";", ",", $vcardsource->name_last) . ";" . str_replace(";", ",", $vcardsource->name_first) . ";" . str_replace(";", ",", $vcardsource->name_middle) . ";;\r\n";
|
|
$str .= "FN:" . str_replace(";", ",", $vcardsource->name_first) . " " . str_replace(";", ",", $vcardsource->name_middle) . " " . str_replace(";", ",", $vcardsource->name_last) . "\r\n";
|
|
$str .= "REV:" . str_replace(" ", "T", $vcardsource->last_update) . "Z\r\n";
|
|
|
|
$item_count = 0;
|
|
for ($i = 0; $i < count($vcardsource->homepages); $i++) {
|
|
if ($i == 0) $str .= "URL;type=" . $vcardsource->homepages[0]->type . ":" . $vcardsource->homepages[0]->homepage . "\r\n";
|
|
else {
|
|
$c = ++$item_count;
|
|
$str .= "item$c.URL;type=" . $vcardsource->homepages[0]->type . ":" . $vcardsource->homepages[0]->homepage . "\r\n";
|
|
$str .= "item$c.X-ABLabel:_\$!<HomePage>!\$_\r\n";
|
|
}
|
|
}
|
|
|
|
if (is_object($vcardsource->photo)) {
|
|
$data = base64_encode($vcardsource->photo->binarydata);
|
|
$str .= "PHOTO;ENCODING=BASE64;TYPE=" . $vcardsource->photo->type . ":" . $data . "\r\n";
|
|
}
|
|
|
|
if (isset($vcardsource->socialnetworks) && is_array($vcardsource->socialnetworks)) foreach ($vcardsource->socialnetworks as $netw) switch ($netw->type) {
|
|
case "dfrn":
|
|
$str .= "X-SOCIALPROFILE;type=dfrn;x-user=" . $netw->nick . ":" . $netw->url . "\r\n";
|
|
break;
|
|
case "facebook":
|
|
$str .= "X-SOCIALPROFILE;type=facebook;x-user=" . $netw->nick . ":" . $netw->url . "\r\n";
|
|
break;
|
|
case "twitter":
|
|
$str .= "X-SOCIALPROFILE;type=twitter;x-user=" . $netw->nick . ":" . $netw->url . "\r\n";
|
|
break;
|
|
}
|
|
|
|
$str .= "END:VCARD\r\n";
|
|
return $str;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param int $phpDate (UTC)
|
|
* @return string (Lokalzeit)
|
|
*/
|
|
function wdcal_php2MySqlTime($phpDate)
|
|
{
|
|
return date(DateTimeFormat::MYSQL, $phpDate);
|
|
}
|
|
|
|
/**
|
|
* @param string $sqlDate
|
|
* @return int
|
|
*/
|
|
function wdcal_mySql2PhpTime($sqlDate)
|
|
{
|
|
$ts = DateTime::createFromFormat(DateTimeFormat::MYSQL, $sqlDate);
|
|
return $ts->format("U");
|
|
}
|
|
|
|
/**
|
|
* @param string $myqlDate
|
|
* @return array
|
|
*/
|
|
function wdcal_mySql2icalTime($myqlDate)
|
|
{
|
|
$x = explode(" ", $myqlDate);
|
|
$y = explode("-", $x[0]);
|
|
$ret = array("year"=> $y[0], "month"=> $y[1], "day"=> $y[2]);
|
|
$y = explode(":", $x[1]);
|
|
$ret["hour"] = $y[0];
|
|
$ret["minute"] = $y[1];
|
|
$ret["second"] = $y[2];
|
|
return $ret;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param string $str
|
|
* @return string
|
|
*/
|
|
function icalendar_sanitize_string($str = "")
|
|
{
|
|
return preg_replace("/[\\r\\n]+/siu", "\r\n", $str);
|
|
}
|
|
|
|
|
|
/**
|
|
* @return Sabre_CalDAV_AnimexxCalendarRootNode
|
|
*/
|
|
function dav_createRootCalendarNode()
|
|
{
|
|
$backends = array(Sabre_CalDAV_Backend_Private::getInstance());
|
|
foreach ($GLOBALS["CALDAV_PRIVATE_SYSTEM_BACKENDS"] as $backendclass) $backends[] = $backendclass::getInstance();
|
|
return new Sabre_CalDAV_AnimexxCalendarRootNode(Sabre_DAVACL_PrincipalBackend_Std::getInstance(), $backends);
|
|
}
|
|
|
|
/**
|
|
* @return Sabre_CardDAV_AddressBookRootFriendica
|
|
*/
|
|
function dav_createRootContactsNode()
|
|
{
|
|
$backends = array(Sabre_CardDAV_Backend_Std::getInstance());
|
|
foreach ($GLOBALS["CARDDAV_PRIVATE_SYSTEM_BACKENDS"] as $backendclass) $backends[] = $backendclass::getInstance();
|
|
|
|
return new Sabre_CardDAV_AddressBookRootFriendica(Sabre_DAVACL_PrincipalBackend_Std::getInstance(), $backends);
|
|
}
|
|
|
|
|
|
/**
|
|
* @param bool $force_authentication
|
|
* @param bool $needs_caldav
|
|
* @param bool $needs_carddav
|
|
* @return Sabre_DAV_Server
|
|
*/
|
|
function dav_create_server($force_authentication = false, $needs_caldav = true, $needs_carddav = true)
|
|
{
|
|
$arr = array(
|
|
new Sabre_DAV_SimpleCollection('principals', array(
|
|
new Sabre_CalDAV_Principal_Collection(Sabre_DAVACL_PrincipalBackend_Std::getInstance(), "principals/users"),
|
|
)),
|
|
);
|
|
if ($needs_caldav) $arr[] = dav_createRootCalendarNode();
|
|
if ($needs_carddav) $arr[] = dav_createRootContactsNode();
|
|
|
|
|
|
$tree = new Sabre_DAV_SimpleCollection('root', $arr);
|
|
|
|
// The object tree needs in turn to be passed to the server class
|
|
$server = new Sabre_DAV_Server($tree);
|
|
|
|
if (CALDAV_URL_PREFIX != "") $server->setBaseUri(CALDAV_URL_PREFIX);
|
|
|
|
$authPlugin = new Sabre_DAV_Auth_Plugin(Sabre_DAV_Auth_Backend_Std::getInstance(), DAV_APPNAME);
|
|
$server->addPlugin($authPlugin);
|
|
|
|
if ($needs_caldav) {
|
|
$caldavPlugin = new Sabre_CalDAV_Plugin();
|
|
$server->addPlugin($caldavPlugin);
|
|
}
|
|
if ($needs_carddav) {
|
|
$carddavPlugin = new Sabre_CardDAV_Plugin();
|
|
$server->addPlugin($carddavPlugin);
|
|
}
|
|
|
|
if ($GLOBALS["CALDAV_ACL_PLUGIN_CLASS"] != "") {
|
|
$aclPlugin = new $GLOBALS["CALDAV_ACL_PLUGIN_CLASS"]();
|
|
$aclPlugin->defaultUsernamePath = "principals/users";
|
|
$server->addPlugin($aclPlugin);
|
|
} else {
|
|
$aclPlugin = new Sabre_DAVACL_Plugin();
|
|
$aclPlugin->defaultUsernamePath = "principals/users";
|
|
$server->addPlugin($aclPlugin);
|
|
}
|
|
|
|
if ($force_authentication) $server->broadcastEvent('beforeMethod', array("GET", "/")); // Make it authenticate
|
|
|
|
return $server;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param Sabre_DAV_Server $server
|
|
* @param string $with_privilege
|
|
* @return array|Sabre_CalDAV_Calendar[]
|
|
*/
|
|
function dav_get_current_user_calendars(&$server, $with_privilege = "")
|
|
{
|
|
if ($with_privilege == "") $with_privilege = DAV_ACL_READ;
|
|
|
|
$a = get_app();
|
|
$calendar_path = "/calendars/" . strtolower($a->user["nickname"]) . "/";
|
|
|
|
/** @var Sabre_CalDAV_AnimexxUserCalendars $tree */
|
|
$tree = $server->tree->getNodeForPath($calendar_path);
|
|
/** @var array|Sabre_CalDAV_Calendar[] $calendars */
|
|
$children = $tree->getChildren();
|
|
|
|
$calendars = array();
|
|
/** @var Sabre_DAVACL_Plugin $aclplugin */
|
|
$aclplugin = $server->getPlugin("acl");
|
|
foreach ($children as $child) if (is_a($child, "Sabre_CalDAV_Calendar") || is_subclass_of($child, "Sabre_CalDAV_Calendar")) {
|
|
if ($with_privilege != "") {
|
|
$caluri = $calendar_path . $child->getName();
|
|
if ($aclplugin->checkPrivileges($caluri, $with_privilege, Sabre_DAVACL_Plugin::R_PARENT, false)) $calendars[] = $child;
|
|
} else {
|
|
$calendars[] = $child;
|
|
}
|
|
}
|
|
return $calendars;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param Sabre_DAV_Server $server
|
|
* @param Sabre_CalDAV_Calendar $calendar
|
|
* @param string $calendarobject_uri
|
|
* @param string $with_privilege
|
|
* @return null|Sabre\VObject\Component\VCalendar
|
|
*/
|
|
function dav_get_current_user_calendarobject(&$server, &$calendar, $calendarobject_uri, $with_privilege = "")
|
|
{
|
|
$obj = $calendar->getChild($calendarobject_uri);
|
|
|
|
if ($with_privilege == "") $with_privilege = DAV_ACL_READ;
|
|
|
|
$a = get_app();
|
|
$uri = "/calendars/" . strtolower($a->user["nickname"]) . "/" . $calendar->getName() . "/" . $calendarobject_uri;
|
|
|
|
/** @var Sabre_DAVACL_Plugin $aclplugin */
|
|
$aclplugin = $server->getPlugin("acl");
|
|
if (!$aclplugin->checkPrivileges($uri, $with_privilege, Sabre_DAVACL_Plugin::R_PARENT, false)) return null;
|
|
|
|
$data = $obj->get();
|
|
$vObject = Sabre\VObject\Reader::read($data);
|
|
|
|
return $vObject;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param Sabre_DAV_Server $server
|
|
* @param int $id
|
|
* @param string $with_privilege
|
|
* @return null|Sabre_CalDAV_Calendar
|
|
*/
|
|
function dav_get_current_user_calendar_by_id(&$server, $id, $with_privilege = "")
|
|
{
|
|
$calendars = dav_get_current_user_calendars($server, $with_privilege);
|
|
|
|
$calendar = null;
|
|
foreach ($calendars as $cal) {
|
|
$prop = $cal->getProperties(array("id"));
|
|
if (isset($prop["id"]) && $prop["id"] == $id) $calendar = $cal;
|
|
}
|
|
|
|
return $calendar;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param string $uid
|
|
* @return Sabre\VObject\Component\VCalendar $vObject
|
|
*/
|
|
function dav_create_empty_vevent($uid = "")
|
|
{
|
|
if ($uid == "") $uid = uniqid();
|
|
return Sabre\VObject\Reader::read("BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//" . DAV_APPNAME . "//DAV-Plugin//EN\r\nBEGIN:VEVENT\r\nUID:" . $uid . "@" . dav_compat_get_hostname() .
|
|
"\r\nDTSTAMP:" . date("Ymd") . "T" . date("His") . "Z\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n");
|
|
}
|
|
|
|
|
|
/**
|
|
* @param Sabre\VObject\Component\VCalendar $vObject
|
|
* @return Sabre\VObject\Component\VEvent|null
|
|
*/
|
|
function dav_get_eventComponent(&$vObject)
|
|
{
|
|
$component = null;
|
|
$componentType = "";
|
|
foreach ($vObject->getComponents() as $component) {
|
|
if ($component->name !== 'VTIMEZONE') {
|
|
$componentType = $component->name;
|
|
break;
|
|
}
|
|
}
|
|
if ($componentType != "VEVENT") return null;
|
|
|
|
return $component;
|
|
}
|