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