SyncML patches from patrick.bihan-faou-AT-mindstep.com (without

logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
  direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
  other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
This commit is contained in:
Ralf Becker 2007-09-29 10:29:48 +00:00
parent 82f2b4e91f
commit 7b6a1013fc
21 changed files with 1216 additions and 392 deletions

View File

@ -1108,4 +1108,86 @@ class bocontacts extends socontacts
//echo "<p>bocontacts::addr_format_by_country('$country'='$code') = '$adr_format'</p>\n";
return $adr_format;
}
var $app_cat;
var $glob_cat;
function find_or_add_categories($catname_list)
{
if (!is_object($this->glob_cat))
{
if (!is_object($GLOBALS['egw']->categories))
{
$GLOBALS['egw']->categories =& CreateObject('phpgwapi.categories',$this->owner,'phpgw');
}
$this->glob_cat =& $GLOBALS['egw']->categories;
}
if (!is_object($this->app_cat))
{
$this->app_cat =& CreateObject('phpgwapi.categories',$this->owner,'addressbook');
}
$cat_id_list = array();
foreach($catname_list as $cat_name)
{
$cat_name = trim($cat_name);
if (!($cat_id = $this->glob_cat->name2id($cat_name))
&& !($cat_id = $this->app_cat->name2id($cat_name)))
{
$cat_id = $this->app_cat->add( array('name' => $cat_name,'descr' => $cat_name ));
}
$cat_id_list[] = $cat_id;
}
if (count($cat_id_list) > 1)
{
sort($cat_id_list, SORT_NUMERIC);
}
return $cat_id_list;
}
function get_categories($cat_id_list)
{
if (!is_object($this->glob_cat))
{
if (!is_object($GLOBALS['egw']->categories))
{
$GLOBALS['egw']->categories =& CreateObject('phpgwapi.categories',$this->owner,'phpgw');
}
$this->glob_cat =& $GLOBALS['egw']->categories;
}
if (!is_object($this->app_cat))
{
$this->app_cat =& CreateObject('phpgwapi.categories',$this->owner,'addressbook');
}
$cat_list = array();
foreach(explode(',',$cat_id_list) as $cat_id)
{
if ( ($cat_data = $this->glob_cat->return_single($cat_id))
|| ($cat_data = $this->app_cat->return_single($cat_id)) )
{
$cat_list[] = $cat_data[0]['name'];
}
}
return $cat_list;
}
function fixup_contact(&$contact)
{
if (!isset($contact['n_fn']) || empty($contact['n_fn']))
{
$contact['n_fn'] = $this->fullname($contact);
}
if (!isset($contact['n_fileas']) || empty($contact['n_fileas']))
{
$contact['n_fileas'] = $this->fileas($contact);
}
}
}

View File

@ -135,23 +135,9 @@ class sifaddressbook extends bocontacts
$value = $GLOBALS['egw']->translation->convert($value, 'utf-8');
switch($key) {
case 'cat_id':
if(!empty($value)) {
$isAdmin = $GLOBALS['egw']->acl->check('run',1,'admin');
$egwCategories =& CreateObject('phpgwapi.categories', $GLOBALS['egw_info']['user']['account_id'], 'addressbook');
$categories = explode(';',$value);
// add missing categories as personal categories as needed
foreach($categories as $categorieName) {
$cat_id = false;
$categorieName = trim($categorieName);
if(!($cat_id = $egwCategories->name2id($categorieName))) {
$cat_id = $egwCategories->add(array('name' => $categorieName, 'descr' => lang('added by synchronisation')));
error_log("added $cat_id => $categorieName");
}
if($cat_id) {
if(!empty($finalContact[$key])) $finalContact[$key] .= ',';
$finalContact[$key] .= $cat_id;
}
}
if(!empty($value))
{
$finalContact[$key] = implode(",", $this->find_or_add_categories(explode(';', $value)));
}
break;
@ -164,6 +150,8 @@ class sifaddressbook extends bocontacts
break;
}
}
$this->fixup_contact($finalContact);
return $finalContact;
}
@ -231,6 +219,9 @@ class sifaddressbook extends bocontacts
#error_log(print_r($entry,true));
$sysCharSet = $GLOBALS['egw']->translation->charset();
// fillup some defaults such as n_fn and n_fileas is needed
$this->fixup_contact($entry);
foreach($this->sifMapping as $sifField => $egwField)
{
if(empty($egwField)) continue;
@ -245,16 +236,8 @@ class sifaddressbook extends bocontacts
// TODO handle multiple categories
case 'Categories':
if(!empty($value)) {
$egwCategories =& CreateObject('phpgwapi.categories',$GLOBALS['egw_info']['user']['account_id'],'addressbook');
$categories = explode(',',$value);
$value = '';
foreach($categories as $cat_id) {
if(($catData = $egwCategories->return_single($cat_id)))
{
if(!empty($value)) $value .= '; ';
$value .= $catData[0]['name'];
}
}
$value = implode("; ", $this->get_categories($value));
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
}
$sifContact .= "<$sifField>$value</$sifField>";
break;
@ -270,7 +253,7 @@ class sifaddressbook extends bocontacts
break;
default:
$sifContact .= "<$sifField>$value</$sifField>";
$sifContact .= "<$sifField>".trim($value)."</$sifField>";
break;
}
}

View File

@ -57,52 +57,83 @@ class vcaladdressbook extends bocontacts
if(!($entry = $this->read($_id))) {
return false;
}
foreach($this->supportedFields as $vcardField => $databaseFields) {
$options = array();
$value = '';
foreach($databaseFields as $databaseField) {
$tempVal = ';';
if(!empty($databaseField)) {
$tempVal = trim($entry[$databaseField]).';';
}
$value .= $tempVal;
}
// remove the last ;
$value = substr($value, 0, -1);
switch($vcardField) {
// TODO handle multiple categories
case 'CATEGORIES':
$catData = ExecMethod('phpgwapi.categories.return_single',$value);
$value = $catData[0]['name'];
break;
case 'CLASS':
$value = $value ? 'PRIVATE' : 'PUBLIC';
break;
case 'BDAY':
if(!empty($value)) {
$value = str_replace('-','',$value).'T000000Z';
}
break;
$this->fixup_contact($entry);
foreach($this->supportedFields as $vcardField => $databaseFields)
{
$values = array();
$options = array();
$hasdata = 0;
foreach($databaseFields as $databaseField)
{
$value = "";
if (!empty($databaseField))
{
$value = trim($entry[$databaseField]);
}
switch($databaseField)
{
case 'private':
$value = $value ? 'PRIVATE' : 'PUBLIC';
$hasdata++;
break;
case 'bday':
if (!empty($value))
{
$value = str_replace('-','',$value).'T000000Z';
$hasdata++;
}
break;
case 'jpegphoto':
if(!empty($value))
{
error_log("PHOTO='".$value."'");
$hasdata++;
}
break;
case 'cat_id':
if (!empty($value))
{
$value = implode(",", $this->get_categories($value));
}
// fall-through to the normal processing of string values
default:
if(!empty($value))
{
$value = $GLOBALS['egw']->translation->convert(trim($value), $sysCharSet, 'utf-8');
$options['CHARSET'] = 'UTF-8';
if(preg_match('/([\000-\012\015\016\020-\037\075])/',$value))
{
$options['ENCODING'] = 'QUOTED-PRINTABLE';
}
$hasdata++;
}
break;
}
if (empty($value))
{
$value = "";
}
$values[] = $value;
}
if ($databaseField != 'jpegphoto') {
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
if ($hasdata <= 0)
{
// don't add the entry if there is no data for this field
continue;
}
// don't add the entry if it contains only ';'
// exeptions for mendatory fields
if( ( strlen(str_replace(';','',$value)) != 0 ) || in_array($vcardField,array('FN','ORG','N')) ) {
$vCard->setAttribute($vcardField, $value);
}
if(preg_match('/([\000-\012\015\016\020-\037\075])/',$value)) {
$options['ENCODING'] = 'QUOTED-PRINTABLE';
}
if(preg_match('/([\177-\377])/',$value)) {
$options['CHARSET'] = 'UTF-8';
}
$vCard->setAttribute($vcardField, implode(';', $values));
$vCard->setParameter($vcardField, $options);
}
@ -177,6 +208,7 @@ class vcaladdressbook extends bocontacts
'CLASS' => array('private'),
'EMAIL' => array('email'),
'N' => array('n_family','n_given','','',''),
'FN' => array('n_fn'),
'NOTE' => array('note'),
'ORG' => array('org_name',''),
'TEL;CELL' => array('tel_cell'),
@ -196,6 +228,7 @@ class vcaladdressbook extends bocontacts
'EMAIL;INTERNET;WORK' => array('email'),
'EMAIL;INTERNET;HOME' => array('email_home'),
'N' => array('n_family','n_given','n_middle','n_prefix','n_suffix'),
'FN' => array('n_fn'),
'NOTE' => array('note'),
'ORG' => array('org_name','org_unit'),
'TEL;CELL;WORK' => array('tel_cell'),
@ -216,6 +249,7 @@ class vcaladdressbook extends bocontacts
'CLASS' => array('private'),
'EMAIL' => array('email'),
'N' => array('n_family','n_given','','',''),
'FN' => array('n_fn'),
'NOTE' => array('note'),
'ORG' => array('org_name',''),
'TEL;CELL;WORK' => array('tel_cell'),
@ -235,6 +269,7 @@ class vcaladdressbook extends bocontacts
'EMAIL;INTERNET;WORK' => array('email'),
'EMAIL;INTERNET;HOME' => array('email_home'),
'N' => array('n_family','n_given','','',''),
'FN' => array('n_fn'),
'NOTE' => array('note'),
'ORG' => array('org_name','org_unit'),
'TEL;CELL;WORK' => array('tel_cell'),
@ -255,6 +290,7 @@ class vcaladdressbook extends bocontacts
'EMAIL;INTERNET;WORK' => array('email'),
'EMAIL;INTERNET;HOME' => array('email_home'),
'N' => array('n_family','n_given','','',''),
'FN' => array('n_fn'),
'NOTE' => array('note'),
'ORG' => array('org_name',''),
'TEL;CELL;WORK' => array('tel_cell'),
@ -278,6 +314,7 @@ class vcaladdressbook extends bocontacts
'EMAIL;INTERNET;WORK' => array('email'),
'EMAIL;INTERNET;HOME' => array('email_home'),
'N' => array('n_family','n_given','','n_prefix','n_suffix'),
'FN' => array('n_fn'),
'NOTE' => array('note'),
'ORG' => array('org_name',''),
'TEL;CELL;WORK' => array('tel_cell'),
@ -293,32 +330,38 @@ class vcaladdressbook extends bocontacts
);
$defaultFields[6] = array(
'ADR;WORK' => array('','','adr_one_street','adr_one_locality','adr_one_region',
'adr_one_postalcode','adr_one_countryname'),
'ADR;HOME' => array('','','adr_two_street','adr_two_locality','adr_two_region',
'adr_two_postalcode','adr_two_countryname'),
'EMAIL' => array('email'),
'EMAIL;HOME' => array('email_home'),
'N' => array('n_family','n_given','','',''),
'NOTE' => array('note'),
'ORG' => array('org_name','org_unit'),
'TEL;CELL' => array('tel_cell'),
'TEL;HOME;FAX' => array('tel_fax'),
'ADR;WORK' => array('','','adr_one_street','adr_one_locality','adr_one_region',
'adr_one_postalcode','adr_one_countryname'),
'ADR;HOME' => array('','','adr_two_street','adr_two_locality','adr_two_region',
'adr_two_postalcode','adr_two_countryname'),
'EMAIL' => array('email'),
'EMAIL;HOME' => array('email_home'),
'N' => array('n_family','n_given','','',''),
'FN' => array('n_fn'),
'NOTE' => array('note'),
'ORG' => array('org_name','org_unit'),
'TEL;CELL' => array('tel_cell'),
'TEL;HOME;FAX' => array('tel_fax'),
'TEL;HOME;VOICE' => array('tel_home'),
'TEL;PAGER' => array('tel_pager'),
'TEL;PAGER' => array('tel_pager'),
'TEL;WORK;VOICE' => array('tel_work'),
'TITLE' => array('title'),
'URL;WORK' => array('url'),
'URL' => array('url_home'),
'TITLE' => array('title'),
'URL;WORK' => array('url'),
'URL' => array('url_home'),
);
//error_log("Client: $_productManufacturer $_productName");
switch(strtolower($_productManufacturer))
{
case 'funambol':
switch(strtolower($_productName))
switch (strtolower($_productName))
{
case 'fmz-thunderbird-plugin':
case 'thunderbird':
$this->supportedFields = $defaultFields[6];
break;
default:
error_log("Funambol product '$_productName', assuming same as thunderbird");
$this->supportedFields = $defaultFields[6];
break;
}
@ -328,7 +371,10 @@ class vcaladdressbook extends bocontacts
switch(strtolower($_productName))
{
case 'syncje outlook edition':
$this->supportedFields = $defaultFields[1];
break;
default:
error_log("Nethaus product '$_productName', assuming same as 'syncje outlook'");
$this->supportedFields = $defaultFields[1];
break;
}
@ -341,7 +387,10 @@ class vcaladdressbook extends bocontacts
$this->supportedFields = $defaultFields[5];
break;
case '6600':
$this->supportedFields = $defaultFields[4];
break;
default:
error_log("Unknown Nokia phone '$_productName', assuming same as '6600'");
$this->supportedFields = $defaultFields[4];
break;
}
@ -363,17 +412,25 @@ class vcaladdressbook extends bocontacts
switch(strtolower($_productName))
{
case 'sx1':
$this->supportedFields = $defaultFields[3];
break;
default:
error_log("Unknown Siemens phone '$_productName', assuming same as 'sx1'");
$this->supportedFields = $defaultFields[3];
break;
}
break;
case 'sonyericsson':
case 'sony ericsson':
switch(strtolower($_productName))
{
case 'd750i':
$this->supportedFields = $defaultFields[2];
break;
case 'p910i':
default:
error_log("unknown Sony Ericsson phone '$_productName', assuming same as 'd750i'");
$this->supportedFields = $defaultFields[2];
break;
}
@ -387,6 +444,7 @@ class vcaladdressbook extends bocontacts
#$this->supportedFields['PHOTO'] = array('jpegphoto');
break;
default:
error_log("Synthesis connector '$_productName', using default fields");
$this->supportedFields = $defaultFields[0];
break;
}
@ -398,7 +456,7 @@ class vcaladdressbook extends bocontacts
// the fallback for SyncML
default:
error_log("Client not found: $_productManufacturer $_productName");
error_log("Client not found: '$_productManufacturer' '$_productName'");
$this->supportedFields = $defaultFields[0];
break;
}
@ -500,30 +558,6 @@ class vcaladdressbook extends bocontacts
}
break;
case 'CATEGORIES':
#cat_id = 7,8
$vcardData['category'] = array();
if ($attributes['value'])
{
if (!is_object($this->cat))
{
if (!is_object($GLOBALS['egw']->categories))
{
$GLOBALS['egw']->categories =& CreateObject('phpgwapi.categories',$this->owner,'addressbook');
}
$this->cat =& $GLOBALS['egw']->categories;
}
foreach(explode(',',$attributes['value']) as $cat_name)
{
if (!($cat_id = $this->cat->name2id($cat_name)))
{
$cat_id = $this->cat->add( array('name' => $cat_name,'descr' => $cat_name ));
}
$vcardData['category'][] = $cat_id;
}
}
break;
case 'VERSION':
break;
@ -546,38 +580,30 @@ class vcaladdressbook extends bocontacts
{
if(!empty($fieldName))
{
$value = trim($vcardValues[$vcardKey]['values'][$fieldKey]);
switch($fieldName)
{
case 'bday':
if(!empty($vcardValues[$vcardKey]['values'][$fieldKey])) {
$contact[$fieldName] = date('Y-m-d', $vcardValues[$vcardKey]['values'][$fieldKey]);
if(!empty($value)) {
$contact[$fieldName] = date('Y-m-d', $value);
}
break;
case 'private':
(int)$contact[$fieldName] = $vcardValues[$vcardKey]['values'][$fieldKey] == 'PRIVATE';
(int)$contact[$fieldName] = $value == 'PRIVATE';
break;
case 'cat_id':
if (!is_object($this->cat)) {
if (!is_object($GLOBALS['egw']->categories)) {
$GLOBALS['egw']->categories =& CreateObject('phpgwapi.categories',$GLOBALS['egw_info']['user']['account_id'],'addressbook');
}
$this->cat =& $GLOBALS['egw']->categories;
}
foreach(explode(',',$vcardValues[$vcardKey]['values'][$fieldKey]) as $cat_name) {
if (!($cat_id = $this->cat->name2id($cat_name))) {
$cat_id = $this->cat->add( array('name' => $cat_name, 'descr' => $cat_name ));
}
$contact[$fieldName] = $cat_id;
}
$contact[$fieldName] = implode(",",$this->find_or_add_categories(explode(',',$value)));
break;
case 'note':
// note may contain ','s but maybe this needs to be fixed in vcard parser...
$contact[$fieldName] = trim($vcardValues[$vcardKey]['value']);
break;
//$contact[$fieldName] = trim($vcardValues[$vcardKey]['value']);
//break;
default:
$contact[$fieldName] = trim($vcardValues[$vcardKey]['values'][$fieldKey]);
$contact[$fieldName] = $value;
break;
}
}
@ -585,7 +611,7 @@ class vcaladdressbook extends bocontacts
}
}
$contact['n_fn'] = trim($contact['n_given'].' '.$contact['n_family']);
$this->fixup_contact($contact);
return $contact;
}

View File

@ -121,6 +121,21 @@ class bocalupdate extends bocal
!$event['id'] && !$this->check_perms(EGW_ACL_EDIT,0,$event['owner'])) &&
!$this->check_perms(EGW_ACL_ADD,0,$event['owner']))
{
// Just update the status, if the user is in the event already
// is user is in both original and updated event
$egw_event = $this->read($event['id']);
if ( isset($egw_event['participants'][$this->user])
&& isset($event['participants'][$this->user]))
{
// Update their status in the event and say we're done.
// Admittedly, this is false, it's dropping any changes on the floor,
// But this will work better than dropping -everything- silently on
// the floor
$this->set_status($event['id'],'u',$this->user,$event['participants'][$this->user],0);
unset($egw_event);
return $event['id'];
}
return false;
}
// check for conflicts only happens !$ignore_conflicts AND if start + end date are given
@ -1017,4 +1032,65 @@ class bocalupdate extends bocal
}
return $this->so->delete_alarm($id);
}
var $app_cat;
var $glob_cat;
function find_or_add_categories($catname_list)
{
if (!is_object($this->glob_cat))
{
$this->glob_cat =& CreateObject('phpgwapi.categories',$GLOBALS['egw_info']['user']['account_id'],'phpgw');
}
if (!is_object($this->app_cat))
{
$this->app_cat =& CreateObject('phpgwapi.categories',$GLOBALS['egw_info']['user']['account_id'],'calendar');
}
$cat_id_list = array();
foreach($catname_list as $cat_name)
{
$cat_name = trim($cat_name);
if (!($cat_id = $this->glob_cat->name2id($cat_name))
&& !($cat_id = $this->app_cat->name2id($cat_name)))
{
$cat_id = $this->app_cat->add( array('name' => $cat_name,'descr' => $cat_name ));
}
$cat_id_list[] = $cat_id;
}
if (count($cat_id_list) > 1)
{
sort($cat_id_list, SORT_NUMERIC);
}
return $cat_id_list;
}
function get_categories($cat_id_list)
{
if (!is_object($this->glob_cat))
{
$this->glob_cat =& CreateObject('phpgwapi.categories',$GLOBALS['egw_info']['user']['account_id'],'phpgw');
}
if (!is_object($this->app_cat))
{
$this->app_cat =& CreateObject('phpgwapi.categories',$GLOBALS['egw_info']['user']['account_id'],'calendar');
}
$cat_list = array();
foreach(explode(',',$cat_id_list) as $cat_id)
{
if ( ($cat_data = $this->glob_cat->return_single($cat_id))
|| ($cat_data = $this->app_cat->return_single($cat_id)) )
{
$cat_list[] = $cat_data[0]['name'];
}
}
return $cat_list;
}
}

View File

@ -117,24 +117,38 @@
function &exportVCal($events,$version='1.0', $method='PUBLISH')
{
$egwSupportedFields = array(
'CLASS' => array('dbName' => 'public'),
'SUMMARY' => array('dbName' => 'title'),
'CLASS' => array('dbName' => 'public'),
'SUMMARY' => array('dbName' => 'title'),
'DESCRIPTION' => array('dbName' => 'description'),
'LOCATION' => array('dbName' => 'location'),
'DTSTART' => array('dbName' => 'start'),
'DTEND' => array('dbName' => 'end'),
'ORGANIZER' => array('dbName' => 'owner'),
'ATTENDEE' => array('dbName' => 'participants'),
'RRULE' => array('dbName' => 'recur_type'),
'EXDATE' => array('dbName' => 'recur_exception'),
'PRIORITY' => array('dbName' => 'priority'),
'TRANSP' => array('dbName' => 'non_blocking'),
'LOCATION' => array('dbName' => 'location'),
'DTSTART' => array('dbName' => 'start'),
'DTEND' => array('dbName' => 'end'),
'ORGANIZER' => array('dbName' => 'owner'),
'ATTENDEE' => array('dbName' => 'participants'),
'RRULE' => array('dbName' => 'recur_type'),
'EXDATE' => array('dbName' => 'recur_exception'),
'PRIORITY' => array('dbName' => 'priority'),
'TRANSP' => array('dbName' => 'non_blocking'),
'CATEGORIES' => array('dbName' => 'category'),
);
if(!is_array($this->supportedFields))
{
$this->setSupportedFields();
}
if($this->productManufacturer == '' )
{ // syncevolution is broken
$version = "2.0";
}
$palm_enddate_workaround=False;
if($this->productManufacturer == 'Synthesis AG'
&& strpos($this->productName, "PalmOS") )
{
// This workaround adds 1 day to the recur_enddate if it exists, to fix a palm bug
$palm_enddate_workaround=True;
}
$vcal = &new Horde_iCalendar;
$vcal->setAttribute('PRODID','-//eGroupWare//NONSGML eGroupWare Calendar '.$GLOBALS['egw_info']['apps']['calendar']['version'].'//'.
strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang']));
@ -186,7 +200,22 @@
// PARTSTAT={NEEDS-ACTION|ACCEPTED|DECLINED|TENTATIVE|DELEGATED|COMPLETED|IN-PROGRESS} everything from delegated is NOT used by eGW atm.
$status = $this->status_egw2ical[$status];
// CUTYPE={INDIVIDUAL|GROUP|RESOURCE|ROOM|UNKNOWN}
$cutype = $GLOBALS['egw']->accounts->get_type($uid) == 'g' ? 'GROUP' : 'INDIVIDUAL';
switch (is_nummeric($uid) ? $GLOBALS['egw']->accounts->get_type($uid) : $uid{0})
{
case 'g':
$cutype = 'GROUP';
break;
case 'r':
$cutype = 'RESOURCE';
break;
case 'u':
$cutype = 'INDIVIDUAL';
break;
default:
$cutype = 'UNKNOWN';
$cutype = 'INDIVIDUAL';
break;
};
$parameters['ATTENDEE'][] = array(
'CN' => $cn,
'ROLE' => $role,
@ -242,7 +271,20 @@
$rrule['FREQ'] = $rrule['FREQ'].' '.$rrule['BYDAY'];
break;
}
$rrule['UNTIL'] = ($event['recur_enddate']) ? date('Ymd',$event['recur_enddate']).'T'.date('His',$event['start']) : '#0';
if ($event['recur_enddate'])
{
$recur_enddate = (int)$event['recur_enddate'];
if ($palm_enddate_workaround)
{
$recur_enddate += 86400;
}
$rrule['UNTIL'] = date('Ymd',$recur_enddate);
}
else
{
$rrule['UNTIL'] = '#0';
}
$attributes['RRULE'] = $rrule['FREQ'].' '.$rrule['UNTIL'];
} else {
@ -289,7 +331,7 @@
{
$days[] = date('Ymd',$day);
}
$attributes['EXDATE'] = implode(';',$days);
$attributes['EXDATE'] = implode(',',$days);
$parameters['EXDATE']['VALUE'] = 'DATE';
}
break;
@ -309,9 +351,10 @@
case 'CATEGORIES':
if ($event['category'])
{
$attributes['CATEGORIES'] = implode(',',$this->categories($event['category'],$nul));
$attributes['CATEGORIES'] = implode(',',$this->get_categories($event['category']));
}
break;
default:
if ($event[$egwFieldInfo['dbName']]) // dont write empty fields
{
@ -394,6 +437,13 @@
}
//echo "supportedFields="; _debug_array($this->supportedFields);
$syncevo_enddate_fix = False;
if( $this->productManufacturer == '' && $this->productName == '' )
{
// syncevolution needs an adjusted recur_enddate
$syncevo_enddate_fix = True;
}
$Ok = false; // returning false, if file contains no components
foreach($vcal->getComponents() as $component)
{
@ -403,7 +453,10 @@
#$event = array('participants' => array());
$event = array();
$alarms = array();
$vcardData = array('recur_type' => 0);
$vcardData = array(
'recur_type' => MCAL_RECUR_NONE,
'recur_exception' => array(),
);
// lets see what we can get from the vcard
foreach($component->_attributes as $attributes)
@ -429,6 +482,11 @@
$alarms[$alarmTime] = array(
'time' => $alarmTime
);
} elseif (preg_match('/(........T......)$/',$attributes['value'],$matches)) {
$alarmTime = $vcal->_parseDateTime($attributes['value']);
$alarms[$alarmTime] = array(
'time' => $alarmTime
);
}
break;
case 'CLASS':
@ -440,7 +498,7 @@
case 'DTEND':
$dtend_ts = is_numeric($attributes['value']) ? $attributes['value'] : $this->date2ts($attributes['value']);
if(date('H:i:s',$dtend_ts) == '00:00:00') {
$dtend_ts--;
$dtend_ts -= 60;
}
$vcardData['end'] = $dtend_ts;
break;
@ -458,9 +516,14 @@
{
$vcardData['recur_enddate'] = $vcal->_parseDateTime($matches[1]);
}
elseif (preg_match('/COUNT=([0-9]+)/',$recurence,$matches))
{
$vcardData['recur_count'] = (int)$matches[1];
}
if (preg_match('/INTERVAL=([0-9]+)/',$recurence,$matches))
{
$vcardData['recur_interval'] = (int) $matches[1];
// 1 is invalid,, egw uses 0 for interval
$vcardData['recur_interval'] = (int) $matches[1] != 0 ? (int) $matches[1] : 0;
}
$vcardData['recur_data'] = 0;
switch($type)
@ -492,6 +555,14 @@
}
$vcardData['recur_type'] = MCAL_RECUR_WEEKLY;
}
if (!empty($vcardData['recur_count']))
{
$vcardData['recur_enddate'] = mktime(0,0,0,
date('m',$vcardData['start']),
date('d',$vcardData['start']) + ($vcardData['recur_interval']*($vcardData['recur_count']-1)*7),
date('Y',$vcardData['start']));
}
break;
case 'D': // 1.0
@ -518,6 +589,14 @@
// fall-through
case 'DAILY': // 2.0
$vcardData['recur_type'] = MCAL_RECUR_DAILY;
if (!empty($vcardData['recur_count']))
{
$vcardData['recur_enddate'] = mktime(0,0,0,
date('m',$vcardData['start']),
date('d',$vcardData['start']) + ($vcardData['recur_interval']*($vcardData['recur_count']-1)),
date('Y',$vcardData['start']));
}
break;
case 'M':
@ -551,6 +630,14 @@
case 'MONTHLY':
$vcardData['recur_type'] = strpos($recurence,'BYDAY') !== false ?
MCAL_RECUR_MONTHLY_WDAY : MCAL_RECUR_MONTHLY_MDAY;
if (!empty($vcardData['recur_count']))
{
$vcardData['recur_enddate'] = mktime(0,0,0,
date('m',$vcardData['start']) + ($vcardData['recur_interval']*($vcardData['recur_count']-1)),
date('d',$vcardData['start']),
date('Y',$vcardData['start']));
}
break;
case 'Y': // 1.0
@ -577,11 +664,24 @@
// fall-through
case 'YEARLY': // 2.0
$vcardData['recur_type'] = MCAL_RECUR_YEARLY;
if (!empty($vcardData['recur_count']))
{
$vcardData['recur_enddate'] = mktime(0,0,0,
date('m',$vcardData['start']),
date('d',$vcardData['start']),
date('Y',$vcardData['start']) + ($vcardData['recur_interval']*($vcardData['recur_count']-1)));
}
break;
}
if( $syncevo_enddate_fix && $vcardData['recur_enddate'] )
{
// Does syncevolution need to adjust recur_enddate
$vcardData['recur_enddate'] = (int)$vcardData['recur_enddate'] + 86400;
}
break;
case 'EXDATE':
$vcardData['recur_exception'] = $attributes['value'];
$vcardData['recur_exception'] = array_merge($vcardData['recur_exception'],$attributes['value']);
break;
case 'SUMMARY':
$vcardData['title'] = $attributes['value'];
@ -605,26 +705,14 @@
$vcardData['priority'] = (int) $this->priority_ical2egw[$attributes['value']];
break;
case 'CATEGORIES':
$vcardData['category'] = array();
if ($attributes['value'])
{
if (!is_object($this->cat))
{
if (!is_object($GLOBALS['egw']->categories))
{
$GLOBALS['egw']->categories =& CreateObject('phpgwapi.categories',$this->owner,'calendar');
}
$this->cat =& $GLOBALS['egw']->categories;
}
foreach(explode(',',$attributes['value']) as $cat_name)
{
if (!($cat_id = $this->cat->name2id($cat_name)))
{
$cat_id = $this->cat->add( array('name' => $cat_name,'descr' => $cat_name ));
}
$vcardData['category'][] = $cat_id;
}
$vcardData['category'] = $this->find_or_add_categorie(explode(',',$attributes['value']));
}
else
{
$vcardData['category'] = array();
}
break;
case 'ATTENDEE':
if (preg_match('/MAILTO:([@.a-z0-9_-]+)/i',$attributes['value'],$matches) &&
@ -734,6 +822,38 @@
$event['participants'] = array($GLOBALS['egw_info']['user']['account_id'] => 'A');
}
// If this is an updated meeting, and the client doesn't support
// participants, add them back
if( $cal_id >0 && !isset($this->supportedFields['participants']))
{
$egw_event = $this->read($cal_id);
if ($egw_event)
{
$event['participants'] = $egw_event['participants'];
$event['participant_types'] = $egw_event['participant_types'];
}
}
// Check for resources, and don't remove them
if( $cal_id > 0 )
{
// for each existing participant:
$egw_event = $this->read($cal_id);
if ( $egw_event )
{
foreach( $egw_event['participants'] as $uid => $status )
{
// Is it a resource?
if ( preg_match("/^r(.*)/", $uid, $matches) )
{
// Add it back in
$event['participants'][$uid] = 'A';
$event['participant_types']['r'][$matches[1]] = 'A';
}
}
}
}
#error_log('ALARMS');
#error_log(print_r($event, true));
@ -773,28 +893,55 @@
$this->productManufacturer = $_productManufacturer;
$this->productName = $_productName;
$defaultFields[0] = array('public' => 'public', 'description' => 'description', 'end' => 'end',
'start' => 'start', 'location' => 'location', 'recur_type' => 'recur_type',
'recur_interval' => 'recur_interval', 'recur_data' => 'recur_data', 'recur_enddate' => 'recur_enddate',
'title' => 'title', 'priority' => 'priority', 'alarms' => 'alarms',
$defaultFields['minimal'] = array(
'public' => 'public',
'description' => 'description',
'end' => 'end',
'start' => 'start',
'location' => 'location',
'recur_type' => 'recur_type',
'recur_interval' => 'recur_interval',
'recur_data' => 'recur_data',
'recur_enddate' => 'recur_enddate',
'title' => 'title',
'alarms' => 'alarms',
);
$defaultFields['basic'] = $defaultFields['minimal'] + array(
'recur_exception' => 'recur_exception',
'priority' => 'priority',
);
$defaultFields['nexthaus'] = $defaultFields['basic'] + array(
'participants' => 'participants',
);
$defaultFields[1] = array('public' => 'public', 'description' => 'description', 'end' => 'end',
'start' => 'start', 'location' => 'location', 'recur_type' => 'recur_type',
'recur_interval' => 'recur_interval', 'recur_data' => 'recur_data', 'recur_enddate' => 'recur_enddate',
'title' => 'title', 'alarms' => 'alarms',
$defaultFields['synthesis'] = $defaultFields['basic'] + array(
'non_blocking' => 'non_blocking',
'category' => 'category',
);
$defaultFields['evolution'] = $defaultFields['basic'] + array(
'participants' => 'participants',
'owner' => 'owner',
'category' => 'category',
);
$defaultFields['full'] = $defaultFields['basic'] + array(
'participants' => 'participants',
'owner' => 'owner',
'category' => 'category',
'non_blocking' => 'non_blocking',
);
switch(strtolower($_productManufacturer))
{
case 'nexthaus corporation':
switch(strtolower($_productName))
{
default:
$this->supportedFields = $defaultFields[0] + array('participants' => 'participants');
#$this->supportedFields = $defaultFields;
$this->supportedFields = $defaultFields['nexthaus'];
break;
}
break;
@ -805,7 +952,7 @@
switch(strtolower($_productName))
{
default:
$this->supportedFields = $defaultFields[0];
$this->supportedFields = $defaultFields['basic'];
break;
}
break;
@ -814,18 +961,26 @@
switch(strtolower($_productName))
{
case 'e61':
$this->supportedFields = $defaultFields['minimal'];
break;
default:
$this->supportedFields = $defaultFields[1];
error_log("Unknown Nokia phone '$_productName', assuming E61");
$this->supportedFields = $defaultFields['minimal'];
break;
}
break;
case 'sonyericsson':
case 'sony ericsson':
switch(strtolower($_productName))
{
case 'd750i':
case 'p910i':
$this->supportedFields = $defaultFields['basic'];
break;
default:
$this->supportedFields = $defaultFields[0];
error_log("Unknown Sony Ericsson phone '$_productName' assuming d750i");
$this->supportedFields = $defaultFields['basic'];
break;
}
break;
@ -834,41 +989,35 @@
switch(strtolower($_productName))
{
default:
$this->supportedFields = $defaultFields[0] + array(
'recur_exception' => 'recur_exception',
'non_blocking' => 'non_blocking',
);
$this->supportedFields = $defaultFields['synthesis'];
break;
}
break;
//Syncevolution compatibility
case 'patrick ohly':
$this->supportedFields = $defaultFields[1] + array(
'participants' => 'participants',
'owner' => 'owner',
'category' => 'category',
);
$this->supportedFields = $defaultFields['evolution'];
break;
case '': // seems syncevolution 0.5 doesn't send a manufacturer
error_log("No vendor name, assuming syncevolution 0.5");
$this->supportedFields = $defaultFields['evolution'];
break;
case 'file': // used outside of SyncML, eg. by the calendar itself ==> all possible fields
$this->supportedFields = $defaultFields[0] + array(
'participants' => 'participants',
'owner' => 'owner',
'non_blocking' => 'non_blocking',
'category' => 'category',
);
$this->supportedFields = $defaultFields['full'];
break;
// the fallback for SyncML
default:
error_log("Client not found: $_productManufacturer $_productName");
$this->supportedFields = $defaultFields[0];
error_log("Unknown calendar SyncML client: manufacturer='$_productManufacturer' product='$_productName'");
$this->supportedFields = $defaultFields['full'];
break;
}
}
function icaltoegw($_vcalData) {
function icaltoegw($_vcalData)
{
// our (patched) horde classes, do NOT unfold folded lines, which causes a lot trouble in the import
$_vcalData = preg_replace("/[\r\n]+ /",'',$_vcalData);
@ -1043,26 +1192,14 @@
}
break;
case 'CATEGORIES':
$vcardData['category'] = array();
if ($attributes['value'])
{
if (!is_object($this->cat))
{
if (!is_object($GLOBALS['egw']->categories))
{
$GLOBALS['egw']->categories =& CreateObject('phpgwapi.categories',$this->owner,'calendar');
}
$this->cat =& $GLOBALS['egw']->categories;
}
foreach(explode(',',$attributes['value']) as $cat_name)
{
if (!($cat_id = $this->cat->name2id($cat_name)))
{
$cat_id = $this->cat->add( array('name' => $cat_name,'descr' => $cat_name ));
}
$vcardData['category'][] = $cat_id;
}
}
$vcardData['category'] = $this->find_or_add_categories(explode(',',$attributes['value']));
}
else
{
$vcardData['category'] = array();
}
break;
case 'ATTENDEE':
if (preg_match('/MAILTO:([@.a-z0-9_-]+)/i',$attributes['value'],$matches) &&
@ -1114,6 +1251,10 @@
{
switch($fieldName)
{
case 'recur_interval':
case 'recur_enddate':
case 'recur_data':
case 'recur_exception':
case 'alarms':
// not handled here
break;
@ -1129,17 +1270,12 @@
}
}
}
unset($supportedFields['recur_type']);
unset($supportedFields['recur_interval']);
unset($supportedFields['recur_enddate']);
unset($supportedFields['recur_data']);
break;
default:
if (isset($vcardData[$fieldName]))
{
$event[$fieldName] = $vcardData[$fieldName];
}
unset($supportedFields[$fieldName]);
break;
}
}
@ -1212,20 +1348,24 @@
{
$vfreebusy->setAttribute($attr, $value, $parameters[$name]);
}
foreach(parent::search(array(
'start' => $this->now_su,
'end' => $end,
'users' => $user,
'date_format' => 'server',
'show_rejected' => false,
)) as $event)
$fbdata = parent::search(array(
'start' => $this->now_su,
'end' => $end,
'users' => $user,
'date_format' => 'server',
'show_rejected' => false,
));
if (is_array($fbdata))
{
if ($event['non_blocking']) continue;
foreach ($fbdata as $event)
{
if ($event['non_blocking']) continue;
$vfreebusy->setAttribute('FREEBUSY',array(array(
'start' => $event['start'],
'end' => $event['end'],
)));
$vfreebusy->setAttribute('FREEBUSY',array(array(
'start' => $event['start'],
'end' => $event['end'],
)));
}
}
$vcal->addComponent($vfreebusy);

View File

@ -71,7 +71,7 @@
}
function endElement($_parser, $_tag) {
#error_log($_tag .' => '. $this->sifData);
//error_log('endElem: ' . $_tag .' => '. trim($this->sifData));
if(!empty($this->sifMapping[$_tag])) {
$this->event[$this->sifMapping[$_tag]] = trim($this->sifData);
}
@ -128,19 +128,7 @@
case 'category':
if(!empty($value)) {
$egwCategories =& CreateObject('phpgwapi.categories', $GLOBALS['egw_info']['user']['account_id'], 'calendar');
$categories = explode(';',$value);
foreach($categories as $categorieName) {
$cat_id = false;
$categorieName = trim($categorieName);
if(!($cat_id = $egwCategories->name2id($categorieName))) {
$cat_id = $egwCategories->add(array('name' => $categorieName, 'descr' => lang('added by synchronisation')));
}
if($cat_id) {
if(!empty($finalEvent[$key])) $finalEvent[$key] .= ',';
$finalEvent[$key] .= $cat_id;
}
}
$finalEvent[$key] = implode(',',$this->find_or_add_categories(explode(';', $value)));
}
break;
@ -148,6 +136,7 @@
case 'start':
if($this->event['alldayevent'] < 1) {
$finalEvent[$key] = $vcal->_parseDateTime($value);
error_log("event ".$key." val=".$value.", parsed=".$finalEvent[$key]);
}
break;
@ -348,15 +337,8 @@
{
case 'Categories':
if(!empty($value)) {
$egwCategories =& CreateObject('phpgwapi.categories',$GLOBALS['egw_info']['user']['account_id'],'calendar');
$categories = explode(',',$value);
$value = '';
foreach($categories as $cat_id) {
if($catData = $egwCategories->return_single($cat_id)) {
if(!empty($value)) $value .= '; ';
$value .= $GLOBALS['egw']->translation->convert($catData[0]['name'], $sysCharSet, 'utf-8');
}
}
$value = implode('; ', $this->get_categories(explode(',',$value)));
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
}
$sifEvent .= "<$sifField>$value</$sifField>";
break;

View File

@ -563,7 +563,7 @@ ORDER BY cal_user_type, cal_usre_id
$exceptions = $event['recur_exception'] ? explode(',',$event['recur_exception']) : array();
$set_recurrences = $event['recur_type'] != $old_recur['recur_type'] || $event['recur_data'] != $old_recur['recur_data'] ||
$event['recur_interval'] != $old_recur['recur_interval'] || $event['recur_enddate'] != $old_recur['recur_enddate'] ||
count(array_diff($old_exceptions,$exceptions)); // exception deleted
count(array_diff($old_exceptions,$exceptions)) || count(array_diff($exceptions, $old_exceptions)); // exception deleted or added
}
if($event['recur_type'] != MCAL_RECUR_NONE)
{

View File

@ -1270,7 +1270,75 @@ class boinfolog
}
return $icons;
}
var $app_cat;
var $glob_cat;
function find_or_add_categories($catname_list)
{
if (!is_object($this->glob_cat))
{
if (!is_object($GLOBALS['egw']->categories))
{
$GLOBALS['egw']->categories =& CreateObject('phpgwapi.categories',$GLOBALS['egw_info']['user']['account_id'],'phpgw');
}
$this->glob_cat =& $GLOBALS['egw']->categories;
}
if (!is_object($this->app_cat))
{
$this->app_cat =& CreateObject('phpgwapi.categories',$GLOBALS['egw_info']['user']['account_id'],'infolog');
}
$cat_id_list = array();
foreach($catname_list as $cat_name)
{
$cat_name = trim($cat_name);
if (!($cat_id = $this->glob_cat->name2id($cat_name))
&& !($cat_id = $this->app_cat->name2id($cat_name)))
{
$cat_id = $this->app_cat->add( array('name' => $cat_name,'descr' => $cat_name ));
}
$cat_id_list[] = $cat_id;
}
if (count($cat_id_list) > 1)
{
sort($cat_id_list, SORT_NUMERIC);
}
return $cat_id_list;
}
function get_categories($cat_id_list)
{
if (!is_object($this->glob_cat))
{
if (!is_object($GLOBALS['egw']->categories))
{
$GLOBALS['egw']->categories =& CreateObject('phpgwapi.categories',$GLOBALS['egw_info']['user']['account_id'],'phpgw');
}
$this->glob_cat =& $GLOBALS['egw']->categories;
}
if (!is_object($this->app_cat))
{
$this->app_cat =& CreateObject('phpgwapi.categories',$GLOBALS['egw_info']['user']['account_id'],'infolog');
}
$cat_list = array();
foreach(explode(',',$cat_id_list) as $cat_id)
{
if ( ($cat_data = $this->glob_cat->return_single($cat_id))
|| ($cat_data = $this->app_cat->return_single($cat_id)) )
{
$cat_list[] = $cat_data[0]['name'];
}
}
return $cat_list;
}
/**
* Send all async infolog notification
*
@ -1352,3 +1420,4 @@ class boinfolog
$GLOBALS['egw_info']['user']['preferences'] = $save_prefs;
}
}

View File

@ -21,12 +21,24 @@
// array containing the current mappings(task or note)
var $_currentSIFMapping;
var $_sifNoteMapping = array(
'Body' => 'info_des',
'Categories' => 'info_cat',
'Color' => '',
'Date' => 'info_startdate',
'Height' => '',
'Left' => '',
'Subject' => 'info_subject',
'Top' => '',
'Width' => '',
);
// mappings for SIFTask to InfologTask
var $_sifTaskMapping = array(
'ActualWork' => '',
'BillingInformation' => '',
'Body' => 'info_des',
'Categories' => '',
'Categories' => 'info_cat',
'Companies' => '',
'Complete' => '',
'DateCompleted' => 'info_datecompleted',
@ -61,8 +73,9 @@
}
function endElement($_parser, $_tag) {
error_log("infolog: tag=$_tag data=".trim($this->sifData));
if(!empty($this->_currentSIFMapping[$_tag])) {
$this->_extractedSIFData[$this->_currentSIFMapping[$_tag]] = $this->sifData;
$this->_extractedSIFData[$this->_currentSIFMapping[$_tag]] = trim($this->sifData);
}
unset($this->sifData);
}
@ -81,7 +94,18 @@
#fwrite($handle, $sifData);
#fclose($handle);
$this->_currentSIFMapping = $this->_sifTaskMapping;
switch ($_sifType)
{
case 'note':
$this->_currentSIFMapping = $this->_sifNoteMapping;
break;
case 'task':
default:
$this->_currentSIFMapping = $this->_sifTaskMapping;
break;
}
$this->xml_parser = xml_parser_create('UTF-8');
xml_set_object($this->xml_parser, $this);
xml_parser_set_option($this->xml_parser, XML_OPTION_CASE_FOLDING, false);
@ -108,6 +132,8 @@
foreach($this->_extractedSIFData as $key => $value) {
$value = $GLOBALS['egw']->translation->convert($value, 'utf-8', $sysCharSet);
error_log("infolog key=$key => value=$value");
switch($key) {
case 'info_access':
$taskData[$key] = ((int)$value > 0) ? 'private' : 'public';
@ -127,6 +153,13 @@
break;
case 'info_cat':
if (!empty($value)) {
$categories = $this->find_or_add_categories(explode(';', $value));
$taskData['info_cat'] = $categories[0];
}
break;
case 'info_priority':
$taskData[$key] = (int)$value;
break;
@ -156,11 +189,52 @@
$taskData[$key] = $value;
break;
}
error_log("infolog task key=$key => value=".$taskData[$key]);
}
return $taskData;
break;
case 'note':
$noteData = array();
$noteData['info_type'] = 'note';
$vcal = &new Horde_iCalendar;
foreach($this->_extractedSIFData as $key => $value)
{
$value = $GLOBALS['egw']->translation->convert($value, 'utf-8', $sysCharSet);
error_log("infolog client key=$key => value=".$value);
switch ($key)
{
case 'info_startdate':
if(!empty($value)) {
$noteData[$key] = $vcal->_parseDateTime($value);
// somehow the client always deliver a timestamp about 3538 seconds, when no startdate set.
if($noteData[$key] < 10000)
$noteData[$key] = '';
} else {
$noteData[$key] = '';
}
break;
case 'info_cat':
if (!empty($value)) {
$categories = $this->find_or_add_categories(explode(';', $value));
$taskData['info_cat'] = $categories[0];
}
break;
default:
$noteData[$key] = $value;
break;
}
error_log("infolog note key=$key => value=".$noteData[$key]);
}
return $noteData;
break;
default:
return false;
}
@ -251,6 +325,15 @@
$sifTask .= "<$sifField>$value</$sifField>";
break;
case 'Categories':
if (!empty($value))
{
$value = implode('; ', $this->get_categories(array($value)));
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
}
$sifTask .= "<$sifField>$value</$sifField>";
break;
default:
$sifTask .= "<$sifField>$value</$sifField>";
break;
@ -296,6 +379,52 @@
}
break;
case 'note':
if($taskData = $this->read($_id)) {
$sysCharSet = $GLOBALS['egw']->translation->charset();
$vcal = &new Horde_iCalendar;
$sifNote = '<note>';
foreach($this->_sifNoteMapping as $sifField => $egwField)
{
if(empty($egwField)) continue;
$value = $GLOBALS['egw']->translation->convert($taskData[$egwField], $sysCharSet, 'utf-8');
switch($sifField) {
case 'Date':
if(!empty($value)) {
$value = $vcal->_exportDateTime($value);
}
$sifNote .= "<$sifField>$value</$sifField>";
break;
case 'Body':
$value = $GLOBALS['egw']->translation->convert($taskData['info_subject'], $sysCharSet, 'utf-8') . "\n" . $value;
$sifNote .= "<$sifField>$value</$sifField>";
break;
case 'Categories':
if (!empty($value))
{
$value = implode('; ', $this->get_categories(array($value)));
$value = $GLOBALS['egw']->translation->convert($value, $sysCharSet, 'utf-8');
}
$sifNote .= "<$sifField>$value</$sifField>";
break;
default:
$sifNote .= "<$sifField>$value</$sifField>";
break;
}
}
return base64_encode($sifNote);
}
break;
default;
return false;
}

View File

@ -186,7 +186,7 @@ class soinfolog // DB-Layer
*/
function aclFilter($filter = False)
{
preg_match('/(my|responsible|delegated|own|privat|all|none|user)([0-9]*)/',$filter_was=$filter,$vars);
preg_match('/(my|responsible|delegated|own|privat|private|all|none|user)([0-9]*)/',$filter_was=$filter,$vars);
$filter = $vars[1];
$f_user = intval($vars[2]);
@ -230,7 +230,7 @@ class soinfolog // DB-Layer
$filtermethod .= " OR (".$this->responsible_filter($this->user)." AND info_access='public')";
// private: own entries plus the one user is responsible for
if ($filter == 'private' || $filter == 'own')
if ($filter == 'private' || $filter == 'privat' || $filter == 'own')
{
$filtermethod .= " OR (".$this->responsible_filter($this->user).
($filter == 'own' && count($public_user_list) ? // offer's should show up in own, eg. startpage, but need read-access

View File

@ -86,6 +86,12 @@
$this->status2vtodo[$taskData['info_status']] : 'NEEDS-ACTION');
$vevent->setAttribute('PRIORITY',$this->egw_priority2vcal_priority[$taskData['info_priority']]);
if (!empty($taskData['info_cat']))
{
$cats = $this->get_categories(array($taskData['info_cat']));
$vevent->setAttribute('CATEGORIES', $cats[0]);
}
#$vevent->setAttribute('TRANSP','OPAQUE');
# status
# ATTENDEE
@ -122,7 +128,8 @@
return $this->write($taskData);
}
function searchVTODO($_vcalData) {
function searchVTODO($_vcalData)
{
if(!$egwData = $this->vtodotoegw($_vcalData)) {
return false;
}
@ -140,7 +147,8 @@
return false;
}
function vtodotoegw($_vcalData) {
function vtodotoegw($_vcalData)
{
$vcal = &new Horde_iCalendar;
if(!$vcal->parsevCalendar($_vcalData)) {
return FALSE;
@ -196,6 +204,13 @@
case 'SUMMARY':
$taskData['info_subject'] = $attributes['value'];
break;
case 'CATEGORIES':
{
$cats = $this->find_or_add_categories(explode(',', $attributes['value']));
$taskData['info_cat'] = $cats[0];
}
break;
}
}
# the horde ical class does already convert in parsevCalendar
@ -207,4 +222,147 @@
}
return FALSE;
}
function exportVNOTE($_noteID, $_type)
{
$note = $this->read($_noteID);
$note = $GLOBALS['egw']->translation->convert($note, $GLOBALS['egw']->translation->charset(), 'UTF-8');
switch($_type)
{
case 'text/plain':
$txt = $note['info_subject']."\n\n".$note['info_des'];
return $txt;
break;
case 'text/x-vnote':
$noteGUID = $GLOBALS['egw']->common->generate_uid('infolog_note',$_noteID);
$vnote = &new Horde_iCalendar_vnote();
$vNote->setAttribute('VERSION', '1.1');
$vnote->setAttribute('SUMMARY',$note['info_subject']);
$vnote->setAttribute('BODY',$note['info_des']);
if($note['info_startdate'])
$vnote->setAttribute('DCREATED',$note['info_startdate']);
$vnote->setAttribute('DCREATED',$GLOBALS['egw']->contenthistory->getTSforAction($eventGUID,'add'));
$vnote->setAttribute('LAST-MODIFIED',$GLOBALS['egw']->contenthistory->getTSforAction($eventGUID,'modify'));
if (!empty($note['info_cat']))
{
$cats = $this->get_categories(array($note['info_cat']));
$vnote->setAttribute('CATEGORIES', $cats[0]);
}
#$vnote->setAttribute('UID',$noteGUID);
#$vnote->setAttribute('CLASS',$taskData['info_access'] == 'public' ? 'PUBLIC' : 'PRIVATE');
#$options = array('CHARSET' => 'UTF-8','ENCODING' => 'QUOTED-PRINTABLE');
#$vnote->setParameter('SUMMARY', $options);
#$vnote->setParameter('DESCRIPTION', $options);
return $vnote->exportvCalendar();
break;
}
return false;
}
function importVNOTE(&$_vcalData, $_type, $_noteID = -1)
{
if(!$note = $this->vnotetoegw($_vcalData, $_type))
{
return false;
}
if($_noteID > 0)
{
$note['info_id'] = $_noteID;
}
if(empty($note['info_status'])) {
$note['info_status'] = 'done';
}
#_debug_array($taskData);exit;
return $this->write($note);
}
function searchVNOTE($_vcalData, $_type)
{
if(!$note = $this->vnotetoegw($_vcalData)) {
return false;
}
$filter = array('col_filter' => $egwData);
if($foundItems = $this->search($filter)) {
if(count($foundItems) > 0) {
$itemIDs = array_keys($foundItems);
return $itemIDs[0];
}
}
return false;
}
function vnotetoegw($_data, $_type)
{
switch($_type)
{
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
{
$note['info_des'] = $txt;
}
return $note;
break;
case 'text/x-vnote':
$vnote = &new Horde_iCalendar;
if (!$vcal->parsevCalendar($_data))
{
return FALSE;
}
$components = $vnote->getComponent();
if(count($components) > 0)
{
$component = $components[0];
if(is_a($component, 'Horde_iCalendar_vnote'))
{
$note = array();
$note['info_type'] = 'note';
foreach($component->_attributes as $attribute)
{
switch ($attribute['name'])
{
case 'BODY':
$note['info_des'] = $attribute['value'];
break;
case 'SUMMARY':
$note['info_subject'] = $attribute['value'];
break;
case 'CATEGORIES':
{
$cats = $this->find_or_add_categories(explode(',', $attribute['value']));
$note['info_cat'] = $cats[0];
}
break;
}
}
}
return $note;
}
}
return FALSE;
}
}

View File

@ -134,6 +134,49 @@ class Horde_SyncML_Command_Put extends Horde_SyncML_Command {
switch($element) {
case 'CTType':
$this->_contentType = trim($this->_chars);
if (substr($this->_contentType, 0, 14) == "text/x-s4j-sif")
{
// workaround a little bug in sync4j for mobile v3.1.3 (and possibly others)
// where the content-type is set to just one value regardless of
// the source... this further leads to a failure to send updates
// by the server since it does not know how to convert say tasks to text/x-s4j-sifc
// (it should be text/x-s4j-sift).
switch ($this->_sourceReference)
{
case 'contact':
if ($this->_contentType != "text/x-s4j-sifc")
{
error_log("forcing 'contact' content type to 'text/x-s4j-sifc' instead of '".$this->_contentType."'");
$this->_contentType = "text/x-s4j-sifc";
}
break;
case 'calendar':
case 'appointment':
if ($this->_contentType != "text/x-s4j-sife")
{
error_log("forcing 'calendar' content type to 'text/x-s4j-sife' instead of '".$this->_contentType."'");
$this->_contentType = "text/x-s4j-sife";
}
break;
case 'task':
if ($this->_contentType != "text/x-s4j-sift")
{
error_log("forcing 'task' content type to 'text/x-s4j-sift' instead of '".$this->_contentType."'");
$this->_contentType = "text/x-s4j-sift";
}
break;
case 'note':
if ($this->_contentType != "text/x-s4j-sifn")
{
error_log("forcing 'note' content type to 'text/x-s4j-sifn' instead of '".$this->_contentType."'");
$this->_contentType = "text/x-s4j-sifn";
}
break;
default:
#error_log("Leaving ContentType='".$this->_contentType."' as is for source '".$this->_sourceReference."'");
break;
}
}
break;
case 'SyncType':

View File

@ -40,17 +40,18 @@ class Horde_SyncML_Command_Results extends Horde_SyncML_Command {
break;
case 'DevID':
switch(trim($this->_chars)) {
$devid = trim($this->_chars);
$this->_deviceInfo['deviceID'] = $devid;
switch ($devid)
{
case 'fmz-thunderbird-plugin':
$this->_deviceInfo['deviceID'] = trim($this->_chars);
$this->_deviceInfo['manufacturer'] = 'funambol';
$this->_deviceInfo['model'] = trim($this->_chars);
if (empty($this->_devinceInfo['manufacturer']))
$this->_deviceInfo['manufacturer'] = 'funambol';
if (empty($this->_devinceInfo['model']))
$this->_deviceInfo['model'] = 'thunderbird';
if (empty($this->_devinceInfo['softwareVersion']))
$this->_deviceInfo['softwareVersion'] = '0.3';
break;
default:
$this->_deviceInfo['deviceID'] = trim($this->_chars);
break;
}
break;

View File

@ -655,28 +655,82 @@ class Horde_SyncML_State {
/**
* This function should use DevINF information.
*/
function getPreferedContentType($type) {
switch($type) {
function adjustContentType($type, $target = null)
{
$ctype;
if (is_array($type))
{
$ctype = $type['ContentType'];
$res = $type;
}
else
{
$ctype = $type;
$res = array();
$res['ContentType'] = $ctype;
}
switch($ctype)
{
case 'text/x-vcard':
case 'text/x-vcalendar':
case 'text/x-vnote':
case 'text/calendar':
case 'text/plain':
$res['mayFragment'] = 1;
break;
case 'text/x-s4j-sifc':
case 'text/x-s4j-sife':
case 'text/x-s4j-sift':
case 'text/x-s4j-sifn':
$res['ContentFormat'] = 'b64';
$res['mayFragment'] = 0;
break;
}
if (!isset($res['mayFragment']))
{
$res['mayFragment'] = 0;
}
if ($target != null)
{
switch($target)
{
case 'calendar':
case 'tasks':
case 'notes':
case 'contacts':
$res['mayFragment'] = 1;
break;
case 'sifcalendar':
case 'siftasks':
case 'sifnotes':
case 'sifcontacts':
case 'scard':
case 'scalendar':
case 'stask':
case 'snote':
default:
$res['mayFragment'] = 0;
break;
}
}
return $res;
}
function getPreferedContentType($type)
{
$_type = str_replace('./','',$type);
switch($_type)
{
case 'contacts':
case './contacts':
return 'text/x-vcard';
break;
case 'sifcalendar':
case './sifcalendar':
return 'text/x-s4j-sife';
break;
case 'sifcontacts':
case './sifcontacts':
return 'text/x-s4j-sifc';
break;
case 'siftasks':
case './siftasks':
return 'text/x-s4j-sift';
break;
case 'notes':
return 'text/x-vnote';
break;
@ -684,14 +738,84 @@ class Horde_SyncML_State {
case 'tasks':
return 'text/x-vcalendar';
break;
case 'calendar':
case './calendar':
return 'text/x-vcalendar';
break;
case 'sifcalendar':
case 'scal':
return 'text/x-s4j-sife';
break;
case 'sifcontacts':
case 'scard':
return 'text/x-s4j-sifc';
break;
case 'siftasks':
case 'stask':
return 'text/x-s4j-sift';
break;
case 'sifnotes':
case 'snote':
return 'text/x-s4j-sifn';
break;
}
}
function getHordeType($type)
{
$_type = str_replace('./','',$type);
switch($_type)
{
case 'contacts':
return 'contacts';
break;
case 'notes':
return 'notes';
break;
case 'tasks':
return 'tasks';
break;
case 'calendar':
return 'calendar';
break;
# funambol related types
case 'sifcalendar':
case 'scal':
return 'sifcalendar';
break;
case 'sifcontacts':
case 'scard':
return 'sifcontacts';
break;
case 'siftasks':
case 'stask':
return 'siftasks';
break;
case 'sifnotes':
case 'snote':
return 'sifnotes';
break;
default:
Horde::logMessage("unknown hordeType for type=$type ($_type)", __FILE__, __LINE__, PEAR_LOG_INFO);
return $_type;
break;
}
}
/**
/**
* Returns the preferred contenttype of the client for the given
* sync data type (database).
@ -699,15 +823,21 @@ class Horde_SyncML_State {
* This is passed as an option to the Horde API export functions.
*/
function getPreferedContentTypeClient($_sourceLocURI) {
function getPreferedContentTypeClient($_sourceLocURI, $_targetLocURI = null) {
$deviceInfo = $this->getClientDeviceInfo();
if(isset($deviceInfo['dataStore'][$_sourceLocURI]['rxPreference']['contentType'])) {
return array('ContentType' => $deviceInfo['dataStore'][$_sourceLocURI]['rxPreference']['contentType']);
if(isset($deviceInfo['dataStore'][$_sourceLocURI]['rxPreference']['contentType']))
{
return $this->adjustContentType($deviceInfo['dataStore'][$_sourceLocURI]['rxPreference']['contentType'], $_targetLocURI);
}
Horde::logMessage('SyncML: sourceLocURI ' . $_sourceLocURI .' not found', __FILE__, __LINE__, PEAR_LOG_DEBUG);
if ($_targetLocURI != null)
{
return $this->adjustContentType($this->getPreferedContentType($_targetLocURI), $_targetLocURI);
}
return PEAR::raiseError(_('sourceLocURI not found'));
}

View File

@ -141,13 +141,14 @@ class Horde_SyncML_Sync {
}
$hordeType = $type = $this->_targetLocURI;
// remove the './' from the beginning
$hordeType = str_replace('./','',$hordeType);
$hordeType = $state->getHordeType($hordeType);
if(!$contentType = $command->getContentType()) {
$contentType = $state->getPreferedContentType($type);
}
if ($this->_targetLocURI == 'calendar' && strpos($command->getContent(), 'BEGIN:VTODO') !== false) {
if (($contentType == 'text/x-vcalendar' || $contentType == 'text/calendar')
&& strpos($command->getContent(), 'BEGIN:VTODO') !== false)
{
$hordeType = 'tasks';
}

View File

@ -36,28 +36,27 @@ class Horde_SyncML_Sync_RefreshFromServerSync extends Horde_SyncML_Sync_TwoWaySy
continue;
}
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI);
if(is_a($contentType, 'PEAR_Error')) {
// Client did not sent devinfo
$contentType = array('ContentType' => $state->getPreferedContentType($this->_targetLocURI));
}
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI);
$cmd = &new Horde_SyncML_Command_Sync_ContentSyncElement();
$c = $registry->call($hordeType . '/export', array('guid' => $guid, 'contentType' => $contentType));
Horde::logMessage("SyncML: slowsync add $guid to client ". print_r($c, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
if (!is_a($c, 'PEAR_Error')) {
$cmd->setContent($c);
if($hordeType == 'sifcalendar' || $hordeType == 'sifcontacts' || $hordeType == 'siftasks') {
$cmd->setContentFormat('b64');
$cmd->setContentType($contentType['ContentType']);
if (isset($contentType['ContentFormat']))
{
$cmd->setContentFormat($contentType['ContentFormat']);
}
$cmd->setContentType($contentType['ContentType']);
$cmd->setSourceURI($guid);
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
$state->log('Server-Add');
// return if we have to much data
if(++$counter >= MAX_ENTRIES && $hordeType != 'sifcalendar' && $hordeType != 'sifcontacts' && $hordeType != 'siftasks') {
if(++$counter >= MAX_ENTRIES
&& isset($contentType['mayFragment'])
&& $contentType['mayFragment'])
{
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
return $currentCmdID;
}
@ -77,7 +76,7 @@ class Horde_SyncML_Sync_RefreshFromServerSync extends Horde_SyncML_Sync_TwoWaySy
$state = &$_SESSION['SyncML.state'];
$syncType = $this->_targetLocURI;
$hordeType = str_replace('./','',$syncType);
$hordeType = $state->getHordeType($syncType);
Horde::logMessage("SyncML: reading added items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
$state->setAddedItems($hordeType, $registry->call($hordeType. '/list', array()));

View File

@ -38,28 +38,27 @@ class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync {
continue;
}
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI);
if(is_a($contentType, 'PEAR_Error')) {
// Client did not sent devinfo
$contentType = array('ContentType' => $state->getPreferedContentType($this->_targetLocURI));
}
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI);
$cmd = &new Horde_SyncML_Command_Sync_ContentSyncElement();
$c = $registry->call($hordeType . '/export', array('guid' => $guid, 'contentType' => $contentType));
#Horde::logMessage("SyncML: slowsync add guid $guid to client ". print_r($c, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
if (!is_a($c, 'PEAR_Error')) {
$cmd->setContent($c);
if($hordeType == 'sifcalendar' || $hordeType == 'sifcontacts' || $hordeType == 'siftasks') {
$cmd->setContentFormat('b64');
$cmd->setContentType($contentType['ContentType']);
if (isset($contentType['ContentFormat']))
{
$cmd->setContentFormat($contentType['ContentFormat']);
}
$cmd->setContentType($contentType['ContentType']);
$cmd->setSourceURI($guid);
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
$state->log('Server-Add');
// return if we have to much data
if(++$counter >= MAX_ENTRIES && $hordeType != 'sifcalendar' && $hordeType != 'sifcontacts' && $hordeType != 'siftasks') {
if(++$counter >= MAX_ENTRIES
&& isset($contentType['mayFragment'])
&& $contentType['mayFragment'])
{
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
return $currentCmdID;
}
@ -129,9 +128,8 @@ class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync {
return;
}
$hordeType = $type = $this->_targetLocURI;
// remove the './' from the beginning
$hordeType = str_replace('./','',$hordeType);
$type = $this->_targetLocURI;
$hordeType = $state->getHordeType($type);
$syncElementItems = $command->getSyncElementItems();
@ -140,7 +138,9 @@ class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync {
$contentType = $state->getPreferedContentType($type);
}
if ($this->_targetLocURI == 'calendar' && strpos($syncItem->getContent(), 'BEGIN:VTODO') !== false) {
if (($contentType == 'text/x-vcalendar' || $contentType == 'text/calendar')
&& strpos($syncItem->getContent(), 'BEGIN:VTODO') !== false)
{
$hordeType = 'tasks';
}
@ -179,7 +179,7 @@ class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync {
$state = &$_SESSION['SyncML.state'];
$syncType = $this->_targetLocURI;
$hordeType = str_replace('./','',$syncType);
$hordeType = $state->getHordeType($syncType);
Horde::logMessage("SyncML: reading added items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
$state->setAddedItems($hordeType, $registry->call($hordeType. '/list', array()));

View File

@ -27,7 +27,7 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
$syncType = $this->_targetLocURI;
$hordeType = str_replace('./','',$syncType);
$hordeType = $state->getHordeType($syncType);
$refts = $state->getServerAnchorLast($syncType);
$currentCmdID = $this->handleSync($currentCmdID,
@ -79,11 +79,7 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
}
// Create a replace request for client.
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI);
if(is_a($contentType, 'PEAR_Error')) {
// Client did not sent devinfo
$contentType = array('ContentType' => $state->getPreferedContentType($this->_targetLocURI));
}
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI);
$c = $registry->call($hordeType. '/export',
array('guid' => $guid, 'contentType' => $contentType));
if (!is_a($c, 'PEAR_Error')) {
@ -95,14 +91,19 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
$cmd->setSourceURI($guid);
$cmd->setTargetURI($locid);
$cmd->setContentType($contentType['ContentType']);
if($hordeType == 'sifcalendar' || $hordeType == 'sifcontacts' || $hordeType == 'siftasks') {
$cmd->setContentFormat('b64');
if (isset($contentType['ContentFormat']))
{
$cmd->setContentFormat($contentType['ContentFormat']);
}
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Replace');
$state->log('Server-Replace');
// return if we have to much data
if(++$counter >= MAX_ENTRIES && $hordeType != 'sifcalendar' && $hordeType != 'sifcontacts' && $hordeType != 'siftasks') {
if (++$counter >= MAX_ENTRIES
&& isset($contentType['mayFragment'])
&& $contentType['mayFragment'])
{
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
return $currentCmdID;
}
@ -139,8 +140,12 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
$state->log('Server-Delete');
$state->removeUID($syncType, $locid);
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI);
// return if we have to much data
if(++$counter >= MAX_ENTRIES && $hordeType != 'sifcalender' && $hordeType != 'sifcontacts' &&$hordeType != 'siftasks') {
if(++$counter >= MAX_ENTRIES
&& isset($contentType['mayFragment'])
&& $contentType['mayFragment'])
{
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
return $currentCmdID;
}
@ -180,11 +185,7 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
Horde::logMessage("SyncML: add: $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
// Create an Add request for client.
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI);
if(is_a($contentType, 'PEAR_Error')) {
// Client did not sent devinfo
$contentType = array('ContentType' => $state->getPreferedContentType($this->_targetLocURI));
}
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI);
$cmd = &new Horde_SyncML_Command_Sync_ContentSyncElement();
$c = $registry->call($hordeType . '/export',
@ -197,16 +198,20 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
if (!is_a($c, 'PEAR_Error')) {
// Item in history but not in database. Strange, but can happen.
$cmd->setContent($c);
if($hordeType == 'sifcalendar' || $hordeType == 'sifcontacts' || $hordeType == 'siftasks') {
$cmd->setContentFormat('b64');
}
$cmd->setContentType($contentType['ContentType']);
if (isset($contentType['ContentFormat']))
{
$cmd->setContentFormat($contentType['ContentFormat']);
}
$cmd->setSourceURI($guid);
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
$state->log('Server-Add');
// return if we have to much data
if(++$counter >= MAX_ENTRIES && $hordeType != 'sifcalendar' && $hordeType != 'sifcontacts' &&$hordeType != 'siftasks') {
if(++$counter >= MAX_ENTRIES
&& isset($contentType['mayFragment'])
&& $contentType['mayFragment'])
{
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
return $currentCmdID;
}
@ -225,7 +230,7 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
$state = &$_SESSION['SyncML.state'];
$syncType = $this->_targetLocURI;
$hordeType = str_replace('./','',$syncType);
$hordeType = $state->getHordeType($syncType);
$refts = $state->getServerAnchorLast($syncType);
Horde::logMessage("SyncML: reading changed items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);

View File

@ -510,18 +510,11 @@ class Horde_iCalendar {
case 'CREATED':
case 'LAST-MODIFIED':
case 'BDAY':
$this->setAttribute($tag, $this->_parseDateTime($value), $params);
break;
case 'DTEND':
case 'DTSTART':
case 'DUE':
case 'RECURRENCE-ID':
if (isset($params['VALUE']) && $params['VALUE'] == 'DATE') {
$this->setAttribute($tag, $this->_parseDate($value), $params);
} else {
$this->setAttribute($tag, $this->_parseDateTime($value), $params);
}
$this->setAttribute($tag, $this->_parseDateTime($value), $params);
break;
case 'RDATE':
@ -902,7 +895,7 @@ class Horde_iCalendar {
if (!$date = $this->_parseDate($text)) {
return $date;
}
return @gmmktime(0, 0, 0, $date['month'], $date['mday'], $date['year']);
return @mktime(0, 0, 0, $date['month'], $date['mday'], $date['year']);
}
if (!$date = $this->_parseDate($dateParts[0])) {
@ -912,6 +905,8 @@ class Horde_iCalendar {
return $time;
}
error_log("parseDateTime: ".$text." => ".print_r($time, true));
if ($time['zone'] == 'UTC') {
return @gmmktime($time['hour'], $time['minute'], $time['second'],
$date['month'], $date['mday'], $date['year']);
@ -1016,7 +1011,12 @@ class Horde_iCalendar {
*/
function _parseDate($text)
{
if (strlen($text) != 8) {
if (strlen($text) == 10)
{
$text = str_replace('-','',$text);
}
if (strlen($text) != 8)
{
return false;
}

View File

@ -18,12 +18,12 @@ $conf['auth']['checkip'] = true;
$conf['auth']['params']['username'] = 'Administrator';
$conf['auth']['params']['requestuser'] = false;
$conf['auth']['driver'] = 'auto';
$conf['log']['priority'] = PEAR_LOG_INFO;
$conf['log']['priority'] = PEAR_LOG_DEBUG;
$conf['log']['ident'] = 'EGWSYNC';
$conf['log']['params'] = array();
$conf['log']['name'] = '/tmp/egroupware_syncml.log';
$conf['log']['params']['append'] = true;
$conf['log']['type'] = 'file';
$conf['log']['type'] = 'error_log';
$conf['log']['enabled'] = true;
$conf['log_accesskeys'] = false;
$conf['prefs']['driver'] = 'none';

View File

@ -77,7 +77,7 @@ $this->applications['egwnotessync'] = array(
'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
'name' => _("Notes"),
'status' => 'active',
'provides' => 'notes',
'provides' => array('notes', 'sifnotes', 'snote'),
'menu_parent' => 'organizing'
);
@ -87,19 +87,19 @@ $this->applications['egwcontactssync'] = array(
'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
'name' => _("Contacts"),
'status' => 'active',
'provides' => 'contacts',
'provides' => array('contacts', 'sifcontacts', 'scard'),
'menu_parent' => 'organizing'
);
$this->applications['egwsifcontactssync'] = array(
'fileroot' => EGW_SERVER_ROOT.'/syncml/sifcontacts',
'webroot' => $this->applications['horde']['webroot'] . '/mnemo',
'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
'name' => _("SIF Contacts"),
'status' => 'active',
'provides' => 'sifcontacts',
'menu_parent' => 'organizing'
);
#$this->applications['egwsifcontactssync'] = array(
# 'fileroot' => EGW_SERVER_ROOT.'/syncml/sifcontacts',
# 'webroot' => $this->applications['horde']['webroot'] . '/mnemo',
# 'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
# 'name' => _("SIF Contacts"),
# 'status' => 'active',
# 'provides' => 'sifcontacts',
# 'menu_parent' => 'organizing'
#);
$this->applications['egwcalendarsync'] = array(
'fileroot' => EGW_SERVER_ROOT.'/syncml/calendar',
@ -107,19 +107,19 @@ $this->applications['egwcalendarsync'] = array(
'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
'name' => _("Calendar"),
'status' => 'active',
'provides' => 'calendar',
'provides' => array('calendar', 'sifcalendar', 'scal'),
'menu_parent' => 'organizing'
);
$this->applications['egwsifcalendarsync'] = array(
'fileroot' => EGW_SERVER_ROOT.'/syncml/sifcalendar',
'webroot' => $this->applications['horde']['webroot'] . '/mnemo',
'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
'name' => _("Calendar"),
'status' => 'active',
'provides' => 'sifcalendar',
'menu_parent' => 'organizing'
);
#$this->applications['egwsifcalendarsync'] = array(
# 'fileroot' => EGW_SERVER_ROOT.'/syncml/sifcalendar',
# 'webroot' => $this->applications['horde']['webroot'] . '/mnemo',
# 'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
# 'name' => _("Calendar"),
# 'status' => 'active',
# 'provides' => 'sifcalendar',
# 'menu_parent' => 'organizing'
#);
$this->applications['egwtaskssync'] = array(
'fileroot' => EGW_SERVER_ROOT.'/syncml/tasks',
@ -127,19 +127,19 @@ $this->applications['egwtaskssync'] = array(
'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
'name' => _("Tasks"),
'status' => 'active',
'provides' => 'tasks',
'provides' => array('tasks', 'siftasks', 'stask'),
'menu_parent' => 'organizing'
);
$this->applications['egwsiftaskssync'] = array(
'fileroot' => EGW_SERVER_ROOT.'/syncml/siftasks',
'webroot' => $this->applications['horde']['webroot'] . '/mnemo',
'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
'name' => _("SIFTasks"),
'status' => 'active',
'provides' => 'siftasks',
'menu_parent' => 'organizing'
);
#$this->applications['egwsiftaskssync'] = array(
# 'fileroot' => EGW_SERVER_ROOT.'/syncml/siftasks',
# 'webroot' => $this->applications['horde']['webroot'] . '/mnemo',
# 'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif',
# 'name' => _("SIFTasks"),
# 'status' => 'active',
# 'provides' => array('siftasks', 'stask'),
# 'menu_parent' => 'organizing'
#);
$this->applications['egwcaltaskssync'] = array(
'fileroot' => EGW_SERVER_ROOT.'/syncml/caltasks',