2008-10-08 09:45:35 +02:00
< ? php
/**
2011-04-11 11:29:39 +02:00
* EGroupware - InfoLog - iCalendar Parser
2008-10-08 09:45:35 +02:00
*
* @ link http :// www . egroupware . org
* @ author Lars Kneschke < lkneschke @ egroupware . org >
2009-07-15 22:04:17 +02:00
* @ author Joerg Lehrke < jlehrke @ noc . de >
2011-04-11 11:29:39 +02:00
* @ author Ralf Becker < RalfBecker @ outdoor - training . de >
2008-10-08 09:45:35 +02:00
* @ package infolog
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
* @ version $Id $
*/
2016-04-05 00:39:49 +02:00
use EGroupware\Api ;
2016-04-30 19:05:23 +02:00
use EGroupware\Api\Acl ;
2016-04-05 00:39:49 +02:00
2008-10-08 09:45:35 +02:00
/**
* InfoLog : Create and parse iCal ' s
*/
class infolog_ical extends infolog_bo
{
2009-07-15 22:04:17 +02:00
/**
2010-01-09 19:04:21 +01:00
* @ var array $priority_egw2ical conversion of the priority egw => ical
2009-07-15 22:04:17 +02:00
*/
2010-01-09 19:04:21 +01:00
var $priority_egw2ical = array (
0 => 9 , // low
1 => 5 , // normal
2 => 3 , // high
3 => 1 , // urgent
2008-10-08 09:45:35 +02:00
);
2009-07-15 22:04:17 +02:00
/**
2010-01-09 19:04:21 +01:00
* @ var array $priority_ical2egw conversion of the priority ical => egw
2009-07-15 22:04:17 +02:00
*/
2010-01-09 19:04:21 +01:00
var $priority_ical2egw = array (
9 => 0 , 8 => 0 , 7 => 0 , // low
6 => 1 , 5 => 1 , 4 => 1 , 0 => 1 , // normal
3 => 2 , 2 => 2 , // high
1 => 3 , // urgent
);
/**
* @ var array $priority_egw2funambol conversion of the priority egw => funambol
*/
var $priority_egw2funambol = array (
0 => 0 , // low
1 => 1 , // normal
2 => 2 , // high
3 => 2 , // urgent
);
/**
* @ var array $priority_funambol2egw conversion of the priority funambol => egw
*/
var $priority_funambol2egw = array (
0 => 0 , // low
1 => 1 , // normal
2 => 3 , // high
2008-10-08 09:45:35 +02:00
);
2008-11-03 10:36:20 +01:00
/**
* manufacturer and name of the sync - client
*
* @ var string
*/
var $productManufacturer = 'file' ;
var $productName = '' ;
2009-07-15 22:04:17 +02:00
/**
* Shall we use the UID extensions of the description field ?
*
* @ var boolean
*/
var $uidExtension = false ;
2010-02-09 22:56:39 +01:00
/**
* user preference : Use this timezone for import from and export to device
*
* @ var string
*/
var $tzid = null ;
2009-07-15 22:04:17 +02:00
/**
* Client CTCap Properties
*
* @ var array
*/
var $clientProperties ;
2019-04-24 00:17:12 +02:00
/**
* Entry callback
* If set , this will be called on each discovered etry so it can be
* modified . Entry is passed by reference , return true to keep the event
* or false to skip it .
*
* @ var callable
*/
var $entry_callback = null ;
2010-01-09 19:04:21 +01:00
/**
* Set Logging
*
* @ var boolean
*/
var $log = false ;
var $logfile = " /tmp/log-infolog-vcal " ;
2009-07-15 22:04:17 +02:00
/**
* Constructor
*
* @ param array $_clientProperties client properties
*/
function __construct ( & $_clientProperties = array ())
{
parent :: __construct ();
2010-01-09 19:04:21 +01:00
if ( $this -> log ) $this -> logfile = $GLOBALS [ 'egw_info' ][ 'server' ][ 'temp_dir' ] . " /log-infolog-vcal " ;
2009-07-15 22:04:17 +02:00
$this -> clientProperties = $_clientProperties ;
}
2012-04-11 18:51:23 +02:00
/**
* Exports multiple InfoLogs
*
* @ param array $tasks array of info_ids or task arrays
2015-06-22 17:36:23 +02:00
* @ param string $_version = '2.0'
* @ param string $_method = null only set for iTip messages
* @ param string $charset = 'UTF-8'
2012-04-11 18:51:23 +02:00
* @ return string | boolean string with vCal or false on error ( eg . no permission to read the event )
*/
function exportVCalendar ( array $tasks , $_version = '2.0' , $_method = null , $charset = 'UTF-8' )
{
2015-06-22 17:36:23 +02:00
$vcal = new Horde_Icalendar ;
2012-04-11 18:51:23 +02:00
foreach ( $tasks as $task )
{
if ( ! $this -> exportVTODO ( $task , $_version , $_method , $charset , $vcal ))
{
return false ;
}
}
return $vcal -> exportVCalendar ();
}
2008-10-08 09:45:35 +02:00
/**
* Exports one InfoLog tast to an iCalendar VTODO
*
2010-03-07 00:06:43 +01:00
* @ param int | array $task infolog_id or infolog - tasks data
2015-06-22 17:36:23 +02:00
* @ param string $_version = '2.0' could be '1.0' too
* @ param string $_method = 'PUBLISH'
* @ param string $charset = 'UTF-8' encoding of the vcalendar , default UTF - 8
* @ param Horde_Icalendar $vcal = null optional iCalendar object to add vtodo to
2010-03-22 19:03:23 +01:00
*
* @ return string | boolean string with vCal or false on error ( eg . no permission to read the event )
2008-10-08 09:45:35 +02:00
*/
2015-06-22 17:36:23 +02:00
function exportVTODO ( $task , $_version = '2.0' , $_method = 'PUBLISH' , $charset = 'UTF-8' , Horde_Icalendar $vcal = null )
2008-10-08 09:45:35 +02:00
{
2010-03-07 00:06:43 +01:00
if ( is_array ( $task ))
{
$taskData = $task ;
}
else
{
if ( ! ( $taskData = $this -> read ( $task , true , 'server' ))) return false ;
}
2008-10-08 09:45:35 +02:00
2009-07-15 22:04:17 +02:00
if ( $taskData [ 'info_id_parent' ])
{
$parent = $this -> read ( $taskData [ 'info_id_parent' ]);
$taskData [ 'info_id_parent' ] = $parent [ 'info_uid' ];
}
else
{
$taskData [ 'info_id_parent' ] = '' ;
}
2008-10-08 09:45:35 +02:00
2009-07-15 22:04:17 +02:00
if ( $this -> uidExtension )
{
if ( ! preg_match ( '/\[UID:.+\]/m' , $taskData [ 'info_des' ]))
{
$taskData [ 'info_des' ] .= " \n [UID: " . $taskData [ 'info_uid' ] . " ] " ;
if ( $taskData [ 'info_id_parent' ] != '' )
{
$taskData [ 'info_des' ] .= " \n [PARENT_UID: " . $taskData [ 'info_id_parent' ] . " ] " ;
}
}
}
if ( ! empty ( $taskData [ 'info_cat' ]))
{
$cats = $this -> get_categories ( array ( $taskData [ 'info_cat' ]));
$taskData [ 'info_cat' ] = $cats [ 0 ];
}
2016-04-30 19:05:23 +02:00
$taskData = Api\Translation :: convert ( $taskData ,
Api\Translation :: charset (), $charset );
2008-10-08 09:45:35 +02:00
2010-03-07 00:06:43 +01:00
if ( $this -> log )
{
error_log ( __FILE__ . '[' . __LINE__ . '] ' . __METHOD__ . " () \n " .
array2string ( $taskData ) . " \n " , 3 , $this -> logfile );
}
2015-06-22 17:36:23 +02:00
if ( ! isset ( $vcal )) $vcal = new Horde_Icalendar ;
2011-10-05 11:24:08 +02:00
$vcal -> setAttribute ( 'PRODID' , '-//EGroupware//NONSGML EGroupware InfoLog ' . $GLOBALS [ 'egw_info' ][ 'apps' ][ 'infolog' ][ 'version' ] . '//' .
2012-04-11 18:51:23 +02:00
strtoupper ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'lang' ]), array (), false );
$vcal -> setAttribute ( 'VERSION' , $_version , array (), false );
if ( $_method ) $vcal -> setAttribute ( 'METHOD' , $_method , array (), false );
2008-10-08 09:45:35 +02:00
2010-02-09 22:56:39 +01:00
$tzid = $this -> tzid ;
if ( $tzid && $tzid != 'UTC' )
{
// check if we have vtimezone component data for tzid of event, if not default to user timezone (default to server tz)
2011-10-08 20:40:29 +02:00
if ( ! calendar_timezones :: add_vtimezone ( $vcal , $tzid ))
2010-02-09 22:56:39 +01:00
{
2016-04-30 19:05:23 +02:00
error_log ( __METHOD__ . " () unknown TZID=' $tzid ', defaulting to user timezone ' " . Api\DateTime :: $user_timezone -> getName () . " '! " );
calendar_timezones :: add_vtimezone ( $vcal , Api\DateTime :: $user_timezone -> getName ());
2010-02-09 22:56:39 +01:00
$tzid = null ;
}
if ( ! isset ( self :: $tz_cache [ $tzid ]))
{
self :: $tz_cache [ $tzid ] = calendar_timezones :: DateTimeZone ( $tzid );
}
}
2015-06-22 17:36:23 +02:00
$vevent = Horde_Icalendar :: newComponent ( 'VTODO' , $vcal );
2008-10-08 09:45:35 +02:00
2009-07-15 22:04:17 +02:00
if ( ! isset ( $this -> clientProperties [ 'SUMMARY' ][ 'Size' ]))
{
// make SUMMARY a required field
$this -> clientProperties [ 'SUMMARY' ][ 'Size' ] = 0xFFFF ;
$this -> clientProperties [ 'SUMMARY' ][ 'NoTruncate' ] = false ;
}
2008-10-08 09:45:35 +02:00
// set fields that may contain non-ascii chars and encode them if necessary
2009-07-15 22:04:17 +02:00
foreach ( array (
2012-01-31 19:01:16 +01:00
'SUMMARY' => $taskData [ 'info_subject' ],
'DESCRIPTION' => $taskData [ 'info_des' ],
'LOCATION' => $taskData [ 'info_location' ],
'RELATED-TO' => $taskData [ 'info_id_parent' ],
'UID' => $taskData [ 'info_uid' ],
'CATEGORIES' => $taskData [ 'info_cat' ],
2017-07-11 09:00:47 +02:00
'X-INFOLOG-TYPE' => $taskData [ 'info_type' ],
2012-01-31 19:01:16 +01:00
) as $field => $value )
2008-10-08 09:45:35 +02:00
{
2009-07-15 22:04:17 +02:00
if ( isset ( $this -> clientProperties [ $field ][ 'Size' ]))
2008-10-08 09:45:35 +02:00
{
2009-07-15 22:04:17 +02:00
$size = $this -> clientProperties [ $field ][ 'Size' ];
$noTruncate = $this -> clientProperties [ $field ][ 'NoTruncate' ];
2010-01-10 20:02:16 +01:00
if ( $this -> log && $size > 0 )
{
error_log ( __FILE__ . '[' . __LINE__ . '] ' . __METHOD__ .
" () $field Size: $size , NoTruncate: " .
( $noTruncate ? 'TRUE' : 'FALSE' ) . " \n " , 3 , $this -> logfile );
}
//Horde::logMessage("VTODO $field Size: $size, NoTruncate: " .
// ($noTruncate ? 'TRUE' : 'FALSE'), __FILE__, __LINE__, PEAR_LOG_DEBUG);
2009-07-15 22:04:17 +02:00
}
else
{
$size = - 1 ;
$noTruncate = false ;
}
$cursize = strlen ( $value );
if (( $size > 0 ) && $cursize > $size )
{
if ( $noTruncate )
{
2010-01-10 20:02:16 +01:00
if ( $this -> log )
{
error_log ( __FILE__ . '[' . __LINE__ . '] ' . __METHOD__ .
" () $field omitted due to maximum size $size\n " , 3 , $this -> logfile );
}
//Horde::logMessage("VTODO $field omitted due to maximum size $size",
// __FILE__, __LINE__, PEAR_LOG_WARNING);
2009-07-15 22:04:17 +02:00
continue ; // skip field
}
// truncate the value to size
$value = substr ( $value , 0 , $size - 1 );
2010-01-10 20:02:16 +01:00
if ( $this -> log )
{
error_log ( __FILE__ . '[' . __LINE__ . '] ' . __METHOD__ .
" () $field truncated to maximum size $size\n " , 3 , $this -> logfile );
}
//Horde::logMessage("VTODO $field truncated to maximum size $size",
// __FILE__, __LINE__, PEAR_LOG_INFO);
2009-07-15 22:04:17 +02:00
}
if ( empty ( $value ) && ( $size < 0 || $noTruncate )) continue ;
if ( $field == 'RELATED-TO' )
{
2010-01-10 20:02:16 +01:00
$options = array ( 'RELTYPE' => 'PARENT' );
2009-07-15 22:04:17 +02:00
}
else
{
2010-01-10 20:02:16 +01:00
$options = array ();
2008-10-08 09:45:35 +02:00
}
2009-07-15 22:04:17 +02:00
2015-07-23 17:51:26 +02:00
if ( $_version == '1.0' && preg_match ( '/[^\x20-\x7F]/' , $value ))
2008-10-08 09:45:35 +02:00
{
2010-03-22 19:03:23 +01:00
$options [ 'CHARSET' ] = $charset ;
2010-01-08 14:09:36 +01:00
switch ( $this -> productManufacturer )
{
case 'groupdav' :
if ( $this -> productName == 'kde' )
{
$options [ 'ENCODING' ] = 'QUOTED-PRINTABLE' ;
}
else
{
$options [ 'CHARSET' ] = '' ;
2019-05-24 15:10:48 +02:00
if ( preg_match ( Api\CalDAV\Handler :: REQUIRE_QUOTED_PRINTABLE_ENCODING , $value ))
2010-01-08 14:09:36 +01:00
{
$options [ 'ENCODING' ] = 'QUOTED-PRINTABLE' ;
}
else
{
$options [ 'ENCODING' ] = '' ;
}
}
break ;
case 'funambol' :
$options [ 'ENCODING' ] = 'FUNAMBOL-QP' ;
}
2008-10-08 09:45:35 +02:00
}
2009-07-15 22:04:17 +02:00
$vevent -> setAttribute ( $field , $value , $options );
2008-10-08 09:45:35 +02:00
}
2009-07-15 22:04:17 +02:00
2016-06-23 16:05:18 +02:00
// only export startdate < duedate, as some clients (eg. CalDAV Sync for Android) have problems with that
if ( $taskData [ 'info_startdate' ] && ( empty ( $taskData [ 'info_enddate' ]) || $taskData [ 'info_startdate' ] <= $taskData [ 'info_enddate' ]))
2009-07-15 22:04:17 +02:00
{
2010-02-09 22:56:39 +01:00
self :: setDateOrTime ( $vevent , 'DTSTART' , $taskData [ 'info_startdate' ], $tzid );
2009-07-15 22:04:17 +02:00
}
if ( $taskData [ 'info_enddate' ])
{
2012-03-08 17:23:43 +01:00
self :: setDateOrTime ( $vevent , 'DUE' , $taskData [ 'info_enddate' ], $tzid );
2009-07-15 22:04:17 +02:00
}
if ( $taskData [ 'info_datecompleted' ])
{
2010-02-09 22:56:39 +01:00
self :: setDateOrTime ( $vevent , 'COMPLETED' , $taskData [ 'info_datecompleted' ], $tzid );
2009-07-15 22:04:17 +02:00
}
2008-10-08 09:45:35 +02:00
$vevent -> setAttribute ( 'DTSTAMP' , time ());
2015-08-18 13:45:59 +02:00
$vevent -> setAttribute ( 'CREATED' , $taskData [ 'info_created' ]);
$vevent -> setAttribute ( 'LAST-MODIFIED' , $taskData [ 'info_datemodified' ]);
2008-10-08 09:45:35 +02:00
$vevent -> setAttribute ( 'CLASS' , $taskData [ 'info_access' ] == 'public' ? 'PUBLIC' : 'PRIVATE' );
$vevent -> setAttribute ( 'STATUS' , $this -> status2vtodo ( $taskData [ 'info_status' ]));
// we try to preserv the original infolog status as X-INFOLOG-STATUS, so we can restore it, if the user does not modify STATUS
$vevent -> setAttribute ( 'X-INFOLOG-STATUS' , $taskData [ 'info_status' ]);
2009-12-30 14:46:37 +01:00
$vevent -> setAttribute ( 'PERCENT-COMPLETE' , $taskData [ 'info_percent' ]);
2010-01-09 23:28:41 +01:00
if ( $this -> productManufacturer == 'funambol' &&
( strpos ( $this -> productName , 'outlook' ) !== false
|| strpos ( $this -> productName , 'pocket pc' ) !== false ))
2010-01-09 19:04:21 +01:00
{
$priority = ( int ) $this -> priority_egw2funambol [ $taskData [ 'info_priority' ]];
}
else
{
2010-01-10 20:02:16 +01:00
$priority = ( int ) $this -> priority_egw2ical [ $taskData [ 'info_priority' ]];
2010-01-09 19:04:21 +01:00
}
$vevent -> setAttribute ( 'PRIORITY' , $priority );
2009-07-15 22:04:17 +02:00
2012-04-03 18:06:42 +02:00
// add ATTENDEE and ORGANIZER only if ATTENDEEs other then owner are specified
if ( $taskData [ 'info_responsible' ] &&
( count ( $taskData [ 'info_responsible' ]) > 1 ||
$taskData [ 'info_responsible' ][ 0 ] != $taskData [ 'info_onwer' ]))
{
if (( $url = $GLOBALS [ 'egw' ] -> accounts -> id2name ( $taskData [ 'info_owner' ], 'account_email' )))
{
$url = 'MAILTO:' . $url ;
}
else
{
2016-04-05 00:39:49 +02:00
$url = 'urn:uuid:' . Api\CalDAV :: generate_uid ( 'accounts' , $taskData [ 'info_owner' ]);
2012-04-03 18:06:42 +02:00
}
$vevent -> setAttribute ( 'ORGANIZER' , $url , array (
'CN' => $GLOBALS [ 'egw' ] -> accounts -> id2name ( $taskData [ 'info_owner' ], 'account_fullname' ),
'X-EGROUPWARE-UID' => $taskData [ 'info_owner' ],
), true );
foreach ( $taskData [ 'info_responsible' ] as $responsible )
{
if (( $url = $GLOBALS [ 'egw' ] -> accounts -> id2name ( $responsible , 'account_email' )))
{
$url = 'MAILTO:' . $url ;
}
else
{
2016-04-05 00:39:49 +02:00
$url = 'urn:uuid:' . Api\CalDAV :: generate_uid ( 'accounts' , $responsible );
2012-04-03 18:06:42 +02:00
}
if ( $responsible > 0 )
{
$vevent -> setAttribute ( 'ATTENDEE' , $url , array (
'CN' => $GLOBALS [ 'egw' ] -> accounts -> id2name ( $responsible , 'account_fullname' ),
'CUTYPE' => 'INDIVIDUAL' ,
'X-EGROUPWARE-UID' => $responsible ,
), true );
}
elseif ( $responsible < 0 )
{
$vevent -> setAttribute ( 'ATTENDEE' , $url , array (
'CN' => $GLOBALS [ 'egw' ] -> accounts -> id2name ( $responsible ),
'CUTYPE' => 'GROUP' ,
'X-EGROUPWARE-UID' => $responsible ,
), true );
}
}
}
2012-01-29 23:34:43 +01:00
// for CalDAV add all X-Properties previously parsed
if ( $this -> productManufacturer == 'groupdav' )
{
foreach ( $taskData as $name => $value )
{
if ( substr ( $name , 0 , 2 ) == '##' )
{
2021-11-10 16:59:47 +01:00
if (( $v = json_php_unserialize ( $value )) && is_array ( $v ))
{
$value = $v ;
}
// fix certain stock fields like GEO, which are not in EGroupware schema, but Horde Icalendar requires a certain format
switch ( $name )
{
case '##GEO' :
if ( ! is_array ( $value ))
{
if ( strpos ( $value , ';' ) !== false )
{
list ( $lat , $long ) = explode ( ';' , $value );
}
else
{
list ( $long , $lat ) = explode ( ',' , $value );
}
$value = [ 'latitude' => $lat , 'logitude' => $long ];
}
break ;
}
2012-01-31 02:02:21 +01:00
if ( $name [ 2 ] == ':' )
{
foreach (( array ) $value as $compvData )
{
2015-06-22 17:36:23 +02:00
$comp = Horde_Icalendar :: newComponent ( substr ( $name , 3 ), $vevent );
2016-04-29 09:51:13 +02:00
$comp -> parsevCalendar ( $compvData , substr ( $name , 3 ));
2012-01-31 02:02:21 +01:00
$vevent -> addComponent ( $comp );
}
}
2021-11-10 16:59:47 +01:00
elseif ( is_array ( $value ))
2012-01-29 23:34:43 +01:00
{
2021-11-10 16:59:47 +01:00
$vevent -> setAttribute ( substr ( $name , 2 ), $value [ 'value' ], $value [ 'params' ], true , $value [ 'values' ]);
2012-01-29 23:34:43 +01:00
}
else
{
$vevent -> setAttribute ( substr ( $name , 2 ), $value );
}
}
}
}
2008-10-08 09:45:35 +02:00
$vcal -> addComponent ( $vevent );
2009-07-15 22:04:17 +02:00
$retval = $vcal -> exportvCalendar ();
2010-01-09 19:04:21 +01:00
if ( $this -> log )
{
error_log ( __FILE__ . '[' . __LINE__ . '] ' . __METHOD__ . " () \n " .
array2string ( $retval ) . " \n " , 3 , $this -> logfile );
}
// Horde::logMessage("exportVTODO:\n" . print_r($retval, true),
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
2009-07-15 22:04:17 +02:00
return $retval ;
2008-10-08 09:45:35 +02:00
}
2009-09-27 10:23:01 +02:00
/**
2010-02-09 22:56:39 +01:00
* set date - time attribute to DATE or DATE - TIME depending on value
* 00 : 00 uses DATE else DATE - TIME
2009-09-27 10:23:01 +02:00
*
2015-06-22 17:36:23 +02:00
* @ param Horde_Icalendar_ * $vevent
2009-09-27 10:23:01 +02:00
* @ param string $attr attribute name
2010-02-09 22:56:39 +01:00
* @ param int $time timestamp in server - time
* @ param string $tzid timezone to use for client , null for user - time , false for server - time
2009-09-27 10:23:01 +02:00
*/
2010-02-09 22:56:39 +01:00
static function setDateOrTime ( & $vevent , $attr , $time , $tzid )
2009-09-27 10:23:01 +02:00
{
2010-02-09 22:56:39 +01:00
$params = array ();
2015-06-22 17:36:23 +02:00
//$time_in = $time;
2010-02-09 22:56:39 +01:00
if ( $tzid )
{
if ( ! isset ( self :: $tz_cache [ $tzid ]))
{
self :: $tz_cache [ $tzid ] = calendar_timezones :: DateTimeZone ( $tzid );
}
$tz = self :: $tz_cache [ $tzid ];
}
elseif ( is_null ( $tzid ))
{
2016-04-30 19:05:23 +02:00
$tz = Api\DateTime :: $user_timezone ;
2010-02-09 22:56:39 +01:00
}
else
{
2016-04-30 19:05:23 +02:00
$tz = Api\DateTime :: $server_timezone ;
2010-02-09 22:56:39 +01:00
}
if ( ! is_a ( $time , 'DateTime' ))
{
2016-04-30 19:05:23 +02:00
$time = new Api\DateTime ( $time , Api\DateTime :: $server_timezone );
2010-02-09 22:56:39 +01:00
}
$time -> setTimezone ( $tz );
// check for date --> export it as such
if ( $time -> format ( 'Hi' ) == '0000' )
2009-09-27 10:23:01 +02:00
{
2016-04-30 19:05:23 +02:00
$arr = Api\DateTime :: to ( $time , 'array' );
2010-02-09 22:56:39 +01:00
$value = array (
'year' => $arr [ 'year' ],
'month' => $arr [ 'month' ],
2012-03-08 17:23:43 +01:00
'mday' => $arr [ 'day' ],
);
2010-02-09 22:56:39 +01:00
$params [ 'VALUE' ] = 'DATE' ;
2009-09-27 10:23:01 +02:00
}
else
{
2010-02-09 22:56:39 +01:00
if ( $tzid == 'UTC' )
{
$value = $time -> format ( 'Ymd\THis\Z' );
}
elseif ( $tzid )
{
$value = $time -> format ( 'Ymd\THis' );
$params [ 'TZID' ] = $tzid ;
}
else
{
2016-04-30 19:05:23 +02:00
$value = Api\DateTime :: to ( $time , 'ts' );
2010-02-09 22:56:39 +01:00
}
2009-09-27 10:23:01 +02:00
}
2012-03-08 17:23:43 +01:00
//error_log(__METHOD__."(, '$attr', ".array2string($time_in).', '.array2string($tzid).') tz='.$tz->getName().', value='.array2string($value).(is_int($value)?date('Y-m-d H:i:s',$value):''));
2010-02-09 22:56:39 +01:00
$vevent -> setAttribute ( $attr , $value , $params );
2009-09-27 10:23:01 +02:00
}
2008-10-08 09:45:35 +02:00
/**
* Import a VTODO component of an iCal
*
* @ param string $_vcalData
2015-06-22 17:36:23 +02:00
* @ param int $_taskID =- 1 info_id , default - 1 = new entry
* @ param boolean $merge = false merge data with existing entry ( no longer used )
* @ param int $user = null delegate new task to this account_id , default null
* @ param string $charset = null The encoding charset for $text . Defaults to
2010-03-22 19:03:23 +01:00
* utf - 8 for new format , iso - 8859 - 1 for old format .
2015-06-22 17:36:23 +02:00
* @ param string $caldav_name = null CalDAV URL name - part for new entries
* @ param array $callback_data = null array with callback and further parameters , first param is task to save
2012-07-20 15:06:47 +02:00
* signature array callback ( $task , $param1 , ... )
2008-10-08 09:45:35 +02:00
* @ return int | boolean integer info_id or false on error
*/
2012-07-20 15:06:47 +02:00
function importVTODO ( & $_vcalData , $_taskID =- 1 , $merge = false , $user = null , $charset = null , $caldav_name = null ,
array $callback_data = null )
2008-10-08 09:45:35 +02:00
{
2015-06-22 17:36:23 +02:00
unset ( $merge ); // no longer used, but required by function signature
2010-02-09 22:56:39 +01:00
if ( $this -> tzid )
{
date_default_timezone_set ( $this -> tzid );
}
2010-03-22 19:03:23 +01:00
$taskData = $this -> vtodotoegw ( $_vcalData , $_taskID , $charset );
2010-02-09 22:56:39 +01:00
if ( $this -> tzid )
{
date_default_timezone_set ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'server_timezone' ]);
}
2019-04-24 00:17:12 +02:00
if ( $this -> entry_callback && is_callable ( $this -> entry_callback ))
{
if ( ! call_user_func_array ( $this -> entry_callback , array ( & $taskData )))
{
// Callback cancelled entry
return false ;
}
}
2010-02-09 22:56:39 +01:00
if ( ! $taskData ) return false ;
// keep the dates
$this -> time2time ( $taskData , $this -> tzid , false );
2009-07-15 22:04:17 +02:00
if ( empty ( $taskData [ 'info_datecompleted' ]))
Big SyncML patch from Philip Herbert <pherbert(at)knauber.de>:
- change the processing of slowsync, to use the content_map instead of
trying to build a new one. This caused duplication issues on the
client if multiple similar records where stored, because only the first
one found in the server-db was matched, These duplicate entries at client
side had no entry at serverside, so deleting the wrong one
on the client (the content with a valid map entry) could cause
unwanted data loss at server side, because it is impossible for the
user to see what is a duplicate, and what is not.
see also:
http://www.nabble.com/again---syncml-duplication-issue-to20333619s3741.html
- reenabled UID from syncml clients, because it was partly used this caused
issues during SlowSync if the content was changed.
- infolog, calendar if a uid is found in the provided data, allway try to
find the corresponding content first using only the UID, instead of
using the content-id taken from content_map.
also fixed:
- a few fixes in ./notes
- creating an entry on the client that can not be imported,
(Example, Nokia E Series Appointment without a Title)
will no longer create an invalid content-map entry
However, at client side this is still counted in the Protocol as
Server-Add
2008-11-16 11:42:29 +01:00
{
2009-07-15 22:04:17 +02:00
$taskData [ 'info_datecompleted' ] = 0 ;
Big SyncML patch from Philip Herbert <pherbert(at)knauber.de>:
- change the processing of slowsync, to use the content_map instead of
trying to build a new one. This caused duplication issues on the
client if multiple similar records where stored, because only the first
one found in the server-db was matched, These duplicate entries at client
side had no entry at serverside, so deleting the wrong one
on the client (the content with a valid map entry) could cause
unwanted data loss at server side, because it is impossible for the
user to see what is a duplicate, and what is not.
see also:
http://www.nabble.com/again---syncml-duplication-issue-to20333619s3741.html
- reenabled UID from syncml clients, because it was partly used this caused
issues during SlowSync if the content was changed.
- infolog, calendar if a uid is found in the provided data, allway try to
find the corresponding content first using only the UID, instead of
using the content-id taken from content_map.
also fixed:
- a few fixes in ./notes
- creating an entry on the client that can not be imported,
(Example, Nokia E Series Appointment without a Title)
will no longer create an invalid content-map entry
However, at client side this is still counted in the Protocol as
Server-Add
2008-11-16 11:42:29 +01:00
}
2008-10-08 09:45:35 +02:00
2012-04-03 18:06:42 +02:00
// setting owner or responsible for new tasks based on folder
2016-07-15 09:25:44 +02:00
if ( ! is_null ( $user ) && $_taskID <= 0 )
2010-03-07 00:06:43 +01:00
{
2016-04-30 19:05:23 +02:00
if ( $this -> check_access ( $taskData , Acl :: ADD ))
2012-01-26 02:49:56 +01:00
{
$taskData [ 'info_owner' ] = $user ;
}
2012-04-03 18:06:42 +02:00
elseif ( ! in_array ( $user , ( array ) $taskData [ 'info_responsible' ]))
2012-01-26 02:49:56 +01:00
{
$taskData [ 'info_responsible' ][] = $user ;
}
2010-03-07 00:06:43 +01:00
}
2010-01-09 19:04:21 +01:00
if ( $this -> log )
{
error_log ( __FILE__ . '[' . __LINE__ . '] ' . __METHOD__ . " () \n " .
array2string ( $taskData ) . " \n " , 3 , $this -> logfile );
}
2011-04-11 11:29:39 +02:00
if ( $caldav_name )
{
$taskData [ 'caldav_name' ] = $caldav_name ;
}
2012-04-03 18:06:42 +02:00
// make sure not to empty fields not supported by iCal or not allowed to change by CalDAV
if ( $_taskID > 0 && ( $old = $this -> read ( $_taskID , true , 'server' )))
{
// remove all values supported by iCal standard
$old = array_diff_key ( $old , array_flip ( array (
'info_subject' , 'info_des' , 'info_location' , 'info_cat' , 'info_responsible' ,
'info_startdate' , 'info_enddate' , 'info_priority' , 'info_location' ,
'info_access' , 'info_status' , 'info_percent' , 'info_datecompleted' ,
)));
// remove all iCal fields not supported by EGroupware (stored like custom fields)
2015-06-22 17:36:23 +02:00
foreach ( array_keys ( $old ) as $name )
2012-04-03 18:06:42 +02:00
{
if ( substr ( $name , 0 , 2 ) == '##' ) unset ( $old [ $name ]);
}
// merge in again all infolog fields not supported by iCal or not allowed to change
$taskData = array_merge ( $taskData , $old );
}
2012-07-20 15:06:47 +02:00
if ( $callback_data )
{
$callback = array_shift ( $callback_data );
array_unshift ( $callback_data , $taskData );
$taskData = call_user_func_array ( $callback , $callback_data );
}
2012-01-29 23:34:43 +01:00
return $this -> write ( $taskData , true , true , false , false , false , 'ical' );
2009-07-15 22:04:17 +02:00
}
2008-10-08 09:45:35 +02:00
2009-07-15 22:04:17 +02:00
/**
* Search a matching infolog entry for the VTODO data
*
* @ param string $_vcalData VTODO
2015-06-22 17:36:23 +02:00
* @ param int $contentID = null infolog_id ( or null , if unkown )
* @ param boolean $relax = false if true , a weaker match algorithm is used
2010-03-22 19:03:23 +01:00
* @ param string $charset The encoding charset for $text . Defaults to
* utf - 8 for new format , iso - 8859 - 1 for old format .
2010-02-09 22:56:39 +01:00
*
* @ return array of infolog_ids of matching entries
2009-07-15 22:04:17 +02:00
*/
2010-03-22 19:03:23 +01:00
function searchVTODO ( $_vcalData , $contentID = null , $relax = false , $charset = null )
2010-02-09 22:56:39 +01:00
{
$result = array ();
2009-07-15 22:04:17 +02:00
2010-02-09 22:56:39 +01:00
if ( $this -> tzid )
{
date_default_timezone_set ( $this -> tzid );
}
2010-03-22 19:03:23 +01:00
$taskData = $this -> vtodotoegw ( $_vcalData , $contentID , $charset );
2010-02-09 22:56:39 +01:00
if ( $this -> tzid )
{
date_default_timezone_set ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'server_timezone' ]);
}
if ( $taskData )
2009-07-15 22:04:17 +02:00
{
if ( $contentID )
{
2010-02-09 22:56:39 +01:00
$taskData [ 'info_id' ] = $contentID ;
2008-10-08 09:45:35 +02:00
}
2010-02-09 22:56:39 +01:00
$result = $this -> findInfo ( $taskData , $relax , $this -> tzid );
2008-10-08 09:45:35 +02:00
}
2009-07-15 22:04:17 +02:00
return $result ;
2008-10-08 09:45:35 +02:00
}
2015-07-16 15:33:25 +02:00
/**
* Convert date ( - array ) to timestamp used in InfoLog
*
* @ param int | array $date
* @ return int
*/
protected static function date2ts ( $date )
{
2016-04-30 19:05:23 +02:00
return is_scalar ( $date ) ? $date : Api\DateTime :: to ( $date , 'ts' );
2015-07-16 15:33:25 +02:00
}
2009-07-15 22:04:17 +02:00
/**
* Convert VTODO into a eGW infolog entry
*
* @ param string $_vcalData VTODO data
2015-06-22 17:36:23 +02:00
* @ param int $_taskID =- 1 infolog_id of the entry
2010-03-22 19:03:23 +01:00
* @ param string $charset The encoding charset for $text . Defaults to
* utf - 8 for new format , iso - 8859 - 1 for old format .
*
2009-07-15 22:04:17 +02:00
* @ return array infolog entry or false on error
*/
2010-03-22 19:03:23 +01:00
function vtodotoegw ( $_vcalData , $_taskID =- 1 , $charset = null )
2008-10-08 09:45:35 +02:00
{
2010-01-09 19:04:21 +01:00
if ( $this -> log )
{
2010-02-09 22:56:39 +01:00
error_log ( __FILE__ . '[' . __LINE__ . '] ' . __METHOD__ . " ( $_taskID ) \n " .
2010-01-09 19:04:21 +01:00
array2string ( $_vcalData ) . " \n " , 3 , $this -> logfile );
}
2015-06-22 17:36:23 +02:00
$vcal = new Horde_Icalendar ;
2016-04-29 09:51:13 +02:00
if ( $charset && $charset != 'utf-8' )
{
$_vcalData = Api\Translation :: convert ( $_vcalData , $charset , 'utf-8' );
}
if ( ! ( $vcal -> parsevCalendar ( $_vcalData , 'VCALENDAR' )))
2010-01-09 19:04:21 +01:00
{
if ( $this -> log )
{
error_log ( __FILE__ . '[' . __LINE__ . '] ' . __METHOD__ .
" (): No vCalendar Container found! \n " , 3 , $this -> logfile );
}
return false ;
}
2009-07-15 22:04:17 +02:00
if ( isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'syncml' ][ 'minimum_uid_length' ]))
2008-10-08 09:45:35 +02:00
{
2009-07-15 22:04:17 +02:00
$minimum_uid_length = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'syncml' ][ 'minimum_uid_length' ];
}
else
{
$minimum_uid_length = 8 ;
2008-10-08 09:45:35 +02:00
}
2010-02-09 22:56:39 +01:00
$taskData = false ;
2010-01-09 19:04:21 +01:00
foreach ( $vcal -> getComponents () as $component )
2008-10-08 09:45:35 +02:00
{
2015-06-22 17:36:23 +02:00
if ( ! is_a ( $component , 'Horde_Icalendar_Vtodo' ))
2010-01-09 19:04:21 +01:00
{
if ( $this -> log )
{
error_log ( __FILE__ . '[' . __LINE__ . '] ' . __METHOD__ .
" (): Not a vTODO container, skipping... \n " , 3 , $this -> logfile );
}
2010-02-09 22:56:39 +01:00
continue ;
2010-01-09 19:04:21 +01:00
}
2010-02-09 22:56:39 +01:00
2019-05-28 18:47:55 +02:00
$taskData = array ( 'info_cat' => $_taskID ? 0 : $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'infolog' ][ 'cat_add_default' ]);
2010-02-09 22:56:39 +01:00
if ( $_taskID > 0 )
2008-10-08 09:45:35 +02:00
{
2010-02-09 22:56:39 +01:00
$taskData [ 'info_id' ] = $_taskID ;
}
2012-03-22 13:15:18 +01:00
// iOS reminder app only sets COMPLETED, but never STATUS nor PERCENT-COMPLETED
// if we have no STATUS, set STATUS by existence of COMPLETED and/or PERCENT-COMPLETE and X-INFOLOG-STATUS
// if we have no PERCENT-COMPLETE set it from STATUS: 0=NEEDS-ACTION, 10=IN-PROCESS, 100=COMPLETED
2015-06-24 14:30:56 +02:00
try {
$status = $component -> getAttribute ( 'STATUS' );
}
catch ( Horde_Icalendar_Exception $e )
2012-01-26 02:49:56 +01:00
{
2015-06-24 14:30:56 +02:00
unset ( $e );
$completed = $component -> getAttributeDefault ( 'COMPLETED' , null );
$x_infolog_status = $component -> getAttributeDefault ( 'X-INFOLOG-STATUS' , null );
2012-03-22 13:15:18 +01:00
// check if we have a X-INFOLOG-STATUS and it's completed state is different from given COMPLETED attr
if ( is_scalar ( $x_infolog_status ) &&
( $this -> _status2vtodo [ $x_infolog_status ] === 'COMPLETED' ) != is_scalar ( $completed ))
{
2015-06-24 14:30:56 +02:00
$percent_completed = $component -> getAttributeDefault ( 'PERCENT-COMPLETE' , null );
2012-03-22 13:15:18 +01:00
$status = $completed && is_scalar ( $completed ) ? 'COMPLETED' :
( $percent_completed && is_scalar ( $percent_completed ) && $percent_completed > 0 ? 'IN-PROCESS' : 'NEEDS-ACTION' );
$component -> setAttribute ( 'STATUS' , $status );
if ( ! is_scalar ( $percent_completed ))
{
$component -> setAttribute ( 'PERCENT-COMPLETE' , $percent_completed = $status == 'COMPLETED' ?
100 : ( $status == 'NEEDS-ACTION' ? 0 : 10 ));
}
if ( $this -> log ) error_log ( __METHOD__ . " () setting STATUS=' $status ' and PERCENT-COMPLETE= $percent_completed from COMPLETED and X-INFOLOG-STATUS=' $x_infolog_status ' \n " , 3 , $this -> logfile );
}
2012-06-05 17:18:37 +02:00
// new task without status --> set a default status of NEEDS-ACTION, as otherwise task is marked closed
elseif ( $_taskID <= 0 && ! is_scalar ( $x_infolog_status ) && ! is_scalar ( $completed ))
{
$component -> setAttribute ( 'STATUS' , 'NEEDS-ACTION' );
}
2012-03-22 13:15:18 +01:00
else
{
if ( $this -> log ) error_log ( __METHOD__ . " () no STATUS, X-INFOLOG-STATUS=' $x_infolog_status ', COMPLETED " . ( is_scalar ( $completed ) ? '=' . $completed : ' not set' ) . " --> leaving status and percent unchanged " , 3 , $this -> logfile );
}
2012-01-26 02:49:56 +01:00
}
2011-10-05 11:24:08 +02:00
foreach ( $component -> getAllAttributes () as $attribute )
2010-02-09 22:56:39 +01:00
{
2015-07-16 15:33:25 +02:00
if ( ! $attribute [ 'value' ] && $attribute [ 'value' ] !== '0' ) continue ;
2009-07-15 22:04:17 +02:00
2010-02-09 22:56:39 +01:00
switch ( $attribute [ 'name' ])
2008-10-08 09:45:35 +02:00
{
2010-02-09 22:56:39 +01:00
case 'CLASS' :
$taskData [ 'info_access' ] = strtolower ( $attribute [ 'value' ]);
break ;
2009-07-15 22:04:17 +02:00
2010-02-09 22:56:39 +01:00
case 'DESCRIPTION' :
$value = str_replace ( " \r \n " , " \n " , $attribute [ 'value' ]);
2015-06-22 17:36:23 +02:00
$matches = null ;
2010-02-09 22:56:39 +01:00
if ( preg_match ( '/\s*\[UID:(.+)?\]/Usm' , $value , $matches ))
{
if ( ! isset ( $taskData [ 'info_uid' ])
&& strlen ( $matches [ 1 ]) >= $minimum_uid_length )
2009-07-15 22:04:17 +02:00
{
2010-02-09 22:56:39 +01:00
$taskData [ 'info_uid' ] = $matches [ 1 ];
2009-07-15 22:04:17 +02:00
}
2010-02-09 22:56:39 +01:00
//$value = str_replace($matches[0], '', $value);
}
if ( preg_match ( '/\s*\[PARENT_UID:(.+)?\]/Usm' , $value , $matches ))
{
if ( ! isset ( $taskData [ 'info_id_parent' ])
&& strlen ( $matches [ 1 ]) >= $minimum_uid_length )
2009-07-15 22:04:17 +02:00
{
2010-02-09 22:56:39 +01:00
$taskData [ 'info_id_parent' ] = $this -> getParentID ( $matches [ 1 ]);
2009-07-15 22:04:17 +02:00
}
2010-02-09 22:56:39 +01:00
//$value = str_replace($matches[0], '', $value);
}
$taskData [ 'info_des' ] = $value ;
break ;
2009-07-15 22:04:17 +02:00
2010-02-09 22:56:39 +01:00
case 'LOCATION' :
$taskData [ 'info_location' ] = str_replace ( " \r \n " , " \n " , $attribute [ 'value' ]);
break ;
2009-07-15 22:04:17 +02:00
2011-10-05 11:24:08 +02:00
case 'DURATION' :
if ( ! isset ( $taskData [ 'info_startdate' ]))
{
2015-06-24 14:30:56 +02:00
$taskData [ 'info_startdate' ] = $component -> getAttributeDefault ( 'DTSTART' , null );
2011-10-05 11:24:08 +02:00
}
$attribute [ 'value' ] += $taskData [ 'info_startdate' ];
2012-01-29 23:34:43 +01:00
$taskData [ '##DURATION' ] = $attribute [ 'value' ];
2011-10-05 11:24:08 +02:00
// fall throught
2010-02-09 22:56:39 +01:00
case 'DUE' :
2011-10-08 14:46:56 +02:00
// even as EGroupware only displays the date, we can still store the full value
// unless infolog get's stored, it does NOT truncate the time
2015-07-16 15:33:25 +02:00
$taskData [ 'info_enddate' ] = self :: date2ts ( $attribute [ 'value' ]);
2010-02-09 22:56:39 +01:00
break ;
2009-07-15 22:04:17 +02:00
2010-02-09 22:56:39 +01:00
case 'COMPLETED' :
2015-07-16 15:33:25 +02:00
$taskData [ 'info_datecompleted' ] = self :: date2ts ( $attribute [ 'value' ]);
2010-02-09 22:56:39 +01:00
break ;
case 'DTSTART' :
2015-07-16 15:33:25 +02:00
$taskData [ 'info_startdate' ] = self :: date2ts ( $attribute [ 'value' ]);
2010-02-09 22:56:39 +01:00
break ;
2008-10-08 09:45:35 +02:00
2010-02-09 22:56:39 +01:00
case 'PRIORITY' :
if ( 0 <= $attribute [ 'value' ] && $attribute [ 'value' ] <= 9 )
{
if ( $this -> productManufacturer == 'funambol' &&
( strpos ( $this -> productName , 'outlook' ) !== false
|| strpos ( $this -> productName , 'pocket pc' ) !== false ))
2009-12-07 10:00:58 +01:00
{
2010-02-09 22:56:39 +01:00
$taskData [ 'info_priority' ] = ( int ) $this -> priority_funambol2egw [ $attribute [ 'value' ]];
2009-12-07 10:00:58 +01:00
}
2010-02-09 22:56:39 +01:00
else
{
$taskData [ 'info_priority' ] = ( int ) $this -> priority_ical2egw [ $attribute [ 'value' ]];
2008-10-08 09:45:35 +02:00
}
2010-02-09 22:56:39 +01:00
}
else
{
$taskData [ 'info_priority' ] = 1 ; // default = normal
}
break ;
2009-07-15 22:04:17 +02:00
2012-01-29 23:34:43 +01:00
case 'X-INFOLOG-STATUS' :
break ;
2010-02-09 22:56:39 +01:00
case 'STATUS' :
// check if we (still) have X-INFOLOG-STATUS set AND it would give an unchanged status (no change by the user)
$taskData [ 'info_status' ] = $this -> vtodo2status ( $attribute [ 'value' ],
2015-06-24 14:30:56 +02:00
$component -> getAttributeDefault ( 'X-INFOLOG-STATUS' , null ));
2010-02-09 22:56:39 +01:00
break ;
case 'SUMMARY' :
$taskData [ 'info_subject' ] = str_replace ( " \r \n " , " \n " , $attribute [ 'value' ]);
break ;
case 'RELATED-TO' :
$taskData [ 'info_id_parent' ] = $this -> getParentID ( $attribute [ 'value' ]);
break ;
case 'CATEGORIES' :
if ( ! empty ( $attribute [ 'value' ]))
{
$cats = $this -> find_or_add_categories ( explode ( ',' , $attribute [ 'value' ]), $_taskID );
$taskData [ 'info_cat' ] = $cats [ 0 ];
}
break ;
2008-10-08 09:45:35 +02:00
2010-02-09 22:56:39 +01:00
case 'UID' :
if ( strlen ( $attribute [ 'value' ]) >= $minimum_uid_length )
{
$taskData [ 'info_uid' ] = $attribute [ 'value' ];
}
break ;
2009-07-15 22:04:17 +02:00
2010-02-09 22:56:39 +01:00
case 'PERCENT-COMPLETE' :
$taskData [ 'info_percent' ] = ( int ) $attribute [ 'value' ];
break ;
2012-01-29 23:34:43 +01:00
2012-04-03 18:06:42 +02:00
case 'ATTENDEE' :
2016-04-05 00:39:49 +02:00
if (( $uid = Api\CalDAV\Principals :: url2uid ( $attribute [ 'value' ])) && is_numeric ( $uid ))
2012-04-03 18:06:42 +02:00
{
$taskData [ 'info_responsible' ][] = $uid ;
}
break ;
case 'ORGANIZER' :
2016-04-05 00:39:49 +02:00
if (( $uid = Api\CalDAV\Principals :: url2uid ( $attribute [ 'value' ])) && is_numeric ( $uid ))
2012-04-03 18:06:42 +02:00
{
$taskData [ 'info_owner' ] = $uid ;
}
break ;
2017-07-11 09:00:47 +02:00
case 'X-INFOLOG-TYPE' :
if ( isset ( $this -> enums [ 'type' ][ $attribute [ 'value' ]]))
{
$taskData [ 'info_type' ] = $attribute [ 'value' ];
}
break ;
2012-01-29 23:34:43 +01:00
// ignore all PROPS, we dont want to store like X-properties or unsupported props
case 'DTSTAMP' :
case 'SEQUENCE' :
case 'CREATED' :
case 'LAST-MODIFIED' :
break ;
default : // X- attribute or other by EGroupware unsupported property
2012-02-09 21:15:18 +01:00
//error_log(__METHOD__."() $attribute[name] = ".array2string($attribute));
2012-01-29 23:34:43 +01:00
// for attributes with multiple values in multiple lines, merge the values
if ( isset ( $taskData [ '##' . $attribute [ 'name' ]]))
{
2012-02-09 21:15:18 +01:00
//error_log(__METHOD__."() taskData['##$attribute[name]'] = ".array2string($taskData['##'.$attribute['name']]));
2012-01-29 23:34:43 +01:00
$attribute [ 'values' ] = array_merge (
is_array ( $taskData [ '##' . $attribute [ 'name' ]]) ? $taskData [ '##' . $attribute [ 'name' ]][ 'values' ] : ( array ) $taskData [ '##' . $attribute [ 'name' ]],
$attribute [ 'values' ]);
}
$taskData [ '##' . $attribute [ 'name' ]] = $attribute [ 'params' ] || count ( $attribute [ 'values' ]) > 1 ?
2015-06-25 22:27:06 +02:00
json_encode ( $attribute ) : $attribute [ 'value' ];
2012-01-29 23:34:43 +01:00
break ;
2010-02-09 22:56:39 +01:00
}
2008-10-08 09:45:35 +02:00
}
2010-02-09 22:56:39 +01:00
break ;
2008-10-08 09:45:35 +02:00
}
2012-01-31 02:02:21 +01:00
// store included, but unsupported components like valarm as x-properties
foreach ( $component -> getComponents () as $comp )
{
$name = '##:' . strtoupper ( $comp -> getType ());
$compvData = $comp -> exportvCalendar ( $comp , 'utf-8' );
if ( isset ( $taskData [ $name ]))
{
$taskData [ $name ] = array ( $taskData [ $name ]);
$taskData [ $name ][] = $compvData ;
}
else
{
$taskData [ $name ] = $compvData ;
}
}
2010-02-09 22:56:39 +01:00
if ( $this -> log )
{
error_log ( __FILE__ . '[' . __LINE__ . '] ' . __METHOD__ . " ( $_taskID ) \n " .
( $taskData ? array2string ( $taskData ) : 'FALSE' ) . " \n " , 3 , $this -> logfile );
}
return $taskData ;
2008-10-08 09:45:35 +02:00
}
2009-07-15 22:04:17 +02:00
/**
* Export an infolog entry as VNOTE
*
* @ param int $_noteID the infolog_id of the entry
* @ param string $_type content type ( e . g . text / plain )
2015-06-22 17:36:23 +02:00
* @ param string $charset = 'UTF-8' encoding of the vcalendar , default UTF - 8
2010-03-22 19:03:23 +01:00
*
* @ return string | boolean VNOTE representation of the infolog entry or false on error
2009-07-15 22:04:17 +02:00
*/
2010-03-22 19:03:23 +01:00
function exportVNOTE ( $_noteID , $_type , $charset = 'UTF-8' )
2008-10-08 09:45:35 +02:00
{
2010-03-07 00:06:43 +01:00
if ( ! ( $note = $this -> read ( $_noteID , true , 'server' ))) return false ;
2016-04-30 19:05:23 +02:00
$note = Api\Translation :: convert ( $note ,
Api\Translation :: charset (), $charset );
2008-10-08 09:45:35 +02:00
2009-07-15 22:04:17 +02:00
switch ( $_type )
2008-10-08 09:45:35 +02:00
{
case 'text/plain' :
$txt = $note [ 'info_subject' ] . " \n \n " . $note [ 'info_des' ];
return $txt ;
case 'text/x-vnote' :
2010-01-08 14:09:36 +01:00
if ( ! empty ( $note [ 'info_cat' ]))
{
$cats = $this -> get_categories ( array ( $note [ 'info_cat' ]));
2016-04-30 19:05:23 +02:00
$note [ 'info_cat' ] = Api\Translation :: convert ( $cats [ 0 ],
Api\Translation :: charset (), $charset );
2010-01-08 14:09:36 +01:00
}
2015-06-22 17:36:23 +02:00
$vnote = new Horde_Icalendar_Vnote ();
2011-10-05 11:24:08 +02:00
$vnote -> setAttribute ( 'PRODID' , '-//EGroupware//NONSGML EGroupware InfoLog ' . $GLOBALS [ 'egw_info' ][ 'apps' ][ 'infolog' ][ 'version' ] . '//' .
strtoupper ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'lang' ]));
$vnote -> setAttribute ( 'VERSION' , '1.1' );
2010-01-08 14:09:36 +01:00
foreach ( array ( 'SUMMARY' => $note [ 'info_subject' ],
'BODY' => $note [ 'info_des' ],
'CATEGORIES' => $note [ 'info_cat' ],
2009-07-15 22:04:17 +02:00
) as $field => $value )
{
2010-01-10 20:02:16 +01:00
$options = array ();
2010-01-08 14:09:36 +01:00
if ( preg_match ( '/[^\x20-\x7F]/' , $value ))
2009-07-15 22:04:17 +02:00
{
2010-03-22 19:03:23 +01:00
$options [ 'CHARSET' ] = $charset ;
2010-01-08 14:09:36 +01:00
switch ( $this -> productManufacturer )
{
case 'groupdav' :
if ( $this -> productName == 'kde' )
{
$options [ 'ENCODING' ] = 'QUOTED-PRINTABLE' ;
}
else
{
$options [ 'CHARSET' ] = '' ;
2019-05-24 15:10:48 +02:00
if ( preg_match ( Api\CalDAV\Handler :: REQUIRE_QUOTED_PRINTABLE_ENCODING , $value ))
2010-01-08 14:09:36 +01:00
{
$options [ 'ENCODING' ] = 'QUOTED-PRINTABLE' ;
}
else
{
$options [ 'ENCODING' ] = '' ;
}
}
break ;
case 'funambol' :
$options [ 'ENCODING' ] = 'FUNAMBOL-QP' ;
}
2009-07-15 22:04:17 +02:00
}
2015-06-22 17:36:23 +02:00
$vnote -> setAttribute ( $field , $value , $options );
2009-07-15 22:04:17 +02:00
}
if ( $note [ 'info_startdate' ])
{
2015-06-22 17:36:23 +02:00
$vnote -> setAttribute ( 'CREATED' , $note [ 'info_startdate' ]);
2009-07-15 22:04:17 +02:00
}
2010-02-09 22:56:39 +01:00
else
{
2015-06-22 17:36:23 +02:00
$vnote -> setAttribute ( 'CREATED' , $GLOBALS [ 'egw' ] -> contenthistory -> getTSforAction ( 'infolog_note' , $_noteID , 'add' ));
2010-02-09 22:56:39 +01:00
}
2008-11-03 08:44:02 +01:00
$vnote -> setAttribute ( 'LAST-MODIFIED' , $GLOBALS [ 'egw' ] -> contenthistory -> getTSforAction ( 'infolog_note' , $_noteID , 'modify' ));
2009-07-15 22:04:17 +02:00
2008-10-08 09:45:35 +02:00
#$vnote->setAttribute('CLASS',$taskData['info_access'] == 'public' ? 'PUBLIC' : 'PRIVATE');
2010-01-09 19:04:21 +01:00
$retval = $vnote -> exportvCalendar ();
if ( $this -> log )
{
error_log ( __FILE__ . '[' . __LINE__ . '] ' . __METHOD__ . " () \n " .
array2string ( $retval ) . " \n " , 3 , $this -> logfile );
}
return $retval ;
2008-10-08 09:45:35 +02:00
}
return false ;
}
2009-07-15 22:04:17 +02:00
/**
* Import a VNOTE component of an iCal
*
* @ param string $_vcalData
* @ param string $_type content type ( eg . g text / plain )
2015-06-22 17:36:23 +02:00
* @ param int $_noteID =- 1 info_id , default - 1 = new entry
* @ param boolean $merge = false merge data with existing entry ( no longer used )
2010-03-22 19:03:23 +01:00
* @ param string $charset The encoding charset for $text . Defaults to
* utf - 8 for new format , iso - 8859 - 1 for old format .
*
2009-07-15 22:04:17 +02:00
* @ return int | boolean integer info_id or false on error
*/
2010-03-22 19:03:23 +01:00
function importVNOTE ( & $_vcalData , $_type , $_noteID =- 1 , $merge = false , $charset = null )
2008-10-08 09:45:35 +02:00
{
2015-06-22 17:36:23 +02:00
unset ( $merge ); // no longer used, but required by function signature
2010-01-09 19:04:21 +01:00
if ( $this -> log )
{
error_log ( __FILE__ . '[' . __LINE__ . '] ' . __METHOD__ . " () \n " .
array2string ( $_vcalData ) . " \n " , 3 , $this -> logfile );
}
2010-03-22 19:03:23 +01:00
if ( ! ( $note = $this -> vnotetoegw ( $_vcalData , $_type , $_noteID , $charset ))) return false ;
2008-10-08 09:45:35 +02:00
2009-07-15 22:04:17 +02:00
if ( $_noteID > 0 ) $note [ 'info_id' ] = $_noteID ;
2008-10-08 09:45:35 +02:00
2009-07-15 22:04:17 +02:00
if ( empty ( $note [ 'info_status' ])) $note [ 'info_status' ] = 'done' ;
2008-10-08 09:45:35 +02:00
2010-01-09 19:04:21 +01:00
if ( $this -> log )
{
error_log ( __FILE__ . '[' . __LINE__ . '] ' . __METHOD__ . " () \n " .
array2string ( $note ) . " \n " , 3 , $this -> logfile );
}
2010-02-04 13:08:03 +01:00
return $this -> write ( $note , true , true , false );
2008-10-08 09:45:35 +02:00
}
2009-07-15 22:04:17 +02:00
/**
* Search a matching infolog entry for the VNOTE data
*
* @ param string $_vcalData VNOTE
* @ param int $contentID = null infolog_id ( or null , if unkown )
2010-02-09 22:56:39 +01:00
* @ param boolean $relax = false if true , a weaker match algorithm is used
2010-03-22 19:03:23 +01:00
* @ param string $charset The encoding charset for $text . Defaults to
* utf - 8 for new format , iso - 8859 - 1 for old format .
2010-02-09 22:56:39 +01:00
*
2009-07-15 22:04:17 +02:00
* @ return infolog_id of a matching entry or false , if nothing was found
*/
2010-03-22 19:03:23 +01:00
function searchVNOTE ( $_vcalData , $_type , $contentID = null , $relax = false , $charset = null )
2008-10-08 09:45:35 +02:00
{
2010-03-22 19:03:23 +01:00
if ( ! ( $note = $this -> vnotetoegw ( $_vcalData , $_type , $contentID , $charset ))) return array ();
2009-07-15 22:04:17 +02:00
if ( $contentID ) $note [ 'info_id' ] = $contentID ;
unset ( $note [ 'info_startdate' ]);
2010-02-09 22:56:39 +01:00
return $this -> findInfo ( $note , $relax , $this -> tzid );
2008-10-08 09:45:35 +02:00
}
2009-07-15 22:04:17 +02:00
/**
* Convert VTODO into a eGW infolog entry
*
* @ param string $_data VNOTE data
* @ param string $_type content type ( eg . g text / plain )
2015-06-22 17:36:23 +02:00
* @ param int $_noteID =- 1 infolog_id of the entry
2010-03-22 19:03:23 +01:00
* @ param string $charset The encoding charset for $text . Defaults to
* utf - 8 for new format , iso - 8859 - 1 for old format .
*
2009-07-15 22:04:17 +02:00
* @ return array infolog entry or false on error
*/
2010-03-22 19:03:23 +01:00
function vnotetoegw ( $_data , $_type , $_noteID =- 1 , $charset = null )
2008-10-08 09:45:35 +02:00
{
2010-02-09 22:56:39 +01:00
if ( $this -> log )
{
error_log ( __FILE__ . '[' . __LINE__ . '] ' . __METHOD__ . " ( $_type , $_noteID ) \n " .
array2string ( $_data ) . " \n " , 3 , $this -> logfile );
}
$note = false ;
2009-07-15 22:04:17 +02:00
switch ( $_type )
2008-10-08 09:45:35 +02:00
{
case 'text/plain' :
$note = array ();
$note [ 'info_type' ] = 'note' ;
2016-04-30 19:05:23 +02:00
$txt = str_replace ( " \r \n " , " \n " , Api\Translation :: convert ( $_data , $charset ));
2008-10-08 09:45:35 +02:00
2015-06-22 17:36:23 +02:00
$match = null ;
2011-06-02 20:14:53 +02:00
if ( preg_match ( '/([^\n]+)\n\n(.*)/ms' , $txt , $match ))
2008-10-08 09:45:35 +02:00
{
2010-02-09 22:56:39 +01:00
$note [ 'info_subject' ] = $match [ 1 ];
$note [ 'info_des' ] = $match [ 2 ];
2008-10-08 09:45:35 +02:00
}
else
{
2010-02-09 22:56:39 +01:00
$note [ 'info_subject' ] = $txt ;
2008-10-08 09:45:35 +02:00
}
break ;
case 'text/x-vnote' :
2015-06-22 17:36:23 +02:00
$vnote = new Horde_Icalendar ;
2016-04-29 09:51:13 +02:00
if ( $charset && $charset != 'utf-8' )
{
$_data = Api\Translation :: convert ( $_data , $charset , 'utf-8' );
}
if ( ! $vnote -> parsevCalendar ( $_data , 'VCALENDAR' )) return false ;
2009-07-15 22:04:17 +02:00
2008-10-08 09:45:35 +02:00
$components = $vnote -> getComponent ();
2009-07-15 22:04:17 +02:00
foreach ( $components as $component )
2008-10-08 09:45:35 +02:00
{
2015-06-22 17:36:23 +02:00
if ( is_a ( $component , 'Horde_Icalendar_Vnote' ))
2008-10-08 09:45:35 +02:00
{
$note = array ();
$note [ 'info_type' ] = 'note' ;
2015-06-24 12:46:19 +02:00
foreach ( $component -> getAllAttributes () as $attribute )
2008-10-08 09:45:35 +02:00
{
switch ( $attribute [ 'name' ])
{
case 'BODY' :
2010-02-09 22:56:39 +01:00
$note [ 'info_des' ] = str_replace ( " \r \n " , " \n " , $attribute [ 'value' ]);
2008-10-08 09:45:35 +02:00
break ;
2009-07-15 22:04:17 +02:00
2008-10-08 09:45:35 +02:00
case 'SUMMARY' :
2010-02-09 22:56:39 +01:00
$note [ 'info_subject' ] = str_replace ( " \r \n " , " \n " , $attribute [ 'value' ]);
2008-10-08 09:45:35 +02:00
break ;
2009-07-15 22:04:17 +02:00
2008-10-08 09:45:35 +02:00
case 'CATEGORIES' :
2009-12-07 10:04:39 +01:00
if ( $attribute [ 'value' ])
{
2010-02-09 22:56:39 +01:00
$cats = $this -> find_or_add_categories ( explode ( ',' , $attribute [ 'value' ]), $_noteID );
2009-12-07 10:04:39 +01:00
$note [ 'info_cat' ] = $cats [ 0 ];
}
2008-10-08 09:45:35 +02:00
break ;
}
}
}
}
}
2010-02-09 22:56:39 +01:00
if ( $this -> log )
{
error_log ( __FILE__ . '[' . __LINE__ . '] ' . __METHOD__ . " ( $_type , $_noteID ) \n " .
( $note ? array2string ( $note ) : 'FALSE' ) . " \n " , 3 , $this -> logfile );
}
return $note ;
2008-10-08 09:45:35 +02:00
}
2008-11-03 10:36:20 +01:00
/**
* Set the supported fields
*
* Currently we only store manufacturer and name
*
* @ param string $_productManufacturer
* @ param string $_productName
*/
2009-07-15 22:04:17 +02:00
function setSupportedFields ( $_productManufacturer = '' , $_productName = '' )
2008-11-03 10:36:20 +01:00
{
2009-07-15 22:04:17 +02:00
$state = & $_SESSION [ 'SyncML.state' ];
if ( isset ( $state ))
{
$deviceInfo = $state -> getClientDeviceInfo ();
}
// store product manufacturer and name, to be able to use it elsewhere
if ( $_productManufacturer )
{
$this -> productManufacturer = strtolower ( $_productManufacturer );
$this -> productName = strtolower ( $_productName );
}
if ( isset ( $deviceInfo ) && is_array ( $deviceInfo ))
{
if ( ! isset ( $this -> productManufacturer )
|| $this -> productManufacturer == ''
|| $this -> productManufacturer == 'file' )
{
$this -> productManufacturer = strtolower ( $deviceInfo [ 'manufacturer' ]);
}
if ( ! isset ( $this -> productName ) || $this -> productName == '' )
{
$this -> productName = strtolower ( $deviceInfo [ 'model' ]);
}
if ( isset ( $deviceInfo [ 'uidExtension' ])
&& $deviceInfo [ 'uidExtension' ])
{
$this -> uidExtension = true ;
}
2010-02-09 22:56:39 +01:00
if ( isset ( $deviceInfo [ 'tzid' ]) &&
$deviceInfo [ 'tzid' ])
{
switch ( $deviceInfo [ 'tzid' ])
{
2010-06-17 09:38:27 +02:00
case - 1 :
2010-02-09 22:56:39 +01:00
$this -> tzid = false ;
break ;
2010-06-17 09:38:27 +02:00
case - 2 :
2010-02-09 22:56:39 +01:00
$this -> tzid = null ;
break ;
default :
$this -> tzid = $deviceInfo [ 'tzid' ];
}
}
}
if ( $this -> log )
{
error_log ( __FILE__ . '[' . __LINE__ . '] ' . __METHOD__ .
'(' . $this -> productManufacturer .
', ' . $this -> productName . ', ' .
2016-04-30 19:05:23 +02:00
( $this -> tzid ? $this -> tzid : Api\DateTime :: $user_timezone -> getName ()) .
2010-02-09 22:56:39 +01:00
" ) \n " , 3 , $this -> logfile );
2009-07-15 22:04:17 +02:00
}
2015-06-24 10:53:18 +02:00
//Horde::logMessage('setSupportedFields(' . $this->productManufacturer . ', '
// . $this->productName .', ' .
2016-04-30 19:05:23 +02:00
// ($this->tzid ? $this->tzid : Api\DateTime::$user_timezone->getName()) .')',
2015-06-24 10:53:18 +02:00
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
2008-11-03 10:36:20 +01:00
}
2008-10-08 09:45:35 +02:00
}