diff vendor/sabre/vobject/lib/Component/VCard.php @ 7:430dbd5346f7

vendor sabre as distributed
author Charlie Root
date Sat, 13 Jan 2018 09:06:10 -0500
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/sabre/vobject/lib/Component/VCard.php	Sat Jan 13 09:06:10 2018 -0500
@@ -0,0 +1,451 @@
+<?php
+
+namespace Sabre\VObject\Component;
+
+use
+    Sabre\VObject;
+
+/**
+ * The VCard component
+ *
+ * This component represents the BEGIN:VCARD and END:VCARD found in every
+ * vcard.
+ *
+ * @copyright Copyright (C) 2011-2015 fruux GmbH (https://fruux.com/).
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class VCard extends VObject\Document {
+
+    /**
+     * The default name for this component.
+     *
+     * This should be 'VCALENDAR' or 'VCARD'.
+     *
+     * @var string
+     */
+    static $defaultName = 'VCARD';
+
+    /**
+     * Caching the version number
+     *
+     * @var int
+     */
+    private $version = null;
+
+    /**
+     * List of value-types, and which classes they map to.
+     *
+     * @var array
+     */
+    static $valueMap = array(
+        'BINARY'           => 'Sabre\\VObject\\Property\\Binary',
+        'BOOLEAN'          => 'Sabre\\VObject\\Property\\Boolean',
+        'CONTENT-ID'       => 'Sabre\\VObject\\Property\\FlatText',   // vCard 2.1 only
+        'DATE'             => 'Sabre\\VObject\\Property\\VCard\\Date',
+        'DATE-TIME'        => 'Sabre\\VObject\\Property\\VCard\\DateTime',
+        'DATE-AND-OR-TIME' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime', // vCard only
+        'FLOAT'            => 'Sabre\\VObject\\Property\\Float',
+        'INTEGER'          => 'Sabre\\VObject\\Property\\Integer',
+        'LANGUAGE-TAG'     => 'Sabre\\VObject\\Property\\VCard\\LanguageTag',
+        'TIMESTAMP'        => 'Sabre\\VObject\\Property\\VCard\\TimeStamp',
+        'TEXT'             => 'Sabre\\VObject\\Property\\Text',
+        'TIME'             => 'Sabre\\VObject\\Property\\Time',
+        'UNKNOWN'          => 'Sabre\\VObject\\Property\\Unknown', // jCard / jCal-only.
+        'URI'              => 'Sabre\\VObject\\Property\\Uri',
+        'URL'              => 'Sabre\\VObject\\Property\\Uri', // vCard 2.1 only
+        'UTC-OFFSET'       => 'Sabre\\VObject\\Property\\UtcOffset',
+    );
+
+    /**
+     * List of properties, and which classes they map to.
+     *
+     * @var array
+     */
+    static $propertyMap = array(
+
+        // vCard 2.1 properties and up
+        'N'       => 'Sabre\\VObject\\Property\\Text',
+        'FN'      => 'Sabre\\VObject\\Property\\FlatText',
+        'PHOTO'   => 'Sabre\\VObject\\Property\\Binary', // Todo: we should add a class for Binary values.
+        'BDAY'    => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
+        'ADR'     => 'Sabre\\VObject\\Property\\Text',
+        'LABEL'   => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
+        'TEL'     => 'Sabre\\VObject\\Property\\FlatText',
+        'EMAIL'   => 'Sabre\\VObject\\Property\\FlatText',
+        'MAILER'  => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
+        'GEO'     => 'Sabre\\VObject\\Property\\FlatText',
+        'TITLE'   => 'Sabre\\VObject\\Property\\FlatText',
+        'ROLE'    => 'Sabre\\VObject\\Property\\FlatText',
+        'LOGO'    => 'Sabre\\VObject\\Property\\Binary',
+        // 'AGENT'   => 'Sabre\\VObject\\Property\\',      // Todo: is an embedded vCard. Probably rare, so
+                                 // not supported at the moment
+        'ORG'     => 'Sabre\\VObject\\Property\\Text',
+        'NOTE'    => 'Sabre\\VObject\\Property\\FlatText',
+        'REV'     => 'Sabre\\VObject\\Property\\VCard\\TimeStamp',
+        'SOUND'   => 'Sabre\\VObject\\Property\\FlatText',
+        'URL'     => 'Sabre\\VObject\\Property\\Uri',
+        'UID'     => 'Sabre\\VObject\\Property\\FlatText',
+        'VERSION' => 'Sabre\\VObject\\Property\\FlatText',
+        'KEY'     => 'Sabre\\VObject\\Property\\FlatText',
+        'TZ'      => 'Sabre\\VObject\\Property\\Text',
+
+        // vCard 3.0 properties
+        'CATEGORIES'  => 'Sabre\\VObject\\Property\\Text',
+        'SORT-STRING' => 'Sabre\\VObject\\Property\\FlatText',
+        'PRODID'      => 'Sabre\\VObject\\Property\\FlatText',
+        'NICKNAME'    => 'Sabre\\VObject\\Property\\Text',
+        'CLASS'       => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
+
+        // rfc2739 properties
+        'FBURL'        => 'Sabre\\VObject\\Property\\Uri',
+        'CAPURI'       => 'Sabre\\VObject\\Property\\Uri',
+        'CALURI'       => 'Sabre\\VObject\\Property\\Uri',
+
+        // rfc4770 properties
+        'IMPP'         => 'Sabre\\VObject\\Property\\Uri',
+
+        // vCard 4.0 properties
+        'XML'          => 'Sabre\\VObject\\Property\\FlatText',
+        'ANNIVERSARY'  => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
+        'CLIENTPIDMAP' => 'Sabre\\VObject\\Property\\Text',
+        'LANG'         => 'Sabre\\VObject\\Property\\VCard\\LanguageTag',
+        'GENDER'       => 'Sabre\\VObject\\Property\\Text',
+        'KIND'         => 'Sabre\\VObject\\Property\\FlatText',
+
+        // rfc6474 properties
+        'BIRTHPLACE'    => 'Sabre\\VObject\\Property\\FlatText',
+        'DEATHPLACE'    => 'Sabre\\VObject\\Property\\FlatText',
+        'DEATHDATE'     => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
+
+        // rfc6715 properties
+        'EXPERTISE'     => 'Sabre\\VObject\\Property\\FlatText',
+        'HOBBY'         => 'Sabre\\VObject\\Property\\FlatText',
+        'INTEREST'      => 'Sabre\\VObject\\Property\\FlatText',
+        'ORG-DIRECTORY' => 'Sabre\\VObject\\Property\\FlatText',
+
+    );
+
+    /**
+     * Returns the current document type.
+     *
+     * @return void
+     */
+    function getDocumentType() {
+
+        if (!$this->version) {
+            $version = (string)$this->VERSION;
+            switch($version) {
+                case '2.1' :
+                    $this->version = self::VCARD21;
+                    break;
+                case '3.0' :
+                    $this->version = self::VCARD30;
+                    break;
+                case '4.0' :
+                    $this->version = self::VCARD40;
+                    break;
+                default :
+                    $this->version = self::UNKNOWN;
+                    break;
+
+            }
+        }
+
+        return $this->version;
+
+    }
+
+    /**
+     * Converts the document to a different vcard version.
+     *
+     * Use one of the VCARD constants for the target. This method will return
+     * a copy of the vcard in the new version.
+     *
+     * At the moment the only supported conversion is from 3.0 to 4.0.
+     *
+     * If input and output version are identical, a clone is returned.
+     *
+     * @param int $target
+     * @return VCard
+     */
+    function convert($target) {
+
+        $converter = new VObject\VCardConverter();
+        return $converter->convert($this, $target);
+
+    }
+
+    /**
+     * VCards with version 2.1, 3.0 and 4.0 are found.
+     *
+     * If the VCARD doesn't know its version, 2.1 is assumed.
+     */
+    const DEFAULT_VERSION = self::VCARD21;
+
+    /**
+     * Validates the node for correctness.
+     *
+     * The following options are supported:
+     *   Node::REPAIR - May attempt to automatically repair the problem.
+     *
+     * This method returns an array with detected problems.
+     * Every element has the following properties:
+     *
+     *  * level - problem level.
+     *  * message - A human-readable string describing the issue.
+     *  * node - A reference to the problematic node.
+     *
+     * The level means:
+     *   1 - The issue was repaired (only happens if REPAIR was turned on)
+     *   2 - An inconsequential issue
+     *   3 - A severe issue.
+     *
+     * @param int $options
+     * @return array
+     */
+    function validate($options = 0) {
+
+        $warnings = array();
+
+        $versionMap = array(
+            self::VCARD21 => '2.1',
+            self::VCARD30 => '3.0',
+            self::VCARD40 => '4.0',
+        );
+
+        $version = $this->select('VERSION');
+        if (count($version)===1) {
+            $version = (string)$this->VERSION;
+            if ($version!=='2.1' && $version!=='3.0' && $version!=='4.0') {
+                $warnings[] = array(
+                    'level' => 3,
+                    'message' => 'Only vcard version 4.0 (RFC6350), version 3.0 (RFC2426) or version 2.1 (icm-vcard-2.1) are supported.',
+                    'node' => $this,
+                );
+                if ($options & self::REPAIR) {
+                    $this->VERSION = $versionMap[self::DEFAULT_VERSION];
+                }
+            }
+            if ($version === '2.1' && ($options & self::PROFILE_CARDDAV)) {
+                $warnings[] = array(
+                    'level' => 3,
+                    'message' => 'CardDAV servers are not allowed to accept vCard 2.1.',
+                    'node' => $this,
+                );
+            }
+
+        }
+        $uid = $this->select('UID');
+        if (count($uid) === 0) {
+            if ($options & self::PROFILE_CARDDAV) {
+                // Required for CardDAV
+                $warningLevel = 3;
+                $message = 'vCards on CardDAV servers MUST have a UID property.';
+            } else {
+                // Not required for regular vcards
+                $warningLevel = 2;
+                $message = 'Adding a UID to a vCard property is recommended.';
+            }
+            if ($options & self::REPAIR) {
+                $this->UID = VObject\UUIDUtil::getUUID();
+                $warningLevel = 1;
+            }
+            $warnings[] = array(
+                'level' => $warningLevel,
+                'message' => $message,
+                'node' => $this,
+            );
+        }
+
+        $fn = $this->select('FN');
+        if (count($fn)!==1) {
+
+            $repaired = false;
+            if (($options & self::REPAIR) && count($fn) === 0) {
+                // We're going to try to see if we can use the contents of the
+                // N property.
+                if (isset($this->N)) {
+                    $value = explode(';', (string)$this->N);
+                    if (isset($value[1]) && $value[1]) {
+                        $this->FN = $value[1] . ' ' . $value[0];
+                    } else {
+                        $this->FN = $value[0];
+                    }
+                    $repaired = true;
+
+                // Otherwise, the ORG property may work
+                } elseif (isset($this->ORG)) {
+                    $this->FN = (string)$this->ORG;
+                    $repaired = true;
+                }
+
+            }
+            $warnings[] = array(
+                'level' => $repaired?1:3,
+                'message' => 'The FN property must appear in the VCARD component exactly 1 time',
+                'node' => $this,
+            );
+        }
+
+        return array_merge(
+            parent::validate($options),
+            $warnings
+        );
+
+    }
+
+    /**
+     * A simple list of validation rules.
+     *
+     * This is simply a list of properties, and how many times they either
+     * must or must not appear.
+     *
+     * Possible values per property:
+     *   * 0 - Must not appear.
+     *   * 1 - Must appear exactly once.
+     *   * + - Must appear at least once.
+     *   * * - Can appear any number of times.
+     *
+     * @var array
+     */
+    function getValidationRules() {
+
+        return array(
+            'ADR'          => '*',
+            'ANNIVERSARY'  => '?',
+            'BDAY'         => '?',
+            'CALADRURI'    => '*',
+            'CALURI'       => '*',
+            'CATEGORIES'   => '*',
+            'CLIENTPIDMAP' => '*',
+            'EMAIL'        => '*',
+            'FBURL'        => '*',
+            'IMPP'         => '*',
+            'GENDER'       => '?',
+            'GEO'          => '*',
+            'KEY'          => '*',
+            'KIND'         => '?',
+            'LANG'         => '*',
+            'LOGO'         => '*',
+            'MEMBER'       => '*',
+            'N'            => '?',
+            'NICKNAME'     => '*',
+            'NOTE'         => '*',
+            'ORG'          => '*',
+            'PHOTO'        => '*',
+            'PRODID'       => '?',
+            'RELATED'      => '*',
+            'REV'          => '?',
+            'ROLE'         => '*',
+            'SOUND'        => '*',
+            'SOURCE'       => '*',
+            'TEL'          => '*',
+            'TITLE'        => '*',
+            'TZ'           => '*',
+            'URL'          => '*',
+            'VERSION'      => '1',
+            'XML'          => '*',
+
+            // FN is commented out, because it's already handled by the
+            // validate function, which may also try to repair it.
+            // 'FN'           => '+',
+
+            'UID'          => '?',
+        );
+
+    }
+
+    /**
+     * Returns a preferred field.
+     *
+     * VCards can indicate wether a field such as ADR, TEL or EMAIL is
+     * preferred by specifying TYPE=PREF (vcard 2.1, 3) or PREF=x (vcard 4, x
+     * being a number between 1 and 100).
+     *
+     * If neither of those parameters are specified, the first is returned, if
+     * a field with that name does not exist, null is returned.
+     *
+     * @param string $fieldName
+     * @return VObject\Property|null
+     */
+    function preferred($propertyName) {
+
+        $preferred = null;
+        $lastPref = 101;
+        foreach($this->select($propertyName) as $field) {
+
+            $pref = 101;
+            if (isset($field['TYPE']) && $field['TYPE']->has('PREF')) {
+                $pref = 1;
+            } elseif (isset($field['PREF'])) {
+                $pref = $field['PREF']->getValue();
+            }
+
+            if ($pref < $lastPref || is_null($preferred)) {
+                $preferred = $field;
+                $lastPref = $pref;
+            }
+
+        }
+        return $preferred;
+
+    }
+
+    /**
+     * This method should return a list of default property values.
+     *
+     * @return array
+     */
+    protected function getDefaults() {
+
+        return array(
+            'VERSION' => '3.0',
+            'PRODID' => '-//Sabre//Sabre VObject ' . VObject\Version::VERSION . '//EN',
+        );
+
+    }
+
+    /**
+     * This method returns an array, with the representation as it should be
+     * encoded in json. This is used to create jCard or jCal documents.
+     *
+     * @return array
+     */
+    function jsonSerialize() {
+
+        // A vcard does not have sub-components, so we're overriding this
+        // method to remove that array element.
+        $properties = array();
+
+        foreach($this->children as $child) {
+            $properties[] = $child->jsonSerialize();
+        }
+
+        return array(
+            strtolower($this->name),
+            $properties,
+        );
+
+    }
+
+    /**
+     * Returns the default class for a property name.
+     *
+     * @param string $propertyName
+     * @return string
+     */
+    function getClassNameForPropertyName($propertyName) {
+
+        $className = parent::getClassNameForPropertyName($propertyName);
+        // In vCard 4, BINARY no longer exists, and we need URI instead.
+
+        if ($className == 'Sabre\\VObject\\Property\\Binary' && $this->getDocumentType()===self::VCARD40) {
+            return 'Sabre\\VObject\\Property\\Uri';
+        }
+        return $className;
+
+    }
+
+}
+