[ Index ] |
|
Code source de Horde 3.1.3 |
1 <?php 2 3 require_once 'Horde/iCalendar.php'; 4 5 /** 6 * Sync4j (www.sync4j.org) 7 * 8 * The Sync4J outlook converter uses its native SIF format for data 9 * exchange. Conversion to text/vcalendar etc. is done by 10 * SifConverter.php The connector seems not support DevInf 11 * information, so SyncML_Device can only detect it by the decice ID: 12 * so in the connector configuration the device ID must be set to 13 * 'sc-pim-<type>' which should be the default anyhow. 14 * 15 * Copyright 2005-2006 Karsten Fourmont <karsten@horde.org> 16 * 17 * See the enclosed file COPYING for license information (LGPL). If you did not 18 * receive this file, see http://www.fsf.org/copyleft/lgpl.html. 19 * 20 * $Horde: framework/SyncML/SyncML/Device/Sync4j.php,v 1.8.2.4 2006/01/01 21:28:37 jan Exp $ 21 * 22 * @author Karsten Fourmont <karsten@horde.org> 23 * @package SyncML 24 */ 25 class SyncML_Device_sync4j extends SyncML_Device { 26 27 /** 28 * Convert the content. 29 * 30 * Currently strips uid (primary key) information as client and 31 * server might use different ones. 32 * 33 * Charset conversions might be added here too. 34 */ 35 function convertClient2Server($content, $contentType) 36 { 37 list($content, $contentType) = 38 parent::convertClient2Server($content, $contentType); 39 40 switch ($contentType) { 41 case 'sif/note' : 42 case 'text/x-s4j-sifn' : 43 $content = $this->sif2vnote(base64_decode($content)); 44 $contentType = 'text/x-vnote'; 45 break; 46 47 case 'sif/contact' : 48 case 'text/x-s4j-sifc' : 49 $content = $this->sif2vcard(base64_decode($content)); 50 $contentType = 'text/x-vcard'; 51 break; 52 53 case 'sif/calendar' : 54 case 'text/x-s4j-sife' : 55 $content = $this->sif2vevent(base64_decode($content)); 56 $contentType = 'text/x-vevent'; 57 break; 58 59 case 'sif/task' : 60 case 'text/x-s4j-sift' : 61 $content = $this->sif2vtodo(base64_decode($content)); 62 $contentType = 'text/x-vtodo'; 63 break; 64 } 65 66 if (DEBUGLOG_ICALENDARDATA) { 67 $fp = @fopen('/tmp/sync/log.txt', 'a'); 68 if ($fp) { 69 @fwrite($fp, "\ninput converted for server: $contentType\n"); 70 @fwrite($fp,$content . "\n"); 71 @fclose($fp); 72 } 73 } 74 75 return array($content, $contentType); 76 } 77 78 /** 79 * Converts the content from the backend to a format suitable for the 80 * client device. 81 * 82 * Strips the uid (primary key) information as client and server might use 83 * different ones. 84 * 85 * @param string $content The content to convert 86 * @param string $contentType The contentType of content as returned from 87 * the backend 88 * @return array array($newcontent, $newcontentType): 89 * the converted content and the 90 * (possibly changed) new ContentType. 91 */ 92 function convertServer2Client($content, $contentType) 93 { 94 global $backend; 95 96 list($content, $contentType) = 97 parent::convertServer2Client($content, $contentType); 98 99 switch ($contentType) { 100 case 'text/calendar' : 101 case 'text/x-icalendar' : 102 case 'text/x-vcalendar' : 103 case 'text/x-vevent' : 104 $content = $this->vevent2sif($content); 105 $content = base64_encode($content); 106 $contentType = 'sif/calendar'; 107 break; 108 109 case 'text/x-vtodo' : 110 $content = $this->vtodo2sif($content); 111 $content = base64_encode($content); 112 $contentType = 'sif/task'; 113 break; 114 115 case 'text/x-vcard' : 116 $content = $this->vcard2sif($content); 117 $content = base64_encode($content); 118 $contentType = 'sif/contact'; 119 break; 120 121 case 'text/x-vnote': 122 $content = $this->vnote2sif($content); 123 $content = base64_encode($content); 124 $contentType = 'sif/note'; 125 break; 126 } 127 128 if (DEBUGLOG_ICALENDARDATA) { 129 $fp = @fopen('/tmp/sync/log.txt', 'a'); 130 if ($fp) { 131 @fwrite($fp, serialize($contentType)); 132 @fwrite($fp, "\nconverted for sync4j client: $contentType\n"); 133 @fwrite($fp, base64_decode($content) . "\n"); 134 @fclose($fp); 135 } 136 } 137 138 return array($content, $contentType); 139 } 140 141 /** 142 * Decodes a sif xml string to an associative array. 143 * 144 * Quick hack to convert from text/vcard and text/vcalendar to 145 * Sync4J's proprietery sif datatypes and vice versa. For details 146 * about the sif format see the appendix of the developer guide on 147 * www.sync4j.org. 148 * 149 * @access private 150 * 151 * @param string $sif A sif string like <k1>v1></k1><k2>v2</k2> 152 * 153 * @return array Assoc array in utf8 like array ('k1' => 'v1>', 'k2' => 'v2'); 154 */ 155 function sif2array($sif) 156 { 157 $r = array(); 158 if (preg_match_all('/<([^>]*)>([^<]*)<\/\1>/si', $sif, $matches, PREG_SET_ORDER)) { 159 foreach ($matches as $match) { 160 $r[$match[1]] = html_entity_decode($match[2]); 161 } 162 } 163 return $r; 164 } 165 166 /** 167 * Encodes an assoc. array to sif xml 168 * 169 * Quick hack to convert from text/vcard and text/vcalendar to 170 * Sync4J's proprietery sif datatypes and vice versa. For details 171 * about the sif format see the appendix of the developer guide on 172 * www.sync4j.org. 173 * 174 * @access private 175 * 176 * @param array $array An assoc array. 177 * 178 * @return string The resulting XML string. 179 */ 180 function array2sif($array, $pre='', $post='') 181 { 182 $search = array('<', '>'); 183 $replace = array('<', '>'); 184 185 $r = $pre; 186 foreach ($array as $key => $value) { 187 $r .= '<' . $key . '>' . 188 str_replace($search, $replace, $value) . 189 '</' . $key . '>'; 190 } 191 192 return $r . $post; 193 } 194 195 function sif2vnote($sif) 196 { 197 $a = $this->sif2array($sif); 198 199 $iCal = &new Horde_iCalendar(); 200 $iCal->setAttribute('VERSION', '1.1'); 201 $iCal->setAttribute('PRODID', '-//The Horde Project//Mnemo //EN'); 202 $iCal->setAttribute('METHOD', 'PUBLISH'); 203 204 $vnote = &Horde_iCalendar::newComponent('vnote', $iCal); 205 $vnote->setAttribute('BODY', isset($a['Body']) ? $a['Body'] : ''); 206 207 return $vnote->exportvCalendar(); 208 } 209 210 function sif2vcard($sif) 211 { 212 $a = $this->sif2array($sif); 213 214 $iCal = &new Horde_iCalendar(); 215 $iCal->setAttribute('VERSION', '2.1'); 216 $iCal->setAttribute('PRODID', '-//The Horde Project//Mnemo //EN'); 217 $iCal->setAttribute('METHOD', 'PUBLISH'); 218 219 $vcard = &Horde_iCalendar::newComponent('vcard', $iCal); 220 221 $vcard->setAttribute('FN', $a['FileAs']); 222 $vcard->setAttribute('NICKNAME', $a['NickName']); 223 $vcard->setAttribute('TEL', $a['HomeTelephoneNumber'], 224 array('TYPE'=>'HOME')); 225 $vcard->setAttribute('TEL', $a['BusinessTelephoneNumber'], 226 array('TYPE'=>'WORK')); 227 $vcard->setAttribute('TEL', $a['MobileTelephoneNumber'], 228 array('TYPE'=>'CELL')); 229 $vcard->setAttribute('TEL', $a['BusinessFaxNumber'], 230 array('TYPE'=>'FAX')); 231 $vcard->setAttribute('EMAIL', $a['Email1Address']); 232 $vcard->setAttribute('TITLE', $a['JobTitle']); 233 $vcard->setAttribute('ORG', $a['CompanyName']); 234 $vcard->setAttribute('NOTE', $a['Body']); 235 $vcard->setAttribute('URL', $a['WebPage']); 236 237 $v = array( 238 VCARD_N_FAMILY => $a['LastName'], 239 VCARD_N_GIVEN => $a['FirstName'], 240 VCARD_N_ADDL => $a['MiddleName'], 241 VCARD_N_PREFIX => $a['Title'], 242 VCARD_N_SUFFIX => $a['Suffix'] 243 ); 244 $vcard->setAttribute('N', implode(';', $v), array(), false, $v); 245 246 $v = array( 247 VCARD_ADR_POB => $a['HomeAddressPostOfficeBox'], 248 VCARD_ADR_EXTEND => '', 249 VCARD_ADR_STREET => $a['HomeAddressStreet'], 250 VCARD_ADR_LOCALITY => $a['HomeAddressCity'], 251 VCARD_ADR_REGION => $a['HomeAddressState'], 252 VCARD_ADR_POSTCODE => $a['HomeAddressPostalCode'], 253 VCARD_ADR_COUNTRY => $a['HomeAddressCountry'], 254 ); 255 $vcard->setAttribute('ADR', implode(';', $v), array('TYPE' => 'HOME' ), true, $v); 256 257 $v = array( 258 VCARD_ADR_POB => $a['BusinessAddressPostOfficeBox'], 259 VCARD_ADR_EXTEND => '', 260 VCARD_ADR_STREET => $a['BusinessAddressStreet'], 261 VCARD_ADR_LOCALITY => $a['BusinessAddressCity'], 262 VCARD_ADR_REGION => $a['BusinessAddressState'], 263 VCARD_ADR_POSTCODE => $a['BusinessAddressPostalCode'], 264 VCARD_ADR_COUNTRY => $a['BusinessAddressCountry'], 265 ); 266 267 $vcard->setAttribute('ADR', implode(';', $v), array('TYPE' => 'WORK' ), true, $v); 268 269 return $vcard->exportvCalendar(); 270 } 271 272 function sif2vevent($sif) 273 { 274 $a = $this->sif2array($sif); 275 276 $iCal = &new Horde_iCalendar(); 277 $iCal->setAttribute('VERSION', '1.0'); 278 $iCal->setAttribute('PRODID', '-//The Horde Project//Mnemo //EN'); 279 $iCal->setAttribute('METHOD', 'PUBLISH'); 280 281 $vEvent = &Horde_iCalendar::newComponent('vevent', $iCal); 282 283 if ($a['AllDayEvent'] == 'True') { 284 $t = $iCal->_parseDateTime($a['Start']); 285 $vEvent->setAttribute('DTSTART', 286 array('year' => date('Y', $t), 287 'month' => date('m', $t), 288 'mday' => date('d',$t)), 289 array('VALUE' => 'DATE')); 290 $t = $iCal->_parseDateTime($a['End']); 291 $vEvent->setAttribute('DTEND', 292 array('year' => date('Y', $t), 293 'month' => date('m', $t), 294 'mday' => date('d',$t)), 295 array('VALUE' => 'DATE')); 296 } else { 297 $vEvent->setAttribute('DTSTART', 298 $iCal->_parseDateTime($a['Start'])); 299 $vEvent->setAttribute('DTEND', 300 $iCal->_parseDateTime($a['End'])); 301 } 302 303 $vEvent->setAttribute('DTSTAMP', time()); 304 $vEvent->setAttribute('SUMMARY', $a['Subject']); 305 $vEvent->setAttribute('DESCRIPTION', $a['Body']); 306 // $vEvent->setAttribute('CATEGORIES', $a['']); 307 $vEvent->setAttribute('LOCATION', $a['Location']); 308 309 return $vEvent->exportvCalendar(); 310 } 311 312 function sif2vtodo($sif) 313 { 314 $a = $this->sif2array($sif); 315 316 $iCal = &new Horde_iCalendar(); 317 $iCal->setAttribute('VERSION', '1.0'); 318 $iCal->setAttribute('PRODID', '-//The Horde Project//Mnemo //EN'); 319 $iCal->setAttribute('METHOD', 'PUBLISH'); 320 321 $vtodo = &Horde_iCalendar::newComponent('vtodo', $iCal); 322 323 $vtodo->setAttribute('SUMMARY', $a['Subject']); 324 $vtodo->setAttribute('DESCRIPTION', $a['Body']); 325 if ($a['Importance'] == 0) { 326 $vtodo->setAttribute('PRIORITY', 5); 327 } elseif ($a['Importance'] == 2) { 328 $vtodo->setAttribute('PRIORITY', 1); 329 } else { 330 $vtodo->setAttribute('PRIORITY', 3); 331 } 332 if ($a['DueDate'] != '45001231T230000Z') { 333 $vtodo->setAttribute('DUE', $iCal->_parseDateTime($a['DueDate'])); 334 } 335 $vtodo->setAttribute('COMPLETED', $a['Complete'] == 'True' ? 1 : 0); 336 337 return $vtodo->exportvCalendar(); 338 } 339 340 function vnote2sif($vnote) 341 { 342 $iCal = &new Horde_iCalendar(); 343 if (!$iCal->parsevCalendar($vnote)) { 344 die("There was an error importing the data."); 345 } 346 347 $components = $iCal->getComponents(); 348 349 switch (count($components)) { 350 case 0: 351 die("No data was found."); 352 353 case 1: 354 $content = $components[0]; 355 break; 356 357 default: 358 die("Multiple components found; only one is supported."); 359 } 360 361 $a = array('Body' => $content->getAttribute('BODY')); 362 363 return $this->array2sif( 364 $a, 365 '<?xml version="1.0"?><note>', 366 '<Categories></Categories>' 367 . '<Subject></Subject><Color></Color><Height></Height><Width></Width><Left></Left><Top></Top>' 368 . '</note>'); 369 } 370 371 function vcard2sif($vcard) 372 { 373 $iCal = &new Horde_iCalendar(); 374 if (!$iCal->parsevCalendar($vcard)) { 375 die("There was an error importing the data."); 376 } 377 378 $components = $iCal->getComponents(); 379 380 switch (count($components)) { 381 case 0: 382 die("No data was found."); 383 384 case 1: 385 $content = $components[0]; 386 break; 387 388 default: 389 die("Multiple components found; only one is supported."); 390 } 391 392 // from here on, the code is taken from 393 // Turba_Driver::toHash, v 1.65 2005/03/12 394 // and modified for the Sync4J attribute names. 395 $attr = $content->getAllAttributes(); 396 foreach ($attr as $item) { 397 switch ($item['name']) { 398 case 'FN': 399 $hash['FileAs'] = $item['value']; 400 break; 401 402 case 'N': 403 $name = $item['values']; 404 $hash['LastName'] = $name[VCARD_N_FAMILY]; 405 $hash['FirstName'] = $name[VCARD_N_GIVEN]; 406 $hash['MiddleName'] = $name[VCARD_N_ADDL]; 407 $hash['Title'] = $name[VCARD_N_PREFIX]; 408 $hash['Suffix'] = $name[VCARD_N_SUFFIX]; 409 break; 410 411 case 'NICKNAME': 412 $hash['NickName'] = $item['value']; 413 break; 414 415 // For vCard 3.0. 416 case 'ADR': 417 if (isset($item['params']['TYPE'])) { 418 if (!is_array($item['params']['TYPE'])) { 419 $item['params']['TYPE'] = array($item['params']['TYPE']); 420 } 421 } else { 422 $item['params']['TYPE'] = array(); 423 if (isset($item['params']['WORK'])) { 424 $item['params']['TYPE'][] = 'WORK'; 425 } 426 if (isset($item['params']['HOME'])) { 427 $item['params']['TYPE'][] = 'HOME'; 428 } 429 } 430 431 $address = $item['values']; 432 foreach ($item['params']['TYPE'] as $adr) { 433 switch (String::upper($adr)) { 434 case 'HOME': 435 $prefix = 'HomeAddress'; 436 break; 437 438 case 'WORK': 439 $prefix = 'WorkAddress'; 440 break; 441 442 default: 443 $prefix = 'HomeAddress'; 444 } 445 446 if ($prefix) { 447 $hash[$prefix . 'Street'] = isset($address[VCARD_ADR_STREET]) ? $address[VCARD_ADR_STREET] : null; 448 $hash[$prefix . 'City'] = isset($address[VCARD_ADR_LOCALITY]) ? $address[VCARD_ADR_LOCALITY] : null; 449 $hash[$prefix . 'State'] = isset($address[VCARD_ADR_REGION]) ? $address[VCARD_ADR_REGION] : null; 450 $hash[$prefix . 'PostalCode'] = isset($address[VCARD_ADR_POSTCODE]) ? $address[VCARD_ADR_POSTCODE] : null; 451 $hash[$prefix . 'Country'] = isset($address[VCARD_ADR_COUNTRY]) ? $address[VCARD_ADR_COUNTRY] : null; 452 $hash[$prefix . 'PostOfficeBox'] = isset($address[VCARD_ADR_POB]) ? $address[VCARD_ADR_POB] : null; 453 } 454 } 455 break; 456 457 case 'TEL': 458 if (isset($item['params']['FAX'])) { 459 $hash['BusinessFaxNumber'] = $item['value']; 460 } elseif (isset($item['params']['TYPE'])) { 461 if (!is_array($item['params']['TYPE'])) { 462 $item['params']['TYPE'] = array($item['params']['TYPE']); 463 } 464 // For vCard 3.0. 465 foreach ($item['params']['TYPE'] as $tel) { 466 if (String::upper($tel) == 'WORK') { 467 $hash['BusinessTelephoneNumber'] = $item['value']; 468 } elseif (String::upper($tel) == 'HOME') { 469 $hash['HomeTelephoneNumber'] = $item['value']; 470 } elseif (String::upper($tel) == 'CELL') { 471 $hash['MobileTelephoneNumber'] = $item['value']; 472 } elseif (String::upper($tel) == 'FAX') { 473 $hash['BusinessFaxNumber'] = $item['value']; 474 } 475 } 476 } else { 477 if (isset($item['params']['HOME'])) { 478 $hash['HomeTelephoneNumber'] = $item['value']; 479 } elseif (isset($item['params']['WORK'])) { 480 $hash['BusinessTelephoneNumber'] = $item['value']; 481 } elseif (isset($item['params']['CELL'])) { 482 $hash['MobileTelephoneNumber'] = $item['value']; 483 } else { 484 $hash['HomeTelephoneNumber'] = $item['value']; 485 } 486 } 487 break; 488 489 case 'EMAIL': 490 if (isset($item['params']['PREF']) || !isset($hash['email'])) { 491 $hash['Email1Address'] = Horde_iCalendar_vcard::getBareEmail($item['value']); 492 $hash['Email1AddressType'] = 'SMTP'; 493 } 494 break; 495 496 case 'TITLE': 497 $hash['JobTitle'] = $item['value']; 498 break; 499 500 case 'ORG': 501 $hash['CompanyName'] = $item['value']; 502 break; 503 504 case 'NOTE': 505 $hash['Body'] = $item['value']; 506 break; 507 508 case 'URL': 509 $hash['WebPage'] = $item['value']; 510 break; 511 } 512 } 513 514 return $this->array2sif( 515 $hash, 516 '<?xml version="1.0"?><contact>', 517 '</contact>'); 518 } 519 520 function vevent2sif($vcard) 521 { 522 $iCal = &new Horde_iCalendar(); 523 if (!$iCal->parsevCalendar($vcard)) { 524 die("There was an error importing the data."); 525 } 526 527 $components = $iCal->getComponents(); 528 529 switch (count($components)) { 530 case 0: 531 die("No data was found."); 532 533 case 1: 534 $content = $components[0]; 535 break; 536 537 default: 538 die("Multiple components found; only one is supported."); 539 } 540 541 // Is there a real need to provide the correct value? 542 $duration = 0; 543 544 $attr = $content->getAllAttributes(); 545 foreach ($attr as $item) { 546 switch ($item['name']) { 547 case 'DTSTART': 548 if (!empty($item['params']['VALUE']) && $item['params']['VALUE'] == "DATE") { 549 $hash['AllDayEvent'] = "True"; 550 $hash['Start'] = Horde_iCalendar::_exportDateTime($item['value']); 551 $duration = 1440; 552 } else { 553 $hash['AllDayEvent'] = "False"; 554 $hash['Start'] = Horde_iCalendar::_exportDateTime($item['value']); 555 } 556 break; 557 558 case 'DTEND': 559 if (!empty($item['params']['VALUE']) && $item['params']['VALUE'] == "DATE") { 560 $hash['AllDayEvent'] = "True"; 561 $hash['End'] = Horde_iCalendar::_exportDateTime($item['value']); 562 $duration = 1440; 563 } else { 564 $hash['AllDayEvent'] = "False"; 565 $hash['End'] = Horde_iCalendar::_exportDateTime($item['value']); 566 } 567 break; 568 569 case 'SUMMARY': 570 $hash['Subject'] = $item['value']; 571 break; 572 573 case 'DESCRIPTION': 574 $hash['Body'] = $item['value']; 575 break; 576 577 case 'LOCATION': 578 $hash['Location'] = $item['value']; 579 break; 580 } 581 } 582 583 return $this->array2sif( 584 $hash, 585 '<?xml version="1.0"?><appointment><Duration>' 586 . $duration . '</Duration>', 587 '<IsRecurring>False</IsRecurring><MeetingStatus>0</MeetingStatus><BusyStatus>2</BusyStatus></appointment>'); 588 } 589 590 function vtodo2sif($vcard) 591 { 592 $iCal = &new Horde_iCalendar(); 593 if (!$iCal->parsevCalendar($vcard)) { 594 return PEAR::raiseError('There was an error importing the data.'); 595 } 596 597 $components = $iCal->getComponents(); 598 599 switch (count($components)) { 600 case 0: 601 return PEAR::raiseError('No data was found'); 602 603 case 1: 604 $content = $components[0]; 605 break; 606 607 default: 608 return PEAR::raiseError('Multiple components found; only one is supported.'); 609 } 610 611 $hash['Complete'] = 'False'; 612 // Outlook's default for no due date 613 $hash['DueDate'] = '45001231T230000Z'; 614 615 $attr = $content->getAllAttributes(); 616 foreach ($attr as $item) { 617 switch ($item['name']) { 618 case 'DUE': 619 $hash['DueDate'] = Horde_iCalendar::_exportDateTime($item['value']); 620 break; 621 622 case 'SUMMARY': 623 $hash['Subject'] = $item['value']; 624 break; 625 626 case 'DESCRIPTION': 627 $hash['Body'] = $item['value']; 628 break; 629 630 case 'PRIORITY': 631 if ($item['value'] == 1) { 632 $hash['Importance'] = 2; 633 } elseif ($item['value'] == 5) { 634 $hash['Importance'] = 0; 635 } else { 636 $hash['Importance'] = 1; 637 } 638 break; 639 640 case 'COMPLETED': 641 $hash['Complete'] = $item['value'] ? 'True' : 'False'; 642 break; 643 } 644 } 645 646 return $this->array2sif( 647 $hash, 648 '<?xml version="1.0"?><task>', 649 '</task>'); 650 } 651 652 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 18:01:28 2007 | par Balluche grâce à PHPXref 0.7 |