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