1: <?php
2: /**
3: * The base driver definition for accessing Kolab storage drivers.
4: *
5: * PHP version 5
6: *
7: * @category Kolab
8: * @package Kolab_Storage
9: * @author Gunnar Wrobel <wrobel@pardus.de>
10: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
11: * @link http://pear.horde.org/index.php?package=Kolab_Storage
12: */
13:
14: /**
15: * The base driver definition for accessing Kolab storage drivers.
16: *
17: * Copyright 2009-2012 Horde LLC (http://www.horde.org/)
18: *
19: * See the enclosed file COPYING for license information (LGPL). If you
20: * did not receive this file, see http://www.horde.org/licenses/lgpl21.
21: *
22: * @category Kolab
23: * @package Kolab_Storage
24: * @author Gunnar Wrobel <wrobel@pardus.de>
25: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
26: * @link http://pear.horde.org/index.php?package=Kolab_Storage
27: */
28: abstract class Horde_Kolab_Storage_Driver_Base
29: implements Horde_Kolab_Storage_Driver
30: {
31: /**
32: * Factory for generating helper objects.
33: *
34: * @var Horde_Kolab_Storage_Factory
35: */
36: private $_factory;
37:
38: /**
39: * Additional connection parameters.
40: *
41: * @var array
42: */
43: private $_params;
44:
45: /**
46: * Memory cache for the namespace of this driver.
47: *
48: * @var Horde_Kolab_Storage_Folder_Namespace
49: */
50: protected $_namespace;
51:
52: /**
53: * The backend to use.
54: *
55: * @var mixed
56: */
57: private $_backend;
58:
59: /**
60: * The parser used for reading data objects.
61: *
62: * @var Horde_Kolab_Storage_Data_Parser
63: */
64: private $_parser;
65:
66: /**
67: * Charset used by this driver.
68: *
69: * @var string
70: */
71: protected $charset = 'UTF7-IMAP';
72:
73: /**
74: * Constructor.
75: *
76: * @param Horde_Kolab_Storage_Factory $factory A factory for helper objects.
77: * @param array $params Connection parameters.
78: */
79: public function __construct(Horde_Kolab_Storage_Factory $factory,
80: $params = array())
81: {
82: $this->_factory = $factory;
83: if (isset($params['backend'])) {
84: $this->setBackend($params['backend']);
85: }
86: $this->_params = $params;
87: }
88:
89: /**
90: * Returns the actual backend driver.
91: *
92: * If there is no driver set the driver should be constructed within this
93: * method.
94: *
95: * @return mixed The backend driver.
96: */
97: public function getBackend()
98: {
99: if ($this->_backend === null) {
100: $this->_backend = $this->createBackend();
101: }
102: return $this->_backend;
103: }
104:
105: /**
106: * Set the backend driver.
107: *
108: * @param mixed $backend The driver that should be used.
109: *
110: * @return NULL
111: */
112: public function setBackend($backend)
113: {
114: $this->_backend = $backend;
115: }
116:
117: /**
118: * Returns the parser for data objects.
119: *
120: * @return Horde_Kolab_Storage_Data_Parser The parser.
121: */
122: public function getParser()
123: {
124: if ($this->_parser === null) {
125: throw new Horde_Kolab_Storage_Exception(
126: 'The parser has been left undefined!'
127: );
128: }
129: return $this->_parser;
130: }
131:
132: /**
133: * Set the data parser.
134: *
135: * @param mixed $parser The parser that should be used.
136: *
137: * @return NULL
138: */
139: public function setParser(Horde_Kolab_Storage_Data_Parser $parser)
140: {
141: $this->_parser = $parser;
142: }
143:
144: /**
145: * Return all parameter settings for this connection.
146: *
147: * @return array The parameters.
148: */
149: public function getParams()
150: {
151: return $this->_params;
152: }
153:
154: /**
155: * Return a parameter setting for this connection.
156: *
157: * @param string $key The parameter key.
158: * @param mixed $default An optional default value.
159: *
160: * @return mixed The parameter value.
161: */
162: public function getParam($key, $default = null)
163: {
164: return isset($this->_params[$key]) ? $this->_params[$key] : $default;
165: }
166:
167: /**
168: * Set a parameter setting for this connection.
169: *
170: * @param string $key The parameter key.
171: * @param mixed $value The parameter value.
172: *
173: * @return NULL
174: */
175: public function setParam($key, $value)
176: {
177: $this->_params[$key] = $value;
178: }
179:
180: /**
181: * Return the id of the user currently authenticated.
182: *
183: * @return string The id of the user that opened the IMAP connection.
184: */
185: public function getAuth()
186: {
187: return $this->getParam('username');
188: }
189:
190: /**
191: * Return the unique connection id.
192: *
193: * @return string The connection id.
194: */
195: public function getId()
196: {
197: return $this->getAuth() . '@'
198: . $this->getParam('host') . ':'
199: . $this->getParam('port');
200: }
201:
202: /**
203: * Return the connection parameters.
204: *
205: * @return array The connection parameters.
206: */
207: public function getParameters()
208: {
209: return array(
210: 'user' => $this->getAuth(),
211: 'host' => $this->getParam('host'),
212: 'port' => $this->getParam('port')
213: );
214: }
215:
216: /**
217: * Return the factory.
218: *
219: * @return Horde_Kolab_Storage_Factory The factory.
220: */
221: protected function getFactory()
222: {
223: return $this->_factory;
224: }
225:
226: /**
227: * Encode IMAP path names from UTF-8 to the driver charset.
228: *
229: * @param string $path The UTF-8 encoded path name.
230: *
231: * @return string The path name in the driver charset.
232: */
233: protected function encodePath($path)
234: {
235: return Horde_String::convertCharset($path, 'UTF-8', $this->charset);
236: }
237:
238: /**
239: * Decode IMAP path names from the driver charset to UTF-8.
240: *
241: * @param string $path The the driver charset encoded path name.
242: *
243: * @return string The path name in UTF-8.
244: */
245: protected function decodePath($path)
246: {
247: return Horde_String::convertCharset($path, $this->charset, 'UTF-8');
248: }
249:
250: /**
251: * Decode a list of IMAP path names from the driver charset to UTF-8.
252: *
253: * @param array $list The the driver charset encoded path names.
254: *
255: * @return array The path names in UTF-8.
256: */
257: protected function decodeList(array $list)
258: {
259: return array_map(array($this, 'decodePath'), $list);
260: }
261:
262: /**
263: * Decode the keys of a list of IMAP path names from the driver charset to
264: * UTF-8.
265: *
266: * @param array $list The list with the driver charset encoded path names as
267: * keys.
268: *
269: * @return array The list with path names in UTF-8 as keys.
270: */
271: protected function decodeListKeys(array $list)
272: {
273: $result = array();
274: foreach ($list as $key => $value) {
275: $result[$this->decodePath($key)] = $value;
276: }
277: return $result;
278: }
279:
280: /**
281: * Checks if the backend supports CATENATE.
282: *
283: * @return boolean True if the backend supports CATENATE.
284: */
285: public function hasCatenateSupport()
286: {
287: return false;
288: }
289:
290: /**
291: * Return a modifiable message object.
292: *
293: * @param string $folder The folder to access.
294: * @param string $obid The backend ID of the object to retrieve from the folder.
295: * @param array $object The object data.
296: *
297: * @return Horde_Kolab_Storage_Driver_Modifiable The modifiable message object.
298: */
299: public function getModifiable($folder, $obid, $object)
300: {
301: return new Horde_Kolab_Storage_Data_Modifiable(
302: $this, $folder, $this->fetchComplete($folder, $obid)
303: );
304: }
305:
306: /**
307: * Retrieve the namespace information for this connection.
308: *
309: * @return Horde_Kolab_Storage_Folder_Namespace The initialized namespace handler.
310: */
311: public function getNamespace()
312: {
313: if ($this->_namespace === null) {
314: if (isset($this->_params['namespaces'])) {
315: $this->_namespace = $this->_factory->createNamespace(
316: 'config', $this->getAuth(), $this->_params['namespaces']
317: );
318: } else {
319: $this->_namespace = $this->_factory->createNamespace(
320: 'fixed', $this->getAuth()
321: );
322: }
323: }
324: return $this->_namespace;
325: }
326:
327: /**
328: * Returns a stamp for the current folder status. This stamp can be used to
329: * identify changes in the folder data.
330: *
331: * @param string $folder Return the stamp for this folder.
332: *
333: * @return Horde_Kolab_Storage_Folder_Stamp A stamp indicating the current
334: * folder status.
335: */
336: public function getStamp($folder)
337: {
338: return new Horde_Kolab_Storage_Folder_Stamp_Uids(
339: $this->status($folder),
340: $this->getUids($folder)
341: );
342: }
343:
344: /**
345: * Fetches the objects for the specified UIDs.
346: *
347: * @param string $folder The folder to access.
348: * @param array $uids The message UIDs.
349: * @param array $options Additional options.
350: * <pre>
351: * - type - (string) The data type.
352: * - version - (int) The format version.
353: * - raw - (bool) Should the raw data be returned?
354: * </pre>
355: *
356: * @return array The objects.
357: */
358: public function fetch($folder, $uids, $options = array())
359: {
360: return $this->getParser()->fetch($folder, $uids, $options);
361: }
362:
363: /**
364: * Retrieves the messages for the given message ids.
365: *
366: * @param string $mailbox The mailbox to fetch the messages from.
367: * @param array $uids The message UIDs.
368: *
369: * @return Horde_Mime_Part The message structure parsed into a
370: * Horde_Mime_Part instance.
371: */
372: public function fetchStructure($mailbox, $uids)
373: {
374: throw new Horde_Kolab_Storage_Exception('"fetchStructure() not supported by this driver!');
375: }
376:
377: /**
378: * Retrieves a bodypart for the given message ID and mime part ID.
379: *
380: * @param string $mailbox The mailbox to fetch the messages from.
381: * @param array $uid The message UID.
382: * @param array $id The mime part ID.
383: *
384: * @return resource The body part, in a stream resource.
385: */
386: public function fetchBodypart($mailbox, $uid, $id)
387: {
388: throw new Horde_Kolab_Storage_Exception('"fetchBodypart() not supported by this driver!');
389: }
390:
391: /**
392: * Retrieves a complete message.
393: *
394: * @param string $folder The folder to fetch the messages from.
395: * @param array $uid The message UID.
396: *
397: * @return array The message encapsuled as an array that contains a
398: * Horde_Mime_Headers and a Horde_Mime_Part object.
399: */
400: public function fetchComplete($folder, $uid)
401: {
402: throw new Horde_Kolab_Storage_Exception('"fetchComplete() not supported by this driver!');
403: }
404: /**
405: * Split a name for the METADATA extension into the correct syntax for the
406: * older ANNOTATEMORE version.
407: *
408: * @param string $name A name for a metadata entry.
409: *
410: * @return array A list of two elements: The entry name and the value
411: * type.
412: * @throws Horde_Imap_Client_Exception
413: */
414: protected function _getAnnotateMoreEntry($name)
415: {
416: if (substr($name, 0, 7) == '/shared') {
417: return array(substr($name, 7), 'value.shared');
418: } else if (substr($name, 0, 8) == '/private') {
419: return array(substr($name, 8), 'value.priv');
420: }
421:
422: $this->_exception('Invalid METADATA entry: ' . $name);
423: }
424:
425: }