1: <?php
2: /**
3: * The Horde_Kolab_Storage_Folder_Namespace:: class handles IMAP namespaces and allows
4: * to derive folder information from folder names.
5: *
6: * PHP version 5
7: *
8: * @category Kolab
9: * @package Kolab_Storage
10: * @author Gunnar Wrobel <wrobel@pardus.de>
11: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
12: * @link http://pear.horde.org/index.php?package=Kolab_Storage
13: */
14:
15: /**
16: * The Horde_Kolab_Storage_Folder_Namespace:: class handles IMAP namespaces and allows
17: * to derive folder information from folder names.
18: *
19: * Copyright 2004-2012 Horde LLC (http://www.horde.org/)
20: *
21: * See the enclosed file COPYING for license information (LGPL). If you
22: * did not receive this file, see http://www.horde.org/licenses/lgpl21.
23: *
24: * @category Kolab
25: * @package Kolab_Storage
26: * @author Gunnar Wrobel <wrobel@pardus.de>
27: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
28: * @link http://pear.horde.org/index.php?package=Kolab_Storage
29: */
30: abstract class Horde_Kolab_Storage_Folder_Namespace
31: implements Iterator, Serializable
32: {
33: /** The possible namespace types (RFC 2342 [5]) */
34: const PERSONAL = 'personal';
35: const OTHER = 'other';
36: const SHARED = 'shared';
37:
38: /**
39: * The current user.
40: *
41: * @var string
42: */
43: protected $user;
44:
45: /**
46: * The namespaces.
47: *
48: * @var array
49: */
50: private $_namespaces = array();
51:
52: /**
53: * The namespaces with a defined prefix.
54: *
55: * @var array
56: */
57: private $_prefix_namespaces = array();
58:
59: /**
60: * The fallback namespace matching any path if no other namesace matches.
61: *
62: * @var Horde_Kolab_Storage_Folder_Namespace_Element
63: */
64: private $_any;
65:
66: /**
67: * Constructor.
68: *
69: * @param array $namespaces The namespaces.
70: */
71: public function __construct(array $namespaces)
72: {
73: $this->initialize($namespaces);
74: }
75:
76: /**
77: * Initialize the class with a set of namespace configurations.
78: *
79: * @param array $namespaces The namespaces.
80: *
81: * @return NULL
82: */
83: protected function initialize(array $namespaces)
84: {
85: $this->_namespaces = $namespaces;
86: foreach ($this->_namespaces as $namespace) {
87: if ($namespace->getName() == '') {
88: $this->_any = $namespace;
89: } else {
90: $this->_prefix_namespaces[] = $namespace;
91: }
92: }
93: }
94:
95: /**
96: * Match a folder name with the corresponding namespace.
97: *
98: * @param string $name The name of the folder.
99: *
100: * @return Horde_Kolab_Storage_Folder_Namespace_Element The corresponding namespace.
101: *
102: * @throws Horde_Kolab_Storage_Exception If the namespace of the folder
103: * cannot be determined.
104: */
105: public function matchNamespace($name)
106: {
107: foreach ($this->_prefix_namespaces as $namespace) {
108: if ($namespace->matches($name)) {
109: return $namespace;
110: }
111: }
112: if (!empty($this->_any)) {
113: return $this->_any;
114: }
115: throw new Horde_Kolab_Storage_Exception(
116: sprintf('Namespace of folder %s cannot be determined.', $name)
117: );
118: }
119:
120: /**
121: * Return the owner of a folder.
122: *
123: * @param string $name The name of the folder.
124: *
125: * @return string The owner of the folder.
126: */
127: public function getOwner($name)
128: {
129: return $this->matchNamespace($name)->getOwner($name);
130: }
131:
132: /**
133: * Get the sub path for the given folder name.
134: *
135: * @param string $name The folder name.
136: *
137: * @return string The sub path.
138: */
139: public function getSubpath($name)
140: {
141: return $this->matchNamespace($name)->getSubpath($name);
142: }
143:
144: /**
145: * Get the parent for the given folder name.
146: *
147: * @param string $name The parent folder name.
148: *
149: * @return string The parent.
150: */
151: public function getParent($name)
152: {
153: return $this->matchNamespace($name)->getParent($name);
154: }
155:
156: /**
157: * Return the title of a folder.
158: *
159: * @param string $name The name of the folder.
160: *
161: * @return string The title of the folder.
162: */
163: public function getTitle($name)
164: {
165: return $this->matchNamespace($name)->getTitle($name);
166: }
167:
168: /**
169: * Construct the Kolab storage folder name based on the folder
170: * title and the owner.
171: *
172: * @param string $owner The owner of the folder.
173: * @param string $subpath The folder subpath.
174: * @param string $prefix The namespace prefix.
175: *
176: * @return string The folder name for the backend.
177: */
178: public function constructFolderName($owner, $subpath, $prefix = null)
179: {
180: if (empty($owner)) {
181: return $this->_getNamespace(self::SHARED, $prefix)
182: ->generatePath($subpath, $owner);
183: } else if ($owner == $this->user) {
184: return $this->_getNamespace(self::PERSONAL, $prefix)
185: ->generatePath($subpath, $owner);
186: } else {
187: return $this->_getNamespace(self::OTHER, $prefix)
188: ->generatePath($subpath, $owner);
189: }
190: }
191:
192: /**
193: * Generate an IMAP folder name in the personal namespace.
194: *
195: * @param string $title The new folder title.
196: *
197: * @return string The IMAP folder name.
198: */
199: public function setTitle($title)
200: {
201: return $this->_getNamespace(self::PERSONAL)
202: ->generateName(explode(':', $title));
203: }
204:
205: /**
206: * Generate an IMAP folder name in the other namespace.
207: *
208: * @param string $title The new folder title.
209: * @param string $owner The new owner of the folder.
210: *
211: * @return string The IMAP folder name.
212: */
213: public function setTitleInOther($title, $owner)
214: {
215: $path = explode(':', $title);
216: array_unshift($path, $owner);
217: return $this->_getNamespace(self::OTHER)->generateName($path);
218: }
219:
220: /**
221: * Generate an IMAP folder name in the shared namespace.
222: *
223: * @param string $title The new folder title.
224: *
225: * @return string The IMAP folder name.
226: */
227: public function setTitleInShared($title)
228: {
229: return $this->_getNamespace(self::SHARED)
230: ->generateName(explode(':', $title));
231: }
232:
233: /**
234: * Get the namespace matching the given type and (optional) prefix.
235: *
236: * @param string $type The namespace type.
237: * @param string $prefix The namespace prefix
238: *
239: * @return Horde_Kolab_Storage_Folder_Namespace_Element The namespace.
240: */
241: private function _getNamespace($type, $prefix = null)
242: {
243: $matching = array();
244: foreach ($this->_namespaces as $namespace) {
245: if ($namespace->getType() == $type &&
246: ($prefix === null || $namespace->getName() === $prefix)) {
247: $matching[] = $namespace;
248: }
249: }
250: if (count($matching) == 1) {
251: return $matching[0];
252: } else if (count($matching) > 1) {
253: throw new Horde_Kolab_Storage_Exception(
254: 'Multiple namespaces of the same type!'
255: );
256: } else {
257: throw new Horde_Kolab_Storage_Exception(
258: sprintf(
259: 'No namespace of the type %s%s!',
260: $type,
261: ($prefix !== null) ? ' with prefix \"' . $prefix . '\"' : ''
262: )
263: );
264: }
265: }
266:
267: /**
268: * Implementation of the Iterator rewind() method. Rewinds the namespace list.
269: *
270: * return NULL
271: */
272: public function rewind()
273: {
274: return reset($this->_namespaces);
275: }
276:
277: /**
278: * Implementation of the Iterator current(). Returns the current namespace.
279: *
280: * @return Horde_Kolab_Storage_Folder_Namespace_Element|null The current namespace.
281: */
282: public function current()
283: {
284: return current($this->_namespaces);
285: }
286:
287: /**
288: * Implementation of the Iterator key() method. Returns the key of the current namespace.
289: *
290: * @return mixed The key for the current position.
291: */
292: public function key()
293: {
294: return key($this->_namespaces);
295: }
296:
297: /**
298: * Implementation of the Iterator next() method. Returns the next namespace.
299: *
300: * @return Horde_Kolab_Storage_Folder_Namespace_Element|null The next
301: * namespace or null if there are no more namespaces.
302: */
303: public function next()
304: {
305: return next($this->_namespaces);
306: }
307:
308: /**
309: * Implementation of the Iterator valid() method. Indicates if the current element is a valid element.
310: *
311: * @return boolean Whether the current element is valid
312: */
313: public function valid()
314: {
315: return key($this->_namespaces) !== null;
316: }
317:
318: /**
319: * Convert the namespace description to a string.
320: *
321: * @return string The namespace description.
322: */
323: public function __toString()
324: {
325: return get_class($this) . ': ' . join(', ', $this->_namespaces);
326: }
327: }