Fix for updating the filters rules when a folder is renamed.
[squirrelmail.git] / functions / imap_mailbox.php
CommitLineData
59177427 1<?php
62f7daa5 2
35586184 3/**
4 * imap_mailbox.php
5 *
6c84ba1e 6 * Copyright (c) 1999-2005 The SquirrelMail Project Team
35586184 7 * Licensed under the GNU GPL. For full terms see the file COPYING.
8 *
9 * This impliments all functions that manipulate mailboxes
10 *
eb19bc67 11 * @version $Id$
d6c32258 12 * @package squirrelmail
eb19bc67 13 * @subpackage imap
35586184 14 */
d6c32258 15
16/** UTF7 support */
334a77f8 17require_once(SM_PATH . 'functions/imap_utf7_local.php');
18
3411d4ec 19global $boxesnew;
1da22cda 20
d6c32258 21/**
22 * Mailboxes class
4669e892 23 *
24 * FIXME. This class should be extracted and placed in a separate file that
d6c32258 25 * can be included before we start the session. That makes caching of the tree
4669e892 26 * possible. On a refresh mailboxes from left_main.php the only function that
27 * should be called is the sqimap_get_status_mbx_tree. In case of subscribe
28 * / rename / delete / new we have to create methods for adding/changing the
d6c32258 29 * mailbox in the mbx_tree without the need for a refresh.
30 * @package squirrelmail
dc027257 31 * @subpackage imap
32 * @since 1.3.0
33 */
60b5724d 34class mailboxes {
86c2763d 35 var $mailboxname_full = '', $mailboxname_sub= '', $is_noselect = false, $is_noinferiors = false,
ff245fbd 36 $is_special = false, $is_root = false, $is_inbox = false, $is_sent = false,
4669e892 37 $is_trash = false, $is_draft = false, $mbxs = array(),
ff245fbd 38 $unseen = false, $total = false;
39
40 function addMbx($mbx, $delimiter, $start, $specialfirst) {
41 $ary = explode($delimiter, $mbx->mailboxname_full);
ae7df16e 42 $mbx_parent =& $this;
ff245fbd 43 for ($i = $start, $c = count($ary)-1; $i < $c; $i++) {
ae7df16e 44 $mbx_childs =& $mbx_parent->mbxs;
ff245fbd 45 $found = false;
46 if ($mbx_childs) {
47 foreach ($mbx_childs as $key => $parent) {
48 if ($parent->mailboxname_sub == $ary[$i]) {
ae7df16e 49 $mbx_parent =& $mbx_parent->mbxs[$key];
ff245fbd 50 $found = true;
ae7df16e 51 break;
ff245fbd 52 }
53 }
54 }
55 if (!$found) {
56 $no_select_mbx = new mailboxes();
57 if (isset($mbx_parent->mailboxname_full) && $mbx_parent->mailboxname_full != '') {
58 $no_select_mbx->mailboxname_full = $mbx_parent->mailboxname_full.$delimiter.$ary[$i];
59 } else {
60 $no_select_mbx->mailboxname_full = $ary[$i];
61 }
587ec647 62 $no_select_mbx->mailboxname_sub = $ary[$i];
ff245fbd 63 $no_select_mbx->is_noselect = true;
64 $mbx_parent->mbxs[] = $no_select_mbx;
65 $i--;
66 }
67 }
68 $mbx_parent->mbxs[] = $mbx;
69 if ($mbx->is_special && $specialfirst) {
70 usort($mbx_parent->mbxs, 'sortSpecialMbx');
71 }
72 }
60b5724d 73}
74
dc027257 75/**
76 * array callback used for sorting in mailboxes class
77 * @param object $a
78 * @param object $b
79 * @since 1.3.0
80 */
60b5724d 81function sortSpecialMbx($a, $b) {
82 if ($a->is_inbox) {
ff245fbd 83 $acmp = '0'. $a->mailboxname_full;
60b5724d 84 } else if ($a->is_special) {
ff245fbd 85 $acmp = '1'. $a->mailboxname_full;
60b5724d 86 } else {
ff245fbd 87 $acmp = '2' . $a->mailboxname_full;
88 }
60b5724d 89 if ($b->is_inbox) {
ff245fbd 90 $bcmp = '0'. $b->mailboxname_full;
60b5724d 91 }else if ($b->is_special) {
ff245fbd 92 $bcmp = '1' . $b->mailboxname_full;
60b5724d 93 } else {
ff245fbd 94 $bcmp = '2' . $b->mailboxname_full;
60b5724d 95 }
4669e892 96 return strnatcasecmp($acmp, $bcmp);
ff245fbd 97}
60b5724d 98
dc027257 99/**
100 * @param array $ary
101 * @return array
102 * @since 1.5.0
103 */
104function compact_mailboxes_response($ary) {
86c2763d 105 /*
106 * Workaround for mailboxes returned as literal
4669e892 107 * FIXME : Doesn't work if the mailbox name is multiple lines
86c2763d 108 * (larger then fgets buffer)
109 */
110 for ($i = 0, $iCnt=count($ary); $i < $iCnt; $i++) {
111 if (isset($ary[$i + 1]) && substr($ary[$i], -3) == "}\r\n") {
112 if (ereg("^(\\* [A-Z]+.*)\\{[0-9]+\\}([ \n\r\t]*)$",
113 $ary[$i], $regs)) {
114 $ary[$i] = $regs[1] . '"' . addslashes(trim($ary[$i+1])) . '"' . $regs[2];
115 array_splice($ary, $i+1, 2);
116 }
117 }
118 }
119 /* remove duplicates and ensure array is contiguous */
120 return array_values(array_unique($ary));
121}
122
48af4b64 123/**
124 * Extract the mailbox name from an untagged LIST (7.2.2) or LSUB (7.2.3) answer
125 * (LIST|LSUB) (<Flags list>) (NIL|"<separator atom>") <mailbox name string>\r\n
126 * mailbox name in quoted string MUST be unquoted and stripslashed (sm API)
dc027257 127 *
128 * Originally stored in functions/strings.php. Since 1.2.6 stored in
129 * functions/imap_mailbox.php
130 * @param string $line imap LIST/LSUB response line
131 * @return string mailbox name
48af4b64 132 */
dc027257 133function find_mailbox_name($line) {
bac13dd7 134 if (preg_match('/^\* (?:LIST|LSUB) \([^\)]*\) (?:NIL|\"[^\"]*\") ([^\r\n]*)[\r\n]*$/i', $line, $regs)) {
135 if (substr($regs[1], 0, 1) == '"')
136 return stripslashes(substr($regs[1], 1, -1));
137 return $regs[1];
138 }
139 return '';
140}
141
48af4b64 142/**
dc027257 143 * Detects if mailbox has noselect flag (can't store messages)
144 * @param string $lsub_line mailbox line from untagged LIST or LSUB response
48af4b64 145 * @return bool whether this is a Noselect mailbox.
dc027257 146 * @since 1.3.2
48af4b64 147 */
f73348a3 148function check_is_noselect ($lsub_line) {
3698bd49 149 return preg_match("/^\* (LSUB|LIST) \([^\)]*\\\\Noselect[^\)]*\)/i", $lsub_line);
79e07c7e 150}
151
48af4b64 152/**
dc027257 153 * Detects if mailbox has noinferiors flag (can't store subfolders)
154 * @param string $lsub_line mailbox line from untagged LIST or LSUB response
48af4b64 155 * @return bool whether this is a Noinferiors mailbox.
dc027257 156 * @since 1.5.0
48af4b64 157 */
86c2763d 158function check_is_noinferiors ($lsub_line) {
159 return preg_match("/^\* (LSUB|LIST) \([^\)]*\\\\Noinferiors[^\)]*\)/i", $lsub_line);
160}
161
97b1248c 162/**
d43853c7 163 * Detects mailbox's parent folder
164 *
97b1248c 165 * If $haystack is a full mailbox name, and $needle is the mailbox
166 * separator character, returns the second last part of the full
167 * mailbox name (i.e. the mailbox's parent mailbox)
d43853c7 168 *
169 * Originally stored in functions/strings.php. Since 1.2.6 stored in
170 * functions/imap_mailbox.php
171 * @param string $haystack full mailbox name
172 * @param string $needle delimiter
173 * @return string parent mailbox
97b1248c 174 */
175function readMailboxParent($haystack, $needle) {
97b1248c 176 if ($needle == '') {
177 $ret = '';
178 } else {
179 $parts = explode($needle, $haystack);
180 $elem = array_pop($parts);
181 while ($elem == '' && count($parts)) {
182 $elem = array_pop($parts);
183 }
184 $ret = join($needle, $parts);
185 }
186 return( $ret );
187}
188
4669e892 189/**
6a8e7cae 190 * Check if $subbox is below the specified $parentbox
d43853c7 191 * @param string $subbox potential sub folder
192 * @param string $parentbox potential parent
193 * @return boolean
194 * @since 1.2.3
6a8e7cae 195 */
196function isBoxBelow( $subbox, $parentbox ) {
cef054e4 197 global $delimiter;
4669e892 198 /*
199 * Eliminate the obvious mismatch, where the
6a8e7cae 200 * subfolder path is shorter than that of the potential parent
201 */
202 if ( strlen($subbox) < strlen($parentbox) ) {
203 return false;
204 }
cef054e4 205 /* check for delimiter */
c3ce607e 206 if (substr($parentbox,-1) != $delimiter) {
207 $parentbox .= $delimiter;
208 }
209
210 return (substr($subbox,0,strlen($parentbox)) == $parentbox);
1e18bf95 211}
212
48af4b64 213/**
214 * Defines special mailboxes: given a mailbox name, it checks if this is a
215 * "special" one: INBOX, Trash, Sent or Draft.
d43853c7 216 *
217 * Since 1.2.5 function includes special_mailbox hook.<br>
218 * Since 1.4.3 hook supports more than one plugin.
219 * @param string $box mailbox name
220 * @return boolean
221 * @since 1.2.3
48af4b64 222 */
1e18bf95 223function isSpecialMailbox( $box ) {
90de1755 224 $ret = ( (strtolower($box) == 'inbox') ||
6a8e7cae 225 isTrashMailbox($box) || isSentMailbox($box) || isDraftMailbox($box) );
90de1755 226
2586d588 227 if ( !$ret ) {
5576644b 228 $ret = boolean_hook_function('special_mailbox',$box,1);
2586d588 229 }
3411d4ec 230 return $ret;
90de1755 231}
232
48af4b64 233/**
d43853c7 234 * Detects if mailbox is a Trash folder or subfolder of Trash
235 * @param string $box mailbox name
48af4b64 236 * @return bool whether this is a Trash folder
d43853c7 237 * @since 1.4.0
48af4b64 238 */
6a8e7cae 239function isTrashMailbox ($box) {
240 global $trash_folder, $move_to_trash;
241 return $move_to_trash && $trash_folder &&
242 ( $box == $trash_folder || isBoxBelow($box, $trash_folder) );
243}
244
48af4b64 245/**
d43853c7 246 * Detects if mailbox is a Sent folder or subfolder of Sent
247 * @param string $box mailbox name
48af4b64 248 * @return bool whether this is a Sent folder
d43853c7 249 * @since 1.4.0
48af4b64 250 */
6a8e7cae 251function isSentMailbox($box) {
252 global $sent_folder, $move_to_sent;
253 return $move_to_sent && $sent_folder &&
254 ( $box == $sent_folder || isBoxBelow($box, $sent_folder) );
255}
256
48af4b64 257/**
d43853c7 258 * Detects if mailbox is a Drafts folder or subfolder of Drafts
259 * @param string $box mailbox name
48af4b64 260 * @return bool whether this is a Draft folder
d43853c7 261 * @since 1.4.0
48af4b64 262 */
6a8e7cae 263function isDraftMailbox($box) {
264 global $draft_folder, $save_as_draft;
265 return $save_as_draft &&
266 ( $box == $draft_folder || isBoxBelow($box, $draft_folder) );
267}
268
48af4b64 269/**
d43853c7 270 * Expunges a mailbox
271 *
272 * WARNING: Select mailbox before calling this function.
273 *
274 * permanently removes all messages that have the \Deleted flag
275 * set from the selected mailbox. See EXPUNGE command chapter in
276 * IMAP RFC.
277 * @param stream $imap_stream imap connection resource
278 * @param string $mailbox mailbox name (unused since 1.1.3).
279 * @param boolean $handle_errors error handling control (displays error_box on error).
280 * @param mixed $id (since 1.3.0) integer message id or array with integer ids
281 * @return integer number of expunged messages
282 *
48af4b64 283 */
8f6505f6 284function sqimap_mailbox_expunge ($imap_stream, $mailbox, $handle_errors = true, $id='') {
06b5c3ff 285 if ($id) {
ff245fbd 286 if (is_array($id)) {
287 $id = sqimap_message_list_squisher($id);
288 }
289 $id = ' '.$id;
9d8d1ebd 290 $uid = TRUE;
06b5c3ff 291 } else {
ff245fbd 292 $uid = false;
8f6505f6 293 }
06b5c3ff 294 $read = sqimap_run_command($imap_stream, 'EXPUNGE'.$id, $handle_errors,
295 $response, $message, $uid);
63240b90 296 $cnt = 0;
ff245fbd 297
298 if (is_array($read)) {
63240b90 299 foreach ($read as $r) {
ff245fbd 300 if (preg_match('/^\*\s[0-9]+\sEXPUNGE/AUi',$r,$regs)) {
301 $cnt++;
302 }
63240b90 303 }
8f6505f6 304 }
ff245fbd 305 return $cnt;
43b698c7 306}
307
653ff1e6 308/**
48af4b64 309 * Checks whether or not the specified mailbox exists
d43853c7 310 * @param stream $imap_stream imap connection resource
311 * @param string $mailbox mailbox name
312 * @return boolean
313 * @since 1.0 or older
48af4b64 314 */
1da22cda 315function sqimap_mailbox_exists ($imap_stream, $mailbox) {
247f700e 316 if (!isset($mailbox) || empty($mailbox)) {
43b698c7 317 return false;
318 }
568cb884 319 $mbx = sqimap_run_command($imap_stream, 'LIST "" ' . sqimap_encode_mailbox_name($mailbox),
3411d4ec 320 true, $response, $message);
43b698c7 321 return isset($mbx[0]);
322}
323
48af4b64 324/**
325 * Selects a mailbox
d43853c7 326 * Before 1.3.0 used more arguments and returned data depended on those argumements.
327 * @param stream $imap_stream imap connection resource
328 * @param string $mailbox mailbox name
329 * @return array results of select command (on success - permanentflags, flags and rights)
330 * @since 1.0 or older
48af4b64 331 */
e4c6fe41 332function sqimap_mailbox_select ($imap_stream, $mailbox) {
ff245fbd 333 if ($mailbox == 'None') {
43b698c7 334 return;
335 }
f69feefe 336
568cb884 337 $read = sqimap_run_command($imap_stream, 'SELECT ' . sqimap_encode_mailbox_name($mailbox),
3411d4ec 338 true, $response, $message);
e4c6fe41 339 $result = array();
ff245fbd 340 for ($i = 0, $cnt = count($read); $i < $cnt; $i++) {
e4c6fe41 341 if (preg_match('/^\*\s+OK\s\[(\w+)\s(\w+)\]/',$read[$i], $regs)) {
ff245fbd 342 $result[strtoupper($regs[1])] = $regs[2];
343 } else if (preg_match('/^\*\s([0-9]+)\s(\w+)/',$read[$i], $regs)) {
344 $result[strtoupper($regs[2])] = $regs[1];
345 } else {
346 if (preg_match("/PERMANENTFLAGS(.*)/i",$read[$i], $regs)) {
347 $regs[1]=trim(preg_replace ( array ("/\(/","/\)/","/\]/") ,'', $regs[1])) ;
4669e892 348 $result['PERMANENTFLAGS'] = explode(' ',strtolower($regs[1]));
ff245fbd 349 } else if (preg_match("/FLAGS(.*)/i",$read[$i], $regs)) {
350 $regs[1]=trim(preg_replace ( array ("/\(/","/\)/") ,'', $regs[1])) ;
4669e892 351 $result['FLAGS'] = explode(' ',strtolower($regs[1]));
ff245fbd 352 }
353 }
e4c6fe41 354 }
4669e892 355 if (!isset($result['PERMANENTFLAGS'])) {
356 $result['PERMANENTFLAGS'] = $result['FLAGS'];
357 }
e4c6fe41 358 if (preg_match('/^\[(.+)\]/',$message, $regs)) {
4669e892 359 $result['RIGHTS']=strtoupper($regs[1]);
e4c6fe41 360 }
f69feefe 361
e4c6fe41 362 return $result;
43b698c7 363}
364
48af4b64 365/**
366 * Creates a folder.
d43853c7 367 *
368 * Mailbox is automatically subscribed.
369 *
370 * Set $type to string that does not match 'noselect' (case insensitive),
371 * if you don't want to prepend delimiter to mailbox name. Please note
372 * that 'noinferiors' might be used someday as keyword for folders
373 * that store only messages.
374 * @param stream $imap_steam imap connection resource
375 * @param string $mailbox mailbox name
376 * @param string $type folder type.
377 * @since 1.0 or older
48af4b64 378 */
3411d4ec 379function sqimap_mailbox_create ($imap_stream, $mailbox, $type) {
43b698c7 380 global $delimiter;
381 if (strtolower($type) == 'noselect') {
3411d4ec 382 $mailbox .= $delimiter;
43b698c7 383 }
e429f014 384
48af4b64 385 $read_ary = sqimap_run_command($imap_stream, 'CREATE ' .
386 sqimap_encode_mailbox_name($mailbox),
3411d4ec 387 true, $response, $message);
43b698c7 388 sqimap_subscribe ($imap_stream, $mailbox);
389}
390
48af4b64 391/**
392 * Subscribes to an existing folder.
d43853c7 393 * @param stream $imap_stream imap connection resource
394 * @param string $mailbox mailbox name
395 * @param boolean $debug (since 1.5.1)
396 * @since 1.0 or older
48af4b64 397 */
852abae7 398function sqimap_subscribe ($imap_stream, $mailbox,$debug=true) {
48af4b64 399 $read_ary = sqimap_run_command($imap_stream, 'SUBSCRIBE ' .
400 sqimap_encode_mailbox_name($mailbox),
852abae7 401 $debug, $response, $message);
43b698c7 402}
403
48af4b64 404/**
405 * Unsubscribes from an existing folder
d43853c7 406 * @param stream $imap_stream imap connection resource
407 * @param string $mailbox mailbox name
408 * @since 1.0 or older
48af4b64 409 */
3411d4ec 410function sqimap_unsubscribe ($imap_stream, $mailbox) {
48af4b64 411 $read_ary = sqimap_run_command($imap_stream, 'UNSUBSCRIBE ' .
412 sqimap_encode_mailbox_name($mailbox),
e2e8b92b 413 false, $response, $message);
43b698c7 414}
415
48af4b64 416/**
417 * Deletes the given folder
418 */
3411d4ec 419function sqimap_mailbox_delete ($imap_stream, $mailbox) {
78cc4b12 420 global $data_dir, $username;
e2e8b92b 421 sqimap_unsubscribe ($imap_stream, $mailbox);
48af4b64 422 $read_ary = sqimap_run_command($imap_stream, 'DELETE ' .
423 sqimap_encode_mailbox_name($mailbox),
3411d4ec 424 true, $response, $message);
e2e8b92b 425 if ($response !== 'OK') {
426 // subscribe again
427 sqimap_subscribe ($imap_stream, $mailbox);
428 } else {
429 do_hook_function('rename_or_delete_folder', $args = array($mailbox, 'delete', ''));
430 removePref($data_dir, $username, "thread_$mailbox");
5659ad2e 431 removePref($data_dir, $username, "collapse_folder_$mailbox");
e2e8b92b 432 }
43b698c7 433}
434
48af4b64 435/**
436 * Determines if the user is subscribed to the folder or not
437 */
1da22cda 438function sqimap_mailbox_is_subscribed($imap_stream, $folder) {
1da22cda 439 $boxesall = sqimap_mailbox_list ($imap_stream);
440 foreach ($boxesall as $ref) {
43b698c7 441 if ($ref['unformatted'] == $folder) {
3411d4ec 442 return true;
43b698c7 443 }
444 }
445 return false;
446}
447
48af4b64 448/**
449 * Renames a mailbox.
450 */
1c52ba77 451function sqimap_mailbox_rename( $imap_stream, $old_name, $new_name ) {
3411d4ec 452 if ( $old_name != $new_name ) {
78cc4b12 453 global $delimiter, $imap_server_type, $data_dir, $username;
1c52ba77 454 if ( substr( $old_name, -1 ) == $delimiter ) {
455 $old_name = substr( $old_name, 0, strlen( $old_name ) - 1 );
456 $new_name = substr( $new_name, 0, strlen( $new_name ) - 1 );
457 $postfix = $delimiter;
1c52ba77 458 } else {
459 $postfix = '';
1c52ba77 460 }
68f2ce7a 461
5659ad2e 462 $boxesall = sqimap_mailbox_list_all($imap_stream);
48af4b64 463 $cmd = 'RENAME ' . sqimap_encode_mailbox_name($old_name) .
91e0dccc 464 ' ' . sqimap_encode_mailbox_name($new_name);
3411d4ec 465 $data = sqimap_run_command($imap_stream, $cmd, true, $response, $message);
1c52ba77 466 sqimap_unsubscribe($imap_stream, $old_name.$postfix);
5659ad2e 467 $oldpref_thread = getPref($data_dir, $username, 'thread_'.$old_name.$postfix);
468 $oldpref_collapse = getPref($data_dir, $username, 'collapse_folder_'.$old_name.$postfix);
68f2ce7a 469 removePref($data_dir, $username, 'thread_'.$old_name.$postfix);
5659ad2e 470 removePref($data_dir, $username, 'collapse_folder_'.$old_name.$postfix);
1c52ba77 471 sqimap_subscribe($imap_stream, $new_name.$postfix);
5659ad2e 472 setPref($data_dir, $username, 'thread_'.$new_name.$postfix, $oldpref_thread);
473 setPref($data_dir, $username, 'collapse_folder_'.$new_name.$postfix, $oldpref_collapse);
e429f014 474 do_hook_function('rename_or_delete_folder',$args = array($old_name, 'rename', $new_name));
648713af 475 $l = strlen( $old_name ) + 1;
476 $p = 'unformatted';
68f2ce7a 477
ff245fbd 478 foreach ($boxesall as $box) {
479 if (substr($box[$p], 0, $l) == $old_name . $delimiter) {
648713af 480 $new_sub = $new_name . $delimiter . substr($box[$p], $l);
5659ad2e 481 /* With Cyrus IMAPd >= 2.0 rename is recursive, so don't check for errors here */
648713af 482 if ($imap_server_type == 'cyrus') {
68f2ce7a 483 $cmd = 'RENAME "' . $box[$p] . '" "' . $new_sub . '"';
5659ad2e 484 $data = sqimap_run_command($imap_stream, $cmd, false,
648713af 485 $response, $message);
1c52ba77 486 }
5659ad2e 487 $was_subscribed = sqimap_mailbox_is_subscribed($imap_stream, $box[$p]);
488 if ( $was_subscribed ) {
489 sqimap_unsubscribe($imap_stream, $box[$p]);
490 }
491 $oldpref_thread = getPref($data_dir, $username, 'thread_'.$box[$p]);
492 $oldpref_collapse = getPref($data_dir, $username, 'collapse_folder_'.$box[$p]);
68f2ce7a 493 removePref($data_dir, $username, 'thread_'.$box[$p]);
5659ad2e 494 removePref($data_dir, $username, 'collapse_folder_'.$box[$p]);
495 if ( $was_subscribed ) {
496 sqimap_subscribe($imap_stream, $new_sub);
497 }
498 setPref($data_dir, $username, 'thread_'.$new_sub, $oldpref_thread);
499 setPref($data_dir, $username, 'collapse_folder_'.$new_sub, $oldpref_collapse);
68f2ce7a 500 do_hook_function('rename_or_delete_folder',
3411d4ec 501 $args = array($box[$p], 'rename', $new_sub));
1c52ba77 502 }
503 }
1c52ba77 504 }
1c52ba77 505}
43b698c7 506
48af4b64 507/**
86c2763d 508 * Formats a mailbox into parts for the $boxesall array
3411d4ec 509 *
86c2763d 510 * The parts are:
3411d4ec 511 *
512 * raw - Raw LIST/LSUB response from the IMAP server
513 * formatted - nicely formatted folder name
514 * unformatted - unformatted, but with delimiter at end removed
515 * unformatted-dm - folder name as it appears in raw response
516 * unformatted-disp - unformatted without $folder_prefix
517 */
518function sqimap_mailbox_parse ($line, $line_lsub) {
43b698c7 519 global $folder_prefix, $delimiter;
3411d4ec 520
43b698c7 521 /* Process each folder line */
cef054e4 522 for ($g = 0, $cnt = count($line); $g < $cnt; ++$g) {
43b698c7 523 /* Store the raw IMAP reply */
524 if (isset($line[$g])) {
e429f014 525 $boxesall[$g]['raw'] = $line[$g];
ff245fbd 526 } else {
e429f014 527 $boxesall[$g]['raw'] = '';
43b698c7 528 }
3411d4ec 529
43b698c7 530 /* Count number of delimiters ($delimiter) in folder name */
86c2763d 531 $mailbox = /*trim(*/$line_lsub[$g]/*)*/;
ff245fbd 532 $dm_count = substr_count($mailbox, $delimiter);
43b698c7 533 if (substr($mailbox, -1) == $delimiter) {
3411d4ec 534 /* If name ends in delimiter, decrement count by one */
535 $dm_count--;
43b698c7 536 }
3411d4ec 537
538 /* Format folder name, but only if it's a INBOX.* or has a parent. */
1da22cda 539 $boxesallbyname[$mailbox] = $g;
43b698c7 540 $parentfolder = readMailboxParent($mailbox, $delimiter);
541 if ( (strtolower(substr($mailbox, 0, 5)) == "inbox") ||
542 (substr($mailbox, 0, strlen($folder_prefix)) == $folder_prefix) ||
ff245fbd 543 (isset($boxesallbyname[$parentfolder]) &&
544 (strlen($parentfolder) > 0) ) ) {
545 $indent = $dm_count - (substr_count($folder_prefix, $delimiter));
43b698c7 546 if ($indent > 0) {
ff245fbd 547 $boxesall[$g]['formatted'] = str_repeat('&nbsp;&nbsp;', $indent);
548 } else {
1da22cda 549 $boxesall[$g]['formatted'] = '';
43b698c7 550 }
447b2166 551 $boxesall[$g]['formatted'] .= imap_utf7_decode_local(readShortMailboxName($mailbox, $delimiter));
ff245fbd 552 } else {
447b2166 553 $boxesall[$g]['formatted'] = imap_utf7_decode_local($mailbox);
43b698c7 554 }
90de1755 555
1da22cda 556 $boxesall[$g]['unformatted-dm'] = $mailbox;
43b698c7 557 if (substr($mailbox, -1) == $delimiter) {
8e9e8afa 558 $mailbox = substr($mailbox, 0, strlen($mailbox) - 1);
43b698c7 559 }
1da22cda 560 $boxesall[$g]['unformatted'] = $mailbox;
43b698c7 561 if (substr($mailbox,0,strlen($folder_prefix))==$folder_prefix) {
631b9da3 562 $mailbox = substr($mailbox, strlen($folder_prefix));
43b698c7 563 }
1da22cda 564 $boxesall[$g]['unformatted-disp'] = $mailbox;
565 $boxesall[$g]['id'] = $g;
90de1755 566
1da22cda 567 $boxesall[$g]['flags'] = array();
43b698c7 568 if (isset($line[$g])) {
36dfb0c9 569 ereg("\(([^)]*)\)",$line[$g],$regs);
4669e892 570 // FIXME Flags do contain the \ character. \NoSelect \NoInferiors
5c300c60 571 // and $MDNSent <= last one doesn't have the \
572 // It's better to follow RFC3501 instead of using our own naming.
1a7e1e97 573 $flags = trim(strtolower(str_replace('\\', '',$regs[1])));
43b698c7 574 if ($flags) {
1da22cda 575 $boxesall[$g]['flags'] = explode(' ', $flags);
43b698c7 576 }
577 }
578 }
1da22cda 579 return $boxesall;
43b698c7 580}
581
48af4b64 582/**
be2d5495 583 * Returns list of options (to be echoed into select statement
584 * based on available mailboxes and separators
6fd95361 585 * Caller should surround options with <select ...> </select> and
be2d5495 586 * any formatting.
587 * $imap_stream - $imapConnection to query for mailboxes
588 * $show_selected - array containing list of mailboxes to pre-select (0 if none)
589 * $folder_skip - array of folders to keep out of option list (compared in lower)
590 * $boxes - list of already fetched boxes (for places like folder panel, where
591 * you know these options will be shown 3 times in a row.. (most often unset).
59a8e3e8 592 * $flag - flag to check for in mailbox flags, used to filter out mailboxes.
593 * 'noselect' by default to remove unselectable mailboxes.
594 * 'noinferiors' used to filter out folders that can not contain subfolders.
595 * NULL to avoid flag check entirely.
d0928dd5 596 * NOTE: noselect and noiferiors are used internally. The IMAP representation is
597 * \NoSelect and \NoInferiors
59a8e3e8 598 * $use_long_format - override folder display preference and always show full folder name.
be2d5495 599 */
4669e892 600function sqimap_mailbox_option_list($imap_stream, $show_selected = 0, $folder_skip = 0, $boxes = 0,
59a8e3e8 601 $flag = 'noselect', $use_long_format = false ) {
be2d5495 602 global $username, $data_dir;
603 $mbox_options = '';
45f836eb 604 if ( $use_long_format ) {
605 $shorten_box_names = 0;
606 } else {
607 $shorten_box_names = getPref($data_dir, $username, 'mailbox_select_style', SMPREF_OFF);
608 }
ff245fbd 609
610 if ($boxes == 0) {
be2d5495 611 $boxes = sqimap_mailbox_list($imap_stream);
ff245fbd 612 }
59a8e3e8 613
be2d5495 614 foreach ($boxes as $boxes_part) {
4df5d823 615 if ($flag == NULL || (is_array($boxes_part['flags'])
616 && !in_array($flag, $boxes_part['flags']))) {
be2d5495 617 $box = $boxes_part['unformatted'];
be2d5495 618
d0928dd5 619 if ($folder_skip != 0 && in_array($box, $folder_skip) ) {
be2d5495 620 continue;
621 }
4669e892 622 $lowerbox = strtolower($box);
5c300c60 623 // mailboxes are casesensitive => inbox.sent != inbox.Sent
624 // nevermind, to many dependencies this should be fixed!
4669e892 625
d0928dd5 626 if (strtolower($box) == 'inbox') { // inbox is special and not casesensitive
be2d5495 627 $box2 = _("INBOX");
4669e892 628 } else {
5c300c60 629 switch ($shorten_box_names)
630 {
631 case 2: /* delimited, style = 2 */
c77a0487 632 $box2 = str_replace('&amp;nbsp;&amp;nbsp;', '.&nbsp;', htmlspecialchars($boxes_part['formatted']));
5c300c60 633 break;
d0928dd5 634 case 1: /* indent, style = 1 */
c77a0487 635 $box2 = str_replace('&amp;nbsp;&amp;nbsp;', '&nbsp;&nbsp;', htmlspecialchars($boxes_part['formatted']));
5c300c60 636 break;
d0928dd5 637 default: /* default, long names, style = 0 */
6c4f0fa1 638 $box2 = str_replace(' ', '&nbsp;', htmlspecialchars(imap_utf7_decode_local($boxes_part['unformatted-disp'])));
5c300c60 639 break;
640 }
be2d5495 641 }
642 if ($show_selected != 0 && in_array($lowerbox, $show_selected) ) {
ff0969a0 643 $mbox_options .= '<option value="' . htmlspecialchars($box) .'" selected="selected">'.$box2.'</option>' . "\n";
be2d5495 644 } else {
ff0969a0 645 $mbox_options .= '<option value="' . htmlspecialchars($box) .'">'.$box2.'</option>' . "\n";
be2d5495 646 }
647 }
648 }
649 return $mbox_options;
650}
43b698c7 651
48af4b64 652/**
4669e892 653 * Returns sorted mailbox lists in several different ways.
3411d4ec 654 * See comment on sqimap_mailbox_parse() for info about the returned array.
3e9441a2 655 * @param resource $imap_stream imap connection resource
656 * @param boolean $force force update of mailbox listing. available since 1.4.2 and 1.5.0
657 * @return array list of mailboxes
3411d4ec 658 */
fe6efa94 659function sqimap_mailbox_list($imap_stream, $force=false) {
fe6efa94 660 if (!sqgetGlobalVar('boxesnew',$boxesnew,SQ_SESSION) || $force) {
3411d4ec 661 global $data_dir, $username, $list_special_folders_first,
7e235a1a 662 $folder_prefix, $trash_folder, $sent_folder, $draft_folder,
663 $move_to_trash, $move_to_sent, $save_as_draft,
4d5f2b31 664 $delimiter, $noselect_fix_enable, $imap_server_type,
665 $show_only_subscribed_folders;
3411d4ec 666 $inbox_subscribed = false;
60a132f8 667 $listsubscribed = sqimap_capability($imap_stream,'LIST-SUBSCRIBED');
7e235a1a 668
08185f2a 669 require_once(SM_PATH . 'include/load_prefs.php');
7e235a1a 670
4d5f2b31 671 if (!$show_only_subscribed_folders) {
672 $lsub = 'LIST';
673 } elseif ($listsubscribed) {
60a132f8 674 $lsub = 'LIST (SUBSCRIBED)';
675 } else {
676 $lsub = 'LSUB';
4669e892 677 }
678
ff245fbd 679 if ($noselect_fix_enable) {
60a132f8 680 $lsub_args = "$lsub \"$folder_prefix\" \"*%\"";
ff245fbd 681 } else {
60a132f8 682 $lsub_args = "$lsub \"$folder_prefix\" \"*\"";
ff245fbd 683 }
3411d4ec 684 /* LSUB array */
ca85aabe 685 $lsub_ary = sqimap_run_command ($imap_stream, $lsub_args,
3411d4ec 686 true, $response, $message);
4669e892 687 $lsub_ary = compact_mailboxes_response($lsub_ary);
7e235a1a 688
7e235a1a 689 $sorted_lsub_ary = array();
ff245fbd 690 for ($i = 0, $cnt = count($lsub_ary);$i < $cnt; $i++) {
159d2af7 691
7e235a1a 692 $temp_mailbox_name = find_mailbox_name($lsub_ary[$i]);
693 $sorted_lsub_ary[] = $temp_mailbox_name;
cef054e4 694 if (!$inbox_subscribed && strtoupper($temp_mailbox_name) == 'INBOX') {
3411d4ec 695 $inbox_subscribed = true;
7e235a1a 696 }
697 }
cef054e4 698
5c300c60 699 /* natural sort mailboxes */
7e235a1a 700 if (isset($sorted_lsub_ary)) {
159d2af7 701 usort($sorted_lsub_ary, 'strnatcasecmp');
7e235a1a 702 }
5c300c60 703 /*
704 * The LSUB response doesn't provide us information about \Noselect
705 * mail boxes. The LIST response does, that's why we need to do a LIST
706 * call to retrieve the flags for the mailbox
cef054e4 707 * Note: according RFC2060 an imap server may provide \NoSelect flags in the LSUB response.
708 * in other words, we cannot rely on it.
fe6efa94 709 */
cef054e4 710 $sorted_list_ary = array();
60a132f8 711 // if (!$listsubscribed) {
712 for ($i=0; $i < count($sorted_lsub_ary); $i++) {
7e235a1a 713 if (substr($sorted_lsub_ary[$i], -1) == $delimiter) {
714 $mbx = substr($sorted_lsub_ary[$i], 0, strlen($sorted_lsub_ary[$i])-1);
715 }
716 else {
717 $mbx = $sorted_lsub_ary[$i];
718 }
fe6efa94 719
159d2af7 720 $read = sqimap_run_command ($imap_stream, 'LIST "" ' . sqimap_encode_mailbox_name($mbx),
3411d4ec 721 true, $response, $message);
4669e892 722
159d2af7 723 $read = compact_mailboxes_response($read);
4669e892 724
7e235a1a 725 if (isset($read[0])) {
726 $sorted_list_ary[$i] = $read[0];
cef054e4 727 } else {
7e235a1a 728 $sorted_list_ary[$i] = '';
729 }
60a132f8 730 }
731 // }
3411d4ec 732 /*
7e235a1a 733 * Just in case they're not subscribed to their inbox,
734 * we'll get it for them anyway
735 */
cef054e4 736 if (!$inbox_subscribed) {
159d2af7 737 $inbox_ary = sqimap_run_command ($imap_stream, 'LIST "" "INBOX"',
3411d4ec 738 true, $response, $message);
159d2af7 739 $sorted_list_ary[] = implode('',compact_mailboxes_response($inbox_ary));
7e235a1a 740 $sorted_lsub_ary[] = find_mailbox_name($inbox_ary[0]);
741 }
742
743 $boxesall = sqimap_mailbox_parse ($sorted_list_ary, $sorted_lsub_ary);
744
3411d4ec 745 /* Now, lets sort for special folders */
7e235a1a 746 $boxesnew = $used = array();
747
748 /* Find INBOX */
ff245fbd 749 $cnt = count($boxesall);
5c300c60 750 $used = array_pad($used,$cnt,false);
cef054e4 751 for($k = 0; $k < $cnt; ++$k) {
ff245fbd 752 if (strtolower($boxesall[$k]['unformatted']) == 'inbox') {
753 $boxesnew[] = $boxesall[$k];
3411d4ec 754 $used[$k] = true;
5c300c60 755 break;
7e235a1a 756 }
757 }
7e235a1a 758 /* List special folders and their subfolders, if requested. */
3411d4ec 759 if ($list_special_folders_first) {
cef054e4 760 for($k = 0; $k < $cnt; ++$k) {
ff245fbd 761 if (!$used[$k] && isSpecialMailbox($boxesall[$k]['unformatted'])) {
762 $boxesnew[] = $boxesall[$k];
763 $used[$k] = true;
7e235a1a 764 }
5c300c60 765 }
766 }
c3ce607e 767
768 /* Find INBOX's children */
769 for($k = 0; $k < $cnt; ++$k) {
66c1aad9 770 if (!$used[$k] && isBoxBelow(strtolower($boxesall[$k]['unformatted']), 'inbox') &&
771 strtolower($boxesall[$k]['unformatted']) != 'inbox') {
c3ce607e 772 $boxesnew[] = $boxesall[$k];
773 $used[$k] = true;
774 }
775 }
776
777 /* Rest of the folders */
ff245fbd 778 for($k = 0; $k < $cnt; $k++) {
779 if (!$used[$k]) {
780 $boxesnew[] = $boxesall[$k];
7e235a1a 781 }
782 }
fe6efa94 783 sqsession_register($boxesnew,'boxesnew');
43b698c7 784 }
3411d4ec 785 return $boxesnew;
43b698c7 786}
787
48af4b64 788/**
90de1755 789 * Returns a list of all folders, subscribed or not
790 */
1da22cda 791function sqimap_mailbox_list_all($imap_stream) {
3411d4ec 792 global $list_special_folders_first, $folder_prefix, $delimiter;
bac13dd7 793
794 $read_ary = sqimap_run_command($imap_stream,"LIST \"$folder_prefix\" *",true,$response, $message,false);
795 $read_ary = compact_mailboxes_response($read_ary);
796
43b698c7 797 $g = 0;
7d82bceb 798 $fld_pre_length = strlen($folder_prefix);
ff245fbd 799 for ($i = 0, $cnt = count($read_ary); $i < $cnt; $i++) {
780dd344 800 /* Store the raw IMAP reply */
801 $boxes[$g]['raw'] = $read_ary[$i];
90de1755 802
780dd344 803 /* Count number of delimiters ($delimiter) in folder name */
804 $mailbox = find_mailbox_name($read_ary[$i]);
805 $dm_count = substr_count($mailbox, $delimiter);
806 if (substr($mailbox, -1) == $delimiter) {
807 /* If name ends in delimiter - decrement count by one */
808 $dm_count--;
809 }
90de1755 810
780dd344 811 /* Format folder name, but only if it's a INBOX.* or has a parent. */
812 $boxesallbyname[$mailbox] = $g;
813 $parentfolder = readMailboxParent($mailbox, $delimiter);
814 if((eregi('^inbox'.quotemeta($delimiter), $mailbox)) ||
815 (ereg('^'.$folder_prefix, $mailbox)) ||
816 ( isset($boxesallbyname[$parentfolder]) && (strlen($parentfolder) > 0) ) ) {
817 if ($dm_count) {
818 $boxes[$g]['formatted'] = str_repeat('&nbsp;&nbsp;', $dm_count);
90de1755 819 } else {
780dd344 820 $boxes[$g]['formatted'] = '';
12d61439 821 }
780dd344 822 $boxes[$g]['formatted'] .= imap_utf7_decode_local(readShortMailboxName($mailbox, $delimiter));
823 } else {
824 $boxes[$g]['formatted'] = imap_utf7_decode_local($mailbox);
825 }
826
827 $boxes[$g]['unformatted-dm'] = $mailbox;
828 if (substr($mailbox, -1) == $delimiter) {
829 $mailbox = substr($mailbox, 0, strlen($mailbox) - 1);
830 }
831 $boxes[$g]['unformatted'] = $mailbox;
832 $boxes[$g]['unformatted-disp'] = substr($mailbox,$fld_pre_length);
833
834 $boxes[$g]['id'] = $g;
835
836 /* Now lets get the flags for this mailbox */
837 $read_mlbx = $read_ary[$i];
838 $flags = substr($read_mlbx, strpos($read_mlbx, '(')+1);
839 $flags = substr($flags, 0, strpos($flags, ')'));
840 $flags = str_replace('\\', '', $flags);
841 $flags = trim(strtolower($flags));
842 if ($flags) {
843 $boxes[$g]['flags'] = explode(' ', $flags);
844 } else {
845 $boxes[$g]['flags'] = array();
43b698c7 846 }
847 $g++;
848 }
849 if(is_array($boxes)) {
e429f014 850 sort ($boxes);
43b698c7 851 }
90de1755 852
43b698c7 853 return $boxes;
854}
5bdd7223 855
60b5724d 856function sqimap_mailbox_tree($imap_stream) {
ce68b76b 857 global $default_folder_prefix;
60a132f8 858 if (true) {
60b5724d 859 global $data_dir, $username, $list_special_folders_first,
a2e66c6d 860 $folder_prefix, $delimiter, $trash_folder, $move_to_trash,
4d5f2b31 861 $imap_server_type, $show_only_subscribed_folders;
60b5724d 862
f08ba804 863 $noselect = false;
86c2763d 864 $noinferiors = false;
60b5724d 865
08185f2a 866 require_once(SM_PATH . 'include/load_prefs.php');
60b5724d 867
4d5f2b31 868 if ($show_only_subscribed_folders) {
869 $lsub_cmd = 'LSUB';
870 } else {
871 $lsub_cmd = 'LIST';
872 }
873
60b5724d 874 /* LSUB array */
4d5f2b31 875 $lsub_ary = sqimap_run_command ($imap_stream, "$lsub_cmd \"$folder_prefix\" \"*\"",
60b5724d 876 true, $response, $message);
bac13dd7 877 $lsub_ary = compact_mailboxes_response($lsub_ary);
60b5724d 878
9871bdaa 879 /* Check to see if we have an INBOX */
78bc908d 880 $has_inbox = false;
881
882 for ($i = 0, $cnt = count($lsub_ary); $i < $cnt; $i++) {
4d5f2b31 883 if (preg_match("/^\*\s+$lsub_cmd.*\s\"?INBOX\"?[^(\/\.)].*$/i",$lsub_ary[$i])) {
9d8d1ebd 884 $lsub_ary[$i] = strtoupper($lsub_ary[$i]);
31a5064d 885 // in case of an unsubscribed inbox an imap server can
4669e892 886 // return the inbox in the lsub results with a \NoSelect
31a5064d 887 // flag.
4d5f2b31 888 if (!preg_match("/\*\s+$lsub_cmd\s+\(.*\\\\NoSelect.*\).*/i",$lsub_ary[$i])) {
31a5064d 889 $has_inbox = true;
890 } else {
891 // remove the result and request it again with a list
892 // response at a later stage.
893 unset($lsub_ary[$i]);
4669e892 894 // re-index the array otherwise the addition of the LIST
35314c5c 895 // response will fail in PHP 4.1.2 and probably other older versions
896 $lsub_ary = array_values($lsub_ary);
31a5064d 897 }
78bc908d 898 break;
899 }
900 }
901
902 if ($has_inbox == false) {
31a5064d 903 // do a list request for inbox because we should always show
904 // inbox even if the user isn't subscribed to it.
3d29eb78 905 $inbox_ary = sqimap_run_command ($imap_stream, 'LIST "" "INBOX"',
31a5064d 906 true, $response, $message);
907 $inbox_ary = compact_mailboxes_response($inbox_ary);
908 if (count($inbox_ary)) {
909 $lsub_ary[] = $inbox_ary[0];
910 }
78bc908d 911 }
912
60b5724d 913 /*
4669e892 914 * Section about removing the last element was removed
60b5724d 915 * We don't return "* OK" anymore from sqimap_read_data
916 */
bac13dd7 917
60b5724d 918 $sorted_lsub_ary = array();
e4c6fe41 919 $cnt = count($lsub_ary);
ff245fbd 920 for ($i = 0; $i < $cnt; $i++) {
ff245fbd 921 $mbx = find_mailbox_name($lsub_ary[$i]);
a2e66c6d 922
483f9ef9 923 // only do the noselect test if !uw, is checked later. FIX ME see conf.pl setting
4669e892 924 if ($imap_server_type != "uw") {
483f9ef9 925 $noselect = check_is_noselect($lsub_ary[$i]);
86c2763d 926 $noinferiors = check_is_noinferiors($lsub_ary[$i]);
a2e66c6d 927 }
ff245fbd 928 if (substr($mbx, -1) == $delimiter) {
929 $mbx = substr($mbx, 0, strlen($mbx) - 1);
930 }
4669e892 931 $sorted_lsub_ary[] = array ('mbx' => $mbx, 'noselect' => $noselect, 'noinferiors' => $noinferiors);
60b5724d 932 }
5c300c60 933 // FIX ME this requires a config setting inside conf.pl instead of checking on server type
483f9ef9 934 if ($imap_server_type == "uw") {
5c300c60 935 $aQuery = array();
936 $aTag = array();
937 // prepare an array with queries
938 foreach ($sorted_lsub_ary as $aMbx) {
bac13dd7 939 $mbx = stripslashes($aMbx['mbx']);
568cb884 940 sqimap_prepare_pipelined_query('LIST "" ' . sqimap_encode_mailbox_name($mbx), $tag, $aQuery, false);
5c300c60 941 $aTag[$tag] = $mbx;
4669e892 942 }
5c300c60 943 $sorted_lsub_ary = array();
944 // execute all the queries at once
945 $aResponse = sqimap_run_pipelined_command ($imap_stream, $aQuery, false, $aServerResponse, $aServerMessage);
946 foreach($aTag as $tag => $mbx) {
947 if ($aServerResponse[$tag] == 'OK') {
948 $sResponse = implode('', $aResponse[$tag]);
949 $noselect = check_is_noselect($sResponse);
86c2763d 950 $noinferiors = check_is_noinferiors($sResponse);
951 $sorted_lsub_ary[] = array ('mbx' => $mbx, 'noselect' => $noselect, 'noinferiors' => $noinferiors);
5c300c60 952 }
953 }
954 $cnt = count($sorted_lsub_ary);
483f9ef9 955 }
bac13dd7 956 $sorted_lsub_ary = array_values($sorted_lsub_ary);
9d8d1ebd 957 usort($sorted_lsub_ary, 'mbxSort');
d1404257 958 $boxestree = sqimap_fill_mailbox_tree($sorted_lsub_ary,false,$imap_stream);
959 return $boxestree;
60b5724d 960 }
961}
962
9d8d1ebd 963function mbxSort($a, $b) {
964 return strnatcasecmp($a['mbx'], $b['mbx']);
965}
966
483f9ef9 967function sqimap_fill_mailbox_tree($mbx_ary, $mbxs=false,$imap_stream) {
60b5724d 968 global $data_dir, $username, $list_special_folders_first,
969 $folder_prefix, $trash_folder, $sent_folder, $draft_folder,
970 $move_to_trash, $move_to_sent, $save_as_draft,
43a31298 971 $delimiter, $imap_server_type;
60b5724d 972
8d8da447 973 // $special_folders = array ('INBOX', $sent_folder, $draft_folder, $trash_folder);
ff245fbd 974
60b5724d 975 /* create virtual root node */
976 $mailboxes= new mailboxes();
977 $mailboxes->is_root = true;
ff245fbd 978 $trail_del = false;
78bc908d 979 $start = 0;
980
587ec647 981
43a31298 982 if (isset($folder_prefix) && ($folder_prefix != '')) {
ff245fbd 983 $start = substr_count($folder_prefix,$delimiter);
984 if (strrpos($folder_prefix, $delimiter) == (strlen($folder_prefix)-1)) {
ff245fbd 985 $mailboxes->mailboxname_full = substr($folder_prefix,0, (strlen($folder_prefix)-1));
986 } else {
987 $mailboxes->mailboxname_full = $folder_prefix;
988 $start++;
989 }
990 $mailboxes->mailboxname_sub = $mailboxes->mailboxname_full;
991 } else {
992 $start = 0;
993 }
78bc908d 994
9d8d1ebd 995 $cnt = count($mbx_ary);
e4c6fe41 996 for ($i=0; $i < $cnt; $i++) {
ff245fbd 997 if ($mbx_ary[$i]['mbx'] !='' ) {
998 $mbx = new mailboxes();
999 $mailbox = $mbx_ary[$i]['mbx'];
cc82c2b7 1000
4669e892 1001 /*
cc82c2b7 1002 sent subfolders messes up using existing code as subfolders
1003 were marked, but the parents were ordered somewhere else in
1004 the list, despite having "special folders at top" option set.
1005 Need a better method than this.
97a5e85f 1006 */
8edc9f31 1007/*
97a5e85f 1008 if ($mailbox == 'INBOX') {
1009 $mbx->is_special = true;
1010 } elseif (stristr($trash_folder , $mailbox)) {
1011 $mbx->is_special = true;
1012 } elseif (stristr($sent_folder , $mailbox)) {
1013 $mbx->is_special = true;
1014 } elseif (stristr($draft_folder , $mailbox)) {
1015 $mbx->is_special = true;
1016 }
cc82c2b7 1017
ff245fbd 1018 switch ($mailbox) {
1019 case 'INBOX':
1020 $mbx->is_inbox = true;
1021 $mbx->is_special = true;
8edc9f31 1022 $mbx_ary[$i]['noselect'] = false;
ff245fbd 1023 break;
1024 case $trash_folder:
1025 $mbx->is_trash = true;
1026 $mbx->is_special = true;
1027 break;
1028 case $sent_folder:
1029 $mbx->is_sent = true;
1030 $mbx->is_special = true;
1031 break;
1032 case $draft_folder:
1033 $mbx->is_draft = true;
1034 $mbx->is_special = true;
1035 break;
1036 }
8edc9f31 1037*/
1038 $mbx->is_special |= ($mbx->is_inbox = (strtoupper($mailbox) == 'INBOX'));
1039 $mbx->is_special |= ($mbx->is_trash = isTrashMailbox($mailbox));
1040 $mbx->is_special |= ($mbx->is_sent = isSentMailbox($mailbox));
1041 $mbx->is_special |= ($mbx->is_draft = isDraftMailbox($mailbox));
1042 if (!$mbx->is_special)
fda01075 1043 $mbx->is_special = boolean_hook_function('special_mailbox', $mailbox, 1);
4669e892 1044
ff245fbd 1045 if (isset($mbx_ary[$i]['unseen'])) {
1046 $mbx->unseen = $mbx_ary[$i]['unseen'];
1047 }
1048 if (isset($mbx_ary[$i]['nummessages'])) {
1049 $mbx->total = $mbx_ary[$i]['nummessages'];
1050 }
1051
1052 $mbx->is_noselect = $mbx_ary[$i]['noselect'];
86c2763d 1053 $mbx->is_noinferiors = $mbx_ary[$i]['noinferiors'];
ff245fbd 1054
60b5724d 1055 $r_del_pos = strrpos($mbx_ary[$i]['mbx'], $delimiter);
ff245fbd 1056 if ($r_del_pos) {
587ec647 1057 $mbx->mailboxname_sub = substr($mbx_ary[$i]['mbx'],$r_del_pos+1);
ff245fbd 1058 } else { /* mailbox is root folder */
587ec647 1059 $mbx->mailboxname_sub = $mbx_ary[$i]['mbx'];
ff245fbd 1060 }
1061 $mbx->mailboxname_full = $mbx_ary[$i]['mbx'];
38068e69 1062
9871bdaa 1063 $mailboxes->addMbx($mbx, $delimiter, $start, $list_special_folders_first);
ff245fbd 1064 }
60b5724d 1065 }
587ec647 1066 sqimap_utf7_decode_mbx_tree($mailboxes);
483f9ef9 1067 sqimap_get_status_mbx_tree($imap_stream,$mailboxes);
60b5724d 1068 return $mailboxes;
1069}
259faa39 1070
587ec647 1071function sqimap_utf7_decode_mbx_tree(&$mbx_tree) {
bd27b70b 1072 if (strtoupper($mbx_tree->mailboxname_full) == 'INBOX')
d94c8d61 1073 $mbx_tree->mailboxname_sub = _("INBOX");
1074 else
1075 $mbx_tree->mailboxname_sub = imap_utf7_decode_local($mbx_tree->mailboxname_sub);
587ec647 1076 if ($mbx_tree->mbxs) {
1077 $iCnt = count($mbx_tree->mbxs);
1078 for ($i=0;$i<$iCnt;++$i) {
d94c8d61 1079 $mbxs_tree->mbxs[$i] = sqimap_utf7_decode_mbx_tree($mbx_tree->mbxs[$i]);
587ec647 1080 }
1081 }
483f9ef9 1082}
1083
1084
1085function sqimap_tree_to_ref_array(&$mbx_tree,&$aMbxs) {
5c300c60 1086 if ($mbx_tree)
483f9ef9 1087 $aMbxs[] =& $mbx_tree;
1088 if ($mbx_tree->mbxs) {
1089 $iCnt = count($mbx_tree->mbxs);
1090 for ($i=0;$i<$iCnt;++$i) {
5c300c60 1091 sqimap_tree_to_ref_array($mbx_tree->mbxs[$i],$aMbxs);
483f9ef9 1092 }
1093 }
4669e892 1094}
483f9ef9 1095
483f9ef9 1096function sqimap_get_status_mbx_tree($imap_stream,&$mbx_tree) {
1097 global $unseen_notify, $unseen_type, $trash_folder,$move_to_trash;
8d8da447 1098 $aMbxs = $aQuery = array();
483f9ef9 1099 sqimap_tree_to_ref_array($mbx_tree,$aMbxs);
1100 // remove the root node
1101 array_shift($aMbxs);
1102
1103 if($unseen_notify == 3) {
1104 $cnt = count($aMbxs);
1105 for($i=0;$i<$cnt;++$i) {
5c300c60 1106 $oMbx =& $aMbxs[$i];
1107 if (!$oMbx->is_noselect) {
483f9ef9 1108 $mbx = $oMbx->mailboxname_full;
5c300c60 1109 if ($unseen_type == 2 ||
1110 ($move_to_trash && $oMbx->mailboxname_full == $trash_folder)) {
568cb884 1111 $query = 'STATUS ' . sqimap_encode_mailbox_name($mbx) . ' (MESSAGES UNSEEN)';
5c300c60 1112 } else {
568cb884 1113 $query = 'STATUS ' . sqimap_encode_mailbox_name($mbx) . ' (UNSEEN)';
5c300c60 1114 }
483f9ef9 1115 sqimap_prepare_pipelined_query($query,$tag,$aQuery,false);
5c300c60 1116 } else {
1117 $oMbx->unseen = $oMbx->total = false;
1118 $tag = false;
1119 }
1120 $oMbx->tag = $tag;
1121 $aMbxs[$i] =& $oMbx;
483f9ef9 1122 }
1123 // execute all the queries at once
1124 $aResponse = sqimap_run_pipelined_command ($imap_stream, $aQuery, false, $aServerResponse, $aServerMessage);
1125 $cnt = count($aMbxs);
1126 for($i=0;$i<$cnt;++$i) {
5c300c60 1127 $oMbx =& $aMbxs[$i];
1128 $tag = $oMbx->tag;
1129 if ($tag && $aServerResponse[$tag] == 'OK') {
1130 $sResponse = implode('', $aResponse[$tag]);
483f9ef9 1131 if (preg_match('/UNSEEN\s+([0-9]+)/i', $sResponse, $regs)) {
1132 $oMbx->unseen = $regs[1];
1133 }
1134 if (preg_match('/MESSAGES\s+([0-9]+)/i', $sResponse, $regs)) {
1135 $oMbx->total = $regs[1];
5c300c60 1136 }
1137 }
1138 unset($oMbx->tag);
1139 }
483f9ef9 1140 } else if ($unseen_notify == 2) { // INBOX only
1141 $cnt = count($aMbxs);
1142 for($i=0;$i<$cnt;++$i) {
5c300c60 1143 $oMbx =& $aMbxs[$i];
1144 if (strtoupper($oMbx->mailboxname_full) == 'INBOX' ||
1145 ($move_to_trash && $oMbx->mailboxname_full == $trash_folder)) {
4669e892 1146 if ($unseen_type == 2 ||
5c300c60 1147 ($oMbx->mailboxname_full == $trash_folder && $move_to_trash)) {
1148 $aStatus = sqimap_status_messages($imap_stream,$oMbx->mailboxname_full);
1149 $oMbx->unseen = $aStatus['UNSEEN'];
1150 $oMbx->total = $aStatus['MESSAGES'];
1151 } else {
1152 $oMbx->unseen = sqimap_unseen_messages($imap_stream,$oMbx->mailboxname_full);
1153 }
1154 $aMbxs[$i] =& $oMbx;
1155 if (!$move_to_trash && $trash_folder) {
1156 break;
1157 } else {
1158 // trash comes after INBOX
1159 if ($oMbx->mailboxname_full == $trash_folder) {
1160 break;
1161 }
1162 }
1163 }
1164 }
4669e892 1165 }
1166}
587ec647 1167
3d29eb78 1168?>