1: <?php
  2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12: 
 13: class Horde_Vfs_Kolab extends Horde_Vfs_Base
 14: {
 15:      16:  17:  18:  19: 
 20:     protected $_imap = false;
 21: 
 22:      23:  24:  25:  26: 
 27:     protected $_folders;
 28: 
 29:      30:  31:  32:  33:  34:  35:  36:  37: 
 38:     public function read($path, $name)
 39:     {
 40:         list($app, $uid) = $this->_getAppUid($path);
 41:         if ($app && $uid) {
 42:             $handler = $this->_getAppHandler($app, $uid);
 43:             $object = $handler->getObject($uid);
 44: 
 45:             if (isset($object['_attachments'][$name])) {
 46:                 return $handler->getAttachment($object['_attachments'][$name]['key']);
 47:             }
 48:         }
 49: 
 50:         
 51:         if ($this->isFolder(dirname($path), basename($path))) {
 52:             $session = Horde_Kolab_Session::singleton();
 53:             $imap = $session->getImap();
 54: 
 55:             $result = $imap->select(substr($path,1));
 56:             if ($result instanceof PEAR_Error) {
 57:                 throw new Horde_Vfs_Exception($result->getMessage());
 58:             }
 59: 
 60:             $file = explode('/', $name);
 61: 
 62:             return $this->_getFile($imap, $file[0], $file[1]);
 63:         }
 64: 
 65:         return '';
 66:     }
 67: 
 68:      69:  70:  71:  72:  73:  74:  75:  76:  77:  78: 
 79:     public function write($path, $name, $tmpFile, $autocreate = false)
 80:     {
 81:         list($app, $uid) = $this->_getAppUid($path);
 82:         if ($app) {
 83:             $handler = $this->_getAppHandler($app, $uid);
 84:             $object = $handler->getObject($uid);
 85:             $object['_attachments'][$name]['path'] = $tmpFile;
 86:             if (empty($object['link-attachment'])) {
 87:                 $object['link-attachment'] = array($name);
 88:             } else {
 89:                 $object['link-attachment'][] = $name;
 90:             }
 91: 
 92:             return $handler->save($object, $uid);
 93:         }
 94: 
 95:         if ($autocreate && !$this->isFolder(dirname($path), basename($path))) {
 96:             $this->autocreatePath($path);
 97:         }
 98: 
 99:         
100:         throw new Horde_Vfs_Exception('Not supported.');
101:     }
102: 
103:     104: 105: 106: 107: 108: 109: 110: 
111:     public function deleteFile($path, $name)
112:     {
113:         list($app, $uid) = $this->_getAppUid($path);
114:         if ($app) {
115:             $handler = $this->_getAppHandler($app, $uid);
116:             $object = $handler->getObject($uid);
117:             if (!isset($object['_attachments'][$name])) {
118:                 throw new Horde_Vfs_Exception('Unable to delete VFS file.');
119:             }
120:             unset($object['_attachments'][$name]);
121:             $object['link-attachment'] = array_values(array_diff($object['link-attachment'], array($name)));
122: 
123:             return $handler->save($object, $uid);
124:         }
125: 
126:         
127:         throw new Horde_Vfs_Exception('Not supported.');
128:     }
129: 
130:     131: 132: 133: 134: 135: 136: 137: 
138:     public function createFolder($path, $name)
139:     {
140:         $list = Kolab_List::singleton();
141:         $folder = $this->_getFolder($path, $name);
142: 
143:         $object = $list->getNewFolder();
144:         $object->setName($folder);
145: 
146:         $object->save(array('type' => 'h-file'));
147:         if ($result instanceof PEAR_Error) {
148:             throw new Horde_Vfs_Exception($result->getMessage());
149:         }
150: 
151:         $this->_folders = null;
152:     }
153: 
154:      155: 156: 157: 158: 159: 160: 161: 162: 
163:     public function deleteFolder($path, $name, $recursive = false)
164:     {
165:         if ($recursive) {
166:             $this->emptyFolder($path . '/' . $name);
167:         } else {
168:             $list = $this->listFolder($path . '/' . $name, null, false);
169:             if (count($list)) {
170:                 throw new Horde_Vfs_Exception(sprintf('Unable to delete %s, the directory is not empty', $path . '/' . $name));
171:             }
172:         }
173: 
174:         list($app, $uid) = $this->_getAppUid($path . '/' . $name);
175:         if ($app) {
176:             177: 178: 
179:             return;
180:         }
181: 
182:         $folders = $this->_getFolders();
183:         $folder = $this->_getFolder($path, $name);
184: 
185:         if (!empty($folders['/' . $folder])) {
186:             $folders['/' . $folder]->delete();
187:             $this->_folders = null;
188:             return;
189:         }
190: 
191:         throw new Horde_Vfs_Exception(sprintf('No such folder %s!', '/' . $folder));
192:     }
193: 
194:     195: 196: 197: 198: 199: 200: 201: 
202:     public function emptyFolder($path)
203:     {
204:         
205:         $list = $this->listFolder($path, null, false, true);
206:         foreach ($list as $folder) {
207:             $this->deleteFolder($path, $folder['name'], true);
208:         }
209: 
210:         
211:         $list = $this->listFolder($path, null, false);
212:         foreach ($list as $file) {
213:             $this->deleteFile($path, $file['name']);
214:         }
215:     }
216: 
217:     218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 
228:     protected function _listFolder($path = '', $filter = null, $dotfiles = true,
229:                                    $dironly = false)
230:     {
231:         list($app, $uid) = $this->_getAppUid($path);
232:         if ($app) {
233:             if ($dironly) {
234:                 235: 236: 
237:                 return array();
238:             }
239:             if ($uid) {
240:                 $handler = $this->_getAppHandler($app, $uid);
241:                 $object = $handler->getObject($uid);
242:                 if ($object instanceof PEAR_Error) {
243:                     throw new Horde_Vfs_Exception($object->getMessage());
244:                 }
245: 
246:                 $filenames = isset($object['_attachments'])
247:                     ? array_keys($object['_attachments'])
248:                     : array();
249:             } else {
250:                 $filenames = $this->_getAppUids($app);
251:             }
252: 
253:             $owner = $GLOBALS['registry']->getAuth();
254: 
255:             $file = $files = array();
256:             foreach ($filenames as $filename) {
257:                 $name = explode('.', $filename);
258: 
259:                 if (count($name) == 1) {
260:                     $file['type'] = '**none';
261:                 } else {
262:                     $file['type'] = Horde_String::lower($name[count($name) - 1]);
263:                 }
264: 
265:                 $file['size'] = '-1';
266:                 $file['name'] = $filename;
267:                 $file['group'] = 'none';
268:                 $file['owner'] = $owner;
269:                 $file['date'] = 0;
270:                 $file['perms'] = 'rwxrwx---';
271: 
272:                 $files[$file['name']] = $file;
273:             }
274: 
275:             return $files;
276:         }
277: 
278:         $owner = $GLOBALS['registry']->getAuth();
279: 
280:         $file = $files = array();
281: 
282:         $folders = $this->listFolders($path, $filter, $dotfiles);
283:         $list = $this->_getFolders();
284: 
285:         foreach ($folders as $folder) {
286:             $file['type'] = '**dir';
287:             $file['size'] = -1;
288:             $file['name'] = $folder['abbrev'];
289:             
290:             $file['group'] = 'none';
291:             
292:             $file['owner'] = $owner;
293:             
294:             $file['date'] = 0;
295:             
296:             $file['perms'] = 'rwxrwx---';
297: 
298:             $files[$file['name']] = $file;
299:         }
300: 
301:         if (!$dironly &&
302:             $this->isFolder(basename($path), basename($path)) &&
303:             !empty($list[$path])) {
304:             $session = Horde_Kolab_Session::singleton();
305:             $imap = $session->getImap();
306: 
307:             $result = $imap->select(substr($path, 1));
308:             if ($result instanceof PEAR_Error) {
309:                 throw new Horde_Vfs_Exception($result->getMessage());
310:             }
311: 
312:             $uids = $imap->getUids();
313:             if ($uids instanceof PEAR_Error) {
314:                 throw new Horde_Vfs_Exception($uids->getMessage());
315:             }
316: 
317:             foreach ($uids as $uid) {
318:                 $result = array_merge($files, $this->_parseMessage($imap, $uid));
319:                 $files = $result;
320:             }
321:         }
322: 
323:         return $files;
324:     }
325: 
326:     327: 
328:     protected function _parseMessage($imap, $uid)
329:     {
330:         $result = $imap->getMessageHeader($uid);
331:         if ($result instanceof PEAR_Error) {
332:             throw new Horde_Vfs_Exception($result->getMessage());
333:         }
334: 
335:         $raw_headers = $result;
336: 
337:         $body = $imap->getMessageBody($uid);
338:         if ($body instanceof PEAR_Error) {
339:             throw new Horde_Vfs_Exception($body->getMessage());
340:         }
341: 
342:         $raw_message = $raw_headers . $body;
343: 
344:         $mime_message = Horde_Mime_Part::parseMessage($raw_message);
345:         $parts = $mime_message->contentTypeMap();
346: 
347:         $owner = $GLOBALS['registry']->getAuth();
348: 
349:         $file = $files = array();
350: 
351:         foreach ($parts as $part_id => $disposition) {
352:             $part = $mime_message->getPart($part_id);
353: 
354:             $filename = $part->getDispositionParameter('filename');
355: 
356:             if ($filename) {
357:                 $file['type'] = '**file';
358:                 $file['size'] = $part->getSize();
359:                 $file['name'] = $uid . '/' . $filename;
360:                 
361:                 $file['group'] = 'none';
362:                 
363:                 $file['owner'] = $owner;
364:                 
365:                 $file['date'] = 0;
366:                 
367:                 $file['perms'] = 'rwxrwx---';
368: 
369:                 $files[$file['name']] = $file;
370:             }
371: 
372:         }
373: 
374:         return $files;
375:     }
376: 
377:     378: 
379:     protected function _getFile($imap, $uid, $filename)
380:     {
381:         $result = $imap->getMessageHeader($uid);
382:         if ($result instanceof PEAR_Error) {
383:             throw new Horde_Vfs_Exception($result->getMessage());
384:         }
385: 
386:         $raw_headers = $result;
387: 
388:         $body = $imap->getMessageBody($uid);
389:         if ($body instanceof PEAR_Error) {
390:             throw new Horde_Vfs_Exception($body->getMessage());
391:         }
392: 
393:         $raw_message = $raw_headers . $body;
394: 
395:         $mime_message = Horde_Mime_Part::parseMessage($raw_message);
396:         $parts = $mime_message->contentTypeMap();
397: 
398:         $owner = $GLOBALS['registry']->getAuth();
399: 
400:         foreach ($parts as $part_id => $disposition) {
401:             $part = $mime_message->getPart($part_id);
402: 
403:             $f = $part->getDispositionParameter('filename');
404:             if ($f && $f == $filename) {
405:                 return $part->transferDecode();
406:             }
407:         }
408: 
409:         return '';
410:     }
411: 
412:     413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 
423:     public function listFolders($path = '', $filter = null, $dotfolders = true)
424:     {
425:         if (substr($path, -1) != '/') {
426:             $path .= '/';
427:         }
428: 
429:         $aFolder = $aFolders = array();
430: 
431:         if ($dotfolders && $path != '/') {
432:             $aFolder['val'] = dirname($path);
433:             $aFolder['abbrev'] = '..';
434:             $aFolder['label'] = '..';
435: 
436:             $aFolders[$aFolder['val']] = $aFolder;
437:         }
438: 
439:         $folders = $this->_getFolders();
440: 
441:         $base_len = strlen($path);
442:         foreach (array_keys($folders) as $folder) {
443:             if (substr($folder, 0, $base_len) == $path) {
444:                 $name = substr($folder, $base_len);
445:                 if (!strpos($name, '/')) {
446:                     $aFolder['val'] = $folder;
447:                     $aFolder['abbrev'] = $name;
448:                     $aFolder['label'] = $folder;
449:                     $aFolders[$aFolder['val']] = $aFolder;
450:                 }
451:             }
452:         }
453: 
454:         ksort($aFolders);
455:         return $aFolders;
456:     }
457: 
458:     459: 
460:     protected function _getFolder($path, $name)
461:     {
462:         $folder = $path . '/' . $name;
463: 
464:         while (substr($folder, 0, 1) == '/') {
465:             $folder = substr($folder, 1);
466:         }
467: 
468:         while (substr($folder, -1) == '/') {
469:             $folder = substr($folder, 0, -1);
470:         }
471: 
472:         return $folder;
473:     }
474: 
475:     476: 
477:     protected function _getFolders()
478:     {
479:         if (!isset($this->_folders)) {
480:             $vfs_folders = array();
481: 
482:             $list = Kolab_List::singleton();
483: 
484:             if (!empty($this->_params['all_folders'])) {
485:                 $folders = $list->getFolders();
486:             } else {
487:                 $folders = $list->getByType('h-file');
488:             }
489: 
490:             if ($folders instanceof PEAR_Error) {
491:                 throw new Horde_Vfs_Exception($folders->getMessage());
492:             }
493: 
494:             foreach ($folders as $folder) {
495:                 $vfs_folders['/' . $folder->name] = &$folder;
496:             }
497: 
498:             foreach (array_keys($vfs_folders) as $name) {
499:                 $dir = dirname($name);
500:                 while ($dir != '/') {
501:                     if (!isset($vfs_folders[$dir])) {
502:                         $vfs_folders[$dir] = null;
503:                     }
504:                     $dir = dirname($dir);
505:                 }
506:             }
507:             $this->_folders = $vfs_folders;
508:         }
509: 
510:         return $this->_folders;
511:     }
512: 
513:     514: 
515:     protected function _getAppUid($path)
516:     {
517:         if (defined('TURBA_VFS_PATH') &&
518:             substr($path, 0, strlen(TURBA_VFS_PATH)) == TURBA_VFS_PATH) {
519:             return array('turba', substr($path, strlen(TURBA_VFS_PATH) + 1));
520:         }
521: 
522:         return array(false, false);
523:     }
524: 
525:     526: 
527:     protected function _getAppHandler($app, $uid)
528:     {
529:         global $registry;
530: 
531:         switch ($app) {
532:         case 'turba':
533:             $sources = $registry->call('contacts/sources',
534:                                        array('writeable' => true));
535:             $fields = array();
536:             foreach (array_keys($sources) as $source) {
537:                 $fields[$source] = array('__uid');
538:             }
539:             $result = $registry->call('contacts/search',
540:                                       array('names' => $uid,
541:                                             'sources' => array_keys($sources),
542:                                             'fields' => $fields));
543:             if (!isset($result[$uid])) {
544:                 throw new Horde_Vfs_Exception('No such contact!');
545:             }
546:             $list = Kolab_List::singleton();
547:             $share = $list->getByShare($result[$uid][0]['source'], 'contact');
548:             if ($share instanceof PEAR_Error) {
549:                 throw new Horde_Vfs_Exception($share->getMessage());
550:             }
551:             return $share->getData();
552:         }
553:     }
554: 
555:     556: 
557:     protected function _getAppUids($app)
558:     {
559:         global $registry;
560: 
561:         switch ($app) {
562:         case 'turba':
563:             $sources = $registry->call('contacts/sources',
564:                                        array('writeable' => true));
565:             $result = $registry->call('contacts/search',
566:                                       array('names' => '',
567:                                             'sources' => array_keys($sources),
568:                                             'fields' => array()));
569:             $uids = array();
570:             foreach ($result[''] as $contact) {
571:                 if (isset($contact['__uid'])) {
572:                     $uids[] = $contact['__uid'];
573:                 }
574:             }
575:             return $uids;
576:         }
577:     }
578: 
579: }
580: