1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
21: class IMP_Imap_Tree implements ArrayAccess, Countable, Iterator, Serializable
22: {
23:
24: const VERSION = 1;
25:
26:
27: const ELT_NOSELECT = 1;
28: const ELT_NAMESPACE = 2;
29: const ELT_IS_OPEN = 4;
30: const ELT_IS_SUBSCRIBED = 8;
31:
32: const ELT_IS_POLLED = 32;
33: const ELT_NEED_SORT = 64;
34: const ELT_VFOLDER = 128;
35: const ELT_NONIMAP = 256;
36: const ELT_INVISIBLE = 512;
37:
38:
39: const OPEN_NONE = 0;
40: const OPEN_ALL = 1;
41: const OPEN_USER = 2;
42:
43:
44: const FLIST_NOCONTAINER = 1;
45: const FLIST_UNSUB = 2;
46: const FLIST_VFOLDER = 4;
47: const FLIST_NOCHILDREN = 8;
48: const FLIST_EXPANDED = 16;
49: const FLIST_ANCESTORS = 32;
50: const FLIST_SAMELEVEL = 64;
51: const FLIST_NOBASE = 128;
52: const FLIST_ASIS = 256;
53:
54: 55: 56:
57: const BASE_ELT = "base\0";
58:
59: 60:
61: const VFOLDER_KEY = "vfolder\0";
62:
63:
64: const SHARED_KEY = "shared\0";
65: const OTHER_KEY = "other\0";
66:
67: 68: 69: 70: 71:
72: public $changed = false;
73:
74: 75: 76: 77: 78:
79: public $unseen = 0;
80:
81: 82: 83: 84: 85:
86: protected $_tree;
87:
88: 89: 90: 91: 92:
93: protected $_currparent;
94:
95: 96: 97: 98: 99:
100: protected $_currkey;
101:
102: 103: 104: 105: 106:
107: protected $_showunsub;
108:
109: 110: 111: 112: 113:
114: protected $_parent;
115:
116: 117: 118: 119: 120:
121: protected $_delimiter;
122:
123: 124: 125: 126: 127:
128: protected $_namespaces;
129:
130: 131: 132: 133: 134:
135: protected $_eltdiff = null;
136:
137: 138: 139: 140: 141:
142: protected $_cache = array(
143: 'filter' => array(
144: 'base' => null,
145: 'mask' => 0
146: )
147: );
148:
149: 150: 151:
152: public function __construct()
153: {
154: $this->init();
155: }
156:
157: 158: 159:
160: public function init()
161: {
162: global $conf, $injector, $prefs, $session;
163:
164: $imp_imap = $injector->getInstance('IMP_Factory_Imap')->create();
165:
166: $unsubmode = (!$imp_imap->access(IMP_Imap::ACCESS_FOLDERS) ||
167: !$prefs->getValue('subscribe') ||
168: $session->get('imp', 'showunsub'));
169:
170:
171: $this->changed = true;
172: $this->_currkey = $this->_currparent = null;
173: $this->_delimiter = null;
174: $this->_namespaces = $this->_parent = $this->_tree = array();
175: $this->_showunsub = $unsubmode;
176: unset($this->_cache['fulllist'], $this->_cache['subscribed']);
177:
178:
179: if ($imp_imap->imap) {
180: $ns = $imp_imap->getNamespaceList();
181: $ptr = reset($ns);
182: $this->_delimiter = $ptr['delimiter'];
183: if ($imp_imap->access(IMP_Imap::ACCESS_FOLDERS)) {
184: $this->_namespaces = $ns;
185: }
186: }
187:
188: 189:
190: $this->_tree[self::BASE_ELT] = array(
191: 'a' => self::ELT_NEED_SORT,
192: 'v' => self::BASE_ELT
193: );
194:
195: 196:
197: if (!$imp_imap->access(IMP_Imap::ACCESS_FOLDERS)) {
198: $this->_insertElt($this->_makeElt('INBOX', self::ELT_IS_SUBSCRIBED));
199: return;
200: }
201:
202:
203: if ($prefs->getValue('tree_view')) {
204: foreach ($this->_namespaces as $val) {
205: $type = null;
206:
207: switch ($val['type']) {
208: case Horde_Imap_Client::NS_OTHER:
209: $type = self::OTHER_KEY;
210: break;
211:
212: case Horde_Imap_Client::NS_SHARED:
213: $type = self::SHARED_KEY;
214: break;
215: }
216:
217: if (!is_null($type) && !isset($this->_tree[$type])) {
218: $this->_insertElt($this->_makeElt(
219: $type,
220: self::ELT_NOSELECT | self::ELT_NAMESPACE | self::ELT_NONIMAP
221: ));
222: }
223: }
224: }
225:
226:
227: $this->_insert($this->_getList($this->_showunsub), $this->_showunsub ? null : true);
228:
229:
230: $imp_search = $injector->getInstance('IMP_Search');
231: $imp_search->setIteratorFilter(IMP_Search::LIST_VFOLDER);
232: $this->updateVFolders(iterator_to_array($imp_search));
233: }
234:
235: 236: 237: 238: 239: 240: 241: 242:
243: protected function _getList($showunsub)
244: {
245: if ($showunsub && isset($this->_cache['fulllist'])) {
246: return $this->_cache['fulllist'];
247: } elseif (!$showunsub && isset($this->_cache['subscribed'])) {
248: return $this->_cache['subscribed'];
249: }
250:
251: $searches = array();
252: foreach (array_keys($this->_namespaces) as $val) {
253: $searches[] = $val . '*';
254: }
255:
256: $imp_imap = $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create();
257: $result = $imp_imap->listMailboxes($searches, $showunsub ? Horde_Imap_Client::MBOX_ALL : Horde_Imap_Client::MBOX_SUBSCRIBED_EXISTS, array('attributes' => true, 'delimiter' => true, 'sort' => true));
258:
259:
260: if (empty($result['INBOX'])) {
261: $result = $imp_imap->listMailboxes('INBOX', Horde_Imap_Client::MBOX_ALL, array('attributes' => true, 'delimiter' => true)) + $result;
262: }
263:
264: $tmp = array();
265: foreach ($result as $val) {
266: $tmp[strval($val['mailbox'])] = $val;
267: }
268: $this->_cache[$showunsub ? 'fulllist' : 'subscribed'] = $tmp;
269:
270: return $result;
271: }
272:
273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287:
288: protected function _makeElt($name, $attributes = 0)
289: {
290: $elt = array(
291: 'a' => $attributes,
292: 'c' => 0,
293: 'p' => self::BASE_ELT,
294: 'v' => strval($name)
295: );
296:
297:
298: $this->_initPollList();
299: $this->_setPolled($elt, isset($this->_cache['poll'][$name]));
300:
301:
302: switch ($GLOBALS['prefs']->getValue('nav_expanded')) {
303: case self::OPEN_NONE:
304: $open = false;
305: break;
306:
307: case self::OPEN_ALL:
308: $open = true;
309: break;
310:
311: case self::OPEN_USER:
312: $this->_initExpandedList();
313: $open = !empty($this->_cache['expanded'][$name]);
314: break;
315: }
316: $this->_setOpen($elt, $open);
317:
318: if (is_null($this->_delimiter)) {
319: $elt['c'] = 0;
320: return $elt;
321: }
322:
323: $ns_info = $this->_getNamespace($name);
324: $delimiter = is_null($ns_info)
325: ? $this->_delimiter
326: : $ns_info['delimiter'];
327: $tmp = explode($delimiter, $name);
328: $elt['c'] = count($tmp) - 1;
329:
330: try {
331: $this->_setInvisible($elt, !Horde::callHook('display_folder', array($elt['v']), 'imp'));
332: } catch (Horde_Exception_HookNotSet $e) {}
333:
334: if ($elt['c'] != 0) {
335: $elt['p'] = implode(is_null($ns_info) ? $this->_delimiter : $ns_info['delimiter'], array_slice($tmp, 0, $elt['c']));
336: }
337:
338: if (is_null($ns_info)) {
339: return $elt;
340: }
341:
342: switch ($ns_info['type']) {
343: case Horde_Imap_Client::NS_PERSONAL:
344:
345: if (!empty($ns_info['name']) && ($elt['c'] != 0)) {
346: --$elt['c'];
347: if (strpos($elt['p'], $ns_info['delimiter']) === false) {
348: $elt['p'] = self::BASE_ELT;
349: } elseif (strpos($elt['v'], $ns_info['name'] . 'INBOX' . $ns_info['delimiter']) === 0) {
350: $elt['p'] = 'INBOX';
351: }
352: }
353: break;
354:
355: case Horde_Imap_Client::NS_OTHER:
356: case Horde_Imap_Client::NS_SHARED:
357: if (substr($ns_info['name'], 0, -1 * strlen($ns_info['delimiter'])) == $elt['v']) {
358: $elt['a'] = self::ELT_NOSELECT | self::ELT_NAMESPACE;
359: }
360:
361: if ($GLOBALS['prefs']->getValue('tree_view')) {
362:
363: if ($this->isNamespace($elt)) {
364: return false;
365: }
366:
367: if ($elt['c'] == 1) {
368: $elt['p'] = ($ns_info['type'] == Horde_Imap_Client::NS_OTHER)
369: ? self::OTHER_KEY
370: : self::SHARED_KEY;
371: }
372: }
373: break;
374: }
375:
376: return $elt;
377: }
378:
379: 380: 381: 382: 383: 384:
385: public function expand($folder, $expandall = false)
386: {
387: $folder = $this->_convertName($folder);
388:
389: if (!isset($this->_tree[$folder])) {
390: return;
391: }
392: $elt = &$this->_tree[$folder];
393:
394: if ($this->hasChildren($elt)) {
395: if (!$this->isOpen($elt)) {
396: $this->changed = true;
397: $this->_setOpen($elt, true);
398: }
399:
400:
401: if ($expandall && !empty($this->_parent[$folder])) {
402: foreach ($this->_parent[$folder] as $val) {
403: $this->expand($this->_tree[$val]['v'], true);
404: }
405: }
406: }
407: }
408:
409: 410: 411: 412: 413:
414: public function collapse($folder)
415: {
416: $folder = $this->_convertName($folder);
417:
418: if (isset($this->_tree[$folder])) {
419: $this->changed = true;
420: $this->_setOpen($this->_tree[$folder], false);
421: }
422: }
423:
424: 425: 426: 427: 428: 429:
430: public function insert($id)
431: {
432: if (is_array($id)) {
433: 434:
435: $this->_sortList($id);
436: } else {
437: $id = array($id);
438: }
439:
440:
441: reset($id);
442: while (list($key, $val) = each($id)) {
443: if (strpos($val, self::VFOLDER_KEY) === 0) {
444: if (!isset($this->_tree[$val])) {
445: if (!isset($this->_tree[self::VFOLDER_KEY])) {
446: $elt = $this->_makeElt(self::VFOLDER_KEY, self::ELT_VFOLDER | self::ELT_NOSELECT | self::ELT_NONIMAP);
447: $this->_insertElt($elt);
448: }
449:
450: $elt = $this->_makeElt($val, self::ELT_VFOLDER | self::ELT_IS_SUBSCRIBED | self::ELT_NONIMAP);
451: $elt['v'] = Horde_String::substr($val, Horde_String::length(self::VFOLDER_KEY) + Horde_String::length($this->_delimiter));
452: $this->_insertElt($elt);
453: }
454:
455: unset($id[$key]);
456: }
457: }
458:
459: if (!empty($id)) {
460: try {
461: $this->_insert($GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create()->listMailboxes($id, Horde_Imap_Client::MBOX_ALL, array('attributes' => true, 'delimiter' => true, 'sort' => true)));
462: } catch (IMP_Imap_Exception $e) {}
463: }
464: }
465:
466: 467: 468: 469: 470: 471: 472: 473: 474:
475: protected function _insert($elts, $sub = null)
476: {
477: $sub_pref = $GLOBALS['prefs']->getValue('subscribe');
478:
479: foreach ($elts as $val) {
480: $key = strval($val['mailbox']);
481: if (isset($this->_tree[$key]) ||
482: in_array('\nonexistent', $val['attributes'])) {
483: continue;
484: }
485:
486: 487: 488:
489: $parts = explode($val['delimiter'], $key);
490: $parts[0] = $this->_convertName($parts[0]);
491: for ($i = 1, $p_count = count($parts); $i <= $p_count; ++$i) {
492: $part = implode($val['delimiter'], array_slice($parts, 0, $i));
493:
494: if (!isset($this->_tree[$part])) {
495: $attributes = 0;
496:
497: 498: 499: 500: 501: 502: 503:
504: if (!$sub_pref ||
505: (($i == $p_count) &&
506: (($sub === true) ||
507: ($key == 'INBOX') ||
508: in_array('\subscribed', $val['attributes'])))) {
509: $attributes |= self::ELT_IS_SUBSCRIBED;
510: } elseif (is_null($sub) && ($i == $p_count)) {
511: $this->_getList(false);
512: if (isset($this->_cache['subscribed'][$part])) {
513: $attributes |= self::ELT_IS_SUBSCRIBED;
514: }
515: }
516:
517: if (($i != $p_count) ||
518: in_array('\noselect', $val['attributes'])) {
519: $attributes |= self::ELT_NOSELECT;
520: }
521:
522: $this->_insertElt($this->_makeElt($part, $attributes));
523: }
524: }
525: }
526: }
527:
528: 529: 530: 531: 532: 533:
534: protected function _insertElt($elt)
535: {
536: if (!$elt || isset($this->_tree[$elt['v']])) {
537: return;
538: }
539:
540:
541:
542:
543: $ns_info = $this->_getNamespace($elt['v']);
544: if (isset($this->_tree[rtrim($elt['v'], is_null($ns_info) ? $this->_delimiter : $ns_info['delimiter'])])) {
545: return;
546: }
547:
548: $this->changed = true;
549:
550: $prev = is_null($this->_eltdiff)
551: ? null
552: : $this->hasChildren($this->_tree[$elt['p']]);
553:
554:
555: if (empty($this->_parent[$elt['p']])) {
556: $this->_parent[$elt['p']] = array();
557: }
558:
559: $this->_parent[$elt['p']][] = $elt['v'];
560: $this->_tree[$elt['v']] = $elt;
561:
562: $this->_addEltDiff($elt, 'a');
563: if (!is_null($prev) &&
564: ($this->hasChildren($this->_tree[$elt['p']]) != $prev)) {
565: $this->_addEltDiff($this->_tree[$elt['p']], 'c');
566: }
567:
568:
569: if (count($this->_parent[$elt['p']]) > 1) {
570: $this->_setNeedSort($this->_tree[$elt['p']], true);
571: }
572: }
573:
574: 575: 576: 577: 578: 579: 580:
581: public function delete($id)
582: {
583: if (is_array($id)) {
584: 585:
586: $this->_sortList($id);
587: $id = array_reverse($id);
588:
589: foreach ($id as $val) {
590: $currsuccess = $this->delete($val);
591: if (!$currsuccess) {
592: return false;
593: }
594: }
595:
596: return true;
597: }
598:
599: $id = $this->_convertName($id, true);
600: $vfolder_base = ($id == self::VFOLDER_KEY);
601: $search_id = $GLOBALS['injector']->getInstance('IMP_Search')->createSearchId($id);
602:
603: if ($vfolder_base ||
604: (isset($this->_tree[$search_id]) &&
605: $this->isVFolder($this->_tree[$search_id]))) {
606: if (!$vfolder_base) {
607: $id = $search_id;
608: }
609:
610: $parent = $this->_tree[$id]['p'];
611: $this->_addEltDiff($this->_tree[$id], 'd');
612: unset($this->_tree[$id]);
613:
614:
615: $key = array_search($id, $this->_parent[$parent]);
616: unset($this->_parent[$parent][$key]);
617:
618:
619: if (!$vfolder_base && empty($this->_parent[$parent])) {
620: $this->delete($parent);
621: } else {
622: $this->_parent[$parent] = array_values($this->_parent[$parent]);
623: }
624: $this->changed = true;
625:
626: return true;
627: }
628:
629: $ns_info = $this->_getNamespace($id);
630:
631: if (($id == 'INBOX') ||
632: !isset($this->_tree[$id]) ||
633: ($id == $ns_info['name'])) {
634: return false;
635: }
636:
637: $this->changed = true;
638:
639: $elt = &$this->_tree[$id];
640:
641:
642: unset($this->_cache['fulllist'][$id], $this->_cache['subscribed'][$id]);
643:
644: 645:
646: if ($this->hasChildren($elt)) {
647: $this->_setContainer($elt, true);
648: return true;
649: }
650:
651: $parent = $elt['p'];
652:
653:
654: $this->_addEltDiff($elt, 'd');
655: unset($this->_tree[$id]);
656:
657:
658: $key = array_search($id, $this->_parent[$parent]);
659: unset($this->_parent[$parent][$key]);
660:
661: if (empty($this->_parent[$parent])) {
662:
663: unset($this->_parent[$parent]);
664: if (isset($this->_tree[$parent])) {
665: if ($this->isContainer($this->_tree[$parent]) &&
666: !$this->isNamespace($this->_tree[$parent])) {
667: $this->delete($parent);
668: } else {
669: $this->_modifyExpandedList($parent, 'remove');
670: $this->_setOpen($this->_tree[$parent], false);
671: $this->_addEltDiff($this->_tree[$parent], 'c');
672: }
673: }
674: } else {
675:
676: $this->_parent[$parent] = array_values($this->_parent[$parent]);
677:
678: if (!$this->hasChildren($this->_tree[$parent])) {
679: $this->_addEltDiff($this->_tree[$parent], 'c');
680: }
681: }
682:
683:
684: $this->_modifyExpandedList($id, 'remove');
685:
686:
687: $this->removePollList($id);
688:
689: return true;
690: }
691:
692: 693: 694: 695: 696:
697: public function subscribe($id)
698: {
699: if (!is_array($id)) {
700: $id = array($id);
701: }
702:
703: foreach ($id as $val) {
704: $val = $this->_convertName($val);
705: if (isset($this->_tree[$val])) {
706: $this->changed = true;
707: $this->_setSubscribed($this->_tree[$val], true);
708: $this->_setContainer($this->_tree[$val], false);
709: }
710: }
711: }
712:
713: 714: 715: 716: 717:
718: public function unsubscribe($id)
719: {
720: if (!is_array($id)) {
721: $id = array($id);
722: } else {
723: 724:
725: $this->_sortList($id);
726: $id = array_reverse($id);
727: }
728:
729: foreach ($id as $val) {
730: $val = $this->_convertName($val);
731:
732:
733: if (isset($this->_tree[$val]) && ($val != 'INBOX')) {
734: $this->changed = true;
735:
736: $elt = &$this->_tree[$val];
737:
738: 739:
740: if (!$this->_showunsub && $this->hasChildren($elt)) {
741: $this->_setContainer($elt, true);
742: }
743:
744: 745:
746: $this->_setSubscribed($elt, false);
747: }
748: }
749: }
750:
751: 752: 753: 754: 755: 756: 757:
758: protected function _setAttribute(&$elt, $const, $bool)
759: {
760: if ($bool) {
761: $elt['a'] |= $const;
762: } else {
763: $elt['a'] &= ~$const;
764: }
765: }
766:
767: 768: 769: 770: 771: 772: 773:
774: public function hasChildren($in)
775: {
776: $elt = $this->getElement($in);
777:
778: if ($elt && isset($this->_parent[$elt['v']])) {
779: foreach ($this->_parent[$elt['v']] as $val) {
780: if ($this->_showunsub &&
781: !$this->isContainer($this->_tree[$val]) &&
782: !$this->isNamespace($this->_tree[$val])) {
783: return true;
784: } elseif ($this->isSubscribed($this->_tree[$val]) ||
785: $this->hasChildren($this->_tree[$val])) {
786: return true;
787: }
788: }
789: }
790:
791: return false;
792: }
793:
794: 795: 796: 797: 798: 799: 800:
801: public function isOpen($in)
802: {
803: $elt = $this->getElement($in);
804:
805: return ($elt &&
806: ($elt['a'] & self::ELT_IS_OPEN) &&
807: $this->hasChildren($elt));
808: }
809:
810: 811: 812: 813: 814: 815:
816: protected function _setOpen(&$elt, $bool)
817: {
818: $this->_setAttribute($elt, self::ELT_IS_OPEN, $bool);
819: $this->_modifyExpandedList($elt['v'], $bool ? 'add' : 'remove');
820: }
821:
822: 823: 824: 825: 826: 827: 828: 829:
830: public function isContainer($in)
831: {
832: $elt = $this->getElement($in);
833:
834: return ($elt &&
835: (($elt['a'] & self::ELT_NOSELECT) ||
836: (!$this->_showunsub &&
837: !$this->isSubscribed($elt) &&
838: $this->hasChildren($elt))));
839: }
840:
841: 842: 843: 844: 845: 846:
847: protected function _setContainer(&$elt, $bool)
848: {
849: $this->_setAttribute($elt, self::ELT_NOSELECT, $bool);
850: $this->_addEltDiff($elt, 'c');
851: }
852:
853: 854: 855: 856: 857: 858: 859:
860: public function isSubscribed($in)
861: {
862: $elt = $this->getElement($in);
863:
864: return ($elt && ($elt['a'] & self::ELT_IS_SUBSCRIBED));
865: }
866:
867: 868: 869: 870: 871: 872:
873: protected function _setSubscribed(&$elt, $bool)
874: {
875: $this->_setAttribute($elt, self::ELT_IS_SUBSCRIBED, $bool);
876: if (isset($this->_cache['subscribed'])) {
877: if ($bool) {
878: $this->_cache['subscribed'][$elt['v']] = 1;
879: } else {
880: unset($this->_cache['subscribed'][$elt['v']]);
881: }
882: }
883: }
884:
885: 886: 887: 888: 889: 890: 891:
892: public function isNamespace($in)
893: {
894: $elt = $this->getElement($in);
895:
896: return ($elt && ($elt['a'] & self::ELT_NAMESPACE));
897: }
898:
899: 900: 901: 902: 903: 904: 905:
906: public function isNonImapElt($in)
907: {
908: $elt = $this->getElement($in);
909:
910: return ($elt && ($elt['a'] & self::ELT_NONIMAP));
911: }
912:
913: 914: 915:
916: protected function _initExpandedList()
917: {
918: if (!isset($this->_cache['expanded'])) {
919: $serialized = $GLOBALS['prefs']->getValue('expanded_folders');
920: $this->_cache['expanded'] = $serialized
921: ? unserialize($serialized)
922: : array();
923: }
924: }
925:
926: 927: 928: 929: 930: 931:
932: protected function _modifyExpandedList($id, $action)
933: {
934: $this->_initExpandedList();
935:
936: if ($action == 'add') {
937: $change = empty($this->_cache['expanded'][$id]);
938: $this->_cache['expanded'][$id] = true;
939: } else {
940: $change = !empty($this->_cache['expanded'][$id]);
941: unset($this->_cache['expanded'][$id]);
942: }
943:
944: if ($change) {
945: $GLOBALS['prefs']->setValue('expanded_folders', serialize($this->_cache['expanded']));
946: }
947: }
948:
949: 950: 951: 952: 953: 954: 955:
956: public function getPollList($sort = false)
957: {
958: $this->setIteratorFilter(self::FLIST_NOCONTAINER);
959:
960: if ($GLOBALS['prefs']->getValue('nav_poll_all')) {
961: return iterator_to_array($this);
962: }
963:
964: $plist = array();
965: foreach ($this as $val) {
966: if ($this->isPolled($val)) {
967: $plist[] = $val;
968: }
969: }
970:
971: if ($sort) {
972: $ns_new = $this->_getNamespace(null);
973: Horde_Imap_Client_Sort::sortMailboxes($plist, array(
974: 'delimiter' => $ns_new['delimiter'],
975: 'inbox' => true
976: ));
977: }
978:
979: return IMP_Mailbox::get(array_filter($plist));
980: }
981:
982: 983: 984:
985: protected function _initPollList()
986: {
987: if (!isset($this->_cache['poll']) &&
988: !$GLOBALS['prefs']->getValue('nav_poll_all')) {
989:
990: $this->_cache['poll'] = array('INBOX' => 1);
991:
992:
993: if ($navPollList = @unserialize($GLOBALS['prefs']->getValue('nav_poll'))) {
994: $this->_cache['poll'] += $navPollList;
995: }
996: }
997: }
998:
999: 1000: 1001: 1002: 1003:
1004: public function addPollList($id)
1005: {
1006: if (!is_array($id)) {
1007: $id = array($id);
1008: }
1009:
1010: if (empty($id) ||
1011: $GLOBALS['prefs']->getValue('nav_poll_all') ||
1012: $GLOBALS['prefs']->isLocked('nav_poll')) {
1013: return;
1014: }
1015:
1016: $changed = false;
1017:
1018: $this->_initPollList();
1019:
1020: foreach (IMP_Mailbox::get($id) as $val) {
1021: if ($val->nonimap || $val->container) {
1022: continue;
1023: }
1024:
1025: $mbox_str = strval($val);
1026:
1027: if (!$this->isSubscribed($this->_tree[$mbox_str])) {
1028: $val->subscribe(true);
1029: }
1030: $this->_setPolled($this->_tree[$mbox_str], true);
1031: if (empty($this->_cache['poll'][$mbox_str])) {
1032: $this->_cache['poll'][$mbox_str] = true;
1033: $changed = true;
1034: }
1035: }
1036:
1037: if ($changed) {
1038: $this->_updatePollList();
1039: }
1040: }
1041:
1042: 1043: 1044: 1045: 1046: 1047:
1048: public function removePollList($id)
1049: {
1050: if ($GLOBALS['prefs']->getValue('nav_poll_all') ||
1051: $GLOBALS['prefs']->isLocked('nav_poll')) {
1052: return;
1053: }
1054:
1055: if (!is_array($id)) {
1056: $id = array($id);
1057: }
1058:
1059: $removed = false;
1060:
1061: $this->_initPollList();
1062:
1063: foreach (IMP_Mailbox::get($id) as $val) {
1064: if (!$val->inbox &&
1065: isset($this->_cache['poll'][strval($val)])) {
1066: unset($this->_cache['poll'][strval($val)]);
1067: if (isset($this->_tree[strval($val)])) {
1068: $this->_setPolled($this->_tree[strval($val)], false);
1069: }
1070: $removed = true;
1071: }
1072: }
1073:
1074: if ($removed) {
1075: $this->_updatePollList();
1076: }
1077: }
1078:
1079: 1080: 1081:
1082: protected function _updatePollList()
1083: {
1084: $GLOBALS['prefs']->setValue('nav_poll', serialize($this->_cache['poll']));
1085: $this->changed = true;
1086: }
1087:
1088: 1089: 1090:
1091: public function prunePollList()
1092: {
1093: $prune = array();
1094:
1095: $this->setIteratorFilter(self::FLIST_NOCONTAINER);
1096: foreach ($this as $val) {
1097: if (!$this->isPolled($val) || !$val->exists) {
1098: $prune[] = $val;
1099: }
1100: }
1101:
1102: $this->removePollList($prune);
1103: }
1104:
1105: 1106: 1107: 1108: 1109: 1110: 1111:
1112: public function isPolled($in)
1113: {
1114: $elt = $this->getElement($in);
1115:
1116: if ($this->isNonImapElt($in) || $this->isContainer($in)) {
1117: return false;
1118: }
1119:
1120: return $GLOBALS['prefs']->getValue('nav_poll_all')
1121: ? true
1122: : ($elt && ($elt['a'] & self::ELT_IS_POLLED));
1123: }
1124:
1125: 1126: 1127: 1128: 1129: 1130:
1131: protected function _setPolled(&$elt, $bool)
1132: {
1133: $this->_setAttribute($elt, self::ELT_IS_POLLED, $bool);
1134: }
1135:
1136: 1137: 1138: 1139: 1140: 1141: 1142:
1143: public function isInvisible($in)
1144: {
1145: $elt = $this->getElement($in);
1146:
1147: return ($elt && ($elt['a'] & self::ELT_INVISIBLE));
1148: }
1149:
1150: 1151: 1152: 1153: 1154: 1155:
1156: protected function _setInvisible(&$elt, $bool)
1157: {
1158: $this->_setAttribute($elt, self::ELT_INVISIBLE, $bool);
1159: }
1160:
1161: 1162: 1163: 1164: 1165: 1166:
1167: protected function _setNeedSort(&$elt, $bool)
1168: {
1169: $this->_setAttribute($elt, self::ELT_NEED_SORT, $bool);
1170: }
1171:
1172: 1173: 1174: 1175: 1176: 1177: 1178:
1179: protected function _needSort($elt)
1180: {
1181: return (($elt['a'] & self::ELT_NEED_SORT) && (count($this->_parent[$elt['v']]) > 1));
1182: }
1183:
1184: 1185: 1186:
1187: public function expandAll()
1188: {
1189: foreach ($this->_parent[self::BASE_ELT] as $val) {
1190: $this->expand($val, true);
1191: }
1192: }
1193:
1194: 1195: 1196:
1197: public function collapseAll()
1198: {
1199: foreach ($this->_tree as $key => $val) {
1200: if ($key !== self::BASE_ELT) {
1201: $this->collapse($val['v']);
1202: }
1203: }
1204: }
1205:
1206: 1207: 1208: 1209: 1210:
1211: public function showUnsubscribed($unsub)
1212: {
1213: if ((bool)$unsub === $this->_showunsub) {
1214: return;
1215: }
1216:
1217: $this->_showunsub = $unsub;
1218: $this->changed = true;
1219:
1220: 1221:
1222: if ($unsub === false) {
1223: return;
1224: }
1225:
1226: 1227: 1228:
1229: $old_eltdiff = $this->_eltdiff;
1230: $this->_eltdiff = null;
1231: $this->_insert($this->_getList(true), false);
1232: $this->_eltdiff = $old_eltdiff;
1233: }
1234:
1235: 1236: 1237: 1238: 1239: 1240: 1241:
1242: protected function _sortList(&$mbox, $base = false)
1243: {
1244: if (!$base) {
1245: Horde_Imap_Client_Sort::sortMailboxes($mbox, array('delimiter' => $this->_delimiter));
1246: return;
1247: }
1248:
1249: $basesort = $othersort = array();
1250:
1251: $sorted = array('INBOX');
1252:
1253: foreach ($mbox as $key => $val) {
1254: if ($this->isNonImapElt($this->_tree[$val])) {
1255: $othersort[$key] = IMP_Mailbox::get($val)->label;
1256: } elseif ($val !== 'INBOX') {
1257: $basesort[$key] = IMP_Mailbox::get($val)->label;
1258: }
1259: }
1260:
1261: natcasesort($basesort);
1262: natcasesort($othersort);
1263: foreach (array_merge(array_keys($basesort), array_keys($othersort)) as $key) {
1264: $sorted[] = $mbox[$key];
1265: }
1266:
1267: $mbox = $sorted;
1268: }
1269:
1270: 1271: 1272: 1273: 1274: 1275: 1276: 1277:
1278: protected function _convertName($name)
1279: {
1280: return (strcasecmp($name, 'INBOX') == 0)
1281: ? 'INBOX'
1282: : strval($name);
1283: }
1284:
1285: 1286: 1287: 1288: 1289: 1290: 1291: 1292:
1293: protected function _getNamespace($mailbox)
1294: {
1295: if (!in_array($mailbox, array(self::OTHER_KEY, self::SHARED_KEY, self::VFOLDER_KEY)) &&
1296: (strpos($mailbox, self::VFOLDER_KEY . $this->_delimiter) !== 0)) {
1297: return $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create()->getNamespace($mailbox);
1298: }
1299: return null;
1300: }
1301:
1302: 1303: 1304:
1305: public function eltDiffStart()
1306: {
1307: $this->_eltdiff = array(
1308: 'a' => array(),
1309: 'c' => array(),
1310: 'd' => array(),
1311: 'o' => array()
1312: );
1313: }
1314:
1315: 1316: 1317: 1318: 1319: 1320:
1321: protected function _addEltDiff($elt, $type)
1322: {
1323: if (is_null($this->_eltdiff)) {
1324: return;
1325: }
1326:
1327: $ed = &$this->_eltdiff;
1328: $id = $elt['v'];
1329:
1330: if (array_key_exists($id, $ed['o'])) {
1331: if (($type != 'd') && ($ed['o'][$id] == $elt)) {
1332: unset(
1333: $ed['a'][$id],
1334: $ed['c'][$id],
1335: $ed['d'][$id],
1336: $ed['o'][$id]
1337: );
1338: return;
1339: }
1340: } else {
1341: $ed['o'][$id] = ($type == 'a')
1342: ? null
1343: : $elt;
1344: }
1345:
1346: switch ($type) {
1347: case 'a':
1348: unset($ed['c'][$id], $ed['d'][$id]);
1349: $ed['a'][$id] = 1;
1350: break;
1351:
1352: case 'c':
1353: if (!isset($ed['a'][$id])) {
1354: $ed['c'][$id] = 1;
1355: }
1356: break;
1357:
1358: case 'd':
1359: unset($ed['a'][$id], $ed['c'][$id]);
1360: $ed['d'][$id] = 1;
1361: break;
1362: }
1363: }
1364:
1365: 1366: 1367: 1368: 1369: 1370: 1371: 1372: 1373: 1374:
1375: public function eltDiff()
1376: {
1377: if (is_null($this->_eltdiff) || !$this->changed) {
1378: return false;
1379: }
1380:
1381: $ret = array(
1382: 'a' => array_keys($this->_eltdiff['a']),
1383: 'c' => array_keys($this->_eltdiff['c']),
1384: 'd' => array_keys($this->_eltdiff['d'])
1385: );
1386:
1387: $this->_eltdiff = null;
1388:
1389: return $ret;
1390: }
1391:
1392: 1393: 1394: 1395: 1396:
1397: public function updateVFolders($vfolders)
1398: {
1399:
1400: if (isset($this->_parent[self::VFOLDER_KEY])) {
1401: foreach ($this->_parent[self::VFOLDER_KEY] as $key) {
1402: unset($this->_tree[$key]);
1403: }
1404: unset($this->_parent[self::VFOLDER_KEY]);
1405: $this->changed = true;
1406: }
1407:
1408: if (!$GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create()->access(IMP_Imap::ACCESS_FOLDERS)) {
1409: return;
1410: }
1411:
1412: foreach ($vfolders as $val) {
1413: if ($val->enabled) {
1414: $this->insert(self::VFOLDER_KEY . $this->_delimiter . $val);
1415: }
1416: }
1417: }
1418:
1419: 1420: 1421: 1422: 1423: 1424: 1425:
1426: public function isVFolder($in)
1427: {
1428: $elt = $this->getElement($in);
1429:
1430: return ($elt && ($elt['a'] & self::ELT_VFOLDER));
1431: }
1432:
1433: 1434: 1435: 1436: 1437: 1438:
1439: public function rename($old, $new)
1440: {
1441: $new_list = $polled = array();
1442:
1443: $this->setIteratorFilter(self::FLIST_NOCONTAINER | self::FLIST_UNSUB | self::FLIST_NOBASE | self::FLIST_ASIS, $old);
1444: $old_list = array_merge(
1445: array(IMP_Mailbox::get($old)),
1446: iterator_to_array($this)
1447: );
1448:
1449: foreach ($old_list as $val) {
1450: $new_list[] = $new_name = substr_replace($val, $new, 0, strlen($old));
1451: if ($val->polled) {
1452: $polled[] = $new_name;
1453: }
1454: }
1455:
1456: $this->insert($new_list);
1457: $this->delete($old_list);
1458:
1459: $this->addPollList($polled);
1460: }
1461:
1462: 1463: 1464: 1465: 1466:
1467: protected function _sortLevel($id)
1468: {
1469: if ($this->_needSort($this->_tree[$id])) {
1470: $this->_sortList($this->_parent[$id], ($id === self::BASE_ELT));
1471: $this->_setNeedSort($this->_tree[$id], false);
1472: $this->changed = true;
1473: }
1474: }
1475:
1476: 1477: 1478: 1479: 1480: 1481: 1482: 1483: 1484:
1485: public function createMailboxName($parent, $new)
1486: {
1487: $ns_info = empty($parent)
1488: ? $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create()->defaultNamespace()
1489: : $this->_getNamespace($parent);
1490:
1491: if (is_null($ns_info)) {
1492: if ($this->isNamespace($this->_tree[$parent])) {
1493: $ns_info = $this->_getNamespace($new);
1494: if (in_array($ns_info['type'], array(Horde_Imap_Client::NS_OTHER, Horde_Imap_Client::NS_SHARED))) {
1495: return IMP_Mailbox::get($new);
1496: }
1497: }
1498: throw new IMP_Exception(_("Cannot directly create mailbox in this folder."));
1499: }
1500:
1501: $mbox = $ns_info['name'];
1502: if (!empty($parent)) {
1503: $mbox .= substr_replace($parent, '', 0, strlen($ns_info['name']));
1504: $mbox = rtrim($mbox, $ns_info['delimiter']) . $ns_info['delimiter'];
1505: }
1506:
1507: return IMP_Mailbox::get($mbox . $new);
1508: }
1509:
1510: 1511: 1512: 1513: 1514: 1515: 1516: 1517: 1518: 1519: 1520: 1521: 1522: 1523: 1524: 1525: 1526: 1527: 1528: 1529: 1530: 1531: 1532: 1533: 1534: 1535: 1536: 1537:
1538: public function createTree($name, array $opts = array())
1539: {
1540: $opts = array_merge(array(
1541: 'parent' => null,
1542: 'render_params' => array(),
1543: 'render_type' => 'Javascript'
1544: ), $opts);
1545:
1546: $this->unseen = 0;
1547:
1548: if ($name instanceof Horde_Tree_Base) {
1549: $tree = $name;
1550: $parent = $opts['parent'];
1551: } else {
1552: $tree = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Tree')->create($name, $opts['render_type'], array_merge(array(
1553: 'alternate' => true,
1554: 'lines' => true,
1555: 'lines_base' => true,
1556: 'nosession' => true
1557: ), $opts['render_params']));
1558: $parent = null;
1559: }
1560:
1561: $mailbox_page = (IMP::getViewMode() == 'mimp')
1562: ? 'mailbox-mimp.php'
1563: : 'mailbox.php';
1564:
1565: foreach ($this as $val) {
1566: $after = '';
1567: $params = array();
1568:
1569: switch ($opts['render_type']) {
1570: case 'IMP_Tree_Flist':
1571: if ($val->vfolder_container) {
1572: continue 2;
1573: }
1574:
1575: $is_open = true;
1576: $label = $params['orig_label'] = empty($opts['basename'])
1577: ? $val->abbrev_label
1578: : $val->basename;
1579: break;
1580:
1581: case 'IMP_Tree_Jquerymobile':
1582: $is_open = true;
1583: $label = $val->display_html;
1584: $icon = $val->icon;
1585: $params['icon'] = $icon->icon;
1586: $params['special'] = $val->special;
1587: $params['class'] = 'imp-folder';
1588: $params['urlattributes'] = array('mailbox' => $val->form_to);
1589: break;
1590:
1591: case 'IMP_Tree_Simplehtml':
1592: $is_open = $val->is_open;
1593: if ($tree->shouldToggle($val->form_to)) {
1594: if ($is_open) {
1595: $this->collapse($val);
1596: } else {
1597: $this->expand($val);
1598: }
1599: $is_open = !$is_open;
1600: }
1601: $label = htmlspecialchars(Horde_String::abbreviate($val->display, 30 - ($val->level * 2)));
1602: break;
1603:
1604: case 'Javascript':
1605: $is_open = $val->is_open;
1606: $label = empty($opts['basename'])
1607: ? htmlspecialchars($val->abbrev_label)
1608: : htmlspecialchars($val->basename);
1609: $icon = $val->icon;
1610: $params['icon'] = $icon->icon;
1611: $params['iconopen'] = $icon->iconopen;
1612: break;
1613: }
1614:
1615: if (!empty($opts['poll_info']) && $val->polled) {
1616: $poll_info = $val->poll_info;
1617:
1618: if ($opts['render_type'] == 'IMP_Tree_Jquerymobile') {
1619: if ($poll_info->unseen) {
1620: $after = $poll_info->unseen;
1621: }
1622: } else {
1623: if ($poll_info->unseen) {
1624: $this->unseen += $poll_info->unseen;
1625: $label = '<strong>' . $label . '</strong>';
1626: }
1627:
1628: $after = ' (' . $poll_info->unseen . '/' . $poll_info->msgs . ')';
1629: }
1630: }
1631:
1632: if ($val->container) {
1633: $params['container'] = true;
1634: } else {
1635: $params['url'] = $val->url($mailbox_page);
1636: if ($this->_showunsub && !$val->sub) {
1637: $params['class'] = 'folderunsub';
1638: }
1639: }
1640:
1641: $checkbox = empty($opts['checkbox'])
1642: ? ''
1643: : '<input type="checkbox" class="checkbox" name="folder_list[]" value="' . $val->form_to . '"';
1644:
1645: if ($val->vfolder) {
1646: $checkbox .= ' disabled="disabled"';
1647:
1648: if (!empty($opts['editvfolder']) && $val->container) {
1649: $after = ' [' .
1650: Horde::getServiceLink('prefs', 'imp')->add('group', 'searches')->link(array('title' => _("Edit Virtual Folder"))) . _("Edit") . '</a>'.
1651: ']';
1652: }
1653: }
1654:
1655: $tree->addNode(
1656: $val->form_to,
1657: ($val->level) ? IMP_Mailbox::get($val->parent)->form_to : $parent,
1658: $label,
1659: $val->level,
1660: isset($opts['open']) ? $opts['open'] : $is_open,
1661: $params,
1662: $after,
1663: empty($opts['checkbox']) ? null : $checkbox . ' />'
1664: );
1665: }
1666:
1667: return $tree;
1668: }
1669:
1670: 1671: 1672: 1673: 1674: 1675: 1676:
1677: public function getElement($in)
1678: {
1679: if (is_array($in)) {
1680: return $in;
1681: }
1682:
1683: $in = $this->_convertName($in);
1684:
1685: return isset($this->_tree[$in])
1686: ? $this->_tree[$in]
1687: : null;
1688: }
1689:
1690:
1691:
1692: public function offsetExists($offset)
1693: {
1694: return isset($this->_tree[$this->_convertName($offset)]);
1695: }
1696:
1697: public function offsetGet($offset)
1698: {
1699: return $this->offsetExists($offset)
1700: ? IMP_Mailbox::get($this->_convertName($offset))
1701: : null;
1702: }
1703:
1704: public function offsetSet($offset, $value)
1705: {
1706: $this->insert($offset);
1707: }
1708:
1709: public function offsetUnset($offset)
1710: {
1711: $this->delete($offset);
1712: }
1713:
1714:
1715:
1716: 1717: 1718:
1719: public function count()
1720: {
1721: $this->setIteratorFilter(self::FLIST_NOCONTAINER | self::FLIST_UNSUB);
1722: return count(iterator_to_array($this));
1723: }
1724:
1725:
1726:
1727: public function current()
1728: {
1729: return $this->valid()
1730: ? $this[$this->_parent[$this->_currparent][$this->_currkey]]
1731: : null;
1732: }
1733:
1734: public function key()
1735: {
1736: return $this->valid()
1737: ? $this->_parent[$this->_currparent][$this->_currkey]
1738: : null;
1739: }
1740:
1741: public function next()
1742: {
1743: $curr = $this->current();
1744: if (is_null($curr)) {
1745: return;
1746: }
1747:
1748: $c = &$this->_cache['filter'];
1749:
1750: $old_showunsub = $this->_showunsub;
1751: if ($c['mask'] & self::FLIST_UNSUB) {
1752: $this->_showunsub = true;
1753: }
1754:
1755: if ($this->_activeElt($curr, true)) {
1756:
1757: $this->_currkey = 0;
1758: $this->_currparent = $curr->value;
1759: $this->_sortLevel($curr->value);
1760:
1761: $curr = $this->current();
1762: } else {
1763:
1764: ++$this->_currkey;
1765:
1766: 1767:
1768: while ((($curr = $this->current()) === null) &&
1769: (!isset($c['samelevel']) ||
1770: ($c['samelevel'] != $this->_currparent)) &&
1771: ($parent = $this->_getParent($this->_currparent, true))) {
1772: list($this->_currparent, $this->_currkey) = $parent;
1773: }
1774: }
1775:
1776: if (is_null($curr)) {
1777: 1778:
1779: $this->_currkey = null;
1780: } elseif (!$this->_activeElt($curr)) {
1781: $this->next();
1782: }
1783:
1784: $this->_showunsub = $old_showunsub;
1785: }
1786:
1787: public function rewind()
1788: {
1789: $this->_currkey = 0;
1790: $this->_currparent = self::BASE_ELT;
1791: $this->_sortLevel($this->_currparent);
1792:
1793: $c = &$this->_cache['filter'];
1794:
1795: 1796:
1797: if (!$this->_showunsub &&
1798: ($c['mask'] & self::FLIST_UNSUB) &&
1799: !($c['mask'] & self::FLIST_ASIS)) {
1800: $this->showUnsubscribed(true);
1801: $this->showUnsubscribed(false);
1802: }
1803:
1804:
1805: if ($c['base']) {
1806: if ($tmp = $this[$c['base']]) {
1807: if ($c['mask'] & self::FLIST_ANCESTORS) {
1808: $p = $tmp->value;
1809: $c['ancestors'] = array($p => null);
1810: while ($parent = $this->_getParent($p)) {
1811: $c['ancestors'][$parent[0]] = $parent[1];
1812: $p = $parent[0];
1813: }
1814: } elseif ($c['mask'] & self::FLIST_NOBASE) {
1815: $this->_currparent = $tmp->value;
1816: $this->_currkey = isset($this->_parent[$tmp->value])
1817: ? 0
1818: : null;
1819: $c['samelevel'] = $tmp->value;
1820:
1821:
1822: $curr = $this->current();
1823: if (is_null($curr)) {
1824: $this->_currkey = null;
1825: } elseif (!$this->_activeElt($curr)) {
1826: $this->next();
1827: }
1828: } else {
1829: $this->_currparent = strval($tmp->parent);
1830: $this->_currkey = array_search($tmp->value, $this->_parent[$this->_currparent]);
1831:
1832: if ($c['mask'] & self::FLIST_SAMELEVEL) {
1833: $this->_currkey = 0;
1834: $c['samelevel'] = $this->_currparent;
1835: }
1836: }
1837: } else {
1838: $this->_currkey = null;
1839: }
1840: }
1841: }
1842:
1843: public function valid()
1844: {
1845: return (!is_null($this->_currkey) &&
1846: isset($this->_parent[$this->_currparent][$this->_currkey]));
1847: }
1848:
1849:
1850:
1851: 1852: 1853: 1854: 1855: 1856: 1857: 1858: 1859: 1860: 1861: 1862: 1863: 1864: 1865: 1866: 1867: 1868: 1869: 1870: 1871: 1872: 1873: 1874: 1875: 1876: 1877: 1878: 1879: 1880: 1881: 1882: 1883: 1884: 1885: 1886: 1887: 1888: 1889: 1890: 1891:
1892: public function setIteratorFilter($mask = 0, $base = null)
1893: {
1894: $this->_cache['filter'] = array(
1895: 'base' => $base,
1896: 'mask' => $mask
1897: );
1898: reset($this);
1899: }
1900:
1901: 1902: 1903: 1904: 1905: 1906: 1907: 1908: 1909:
1910: protected function _activeElt($elt, $child_check = false)
1911: {
1912:
1913: if ($elt->invisible) {
1914: return false;
1915: }
1916:
1917: $c = &$this->_cache['filter'];
1918:
1919:
1920: if ($elt->vfolder && !($c['mask'] & self::FLIST_VFOLDER)) {
1921: return false;
1922: }
1923:
1924: if ($child_check) {
1925: 1926:
1927: if (!isset($this->_parent[$elt->value])) {
1928: return false;
1929: }
1930:
1931:
1932: if (isset($c['ancestors']) &&
1933: isset($c['ancestors'][$this->_currparent]) &&
1934: ($c['ancestors'][$this->_currparent] == $this->_currkey)) {
1935: return true;
1936: }
1937:
1938:
1939: if ($c['mask'] & self::FLIST_EXPANDED) {
1940: return $elt->is_open;
1941: }
1942:
1943: if ($c['mask'] & self::FLIST_NOCHILDREN) {
1944: return false;
1945: }
1946: } else {
1947: 1948:
1949: if ($elt->container) {
1950: if (($c['mask'] & self::FLIST_NOCONTAINER) ||
1951: !$elt->children) {
1952: return false;
1953: }
1954: } elseif (!$this->_showunsub && !$elt->sub) {
1955: return false;
1956: }
1957: }
1958:
1959: return true;
1960: }
1961:
1962: 1963: 1964: 1965: 1966: 1967: 1968: 1969:
1970: protected function _getParent($parent, $inc = false)
1971: {
1972: if ($parent == self::BASE_ELT) {
1973: return null;
1974: }
1975:
1976: $p = strval($this[$parent]->parent);
1977:
1978: return array(
1979: $p,
1980: array_search($parent, $this->_parent[$p], true) + ($inc ? 1 : 0)
1981: );
1982: }
1983:
1984:
1985:
1986: 1987:
1988: public function serialize()
1989: {
1990: return serialize(array(
1991:
1992: self::VERSION,
1993: $this->_delimiter,
1994: $this->_namespaces,
1995: $this->_parent,
1996: $this->_showunsub,
1997: $this->_tree
1998: ));
1999: }
2000:
2001: 2002: 2003:
2004: public function unserialize($data)
2005: {
2006: $data = @unserialize($data);
2007: if (!is_array($data) ||
2008: !isset($data[0]) ||
2009: ($data[0] != self::VERSION)) {
2010: throw new Exception('Cache version change');
2011: }
2012:
2013: $this->_delimiter = $data[1];
2014: $this->_namespaces = $data[2];
2015: $this->_parent = $data[3];
2016: $this->_showunsub = $data[4];
2017: $this->_tree = $data[5];
2018: }
2019:
2020: }
2021: