*
* This implements all functions that manipulate mailboxes
*
- * @copyright © 1999-2006 The SquirrelMail Project Team
+ * @copyright 1999-2021 The SquirrelMail Project Team
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @version $Id$
* @package squirrelmail
*/
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);
}
* 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.2.5 function includes special_mailbox hook.
+ *
* Since 1.4.3 hook supports more than one plugin.
+ *
+//FIXME: make $subfolders_of_inbox_are_special a configuration setting in conf.pl and config.php
+ * Since 1.4.22/1.5.2, the administrator can add
+ * $subfolders_of_inbox_are_special = TRUE;
+ * to config/config_local.php and all subfolders
+ * of the INBOX will be treated as special.
+ *
* @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
* @since 1.2.3
*/
function isSpecialMailbox($box,$include_subs=true) {
- $ret = ( (strtolower($box) == 'inbox') ||
+ global $subfolders_of_inbox_are_special;
+ $ret = ( ($subfolders_of_inbox_are_special && isInboxMailbox($box,$include_subs)) ||
+ (!$subfolders_of_inbox_are_special && strtolower($box) == 'inbox') ||
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 the Inbox folder or subfolder of the Inbox
+ *
+ * @param string $box The mailbox name to test
+ * @param boolean $include_subs If true, subfolders of system folders
+ * are special. If false, subfolders are
+ * not special mailboxes.
+ *
+ * @return boolean Whether this is the Inbox or a child thereof.
+ *
+ * @since 1.4.22
+ */
+function isInboxMailbox($box, $include_subs=TRUE) {
+ return ((strtolower($box) == 'inbox')
+ || ($include_subs && isBoxBelow(strtolower($box), 'inbox')));
+}
+
/**
* Detects if mailbox is a Trash folder or subfolder of Trash
* @param string $box mailbox name
($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;
+}
+
/**
* Expunges a mailbox
*
* 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
+ * @param boolean $handle_errors When TRUE, IMAP errors
+ * are handled herein, causing
+ * an error to be displayed on
+ * screen and execution to stop
+ * and when FALSE, error status
+ * is returned to the caller
+ * (OPTIONAL; default is TRUE)
* @return array results of select command (on success - permanentflags, flags and rights)
+ * (on failure (and when $handle_errors is false), empty array)
* @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') {
+function sqimap_mailbox_select ($imap_stream, $mailbox, $handle_errors=true) {
+ 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"),sm_encode_html_special_chars($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);
+ $handle_errors, $response, $message);
$result = array();
for ($i = 0, $cnt = count($read); $i < $cnt; $i++) {
if (preg_match('/^\*\s+OK\s\[(\w+)\s(\w+)\]/',$read[$i], $regs)) {
}
}
}
- if (!isset($result['PERMANENTFLAGS'])) {
+ if (!empty($result) && !isset($result['PERMANENTFLAGS'])) {
$result['PERMANENTFLAGS'] = $result['FLAGS'];
}
if (preg_match('/^\[(.+)\]/',$message, $regs)) {
// 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);
}
}
}
global $folder_prefix, $delimiter;
/* Process each folder line */
- for ($g = 0, $cnt = count($line); $g < $cnt; ++$g) {
+ ksort($line); // get physical ordering same as alphabetical sort we did before now (might be a better place for this)
+ foreach ($line as $g => $l)
+ // was this but array not guaranteed to be contiguous: for ($g = 0, $cnt = count($line); $g < $cnt; ++$g)
+ {
/* Store the raw IMAP reply */
if (isset($line[$g])) {
$boxesall[$g]['raw'] = $line[$g];
$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
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) {
} else {
switch ($shorten_box_names)
{
- case 2: /* delimited, style = 2 */
+ 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
// i18n: Name of Drafts folder
$box2 = $pad . _("Drafts");
} else {
- $box2 = str_replace('&nbsp;&nbsp;', '. ', htmlspecialchars($boxes_part['formatted']));
+ $box2 = str_replace('&nbsp;&nbsp;', '. ', sm_encode_html_special_chars($boxes_part['formatted']));
}
break;
- case 1: /* indent, style = 1 */
+ 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");
$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']));
+ $box2 = str_replace('&nbsp;&nbsp;', ' ', sm_encode_html_special_chars($boxes_part['formatted']));
}
break;
default: /* default, long names, style = 0 */
- $box2 = str_replace(' ', ' ', htmlspecialchars(imap_utf7_decode_local($boxes_part['unformatted-disp'])));
+ $box2 = str_replace(' ', ' ', sm_encode_html_special_chars(imap_utf7_decode_local($boxes_part['unformatted-disp'])));
break;
}
}
- $a[htmlspecialchars($box)] = $box2;
+ $a[sm_encode_html_special_chars($box)] = $box2;
}
}
$str = '';
foreach ($boxes as $value=>$option) {
- $lowerbox = strtolower(htmlspecialchars($value));
+ $lowerbox = strtolower(sm_encode_html_special_chars($value));
$sel = false;
if ($show_selected != 0) {
- reset($show_selected);
- while (!$sel && (list($x, $val) = each($show_selected))) {
- if (strtolower($value) == strtolower(htmlspecialchars($val))) {
+ foreach ($show_selected as $val) {
+ if (strtolower($value) == strtolower(sm_encode_html_special_chars($val))) {
$sel = true;
+ break;
}
}
}
$cnt = count($boxesall);
$used = array_pad($used,$cnt,false);
$has_inbox = false;
- for($k = 0; $k < $cnt; ++$k) {
+ foreach ($boxesall as $k => $b)
+ // was this but array not guaranteed to be contiguous: for($k = 0; $k < $cnt; ++$k)
+ {
if (strtoupper($boxesall[$k]['unformatted']) == 'INBOX') {
$boxesnew[] = $boxesall[$k];
$used[$k] = true;
/* List special folders and their subfolders, if requested. */
if ($list_special_folders_first) {
- for($k = 0; $k < $cnt; ++$k) {
+ foreach ($boxesall as $k => $b)
+ // was this but array not guaranteed to be contiguous: for($k = 0; $k < $cnt; ++$k)
+ {
if (!$used[$k] && isSpecialMailbox($boxesall[$k]['unformatted'])) {
$boxesnew[] = $boxesall[$k];
$used[$k] = true;
}
/* Find INBOX's children */
- for($k = 0; $k < $cnt; ++$k) {
+ foreach ($boxesall as $k => $b)
+ // was this but array not guaranteed to be contiguous: for($k = 0; $k < $cnt; ++$k)
+ {
$isboxbelow=isBoxBelow(strtoupper($boxesall[$k]['unformatted']),'INBOX');
if (strtoupper($boxesall[$k]['unformatted']) == 'INBOX') {
$is_inbox=1;
}
/* Rest of the folders */
- for($k = 0; $k < $cnt; $k++) {
+ foreach ($boxesall as $k => $b)
+ // was this but array not guaranteed to be contiguous: for($k = 0; $k < $cnt; ++$k)
+ {
if (!$used[$k]) {
$boxesnew[] = $boxesall[$k];
}
{
$hook_status['MAILBOX']=$oMbx->mailboxname_full;
$hook_status['CALLER']='sqimap_get_status_mbx_tree'; // helps w/ debugging
- do_hook_function('folder_status',$hook_status);
+ do_hook('folder_status', $hook_status);
}
}
}