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