2013-03-13 04:10:06 +01:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* ownCloud - JSONSerializer
|
|
|
|
*
|
2014-01-26 00:40:22 +01:00
|
|
|
* @author Thomas Tanghus
|
|
|
|
* @copyright 2013-2014 Thomas Tanghus (thomas@tanghus.net)
|
2013-03-13 04:10:06 +01:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 3 of the License, or any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public
|
|
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace OCA\Contacts\Utils;
|
|
|
|
|
|
|
|
use OCA\Contacts\VObject;
|
2013-11-07 14:06:12 +01:00
|
|
|
use OCA\Contacts\Contact,
|
|
|
|
OCA\Contacts\Utils\Properties;
|
2013-03-13 04:10:06 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This class serializes properties, components an
|
|
|
|
* arrays of components into a format suitable for
|
|
|
|
* passing to a JSON response.
|
2013-03-25 17:10:21 +01:00
|
|
|
* TODO: Return jCard (almost) compliant data, but still omitting unneeded data.
|
|
|
|
* http://tools.ietf.org/html/draft-kewisch-vcard-in-json-01
|
2013-03-13 04:10:06 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
class JSONSerializer {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* General method serialize method. Use this for arrays
|
|
|
|
* of contacts.
|
|
|
|
*
|
2013-03-16 15:57:22 +01:00
|
|
|
* @param Contact[] $input
|
2013-03-13 04:10:06 +01:00
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public static function serialize($input) {
|
|
|
|
$response = array();
|
|
|
|
if(is_array($input)) {
|
|
|
|
foreach($input as $object) {
|
2013-03-16 15:57:22 +01:00
|
|
|
if($object instanceof Contact) {
|
|
|
|
\OCP\Util::writeLog('contacts', __METHOD__.' serializing: ' . print_r($object, true), \OCP\Util::DEBUG);
|
|
|
|
$tmp = self::serializeContact($object);
|
|
|
|
if($tmp !== null) {
|
|
|
|
$response[] = $tmp;
|
|
|
|
}
|
2013-03-13 04:10:06 +01:00
|
|
|
} else {
|
|
|
|
throw new \Exception(
|
|
|
|
'Only arrays of OCA\\Contacts\\VObject\\VCard '
|
|
|
|
. 'and Sabre\VObject\Property are accepted.'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if($input instanceof VObject\VCard) {
|
|
|
|
return self::serializeContact($input);
|
|
|
|
} elseif($input instanceof Sabre\VObject\Property) {
|
|
|
|
return self::serializeProperty($input);
|
|
|
|
} else {
|
|
|
|
throw new \Exception(
|
|
|
|
'Only instances of OCA\\Contacts\\VObject\\VCard '
|
|
|
|
. 'and Sabre\VObject\Property are accepted.'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Data structure of vCard
|
2013-03-16 15:57:22 +01:00
|
|
|
* @param VObject\VCard $contact
|
|
|
|
* @return associative array|null
|
2013-03-13 04:10:06 +01:00
|
|
|
*/
|
2013-03-16 15:57:22 +01:00
|
|
|
public static function serializeContact(Contact $contact) {
|
|
|
|
|
|
|
|
if(!$contact->retrieve()) {
|
|
|
|
\OCP\Util::writeLog('contacts', __METHOD__.' error reading: ' . print_r($contact, true), \OCP\Util::DEBUG);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-03-13 04:10:06 +01:00
|
|
|
$details = array();
|
|
|
|
|
2013-04-04 17:00:22 +02:00
|
|
|
if(isset($contact->PHOTO) || isset($contact->LOGO)) {
|
2014-01-26 03:22:49 +01:00
|
|
|
$details['photo'] = true;
|
2013-11-07 14:06:12 +01:00
|
|
|
$details['thumbnail'] = Properties::cacheThumbnail(
|
|
|
|
$contact->getBackend()->name,
|
|
|
|
$contact->getParent()->getId(),
|
|
|
|
$contact->getId(),
|
|
|
|
null,
|
|
|
|
$contact
|
|
|
|
);
|
2013-04-04 17:00:22 +02:00
|
|
|
}
|
|
|
|
|
2013-04-04 02:53:17 +02:00
|
|
|
foreach($contact->children as $property) {
|
2013-03-13 04:10:06 +01:00
|
|
|
$pname = $property->name;
|
|
|
|
$temp = self::serializeProperty($property);
|
|
|
|
if(!is_null($temp)) {
|
|
|
|
// Get Apple X-ABLabels
|
2013-03-16 15:57:22 +01:00
|
|
|
if(isset($contact->{$property->group . '.X-ABLABEL'})) {
|
|
|
|
$temp['label'] = $contact->{$property->group . '.X-ABLABEL'}->value;
|
2013-03-13 04:10:06 +01:00
|
|
|
if($temp['label'] == '_$!<Other>!$_') {
|
2013-03-16 15:57:22 +01:00
|
|
|
$temp['label'] = Properties::$l10n->t('Other');
|
2013-03-13 04:10:06 +01:00
|
|
|
}
|
|
|
|
if($temp['label'] == '_$!<HomePage>!$_') {
|
2013-03-16 15:57:22 +01:00
|
|
|
$temp['label'] = Properties::$l10n->t('HomePage');
|
2013-03-13 04:10:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if(array_key_exists($pname, $details)) {
|
|
|
|
$details[$pname][] = $temp;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
$details[$pname] = array($temp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-03-16 15:57:22 +01:00
|
|
|
return array('data' =>$details, 'metadata' => $contact->getMetaData());
|
2013-03-13 04:10:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-03-16 15:57:22 +01:00
|
|
|
* @brief Get data structure of property.
|
2013-03-13 04:10:06 +01:00
|
|
|
* @param \Sabre\VObject\Property $property
|
|
|
|
* @return associative array
|
|
|
|
*
|
|
|
|
* returns an associative array with
|
|
|
|
* ['name'] name of property
|
|
|
|
* ['value'] htmlspecialchars escaped value of property
|
|
|
|
* ['parameters'] associative array name=>value
|
|
|
|
* ['checksum'] checksum of whole property
|
|
|
|
* NOTE: $value is not escaped anymore. It shouldn't make any difference
|
|
|
|
* but we should look out for any problems.
|
|
|
|
*/
|
|
|
|
public static function serializeProperty(\Sabre\VObject\Property $property) {
|
2013-03-16 15:57:22 +01:00
|
|
|
if(!in_array($property->name, Properties::$index_properties)) {
|
2013-03-13 04:10:06 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
$value = $property->value;
|
|
|
|
if($property->name == 'ADR' || $property->name == 'N' || $property->name == 'ORG' || $property->name == 'CATEGORIES') {
|
|
|
|
$value = $property->getParts();
|
|
|
|
$value = array_map('trim', $value);
|
|
|
|
}
|
|
|
|
elseif($property->name == 'BDAY') {
|
2014-02-04 22:23:36 +01:00
|
|
|
// If the BDAY has a format of e.g. 19960401
|
|
|
|
if(strlen($value) >= 8
|
|
|
|
&& is_int(substr($value, 0, 4))
|
|
|
|
&& is_int(substr($value, 4, 2))
|
|
|
|
&& is_int(substr($value, 6, 2))) {
|
|
|
|
$value = substr($value, 0, 4).'-'.substr($value, 4, 2).'-'.substr($value, 6, 2);
|
|
|
|
} else if($value[5] !== '-' || $value[7] !== '-') {
|
|
|
|
try {
|
|
|
|
// Skype exports as e.g. Jan 14, 1996
|
|
|
|
$date = new \DateTime($value);
|
|
|
|
$value = $date->format('Y-m-d');
|
|
|
|
} catch(\Exception $e) {
|
|
|
|
\OCP\Util::writeLog('contacts', __METHOD__.' Error parsing date: ' . $value, \OCP\Util::DEBUG);
|
|
|
|
return;
|
2013-03-13 04:10:06 +01:00
|
|
|
}
|
|
|
|
}
|
2014-02-04 22:23:36 +01:00
|
|
|
// Otherwise we assume it's OK.
|
2013-03-13 04:10:06 +01:00
|
|
|
} elseif($property->name == 'PHOTO') {
|
|
|
|
$value = true;
|
|
|
|
}
|
|
|
|
elseif($property->name == 'IMPP') {
|
|
|
|
if(strpos($value, ':') !== false) {
|
|
|
|
$value = explode(':', $value);
|
|
|
|
$protocol = array_shift($value);
|
|
|
|
if(!isset($property['X-SERVICE-TYPE'])) {
|
2013-03-29 18:06:10 +01:00
|
|
|
$property['X-SERVICE-TYPE'] = strtoupper($protocol);
|
2013-03-13 04:10:06 +01:00
|
|
|
}
|
|
|
|
$value = implode('', $value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(is_string($value)) {
|
|
|
|
$value = strtr($value, array('\,' => ',', '\;' => ';'));
|
|
|
|
}
|
|
|
|
$temp = array(
|
|
|
|
//'name' => $property->name,
|
2013-03-29 18:06:10 +01:00
|
|
|
'value' => $value,
|
2013-03-13 04:10:06 +01:00
|
|
|
'parameters' => array()
|
|
|
|
);
|
|
|
|
|
|
|
|
// This cuts around a 3rd off of the json response size.
|
2013-03-16 15:57:22 +01:00
|
|
|
if(in_array($property->name, Properties::$multi_properties)) {
|
2013-03-13 04:10:06 +01:00
|
|
|
$temp['checksum'] = substr(md5($property->serialize()), 0, 8);
|
|
|
|
}
|
|
|
|
foreach($property->parameters as $parameter) {
|
|
|
|
// Faulty entries by kaddressbook
|
|
|
|
// Actually TYPE=PREF is correct according to RFC 2426
|
|
|
|
// but this way is more handy in the UI. Tanghus.
|
|
|
|
if($parameter->name == 'TYPE' && strtoupper($parameter->value) == 'PREF') {
|
|
|
|
$parameter->name = 'PREF';
|
|
|
|
$parameter->value = '1';
|
|
|
|
}
|
|
|
|
// NOTE: Apparently Sabre_VObject_Reader can't always deal with value list parameters
|
|
|
|
// like TYPE=HOME,CELL,VOICE. Tanghus.
|
|
|
|
// TODO: Check if parameter is has commas and split + merge if so.
|
|
|
|
if ($parameter->name == 'TYPE') {
|
|
|
|
$pvalue = $parameter->value;
|
|
|
|
if(is_string($pvalue) && strpos($pvalue, ',') !== false) {
|
|
|
|
$pvalue = array_map('trim', explode(',', $pvalue));
|
|
|
|
}
|
|
|
|
$pvalue = is_array($pvalue) ? $pvalue : array($pvalue);
|
|
|
|
if (isset($temp['parameters'][$parameter->name])) {
|
|
|
|
$temp['parameters'][$parameter->name][] = \OCP\Util::sanitizeHTML($pvalue);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$temp['parameters'][$parameter->name] = \OCP\Util::sanitizeHTML($pvalue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
$temp['parameters'][$parameter->name] = \OCP\Util::sanitizeHTML($parameter->value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $temp;
|
|
|
|
}
|
|
|
|
}
|