aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/sabre/vobject/lib/VCardConverter.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/sabre/vobject/lib/VCardConverter.php')
-rw-r--r--vendor/sabre/vobject/lib/VCardConverter.php467
1 files changed, 467 insertions, 0 deletions
diff --git a/vendor/sabre/vobject/lib/VCardConverter.php b/vendor/sabre/vobject/lib/VCardConverter.php
new file mode 100644
index 000000000..1f6d016f1
--- /dev/null
+++ b/vendor/sabre/vobject/lib/VCardConverter.php
@@ -0,0 +1,467 @@
+<?php
+
+namespace Sabre\VObject;
+
+/**
+ * This utility converts vcards from one version to another.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class VCardConverter {
+
+ /**
+ * Converts a vCard object to a new version.
+ *
+ * targetVersion must be one of:
+ * Document::VCARD21
+ * Document::VCARD30
+ * Document::VCARD40
+ *
+ * Currently only 3.0 and 4.0 as input and output versions.
+ *
+ * 2.1 has some minor support for the input version, it's incomplete at the
+ * moment though.
+ *
+ * If input and output version are identical, a clone is returned.
+ *
+ * @param Component\VCard $input
+ * @param int $targetVersion
+ */
+ function convert(Component\VCard $input, $targetVersion) {
+
+ $inputVersion = $input->getDocumentType();
+ if ($inputVersion === $targetVersion) {
+ return clone $input;
+ }
+
+ if (!in_array($inputVersion, [Document::VCARD21, Document::VCARD30, Document::VCARD40])) {
+ throw new \InvalidArgumentException('Only vCard 2.1, 3.0 and 4.0 are supported for the input data');
+ }
+ if (!in_array($targetVersion, [Document::VCARD30, Document::VCARD40])) {
+ throw new \InvalidArgumentException('You can only use vCard 3.0 or 4.0 for the target version');
+ }
+
+ $newVersion = $targetVersion === Document::VCARD40 ? '4.0' : '3.0';
+
+ $output = new Component\VCard([
+ 'VERSION' => $newVersion,
+ ]);
+
+ // We might have generated a default UID. Remove it!
+ unset($output->UID);
+
+ foreach ($input->children() as $property) {
+
+ $this->convertProperty($input, $output, $property, $targetVersion);
+
+ }
+
+ return $output;
+
+ }
+
+ /**
+ * Handles conversion of a single property.
+ *
+ * @param Component\VCard $input
+ * @param Component\VCard $output
+ * @param Property $property
+ * @param int $targetVersion
+ *
+ * @return void
+ */
+ protected function convertProperty(Component\VCard $input, Component\VCard $output, Property $property, $targetVersion) {
+
+ // Skipping these, those are automatically added.
+ if (in_array($property->name, ['VERSION', 'PRODID'])) {
+ return;
+ }
+
+ $parameters = $property->parameters();
+ $valueType = null;
+ if (isset($parameters['VALUE'])) {
+ $valueType = $parameters['VALUE']->getValue();
+ unset($parameters['VALUE']);
+ }
+ if (!$valueType) {
+ $valueType = $property->getValueType();
+ }
+ $newProperty = $output->createProperty(
+ $property->name,
+ $property->getParts(),
+ [], // parameters will get added a bit later.
+ $valueType
+ );
+
+
+ if ($targetVersion === Document::VCARD30) {
+
+ if ($property instanceof Property\Uri && in_array($property->name, ['PHOTO', 'LOGO', 'SOUND'])) {
+
+ $newProperty = $this->convertUriToBinary($output, $newProperty);
+
+ } elseif ($property instanceof Property\VCard\DateAndOrTime) {
+
+ // In vCard 4, the birth year may be optional. This is not the
+ // case for vCard 3. Apple has a workaround for this that
+ // allows applications that support Apple's extension still
+ // omit birthyears in vCard 3, but applications that do not
+ // support this, will just use a random birthyear. We're
+ // choosing 1604 for the birthyear, because that's what apple
+ // uses.
+ $parts = DateTimeParser::parseVCardDateTime($property->getValue());
+ if (is_null($parts['year'])) {
+ $newValue = '1604-' . $parts['month'] . '-' . $parts['date'];
+ $newProperty->setValue($newValue);
+ $newProperty['X-APPLE-OMIT-YEAR'] = '1604';
+ }
+
+ if ($newProperty->name == 'ANNIVERSARY') {
+ // Microsoft non-standard anniversary
+ $newProperty->name = 'X-ANNIVERSARY';
+
+ // We also need to add a new apple property for the same
+ // purpose. This apple property needs a 'label' in the same
+ // group, so we first need to find a groupname that doesn't
+ // exist yet.
+ $x = 1;
+ while ($output->select('ITEM' . $x . '.')) {
+ $x++;
+ }
+ $output->add('ITEM' . $x . '.X-ABDATE', $newProperty->getValue(), ['VALUE' => 'DATE-AND-OR-TIME']);
+ $output->add('ITEM' . $x . '.X-ABLABEL', '_$!<Anniversary>!$_');
+ }
+
+ } elseif ($property->name === 'KIND') {
+
+ switch (strtolower($property->getValue())) {
+ case 'org' :
+ // vCard 3.0 does not have an equivalent to KIND:ORG,
+ // but apple has an extension that means the same
+ // thing.
+ $newProperty = $output->createProperty('X-ABSHOWAS', 'COMPANY');
+ break;
+
+ case 'individual' :
+ // Individual is implicit, so we skip it.
+ return;
+
+ case 'group' :
+ // OS X addressbook property
+ $newProperty = $output->createProperty('X-ADDRESSBOOKSERVER-KIND', 'GROUP');
+ break;
+ }
+
+
+ }
+
+ } elseif ($targetVersion === Document::VCARD40) {
+
+ // These properties were removed in vCard 4.0
+ if (in_array($property->name, ['NAME', 'MAILER', 'LABEL', 'CLASS'])) {
+ return;
+ }
+
+ if ($property instanceof Property\Binary) {
+
+ $newProperty = $this->convertBinaryToUri($output, $newProperty, $parameters);
+
+ } elseif ($property instanceof Property\VCard\DateAndOrTime && isset($parameters['X-APPLE-OMIT-YEAR'])) {
+
+ // If a property such as BDAY contained 'X-APPLE-OMIT-YEAR',
+ // then we're stripping the year from the vcard 4 value.
+ $parts = DateTimeParser::parseVCardDateTime($property->getValue());
+ if ($parts['year'] === $property['X-APPLE-OMIT-YEAR']->getValue()) {
+ $newValue = '--' . $parts['month'] . '-' . $parts['date'];
+ $newProperty->setValue($newValue);
+ }
+
+ // Regardless if the year matched or not, we do need to strip
+ // X-APPLE-OMIT-YEAR.
+ unset($parameters['X-APPLE-OMIT-YEAR']);
+
+ }
+ switch ($property->name) {
+ case 'X-ABSHOWAS' :
+ if (strtoupper($property->getValue()) === 'COMPANY') {
+ $newProperty = $output->createProperty('KIND', 'ORG');
+ }
+ break;
+ case 'X-ADDRESSBOOKSERVER-KIND' :
+ if (strtoupper($property->getValue()) === 'GROUP') {
+ $newProperty = $output->createProperty('KIND', 'GROUP');
+ }
+ break;
+ case 'X-ANNIVERSARY' :
+ $newProperty->name = 'ANNIVERSARY';
+ // If we already have an anniversary property with the same
+ // value, ignore.
+ foreach ($output->select('ANNIVERSARY') as $anniversary) {
+ if ($anniversary->getValue() === $newProperty->getValue()) {
+ return;
+ }
+ }
+ break;
+ case 'X-ABDATE' :
+ // Find out what the label was, if it exists.
+ if (!$property->group) {
+ break;
+ }
+ $label = $input->{$property->group . '.X-ABLABEL'};
+
+ // We only support converting anniversaries.
+ if (!$label || $label->getValue() !== '_$!<Anniversary>!$_') {
+ break;
+ }
+
+ // If we already have an anniversary property with the same
+ // value, ignore.
+ foreach ($output->select('ANNIVERSARY') as $anniversary) {
+ if ($anniversary->getValue() === $newProperty->getValue()) {
+ return;
+ }
+ }
+ $newProperty->name = 'ANNIVERSARY';
+ break;
+ // Apple's per-property label system.
+ case 'X-ABLABEL' :
+ if ($newProperty->getValue() === '_$!<Anniversary>!$_') {
+ // We can safely remove these, as they are converted to
+ // ANNIVERSARY properties.
+ return;
+ }
+ break;
+
+ }
+
+ }
+
+ // set property group
+ $newProperty->group = $property->group;
+
+ if ($targetVersion === Document::VCARD40) {
+ $this->convertParameters40($newProperty, $parameters);
+ } else {
+ $this->convertParameters30($newProperty, $parameters);
+ }
+
+ // Lastly, we need to see if there's a need for a VALUE parameter.
+ //
+ // We can do that by instantating a empty property with that name, and
+ // seeing if the default valueType is identical to the current one.
+ $tempProperty = $output->createProperty($newProperty->name);
+ if ($tempProperty->getValueType() !== $newProperty->getValueType()) {
+ $newProperty['VALUE'] = $newProperty->getValueType();
+ }
+
+ $output->add($newProperty);
+
+
+ }
+
+ /**
+ * Converts a BINARY property to a URI property.
+ *
+ * vCard 4.0 no longer supports BINARY properties.
+ *
+ * @param Component\VCard $output
+ * @param Property\Uri $property The input property.
+ * @param $parameters List of parameters that will eventually be added to
+ * the new property.
+ *
+ * @return Property\Uri
+ */
+ protected function convertBinaryToUri(Component\VCard $output, Property\Binary $newProperty, array &$parameters) {
+
+ $value = $newProperty->getValue();
+ $newProperty = $output->createProperty(
+ $newProperty->name,
+ null, // no value
+ [], // no parameters yet
+ 'URI' // Forcing the BINARY type
+ );
+
+ $mimeType = 'application/octet-stream';
+
+ // See if we can find a better mimetype.
+ if (isset($parameters['TYPE'])) {
+
+ $newTypes = [];
+ foreach ($parameters['TYPE']->getParts() as $typePart) {
+ if (in_array(
+ strtoupper($typePart),
+ ['JPEG', 'PNG', 'GIF']
+ )) {
+ $mimeType = 'image/' . strtolower($typePart);
+ } else {
+ $newTypes[] = $typePart;
+ }
+ }
+
+ // If there were any parameters we're not converting to a
+ // mime-type, we need to keep them.
+ if ($newTypes) {
+ $parameters['TYPE']->setParts($newTypes);
+ } else {
+ unset($parameters['TYPE']);
+ }
+
+ }
+
+ $newProperty->setValue('data:' . $mimeType . ';base64,' . base64_encode($value));
+ return $newProperty;
+
+ }
+
+ /**
+ * Converts a URI property to a BINARY property.
+ *
+ * In vCard 4.0 attachments are encoded as data: uri. Even though these may
+ * be valid in vCard 3.0 as well, we should convert those to BINARY if
+ * possible, to improve compatibility.
+ *
+ * @param Component\VCard $output
+ * @param Property\Uri $property The input property.
+ *
+ * @return Property\Binary|null
+ */
+ protected function convertUriToBinary(Component\VCard $output, Property\Uri $newProperty) {
+
+ $value = $newProperty->getValue();
+
+ // Only converting data: uris
+ if (substr($value, 0, 5) !== 'data:') {
+ return $newProperty;
+ }
+
+ $newProperty = $output->createProperty(
+ $newProperty->name,
+ null, // no value
+ [], // no parameters yet
+ 'BINARY'
+ );
+
+ $mimeType = substr($value, 5, strpos($value, ',') - 5);
+ if (strpos($mimeType, ';')) {
+ $mimeType = substr($mimeType, 0, strpos($mimeType, ';'));
+ $newProperty->setValue(base64_decode(substr($value, strpos($value, ',') + 1)));
+ } else {
+ $newProperty->setValue(substr($value, strpos($value, ',') + 1));
+ }
+ unset($value);
+
+ $newProperty['ENCODING'] = 'b';
+ switch ($mimeType) {
+
+ case 'image/jpeg' :
+ $newProperty['TYPE'] = 'JPEG';
+ break;
+ case 'image/png' :
+ $newProperty['TYPE'] = 'PNG';
+ break;
+ case 'image/gif' :
+ $newProperty['TYPE'] = 'GIF';
+ break;
+
+ }
+
+
+ return $newProperty;
+
+ }
+
+ /**
+ * Adds parameters to a new property for vCard 4.0.
+ *
+ * @param Property $newProperty
+ * @param array $parameters
+ *
+ * @return void
+ */
+ protected function convertParameters40(Property $newProperty, array $parameters) {
+
+ // Adding all parameters.
+ foreach ($parameters as $param) {
+
+ // vCard 2.1 allowed parameters with no name
+ if ($param->noName) $param->noName = false;
+
+ switch ($param->name) {
+
+ // We need to see if there's any TYPE=PREF, because in vCard 4
+ // that's now PREF=1.
+ case 'TYPE' :
+ foreach ($param->getParts() as $paramPart) {
+
+ if (strtoupper($paramPart) === 'PREF') {
+ $newProperty->add('PREF', '1');
+ } else {
+ $newProperty->add($param->name, $paramPart);
+ }
+
+ }
+ break;
+ // These no longer exist in vCard 4
+ case 'ENCODING' :
+ case 'CHARSET' :
+ break;
+
+ default :
+ $newProperty->add($param->name, $param->getParts());
+ break;
+
+ }
+
+ }
+
+ }
+
+ /**
+ * Adds parameters to a new property for vCard 3.0.
+ *
+ * @param Property $newProperty
+ * @param array $parameters
+ *
+ * @return void
+ */
+ protected function convertParameters30(Property $newProperty, array $parameters) {
+
+ // Adding all parameters.
+ foreach ($parameters as $param) {
+
+ // vCard 2.1 allowed parameters with no name
+ if ($param->noName) $param->noName = false;
+
+ switch ($param->name) {
+
+ case 'ENCODING' :
+ // This value only existed in vCard 2.1, and should be
+ // removed for anything else.
+ if (strtoupper($param->getValue()) !== 'QUOTED-PRINTABLE') {
+ $newProperty->add($param->name, $param->getParts());
+ }
+ break;
+
+ /*
+ * Converting PREF=1 to TYPE=PREF.
+ *
+ * Any other PREF numbers we'll drop.
+ */
+ case 'PREF' :
+ if ($param->getValue() == '1') {
+ $newProperty->add('TYPE', 'PREF');
+ }
+ break;
+
+ default :
+ $newProperty->add($param->name, $param->getParts());
+ break;
+
+ }
+
+ }
+
+ }
+}