Source for file imap_mailbox.php
Documentation is available at imap_mailbox.php
* This implements all functions that manipulate mailboxes
* @copyright © 1999-2006 The SquirrelMail Project Team
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @version $Id: imap_mailbox.php,v 1.277 2006/09/30 07:34:47 tokul Exp $
require_once(SM_PATH .
'functions/imap_utf7_local.php');
* FIXME. This class should be extracted and placed in a separate file that
* can be included before we start the session. That makes caching of the tree
* possible. On a refresh mailboxes from left_main.php the only function that
* should be called is the sqimap_get_status_mbx_tree. In case of subscribe
* / rename / delete / new we have to create methods for adding/changing the
* mailbox in the mbx_tree without the need for a refresh.
* Some code fragments are present in 1.3.0 - 1.4.4.
function addMbx($mbx, $delimiter, $start, $specialfirst) {
$ary =
explode($delimiter, $mbx->mailboxname_full);
for ($i =
$start, $c =
count($ary)-
1; $i <
$c; $i++
) {
$mbx_childs =
& $mbx_parent->mbxs;
foreach ($mbx_childs as $key =>
$parent) {
if ($parent->mailboxname_sub ==
$ary[$i]) {
$mbx_parent =
& $mbx_parent->mbxs[$key];
if (isset
($mbx_parent->mailboxname_full) &&
$mbx_parent->mailboxname_full !=
'') {
$no_select_mbx->mailboxname_full =
$mbx_parent->mailboxname_full.
$delimiter.
$ary[$i];
$no_select_mbx->mailboxname_full =
$ary[$i];
$no_select_mbx->mailboxname_sub =
$ary[$i];
$no_select_mbx->is_noselect =
true;
$mbx_parent->mbxs[] =
$no_select_mbx;
$mbx_parent->mbxs[] =
$mbx;
if ($mbx->is_special &&
$specialfirst) {
usort($mbx_parent->mbxs, 'sortSpecialMbx');
* array callback used for sorting in mailboxes class
* @return integer see php strnatcasecmp()
* Workaround for mailboxes returned as literal
* FIXME : Doesn't work if the mailbox name is multiple lines
* (larger then fgets buffer)
for ($i =
0, $iCnt=
count($ary); $i <
$iCnt; $i++
) {
if (isset
($ary[$i +
1]) &&
substr($ary[$i], -
3) ==
"}\r\n") {
if (ereg("^(\\* [A-Z]+.*)\\{[0-9]+\\}([ \n\r\t]*)$",
$ary[$i] =
$regs[1] .
'"' .
addslashes(trim($ary[$i+
1])) .
'"' .
$regs[2];
/* remove duplicates and ensure array is contiguous */
* Extract the mailbox name from an untagged LIST (7.2.2) or LSUB (7.2.3) answer
* (LIST|LSUB) (<Flags list>) (NIL|"<separator atom>") <mailbox name string>\r\n
* mailbox name in quoted string MUST be unquoted and stripslashed (sm API)
* Originally stored in functions/strings.php. Since 1.2.6 stored in
* functions/imap_mailbox.php
* @param string $line imap LIST/LSUB response line
* @return string mailbox name
if (preg_match('/^\* (?:LIST|LSUB) \([^\)]*\) (?:NIL|\"[^\"]*\") ([^\r\n]*)[\r\n]*$/i', $line, $regs)) {
if (substr($regs[1], 0, 1) ==
'"')
* Detects if mailbox has noselect flag (can't store messages)
* In versions older than 1.4.5 function checks only LSUB responses
* and can produce pcre warnings.
* @param string $lsub_line mailbox line from untagged LIST or LSUB response
* @return bool whether this is a Noselect mailbox.
return preg_match("/^\* (LSUB|LIST) \([^\)]*\\\\Noselect[^\)]*\)/i", $lsub_line);
* Detects if mailbox has noinferiors flag (can't store subfolders)
* @param string $lsub_line mailbox line from untagged LIST or LSUB response
* @return bool whether this is a Noinferiors mailbox.
return preg_match("/^\* (LSUB|LIST) \([^\)]*\\\\Noinferiors[^\)]*\)/i", $lsub_line);
* Detects mailbox's parent folder
* If $haystack is a full mailbox name, and $needle is the mailbox
* separator character, returns the second last part of the full
* mailbox name (i.e. the mailbox's parent mailbox)
* Originally stored in functions/strings.php. Since 1.2.6 stored in
* functions/imap_mailbox.php
* @param string $haystack full mailbox name
* @param string $needle delimiter
* @return string parent mailbox
$parts =
explode($needle, $haystack);
while ($elem ==
'' &&
count($parts)) {
$ret =
join($needle, $parts);
* Check if $subbox is below the specified $parentbox
* @param string $subbox potential sub folder
* @param string $parentbox potential parent
* Eliminate the obvious mismatch, where the
* subfolder path is shorter than that of the potential parent
/* check for delimiter */
if (substr($parentbox,-
1) !=
$delimiter) {
$parentbox .=
$delimiter;
return (substr($subbox,0,strlen($parentbox)) ==
$parentbox);
* Defines special mailboxes: given a mailbox name, it checks if this is a
* "special" one: INBOX, Trash, Sent or Draft.
* Since 1.2.5 function includes special_mailbox hook.<br>
* Since 1.4.3 hook supports more than one plugin.
* @param string $box mailbox name
* @param boolean $include_subs (since 1.5.2) if true, subfolders of system
* folders are special. if false, subfolders are not special mailboxes
* unless they are tagged as special in 'special_mailbox' hook.
* Detects if mailbox is a Trash folder or subfolder of Trash
* @param string $box mailbox name
* @param boolean $include_subs (since 1.5.2) if true, subfolders of system
* folders are special. if false, subfolders are not special mailboxes.
* @return bool whether this is a Trash folder
global $trash_folder, $move_to_trash;
return $move_to_trash &&
$trash_folder &&
( $box ==
$trash_folder ||
($include_subs &&
isBoxBelow($box, $trash_folder)) );
* Detects if mailbox is a Sent folder or subfolder of Sent
* @param string $box mailbox name
* @param boolean $include_subs (since 1.5.2) if true, subfolders of system
* folders are special. if false, subfolders are not special mailboxes.
* @return bool whether this is a Sent folder
global $sent_folder, $move_to_sent;
return $move_to_sent &&
$sent_folder &&
( $box ==
$sent_folder ||
($include_subs &&
isBoxBelow($box, $sent_folder)) );
* Detects if mailbox is a Drafts folder or subfolder of Drafts
* @param string $box mailbox name
* @param boolean $include_subs (since 1.5.2) if true, subfolders of system
* folders are special. if false, subfolders are not special mailboxes.
* @return bool whether this is a Draft folder
global $draft_folder, $save_as_draft;
( $box ==
$draft_folder ||
($include_subs &&
isBoxBelow($box, $draft_folder)) );
* WARNING: Select mailbox before calling this function.
* permanently removes all messages that have the \Deleted flag
* set from the selected mailbox. See EXPUNGE command chapter in
* @param stream $imap_stream imap connection resource
* @param string $mailbox mailbox name (unused since 1.1.3).
* @param boolean $handle_errors error handling control (displays error_box on error).
* @param mixed $id (since 1.3.0) integer message id or array with integer ids
* @return integer number of expunged messages
$response, $message, $uid);
if (preg_match('/^\*\s[0-9]+\sEXPUNGE/AUi',$r,$regs)) {
* Checks whether or not the specified mailbox exists
* @param stream $imap_stream imap connection resource
* @param string $mailbox mailbox name
* @param array $mailboxlist (since 1.5.1) optional array of mailboxes from
* sqimap_get_mailboxes() (to avoid having to talk to imap server)
if (!isset
($mailbox) ||
empty($mailbox)) {
// use previously retrieved mailbox list
foreach ($mailboxlist as $mbox) {
if ($mbox['unformatted-dm'] ==
$mailbox) { return true; }
true, $response, $message);
* Before 1.3.0 used more arguments and returned data depended on those arguments.
* @param stream $imap_stream imap connection resource
* @param string $mailbox mailbox name
* @return array results of select command (on success - permanentflags, flags and rights)
// FIX ME: WHAAAA DO NOT USE "None" for something that does not exist. Use false or NULL instead
if ($mailbox ==
'None') {
// cleanup $mailbox in order to prevent IMAP injection attacks
$mailbox =
str_replace(array("\r","\n"), array("",""),$mailbox);
* Default UW IMAP server configuration allows to access other files
* on server. $imap_server_type is not checked because interface can
* be used with 'other' or any other server type setting. $mailbox
* variable can be modified in any script that uses variable from GET
* or POST. This code blocks all standard SquirrelMail IMAP API requests
* that use mailbox with full path (/etc/passwd) or with ../ characters
* in path (../../etc/passwd)
if (strstr($mailbox, '../') ||
substr($mailbox, 0, 1) ==
'/') {
$oTemplate->display('footer.tpl');
true, $response, $message);
for ($i =
0, $cnt =
count($read); $i <
$cnt; $i++
) {
if (preg_match('/^\*\s+OK\s\[(\w+)\s(\w+)\]/',$read[$i], $regs)) {
} else if (preg_match('/^\*\s([0-9]+)\s(\w+)/',$read[$i], $regs)) {
if (preg_match("/PERMANENTFLAGS(.*)/i",$read[$i], $regs)) {
} else if (preg_match("/FLAGS(.*)/i",$read[$i], $regs)) {
if (!isset
($result['PERMANENTFLAGS'])) {
$result['PERMANENTFLAGS'] =
$result['FLAGS'];
* Mailbox is automatically subscribed.
* Set $type to string that does not match 'noselect' (case insensitive),
* if you don't want to prepend delimiter to mailbox name. Please note
* that 'noinferiors' might be used someday as keyword for folders
* that store only messages.
* @param stream $imap_steam imap connection resource
* @param string $mailbox mailbox name
* @param string $type folder type.
$create_mailbox =
$mailbox .
$delimiter;
$create_mailbox =
$mailbox;
true, $response, $message);
* Subscribes to an existing folder.
* @param stream $imap_stream imap connection resource
* @param string $mailbox mailbox name
* @param boolean $debug (since 1.5.1)
$debug, $response, $message);
* Unsubscribes from an existing folder
* @param stream $imap_stream imap connection resource
* @param string $mailbox mailbox name
false, $response, $message);
* Deletes the given folder
* Since 1.2.6 and 1.3.0 contains rename_or_delete_folder hook
* @param stream $imap_stream imap connection resource
* @param string $mailbox mailbox name
true, $response, $message);
if ($response !==
'OK') {
do_hook_function('rename_or_delete_folder', $args =
array($mailbox, 'delete', ''));
removePref($data_dir, $username, "thread_$mailbox");
removePref($data_dir, $username, "collapse_folder_$mailbox");