From 1761dcab06b4e8e3dc2b417067adbedf32179dba Mon Sep 17 00:00:00 2001 From: Lars Kneschke Date: Mon, 27 Mar 2006 23:22:59 +0000 Subject: [PATCH] added calendar sif support --- calendar/inc/class.sifcalendar.inc.php | 488 +++++++++++++++++++++++++ 1 file changed, 488 insertions(+) create mode 100644 calendar/inc/class.sifcalendar.inc.php diff --git a/calendar/inc/class.sifcalendar.inc.php b/calendar/inc/class.sifcalendar.inc.php new file mode 100644 index 0000000000..03fc347ef7 --- /dev/null +++ b/calendar/inc/class.sifcalendar.inc.php @@ -0,0 +1,488 @@ + * + * -------------------------------------------- * + * This program is free software; you can redistribute it and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; version 2 of the License. * + \**************************************************************************/ + + /* $Id$ */ + + require_once EGW_SERVER_ROOT.'/calendar/inc/class.bocalupdate.inc.php'; + require_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/Horde/iCalendar.php'; + + class sifcalendar extends bocalupdate + { + var $sifMapping = array( + 'Start' => 'start', + 'End' => 'end', + 'AllDayEvent' => 'alldayevent', + 'BillingInformation' => '', + 'Body' => 'description', + 'BusyStatus' => '', + 'Categories' => 'category', + 'Companies' => '', + 'Importance' => 'priority', + 'IsRecurring' => 'isrecurring', + 'Location' => 'location', + 'MeetingStatus' => '', + 'Mileage' => '', + 'ReminderMinutesBeforeStart' => 'reminderstart', + 'ReminderSet' => 'reminderset', + 'ReplyTime' => '', + 'Sensitivity' => 'public', + 'Subject' => 'title', + 'RecurrenceType' => 'recur_type', + 'Interval' => 'recur_interval', + 'MonthOfYear' => '', + 'DayOfMonth' => '', + 'DayOfWeekMask' => 'recur_weekmask', + 'Instance' => '', + 'PatternStartDate' => '', + 'NoEndDate' => 'recur_noenddate', + 'PatternEndDate' => 'recur_enddate', + 'Occurrences' => '', + ); + + // the calendar event array + var $event; + + // constants for recurence type + const olRecursDaily = 0; + const olRecursWeekly = 1; + const olRecursMonthly = 2; + const olRecursMonthNth = 3; + const olRecursYearly = 5; + const olRecursYearNth = 6; + + // constants for weekdays + const olSunday = 1; + const olMonday = 2; + const olTuesday = 4; + const olWednesday = 8; + const olThursday = 16; + const olFriday = 32; + const olSaturday = 64; + + function startElement($_parser, $_tag, $_attributes) { + } + + function endElement($_parser, $_tag) { + #error_log($_tag .' => '. $this->sifData); + if(!empty($this->sifMapping[$_tag])) { + $this->event[$this->sifMapping[$_tag]] = $this->sifData; + } + unset($this->sifData); + } + + function characterData($_parser, $_data) { + $this->sifData .= $_data; + } + + function siftoegw($_sifdata) { + $vcal = &new Horde_iCalendar; + $finalEvent = array(); + $sysCharSet = $GLOBALS['egw']->translation->charset(); + $sifData = base64_decode($_sifdata); + #error_log($sifData); + + $tmpfname = tempnam('/tmp/sync/contents','sife_'); + + $handle = fopen($tmpfname, "w"); + fwrite($handle, $sifData); + fclose($handle); + + $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); + xml_set_element_handler($this->xml_parser, "startElement", "endElement"); + xml_set_character_data_handler($this->xml_parser, "characterData"); + $this->strXmlData = xml_parse($this->xml_parser, $sifData); + if(!$this->strXmlData) { + error_log(sprintf("XML error: %s at line %d", + xml_error_string(xml_get_error_code($this->xml_parser)), + xml_get_current_line_number($this->xml_parser))); + return false; + } + #error_log(print_r($this->event, true)); + + foreach($this->event as $key => $value) { + $value = $GLOBALS['egw']->translation->convert($value, 'utf-8', $sysCharSet); + #error_log("$key => $value"); + switch($key) { + case 'alldayevent': + if($value == 1) { + $startParts = explode('-',$this->event['start']); + $finalEvent['start'] = mktime(0, 0, 0, $startParts[1], $startParts[2], $startParts[0]); + $finalEvent['end'] = mktime(23, 59, 59, $startParts[1], $startParts[2], $startParts[0]); + } + break; + + case 'public': + $finalEvent[$key] = ((int)$value > 0) ? 0 : 1; + break; + + case 'category': + if(!empty($value)) { + $isAdmin = $GLOBALS['egw']->acl->check('run',1,'admin'); + $egwCategories =& CreateObject('phpgwapi.categories',$GLOBALS['egw_info']['user']['account_id'],'calendar'); + $categories = explode('; ',$value); + $cat_id = ''; + foreach($categories as $categorieName) { + $categorieName = trim($categorieName); + if(!($cat_id = $egwCategories->name2id($categorieName)) && $isAdmin) { + $cat_id = $egwCategories->add(array('name' => $categorieName, 'descr' => $categorieName)); + } + if($cat_id) { + if(!empty($finalEvent[$key])) $finalEvent[$key] .= ','; + $finalEvent[$key] .= $cat_id; + } + } + } + break; + + case 'end': + case 'start': + if($this->event['alldayevent'] < 1) { + $finalEvent[$key] = $vcal->_parseDateTime($value); + } + break; + + case 'isrecurring': + if($value == 1) { + $finalEvent['recur_interval'] = $this->event['recur_interval']; + if($this->event['recur_noenddate'] == 0) { + $finalEvent['recur_enddate'] = $vcal->_parseDateTime($this->event['recur_enddate']); + } + switch($this->event['recur_type']) { + case self::olRecursDaily: + $finalEvent['recur_type'] = MCAL_RECUR_DAILY; + break; + + case self::olRecursWeekly: + $finalEvent['recur_type'] = MCAL_RECUR_WEEKLY; + $finalEvent['recur_data'] = $this->event['recur_weekmask']; + break; + + case self::olRecursMonthly: + $finalEvent['recur_type'] = MCAL_RECUR_MONTHLY_MDAY; + break; + + case self::olRecursMonthNth: + $finalEvent['recur_type'] = MCAL_RECUR_MONTHLY_WDAY; + break; + + case self::olRecursYearly: + $finalEvent['recur_type'] = MCAL_RECUR_YEARLY; + $finalEvent['recur_interval'] = 1; + break; + } + } + break; + + case 'priority': + $finalEvent[$key] = $value+1; + break; + + case 'reminderset': + if($value == 1) { + $finalEvent['alarm'] = $this->event['reminderstart']; + } + break; + + case 'recur_type': + case 'recur_enddate': + case 'recur_interval': + case 'recur_weekmask': + case 'reminderstart': + // do nothing, get's handled in isrecuring clause + break; + + default: + $finalEvent[$key] = $value; + break; + } + } + + #$middleName = ($finalEvent['n_middle']) ? ' '.trim($finalEvent['n_middle']) : ''; + #$finalEvent['fn'] = trim($finalEvent['n_given']. $middleName .' '. $finalEvent['n_family']); + + error_log(print_r($finalEvent, true)); + + + return $finalEvent; + } + + function search($_sifdata) { + if(!$event = $this->siftoegw($_sifdata)) { + return false; + } + + return false; + + if($foundEvents = $this->read_entries(array('query' => $contact))) { + error_log(print_r($foundContacts,true)); + return $foundContacts[0][id]; + } + + return false; + } + + /** + * @return int contact id + * @param string $_vcard the vcard + * @param int $_abID the internal addressbook id + * @desc import a vard into addressbook + */ + function addSIF($_sifdata, $_calID) + { + $calID = false; + + #error_log('ABID: '.$_abID); + #error_log(base64_decode($_sifdata)); + + if(!$event = $this->siftoegw($_sifdata)) { + return false; + } + + if(isset($event['alarm'])) { + $alarm = $event['alarm']; + unset($event['alarm']); + } + + if($_calID > 0) + { + // update entry + $event['id'] = $_calID; + } + + if($eventID = $this->update($event, TRUE)) { + $updatedEvent = $this->read($eventID); + foreach($updatedEvent['alarm'] as $alarmID => $alarmData) + { + $this->delete_alarm($alarmID); + } + + if(isset($alarm)) { + $alarmData['time'] = $event['start'] - ($alarm*60); + $alarmData['offset'] = $alarm*60; + $alarmData['all'] = 1; + $alarmData['owner'] = $GLOBALS['egw_info']['user']['account_id']; + error_log(print_r($alarm, true)); + $this->save_alarm($eventID, $alarmData); + } + } + + return $calID; + } + + /** + * return a vcard + * + * @param int $_id the id of the contact + * @param int $_vcardProfile profile id for mapping from vcard values to egw addressbook + * @return string containing the vcard + */ + function getSIF($_id) + { + $fields = array_unique(array_values($this->sifMapping)); + sort($fields); + + #$event = $this->read($_id,null,false,'server'); + #error_log("FOUND EVENT: ". print_r($event, true)); + + if($event = $this->read($_id,null,false,'server')) { + $sysCharSet = $GLOBALS['egw']->translation->charset(); + $vcal = &new Horde_iCalendar; + + + $sifEvent = ''; + + foreach($this->sifMapping as $sifField => $egwField) + { + if(empty($egwField)) continue; + + #error_log("$sifField => $egwField"); + #error_log('VALUE1: '.$event[$egwField]); + $value = $GLOBALS['egw']->translation->convert($event[$egwField], $sysCharSet, 'utf-8'); + #error_log('VALUE2: '.$value); + + switch($sifField) + { + 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 .= $catData[0]['name']; + } + } + } + $sifEvent .= "<$sifField>$value"; + break; + + case 'Importance': + $value = $value-1; + $sifEvent .= "<$sifField>$value"; + break; + + case 'RecurrenceType': + case 'Interval': + case 'PatternStartDate': + case 'NoEndDate': + case 'DayOfWeekMask': + case 'PatternEndDate': + break; + + case 'IsRecurring': + switch($event['recur_type']) { + case MCAL_RECUR_NONE: + $sifEvent .= "<$sifField>0"; + break; + + case MCAL_RECUR_DAILY: + $eventInterval = ($event['recur_interval'] > 1 ? $event['recur_interval'] : 1); + $recurStartDate = mktime(0,0,0,date('m',$event['start']), date('d', $event['start']), date('Y', $event['start'])); + + $sifEvent .= "<$sifField>1"; + $sifEvent .= ''. self::olRecursDaily .''; + $sifEvent .= ''. $eventInterval .''; + $sifEvent .= ''. $vcal->_exportDateTime($recurStartDate) .''; + if($event['recur_enddate'] == 0) { + $sifEvent .= '1'; + } else { + $recurEndDate = mktime(24,0,0,date('m',$event['recur_enddate']), date('d', $event['recur_enddate']), date('Y', $event['recur_enddate'])); + + $sifEvent .= '0'; + $sifEvent .= ''. $vcal->_exportDateTime($recurEndDate) .''; + $totalDays = ($recurEndDate - $recurStartDate) / 86400; + $occurrences = ceil($totalDays / $eventInterval); + $sifEvent .= ''. $occurrences .''; + } + break; + + case MCAL_RECUR_WEEKLY: + $eventInterval = ($event['recur_interval'] > 1 ? $event['recur_interval'] : 1); + $recurStartDate = mktime(0,0,0,date('m',$event['start']), date('d', $event['start']), date('Y', $event['start'])); + + $sifEvent .= "<$sifField>1"; + $sifEvent .= ''. self::olRecursWeekly .''; + $sifEvent .= ''. $eventInterval .''; + $sifEvent .= ''. $vcal->_exportDateTime($recurStartDate) .''; + $sifEvent .= ''. $event['recur_data'] .''; + if($event['recur_enddate'] == 0) { + $sifEvent .= '1'; + } else { + $recurEndDate = mktime(24, 0, 0, date('m',$event['recur_enddate']), date('d', $event['recur_enddate']), date('Y', $event['recur_enddate'])); + + $daysPerWeek = substr_count(decbin($event['recur_data']),'1'); + $sifEvent .= '0'; + $sifEvent .= ''. $vcal->_exportDateTime($recurEndDate) .''; + $totalWeeks = floor(($recurEndDate - $recurStartDate) / (86400*7)); + #error_log("AAA: $daysPerWeek $totalWeeks"); + $occurrences = ($totalWeeks / $eventInterval) * $daysPerWeek; + for($i = $recurEndDate; $i > $recurStartDate + ($totalWeeks * 86400*7); $i = $i - 86400) { + switch(date('w', $i-1)) { + case 0: + if($event['recur_data'] & 1) $occurrences++; + break; + // monday + case 1: + if($event['recur_data'] & 2) $occurrences++; + break; + case 2: + if($event['recur_data'] & 4) $occurrences++; + break; + case 3: + if($event['recur_data'] & 8) $occurrences++; + break; + case 4: + error_log(decbin($event['recur_data'])); + error_log(decbin(8)); + if($event['recur_data'] & 16) $occurrences++; + break; + case 5: + if($event['recur_data'] & 32) $occurrences++; + break; + case 6: + if($event['recur_data'] & 64) $occurrences++; + break; + } + } + $sifEvent .= ''. $occurrences .''; + } + break; + } + break; + + case 'Sensitivity': + $value = (!$value ? '2' : '0'); + $sifEvent .= "<$sifField>$value"; + break; + + case 'Folder': + # skip currently. This is the folder where Outlook stores the contact. + #$sifEvent .= "<$sifField>/"; + break; + + case 'AllDayEvent': + case 'End': + // get's handled by Start clause + break; + + case 'Start': + if($event['end'] - $event['start'] == 86399 && date('Y-m-d', $event['end']) == date('Y-m-d', $event['start'])) { + $value = date('Y-m-d'); + $sifEvent .= "$value"; + $sifEvent .= "$value"; + $sifEvent .= "1"; + } else { + $value = $vcal->_exportDateTime($event['start']); + $sifEvent .= "$value"; + $value = $vcal->_exportDateTime($event['end']); + $sifEvent .= "$value"; + $sifEvent .= "0"; + } + break; + + case 'ReminderMinutesBeforeStart': + break; + + case 'ReminderSet': + if(count((array)$event['alarm']) > 0) { + $sifEvent .= "<$sifField>1"; + foreach($event['alarm'] as $alarmID => $alarmData) + { + $sifEvent .= ''. $alarmData['offset']/60 .''; + // lets take only the first alarm + break; + } + } else { + $sifEvent .= "<$sifField>0"; + } + break; + + default: + $sifEvent .= "<$sifField>$value"; + break; + } + } + $sifEvent .= ''; +error_log($sifEvent); + return base64_encode($sifEvent); + } + + if($this->xmlrpc) + { + $GLOBALS['server']->xmlrpc_error($GLOBALS['xmlrpcerr']['no_access'],$GLOBALS['xmlrpcstr']['no_access']); + } + return False; + } + + }