*
* This implements all functions that manipulate mailboxes
*
- * @copyright © 1999-2006 The SquirrelMail Project Team
+ * @copyright © 1999-2009 The SquirrelMail Project Team
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @version $Id$
* @package squirrelmail
* @subpackage imap
*/
-/** @ignore */
-if (! defined('SM_PATH')) define('SM_PATH','../');
-
/** UTF7 support */
require_once(SM_PATH . 'functions/imap_utf7_local.php');
-global $boxesnew;
/**
* Mailboxes class
var $mailboxname_full = '', $mailboxname_sub= '', $is_noselect = false, $is_noinferiors = false,
$is_special = false, $is_root = false, $is_inbox = false, $is_sent = false,
$is_trash = false, $is_draft = false, $mbxs = array(),
- $unseen = false, $total = false;
+ $unseen = false, $total = false, $recent = false;
function addMbx($mbx, $delimiter, $start, $specialfirst) {
$ary = explode($delimiter, $mbx->mailboxname_full);
*/
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)) {
+ if (preg_match('/^(\* [A-Z]+.*)\{[0-9]+\}([ \n\r\t]*)$/', $ary[$i], $regs)) {
$ary[$i] = $regs[1] . '"' . addslashes(trim($ary[$i+1])) . '"' . $regs[2];
array_splice($ary, $i+1, 2);
}
* 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.
* @return boolean
* @since 1.2.3
*/
-function isSpecialMailbox( $box ) {
+function isSpecialMailbox($box,$include_subs=true) {
$ret = ( (strtolower($box) == 'inbox') ||
- isTrashMailbox($box) || isSentMailbox($box) || isDraftMailbox($box) );
+ isTrashMailbox($box,$include_subs) ||
+ isSentMailbox($box,$include_subs) ||
+ isDraftMailbox($box,$include_subs) );
if ( !$ret ) {
- $ret = boolean_hook_function('special_mailbox',$box,1);
+ $ret = boolean_hook_function('special_mailbox', $box, 1);
}
return $ret;
}
/**
* 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
* @since 1.4.0
*/
-function isTrashMailbox ($box) {
+function isTrashMailbox ($box,$include_subs=true) {
global $trash_folder, $move_to_trash;
return $move_to_trash && $trash_folder &&
- ( $box == $trash_folder || isBoxBelow($box, $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
* @since 1.4.0
*/
-function isSentMailbox($box) {
+function isSentMailbox($box,$include_subs=true) {
global $sent_folder, $move_to_sent;
return $move_to_sent && $sent_folder &&
- ( $box == $sent_folder || isBoxBelow($box, $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
* @since 1.4.0
*/
-function isDraftMailbox($box) {
+function isDraftMailbox($box,$include_subs=true) {
global $draft_folder, $save_as_draft;
return $save_as_draft &&
- ( $box == $draft_folder || isBoxBelow($box, $draft_folder) );
+ ( $box == $draft_folder ||
+ ($include_subs && isBoxBelow($box, $draft_folder)) );
+}
+
+/**
+ * Is the given folder "sent-like" in nature?
+ *
+ * The most obvious use of this is to know what folders you usually
+ * want to show the To field instead of the From field on the mailbox list
+ *
+ * This function returns TRUE if the given folder is the sent
+ * folder (or any of its subfolders) or if it is the draft
+ * folder (or any of its subfolders)
+ *
+ * @param string $mailbox
+ *
+ * @return boolean See explanation above
+ *
+ */
+function handleAsSent($mailbox) {
+ global $handleAsSent_result;
+
+ /* First check if this is the sent or draft folder. */
+ $handleAsSent_result = isSentMailbox($mailbox) || isDraftMailbox($mailbox);
+
+ /* Then check the result of the handleAsSent hook. */
+ do_hook('check_handleAsSent_result', $mailbox);
+
+ /* And return the result. */
+ return $handleAsSent_result;
}
/**
/**
* Selects a mailbox
- * Before 1.3.0 used more arguments and returned data depended on those argumements.
+ * 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)
* @since 1.0 or older
*/
function sqimap_mailbox_select ($imap_stream, $mailbox) {
- // FIX ME: WHAAAA DO NOT USE "None" for something that does not exist. Use false or NULL instead
- if ($mailbox == 'None') {
+ if (empty($mailbox)) {
return;
}
+
// 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) == '/') {
+ global $oTemplate;
+ error_box(sprintf(_("Invalid mailbox name: %s"),htmlspecialchars($mailbox)));
+ sqimap_logout($imap_stream);
+ $oTemplate->display('footer.tpl');
+ die();
+ }
+
$read = sqimap_run_command($imap_stream, 'SELECT ' . sqimap_encode_mailbox_name($mailbox),
true, $response, $message);
$result = array();
function sqimap_mailbox_create ($imap_stream, $mailbox, $type) {
global $delimiter;
if (strtolower($type) == 'noselect') {
- $mailbox .= $delimiter;
+ $create_mailbox = $mailbox . $delimiter;
+ } else {
+ $create_mailbox = $mailbox;
}
$read_ary = sqimap_run_command($imap_stream, 'CREATE ' .
- sqimap_encode_mailbox_name($mailbox),
+ sqimap_encode_mailbox_name($create_mailbox),
true, $response, $message);
sqimap_subscribe ($imap_stream, $mailbox);
}
// subscribe again
sqimap_subscribe ($imap_stream, $mailbox);
} else {
- do_hook_function('rename_or_delete_folder', $args = array($mailbox, 'delete', ''));
+ $temp = array(&$mailbox, 'delete', '');
+ do_hook('rename_or_delete_folder', $temp);
removePref($data_dir, $username, "thread_$mailbox");
removePref($data_dir, $username, "collapse_folder_$mailbox");
}
sqimap_subscribe($imap_stream, $new_name.$postfix);
setPref($data_dir, $username, 'thread_'.$new_name.$postfix, $oldpref_thread);
setPref($data_dir, $username, 'collapse_folder_'.$new_name.$postfix, $oldpref_collapse);
- do_hook_function('rename_or_delete_folder',$args = array($old_name, 'rename', $new_name));
+ $temp = array(&$old_name, 'rename', &$new_name);
+ do_hook('rename_or_delete_folder', $temp);
$l = strlen( $old_name ) + 1;
$p = 'unformatted';
}
setPref($data_dir, $username, 'thread_'.$new_sub, $oldpref_thread);
setPref($data_dir, $username, 'collapse_folder_'.$new_sub, $oldpref_collapse);
- do_hook_function('rename_or_delete_folder',
- $args = array($box[$p], 'rename', $new_sub));
+ $temp = array(&$box[$p], 'rename', &$new_sub);
+ do_hook('rename_or_delete_folder', $temp);
}
}
}
$boxesall[$g]['id'] = $g;
$boxesall[$g]['flags'] = array();
- if (isset($line[$g])) {
- ereg("\(([^)]*)\)",$line[$g],$regs);
+ if (isset($line[$g]) && preg_match('/\(([^)]*)\)/',$line[$g],$regs) ) {
/**
* Since 1.5.1 flags are stored with RFC3501 naming
* and also the old way for backwards compatibility
}
/**
- * Returns list of options (to be echoed into select statement
- * based on available mailboxes and separators
- * Caller should surround options with <select ...> </select> and
- * any formatting.
- * @param stream $imap_stream imap connection resource to query for mailboxes
- * @param array $show_selected array containing list of mailboxes to pre-select (0 if none)
- * @param array $folder_skip array of folders to keep out of option list (compared in lower)
- * @param $boxes list of already fetched boxes (for places like folder panel, where
- * you know these options will be shown 3 times in a row.. (most often unset).
- * @param string $flag (since 1.4.1) flag to check for in mailbox flags, used to filter out mailboxes.
- * 'noselect' by default to remove unselectable mailboxes.
- * 'noinferiors' used to filter out folders that can not contain subfolders.
- * NULL to avoid flag check entirely.
- * NOTE: noselect and noiferiors are used internally. The IMAP representation is
- * \NoSelect and \NoInferiors
- * @param boolean $use_long_format (since 1.4.1) override folder display preference and always show full folder name.
- * @return string html formated mailbox selection options
- * @since 1.3.2
+ * Returns an array of mailboxes available. Separated from sqimap_mailbox_option_list()
+ * below for template development.
+ *
+ * @author Steve Brown
+ * @since 1.5.2
*/
-function sqimap_mailbox_option_list($imap_stream, $show_selected = 0, $folder_skip = 0, $boxes = 0,
+function sqimap_mailbox_option_array($imap_stream, $folder_skip = 0, $boxes = 0,
$flag = 'noselect', $use_long_format = false ) {
- global $username, $data_dir;
+ global $username, $data_dir, $translate_special_folders, $sent_folder,
+ $trash_folder, $draft_folder;
+
+ $delimiter = sqimap_get_delimiter($imap_stream);
+
$mbox_options = '';
if ( $use_long_format ) {
$shorten_box_names = 0;
} else {
- $shorten_box_names = getPref($data_dir, $username, 'mailbox_select_style', SMPREF_OFF);
+ $shorten_box_names = getPref($data_dir, $username, 'mailbox_select_style', SMPREF_MAILBOX_SELECT_INDENTED);
}
if ($boxes == 0) {
$boxes = sqimap_mailbox_list($imap_stream);
}
+ $a = array();
foreach ($boxes as $boxes_part) {
if ($flag == NULL || (is_array($boxes_part['flags'])
&& !in_array($flag, $boxes_part['flags']))) {
} else {
switch ($shorten_box_names)
{
- case 2: /* delimited, style = 2 */
- $box2 = str_replace('&nbsp;&nbsp;', '. ', htmlspecialchars($boxes_part['formatted']));
+ case SMPREF_MAILBOX_SELECT_DELIMITED:
+ if ($translate_special_folders && $boxes_part['unformatted-dm']==$sent_folder) {
+ /*
+ * calculate pad level from number of delimiters. do it inside if control in order
+ * to reduce number of calculations. Other folders don't need it.
+ */
+ $pad = str_pad('',7 * (count(explode($delimiter,$boxes_part['unformatted-dm']))-1),'. ');
+ // i18n: Name of Sent folder
+ $box2 = $pad . _("Sent");
+ } elseif ($translate_special_folders && $boxes_part['unformatted-dm']==$trash_folder) {
+ $pad = str_pad('',7 * (count(explode($delimiter,$boxes_part['unformatted-dm']))-1),'. ');
+ // i18n: Name of Trash folder
+ $box2 = $pad . _("Trash");
+ } elseif ($translate_special_folders && $boxes_part['unformatted-dm']==$draft_folder) {
+ $pad = str_pad('',7 * (count(explode($delimiter,$boxes_part['unformatted-dm']))-1),'. ');
+ // i18n: Name of Drafts folder
+ $box2 = $pad . _("Drafts");
+ } else {
+ $box2 = str_replace('&nbsp;&nbsp;', '. ', htmlspecialchars($boxes_part['formatted']));
+ }
break;
- case 1: /* indent, style = 1 */
- $box2 = str_replace('&nbsp;&nbsp;', ' ', htmlspecialchars($boxes_part['formatted']));
+ case SMPREF_MAILBOX_SELECT_INDENTED:
+ if ($translate_special_folders && $boxes_part['unformatted-dm']==$sent_folder) {
+ $pad = str_pad('',12 * (count(explode($delimiter,$boxes_part['unformatted-dm']))-1),' ');
+ $box2 = $pad . _("Sent");
+ } elseif ($translate_special_folders && $boxes_part['unformatted-dm']==$trash_folder) {
+ $pad = str_pad('',12 * (count(explode($delimiter,$boxes_part['unformatted-dm']))-1),' ');
+ $box2 = $pad . _("Trash");
+ } elseif ($translate_special_folders && $boxes_part['unformatted-dm']==$draft_folder) {
+ $pad = str_pad('',12 * (count(explode($delimiter,$boxes_part['unformatted-dm']))-1),' ');
+ $box2 = $pad . _("Drafts");
+ } else {
+ $box2 = str_replace('&nbsp;&nbsp;', ' ', htmlspecialchars($boxes_part['formatted']));
+ }
break;
default: /* default, long names, style = 0 */
$box2 = str_replace(' ', ' ', htmlspecialchars(imap_utf7_decode_local($boxes_part['unformatted-disp'])));
break;
}
}
- if ($show_selected != 0 && in_array($lowerbox, $show_selected) ) {
- $mbox_options .= '<option value="' . htmlspecialchars($box) .'" selected="selected">'.$box2.'</option>' . "\n";
- } else {
- $mbox_options .= '<option value="' . htmlspecialchars($box) .'">'.$box2.'</option>' . "\n";
+
+ $a[htmlspecialchars($box)] = $box2;
+ }
+ }
+
+ return $a;
+}
+
+/**
+ * Returns list of options (to be echoed into select statement
+ * based on available mailboxes and separators
+ * Caller should surround options with <select ...> </select> and
+ * any formatting.
+ * @param stream $imap_stream imap connection resource to query for mailboxes
+ * @param array $show_selected array containing list of mailboxes to pre-select (0 if none)
+ * @param array $folder_skip array of folders to keep out of option list (compared in lower)
+ * @param $boxes list of already fetched boxes (for places like folder panel, where
+ * you know these options will be shown 3 times in a row.. (most often unset).
+ * @param string $flag (since 1.4.1) flag to check for in mailbox flags, used to filter out mailboxes.
+ * 'noselect' by default to remove unselectable mailboxes.
+ * 'noinferiors' used to filter out folders that can not contain subfolders.
+ * NULL to avoid flag check entirely.
+ * NOTE: noselect and noiferiors are used internally. The IMAP representation is
+ * \NoSelect and \NoInferiors
+ * @param boolean $use_long_format (since 1.4.1) override folder display preference and always show full folder name.
+ * @return string html formated mailbox selection options
+ * @since 1.3.2
+ */
+function sqimap_mailbox_option_list($imap_stream, $show_selected = 0, $folder_skip = 0, $boxes = 0,
+ $flag = 'noselect', $use_long_format = false ) {
+ global $username, $data_dir, $translate_special_folders, $sent_folder,
+ $trash_folder, $draft_folder;
+
+ $boxes = sqimap_mailbox_option_array($imap_stream, $folder_skip, $boxes, $flag, $use_long_format);
+
+ $str = '';
+ foreach ($boxes as $value=>$option) {
+ $lowerbox = strtolower(htmlspecialchars($value));
+ $sel = false;
+ if ($show_selected != 0) {
+ reset($show_selected);
+ while (!$sel && (list($x, $val) = each($show_selected))) {
+ if (strtolower($value) == strtolower(htmlspecialchars($val))) {
+ $sel = true;
+ }
}
}
+
+ $str .= '<option value="'. $value .'"'. ($sel ? ' selected="selected"' : '').'>'. $option ."</option>\n";
}
- return $mbox_options;
+
+ return $str;
}
/**
if ($show_only_subscribed) { $show_only_subscribed=$show_only_subscribed_folders; }
- require_once(SM_PATH . 'include/load_prefs.php');
+ //require_once(SM_PATH . 'include/load_prefs.php');
/**
* There are three main listing commands we can use in IMAP:
// get subscribed mailbox list from cache (session)
// if not there, then get it from the imap server and store in cache
- sqsession_is_active();
if (!$force) {
sqgetGlobalVar($sub_cache_name,$lsub_cache,SQ_SESSION);
$trail_del = false;
$start = 0;
-
if (isset($folder_prefix) && ($folder_prefix != '')) {
$start = substr_count($folder_prefix,$delimiter);
if (strrpos($folder_prefix, $delimiter) == (strlen($folder_prefix)-1)) {
* @since 1.5.0
*/
function sqimap_utf7_decode_mbx_tree(&$mbx_tree) {
+ global $draft_folder, $sent_folder, $trash_folder, $translate_special_folders;
+
+ /* decode folder name and set mailboxname_sub */
+ if ($translate_special_folders && strtoupper($mbx_tree->mailboxname_full) == 'INBOX') {
+ $mbx_tree->mailboxname_sub = _("INBOX");
+ } elseif ($translate_special_folders && $mbx_tree->mailboxname_full == $draft_folder) {
+ $mbx_tree->mailboxname_sub = _("Drafts");
+ } elseif ($translate_special_folders && $mbx_tree->mailboxname_full == $sent_folder) {
+ $mbx_tree->mailboxname_sub = _("Sent");
+ } elseif ($translate_special_folders && $mbx_tree->mailboxname_full == $trash_folder) {
+ $mbx_tree->mailboxname_sub = _("Trash");
+ } else {
+ $mbx_tree->mailboxname_sub = imap_utf7_decode_local($mbx_tree->mailboxname_sub);
+ }
- if (strtoupper($mbx_tree->mailboxname_full) == 'INBOX')
- $mbx_tree->mailboxname_sub = _("INBOX");
- else
- $mbx_tree->mailboxname_sub = imap_utf7_decode_local($mbx_tree->mailboxname_sub);
- if ($mbx_tree->mbxs) {
- $iCnt = count($mbx_tree->mbxs);
- for ($i=0;$i<$iCnt;++$i) {
+ if ($mbx_tree->mbxs) {
+ $iCnt = count($mbx_tree->mbxs);
+ for ($i=0;$i<$iCnt;++$i) {
sqimap_utf7_decode_mbx_tree($mbx_tree->mbxs[$i]);
- }
- }
+ }
+ }
}
/**
$mbx = $oMbx->mailboxname_full;
if ($unseen_type == 2 ||
($move_to_trash && $oMbx->mailboxname_full == $trash_folder)) {
- $query = 'STATUS ' . sqimap_encode_mailbox_name($mbx) . ' (MESSAGES UNSEEN)';
+ $query = 'STATUS ' . sqimap_encode_mailbox_name($mbx) . ' (MESSAGES UNSEEN RECENT)';
} else {
- $query = 'STATUS ' . sqimap_encode_mailbox_name($mbx) . ' (UNSEEN)';
+ $query = 'STATUS ' . sqimap_encode_mailbox_name($mbx) . ' (UNSEEN RECENT)';
}
sqimap_prepare_pipelined_query($query,$tag,$aQuery,false);
} else {
- $oMbx->unseen = $oMbx->total = false;
+ $oMbx->unseen = $oMbx->total = $oMbx->recent = false;
$tag = false;
}
$oMbx->tag = $tag;
if (preg_match('/MESSAGES\s+([0-9]+)/i', $sResponse, $regs)) {
$oMbx->total = $regs[1];
}
+ if (preg_match('/RECENT\s+([0-9]+)/i', $sResponse, $regs)) {
+ $oMbx->recent = $regs[1];
+ }
+
}
unset($oMbx->tag);
}
$aStatus = sqimap_status_messages($imap_stream,$oMbx->mailboxname_full);
$oMbx->unseen = $aStatus['UNSEEN'];
$oMbx->total = $aStatus['MESSAGES'];
+ $oMbx->recent = $aStatus['RECENT'];
} else {
$oMbx->unseen = sqimap_unseen_messages($imap_stream,$oMbx->mailboxname_full);
}
}
}
}
+
+ $cnt = count($aMbxs);
+ for($i=0;$i<$cnt;++$i) {
+ $oMbx =& $aMbxs[$i];
+ unset($hook_status);
+ if (!empty($oMbx->unseen)) { $hook_status['UNSEEN']=$oMbx->unseen; }
+ if (!empty($oMbx->total)) { $hook_status['MESSAGES']=$oMbx->total; }
+ if (!empty($oMbx->recent)) { $hook_status['RECENT']=$oMbx->recent; }
+ if (!empty($hook_status))
+ {
+ $hook_status['MAILBOX']=$oMbx->mailboxname_full;
+ $hook_status['CALLER']='sqimap_get_status_mbx_tree'; // helps w/ debugging
+ do_hook('folder_status', $hook_status);
+ }
+ }
}
/**
}
return false;
}
-
-?>