/
Mailbox.php
1871 lines (1610 loc) · 63.9 KB
/
Mailbox.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?php
/**
* Copyright 2011-2017 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (GPL). If you
* did not receive this file, see http://www.horde.org/licenses/gpl.
*
* @category Horde
* @copyright 2011-2017 Horde LLC
* @license http://www.horde.org/licenses/gpl GPL
* @package IMP
*/
/**
* This object is a clearinghouse for actions related to an IMP mailbox.
*
* @author Michael Slusarz <slusarz@horde.org>
* @category Horde
* @copyright 2011-2017 Horde LLC
* @license http://www.horde.org/licenses/gpl GPL
* @package IMP
*
* @property-read string $abbrev_label Abbreviated version of $label -
* displays only the bare mailbox name
* (no parents).
* @property-read boolean $access_creatembox Can sub mailboxes be created?
* @property-read boolean $access_deletembox Can this mailbox be deleted?
* @property-read boolean $access_deletembox_acl Can this mailbox be deleted
* according to ACL rules?
* @property-read boolean $access_deletemsgs Can messages be deleted in this
* mailbox?
* @property-read boolean $access_empty Can this mailbox be emptied?
* @property-read boolean $access_expunge Can messages be expunged in this
* mailbox?
* @property-read boolean $access_filters Is filtering available?
* @property-read boolean $access_flags Are flags available?
* @property-read boolean $access_search Is searching available?
* @property-read boolean $access_sort Is sorting available?
* @property-read boolean $access_sortthread Is thread sort available?
* @property-read mixed $acl Either an ACL object for the mailbox, or null if
* no ACL found for the mailbox.
* @property-read string $basename The basename of the mailbox (UTF-8).
* @property-read string $cacheid Cache ID for the mailbox.
* @property-read string $cacheid_date Cache ID for the mailbox, with added
* data information.
* @property-read boolean $children Does the element have children?
* @property-read boolean $container Is this a container element?
* @property string $display Display version of mailbox. Special mailboxes
* are replaced with localized strings and
* namespace information is removed.
* @property-read string $display_html $display that has been HTML encoded.
* @property-read boolean $drafts Is this a Drafts mailbox?
* @property-read boolean $editquery Can this search query be edited?
* @property-read boolean $editvfolder Can this virtual folder be edited?
* @property-read boolean $exists Does this mailbox exist on the IMAP server?
* @property-read string $form_to Converts this mailbox to a form
* representation.
* @property-read object $icon Icon information for the mailbox. Properties:
* - alt: (string) The alt text for the icon.
* - class: (string) The CSS class name.
* - icon: (Horde_Themes_Image) The icon graphic to use.
* - iconopen: (Horde_Themes_Image) The openicon to use.
* - user_icon: (boolean) Use a user defined icon?
* @property-read IMP_Imap $imp_imap The IMP_Imap object for this mailbox.
* @property-read string $imap_mbox The actual name of the underlying IMAP
* mailbox.
* @property-read Horde_Imap_Client_Mailbox $imap_mbox_ob Convert this object
* tp an
* Imap_Client mailbox
* object.
* @property-read boolean $inbox Is this the INBOX?
* @property-read boolean $innocent_show Show the innocent action in this
* mailbox?
* @property-read boolean $is_imap Is this an IMAP mailbox?
* @property-read boolean $is_open Is this level expanded?
* @property-read string $label The mailbox label. Essentially is $display
* that can be modified by user hook.
* @property-read integer $level The child level of this element.
* @property-read IMP_Mailbox_List $list_ob Returns the List object for the
* mailbox.
* @property-read string $namespace Is this a namespace element?
* @property-read IMP_Mailbox $namespace_append The mailbox with necessary
* namespace information appended.
* @property-read string $namespace_delimiter The delimiter for this
* namespace.
* @property-read Horde_Imap_Client_Data_Namespace $namespace_info Namespace
* info.
* @property-read boolean $nonimap Is this a non-IMAP element?
* @property-read IMP_Mailbox $parent The parent element. Returns null if no
* parent. (Base of tree is returned as
* a special element).
* @property-read string $parent_imap The IMAP parent name.
* @property-read IMP_Imap_PermanentFlags $permflags Return the list of
* permanent flags
* available to set in the
* mailbox.
* @property-read boolean $polled Show polled information?
* @property-read object $poll_info Poll information for the mailbox.
* Properties:
* - msgs: (integer) The number of total messages in the element, if polled.
* - recent: (integer) The number of new messages in the element, if polled.
* - unseen: (integer) The number of unseen messages in the element, if
* polled.
* @property-read string $pref_from Convert mailbox name from preference
* storage.
* @property-read string $pref_to Convert mailbox name to preference storage.
* @property-read boolean $query Is this a search query?
* @property-read boolean $readonly Is this mailbox read-only?
* @property-read boolean $remote Is this a remote element?
* @property-read IMP_Remote_Account $remote_account Return the account
* object for this element
* (null if not a remote
* element).
* @property-read boolean $remote_container Is this mailbox a remote special
* element?
* @property-read boolean $remote_mbox Is this mailbox on a remote server?
* @property-read boolean $search Is this a search mailbox?
* @property-read string $size Human readable size of the mailbox.
* @property-read IMP_Prefs_Sort $sortob Sort ob for use with this mailbox.
* @property-read boolean $spam Is this a Spam mailbox?
* @property-read boolean $spam_show Show the spam action in this mailbox?
* @property-read boolean $special Is this is a "special" element?
* @property-read boolean $special_outgoing Is this a "special" element
* dealing with outgoing messages?
* @property-read boolean $specialvfolder Is this a "special" virtual folder?
* @property-read boolean $sub Is this mailbox subscribed to?
* @property-read array $subfolders Returns the list of subfolders as mailbox
* objects (including the current mailbox).
* @property-read array $subfolders_only Returns the list of subfolders as
* mailbox objects (NOT including the
* current mailbox).
* @property-read boolean $systemquery Is this a system (built-in) search
* query?
* @property-read boolean $templates Is this a Templates mailbox?
* @property-read boolean $trash Is this a Trash mailbox?
* @property-read IMP_Ftree_Element $tree_elt The tree element (null if it
* doesn't exist in the tree).
* @property-read string $uidvalid Returns the UIDVALIDITY string. Throws an
* IMP_Exception on error.
* @property-read string $value The value of this element (IMAP mailbox name;
* UTF-8).
* @property-read boolean $vfolder Is this a virtual folder?
* @property-read boolean $vfolder_container Is this the virtual folder
* container?
* @property-read boolean $vinbox Is this the virtual inbox?
* @property-read boolean $vtrash Is this the virtual trash?
*/
class IMP_Mailbox
{
/* Special mailbox prefs. */
const MBOX_DRAFTS = 'drafts_folder';
const MBOX_SENT = 'sent_mail_folder';
const MBOX_SPAM = 'spam_folder';
const MBOX_TEMPLATES = 'composetemplates_mbox';
const MBOX_TRASH = 'trash_folder';
// This is just a placeholder - this pref doesn't exist.
const MBOX_USERSPECIAL = 'user_special';
/* Special mailbox identifiers. */
const SPECIAL_COMPOSETEMPLATES = 'composetemplates';
const SPECIAL_DRAFTS = 'drafts';
const SPECIAL_SENT = 'sent';
const SPECIAL_SPAM = 'spam';
const SPECIAL_TRASH = 'trash';
const SPECIAL_USER = 'userspecial';
/**
* The IMAP mailbox name (UTF-8).
*
* @var string
*/
protected $_mbox;
/**
* Shortcut to obtaining mailbox object(s).
*
* @param mixed $mbox The full IMAP mailbox name(s).
*
* @return mixed The IMP_Mailbox object(s).
*/
public static function get($mbox)
{
if (is_array($mbox)) {
return array_filter(array_map(array(__CLASS__, 'get'), $mbox));
}
if ($mbox instanceof IMP_Mailbox) {
return $mbox;
}
try {
return $GLOBALS['injector']
->getInstance('IMP_Factory_Mailbox')
->create(strval($mbox));
} catch (IMP_Exception $e) {
return null;
}
}
/**
* Shortcut to obtaining Horde_Imap_Client_Mailbox object(s).
*
* @param mixed $mbox The full IMAP mailbox name(s).
*
* @return mixed The Horde_Imap_Client_Mailbox object(s).
*/
public static function getImapMboxOb($mbox)
{
if (is_array($mbox)) {
return array_filter(array_map(array(__CLASS__, 'getImapMboxOb'), $mbox));
}
if ($mbox instanceof Horde_Imap_Client_Mailbox) {
return $mbox;
}
// Mailbox names are always UTF-8 within IMP.
$mbox_ob = new self($mbox);
return Horde_Imap_Client_Mailbox::get($mbox_ob->imap_mbox);
}
/**
* Shortcut to obtaining a mailbox object from a preference name.
*
* @var string $pref The preference name.
*
* @return IMP_Mailbox The IMP_Mailbox object.
*/
public static function getPref($pref)
{
return self::get(self::prefFrom($GLOBALS['prefs']->getValue($pref)));
}
/**
* Constructor.
*
* @var string $mbox The full IMAP mailbox name.
*
* @throws IMP_Exception
*/
public function __construct($mbox)
{
if (strlen($mbox) === 0) {
throw new IMP_Exception('Mailbox name must not be empty.');
}
$this->_mbox = $mbox;
}
/**
*/
public function __toString()
{
return strval(
($this->_mbox == IMP_Ftree::BASE_ELT) ? '' : $this->_mbox
);
}
/**
*/
public function __get($key)
{
global $injector;
switch ($key) {
case 'abbrev_label':
$label = $this->label;
return ($this->nonimap || ($pos = strrpos($label, $this->namespace_delimiter)) === false)
? $label
: substr($label, $pos + 1);
case 'access_creatembox':
return (!($acl = $this->acl) ||
($acl[Horde_Imap_Client::ACL_CREATEMBOX]));
case 'access_deletembox':
return ($this->access_deletembox_acl);
case 'access_deletembox_acl':
return (!($acl = $this->acl) ||
($acl[Horde_Imap_Client::ACL_DELETEMBOX]));
case 'access_deletemsgs':
return (!($acl = $this->acl) ||
($acl[Horde_Imap_Client::ACL_DELETEMSGS]));
case 'access_empty':
if ($this->access_deletemsgs && $this->access_expunge) {
$special = $this->getSpecialMailboxes();
return empty($special[self::SPECIAL_TRASH]) ||
!$special[self::SPECIAL_TRASH]->vtrash ||
($special[self::SPECIAL_TRASH] == $this);
}
return false;
case 'access_expunge':
return (!($acl = $this->acl) ||
($acl[Horde_Imap_Client::ACL_EXPUNGE]));
case 'access_filters':
return !$this->search && $this->is_imap;
case 'access_flags':
return $this->is_imap;
case 'access_search':
return $this->is_imap;
case 'access_sort':
/* Although possible to abstract other sorting methods, all other
* non-sequence methods require a download of ALL messages, which
* is too much overhead.*/
return $this->is_imap;
case 'access_sortthread':
/* Thread sort is always available for IMAP servers, since
* Horde_Imap_Client_Socket has a built-in ORDEREDSUBJECT
* implementation. We will always prefer REFERENCES, but will
* fallback to ORDEREDSUBJECT if the server doesn't support THREAD
* sorting. */
return $this->is_imap;
case 'acl':
$cache = $injector->getInstance('IMP_Mailbox_SessionCache');
if (($acl = $cache->getAcl($this->_mbox)) !== false) {
return $acl;
}
if ($this->nonimap) {
$acl = null;
} else {
$acl = $injector->getInstance('IMP_Imap_Acl')->getACL($this, true);
$hooks = $injector->getInstance('Horde_Core_Hooks');
if ($hooks->hookExists('mbox_acl', 'imp')) {
$hooks->callHook('mbox_acl', 'imp', array($this, $acl));
}
}
$cache->setAcl($this->_mbox, $acl);
return $acl;
case 'basename':
if ($this->nonimap) {
return $this->label;
}
$mbox = $this->remote_mbox
? $this->label
: $this->_mbox;
return (($pos = strrpos($mbox, $this->namespace_delimiter)) === false)
? strval($mbox)
: substr($mbox, $pos + 1);
case 'cacheid':
case 'cacheid_date':
return $this->_getCacheID($key == 'cacheid_date');
case 'children':
return (($elt = $this->tree_elt) && $elt->children);
case 'container':
return (($elt = $this->tree_elt) && $elt->container);
case 'display':
return $this->nonimap
? $this->label
: $this->_getDisplay();
case 'display_html':
return htmlspecialchars($this->display);
case 'display_notranslate':
return $this->nonimap
? $this->label
: $this->_getDisplay(true);
case 'drafts':
$special = $this->getSpecialMailboxes();
return ($this->_mbox == $special[self::SPECIAL_DRAFTS]);
case 'editquery':
return $injector->getInstance('IMP_Search')->isQuery($this->_mbox, true);
case 'editvfolder':
return $injector->getInstance('IMP_Search')->isVFolder($this->_mbox, true);
case 'exists':
return $injector->getInstance('IMP_Mailbox_SessionCache')->exists($this);
case 'form_to':
return $this->formTo($this->_mbox);
case 'icon':
return $this->_getIcon();
case 'imp_imap':
return $injector->getInstance('IMP_Factory_Imap')->create(strval($this));
case 'imap_mbox':
return strval(
$injector->getInstance('IMP_Remote')->getMailboxById($this->_mbox) ?: $this->_mbox
);
case 'imap_mbox_ob':
return self::getImapMboxOb($this->_mbox);
case 'inbox':
return (strcasecmp($this->_mbox, 'INBOX') === 0);
case 'innocent_show':
$p = $this->imp_imap->config->innocent_params;
return (!empty($p) &&
((isset($p['display']) && empty($p['display'])) || $this->spam));
case 'is_imap':
return $this->imp_imap->isImap();
case 'is_open':
return (($elt = $this->tree_elt) && $elt->open);
case 'label':
$cache = $injector->getInstance('IMP_Mailbox_SessionCache');
if (($label = $cache->getLabel($this->_mbox)) !== false) {
return $label;
}
/* Returns the plain text label that is displayed for the
* current mailbox, replacing virtual search mailboxes with an
* appropriate description, removing namespace and mailbox
* prefix information from what is shown to the user, and
* passing the label through a user-defined hook. */
$imp_search = $injector->getInstance('IMP_Search');
$label = ($ob = $imp_search[$this->_mbox])
? $ob->label
: $this->_getDisplay();
$hooks = $injector->getInstance('Horde_Core_Hooks');
if ($hooks->hookExists('mbox_label' ,'imp')) {
$label = $hooks->callHook(
'mbox_label',
'imp',
array($this->_mbox, $label)
);
}
$cache->setLabel($this->_mbox, $label);
return $label;
case 'level':
return ($elt = $this->tree_elt) ? $elt->level : 0;
case 'list_ob':
return $injector->getInstance('IMP_Factory_MailboxList')->create($this);
case 'namespace':
return (($elt = $this->tree_elt) && $elt->namespace);
case 'namespace_append':
$imp_imap = $this->imp_imap;
$def_ns = $imp_imap->getNamespace($imp_imap::NS_DEFAULT);
if (is_null($def_ns)) {
return $this;
}
$empty_ns = $imp_imap->getNamespace('');
/* If default namespace is empty, or there is no empty namespace,
* then we can auto-detect namespace from input.
* If a non-default namespace is empty, then we must always use
* default namespace. */
if (!is_null($empty_ns) &&
($def_ns->name == $empty_ns->name)) {
return $this;
}
$ns_info = $this->namespace_info;
if (is_null($ns_info) || !is_null($empty_ns)) {
return self::get($def_ns->name . $this->_mbox);
}
return $this;
case 'namespace_delimiter':
$ns_info = $this->namespace_info;
return is_null($ns_info)
? ''
: $ns_info->delimiter;
case 'namespace_info':
return $this->imp_imap->getNamespace(strlen($this) ? $this->_mbox : IMP_Imap::NS_DEFAULT);
case 'nonimap':
return ($this->search ||
(($elt = $this->tree_elt) && $elt->nonimap));
case 'parent':
return ($elt = $this->tree_elt) ? $elt->parent->mbox_ob : null;
case 'parent_imap':
return (is_null($p = $this->parent) || !strlen($p))
? null
: $p;
case 'permflags':
if ($this->access_flags) {
$imp_imap = $this->imp_imap;
try {
/* Make sure we are in R/W mailbox mode (SELECT). No flags
* are allowed in EXAMINE mode. */
$imp_imap->openMailbox($this, Horde_Imap_Client::OPEN_READWRITE);
$status = $imp_imap->status($this->_mbox, Horde_Imap_Client::STATUS_FLAGS | Horde_Imap_Client::STATUS_PERMFLAGS);
return new IMP_Imap_PermanentFlags($status['permflags'], $status['flags']);
} catch (Exception $e) {}
}
return new IMP_Imap_PermanentFlags();
case 'poll_info':
$info = new stdClass;
$info->msgs = 0;
$info->recent = 0;
$info->unseen = 0;
try {
if ($msgs_info = $this->imp_imap->status($this->_mbox, Horde_Imap_Client::STATUS_RECENT_TOTAL | Horde_Imap_Client::STATUS_UNSEEN | Horde_Imap_Client::STATUS_MESSAGES)) {
if (!empty($msgs_info['recent_total'])) {
$info->recent = intval($msgs_info['recent_total']);
}
$info->msgs = intval($msgs_info['messages']);
$info->unseen = intval($msgs_info['unseen']);
}
} catch (IMP_Imap_Exception $e) {}
return $info;
case 'polled':
return (!$this->search &&
(($elt = $this->tree_elt) && $elt->polled));
case 'pref_from':
return $this->prefFrom($this->_mbox);
case 'pref_to':
return $this->prefTo($this->_mbox);
case 'query':
return $injector->getInstance('IMP_Search')->isQuery($this->_mbox);
case 'readonly':
return (($acl = $this->acl) &&
!$acl[Horde_Imap_Client::ACL_DELETEMBOX] &&
!$acl[Horde_Imap_Client::ACL_DELETEMSGS] &&
!$acl[Horde_Imap_Client::ACL_EXPUNGE] &&
!$acl[Horde_Imap_Client::ACL_INSERT] &&
!$acl[Horde_Imap_Client::ACL_SEEN] &&
!$acl[Horde_Imap_Client::ACL_WRITE]);
case 'remote':
return $injector->getInstance('IMP_Remote')->isRemoteMbox($this->_mbox);
case 'remote_account':
$remote = $injector->getInstance('IMP_Remote');
$account = ($this->remote_container)
? $remote[$this->_mbox]
: $remote->getRemoteById($this->_mbox);
return $account ?: null;
case 'remote_container':
return (($elt = $this->tree_elt) && $elt->remote);
case 'remote_mbox':
return (($elt = $this->tree_elt) && $elt->remote_mbox);
case 'search':
return $injector->getInstance('IMP_Search')->isSearchMbox($this->_mbox);
case 'size':
return $injector->getInstance('IMP_Mbox_Size')->getSize($this);
case 'sortob':
return $this->imp_imap->access(IMP_Imap::ACCESS_SORT)
? $injector->getInstance('IMP_Prefs_Sort')
: $injector->getInstance('IMP_Prefs_Sort_None');
case 'spam':
$special = $this->getSpecialMailboxes();
return ($this->_mbox == $special[self::SPECIAL_SPAM]);
case 'spam_show':
$p = $this->imp_imap->config->spam_params;
return (!empty($p) && (!empty($p['display']) || !$this->spam));
case 'special':
$special = $this->getSpecialMailboxes();
switch ($this->_mbox) {
case $special[self::SPECIAL_COMPOSETEMPLATES]:
case $special[self::SPECIAL_DRAFTS]:
case $special[self::SPECIAL_SPAM]:
case $special[self::SPECIAL_TRASH]:
return true;
}
return in_array($this->_mbox, array_merge(
$special[self::SPECIAL_SENT],
$special[self::SPECIAL_USER]
));
case 'special_outgoing':
$special = $this->getSpecialMailboxes();
return in_array($this->_mbox, array_merge(
array(
$special[self::SPECIAL_COMPOSETEMPLATES],
$special[self::SPECIAL_DRAFTS]
),
$special[self::SPECIAL_SENT]
));
case 'specialvfolder':
return !$this->editvfolder;
case 'sub':
return (($elt = $this->tree_elt) && $elt->subscribed);
case 'subfolders':
return $this->get(array_merge(array($this->_mbox), $this->subfolders_only));
case 'subfolders_only':
return $this->get($this->imp_imap->listMailboxes($this->imap_mbox_ob->list_escape . $this->namespace_delimiter . '*', null, array('flat' => true)));
case 'systemquery':
return $injector->getInstance('IMP_Search')->isSystemQuery($this->_mbox);
case 'templates':
$special = $this->getSpecialMailboxes();
return ($this->_mbox == $special[self::SPECIAL_COMPOSETEMPLATES]);
case 'trash':
$special = $this->getSpecialMailboxes();
return ($this->_mbox == $special[self::SPECIAL_TRASH]);
case 'tree_elt':
$ftree = $injector->getInstance('IMP_Ftree');
return $ftree[$this->_mbox];
case 'uidvalid':
$cache = $injector->getInstance('IMP_Mailbox_SessionCache');
$uidvalid = $cache->getUidvalidity($this->_mbox);
if ($uidvalid === 0) {
return;
}
// POP3 and non-IMAP mailboxes do not support UIDVALIDITY.
if (!$this->is_imap || $this->nonimap) {
$cache->setUidvalidity($this->_mbox, 0);
return false;
}
$status = $this->imp_imap->status($this->_mbox, Horde_Imap_Client::STATUS_UIDVALIDITY);
if (($first = ($uidvalid === false)) ||
($status['uidvalidity'] != $uidvalid)) {
$uidvalid = $status['uidvalidity'];
$cache->setUidvalidity($this->_mbox, $uidvalid);
if (!$first) {
throw new IMP_Exception(_("Mailbox structure on server has changed."));
}
}
return $uidvalid;
case 'value':
return $this->_mbox;
case 'vfolder':
return $injector->getInstance('IMP_Search')->isVFolder($this->_mbox);
case 'vfolder_container':
return ($this->_mbox == IMP_Ftree_Account_Vfolder::VFOLDER_KEY);
case 'vinbox':
return $injector->getInstance('IMP_Search')->isVinbox($this->_mbox);
case 'vtrash':
return $injector->getInstance('IMP_Search')->isVTrash($this->_mbox);
}
return false;
}
/**
*/
public function __set($key, $value)
{
global $injector;
switch ($key) {
case 'display':
$injector->getInstance('IMP_Mailbox_SessionCache')->setDisplay($this->_mbox, $value);
break;
}
}
/**
* Create this mailbox on the server.
*
* @param array $opts Additional options:
* - special_use: (array) An array of special-use attributes to attempt
* to add to the mailbox.
* DEFAULT: NONE
* - subscribe: (boolean) Override preference value of subscribe.
*
* @return boolean True on success.
* @throws Horde_Exception
*/
public function create(array $opts = array())
{
global $injector, $notification, $prefs;
if ($this->exists) {
return true;
}
$imp_imap = $this->imp_imap;
/* Check permissions. */
if (!$imp_imap->access(IMP_Imap::ACCESS_CREATEMBOX)) {
Horde::permissionDeniedError(
'imp',
'create_mboxes',
_("You are not allowed to create mailboxes.")
);
return false;
}
if (!$imp_imap->access(IMP_Imap::ACCESS_CREATEMBOX_MAX)) {
Horde::permissionDeniedError(
'imp',
'max_create_mboxes',
sprintf(_("You are not allowed to create more than %d mailboxes."), $imp_imap->max_create_mboxes)
);
return false;
}
/* Special use flags. */
$special_use = isset($opts['special_use'])
? $opts['special_use']
: array();
/* Attempt to create the mailbox. */
try {
$imp_imap->createMailbox($this->_mbox, array('special_use' => $special_use));
} catch (IMP_Imap_Exception $e) {
if ($e->getCode() == $e::USEATTR) {
unset($opts['special_use']);
return $this->create($opts);
}
$e->notify(sprintf(_("The mailbox \"%s\" was not created. This is what the server said"), $this->display) . ': ' . $e->getMessage());
return false;
}
$notification->push(sprintf(_("The mailbox \"%s\" was successfully created."), $this->display), 'horde.success');
/* Subscribe, if requested. */
if ((!isset($opts['subscribe']) && $prefs->getValue('subscribe')) ||
!empty($opts['subscribe'])) {
try {
$imp_imap->subscribeMailbox($this->_mbox, true);
} catch (IMP_Imap_Exception $e) {}
}
/* Update the mailbox tree. */
$injector->getInstance('IMP_Ftree')->insert($this->_mbox);
return true;
}
/**
* Deletes mailbox.
*
* @param array $opts Addtional options:
* - subfolders: (boolean) Delete all subfolders?
* DEFAULT: false
* - subfolders_only: (boolean) If deleting subfolders, delete only
* subfolders (not current mailbox)?
* DEFAULT: false
*
* @return boolean True on success.
*/
public function delete(array $opts = array())
{
global $injector, $notification;
if ($this->vfolder) {
if ($this->editvfolder) {
$imp_search = $injector->getInstance('IMP_Search');
$label = $imp_search[$this->_mbox]->label;
unset($imp_search[$this->_mbox]);
$notification->push(sprintf(_("Deleted Virtual Folder \"%s\"."), $label), 'horde.success');
return true;
}
$notification->push(sprintf(_("Could not delete Virtual Folder \"%s\"."), $this->label), 'horde.error');
return false;
}
$deleted = array();
$imp_imap = $this->imp_imap;
if (empty($opts['subfolders'])) {
$to_delete = array($this);
} else {
$to_delete = empty($opts['subfolders_only'])
? $this->subfolders
: $this->subfolders_only;
}
foreach ($to_delete as $val) {
if (!$val->access_deletembox_acl) {
$notification->push(sprintf(_("The mailbox \"%s\" may not be deleted."), $val->display), 'horde.error');
continue;
}
try {
$imp_imap->deleteMailbox($val->value);
$notification->push(sprintf(_("The mailbox \"%s\" was successfully deleted."), $val->display), 'horde.success');
$deleted[] = $val;
} catch (IMP_Imap_Exception $e) {
$e->notify(sprintf(_("The mailbox \"%s\" was not deleted. This is what the server said"), $val->display) . ': ' . $e->getMessage());
}
}
if (!empty($deleted)) {
$injector->getInstance('IMP_Ftree')->delete($deleted);
$this->_onDelete($deleted);
}
return (count($deleted) == count($to_delete));
}
/**
* Rename this mailbox on the server. The subscription status remains the
* same. All subfolders will also be renamed.
*
* @param string $new_name The new mailbox name (UTF-8).
*
* @return boolean True on success
*/
public function rename($new_name)
{
global $injector, $notification;
/* Don't try to rename to an empty string. */
if (!strlen($new_name)) {
return false;
}
if (!$this->access_deletembox_acl) {
$notification->push(sprintf(_("The mailbox \"%s\" may not be renamed."), $this->display), 'horde.error');
return false;
}
$new_mbox = $this->get($new_name);
$old_list = $this->subfolders;
try {
$this->imp_imap->renameMailbox($this->_mbox, $new_mbox);
} catch (IMP_Imap_Exception $e) {
$e->notify(sprintf(_("Renaming \"%s\" to \"%s\" failed. This is what the server said"), $this->display, $new_mbox->display) . ': ' . $e->getMessage());
return false;
}
$notification->push(sprintf(_("The mailbox \"%s\" was successfully renamed to \"%s\"."), $this->display, $new_mbox->display), 'horde.success');
$injector->getInstance('IMP_Ftree')->rename($this->_mbox, $new_mbox);
$this->_onDelete($old_list);
return true;
}
/**
* Subscribe/unsubscribe to an IMAP mailbox.
*
* @param boolean $sub True to subscribe, false to unsubscribe.
* @param array $opts Additional options:
* - subfolders: (boolean) If true, applies actions to all subfolders.
*
* @return boolean True on success.
*/
public function subscribe($sub, array $opts = array())
{
global $injector, $notification, $prefs;
/* Skip non-IMAP/container mailboxes. */
if (!$prefs->getValue('subscribe') ||
$this->nonimap ||
$this->container) {
return false;
}
if (!$sub && $this->inbox) {
$notification->push(sprintf(_("You cannot unsubscribe from \"%s\"."), $this->display), 'horde.error');
return false;
}
$imp_imap = $this->imp_imap;
try {
$imp_imap->subscribeMailbox($this->_mbox, $sub);
} catch (IMP_Imap_Exception $e) {
if ($sub) {
$e->notify(sprintf(_("You were not subscribed to \"%s\". Here is what the server said"), $this->display) . ': ' . $e->getMessage());
} else {
$e->notify(sprintf(_("You were not unsubscribed from \"%s\". Here is what the server said"), $this->display) . ': ' . $e->getMessage());
}
return false;
}
$imap_tree = $injector->getInstance('IMP_Ftree');
if ($sub) {
$imap_tree->subscribe($this->_mbox);
} else {
$imap_tree->unsubscribe($this->_mbox);
}
if (empty($opts['subfolders'])) {
$notify = $sub
? sprintf(_("You were successfully subscribed to \"%s\"."), $this->display)
: sprintf(_("You were successfully unsubscribed from \"%s\"."), $this->display);
} else {
$action = false;
foreach ($this->subfolders_only as $val) {
try {
$imp_imap->subscribeMailbox($val, $sub);
if ($sub) {
$imap_tree->subscribe($val);
} else {
$imap_tree->unsubscribe($val);
}
$action = true;
} catch (IMP_Imap_Exception $e) {
// Ignore errors for sub-mailboxes.
}
}
if ($action) {
$notify = $sub
? sprintf(_("You were successfully subscribed to \"%s\" and all subfolders."), $this->display)
: sprintf(_("You were successfully unsubscribed from \"%s\" and all subfolders."), $this->display);
}
}
$notification->push($notify, 'horde.success');
return true;
}
/**
* Runs filters on this mailbox.
*/
public function filter()
{
if (!$this->search) {
$GLOBALS['injector']->getInstance('IMP_Filter')->filter($this);
}
}
/**
* Filters this mailbox if it is the INBOX and the filter on display pref
* is active.
*
* @return boolean True if filter() was called.
*/
public function filterOnDisplay()
{
if ($this->inbox &&
$GLOBALS['prefs']->getValue('filter_on_display')) {
$this->filter();
return true;
}
return false;
}
/**
* Return the search query object for this mailbox.
*
* @return IMP_Search_Query The search query object.
*/
public function getSearchOb()
{
$imp_search = $GLOBALS['injector']->getInstance('IMP_Search');
return $imp_search[$this->_mbox];