Completed
Branch develop (37f7b7)
by
unknown
24:41
created
htdocs/includes/sabre/sabre/vobject/lib/Property/FlatText.php 1 patch
Indentation   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -24,23 +24,23 @@
 block discarded – undo
24 24
  */
25 25
 class FlatText extends Text
26 26
 {
27
-    /**
28
-     * Field separator.
29
-     *
30
-     * @var string
31
-     */
32
-    public $delimiter = ',';
27
+	/**
28
+	 * Field separator.
29
+	 *
30
+	 * @var string
31
+	 */
32
+	public $delimiter = ',';
33 33
 
34
-    /**
35
-     * Sets the value as a quoted-printable encoded string.
36
-     *
37
-     * Overriding this so we're not splitting on a ; delimiter.
38
-     *
39
-     * @param string $val
40
-     */
41
-    public function setQuotedPrintableValue($val)
42
-    {
43
-        $val = quoted_printable_decode($val);
44
-        $this->setValue($val);
45
-    }
34
+	/**
35
+	 * Sets the value as a quoted-printable encoded string.
36
+	 *
37
+	 * Overriding this so we're not splitting on a ; delimiter.
38
+	 *
39
+	 * @param string $val
40
+	 */
41
+	public function setQuotedPrintableValue($val)
42
+	{
43
+		$val = quoted_printable_decode($val);
44
+		$this->setValue($val);
45
+	}
46 46
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Property/FloatValue.php 1 patch
Indentation   +95 added lines, -95 removed lines patch added patch discarded remove patch
@@ -17,108 +17,108 @@
 block discarded – undo
17 17
  */
18 18
 class FloatValue extends Property
19 19
 {
20
-    /**
21
-     * In case this is a multi-value property. This string will be used as a
22
-     * delimiter.
23
-     *
24
-     * @var string
25
-     */
26
-    public $delimiter = ';';
20
+	/**
21
+	 * In case this is a multi-value property. This string will be used as a
22
+	 * delimiter.
23
+	 *
24
+	 * @var string
25
+	 */
26
+	public $delimiter = ';';
27 27
 
28
-    /**
29
-     * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
30
-     *
31
-     * This has been 'unfolded', so only 1 line will be passed. Unescaping is
32
-     * not yet done, but parameters are not included.
33
-     *
34
-     * @param string $val
35
-     */
36
-    public function setRawMimeDirValue($val)
37
-    {
38
-        $val = explode($this->delimiter, $val);
39
-        foreach ($val as &$item) {
40
-            $item = (float) $item;
41
-        }
42
-        $this->setParts($val);
43
-    }
28
+	/**
29
+	 * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
30
+	 *
31
+	 * This has been 'unfolded', so only 1 line will be passed. Unescaping is
32
+	 * not yet done, but parameters are not included.
33
+	 *
34
+	 * @param string $val
35
+	 */
36
+	public function setRawMimeDirValue($val)
37
+	{
38
+		$val = explode($this->delimiter, $val);
39
+		foreach ($val as &$item) {
40
+			$item = (float) $item;
41
+		}
42
+		$this->setParts($val);
43
+	}
44 44
 
45
-    /**
46
-     * Returns a raw mime-dir representation of the value.
47
-     *
48
-     * @return string
49
-     */
50
-    public function getRawMimeDirValue()
51
-    {
52
-        return implode(
53
-            $this->delimiter,
54
-            $this->getParts()
55
-        );
56
-    }
45
+	/**
46
+	 * Returns a raw mime-dir representation of the value.
47
+	 *
48
+	 * @return string
49
+	 */
50
+	public function getRawMimeDirValue()
51
+	{
52
+		return implode(
53
+			$this->delimiter,
54
+			$this->getParts()
55
+		);
56
+	}
57 57
 
58
-    /**
59
-     * Returns the type of value.
60
-     *
61
-     * This corresponds to the VALUE= parameter. Every property also has a
62
-     * 'default' valueType.
63
-     *
64
-     * @return string
65
-     */
66
-    public function getValueType()
67
-    {
68
-        return 'FLOAT';
69
-    }
58
+	/**
59
+	 * Returns the type of value.
60
+	 *
61
+	 * This corresponds to the VALUE= parameter. Every property also has a
62
+	 * 'default' valueType.
63
+	 *
64
+	 * @return string
65
+	 */
66
+	public function getValueType()
67
+	{
68
+		return 'FLOAT';
69
+	}
70 70
 
71
-    /**
72
-     * Returns the value, in the format it should be encoded for JSON.
73
-     *
74
-     * This method must always return an array.
75
-     *
76
-     * @return array
77
-     */
78
-    public function getJsonValue()
79
-    {
80
-        $val = array_map('floatval', $this->getParts());
71
+	/**
72
+	 * Returns the value, in the format it should be encoded for JSON.
73
+	 *
74
+	 * This method must always return an array.
75
+	 *
76
+	 * @return array
77
+	 */
78
+	public function getJsonValue()
79
+	{
80
+		$val = array_map('floatval', $this->getParts());
81 81
 
82
-        // Special-casing the GEO property.
83
-        //
84
-        // See:
85
-        // http://tools.ietf.org/html/draft-ietf-jcardcal-jcal-04#section-3.4.1.2
86
-        if ('GEO' === $this->name) {
87
-            return [$val];
88
-        }
82
+		// Special-casing the GEO property.
83
+		//
84
+		// See:
85
+		// http://tools.ietf.org/html/draft-ietf-jcardcal-jcal-04#section-3.4.1.2
86
+		if ('GEO' === $this->name) {
87
+			return [$val];
88
+		}
89 89
 
90
-        return $val;
91
-    }
90
+		return $val;
91
+	}
92 92
 
93
-    /**
94
-     * Hydrate data from a XML subtree, as it would appear in a xCard or xCal
95
-     * object.
96
-     */
97
-    public function setXmlValue(array $value)
98
-    {
99
-        $value = array_map('floatval', $value);
100
-        parent::setXmlValue($value);
101
-    }
93
+	/**
94
+	 * Hydrate data from a XML subtree, as it would appear in a xCard or xCal
95
+	 * object.
96
+	 */
97
+	public function setXmlValue(array $value)
98
+	{
99
+		$value = array_map('floatval', $value);
100
+		parent::setXmlValue($value);
101
+	}
102 102
 
103
-    /**
104
-     * This method serializes only the value of a property. This is used to
105
-     * create xCard or xCal documents.
106
-     *
107
-     * @param Xml\Writer $writer XML writer
108
-     */
109
-    protected function xmlSerializeValue(Xml\Writer $writer)
110
-    {
111
-        // Special-casing the GEO property.
112
-        //
113
-        // See:
114
-        // http://tools.ietf.org/html/rfc6321#section-3.4.1.2
115
-        if ('GEO' === $this->name) {
116
-            $value = array_map('floatval', $this->getParts());
103
+	/**
104
+	 * This method serializes only the value of a property. This is used to
105
+	 * create xCard or xCal documents.
106
+	 *
107
+	 * @param Xml\Writer $writer XML writer
108
+	 */
109
+	protected function xmlSerializeValue(Xml\Writer $writer)
110
+	{
111
+		// Special-casing the GEO property.
112
+		//
113
+		// See:
114
+		// http://tools.ietf.org/html/rfc6321#section-3.4.1.2
115
+		if ('GEO' === $this->name) {
116
+			$value = array_map('floatval', $this->getParts());
117 117
 
118
-            $writer->writeElement('latitude', $value[0]);
119
-            $writer->writeElement('longitude', $value[1]);
120
-        } else {
121
-            parent::xmlSerializeValue($writer);
122
-        }
123
-    }
118
+			$writer->writeElement('latitude', $value[0]);
119
+			$writer->writeElement('longitude', $value[1]);
120
+		} else {
121
+			parent::xmlSerializeValue($writer);
122
+		}
123
+	}
124 124
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Parser/XML.php 1 patch
Indentation   +354 added lines, -354 removed lines patch added patch discarded remove patch
@@ -20,358 +20,358 @@
 block discarded – undo
20 20
  */
21 21
 class XML extends Parser
22 22
 {
23
-    const XCAL_NAMESPACE = 'urn:ietf:params:xml:ns:icalendar-2.0';
24
-    const XCARD_NAMESPACE = 'urn:ietf:params:xml:ns:vcard-4.0';
25
-
26
-    /**
27
-     * The input data.
28
-     *
29
-     * @var array
30
-     */
31
-    protected $input;
32
-
33
-    /**
34
-     * A pointer/reference to the input.
35
-     *
36
-     * @var array
37
-     */
38
-    private $pointer;
39
-
40
-    /**
41
-     * Document, root component.
42
-     *
43
-     * @var \Sabre\VObject\Document
44
-     */
45
-    protected $root;
46
-
47
-    /**
48
-     * Creates the parser.
49
-     *
50
-     * Optionally, it's possible to parse the input stream here.
51
-     *
52
-     * @param mixed $input
53
-     * @param int   $options any parser options (OPTION constants)
54
-     */
55
-    public function __construct($input = null, $options = 0)
56
-    {
57
-        if (0 === $options) {
58
-            $options = parent::OPTION_FORGIVING;
59
-        }
60
-
61
-        parent::__construct($input, $options);
62
-    }
63
-
64
-    /**
65
-     * Parse xCal or xCard.
66
-     *
67
-     * @param resource|string $input
68
-     * @param int             $options
69
-     *
70
-     * @throws \Exception
71
-     *
72
-     * @return \Sabre\VObject\Document
73
-     */
74
-    public function parse($input = null, $options = 0)
75
-    {
76
-        if (!is_null($input)) {
77
-            $this->setInput($input);
78
-        }
79
-
80
-        if (0 !== $options) {
81
-            $this->options = $options;
82
-        }
83
-
84
-        if (is_null($this->input)) {
85
-            throw new EofException('End of input stream, or no input supplied');
86
-        }
87
-
88
-        switch ($this->input['name']) {
89
-            case '{'.self::XCAL_NAMESPACE.'}icalendar':
90
-                $this->root = new VCalendar([], false);
91
-                $this->pointer = &$this->input['value'][0];
92
-                $this->parseVCalendarComponents($this->root);
93
-                break;
94
-
95
-            case '{'.self::XCARD_NAMESPACE.'}vcards':
96
-                foreach ($this->input['value'] as &$vCard) {
97
-                    $this->root = new VCard(['version' => '4.0'], false);
98
-                    $this->pointer = &$vCard;
99
-                    $this->parseVCardComponents($this->root);
100
-
101
-                    // We just parse the first <vcard /> element.
102
-                    break;
103
-                }
104
-                break;
105
-
106
-            default:
107
-                throw new ParseException('Unsupported XML standard');
108
-        }
109
-
110
-        return $this->root;
111
-    }
112
-
113
-    /**
114
-     * Parse a xCalendar component.
115
-     */
116
-    protected function parseVCalendarComponents(Component $parentComponent)
117
-    {
118
-        foreach ($this->pointer['value'] ?: [] as $children) {
119
-            switch (static::getTagName($children['name'])) {
120
-                case 'properties':
121
-                    $this->pointer = &$children['value'];
122
-                    $this->parseProperties($parentComponent);
123
-                    break;
124
-
125
-                case 'components':
126
-                    $this->pointer = &$children;
127
-                    $this->parseComponent($parentComponent);
128
-                    break;
129
-            }
130
-        }
131
-    }
132
-
133
-    /**
134
-     * Parse a xCard component.
135
-     */
136
-    protected function parseVCardComponents(Component $parentComponent)
137
-    {
138
-        $this->pointer = &$this->pointer['value'];
139
-        $this->parseProperties($parentComponent);
140
-    }
141
-
142
-    /**
143
-     * Parse xCalendar and xCard properties.
144
-     *
145
-     * @param string $propertyNamePrefix
146
-     */
147
-    protected function parseProperties(Component $parentComponent, $propertyNamePrefix = '')
148
-    {
149
-        foreach ($this->pointer ?: [] as $xmlProperty) {
150
-            list($namespace, $tagName) = SabreXml\Service::parseClarkNotation($xmlProperty['name']);
151
-
152
-            $propertyName = $tagName;
153
-            $propertyValue = [];
154
-            $propertyParameters = [];
155
-            $propertyType = 'text';
156
-
157
-            // A property which is not part of the standard.
158
-            if (self::XCAL_NAMESPACE !== $namespace
159
-                && self::XCARD_NAMESPACE !== $namespace) {
160
-                $propertyName = 'xml';
161
-                $value = '<'.$tagName.' xmlns="'.$namespace.'"';
162
-
163
-                foreach ($xmlProperty['attributes'] as $attributeName => $attributeValue) {
164
-                    $value .= ' '.$attributeName.'="'.str_replace('"', '\"', $attributeValue).'"';
165
-                }
166
-
167
-                $value .= '>'.$xmlProperty['value'].'</'.$tagName.'>';
168
-
169
-                $propertyValue = [$value];
170
-
171
-                $this->createProperty(
172
-                    $parentComponent,
173
-                    $propertyName,
174
-                    $propertyParameters,
175
-                    $propertyType,
176
-                    $propertyValue
177
-                );
178
-
179
-                continue;
180
-            }
181
-
182
-            // xCard group.
183
-            if ('group' === $propertyName) {
184
-                if (!isset($xmlProperty['attributes']['name'])) {
185
-                    continue;
186
-                }
187
-
188
-                $this->pointer = &$xmlProperty['value'];
189
-                $this->parseProperties(
190
-                    $parentComponent,
191
-                    strtoupper($xmlProperty['attributes']['name']).'.'
192
-                );
193
-
194
-                continue;
195
-            }
196
-
197
-            // Collect parameters.
198
-            foreach ($xmlProperty['value'] as $i => $xmlPropertyChild) {
199
-                if (!is_array($xmlPropertyChild)
200
-                    || 'parameters' !== static::getTagName($xmlPropertyChild['name'])) {
201
-                    continue;
202
-                }
203
-
204
-                $xmlParameters = $xmlPropertyChild['value'];
205
-
206
-                foreach ($xmlParameters as $xmlParameter) {
207
-                    $propertyParameterValues = [];
208
-
209
-                    foreach ($xmlParameter['value'] as $xmlParameterValues) {
210
-                        $propertyParameterValues[] = $xmlParameterValues['value'];
211
-                    }
212
-
213
-                    $propertyParameters[static::getTagName($xmlParameter['name'])]
214
-                        = implode(',', $propertyParameterValues);
215
-                }
216
-
217
-                array_splice($xmlProperty['value'], $i, 1);
218
-            }
219
-
220
-            $propertyNameExtended = ($this->root instanceof VCalendar
221
-                                      ? 'xcal'
222
-                                      : 'xcard').':'.$propertyName;
223
-
224
-            switch ($propertyNameExtended) {
225
-                case 'xcal:geo':
226
-                    $propertyType = 'float';
227
-                    $propertyValue['latitude'] = 0;
228
-                    $propertyValue['longitude'] = 0;
229
-
230
-                    foreach ($xmlProperty['value'] as $xmlRequestChild) {
231
-                        $propertyValue[static::getTagName($xmlRequestChild['name'])]
232
-                            = $xmlRequestChild['value'];
233
-                    }
234
-                    break;
235
-
236
-                case 'xcal:request-status':
237
-                    $propertyType = 'text';
238
-
239
-                    foreach ($xmlProperty['value'] as $xmlRequestChild) {
240
-                        $propertyValue[static::getTagName($xmlRequestChild['name'])]
241
-                            = $xmlRequestChild['value'];
242
-                    }
243
-                    break;
244
-
245
-                case 'xcal:freebusy':
246
-                    $propertyType = 'freebusy';
247
-                    // We don't break because we only want to set
248
-                    // another property type.
249
-
250
-                    // no break
251
-                case 'xcal:categories':
252
-                case 'xcal:resources':
253
-                case 'xcal:exdate':
254
-                    foreach ($xmlProperty['value'] as $specialChild) {
255
-                        $propertyValue[static::getTagName($specialChild['name'])]
256
-                            = $specialChild['value'];
257
-                    }
258
-                    break;
259
-
260
-                case 'xcal:rdate':
261
-                    $propertyType = 'date-time';
262
-
263
-                    foreach ($xmlProperty['value'] as $specialChild) {
264
-                        $tagName = static::getTagName($specialChild['name']);
265
-
266
-                        if ('period' === $tagName) {
267
-                            $propertyParameters['value'] = 'PERIOD';
268
-                            $propertyValue[] = implode('/', $specialChild['value']);
269
-                        } else {
270
-                            $propertyValue[] = $specialChild['value'];
271
-                        }
272
-                    }
273
-                    break;
274
-
275
-                default:
276
-                    $propertyType = static::getTagName($xmlProperty['value'][0]['name']);
277
-
278
-                    foreach ($xmlProperty['value'] as $value) {
279
-                        $propertyValue[] = $value['value'];
280
-                    }
281
-
282
-                    if ('date' === $propertyType) {
283
-                        $propertyParameters['value'] = 'DATE';
284
-                    }
285
-                    break;
286
-            }
287
-
288
-            $this->createProperty(
289
-                $parentComponent,
290
-                $propertyNamePrefix.$propertyName,
291
-                $propertyParameters,
292
-                $propertyType,
293
-                $propertyValue
294
-            );
295
-        }
296
-    }
297
-
298
-    /**
299
-     * Parse a component.
300
-     */
301
-    protected function parseComponent(Component $parentComponent)
302
-    {
303
-        $components = $this->pointer['value'] ?: [];
304
-
305
-        foreach ($components as $component) {
306
-            $componentName = static::getTagName($component['name']);
307
-            $currentComponent = $this->root->createComponent(
308
-                $componentName,
309
-                null,
310
-                false
311
-            );
312
-
313
-            $this->pointer = &$component;
314
-            $this->parseVCalendarComponents($currentComponent);
315
-
316
-            $parentComponent->add($currentComponent);
317
-        }
318
-    }
319
-
320
-    /**
321
-     * Create a property.
322
-     *
323
-     * @param string $name
324
-     * @param array  $parameters
325
-     * @param string $type
326
-     * @param mixed  $value
327
-     */
328
-    protected function createProperty(Component $parentComponent, $name, $parameters, $type, $value)
329
-    {
330
-        $property = $this->root->createProperty(
331
-            $name,
332
-            null,
333
-            $parameters,
334
-            $type
335
-        );
336
-        $parentComponent->add($property);
337
-        $property->setXmlValue($value);
338
-    }
339
-
340
-    /**
341
-     * Sets the input data.
342
-     *
343
-     * @param resource|string $input
344
-     */
345
-    public function setInput($input)
346
-    {
347
-        if (is_resource($input)) {
348
-            $input = stream_get_contents($input);
349
-        }
350
-
351
-        if (is_string($input)) {
352
-            $reader = new SabreXml\Reader();
353
-            $reader->elementMap['{'.self::XCAL_NAMESPACE.'}period']
354
-                = XML\Element\KeyValue::class;
355
-            $reader->elementMap['{'.self::XCAL_NAMESPACE.'}recur']
356
-                = XML\Element\KeyValue::class;
357
-            $reader->xml($input);
358
-            $input = $reader->parse();
359
-        }
360
-
361
-        $this->input = $input;
362
-    }
363
-
364
-    /**
365
-     * Get tag name from a Clark notation.
366
-     *
367
-     * @param string $clarkedTagName
368
-     *
369
-     * @return string
370
-     */
371
-    protected static function getTagName($clarkedTagName)
372
-    {
373
-        list(, $tagName) = SabreXml\Service::parseClarkNotation($clarkedTagName);
374
-
375
-        return $tagName;
376
-    }
23
+	const XCAL_NAMESPACE = 'urn:ietf:params:xml:ns:icalendar-2.0';
24
+	const XCARD_NAMESPACE = 'urn:ietf:params:xml:ns:vcard-4.0';
25
+
26
+	/**
27
+	 * The input data.
28
+	 *
29
+	 * @var array
30
+	 */
31
+	protected $input;
32
+
33
+	/**
34
+	 * A pointer/reference to the input.
35
+	 *
36
+	 * @var array
37
+	 */
38
+	private $pointer;
39
+
40
+	/**
41
+	 * Document, root component.
42
+	 *
43
+	 * @var \Sabre\VObject\Document
44
+	 */
45
+	protected $root;
46
+
47
+	/**
48
+	 * Creates the parser.
49
+	 *
50
+	 * Optionally, it's possible to parse the input stream here.
51
+	 *
52
+	 * @param mixed $input
53
+	 * @param int   $options any parser options (OPTION constants)
54
+	 */
55
+	public function __construct($input = null, $options = 0)
56
+	{
57
+		if (0 === $options) {
58
+			$options = parent::OPTION_FORGIVING;
59
+		}
60
+
61
+		parent::__construct($input, $options);
62
+	}
63
+
64
+	/**
65
+	 * Parse xCal or xCard.
66
+	 *
67
+	 * @param resource|string $input
68
+	 * @param int             $options
69
+	 *
70
+	 * @throws \Exception
71
+	 *
72
+	 * @return \Sabre\VObject\Document
73
+	 */
74
+	public function parse($input = null, $options = 0)
75
+	{
76
+		if (!is_null($input)) {
77
+			$this->setInput($input);
78
+		}
79
+
80
+		if (0 !== $options) {
81
+			$this->options = $options;
82
+		}
83
+
84
+		if (is_null($this->input)) {
85
+			throw new EofException('End of input stream, or no input supplied');
86
+		}
87
+
88
+		switch ($this->input['name']) {
89
+			case '{'.self::XCAL_NAMESPACE.'}icalendar':
90
+				$this->root = new VCalendar([], false);
91
+				$this->pointer = &$this->input['value'][0];
92
+				$this->parseVCalendarComponents($this->root);
93
+				break;
94
+
95
+			case '{'.self::XCARD_NAMESPACE.'}vcards':
96
+				foreach ($this->input['value'] as &$vCard) {
97
+					$this->root = new VCard(['version' => '4.0'], false);
98
+					$this->pointer = &$vCard;
99
+					$this->parseVCardComponents($this->root);
100
+
101
+					// We just parse the first <vcard /> element.
102
+					break;
103
+				}
104
+				break;
105
+
106
+			default:
107
+				throw new ParseException('Unsupported XML standard');
108
+		}
109
+
110
+		return $this->root;
111
+	}
112
+
113
+	/**
114
+	 * Parse a xCalendar component.
115
+	 */
116
+	protected function parseVCalendarComponents(Component $parentComponent)
117
+	{
118
+		foreach ($this->pointer['value'] ?: [] as $children) {
119
+			switch (static::getTagName($children['name'])) {
120
+				case 'properties':
121
+					$this->pointer = &$children['value'];
122
+					$this->parseProperties($parentComponent);
123
+					break;
124
+
125
+				case 'components':
126
+					$this->pointer = &$children;
127
+					$this->parseComponent($parentComponent);
128
+					break;
129
+			}
130
+		}
131
+	}
132
+
133
+	/**
134
+	 * Parse a xCard component.
135
+	 */
136
+	protected function parseVCardComponents(Component $parentComponent)
137
+	{
138
+		$this->pointer = &$this->pointer['value'];
139
+		$this->parseProperties($parentComponent);
140
+	}
141
+
142
+	/**
143
+	 * Parse xCalendar and xCard properties.
144
+	 *
145
+	 * @param string $propertyNamePrefix
146
+	 */
147
+	protected function parseProperties(Component $parentComponent, $propertyNamePrefix = '')
148
+	{
149
+		foreach ($this->pointer ?: [] as $xmlProperty) {
150
+			list($namespace, $tagName) = SabreXml\Service::parseClarkNotation($xmlProperty['name']);
151
+
152
+			$propertyName = $tagName;
153
+			$propertyValue = [];
154
+			$propertyParameters = [];
155
+			$propertyType = 'text';
156
+
157
+			// A property which is not part of the standard.
158
+			if (self::XCAL_NAMESPACE !== $namespace
159
+				&& self::XCARD_NAMESPACE !== $namespace) {
160
+				$propertyName = 'xml';
161
+				$value = '<'.$tagName.' xmlns="'.$namespace.'"';
162
+
163
+				foreach ($xmlProperty['attributes'] as $attributeName => $attributeValue) {
164
+					$value .= ' '.$attributeName.'="'.str_replace('"', '\"', $attributeValue).'"';
165
+				}
166
+
167
+				$value .= '>'.$xmlProperty['value'].'</'.$tagName.'>';
168
+
169
+				$propertyValue = [$value];
170
+
171
+				$this->createProperty(
172
+					$parentComponent,
173
+					$propertyName,
174
+					$propertyParameters,
175
+					$propertyType,
176
+					$propertyValue
177
+				);
178
+
179
+				continue;
180
+			}
181
+
182
+			// xCard group.
183
+			if ('group' === $propertyName) {
184
+				if (!isset($xmlProperty['attributes']['name'])) {
185
+					continue;
186
+				}
187
+
188
+				$this->pointer = &$xmlProperty['value'];
189
+				$this->parseProperties(
190
+					$parentComponent,
191
+					strtoupper($xmlProperty['attributes']['name']).'.'
192
+				);
193
+
194
+				continue;
195
+			}
196
+
197
+			// Collect parameters.
198
+			foreach ($xmlProperty['value'] as $i => $xmlPropertyChild) {
199
+				if (!is_array($xmlPropertyChild)
200
+					|| 'parameters' !== static::getTagName($xmlPropertyChild['name'])) {
201
+					continue;
202
+				}
203
+
204
+				$xmlParameters = $xmlPropertyChild['value'];
205
+
206
+				foreach ($xmlParameters as $xmlParameter) {
207
+					$propertyParameterValues = [];
208
+
209
+					foreach ($xmlParameter['value'] as $xmlParameterValues) {
210
+						$propertyParameterValues[] = $xmlParameterValues['value'];
211
+					}
212
+
213
+					$propertyParameters[static::getTagName($xmlParameter['name'])]
214
+						= implode(',', $propertyParameterValues);
215
+				}
216
+
217
+				array_splice($xmlProperty['value'], $i, 1);
218
+			}
219
+
220
+			$propertyNameExtended = ($this->root instanceof VCalendar
221
+									  ? 'xcal'
222
+									  : 'xcard').':'.$propertyName;
223
+
224
+			switch ($propertyNameExtended) {
225
+				case 'xcal:geo':
226
+					$propertyType = 'float';
227
+					$propertyValue['latitude'] = 0;
228
+					$propertyValue['longitude'] = 0;
229
+
230
+					foreach ($xmlProperty['value'] as $xmlRequestChild) {
231
+						$propertyValue[static::getTagName($xmlRequestChild['name'])]
232
+							= $xmlRequestChild['value'];
233
+					}
234
+					break;
235
+
236
+				case 'xcal:request-status':
237
+					$propertyType = 'text';
238
+
239
+					foreach ($xmlProperty['value'] as $xmlRequestChild) {
240
+						$propertyValue[static::getTagName($xmlRequestChild['name'])]
241
+							= $xmlRequestChild['value'];
242
+					}
243
+					break;
244
+
245
+				case 'xcal:freebusy':
246
+					$propertyType = 'freebusy';
247
+					// We don't break because we only want to set
248
+					// another property type.
249
+
250
+					// no break
251
+				case 'xcal:categories':
252
+				case 'xcal:resources':
253
+				case 'xcal:exdate':
254
+					foreach ($xmlProperty['value'] as $specialChild) {
255
+						$propertyValue[static::getTagName($specialChild['name'])]
256
+							= $specialChild['value'];
257
+					}
258
+					break;
259
+
260
+				case 'xcal:rdate':
261
+					$propertyType = 'date-time';
262
+
263
+					foreach ($xmlProperty['value'] as $specialChild) {
264
+						$tagName = static::getTagName($specialChild['name']);
265
+
266
+						if ('period' === $tagName) {
267
+							$propertyParameters['value'] = 'PERIOD';
268
+							$propertyValue[] = implode('/', $specialChild['value']);
269
+						} else {
270
+							$propertyValue[] = $specialChild['value'];
271
+						}
272
+					}
273
+					break;
274
+
275
+				default:
276
+					$propertyType = static::getTagName($xmlProperty['value'][0]['name']);
277
+
278
+					foreach ($xmlProperty['value'] as $value) {
279
+						$propertyValue[] = $value['value'];
280
+					}
281
+
282
+					if ('date' === $propertyType) {
283
+						$propertyParameters['value'] = 'DATE';
284
+					}
285
+					break;
286
+			}
287
+
288
+			$this->createProperty(
289
+				$parentComponent,
290
+				$propertyNamePrefix.$propertyName,
291
+				$propertyParameters,
292
+				$propertyType,
293
+				$propertyValue
294
+			);
295
+		}
296
+	}
297
+
298
+	/**
299
+	 * Parse a component.
300
+	 */
301
+	protected function parseComponent(Component $parentComponent)
302
+	{
303
+		$components = $this->pointer['value'] ?: [];
304
+
305
+		foreach ($components as $component) {
306
+			$componentName = static::getTagName($component['name']);
307
+			$currentComponent = $this->root->createComponent(
308
+				$componentName,
309
+				null,
310
+				false
311
+			);
312
+
313
+			$this->pointer = &$component;
314
+			$this->parseVCalendarComponents($currentComponent);
315
+
316
+			$parentComponent->add($currentComponent);
317
+		}
318
+	}
319
+
320
+	/**
321
+	 * Create a property.
322
+	 *
323
+	 * @param string $name
324
+	 * @param array  $parameters
325
+	 * @param string $type
326
+	 * @param mixed  $value
327
+	 */
328
+	protected function createProperty(Component $parentComponent, $name, $parameters, $type, $value)
329
+	{
330
+		$property = $this->root->createProperty(
331
+			$name,
332
+			null,
333
+			$parameters,
334
+			$type
335
+		);
336
+		$parentComponent->add($property);
337
+		$property->setXmlValue($value);
338
+	}
339
+
340
+	/**
341
+	 * Sets the input data.
342
+	 *
343
+	 * @param resource|string $input
344
+	 */
345
+	public function setInput($input)
346
+	{
347
+		if (is_resource($input)) {
348
+			$input = stream_get_contents($input);
349
+		}
350
+
351
+		if (is_string($input)) {
352
+			$reader = new SabreXml\Reader();
353
+			$reader->elementMap['{'.self::XCAL_NAMESPACE.'}period']
354
+				= XML\Element\KeyValue::class;
355
+			$reader->elementMap['{'.self::XCAL_NAMESPACE.'}recur']
356
+				= XML\Element\KeyValue::class;
357
+			$reader->xml($input);
358
+			$input = $reader->parse();
359
+		}
360
+
361
+		$this->input = $input;
362
+	}
363
+
364
+	/**
365
+	 * Get tag name from a Clark notation.
366
+	 *
367
+	 * @param string $clarkedTagName
368
+	 *
369
+	 * @return string
370
+	 */
371
+	protected static function getTagName($clarkedTagName)
372
+	{
373
+		list(, $tagName) = SabreXml\Service::parseClarkNotation($clarkedTagName);
374
+
375
+		return $tagName;
376
+	}
377 377
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Parser/Json.php 2 patches
Indentation   +166 added lines, -166 removed lines patch added patch discarded remove patch
@@ -21,170 +21,170 @@
 block discarded – undo
21 21
  */
22 22
 class Json extends Parser
23 23
 {
24
-    /**
25
-     * The input data.
26
-     *
27
-     * @var array
28
-     */
29
-    protected $input;
30
-
31
-    /**
32
-     * Root component.
33
-     *
34
-     * @var Document
35
-     */
36
-    protected $root;
37
-
38
-    /**
39
-     * This method starts the parsing process.
40
-     *
41
-     * If the input was not supplied during construction, it's possible to pass
42
-     * it here instead.
43
-     *
44
-     * If either input or options are not supplied, the defaults will be used.
45
-     *
46
-     * @param resource|string|array|null $input
47
-     * @param int                        $options
48
-     *
49
-     * @return \Sabre\VObject\Document
50
-     */
51
-    public function parse($input = null, $options = 0)
52
-    {
53
-        if (!is_null($input)) {
54
-            $this->setInput($input);
55
-        }
56
-        if (is_null($this->input)) {
57
-            throw new EofException('End of input stream, or no input supplied');
58
-        }
59
-
60
-        if (0 !== $options) {
61
-            $this->options = $options;
62
-        }
63
-
64
-        switch ($this->input[0]) {
65
-            case 'vcalendar':
66
-                $this->root = new VCalendar([], false);
67
-                break;
68
-            case 'vcard':
69
-                $this->root = new VCard([], false);
70
-                break;
71
-            default:
72
-                throw new ParseException('The root component must either be a vcalendar, or a vcard');
73
-        }
74
-        foreach ($this->input[1] as $prop) {
75
-            $this->root->add($this->parseProperty($prop));
76
-        }
77
-        if (isset($this->input[2])) {
78
-            foreach ($this->input[2] as $comp) {
79
-                $this->root->add($this->parseComponent($comp));
80
-            }
81
-        }
82
-
83
-        // Resetting the input so we can throw an feof exception the next time.
84
-        $this->input = null;
85
-
86
-        return $this->root;
87
-    }
88
-
89
-    /**
90
-     * Parses a component.
91
-     *
92
-     * @return \Sabre\VObject\Component
93
-     */
94
-    public function parseComponent(array $jComp)
95
-    {
96
-        // We can remove $self from PHP 5.4 onward.
97
-        $self = $this;
98
-
99
-        $properties = array_map(
100
-            function ($jProp) use ($self) {
101
-                return $self->parseProperty($jProp);
102
-            },
103
-            $jComp[1]
104
-        );
105
-
106
-        if (isset($jComp[2])) {
107
-            $components = array_map(
108
-                function ($jComp) use ($self) {
109
-                    return $self->parseComponent($jComp);
110
-                },
111
-                $jComp[2]
112
-            );
113
-        } else {
114
-            $components = [];
115
-        }
116
-
117
-        return $this->root->createComponent(
118
-            $jComp[0],
119
-            array_merge($properties, $components),
120
-            $defaults = false
121
-        );
122
-    }
123
-
124
-    /**
125
-     * Parses properties.
126
-     *
127
-     * @return \Sabre\VObject\Property
128
-     */
129
-    public function parseProperty(array $jProp)
130
-    {
131
-        list(
132
-            $propertyName,
133
-            $parameters,
134
-            $valueType
135
-        ) = $jProp;
136
-
137
-        $propertyName = strtoupper($propertyName);
138
-
139
-        // This is the default class we would be using if we didn't know the
140
-        // value type. We're using this value later in this function.
141
-        $defaultPropertyClass = $this->root->getClassNameForPropertyName($propertyName);
142
-
143
-        $parameters = (array) $parameters;
144
-
145
-        $value = array_slice($jProp, 3);
146
-
147
-        $valueType = strtoupper($valueType);
148
-
149
-        if (isset($parameters['group'])) {
150
-            $propertyName = $parameters['group'].'.'.$propertyName;
151
-            unset($parameters['group']);
152
-        }
153
-
154
-        $prop = $this->root->createProperty($propertyName, null, $parameters, $valueType);
155
-        $prop->setJsonValue($value);
156
-
157
-        // We have to do something awkward here. FlatText as well as Text
158
-        // represents TEXT values. We have to normalize these here. In the
159
-        // future we can get rid of FlatText once we're allowed to break BC
160
-        // again.
161
-        if (FlatText::class === $defaultPropertyClass) {
162
-            $defaultPropertyClass = Text::class;
163
-        }
164
-
165
-        // If the value type we received (e.g.: TEXT) was not the default value
166
-        // type for the given property (e.g.: BDAY), we need to add a VALUE=
167
-        // parameter.
168
-        if ($defaultPropertyClass !== get_class($prop)) {
169
-            $prop['VALUE'] = $valueType;
170
-        }
171
-
172
-        return $prop;
173
-    }
174
-
175
-    /**
176
-     * Sets the input data.
177
-     *
178
-     * @param resource|string|array $input
179
-     */
180
-    public function setInput($input)
181
-    {
182
-        if (is_resource($input)) {
183
-            $input = stream_get_contents($input);
184
-        }
185
-        if (is_string($input)) {
186
-            $input = json_decode($input);
187
-        }
188
-        $this->input = $input;
189
-    }
24
+	/**
25
+	 * The input data.
26
+	 *
27
+	 * @var array
28
+	 */
29
+	protected $input;
30
+
31
+	/**
32
+	 * Root component.
33
+	 *
34
+	 * @var Document
35
+	 */
36
+	protected $root;
37
+
38
+	/**
39
+	 * This method starts the parsing process.
40
+	 *
41
+	 * If the input was not supplied during construction, it's possible to pass
42
+	 * it here instead.
43
+	 *
44
+	 * If either input or options are not supplied, the defaults will be used.
45
+	 *
46
+	 * @param resource|string|array|null $input
47
+	 * @param int                        $options
48
+	 *
49
+	 * @return \Sabre\VObject\Document
50
+	 */
51
+	public function parse($input = null, $options = 0)
52
+	{
53
+		if (!is_null($input)) {
54
+			$this->setInput($input);
55
+		}
56
+		if (is_null($this->input)) {
57
+			throw new EofException('End of input stream, or no input supplied');
58
+		}
59
+
60
+		if (0 !== $options) {
61
+			$this->options = $options;
62
+		}
63
+
64
+		switch ($this->input[0]) {
65
+			case 'vcalendar':
66
+				$this->root = new VCalendar([], false);
67
+				break;
68
+			case 'vcard':
69
+				$this->root = new VCard([], false);
70
+				break;
71
+			default:
72
+				throw new ParseException('The root component must either be a vcalendar, or a vcard');
73
+		}
74
+		foreach ($this->input[1] as $prop) {
75
+			$this->root->add($this->parseProperty($prop));
76
+		}
77
+		if (isset($this->input[2])) {
78
+			foreach ($this->input[2] as $comp) {
79
+				$this->root->add($this->parseComponent($comp));
80
+			}
81
+		}
82
+
83
+		// Resetting the input so we can throw an feof exception the next time.
84
+		$this->input = null;
85
+
86
+		return $this->root;
87
+	}
88
+
89
+	/**
90
+	 * Parses a component.
91
+	 *
92
+	 * @return \Sabre\VObject\Component
93
+	 */
94
+	public function parseComponent(array $jComp)
95
+	{
96
+		// We can remove $self from PHP 5.4 onward.
97
+		$self = $this;
98
+
99
+		$properties = array_map(
100
+			function ($jProp) use ($self) {
101
+				return $self->parseProperty($jProp);
102
+			},
103
+			$jComp[1]
104
+		);
105
+
106
+		if (isset($jComp[2])) {
107
+			$components = array_map(
108
+				function ($jComp) use ($self) {
109
+					return $self->parseComponent($jComp);
110
+				},
111
+				$jComp[2]
112
+			);
113
+		} else {
114
+			$components = [];
115
+		}
116
+
117
+		return $this->root->createComponent(
118
+			$jComp[0],
119
+			array_merge($properties, $components),
120
+			$defaults = false
121
+		);
122
+	}
123
+
124
+	/**
125
+	 * Parses properties.
126
+	 *
127
+	 * @return \Sabre\VObject\Property
128
+	 */
129
+	public function parseProperty(array $jProp)
130
+	{
131
+		list(
132
+			$propertyName,
133
+			$parameters,
134
+			$valueType
135
+		) = $jProp;
136
+
137
+		$propertyName = strtoupper($propertyName);
138
+
139
+		// This is the default class we would be using if we didn't know the
140
+		// value type. We're using this value later in this function.
141
+		$defaultPropertyClass = $this->root->getClassNameForPropertyName($propertyName);
142
+
143
+		$parameters = (array) $parameters;
144
+
145
+		$value = array_slice($jProp, 3);
146
+
147
+		$valueType = strtoupper($valueType);
148
+
149
+		if (isset($parameters['group'])) {
150
+			$propertyName = $parameters['group'].'.'.$propertyName;
151
+			unset($parameters['group']);
152
+		}
153
+
154
+		$prop = $this->root->createProperty($propertyName, null, $parameters, $valueType);
155
+		$prop->setJsonValue($value);
156
+
157
+		// We have to do something awkward here. FlatText as well as Text
158
+		// represents TEXT values. We have to normalize these here. In the
159
+		// future we can get rid of FlatText once we're allowed to break BC
160
+		// again.
161
+		if (FlatText::class === $defaultPropertyClass) {
162
+			$defaultPropertyClass = Text::class;
163
+		}
164
+
165
+		// If the value type we received (e.g.: TEXT) was not the default value
166
+		// type for the given property (e.g.: BDAY), we need to add a VALUE=
167
+		// parameter.
168
+		if ($defaultPropertyClass !== get_class($prop)) {
169
+			$prop['VALUE'] = $valueType;
170
+		}
171
+
172
+		return $prop;
173
+	}
174
+
175
+	/**
176
+	 * Sets the input data.
177
+	 *
178
+	 * @param resource|string|array $input
179
+	 */
180
+	public function setInput($input)
181
+	{
182
+		if (is_resource($input)) {
183
+			$input = stream_get_contents($input);
184
+		}
185
+		if (is_string($input)) {
186
+			$input = json_decode($input);
187
+		}
188
+		$this->input = $input;
189
+	}
190 190
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -97,7 +97,7 @@  discard block
 block discarded – undo
97 97
         $self = $this;
98 98
 
99 99
         $properties = array_map(
100
-            function ($jProp) use ($self) {
100
+            function($jProp) use ($self) {
101 101
                 return $self->parseProperty($jProp);
102 102
             },
103 103
             $jComp[1]
@@ -105,7 +105,7 @@  discard block
 block discarded – undo
105 105
 
106 106
         if (isset($jComp[2])) {
107 107
             $components = array_map(
108
-                function ($jComp) use ($self) {
108
+                function($jComp) use ($self) {
109 109
                     return $self->parseComponent($jComp);
110 110
                 },
111 111
                 $jComp[2]
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Parser/Parser.php 1 patch
Indentation   +54 added lines, -54 removed lines patch added patch discarded remove patch
@@ -13,63 +13,63 @@
 block discarded – undo
13 13
  */
14 14
 abstract class Parser
15 15
 {
16
-    /**
17
-     * Turning on this option makes the parser more forgiving.
18
-     *
19
-     * In the case of the MimeDir parser, this means that the parser will
20
-     * accept slashes and underscores in property names, and it will also
21
-     * attempt to fix Microsoft vCard 2.1's broken line folding.
22
-     */
23
-    const OPTION_FORGIVING = 1;
16
+	/**
17
+	 * Turning on this option makes the parser more forgiving.
18
+	 *
19
+	 * In the case of the MimeDir parser, this means that the parser will
20
+	 * accept slashes and underscores in property names, and it will also
21
+	 * attempt to fix Microsoft vCard 2.1's broken line folding.
22
+	 */
23
+	const OPTION_FORGIVING = 1;
24 24
 
25
-    /**
26
-     * If this option is turned on, any lines we cannot parse will be ignored
27
-     * by the reader.
28
-     */
29
-    const OPTION_IGNORE_INVALID_LINES = 2;
25
+	/**
26
+	 * If this option is turned on, any lines we cannot parse will be ignored
27
+	 * by the reader.
28
+	 */
29
+	const OPTION_IGNORE_INVALID_LINES = 2;
30 30
 
31
-    /**
32
-     * Bitmask of parser options.
33
-     *
34
-     * @var int
35
-     */
36
-    protected $options;
31
+	/**
32
+	 * Bitmask of parser options.
33
+	 *
34
+	 * @var int
35
+	 */
36
+	protected $options;
37 37
 
38
-    /**
39
-     * Creates the parser.
40
-     *
41
-     * Optionally, it's possible to parse the input stream here.
42
-     *
43
-     * @param mixed $input
44
-     * @param int   $options any parser options (OPTION constants)
45
-     */
46
-    public function __construct($input = null, $options = 0)
47
-    {
48
-        if (!is_null($input)) {
49
-            $this->setInput($input);
50
-        }
51
-        $this->options = $options;
52
-    }
38
+	/**
39
+	 * Creates the parser.
40
+	 *
41
+	 * Optionally, it's possible to parse the input stream here.
42
+	 *
43
+	 * @param mixed $input
44
+	 * @param int   $options any parser options (OPTION constants)
45
+	 */
46
+	public function __construct($input = null, $options = 0)
47
+	{
48
+		if (!is_null($input)) {
49
+			$this->setInput($input);
50
+		}
51
+		$this->options = $options;
52
+	}
53 53
 
54
-    /**
55
-     * This method starts the parsing process.
56
-     *
57
-     * If the input was not supplied during construction, it's possible to pass
58
-     * it here instead.
59
-     *
60
-     * If either input or options are not supplied, the defaults will be used.
61
-     *
62
-     * @param mixed $input
63
-     * @param int   $options
64
-     *
65
-     * @return array
66
-     */
67
-    abstract public function parse($input = null, $options = 0);
54
+	/**
55
+	 * This method starts the parsing process.
56
+	 *
57
+	 * If the input was not supplied during construction, it's possible to pass
58
+	 * it here instead.
59
+	 *
60
+	 * If either input or options are not supplied, the defaults will be used.
61
+	 *
62
+	 * @param mixed $input
63
+	 * @param int   $options
64
+	 *
65
+	 * @return array
66
+	 */
67
+	abstract public function parse($input = null, $options = 0);
68 68
 
69
-    /**
70
-     * Sets the input data.
71
-     *
72
-     * @param mixed $input
73
-     */
74
-    abstract public function setInput($input);
69
+	/**
70
+	 * Sets the input data.
71
+	 *
72
+	 * @param mixed $input
73
+	 */
74
+	abstract public function setInput($input);
75 75
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Parser/MimeDir.php 2 patches
Indentation   +628 added lines, -628 removed lines patch added patch discarded remove patch
@@ -25,316 +25,316 @@  discard block
 block discarded – undo
25 25
  */
26 26
 class MimeDir extends Parser
27 27
 {
28
-    /**
29
-     * The input stream.
30
-     *
31
-     * @var resource
32
-     */
33
-    protected $input;
34
-
35
-    /**
36
-     * Root component.
37
-     *
38
-     * @var Component
39
-     */
40
-    protected $root;
41
-
42
-    /**
43
-     * By default all input will be assumed to be UTF-8.
44
-     *
45
-     * However, both iCalendar and vCard might be encoded using different
46
-     * character sets. The character set is usually set in the mime-type.
47
-     *
48
-     * If this is the case, use setEncoding to specify that a different
49
-     * encoding will be used. If this is set, the parser will automatically
50
-     * convert all incoming data to UTF-8.
51
-     *
52
-     * @var string
53
-     */
54
-    protected $charset = 'UTF-8';
55
-
56
-    /**
57
-     * The list of character sets we support when decoding.
58
-     *
59
-     * This would be a const expression but for now we need to support PHP 5.5
60
-     */
61
-    protected static $SUPPORTED_CHARSETS = [
62
-        'UTF-8',
63
-        'ISO-8859-1',
64
-        'Windows-1252',
65
-    ];
66
-
67
-    /**
68
-     * Parses an iCalendar or vCard file.
69
-     *
70
-     * Pass a stream or a string. If null is parsed, the existing buffer is
71
-     * used.
72
-     *
73
-     * @param string|resource|null $input
74
-     * @param int                  $options
75
-     *
76
-     * @return \Sabre\VObject\Document
77
-     */
78
-    public function parse($input = null, $options = 0)
79
-    {
80
-        $this->root = null;
81
-
82
-        if (!is_null($input)) {
83
-            $this->setInput($input);
84
-        }
85
-
86
-        if (0 !== $options) {
87
-            $this->options = $options;
88
-        }
89
-
90
-        $this->parseDocument();
91
-
92
-        return $this->root;
93
-    }
94
-
95
-    /**
96
-     * By default all input will be assumed to be UTF-8.
97
-     *
98
-     * However, both iCalendar and vCard might be encoded using different
99
-     * character sets. The character set is usually set in the mime-type.
100
-     *
101
-     * If this is the case, use setEncoding to specify that a different
102
-     * encoding will be used. If this is set, the parser will automatically
103
-     * convert all incoming data to UTF-8.
104
-     *
105
-     * @param string $charset
106
-     */
107
-    public function setCharset($charset)
108
-    {
109
-        if (!in_array($charset, self::$SUPPORTED_CHARSETS)) {
110
-            throw new \InvalidArgumentException('Unsupported encoding. (Supported encodings: '.implode(', ', self::$SUPPORTED_CHARSETS).')');
111
-        }
112
-        $this->charset = $charset;
113
-    }
114
-
115
-    /**
116
-     * Sets the input buffer. Must be a string or stream.
117
-     *
118
-     * @param resource|string $input
119
-     */
120
-    public function setInput($input)
121
-    {
122
-        // Resetting the parser
123
-        $this->lineIndex = 0;
124
-        $this->startLine = 0;
125
-
126
-        if (is_string($input)) {
127
-            // Converting to a stream.
128
-            $stream = fopen('php://temp', 'r+');
129
-            fwrite($stream, $input);
130
-            rewind($stream);
131
-            $this->input = $stream;
132
-        } elseif (is_resource($input)) {
133
-            $this->input = $input;
134
-        } else {
135
-            throw new \InvalidArgumentException('This parser can only read from strings or streams.');
136
-        }
137
-    }
138
-
139
-    /**
140
-     * Parses an entire document.
141
-     */
142
-    protected function parseDocument()
143
-    {
144
-        $line = $this->readLine();
145
-
146
-        // BOM is ZERO WIDTH NO-BREAK SPACE (U+FEFF).
147
-        // It's 0xEF 0xBB 0xBF in UTF-8 hex.
148
-        if (3 <= strlen($line)
149
-            && 0xef === ord($line[0])
150
-            && 0xbb === ord($line[1])
151
-            && 0xbf === ord($line[2])) {
152
-            $line = substr($line, 3);
153
-        }
154
-
155
-        switch (strtoupper($line)) {
156
-            case 'BEGIN:VCALENDAR':
157
-                $class = VCalendar::$componentMap['VCALENDAR'];
158
-                break;
159
-            case 'BEGIN:VCARD':
160
-                $class = VCard::$componentMap['VCARD'];
161
-                break;
162
-            default:
163
-                throw new ParseException('This parser only supports VCARD and VCALENDAR files');
164
-        }
165
-
166
-        $this->root = new $class([], false);
167
-
168
-        while (true) {
169
-            // Reading until we hit END:
170
-            try {
171
-                $line = $this->readLine();
172
-            } catch (EofException $oEx) {
173
-                $line = 'END:'.$this->root->name;
174
-            }
175
-            if ('END:' === strtoupper(substr($line, 0, 4))) {
176
-                break;
177
-            }
178
-            $result = $this->parseLine($line);
179
-            if ($result) {
180
-                $this->root->add($result);
181
-            }
182
-        }
183
-
184
-        $name = strtoupper(substr($line, 4));
185
-        if ($name !== $this->root->name) {
186
-            throw new ParseException('Invalid MimeDir file. expected: "END:'.$this->root->name.'" got: "END:'.$name.'"');
187
-        }
188
-    }
189
-
190
-    /**
191
-     * Parses a line, and if it hits a component, it will also attempt to parse
192
-     * the entire component.
193
-     *
194
-     * @param string $line Unfolded line
195
-     *
196
-     * @return Node
197
-     */
198
-    protected function parseLine($line)
199
-    {
200
-        // Start of a new component
201
-        if ('BEGIN:' === strtoupper(substr($line, 0, 6))) {
202
-            if (substr($line, 6) === $this->root->name) {
203
-                throw new ParseException('Invalid MimeDir file. Unexpected component: "'.$line.'" in document type '.$this->root->name);
204
-            }
205
-            $component = $this->root->createComponent(substr($line, 6), [], false);
206
-
207
-            while (true) {
208
-                // Reading until we hit END:
209
-                $line = $this->readLine();
210
-                if ('END:' === strtoupper(substr($line, 0, 4))) {
211
-                    break;
212
-                }
213
-                $result = $this->parseLine($line);
214
-                if ($result) {
215
-                    $component->add($result);
216
-                }
217
-            }
218
-
219
-            $name = strtoupper(substr($line, 4));
220
-            if ($name !== $component->name) {
221
-                throw new ParseException('Invalid MimeDir file. expected: "END:'.$component->name.'" got: "END:'.$name.'"');
222
-            }
223
-
224
-            return $component;
225
-        } else {
226
-            // Property reader
227
-            $property = $this->readProperty($line);
228
-            if (!$property) {
229
-                // Ignored line
230
-                return false;
231
-            }
232
-
233
-            return $property;
234
-        }
235
-    }
236
-
237
-    /**
238
-     * We need to look ahead 1 line every time to see if we need to 'unfold'
239
-     * the next line.
240
-     *
241
-     * If that was not the case, we store it here.
242
-     *
243
-     * @var string|null
244
-     */
245
-    protected $lineBuffer;
246
-
247
-    /**
248
-     * The real current line number.
249
-     */
250
-    protected $lineIndex = 0;
251
-
252
-    /**
253
-     * In the case of unfolded lines, this property holds the line number for
254
-     * the start of the line.
255
-     *
256
-     * @var int
257
-     */
258
-    protected $startLine = 0;
259
-
260
-    /**
261
-     * Contains a 'raw' representation of the current line.
262
-     *
263
-     * @var string
264
-     */
265
-    protected $rawLine;
266
-
267
-    /**
268
-     * Reads a single line from the buffer.
269
-     *
270
-     * This method strips any newlines and also takes care of unfolding.
271
-     *
272
-     * @throws \Sabre\VObject\EofException
273
-     *
274
-     * @return string
275
-     */
276
-    protected function readLine()
277
-    {
278
-        if (!\is_null($this->lineBuffer)) {
279
-            $rawLine = $this->lineBuffer;
280
-            $this->lineBuffer = null;
281
-        } else {
282
-            do {
283
-                $eof = \feof($this->input);
284
-
285
-                $rawLine = \fgets($this->input);
286
-
287
-                if ($eof || (\feof($this->input) && false === $rawLine)) {
288
-                    throw new EofException('End of document reached prematurely');
289
-                }
290
-                if (false === $rawLine) {
291
-                    throw new ParseException('Error reading from input stream');
292
-                }
293
-                $rawLine = \rtrim($rawLine, "\r\n");
294
-            } while ('' === $rawLine); // Skipping empty lines
295
-            ++$this->lineIndex;
296
-        }
297
-        $line = $rawLine;
298
-
299
-        $this->startLine = $this->lineIndex;
300
-
301
-        // Looking ahead for folded lines.
302
-        while (true) {
303
-            $nextLine = \rtrim(\fgets($this->input), "\r\n");
304
-            ++$this->lineIndex;
305
-            if (!$nextLine) {
306
-                break;
307
-            }
308
-            if ("\t" === $nextLine[0] || ' ' === $nextLine[0]) {
309
-                $curLine = \substr($nextLine, 1);
310
-                $line .= $curLine;
311
-                $rawLine .= "\n ".$curLine;
312
-            } else {
313
-                $this->lineBuffer = $nextLine;
314
-                break;
315
-            }
316
-        }
317
-        $this->rawLine = $rawLine;
318
-
319
-        return $line;
320
-    }
321
-
322
-    /**
323
-     * Reads a property or component from a line.
324
-     */
325
-    protected function readProperty($line)
326
-    {
327
-        if ($this->options & self::OPTION_FORGIVING) {
328
-            $propNameToken = 'A-Z0-9\-\._\\/';
329
-        } else {
330
-            $propNameToken = 'A-Z0-9\-\.';
331
-        }
332
-
333
-        $paramNameToken = 'A-Z0-9\-';
334
-        $safeChar = '^";:,';
335
-        $qSafeChar = '^"';
336
-
337
-        $regex = "/
28
+	/**
29
+	 * The input stream.
30
+	 *
31
+	 * @var resource
32
+	 */
33
+	protected $input;
34
+
35
+	/**
36
+	 * Root component.
37
+	 *
38
+	 * @var Component
39
+	 */
40
+	protected $root;
41
+
42
+	/**
43
+	 * By default all input will be assumed to be UTF-8.
44
+	 *
45
+	 * However, both iCalendar and vCard might be encoded using different
46
+	 * character sets. The character set is usually set in the mime-type.
47
+	 *
48
+	 * If this is the case, use setEncoding to specify that a different
49
+	 * encoding will be used. If this is set, the parser will automatically
50
+	 * convert all incoming data to UTF-8.
51
+	 *
52
+	 * @var string
53
+	 */
54
+	protected $charset = 'UTF-8';
55
+
56
+	/**
57
+	 * The list of character sets we support when decoding.
58
+	 *
59
+	 * This would be a const expression but for now we need to support PHP 5.5
60
+	 */
61
+	protected static $SUPPORTED_CHARSETS = [
62
+		'UTF-8',
63
+		'ISO-8859-1',
64
+		'Windows-1252',
65
+	];
66
+
67
+	/**
68
+	 * Parses an iCalendar or vCard file.
69
+	 *
70
+	 * Pass a stream or a string. If null is parsed, the existing buffer is
71
+	 * used.
72
+	 *
73
+	 * @param string|resource|null $input
74
+	 * @param int                  $options
75
+	 *
76
+	 * @return \Sabre\VObject\Document
77
+	 */
78
+	public function parse($input = null, $options = 0)
79
+	{
80
+		$this->root = null;
81
+
82
+		if (!is_null($input)) {
83
+			$this->setInput($input);
84
+		}
85
+
86
+		if (0 !== $options) {
87
+			$this->options = $options;
88
+		}
89
+
90
+		$this->parseDocument();
91
+
92
+		return $this->root;
93
+	}
94
+
95
+	/**
96
+	 * By default all input will be assumed to be UTF-8.
97
+	 *
98
+	 * However, both iCalendar and vCard might be encoded using different
99
+	 * character sets. The character set is usually set in the mime-type.
100
+	 *
101
+	 * If this is the case, use setEncoding to specify that a different
102
+	 * encoding will be used. If this is set, the parser will automatically
103
+	 * convert all incoming data to UTF-8.
104
+	 *
105
+	 * @param string $charset
106
+	 */
107
+	public function setCharset($charset)
108
+	{
109
+		if (!in_array($charset, self::$SUPPORTED_CHARSETS)) {
110
+			throw new \InvalidArgumentException('Unsupported encoding. (Supported encodings: '.implode(', ', self::$SUPPORTED_CHARSETS).')');
111
+		}
112
+		$this->charset = $charset;
113
+	}
114
+
115
+	/**
116
+	 * Sets the input buffer. Must be a string or stream.
117
+	 *
118
+	 * @param resource|string $input
119
+	 */
120
+	public function setInput($input)
121
+	{
122
+		// Resetting the parser
123
+		$this->lineIndex = 0;
124
+		$this->startLine = 0;
125
+
126
+		if (is_string($input)) {
127
+			// Converting to a stream.
128
+			$stream = fopen('php://temp', 'r+');
129
+			fwrite($stream, $input);
130
+			rewind($stream);
131
+			$this->input = $stream;
132
+		} elseif (is_resource($input)) {
133
+			$this->input = $input;
134
+		} else {
135
+			throw new \InvalidArgumentException('This parser can only read from strings or streams.');
136
+		}
137
+	}
138
+
139
+	/**
140
+	 * Parses an entire document.
141
+	 */
142
+	protected function parseDocument()
143
+	{
144
+		$line = $this->readLine();
145
+
146
+		// BOM is ZERO WIDTH NO-BREAK SPACE (U+FEFF).
147
+		// It's 0xEF 0xBB 0xBF in UTF-8 hex.
148
+		if (3 <= strlen($line)
149
+			&& 0xef === ord($line[0])
150
+			&& 0xbb === ord($line[1])
151
+			&& 0xbf === ord($line[2])) {
152
+			$line = substr($line, 3);
153
+		}
154
+
155
+		switch (strtoupper($line)) {
156
+			case 'BEGIN:VCALENDAR':
157
+				$class = VCalendar::$componentMap['VCALENDAR'];
158
+				break;
159
+			case 'BEGIN:VCARD':
160
+				$class = VCard::$componentMap['VCARD'];
161
+				break;
162
+			default:
163
+				throw new ParseException('This parser only supports VCARD and VCALENDAR files');
164
+		}
165
+
166
+		$this->root = new $class([], false);
167
+
168
+		while (true) {
169
+			// Reading until we hit END:
170
+			try {
171
+				$line = $this->readLine();
172
+			} catch (EofException $oEx) {
173
+				$line = 'END:'.$this->root->name;
174
+			}
175
+			if ('END:' === strtoupper(substr($line, 0, 4))) {
176
+				break;
177
+			}
178
+			$result = $this->parseLine($line);
179
+			if ($result) {
180
+				$this->root->add($result);
181
+			}
182
+		}
183
+
184
+		$name = strtoupper(substr($line, 4));
185
+		if ($name !== $this->root->name) {
186
+			throw new ParseException('Invalid MimeDir file. expected: "END:'.$this->root->name.'" got: "END:'.$name.'"');
187
+		}
188
+	}
189
+
190
+	/**
191
+	 * Parses a line, and if it hits a component, it will also attempt to parse
192
+	 * the entire component.
193
+	 *
194
+	 * @param string $line Unfolded line
195
+	 *
196
+	 * @return Node
197
+	 */
198
+	protected function parseLine($line)
199
+	{
200
+		// Start of a new component
201
+		if ('BEGIN:' === strtoupper(substr($line, 0, 6))) {
202
+			if (substr($line, 6) === $this->root->name) {
203
+				throw new ParseException('Invalid MimeDir file. Unexpected component: "'.$line.'" in document type '.$this->root->name);
204
+			}
205
+			$component = $this->root->createComponent(substr($line, 6), [], false);
206
+
207
+			while (true) {
208
+				// Reading until we hit END:
209
+				$line = $this->readLine();
210
+				if ('END:' === strtoupper(substr($line, 0, 4))) {
211
+					break;
212
+				}
213
+				$result = $this->parseLine($line);
214
+				if ($result) {
215
+					$component->add($result);
216
+				}
217
+			}
218
+
219
+			$name = strtoupper(substr($line, 4));
220
+			if ($name !== $component->name) {
221
+				throw new ParseException('Invalid MimeDir file. expected: "END:'.$component->name.'" got: "END:'.$name.'"');
222
+			}
223
+
224
+			return $component;
225
+		} else {
226
+			// Property reader
227
+			$property = $this->readProperty($line);
228
+			if (!$property) {
229
+				// Ignored line
230
+				return false;
231
+			}
232
+
233
+			return $property;
234
+		}
235
+	}
236
+
237
+	/**
238
+	 * We need to look ahead 1 line every time to see if we need to 'unfold'
239
+	 * the next line.
240
+	 *
241
+	 * If that was not the case, we store it here.
242
+	 *
243
+	 * @var string|null
244
+	 */
245
+	protected $lineBuffer;
246
+
247
+	/**
248
+	 * The real current line number.
249
+	 */
250
+	protected $lineIndex = 0;
251
+
252
+	/**
253
+	 * In the case of unfolded lines, this property holds the line number for
254
+	 * the start of the line.
255
+	 *
256
+	 * @var int
257
+	 */
258
+	protected $startLine = 0;
259
+
260
+	/**
261
+	 * Contains a 'raw' representation of the current line.
262
+	 *
263
+	 * @var string
264
+	 */
265
+	protected $rawLine;
266
+
267
+	/**
268
+	 * Reads a single line from the buffer.
269
+	 *
270
+	 * This method strips any newlines and also takes care of unfolding.
271
+	 *
272
+	 * @throws \Sabre\VObject\EofException
273
+	 *
274
+	 * @return string
275
+	 */
276
+	protected function readLine()
277
+	{
278
+		if (!\is_null($this->lineBuffer)) {
279
+			$rawLine = $this->lineBuffer;
280
+			$this->lineBuffer = null;
281
+		} else {
282
+			do {
283
+				$eof = \feof($this->input);
284
+
285
+				$rawLine = \fgets($this->input);
286
+
287
+				if ($eof || (\feof($this->input) && false === $rawLine)) {
288
+					throw new EofException('End of document reached prematurely');
289
+				}
290
+				if (false === $rawLine) {
291
+					throw new ParseException('Error reading from input stream');
292
+				}
293
+				$rawLine = \rtrim($rawLine, "\r\n");
294
+			} while ('' === $rawLine); // Skipping empty lines
295
+			++$this->lineIndex;
296
+		}
297
+		$line = $rawLine;
298
+
299
+		$this->startLine = $this->lineIndex;
300
+
301
+		// Looking ahead for folded lines.
302
+		while (true) {
303
+			$nextLine = \rtrim(\fgets($this->input), "\r\n");
304
+			++$this->lineIndex;
305
+			if (!$nextLine) {
306
+				break;
307
+			}
308
+			if ("\t" === $nextLine[0] || ' ' === $nextLine[0]) {
309
+				$curLine = \substr($nextLine, 1);
310
+				$line .= $curLine;
311
+				$rawLine .= "\n ".$curLine;
312
+			} else {
313
+				$this->lineBuffer = $nextLine;
314
+				break;
315
+			}
316
+		}
317
+		$this->rawLine = $rawLine;
318
+
319
+		return $line;
320
+	}
321
+
322
+	/**
323
+	 * Reads a property or component from a line.
324
+	 */
325
+	protected function readProperty($line)
326
+	{
327
+		if ($this->options & self::OPTION_FORGIVING) {
328
+			$propNameToken = 'A-Z0-9\-\._\\/';
329
+		} else {
330
+			$propNameToken = 'A-Z0-9\-\.';
331
+		}
332
+
333
+		$paramNameToken = 'A-Z0-9\-';
334
+		$safeChar = '^";:,';
335
+		$qSafeChar = '^"';
336
+
337
+		$regex = "/
338 338
             ^(?P<name> [$propNameToken]+ ) (?=[;:])        # property name
339 339
             |
340 340
             (?<=:)(?P<propValue> .+)$                      # property value
@@ -347,337 +347,337 @@  discard block
 block discarded – undo
347 347
             ) (?=[;:,])
348 348
             /xi";
349 349
 
350
-        //echo $regex, "\n"; exit();
351
-        preg_match_all($regex, $line, $matches, PREG_SET_ORDER);
350
+		//echo $regex, "\n"; exit();
351
+		preg_match_all($regex, $line, $matches, PREG_SET_ORDER);
352 352
 
353
-        $property = [
354
-            'name' => null,
355
-            'parameters' => [],
356
-            'value' => null,
357
-        ];
353
+		$property = [
354
+			'name' => null,
355
+			'parameters' => [],
356
+			'value' => null,
357
+		];
358 358
 
359
-        $lastParam = null;
359
+		$lastParam = null;
360 360
 
361
-        /*
361
+		/*
362 362
          * Looping through all the tokens.
363 363
          *
364 364
          * Note that we are looping through them in reverse order, because if a
365 365
          * sub-pattern matched, the subsequent named patterns will not show up
366 366
          * in the result.
367 367
          */
368
-        foreach ($matches as $match) {
369
-            if (isset($match['paramValue'])) {
370
-                if ($match['paramValue'] && '"' === $match['paramValue'][0]) {
371
-                    $value = substr($match['paramValue'], 1, -1);
372
-                } else {
373
-                    $value = $match['paramValue'];
374
-                }
375
-
376
-                $value = $this->unescapeParam($value);
377
-
378
-                if (is_null($lastParam)) {
379
-                    if ($this->options & self::OPTION_IGNORE_INVALID_LINES) {
380
-                        // When the property can't be matched and the configuration
381
-                        // option is set to ignore invalid lines, we ignore this line
382
-                        // This can happen when servers provide faulty data as iCloud
383
-                        //  frequently does with X-APPLE-STRUCTURED-LOCATION
384
-                        continue;
385
-                    }
386
-                    throw new ParseException('Invalid Mimedir file. Line starting at '.$this->startLine.' did not follow iCalendar/vCard conventions');
387
-                }
388
-                if (is_null($property['parameters'][$lastParam])) {
389
-                    $property['parameters'][$lastParam] = $value;
390
-                } elseif (is_array($property['parameters'][$lastParam])) {
391
-                    $property['parameters'][$lastParam][] = $value;
392
-                } elseif ($property['parameters'][$lastParam] === $value) {
393
-                    // When the current value of the parameter is the same as the
394
-                    // new one, then we can leave the current parameter as it is.
395
-                } else {
396
-                    $property['parameters'][$lastParam] = [
397
-                        $property['parameters'][$lastParam],
398
-                        $value,
399
-                    ];
400
-                }
401
-                continue;
402
-            }
403
-            if (isset($match['paramName'])) {
404
-                $lastParam = strtoupper($match['paramName']);
405
-                if (!isset($property['parameters'][$lastParam])) {
406
-                    $property['parameters'][$lastParam] = null;
407
-                }
408
-                continue;
409
-            }
410
-            if (isset($match['propValue'])) {
411
-                $property['value'] = $match['propValue'];
412
-                continue;
413
-            }
414
-            if (isset($match['name']) && $match['name']) {
415
-                $property['name'] = strtoupper($match['name']);
416
-                continue;
417
-            }
418
-
419
-            // @codeCoverageIgnoreStart
420
-            throw new \LogicException('This code should not be reachable');
421
-            // @codeCoverageIgnoreEnd
422
-        }
423
-
424
-        if (is_null($property['value'])) {
425
-            $property['value'] = '';
426
-        }
427
-        if (!$property['name']) {
428
-            if ($this->options & self::OPTION_IGNORE_INVALID_LINES) {
429
-                return false;
430
-            }
431
-            throw new ParseException('Invalid Mimedir file. Line starting at '.$this->startLine.' did not follow iCalendar/vCard conventions');
432
-        }
433
-
434
-        // vCard 2.1 states that parameters may appear without a name, and only
435
-        // a value. We can deduce the value based on its name.
436
-        //
437
-        // Our parser will get those as parameters without a value instead, so
438
-        // we're filtering these parameters out first.
439
-        $namedParameters = [];
440
-        $namelessParameters = [];
441
-
442
-        foreach ($property['parameters'] as $name => $value) {
443
-            if (!is_null($value)) {
444
-                $namedParameters[$name] = $value;
445
-            } else {
446
-                $namelessParameters[] = $name;
447
-            }
448
-        }
449
-
450
-        $propObj = $this->root->createProperty($property['name'], null, $namedParameters);
451
-
452
-        foreach ($namelessParameters as $namelessParameter) {
453
-            $propObj->add(null, $namelessParameter);
454
-        }
455
-
456
-        if (isset($propObj['ENCODING']) && 'QUOTED-PRINTABLE' === strtoupper($propObj['ENCODING'])) {
457
-            $propObj->setQuotedPrintableValue($this->extractQuotedPrintableValue());
458
-        } else {
459
-            $charset = $this->charset;
460
-            if (Document::VCARD21 === $this->root->getDocumentType() && isset($propObj['CHARSET'])) {
461
-                // vCard 2.1 allows the character set to be specified per property.
462
-                $charset = (string) $propObj['CHARSET'];
463
-            }
464
-            switch (strtolower($charset)) {
465
-                case 'utf-8':
466
-                    break;
467
-                case 'windows-1252':
468
-                case 'iso-8859-1':
469
-                    $property['value'] = mb_convert_encoding($property['value'], 'UTF-8', $charset);
470
-                    break;
471
-                default:
472
-                    throw new ParseException('Unsupported CHARSET: '.$propObj['CHARSET']);
473
-            }
474
-            $propObj->setRawMimeDirValue($property['value']);
475
-        }
476
-
477
-        return $propObj;
478
-    }
479
-
480
-    /**
481
-     * Unescapes a property value.
482
-     *
483
-     * vCard 2.1 says:
484
-     *   * Semi-colons must be escaped in some property values, specifically
485
-     *     ADR, ORG and N.
486
-     *   * Semi-colons must be escaped in parameter values, because semi-colons
487
-     *     are also use to separate values.
488
-     *   * No mention of escaping backslashes with another backslash.
489
-     *   * newlines are not escaped either, instead QUOTED-PRINTABLE is used to
490
-     *     span values over more than 1 line.
491
-     *
492
-     * vCard 3.0 says:
493
-     *   * (rfc2425) Backslashes, newlines (\n or \N) and comma's must be
494
-     *     escaped, all time time.
495
-     *   * Comma's are used for delimiters in multiple values
496
-     *   * (rfc2426) Adds to to this that the semi-colon MUST also be escaped,
497
-     *     as in some properties semi-colon is used for separators.
498
-     *   * Properties using semi-colons: N, ADR, GEO, ORG
499
-     *   * Both ADR and N's individual parts may be broken up further with a
500
-     *     comma.
501
-     *   * Properties using commas: NICKNAME, CATEGORIES
502
-     *
503
-     * vCard 4.0 (rfc6350) says:
504
-     *   * Commas must be escaped.
505
-     *   * Semi-colons may be escaped, an unescaped semi-colon _may_ be a
506
-     *     delimiter, depending on the property.
507
-     *   * Backslashes must be escaped
508
-     *   * Newlines must be escaped as either \N or \n.
509
-     *   * Some compound properties may contain multiple parts themselves, so a
510
-     *     comma within a semi-colon delimited property may also be unescaped
511
-     *     to denote multiple parts _within_ the compound property.
512
-     *   * Text-properties using semi-colons: N, ADR, ORG, CLIENTPIDMAP.
513
-     *   * Text-properties using commas: NICKNAME, RELATED, CATEGORIES, PID.
514
-     *
515
-     * Even though the spec says that commas must always be escaped, the
516
-     * example for GEO in Section 6.5.2 seems to violate this.
517
-     *
518
-     * iCalendar 2.0 (rfc5545) says:
519
-     *   * Commas or semi-colons may be used as delimiters, depending on the
520
-     *     property.
521
-     *   * Commas, semi-colons, backslashes, newline (\N or \n) are always
522
-     *     escaped, unless they are delimiters.
523
-     *   * Colons shall not be escaped.
524
-     *   * Commas can be considered the 'default delimiter' and is described as
525
-     *     the delimiter in cases where the order of the multiple values is
526
-     *     insignificant.
527
-     *   * Semi-colons are described as the delimiter for 'structured values'.
528
-     *     They are specifically used in Semi-colons are used as a delimiter in
529
-     *     REQUEST-STATUS, RRULE, GEO and EXRULE. EXRULE is deprecated however.
530
-     *
531
-     * Now for the parameters
532
-     *
533
-     * If delimiter is not set (empty string) this method will just return a string.
534
-     * If it's a comma or a semi-colon the string will be split on those
535
-     * characters, and always return an array.
536
-     *
537
-     * @param string $input
538
-     * @param string $delimiter
539
-     *
540
-     * @return string|string[]
541
-     */
542
-    public static function unescapeValue($input, $delimiter = ';')
543
-    {
544
-        $regex = '#  (?: (\\\\ (?: \\\\ | N | n | ; | , ) )';
545
-        if ($delimiter) {
546
-            $regex .= ' | ('.$delimiter.')';
547
-        }
548
-        $regex .= ') #x';
549
-
550
-        $matches = preg_split($regex, $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
551
-
552
-        $resultArray = [];
553
-        $result = '';
554
-
555
-        foreach ($matches as $match) {
556
-            switch ($match) {
557
-                case '\\\\':
558
-                    $result .= '\\';
559
-                    break;
560
-                case '\N':
561
-                case '\n':
562
-                    $result .= "\n";
563
-                    break;
564
-                case '\;':
565
-                    $result .= ';';
566
-                    break;
567
-                case '\,':
568
-                    $result .= ',';
569
-                    break;
570
-                case $delimiter:
571
-                    $resultArray[] = $result;
572
-                    $result = '';
573
-                    break;
574
-                default:
575
-                    $result .= $match;
576
-                    break;
577
-            }
578
-        }
579
-
580
-        $resultArray[] = $result;
581
-
582
-        return $delimiter ? $resultArray : $result;
583
-    }
584
-
585
-    /**
586
-     * Unescapes a parameter value.
587
-     *
588
-     * vCard 2.1:
589
-     *   * Does not mention a mechanism for this. In addition, double quotes
590
-     *     are never used to wrap values.
591
-     *   * This means that parameters can simply not contain colons or
592
-     *     semi-colons.
593
-     *
594
-     * vCard 3.0 (rfc2425, rfc2426):
595
-     *   * Parameters _may_ be surrounded by double quotes.
596
-     *   * If this is not the case, semi-colon, colon and comma may simply not
597
-     *     occur (the comma used for multiple parameter values though).
598
-     *   * If it is surrounded by double-quotes, it may simply not contain
599
-     *     double-quotes.
600
-     *   * This means that a parameter can in no case encode double-quotes, or
601
-     *     newlines.
602
-     *
603
-     * vCard 4.0 (rfc6350)
604
-     *   * Behavior seems to be identical to vCard 3.0
605
-     *
606
-     * iCalendar 2.0 (rfc5545)
607
-     *   * Behavior seems to be identical to vCard 3.0
608
-     *
609
-     * Parameter escaping mechanism (rfc6868) :
610
-     *   * This rfc describes a new way to escape parameter values.
611
-     *   * New-line is encoded as ^n
612
-     *   * ^ is encoded as ^^.
613
-     *   * " is encoded as ^'
614
-     *
615
-     * @param string $input
616
-     */
617
-    private function unescapeParam($input)
618
-    {
619
-        return
620
-            preg_replace_callback(
621
-                '#(\^(\^|n|\'))#',
622
-                function ($matches) {
623
-                    switch ($matches[2]) {
624
-                        case 'n':
625
-                            return "\n";
626
-                        case '^':
627
-                            return '^';
628
-                        case '\'':
629
-                            return '"';
630
-
631
-                    // @codeCoverageIgnoreStart
632
-                    }
633
-                    // @codeCoverageIgnoreEnd
634
-                },
635
-                $input
636
-            );
637
-    }
638
-
639
-    /**
640
-     * Gets the full quoted printable value.
641
-     *
642
-     * We need a special method for this, because newlines have both a meaning
643
-     * in vCards, and in QuotedPrintable.
644
-     *
645
-     * This method does not do any decoding.
646
-     *
647
-     * @return string
648
-     */
649
-    private function extractQuotedPrintableValue()
650
-    {
651
-        // We need to parse the raw line again to get the start of the value.
652
-        //
653
-        // We are basically looking for the first colon (:), but we need to
654
-        // skip over the parameters first, as they may contain one.
655
-        $regex = '/^
368
+		foreach ($matches as $match) {
369
+			if (isset($match['paramValue'])) {
370
+				if ($match['paramValue'] && '"' === $match['paramValue'][0]) {
371
+					$value = substr($match['paramValue'], 1, -1);
372
+				} else {
373
+					$value = $match['paramValue'];
374
+				}
375
+
376
+				$value = $this->unescapeParam($value);
377
+
378
+				if (is_null($lastParam)) {
379
+					if ($this->options & self::OPTION_IGNORE_INVALID_LINES) {
380
+						// When the property can't be matched and the configuration
381
+						// option is set to ignore invalid lines, we ignore this line
382
+						// This can happen when servers provide faulty data as iCloud
383
+						//  frequently does with X-APPLE-STRUCTURED-LOCATION
384
+						continue;
385
+					}
386
+					throw new ParseException('Invalid Mimedir file. Line starting at '.$this->startLine.' did not follow iCalendar/vCard conventions');
387
+				}
388
+				if (is_null($property['parameters'][$lastParam])) {
389
+					$property['parameters'][$lastParam] = $value;
390
+				} elseif (is_array($property['parameters'][$lastParam])) {
391
+					$property['parameters'][$lastParam][] = $value;
392
+				} elseif ($property['parameters'][$lastParam] === $value) {
393
+					// When the current value of the parameter is the same as the
394
+					// new one, then we can leave the current parameter as it is.
395
+				} else {
396
+					$property['parameters'][$lastParam] = [
397
+						$property['parameters'][$lastParam],
398
+						$value,
399
+					];
400
+				}
401
+				continue;
402
+			}
403
+			if (isset($match['paramName'])) {
404
+				$lastParam = strtoupper($match['paramName']);
405
+				if (!isset($property['parameters'][$lastParam])) {
406
+					$property['parameters'][$lastParam] = null;
407
+				}
408
+				continue;
409
+			}
410
+			if (isset($match['propValue'])) {
411
+				$property['value'] = $match['propValue'];
412
+				continue;
413
+			}
414
+			if (isset($match['name']) && $match['name']) {
415
+				$property['name'] = strtoupper($match['name']);
416
+				continue;
417
+			}
418
+
419
+			// @codeCoverageIgnoreStart
420
+			throw new \LogicException('This code should not be reachable');
421
+			// @codeCoverageIgnoreEnd
422
+		}
423
+
424
+		if (is_null($property['value'])) {
425
+			$property['value'] = '';
426
+		}
427
+		if (!$property['name']) {
428
+			if ($this->options & self::OPTION_IGNORE_INVALID_LINES) {
429
+				return false;
430
+			}
431
+			throw new ParseException('Invalid Mimedir file. Line starting at '.$this->startLine.' did not follow iCalendar/vCard conventions');
432
+		}
433
+
434
+		// vCard 2.1 states that parameters may appear without a name, and only
435
+		// a value. We can deduce the value based on its name.
436
+		//
437
+		// Our parser will get those as parameters without a value instead, so
438
+		// we're filtering these parameters out first.
439
+		$namedParameters = [];
440
+		$namelessParameters = [];
441
+
442
+		foreach ($property['parameters'] as $name => $value) {
443
+			if (!is_null($value)) {
444
+				$namedParameters[$name] = $value;
445
+			} else {
446
+				$namelessParameters[] = $name;
447
+			}
448
+		}
449
+
450
+		$propObj = $this->root->createProperty($property['name'], null, $namedParameters);
451
+
452
+		foreach ($namelessParameters as $namelessParameter) {
453
+			$propObj->add(null, $namelessParameter);
454
+		}
455
+
456
+		if (isset($propObj['ENCODING']) && 'QUOTED-PRINTABLE' === strtoupper($propObj['ENCODING'])) {
457
+			$propObj->setQuotedPrintableValue($this->extractQuotedPrintableValue());
458
+		} else {
459
+			$charset = $this->charset;
460
+			if (Document::VCARD21 === $this->root->getDocumentType() && isset($propObj['CHARSET'])) {
461
+				// vCard 2.1 allows the character set to be specified per property.
462
+				$charset = (string) $propObj['CHARSET'];
463
+			}
464
+			switch (strtolower($charset)) {
465
+				case 'utf-8':
466
+					break;
467
+				case 'windows-1252':
468
+				case 'iso-8859-1':
469
+					$property['value'] = mb_convert_encoding($property['value'], 'UTF-8', $charset);
470
+					break;
471
+				default:
472
+					throw new ParseException('Unsupported CHARSET: '.$propObj['CHARSET']);
473
+			}
474
+			$propObj->setRawMimeDirValue($property['value']);
475
+		}
476
+
477
+		return $propObj;
478
+	}
479
+
480
+	/**
481
+	 * Unescapes a property value.
482
+	 *
483
+	 * vCard 2.1 says:
484
+	 *   * Semi-colons must be escaped in some property values, specifically
485
+	 *     ADR, ORG and N.
486
+	 *   * Semi-colons must be escaped in parameter values, because semi-colons
487
+	 *     are also use to separate values.
488
+	 *   * No mention of escaping backslashes with another backslash.
489
+	 *   * newlines are not escaped either, instead QUOTED-PRINTABLE is used to
490
+	 *     span values over more than 1 line.
491
+	 *
492
+	 * vCard 3.0 says:
493
+	 *   * (rfc2425) Backslashes, newlines (\n or \N) and comma's must be
494
+	 *     escaped, all time time.
495
+	 *   * Comma's are used for delimiters in multiple values
496
+	 *   * (rfc2426) Adds to to this that the semi-colon MUST also be escaped,
497
+	 *     as in some properties semi-colon is used for separators.
498
+	 *   * Properties using semi-colons: N, ADR, GEO, ORG
499
+	 *   * Both ADR and N's individual parts may be broken up further with a
500
+	 *     comma.
501
+	 *   * Properties using commas: NICKNAME, CATEGORIES
502
+	 *
503
+	 * vCard 4.0 (rfc6350) says:
504
+	 *   * Commas must be escaped.
505
+	 *   * Semi-colons may be escaped, an unescaped semi-colon _may_ be a
506
+	 *     delimiter, depending on the property.
507
+	 *   * Backslashes must be escaped
508
+	 *   * Newlines must be escaped as either \N or \n.
509
+	 *   * Some compound properties may contain multiple parts themselves, so a
510
+	 *     comma within a semi-colon delimited property may also be unescaped
511
+	 *     to denote multiple parts _within_ the compound property.
512
+	 *   * Text-properties using semi-colons: N, ADR, ORG, CLIENTPIDMAP.
513
+	 *   * Text-properties using commas: NICKNAME, RELATED, CATEGORIES, PID.
514
+	 *
515
+	 * Even though the spec says that commas must always be escaped, the
516
+	 * example for GEO in Section 6.5.2 seems to violate this.
517
+	 *
518
+	 * iCalendar 2.0 (rfc5545) says:
519
+	 *   * Commas or semi-colons may be used as delimiters, depending on the
520
+	 *     property.
521
+	 *   * Commas, semi-colons, backslashes, newline (\N or \n) are always
522
+	 *     escaped, unless they are delimiters.
523
+	 *   * Colons shall not be escaped.
524
+	 *   * Commas can be considered the 'default delimiter' and is described as
525
+	 *     the delimiter in cases where the order of the multiple values is
526
+	 *     insignificant.
527
+	 *   * Semi-colons are described as the delimiter for 'structured values'.
528
+	 *     They are specifically used in Semi-colons are used as a delimiter in
529
+	 *     REQUEST-STATUS, RRULE, GEO and EXRULE. EXRULE is deprecated however.
530
+	 *
531
+	 * Now for the parameters
532
+	 *
533
+	 * If delimiter is not set (empty string) this method will just return a string.
534
+	 * If it's a comma or a semi-colon the string will be split on those
535
+	 * characters, and always return an array.
536
+	 *
537
+	 * @param string $input
538
+	 * @param string $delimiter
539
+	 *
540
+	 * @return string|string[]
541
+	 */
542
+	public static function unescapeValue($input, $delimiter = ';')
543
+	{
544
+		$regex = '#  (?: (\\\\ (?: \\\\ | N | n | ; | , ) )';
545
+		if ($delimiter) {
546
+			$regex .= ' | ('.$delimiter.')';
547
+		}
548
+		$regex .= ') #x';
549
+
550
+		$matches = preg_split($regex, $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
551
+
552
+		$resultArray = [];
553
+		$result = '';
554
+
555
+		foreach ($matches as $match) {
556
+			switch ($match) {
557
+				case '\\\\':
558
+					$result .= '\\';
559
+					break;
560
+				case '\N':
561
+				case '\n':
562
+					$result .= "\n";
563
+					break;
564
+				case '\;':
565
+					$result .= ';';
566
+					break;
567
+				case '\,':
568
+					$result .= ',';
569
+					break;
570
+				case $delimiter:
571
+					$resultArray[] = $result;
572
+					$result = '';
573
+					break;
574
+				default:
575
+					$result .= $match;
576
+					break;
577
+			}
578
+		}
579
+
580
+		$resultArray[] = $result;
581
+
582
+		return $delimiter ? $resultArray : $result;
583
+	}
584
+
585
+	/**
586
+	 * Unescapes a parameter value.
587
+	 *
588
+	 * vCard 2.1:
589
+	 *   * Does not mention a mechanism for this. In addition, double quotes
590
+	 *     are never used to wrap values.
591
+	 *   * This means that parameters can simply not contain colons or
592
+	 *     semi-colons.
593
+	 *
594
+	 * vCard 3.0 (rfc2425, rfc2426):
595
+	 *   * Parameters _may_ be surrounded by double quotes.
596
+	 *   * If this is not the case, semi-colon, colon and comma may simply not
597
+	 *     occur (the comma used for multiple parameter values though).
598
+	 *   * If it is surrounded by double-quotes, it may simply not contain
599
+	 *     double-quotes.
600
+	 *   * This means that a parameter can in no case encode double-quotes, or
601
+	 *     newlines.
602
+	 *
603
+	 * vCard 4.0 (rfc6350)
604
+	 *   * Behavior seems to be identical to vCard 3.0
605
+	 *
606
+	 * iCalendar 2.0 (rfc5545)
607
+	 *   * Behavior seems to be identical to vCard 3.0
608
+	 *
609
+	 * Parameter escaping mechanism (rfc6868) :
610
+	 *   * This rfc describes a new way to escape parameter values.
611
+	 *   * New-line is encoded as ^n
612
+	 *   * ^ is encoded as ^^.
613
+	 *   * " is encoded as ^'
614
+	 *
615
+	 * @param string $input
616
+	 */
617
+	private function unescapeParam($input)
618
+	{
619
+		return
620
+			preg_replace_callback(
621
+				'#(\^(\^|n|\'))#',
622
+				function ($matches) {
623
+					switch ($matches[2]) {
624
+						case 'n':
625
+							return "\n";
626
+						case '^':
627
+							return '^';
628
+						case '\'':
629
+							return '"';
630
+
631
+					// @codeCoverageIgnoreStart
632
+					}
633
+					// @codeCoverageIgnoreEnd
634
+				},
635
+				$input
636
+			);
637
+	}
638
+
639
+	/**
640
+	 * Gets the full quoted printable value.
641
+	 *
642
+	 * We need a special method for this, because newlines have both a meaning
643
+	 * in vCards, and in QuotedPrintable.
644
+	 *
645
+	 * This method does not do any decoding.
646
+	 *
647
+	 * @return string
648
+	 */
649
+	private function extractQuotedPrintableValue()
650
+	{
651
+		// We need to parse the raw line again to get the start of the value.
652
+		//
653
+		// We are basically looking for the first colon (:), but we need to
654
+		// skip over the parameters first, as they may contain one.
655
+		$regex = '/^
656 656
             (?: [^:])+ # Anything but a colon
657 657
             (?: "[^"]")* # A parameter in double quotes
658 658
             : # start of the value we really care about
659 659
             (.*)$
660 660
         /xs';
661 661
 
662
-        preg_match($regex, $this->rawLine, $matches);
663
-
664
-        $value = $matches[1];
665
-        // Removing the first whitespace character from every line. Kind of
666
-        // like unfolding, but we keep the newline.
667
-        $value = str_replace("\n ", "\n", $value);
668
-
669
-        // Microsoft products don't always correctly fold lines, they may be
670
-        // missing a whitespace. So if 'forgiving' is turned on, we will take
671
-        // those as well.
672
-        if ($this->options & self::OPTION_FORGIVING) {
673
-            while ('=' === substr($value, -1) && $this->lineBuffer) {
674
-                // Reading the line
675
-                $this->readLine();
676
-                // Grabbing the raw form
677
-                $value .= "\n".$this->rawLine;
678
-            }
679
-        }
680
-
681
-        return $value;
682
-    }
662
+		preg_match($regex, $this->rawLine, $matches);
663
+
664
+		$value = $matches[1];
665
+		// Removing the first whitespace character from every line. Kind of
666
+		// like unfolding, but we keep the newline.
667
+		$value = str_replace("\n ", "\n", $value);
668
+
669
+		// Microsoft products don't always correctly fold lines, they may be
670
+		// missing a whitespace. So if 'forgiving' is turned on, we will take
671
+		// those as well.
672
+		if ($this->options & self::OPTION_FORGIVING) {
673
+			while ('=' === substr($value, -1) && $this->lineBuffer) {
674
+				// Reading the line
675
+				$this->readLine();
676
+				// Grabbing the raw form
677
+				$value .= "\n".$this->rawLine;
678
+			}
679
+		}
680
+
681
+		return $value;
682
+	}
683 683
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -619,7 +619,7 @@
 block discarded – undo
619 619
         return
620 620
             preg_replace_callback(
621 621
                 '#(\^(\^|n|\'))#',
622
-                function ($matches) {
622
+                function($matches) {
623 623
                     switch ($matches[2]) {
624 624
                         case 'n':
625 625
                             return "\n";
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Component/VJournal.php 1 patch
Indentation   +75 added lines, -75 removed lines patch added patch discarded remove patch
@@ -16,86 +16,86 @@
 block discarded – undo
16 16
  */
17 17
 class VJournal extends VObject\Component
18 18
 {
19
-    /**
20
-     * Returns true or false depending on if the event falls in the specified
21
-     * time-range. This is used for filtering purposes.
22
-     *
23
-     * The rules used to determine if an event falls within the specified
24
-     * time-range is based on the CalDAV specification.
25
-     *
26
-     * @return bool
27
-     */
28
-    public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end)
29
-    {
30
-        $dtstart = isset($this->DTSTART) ? $this->DTSTART->getDateTime() : null;
31
-        if ($dtstart) {
32
-            $effectiveEnd = $dtstart;
33
-            if (!$this->DTSTART->hasTime()) {
34
-                $effectiveEnd = $effectiveEnd->modify('+1 day');
35
-            }
19
+	/**
20
+	 * Returns true or false depending on if the event falls in the specified
21
+	 * time-range. This is used for filtering purposes.
22
+	 *
23
+	 * The rules used to determine if an event falls within the specified
24
+	 * time-range is based on the CalDAV specification.
25
+	 *
26
+	 * @return bool
27
+	 */
28
+	public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end)
29
+	{
30
+		$dtstart = isset($this->DTSTART) ? $this->DTSTART->getDateTime() : null;
31
+		if ($dtstart) {
32
+			$effectiveEnd = $dtstart;
33
+			if (!$this->DTSTART->hasTime()) {
34
+				$effectiveEnd = $effectiveEnd->modify('+1 day');
35
+			}
36 36
 
37
-            return $start <= $effectiveEnd && $end > $dtstart;
38
-        }
37
+			return $start <= $effectiveEnd && $end > $dtstart;
38
+		}
39 39
 
40
-        return false;
41
-    }
40
+		return false;
41
+	}
42 42
 
43
-    /**
44
-     * A simple list of validation rules.
45
-     *
46
-     * This is simply a list of properties, and how many times they either
47
-     * must or must not appear.
48
-     *
49
-     * Possible values per property:
50
-     *   * 0 - Must not appear.
51
-     *   * 1 - Must appear exactly once.
52
-     *   * + - Must appear at least once.
53
-     *   * * - Can appear any number of times.
54
-     *   * ? - May appear, but not more than once.
55
-     *
56
-     * @var array
57
-     */
58
-    public function getValidationRules()
59
-    {
60
-        return [
61
-            'UID' => 1,
62
-            'DTSTAMP' => 1,
43
+	/**
44
+	 * A simple list of validation rules.
45
+	 *
46
+	 * This is simply a list of properties, and how many times they either
47
+	 * must or must not appear.
48
+	 *
49
+	 * Possible values per property:
50
+	 *   * 0 - Must not appear.
51
+	 *   * 1 - Must appear exactly once.
52
+	 *   * + - Must appear at least once.
53
+	 *   * * - Can appear any number of times.
54
+	 *   * ? - May appear, but not more than once.
55
+	 *
56
+	 * @var array
57
+	 */
58
+	public function getValidationRules()
59
+	{
60
+		return [
61
+			'UID' => 1,
62
+			'DTSTAMP' => 1,
63 63
 
64
-            'CLASS' => '?',
65
-            'CREATED' => '?',
66
-            'DTSTART' => '?',
67
-            'LAST-MODIFIED' => '?',
68
-            'ORGANIZER' => '?',
69
-            'RECURRENCE-ID' => '?',
70
-            'SEQUENCE' => '?',
71
-            'STATUS' => '?',
72
-            'SUMMARY' => '?',
73
-            'URL' => '?',
64
+			'CLASS' => '?',
65
+			'CREATED' => '?',
66
+			'DTSTART' => '?',
67
+			'LAST-MODIFIED' => '?',
68
+			'ORGANIZER' => '?',
69
+			'RECURRENCE-ID' => '?',
70
+			'SEQUENCE' => '?',
71
+			'STATUS' => '?',
72
+			'SUMMARY' => '?',
73
+			'URL' => '?',
74 74
 
75
-            'RRULE' => '?',
75
+			'RRULE' => '?',
76 76
 
77
-            'ATTACH' => '*',
78
-            'ATTENDEE' => '*',
79
-            'CATEGORIES' => '*',
80
-            'COMMENT' => '*',
81
-            'CONTACT' => '*',
82
-            'DESCRIPTION' => '*',
83
-            'EXDATE' => '*',
84
-            'RELATED-TO' => '*',
85
-            'RDATE' => '*',
86
-        ];
87
-    }
77
+			'ATTACH' => '*',
78
+			'ATTENDEE' => '*',
79
+			'CATEGORIES' => '*',
80
+			'COMMENT' => '*',
81
+			'CONTACT' => '*',
82
+			'DESCRIPTION' => '*',
83
+			'EXDATE' => '*',
84
+			'RELATED-TO' => '*',
85
+			'RDATE' => '*',
86
+		];
87
+	}
88 88
 
89
-    /**
90
-     * This method should return a list of default property values.
91
-     *
92
-     * @return array
93
-     */
94
-    protected function getDefaults()
95
-    {
96
-        return [
97
-            'UID' => 'sabre-vobject-'.VObject\UUIDUtil::getUUID(),
98
-            'DTSTAMP' => gmdate('Ymd\\THis\\Z'),
99
-        ];
100
-    }
89
+	/**
90
+	 * This method should return a list of default property values.
91
+	 *
92
+	 * @return array
93
+	 */
94
+	protected function getDefaults()
95
+	{
96
+		return [
97
+			'UID' => 'sabre-vobject-'.VObject\UUIDUtil::getUUID(),
98
+			'DTSTAMP' => gmdate('Ymd\\THis\\Z'),
99
+		];
100
+	}
101 101
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Component/VAvailability.php 1 patch
Indentation   +119 added lines, -119 removed lines patch added patch discarded remove patch
@@ -17,133 +17,133 @@
 block discarded – undo
17 17
  */
18 18
 class VAvailability extends VObject\Component
19 19
 {
20
-    /**
21
-     * Returns true or false depending on if the event falls in the specified
22
-     * time-range. This is used for filtering purposes.
23
-     *
24
-     * The rules used to determine if an event falls within the specified
25
-     * time-range is based on:
26
-     *
27
-     * https://tools.ietf.org/html/draft-daboo-calendar-availability-05#section-3.1
28
-     *
29
-     * @return bool
30
-     */
31
-    public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end)
32
-    {
33
-        list($effectiveStart, $effectiveEnd) = $this->getEffectiveStartEnd();
20
+	/**
21
+	 * Returns true or false depending on if the event falls in the specified
22
+	 * time-range. This is used for filtering purposes.
23
+	 *
24
+	 * The rules used to determine if an event falls within the specified
25
+	 * time-range is based on:
26
+	 *
27
+	 * https://tools.ietf.org/html/draft-daboo-calendar-availability-05#section-3.1
28
+	 *
29
+	 * @return bool
30
+	 */
31
+	public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end)
32
+	{
33
+		list($effectiveStart, $effectiveEnd) = $this->getEffectiveStartEnd();
34 34
 
35
-        return
36
-            (is_null($effectiveStart) || $start < $effectiveEnd) &&
37
-            (is_null($effectiveEnd) || $end > $effectiveStart)
38
-        ;
39
-    }
35
+		return
36
+			(is_null($effectiveStart) || $start < $effectiveEnd) &&
37
+			(is_null($effectiveEnd) || $end > $effectiveStart)
38
+		;
39
+	}
40 40
 
41
-    /**
42
-     * Returns the 'effective start' and 'effective end' of this VAVAILABILITY
43
-     * component.
44
-     *
45
-     * We use the DTSTART and DTEND or DURATION to determine this.
46
-     *
47
-     * The returned value is an array containing DateTimeImmutable instances.
48
-     * If either the start or end is 'unbounded' its value will be null
49
-     * instead.
50
-     *
51
-     * @return array
52
-     */
53
-    public function getEffectiveStartEnd()
54
-    {
55
-        $effectiveStart = null;
56
-        $effectiveEnd = null;
41
+	/**
42
+	 * Returns the 'effective start' and 'effective end' of this VAVAILABILITY
43
+	 * component.
44
+	 *
45
+	 * We use the DTSTART and DTEND or DURATION to determine this.
46
+	 *
47
+	 * The returned value is an array containing DateTimeImmutable instances.
48
+	 * If either the start or end is 'unbounded' its value will be null
49
+	 * instead.
50
+	 *
51
+	 * @return array
52
+	 */
53
+	public function getEffectiveStartEnd()
54
+	{
55
+		$effectiveStart = null;
56
+		$effectiveEnd = null;
57 57
 
58
-        if (isset($this->DTSTART)) {
59
-            $effectiveStart = $this->DTSTART->getDateTime();
60
-        }
61
-        if (isset($this->DTEND)) {
62
-            $effectiveEnd = $this->DTEND->getDateTime();
63
-        } elseif ($effectiveStart && isset($this->DURATION)) {
64
-            $effectiveEnd = $effectiveStart->add(VObject\DateTimeParser::parseDuration($this->DURATION));
65
-        }
58
+		if (isset($this->DTSTART)) {
59
+			$effectiveStart = $this->DTSTART->getDateTime();
60
+		}
61
+		if (isset($this->DTEND)) {
62
+			$effectiveEnd = $this->DTEND->getDateTime();
63
+		} elseif ($effectiveStart && isset($this->DURATION)) {
64
+			$effectiveEnd = $effectiveStart->add(VObject\DateTimeParser::parseDuration($this->DURATION));
65
+		}
66 66
 
67
-        return [$effectiveStart, $effectiveEnd];
68
-    }
67
+		return [$effectiveStart, $effectiveEnd];
68
+	}
69 69
 
70
-    /**
71
-     * A simple list of validation rules.
72
-     *
73
-     * This is simply a list of properties, and how many times they either
74
-     * must or must not appear.
75
-     *
76
-     * Possible values per property:
77
-     *   * 0 - Must not appear.
78
-     *   * 1 - Must appear exactly once.
79
-     *   * + - Must appear at least once.
80
-     *   * * - Can appear any number of times.
81
-     *   * ? - May appear, but not more than once.
82
-     *
83
-     * @var array
84
-     */
85
-    public function getValidationRules()
86
-    {
87
-        return [
88
-            'UID' => 1,
89
-            'DTSTAMP' => 1,
70
+	/**
71
+	 * A simple list of validation rules.
72
+	 *
73
+	 * This is simply a list of properties, and how many times they either
74
+	 * must or must not appear.
75
+	 *
76
+	 * Possible values per property:
77
+	 *   * 0 - Must not appear.
78
+	 *   * 1 - Must appear exactly once.
79
+	 *   * + - Must appear at least once.
80
+	 *   * * - Can appear any number of times.
81
+	 *   * ? - May appear, but not more than once.
82
+	 *
83
+	 * @var array
84
+	 */
85
+	public function getValidationRules()
86
+	{
87
+		return [
88
+			'UID' => 1,
89
+			'DTSTAMP' => 1,
90 90
 
91
-            'BUSYTYPE' => '?',
92
-            'CLASS' => '?',
93
-            'CREATED' => '?',
94
-            'DESCRIPTION' => '?',
95
-            'DTSTART' => '?',
96
-            'LAST-MODIFIED' => '?',
97
-            'ORGANIZER' => '?',
98
-            'PRIORITY' => '?',
99
-            'SEQUENCE' => '?',
100
-            'SUMMARY' => '?',
101
-            'URL' => '?',
102
-            'DTEND' => '?',
103
-            'DURATION' => '?',
91
+			'BUSYTYPE' => '?',
92
+			'CLASS' => '?',
93
+			'CREATED' => '?',
94
+			'DESCRIPTION' => '?',
95
+			'DTSTART' => '?',
96
+			'LAST-MODIFIED' => '?',
97
+			'ORGANIZER' => '?',
98
+			'PRIORITY' => '?',
99
+			'SEQUENCE' => '?',
100
+			'SUMMARY' => '?',
101
+			'URL' => '?',
102
+			'DTEND' => '?',
103
+			'DURATION' => '?',
104 104
 
105
-            'CATEGORIES' => '*',
106
-            'COMMENT' => '*',
107
-            'CONTACT' => '*',
108
-        ];
109
-    }
105
+			'CATEGORIES' => '*',
106
+			'COMMENT' => '*',
107
+			'CONTACT' => '*',
108
+		];
109
+	}
110 110
 
111
-    /**
112
-     * Validates the node for correctness.
113
-     *
114
-     * The following options are supported:
115
-     *   Node::REPAIR - May attempt to automatically repair the problem.
116
-     *   Node::PROFILE_CARDDAV - Validate the vCard for CardDAV purposes.
117
-     *   Node::PROFILE_CALDAV - Validate the iCalendar for CalDAV purposes.
118
-     *
119
-     * This method returns an array with detected problems.
120
-     * Every element has the following properties:
121
-     *
122
-     *  * level - problem level.
123
-     *  * message - A human-readable string describing the issue.
124
-     *  * node - A reference to the problematic node.
125
-     *
126
-     * The level means:
127
-     *   1 - The issue was repaired (only happens if REPAIR was turned on).
128
-     *   2 - A warning.
129
-     *   3 - An error.
130
-     *
131
-     * @param int $options
132
-     *
133
-     * @return array
134
-     */
135
-    public function validate($options = 0)
136
-    {
137
-        $result = parent::validate($options);
111
+	/**
112
+	 * Validates the node for correctness.
113
+	 *
114
+	 * The following options are supported:
115
+	 *   Node::REPAIR - May attempt to automatically repair the problem.
116
+	 *   Node::PROFILE_CARDDAV - Validate the vCard for CardDAV purposes.
117
+	 *   Node::PROFILE_CALDAV - Validate the iCalendar for CalDAV purposes.
118
+	 *
119
+	 * This method returns an array with detected problems.
120
+	 * Every element has the following properties:
121
+	 *
122
+	 *  * level - problem level.
123
+	 *  * message - A human-readable string describing the issue.
124
+	 *  * node - A reference to the problematic node.
125
+	 *
126
+	 * The level means:
127
+	 *   1 - The issue was repaired (only happens if REPAIR was turned on).
128
+	 *   2 - A warning.
129
+	 *   3 - An error.
130
+	 *
131
+	 * @param int $options
132
+	 *
133
+	 * @return array
134
+	 */
135
+	public function validate($options = 0)
136
+	{
137
+		$result = parent::validate($options);
138 138
 
139
-        if (isset($this->DTEND) && isset($this->DURATION)) {
140
-            $result[] = [
141
-                'level' => 3,
142
-                'message' => 'DTEND and DURATION cannot both be present',
143
-                'node' => $this,
144
-            ];
145
-        }
139
+		if (isset($this->DTEND) && isset($this->DURATION)) {
140
+			$result[] = [
141
+				'level' => 3,
142
+				'message' => 'DTEND and DURATION cannot both be present',
143
+				'node' => $this,
144
+			];
145
+		}
146 146
 
147
-        return $result;
148
-    }
147
+		return $result;
148
+	}
149 149
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Component/VCard.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -50,7 +50,7 @@
 block discarded – undo
50 50
     public static $valueMap = [
51 51
         'BINARY' => VObject\Property\Binary::class,
52 52
         'BOOLEAN' => VObject\Property\Boolean::class,
53
-        'CONTENT-ID' => VObject\Property\FlatText::class,   // vCard 2.1 only
53
+        'CONTENT-ID' => VObject\Property\FlatText::class, // vCard 2.1 only
54 54
         'DATE' => VObject\Property\VCard\Date::class,
55 55
         'DATE-TIME' => VObject\Property\VCard\DateTime::class,
56 56
         'DATE-AND-OR-TIME' => VObject\Property\VCard\DateAndOrTime::class, // vCard only
Please login to merge, or discard this patch.
Indentation   +521 added lines, -521 removed lines patch added patch discarded remove patch
@@ -17,525 +17,525 @@
 block discarded – undo
17 17
  */
18 18
 class VCard extends VObject\Document
19 19
 {
20
-    /**
21
-     * The default name for this component.
22
-     *
23
-     * This should be 'VCALENDAR' or 'VCARD'.
24
-     *
25
-     * @var string
26
-     */
27
-    public static $defaultName = 'VCARD';
28
-
29
-    /**
30
-     * Caching the version number.
31
-     *
32
-     * @var int
33
-     */
34
-    private $version = null;
35
-
36
-    /**
37
-     * This is a list of components, and which classes they should map to.
38
-     *
39
-     * @var array
40
-     */
41
-    public static $componentMap = [
42
-        'VCARD' => VCard::class,
43
-    ];
44
-
45
-    /**
46
-     * List of value-types, and which classes they map to.
47
-     *
48
-     * @var array
49
-     */
50
-    public static $valueMap = [
51
-        'BINARY' => VObject\Property\Binary::class,
52
-        'BOOLEAN' => VObject\Property\Boolean::class,
53
-        'CONTENT-ID' => VObject\Property\FlatText::class,   // vCard 2.1 only
54
-        'DATE' => VObject\Property\VCard\Date::class,
55
-        'DATE-TIME' => VObject\Property\VCard\DateTime::class,
56
-        'DATE-AND-OR-TIME' => VObject\Property\VCard\DateAndOrTime::class, // vCard only
57
-        'FLOAT' => VObject\Property\FloatValue::class,
58
-        'INTEGER' => VObject\Property\IntegerValue::class,
59
-        'LANGUAGE-TAG' => VObject\Property\VCard\LanguageTag::class,
60
-        'PHONE-NUMBER' => VObject\Property\VCard\PhoneNumber::class, // vCard 3.0 only
61
-        'TIMESTAMP' => VObject\Property\VCard\TimeStamp::class,
62
-        'TEXT' => VObject\Property\Text::class,
63
-        'TIME' => VObject\Property\Time::class,
64
-        'UNKNOWN' => VObject\Property\Unknown::class, // jCard / jCal-only.
65
-        'URI' => VObject\Property\Uri::class,
66
-        'URL' => VObject\Property\Uri::class, // vCard 2.1 only
67
-        'UTC-OFFSET' => VObject\Property\UtcOffset::class,
68
-    ];
69
-
70
-    /**
71
-     * List of properties, and which classes they map to.
72
-     *
73
-     * @var array
74
-     */
75
-    public static $propertyMap = [
76
-        // vCard 2.1 properties and up
77
-        'N' => VObject\Property\Text::class,
78
-        'FN' => VObject\Property\FlatText::class,
79
-        'PHOTO' => VObject\Property\Binary::class,
80
-        'BDAY' => VObject\Property\VCard\DateAndOrTime::class,
81
-        'ADR' => VObject\Property\Text::class,
82
-        'LABEL' => VObject\Property\FlatText::class, // Removed in vCard 4.0
83
-        'TEL' => VObject\Property\FlatText::class,
84
-        'EMAIL' => VObject\Property\FlatText::class,
85
-        'MAILER' => VObject\Property\FlatText::class, // Removed in vCard 4.0
86
-        'GEO' => VObject\Property\FlatText::class,
87
-        'TITLE' => VObject\Property\FlatText::class,
88
-        'ROLE' => VObject\Property\FlatText::class,
89
-        'LOGO' => VObject\Property\Binary::class,
90
-        // 'AGENT'   => 'Sabre\\VObject\\Property\\',      // Todo: is an embedded vCard. Probably rare, so
91
-                                 // not supported at the moment
92
-        'ORG' => VObject\Property\Text::class,
93
-        'NOTE' => VObject\Property\FlatText::class,
94
-        'REV' => VObject\Property\VCard\TimeStamp::class,
95
-        'SOUND' => VObject\Property\FlatText::class,
96
-        'URL' => VObject\Property\Uri::class,
97
-        'UID' => VObject\Property\FlatText::class,
98
-        'VERSION' => VObject\Property\FlatText::class,
99
-        'KEY' => VObject\Property\FlatText::class,
100
-        'TZ' => VObject\Property\Text::class,
101
-
102
-        // vCard 3.0 properties
103
-        'CATEGORIES' => VObject\Property\Text::class,
104
-        'SORT-STRING' => VObject\Property\FlatText::class,
105
-        'PRODID' => VObject\Property\FlatText::class,
106
-        'NICKNAME' => VObject\Property\Text::class,
107
-        'CLASS' => VObject\Property\FlatText::class, // Removed in vCard 4.0
108
-
109
-        // rfc2739 properties
110
-        'FBURL' => VObject\Property\Uri::class,
111
-        'CAPURI' => VObject\Property\Uri::class,
112
-        'CALURI' => VObject\Property\Uri::class,
113
-        'CALADRURI' => VObject\Property\Uri::class,
114
-
115
-        // rfc4770 properties
116
-        'IMPP' => VObject\Property\Uri::class,
117
-
118
-        // vCard 4.0 properties
119
-        'SOURCE' => VObject\Property\Uri::class,
120
-        'XML' => VObject\Property\FlatText::class,
121
-        'ANNIVERSARY' => VObject\Property\VCard\DateAndOrTime::class,
122
-        'CLIENTPIDMAP' => VObject\Property\Text::class,
123
-        'LANG' => VObject\Property\VCard\LanguageTag::class,
124
-        'GENDER' => VObject\Property\Text::class,
125
-        'KIND' => VObject\Property\FlatText::class,
126
-        'MEMBER' => VObject\Property\Uri::class,
127
-        'RELATED' => VObject\Property\Uri::class,
128
-
129
-        // rfc6474 properties
130
-        'BIRTHPLACE' => VObject\Property\FlatText::class,
131
-        'DEATHPLACE' => VObject\Property\FlatText::class,
132
-        'DEATHDATE' => VObject\Property\VCard\DateAndOrTime::class,
133
-
134
-        // rfc6715 properties
135
-        'EXPERTISE' => VObject\Property\FlatText::class,
136
-        'HOBBY' => VObject\Property\FlatText::class,
137
-        'INTEREST' => VObject\Property\FlatText::class,
138
-        'ORG-DIRECTORY' => VObject\Property\FlatText::class,
139
-    ];
140
-
141
-    /**
142
-     * Returns the current document type.
143
-     *
144
-     * @return int
145
-     */
146
-    public function getDocumentType()
147
-    {
148
-        if (!$this->version) {
149
-            $version = (string) $this->VERSION;
150
-
151
-            switch ($version) {
152
-                case '2.1':
153
-                    $this->version = self::VCARD21;
154
-                    break;
155
-                case '3.0':
156
-                    $this->version = self::VCARD30;
157
-                    break;
158
-                case '4.0':
159
-                    $this->version = self::VCARD40;
160
-                    break;
161
-                default:
162
-                    // We don't want to cache the version if it's unknown,
163
-                    // because we might get a version property in a bit.
164
-                    return self::UNKNOWN;
165
-            }
166
-        }
167
-
168
-        return $this->version;
169
-    }
170
-
171
-    /**
172
-     * Converts the document to a different vcard version.
173
-     *
174
-     * Use one of the VCARD constants for the target. This method will return
175
-     * a copy of the vcard in the new version.
176
-     *
177
-     * At the moment the only supported conversion is from 3.0 to 4.0.
178
-     *
179
-     * If input and output version are identical, a clone is returned.
180
-     *
181
-     * @param int $target
182
-     *
183
-     * @return VCard
184
-     */
185
-    public function convert($target)
186
-    {
187
-        $converter = new VObject\VCardConverter();
188
-
189
-        return $converter->convert($this, $target);
190
-    }
191
-
192
-    /**
193
-     * VCards with version 2.1, 3.0 and 4.0 are found.
194
-     *
195
-     * If the VCARD doesn't know its version, 2.1 is assumed.
196
-     */
197
-    const DEFAULT_VERSION = self::VCARD21;
198
-
199
-    /**
200
-     * Validates the node for correctness.
201
-     *
202
-     * The following options are supported:
203
-     *   Node::REPAIR - May attempt to automatically repair the problem.
204
-     *
205
-     * This method returns an array with detected problems.
206
-     * Every element has the following properties:
207
-     *
208
-     *  * level - problem level.
209
-     *  * message - A human-readable string describing the issue.
210
-     *  * node - A reference to the problematic node.
211
-     *
212
-     * The level means:
213
-     *   1 - The issue was repaired (only happens if REPAIR was turned on)
214
-     *   2 - An inconsequential issue
215
-     *   3 - A severe issue.
216
-     *
217
-     * @param int $options
218
-     *
219
-     * @return array
220
-     */
221
-    public function validate($options = 0)
222
-    {
223
-        $warnings = [];
224
-
225
-        $versionMap = [
226
-            self::VCARD21 => '2.1',
227
-            self::VCARD30 => '3.0',
228
-            self::VCARD40 => '4.0',
229
-        ];
230
-
231
-        $version = $this->select('VERSION');
232
-        if (1 === count($version)) {
233
-            $version = (string) $this->VERSION;
234
-            if ('2.1' !== $version && '3.0' !== $version && '4.0' !== $version) {
235
-                $warnings[] = [
236
-                    'level' => 3,
237
-                    'message' => 'Only vcard version 4.0 (RFC6350), version 3.0 (RFC2426) or version 2.1 (icm-vcard-2.1) are supported.',
238
-                    'node' => $this,
239
-                ];
240
-                if ($options & self::REPAIR) {
241
-                    $this->VERSION = $versionMap[self::DEFAULT_VERSION];
242
-                }
243
-            }
244
-            if ('2.1' === $version && ($options & self::PROFILE_CARDDAV)) {
245
-                $warnings[] = [
246
-                    'level' => 3,
247
-                    'message' => 'CardDAV servers are not allowed to accept vCard 2.1.',
248
-                    'node' => $this,
249
-                ];
250
-            }
251
-        }
252
-        $uid = $this->select('UID');
253
-        if (0 === count($uid)) {
254
-            if ($options & self::PROFILE_CARDDAV) {
255
-                // Required for CardDAV
256
-                $warningLevel = 3;
257
-                $message = 'vCards on CardDAV servers MUST have a UID property.';
258
-            } else {
259
-                // Not required for regular vcards
260
-                $warningLevel = 2;
261
-                $message = 'Adding a UID to a vCard property is recommended.';
262
-            }
263
-            if ($options & self::REPAIR) {
264
-                $this->UID = VObject\UUIDUtil::getUUID();
265
-                $warningLevel = 1;
266
-            }
267
-            $warnings[] = [
268
-                'level' => $warningLevel,
269
-                'message' => $message,
270
-                'node' => $this,
271
-            ];
272
-        }
273
-
274
-        $fn = $this->select('FN');
275
-        if (1 !== count($fn)) {
276
-            $repaired = false;
277
-            if (($options & self::REPAIR) && 0 === count($fn)) {
278
-                // We're going to try to see if we can use the contents of the
279
-                // N property.
280
-                if (isset($this->N)) {
281
-                    $value = explode(';', (string) $this->N);
282
-                    if (isset($value[1]) && $value[1]) {
283
-                        $this->FN = $value[1].' '.$value[0];
284
-                    } else {
285
-                        $this->FN = $value[0];
286
-                    }
287
-                    $repaired = true;
288
-
289
-                // Otherwise, the ORG property may work
290
-                } elseif (isset($this->ORG)) {
291
-                    $this->FN = (string) $this->ORG;
292
-                    $repaired = true;
293
-
294
-                // Otherwise, the NICKNAME property may work
295
-                } elseif (isset($this->NICKNAME)) {
296
-                    $this->FN = (string) $this->NICKNAME;
297
-                    $repaired = true;
298
-
299
-                // Otherwise, the EMAIL property may work
300
-                } elseif (isset($this->EMAIL)) {
301
-                    $this->FN = (string) $this->EMAIL;
302
-                    $repaired = true;
303
-                }
304
-            }
305
-            $warnings[] = [
306
-                'level' => $repaired ? 1 : 3,
307
-                'message' => 'The FN property must appear in the VCARD component exactly 1 time',
308
-                'node' => $this,
309
-            ];
310
-        }
311
-
312
-        return array_merge(
313
-            parent::validate($options),
314
-            $warnings
315
-        );
316
-    }
317
-
318
-    /**
319
-     * A simple list of validation rules.
320
-     *
321
-     * This is simply a list of properties, and how many times they either
322
-     * must or must not appear.
323
-     *
324
-     * Possible values per property:
325
-     *   * 0 - Must not appear.
326
-     *   * 1 - Must appear exactly once.
327
-     *   * + - Must appear at least once.
328
-     *   * * - Can appear any number of times.
329
-     *   * ? - May appear, but not more than once.
330
-     *
331
-     * @var array
332
-     */
333
-    public function getValidationRules()
334
-    {
335
-        return [
336
-            'ADR' => '*',
337
-            'ANNIVERSARY' => '?',
338
-            'BDAY' => '?',
339
-            'CALADRURI' => '*',
340
-            'CALURI' => '*',
341
-            'CATEGORIES' => '*',
342
-            'CLIENTPIDMAP' => '*',
343
-            'EMAIL' => '*',
344
-            'FBURL' => '*',
345
-            'IMPP' => '*',
346
-            'GENDER' => '?',
347
-            'GEO' => '*',
348
-            'KEY' => '*',
349
-            'KIND' => '?',
350
-            'LANG' => '*',
351
-            'LOGO' => '*',
352
-            'MEMBER' => '*',
353
-            'N' => '?',
354
-            'NICKNAME' => '*',
355
-            'NOTE' => '*',
356
-            'ORG' => '*',
357
-            'PHOTO' => '*',
358
-            'PRODID' => '?',
359
-            'RELATED' => '*',
360
-            'REV' => '?',
361
-            'ROLE' => '*',
362
-            'SOUND' => '*',
363
-            'SOURCE' => '*',
364
-            'TEL' => '*',
365
-            'TITLE' => '*',
366
-            'TZ' => '*',
367
-            'URL' => '*',
368
-            'VERSION' => '1',
369
-            'XML' => '*',
370
-
371
-            // FN is commented out, because it's already handled by the
372
-            // validate function, which may also try to repair it.
373
-            // 'FN'           => '+',
374
-            'UID' => '?',
375
-        ];
376
-    }
377
-
378
-    /**
379
-     * Returns a preferred field.
380
-     *
381
-     * VCards can indicate whether a field such as ADR, TEL or EMAIL is
382
-     * preferred by specifying TYPE=PREF (vcard 2.1, 3) or PREF=x (vcard 4, x
383
-     * being a number between 1 and 100).
384
-     *
385
-     * If neither of those parameters are specified, the first is returned, if
386
-     * a field with that name does not exist, null is returned.
387
-     *
388
-     * @param string $fieldName
389
-     *
390
-     * @return VObject\Property|null
391
-     */
392
-    public function preferred($propertyName)
393
-    {
394
-        $preferred = null;
395
-        $lastPref = 101;
396
-        foreach ($this->select($propertyName) as $field) {
397
-            $pref = 101;
398
-            if (isset($field['TYPE']) && $field['TYPE']->has('PREF')) {
399
-                $pref = 1;
400
-            } elseif (isset($field['PREF'])) {
401
-                $pref = $field['PREF']->getValue();
402
-            }
403
-
404
-            if ($pref < $lastPref || is_null($preferred)) {
405
-                $preferred = $field;
406
-                $lastPref = $pref;
407
-            }
408
-        }
409
-
410
-        return $preferred;
411
-    }
412
-
413
-    /**
414
-     * Returns a property with a specific TYPE value (ADR, TEL, or EMAIL).
415
-     *
416
-     * This function will return null if the property does not exist. If there are
417
-     * multiple properties with the same TYPE value, only one will be returned.
418
-     *
419
-     * @param string $propertyName
420
-     * @param string $type
421
-     *
422
-     * @return VObject\Property|null
423
-     */
424
-    public function getByType($propertyName, $type)
425
-    {
426
-        foreach ($this->select($propertyName) as $field) {
427
-            if (isset($field['TYPE']) && $field['TYPE']->has($type)) {
428
-                return $field;
429
-            }
430
-        }
431
-    }
432
-
433
-    /**
434
-     * This method should return a list of default property values.
435
-     *
436
-     * @return array
437
-     */
438
-    protected function getDefaults()
439
-    {
440
-        return [
441
-            'VERSION' => '4.0',
442
-            'PRODID' => '-//Sabre//Sabre VObject '.VObject\Version::VERSION.'//EN',
443
-            'UID' => 'sabre-vobject-'.VObject\UUIDUtil::getUUID(),
444
-        ];
445
-    }
446
-
447
-    /**
448
-     * This method returns an array, with the representation as it should be
449
-     * encoded in json. This is used to create jCard or jCal documents.
450
-     *
451
-     * @return array
452
-     */
453
-    #[\ReturnTypeWillChange]
454
-    public function jsonSerialize()
455
-    {
456
-        // A vcard does not have sub-components, so we're overriding this
457
-        // method to remove that array element.
458
-        $properties = [];
459
-
460
-        foreach ($this->children() as $child) {
461
-            $properties[] = $child->jsonSerialize();
462
-        }
463
-
464
-        return [
465
-            strtolower($this->name),
466
-            $properties,
467
-        ];
468
-    }
469
-
470
-    /**
471
-     * This method serializes the data into XML. This is used to create xCard or
472
-     * xCal documents.
473
-     *
474
-     * @param Xml\Writer $writer XML writer
475
-     */
476
-    public function xmlSerialize(Xml\Writer $writer): void
477
-    {
478
-        $propertiesByGroup = [];
479
-
480
-        foreach ($this->children() as $property) {
481
-            $group = $property->group;
482
-
483
-            if (!isset($propertiesByGroup[$group])) {
484
-                $propertiesByGroup[$group] = [];
485
-            }
486
-
487
-            $propertiesByGroup[$group][] = $property;
488
-        }
489
-
490
-        $writer->startElement(strtolower($this->name));
491
-
492
-        foreach ($propertiesByGroup as $group => $properties) {
493
-            if (!empty($group)) {
494
-                $writer->startElement('group');
495
-                $writer->writeAttribute('name', strtolower($group));
496
-            }
497
-
498
-            foreach ($properties as $property) {
499
-                switch ($property->name) {
500
-                    case 'VERSION':
501
-                        break;
502
-
503
-                    case 'XML':
504
-                        $value = $property->getParts();
505
-                        $fragment = new Xml\Element\XmlFragment($value[0]);
506
-                        $writer->write($fragment);
507
-                        break;
508
-
509
-                    default:
510
-                        $property->xmlSerialize($writer);
511
-                        break;
512
-                }
513
-            }
514
-
515
-            if (!empty($group)) {
516
-                $writer->endElement();
517
-            }
518
-        }
519
-
520
-        $writer->endElement();
521
-    }
522
-
523
-    /**
524
-     * Returns the default class for a property name.
525
-     *
526
-     * @param string $propertyName
527
-     *
528
-     * @return string
529
-     */
530
-    public function getClassNameForPropertyName($propertyName)
531
-    {
532
-        $className = parent::getClassNameForPropertyName($propertyName);
533
-
534
-        // In vCard 4, BINARY no longer exists, and we need URI instead.
535
-        if (VObject\Property\Binary::class == $className && self::VCARD40 === $this->getDocumentType()) {
536
-            return VObject\Property\Uri::class;
537
-        }
538
-
539
-        return $className;
540
-    }
20
+	/**
21
+	 * The default name for this component.
22
+	 *
23
+	 * This should be 'VCALENDAR' or 'VCARD'.
24
+	 *
25
+	 * @var string
26
+	 */
27
+	public static $defaultName = 'VCARD';
28
+
29
+	/**
30
+	 * Caching the version number.
31
+	 *
32
+	 * @var int
33
+	 */
34
+	private $version = null;
35
+
36
+	/**
37
+	 * This is a list of components, and which classes they should map to.
38
+	 *
39
+	 * @var array
40
+	 */
41
+	public static $componentMap = [
42
+		'VCARD' => VCard::class,
43
+	];
44
+
45
+	/**
46
+	 * List of value-types, and which classes they map to.
47
+	 *
48
+	 * @var array
49
+	 */
50
+	public static $valueMap = [
51
+		'BINARY' => VObject\Property\Binary::class,
52
+		'BOOLEAN' => VObject\Property\Boolean::class,
53
+		'CONTENT-ID' => VObject\Property\FlatText::class,   // vCard 2.1 only
54
+		'DATE' => VObject\Property\VCard\Date::class,
55
+		'DATE-TIME' => VObject\Property\VCard\DateTime::class,
56
+		'DATE-AND-OR-TIME' => VObject\Property\VCard\DateAndOrTime::class, // vCard only
57
+		'FLOAT' => VObject\Property\FloatValue::class,
58
+		'INTEGER' => VObject\Property\IntegerValue::class,
59
+		'LANGUAGE-TAG' => VObject\Property\VCard\LanguageTag::class,
60
+		'PHONE-NUMBER' => VObject\Property\VCard\PhoneNumber::class, // vCard 3.0 only
61
+		'TIMESTAMP' => VObject\Property\VCard\TimeStamp::class,
62
+		'TEXT' => VObject\Property\Text::class,
63
+		'TIME' => VObject\Property\Time::class,
64
+		'UNKNOWN' => VObject\Property\Unknown::class, // jCard / jCal-only.
65
+		'URI' => VObject\Property\Uri::class,
66
+		'URL' => VObject\Property\Uri::class, // vCard 2.1 only
67
+		'UTC-OFFSET' => VObject\Property\UtcOffset::class,
68
+	];
69
+
70
+	/**
71
+	 * List of properties, and which classes they map to.
72
+	 *
73
+	 * @var array
74
+	 */
75
+	public static $propertyMap = [
76
+		// vCard 2.1 properties and up
77
+		'N' => VObject\Property\Text::class,
78
+		'FN' => VObject\Property\FlatText::class,
79
+		'PHOTO' => VObject\Property\Binary::class,
80
+		'BDAY' => VObject\Property\VCard\DateAndOrTime::class,
81
+		'ADR' => VObject\Property\Text::class,
82
+		'LABEL' => VObject\Property\FlatText::class, // Removed in vCard 4.0
83
+		'TEL' => VObject\Property\FlatText::class,
84
+		'EMAIL' => VObject\Property\FlatText::class,
85
+		'MAILER' => VObject\Property\FlatText::class, // Removed in vCard 4.0
86
+		'GEO' => VObject\Property\FlatText::class,
87
+		'TITLE' => VObject\Property\FlatText::class,
88
+		'ROLE' => VObject\Property\FlatText::class,
89
+		'LOGO' => VObject\Property\Binary::class,
90
+		// 'AGENT'   => 'Sabre\\VObject\\Property\\',      // Todo: is an embedded vCard. Probably rare, so
91
+								 // not supported at the moment
92
+		'ORG' => VObject\Property\Text::class,
93
+		'NOTE' => VObject\Property\FlatText::class,
94
+		'REV' => VObject\Property\VCard\TimeStamp::class,
95
+		'SOUND' => VObject\Property\FlatText::class,
96
+		'URL' => VObject\Property\Uri::class,
97
+		'UID' => VObject\Property\FlatText::class,
98
+		'VERSION' => VObject\Property\FlatText::class,
99
+		'KEY' => VObject\Property\FlatText::class,
100
+		'TZ' => VObject\Property\Text::class,
101
+
102
+		// vCard 3.0 properties
103
+		'CATEGORIES' => VObject\Property\Text::class,
104
+		'SORT-STRING' => VObject\Property\FlatText::class,
105
+		'PRODID' => VObject\Property\FlatText::class,
106
+		'NICKNAME' => VObject\Property\Text::class,
107
+		'CLASS' => VObject\Property\FlatText::class, // Removed in vCard 4.0
108
+
109
+		// rfc2739 properties
110
+		'FBURL' => VObject\Property\Uri::class,
111
+		'CAPURI' => VObject\Property\Uri::class,
112
+		'CALURI' => VObject\Property\Uri::class,
113
+		'CALADRURI' => VObject\Property\Uri::class,
114
+
115
+		// rfc4770 properties
116
+		'IMPP' => VObject\Property\Uri::class,
117
+
118
+		// vCard 4.0 properties
119
+		'SOURCE' => VObject\Property\Uri::class,
120
+		'XML' => VObject\Property\FlatText::class,
121
+		'ANNIVERSARY' => VObject\Property\VCard\DateAndOrTime::class,
122
+		'CLIENTPIDMAP' => VObject\Property\Text::class,
123
+		'LANG' => VObject\Property\VCard\LanguageTag::class,
124
+		'GENDER' => VObject\Property\Text::class,
125
+		'KIND' => VObject\Property\FlatText::class,
126
+		'MEMBER' => VObject\Property\Uri::class,
127
+		'RELATED' => VObject\Property\Uri::class,
128
+
129
+		// rfc6474 properties
130
+		'BIRTHPLACE' => VObject\Property\FlatText::class,
131
+		'DEATHPLACE' => VObject\Property\FlatText::class,
132
+		'DEATHDATE' => VObject\Property\VCard\DateAndOrTime::class,
133
+
134
+		// rfc6715 properties
135
+		'EXPERTISE' => VObject\Property\FlatText::class,
136
+		'HOBBY' => VObject\Property\FlatText::class,
137
+		'INTEREST' => VObject\Property\FlatText::class,
138
+		'ORG-DIRECTORY' => VObject\Property\FlatText::class,
139
+	];
140
+
141
+	/**
142
+	 * Returns the current document type.
143
+	 *
144
+	 * @return int
145
+	 */
146
+	public function getDocumentType()
147
+	{
148
+		if (!$this->version) {
149
+			$version = (string) $this->VERSION;
150
+
151
+			switch ($version) {
152
+				case '2.1':
153
+					$this->version = self::VCARD21;
154
+					break;
155
+				case '3.0':
156
+					$this->version = self::VCARD30;
157
+					break;
158
+				case '4.0':
159
+					$this->version = self::VCARD40;
160
+					break;
161
+				default:
162
+					// We don't want to cache the version if it's unknown,
163
+					// because we might get a version property in a bit.
164
+					return self::UNKNOWN;
165
+			}
166
+		}
167
+
168
+		return $this->version;
169
+	}
170
+
171
+	/**
172
+	 * Converts the document to a different vcard version.
173
+	 *
174
+	 * Use one of the VCARD constants for the target. This method will return
175
+	 * a copy of the vcard in the new version.
176
+	 *
177
+	 * At the moment the only supported conversion is from 3.0 to 4.0.
178
+	 *
179
+	 * If input and output version are identical, a clone is returned.
180
+	 *
181
+	 * @param int $target
182
+	 *
183
+	 * @return VCard
184
+	 */
185
+	public function convert($target)
186
+	{
187
+		$converter = new VObject\VCardConverter();
188
+
189
+		return $converter->convert($this, $target);
190
+	}
191
+
192
+	/**
193
+	 * VCards with version 2.1, 3.0 and 4.0 are found.
194
+	 *
195
+	 * If the VCARD doesn't know its version, 2.1 is assumed.
196
+	 */
197
+	const DEFAULT_VERSION = self::VCARD21;
198
+
199
+	/**
200
+	 * Validates the node for correctness.
201
+	 *
202
+	 * The following options are supported:
203
+	 *   Node::REPAIR - May attempt to automatically repair the problem.
204
+	 *
205
+	 * This method returns an array with detected problems.
206
+	 * Every element has the following properties:
207
+	 *
208
+	 *  * level - problem level.
209
+	 *  * message - A human-readable string describing the issue.
210
+	 *  * node - A reference to the problematic node.
211
+	 *
212
+	 * The level means:
213
+	 *   1 - The issue was repaired (only happens if REPAIR was turned on)
214
+	 *   2 - An inconsequential issue
215
+	 *   3 - A severe issue.
216
+	 *
217
+	 * @param int $options
218
+	 *
219
+	 * @return array
220
+	 */
221
+	public function validate($options = 0)
222
+	{
223
+		$warnings = [];
224
+
225
+		$versionMap = [
226
+			self::VCARD21 => '2.1',
227
+			self::VCARD30 => '3.0',
228
+			self::VCARD40 => '4.0',
229
+		];
230
+
231
+		$version = $this->select('VERSION');
232
+		if (1 === count($version)) {
233
+			$version = (string) $this->VERSION;
234
+			if ('2.1' !== $version && '3.0' !== $version && '4.0' !== $version) {
235
+				$warnings[] = [
236
+					'level' => 3,
237
+					'message' => 'Only vcard version 4.0 (RFC6350), version 3.0 (RFC2426) or version 2.1 (icm-vcard-2.1) are supported.',
238
+					'node' => $this,
239
+				];
240
+				if ($options & self::REPAIR) {
241
+					$this->VERSION = $versionMap[self::DEFAULT_VERSION];
242
+				}
243
+			}
244
+			if ('2.1' === $version && ($options & self::PROFILE_CARDDAV)) {
245
+				$warnings[] = [
246
+					'level' => 3,
247
+					'message' => 'CardDAV servers are not allowed to accept vCard 2.1.',
248
+					'node' => $this,
249
+				];
250
+			}
251
+		}
252
+		$uid = $this->select('UID');
253
+		if (0 === count($uid)) {
254
+			if ($options & self::PROFILE_CARDDAV) {
255
+				// Required for CardDAV
256
+				$warningLevel = 3;
257
+				$message = 'vCards on CardDAV servers MUST have a UID property.';
258
+			} else {
259
+				// Not required for regular vcards
260
+				$warningLevel = 2;
261
+				$message = 'Adding a UID to a vCard property is recommended.';
262
+			}
263
+			if ($options & self::REPAIR) {
264
+				$this->UID = VObject\UUIDUtil::getUUID();
265
+				$warningLevel = 1;
266
+			}
267
+			$warnings[] = [
268
+				'level' => $warningLevel,
269
+				'message' => $message,
270
+				'node' => $this,
271
+			];
272
+		}
273
+
274
+		$fn = $this->select('FN');
275
+		if (1 !== count($fn)) {
276
+			$repaired = false;
277
+			if (($options & self::REPAIR) && 0 === count($fn)) {
278
+				// We're going to try to see if we can use the contents of the
279
+				// N property.
280
+				if (isset($this->N)) {
281
+					$value = explode(';', (string) $this->N);
282
+					if (isset($value[1]) && $value[1]) {
283
+						$this->FN = $value[1].' '.$value[0];
284
+					} else {
285
+						$this->FN = $value[0];
286
+					}
287
+					$repaired = true;
288
+
289
+				// Otherwise, the ORG property may work
290
+				} elseif (isset($this->ORG)) {
291
+					$this->FN = (string) $this->ORG;
292
+					$repaired = true;
293
+
294
+				// Otherwise, the NICKNAME property may work
295
+				} elseif (isset($this->NICKNAME)) {
296
+					$this->FN = (string) $this->NICKNAME;
297
+					$repaired = true;
298
+
299
+				// Otherwise, the EMAIL property may work
300
+				} elseif (isset($this->EMAIL)) {
301
+					$this->FN = (string) $this->EMAIL;
302
+					$repaired = true;
303
+				}
304
+			}
305
+			$warnings[] = [
306
+				'level' => $repaired ? 1 : 3,
307
+				'message' => 'The FN property must appear in the VCARD component exactly 1 time',
308
+				'node' => $this,
309
+			];
310
+		}
311
+
312
+		return array_merge(
313
+			parent::validate($options),
314
+			$warnings
315
+		);
316
+	}
317
+
318
+	/**
319
+	 * A simple list of validation rules.
320
+	 *
321
+	 * This is simply a list of properties, and how many times they either
322
+	 * must or must not appear.
323
+	 *
324
+	 * Possible values per property:
325
+	 *   * 0 - Must not appear.
326
+	 *   * 1 - Must appear exactly once.
327
+	 *   * + - Must appear at least once.
328
+	 *   * * - Can appear any number of times.
329
+	 *   * ? - May appear, but not more than once.
330
+	 *
331
+	 * @var array
332
+	 */
333
+	public function getValidationRules()
334
+	{
335
+		return [
336
+			'ADR' => '*',
337
+			'ANNIVERSARY' => '?',
338
+			'BDAY' => '?',
339
+			'CALADRURI' => '*',
340
+			'CALURI' => '*',
341
+			'CATEGORIES' => '*',
342
+			'CLIENTPIDMAP' => '*',
343
+			'EMAIL' => '*',
344
+			'FBURL' => '*',
345
+			'IMPP' => '*',
346
+			'GENDER' => '?',
347
+			'GEO' => '*',
348
+			'KEY' => '*',
349
+			'KIND' => '?',
350
+			'LANG' => '*',
351
+			'LOGO' => '*',
352
+			'MEMBER' => '*',
353
+			'N' => '?',
354
+			'NICKNAME' => '*',
355
+			'NOTE' => '*',
356
+			'ORG' => '*',
357
+			'PHOTO' => '*',
358
+			'PRODID' => '?',
359
+			'RELATED' => '*',
360
+			'REV' => '?',
361
+			'ROLE' => '*',
362
+			'SOUND' => '*',
363
+			'SOURCE' => '*',
364
+			'TEL' => '*',
365
+			'TITLE' => '*',
366
+			'TZ' => '*',
367
+			'URL' => '*',
368
+			'VERSION' => '1',
369
+			'XML' => '*',
370
+
371
+			// FN is commented out, because it's already handled by the
372
+			// validate function, which may also try to repair it.
373
+			// 'FN'           => '+',
374
+			'UID' => '?',
375
+		];
376
+	}
377
+
378
+	/**
379
+	 * Returns a preferred field.
380
+	 *
381
+	 * VCards can indicate whether a field such as ADR, TEL or EMAIL is
382
+	 * preferred by specifying TYPE=PREF (vcard 2.1, 3) or PREF=x (vcard 4, x
383
+	 * being a number between 1 and 100).
384
+	 *
385
+	 * If neither of those parameters are specified, the first is returned, if
386
+	 * a field with that name does not exist, null is returned.
387
+	 *
388
+	 * @param string $fieldName
389
+	 *
390
+	 * @return VObject\Property|null
391
+	 */
392
+	public function preferred($propertyName)
393
+	{
394
+		$preferred = null;
395
+		$lastPref = 101;
396
+		foreach ($this->select($propertyName) as $field) {
397
+			$pref = 101;
398
+			if (isset($field['TYPE']) && $field['TYPE']->has('PREF')) {
399
+				$pref = 1;
400
+			} elseif (isset($field['PREF'])) {
401
+				$pref = $field['PREF']->getValue();
402
+			}
403
+
404
+			if ($pref < $lastPref || is_null($preferred)) {
405
+				$preferred = $field;
406
+				$lastPref = $pref;
407
+			}
408
+		}
409
+
410
+		return $preferred;
411
+	}
412
+
413
+	/**
414
+	 * Returns a property with a specific TYPE value (ADR, TEL, or EMAIL).
415
+	 *
416
+	 * This function will return null if the property does not exist. If there are
417
+	 * multiple properties with the same TYPE value, only one will be returned.
418
+	 *
419
+	 * @param string $propertyName
420
+	 * @param string $type
421
+	 *
422
+	 * @return VObject\Property|null
423
+	 */
424
+	public function getByType($propertyName, $type)
425
+	{
426
+		foreach ($this->select($propertyName) as $field) {
427
+			if (isset($field['TYPE']) && $field['TYPE']->has($type)) {
428
+				return $field;
429
+			}
430
+		}
431
+	}
432
+
433
+	/**
434
+	 * This method should return a list of default property values.
435
+	 *
436
+	 * @return array
437
+	 */
438
+	protected function getDefaults()
439
+	{
440
+		return [
441
+			'VERSION' => '4.0',
442
+			'PRODID' => '-//Sabre//Sabre VObject '.VObject\Version::VERSION.'//EN',
443
+			'UID' => 'sabre-vobject-'.VObject\UUIDUtil::getUUID(),
444
+		];
445
+	}
446
+
447
+	/**
448
+	 * This method returns an array, with the representation as it should be
449
+	 * encoded in json. This is used to create jCard or jCal documents.
450
+	 *
451
+	 * @return array
452
+	 */
453
+	#[\ReturnTypeWillChange]
454
+	public function jsonSerialize()
455
+	{
456
+		// A vcard does not have sub-components, so we're overriding this
457
+		// method to remove that array element.
458
+		$properties = [];
459
+
460
+		foreach ($this->children() as $child) {
461
+			$properties[] = $child->jsonSerialize();
462
+		}
463
+
464
+		return [
465
+			strtolower($this->name),
466
+			$properties,
467
+		];
468
+	}
469
+
470
+	/**
471
+	 * This method serializes the data into XML. This is used to create xCard or
472
+	 * xCal documents.
473
+	 *
474
+	 * @param Xml\Writer $writer XML writer
475
+	 */
476
+	public function xmlSerialize(Xml\Writer $writer): void
477
+	{
478
+		$propertiesByGroup = [];
479
+
480
+		foreach ($this->children() as $property) {
481
+			$group = $property->group;
482
+
483
+			if (!isset($propertiesByGroup[$group])) {
484
+				$propertiesByGroup[$group] = [];
485
+			}
486
+
487
+			$propertiesByGroup[$group][] = $property;
488
+		}
489
+
490
+		$writer->startElement(strtolower($this->name));
491
+
492
+		foreach ($propertiesByGroup as $group => $properties) {
493
+			if (!empty($group)) {
494
+				$writer->startElement('group');
495
+				$writer->writeAttribute('name', strtolower($group));
496
+			}
497
+
498
+			foreach ($properties as $property) {
499
+				switch ($property->name) {
500
+					case 'VERSION':
501
+						break;
502
+
503
+					case 'XML':
504
+						$value = $property->getParts();
505
+						$fragment = new Xml\Element\XmlFragment($value[0]);
506
+						$writer->write($fragment);
507
+						break;
508
+
509
+					default:
510
+						$property->xmlSerialize($writer);
511
+						break;
512
+				}
513
+			}
514
+
515
+			if (!empty($group)) {
516
+				$writer->endElement();
517
+			}
518
+		}
519
+
520
+		$writer->endElement();
521
+	}
522
+
523
+	/**
524
+	 * Returns the default class for a property name.
525
+	 *
526
+	 * @param string $propertyName
527
+	 *
528
+	 * @return string
529
+	 */
530
+	public function getClassNameForPropertyName($propertyName)
531
+	{
532
+		$className = parent::getClassNameForPropertyName($propertyName);
533
+
534
+		// In vCard 4, BINARY no longer exists, and we need URI instead.
535
+		if (VObject\Property\Binary::class == $className && self::VCARD40 === $this->getDocumentType()) {
536
+			return VObject\Property\Uri::class;
537
+		}
538
+
539
+		return $className;
540
+	}
541 541
 }
Please login to merge, or discard this patch.