2013-09-20 16:24:29 +02:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* ownCloud - VCard Import connector
|
|
|
|
*
|
|
|
|
* @author Nicolas Mora
|
|
|
|
* @copyright 2014 Nicolas Mora mail@babelouest.org
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
* version 3 of the License
|
|
|
|
*
|
|
|
|
* 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\Connector;
|
|
|
|
|
|
|
|
use Sabre\VObject\Component,
|
|
|
|
Sabre\VObject\StringUtil,
|
|
|
|
\SplFileObject as SplFileObject,
|
|
|
|
Sabre\VObject;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Implementation of the VCard import format
|
|
|
|
*/
|
|
|
|
class ImportVCardConnector extends ImportConnector{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief separates elements from the input stream according to the entry_separator value in config
|
|
|
|
* ignoring the first line if mentionned in the config
|
|
|
|
* @param $input the input file to import
|
|
|
|
* @param $limit the number of elements to return (-1 = no limit)
|
|
|
|
* @return array of strings
|
|
|
|
*/
|
|
|
|
public function getElementsFromInput($file, $limit=-1) {
|
|
|
|
|
|
|
|
$parts = $this->getSourceElementsFromFile($file, $limit);
|
|
|
|
|
|
|
|
$elements = array();
|
|
|
|
foreach($parts as $part) {
|
2014-05-07 22:54:58 +02:00
|
|
|
$converted = $this->convertElementToVCard($part);
|
|
|
|
if ($converted) {
|
|
|
|
$elements[] = $converted;
|
|
|
|
}
|
2013-09-20 16:24:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return array_values($elements);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief parses the file in vcard format
|
|
|
|
* @param $file the input file to import
|
|
|
|
* @param $limit the number of elements to return (-1 = no limit)
|
|
|
|
* @return array()
|
|
|
|
*/
|
|
|
|
private function getSourceElementsFromFile($file, $limit=-1) {
|
|
|
|
$file = StringUtil::convertToUTF8(file_get_contents($file));
|
|
|
|
|
|
|
|
$nl = "\n";
|
2014-03-21 06:59:19 +01:00
|
|
|
$replaceFrom = array("\r","\n\n");
|
|
|
|
$replaceTo = array("\n","\n");
|
2013-09-20 16:24:29 +02:00
|
|
|
foreach ($this->configContent->import_core->replace as $replace) {
|
|
|
|
if (isset($replace['from']) && isset($replace['to'])) {
|
2014-03-21 06:59:19 +01:00
|
|
|
$replaceFrom[] = $replace['from'];
|
|
|
|
$replaceTo[] = $replace['to'];
|
2013-09-20 16:24:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-21 06:59:19 +01:00
|
|
|
$file = str_replace($replaceFrom, $replaceTo, $file);
|
2013-09-20 16:24:29 +02:00
|
|
|
|
|
|
|
$lines = explode($nl, $file);
|
|
|
|
$inelement = false;
|
|
|
|
$parts = array();
|
|
|
|
$card = array();
|
|
|
|
$numParts = 0;
|
|
|
|
foreach($lines as $line) {
|
|
|
|
if(strtoupper(trim($line)) == (string)$this->configContent->import_core->card_begin) {
|
|
|
|
$inelement = true;
|
|
|
|
} elseif (strtoupper(trim($line)) == (string)$this->configContent->import_core->card_end) {
|
|
|
|
$card[] = $line;
|
|
|
|
$parts[] = implode($nl, $card);
|
|
|
|
$card = array();
|
|
|
|
$inelement = false;
|
|
|
|
$numParts++;
|
|
|
|
if ($numParts == $limit) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($inelement === true && trim($line) != '') {
|
|
|
|
$card[] = $line;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $parts;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief converts a VCard into a owncloud VCard
|
|
|
|
* @param $element the VCard element to convert
|
2014-05-07 22:54:58 +02:00
|
|
|
* @return VCard|false
|
2013-09-20 16:24:29 +02:00
|
|
|
*/
|
|
|
|
public function convertElementToVCard($element) {
|
2014-05-07 22:54:58 +02:00
|
|
|
try {
|
|
|
|
$source = VObject\Reader::read($element, VObject\Reader::OPTION_FORGIVING);
|
|
|
|
} catch (VObject\ParseException $error) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-02-16 18:42:41 +01:00
|
|
|
$dest = new \OCA\Contacts\VObject\VCard();
|
2013-09-20 16:24:29 +02:00
|
|
|
|
|
|
|
foreach ($source->children() as $sourceProperty) {
|
|
|
|
$importEntry = $this->getImportEntry($sourceProperty, $source);
|
|
|
|
if ($importEntry) {
|
2015-02-16 18:42:41 +01:00
|
|
|
$value = $sourceProperty->getValue();
|
2013-09-20 16:24:29 +02:00
|
|
|
if (isset($importEntry['remove'])) {
|
2015-02-16 18:42:41 +01:00
|
|
|
$value = str_replace($importEntry['remove'], '', $sourceProperty->getValue());
|
2013-09-20 16:24:29 +02:00
|
|
|
}
|
|
|
|
$values = array($value);
|
|
|
|
if (isset($importEntry['separator'])) {
|
|
|
|
$values = explode($importEntry['separator'], $value);
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($values as $oneValue) {
|
|
|
|
if (isset($importEntry->vcard_favourites)) {
|
|
|
|
foreach ($importEntry->vcard_favourites as $vcardFavourite) {
|
|
|
|
if (strcasecmp((string)$vcardFavourite, trim($oneValue)) == 0) {
|
2015-02-16 18:42:41 +01:00
|
|
|
$property = $dest->createProperty("X-FAVOURITES", 'yes');
|
2013-09-20 16:24:29 +02:00
|
|
|
$dest->add($property);
|
|
|
|
} else {
|
|
|
|
$property = $this->getOrCreateVCardProperty($dest, $importEntry->vcard_entry);
|
|
|
|
$this->updateProperty($property, $importEntry, trim($oneValue));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$property = $this->getOrCreateVCardProperty($dest, $importEntry->vcard_entry);
|
2015-02-16 18:42:41 +01:00
|
|
|
$this->updateProperty($property, $importEntry, $sourceProperty->getValue());
|
2013-09-20 16:24:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$property = clone $sourceProperty;
|
|
|
|
$dest->add($property);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$dest->validate(\Sabre\VObject\Component\VCard::REPAIR);
|
|
|
|
return $dest;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief tests if the property has to be translated by looking for its signature in the xml configuration
|
|
|
|
* @param $property Sabre VObject Property too look
|
|
|
|
* @param $vcard the parent Sabre VCard object to look for a
|
|
|
|
*/
|
|
|
|
private function getImportEntry($property, $vcard) {
|
2014-03-21 06:59:19 +01:00
|
|
|
$nbElt = $this->configContent->import_entry->count();
|
|
|
|
for ($i=0; $i < $nbElt; $i++) {
|
2013-09-20 16:24:29 +02:00
|
|
|
if ($this->configContent->import_entry[$i]['property'] == $property->name && $this->configContent->import_entry[$i]['enabled'] == 'true') {
|
|
|
|
if (isset($this->configContent->import_entry[$i]->group_entry)) {
|
|
|
|
$numElt = 0;
|
|
|
|
foreach($this->configContent->import_entry[$i]->group_entry as $groupEntry) {
|
|
|
|
$sourceGroupList = $vcard->select($groupEntry['property']);
|
|
|
|
if (count($sourceGroupList>0)) {
|
|
|
|
foreach ($sourceGroupList as $oneSourceGroup) {
|
2015-02-16 18:42:41 +01:00
|
|
|
if ($oneSourceGroup->getValue() == $groupEntry['value'] && isset($oneSourceGroup->group) && isset($property->group) && $oneSourceGroup->group == $property->group) {
|
2013-09-20 16:24:29 +02:00
|
|
|
$numElt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($numElt == count($this->configContent->import_entry[$i]->group_entry)) {
|
|
|
|
return $this->configContent->import_entry[$i];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return $this->configContent->import_entry[$i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief returns the probability that the first element is a match for this format
|
|
|
|
* @param $file the file to examine
|
|
|
|
* @return 0 if not a valid vcard
|
|
|
|
* 1-0.5^(number of translated elements+1)
|
|
|
|
* The more the first element has parameters to translate, the more the result is close to 1
|
|
|
|
*/
|
|
|
|
public function getFormatMatch($file) {
|
|
|
|
// Examining the first element only
|
|
|
|
$parts = $this->getSourceElementsFromFile($file, 1);
|
|
|
|
|
2015-01-29 15:42:22 +01:00
|
|
|
if (!$parts || ($parts && count($parts[0]) == 0)) {
|
2013-09-20 16:24:29 +02:00
|
|
|
// Doesn't look like a vcf file
|
|
|
|
return 0;
|
|
|
|
} else {
|
2014-12-06 22:57:00 +01:00
|
|
|
$element = $this->convertElementToVCard($parts[0]);
|
2015-02-10 20:43:23 +01:00
|
|
|
if ($element) {
|
|
|
|
$unknownElements = $element->select("X-Unknown-Element");
|
|
|
|
return (1 - (0.5 * count($unknownElements)/count($parts[0])));
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
2013-09-20 16:24:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
?>
|