egroupware_official/addressbook/inc/class.addressbook_vcal.inc.php
Ralf Becker 43f860ba8f Reworked GroupDAV and iCal/vCard handler to set 'GroupDAV' as product
manufacturer and the recogniced GroupDAV client as product name.
This way we are able to handle different GroupDAV clients, as we
allready do with different SyncML clients.
Also removed the no longer needed code enabling the use of the real UID, 
as SyncML does no longer misuse the UID for it's GUID.
2008-11-03 09:36:20 +00:00

847 lines
25 KiB
PHP

<?php
/**
* Addressbook - vCard / iCal parser
*
* @link http://www.egroupware.org
* @author Lars Kneschke <lkneschke@egroupware.org>
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package addressbook
* @subpackage export
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
require_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/Horde/iCalendar.php';
/**
* Addressbook - vCard parser
*
*/
class addressbook_vcal extends addressbook_bo
{
/**
* product manufacturer from setSupportedFields (lowercase!)
*
* @var string
*/
var $productManufacturer='file';
/**
* product name from setSupportedFields (lowercase!)
*
* @var string
*/
var $productName;
/**
* import a vard into addressbook
*
* @param string $_vcard the vcard
* @param int/string $_abID=null the internal addressbook id or !$_abID for a new enty
* @return int contact id
*/
function addVCard($_vcard, $_abID)
{
if(!$contact = $this->vcardtoegw($_vcard)) {
return false;
}
if($_abID) {
// update entry
$contact['id'] = $_abID;
}
return $this->save($contact);
}
/**
* return a vcard
*
* @param int/string $_id the id of the contact
* @param string $_charset='utf-8' encoding of the vcard, default utf-8
* @param boolean $extra_charset_attribute=true GroupDAV/CalDAV dont need the charset attribute and some clients have problems with it
* @return string containing the vcard
*/
function getVCard($_id,$_charset='utf-8',$extra_charset_attribute=true)
{
require_once(EGW_SERVER_ROOT.'/phpgwapi/inc/horde/Horde/iCalendar/vcard.php');
$vCard =& new Horde_iCalendar_vcard;
if(!is_array($this->supportedFields)) {
$this->setSupportedFields();
}
$sysCharSet = $GLOBALS['egw']->translation->charset();
if(!($entry = $this->read($_id))) {
return false;
}
$this->fixup_contact($entry);
foreach($this->supportedFields as $vcardField => $databaseFields)
{
$values = array();
$options = array();
$hasdata = 0;
foreach($databaseFields as $databaseField)
{
$value = "";
if (!empty($databaseField))
{
$value = trim($entry[$databaseField]);
}
switch($databaseField)
{
case 'private':
$value = $value ? 'PRIVATE' : 'PUBLIC';
$hasdata++;
break;
case 'bday':
if (!empty($value))
{
$value = str_replace('-','',$value).'T000000Z';
$hasdata++;
}
break;
case 'jpegphoto':
if(!empty($value))
{
//error_log("PHOTO='".$value."'");
$options['ENCODING'] = 'BASE64';
$options['TYPE'] = 'JPEG';
$value = base64_encode($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) || in_array($vcardField,array('FN','ORG','N')))
{
$value = $GLOBALS['egw']->translation->convert(trim($value), $sysCharSet,$_charset);
if(($extra_charset_attribute || $this->productName == 'kde') && preg_match('/([\177-\377])/',$value))
{
$options['CHARSET'] = $_charset;
// KAddressbook requires non-ascii chars to be qprint encoded, other clients eg. nokia phones have trouble with that
if ($this->productName == 'kde')
{
$options['ENCODING'] = 'QUOTED-PRINTABLE';
}
}
elseif(preg_match('/([\000-\012\015\016\020-\037\075])/',$value))
{
$options['ENCODING'] = 'QUOTED-PRINTABLE';
}
$hasdata++;
}
break;
}
if (empty($value))
{
$value = "";
}
$values[] = $value;
}
if ($hasdata <= 0)
{
// don't add the entry if there is no data for this field,
// except it's a mendatory field
continue;
}
$vCard->setAttribute($vcardField, implode(';', $values));
$vCard->setParameter($vcardField, $options);
}
$result = $vCard->exportvCalendar();
return $result;
}
function search($_vcard)
{
if(!($contact = $this->vcardtoegw($_vcard))) {
return false;
}
unset($contact['private']);
unset($contact['note']);
unset($contact['n_fn']);
unset($contact['email']);
unset($contact['email_home']);
unset($contact['url']);
unset($contact['url_home']);
unset($contact['n_fileas']);
// some clients cut the values, because they do not support the same length of data like eGW
// at least the first 10 characters must match
$maybeCuttedFields = array('org_unit', 'org_name','title');
foreach($maybeCuttedFields as $fieldName) {
if(!empty($contact[$fieldName]) && strlen($contact[$fieldName]) > 10) {
$contact[$fieldName] .= '*';
}
}
//error_log(print_r($contact, true));
#if($foundContacts = parent::search($contact, true, '', '', '%')) {
if($foundContacts = parent::search($contact)) {
return $foundContacts[0]['id'];
}
return false;
}
function setSupportedFields($_productManufacturer='file', $_productName='')
{
// store product manufacturer and name, to be able to use it elsewhere
$this->productManufacturer = strtolower($_productManufacturer);
$this->productName = strtolower($_productName);
/**
* ToDo Lars:
* + changes / renamed fields in 1.3+:
* - access --> private (already done by Ralf)
* - tel_msg --> tel_assistent
* - tel_modem --> tel_fax_home
* - tel_isdn --> tel_cell_private
* - tel_voice/ophone --> tel_other
* - address2 --> adr_one_street2
* - address3 --> adr_two_street2
* - freebusy_url --> freebusy_uri (i instead l !)
* - fn --> n_fn
* - last_mod --> modified
* + new fields in 1.3+:
* - n_fileas
* - role
* - assistent
* - room
* - calendar_uri
* - url_home
* - created
* - creator (preset with owner)
* - modifier
* - jpegphoto
*/
$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'),
'TEL;FAX' => array('tel_fax'),
'TEL;HOME' => array('tel_home'),
'TEL;WORK' => array('tel_work'),
'TITLE' => array('title'),
);
$defaultFields[1] = array( // all entries, nexthaus corporation, groupdav, ...
'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'),
'BDAY' => array('bday'),
'CATEGORIES' => array('cat_id'),
'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'),
'PHOTO' => array('jpegphoto'),
'UID' => array('uid'),
);
$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'),
'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;WORK' => array('tel_cell'),
'TEL;FAX;WORK' => array('tel_fax'),
'TEL;HOME' => array('tel_home'),
'TEL;WORK' => array('tel_work'),
'TITLE' => array('title'),
'URL;WORK' => array('url'),
);
$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',
'adr_two_postalcode','adr_two_countryname'),
'BDAY' => array('bday'),
'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'),
'TEL;FAX;WORK' => array('tel_fax'),
'TEL;HOME' => array('tel_home'),
'TEL;PAGER;WORK' => array('tel_pager'),
'TEL;WORK' => array('tel_work'),
'TITLE' => array('title'),
'URL;WORK' => array('url'),
);
$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',
'adr_two_postalcode','adr_two_countryname'),
'BDAY' => array('bday'),
'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'),
'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'),
'URL;HOME' => array('url_home'),
);
$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',
'adr_two_postalcode','adr_two_countryname'),
'BDAY' => array('bday'),
'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'),
'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'),
'URL;HOME' => array('url_home'),
);
$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;WORK;VOICE' => array('tel_work'),
'TITLE' => array('title'),
'URL;WORK' => array('url'),
'URL' => array('url_home'),
);
$defaultFields[7] = array( // SyncEvolution
'N'=> array('n_family','n_given','n_middle','n_prefix','n_suffix'),
'TITLE' => array('title'),
'ROLE' => array('role'),
'ORG' => array('org_name','org_unit','room'),
'ADR;WORK' => array('','adr_one_street2','adr_one_street','adr_one_locality','adr_one_region', 'adr_one_postalcode','adr_one_countryname'),
'ADR;HOME' => array('','adr_two_street2','adr_two_street','adr_two_locality','adr_two_region', 'adr_two_postalcode','adr_two_countryname'),
'TEL;WORK;VOICE' => array('tel_work'),
'TEL;HOME;VOICE' => array('tel_home'),
'TEL;CELL;WORK' => array('tel_cell'),
'TEL;FAX;WORK' => array('tel_fax'),
'TEL;FAX;HOME' => array('tel_fax_home'),
'TEL;PAGER;WORK' => array('tel_pager'),
'TEL;CAR' => array('tel_car'),
'TEL;VOICE' => array('tel_other'),
'EMAIL;INTERNET;WORK' => array('email'),
'EMAIL;INTERNET;HOME' => array('email_home'),
'URL;WORK' => array('url'),
'BDAY' => array('bday'),
'CATEGORIES' => array('cat_id'),
'NOTE' => array('note'),
'X-EVOLUTION-ASSISTANT' => array('assistent'),
'PHOTO' => array('jpegphoto'),
);
$defaultFields[8] = array_merge($defaultFields[1],array( // KDE Addressbook, only changes from all=1
'ORG' => array('org_name'),
'X-KADDRESSBOOK-X-Department' => array('org_unit'),
'PHOTO' => array('jpegphoto'),
));
$defaultFields[9] = array( // nokia e90
'ADR;WORK' => array('','adr_one_street2','adr_one_street','adr_one_locality','adr_one_region',
'adr_one_postalcode','adr_one_countryname'),
'ADR;HOME' => array('','adr_two_street2','adr_two_street','adr_two_locality','adr_two_region',
'adr_two_postalcode','adr_two_countryname'),
'BDAY' => array('bday'),
'X-CLASS' => array('private'),
'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;CAR' => array('tel_car'),
'TEL;PAGER;WORK' => array('tel_pager'),
'TEL;VOICE;WORK' => array('tel_work'),
'TEL;VOICE;HOME' => array('tel_home'),
'TITLE' => array('title'),
'URL;WORK' => array('url'),
'URL;HOME' => array('url_home'),
'X-ASSISTANT' => array('assistent'),
'X-ASSISTANT-TEL' => array('tel_assistent'),
'PHOTO' => array('jpegphoto'),
);
$defaultFields[10] = array( // nokia 9300
'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'),
'BDAY' => array('bday'),
'EMAIL;INTERNET' => array('email'),
'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' => array('tel_cell'),
'TEL;WORK;FAX' => array('tel_fax'),
'TEL;FAX' => array('tel_fax_home'),
'TEL;PAGER' => array('tel_pager'),
'TEL;WORK;VOICE' => array('tel_work'),
'TEL;HOME;VOICE' => array('tel_home'),
'TITLE' => array('contact_role'),
'URL' => array('url'),
);
$defaultFields[11] = array( // funambol: iphone
'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;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' => array('tel_cell'),
'TEL;HOME;FAX' => array('tel_fax_home'),
'TEL;WORK;FAX' => array('tel_fax'),
'TEL;VOICE;HOME' => array('tel_home'),
'TEL;VOICE;WORK' => array('tel_work'),
'TEL;PAGER' => array('tel_pager'),
'TEL;CAR' => array('tel_car'),
'TITLE' => array('title'),
'URL;WORK' => array('url'),
'URL;HOME' => array('url_home'),
'PHOTO' => array('jpegphoto'),
);
//error_log("Client: $_productManufacturer $_productName");
switch($this->productManufacturer)
{
case 'funambol':
case 'funambol inc.':
switch ($this->productName)
{
case 'thunderbird':
$this->supportedFields = $defaultFields[6];
break;
case 'iphone':
$this->supportedFields = $defaultFields[11];
break;
default:
error_log("Funambol product '$_productName', assuming same as thunderbird");
$this->supportedFields = $defaultFields[6];
break;
}
break;
case 'nexthaus corporation':
case 'nexthaus corp':
switch($this->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;
}
break;
case 'nokia':
switch($this->productName)
{
case 'e61':
$this->supportedFields = $defaultFields[5];
break;
case 'e51':
case 'e90':
case 'e71':
$this->supportedFields = $defaultFields[9];
break;
case '9300':
$this->supportedFields = $defaultFields[10];
break;
case '6600':
$this->supportedFields = $defaultFields[4];
break;
default:
error_log("Unknown Nokia phone '$_productName', assuming same as '6600'");
$this->supportedFields = $defaultFields[4];
break;
}
break;
// multisync does not provide anymore information then the manufacturer
// we suppose multisync with evolution
case 'the multisync project':
switch($this->productName)
{
default:
$this->supportedFields = $defaultFields[0];
break;
}
break;
case 'siemens':
switch($this->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($this->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;
}
break;
case 'synthesis ag':
switch($this->productName)
{
case 'sysync client pocketpc pro':
case 'sysync client pocketpc std':
$this->supportedFields = $defaultFields[1];
#$this->supportedFields['PHOTO'] = array('jpegphoto');
break;
default:
error_log("Synthesis connector '$_productName', using default fields");
$this->supportedFields = $defaultFields[0];
break;
}
break;
case 'patrick ohly': // SyncEvolution
$this->supportedFields = $defaultFields[7];
break;
case 'file': // used outside of SyncML, eg. by the calendar itself ==> all possible fields
$this->supportedFields = $defaultFields[1];
break;
case 'groupdav': // all GroupDAV access goes through here
switch($this->productName)
{
case 'kde': // KDE Addressbook
$this->supportedFields = $defaultFields[8];
break;
default:
$this->supportedFields = $defaultFields[1];
}
break;
// the fallback for SyncML
default:
error_log("Client not found: '$_productManufacturer' '$_productName'");
$this->supportedFields = $defaultFields[0];
break;
}
}
function vcardtoegw($_vcard)
{
// the horde class does the charset conversion. DO NOT CONVERT HERE.
if(!is_array($this->supportedFields))
{
$this->setSupportedFields();
}
require_once(EGW_SERVER_ROOT.'/phpgwapi/inc/horde/Horde/iCalendar.php');
$vCard = Horde_iCalendar::newComponent('vcard', $container);
// Unfold any folded lines.
$vCardUnfolded = preg_replace ('/(\r|\n)+ /', ' ', $_vcard);
if(!$vCard->parsevCalendar($vCardUnfolded, 'VCARD'))
{
return False;
}
$vcardValues = $vCard->getAllAttributes();
#print "<pre>$_vcard</pre>";
#error_log(print_r($vcardValues, true));
foreach($vcardValues as $key => $vcardRow)
{
$rowName = $vcardRow['name'];
$vcardElementCount = count($vcardRow['params'],COUNT_RECURSIVE);
if( $vcardElementCount > 0 )
{
foreach($vcardRow['params'] as $VKey => $vcardParam)
{
if( ! strlen($vcardParam) )
{
$rowName .= ';'.$VKey;
}
if( $VKey == 'TYPE' && in_array(strtoupper($vcardParam),array('CELL','FAX','PAGER','WORK','HOME','VOICE','CAR')))
{
$rowName .= ';'.strtoupper($vcardParam);
}
}
}
$rowNames[$rowName] = $key;
}
#error_log(print_r($rowNames, true));
// now we have all rowNames the vcard provides
// we just need to map to the right addressbook fieldnames
// we need also to take care about ADR for example. we do not
// support this. We support only ADR;WORK or ADR;HOME
foreach($rowNames as $rowName => $vcardKey)
{
switch($rowName)
{
case 'ADR':
case 'TEL':
case 'URL':
case 'TEL;FAX':
case 'TEL;CELL':
case 'TEL;PAGER':
case 'TEL;VOICE':
if(!isset($rowNames[$rowName. ';WORK']) && array_key_exists($rowName. ';WORK', $this->supportedFields) )
{
$finalRowNames[$rowName. ';WORK'] = $vcardKey;
}
else
{
$InvolvedValues = explode(';',$rowName.';WORK');
foreach($this->supportedFields as $suppFields => $suppFieldsValue )
{
$InvolvedHits = 0;
foreach($InvolvedValues as $hlparr => $hlparrKey )
{
if( ! stristr( $suppFields,$hlparrKey ) === FALSE )
{
$InvolvedHits++;
}
}
if( count($InvolvedValues) == $InvolvedHits && !isset($finalRowNames[$suppFields]) )
{
$finalRowNames[$suppFields] = $vcardKey;
break; // if a combination of all words in $InvolvedValues were found
}
}
if( count($InvolvedValues) != $InvolvedHits && ! isset($finalRowNames[$rowName]) && array_key_exists($rowName, $this->supportedFields) )
{
$finalRowNames[$rowName] = $vcardKey;
}
}
break;
case 'EMAIL':
case 'EMAIL;WORK':
case 'EMAIL;INTERNET':
if(!isset($rowNames['EMAIL;INTERNET;WORK']))
{
$finalRowNames['EMAIL;INTERNET;WORK'] = $vcardKey;
}
break;
case 'EMAIL;HOME':
if(!isset($rowNames['EMAIL;INTERNET;HOME']))
{
$finalRowNames['EMAIL;INTERNET;HOME'] = $vcardKey;
}
break;
case 'VERSION':
break;
default:
$finalRowNames[$rowName] = $vcardKey;
break;
}
}
#error_log(print_r($finalRowNames, true));
$contact = array();
foreach($finalRowNames as $key => $vcardKey)
{
if(isset($this->supportedFields[$key]))
{
$fieldNames = $this->supportedFields[$key];
foreach($fieldNames as $fieldKey => $fieldName)
{
if(!empty($fieldName))
{
if ($fieldName == 'jpegphoto' || $vcardValues[$vcardKey]['params']['ENCODING'] == 'b')
{
$value = base64_decode($vcardValues[$vcardKey]['values'][$fieldKey]);
}
else
{
$value = trim($vcardValues[$vcardKey]['values'][$fieldKey]);
}
switch($fieldName)
{
case 'bday':
if(!empty($value)) {
$contact[$fieldName] = date('Y-m-d', $value);
}
break;
case 'private':
$contact[$fieldName] = (int) ( strtoupper($value) == 'PRIVATE');
break;
case '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;
default:
$contact[$fieldName] = $value;
break;
}
}
}
}
}
$this->fixup_contact($contact);
return $contact;
}
/**
* Exports some contacts: download or write to a file
*
* @param array $ids contact-ids
* @param string $file filename or null for download
*/
function export($ids,$file=null)
{
if (!$file)
{
$browser =& CreateObject('phpgwapi.browser');
$browser->content_header('addressbook.vcf','text/x-vcard');
}
if (!($fp = fopen($file ? $file : 'php://output','w')))
{
return false;
}
foreach($ids as $id)
{
fwrite($fp,$this->getVCard($id));
}
fclose($fp);
if (!$file)
{
$GLOBALS['egw']->common->egw_exit();
}
return true;
}
}