Completed
Push — developer ( d751a3...e1a3df )
by Błażej
164:44 queued 111:37
created
libraries/SabreDAV/VObject/Property/VCard/DateTime.php 1 patch
Indentation   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -13,18 +13,18 @@
 block discarded – undo
13 13
  */
14 14
 class DateTime extends DateAndOrTime {
15 15
 
16
-    /**
17
-     * Returns the type of value.
18
-     *
19
-     * This corresponds to the VALUE= parameter. Every property also has a
20
-     * 'default' valueType.
21
-     *
22
-     * @return string
23
-     */
24
-    public function getValueType() {
16
+	/**
17
+	 * Returns the type of value.
18
+	 *
19
+	 * This corresponds to the VALUE= parameter. Every property also has a
20
+	 * 'default' valueType.
21
+	 *
22
+	 * @return string
23
+	 */
24
+	public function getValueType() {
25 25
 
26
-        return 'DATE-TIME';
26
+		return 'DATE-TIME';
27 27
 
28
-    }
28
+	}
29 29
 
30 30
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/Property/Time.php 1 patch
Indentation   +125 added lines, -125 removed lines patch added patch discarded remove patch
@@ -15,130 +15,130 @@
 block discarded – undo
15 15
  */
16 16
 class Time extends Text {
17 17
 
18
-    /**
19
-     * In case this is a multi-value property. This string will be used as a
20
-     * delimiter.
21
-     *
22
-     * @var string|null
23
-     */
24
-    public $delimiter = null;
25
-
26
-    /**
27
-     * Returns the type of value.
28
-     *
29
-     * This corresponds to the VALUE= parameter. Every property also has a
30
-     * 'default' valueType.
31
-     *
32
-     * @return string
33
-     */
34
-    public function getValueType() {
35
-
36
-        return 'TIME';
37
-
38
-    }
39
-
40
-    /**
41
-     * Sets the JSON value, as it would appear in a jCard or jCal object.
42
-     *
43
-     * The value must always be an array.
44
-     *
45
-     * @param array $value
46
-     *
47
-     * @return void
48
-     */
49
-    public function setJsonValue(array $value) {
50
-
51
-        // Removing colons from value.
52
-        $value = str_replace(
53
-            ':',
54
-            '',
55
-            $value
56
-        );
57
-
58
-        if (count($value) === 1) {
59
-            $this->setValue(reset($value));
60
-        } else {
61
-            $this->setValue($value);
62
-        }
63
-
64
-    }
65
-
66
-    /**
67
-     * Returns the value, in the format it should be encoded for json.
68
-     *
69
-     * This method must always return an array.
70
-     *
71
-     * @return array
72
-     */
73
-    public function getJsonValue() {
74
-
75
-        $parts = DateTimeParser::parseVCardTime($this->getValue());
76
-        $timeStr = '';
77
-
78
-        // Hour
79
-        if (!is_null($parts['hour'])) {
80
-            $timeStr .= $parts['hour'];
81
-
82
-            if (!is_null($parts['minute'])) {
83
-                $timeStr .= ':';
84
-            }
85
-        } else {
86
-            // We know either minute or second _must_ be set, so we insert a
87
-            // dash for an empty value.
88
-            $timeStr .= '-';
89
-        }
90
-
91
-        // Minute
92
-        if (!is_null($parts['minute'])) {
93
-            $timeStr .= $parts['minute'];
94
-
95
-            if (!is_null($parts['second'])) {
96
-                $timeStr .= ':';
97
-            }
98
-        } else {
99
-            if (isset($parts['second'])) {
100
-                // Dash for empty minute
101
-                $timeStr .= '-';
102
-            }
103
-        }
104
-
105
-        // Second
106
-        if (!is_null($parts['second'])) {
107
-            $timeStr .= $parts['second'];
108
-        }
109
-
110
-        // Timezone
111
-        if (!is_null($parts['timezone'])) {
112
-            if ($parts['timezone'] === 'Z') {
113
-                $timeStr .= 'Z';
114
-            } else {
115
-                $timeStr .=
116
-                    preg_replace('/([0-9]{2})([0-9]{2})$/', '$1:$2', $parts['timezone']);
117
-            }
118
-        }
119
-
120
-        return [$timeStr];
121
-
122
-    }
123
-
124
-    /**
125
-     * Hydrate data from a XML subtree, as it would appear in a xCard or xCal
126
-     * object.
127
-     *
128
-     * @param array $value
129
-     *
130
-     * @return void
131
-     */
132
-    public function setXmlValue(array $value) {
133
-
134
-        $value = array_map(
135
-            public function($value) {
136
-                return str_replace(':', '', $value);
137
-            },
138
-            $value
139
-        );
140
-        parent::setXmlValue($value);
141
-
142
-    }
18
+	/**
19
+	 * In case this is a multi-value property. This string will be used as a
20
+	 * delimiter.
21
+	 *
22
+	 * @var string|null
23
+	 */
24
+	public $delimiter = null;
25
+
26
+	/**
27
+	 * Returns the type of value.
28
+	 *
29
+	 * This corresponds to the VALUE= parameter. Every property also has a
30
+	 * 'default' valueType.
31
+	 *
32
+	 * @return string
33
+	 */
34
+	public function getValueType() {
35
+
36
+		return 'TIME';
37
+
38
+	}
39
+
40
+	/**
41
+	 * Sets the JSON value, as it would appear in a jCard or jCal object.
42
+	 *
43
+	 * The value must always be an array.
44
+	 *
45
+	 * @param array $value
46
+	 *
47
+	 * @return void
48
+	 */
49
+	public function setJsonValue(array $value) {
50
+
51
+		// Removing colons from value.
52
+		$value = str_replace(
53
+			':',
54
+			'',
55
+			$value
56
+		);
57
+
58
+		if (count($value) === 1) {
59
+			$this->setValue(reset($value));
60
+		} else {
61
+			$this->setValue($value);
62
+		}
63
+
64
+	}
65
+
66
+	/**
67
+	 * Returns the value, in the format it should be encoded for json.
68
+	 *
69
+	 * This method must always return an array.
70
+	 *
71
+	 * @return array
72
+	 */
73
+	public function getJsonValue() {
74
+
75
+		$parts = DateTimeParser::parseVCardTime($this->getValue());
76
+		$timeStr = '';
77
+
78
+		// Hour
79
+		if (!is_null($parts['hour'])) {
80
+			$timeStr .= $parts['hour'];
81
+
82
+			if (!is_null($parts['minute'])) {
83
+				$timeStr .= ':';
84
+			}
85
+		} else {
86
+			// We know either minute or second _must_ be set, so we insert a
87
+			// dash for an empty value.
88
+			$timeStr .= '-';
89
+		}
90
+
91
+		// Minute
92
+		if (!is_null($parts['minute'])) {
93
+			$timeStr .= $parts['minute'];
94
+
95
+			if (!is_null($parts['second'])) {
96
+				$timeStr .= ':';
97
+			}
98
+		} else {
99
+			if (isset($parts['second'])) {
100
+				// Dash for empty minute
101
+				$timeStr .= '-';
102
+			}
103
+		}
104
+
105
+		// Second
106
+		if (!is_null($parts['second'])) {
107
+			$timeStr .= $parts['second'];
108
+		}
109
+
110
+		// Timezone
111
+		if (!is_null($parts['timezone'])) {
112
+			if ($parts['timezone'] === 'Z') {
113
+				$timeStr .= 'Z';
114
+			} else {
115
+				$timeStr .=
116
+					preg_replace('/([0-9]{2})([0-9]{2})$/', '$1:$2', $parts['timezone']);
117
+			}
118
+		}
119
+
120
+		return [$timeStr];
121
+
122
+	}
123
+
124
+	/**
125
+	 * Hydrate data from a XML subtree, as it would appear in a xCard or xCal
126
+	 * object.
127
+	 *
128
+	 * @param array $value
129
+	 *
130
+	 * @return void
131
+	 */
132
+	public function setXmlValue(array $value) {
133
+
134
+		$value = array_map(
135
+			public function($value) {
136
+				return str_replace(':', '', $value);
137
+			},
138
+			$value
139
+		);
140
+		parent::setXmlValue($value);
141
+
142
+	}
143 143
 
144 144
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/Property/Uri.php 1 patch
Indentation   +102 added lines, -102 removed lines patch added patch discarded remove patch
@@ -16,107 +16,107 @@
 block discarded – undo
16 16
  */
17 17
 class Uri extends Text {
18 18
 
19
-    /**
20
-     * In case this is a multi-value property. This string will be used as a
21
-     * delimiter.
22
-     *
23
-     * @var string|null
24
-     */
25
-    public $delimiter = null;
26
-
27
-    /**
28
-     * Returns the type of value.
29
-     *
30
-     * This corresponds to the VALUE= parameter. Every property also has a
31
-     * 'default' valueType.
32
-     *
33
-     * @return string
34
-     */
35
-    public function getValueType() {
36
-
37
-        return 'URI';
38
-
39
-    }
40
-
41
-    /**
42
-     * Returns an iterable list of children.
43
-     *
44
-     * @return array
45
-     */
46
-    public function parameters() {
47
-
48
-        $parameters = parent::parameters();
49
-        if (!isset($parameters['VALUE']) && in_array($this->name, ['URL', 'PHOTO'])) {
50
-            // If we are encoding a URI value, and this URI value has no
51
-            // VALUE=URI parameter, we add it anyway.
52
-            //
53
-            // This is not required by any spec, but both Apple iCal and Apple
54
-            // AddressBook (at least in version 10.8) will trip over this if
55
-            // this is not set, and so it improves compatibility.
56
-            //
57
-            // See Issue #227 and #235
58
-            $parameters['VALUE'] = new Parameter($this->root, 'VALUE', 'URI');
59
-        }
60
-        return $parameters;
61
-
62
-    }
63
-
64
-    /**
65
-     * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
66
-     *
67
-     * This has been 'unfolded', so only 1 line will be passed. Unescaping is
68
-     * not yet done, but parameters are not included.
69
-     *
70
-     * @param string $val
71
-     *
72
-     * @return void
73
-     */
74
-    public function setRawMimeDirValue($val) {
75
-
76
-        // Normally we don't need to do any type of unescaping for these
77
-        // properties, however.. we've noticed that Google Contacts
78
-        // specifically escapes the colon (:) with a blackslash. While I have
79
-        // no clue why they thought that was a good idea, I'm unescaping it
80
-        // anyway.
81
-        //
82
-        // Good thing backslashes are not allowed in urls. Makes it easy to
83
-        // assume that a backslash is always intended as an escape character.
84
-        if ($this->name === 'URL') {
85
-            $regex = '#  (?: (\\\\ (?: \\\\ | : ) ) ) #x';
86
-            $matches = preg_split($regex, $val, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
87
-            $newVal = '';
88
-            foreach ($matches as $match) {
89
-                switch ($match) {
90
-                    case '\:' :
91
-                        $newVal .= ':';
92
-                        break;
93
-                    default :
94
-                        $newVal .= $match;
95
-                        break;
96
-                }
97
-            }
98
-            $this->value = $newVal;
99
-        } else {
100
-            $this->value = strtr($val, ['\,' => ',']);
101
-        }
102
-
103
-    }
104
-
105
-    /**
106
-     * Returns a raw mime-dir representation of the value.
107
-     *
108
-     * @return string
109
-     */
110
-    public function getRawMimeDirValue() {
111
-
112
-        if (is_array($this->value)) {
113
-            $value = $this->value[0];
114
-        } else {
115
-            $value = $this->value;
116
-        }
117
-
118
-        return strtr($value, [',' => '\,']);
119
-
120
-    }
19
+	/**
20
+	 * In case this is a multi-value property. This string will be used as a
21
+	 * delimiter.
22
+	 *
23
+	 * @var string|null
24
+	 */
25
+	public $delimiter = null;
26
+
27
+	/**
28
+	 * Returns the type of value.
29
+	 *
30
+	 * This corresponds to the VALUE= parameter. Every property also has a
31
+	 * 'default' valueType.
32
+	 *
33
+	 * @return string
34
+	 */
35
+	public function getValueType() {
36
+
37
+		return 'URI';
38
+
39
+	}
40
+
41
+	/**
42
+	 * Returns an iterable list of children.
43
+	 *
44
+	 * @return array
45
+	 */
46
+	public function parameters() {
47
+
48
+		$parameters = parent::parameters();
49
+		if (!isset($parameters['VALUE']) && in_array($this->name, ['URL', 'PHOTO'])) {
50
+			// If we are encoding a URI value, and this URI value has no
51
+			// VALUE=URI parameter, we add it anyway.
52
+			//
53
+			// This is not required by any spec, but both Apple iCal and Apple
54
+			// AddressBook (at least in version 10.8) will trip over this if
55
+			// this is not set, and so it improves compatibility.
56
+			//
57
+			// See Issue #227 and #235
58
+			$parameters['VALUE'] = new Parameter($this->root, 'VALUE', 'URI');
59
+		}
60
+		return $parameters;
61
+
62
+	}
63
+
64
+	/**
65
+	 * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
66
+	 *
67
+	 * This has been 'unfolded', so only 1 line will be passed. Unescaping is
68
+	 * not yet done, but parameters are not included.
69
+	 *
70
+	 * @param string $val
71
+	 *
72
+	 * @return void
73
+	 */
74
+	public function setRawMimeDirValue($val) {
75
+
76
+		// Normally we don't need to do any type of unescaping for these
77
+		// properties, however.. we've noticed that Google Contacts
78
+		// specifically escapes the colon (:) with a blackslash. While I have
79
+		// no clue why they thought that was a good idea, I'm unescaping it
80
+		// anyway.
81
+		//
82
+		// Good thing backslashes are not allowed in urls. Makes it easy to
83
+		// assume that a backslash is always intended as an escape character.
84
+		if ($this->name === 'URL') {
85
+			$regex = '#  (?: (\\\\ (?: \\\\ | : ) ) ) #x';
86
+			$matches = preg_split($regex, $val, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
87
+			$newVal = '';
88
+			foreach ($matches as $match) {
89
+				switch ($match) {
90
+					case '\:' :
91
+						$newVal .= ':';
92
+						break;
93
+					default :
94
+						$newVal .= $match;
95
+						break;
96
+				}
97
+			}
98
+			$this->value = $newVal;
99
+		} else {
100
+			$this->value = strtr($val, ['\,' => ',']);
101
+		}
102
+
103
+	}
104
+
105
+	/**
106
+	 * Returns a raw mime-dir representation of the value.
107
+	 *
108
+	 * @return string
109
+	 */
110
+	public function getRawMimeDirValue() {
111
+
112
+		if (is_array($this->value)) {
113
+			$value = $this->value[0];
114
+		} else {
115
+			$value = $this->value;
116
+		}
117
+
118
+		return strtr($value, [',' => '\,']);
119
+
120
+	}
121 121
 
122 122
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/FreeBusyData.php 1 patch
Indentation   +178 added lines, -178 removed lines patch added patch discarded remove patch
@@ -11,183 +11,183 @@
 block discarded – undo
11 11
  */
12 12
 class FreeBusyData {
13 13
 
14
-    /**
15
-     * Start timestamp
16
-     *
17
-     * @var int
18
-     */
19
-    protected $start;
20
-
21
-    /**
22
-     * End timestamp
23
-     *
24
-     * @var int
25
-     */
26
-    protected $end;
27
-
28
-    /**
29
-     * A list of free-busy times.
30
-     *
31
-     * @var array
32
-     */
33
-    protected $data;
34
-
35
-    public function __construct($start, $end) {
36
-
37
-        $this->start = $start;
38
-        $this->end = $end;
39
-        $this->data = [];
40
-
41
-        $this->data[] = [
42
-            'start' => $this->start,
43
-            'end'   => $this->end,
44
-            'type'  => 'FREE',
45
-        ];
46
-
47
-    }
48
-
49
-    /**
50
-     * Adds free or busytime to the data.
51
-     *
52
-     * @param int $start
53
-     * @param int $end
54
-     * @param string $type FREE, BUSY, BUSY-UNAVAILABLE or BUSY-TENTATIVE
55
-     * @return void
56
-     */
57
-    public function add($start, $end, $type) {
58
-
59
-        if ($start > $this->end || $end < $this->start) {
60
-
61
-            // This new data is outside our timerange.
62
-            return;
63
-
64
-        }
65
-
66
-        if ($start < $this->start) {
67
-            // The item starts before our requested time range
68
-            $start = $this->start;
69
-        }
70
-        if ($end > $this->end) {
71
-            // The item ends after our requested time range
72
-            $end = $this->end;
73
-        }
74
-
75
-        // Finding out where we need to insert the new item.
76
-        $currentIndex = 0;
77
-        while ($start > $this->data[$currentIndex]['end']) {
78
-            $currentIndex++;
79
-        }
80
-
81
-        // The standard insertion point will be one _after_ the first
82
-        // overlapping item.
83
-        $insertStartIndex = $currentIndex + 1;
84
-
85
-        $newItem = [
86
-            'start' => $start,
87
-            'end'   => $end,
88
-            'type'  => $type,
89
-        ];
90
-
91
-        $preceedingItem = $this->data[$insertStartIndex - 1];
92
-        if ($this->data[$insertStartIndex - 1]['start'] === $start) {
93
-            // The old item starts at the exact same point as the new item.
94
-            $insertStartIndex--;
95
-        }
96
-
97
-        // Now we know where to insert the item, we need to know where it
98
-        // starts overlapping with items on the tail end. We need to start
99
-        // looking one item before the insertStartIndex, because it's possible
100
-        // that the new item 'sits inside' the previous old item.
101
-        if ($insertStartIndex > 0) {
102
-            $currentIndex = $insertStartIndex - 1;
103
-        } else {
104
-            $currentIndex = 0;
105
-        }
106
-
107
-        while ($end > $this->data[$currentIndex]['end']) {
108
-
109
-            $currentIndex++;
110
-
111
-        }
112
-
113
-        // What we are about to insert into the array
114
-        $newItems = [
115
-            $newItem
116
-        ];
117
-
118
-        // This is the amount of items that are completely overwritten by the
119
-        // new item.
120
-        $itemsToDelete = $currentIndex - $insertStartIndex;
121
-        if ($this->data[$currentIndex]['end'] <= $end) $itemsToDelete++;
122
-
123
-        // If itemsToDelete was -1, it means that the newly inserted item is
124
-        // actually sitting inside an existing one. This means we need to split
125
-        // the item at the current position in two and insert the new item in
126
-        // between.
127
-        if ($itemsToDelete === -1) {
128
-            $itemsToDelete = 0;
129
-            if ($newItem['end'] < $preceedingItem['end']) {
130
-                $newItems[] = [
131
-                    'start' => $newItem['end'] + 1,
132
-                    'end'   => $preceedingItem['end'],
133
-                    'type'  => $preceedingItem['type']
134
-                ];
135
-            }
136
-        }
137
-
138
-        array_splice(
139
-            $this->data,
140
-            $insertStartIndex,
141
-            $itemsToDelete,
142
-            $newItems
143
-        );
144
-
145
-        $doMerge = false;
146
-        $mergeOffset = $insertStartIndex;
147
-        $mergeItem = $newItem;
148
-        $mergeDelete = 1;
149
-
150
-        if (isset($this->data[$insertStartIndex - 1])) {
151
-            // Updating the start time of the previous item.
152
-            $this->data[$insertStartIndex - 1]['end'] = $start;
153
-
154
-            // If the previous and the current are of the same type, we can
155
-            // merge them into one item.
156
-            if ($this->data[$insertStartIndex - 1]['type'] === $this->data[$insertStartIndex]['type']) {
157
-                $doMerge = true;
158
-                $mergeOffset--;
159
-                $mergeDelete++;
160
-                $mergeItem['start'] = $this->data[$insertStartIndex - 1]['start'];
161
-            }
162
-        }
163
-        if (isset($this->data[$insertStartIndex + 1])) {
164
-            // Updating the start time of the next item.
165
-            $this->data[$insertStartIndex + 1]['start'] = $end;
166
-
167
-            // If the next and the current are of the same type, we can
168
-            // merge them into one item.
169
-            if ($this->data[$insertStartIndex + 1]['type'] === $this->data[$insertStartIndex]['type']) {
170
-                $doMerge = true;
171
-                $mergeDelete++;
172
-                $mergeItem['end'] = $this->data[$insertStartIndex + 1]['end'];
173
-            }
174
-
175
-        }
176
-        if ($doMerge) {
177
-            array_splice(
178
-                $this->data,
179
-                $mergeOffset,
180
-                $mergeDelete,
181
-                [$mergeItem]
182
-            );
183
-        }
184
-
185
-    }
186
-
187
-    public function getData() {
188
-
189
-        return $this->data;
190
-
191
-    }
14
+	/**
15
+	 * Start timestamp
16
+	 *
17
+	 * @var int
18
+	 */
19
+	protected $start;
20
+
21
+	/**
22
+	 * End timestamp
23
+	 *
24
+	 * @var int
25
+	 */
26
+	protected $end;
27
+
28
+	/**
29
+	 * A list of free-busy times.
30
+	 *
31
+	 * @var array
32
+	 */
33
+	protected $data;
34
+
35
+	public function __construct($start, $end) {
36
+
37
+		$this->start = $start;
38
+		$this->end = $end;
39
+		$this->data = [];
40
+
41
+		$this->data[] = [
42
+			'start' => $this->start,
43
+			'end'   => $this->end,
44
+			'type'  => 'FREE',
45
+		];
46
+
47
+	}
48
+
49
+	/**
50
+	 * Adds free or busytime to the data.
51
+	 *
52
+	 * @param int $start
53
+	 * @param int $end
54
+	 * @param string $type FREE, BUSY, BUSY-UNAVAILABLE or BUSY-TENTATIVE
55
+	 * @return void
56
+	 */
57
+	public function add($start, $end, $type) {
58
+
59
+		if ($start > $this->end || $end < $this->start) {
60
+
61
+			// This new data is outside our timerange.
62
+			return;
63
+
64
+		}
65
+
66
+		if ($start < $this->start) {
67
+			// The item starts before our requested time range
68
+			$start = $this->start;
69
+		}
70
+		if ($end > $this->end) {
71
+			// The item ends after our requested time range
72
+			$end = $this->end;
73
+		}
74
+
75
+		// Finding out where we need to insert the new item.
76
+		$currentIndex = 0;
77
+		while ($start > $this->data[$currentIndex]['end']) {
78
+			$currentIndex++;
79
+		}
80
+
81
+		// The standard insertion point will be one _after_ the first
82
+		// overlapping item.
83
+		$insertStartIndex = $currentIndex + 1;
84
+
85
+		$newItem = [
86
+			'start' => $start,
87
+			'end'   => $end,
88
+			'type'  => $type,
89
+		];
90
+
91
+		$preceedingItem = $this->data[$insertStartIndex - 1];
92
+		if ($this->data[$insertStartIndex - 1]['start'] === $start) {
93
+			// The old item starts at the exact same point as the new item.
94
+			$insertStartIndex--;
95
+		}
96
+
97
+		// Now we know where to insert the item, we need to know where it
98
+		// starts overlapping with items on the tail end. We need to start
99
+		// looking one item before the insertStartIndex, because it's possible
100
+		// that the new item 'sits inside' the previous old item.
101
+		if ($insertStartIndex > 0) {
102
+			$currentIndex = $insertStartIndex - 1;
103
+		} else {
104
+			$currentIndex = 0;
105
+		}
106
+
107
+		while ($end > $this->data[$currentIndex]['end']) {
108
+
109
+			$currentIndex++;
110
+
111
+		}
112
+
113
+		// What we are about to insert into the array
114
+		$newItems = [
115
+			$newItem
116
+		];
117
+
118
+		// This is the amount of items that are completely overwritten by the
119
+		// new item.
120
+		$itemsToDelete = $currentIndex - $insertStartIndex;
121
+		if ($this->data[$currentIndex]['end'] <= $end) $itemsToDelete++;
122
+
123
+		// If itemsToDelete was -1, it means that the newly inserted item is
124
+		// actually sitting inside an existing one. This means we need to split
125
+		// the item at the current position in two and insert the new item in
126
+		// between.
127
+		if ($itemsToDelete === -1) {
128
+			$itemsToDelete = 0;
129
+			if ($newItem['end'] < $preceedingItem['end']) {
130
+				$newItems[] = [
131
+					'start' => $newItem['end'] + 1,
132
+					'end'   => $preceedingItem['end'],
133
+					'type'  => $preceedingItem['type']
134
+				];
135
+			}
136
+		}
137
+
138
+		array_splice(
139
+			$this->data,
140
+			$insertStartIndex,
141
+			$itemsToDelete,
142
+			$newItems
143
+		);
144
+
145
+		$doMerge = false;
146
+		$mergeOffset = $insertStartIndex;
147
+		$mergeItem = $newItem;
148
+		$mergeDelete = 1;
149
+
150
+		if (isset($this->data[$insertStartIndex - 1])) {
151
+			// Updating the start time of the previous item.
152
+			$this->data[$insertStartIndex - 1]['end'] = $start;
153
+
154
+			// If the previous and the current are of the same type, we can
155
+			// merge them into one item.
156
+			if ($this->data[$insertStartIndex - 1]['type'] === $this->data[$insertStartIndex]['type']) {
157
+				$doMerge = true;
158
+				$mergeOffset--;
159
+				$mergeDelete++;
160
+				$mergeItem['start'] = $this->data[$insertStartIndex - 1]['start'];
161
+			}
162
+		}
163
+		if (isset($this->data[$insertStartIndex + 1])) {
164
+			// Updating the start time of the next item.
165
+			$this->data[$insertStartIndex + 1]['start'] = $end;
166
+
167
+			// If the next and the current are of the same type, we can
168
+			// merge them into one item.
169
+			if ($this->data[$insertStartIndex + 1]['type'] === $this->data[$insertStartIndex]['type']) {
170
+				$doMerge = true;
171
+				$mergeDelete++;
172
+				$mergeItem['end'] = $this->data[$insertStartIndex + 1]['end'];
173
+			}
174
+
175
+		}
176
+		if ($doMerge) {
177
+			array_splice(
178
+				$this->data,
179
+				$mergeOffset,
180
+				$mergeDelete,
181
+				[$mergeItem]
182
+			);
183
+		}
184
+
185
+	}
186
+
187
+	public function getData() {
188
+
189
+		return $this->data;
190
+
191
+	}
192 192
 
193 193
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/Parameter.php 1 patch
Indentation   +371 added lines, -371 removed lines patch added patch discarded remove patch
@@ -19,376 +19,376 @@
 block discarded – undo
19 19
  */
20 20
 class Parameter extends Node {
21 21
 
22
-    /**
23
-     * Parameter name.
24
-     *
25
-     * @var string
26
-     */
27
-    public $name;
28
-
29
-    /**
30
-     * vCard 2.1 allows parameters to be encoded without a name.
31
-     *
32
-     * We can deduce the parameter name based on it's value.
33
-     *
34
-     * @var bool
35
-     */
36
-    public $noName = false;
37
-
38
-    /**
39
-     * Parameter value.
40
-     *
41
-     * @var string
42
-     */
43
-    protected $value;
44
-
45
-    /**
46
-     * Sets up the object.
47
-     *
48
-     * It's recommended to use the create:: factory method instead.
49
-     *
50
-     * @param string $name
51
-     * @param string $value
52
-     */
53
-    public function __construct(Document $root, $name, $value = null) {
54
-
55
-        $this->name = strtoupper($name);
56
-        $this->root = $root;
57
-        if (is_null($name)) {
58
-            $this->noName = true;
59
-            $this->name = static::guessParameterNameByValue($value);
60
-        }
61
-
62
-        // If guessParameterNameByValue() returns an empty string
63
-        // above, we're actually dealing with a parameter that has no value.
64
-        // In that case we have to move the value to the name.
65
-        if ($this->name === '') {
66
-            $this->noName = false;
67
-            $this->name = strtoupper($value);
68
-        } else {
69
-            $this->setValue($value);
70
-        }
71
-
72
-    }
73
-
74
-    /**
75
-     * Try to guess property name by value, can be used for vCard 2.1 nameless parameters.
76
-     *
77
-     * Figuring out what the name should have been. Note that a ton of
78
-     * these are rather silly in 2014 and would probably rarely be
79
-     * used, but we like to be complete.
80
-     *
81
-     * @param string $value
82
-     *
83
-     * @return string
84
-     */
85
-    static function guessParameterNameByValue($value) {
86
-        switch (strtoupper($value)) {
87
-
88
-            // Encodings
89
-            case '7-BIT' :
90
-            case 'QUOTED-PRINTABLE' :
91
-            case 'BASE64' :
92
-                $name = 'ENCODING';
93
-                break;
94
-
95
-            // Common types
96
-            case 'WORK' :
97
-            case 'HOME' :
98
-            case 'PREF' :
99
-
100
-            // Delivery Label Type
101
-            case 'DOM' :
102
-            case 'INTL' :
103
-            case 'POSTAL' :
104
-            case 'PARCEL' :
105
-
106
-            // Telephone types
107
-            case 'VOICE' :
108
-            case 'FAX' :
109
-            case 'MSG' :
110
-            case 'CELL' :
111
-            case 'PAGER' :
112
-            case 'BBS' :
113
-            case 'MODEM' :
114
-            case 'CAR' :
115
-            case 'ISDN' :
116
-            case 'VIDEO' :
117
-
118
-            // EMAIL types (lol)
119
-            case 'AOL' :
120
-            case 'APPLELINK' :
121
-            case 'ATTMAIL' :
122
-            case 'CIS' :
123
-            case 'EWORLD' :
124
-            case 'INTERNET' :
125
-            case 'IBMMAIL' :
126
-            case 'MCIMAIL' :
127
-            case 'POWERSHARE' :
128
-            case 'PRODIGY' :
129
-            case 'TLX' :
130
-            case 'X400' :
131
-
132
-            // Photo / Logo format types
133
-            case 'GIF' :
134
-            case 'CGM' :
135
-            case 'WMF' :
136
-            case 'BMP' :
137
-            case 'DIB' :
138
-            case 'PICT' :
139
-            case 'TIFF' :
140
-            case 'PDF' :
141
-            case 'PS' :
142
-            case 'JPEG' :
143
-            case 'MPEG' :
144
-            case 'MPEG2' :
145
-            case 'AVI' :
146
-            case 'QTIME' :
147
-
148
-            // Sound Digital Audio Type
149
-            case 'WAVE' :
150
-            case 'PCM' :
151
-            case 'AIFF' :
152
-
153
-            // Key types
154
-            case 'X509' :
155
-            case 'PGP' :
156
-                $name = 'TYPE';
157
-                break;
158
-
159
-            // Value types
160
-            case 'INLINE' :
161
-            case 'URL' :
162
-            case 'CONTENT-ID' :
163
-            case 'CID' :
164
-                $name = 'VALUE';
165
-                break;
166
-
167
-            default:
168
-                $name = '';
169
-        }
170
-
171
-        return $name;
172
-    }
173
-
174
-    /**
175
-     * Updates the current value.
176
-     *
177
-     * This may be either a single, or multiple strings in an array.
178
-     *
179
-     * @param string|array $value
180
-     *
181
-     * @return void
182
-     */
183
-    public function setValue($value) {
184
-
185
-        $this->value = $value;
186
-
187
-    }
188
-
189
-    /**
190
-     * Returns the current value.
191
-     *
192
-     * This method will always return a string, or null. If there were multiple
193
-     * values, it will automatically concatenate them (separated by comma).
194
-     *
195
-     * @return string|null
196
-     */
197
-    public function getValue() {
198
-
199
-        if (is_array($this->value)) {
200
-            return implode(',', $this->value);
201
-        } else {
202
-            return $this->value;
203
-        }
204
-
205
-    }
206
-
207
-    /**
208
-     * Sets multiple values for this parameter.
209
-     *
210
-     * @param array $value
211
-     *
212
-     * @return void
213
-     */
214
-    public function setParts(array $value) {
215
-
216
-        $this->value = $value;
217
-
218
-    }
219
-
220
-    /**
221
-     * Returns all values for this parameter.
222
-     *
223
-     * If there were no values, an empty array will be returned.
224
-     *
225
-     * @return array
226
-     */
227
-    public function getParts() {
228
-
229
-        if (is_array($this->value)) {
230
-            return $this->value;
231
-        } elseif (is_null($this->value)) {
232
-            return [];
233
-        } else {
234
-            return [$this->value];
235
-        }
236
-
237
-    }
238
-
239
-    /**
240
-     * Adds a value to this parameter.
241
-     *
242
-     * If the argument is specified as an array, all items will be added to the
243
-     * parameter value list.
244
-     *
245
-     * @param string|array $part
246
-     *
247
-     * @return void
248
-     */
249
-    public function addValue($part) {
250
-
251
-        if (is_null($this->value)) {
252
-            $this->value = $part;
253
-        } else {
254
-            $this->value = array_merge((array)$this->value, (array)$part);
255
-        }
256
-
257
-    }
258
-
259
-    /**
260
-     * Checks if this parameter contains the specified value.
261
-     *
262
-     * This is a case-insensitive match. It makes sense to call this for for
263
-     * instance the TYPE parameter, to see if it contains a keyword such as
264
-     * 'WORK' or 'FAX'.
265
-     *
266
-     * @param string $value
267
-     *
268
-     * @return bool
269
-     */
270
-    public function has($value) {
271
-
272
-        return in_array(
273
-            strtolower($value),
274
-            array_map('strtolower', (array)$this->value)
275
-        );
276
-
277
-    }
278
-
279
-    /**
280
-     * Turns the object back into a serialized blob.
281
-     *
282
-     * @return string
283
-     */
284
-    public function serialize() {
285
-
286
-        $value = $this->getParts();
287
-
288
-        if (count($value) === 0) {
289
-            return $this->name . '=';
290
-        }
291
-
292
-        if ($this->root->getDocumentType() === Document::VCARD21 && $this->noName) {
293
-
294
-            return implode(';', $value);
295
-
296
-        }
297
-
298
-        return $this->name . '=' . array_reduce(
299
-            $value,
300
-            public function($out, $item) {
301
-
302
-                if (!is_null($out)) $out .= ',';
303
-
304
-                // If there's no special characters in the string, we'll use the simple
305
-                // format.
306
-                //
307
-                // The list of special characters is defined as:
308
-                //
309
-                // Any character except CONTROL, DQUOTE, ";", ":", ","
310
-                //
311
-                // by the iCalendar spec:
312
-                // https://tools.ietf.org/html/rfc5545#section-3.1
313
-                //
314
-                // And we add ^ to that because of:
315
-                // https://tools.ietf.org/html/rfc6868
316
-                //
317
-                // But we've found that iCal (7.0, shipped with OSX 10.9)
318
-                // severaly trips on + characters not being quoted, so we
319
-                // added + as well.
320
-                if (!preg_match('#(?: [\n":;\^,\+] )#x', $item)) {
321
-                    return $out . $item;
322
-                } else {
323
-                    // Enclosing in double-quotes, and using RFC6868 for encoding any
324
-                    // special characters
325
-                    $out .= '"' . strtr(
326
-                        $item,
327
-                        [
328
-                            '^'  => '^^',
329
-                            "\n" => '^n',
330
-                            '"'  => '^\'',
331
-                        ]
332
-                    ) . '"';
333
-                    return $out;
334
-                }
335
-
336
-            }
337
-        );
338
-
339
-    }
340
-
341
-    /**
342
-     * This method returns an array, with the representation as it should be
343
-     * encoded in JSON. This is used to create jCard or jCal documents.
344
-     *
345
-     * @return array
346
-     */
347
-    public function jsonSerialize() {
348
-
349
-        return $this->value;
350
-
351
-    }
352
-
353
-    /**
354
-     * This method serializes the data into XML. This is used to create xCard or
355
-     * xCal documents.
356
-     *
357
-     * @param Xml\Writer $writer  XML writer.
358
-     *
359
-     * @return void
360
-     */
361
-    public function xmlSerialize(Xml\Writer $writer) {
362
-
363
-        foreach (explode(',', $this->value) as $value) {
364
-            $writer->writeElement('text', $value);
365
-        }
366
-
367
-    }
368
-
369
-    /**
370
-     * Called when this object is being cast to a string.
371
-     *
372
-     * @return string
373
-     */
374
-    public function __toString() {
375
-
376
-        return (string)$this->getValue();
377
-
378
-    }
379
-
380
-    /**
381
-     * Returns the iterator for this object.
382
-     *
383
-     * @return ElementList
384
-     */
385
-    public function getIterator() {
386
-
387
-        if (!is_null($this->iterator))
388
-            return $this->iterator;
389
-
390
-        return $this->iterator = new ArrayIterator((array)$this->value);
391
-
392
-    }
22
+	/**
23
+	 * Parameter name.
24
+	 *
25
+	 * @var string
26
+	 */
27
+	public $name;
28
+
29
+	/**
30
+	 * vCard 2.1 allows parameters to be encoded without a name.
31
+	 *
32
+	 * We can deduce the parameter name based on it's value.
33
+	 *
34
+	 * @var bool
35
+	 */
36
+	public $noName = false;
37
+
38
+	/**
39
+	 * Parameter value.
40
+	 *
41
+	 * @var string
42
+	 */
43
+	protected $value;
44
+
45
+	/**
46
+	 * Sets up the object.
47
+	 *
48
+	 * It's recommended to use the create:: factory method instead.
49
+	 *
50
+	 * @param string $name
51
+	 * @param string $value
52
+	 */
53
+	public function __construct(Document $root, $name, $value = null) {
54
+
55
+		$this->name = strtoupper($name);
56
+		$this->root = $root;
57
+		if (is_null($name)) {
58
+			$this->noName = true;
59
+			$this->name = static::guessParameterNameByValue($value);
60
+		}
61
+
62
+		// If guessParameterNameByValue() returns an empty string
63
+		// above, we're actually dealing with a parameter that has no value.
64
+		// In that case we have to move the value to the name.
65
+		if ($this->name === '') {
66
+			$this->noName = false;
67
+			$this->name = strtoupper($value);
68
+		} else {
69
+			$this->setValue($value);
70
+		}
71
+
72
+	}
73
+
74
+	/**
75
+	 * Try to guess property name by value, can be used for vCard 2.1 nameless parameters.
76
+	 *
77
+	 * Figuring out what the name should have been. Note that a ton of
78
+	 * these are rather silly in 2014 and would probably rarely be
79
+	 * used, but we like to be complete.
80
+	 *
81
+	 * @param string $value
82
+	 *
83
+	 * @return string
84
+	 */
85
+	static function guessParameterNameByValue($value) {
86
+		switch (strtoupper($value)) {
87
+
88
+			// Encodings
89
+			case '7-BIT' :
90
+			case 'QUOTED-PRINTABLE' :
91
+			case 'BASE64' :
92
+				$name = 'ENCODING';
93
+				break;
94
+
95
+			// Common types
96
+			case 'WORK' :
97
+			case 'HOME' :
98
+			case 'PREF' :
99
+
100
+			// Delivery Label Type
101
+			case 'DOM' :
102
+			case 'INTL' :
103
+			case 'POSTAL' :
104
+			case 'PARCEL' :
105
+
106
+			// Telephone types
107
+			case 'VOICE' :
108
+			case 'FAX' :
109
+			case 'MSG' :
110
+			case 'CELL' :
111
+			case 'PAGER' :
112
+			case 'BBS' :
113
+			case 'MODEM' :
114
+			case 'CAR' :
115
+			case 'ISDN' :
116
+			case 'VIDEO' :
117
+
118
+			// EMAIL types (lol)
119
+			case 'AOL' :
120
+			case 'APPLELINK' :
121
+			case 'ATTMAIL' :
122
+			case 'CIS' :
123
+			case 'EWORLD' :
124
+			case 'INTERNET' :
125
+			case 'IBMMAIL' :
126
+			case 'MCIMAIL' :
127
+			case 'POWERSHARE' :
128
+			case 'PRODIGY' :
129
+			case 'TLX' :
130
+			case 'X400' :
131
+
132
+			// Photo / Logo format types
133
+			case 'GIF' :
134
+			case 'CGM' :
135
+			case 'WMF' :
136
+			case 'BMP' :
137
+			case 'DIB' :
138
+			case 'PICT' :
139
+			case 'TIFF' :
140
+			case 'PDF' :
141
+			case 'PS' :
142
+			case 'JPEG' :
143
+			case 'MPEG' :
144
+			case 'MPEG2' :
145
+			case 'AVI' :
146
+			case 'QTIME' :
147
+
148
+			// Sound Digital Audio Type
149
+			case 'WAVE' :
150
+			case 'PCM' :
151
+			case 'AIFF' :
152
+
153
+			// Key types
154
+			case 'X509' :
155
+			case 'PGP' :
156
+				$name = 'TYPE';
157
+				break;
158
+
159
+			// Value types
160
+			case 'INLINE' :
161
+			case 'URL' :
162
+			case 'CONTENT-ID' :
163
+			case 'CID' :
164
+				$name = 'VALUE';
165
+				break;
166
+
167
+			default:
168
+				$name = '';
169
+		}
170
+
171
+		return $name;
172
+	}
173
+
174
+	/**
175
+	 * Updates the current value.
176
+	 *
177
+	 * This may be either a single, or multiple strings in an array.
178
+	 *
179
+	 * @param string|array $value
180
+	 *
181
+	 * @return void
182
+	 */
183
+	public function setValue($value) {
184
+
185
+		$this->value = $value;
186
+
187
+	}
188
+
189
+	/**
190
+	 * Returns the current value.
191
+	 *
192
+	 * This method will always return a string, or null. If there were multiple
193
+	 * values, it will automatically concatenate them (separated by comma).
194
+	 *
195
+	 * @return string|null
196
+	 */
197
+	public function getValue() {
198
+
199
+		if (is_array($this->value)) {
200
+			return implode(',', $this->value);
201
+		} else {
202
+			return $this->value;
203
+		}
204
+
205
+	}
206
+
207
+	/**
208
+	 * Sets multiple values for this parameter.
209
+	 *
210
+	 * @param array $value
211
+	 *
212
+	 * @return void
213
+	 */
214
+	public function setParts(array $value) {
215
+
216
+		$this->value = $value;
217
+
218
+	}
219
+
220
+	/**
221
+	 * Returns all values for this parameter.
222
+	 *
223
+	 * If there were no values, an empty array will be returned.
224
+	 *
225
+	 * @return array
226
+	 */
227
+	public function getParts() {
228
+
229
+		if (is_array($this->value)) {
230
+			return $this->value;
231
+		} elseif (is_null($this->value)) {
232
+			return [];
233
+		} else {
234
+			return [$this->value];
235
+		}
236
+
237
+	}
238
+
239
+	/**
240
+	 * Adds a value to this parameter.
241
+	 *
242
+	 * If the argument is specified as an array, all items will be added to the
243
+	 * parameter value list.
244
+	 *
245
+	 * @param string|array $part
246
+	 *
247
+	 * @return void
248
+	 */
249
+	public function addValue($part) {
250
+
251
+		if (is_null($this->value)) {
252
+			$this->value = $part;
253
+		} else {
254
+			$this->value = array_merge((array)$this->value, (array)$part);
255
+		}
256
+
257
+	}
258
+
259
+	/**
260
+	 * Checks if this parameter contains the specified value.
261
+	 *
262
+	 * This is a case-insensitive match. It makes sense to call this for for
263
+	 * instance the TYPE parameter, to see if it contains a keyword such as
264
+	 * 'WORK' or 'FAX'.
265
+	 *
266
+	 * @param string $value
267
+	 *
268
+	 * @return bool
269
+	 */
270
+	public function has($value) {
271
+
272
+		return in_array(
273
+			strtolower($value),
274
+			array_map('strtolower', (array)$this->value)
275
+		);
276
+
277
+	}
278
+
279
+	/**
280
+	 * Turns the object back into a serialized blob.
281
+	 *
282
+	 * @return string
283
+	 */
284
+	public function serialize() {
285
+
286
+		$value = $this->getParts();
287
+
288
+		if (count($value) === 0) {
289
+			return $this->name . '=';
290
+		}
291
+
292
+		if ($this->root->getDocumentType() === Document::VCARD21 && $this->noName) {
293
+
294
+			return implode(';', $value);
295
+
296
+		}
297
+
298
+		return $this->name . '=' . array_reduce(
299
+			$value,
300
+			public function($out, $item) {
301
+
302
+				if (!is_null($out)) $out .= ',';
303
+
304
+				// If there's no special characters in the string, we'll use the simple
305
+				// format.
306
+				//
307
+				// The list of special characters is defined as:
308
+				//
309
+				// Any character except CONTROL, DQUOTE, ";", ":", ","
310
+				//
311
+				// by the iCalendar spec:
312
+				// https://tools.ietf.org/html/rfc5545#section-3.1
313
+				//
314
+				// And we add ^ to that because of:
315
+				// https://tools.ietf.org/html/rfc6868
316
+				//
317
+				// But we've found that iCal (7.0, shipped with OSX 10.9)
318
+				// severaly trips on + characters not being quoted, so we
319
+				// added + as well.
320
+				if (!preg_match('#(?: [\n":;\^,\+] )#x', $item)) {
321
+					return $out . $item;
322
+				} else {
323
+					// Enclosing in double-quotes, and using RFC6868 for encoding any
324
+					// special characters
325
+					$out .= '"' . strtr(
326
+						$item,
327
+						[
328
+							'^'  => '^^',
329
+							"\n" => '^n',
330
+							'"'  => '^\'',
331
+						]
332
+					) . '"';
333
+					return $out;
334
+				}
335
+
336
+			}
337
+		);
338
+
339
+	}
340
+
341
+	/**
342
+	 * This method returns an array, with the representation as it should be
343
+	 * encoded in JSON. This is used to create jCard or jCal documents.
344
+	 *
345
+	 * @return array
346
+	 */
347
+	public function jsonSerialize() {
348
+
349
+		return $this->value;
350
+
351
+	}
352
+
353
+	/**
354
+	 * This method serializes the data into XML. This is used to create xCard or
355
+	 * xCal documents.
356
+	 *
357
+	 * @param Xml\Writer $writer  XML writer.
358
+	 *
359
+	 * @return void
360
+	 */
361
+	public function xmlSerialize(Xml\Writer $writer) {
362
+
363
+		foreach (explode(',', $this->value) as $value) {
364
+			$writer->writeElement('text', $value);
365
+		}
366
+
367
+	}
368
+
369
+	/**
370
+	 * Called when this object is being cast to a string.
371
+	 *
372
+	 * @return string
373
+	 */
374
+	public function __toString() {
375
+
376
+		return (string)$this->getValue();
377
+
378
+	}
379
+
380
+	/**
381
+	 * Returns the iterator for this object.
382
+	 *
383
+	 * @return ElementList
384
+	 */
385
+	public function getIterator() {
386
+
387
+		if (!is_null($this->iterator))
388
+			return $this->iterator;
389
+
390
+		return $this->iterator = new ArrayIterator((array)$this->value);
391
+
392
+	}
393 393
 
394 394
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/Cli.php 1 patch
Indentation   +748 added lines, -748 removed lines patch added patch discarded remove patch
@@ -3,7 +3,7 @@  discard block
 block discarded – undo
3 3
 namespace Sabre\VObject;
4 4
 
5 5
 use
6
-    InvalidArgumentException;
6
+	InvalidArgumentException;
7 7
 
8 8
 /**
9 9
  * This is the CLI interface for sabre-vobject.
@@ -14,758 +14,758 @@  discard block
 block discarded – undo
14 14
  */
15 15
 class Cli {
16 16
 
17
-    /**
18
-     * No output.
19
-     *
20
-     * @var bool
21
-     */
22
-    protected $quiet = false;
23
-
24
-    /**
25
-     * Help display.
26
-     *
27
-     * @var bool
28
-     */
29
-    protected $showHelp = false;
30
-
31
-    /**
32
-     * Wether to spit out 'mimedir' or 'json' format.
33
-     *
34
-     * @var string
35
-     */
36
-    protected $format;
37
-
38
-    /**
39
-     * JSON pretty print.
40
-     *
41
-     * @var bool
42
-     */
43
-    protected $pretty;
44
-
45
-    /**
46
-     * Source file.
47
-     *
48
-     * @var string
49
-     */
50
-    protected $inputPath;
51
-
52
-    /**
53
-     * Destination file.
54
-     *
55
-     * @var string
56
-     */
57
-    protected $outputPath;
58
-
59
-    /**
60
-     * output stream.
61
-     *
62
-     * @var resource
63
-     */
64
-    protected $stdout;
65
-
66
-    /**
67
-     * stdin.
68
-     *
69
-     * @var resource
70
-     */
71
-    protected $stdin;
72
-
73
-    /**
74
-     * stderr.
75
-     *
76
-     * @var resource
77
-     */
78
-    protected $stderr;
79
-
80
-    /**
81
-     * Input format (one of json or mimedir).
82
-     *
83
-     * @var string
84
-     */
85
-    protected $inputFormat;
86
-
87
-    /**
88
-     * Makes the parser less strict.
89
-     *
90
-     * @var bool
91
-     */
92
-    protected $forgiving = false;
93
-
94
-    /**
95
-     * Main function.
96
-     *
97
-     * @return int
98
-     */
99
-    public function main(array $argv) {
100
-
101
-        // @codeCoverageIgnoreStart
102
-        // We cannot easily test this, so we'll skip it. Pretty basic anyway.
103
-
104
-        if (!$this->stderr) {
105
-            $this->stderr = fopen('php://stderr', 'w');
106
-        }
107
-        if (!$this->stdout) {
108
-            $this->stdout = fopen('php://stdout', 'w');
109
-        }
110
-        if (!$this->stdin) {
111
-            $this->stdin = fopen('php://stdin', 'r');
112
-        }
113
-
114
-        // @codeCoverageIgnoreEnd
115
-
116
-
117
-        try {
118
-
119
-            list($options, $positional) = $this->parseArguments($argv);
120
-
121
-            if (isset($options['q'])) {
122
-                $this->quiet = true;
123
-            }
124
-            $this->log($this->colorize('green', "sabre/vobject ") . $this->colorize('yellow', Version::VERSION));
125
-
126
-            foreach ($options as $name => $value) {
127
-
128
-                switch ($name) {
129
-
130
-                    case 'q' :
131
-                        // Already handled earlier.
132
-                        break;
133
-                    case 'h' :
134
-                    case 'help' :
135
-                        $this->showHelp();
136
-                        return 0;
137
-                        break;
138
-                    case 'format' :
139
-                        switch ($value) {
140
-
141
-                            // jcard/jcal documents
142
-                            case 'jcard' :
143
-                            case 'jcal' :
144
-
145
-                            // specific document versions
146
-                            case 'vcard21' :
147
-                            case 'vcard30' :
148
-                            case 'vcard40' :
149
-                            case 'icalendar20' :
150
-
151
-                            // specific formats
152
-                            case 'json' :
153
-                            case 'mimedir' :
154
-
155
-                            // icalendar/vcad
156
-                            case 'icalendar' :
157
-                            case 'vcard' :
158
-                                $this->format = $value;
159
-                                break;
160
-
161
-                            default :
162
-                                throw new InvalidArgumentException('Unknown format: ' . $value);
163
-
164
-                        }
165
-                        break;
166
-                    case 'pretty' :
167
-                        if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
168
-                            $this->pretty = true;
169
-                        }
170
-                        break;
171
-                    case 'forgiving' :
172
-                        $this->forgiving = true;
173
-                        break;
174
-                    case 'inputformat' :
175
-                        switch ($value) {
176
-                            // json formats
177
-                            case 'jcard' :
178
-                            case 'jcal' :
179
-                            case 'json' :
180
-                                $this->inputFormat = 'json';
181
-                                break;
182
-
183
-                            // mimedir formats
184
-                            case 'mimedir' :
185
-                            case 'icalendar' :
186
-                            case 'vcard' :
187
-                            case 'vcard21' :
188
-                            case 'vcard30' :
189
-                            case 'vcard40' :
190
-                            case 'icalendar20' :
191
-
192
-                                $this->inputFormat = 'mimedir';
193
-                                break;
194
-
195
-                            default :
196
-                                throw new InvalidArgumentException('Unknown format: ' . $value);
197
-
198
-                        }
199
-                        break;
200
-                    default :
201
-                        throw new InvalidArgumentException('Unknown option: ' . $name);
202
-
203
-                }
204
-
205
-            }
206
-
207
-            if (count($positional) === 0) {
208
-                $this->showHelp();
209
-                return 1;
210
-            }
211
-
212
-            if (count($positional) === 1) {
213
-                throw new InvalidArgumentException('Inputfile is a required argument');
214
-            }
215
-
216
-            if (count($positional) > 3) {
217
-                throw new InvalidArgumentException('Too many arguments');
218
-            }
219
-
220
-            if (!in_array($positional[0], ['validate', 'repair', 'convert', 'color'])) {
221
-                throw new InvalidArgumentException('Uknown command: ' . $positional[0]);
222
-            }
223
-
224
-        } catch (InvalidArgumentException $e) {
225
-            $this->showHelp();
226
-            $this->log('Error: ' . $e->getMessage(), 'red');
227
-            return 1;
228
-        }
229
-
230
-        $command = $positional[0];
231
-
232
-        $this->inputPath = $positional[1];
233
-        $this->outputPath = isset($positional[2]) ? $positional[2] : '-';
234
-
235
-        if ($this->outputPath !== '-') {
236
-            $this->stdout = fopen($this->outputPath, 'w');
237
-        }
238
-
239
-        if (!$this->inputFormat) {
240
-            if (substr($this->inputPath, -5) === '.json') {
241
-                $this->inputFormat = 'json';
242
-            } else {
243
-                $this->inputFormat = 'mimedir';
244
-            }
245
-        }
246
-        if (!$this->format) {
247
-            if (substr($this->outputPath, -5) === '.json') {
248
-                $this->format = 'json';
249
-            } else {
250
-                $this->format = 'mimedir';
251
-            }
252
-        }
253
-
254
-
255
-        $realCode = 0;
256
-
257
-        try {
258
-
259
-            while ($input = $this->readInput()) {
260
-
261
-                $returnCode = $this->$command($input);
262
-                if ($returnCode !== 0) $realCode = $returnCode;
263
-
264
-            }
265
-
266
-        } catch (EofException $e) {
267
-            // end of file
268
-        } catch (\Exception $e) {
269
-            $this->log('Error: ' . $e->getMessage(), 'red');
270
-            return 2;
271
-        }
272
-
273
-        return $realCode;
274
-
275
-    }
276
-
277
-    /**
278
-     * Shows the help message.
279
-     *
280
-     * @return void
281
-     */
282
-    protected function showHelp() {
283
-
284
-        $this->log('Usage:', 'yellow');
285
-        $this->log("  vobject [options] command [arguments]");
286
-        $this->log('');
287
-        $this->log('Options:', 'yellow');
288
-        $this->log($this->colorize('green', '  -q            ') . "Don't output anything.");
289
-        $this->log($this->colorize('green', '  -help -h      ') . "Display this help message.");
290
-        $this->log($this->colorize('green', '  --format      ') . "Convert to a specific format. Must be one of: vcard, vcard21,");
291
-        $this->log($this->colorize('green', '  --forgiving   ') . "Makes the parser less strict.");
292
-        $this->log("                vcard30, vcard40, icalendar20, jcal, jcard, json, mimedir.");
293
-        $this->log($this->colorize('green', '  --inputformat ') . "If the input format cannot be guessed from the extension, it");
294
-        $this->log("                must be specified here.");
295
-        // Only PHP 5.4 and up
296
-        if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
297
-            $this->log($this->colorize('green', '  --pretty      ') . "json pretty-print.");
298
-        }
299
-        $this->log('');
300
-        $this->log('Commands:', 'yellow');
301
-        $this->log($this->colorize('green', '  validate') . ' source_file              Validates a file for correctness.');
302
-        $this->log($this->colorize('green', '  repair') . ' source_file [output_file]  Repairs a file.');
303
-        $this->log($this->colorize('green', '  convert') . ' source_file [output_file] Converts a file.');
304
-        $this->log($this->colorize('green', '  color') . ' source_file                 Colorize a file, useful for debbugging.');
305
-        $this->log(
306
-        <<<HELP
17
+	/**
18
+	 * No output.
19
+	 *
20
+	 * @var bool
21
+	 */
22
+	protected $quiet = false;
23
+
24
+	/**
25
+	 * Help display.
26
+	 *
27
+	 * @var bool
28
+	 */
29
+	protected $showHelp = false;
30
+
31
+	/**
32
+	 * Wether to spit out 'mimedir' or 'json' format.
33
+	 *
34
+	 * @var string
35
+	 */
36
+	protected $format;
37
+
38
+	/**
39
+	 * JSON pretty print.
40
+	 *
41
+	 * @var bool
42
+	 */
43
+	protected $pretty;
44
+
45
+	/**
46
+	 * Source file.
47
+	 *
48
+	 * @var string
49
+	 */
50
+	protected $inputPath;
51
+
52
+	/**
53
+	 * Destination file.
54
+	 *
55
+	 * @var string
56
+	 */
57
+	protected $outputPath;
58
+
59
+	/**
60
+	 * output stream.
61
+	 *
62
+	 * @var resource
63
+	 */
64
+	protected $stdout;
65
+
66
+	/**
67
+	 * stdin.
68
+	 *
69
+	 * @var resource
70
+	 */
71
+	protected $stdin;
72
+
73
+	/**
74
+	 * stderr.
75
+	 *
76
+	 * @var resource
77
+	 */
78
+	protected $stderr;
79
+
80
+	/**
81
+	 * Input format (one of json or mimedir).
82
+	 *
83
+	 * @var string
84
+	 */
85
+	protected $inputFormat;
86
+
87
+	/**
88
+	 * Makes the parser less strict.
89
+	 *
90
+	 * @var bool
91
+	 */
92
+	protected $forgiving = false;
93
+
94
+	/**
95
+	 * Main function.
96
+	 *
97
+	 * @return int
98
+	 */
99
+	public function main(array $argv) {
100
+
101
+		// @codeCoverageIgnoreStart
102
+		// We cannot easily test this, so we'll skip it. Pretty basic anyway.
103
+
104
+		if (!$this->stderr) {
105
+			$this->stderr = fopen('php://stderr', 'w');
106
+		}
107
+		if (!$this->stdout) {
108
+			$this->stdout = fopen('php://stdout', 'w');
109
+		}
110
+		if (!$this->stdin) {
111
+			$this->stdin = fopen('php://stdin', 'r');
112
+		}
113
+
114
+		// @codeCoverageIgnoreEnd
115
+
116
+
117
+		try {
118
+
119
+			list($options, $positional) = $this->parseArguments($argv);
120
+
121
+			if (isset($options['q'])) {
122
+				$this->quiet = true;
123
+			}
124
+			$this->log($this->colorize('green', "sabre/vobject ") . $this->colorize('yellow', Version::VERSION));
125
+
126
+			foreach ($options as $name => $value) {
127
+
128
+				switch ($name) {
129
+
130
+					case 'q' :
131
+						// Already handled earlier.
132
+						break;
133
+					case 'h' :
134
+					case 'help' :
135
+						$this->showHelp();
136
+						return 0;
137
+						break;
138
+					case 'format' :
139
+						switch ($value) {
140
+
141
+							// jcard/jcal documents
142
+							case 'jcard' :
143
+							case 'jcal' :
144
+
145
+							// specific document versions
146
+							case 'vcard21' :
147
+							case 'vcard30' :
148
+							case 'vcard40' :
149
+							case 'icalendar20' :
150
+
151
+							// specific formats
152
+							case 'json' :
153
+							case 'mimedir' :
154
+
155
+							// icalendar/vcad
156
+							case 'icalendar' :
157
+							case 'vcard' :
158
+								$this->format = $value;
159
+								break;
160
+
161
+							default :
162
+								throw new InvalidArgumentException('Unknown format: ' . $value);
163
+
164
+						}
165
+						break;
166
+					case 'pretty' :
167
+						if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
168
+							$this->pretty = true;
169
+						}
170
+						break;
171
+					case 'forgiving' :
172
+						$this->forgiving = true;
173
+						break;
174
+					case 'inputformat' :
175
+						switch ($value) {
176
+							// json formats
177
+							case 'jcard' :
178
+							case 'jcal' :
179
+							case 'json' :
180
+								$this->inputFormat = 'json';
181
+								break;
182
+
183
+							// mimedir formats
184
+							case 'mimedir' :
185
+							case 'icalendar' :
186
+							case 'vcard' :
187
+							case 'vcard21' :
188
+							case 'vcard30' :
189
+							case 'vcard40' :
190
+							case 'icalendar20' :
191
+
192
+								$this->inputFormat = 'mimedir';
193
+								break;
194
+
195
+							default :
196
+								throw new InvalidArgumentException('Unknown format: ' . $value);
197
+
198
+						}
199
+						break;
200
+					default :
201
+						throw new InvalidArgumentException('Unknown option: ' . $name);
202
+
203
+				}
204
+
205
+			}
206
+
207
+			if (count($positional) === 0) {
208
+				$this->showHelp();
209
+				return 1;
210
+			}
211
+
212
+			if (count($positional) === 1) {
213
+				throw new InvalidArgumentException('Inputfile is a required argument');
214
+			}
215
+
216
+			if (count($positional) > 3) {
217
+				throw new InvalidArgumentException('Too many arguments');
218
+			}
219
+
220
+			if (!in_array($positional[0], ['validate', 'repair', 'convert', 'color'])) {
221
+				throw new InvalidArgumentException('Uknown command: ' . $positional[0]);
222
+			}
223
+
224
+		} catch (InvalidArgumentException $e) {
225
+			$this->showHelp();
226
+			$this->log('Error: ' . $e->getMessage(), 'red');
227
+			return 1;
228
+		}
229
+
230
+		$command = $positional[0];
231
+
232
+		$this->inputPath = $positional[1];
233
+		$this->outputPath = isset($positional[2]) ? $positional[2] : '-';
234
+
235
+		if ($this->outputPath !== '-') {
236
+			$this->stdout = fopen($this->outputPath, 'w');
237
+		}
238
+
239
+		if (!$this->inputFormat) {
240
+			if (substr($this->inputPath, -5) === '.json') {
241
+				$this->inputFormat = 'json';
242
+			} else {
243
+				$this->inputFormat = 'mimedir';
244
+			}
245
+		}
246
+		if (!$this->format) {
247
+			if (substr($this->outputPath, -5) === '.json') {
248
+				$this->format = 'json';
249
+			} else {
250
+				$this->format = 'mimedir';
251
+			}
252
+		}
253
+
254
+
255
+		$realCode = 0;
256
+
257
+		try {
258
+
259
+			while ($input = $this->readInput()) {
260
+
261
+				$returnCode = $this->$command($input);
262
+				if ($returnCode !== 0) $realCode = $returnCode;
263
+
264
+			}
265
+
266
+		} catch (EofException $e) {
267
+			// end of file
268
+		} catch (\Exception $e) {
269
+			$this->log('Error: ' . $e->getMessage(), 'red');
270
+			return 2;
271
+		}
272
+
273
+		return $realCode;
274
+
275
+	}
276
+
277
+	/**
278
+	 * Shows the help message.
279
+	 *
280
+	 * @return void
281
+	 */
282
+	protected function showHelp() {
283
+
284
+		$this->log('Usage:', 'yellow');
285
+		$this->log("  vobject [options] command [arguments]");
286
+		$this->log('');
287
+		$this->log('Options:', 'yellow');
288
+		$this->log($this->colorize('green', '  -q            ') . "Don't output anything.");
289
+		$this->log($this->colorize('green', '  -help -h      ') . "Display this help message.");
290
+		$this->log($this->colorize('green', '  --format      ') . "Convert to a specific format. Must be one of: vcard, vcard21,");
291
+		$this->log($this->colorize('green', '  --forgiving   ') . "Makes the parser less strict.");
292
+		$this->log("                vcard30, vcard40, icalendar20, jcal, jcard, json, mimedir.");
293
+		$this->log($this->colorize('green', '  --inputformat ') . "If the input format cannot be guessed from the extension, it");
294
+		$this->log("                must be specified here.");
295
+		// Only PHP 5.4 and up
296
+		if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
297
+			$this->log($this->colorize('green', '  --pretty      ') . "json pretty-print.");
298
+		}
299
+		$this->log('');
300
+		$this->log('Commands:', 'yellow');
301
+		$this->log($this->colorize('green', '  validate') . ' source_file              Validates a file for correctness.');
302
+		$this->log($this->colorize('green', '  repair') . ' source_file [output_file]  Repairs a file.');
303
+		$this->log($this->colorize('green', '  convert') . ' source_file [output_file] Converts a file.');
304
+		$this->log($this->colorize('green', '  color') . ' source_file                 Colorize a file, useful for debbugging.');
305
+		$this->log(
306
+		<<<HELP
307 307
 
308 308
 If source_file is set as '-', STDIN will be used.
309 309
 If output_file is omitted, STDOUT will be used.
310 310
 All other output is sent to STDERR.
311 311
 
312 312
 HELP
313
-        );
314
-
315
-        $this->log('Examples:', 'yellow');
316
-        $this->log('   vobject convert contact.vcf contact.json');
317
-        $this->log('   vobject convert --format=vcard40 old.vcf new.vcf');
318
-        $this->log('   vobject convert --inputformat=json --format=mimedir - -');
319
-        $this->log('   vobject color calendar.ics');
320
-        $this->log('');
321
-        $this->log('https://github.com/fruux/sabre-vobject', 'purple');
322
-
323
-    }
324
-
325
-    /**
326
-     * Validates a VObject file.
327
-     *
328
-     * @param Component $vObj
329
-     *
330
-     * @return int
331
-     */
332
-    protected function validate(Component $vObj) {
333
-
334
-        $returnCode = 0;
335
-
336
-        switch ($vObj->name) {
337
-            case 'VCALENDAR' :
338
-                $this->log("iCalendar: " . (string)$vObj->VERSION);
339
-                break;
340
-            case 'VCARD' :
341
-                $this->log("vCard: " . (string)$vObj->VERSION);
342
-                break;
343
-        }
344
-
345
-        $warnings = $vObj->validate();
346
-        if (!count($warnings)) {
347
-            $this->log("  No warnings!");
348
-        } else {
349
-
350
-            $levels = [
351
-                1 => 'REPAIRED',
352
-                2 => 'WARNING',
353
-                3 => 'ERROR',
354
-            ];
355
-            $returnCode = 2;
356
-            foreach ($warnings as $warn) {
357
-
358
-                $extra = '';
359
-                if ($warn['node'] instanceof Property) {
360
-                    $extra = ' (property: "' . $warn['node']->name . '")';
361
-                }
362
-                $this->log("  [" . $levels[$warn['level']] . '] ' . $warn['message'] . $extra);
363
-
364
-            }
365
-
366
-        }
367
-
368
-        return $returnCode;
369
-
370
-    }
371
-
372
-    /**
373
-     * Repairs a VObject file.
374
-     *
375
-     * @param Component $vObj
376
-     *
377
-     * @return int
378
-     */
379
-    protected function repair(Component $vObj) {
380
-
381
-        $returnCode = 0;
382
-
383
-        switch ($vObj->name) {
384
-            case 'VCALENDAR' :
385
-                $this->log("iCalendar: " . (string)$vObj->VERSION);
386
-                break;
387
-            case 'VCARD' :
388
-                $this->log("vCard: " . (string)$vObj->VERSION);
389
-                break;
390
-        }
391
-
392
-        $warnings = $vObj->validate(Node::REPAIR);
393
-        if (!count($warnings)) {
394
-            $this->log("  No warnings!");
395
-        } else {
396
-
397
-            $levels = [
398
-                1 => 'REPAIRED',
399
-                2 => 'WARNING',
400
-                3 => 'ERROR',
401
-            ];
402
-            $returnCode = 2;
403
-            foreach ($warnings as $warn) {
404
-
405
-                $extra = '';
406
-                if ($warn['node'] instanceof Property) {
407
-                    $extra = ' (property: "' . $warn['node']->name . '")';
408
-                }
409
-                $this->log("  [" . $levels[$warn['level']] . '] ' . $warn['message'] . $extra);
410
-
411
-            }
412
-
413
-        }
414
-        fwrite($this->stdout, $vObj->serialize());
415
-
416
-        return $returnCode;
417
-
418
-    }
419
-
420
-    /**
421
-     * Converts a vObject file to a new format.
422
-     *
423
-     * @param Component $vObj
424
-     *
425
-     * @return int
426
-     */
427
-    protected function convert($vObj) {
428
-
429
-        $json = false;
430
-        $convertVersion = null;
431
-        $forceInput = null;
432
-
433
-        switch ($this->format) {
434
-            case 'json' :
435
-                $json = true;
436
-                if ($vObj->name === 'VCARD') {
437
-                    $convertVersion = Document::VCARD40;
438
-                }
439
-                break;
440
-            case 'jcard' :
441
-                $json = true;
442
-                $forceInput = 'VCARD';
443
-                $convertVersion = Document::VCARD40;
444
-                break;
445
-            case 'jcal' :
446
-                $json = true;
447
-                $forceInput = 'VCALENDAR';
448
-                break;
449
-            case 'mimedir' :
450
-            case 'icalendar' :
451
-            case 'icalendar20' :
452
-            case 'vcard' :
453
-                break;
454
-            case 'vcard21' :
455
-                $convertVersion = Document::VCARD21;
456
-                break;
457
-            case 'vcard30' :
458
-                $convertVersion = Document::VCARD30;
459
-                break;
460
-            case 'vcard40' :
461
-                $convertVersion = Document::VCARD40;
462
-                break;
463
-
464
-        }
465
-
466
-        if ($forceInput && $vObj->name !== $forceInput) {
467
-            throw new \Exception('You cannot convert a ' . strtolower($vObj->name) . ' to ' . $this->format);
468
-        }
469
-        if ($convertVersion) {
470
-            $vObj = $vObj->convert($convertVersion);
471
-        }
472
-        if ($json) {
473
-            $jsonOptions = 0;
474
-            if ($this->pretty) {
475
-                $jsonOptions = JSON_PRETTY_PRINT;
476
-            }
477
-            fwrite($this->stdout, json_encode($vObj->jsonSerialize(), $jsonOptions));
478
-        } else {
479
-            fwrite($this->stdout, $vObj->serialize());
480
-        }
481
-
482
-        return 0;
483
-
484
-    }
485
-
486
-    /**
487
-     * Colorizes a file.
488
-     *
489
-     * @param Component $vObj
490
-     *
491
-     * @return int
492
-     */
493
-    protected function color($vObj) {
494
-
495
-        fwrite($this->stdout, $this->serializeComponent($vObj));
496
-
497
-    }
498
-
499
-    /**
500
-     * Returns an ansi color string for a color name.
501
-     *
502
-     * @param string $color
503
-     *
504
-     * @return string
505
-     */
506
-    protected function colorize($color, $str, $resetTo = 'default') {
507
-
508
-        $colors = [
509
-            'cyan'    => '1;36',
510
-            'red'     => '1;31',
511
-            'yellow'  => '1;33',
512
-            'blue'    => '0;34',
513
-            'green'   => '0;32',
514
-            'default' => '0',
515
-            'purple'  => '0;35',
516
-        ];
517
-        return "\033[" . $colors[$color] . 'm' . $str . "\033[" . $colors[$resetTo] . "m";
518
-
519
-    }
520
-
521
-    /**
522
-     * Writes out a string in specific color.
523
-     *
524
-     * @param string $color
525
-     * @param string $str
526
-     *
527
-     * @return void
528
-     */
529
-    protected function cWrite($color, $str) {
530
-
531
-        fwrite($this->stdout, $this->colorize($color, $str));
532
-
533
-    }
534
-
535
-    protected function serializeComponent(Component $vObj) {
536
-
537
-        $this->cWrite('cyan', 'BEGIN');
538
-        $this->cWrite('red', ':');
539
-        $this->cWrite('yellow', $vObj->name . "\n");
540
-
541
-        /**
542
-         * Gives a component a 'score' for sorting purposes.
543
-         *
544
-         * This is solely used by the childrenSort method.
545
-         *
546
-         * A higher score means the item will be lower in the list.
547
-         * To avoid score collisions, each "score category" has a reasonable
548
-         * space to accomodate elements. The $key is added to the $score to
549
-         * preserve the original relative order of elements.
550
-         *
551
-         * @param int $key
552
-         * @param array $array
553
-         *
554
-         * @return int
555
-         */
556
-        $sortScore = function($key, $array) {
557
-
558
-            if ($array[$key] instanceof Component) {
559
-
560
-                // We want to encode VTIMEZONE first, this is a personal
561
-                // preference.
562
-                if ($array[$key]->name === 'VTIMEZONE') {
563
-                    $score = 300000000;
564
-                    return $score + $key;
565
-                } else {
566
-                    $score = 400000000;
567
-                    return $score + $key;
568
-                }
569
-            } else {
570
-                // Properties get encoded first
571
-                // VCARD version 4.0 wants the VERSION property to appear first
572
-                if ($array[$key] instanceof Property) {
573
-                    if ($array[$key]->name === 'VERSION') {
574
-                        $score = 100000000;
575
-                        return $score + $key;
576
-                    } else {
577
-                        // All other properties
578
-                        $score = 200000000;
579
-                        return $score + $key;
580
-                    }
581
-                }
582
-            }
583
-
584
-        };
585
-
586
-        $children = $vObj->children();
587
-        $tmp = $children;
588
-        uksort(
589
-            $children,
590
-            public function($a, $b) use ($sortScore, $tmp) {
591
-
592
-                $sA = $sortScore($a, $tmp);
593
-                $sB = $sortScore($b, $tmp);
594
-
595
-                return $sA - $sB;
596
-
597
-            }
598
-        );
599
-
600
-        foreach ($children as $child) {
601
-            if ($child instanceof Component) {
602
-                $this->serializeComponent($child);
603
-            } else {
604
-                $this->serializeProperty($child);
605
-            }
606
-        }
607
-
608
-        $this->cWrite('cyan', 'END');
609
-        $this->cWrite('red', ':');
610
-        $this->cWrite('yellow', $vObj->name . "\n");
611
-
612
-    }
613
-
614
-    /**
615
-     * Colorizes a property.
616
-     *
617
-     * @param Property $property
618
-     *
619
-     * @return void
620
-     */
621
-    protected function serializeProperty(Property $property) {
622
-
623
-        if ($property->group) {
624
-            $this->cWrite('default', $property->group);
625
-            $this->cWrite('red', '.');
626
-        }
627
-
628
-        $this->cWrite('yellow', $property->name);
629
-
630
-        foreach ($property->parameters as $param) {
631
-
632
-            $this->cWrite('red', ';');
633
-            $this->cWrite('blue', $param->serialize());
634
-
635
-        }
636
-        $this->cWrite('red', ':');
637
-
638
-        if ($property instanceof Property\Binary) {
639
-
640
-            $this->cWrite('default', 'embedded binary stripped. (' . strlen($property->getValue()) . ' bytes)');
641
-
642
-        } else {
643
-
644
-            $parts = $property->getParts();
645
-            $first1 = true;
646
-            // Looping through property values
647
-            foreach ($parts as $part) {
648
-                if ($first1) {
649
-                    $first1 = false;
650
-                } else {
651
-                    $this->cWrite('red', $property->delimiter);
652
-                }
653
-                $first2 = true;
654
-                // Looping through property sub-values
655
-                foreach ((array)$part as $subPart) {
656
-                    if ($first2) {
657
-                        $first2 = false;
658
-                    } else {
659
-                        // The sub-value delimiter is always comma
660
-                        $this->cWrite('red', ',');
661
-                    }
662
-
663
-                    $subPart = strtr(
664
-                        $subPart,
665
-                        [
666
-                            '\\' => $this->colorize('purple', '\\\\', 'green'),
667
-                            ';'  => $this->colorize('purple', '\;', 'green'),
668
-                            ','  => $this->colorize('purple', '\,', 'green'),
669
-                            "\n" => $this->colorize('purple', "\\n\n\t", 'green'),
670
-                            "\r" => "",
671
-                        ]
672
-                    );
673
-
674
-                    $this->cWrite('green', $subPart);
675
-                }
676
-            }
677
-
678
-        }
679
-        $this->cWrite("default", "\n");
680
-
681
-    }
682
-
683
-    /**
684
-     * Parses the list of arguments.
685
-     *
686
-     * @param array $argv
687
-     *
688
-     * @return void
689
-     */
690
-    protected function parseArguments(array $argv) {
691
-
692
-        $positional = [];
693
-        $options = [];
694
-
695
-        for ($ii = 0; $ii < count($argv); $ii++) {
696
-
697
-            // Skipping the first argument.
698
-            if ($ii === 0) continue;
699
-
700
-            $v = $argv[$ii];
701
-
702
-            if (substr($v, 0, 2) === '--') {
703
-                // This is a long-form option.
704
-                $optionName = substr($v, 2);
705
-                $optionValue = true;
706
-                if (strpos($optionName, '=')) {
707
-                    list($optionName, $optionValue) = explode('=', $optionName);
708
-                }
709
-                $options[$optionName] = $optionValue;
710
-            } elseif (substr($v, 0, 1) === '-' && strlen($v) > 1) {
711
-                // This is a short-form option.
712
-                foreach (str_split(substr($v, 1)) as $option) {
713
-                    $options[$option] = true;
714
-                }
715
-
716
-            } else {
717
-
718
-                $positional[] = $v;
719
-
720
-            }
721
-
722
-        }
723
-
724
-        return [$options, $positional];
725
-
726
-    }
727
-
728
-    protected $parser;
729
-
730
-    /**
731
-     * Reads the input file.
732
-     *
733
-     * @return Component
734
-     */
735
-    protected function readInput() {
736
-
737
-        if (!$this->parser) {
738
-            if ($this->inputPath !== '-') {
739
-                $this->stdin = fopen($this->inputPath, 'r');
740
-            }
741
-
742
-            if ($this->inputFormat === 'mimedir') {
743
-                $this->parser = new Parser\MimeDir($this->stdin, ($this->forgiving ? Reader::OPTION_FORGIVING : 0));
744
-            } else {
745
-                $this->parser = new Parser\Json($this->stdin, ($this->forgiving ? Reader::OPTION_FORGIVING : 0));
746
-            }
747
-        }
748
-
749
-        return $this->parser->parse();
750
-
751
-    }
752
-
753
-    /**
754
-     * Sends a message to STDERR.
755
-     *
756
-     * @param string $msg
757
-     *
758
-     * @return void
759
-     */
760
-    protected function log($msg, $color = 'default') {
761
-
762
-        if (!$this->quiet) {
763
-            if ($color !== 'default') {
764
-                $msg = $this->colorize($color, $msg);
765
-            }
766
-            fwrite($this->stderr, $msg . "\n");
767
-        }
768
-
769
-    }
313
+		);
314
+
315
+		$this->log('Examples:', 'yellow');
316
+		$this->log('   vobject convert contact.vcf contact.json');
317
+		$this->log('   vobject convert --format=vcard40 old.vcf new.vcf');
318
+		$this->log('   vobject convert --inputformat=json --format=mimedir - -');
319
+		$this->log('   vobject color calendar.ics');
320
+		$this->log('');
321
+		$this->log('https://github.com/fruux/sabre-vobject', 'purple');
322
+
323
+	}
324
+
325
+	/**
326
+	 * Validates a VObject file.
327
+	 *
328
+	 * @param Component $vObj
329
+	 *
330
+	 * @return int
331
+	 */
332
+	protected function validate(Component $vObj) {
333
+
334
+		$returnCode = 0;
335
+
336
+		switch ($vObj->name) {
337
+			case 'VCALENDAR' :
338
+				$this->log("iCalendar: " . (string)$vObj->VERSION);
339
+				break;
340
+			case 'VCARD' :
341
+				$this->log("vCard: " . (string)$vObj->VERSION);
342
+				break;
343
+		}
344
+
345
+		$warnings = $vObj->validate();
346
+		if (!count($warnings)) {
347
+			$this->log("  No warnings!");
348
+		} else {
349
+
350
+			$levels = [
351
+				1 => 'REPAIRED',
352
+				2 => 'WARNING',
353
+				3 => 'ERROR',
354
+			];
355
+			$returnCode = 2;
356
+			foreach ($warnings as $warn) {
357
+
358
+				$extra = '';
359
+				if ($warn['node'] instanceof Property) {
360
+					$extra = ' (property: "' . $warn['node']->name . '")';
361
+				}
362
+				$this->log("  [" . $levels[$warn['level']] . '] ' . $warn['message'] . $extra);
363
+
364
+			}
365
+
366
+		}
367
+
368
+		return $returnCode;
369
+
370
+	}
371
+
372
+	/**
373
+	 * Repairs a VObject file.
374
+	 *
375
+	 * @param Component $vObj
376
+	 *
377
+	 * @return int
378
+	 */
379
+	protected function repair(Component $vObj) {
380
+
381
+		$returnCode = 0;
382
+
383
+		switch ($vObj->name) {
384
+			case 'VCALENDAR' :
385
+				$this->log("iCalendar: " . (string)$vObj->VERSION);
386
+				break;
387
+			case 'VCARD' :
388
+				$this->log("vCard: " . (string)$vObj->VERSION);
389
+				break;
390
+		}
391
+
392
+		$warnings = $vObj->validate(Node::REPAIR);
393
+		if (!count($warnings)) {
394
+			$this->log("  No warnings!");
395
+		} else {
396
+
397
+			$levels = [
398
+				1 => 'REPAIRED',
399
+				2 => 'WARNING',
400
+				3 => 'ERROR',
401
+			];
402
+			$returnCode = 2;
403
+			foreach ($warnings as $warn) {
404
+
405
+				$extra = '';
406
+				if ($warn['node'] instanceof Property) {
407
+					$extra = ' (property: "' . $warn['node']->name . '")';
408
+				}
409
+				$this->log("  [" . $levels[$warn['level']] . '] ' . $warn['message'] . $extra);
410
+
411
+			}
412
+
413
+		}
414
+		fwrite($this->stdout, $vObj->serialize());
415
+
416
+		return $returnCode;
417
+
418
+	}
419
+
420
+	/**
421
+	 * Converts a vObject file to a new format.
422
+	 *
423
+	 * @param Component $vObj
424
+	 *
425
+	 * @return int
426
+	 */
427
+	protected function convert($vObj) {
428
+
429
+		$json = false;
430
+		$convertVersion = null;
431
+		$forceInput = null;
432
+
433
+		switch ($this->format) {
434
+			case 'json' :
435
+				$json = true;
436
+				if ($vObj->name === 'VCARD') {
437
+					$convertVersion = Document::VCARD40;
438
+				}
439
+				break;
440
+			case 'jcard' :
441
+				$json = true;
442
+				$forceInput = 'VCARD';
443
+				$convertVersion = Document::VCARD40;
444
+				break;
445
+			case 'jcal' :
446
+				$json = true;
447
+				$forceInput = 'VCALENDAR';
448
+				break;
449
+			case 'mimedir' :
450
+			case 'icalendar' :
451
+			case 'icalendar20' :
452
+			case 'vcard' :
453
+				break;
454
+			case 'vcard21' :
455
+				$convertVersion = Document::VCARD21;
456
+				break;
457
+			case 'vcard30' :
458
+				$convertVersion = Document::VCARD30;
459
+				break;
460
+			case 'vcard40' :
461
+				$convertVersion = Document::VCARD40;
462
+				break;
463
+
464
+		}
465
+
466
+		if ($forceInput && $vObj->name !== $forceInput) {
467
+			throw new \Exception('You cannot convert a ' . strtolower($vObj->name) . ' to ' . $this->format);
468
+		}
469
+		if ($convertVersion) {
470
+			$vObj = $vObj->convert($convertVersion);
471
+		}
472
+		if ($json) {
473
+			$jsonOptions = 0;
474
+			if ($this->pretty) {
475
+				$jsonOptions = JSON_PRETTY_PRINT;
476
+			}
477
+			fwrite($this->stdout, json_encode($vObj->jsonSerialize(), $jsonOptions));
478
+		} else {
479
+			fwrite($this->stdout, $vObj->serialize());
480
+		}
481
+
482
+		return 0;
483
+
484
+	}
485
+
486
+	/**
487
+	 * Colorizes a file.
488
+	 *
489
+	 * @param Component $vObj
490
+	 *
491
+	 * @return int
492
+	 */
493
+	protected function color($vObj) {
494
+
495
+		fwrite($this->stdout, $this->serializeComponent($vObj));
496
+
497
+	}
498
+
499
+	/**
500
+	 * Returns an ansi color string for a color name.
501
+	 *
502
+	 * @param string $color
503
+	 *
504
+	 * @return string
505
+	 */
506
+	protected function colorize($color, $str, $resetTo = 'default') {
507
+
508
+		$colors = [
509
+			'cyan'    => '1;36',
510
+			'red'     => '1;31',
511
+			'yellow'  => '1;33',
512
+			'blue'    => '0;34',
513
+			'green'   => '0;32',
514
+			'default' => '0',
515
+			'purple'  => '0;35',
516
+		];
517
+		return "\033[" . $colors[$color] . 'm' . $str . "\033[" . $colors[$resetTo] . "m";
518
+
519
+	}
520
+
521
+	/**
522
+	 * Writes out a string in specific color.
523
+	 *
524
+	 * @param string $color
525
+	 * @param string $str
526
+	 *
527
+	 * @return void
528
+	 */
529
+	protected function cWrite($color, $str) {
530
+
531
+		fwrite($this->stdout, $this->colorize($color, $str));
532
+
533
+	}
534
+
535
+	protected function serializeComponent(Component $vObj) {
536
+
537
+		$this->cWrite('cyan', 'BEGIN');
538
+		$this->cWrite('red', ':');
539
+		$this->cWrite('yellow', $vObj->name . "\n");
540
+
541
+		/**
542
+		 * Gives a component a 'score' for sorting purposes.
543
+		 *
544
+		 * This is solely used by the childrenSort method.
545
+		 *
546
+		 * A higher score means the item will be lower in the list.
547
+		 * To avoid score collisions, each "score category" has a reasonable
548
+		 * space to accomodate elements. The $key is added to the $score to
549
+		 * preserve the original relative order of elements.
550
+		 *
551
+		 * @param int $key
552
+		 * @param array $array
553
+		 *
554
+		 * @return int
555
+		 */
556
+		$sortScore = function($key, $array) {
557
+
558
+			if ($array[$key] instanceof Component) {
559
+
560
+				// We want to encode VTIMEZONE first, this is a personal
561
+				// preference.
562
+				if ($array[$key]->name === 'VTIMEZONE') {
563
+					$score = 300000000;
564
+					return $score + $key;
565
+				} else {
566
+					$score = 400000000;
567
+					return $score + $key;
568
+				}
569
+			} else {
570
+				// Properties get encoded first
571
+				// VCARD version 4.0 wants the VERSION property to appear first
572
+				if ($array[$key] instanceof Property) {
573
+					if ($array[$key]->name === 'VERSION') {
574
+						$score = 100000000;
575
+						return $score + $key;
576
+					} else {
577
+						// All other properties
578
+						$score = 200000000;
579
+						return $score + $key;
580
+					}
581
+				}
582
+			}
583
+
584
+		};
585
+
586
+		$children = $vObj->children();
587
+		$tmp = $children;
588
+		uksort(
589
+			$children,
590
+			public function($a, $b) use ($sortScore, $tmp) {
591
+
592
+				$sA = $sortScore($a, $tmp);
593
+				$sB = $sortScore($b, $tmp);
594
+
595
+				return $sA - $sB;
596
+
597
+			}
598
+		);
599
+
600
+		foreach ($children as $child) {
601
+			if ($child instanceof Component) {
602
+				$this->serializeComponent($child);
603
+			} else {
604
+				$this->serializeProperty($child);
605
+			}
606
+		}
607
+
608
+		$this->cWrite('cyan', 'END');
609
+		$this->cWrite('red', ':');
610
+		$this->cWrite('yellow', $vObj->name . "\n");
611
+
612
+	}
613
+
614
+	/**
615
+	 * Colorizes a property.
616
+	 *
617
+	 * @param Property $property
618
+	 *
619
+	 * @return void
620
+	 */
621
+	protected function serializeProperty(Property $property) {
622
+
623
+		if ($property->group) {
624
+			$this->cWrite('default', $property->group);
625
+			$this->cWrite('red', '.');
626
+		}
627
+
628
+		$this->cWrite('yellow', $property->name);
629
+
630
+		foreach ($property->parameters as $param) {
631
+
632
+			$this->cWrite('red', ';');
633
+			$this->cWrite('blue', $param->serialize());
634
+
635
+		}
636
+		$this->cWrite('red', ':');
637
+
638
+		if ($property instanceof Property\Binary) {
639
+
640
+			$this->cWrite('default', 'embedded binary stripped. (' . strlen($property->getValue()) . ' bytes)');
641
+
642
+		} else {
643
+
644
+			$parts = $property->getParts();
645
+			$first1 = true;
646
+			// Looping through property values
647
+			foreach ($parts as $part) {
648
+				if ($first1) {
649
+					$first1 = false;
650
+				} else {
651
+					$this->cWrite('red', $property->delimiter);
652
+				}
653
+				$first2 = true;
654
+				// Looping through property sub-values
655
+				foreach ((array)$part as $subPart) {
656
+					if ($first2) {
657
+						$first2 = false;
658
+					} else {
659
+						// The sub-value delimiter is always comma
660
+						$this->cWrite('red', ',');
661
+					}
662
+
663
+					$subPart = strtr(
664
+						$subPart,
665
+						[
666
+							'\\' => $this->colorize('purple', '\\\\', 'green'),
667
+							';'  => $this->colorize('purple', '\;', 'green'),
668
+							','  => $this->colorize('purple', '\,', 'green'),
669
+							"\n" => $this->colorize('purple', "\\n\n\t", 'green'),
670
+							"\r" => "",
671
+						]
672
+					);
673
+
674
+					$this->cWrite('green', $subPart);
675
+				}
676
+			}
677
+
678
+		}
679
+		$this->cWrite("default", "\n");
680
+
681
+	}
682
+
683
+	/**
684
+	 * Parses the list of arguments.
685
+	 *
686
+	 * @param array $argv
687
+	 *
688
+	 * @return void
689
+	 */
690
+	protected function parseArguments(array $argv) {
691
+
692
+		$positional = [];
693
+		$options = [];
694
+
695
+		for ($ii = 0; $ii < count($argv); $ii++) {
696
+
697
+			// Skipping the first argument.
698
+			if ($ii === 0) continue;
699
+
700
+			$v = $argv[$ii];
701
+
702
+			if (substr($v, 0, 2) === '--') {
703
+				// This is a long-form option.
704
+				$optionName = substr($v, 2);
705
+				$optionValue = true;
706
+				if (strpos($optionName, '=')) {
707
+					list($optionName, $optionValue) = explode('=', $optionName);
708
+				}
709
+				$options[$optionName] = $optionValue;
710
+			} elseif (substr($v, 0, 1) === '-' && strlen($v) > 1) {
711
+				// This is a short-form option.
712
+				foreach (str_split(substr($v, 1)) as $option) {
713
+					$options[$option] = true;
714
+				}
715
+
716
+			} else {
717
+
718
+				$positional[] = $v;
719
+
720
+			}
721
+
722
+		}
723
+
724
+		return [$options, $positional];
725
+
726
+	}
727
+
728
+	protected $parser;
729
+
730
+	/**
731
+	 * Reads the input file.
732
+	 *
733
+	 * @return Component
734
+	 */
735
+	protected function readInput() {
736
+
737
+		if (!$this->parser) {
738
+			if ($this->inputPath !== '-') {
739
+				$this->stdin = fopen($this->inputPath, 'r');
740
+			}
741
+
742
+			if ($this->inputFormat === 'mimedir') {
743
+				$this->parser = new Parser\MimeDir($this->stdin, ($this->forgiving ? Reader::OPTION_FORGIVING : 0));
744
+			} else {
745
+				$this->parser = new Parser\Json($this->stdin, ($this->forgiving ? Reader::OPTION_FORGIVING : 0));
746
+			}
747
+		}
748
+
749
+		return $this->parser->parse();
750
+
751
+	}
752
+
753
+	/**
754
+	 * Sends a message to STDERR.
755
+	 *
756
+	 * @param string $msg
757
+	 *
758
+	 * @return void
759
+	 */
760
+	protected function log($msg, $color = 'default') {
761
+
762
+		if (!$this->quiet) {
763
+			if ($color !== 'default') {
764
+				$msg = $this->colorize($color, $msg);
765
+			}
766
+			fwrite($this->stderr, $msg . "\n");
767
+		}
768
+
769
+	}
770 770
 
771 771
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/ElementList.php 1 patch
Indentation   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -18,37 +18,37 @@
 block discarded – undo
18 18
 class ElementList extends ArrayIterator {
19 19
 
20 20
 
21
-    /* {{{ ArrayAccess Interface */
22
-
23
-    /**
24
-     * Sets an item through ArrayAccess.
25
-     *
26
-     * @param int $offset
27
-     * @param mixed $value
28
-     *
29
-     * @return void
30
-     */
31
-    public function offsetSet($offset, $value) {
32
-
33
-        throw new LogicException('You can not add new objects to an ElementList');
34
-
35
-    }
36
-
37
-    /**
38
-     * Sets an item through ArrayAccess.
39
-     *
40
-     * This method just forwards the request to the inner iterator
41
-     *
42
-     * @param int $offset
43
-     *
44
-     * @return void
45
-     */
46
-    public function offsetUnset($offset) {
47
-
48
-        throw new LogicException('You can not remove objects from an ElementList');
49
-
50
-    }
51
-
52
-    /* }}} */
21
+	/* {{{ ArrayAccess Interface */
22
+
23
+	/**
24
+	 * Sets an item through ArrayAccess.
25
+	 *
26
+	 * @param int $offset
27
+	 * @param mixed $value
28
+	 *
29
+	 * @return void
30
+	 */
31
+	public function offsetSet($offset, $value) {
32
+
33
+		throw new LogicException('You can not add new objects to an ElementList');
34
+
35
+	}
36
+
37
+	/**
38
+	 * Sets an item through ArrayAccess.
39
+	 *
40
+	 * This method just forwards the request to the inner iterator
41
+	 *
42
+	 * @param int $offset
43
+	 *
44
+	 * @return void
45
+	 */
46
+	public function offsetUnset($offset) {
47
+
48
+		throw new LogicException('You can not remove objects from an ElementList');
49
+
50
+	}
51
+
52
+	/* }}} */
53 53
 
54 54
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/VCardConverter.php 1 patch
Indentation   +445 added lines, -445 removed lines patch added patch discarded remove patch
@@ -11,457 +11,457 @@
 block discarded – undo
11 11
  */
12 12
 class VCardConverter {
13 13
 
14
-    /**
15
-     * Converts a vCard object to a new version.
16
-     *
17
-     * targetVersion must be one of:
18
-     *   Document::VCARD21
19
-     *   Document::VCARD30
20
-     *   Document::VCARD40
21
-     *
22
-     * Currently only 3.0 and 4.0 as input and output versions.
23
-     *
24
-     * 2.1 has some minor support for the input version, it's incomplete at the
25
-     * moment though.
26
-     *
27
-     * If input and output version are identical, a clone is returned.
28
-     *
29
-     * @param Component\VCard $input
30
-     * @param int $targetVersion
31
-     */
32
-    public function convert(Component\VCard $input, $targetVersion) {
33
-
34
-        $inputVersion = $input->getDocumentType();
35
-        if ($inputVersion === $targetVersion) {
36
-            return clone $input;
37
-        }
38
-
39
-        if (!in_array($inputVersion, [Document::VCARD21, Document::VCARD30, Document::VCARD40])) {
40
-            throw new \InvalidArgumentException('Only vCard 2.1, 3.0 and 4.0 are supported for the input data');
41
-        }
42
-        if (!in_array($targetVersion, [Document::VCARD30, Document::VCARD40])) {
43
-            throw new \InvalidArgumentException('You can only use vCard 3.0 or 4.0 for the target version');
44
-        }
45
-
46
-        $newVersion = $targetVersion === Document::VCARD40 ? '4.0' : '3.0';
47
-
48
-        $output = new Component\VCard([
49
-            'VERSION' => $newVersion,
50
-        ]);
51
-
52
-        // We might have generated a default UID. Remove it!
53
-        unset($output->UID);
54
-
55
-        foreach ($input->children() as $property) {
56
-
57
-            $this->convertProperty($input, $output, $property, $targetVersion);
58
-
59
-        }
60
-
61
-        return $output;
62
-
63
-    }
64
-
65
-    /**
66
-     * Handles conversion of a single property.
67
-     *
68
-     * @param Component\VCard $input
69
-     * @param Component\VCard $output
70
-     * @param Property $property
71
-     * @param int $targetVersion
72
-     *
73
-     * @return void
74
-     */
75
-    protected function convertProperty(Component\VCard $input, Component\VCard $output, Property $property, $targetVersion) {
76
-
77
-        // Skipping these, those are automatically added.
78
-        if (in_array($property->name, ['VERSION', 'PRODID'])) {
79
-            return;
80
-        }
81
-
82
-        $parameters = $property->parameters();
83
-        $valueType = null;
84
-        if (isset($parameters['VALUE'])) {
85
-            $valueType = $parameters['VALUE']->getValue();
86
-            unset($parameters['VALUE']);
87
-        }
88
-        if (!$valueType) {
89
-            $valueType = $property->getValueType();
90
-        }
91
-        $newProperty = $output->createProperty(
92
-            $property->name,
93
-            $property->getParts(),
94
-            [], // parameters will get added a bit later.
95
-            $valueType
96
-        );
97
-
98
-
99
-        if ($targetVersion === Document::VCARD30) {
100
-
101
-            if ($property instanceof Property\Uri && in_array($property->name, ['PHOTO', 'LOGO', 'SOUND'])) {
102
-
103
-                $newProperty = $this->convertUriToBinary($output, $newProperty);
104
-
105
-            } elseif ($property instanceof Property\VCard\DateAndOrTime) {
106
-
107
-                // In vCard 4, the birth year may be optional. This is not the
108
-                // case for vCard 3. Apple has a workaround for this that
109
-                // allows applications that support Apple's extension still
110
-                // omit birthyears in vCard 3, but applications that do not
111
-                // support this, will just use a random birthyear. We're
112
-                // choosing 1604 for the birthyear, because that's what apple
113
-                // uses.
114
-                $parts = DateTimeParser::parseVCardDateTime($property->getValue());
115
-                if (is_null($parts['year'])) {
116
-                    $newValue = '1604-' . $parts['month'] . '-' . $parts['date'];
117
-                    $newProperty->setValue($newValue);
118
-                    $newProperty['X-APPLE-OMIT-YEAR'] = '1604';
119
-                }
120
-
121
-                if ($newProperty->name == 'ANNIVERSARY') {
122
-                    // Microsoft non-standard anniversary
123
-                    $newProperty->name = 'X-ANNIVERSARY';
124
-
125
-                    // We also need to add a new apple property for the same
126
-                    // purpose. This apple property needs a 'label' in the same
127
-                    // group, so we first need to find a groupname that doesn't
128
-                    // exist yet.
129
-                    $x = 1;
130
-                    while ($output->select('ITEM' . $x . '.')) {
131
-                        $x++;
132
-                    }
133
-                    $output->add('ITEM' . $x . '.X-ABDATE', $newProperty->getValue(), ['VALUE' => 'DATE-AND-OR-TIME']);
134
-                    $output->add('ITEM' . $x . '.X-ABLABEL', '_$!<Anniversary>!$_');
135
-                }
136
-
137
-            } elseif ($property->name === 'KIND') {
138
-
139
-                switch (strtolower($property->getValue())) {
140
-                    case 'org' :
141
-                        // vCard 3.0 does not have an equivalent to KIND:ORG,
142
-                        // but apple has an extension that means the same
143
-                        // thing.
144
-                        $newProperty = $output->createProperty('X-ABSHOWAS', 'COMPANY');
145
-                        break;
146
-
147
-                    case 'individual' :
148
-                        // Individual is implicit, so we skip it.
149
-                        return;
150
-
151
-                    case 'group' :
152
-                        // OS X addressbook property
153
-                        $newProperty = $output->createProperty('X-ADDRESSBOOKSERVER-KIND', 'GROUP');
154
-                        break;
155
-                }
156
-
157
-
158
-            }
159
-
160
-        } elseif ($targetVersion === Document::VCARD40) {
161
-
162
-            // These properties were removed in vCard 4.0
163
-            if (in_array($property->name, ['NAME', 'MAILER', 'LABEL', 'CLASS'])) {
164
-                return;
165
-            }
166
-
167
-            if ($property instanceof Property\Binary) {
168
-
169
-                $newProperty = $this->convertBinaryToUri($output, $newProperty, $parameters);
170
-
171
-            } elseif ($property instanceof Property\VCard\DateAndOrTime && isset($parameters['X-APPLE-OMIT-YEAR'])) {
172
-
173
-                // If a property such as BDAY contained 'X-APPLE-OMIT-YEAR',
174
-                // then we're stripping the year from the vcard 4 value.
175
-                $parts = DateTimeParser::parseVCardDateTime($property->getValue());
176
-                if ($parts['year'] === $property['X-APPLE-OMIT-YEAR']->getValue()) {
177
-                    $newValue = '--' . $parts['month'] . '-' . $parts['date'];
178
-                    $newProperty->setValue($newValue);
179
-                }
180
-
181
-                // Regardless if the year matched or not, we do need to strip
182
-                // X-APPLE-OMIT-YEAR.
183
-                unset($parameters['X-APPLE-OMIT-YEAR']);
184
-
185
-            }
186
-            switch ($property->name) {
187
-                case 'X-ABSHOWAS' :
188
-                    if (strtoupper($property->getValue()) === 'COMPANY') {
189
-                        $newProperty = $output->createProperty('KIND', 'ORG');
190
-                    }
191
-                    break;
192
-                case 'X-ADDRESSBOOKSERVER-KIND' :
193
-                    if (strtoupper($property->getValue()) === 'GROUP') {
194
-                        $newProperty = $output->createProperty('KIND', 'GROUP');
195
-                    }
196
-                    break;
197
-                case 'X-ANNIVERSARY' :
198
-                    $newProperty->name = 'ANNIVERSARY';
199
-                    // If we already have an anniversary property with the same
200
-                    // value, ignore.
201
-                    foreach ($output->select('ANNIVERSARY') as $anniversary) {
202
-                        if ($anniversary->getValue() === $newProperty->getValue()) {
203
-                            return;
204
-                        }
205
-                    }
206
-                    break;
207
-                case 'X-ABDATE' :
208
-                    // Find out what the label was, if it exists.
209
-                    if (!$property->group) {
210
-                        break;
211
-                    }
212
-                    $label = $input->{$property->group . '.X-ABLABEL'};
213
-
214
-                    // We only support converting anniversaries.
215
-                    if (!$label || $label->getValue() !== '_$!<Anniversary>!$_') {
216
-                        break;
217
-                    }
218
-
219
-                    // If we already have an anniversary property with the same
220
-                    // value, ignore.
221
-                    foreach ($output->select('ANNIVERSARY') as $anniversary) {
222
-                        if ($anniversary->getValue() === $newProperty->getValue()) {
223
-                            return;
224
-                        }
225
-                    }
226
-                    $newProperty->name = 'ANNIVERSARY';
227
-                    break;
228
-                // Apple's per-property label system.
229
-                case 'X-ABLABEL' :
230
-                    if ($newProperty->getValue() === '_$!<Anniversary>!$_') {
231
-                        // We can safely remove these, as they are converted to
232
-                        // ANNIVERSARY properties.
233
-                        return;
234
-                    }
235
-                    break;
236
-
237
-            }
238
-
239
-        }
240
-
241
-        // set property group
242
-        $newProperty->group = $property->group;
243
-
244
-        if ($targetVersion === Document::VCARD40) {
245
-            $this->convertParameters40($newProperty, $parameters);
246
-        } else {
247
-            $this->convertParameters30($newProperty, $parameters);
248
-        }
249
-
250
-        // Lastly, we need to see if there's a need for a VALUE parameter.
251
-        //
252
-        // We can do that by instantating a empty property with that name, and
253
-        // seeing if the default valueType is identical to the current one.
254
-        $tempProperty = $output->createProperty($newProperty->name);
255
-        if ($tempProperty->getValueType() !== $newProperty->getValueType()) {
256
-            $newProperty['VALUE'] = $newProperty->getValueType();
257
-        }
258
-
259
-        $output->add($newProperty);
260
-
261
-
262
-    }
263
-
264
-    /**
265
-     * Converts a BINARY property to a URI property.
266
-     *
267
-     * vCard 4.0 no longer supports BINARY properties.
268
-     *
269
-     * @param Component\VCard $output
270
-     * @param Property\Uri $property The input property.
271
-     * @param $parameters List of parameters that will eventually be added to
272
-     *                    the new property.
273
-     *
274
-     * @return Property\Uri
275
-     */
276
-    protected function convertBinaryToUri(Component\VCard $output, Property\Binary $newProperty, array &$parameters) {
277
-
278
-        $value = $newProperty->getValue();
279
-        $newProperty = $output->createProperty(
280
-            $newProperty->name,
281
-            null, // no value
282
-            [], // no parameters yet
283
-            'URI' // Forcing the BINARY type
284
-        );
285
-
286
-        $mimeType = 'application/octet-stream';
287
-
288
-        // See if we can find a better mimetype.
289
-        if (isset($parameters['TYPE'])) {
290
-
291
-            $newTypes = [];
292
-            foreach ($parameters['TYPE']->getParts() as $typePart) {
293
-                if (in_array(
294
-                    strtoupper($typePart),
295
-                    ['JPEG', 'PNG', 'GIF']
296
-                )) {
297
-                    $mimeType = 'image/' . strtolower($typePart);
298
-                } else {
299
-                    $newTypes[] = $typePart;
300
-                }
301
-            }
302
-
303
-            // If there were any parameters we're not converting to a
304
-            // mime-type, we need to keep them.
305
-            if ($newTypes) {
306
-                $parameters['TYPE']->setParts($newTypes);
307
-            } else {
308
-                unset($parameters['TYPE']);
309
-            }
310
-
311
-        }
312
-
313
-        $newProperty->setValue('data:' . $mimeType . ';base64,' . base64_encode($value));
314
-        return $newProperty;
315
-
316
-    }
317
-
318
-    /**
319
-     * Converts a URI property to a BINARY property.
320
-     *
321
-     * In vCard 4.0 attachments are encoded as data: uri. Even though these may
322
-     * be valid in vCard 3.0 as well, we should convert those to BINARY if
323
-     * possible, to improve compatibility.
324
-     *
325
-     * @param Component\VCard $output
326
-     * @param Property\Uri $property The input property.
327
-     *
328
-     * @return Property\Binary|null
329
-     */
330
-    protected function convertUriToBinary(Component\VCard $output, Property\Uri $newProperty) {
331
-
332
-        $value = $newProperty->getValue();
333
-
334
-        // Only converting data: uris
335
-        if (substr($value, 0, 5) !== 'data:') {
336
-            return $newProperty;
337
-        }
338
-
339
-        $newProperty = $output->createProperty(
340
-            $newProperty->name,
341
-            null, // no value
342
-            [], // no parameters yet
343
-            'BINARY'
344
-        );
345
-
346
-        $mimeType = substr($value, 5, strpos($value, ',') - 5);
347
-        if (strpos($mimeType, ';')) {
348
-            $mimeType = substr($mimeType, 0, strpos($mimeType, ';'));
349
-            $newProperty->setValue(base64_decode(substr($value, strpos($value, ',') + 1)));
350
-        } else {
351
-            $newProperty->setValue(substr($value, strpos($value, ',') + 1));
352
-        }
353
-        unset($value);
354
-
355
-        $newProperty['ENCODING'] = 'b';
356
-        switch ($mimeType) {
357
-
358
-            case 'image/jpeg' :
359
-                $newProperty['TYPE'] = 'JPEG';
360
-                break;
361
-            case 'image/png' :
362
-                $newProperty['TYPE'] = 'PNG';
363
-                break;
364
-            case 'image/gif' :
365
-                $newProperty['TYPE'] = 'GIF';
366
-                break;
367
-
368
-        }
369
-
370
-
371
-        return $newProperty;
372
-
373
-    }
374
-
375
-    /**
376
-     * Adds parameters to a new property for vCard 4.0.
377
-     *
378
-     * @param Property $newProperty
379
-     * @param array $parameters
380
-     *
381
-     * @return void
382
-     */
383
-    protected function convertParameters40(Property $newProperty, array $parameters) {
384
-
385
-        // Adding all parameters.
386
-        foreach ($parameters as $param) {
387
-
388
-            // vCard 2.1 allowed parameters with no name
389
-            if ($param->noName) $param->noName = false;
390
-
391
-            switch ($param->name) {
392
-
393
-                // We need to see if there's any TYPE=PREF, because in vCard 4
394
-                // that's now PREF=1.
395
-                case 'TYPE' :
396
-                    foreach ($param->getParts() as $paramPart) {
397
-
398
-                        if (strtoupper($paramPart) === 'PREF') {
399
-                            $newProperty->add('PREF', '1');
400
-                        } else {
401
-                            $newProperty->add($param->name, $paramPart);
402
-                        }
403
-
404
-                    }
405
-                    break;
406
-                // These no longer exist in vCard 4
407
-                case 'ENCODING' :
408
-                case 'CHARSET' :
409
-                    break;
410
-
411
-                default :
412
-                    $newProperty->add($param->name, $param->getParts());
413
-                    break;
414
-
415
-            }
416
-
417
-        }
418
-
419
-    }
420
-
421
-    /**
422
-     * Adds parameters to a new property for vCard 3.0.
423
-     *
424
-     * @param Property $newProperty
425
-     * @param array $parameters
426
-     *
427
-     * @return void
428
-     */
429
-    protected function convertParameters30(Property $newProperty, array $parameters) {
430
-
431
-        // Adding all parameters.
432
-        foreach ($parameters as $param) {
433
-
434
-            // vCard 2.1 allowed parameters with no name
435
-            if ($param->noName) $param->noName = false;
436
-
437
-            switch ($param->name) {
438
-
439
-                case 'ENCODING' :
440
-                    // This value only existed in vCard 2.1, and should be
441
-                    // removed for anything else.
442
-                    if (strtoupper($param->getValue()) !== 'QUOTED-PRINTABLE') {
443
-                        $newProperty->add($param->name, $param->getParts());
444
-                    }
445
-                    break;
446
-
447
-                /*
14
+	/**
15
+	 * Converts a vCard object to a new version.
16
+	 *
17
+	 * targetVersion must be one of:
18
+	 *   Document::VCARD21
19
+	 *   Document::VCARD30
20
+	 *   Document::VCARD40
21
+	 *
22
+	 * Currently only 3.0 and 4.0 as input and output versions.
23
+	 *
24
+	 * 2.1 has some minor support for the input version, it's incomplete at the
25
+	 * moment though.
26
+	 *
27
+	 * If input and output version are identical, a clone is returned.
28
+	 *
29
+	 * @param Component\VCard $input
30
+	 * @param int $targetVersion
31
+	 */
32
+	public function convert(Component\VCard $input, $targetVersion) {
33
+
34
+		$inputVersion = $input->getDocumentType();
35
+		if ($inputVersion === $targetVersion) {
36
+			return clone $input;
37
+		}
38
+
39
+		if (!in_array($inputVersion, [Document::VCARD21, Document::VCARD30, Document::VCARD40])) {
40
+			throw new \InvalidArgumentException('Only vCard 2.1, 3.0 and 4.0 are supported for the input data');
41
+		}
42
+		if (!in_array($targetVersion, [Document::VCARD30, Document::VCARD40])) {
43
+			throw new \InvalidArgumentException('You can only use vCard 3.0 or 4.0 for the target version');
44
+		}
45
+
46
+		$newVersion = $targetVersion === Document::VCARD40 ? '4.0' : '3.0';
47
+
48
+		$output = new Component\VCard([
49
+			'VERSION' => $newVersion,
50
+		]);
51
+
52
+		// We might have generated a default UID. Remove it!
53
+		unset($output->UID);
54
+
55
+		foreach ($input->children() as $property) {
56
+
57
+			$this->convertProperty($input, $output, $property, $targetVersion);
58
+
59
+		}
60
+
61
+		return $output;
62
+
63
+	}
64
+
65
+	/**
66
+	 * Handles conversion of a single property.
67
+	 *
68
+	 * @param Component\VCard $input
69
+	 * @param Component\VCard $output
70
+	 * @param Property $property
71
+	 * @param int $targetVersion
72
+	 *
73
+	 * @return void
74
+	 */
75
+	protected function convertProperty(Component\VCard $input, Component\VCard $output, Property $property, $targetVersion) {
76
+
77
+		// Skipping these, those are automatically added.
78
+		if (in_array($property->name, ['VERSION', 'PRODID'])) {
79
+			return;
80
+		}
81
+
82
+		$parameters = $property->parameters();
83
+		$valueType = null;
84
+		if (isset($parameters['VALUE'])) {
85
+			$valueType = $parameters['VALUE']->getValue();
86
+			unset($parameters['VALUE']);
87
+		}
88
+		if (!$valueType) {
89
+			$valueType = $property->getValueType();
90
+		}
91
+		$newProperty = $output->createProperty(
92
+			$property->name,
93
+			$property->getParts(),
94
+			[], // parameters will get added a bit later.
95
+			$valueType
96
+		);
97
+
98
+
99
+		if ($targetVersion === Document::VCARD30) {
100
+
101
+			if ($property instanceof Property\Uri && in_array($property->name, ['PHOTO', 'LOGO', 'SOUND'])) {
102
+
103
+				$newProperty = $this->convertUriToBinary($output, $newProperty);
104
+
105
+			} elseif ($property instanceof Property\VCard\DateAndOrTime) {
106
+
107
+				// In vCard 4, the birth year may be optional. This is not the
108
+				// case for vCard 3. Apple has a workaround for this that
109
+				// allows applications that support Apple's extension still
110
+				// omit birthyears in vCard 3, but applications that do not
111
+				// support this, will just use a random birthyear. We're
112
+				// choosing 1604 for the birthyear, because that's what apple
113
+				// uses.
114
+				$parts = DateTimeParser::parseVCardDateTime($property->getValue());
115
+				if (is_null($parts['year'])) {
116
+					$newValue = '1604-' . $parts['month'] . '-' . $parts['date'];
117
+					$newProperty->setValue($newValue);
118
+					$newProperty['X-APPLE-OMIT-YEAR'] = '1604';
119
+				}
120
+
121
+				if ($newProperty->name == 'ANNIVERSARY') {
122
+					// Microsoft non-standard anniversary
123
+					$newProperty->name = 'X-ANNIVERSARY';
124
+
125
+					// We also need to add a new apple property for the same
126
+					// purpose. This apple property needs a 'label' in the same
127
+					// group, so we first need to find a groupname that doesn't
128
+					// exist yet.
129
+					$x = 1;
130
+					while ($output->select('ITEM' . $x . '.')) {
131
+						$x++;
132
+					}
133
+					$output->add('ITEM' . $x . '.X-ABDATE', $newProperty->getValue(), ['VALUE' => 'DATE-AND-OR-TIME']);
134
+					$output->add('ITEM' . $x . '.X-ABLABEL', '_$!<Anniversary>!$_');
135
+				}
136
+
137
+			} elseif ($property->name === 'KIND') {
138
+
139
+				switch (strtolower($property->getValue())) {
140
+					case 'org' :
141
+						// vCard 3.0 does not have an equivalent to KIND:ORG,
142
+						// but apple has an extension that means the same
143
+						// thing.
144
+						$newProperty = $output->createProperty('X-ABSHOWAS', 'COMPANY');
145
+						break;
146
+
147
+					case 'individual' :
148
+						// Individual is implicit, so we skip it.
149
+						return;
150
+
151
+					case 'group' :
152
+						// OS X addressbook property
153
+						$newProperty = $output->createProperty('X-ADDRESSBOOKSERVER-KIND', 'GROUP');
154
+						break;
155
+				}
156
+
157
+
158
+			}
159
+
160
+		} elseif ($targetVersion === Document::VCARD40) {
161
+
162
+			// These properties were removed in vCard 4.0
163
+			if (in_array($property->name, ['NAME', 'MAILER', 'LABEL', 'CLASS'])) {
164
+				return;
165
+			}
166
+
167
+			if ($property instanceof Property\Binary) {
168
+
169
+				$newProperty = $this->convertBinaryToUri($output, $newProperty, $parameters);
170
+
171
+			} elseif ($property instanceof Property\VCard\DateAndOrTime && isset($parameters['X-APPLE-OMIT-YEAR'])) {
172
+
173
+				// If a property such as BDAY contained 'X-APPLE-OMIT-YEAR',
174
+				// then we're stripping the year from the vcard 4 value.
175
+				$parts = DateTimeParser::parseVCardDateTime($property->getValue());
176
+				if ($parts['year'] === $property['X-APPLE-OMIT-YEAR']->getValue()) {
177
+					$newValue = '--' . $parts['month'] . '-' . $parts['date'];
178
+					$newProperty->setValue($newValue);
179
+				}
180
+
181
+				// Regardless if the year matched or not, we do need to strip
182
+				// X-APPLE-OMIT-YEAR.
183
+				unset($parameters['X-APPLE-OMIT-YEAR']);
184
+
185
+			}
186
+			switch ($property->name) {
187
+				case 'X-ABSHOWAS' :
188
+					if (strtoupper($property->getValue()) === 'COMPANY') {
189
+						$newProperty = $output->createProperty('KIND', 'ORG');
190
+					}
191
+					break;
192
+				case 'X-ADDRESSBOOKSERVER-KIND' :
193
+					if (strtoupper($property->getValue()) === 'GROUP') {
194
+						$newProperty = $output->createProperty('KIND', 'GROUP');
195
+					}
196
+					break;
197
+				case 'X-ANNIVERSARY' :
198
+					$newProperty->name = 'ANNIVERSARY';
199
+					// If we already have an anniversary property with the same
200
+					// value, ignore.
201
+					foreach ($output->select('ANNIVERSARY') as $anniversary) {
202
+						if ($anniversary->getValue() === $newProperty->getValue()) {
203
+							return;
204
+						}
205
+					}
206
+					break;
207
+				case 'X-ABDATE' :
208
+					// Find out what the label was, if it exists.
209
+					if (!$property->group) {
210
+						break;
211
+					}
212
+					$label = $input->{$property->group . '.X-ABLABEL'};
213
+
214
+					// We only support converting anniversaries.
215
+					if (!$label || $label->getValue() !== '_$!<Anniversary>!$_') {
216
+						break;
217
+					}
218
+
219
+					// If we already have an anniversary property with the same
220
+					// value, ignore.
221
+					foreach ($output->select('ANNIVERSARY') as $anniversary) {
222
+						if ($anniversary->getValue() === $newProperty->getValue()) {
223
+							return;
224
+						}
225
+					}
226
+					$newProperty->name = 'ANNIVERSARY';
227
+					break;
228
+				// Apple's per-property label system.
229
+				case 'X-ABLABEL' :
230
+					if ($newProperty->getValue() === '_$!<Anniversary>!$_') {
231
+						// We can safely remove these, as they are converted to
232
+						// ANNIVERSARY properties.
233
+						return;
234
+					}
235
+					break;
236
+
237
+			}
238
+
239
+		}
240
+
241
+		// set property group
242
+		$newProperty->group = $property->group;
243
+
244
+		if ($targetVersion === Document::VCARD40) {
245
+			$this->convertParameters40($newProperty, $parameters);
246
+		} else {
247
+			$this->convertParameters30($newProperty, $parameters);
248
+		}
249
+
250
+		// Lastly, we need to see if there's a need for a VALUE parameter.
251
+		//
252
+		// We can do that by instantating a empty property with that name, and
253
+		// seeing if the default valueType is identical to the current one.
254
+		$tempProperty = $output->createProperty($newProperty->name);
255
+		if ($tempProperty->getValueType() !== $newProperty->getValueType()) {
256
+			$newProperty['VALUE'] = $newProperty->getValueType();
257
+		}
258
+
259
+		$output->add($newProperty);
260
+
261
+
262
+	}
263
+
264
+	/**
265
+	 * Converts a BINARY property to a URI property.
266
+	 *
267
+	 * vCard 4.0 no longer supports BINARY properties.
268
+	 *
269
+	 * @param Component\VCard $output
270
+	 * @param Property\Uri $property The input property.
271
+	 * @param $parameters List of parameters that will eventually be added to
272
+	 *                    the new property.
273
+	 *
274
+	 * @return Property\Uri
275
+	 */
276
+	protected function convertBinaryToUri(Component\VCard $output, Property\Binary $newProperty, array &$parameters) {
277
+
278
+		$value = $newProperty->getValue();
279
+		$newProperty = $output->createProperty(
280
+			$newProperty->name,
281
+			null, // no value
282
+			[], // no parameters yet
283
+			'URI' // Forcing the BINARY type
284
+		);
285
+
286
+		$mimeType = 'application/octet-stream';
287
+
288
+		// See if we can find a better mimetype.
289
+		if (isset($parameters['TYPE'])) {
290
+
291
+			$newTypes = [];
292
+			foreach ($parameters['TYPE']->getParts() as $typePart) {
293
+				if (in_array(
294
+					strtoupper($typePart),
295
+					['JPEG', 'PNG', 'GIF']
296
+				)) {
297
+					$mimeType = 'image/' . strtolower($typePart);
298
+				} else {
299
+					$newTypes[] = $typePart;
300
+				}
301
+			}
302
+
303
+			// If there were any parameters we're not converting to a
304
+			// mime-type, we need to keep them.
305
+			if ($newTypes) {
306
+				$parameters['TYPE']->setParts($newTypes);
307
+			} else {
308
+				unset($parameters['TYPE']);
309
+			}
310
+
311
+		}
312
+
313
+		$newProperty->setValue('data:' . $mimeType . ';base64,' . base64_encode($value));
314
+		return $newProperty;
315
+
316
+	}
317
+
318
+	/**
319
+	 * Converts a URI property to a BINARY property.
320
+	 *
321
+	 * In vCard 4.0 attachments are encoded as data: uri. Even though these may
322
+	 * be valid in vCard 3.0 as well, we should convert those to BINARY if
323
+	 * possible, to improve compatibility.
324
+	 *
325
+	 * @param Component\VCard $output
326
+	 * @param Property\Uri $property The input property.
327
+	 *
328
+	 * @return Property\Binary|null
329
+	 */
330
+	protected function convertUriToBinary(Component\VCard $output, Property\Uri $newProperty) {
331
+
332
+		$value = $newProperty->getValue();
333
+
334
+		// Only converting data: uris
335
+		if (substr($value, 0, 5) !== 'data:') {
336
+			return $newProperty;
337
+		}
338
+
339
+		$newProperty = $output->createProperty(
340
+			$newProperty->name,
341
+			null, // no value
342
+			[], // no parameters yet
343
+			'BINARY'
344
+		);
345
+
346
+		$mimeType = substr($value, 5, strpos($value, ',') - 5);
347
+		if (strpos($mimeType, ';')) {
348
+			$mimeType = substr($mimeType, 0, strpos($mimeType, ';'));
349
+			$newProperty->setValue(base64_decode(substr($value, strpos($value, ',') + 1)));
350
+		} else {
351
+			$newProperty->setValue(substr($value, strpos($value, ',') + 1));
352
+		}
353
+		unset($value);
354
+
355
+		$newProperty['ENCODING'] = 'b';
356
+		switch ($mimeType) {
357
+
358
+			case 'image/jpeg' :
359
+				$newProperty['TYPE'] = 'JPEG';
360
+				break;
361
+			case 'image/png' :
362
+				$newProperty['TYPE'] = 'PNG';
363
+				break;
364
+			case 'image/gif' :
365
+				$newProperty['TYPE'] = 'GIF';
366
+				break;
367
+
368
+		}
369
+
370
+
371
+		return $newProperty;
372
+
373
+	}
374
+
375
+	/**
376
+	 * Adds parameters to a new property for vCard 4.0.
377
+	 *
378
+	 * @param Property $newProperty
379
+	 * @param array $parameters
380
+	 *
381
+	 * @return void
382
+	 */
383
+	protected function convertParameters40(Property $newProperty, array $parameters) {
384
+
385
+		// Adding all parameters.
386
+		foreach ($parameters as $param) {
387
+
388
+			// vCard 2.1 allowed parameters with no name
389
+			if ($param->noName) $param->noName = false;
390
+
391
+			switch ($param->name) {
392
+
393
+				// We need to see if there's any TYPE=PREF, because in vCard 4
394
+				// that's now PREF=1.
395
+				case 'TYPE' :
396
+					foreach ($param->getParts() as $paramPart) {
397
+
398
+						if (strtoupper($paramPart) === 'PREF') {
399
+							$newProperty->add('PREF', '1');
400
+						} else {
401
+							$newProperty->add($param->name, $paramPart);
402
+						}
403
+
404
+					}
405
+					break;
406
+				// These no longer exist in vCard 4
407
+				case 'ENCODING' :
408
+				case 'CHARSET' :
409
+					break;
410
+
411
+				default :
412
+					$newProperty->add($param->name, $param->getParts());
413
+					break;
414
+
415
+			}
416
+
417
+		}
418
+
419
+	}
420
+
421
+	/**
422
+	 * Adds parameters to a new property for vCard 3.0.
423
+	 *
424
+	 * @param Property $newProperty
425
+	 * @param array $parameters
426
+	 *
427
+	 * @return void
428
+	 */
429
+	protected function convertParameters30(Property $newProperty, array $parameters) {
430
+
431
+		// Adding all parameters.
432
+		foreach ($parameters as $param) {
433
+
434
+			// vCard 2.1 allowed parameters with no name
435
+			if ($param->noName) $param->noName = false;
436
+
437
+			switch ($param->name) {
438
+
439
+				case 'ENCODING' :
440
+					// This value only existed in vCard 2.1, and should be
441
+					// removed for anything else.
442
+					if (strtoupper($param->getValue()) !== 'QUOTED-PRINTABLE') {
443
+						$newProperty->add($param->name, $param->getParts());
444
+					}
445
+					break;
446
+
447
+				/*
448 448
                  * Converting PREF=1 to TYPE=PREF.
449 449
                  *
450 450
                  * Any other PREF numbers we'll drop.
451 451
                  */
452
-                case 'PREF' :
453
-                    if ($param->getValue() == '1') {
454
-                        $newProperty->add('TYPE', 'PREF');
455
-                    }
456
-                    break;
452
+				case 'PREF' :
453
+					if ($param->getValue() == '1') {
454
+						$newProperty->add('TYPE', 'PREF');
455
+					}
456
+					break;
457 457
 
458
-                default :
459
-                    $newProperty->add($param->name, $param->getParts());
460
-                    break;
458
+				default :
459
+					$newProperty->add($param->name, $param->getParts());
460
+					break;
461 461
 
462
-            }
462
+			}
463 463
 
464
-        }
464
+		}
465 465
 
466
-    }
466
+	}
467 467
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/Component/VAlarm.php 1 patch
Indentation   +120 added lines, -120 removed lines patch added patch discarded remove patch
@@ -18,125 +18,125 @@
 block discarded – undo
18 18
  */
19 19
 class VAlarm extends VObject\Component {
20 20
 
21
-    /**
22
-     * Returns a DateTime object when this alarm is going to trigger.
23
-     *
24
-     * This ignores repeated alarm, only the first trigger is returned.
25
-     *
26
-     * @return DateTimeImmutable
27
-     */
28
-    public function getEffectiveTriggerTime() {
29
-
30
-        $trigger = $this->TRIGGER;
31
-        if (!isset($trigger['VALUE']) || strtoupper($trigger['VALUE']) === 'DURATION') {
32
-            $triggerDuration = VObject\DateTimeParser::parseDuration($this->TRIGGER);
33
-            $related = (isset($trigger['RELATED']) && strtoupper($trigger['RELATED']) == 'END') ? 'END' : 'START';
34
-
35
-            $parentComponent = $this->parent;
36
-            if ($related === 'START') {
37
-
38
-                if ($parentComponent->name === 'VTODO') {
39
-                    $propName = 'DUE';
40
-                } else {
41
-                    $propName = 'DTSTART';
42
-                }
43
-
44
-                $effectiveTrigger = $parentComponent->$propName->getDateTime();
45
-                $effectiveTrigger = $effectiveTrigger->add($triggerDuration);
46
-            } else {
47
-                if ($parentComponent->name === 'VTODO') {
48
-                    $endProp = 'DUE';
49
-                } elseif ($parentComponent->name === 'VEVENT') {
50
-                    $endProp = 'DTEND';
51
-                } else {
52
-                    throw new InvalidDataException('time-range filters on VALARM components are only supported when they are a child of VTODO or VEVENT');
53
-                }
54
-
55
-                if (isset($parentComponent->$endProp)) {
56
-                    $effectiveTrigger = $parentComponent->$endProp->getDateTime();
57
-                    $effectiveTrigger = $effectiveTrigger->add($triggerDuration);
58
-                } elseif (isset($parentComponent->DURATION)) {
59
-                    $effectiveTrigger = $parentComponent->DTSTART->getDateTime();
60
-                    $duration = VObject\DateTimeParser::parseDuration($parentComponent->DURATION);
61
-                    $effectiveTrigger = $effectiveTrigger->add($duration);
62
-                    $effectiveTrigger = $effectiveTrigger->add($triggerDuration);
63
-                } else {
64
-                    $effectiveTrigger = $parentComponent->DTSTART->getDateTime();
65
-                    $effectiveTrigger = $effectiveTrigger->add($triggerDuration);
66
-                }
67
-            }
68
-        } else {
69
-            $effectiveTrigger = $trigger->getDateTime();
70
-        }
71
-        return $effectiveTrigger;
72
-
73
-    }
74
-
75
-    /**
76
-     * Returns true or false depending on if the event falls in the specified
77
-     * time-range. This is used for filtering purposes.
78
-     *
79
-     * The rules used to determine if an event falls within the specified
80
-     * time-range is based on the CalDAV specification.
81
-     *
82
-     * @param DateTime $start
83
-     * @param DateTime $end
84
-     *
85
-     * @return bool
86
-     */
87
-    public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) {
88
-
89
-        $effectiveTrigger = $this->getEffectiveTriggerTime();
90
-
91
-        if (isset($this->DURATION)) {
92
-            $duration = VObject\DateTimeParser::parseDuration($this->DURATION);
93
-            $repeat = (string)$this->REPEAT;
94
-            if (!$repeat) {
95
-                $repeat = 1;
96
-            }
97
-
98
-            $period = new \DatePeriod($effectiveTrigger, $duration, (int)$repeat);
99
-
100
-            foreach ($period as $occurrence) {
101
-
102
-                if ($start <= $occurrence && $end > $occurrence) {
103
-                    return true;
104
-                }
105
-            }
106
-            return false;
107
-        } else {
108
-            return ($start <= $effectiveTrigger && $end > $effectiveTrigger);
109
-        }
110
-
111
-    }
112
-
113
-    /**
114
-     * A simple list of validation rules.
115
-     *
116
-     * This is simply a list of properties, and how many times they either
117
-     * must or must not appear.
118
-     *
119
-     * Possible values per property:
120
-     *   * 0 - Must not appear.
121
-     *   * 1 - Must appear exactly once.
122
-     *   * + - Must appear at least once.
123
-     *   * * - Can appear any number of times.
124
-     *   * ? - May appear, but not more than once.
125
-     *
126
-     * @var array
127
-     */
128
-    public function getValidationRules() {
129
-
130
-        return [
131
-            'ACTION'  => 1,
132
-            'TRIGGER' => 1,
133
-
134
-            'DURATION' => '?',
135
-            'REPEAT'   => '?',
136
-
137
-            'ATTACH' => '?',
138
-        ];
139
-
140
-    }
21
+	/**
22
+	 * Returns a DateTime object when this alarm is going to trigger.
23
+	 *
24
+	 * This ignores repeated alarm, only the first trigger is returned.
25
+	 *
26
+	 * @return DateTimeImmutable
27
+	 */
28
+	public function getEffectiveTriggerTime() {
29
+
30
+		$trigger = $this->TRIGGER;
31
+		if (!isset($trigger['VALUE']) || strtoupper($trigger['VALUE']) === 'DURATION') {
32
+			$triggerDuration = VObject\DateTimeParser::parseDuration($this->TRIGGER);
33
+			$related = (isset($trigger['RELATED']) && strtoupper($trigger['RELATED']) == 'END') ? 'END' : 'START';
34
+
35
+			$parentComponent = $this->parent;
36
+			if ($related === 'START') {
37
+
38
+				if ($parentComponent->name === 'VTODO') {
39
+					$propName = 'DUE';
40
+				} else {
41
+					$propName = 'DTSTART';
42
+				}
43
+
44
+				$effectiveTrigger = $parentComponent->$propName->getDateTime();
45
+				$effectiveTrigger = $effectiveTrigger->add($triggerDuration);
46
+			} else {
47
+				if ($parentComponent->name === 'VTODO') {
48
+					$endProp = 'DUE';
49
+				} elseif ($parentComponent->name === 'VEVENT') {
50
+					$endProp = 'DTEND';
51
+				} else {
52
+					throw new InvalidDataException('time-range filters on VALARM components are only supported when they are a child of VTODO or VEVENT');
53
+				}
54
+
55
+				if (isset($parentComponent->$endProp)) {
56
+					$effectiveTrigger = $parentComponent->$endProp->getDateTime();
57
+					$effectiveTrigger = $effectiveTrigger->add($triggerDuration);
58
+				} elseif (isset($parentComponent->DURATION)) {
59
+					$effectiveTrigger = $parentComponent->DTSTART->getDateTime();
60
+					$duration = VObject\DateTimeParser::parseDuration($parentComponent->DURATION);
61
+					$effectiveTrigger = $effectiveTrigger->add($duration);
62
+					$effectiveTrigger = $effectiveTrigger->add($triggerDuration);
63
+				} else {
64
+					$effectiveTrigger = $parentComponent->DTSTART->getDateTime();
65
+					$effectiveTrigger = $effectiveTrigger->add($triggerDuration);
66
+				}
67
+			}
68
+		} else {
69
+			$effectiveTrigger = $trigger->getDateTime();
70
+		}
71
+		return $effectiveTrigger;
72
+
73
+	}
74
+
75
+	/**
76
+	 * Returns true or false depending on if the event falls in the specified
77
+	 * time-range. This is used for filtering purposes.
78
+	 *
79
+	 * The rules used to determine if an event falls within the specified
80
+	 * time-range is based on the CalDAV specification.
81
+	 *
82
+	 * @param DateTime $start
83
+	 * @param DateTime $end
84
+	 *
85
+	 * @return bool
86
+	 */
87
+	public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) {
88
+
89
+		$effectiveTrigger = $this->getEffectiveTriggerTime();
90
+
91
+		if (isset($this->DURATION)) {
92
+			$duration = VObject\DateTimeParser::parseDuration($this->DURATION);
93
+			$repeat = (string)$this->REPEAT;
94
+			if (!$repeat) {
95
+				$repeat = 1;
96
+			}
97
+
98
+			$period = new \DatePeriod($effectiveTrigger, $duration, (int)$repeat);
99
+
100
+			foreach ($period as $occurrence) {
101
+
102
+				if ($start <= $occurrence && $end > $occurrence) {
103
+					return true;
104
+				}
105
+			}
106
+			return false;
107
+		} else {
108
+			return ($start <= $effectiveTrigger && $end > $effectiveTrigger);
109
+		}
110
+
111
+	}
112
+
113
+	/**
114
+	 * A simple list of validation rules.
115
+	 *
116
+	 * This is simply a list of properties, and how many times they either
117
+	 * must or must not appear.
118
+	 *
119
+	 * Possible values per property:
120
+	 *   * 0 - Must not appear.
121
+	 *   * 1 - Must appear exactly once.
122
+	 *   * + - Must appear at least once.
123
+	 *   * * - Can appear any number of times.
124
+	 *   * ? - May appear, but not more than once.
125
+	 *
126
+	 * @var array
127
+	 */
128
+	public function getValidationRules() {
129
+
130
+		return [
131
+			'ACTION'  => 1,
132
+			'TRIGGER' => 1,
133
+
134
+			'DURATION' => '?',
135
+			'REPEAT'   => '?',
136
+
137
+			'ATTACH' => '?',
138
+		];
139
+
140
+	}
141 141
 
142 142
 }
Please login to merge, or discard this patch.