X-Git-Url: https://vcs.fsf.org/?p=squirrelmail.git;a=blobdiff_plain;f=functions%2Fimap_mailbox.php;h=1ea7c59c08531552ec3386d5c9af81acfcb1b723;hp=40ceac2d787b9fe2360dead84bbb06362057ac3e;hb=7b2092f1298addb768a06c390935599c672e2eca;hpb=f5b3b0fc5f07d42975b0a9104d4a70cadb254efa diff --git a/functions/imap_mailbox.php b/functions/imap_mailbox.php index 40ceac2d..1ea7c59c 100755 --- a/functions/imap_mailbox.php +++ b/functions/imap_mailbox.php @@ -5,7 +5,7 @@ * * This implements all functions that manipulate mailboxes * - * @copyright © 1999-2006 The SquirrelMail Project Team + * @copyright 1999-2018 The SquirrelMail Project Team * @license http://opensource.org/licenses/gpl-license.php GNU Public License * @version $Id$ * @package squirrelmail @@ -110,8 +110,7 @@ function compact_mailboxes_response($ary) { */ 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); } @@ -217,8 +216,16 @@ function isBoxBelow( $subbox, $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.
+ * 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 @@ -227,17 +234,36 @@ function isBoxBelow( $subbox, $parentbox ) { * @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 @@ -283,6 +309,34 @@ function isDraftMailbox($box,$include_subs=true) { ($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 * @@ -356,18 +410,44 @@ function sqimap_mailbox_exists ($imap_stream, $mailbox, $mailboxlist=null) { * 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)) { @@ -384,7 +464,7 @@ function sqimap_mailbox_select ($imap_stream, $mailbox) { } } } - if (!isset($result['PERMANENTFLAGS'])) { + if (!empty($result) && !isset($result['PERMANENTFLAGS'])) { $result['PERMANENTFLAGS'] = $result['FLAGS']; } if (preg_match('/^\[(.+)\]/',$message, $regs)) { @@ -467,7 +547,8 @@ function sqimap_mailbox_delete ($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"); } @@ -522,7 +603,8 @@ function sqimap_mailbox_rename( $imap_stream, $old_name, $new_name ) { 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'; @@ -548,8 +630,8 @@ function sqimap_mailbox_rename( $imap_stream, $old_name, $new_name ) { } 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); } } } @@ -582,7 +664,10 @@ function sqimap_mailbox_parse ($line) { 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]; @@ -628,8 +713,7 @@ function sqimap_mailbox_parse ($line) { $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 @@ -668,7 +752,7 @@ function sqimap_mailbox_option_array($imap_stream, $folder_skip = 0, $boxes = 0, 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) { @@ -693,7 +777,7 @@ function sqimap_mailbox_option_array($imap_stream, $folder_skip = 0, $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 @@ -711,10 +795,10 @@ function sqimap_mailbox_option_array($imap_stream, $folder_skip = 0, $boxes = 0, // 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"); @@ -725,16 +809,16 @@ function sqimap_mailbox_option_array($imap_stream, $folder_skip = 0, $boxes = 0, $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; } } @@ -770,12 +854,12 @@ function sqimap_mailbox_option_list($imap_stream, $show_selected = 0, $folder_sk $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))) { + if (strtolower($value) == strtolower(sm_encode_html_special_chars($val))) { $sel = true; } } @@ -1015,7 +1099,9 @@ function sqimap_get_mailboxes($imap_stream,$force=false,$show_only_subscribed=tr $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; @@ -1044,7 +1130,9 @@ function sqimap_get_mailboxes($imap_stream,$force=false,$show_only_subscribed=tr /* 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; @@ -1053,7 +1141,9 @@ function sqimap_get_mailboxes($imap_stream,$force=false,$show_only_subscribed=tr } /* 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; @@ -1068,7 +1158,9 @@ function sqimap_get_mailboxes($imap_stream,$force=false,$show_only_subscribed=tr } /* 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]; } @@ -1362,7 +1454,7 @@ function sqimap_get_status_mbx_tree($imap_stream,&$mbx_tree) { { $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); } } }