Overview

Packages

  • Kolab
    • Storage

Classes

  • Horde_Kolab_Storage_Base
  • Horde_Kolab_Storage_Cache
  • Horde_Kolab_Storage_Cache_Data
  • Horde_Kolab_Storage_Cache_List
  • Horde_Kolab_Storage_Cached
  • Horde_Kolab_Storage_Data_Base
  • Horde_Kolab_Storage_Data_Cached
  • Horde_Kolab_Storage_Data_Decorator_Log
  • Horde_Kolab_Storage_Data_Format_Mime
  • Horde_Kolab_Storage_Data_Modifiable
  • Horde_Kolab_Storage_Data_Old
  • Horde_Kolab_Storage_Data_Parser_Structure
  • Horde_Kolab_Storage_Data_Query_History_Base
  • Horde_Kolab_Storage_Data_Query_History_Cache
  • Horde_Kolab_Storage_Data_Query_Preferences_Base
  • Horde_Kolab_Storage_Data_Query_Preferences_Cache
  • Horde_Kolab_Storage_Decorator_Synchronization
  • Horde_Kolab_Storage_Driver_Base
  • Horde_Kolab_Storage_Driver_Cclient
  • Horde_Kolab_Storage_Driver_Decorator_Base
  • Horde_Kolab_Storage_Driver_Decorator_Log
  • Horde_Kolab_Storage_Driver_Decorator_Timer
  • Horde_Kolab_Storage_Driver_Imap
  • Horde_Kolab_Storage_Driver_Mock
  • Horde_Kolab_Storage_Driver_Mock_Data
  • Horde_Kolab_Storage_Driver_Pear
  • Horde_Kolab_Storage_Driver_Rcube
  • Horde_Kolab_Storage_Exception
  • Horde_Kolab_Storage_Exception_Pear
  • Horde_Kolab_Storage_Factory
  • Horde_Kolab_Storage_Folder_Base
  • Horde_Kolab_Storage_Folder_Decorator_Base
  • Horde_Kolab_Storage_Folder_Decorator_Trigger
  • Horde_Kolab_Storage_Folder_Namespace
  • Horde_Kolab_Storage_Folder_Namespace_Config
  • Horde_Kolab_Storage_Folder_Namespace_Element
  • Horde_Kolab_Storage_Folder_Namespace_Element_Other
  • Horde_Kolab_Storage_Folder_Namespace_Element_Personal
  • Horde_Kolab_Storage_Folder_Namespace_Element_Shared
  • Horde_Kolab_Storage_Folder_Namespace_Element_SharedWithPrefix
  • Horde_Kolab_Storage_Folder_Namespace_Fixed
  • Horde_Kolab_Storage_Folder_Namespace_Imap
  • Horde_Kolab_Storage_Folder_Stamp_Uids
  • Horde_Kolab_Storage_Folder_Type
  • Horde_Kolab_Storage_List_Base
  • Horde_Kolab_Storage_List_Decorator_Cache
  • Horde_Kolab_Storage_List_Decorator_Log
  • Horde_Kolab_Storage_List_Query_Acl_Base
  • Horde_Kolab_Storage_List_Query_Acl_Cache
  • Horde_Kolab_Storage_List_Query_ActiveSync_Base
  • Horde_Kolab_Storage_List_Query_ActiveSync_Cache
  • Horde_Kolab_Storage_List_Query_List_Base
  • Horde_Kolab_Storage_List_Query_List_Cache
  • Horde_Kolab_Storage_List_Query_Share_Base
  • Horde_Kolab_Storage_List_Query_Share_Cache
  • Horde_Kolab_Storage_QuerySet_Base
  • Horde_Kolab_Storage_QuerySet_Cached
  • Horde_Kolab_Storage_QuerySet_Uncached
  • Horde_Kolab_Storage_Synchronization
  • Horde_Kolab_Storage_Translation
  • Horde_Kolab_Storage_Uncached

Interfaces

  • Horde_Kolab_Storage
  • Horde_Kolab_Storage_Data
  • Horde_Kolab_Storage_Data_Format
  • Horde_Kolab_Storage_Data_Parser
  • Horde_Kolab_Storage_Data_Query
  • Horde_Kolab_Storage_Data_Query_History
  • Horde_Kolab_Storage_Data_Query_Preferences
  • Horde_Kolab_Storage_Driver
  • Horde_Kolab_Storage_Folder
  • Horde_Kolab_Storage_Folder_Stamp
  • Horde_Kolab_Storage_List
  • Horde_Kolab_Storage_List_Query
  • Horde_Kolab_Storage_List_Query_Acl
  • Horde_Kolab_Storage_List_Query_ActiveSync
  • Horde_Kolab_Storage_List_Query_List
  • Horde_Kolab_Storage_List_Query_Share
  • Horde_Kolab_Storage_Queriable
  • Horde_Kolab_Storage_Query
  • Horde_Kolab_Storage_QuerySet
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Handles data objects in a Kolab storage folder.
  4:  *
  5:  * PHP version 5
  6:  *
  7:  * @category Kolab
  8:  * @package  Kolab_Storage
  9:  * @author   Stuart Binge <omicron@mighty.co.za>
 10:  * @author   Thomas Jarosch <thomas.jarosch@intra2net.com>
 11:  * @author   Gunnar Wrobel <wrobel@pardus.de>
 12:  * @license  http://www.horde.org/licenses/lgpl21 LGPL 2.1
 13:  * @link     http://pear.horde.org/index.php?package=Kolab_Storage
 14:  */
 15: 
 16: /**
 17:  * The Kolab_Data class represents a data type in a Kolab storage
 18:  * folder on the Kolab server.
 19:  *
 20:  * Copyright 2009-2012 Horde LLC (http://www.horde.org/)
 21:  *
 22:  * See the enclosed file COPYING for license information (LGPL). If you
 23:  * did not receive this file, see http://www.horde.org/licenses/lgpl21.
 24:  *
 25:  * @category Kolab
 26:  * @package  Kolab_Storage
 27:  * @author   Stuart Binge <omicron@mighty.co.za>
 28:  * @author   Thomas Jarosch <thomas.jarosch@intra2net.com>
 29:  * @author   Gunnar Wrobel <wrobel@pardus.de>
 30:  * @license  http://www.horde.org/licenses/lgpl21 LGPL 2.1
 31:  * @link     http://pear.horde.org/index.php?package=Kolab_Storage
 32:  */
 33: class Horde_Kolab_Storage_Data_Old
 34: {
 35:     /**
 36:      * The link to the parent folder object.
 37:      *
 38:      * @var Kolab_Folder
 39:      */
 40:     private $_folder;
 41: 
 42:     /**
 43:      * The folder type.
 44:      *
 45:      * @var string
 46:      */
 47:     private $_type;
 48: 
 49:     /**
 50:      * The driver for accessing the Kolab storage system.
 51:      *
 52:      * @var Horde_Kolab_Storage_Driver
 53:      */
 54:     private $_driver;
 55: 
 56:     /**
 57:      * The factory for generating additional resources.
 58:      *
 59:      * @var Horde_Kolab_Storage_Factory
 60:      */
 61:     private $_factory;
 62: 
 63:     /**
 64:      * The object type of the data.
 65:      *
 66:      * @var string
 67:      */
 68:     private $_object_type;
 69: 
 70:     /**
 71:      * The version of the data.
 72:      *
 73:      * @var int
 74:      */
 75:     private $_data_version;
 76: 
 77:     /**
 78:      * The data cache.
 79:      *
 80:      * @var Kolab_Cache
 81:      */
 82:     private $_cache;
 83: 
 84:     /**
 85:      * The Id of this data object in the cache.
 86:      *
 87:      * @var string
 88:      */
 89:     private $_cache_key;
 90: 
 91:     /**
 92:      * An addition to the cache key in case we are operating on
 93:      * something other than the default type.
 94:      *
 95:      * @var string
 96:      */
 97:     private $_type_key;
 98: 
 99:     /**
100:      * Do we optimize for cyrus IMAPD?
101:      *
102:      * @var boolean
103:      */
104:     private $_cache_cyrus_optimize = true;
105: 
106:     /**
107:      * Creates a Kolab Folder Data representation.
108:      *
109:      * @param string $folder       Name/ID of the folder.
110:      * @param string $type         Type of the folder.
111:      * @param Horde_Kolab_Storage_Driver      $driver  The primary connection driver.
112:      * @param Horde_Kolab_Storage_Factory     $factory The factory.
113:      * @param string $object_type  Type of the objects we want to read.
114:      * @param int    $data_version Format version of the object data.
115:      */
116:     public function __construct($folder, $type, $driver, $factory, $object_type = null, $data_version = 1)
117:     {
118:         $this->_type = $type;
119:         if (!empty($object_type)) {
120:             $this->_object_type = $object_type;
121:         } else {
122:             $this->_object_type = $type;
123:         }
124:         $this->_data_version = $data_version;
125: 
126:         if ($this->_object_type != $this->_type) {
127:             $this->_type_key = '@' . $this->_object_type;
128:         } else {
129:             $this->_type_key = '';
130:         }
131:     }
132: 
133:     /**
134:      * Delete the specified message from this folder.
135:      *
136:      * @param string $object_uid Id of the message to be deleted.
137:      *
138:      * @return boolean|PEAR_Error True is successful, false if the
139:      *                            message does not exist.
140:      */
141:     public function delete($object_uid)
142:     {
143:         if (!$this->objectUidExists($object_uid)) {
144:             return false;
145:         }
146: 
147:         // Find the storage ID
148:         $id = $this->getStorageId($object_uid);
149:         if ($id === false) {
150:             return false;
151:         }
152: 
153:         $result = $this->_folder->deleteMessage($id);
154:         if (is_a($result, 'PEAR_Error')) {
155:             return $result;
156:         }
157: 
158:         unset($this->_cache->objects[$object_uid]);
159:         unset($this->_cache->uids[$id]);
160:         $this->_cache->save();
161:         return true;
162:     }
163: 
164:     /**
165:      * Delete all messages from the current folder.
166:      *
167:      * @return boolean|PEAR_Error True if successful.
168:      */
169:     public function deleteAll()
170:     {
171:         $this->_cache->load($this->_cache_key, $this->_data_version);
172: 
173:         if (empty($this->_cache->uids)) {
174:             return true;
175:         }
176:         foreach ($this->_cache->uids as $id => $object_uid) {
177:             $this->_folder->deleteMessage($id, false);
178: 
179:             unset($this->_cache->objects[$object_uid]);
180:             unset($this->_cache->uids[$id]);
181:         }
182:         $this->_cache->save();
183: 
184:         $result = $this->_folder->trigger();
185:         if (is_a($result, 'PEAR_Error')) {
186:             Horde::logMessage(sprintf('Failed triggering folder %s!',
187:                                       $this->_folder->name), 'ERR');
188:         }
189: 
190:         return true;
191:     }
192: 
193:     /**
194:      * Move the specified message from the current folder into a new
195:      * folder.
196:      *
197:      * @param string $object_uid ID of the message to be deleted.
198:      * @param string $new_share  ID of the target share.
199:      *
200:      * @return boolean|PEAR_Error True is successful, false if the
201:      *                            object does not exist.
202:      */
203:     public function move($object_uid, $new_share)
204:     {
205:         if (!$this->objectUidExists($object_uid)) {
206:             return false;
207:         }
208: 
209:         // Find the storage ID
210:         $id = $this->getStorageId($object_uid);
211:         if ($id === false) {
212:             return false;
213:         }
214: 
215:         $result = $this->_folder->moveMessageToShare($id, $new_share);
216: 
217:         unset($this->_cache->objects[$object_uid]);
218:         unset($this->_cache->uids[$id]);
219:         $this->_cache->save();
220:         return true;
221:     }
222: 
223:     /**
224:      * Save an object.
225:      *
226:      * @param array  $object        The array that holds the data object.
227:      * @param string $old_object_id The id of the object if it existed before.
228:      *
229:      * @return boolean True on success.
230:      *
231:      * @throws Horde_Kolab_Storage_Exception In case the given old object id
232:      *                                       is invalid or an error occured
233:      *                                       while saving the data.
234:      */
235:     public function save($object, $old_object_id = null)
236:     {
237:         // update existing kolab object
238:         if ($old_object_id != null) {
239:             // check if object really exists
240:             if (!$this->objectUidExists($old_object_id)) {
241:                 throw new Horde_Kolab_Storage_Exception(sprintf(Horde_Kolab_Storage_Translation::t("Old object %s does not exist."),
242:                                                                 $old_object_id));
243:             }
244: 
245:             // get the storage ID
246:             $id = $this->getStorageId($old_object_id);
247:             if ($id === false) {
248:                 throw new Horde_Kolab_Storage_Exception(sprintf(Horde_Kolab_Storage_Translation::t("Old object %s does not map to a uid."),
249:                                                                 $old_object_id));
250:             }
251: 
252:             $old_object = $this->getObject($old_object_id);
253:         } else {
254:             $id         = null;
255:             $old_object = null;
256:         }
257: 
258:         $this->_folder->saveObject($object, $this->_data_version,
259:                                    $this->_object_type, $id, $old_object);
260: 
261:         $this->synchronize($old_object_id);
262:         return true;
263:     }
264: 
265:     /**
266:      * Synchronize the data cache for the current folder.
267:      *
268:      * @param string $history_ignore Object uid that should not be
269:      *                               updated in the History
270:      *
271:      * @return NULL
272:      */
273:     public function synchronize($history_ignore = null)
274:     {
275:         $this->_cache->load($this->_cache_key, $this->_data_version);
276: 
277:         $result = $this->_folder->getStatus();
278: 
279:         list($validity, $nextid, $ids) = $result;
280: 
281:         $changes = $this->_folderChanged($validity, $nextid,
282:                                          array_keys($this->_cache->uids), $ids);
283:         if ($changes) {
284:             $modified = array();
285: 
286:             $recent_uids = array_diff($ids, array_keys($this->_cache->uids));
287: 
288:             $formats = $this->_folder->getFormats();
289: 
290:             $handler = Horde_Kolab_Format::factory('Xml', $this->_object_type,
291:                                                    $this->_data_version);
292: 
293:             $count = 0;
294:             foreach ($recent_uids as $id) {
295: 
296:                 if ($this->_type == 'annotation' && $id != 1) {
297:                     continue;
298:                 }
299: 
300:                 try {
301:                     $mime = $this->_folder->parseMessage($id,
302:                                                          $handler->getMimeType(),
303:                                                          false);
304:                     $text = $mime[0];
305:                 } catch (Horde_Kolab_Storage_Exception $e) {
306:                     Horde::logMessage($mime, 'WARN');
307:                     $text = false;
308:                 }
309: 
310:                 if ($text) {
311:                     $object = $handler->load($text);
312:                     if (is_a($object, 'PEAR_Error')) {
313:                         $this->_cache->ignore($id);
314:                         $object->addUserInfo('STORAGE ID: ' . $id);
315:                         Horde::logMessage($object, 'WARN');
316:                         continue;
317:                     }
318:                 } else {
319:                     $object = false;
320:                 }
321: 
322:                 if ($object !== false) {
323:                     $message      = &$mime[2];
324:                     $handler_type = $handler->getMimeType();
325:                     foreach ($message->getParts() as $part) {
326:                         $name = $part->getName();
327:                         $type = $part->getType();
328:                         $dp   = $part->getDispositionParameter('x-kolab-type');
329:                         if (!empty($name) && $type != $handler_type
330:                             || (!empty($dp) && in_array($dp, $formats))) {
331:                             $object['_attachments'][$name]['type'] = $type;
332:                             $object['_attachments'][$name]['key']  = $this->_cache_key . '/' . $object['uid'] . ':' . $name;
333:                             //@todo: Check what to do with this call
334:                             //$part->transferDecodeContents();
335:                             $result = $this->_cache->storeAttachment($object['_attachments'][$name]['key'],
336:                                                                      $part->getContents());
337:                             if (is_a($result, 'PEAR_Error')) {
338:                                 Horde::logMessage(sprintf('Failed storing attachment of object %s: %s',
339:                                                           $id,
340:                                                           $result->getMessage()), 'ERR');
341:                                 $object = false;
342:                                 break;
343:                             }
344:                         }
345:                     }
346:                 }
347: 
348:                 if ($object !== false) {
349:                     $this->_cache->store($id, $object['uid'], $object);
350:                     $mod_ts = time();
351:                     if (is_array($changes) && in_array($object['uid'], $changes)
352:                         && $object['uid'] != $history_ignore) {
353:                         $this->_updateHistory($object['uid'], $mod_ts, 'modify');
354:                         $modified[] = $object['uid'];
355:                     } else {
356:                         $this->_updateHistory($object['uid'], $mod_ts, 'add');
357:                     }
358:                 } else {
359:                     $this->_cache->ignore($id);
360:                 }
361: 
362:                 // write out cache once in a while so if the browser times out
363:                 // we don't have to start from the beginning.
364:                 if ($count > 500) {
365:                     $count = 0;
366:                     $this->_cache->save();
367:                 }
368:                 $count++;
369:             }
370: 
371:             $this->_cache->save();
372: 
373:             if (is_array($changes)) {
374:                 $deleted = array_diff($changes, $modified);
375:                 foreach ($deleted as $deleted_oid) {
376:                     if ($deleted_oid != $history_ignore) {
377:                         $this->_updateHistory($deleted_oid, time(), 'delete');
378:                     }
379:                 }
380:             }
381:         }
382:     }
383: 
384:     /**
385:      * Update the Horde history in case an element was modified
386:      * outside of Horde.
387:      *
388:      * @param string $object_uid Object uid that should be updated.
389:      * @param int    $mod_ts     Timestamp of the modification.
390:      * @param string $action     The action that was performed.
391:      *
392:      * @return NULL
393:      */
394:     private function _updateHistory($object_uid, $mod_ts, $action)
395:     {
396:         global $registry;
397: 
398:         if (!isset($registry)) {
399:             return;
400:         }
401: 
402:         $app = $registry->getApp();
403:         if (empty($app) || is_a($app, 'PEAR_Error')) {
404:             /**
405:              * Ignore the history if we are not in application
406:              * context.
407:              */
408:             return $app;
409:         }
410: 
411:         if (!class_exists('Horde_History')) {
412:             return;
413:         }
414: 
415:         /* Log the action on this item in the history log. */
416:         try {
417:             $GLOBALS['injector']->getInstance('Horde_History')
418:                 ->log($app . ':' . $this->_folder->getShareId() . ':' . $object_uid,
419:                       array('action' => $action, 'ts' => $mod_ts),
420:                       true);
421:         } catch (Horde_Exception $e) {
422:         }
423:     }
424: 
425: 
426:     /**
427:      * Test if the storage ID exists.
428:      *
429:      * @param int $uid The storage ID.
430:      *
431:      * @return boolean True if the ID exists.
432:      */
433:     public function storageIdExists($uid)
434:     {
435:         $this->_cache->load($this->_cache_key, $this->_data_version);
436: 
437:         return array_key_exists($uid, $this->_cache->uids);
438:     }
439: 
440:     /**
441:      * Generate a unique object id.
442:      *
443:      * @return string  The unique id.
444:      */
445:     public function generateUID()
446:     {
447:         do {
448:             $key = md5(uniqid(mt_rand(), true));
449:         } while ($this->objectUidExists($key));
450: 
451:         return $key;
452:     }
453: 
454:     /**
455:      * Return the specified attachment.
456:      *
457:      * @param string $attachment_id The attachment id.
458:      *
459:      * @return string|PEAR_Error  The attachment data as a string.
460:      */
461:     public function getAttachment($attachment_id)
462:     {
463:         $this->_cache->load($this->_cache_key, $this->_data_version);
464: 
465:         return $this->_cache->loadAttachment($attachment_id);
466:     }
467: 
468:     /**
469:      * Retrieve all objects in the current folder as an array.
470:      *
471:      * @return array  The object data array.
472:      */
473:     public function getObjectArray()
474:     {
475:         $this->_cache->load($this->_cache_key, $this->_data_version);
476: 
477:         return $this->_cache->objects;
478:     }
479: }
480: 
API documentation generated by ApiGen