diff --git a/calendar/inc/class.calendar_ical.inc.php b/calendar/inc/class.calendar_ical.inc.php index 15c0d41a1f..8bc8929ac2 100644 --- a/calendar/inc/class.calendar_ical.inc.php +++ b/calendar/inc/class.calendar_ical.inc.php @@ -86,6 +86,13 @@ class calendar_ical extends calendar_boupdate */ var $uidExtension = false; + /** + * user preference: calendar to synchronize with + * + * @var int + */ + var $calendarOwner = 0; + /** * Original timezone * @@ -942,6 +949,7 @@ class calendar_ical extends calendar_boupdate unset($event_to_store); $event['reference'] = $event_info['master_event']['id']; $event['category'] = $event_info['master_event']['category']; + $event['owner'] = $event_info['master_event']['owner']; } $event_to_store = $event; // prevent $event from being changed by update method @@ -1160,6 +1168,14 @@ class calendar_ical extends calendar_boupdate { $this->tzid = $deviceInfo['tzid']; } + if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['calendar_owner'])) + { + $owner = $GLOBALS['egw_info']['user']['preferences']['syncml']['calendar_owner']; + if (0 < (int)$owner && $this->check_perms(EGW_ACL_EDIT,0,$owner)) + { + $this->calendarOwner = $owner; + } + } if (!isset($this->productManufacturer) || $this->productManufacturer == '' || $this->productManufacturer == 'file') @@ -1549,7 +1565,7 @@ class calendar_ical extends calendar_boupdate $recurence = $attributes['value']; $type = preg_match('/FREQ=([^;: ]+)/i',$recurence,$matches) ? $matches[1] : $recurence[0]; // vCard 2.0 values for all types - if (preg_match('/UNTIL=([0-9T]+)/',$recurence,$matches)) + if (preg_match('/UNTIL=([0-9TZ]+)/',$recurence,$matches)) { $vcardData['recur_enddate'] = $this->vCalendar->_parseDateTime($matches[1]); } @@ -1886,11 +1902,7 @@ class calendar_ical extends calendar_boupdate { //Horde::logMessage("vevent2egw: group participant $uid", // __FILE__, __LINE__, PEAR_LOG_DEBUG); - if ($status == 'U') - { - - } - else + if ($status != 'U') { // User tries to reply to the group invitiation $members = $GLOBALS['egw']->accounts->members($uid, true); @@ -1904,7 +1916,7 @@ class calendar_ical extends calendar_boupdate continue; } } - else continue; // can not find this group + else continue; // can't find this group } elseif ($attributes['value'] == 'Unknown') { @@ -1954,12 +1966,14 @@ class calendar_ical extends calendar_boupdate $event['participants'][$uid] = calendar_so::combine_status($status, $quantity, 'CHAIR'); } - if (is_numeric($uid)) + if (is_numeric($uid) && ($uid == $this->calendarOwner || !$this->calendarOwner)) { + // we can store the ORGANIZER as event owner $event['owner'] = $uid; } else { + // we must insert a CHAIR participant to keep the ORGANIZER $event['owner'] = $this->user; if (!isset($event['participants'][$uid])) { @@ -1968,7 +1982,6 @@ class calendar_ical extends calendar_boupdate calendar_so::combine_status('U', 1, 'CHAIR'); } } - break; } break; case 'CREATED': // will be written direct to the event @@ -2048,6 +2061,7 @@ class calendar_ical extends calendar_boupdate break; } } + if ($this->calendarOwner) $event['owner'] = $this->calendarOwner; //Horde::logMessage("vevent2egw:\n" . print_r($event, true), // __FILE__, __LINE__, PEAR_LOG_DEBUG); return $event; @@ -2239,8 +2253,8 @@ class calendar_ical extends calendar_boupdate $recurrence_event['start'] = $event['recurrence']; $recurrence_event['end'] = $event['recurrence'] + ($master_event['end'] - $master_event['start']); // check for changed data - foreach (array('start','end','uid','owner','title','description', - 'location','priority','public','special','non_blocking') as $key) + foreach (array('start','end','uid','title','location', + 'priority','public','special','non_blocking') as $key) { if (!empty($event[$key]) && $recurrence_event[$key] != $event[$key]) { diff --git a/calendar/inc/class.calendar_so.inc.php b/calendar/inc/class.calendar_so.inc.php index 02982082dd..466993140a 100644 --- a/calendar/inc/class.calendar_so.inc.php +++ b/calendar/inc/class.calendar_so.inc.php @@ -935,6 +935,8 @@ ORDER BY cal_user_type, cal_usre_id */ function participants($cal_id,$participants,$change_since=0,$add_only=false) { + $recurrences = array(); + // remove group-invitations, they are NOT stored in the db foreach($participants as $uid => $status) { @@ -950,8 +952,15 @@ ORDER BY cal_user_type, cal_usre_id $where[0] = '(cal_recur_date=0 OR cal_recur_date >= '.(int)$change_since.')'; } - if ($change_since !== false) // update existing entries + if ($change_since !== false) { + // find all existing recurrences + foreach($this->db->select($this->user_table,'DISTINCT cal_recur_date',$where,__LINE__,__FILE__,false,'','calendar') as $row) + { + $recurrences[] = $row['cal_recur_date']; + } + + // update existing entries $existing_entries = $this->db->select($this->user_table,'DISTINCT cal_user_type,cal_user_id',$where,__LINE__,__FILE__,false,'','calendar'); // create a full list of participants which already exist in the db @@ -999,16 +1008,7 @@ ORDER BY cal_user_type, cal_usre_id if (count($participants)) // participants which need to be added { - // find all recurrences, as they all need the new parts to be added - $recurrences = array(); - if ($change_since !== false) // existing entries - { - foreach($this->db->select($this->user_table,'DISTINCT cal_recur_date',$where,__LINE__,__FILE__,false,'','calendar') as $row) - { - $recurrences[] = $row['cal_recur_date']; - } - } - if (!count($recurrences)) $recurrences[] = 0; // insert the default one + if (!count($recurrences)) $recurrences[] = 0; // insert the default recurrence // update participants foreach($participants as $uid => $status) @@ -1315,7 +1315,7 @@ ORDER BY cal_user_type, cal_usre_id { $user_type = ''; $user_id = null; - $this->split_user($old_user,$user_type,$user_id); + self::split_user($old_user,$user_type,$user_id); if ($user_type == 'u') // only accounts can be owners of events { @@ -1369,14 +1369,24 @@ ORDER BY cal_user_type, cal_usre_id * * @param int $cal_id * @param int $uid participant uid + * @param int $start=0 if != 0: startdate of the search/list (servertime) + * @param int $end=0 if != 0: enddate of the search/list (servertime) + * * @return array recur_date => status pairs (index 0 => main status) */ - function get_recurrences($cal_id, $uid) + function get_recurrences($cal_id, $uid, $start=0, $end=0) { $user_type = $user_id = null; - $this->split_user($uid, $user_type, $user_id); + self::split_user($uid, $user_type, $user_id); $participant_status = array(); $where = array('cal_id' => $cal_id); + if ($start != 0 && $end == 0) $where[] = '(cal_recur_date = 0 OR cal_recur_date >= ' . (int)$start . ')'; + if ($start == 0 && $end != 0) $where[] = '(cal_recur_date = 0 OR cal_recur_date =< ' . (int)$end . ')'; + if ($start != 0 && $end != 0) + { + $where[] = '(cal_recur_date = 0 OR (cal_recur_date >= ' . (int)$start . + ' AND cal_recur_date <= ' . (int)$end . '))'; + } foreach($this->db->select($this->user_table,'DISTINCT cal_recur_date',$where,__LINE__,__FILE__,false,'','calendar') as $row) { // inititalize the array @@ -1387,6 +1397,13 @@ ORDER BY cal_user_type, cal_usre_id 'cal_user_type' => $user_type ? $user_type : 'u', 'cal_user_id' => $user_id, ); + if ($start != 0 && $end == 0) $where[] = '(cal_recur_date = 0 OR cal_recur_date >= ' . (int)$start . ')'; + if ($start == 0 && $end != 0) $where[] = '(cal_recur_date = 0 OR cal_recur_date =< ' . (int)$end . ')'; + if ($start != 0 && $end != 0) + { + $where[] = '(cal_recur_date = 0 OR (cal_recur_date >= ' . (int)$start . + ' AND cal_recur_date <= ' . (int)$end . '))'; + } foreach ($this->db->select($this->user_table,'cal_recur_date,cal_status,cal_quantity,cal_role',$where, __LINE__,__FILE__,false,'','calendar') as $row) { @@ -1416,7 +1433,7 @@ ORDER BY cal_user_type, cal_usre_id foreach ($this->db->select($this->user_table,'DISTINCT cal_user_type,cal_user_id', $where, __LINE__,__FILE__,false,'','calendar') as $row) { - $uid = $this->combine_user($row['cal_user_type'], $row['cal_user_id']); + $uid = self::combine_user($row['cal_user_type'], $row['cal_user_id']); $id = $row['cal_user_type'] . $row['cal_user_id']; $participants[$id]['type'] = $row['cal_user_type']; $participants[$id]['id'] = $row['cal_user_id']; @@ -1456,10 +1473,12 @@ ORDER BY cal_user_type, cal_usre_id * * @param array $event Recurring Event. * @param string tz_id=null timezone for exports (null for event's timezone) + * @param int $start=0 if != 0: startdate of the search/list (servertime) + * @param int $end=0 if != 0: enddate of the search/list (servertime) * * @return array Array of exception days (false for non-recurring events). */ - function get_recurrence_exceptions(&$event, $tz_id=null) + function get_recurrence_exceptions(&$event, $tz_id=null, $start=0, $end=0) { $cal_id = (int) $event['id']; if (!$cal_id || $event['recur_type'] == MCAL_RECUR_NONE) return false; @@ -1489,7 +1508,7 @@ ORDER BY cal_user_type, cal_usre_id case 'u': // account case 'c': // contact case 'e': // email address - $recurrences = $this->get_recurrences($event['id'], $uid); + $recurrences = $this->get_recurrences($event['id'], $uid, $start, $end); foreach ($recurrences as $recur_date => $recur_status) { if ($recur_date) diff --git a/phpgwapi/inc/horde/Horde/SyncML/Sync/TwoWaySync.php b/phpgwapi/inc/horde/Horde/SyncML/Sync/TwoWaySync.php index 9c0352422d..267ef372a7 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Sync/TwoWaySync.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Sync/TwoWaySync.php @@ -423,15 +423,28 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync { 'type' => $syncType, 'filter' => $this->_filterExpression ))); - $state->mergeChangedItems($syncType, $registry->call($hordeType . '/listBy', array ( + + $changedItems =& $registry->call($hordeType . '/listBy', array ( 'action' => 'modify', 'timestamp' => $refts, 'type' => $syncType, 'filter' => $this->_filterExpression - ))); + )); + + $addedItems =& $registry->call($hordeType . '/listBy', array ( + 'action' => 'add', + 'timestamp' => $refts, + 'type' => $syncType, + 'filter' => $this->_filterExpression + )); + + // added items may show up as changed, too + $changedItems = array_diff($changedItems, $addedItems); + + $state->mergeChangedItems($syncType, $changedItems); + + $state->mergeAddedItems($syncType, $addedItems); - Horde :: logMessage("SyncML: reading deleted items from database for $hordeType", - __FILE__, __LINE__, PEAR_LOG_DEBUG); $state->setDeletedItems($syncType, $registry->call($hordeType . '/listBy', array ( 'action' => 'delete', 'timestamp' => $refts, @@ -439,8 +452,6 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync { 'filter' => $this->_filterExpression ))); - Horde :: logMessage("SyncML: reading added items from database for $hordeType", - __FILE__, __LINE__, PEAR_LOG_DEBUG); /* The items, which now match the filter criteria are show here, too $delta_add = count($registry->call($hordeType . '/listBy', array ( 'action' => 'add', @@ -449,12 +460,6 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync { 'filter' => $this->_filterExpression ))); */ - $state->mergeAddedItems($syncType, $registry->call($hordeType . '/listBy', array ( - 'action' => 'add', - 'timestamp' => $refts, - 'type' => $syncType, - 'filter' => $this->_filterExpression - ))); $this->_syncDataLoaded = TRUE;