forked from extern/egroupware
Merged several SyncML fixes from trunk:
- 24518: prevent deleting of accounts via SyncML and to read private flag from the DB if missing - 24531: Merge SyncML patches from Patrick Bihan-Faou plus some other SyncML fixes from trunk - 24555: fixed bug introduced by my commit r24522 (included in 24531): egw could not deal with LDAP Ids - 24571: fixed typo reported by Thomas Hoth on the developer list, causing calendar sync in trunk to fail if the clients wants categories - 24591: diverse vCard improvments, incl. rudimentary vCard3 support
This commit is contained in:
parent
ef95e5527c
commit
517bdb9f65
@ -392,9 +392,10 @@ class bocontacts extends socontacts
|
||||
* deletes contact in db
|
||||
*
|
||||
* @param mixed &$contact contact array with key id or (array of) id(s)
|
||||
* @param boolean $deny_account_delete=true if true never allow to delete accounts
|
||||
* @return boolean true on success or false on failiure
|
||||
*/
|
||||
function delete($contact)
|
||||
function delete($contact,$deny_account_delete=true)
|
||||
{
|
||||
if (is_array($contact) && isset($contact['id']))
|
||||
{
|
||||
@ -413,7 +414,7 @@ class bocontacts extends socontacts
|
||||
{
|
||||
$id = is_array($c) ? $c['id'] : $c;
|
||||
|
||||
if ($this->check_perms(EGW_ACL_DELETE,$c) && parent::delete($id))
|
||||
if ($this->check_perms(EGW_ACL_DELETE,$c,$deny_account_delete) && parent::delete($id))
|
||||
{
|
||||
$GLOBALS['egw']->link->unlink(0,'addressbook',$id);
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('contacts', $id, 'delete', time());
|
||||
@ -438,11 +439,14 @@ class bocontacts extends socontacts
|
||||
// remember if we add or update a entry
|
||||
if (($isUpdate = $contact['id']))
|
||||
{
|
||||
if (!isset($contact['owner'])) // owner not set on update, eg. SyncML
|
||||
if (!isset($contact['owner']) || !isset($contact['private'])) // owner/private not set on update, eg. SyncML
|
||||
{
|
||||
if (($old = $this->read($contact['id']))) // --> try reading the old entry and set it from there
|
||||
{
|
||||
$contact['owner'] = $old['owner'];
|
||||
if(!isset($contact['owner']))
|
||||
{
|
||||
$contact['owner'] = $old['owner'];
|
||||
}
|
||||
if(!isset($contact['private']))
|
||||
{
|
||||
$contact['private'] = $old['private'];
|
||||
@ -544,14 +548,15 @@ class bocontacts extends socontacts
|
||||
*
|
||||
* @param int $needed necessary ACL right: EGW_ACL_{READ|EDIT|DELETE}
|
||||
* @param mixed $contact contact as array or the contact-id
|
||||
* @return boolean true permission granted or false for permission denied
|
||||
* @param boolean $deny_account_delete=false if true never allow to delete accounts
|
||||
* @return boolean true permission granted, false for permission denied, null for contact does not exist
|
||||
*/
|
||||
function check_perms($needed,$contact)
|
||||
function check_perms($needed,$contact,$deny_account_delete=false)
|
||||
{
|
||||
if ((!is_array($contact) || !isset($contact['owner'])) &&
|
||||
!($contact = parent::read(is_array($contact) ? $contact['id'] : $contact)))
|
||||
{
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
$owner = $contact['owner'];
|
||||
|
||||
@ -561,7 +566,7 @@ class bocontacts extends socontacts
|
||||
return true;
|
||||
}
|
||||
// dont allow to delete own account (as admin handels it too)
|
||||
if (!$owner && $needed == EGW_ACL_DELETE && $contact['account_id'] == $this->user)
|
||||
if (!$owner && $needed == EGW_ACL_DELETE && ($deny_account_delete || $contact['account_id'] == $this->user))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -1108,4 +1113,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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -135,28 +135,18 @@ 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)));
|
||||
}
|
||||
else
|
||||
{
|
||||
$finalContact[$key] = '';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'private':
|
||||
$finalContact[$key] = (int) $value > 0; // eGW private is 0 (public) or 1 (private), SIF seems to use 0 and 2
|
||||
$finalContact[$key] = (int) ($value > 0); // eGW private is 0 (public) or 1 (private), SIF seems to use 0 and 2
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -164,6 +154,8 @@ class sifaddressbook extends bocontacts
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->fixup_contact($finalContact);
|
||||
return $finalContact;
|
||||
}
|
||||
|
||||
@ -179,6 +171,9 @@ class sifaddressbook extends bocontacts
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// patch from Di Guest says: we need to ignore the n_fileas
|
||||
unset($contact['n_fileas']);
|
||||
// we probably need to ignore even more as we do in vcaladdressbook
|
||||
|
||||
if(($foundContacts = bocontacts::search($contact)))
|
||||
{
|
||||
@ -231,6 +226,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 +243,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 +260,7 @@ class sifaddressbook extends bocontacts
|
||||
break;
|
||||
|
||||
default:
|
||||
$sifContact .= "<$sifField>$value</$sifField>";
|
||||
$sifContact .= "<$sifField>".trim($value)."</$sifField>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -58,51 +58,82 @@ class vcaladdressbook extends bocontacts
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach($this->supportedFields as $vcardField => $databaseFields) {
|
||||
$this->fixup_contact($entry);
|
||||
|
||||
foreach($this->supportedFields as $vcardField => $databaseFields)
|
||||
{
|
||||
$values = array();
|
||||
$options = array();
|
||||
$value = '';
|
||||
foreach($databaseFields as $databaseField) {
|
||||
$tempVal = ';';
|
||||
if(!empty($databaseField)) {
|
||||
$tempVal = trim($entry[$databaseField]).';';
|
||||
$hasdata = 0;
|
||||
foreach($databaseFields as $databaseField)
|
||||
{
|
||||
$value = "";
|
||||
|
||||
if (!empty($databaseField))
|
||||
{
|
||||
$value = 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;
|
||||
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');
|
||||
}
|
||||
|
||||
// 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';
|
||||
if ($hasdata <= 0)
|
||||
{
|
||||
// don't add the entry if there is no data for this field
|
||||
continue;
|
||||
}
|
||||
|
||||
$vCard->setAttribute($vcardField, implode(';', $values));
|
||||
$vCard->setParameter($vcardField, $options);
|
||||
}
|
||||
|
||||
@ -170,13 +201,14 @@ class vcaladdressbook extends bocontacts
|
||||
* - modifier
|
||||
* - jpegphoto
|
||||
*/
|
||||
$defaultFields[0] = array(
|
||||
$defaultFields[0] = array( // multisync
|
||||
'ADR' => array('','','adr_one_street','adr_one_locality','adr_one_region',
|
||||
'adr_one_postalcode','adr_one_countryname'),
|
||||
'CATEGORIES' => array('cat_id'),
|
||||
'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'),
|
||||
@ -186,7 +218,7 @@ class vcaladdressbook extends bocontacts
|
||||
'TITLE' => array('title'),
|
||||
);
|
||||
|
||||
$defaultFields[1] = array(
|
||||
$defaultFields[1] = array( // all entries, nexthaus corporation, ...
|
||||
'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',
|
||||
@ -196,19 +228,24 @@ 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'),
|
||||
'TEL;CELL;HOME' => array('tel_cell_private'),
|
||||
'TEL;FAX;WORK' => array('tel_fax'),
|
||||
'TEL;FAX;HOME' => array('tel_fax_home'),
|
||||
'TEL;HOME' => array('tel_home'),
|
||||
'TEL;PAGER;WORK' => array('tel_pager'),
|
||||
'TEL;WORK' => array('tel_work'),
|
||||
'TITLE' => array('title'),
|
||||
'URL;WORK' => array('url'),
|
||||
'ROLE' => array('role'),
|
||||
'URL;HOME' => array('url_home'),
|
||||
'FBURL' => array('freebusy_uri'),
|
||||
);
|
||||
|
||||
$defaultFields[2] = array(
|
||||
$defaultFields[2] = array( // sony ericson
|
||||
'ADR;HOME' => array('','','adr_one_street','adr_one_locality','adr_one_region',
|
||||
'adr_one_postalcode','adr_one_countryname'),
|
||||
'BDAY' => array('bday'),
|
||||
@ -216,6 +253,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'),
|
||||
@ -226,7 +264,7 @@ class vcaladdressbook extends bocontacts
|
||||
'URL;WORK' => array('url'),
|
||||
);
|
||||
|
||||
$defaultFields[3] = array(
|
||||
$defaultFields[3] = array( // siemens
|
||||
'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',
|
||||
@ -235,6 +273,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'),
|
||||
@ -246,7 +285,7 @@ class vcaladdressbook extends bocontacts
|
||||
'URL;WORK' => array('url'),
|
||||
);
|
||||
|
||||
$defaultFields[4] = array(
|
||||
$defaultFields[4] = array( // nokia 6600
|
||||
'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',
|
||||
@ -255,6 +294,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'),
|
||||
@ -269,7 +309,7 @@ class vcaladdressbook extends bocontacts
|
||||
'URL;HOME' => array('url_home'),
|
||||
);
|
||||
|
||||
$defaultFields[5] = array(
|
||||
$defaultFields[5] = array( // nokia e61
|
||||
'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',
|
||||
@ -278,6 +318,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'),
|
||||
@ -292,33 +333,39 @@ class vcaladdressbook extends bocontacts
|
||||
'URL;HOME' => array('url_home'),
|
||||
);
|
||||
|
||||
$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'),
|
||||
$defaultFields[6] = array( // funambol: fmz-thunderbird-plugin
|
||||
'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 +375,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 +391,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 +416,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 +448,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 +460,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;
|
||||
}
|
||||
@ -439,27 +501,29 @@ class vcaladdressbook extends bocontacts
|
||||
{
|
||||
$rowName .= ";INTERNET";
|
||||
}
|
||||
if(isset($vcardRow['params']['CELL']))
|
||||
$type = strtoupper($vcardRow['params']['TYPE']); // vCard3 sets TYPE={work|home|cell|fax}!
|
||||
|
||||
if(isset($vcardRow['params']['CELL']) || $type == 'CELL')
|
||||
{
|
||||
$rowName .= ';CELL';
|
||||
}
|
||||
if(isset($vcardRow['params']['FAX']))
|
||||
if(isset($vcardRow['params']['FAX']) || $type == 'FAX')
|
||||
{
|
||||
$rowName .= ';FAX';
|
||||
}
|
||||
if(isset($vcardRow['params']['PAGER']))
|
||||
if(isset($vcardRow['params']['PAGER']) || $type == 'PAGER')
|
||||
{
|
||||
$rowName .= ';PAGER';
|
||||
}
|
||||
if(isset($vcardRow['params']['WORK']))
|
||||
if(isset($vcardRow['params']['WORK']) || $type == 'WORK')
|
||||
{
|
||||
$rowName .= ';WORK';
|
||||
}
|
||||
if(isset($vcardRow['params']['HOME']))
|
||||
if(isset($vcardRow['params']['HOME']) || $type == 'HOME')
|
||||
{
|
||||
$rowName .= ';HOME';
|
||||
}
|
||||
|
||||
//error_log("key: $key --> $rowName: name=$vcardRow[name], params=".print_r($vcardRow['params'],true));
|
||||
$rowNames[$rowName] = $key;
|
||||
}
|
||||
|
||||
@ -500,30 +564,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 +586,31 @@ class vcaladdressbook extends bocontacts
|
||||
{
|
||||
if(!empty($fieldName))
|
||||
{
|
||||
$value = trim($vcardValues[$vcardKey]['values'][$fieldKey]);
|
||||
//error_log("$fieldName=$vcardKey[$fieldKey]='$value'");
|
||||
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';
|
||||
$contact[$fieldName] = (int) ($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 +618,7 @@ class vcaladdressbook extends bocontacts
|
||||
}
|
||||
}
|
||||
|
||||
$contact['n_fn'] = trim($contact['n_given'].' '.$contact['n_family']);
|
||||
$this->fixup_contact($contact);
|
||||
return $contact;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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']));
|
||||
@ -188,7 +202,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_numeric($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,
|
||||
@ -245,7 +274,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 {
|
||||
@ -292,7 +334,7 @@
|
||||
{
|
||||
$days[] = date('Ymd',$day);
|
||||
}
|
||||
$attributes['EXDATE'] = implode(';',$days);
|
||||
$attributes['EXDATE'] = implode(',',$days);
|
||||
$parameters['EXDATE']['VALUE'] = 'DATE';
|
||||
}
|
||||
break;
|
||||
@ -312,9 +354,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
|
||||
{
|
||||
@ -397,6 +440,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)
|
||||
{
|
||||
@ -406,7 +456,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)
|
||||
@ -432,6 +485,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':
|
||||
@ -443,7 +501,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;
|
||||
@ -461,9 +519,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)
|
||||
@ -495,6 +558,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
|
||||
@ -521,6 +592,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':
|
||||
@ -554,6 +633,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
|
||||
@ -580,11 +667,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'];
|
||||
@ -608,26 +708,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_categories(explode(',',$attributes['value']));
|
||||
}
|
||||
else
|
||||
{
|
||||
$vcardData['category'] = array();
|
||||
}
|
||||
break;
|
||||
case 'ATTENDEE':
|
||||
if (preg_match('/MAILTO:([@.a-z0-9_-]+)/i',$attributes['value'],$matches) &&
|
||||
@ -737,6 +825,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));
|
||||
|
||||
@ -776,28 +896,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[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['basic'] = $defaultFields['minimal'] + array(
|
||||
'recur_exception' => 'recur_exception',
|
||||
'priority' => 'priority',
|
||||
);
|
||||
|
||||
$defaultFields['nexthaus'] = $defaultFields['basic'] + array(
|
||||
'participants' => 'participants',
|
||||
);
|
||||
|
||||
$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;
|
||||
@ -808,7 +955,7 @@
|
||||
switch(strtolower($_productName))
|
||||
{
|
||||
default:
|
||||
$this->supportedFields = $defaultFields[0];
|
||||
$this->supportedFields = $defaultFields['basic'];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -817,18 +964,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;
|
||||
@ -837,41 +992,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);
|
||||
|
||||
@ -1046,26 +1195,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) &&
|
||||
@ -1117,6 +1254,10 @@
|
||||
{
|
||||
switch($fieldName)
|
||||
{
|
||||
case 'recur_interval':
|
||||
case 'recur_enddate':
|
||||
case 'recur_data':
|
||||
case 'recur_exception':
|
||||
case 'alarms':
|
||||
// not handled here
|
||||
break;
|
||||
@ -1132,17 +1273,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;
|
||||
}
|
||||
}
|
||||
@ -1215,20 +1351,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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -1270,6 +1270,74 @@ 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
|
||||
*
|
||||
@ -1351,3 +1419,4 @@ class boinfolog
|
||||
$GLOBALS['egw_info']['user']['preferences'] = $save_prefs;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,7 +215,7 @@ class accounts_backend
|
||||
{
|
||||
$GLOBALS['egw']->contacts =& CreateObject('phpgwapi.contacts');
|
||||
}
|
||||
$GLOBALS['egw']->contacts->delete($contact_id);
|
||||
$GLOBALS['egw']->contacts->delete($contact_id,false); // false = allow to delete accounts (!)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -169,8 +169,10 @@
|
||||
if(empty($_globalUid)) return false;
|
||||
|
||||
$globalUidParts = explode('-',$_globalUid);
|
||||
array_shift($globalUidParts); // remove the app name
|
||||
array_pop($globalUidParts); // remove the install_id
|
||||
|
||||
return $globalUidParts[1];
|
||||
return implode('-',$globalUidParts); // return the rest, allowing to have dashs in the id, can happen with LDAP!
|
||||
}
|
||||
|
||||
// This is used for searching the access fields
|
||||
|
@ -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':
|
||||
|
@ -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;
|
||||
|
||||
|
@ -109,7 +109,11 @@ class Horde_SyncML_Command_Sync extends Horde_Syncml_Command {
|
||||
|
||||
foreach($targets as $target)
|
||||
{
|
||||
$sync = $state->getSync($target);
|
||||
$sync = $state->getSync($target);
|
||||
|
||||
// make sure that the state reflects what is currently being done
|
||||
$state->_currentSourceURI = $sync->_sourceLocURI;
|
||||
$state->_currentTargetURI = $sync->_targetLocURI;
|
||||
|
||||
$output->startElement($state->getURI(), 'Sync', $attrs);
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
|
@ -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;
|
||||
@ -686,12 +740,82 @@ class Horde_SyncML_State {
|
||||
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'));
|
||||
}
|
||||
|
||||
|
@ -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';
|
||||
}
|
||||
|
||||
|
@ -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()));
|
||||
|
@ -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()));
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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';
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user