2017-06-22 05:11:21 +00:00
< ? php
namespace Zotlabs\Module ;
2018-09-15 08:10:43 +00:00
use App ;
2019-05-13 03:52:10 +00:00
use DBA ;
use DateTime ;
2018-09-15 08:10:43 +00:00
use Zotlabs\Lib\Apps ;
2018-09-15 08:48:51 +00:00
use Zotlabs\Web\Controller ;
2019-05-13 03:52:10 +00:00
use Zotlabs\Web\HTTPSig ;
use Zotlabs\Storage\BasicAuth ;
use Zotlabs\Lib\System ;
2018-09-15 08:10:43 +00:00
2017-06-23 03:16:54 +00:00
require_once ( 'include/event.php' );
2017-09-01 03:45:13 +00:00
require_once ( 'include/auth.php' );
require_once ( 'include/security.php' );
2018-09-15 08:48:51 +00:00
class Cdav extends Controller {
2017-06-22 05:11:21 +00:00
function init () {
2017-09-01 03:45:13 +00:00
$record = null ;
$channel_login = false ;
2017-06-22 05:11:21 +00:00
if (( argv ( 1 ) !== 'calendar' ) && ( argv ( 1 ) !== 'addressbook' )) {
2017-09-01 03:45:13 +00:00
foreach ([ 'REDIRECT_REMOTE_USER' , 'HTTP_AUTHORIZATION' ] as $head ) {
/* Basic authentication */
if ( array_key_exists ( $head , $_SERVER ) && substr ( trim ( $_SERVER [ $head ]), 0 , 5 ) === 'Basic' ) {
$userpass = @ base64_decode ( substr ( trim ( $_SERVER [ $head ]), 6 )) ;
if ( strlen ( $userpass )) {
list ( $name , $password ) = explode ( ':' , $userpass );
$_SERVER [ 'PHP_AUTH_USER' ] = $name ;
$_SERVER [ 'PHP_AUTH_PW' ] = $password ;
}
break ;
2017-06-22 05:11:21 +00:00
}
2017-09-01 03:45:13 +00:00
/* Signature authentication */
if ( array_key_exists ( $head , $_SERVER ) && substr ( trim ( $_SERVER [ $head ]), 0 , 9 ) === 'Signature' ) {
2017-09-01 04:38:03 +00:00
if ( $head !== 'HTTP_AUTHORIZATION' ) {
$_SERVER [ 'HTTP_AUTHORIZATION' ] = $_SERVER [ $head ];
continue ;
}
2019-05-13 03:52:10 +00:00
$sigblock = HTTPSig :: parse_sigheader ( $_SERVER [ $head ]);
2017-09-01 03:45:13 +00:00
if ( $sigblock ) {
2017-12-08 02:56:26 +00:00
$keyId = str_replace ( 'acct:' , '' , $sigblock [ 'keyId' ]);
2017-09-01 03:45:13 +00:00
if ( $keyId ) {
$r = q ( " select * from hubloc where hubloc_addr = '%s' limit 1 " ,
dbesc ( $keyId )
);
if ( $r ) {
$c = channelx_by_hash ( $r [ 0 ][ 'hubloc_hash' ]);
if ( $c ) {
$a = q ( " select * from account where account_id = %d limit 1 " ,
2017-09-01 04:38:03 +00:00
intval ( $c [ 'channel_account_id' ])
2017-09-01 03:45:13 +00:00
);
if ( $a ) {
2017-09-01 04:38:03 +00:00
$record = [ 'channel' => $c , 'account' => $a [ 0 ] ];
$channel_login = $c [ 'channel_id' ];
2017-09-01 03:45:13 +00:00
}
}
}
if ( ! $record )
continue ;
if ( $record ) {
2019-05-13 03:52:10 +00:00
$verified = HTTPSig :: verify ( '' , $record [ 'channel' ][ 'channel_pubkey' ]);
2017-09-01 03:45:13 +00:00
if ( ! ( $verified && $verified [ 'header_signed' ] && $verified [ 'header_valid' ])) {
$record = null ;
}
if ( $record [ 'account' ]) {
authenticate_success ( $record [ 'account' ]);
if ( $channel_login ) {
change_channel ( $channel_login );
}
}
break ;
}
}
}
2017-06-22 05:11:21 +00:00
}
}
2017-09-01 03:45:13 +00:00
2017-06-22 05:11:21 +00:00
/**
* This server combines both CardDAV and CalDAV functionality into a single
* server . It is assumed that the server runs at the root of a HTTP domain ( be
* that a domainname - based vhost or a specific TCP port .
*
* This example also assumes that you ' re using SQLite and the database has
* already been setup ( along with the database tables ) .
*
* You may choose to use MySQL instead , just change the PDO connection
* statement .
*/
/**
* UTC or GMT is easy to work with , and usually recommended for any
* application .
*/
date_default_timezone_set ( 'UTC' );
/**
* Make sure this setting is turned on and reflect the root url for your WebDAV
* server .
*
* This can be for example the root / or a complete path to your server script .
*/
$baseUri = '/cdav/' ;
/**
* Database
*
*/
2019-05-13 03:52:10 +00:00
$pdo = DBA :: $dba -> db ;
2017-06-22 05:11:21 +00:00
// Autoloader
require_once 'vendor/autoload.php' ;
/**
* The backends . Yes we do really need all of them .
*
* This allows any developer to subclass just any of them and hook into their
* own backend systems .
*/
2019-05-13 03:52:10 +00:00
$auth = new BasicAuth ();
$auth -> setRealm ( ucfirst ( System :: get_platform_name ()) . ' ' . 'CalDAV/CardDAV' );
2017-06-22 05:11:21 +00:00
if ( local_channel ()) {
2018-09-15 08:10:43 +00:00
2017-06-22 05:11:21 +00:00
logger ( 'loggedin' );
2018-09-15 08:10:43 +00:00
2019-05-13 03:52:10 +00:00
if (( argv ( 1 ) == 'addressbooks' ) && ( ! Apps :: system_app_installed ( local_channel (), 'CardDAV' ))) {
2018-09-15 08:10:43 +00:00
killme ();
}
$channel = App :: get_channel ();
2017-06-22 05:11:21 +00:00
$auth -> setCurrentUser ( $channel [ 'channel_address' ]);
$auth -> channel_id = $channel [ 'channel_id' ];
$auth -> channel_hash = $channel [ 'channel_hash' ];
$auth -> channel_account_id = $channel [ 'channel_account_id' ];
2019-05-13 03:52:10 +00:00
if ( $channel [ 'channel_timezone' ]) {
2017-06-22 05:11:21 +00:00
$auth -> setTimezone ( $channel [ 'channel_timezone' ]);
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
$auth -> observer = $channel [ 'channel_hash' ];
2017-08-10 19:58:44 +00:00
$principalUri = 'principals/' . $channel [ 'channel_address' ];
2019-05-13 03:52:10 +00:00
if ( ! cdav_principal ( $principalUri )) {
2017-08-10 19:58:44 +00:00
$this -> activate ( $pdo , $channel );
2019-05-13 03:52:10 +00:00
if ( ! cdav_principal ( $principalUri )) {
2017-08-10 19:58:44 +00:00
return ;
}
}
2017-06-22 05:11:21 +00:00
}
$principalBackend = new \Sabre\DAVACL\PrincipalBackend\PDO ( $pdo );
$carddavBackend = new \Sabre\CardDAV\Backend\PDO ( $pdo );
$caldavBackend = new \Sabre\CalDAV\Backend\PDO ( $pdo );
/**
* The directory tree
*
* Basically this is an array which contains the 'top-level' directories in the
* WebDAV server .
*/
$nodes = [
// /principals
new \Sabre\CalDAV\Principal\Collection ( $principalBackend ),
2018-09-15 08:10:43 +00:00
2017-06-22 05:11:21 +00:00
// /calendars
new \Sabre\CalDAV\CalendarRoot ( $principalBackend , $caldavBackend ),
2018-09-15 08:10:43 +00:00
2017-06-22 05:11:21 +00:00
// /addressbook
2018-09-15 08:10:43 +00:00
new \Sabre\CardDAV\AddressBookRoot ( $principalBackend , $carddavBackend )
2017-06-22 05:11:21 +00:00
];
2018-09-15 08:10:43 +00:00
2017-06-22 05:11:21 +00:00
// The object tree needs in turn to be passed to the server class
$server = new \Sabre\DAV\Server ( $nodes );
2019-05-13 03:52:10 +00:00
if ( isset ( $baseUri )) {
2017-06-22 05:11:21 +00:00
$server -> setBaseUri ( $baseUri );
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
// Plugins
$server -> addPlugin ( new \Sabre\DAV\Auth\Plugin ( $auth ));
//$server->addPlugin(new \Sabre\DAV\Browser\Plugin());
$server -> addPlugin ( new \Sabre\DAV\Sync\Plugin ());
$server -> addPlugin ( new \Sabre\DAV\Sharing\Plugin ());
$server -> addPlugin ( new \Sabre\DAVACL\Plugin ());
// CalDAV plugins
$server -> addPlugin ( new \Sabre\CalDAV\Plugin ());
$server -> addPlugin ( new \Sabre\CalDAV\SharingPlugin ());
//$server->addPlugin(new \Sabre\CalDAV\Schedule\Plugin());
$server -> addPlugin ( new \Sabre\CalDAV\ICSExportPlugin ());
// CardDAV plugins
$server -> addPlugin ( new \Sabre\CardDAV\Plugin ());
$server -> addPlugin ( new \Sabre\CardDAV\VCFExportPlugin ());
// And off we go!
2021-01-20 19:15:41 +00:00
$server -> exec ();
2017-06-22 05:11:21 +00:00
killme ();
}
}
function post () {
2019-05-13 03:52:10 +00:00
if ( ! local_channel ())
2017-06-22 05:11:21 +00:00
return ;
2019-05-13 03:52:10 +00:00
if (( argv ( 1 ) === 'addressbook' ) && ( ! Apps :: system_app_installed ( local_channel (), 'CardDAV' ))) {
2018-09-15 08:10:43 +00:00
return ;
}
$channel = App :: get_channel ();
2017-07-04 04:20:22 +00:00
$principalUri = 'principals/' . $channel [ 'channel_address' ];
2017-06-22 05:11:21 +00:00
2019-05-13 03:52:10 +00:00
if ( ! cdav_principal ( $principalUri ))
2017-06-22 05:11:21 +00:00
return ;
2019-05-13 03:52:10 +00:00
$pdo = DBA :: $dba -> db ;
2017-06-22 05:11:21 +00:00
require_once 'vendor/autoload.php' ;
2019-05-13 03:52:10 +00:00
if ( argc () == 2 && argv ( 1 ) === 'calendar' ) {
2017-06-22 05:11:21 +00:00
$caldavBackend = new \Sabre\CalDAV\Backend\PDO ( $pdo );
$calendars = $caldavBackend -> getCalendarsForUser ( $principalUri );
2019-05-13 03:52:10 +00:00
// create new calendar
if ( $_REQUEST [ '{DAV:}displayname' ] && $_REQUEST [ 'create' ]) {
2017-06-22 05:11:21 +00:00
do {
$duplicate = false ;
$calendarUri = random_string ( 40 );
$r = q ( " SELECT uri FROM calendarinstances WHERE principaluri = '%s' AND uri = '%s' LIMIT 1 " ,
dbesc ( $principalUri ),
dbesc ( $calendarUri )
);
2019-05-13 03:52:10 +00:00
if ( $r ) {
2017-06-22 05:11:21 +00:00
$duplicate = true ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
} while ( $duplicate == true );
$properties = [
'{DAV:}displayname' => $_REQUEST [ '{DAV:}displayname' ],
'{http://apple.com/ns/ical/}calendar-color' => $_REQUEST [ 'color' ],
'{urn:ietf:params:xml:ns:caldav}calendar-description' => $channel [ 'channel_name' ]
];
$id = $caldavBackend -> createCalendar ( $principalUri , $calendarUri , $properties );
// set new calendar to be visible
set_pconfig ( local_channel (), 'cdav_calendar' , $id [ 0 ], 1 );
}
//create new calendar object via ajax request
2019-05-13 03:52:10 +00:00
if ( $_REQUEST [ 'submit' ] === 'create_event' && $_REQUEST [ 'title' ] && $_REQUEST [ 'target' ] && $_REQUEST [ 'dtstart' ]) {
2017-06-22 05:11:21 +00:00
$id = explode ( ':' , $_REQUEST [ 'target' ]);
2019-05-13 03:52:10 +00:00
if ( ! cdav_perms ( $id [ 0 ], $calendars , true ))
2017-06-22 05:11:21 +00:00
return ;
$title = $_REQUEST [ 'title' ];
2019-05-13 01:20:37 +00:00
$start = datetime_convert ( App :: $timezone , 'UTC' , $_REQUEST [ 'dtstart' ]);
2019-05-13 03:52:10 +00:00
$dtstart = new DateTime ( $start );
if ( $_REQUEST [ 'dtend' ]) {
2019-05-13 01:20:37 +00:00
$end = datetime_convert ( App :: $timezone , 'UTC' , $_REQUEST [ 'dtend' ]);
2019-05-13 03:52:10 +00:00
$dtend = new DateTime ( $end );
2019-05-13 01:20:37 +00:00
}
2017-06-22 05:11:21 +00:00
$description = $_REQUEST [ 'description' ];
$location = $_REQUEST [ 'location' ];
do {
$duplicate = false ;
$objectUri = random_string ( 40 ) . '.ics' ;
$r = q ( " SELECT uri FROM calendarobjects WHERE calendarid = %s AND uri = '%s' LIMIT 1 " ,
intval ( $id [ 0 ]),
dbesc ( $objectUri )
);
if ( count ( $r ))
$duplicate = true ;
} while ( $duplicate == true );
$vcalendar = new \Sabre\VObject\Component\VCalendar ([
'VEVENT' => [
'SUMMARY' => $title ,
'DTSTART' => $dtstart
]
]);
2019-05-13 01:20:37 +00:00
if ( $dtend ) {
2017-06-22 05:11:21 +00:00
$vcalendar -> VEVENT -> add ( 'DTEND' , $dtend );
2019-05-13 01:20:37 +00:00
$vcalendar -> VEVENT -> DTEND [ 'TZID' ] = App :: $timezone ;
}
2017-06-22 05:11:21 +00:00
if ( $description )
$vcalendar -> VEVENT -> add ( 'DESCRIPTION' , $description );
if ( $location )
$vcalendar -> VEVENT -> add ( 'LOCATION' , $location );
2019-05-13 01:20:37 +00:00
$vcalendar -> VEVENT -> DTSTART [ 'TZID' ] = App :: $timezone ;
2017-06-22 05:11:21 +00:00
$calendarData = $vcalendar -> serialize ();
$caldavBackend -> createCalendarObject ( $id , $objectUri , $calendarData );
killme ();
}
2019-05-13 03:52:10 +00:00
// edit calendar name and color
if ( $_REQUEST [ '{DAV:}displayname' ] && $_REQUEST [ 'edit' ] && $_REQUEST [ 'id' ]) {
2017-06-22 05:11:21 +00:00
$id = explode ( ':' , $_REQUEST [ 'id' ]);
2019-05-13 03:52:10 +00:00
if ( ! cdav_perms ( $id [ 0 ], $calendars )) {
2017-06-22 05:11:21 +00:00
return ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
$mutations = [
'{DAV:}displayname' => $_REQUEST [ '{DAV:}displayname' ],
'{http://apple.com/ns/ical/}calendar-color' => $_REQUEST [ 'color' ]
];
$patch = new \Sabre\DAV\PropPatch ( $mutations );
$caldavBackend -> updateCalendar ( $id , $patch );
$patch -> commit ();
}
2019-05-13 03:52:10 +00:00
// edit calendar object via ajax request
if ( $_REQUEST [ 'submit' ] === 'update_event' && $_REQUEST [ 'uri' ] && $_REQUEST [ 'title' ] && $_REQUEST [ 'target' ] && $_REQUEST [ 'dtstart' ]) {
2017-06-22 05:11:21 +00:00
$id = explode ( ':' , $_REQUEST [ 'target' ]);
2019-05-13 03:52:10 +00:00
if ( ! cdav_perms ( $id [ 0 ], $calendars , true ))
2017-06-22 05:11:21 +00:00
return ;
$uri = $_REQUEST [ 'uri' ];
$title = $_REQUEST [ 'title' ];
2019-05-13 01:20:37 +00:00
$start = datetime_convert ( App :: $timezone , 'UTC' , $_REQUEST [ 'dtstart' ]);
2019-05-13 03:52:10 +00:00
$dtstart = new DateTime ( $start );
if ( $_REQUEST [ 'dtend' ]) {
2019-05-13 01:20:37 +00:00
$end = datetime_convert ( App :: $timezone , 'UTC' , $_REQUEST [ 'dtend' ]);
2019-05-13 03:52:10 +00:00
$dtend = new DateTime ( $end );
2019-05-13 01:20:37 +00:00
}
2017-06-22 05:11:21 +00:00
$description = $_REQUEST [ 'description' ];
$location = $_REQUEST [ 'location' ];
$object = $caldavBackend -> getCalendarObject ( $id , $uri );
$vcalendar = \Sabre\VObject\Reader :: read ( $object [ 'calendardata' ]);
2019-05-13 03:52:10 +00:00
if ( $title ) {
2017-06-22 05:11:21 +00:00
$vcalendar -> VEVENT -> SUMMARY = $title ;
2019-05-13 03:52:10 +00:00
}
if ( $dtstart ) {
2017-06-22 05:11:21 +00:00
$vcalendar -> VEVENT -> DTSTART = $dtstart ;
2019-05-13 03:52:10 +00:00
}
if ( $dtend ) {
2017-06-22 05:11:21 +00:00
$vcalendar -> VEVENT -> DTEND = $dtend ;
2019-05-13 03:52:10 +00:00
}
else {
2017-06-22 05:11:21 +00:00
unset ( $vcalendar -> VEVENT -> DTEND );
2019-05-13 03:52:10 +00:00
}
if ( $description ) {
2017-06-22 05:11:21 +00:00
$vcalendar -> VEVENT -> DESCRIPTION = $description ;
2019-05-13 03:52:10 +00:00
}
if ( $location ) {
2017-06-22 05:11:21 +00:00
$vcalendar -> VEVENT -> LOCATION = $location ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
$calendarData = $vcalendar -> serialize ();
$caldavBackend -> updateCalendarObject ( $id , $uri , $calendarData );
killme ();
}
2019-05-13 03:52:10 +00:00
// delete calendar object via ajax request
if ( $_REQUEST [ 'delete' ] && $_REQUEST [ 'uri' ] && $_REQUEST [ 'target' ]) {
2017-06-22 05:11:21 +00:00
$id = explode ( ':' , $_REQUEST [ 'target' ]);
2019-05-13 03:52:10 +00:00
if ( ! cdav_perms ( $id [ 0 ], $calendars , true )) {
2017-06-22 05:11:21 +00:00
return ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
$uri = $_REQUEST [ 'uri' ];
$caldavBackend -> deleteCalendarObject ( $id , $uri );
killme ();
}
2019-05-13 03:52:10 +00:00
// edit calendar object date/timeme via ajax request (drag and drop)
if ( $_REQUEST [ 'update' ] && $_REQUEST [ 'id' ] && $_REQUEST [ 'uri' ]) {
2017-06-22 05:11:21 +00:00
$id = [ $_REQUEST [ 'id' ][ 0 ], $_REQUEST [ 'id' ][ 1 ]];
2019-05-13 03:52:10 +00:00
if ( ! cdav_perms ( $id [ 0 ], $calendars , true )) {
2017-06-22 05:11:21 +00:00
return ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
$uri = $_REQUEST [ 'uri' ];
2019-05-13 01:20:37 +00:00
$start = datetime_convert ( App :: $timezone , 'UTC' , $_REQUEST [ 'dtstart' ]);
2019-05-13 03:52:10 +00:00
$dtstart = new DateTime ( $start );
2019-05-13 01:20:37 +00:00
if ( $_REQUEST [ 'dtend' ]) {
$end = datetime_convert ( App :: $timezone , 'UTC' , $_REQUEST [ 'dtend' ]);
2019-05-13 03:52:10 +00:00
$dtend = new DateTime ( $end );
2019-05-13 01:20:37 +00:00
}
2017-06-22 05:11:21 +00:00
$object = $caldavBackend -> getCalendarObject ( $id , $uri );
$vcalendar = \Sabre\VObject\Reader :: read ( $object [ 'calendardata' ]);
2019-05-13 03:52:10 +00:00
if ( $dtstart ) {
2017-06-22 05:11:21 +00:00
$vcalendar -> VEVENT -> DTSTART = $dtstart ;
}
2019-05-13 03:52:10 +00:00
if ( $dtend ) {
2017-06-22 05:11:21 +00:00
$vcalendar -> VEVENT -> DTEND = $dtend ;
}
else {
unset ( $vcalendar -> VEVENT -> DTEND );
}
$calendarData = $vcalendar -> serialize ();
$caldavBackend -> updateCalendarObject ( $id , $uri , $calendarData );
killme ();
}
2019-05-13 03:52:10 +00:00
// share a calendar - this only works on local system (with channels on the same server)
if ( $_REQUEST [ 'sharee' ] && $_REQUEST [ 'share' ]) {
2017-06-22 05:11:21 +00:00
$id = [ intval ( $_REQUEST [ 'calendarid' ]), intval ( $_REQUEST [ 'instanceid' ])];
2019-05-13 03:52:10 +00:00
if ( ! cdav_perms ( $id [ 0 ], $calendars )) {
2017-06-22 05:11:21 +00:00
return ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
$hash = $_REQUEST [ 'sharee' ];
$sharee_arr = channelx_by_hash ( $hash );
$sharee = new \Sabre\DAV\Xml\Element\Sharee ();
2017-07-04 04:20:22 +00:00
$sharee -> href = 'mailto:' . $sharee_arr [ 'xchan_addr' ];
2017-06-22 05:11:21 +00:00
$sharee -> principal = 'principals/' . $sharee_arr [ 'channel_address' ];
$sharee -> access = intval ( $_REQUEST [ 'access' ]);
$sharee -> properties = [ '{DAV:}displayname' => $channel [ 'channel_name' ]];
$caldavBackend -> updateInvites ( $id , [ $sharee ]);
}
}
2019-05-13 03:52:10 +00:00
if ( argc () >= 2 && argv ( 1 ) === 'addressbook' ) {
2017-06-22 05:11:21 +00:00
$carddavBackend = new \Sabre\CardDAV\Backend\PDO ( $pdo );
$addressbooks = $carddavBackend -> getAddressBooksForUser ( $principalUri );
2019-05-13 03:52:10 +00:00
// create new addressbook
if ( $_REQUEST [ '{DAV:}displayname' ] && $_REQUEST [ 'create' ]) {
2017-06-22 05:11:21 +00:00
do {
$duplicate = false ;
$addressbookUri = random_string ( 20 );
$r = q ( " SELECT uri FROM addressbooks WHERE principaluri = '%s' AND uri = '%s' LIMIT 1 " ,
dbesc ( $principalUri ),
dbesc ( $addressbookUri )
);
2019-05-13 03:52:10 +00:00
if ( $r ) {
2017-06-22 05:11:21 +00:00
$duplicate = true ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
} while ( $duplicate == true );
$properties = [ '{DAV:}displayname' => $_REQUEST [ '{DAV:}displayname' ]];
$carddavBackend -> createAddressBook ( $principalUri , $addressbookUri , $properties );
}
2019-05-13 03:52:10 +00:00
// edit addressbook
if ( $_REQUEST [ '{DAV:}displayname' ] && $_REQUEST [ 'edit' ] && intval ( $_REQUEST [ 'id' ])) {
2017-06-22 05:11:21 +00:00
$id = $_REQUEST [ 'id' ];
2019-05-13 03:52:10 +00:00
if ( ! cdav_perms ( $id , $addressbooks )) {
2017-06-22 05:11:21 +00:00
return ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
$mutations = [
'{DAV:}displayname' => $_REQUEST [ '{DAV:}displayname' ]
];
$patch = new \Sabre\DAV\PropPatch ( $mutations );
$carddavBackend -> updateAddressBook ( $id , $patch );
$patch -> commit ();
}
2019-05-13 03:52:10 +00:00
// create addressbook card
if ( $_REQUEST [ 'create' ] && $_REQUEST [ 'target' ] && $_REQUEST [ 'fn' ]) {
2017-06-22 05:11:21 +00:00
$id = $_REQUEST [ 'target' ];
do {
$duplicate = false ;
$uri = random_string ( 40 ) . '.vcf' ;
$r = q ( " SELECT uri FROM cards WHERE addressbookid = %s AND uri = '%s' LIMIT 1 " ,
intval ( $id ),
dbesc ( $uri )
);
2019-05-13 03:52:10 +00:00
if ( $r ) {
2017-06-22 05:11:21 +00:00
$duplicate = true ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
} while ( $duplicate == true );
2019-05-13 03:52:10 +00:00
// TODO: this mostly duplictes the procedure in update addressbook card.
// Should move this part to a function to avoid duplication
2017-06-22 05:11:21 +00:00
$fn = $_REQUEST [ 'fn' ];
$vcard = new \Sabre\VObject\Component\VCard ([
'FN' => $fn ,
'N' => array_reverse ( explode ( ' ' , $fn ))
]);
$org = $_REQUEST [ 'org' ];
2019-05-13 03:52:10 +00:00
if ( $org ) {
2017-06-22 05:11:21 +00:00
$vcard -> ORG = $org ;
}
$title = $_REQUEST [ 'title' ];
2019-05-13 03:52:10 +00:00
if ( $title ) {
2017-06-22 05:11:21 +00:00
$vcard -> TITLE = $title ;
}
$tel = $_REQUEST [ 'tel' ];
$tel_type = $_REQUEST [ 'tel_type' ];
2019-05-13 03:52:10 +00:00
if ( $tel ) {
2017-06-22 05:11:21 +00:00
$i = 0 ;
2019-05-13 03:52:10 +00:00
foreach ( $tel as $item ) {
if ( $item ) {
2017-06-22 05:11:21 +00:00
$vcard -> add ( 'TEL' , $item , [ 'type' => $tel_type [ $i ]]);
}
$i ++ ;
}
}
$email = $_REQUEST [ 'email' ];
$email_type = $_REQUEST [ 'email_type' ];
2019-05-13 03:52:10 +00:00
if ( $email ) {
2017-06-22 05:11:21 +00:00
$i = 0 ;
2019-05-13 03:52:10 +00:00
foreach ( $email as $item ) {
if ( $item ) {
2017-06-22 05:11:21 +00:00
$vcard -> add ( 'EMAIL' , $item , [ 'type' => $email_type [ $i ]]);
}
$i ++ ;
}
}
$impp = $_REQUEST [ 'impp' ];
$impp_type = $_REQUEST [ 'impp_type' ];
2019-05-13 03:52:10 +00:00
if ( $impp ) {
2017-06-22 05:11:21 +00:00
$i = 0 ;
2019-05-13 03:52:10 +00:00
foreach ( $impp as $item ) {
if ( $item ) {
2017-06-22 05:11:21 +00:00
$vcard -> add ( 'IMPP' , $item , [ 'type' => $impp_type [ $i ]]);
}
$i ++ ;
}
}
$url = $_REQUEST [ 'url' ];
$url_type = $_REQUEST [ 'url_type' ];
2019-05-13 03:52:10 +00:00
if ( $url ) {
2017-06-22 05:11:21 +00:00
$i = 0 ;
2019-05-13 03:52:10 +00:00
foreach ( $url as $item ) {
if ( $item ) {
2017-06-22 05:11:21 +00:00
$vcard -> add ( 'URL' , $item , [ 'type' => $url_type [ $i ]]);
}
$i ++ ;
}
}
$adr = $_REQUEST [ 'adr' ];
$adr_type = $_REQUEST [ 'adr_type' ];
2019-05-13 03:52:10 +00:00
if ( $adr ) {
2017-06-22 05:11:21 +00:00
$i = 0 ;
2019-05-13 03:52:10 +00:00
foreach ( $adr as $item ) {
if ( $item ) {
2017-06-22 05:11:21 +00:00
$vcard -> add ( 'ADR' , $item , [ 'type' => $adr_type [ $i ]]);
}
$i ++ ;
}
}
$note = $_REQUEST [ 'note' ];
2019-05-13 03:52:10 +00:00
if ( $note ) {
2017-06-22 05:11:21 +00:00
$vcard -> NOTE = $note ;
}
$cardData = $vcard -> serialize ();
$carddavBackend -> createCard ( $id , $uri , $cardData );
}
2019-05-13 03:52:10 +00:00
// edit addressbook card
if ( $_REQUEST [ 'update' ] && $_REQUEST [ 'uri' ] && $_REQUEST [ 'target' ]) {
2017-06-22 05:11:21 +00:00
$id = $_REQUEST [ 'target' ];
2019-05-13 03:52:10 +00:00
if ( ! cdav_perms ( $id , $addressbooks )) {
2017-06-22 05:11:21 +00:00
return ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
$uri = $_REQUEST [ 'uri' ];
$object = $carddavBackend -> getCard ( $id , $uri );
$vcard = \Sabre\VObject\Reader :: read ( $object [ 'carddata' ]);
$fn = $_REQUEST [ 'fn' ];
2019-05-13 03:52:10 +00:00
if ( $fn ) {
2017-06-22 05:11:21 +00:00
$vcard -> FN = $fn ;
$vcard -> N = array_reverse ( explode ( ' ' , $fn ));
}
$org = $_REQUEST [ 'org' ];
2019-05-13 03:52:10 +00:00
if ( $org ) {
2017-06-22 05:11:21 +00:00
$vcard -> ORG = $org ;
}
else {
unset ( $vcard -> ORG );
}
$title = $_REQUEST [ 'title' ];
2019-05-13 03:52:10 +00:00
if ( $title ) {
2017-06-22 05:11:21 +00:00
$vcard -> TITLE = $title ;
}
else {
unset ( $vcard -> TITLE );
}
$tel = $_REQUEST [ 'tel' ];
$tel_type = $_REQUEST [ 'tel_type' ];
2019-05-13 03:52:10 +00:00
if ( $tel ) {
2017-06-22 05:11:21 +00:00
$i = 0 ;
unset ( $vcard -> TEL );
2019-05-13 03:52:10 +00:00
foreach ( $tel as $item ) {
if ( $item ) {
2017-06-22 05:11:21 +00:00
$vcard -> add ( 'TEL' , $item , [ 'type' => $tel_type [ $i ]]);
}
$i ++ ;
}
}
else {
unset ( $vcard -> TEL );
}
$email = $_REQUEST [ 'email' ];
$email_type = $_REQUEST [ 'email_type' ];
2019-05-13 03:52:10 +00:00
if ( $email ) {
2017-06-22 05:11:21 +00:00
$i = 0 ;
unset ( $vcard -> EMAIL );
2019-05-13 03:52:10 +00:00
foreach ( $email as $item ) {
if ( $item ) {
2017-06-22 05:11:21 +00:00
$vcard -> add ( 'EMAIL' , $item , [ 'type' => $email_type [ $i ]]);
}
$i ++ ;
}
}
else {
unset ( $vcard -> EMAIL );
}
$impp = $_REQUEST [ 'impp' ];
$impp_type = $_REQUEST [ 'impp_type' ];
2019-05-13 03:52:10 +00:00
if ( $impp ) {
2017-06-22 05:11:21 +00:00
$i = 0 ;
unset ( $vcard -> IMPP );
2019-05-13 03:52:10 +00:00
foreach ( $impp as $item ) {
if ( $item ) {
2017-06-22 05:11:21 +00:00
$vcard -> add ( 'IMPP' , $item , [ 'type' => $impp_type [ $i ]]);
}
$i ++ ;
}
}
else {
unset ( $vcard -> IMPP );
}
$url = $_REQUEST [ 'url' ];
$url_type = $_REQUEST [ 'url_type' ];
2019-05-13 03:52:10 +00:00
if ( $url ) {
2017-06-22 05:11:21 +00:00
$i = 0 ;
unset ( $vcard -> URL );
2019-05-13 03:52:10 +00:00
foreach ( $url as $item ) {
if ( $item ) {
2017-06-22 05:11:21 +00:00
$vcard -> add ( 'URL' , $item , [ 'type' => $url_type [ $i ]]);
}
$i ++ ;
}
}
else {
unset ( $vcard -> URL );
}
$adr = $_REQUEST [ 'adr' ];
$adr_type = $_REQUEST [ 'adr_type' ];
2019-05-13 03:52:10 +00:00
if ( $adr ) {
2017-06-22 05:11:21 +00:00
$i = 0 ;
unset ( $vcard -> ADR );
2019-05-13 03:52:10 +00:00
foreach ( $adr as $item ) {
if ( $item ) {
2017-06-22 05:11:21 +00:00
$vcard -> add ( 'ADR' , $item , [ 'type' => $adr_type [ $i ]]);
}
$i ++ ;
}
}
else {
unset ( $vcard -> ADR );
}
$note = $_REQUEST [ 'note' ];
2019-05-13 03:52:10 +00:00
if ( $note ) {
2017-06-22 05:11:21 +00:00
$vcard -> NOTE = $note ;
}
else {
unset ( $vcard -> NOTE );
}
$cardData = $vcard -> serialize ();
$carddavBackend -> updateCard ( $id , $uri , $cardData );
}
2019-05-13 03:52:10 +00:00
// delete addressbook card
if ( $_REQUEST [ 'delete' ] && $_REQUEST [ 'uri' ] && $_REQUEST [ 'target' ]) {
2017-06-22 05:11:21 +00:00
$id = $_REQUEST [ 'target' ];
2019-05-13 03:52:10 +00:00
if ( ! cdav_perms ( $id , $addressbooks )) {
2017-06-22 05:11:21 +00:00
return ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
$uri = $_REQUEST [ 'uri' ];
$carddavBackend -> deleteCard ( $id , $uri );
}
}
2019-05-13 03:52:10 +00:00
// Import calendar or addressbook
if (( $_FILES ) && array_key_exists ( 'userfile' , $_FILES ) && intval ( $_FILES [ 'userfile' ][ 'size' ]) && $_REQUEST [ 'target' ]) {
2017-06-22 05:11:21 +00:00
2019-05-13 01:20:37 +00:00
$src = $_FILES [ 'userfile' ][ 'tmp_name' ];
2017-06-22 05:11:21 +00:00
2019-05-13 03:52:10 +00:00
if ( $src ) {
2017-06-22 05:11:21 +00:00
2019-05-13 03:52:10 +00:00
if ( $_REQUEST [ 'c_upload' ]) {
if ( $_REQUEST [ 'target' ] == 'calendar' ) {
2019-05-13 01:20:37 +00:00
$result = parse_ical_file ( $src , local_channel ());
2019-05-13 03:52:10 +00:00
if ( $result ) {
2019-05-13 01:20:37 +00:00
info ( t ( 'Calendar entries imported.' ) . EOL );
2019-05-13 03:52:10 +00:00
}
else {
2019-05-13 01:20:37 +00:00
notice ( t ( 'No calendar entries found.' ) . EOL );
2019-05-13 03:52:10 +00:00
}
2019-05-13 01:20:37 +00:00
@ unlink ( $src );
return ;
}
2017-06-22 05:11:21 +00:00
$id = explode ( ':' , $_REQUEST [ 'target' ]);
$ext = 'ics' ;
$table = 'calendarobjects' ;
$column = 'calendarid' ;
2019-05-13 01:20:37 +00:00
$objects = new \Sabre\VObject\Splitter\ICalendar ( @ file_get_contents ( $src ));
2017-06-22 05:11:21 +00:00
$profile = \Sabre\VObject\Node :: PROFILE_CALDAV ;
$backend = new \Sabre\CalDAV\Backend\PDO ( $pdo );
}
2019-05-13 03:52:10 +00:00
if ( $_REQUEST [ 'a_upload' ]) {
2017-06-22 05:11:21 +00:00
$id [] = intval ( $_REQUEST [ 'target' ]);
$ext = 'vcf' ;
$table = 'cards' ;
$column = 'addressbookid' ;
2019-05-13 01:20:37 +00:00
$objects = new \Sabre\VObject\Splitter\VCard ( @ file_get_contents ( $src ));
2017-06-22 05:11:21 +00:00
$profile = \Sabre\VObject\Node :: PROFILE_CARDDAV ;
$backend = new \Sabre\CardDAV\Backend\PDO ( $pdo );
}
while ( $object = $objects -> getNext ()) {
2019-05-13 03:52:10 +00:00
if ( $_REQUEST [ 'a_upload' ]) {
2017-06-22 05:11:21 +00:00
$object = $object -> convert ( \Sabre\VObject\Document :: VCARD40 );
}
$ret = $object -> validate ( $profile & \Sabre\VObject\Node :: REPAIR );
2019-05-13 03:52:10 +00:00
// level 3 Means that the document is invalid,
// level 2 means a warning. A warning means it's valid but it could cause interopability issues,
// level 1 means that there was a problem earlier, but the problem was automatically repaired.
2017-06-22 05:11:21 +00:00
2019-05-13 03:52:10 +00:00
if ( $ret [ 0 ][ 'level' ] < 3 ) {
2017-06-22 05:11:21 +00:00
do {
$duplicate = false ;
$objectUri = random_string ( 40 ) . '.' . $ext ;
$r = q ( " SELECT uri FROM $table WHERE $column = %d AND uri = '%s' LIMIT 1 " ,
dbesc ( $id [ 0 ]),
dbesc ( $objectUri )
);
2019-05-13 03:52:10 +00:00
if ( $r ) {
2017-06-22 05:11:21 +00:00
$duplicate = true ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
} while ( $duplicate == true );
2019-05-13 03:52:10 +00:00
if ( $_REQUEST [ 'c_upload' ]) {
2017-06-22 05:11:21 +00:00
$backend -> createCalendarObject ( $id , $objectUri , $object -> serialize ());
}
2019-05-13 03:52:10 +00:00
if ( $_REQUEST [ 'a_upload' ]) {
2017-06-22 05:11:21 +00:00
$backend -> createCard ( $id [ 0 ], $objectUri , $object -> serialize ());
}
}
else {
2019-05-13 03:52:10 +00:00
if ( $_REQUEST [ 'c_upload' ]) {
2017-06-22 05:11:21 +00:00
notice ( '<strong>' . t ( 'INVALID EVENT DISMISSED!' ) . '</strong>' . EOL .
'<strong>' . t ( 'Summary: ' ) . '</strong>' . (( $object -> VEVENT -> SUMMARY ) ? $object -> VEVENT -> SUMMARY : t ( 'Unknown' )) . EOL .
'<strong>' . t ( 'Date: ' ) . '</strong>' . (( $object -> VEVENT -> DTSTART ) ? $object -> VEVENT -> DTSTART : t ( 'Unknown' )) . EOL .
'<strong>' . t ( 'Reason: ' ) . '</strong>' . $ret [ 0 ][ 'message' ] . EOL
);
}
2019-05-13 03:52:10 +00:00
if ( $_REQUEST [ 'a_upload' ]) {
2017-06-22 05:11:21 +00:00
notice ( '<strong>' . t ( 'INVALID CARD DISMISSED!' ) . '</strong>' . EOL .
'<strong>' . t ( 'Name: ' ) . '</strong>' . (( $object -> FN ) ? $object -> FN : t ( 'Unknown' )) . EOL .
'<strong>' . t ( 'Reason: ' ) . '</strong>' . $ret [ 0 ][ 'message' ] . EOL
);
}
}
}
}
@ unlink ( $src );
}
}
function get () {
2019-05-13 03:52:10 +00:00
if ( ! local_channel ()) {
2017-06-22 05:11:21 +00:00
return ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
2019-05-13 03:52:10 +00:00
if (( argv ( 1 ) === 'addressbook' ) && ( ! Apps :: system_app_installed ( local_channel (), 'CardDAV' ))) {
// Do not display any associated widgets at this point
2018-09-15 08:10:43 +00:00
App :: $pdl = '' ;
2019-05-13 01:20:37 +00:00
$o = '<b>' . t ( 'CardDAV App' ) . ' (' . t ( 'Not Installed' ) . '):</b><br>' ;
2018-09-15 08:10:43 +00:00
$o .= t ( 'CalDAV capable addressbook' );
return $o ;
}
2019-05-13 01:20:37 +00:00
App :: $profile_uid = local_channel ();
2018-09-15 08:10:43 +00:00
$channel = App :: get_channel ();
2017-07-04 04:20:22 +00:00
$principalUri = 'principals/' . $channel [ 'channel_address' ];
2017-06-22 05:11:21 +00:00
2019-05-13 03:52:10 +00:00
$pdo = DBA :: $dba -> db ;
2017-07-04 10:07:11 +00:00
require_once 'vendor/autoload.php' ;
head_add_css ( 'cdav.css' );
2017-06-22 05:11:21 +00:00
2019-05-13 03:52:10 +00:00
if ( ! cdav_principal ( $principalUri )) {
2017-07-04 10:07:11 +00:00
$this -> activate ( $pdo , $channel );
2019-05-13 03:52:10 +00:00
if ( ! cdav_principal ( $principalUri )) {
2017-06-22 05:11:21 +00:00
return ;
}
}
2019-05-13 03:52:10 +00:00
if ( argv ( 1 ) === 'calendar' ) {
2019-05-13 01:20:37 +00:00
nav_set_selected ( 'Calendar' );
2017-06-22 05:11:21 +00:00
$caldavBackend = new \Sabre\CalDAV\Backend\PDO ( $pdo );
$calendars = $caldavBackend -> getCalendarsForUser ( $principalUri );
}
2019-05-13 03:52:10 +00:00
// Display calendar(s) here
2019-05-13 01:20:37 +00:00
if ( argc () <= 3 && argv ( 1 ) === 'calendar' ) {
2017-06-22 05:11:21 +00:00
2019-05-13 01:20:37 +00:00
head_add_css ( '/library/fullcalendar/packages/core/main.min.css' );
head_add_css ( '/library/fullcalendar/packages/daygrid/main.min.css' );
head_add_css ( '/library/fullcalendar/packages/timegrid/main.min.css' );
head_add_css ( '/library/fullcalendar/packages/list/main.min.css' );
2017-06-23 03:16:54 +00:00
head_add_css ( 'cdav_calendar.css' );
2017-06-22 05:11:21 +00:00
2019-05-13 01:20:37 +00:00
head_add_js ( '/library/fullcalendar/packages/core/main.min.js' );
head_add_js ( '/library/fullcalendar/packages/interaction/main.min.js' );
head_add_js ( '/library/fullcalendar/packages/daygrid/main.min.js' );
head_add_js ( '/library/fullcalendar/packages/timegrid/main.min.js' );
head_add_js ( '/library/fullcalendar/packages/list/main.min.js' );
$sources = '' ;
$resource_id = '' ;
$resource = null ;
2019-05-13 03:52:10 +00:00
if ( argc () == 3 ) {
2019-05-13 01:20:37 +00:00
$resource_id = argv ( 2 );
2019-05-13 03:52:10 +00:00
}
2019-05-13 01:20:37 +00:00
2019-05-13 03:52:10 +00:00
if ( $resource_id ) {
2019-05-13 01:20:37 +00:00
$r = q ( " SELECT event.*, item.author_xchan, item.owner_xchan, item.plink, item.id as item_id FROM event LEFT JOIN item ON event.event_hash = item.resource_id
WHERE event . uid = % d AND event . event_hash = '%s' LIMIT 1 " ,
intval ( local_channel ()),
dbesc ( $resource_id )
);
2019-05-13 03:52:10 +00:00
if ( $r ) {
2019-05-13 01:20:37 +00:00
xchan_query ( $r );
$r = fetch_post_tags ( $r , true );
$r [ 0 ][ 'dtstart' ] = (( $r [ 0 ][ 'adjust' ]) ? datetime_convert ( 'UTC' , date_default_timezone_get (), $r [ 0 ][ 'dtstart' ], 'c' ) : datetime_convert ( 'UTC' , 'UTC' , $r [ 0 ][ 'dtstart' ], 'c' ));
$r [ 0 ][ 'dtend' ] = (( $r [ 0 ][ 'adjust' ]) ? datetime_convert ( 'UTC' , date_default_timezone_get (), $r [ 0 ][ 'dtend' ], 'c' ) : datetime_convert ( 'UTC' , 'UTC' , $r [ 0 ][ 'dtend' ], 'c' ));
$r [ 0 ][ 'plink' ] = [ $r [ 0 ][ 'plink' ], t ( 'Link to source' )];
$resource = $r [ 0 ];
2019-05-13 23:59:50 +00:00
$catsenabled = Apps :: system_app_installed ( local_channel (), 'Categories' );
2019-05-13 03:52:10 +00:00
2019-05-13 01:20:37 +00:00
$categories = '' ;
2019-05-13 03:52:10 +00:00
if ( $catsenabled ){
2019-05-13 01:20:37 +00:00
if ( $r [ 0 ][ 'term' ]) {
2019-05-13 03:52:10 +00:00
$categories = array_elm_to_str ( get_terms_oftype ( $r [ 0 ][ 'term' ], TERM_CATEGORY ), 'term' );
2019-05-13 01:20:37 +00:00
}
}
2019-05-13 03:52:10 +00:00
if ( $r [ 0 ][ 'dismissed' ] == 0 ) {
2019-05-13 01:20:37 +00:00
q ( " UPDATE event SET dismissed = 1 WHERE event.uid = %d AND event.event_hash = '%s' " ,
intval ( local_channel ()),
dbesc ( $resource_id )
);
}
}
}
2019-05-13 03:52:10 +00:00
if ( get_pconfig ( local_channel (), 'cdav_calendar' , 'calendar' )) {
2019-05-13 01:20:37 +00:00
$sources .= ' {
id : \ ' calendar\ ' ,
url : \ ' / calendar / json / \ ' ,
color : \ ' #3a87ad\'
}, ' ;
}
$calendars [] = [
'displayname' => $channel [ 'channel_name' ],
'id' => 'calendar'
];
2017-06-22 05:11:21 +00:00
2019-05-13 03:52:10 +00:00
foreach ( $calendars as $calendar ) {
2017-06-22 05:11:21 +00:00
$editable = (( $calendar [ 'share-access' ] == 2 ) ? 'false' : 'true' ); // false/true must be string since we're passing it to javascript
2019-05-13 01:20:37 +00:00
$color = (( $calendar [ '{http://apple.com/ns/ical/}calendar-color' ]) ? $calendar [ '{http://apple.com/ns/ical/}calendar-color' ] : '#6cad39' );
2017-06-22 05:11:21 +00:00
$sharer = (( $calendar [ 'share-access' ] == 3 ) ? $calendar [ '{urn:ietf:params:xml:ns:caldav}calendar-description' ] : '' );
$switch = get_pconfig ( local_channel (), 'cdav_calendar' , $calendar [ 'id' ][ 0 ]);
2019-05-13 03:52:10 +00:00
if ( $switch ) {
2017-06-22 05:11:21 +00:00
$sources .= ' {
2019-05-13 01:20:37 +00:00
id : ' . $calendar[' id '][0] . ' ,
2017-06-22 05:11:21 +00:00
url : \ '/cdav/calendar/json/' . $calendar [ 'id' ][ 0 ] . '/' . $calendar [ 'id' ][ 1 ] . ' \ ' ,
color : \ '' . $color . ' \ '
}, ' ;
}
2019-05-13 03:52:10 +00:00
if ( $calendar [ 'share-access' ] != 2 ) {
2017-06-22 05:11:21 +00:00
$writable_calendars [] = [
'displayname' => $calendar [ '{DAV:}displayname' ],
'sharer' => $sharer ,
'id' => $calendar [ 'id' ]
];
}
}
$sources = rtrim ( $sources , ', ' );
2019-05-13 01:20:37 +00:00
$first_day = feature_enabled ( local_channel (), 'cal_first_day' );
2017-06-22 05:11:21 +00:00
$first_day = (( $first_day ) ? $first_day : 0 );
$title = [ 'title' , t ( 'Event title' )];
2019-05-13 01:20:37 +00:00
$dtstart = [ 'dtstart' , t ( 'Start date and time' )];
$dtend = [ 'dtend' , t ( 'End date and time' )];
2017-06-22 05:11:21 +00:00
$description = [ 'description' , t ( 'Description' )];
$location = [ 'location' , t ( 'Location' )];
2019-05-13 23:59:50 +00:00
$catsenabled = Apps :: system_app_installed ( local_channel (), 'Categories' );
2019-05-13 01:20:37 +00:00
require_once ( 'include/acl_selectors.php' );
$accesslist = new \Zotlabs\Access\AccessControl ( $channel );
$perm_defaults = $accesslist -> get ();
$acl = populate_acl ( $perm_defaults , false , \Zotlabs\Lib\PermissionDescription :: fromGlobalPermission ( 'view_stream' ));
$permissions = $perm_defaults ;
2017-06-23 03:16:54 +00:00
$o .= replace_macros ( get_markup_template ( 'cdav_calendar.tpl' ), [
2017-06-22 05:11:21 +00:00
'$sources' => $sources ,
'$color' => $color ,
2018-09-15 08:10:43 +00:00
'$lang' => App :: $language ,
2019-05-13 01:20:37 +00:00
'$timezone' => App :: $timezone ,
2017-06-22 05:11:21 +00:00
'$first_day' => $first_day ,
'$prev' => t ( 'Previous' ),
'$next' => t ( 'Next' ),
'$today' => t ( 'Today' ),
'$month' => t ( 'Month' ),
'$week' => t ( 'Week' ),
'$day' => t ( 'Day' ),
'$list_month' => t ( 'List month' ),
'$list_week' => t ( 'List week' ),
'$list_day' => t ( 'List day' ),
'$title' => $title ,
2019-05-13 01:20:37 +00:00
'$calendars' => $calendars ,
2017-06-22 05:11:21 +00:00
'$writable_calendars' => $writable_calendars ,
'$dtstart' => $dtstart ,
'$dtend' => $dtend ,
'$description' => $description ,
'$location' => $location ,
'$more' => t ( 'More' ),
'$less' => t ( 'Less' ),
2019-05-13 01:20:37 +00:00
'$update' => t ( 'Update' ),
2017-06-22 05:11:21 +00:00
'$calendar_select_label' => t ( 'Select calendar' ),
2019-05-13 01:20:37 +00:00
'$calendar_optiopns_label' => [ t ( 'Channel Calendars' ), t ( 'CalDAV Calendars' )],
2017-06-22 05:11:21 +00:00
'$delete' => t ( 'Delete' ),
'$delete_all' => t ( 'Delete all' ),
'$cancel' => t ( 'Cancel' ),
2019-05-13 01:20:37 +00:00
'$create' => t ( 'Create' ),
'$recurrence_warning' => t ( 'Sorry! Editing of recurrent events is not yet implemented.' ),
'$channel_hash' => $channel [ 'channel_hash' ],
'$acl' => $acl ,
'$lockstate' => (( $accesslist -> is_private ()) ? 'lock' : 'unlock' ),
'$allow_cid' => acl2json ( $permissions [ 'allow_cid' ]),
'$allow_gid' => acl2json ( $permissions [ 'allow_gid' ]),
'$deny_cid' => acl2json ( $permissions [ 'deny_cid' ]),
'$deny_gid' => acl2json ( $permissions [ 'deny_gid' ]),
'$catsenabled' => $catsenabled ,
'$categories_label' => t ( 'Categories' ),
'$resource' => json_encode ( $resource ),
'$categories' => $categories
2017-06-22 05:11:21 +00:00
]);
return $o ;
}
2019-05-13 03:52:10 +00:00
// Provide json data for calendar
if ( argc () == 5 && argv ( 1 ) === 'calendar' && argv ( 2 ) === 'json' && intval ( argv ( 3 )) && intval ( argv ( 4 ))) {
2017-06-22 05:11:21 +00:00
2019-05-13 01:20:37 +00:00
$events = [];
2017-06-22 05:11:21 +00:00
$id = [ argv ( 3 ), argv ( 4 )];
2019-05-13 03:52:10 +00:00
if ( ! cdav_perms ( $id [ 0 ], $calendars )) {
2019-05-13 01:20:37 +00:00
json_return_and_die ( $events );
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
2019-05-13 03:52:10 +00:00
if ( x ( $_GET , 'start' )) {
2017-06-22 05:11:21 +00:00
$start = new \DateTime ( $_GET [ 'start' ]);
2019-05-13 03:52:10 +00:00
}
if ( x ( $_GET , 'end' )) {
2017-06-22 05:11:21 +00:00
$end = new \DateTime ( $_GET [ 'end' ]);
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
$filters [ 'name' ] = 'VCALENDAR' ;
$filters [ 'prop-filters' ][ 0 ][ 'name' ] = 'VEVENT' ;
$filters [ 'comp-filters' ][ 0 ][ 'name' ] = 'VEVENT' ;
$filters [ 'comp-filters' ][ 0 ][ 'time-range' ][ 'start' ] = $start ;
$filters [ 'comp-filters' ][ 0 ][ 'time-range' ][ 'end' ] = $end ;
$uris = $caldavBackend -> calendarQuery ( $id , $filters );
2019-05-13 03:52:10 +00:00
if ( $uris ) {
2017-06-22 05:11:21 +00:00
$objects = $caldavBackend -> getMultipleCalendarObjects ( $id , $uris );
2019-05-13 03:52:10 +00:00
foreach ( $objects as $object ) {
2017-06-22 05:11:21 +00:00
$vcalendar = \Sabre\VObject\Reader :: read ( $object [ 'calendardata' ]);
2019-05-13 03:52:10 +00:00
if ( isset ( $vcalendar -> VEVENT -> RRULE )) {
2019-05-13 01:20:37 +00:00
// expanding recurrent events seems to loose timezone info
// save it here so we can add it later
$recurrent_timezone = ( string ) $vcalendar -> VEVENT -> DTSTART [ 'TZID' ];
2017-06-22 05:11:21 +00:00
$vcalendar = $vcalendar -> expand ( $start , $end );
2019-05-13 01:20:37 +00:00
}
2017-06-22 05:11:21 +00:00
2019-05-13 03:52:10 +00:00
foreach ( $vcalendar -> VEVENT as $vevent ) {
2017-06-22 05:11:21 +00:00
$title = ( string ) $vevent -> SUMMARY ;
$dtstart = ( string ) $vevent -> DTSTART ;
$dtend = ( string ) $vevent -> DTEND ;
$description = ( string ) $vevent -> DESCRIPTION ;
$location = ( string ) $vevent -> LOCATION ;
2019-05-13 01:20:37 +00:00
$timezone = ( string ) $vevent -> DTSTART [ 'TZID' ];
2017-06-22 05:11:21 +00:00
$rw = (( cdav_perms ( $id [ 0 ], $calendars , true )) ? true : false );
$editable = $rw ? true : false ;
2019-05-13 01:20:37 +00:00
$recurrent = (( isset ( $vevent -> { 'RECURRENCE-ID' })) ? true : false );
2017-06-22 05:11:21 +00:00
2019-05-13 03:52:10 +00:00
if ( $recurrent ) {
2017-06-22 05:11:21 +00:00
$editable = false ;
2019-05-13 01:20:37 +00:00
$timezone = $recurrent_timezone ;
}
2017-06-22 05:11:21 +00:00
$allDay = false ;
// allDay event rules
2019-05-13 03:52:10 +00:00
if ( ! strpos ( $dtstart , 'T' ) && ! strpos ( $dtend , 'T' )) {
2017-06-22 05:11:21 +00:00
$allDay = true ;
2019-05-13 03:52:10 +00:00
}
if ( strpos ( $dtstart , 'T000000' ) && strpos ( $dtend , 'T000000' )) {
2017-06-22 05:11:21 +00:00
$allDay = true ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
$events [] = [
'calendar_id' => $id ,
'uri' => $object [ 'uri' ],
'title' => $title ,
2019-05-13 01:20:37 +00:00
'start' => datetime_convert ( $timezone , $timezone , $dtstart , 'c' ),
'end' => (( $dtend ) ? datetime_convert ( $timezone , $timezone , $dtend , 'c' ) : '' ),
2017-06-22 05:11:21 +00:00
'description' => $description ,
'location' => $location ,
'allDay' => $allDay ,
'editable' => $editable ,
'recurrent' => $recurrent ,
'rw' => $rw
];
}
}
}
2019-05-13 01:20:37 +00:00
json_return_and_die ( $events );
2017-06-22 05:11:21 +00:00
}
2019-05-13 03:52:10 +00:00
// enable/disable calendars
if ( argc () == 5 && argv ( 1 ) === 'calendar' && argv ( 2 ) === 'switch' && argv ( 3 ) && ( argv ( 4 ) == 1 || argv ( 4 ) == 0 )) {
2017-06-22 05:11:21 +00:00
$id = argv ( 3 );
2019-05-13 03:52:10 +00:00
if ( ! cdav_perms ( $id , $calendars )) {
2017-06-22 05:11:21 +00:00
killme ();
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
set_pconfig ( local_channel (), 'cdav_calendar' , argv ( 3 ), argv ( 4 ));
killme ();
}
2019-05-13 03:52:10 +00:00
// drop calendar
if ( argc () == 5 && argv ( 1 ) === 'calendar' && argv ( 2 ) === 'drop' && intval ( argv ( 3 )) && intval ( argv ( 4 ))) {
2017-06-22 05:11:21 +00:00
$id = [ argv ( 3 ), argv ( 4 )];
2019-05-13 03:52:10 +00:00
if ( ! cdav_perms ( $id [ 0 ], $calendars )) {
2017-06-22 05:11:21 +00:00
killme ();
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
$caldavBackend -> deleteCalendar ( $id );
killme ();
}
2019-05-13 03:52:10 +00:00
// drop sharee
if ( argc () == 6 && argv ( 1 ) === 'calendar' && argv ( 2 ) === 'dropsharee' && intval ( argv ( 3 )) && intval ( argv ( 4 ))) {
2017-06-22 05:11:21 +00:00
$id = [ argv ( 3 ), argv ( 4 )];
$hash = argv ( 5 );
2019-05-13 03:52:10 +00:00
if ( ! cdav_perms ( $id [ 0 ], $calendars )) {
2017-06-22 05:11:21 +00:00
killme ();
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
$sharee_arr = channelx_by_hash ( $hash );
$sharee = new \Sabre\DAV\Xml\Element\Sharee ();
2017-07-04 04:20:22 +00:00
$sharee -> href = 'mailto:' . $sharee_arr [ 'xchan_addr' ];
2017-06-22 05:11:21 +00:00
$sharee -> principal = 'principals/' . $sharee_arr [ 'channel_address' ];
$sharee -> access = 4 ;
$caldavBackend -> updateInvites ( $id , [ $sharee ]);
killme ();
}
2019-05-13 03:52:10 +00:00
if ( argv ( 1 ) === 'addressbook' ) {
2017-10-09 19:22:57 +00:00
nav_set_selected ( 'CardDAV' );
2017-06-22 05:11:21 +00:00
$carddavBackend = new \Sabre\CardDAV\Backend\PDO ( $pdo );
$addressbooks = $carddavBackend -> getAddressBooksForUser ( $principalUri );
}
2019-05-13 03:52:10 +00:00
// Display Adressbook here
if ( argc () == 3 && argv ( 1 ) === 'addressbook' && intval ( argv ( 2 ))) {
2017-06-22 05:11:21 +00:00
$id = argv ( 2 );
$displayname = cdav_perms ( $id , $addressbooks );
2019-05-13 03:52:10 +00:00
if ( ! $displayname ) {
2017-06-22 05:11:21 +00:00
return ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
2017-06-23 03:16:54 +00:00
head_add_css ( 'cdav_addressbook.css' );
2017-06-22 05:11:21 +00:00
$o = '' ;
$sabrecards = $carddavBackend -> getCards ( $id );
2019-05-13 03:52:10 +00:00
foreach ( $sabrecards as $sabrecard ) {
2017-06-22 05:11:21 +00:00
$uris [] = $sabrecard [ 'uri' ];
}
2019-05-13 03:52:10 +00:00
if ( $uris ) {
2017-06-22 05:11:21 +00:00
$objects = $carddavBackend -> getMultipleCards ( $id , $uris );
2019-05-13 03:52:10 +00:00
foreach ( $objects as $object ) {
2017-06-22 05:11:21 +00:00
$vcard = \Sabre\VObject\Reader :: read ( $object [ 'carddata' ]);
$photo = '' ;
2019-05-13 03:52:10 +00:00
if ( $vcard -> PHOTO ) {
2017-06-22 05:11:21 +00:00
$photo_value = strtolower ( $vcard -> PHOTO -> getValueType ()); // binary or uri
2019-05-13 03:52:10 +00:00
if ( $photo_value === 'binary' ) {
2017-06-22 05:11:21 +00:00
$photo_type = strtolower ( $vcard -> PHOTO [ 'TYPE' ]); // mime jpeg, png or gif
$photo = 'data:image/' . $photo_type . ';base64,' . base64_encode (( string ) $vcard -> PHOTO );
}
else {
$url = parse_url (( string ) $vcard -> PHOTO );
$photo = 'data:' . $url [ 'path' ];
}
}
$fn = '' ;
2019-05-13 03:52:10 +00:00
if ( $vcard -> FN ) {
2017-06-22 05:11:21 +00:00
$fn = ( string ) $vcard -> FN ;
}
$org = '' ;
2019-05-13 03:52:10 +00:00
if ( $vcard -> ORG ) {
2017-06-22 05:11:21 +00:00
$org = ( string ) $vcard -> ORG ;
}
$title = '' ;
2019-05-13 03:52:10 +00:00
if ( $vcard -> TITLE ) {
2017-06-22 05:11:21 +00:00
$title = ( string ) $vcard -> TITLE ;
}
$tels = [];
2019-05-13 03:52:10 +00:00
if ( $vcard -> TEL ) {
foreach ( $vcard -> TEL as $tel ) {
2017-06-22 05:11:21 +00:00
$type = (( $tel [ 'TYPE' ]) ? translate_type (( string ) $tel [ 'TYPE' ]) : '' );
$tels [] = [
'type' => $type ,
'nr' => ( string ) $tel
];
}
}
$emails = [];
2019-05-13 03:52:10 +00:00
if ( $vcard -> EMAIL ) {
foreach ( $vcard -> EMAIL as $email ) {
2017-06-22 05:11:21 +00:00
$type = (( $email [ 'TYPE' ]) ? translate_type (( string ) $email [ 'TYPE' ]) : '' );
$emails [] = [
'type' => $type ,
'address' => ( string ) $email
];
}
}
$impps = [];
2019-05-13 03:52:10 +00:00
if ( $vcard -> IMPP ) {
foreach ( $vcard -> IMPP as $impp ) {
2017-06-22 05:11:21 +00:00
$type = (( $impp [ 'TYPE' ]) ? translate_type (( string ) $impp [ 'TYPE' ]) : '' );
$impps [] = [
'type' => $type ,
'address' => ( string ) $impp
];
}
}
$urls = [];
2019-05-13 03:52:10 +00:00
if ( $vcard -> URL ) {
foreach ( $vcard -> URL as $url ) {
2017-06-22 05:11:21 +00:00
$type = (( $url [ 'TYPE' ]) ? translate_type (( string ) $url [ 'TYPE' ]) : '' );
$urls [] = [
'type' => $type ,
'address' => ( string ) $url
];
}
}
$adrs = [];
2019-05-13 03:52:10 +00:00
if ( $vcard -> ADR ) {
foreach ( $vcard -> ADR as $adr ) {
2017-06-22 05:11:21 +00:00
$type = (( $adr [ 'TYPE' ]) ? translate_type (( string ) $adr [ 'TYPE' ]) : '' );
$adrs [] = [
'type' => $type ,
'address' => $adr -> getParts ()
];
}
}
$note = '' ;
2019-05-13 03:52:10 +00:00
if ( $vcard -> NOTE ) {
2017-06-22 05:11:21 +00:00
$note = ( string ) $vcard -> NOTE ;
}
$cards [] = [
'id' => $object [ 'id' ],
'uri' => $object [ 'uri' ],
'photo' => $photo ,
'fn' => $fn ,
'org' => $org ,
'title' => $title ,
'tels' => $tels ,
'emails' => $emails ,
'impps' => $impps ,
'urls' => $urls ,
'adrs' => $adrs ,
'note' => $note
];
}
usort ( $cards , function ( $a , $b ) { return strcasecmp ( $a [ 'fn' ], $b [ 'fn' ]); });
}
2017-06-23 03:16:54 +00:00
$o .= replace_macros ( get_markup_template ( 'cdav_addressbook.tpl' ), [
2017-06-22 05:11:21 +00:00
'$id' => $id ,
'$cards' => $cards ,
'$displayname' => $displayname ,
'$name_label' => t ( 'Name' ),
'$org_label' => t ( 'Organisation' ),
'$title_label' => t ( 'Title' ),
'$tel_label' => t ( 'Phone' ),
'$email_label' => t ( 'Email' ),
'$impp_label' => t ( 'Instant messenger' ),
'$url_label' => t ( 'Website' ),
'$adr_label' => t ( 'Address' ),
'$note_label' => t ( 'Note' ),
'$mobile' => t ( 'Mobile' ),
'$home' => t ( 'Home' ),
'$work' => t ( 'Work' ),
'$other' => t ( 'Other' ),
'$add_card' => t ( 'Add Contact' ),
'$add_field' => t ( 'Add Field' ),
'$create' => t ( 'Create' ),
'$update' => t ( 'Update' ),
'$delete' => t ( 'Delete' ),
'$cancel' => t ( 'Cancel' ),
'$po_box' => t ( 'P.O. Box' ),
'$extra' => t ( 'Additional' ),
'$street' => t ( 'Street' ),
'$locality' => t ( 'Locality' ),
'$region' => t ( 'Region' ),
'$zip_code' => t ( 'ZIP Code' ),
'$country' => t ( 'Country' )
]);
return $o ;
}
2019-05-13 03:52:10 +00:00
// delete addressbook
if ( argc () > 3 && argv ( 1 ) === 'addressbook' && argv ( 2 ) === 'drop' && intval ( argv ( 3 ))) {
2017-06-22 05:11:21 +00:00
$id = argv ( 3 );
2019-05-13 03:52:10 +00:00
if ( ! cdav_perms ( $id , $addressbooks )) {
2017-06-22 05:11:21 +00:00
return ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
$carddavBackend -> deleteAddressBook ( $id );
killme ();
}
}
2017-07-04 10:07:11 +00:00
function activate ( $pdo , $channel ) {
2017-06-22 05:11:21 +00:00
2019-05-13 03:52:10 +00:00
if ( ! $channel ) {
2017-06-22 05:11:21 +00:00
return ;
2019-05-13 03:52:10 +00:00
}
2017-06-22 05:11:21 +00:00
2017-07-04 04:20:22 +00:00
$uri = 'principals/' . $channel [ 'channel_address' ];
2017-06-22 05:11:21 +00:00
$r = q ( " select * from principals where uri = '%s' limit 1 " ,
dbesc ( $uri )
);
if ( $r ) {
$r = q ( " update principals set email = '%s', displayname = '%s' where uri = '%s' " ,
dbesc ( $channel [ 'xchan_addr' ]),
dbesc ( $channel [ 'channel_name' ]),
dbesc ( $uri )
);
}
else {
$r = q ( " insert into principals ( uri, email, displayname ) values('%s','%s','%s') " ,
dbesc ( $uri ),
dbesc ( $channel [ 'xchan_addr' ]),
dbesc ( $channel [ 'channel_name' ])
);
2019-05-13 03:52:10 +00:00
// create default calendar
2017-07-04 10:07:11 +00:00
$caldavBackend = new \Sabre\CalDAV\Backend\PDO ( $pdo );
$properties = [
'{DAV:}displayname' => t ( 'Default Calendar' ),
2019-05-13 01:20:37 +00:00
'{http://apple.com/ns/ical/}calendar-color' => '#6cad39' ,
2017-07-04 10:07:11 +00:00
'{urn:ietf:params:xml:ns:caldav}calendar-description' => $channel [ 'channel_name' ]
];
2017-06-22 05:11:21 +00:00
2017-07-04 10:07:11 +00:00
$id = $caldavBackend -> createCalendar ( $uri , 'default' , $properties );
set_pconfig ( local_channel (), 'cdav_calendar' , $id [ 0 ], 1 );
2019-05-13 01:20:37 +00:00
set_pconfig ( local_channel (), 'cdav_calendar' , 'calendar' , 1 );
2017-06-22 05:11:21 +00:00
2019-05-13 03:52:10 +00:00
// create default addressbook
2017-07-04 10:07:11 +00:00
$carddavBackend = new \Sabre\CardDAV\Backend\PDO ( $pdo );
$properties = [ '{DAV:}displayname' => t ( 'Default Addressbook' )];
2017-11-30 12:40:36 +00:00
$carddavBackend -> createAddressBook ( $uri , 'default' , $properties );
2017-07-04 10:07:11 +00:00
2017-06-22 05:11:21 +00:00
}
}
}