2008-10-08 09:45:35 +02:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* InfoLog - iCalendar Parser
|
|
|
|
*
|
|
|
|
* @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>
|
2008-10-08 09:45:35 +02:00
|
|
|
* @package infolog
|
|
|
|
* @subpackage syncml
|
|
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
|
|
* @version $Id$
|
|
|
|
*/
|
|
|
|
|
2009-07-15 22:04:17 +02:00
|
|
|
require_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/lib/core.php';
|
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
|
|
|
/**
|
|
|
|
* @var array conversion of the priority egw => ical
|
|
|
|
*/
|
2008-10-08 09:45:35 +02:00
|
|
|
var $egw_priority2vcal_priority = array(
|
2009-07-15 22:04:17 +02:00
|
|
|
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
|
|
|
/**
|
|
|
|
* @var array conversion of the priority ical => egw
|
|
|
|
*/
|
2008-10-08 09:45:35 +02:00
|
|
|
var $vcal_priority2egw_priority = array(
|
2009-07-15 22:04:17 +02:00
|
|
|
9 => 0, 8 => 0, 7 => 0, // low
|
|
|
|
6 => 1, 5 => 1, 4 => 1, 0 => 1, // normal
|
|
|
|
3 => 2, 2 => 2, // high
|
|
|
|
1 => 3, // urgent
|
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;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Client CTCap Properties
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
var $clientProperties;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* @param array $_clientProperties client properties
|
|
|
|
*/
|
|
|
|
function __construct(&$_clientProperties = array())
|
|
|
|
{
|
|
|
|
parent::__construct();
|
|
|
|
|
|
|
|
$this->clientProperties = $_clientProperties;
|
|
|
|
}
|
|
|
|
|
2008-10-08 09:45:35 +02:00
|
|
|
/**
|
|
|
|
* Exports one InfoLog tast to an iCalendar VTODO
|
|
|
|
*
|
|
|
|
* @param int $_taskID info_id
|
2008-11-03 10:36:20 +01:00
|
|
|
* @param string $_version='2.0' could be '1.0' too
|
|
|
|
* @param string $_method='PUBLISH'
|
2008-10-08 09:45:35 +02:00
|
|
|
* @return string/boolean string with vCal or false on error (eg. no permission to read the event)
|
|
|
|
*/
|
2008-11-03 10:36:20 +01:00
|
|
|
function exportVTODO($_taskID, $_version='2.0',$_method='PUBLISH')
|
2008-10-08 09:45:35 +02:00
|
|
|
{
|
|
|
|
$taskData = $this->read($_taskID);
|
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
|
|
|
$taskData = $GLOBALS['egw']->translation->convert($taskData,
|
|
|
|
$GLOBALS['egw']->translation->charset(), 'UTF-8');
|
2008-10-08 09:45:35 +02:00
|
|
|
|
2009-06-08 18:21:14 +02:00
|
|
|
$vcal = new Horde_iCalendar;
|
2008-10-08 09:45:35 +02:00
|
|
|
$vcal->setAttribute('VERSION',$_version);
|
2008-11-03 10:36:20 +01:00
|
|
|
$vcal->setAttribute('METHOD',$_method);
|
2008-10-08 09:45:35 +02:00
|
|
|
|
|
|
|
$vevent = Horde_iCalendar::newComponent('VTODO',$vcal);
|
|
|
|
|
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(
|
|
|
|
'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'],
|
|
|
|
) 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'];
|
|
|
|
#Horde::logMessage("VTODO $field Size: $size, NoTruncate: " .
|
|
|
|
# ($noTruncate ? 'TRUE' : 'FALSE'), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$size = -1;
|
|
|
|
$noTruncate = false;
|
|
|
|
}
|
|
|
|
$cursize = strlen($value);
|
|
|
|
if (($size > 0) && $cursize > $size)
|
|
|
|
{
|
|
|
|
if ($noTruncate)
|
|
|
|
{
|
|
|
|
Horde::logMessage("VTODO $field omitted due to maximum size $size",
|
|
|
|
__FILE__, __LINE__, PEAR_LOG_WARNING);
|
|
|
|
continue; // skip field
|
|
|
|
}
|
|
|
|
// truncate the value to size
|
|
|
|
$value = substr($value, 0, $size -1);
|
|
|
|
#Horde::logMessage("VTODO $field truncated to maximum size $size",
|
|
|
|
# __FILE__, __LINE__, PEAR_LOG_INFO);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (empty($value) && ($size < 0 || $noTruncate)) continue;
|
|
|
|
|
|
|
|
if ($field == 'RELATED-TO')
|
|
|
|
{
|
|
|
|
$options = array('RELTYPE' => 'PARENT');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$options = array();
|
2008-10-08 09:45:35 +02:00
|
|
|
}
|
2009-07-15 22:04:17 +02:00
|
|
|
|
|
|
|
/*if(preg_match('/([\000-\012\015\016\020-\037\075])/', $value)) {
|
|
|
|
$options['ENCODING'] = 'QUOTED-PRINTABLE';
|
|
|
|
}*/
|
|
|
|
if ($this->productManufacturer != 'groupdav'
|
|
|
|
&& preg_match('/([\177-\377])/',$value))
|
2008-10-08 09:45:35 +02:00
|
|
|
{
|
|
|
|
$options['CHARSET'] = 'UTF-8';
|
|
|
|
}
|
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
|
|
|
|
|
|
|
if ($taskData['info_startdate'])
|
|
|
|
{
|
2009-09-27 10:23:01 +02:00
|
|
|
self::setDateOrTime($vevent,'DTSTART',$taskData['info_startdate']);
|
2009-07-15 22:04:17 +02:00
|
|
|
}
|
|
|
|
if ($taskData['info_enddate'])
|
|
|
|
{
|
2009-09-27 10:23:01 +02:00
|
|
|
self::setDateOrTime($vevent,'DUE',$taskData['info_enddate']);
|
2009-07-15 22:04:17 +02:00
|
|
|
}
|
|
|
|
if ($taskData['info_datecompleted'])
|
|
|
|
{
|
2009-09-27 10:23:01 +02:00
|
|
|
self::setDateOrTime($vevent,'COMPLETED',$taskData['info_datecompleted']);
|
2009-07-15 22:04:17 +02:00
|
|
|
}
|
|
|
|
|
2008-10-08 09:45:35 +02:00
|
|
|
$vevent->setAttribute('DTSTAMP',time());
|
2008-11-03 08:44:02 +01:00
|
|
|
$vevent->setAttribute('CREATED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_task',$_taskID,'add'));
|
|
|
|
$vevent->setAttribute('LAST-MODIFIED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_task',$_taskID,'modify'));
|
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']);
|
2008-10-08 09:45:35 +02:00
|
|
|
$vevent->setAttribute('PRIORITY',$this->egw_priority2vcal_priority[$taskData['info_priority']]);
|
|
|
|
|
2009-07-15 22:04:17 +02:00
|
|
|
|
2008-10-08 09:45:35 +02:00
|
|
|
$vcal->addComponent($vevent);
|
2009-07-15 22:04:17 +02:00
|
|
|
|
|
|
|
$retval = $vcal->exportvCalendar();
|
|
|
|
Horde::logMessage("exportVTODO:\n" . print_r($retval, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
|
|
return $retval;
|
2008-10-08 09:45:35 +02:00
|
|
|
}
|
|
|
|
|
2009-09-27 10:23:01 +02:00
|
|
|
/**
|
|
|
|
* Check if use set a date or date+time and export it as such
|
|
|
|
*
|
|
|
|
* @param Horde_iCalendar_* $vevent
|
|
|
|
* @param string $attr attribute name
|
|
|
|
* @param int $value timestamp
|
|
|
|
*/
|
|
|
|
static function setDateOrTime($vevent,$attr,$value)
|
|
|
|
{
|
|
|
|
// check if use set only a date --> export it as such
|
|
|
|
if (date('H:i',$value) == '00:00')
|
|
|
|
{
|
|
|
|
$vevent->setAttribute($attr,array(
|
|
|
|
'year' => date('Y',$value),
|
|
|
|
'month' => date('m',$value),
|
|
|
|
'mday' => date('d',$value),
|
|
|
|
),array('VALUE' => 'DATE'));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$vevent->setAttribute($attr,$value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-08 09:45:35 +02:00
|
|
|
/**
|
|
|
|
* Import a VTODO component of an iCal
|
|
|
|
*
|
|
|
|
* @param string $_vcalData
|
|
|
|
* @param int $_taskID=-1 info_id, default -1 = new entry
|
2009-07-15 22:04:17 +02:00
|
|
|
* @param boolean $merge=false merge data with existing entry
|
2008-10-08 09:45:35 +02:00
|
|
|
* @return int|boolean integer info_id or false on error
|
|
|
|
*/
|
2009-07-15 22:04:17 +02:00
|
|
|
function importVTODO(&$_vcalData, $_taskID=-1, $merge=false)
|
2008-10-08 09:45:35 +02:00
|
|
|
{
|
2009-07-15 22:04:17 +02:00
|
|
|
if (!$taskData = $this->vtodotoegw($_vcalData,$_taskID)) return false;
|
|
|
|
|
2008-10-08 09:45:35 +02:00
|
|
|
// we suppose that a not set status in a vtodo means that the task did not started yet
|
2009-07-15 22:04:17 +02:00
|
|
|
if (empty($taskData['info_status']))
|
2008-10-08 09:45:35 +02:00
|
|
|
{
|
|
|
|
$taskData['info_status'] = 'not-started';
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2009-07-15 22:04:17 +02:00
|
|
|
return $this->write($taskData);
|
|
|
|
}
|
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
|
|
|
|
* @param int $contentID=null infolog_id (or null, if unkown)
|
|
|
|
* @param boolean $relax=false if true, a weaker match algorithm is used
|
|
|
|
* @return infolog_id of a matching entry or false, if nothing was found
|
|
|
|
*/
|
|
|
|
function searchVTODO($_vcalData, $contentID=null, $relax=false) {
|
|
|
|
$result = false;
|
|
|
|
|
2009-11-19 11:40:54 +01:00
|
|
|
if (($egwData = $this->vtodotoegw($_vcalData,$contentID)))
|
2009-07-15 22:04:17 +02:00
|
|
|
{
|
|
|
|
if ($contentID)
|
|
|
|
{
|
|
|
|
$egwData['info_id'] = $contentID;
|
2008-10-08 09:45:35 +02:00
|
|
|
}
|
2009-07-15 22:04:17 +02:00
|
|
|
$result = $this->findVTODO($egwData, $relax);
|
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
|
|
|
}
|
|
|
|
|
2009-07-15 22:04:17 +02:00
|
|
|
/**
|
|
|
|
* Convert VTODO into a eGW infolog entry
|
|
|
|
*
|
|
|
|
* @param string $_vcalData VTODO data
|
|
|
|
* @param int $_taskID=-1 infolog_id of the entry
|
|
|
|
* @return array infolog entry or false on error
|
|
|
|
*/
|
|
|
|
function vtodotoegw($_vcalData, $_taskID=-1)
|
2008-10-08 09:45:35 +02:00
|
|
|
{
|
2009-06-08 18:21:14 +02:00
|
|
|
$vcal = new Horde_iCalendar;
|
2009-07-15 22:04:17 +02:00
|
|
|
if (!($vcal->parsevCalendar($_vcalData))) return false;
|
2009-12-07 10:08:51 +01:00
|
|
|
$version = $vcal->getAttribute('VERSION');
|
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
|
|
|
}
|
|
|
|
|
|
|
|
$components = $vcal->getComponents();
|
|
|
|
|
2009-07-15 22:04:17 +02:00
|
|
|
foreach ($components as $component)
|
2008-10-08 09:45:35 +02:00
|
|
|
{
|
2009-07-15 22:04:17 +02:00
|
|
|
if (is_a($component, 'Horde_iCalendar_vtodo'))
|
2008-10-08 09:45:35 +02:00
|
|
|
{
|
|
|
|
$taskData = array();
|
2009-07-15 22:04:17 +02:00
|
|
|
$taskData['info_type'] = 'task';
|
|
|
|
|
|
|
|
if ($_taskID > 0)
|
2008-10-08 09:45:35 +02:00
|
|
|
{
|
|
|
|
$taskData['info_id'] = $_taskID;
|
|
|
|
}
|
2009-07-15 22:04:17 +02:00
|
|
|
foreach ($component->_attributes as $attributes)
|
2008-10-08 09:45:35 +02:00
|
|
|
{
|
2009-07-15 22:04:17 +02:00
|
|
|
//$attributes['value'] = trim($attributes['value']);
|
|
|
|
if (empty($attributes['value'])) continue;
|
|
|
|
switch ($attributes['name'])
|
2008-10-08 09:45:35 +02:00
|
|
|
{
|
|
|
|
case 'CLASS':
|
2009-07-15 22:04:17 +02:00
|
|
|
$taskData['info_access'] = strtolower($attributes['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 'DESCRIPTION':
|
2009-07-15 22:04:17 +02:00
|
|
|
$value = $attributes['value'];
|
|
|
|
if (preg_match('/\s*\[UID:(.+)?\]/Usm', $value, $matches))
|
|
|
|
{
|
|
|
|
if (!isset($taskData['info_uid'])
|
|
|
|
&& strlen($matches[1]) >= $minimum_uid_length)
|
|
|
|
{
|
|
|
|
$taskData['info_uid'] = $matches[1];
|
|
|
|
}
|
|
|
|
//$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)
|
|
|
|
{
|
|
|
|
$taskData['info_id_parent'] = $this->getParentID($matches[1]);
|
|
|
|
}
|
|
|
|
//$value = str_replace($matches[0], '', $value);
|
|
|
|
}
|
|
|
|
$taskData['info_des'] = $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 'LOCATION':
|
2009-07-15 22:04:17 +02:00
|
|
|
$taskData['info_location'] = $attributes['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 'DUE':
|
2009-07-15 22:04:17 +02:00
|
|
|
// eGroupWare uses date only
|
|
|
|
$parts = @getdate($attributes['value']);
|
|
|
|
$value = @mktime(0, 0, 0, $parts['mon'], $parts['mday'], $parts['year']);
|
|
|
|
$taskData['info_enddate'] = $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 'COMPLETED':
|
|
|
|
$taskData['info_datecompleted'] = $attributes['value'];
|
|
|
|
break;
|
2009-07-15 22:04:17 +02:00
|
|
|
|
2008-10-08 09:45:35 +02:00
|
|
|
case 'DTSTART':
|
2009-07-15 22:04:17 +02:00
|
|
|
$taskData['info_startdate'] = $attributes['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 'PRIORITY':
|
2009-12-09 09:17:26 +01:00
|
|
|
if (1 <= $attributes['value'] && $attributes['value'] <= 9) {
|
2009-07-15 22:04:17 +02:00
|
|
|
$taskData['info_priority'] = $this->vcal_priority2egw_priority[$attributes['value']];
|
|
|
|
} else {
|
|
|
|
$taskData['info_priority'] = 1; // default = normal
|
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 'STATUS':
|
|
|
|
// check if we (still) have X-INFOLOG-STATUS set AND it would give an unchanged status (no change by the user)
|
|
|
|
foreach($component->_attributes as $attr)
|
|
|
|
{
|
|
|
|
if ($attr['name'] == 'X-INFOLOG-STATUS') break;
|
|
|
|
}
|
|
|
|
$taskData['info_status'] = $this->vtodo2status($attributes['value'],
|
|
|
|
$attr['name'] == 'X-INFOLOG-STATUS' ? $attr['value'] : null);
|
|
|
|
break;
|
2009-07-15 22:04:17 +02:00
|
|
|
|
2008-10-08 09:45:35 +02:00
|
|
|
case 'SUMMARY':
|
2009-07-15 22:04:17 +02:00
|
|
|
$taskData['info_subject'] = $attributes['value'];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'RELATED-TO':
|
|
|
|
$taskData['info_id_parent'] = $this->getParentID($attributes['value']);
|
2008-10-08 09:45:35 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'CATEGORIES':
|
2009-12-07 10:00:58 +01:00
|
|
|
if ($attributes['value'])
|
|
|
|
{
|
|
|
|
if($version == '1.0')
|
|
|
|
{
|
|
|
|
$vcats = $this->find_or_add_categories(explode(';',$attributes['value']), $_taskID);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$cats = $this->find_or_add_categories(explode(',',$attributes['value']), $_taskID);
|
|
|
|
}
|
|
|
|
$taskData['info_cat'] = $cats[0];
|
|
|
|
}
|
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 'UID':
|
2009-07-15 22:04:17 +02:00
|
|
|
if (strlen($attributes['value']) >= $minimum_uid_length) {
|
|
|
|
$taskData['info_uid'] = $attributes['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 'PERCENT-COMPLETE':
|
|
|
|
$taskData['info_percent'] = (int) $attributes['value'];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# the horde ical class does already convert in parsevCalendar
|
|
|
|
# do NOT convert here
|
|
|
|
#$taskData = $GLOBALS['egw']->translation->convert($taskData, 'UTF-8');
|
|
|
|
|
2009-07-15 22:04:17 +02:00
|
|
|
Horde::logMessage("vtodotoegw:\n" . print_r($taskData, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
|
|
|
2008-10-08 09:45:35 +02:00
|
|
|
return $taskData;
|
|
|
|
}
|
|
|
|
}
|
2009-07-15 22:04:17 +02:00
|
|
|
return false;
|
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)
|
|
|
|
* @return string VNOTE representation of the infolog entry
|
|
|
|
*/
|
2008-10-08 09:45:35 +02:00
|
|
|
function exportVNOTE($_noteID, $_type)
|
|
|
|
{
|
|
|
|
$note = $this->read($_noteID);
|
2009-07-15 22:04:17 +02:00
|
|
|
$note = $GLOBALS['egw']->translation->convert($note,
|
|
|
|
$GLOBALS['egw']->translation->charset(), 'UTF-8');
|
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;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'text/x-vnote':
|
2009-06-08 18:21:14 +02:00
|
|
|
$vnote = new Horde_iCalendar_vnote();
|
2009-07-15 22:04:17 +02:00
|
|
|
$options = array('CHARSET' => 'UTF-8');
|
2008-10-08 09:45:35 +02:00
|
|
|
$vNote->setAttribute('VERSION', '1.1');
|
2009-07-15 22:04:17 +02:00
|
|
|
foreach (array( 'SUMMARY' => $note['info_subject'],
|
|
|
|
'BODY' => $note['info_des'],
|
|
|
|
) as $field => $value)
|
|
|
|
{
|
|
|
|
$vnote->setAttribute($field, $value);
|
|
|
|
if ($this->productManufacturer != 'groupdav'
|
|
|
|
&& preg_match('/([\177-\377])/', $value))
|
|
|
|
{
|
|
|
|
$vevent->setParameter($field, $options);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($note['info_startdate'])
|
|
|
|
{
|
2008-10-08 09:45:35 +02:00
|
|
|
$vnote->setAttribute('DCREATED',$note['info_startdate']);
|
2009-07-15 22:04:17 +02:00
|
|
|
}
|
2008-11-03 08:44:02 +01:00
|
|
|
$vnote->setAttribute('DCREATED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_note',$_noteID,'add'));
|
|
|
|
$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
|
|
|
if (!empty($note['info_cat']))
|
|
|
|
{
|
|
|
|
$cats = $this->get_categories(array($note['info_cat']));
|
2009-07-15 22:04:17 +02:00
|
|
|
$value = $cats[0];
|
|
|
|
$vnote->setAttribute('CATEGORIES', $value);
|
|
|
|
if ($this->productManufacturer != 'groupdav'
|
|
|
|
&& preg_match('/([\177-\377])/', $value))
|
|
|
|
{
|
|
|
|
$vevent->setParameter('CATEGORIES', $options);
|
|
|
|
}
|
2008-10-08 09:45:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#$vnote->setAttribute('CLASS',$taskData['info_access'] == 'public' ? 'PUBLIC' : 'PRIVATE');
|
|
|
|
|
|
|
|
return $vnote->exportvCalendar();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
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)
|
2009-11-19 11:40:54 +01:00
|
|
|
* @param int $_noteID=-1 info_id, default -1 = new entry
|
2009-07-15 22:04:17 +02:00
|
|
|
* @param boolean $merge=false merge data with existing entry
|
|
|
|
* @return int|boolean integer info_id or false on error
|
|
|
|
*/
|
2009-11-19 11:40:54 +01:00
|
|
|
function importVNOTE(&$_vcalData, $_type, $_noteID=-1, $merge=false)
|
2008-10-08 09:45:35 +02:00
|
|
|
{
|
2009-11-19 11:40:54 +01:00
|
|
|
if (!($note = $this->vnotetoegw($_vcalData, $_type, $_noteID))) 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
|
|
|
|
|
|
|
#_debug_array($taskData);exit;
|
|
|
|
return $this->write($note);
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
* @return infolog_id of a matching entry or false, if nothing was found
|
|
|
|
*/
|
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
|
|
|
function searchVNOTE($_vcalData, $_type, $contentID=null)
|
2008-10-08 09:45:35 +02:00
|
|
|
{
|
2009-11-19 11:40:54 +01:00
|
|
|
if (!($note = $this->vnotetoegw($_vcalData,$_type,$contentID))) return false;
|
2009-07-15 22:04:17 +02:00
|
|
|
|
|
|
|
if ($contentID) $note['info_id'] = $contentID;
|
|
|
|
|
|
|
|
unset($note['info_startdate']);
|
|
|
|
|
|
|
|
$filter = array();
|
|
|
|
|
|
|
|
if (!empty($note['info_des']))
|
|
|
|
{
|
|
|
|
$description = trim(preg_replace("/\r?\n?\\[[A-Z_]+:.*\\]/i", '', $note['info_des']));
|
|
|
|
unset($note['info_des']);
|
|
|
|
if (strlen($description))
|
|
|
|
{
|
|
|
|
$filter['search'] = $description;
|
|
|
|
}
|
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
|
|
|
|
2009-07-15 22:04:17 +02:00
|
|
|
$filter['col_filter'] = $note;
|
|
|
|
|
|
|
|
if (($foundItems = $this->search($filter)))
|
|
|
|
{
|
|
|
|
if (count($foundItems) > 0)
|
|
|
|
{
|
2008-10-08 09:45:35 +02:00
|
|
|
$itemIDs = array_keys($foundItems);
|
|
|
|
return $itemIDs[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
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)
|
2009-11-19 11:40:54 +01:00
|
|
|
* @param int $_noteID=-1 infolog_id of the entry
|
2009-07-15 22:04:17 +02:00
|
|
|
* @return array infolog entry or false on error
|
|
|
|
*/
|
2009-11-19 11:40:54 +01:00
|
|
|
function vnotetoegw($_data, $_type, $_noteID=-1)
|
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':
|
|
|
|
$note = array();
|
|
|
|
$note['info_type'] = 'note';
|
|
|
|
$botranslation =& CreateObject('phpgwapi.translation');
|
|
|
|
$txt = $botranslation->convert($_data, 'utf-8');
|
|
|
|
$txt = str_replace("\r\n", "\n", $txt);
|
|
|
|
|
|
|
|
if (preg_match("/^(^\n)\n\n(.*)$/", $txt, $match))
|
|
|
|
{
|
|
|
|
$note['info_subject'] = $match[0];
|
|
|
|
$note['info_des'] = $match[1];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
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
|
|
|
// should better be imported as subject, but causes duplicates
|
2009-07-15 22:04:17 +02:00
|
|
|
// TODO: should be examined
|
2008-10-08 09:45:35 +02:00
|
|
|
$note['info_des'] = $txt;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $note;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'text/x-vnote':
|
2009-06-08 18:21:14 +02:00
|
|
|
$vnote = new Horde_iCalendar;
|
2009-07-15 22:04:17 +02:00
|
|
|
if (!$vcal->parsevCalendar($_data)) return false;
|
2009-12-07 10:08:51 +01:00
|
|
|
$version = $vcal->getAttribute('VERSION');
|
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
|
|
|
{
|
2009-07-15 22:04:17 +02:00
|
|
|
if (is_a($component, 'Horde_iCalendar_vnote'))
|
2008-10-08 09:45:35 +02:00
|
|
|
{
|
|
|
|
$note = array();
|
|
|
|
$note['info_type'] = 'note';
|
|
|
|
|
2009-07-15 22:04:17 +02:00
|
|
|
foreach ($component->_attributes as $attribute)
|
2008-10-08 09:45:35 +02:00
|
|
|
{
|
|
|
|
switch ($attribute['name'])
|
|
|
|
{
|
|
|
|
case 'BODY':
|
|
|
|
$note['info_des'] = $attribute['value'];
|
|
|
|
break;
|
2009-07-15 22:04:17 +02:00
|
|
|
|
2008-10-08 09:45:35 +02:00
|
|
|
case 'SUMMARY':
|
|
|
|
$note['info_subject'] = $attribute['value'];
|
|
|
|
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'])
|
|
|
|
{
|
|
|
|
if($version == '1.0')
|
|
|
|
{
|
2009-12-07 10:08:51 +01:00
|
|
|
$cats = $this->find_or_add_categories(explode(';',$attribute['value']), $_noteID);
|
2009-12-07 10:04:39 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$cats = $this->find_or_add_categories(explode(',',$attribute['value']), $_noteID);
|
|
|
|
}
|
|
|
|
$note['info_cat'] = $cats[0];
|
|
|
|
}
|
2008-10-08 09:45:35 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $note;
|
|
|
|
}
|
|
|
|
}
|
2009-07-15 22:04:17 +02:00
|
|
|
return false;
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Horde::logMessage('setSupportedFields(' . $this->productManufacturer . ', ' . $this->productName .')', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
|
|
|
2008-11-03 10:36:20 +01:00
|
|
|
}
|
2008-10-08 09:45:35 +02:00
|
|
|
}
|