X-Git-Url: https://vcs.fsf.org/?p=squirrelmail.git;a=blobdiff_plain;f=functions%2Fmailbox_display.php;h=f44e1ebe44939beba991aa25dfb2409ebae2dada;hp=d5eb6214ca735faf84c96bb6f26399c201864b2d;hb=865050ce6daedb8dbbbb568a36e802b0b6459565;hpb=47ccfad452e8d345542d09e59112cac317cffed8 diff --git a/functions/mailbox_display.php b/functions/mailbox_display.php index d5eb6214..f44e1ebe 100644 --- a/functions/mailbox_display.php +++ b/functions/mailbox_display.php @@ -6,21 +6,12 @@ * This contains functions that display mailbox information, such as the * table row that has sender, date, subject, etc... * - * @copyright © 1999-2006 The SquirrelMail Project Team + * @copyright 1999-2010 The SquirrelMail Project Team * @license http://opensource.org/licenses/gpl-license.php GNU Public License * @version $Id$ * @package squirrelmail */ -/** The standard includes.. */ -require_once(SM_PATH . 'functions/strings.php'); -require_once(SM_PATH . 'functions/html.php'); -require_once(SM_PATH . 'functions/imap_mailbox.php'); -require_once(SM_PATH . 'functions/imap_messages.php'); -require_once(SM_PATH . 'functions/imap_asearch.php'); -require_once(SM_PATH . 'functions/mime.php'); -require_once(SM_PATH . 'functions/forms.php'); - /** * Selects a mailbox for header retrieval. @@ -30,7 +21,9 @@ require_once(SM_PATH . 'functions/forms.php'); * @param string $mailbox mailbox to select and retrieve message headers from * @param array $aConfig array with system config settings and incoming vars * @param array $aProps mailbox specific properties + * * @return array $aMailbox mailbox array with all relevant information + * * @since 1.5.1 * @author Marc Groot Koerkamp */ @@ -346,6 +339,12 @@ function fetchMessageHeaders($imapConnection, &$aMailbox) { $id_slice = array_slice($aUid,$start_msg-1,$iLimit); /* do some funky cache checks */ if (isset($aMailbox['MSG_HEADERS']) && is_array($aMailbox['MSG_HEADERS'])) { + // temp code, read_body del / next links fo not update fields. + foreach ($aMailbox['MSG_HEADERS'] as $iUid => $aValue) { + if (!isset($aValue['UID'])) { + unset($aMailbox['MSG_HEADERS'][$iUid]); + } + } $aUidCached = array_keys($aMailbox['MSG_HEADERS']); } else { $aMailbox['MSG_HEADERS'] = array(); @@ -428,7 +427,7 @@ function fetchMessageHeaders($imapConnection, &$aMailbox) { function prepareMessageList(&$aMailbox, $aProps) { /* Globalize link attributes so plugins can share in modifying them */ - global $link, $title, $target, $onclick, $link_extra; + global $link, $title, $target, $onclick, $link_extra, $preselected; /* retrieve the properties */ $my_email_address = (isset($aProps['email'])) ? $aProps['email'] : false; @@ -567,10 +566,10 @@ function prepareMessageList(&$aMailbox, $aProps) { } $sTmp = decodeHeader($sTmp); if (isset($aColumnDesc[$k]['truncate']) && $aColumnDesc[$k]['truncate']) { - $sTrunc = truncateWithEntities($sTmp, $aColumnDesc[$k]['truncate']); + $sTrunc = sm_truncate_string($sTmp, $aColumnDesc[$k]['truncate'], '...', TRUE); if ($sTrunc != $sTmp) { if (!$title) { - $title = htmlspecialchars($sTmp); + $title = $sTmp; } else if ($title_maybe) { $title = $title .', '.$title_maybe; $title = substr($title,0,-2); // strip ', '; @@ -592,7 +591,7 @@ function prepareMessageList(&$aMailbox, $aProps) { $iIndent = (isset($aIndentArray[$aId[$i]])) ? $aIndentArray[$aId[$i]] : 0; // FIXME: don't break 8bit symbols and html entities during truncation if (isset($aColumnDesc[$k]['truncate']) && $aColumnDesc[$k]['truncate']) { - $sTmp = truncateWithEntities($value, $aColumnDesc[$k]['truncate']-$iIndent); + $sTmp = sm_truncate_string($value, $aColumnDesc[$k]['truncate']-$iIndent, '...', TRUE); // drop any double spaces since these will be displayed in the title $title = ($sTmp != $value) ? preg_replace('/\s{2,}/', ' ', $value) : ''; $value = $sTmp; @@ -603,11 +602,12 @@ function prepareMessageList(&$aMailbox, $aProps) { $link = $sTargetModule.'.php?' . implode('&',$aQuery); // see top of this function for which attributes are available - // in the global scope for plugin use (like $link, $target, + // in the global scope for plugin use (like $link, $target, // $onclick, $link_extra, $title, and so forth) - // plugins are responsible for sharing nicely (such as for + // plugins are responsible for sharing nicely (such as for // setting the target, etc) - do_hook('subject_link', array($iPageOffset, $sSearch, $aSearch)); + $temp = array(&$iPageOffset, &$sSearch, &$aSearch, $aMsg); + do_hook('subject_link', $temp); } $value = (trim($value)) ? $value : _("(no subject)"); /* add thread indentation */ @@ -624,17 +624,19 @@ function prepareMessageList(&$aMailbox, $aProps) { $aFlagColumn = array('seen' => false, 'deleted'=>false, 'answered'=>false, + 'forwarded'=>false, 'flagged' => false, 'draft' => false); if(!is_array($value)) $value = array(); - foreach ($value as $sFlag => $value) { + foreach ($value as $sFlag => $v) { switch ($sFlag) { - case '\\seen' : $aFlagColumn['seen'] = true; break; - case '\\deleted' : $aFlagColumn['deleted'] = true; break; - case '\\answered': $aFlagColumn['answered'] = true; break; - case '\\flagged' : $aFlagColumn['flagged'] = true; break; - case '\\draft' : $aFlagColumn['draft'] = true; break; + case '\\seen' : $aFlagColumn['seen'] = true; break; + case '\\deleted' : $aFlagColumn['deleted'] = true; break; + case '\\answered': $aFlagColumn['answered'] = true; break; + case '$forwarded': $aFlagColumn['forwarded'] = true; break; + case '\\flagged' : $aFlagColumn['flagged'] = true; break; + case '\\draft' : $aFlagColumn['draft'] = true; break; default: break; } } @@ -647,7 +649,7 @@ function prepareMessageList(&$aMailbox, $aProps) { $value = (is_array($value) && $value[0] == 'multipart' && $value[1] == 'mixed') ? true : false; break; case SQM_COL_CHECK: - $value = $checkall; + $value = ($checkall || in_array($iUid, $preselected)); break; default : break; } @@ -907,7 +909,7 @@ function calcFetchColumns(&$aMailbox, &$aProps) { */ function showMessagesForMailbox($imapConnection, &$aMailbox,$aProps, &$iError) { global $PHP_SELF; - global $boxes; + global $boxes, $show_copy_buttons; $highlight_list = (isset($aProps['config']['highlight_list'])) ? $aProps['config']['highlight_list'] : false; $fancy_index_highlite = (isset($aProps['config']['fancy_index_highlite'])) ? $aProps['config']['fancy_index_highlite'] : true; @@ -916,6 +918,11 @@ function showMessagesForMailbox($imapConnection, &$aMailbox,$aProps, &$iError) { $sMailbox = (isset($aProps['mailbox'])) ? $aProps['mailbox'] : false; $sTargetModule = (isset($aProps['module'])) ? $aProps['module'] : 'read_body'; $show_flag_buttons = (isset($aProps['config']['show_flag_buttons'])) ? $aProps['config']['show_flag_buttons'] : true; + + /* allows to control copy button in function call. If array key is not set, code follows user preferences */ + if (isset($aProps['config']['show_copy_buttons'])) + $show_copy_buttons = $aProps['config']['show_copy_buttons']; + $lastTargetMailbox = (isset($aProps['config']['lastTargetMailbox'])) ? $aProps['config']['lastTargetMailbox'] : ''; $aOrder = array_keys($aProps['columns']); $trash_folder = (isset($aProps['config']['trash_folder']) && $aProps['config']['trash_folder']) @@ -968,7 +975,7 @@ function showMessagesForMailbox($imapConnection, &$aMailbox,$aProps, &$iError) { $source_url = $php_self; } - $baseurl = $source_url.'?mailbox=' . urlencode($aMailbox['NAME']) .'&account='.$aMailbox['ACCOUNT']; + $baseurl = $source_url.'?mailbox=' . urlencode($aMailbox['NAME']) .'&account='.$aMailbox['ACCOUNT'] . (strpos($source_url, 'src/search.php') ? '&smtoken=' . sm_generate_security_token() : ''); $where = urlencode($aMailbox['SEARCH'][$iSetIndx][0]); $what = urlencode($aMailbox['SEARCH'][$iSetIndx][1]); $baseurl .= '&where=' . $where . '&what=' . $what; @@ -983,11 +990,11 @@ function showMessagesForMailbox($imapConnection, &$aMailbox,$aProps, &$iError) { $thread_name = _("Thread View"); $newsort = $aMailbox['SORT'] + SQSORT_THREAD; } - $thread_link_str = '[' . $thread_name - . ']'; + $thread_link_uri = $baseurl . '&srt=' . $newsort + . '&startMessage=1'; } else { - $thread_link_str =''; + $thread_link_uri =''; + $thread_name = ''; } $sort = $aMailbox['SORT']; @@ -996,10 +1003,9 @@ function showMessagesForMailbox($imapConnection, &$aMailbox,$aProps, &$iError) { /* future admin control over displayable buttons */ - $aAdminControl = array( - 'markUnflagged' => 1, 'markFlagged' => 1, + 'markUnflagged' => 1, 'markRead' => 1, 'markUnread' => 1, 'forward' => 1, @@ -1007,13 +1013,15 @@ function showMessagesForMailbox($imapConnection, &$aMailbox,$aProps, &$iError) { 'undeleteButton'=> 1, 'bypass_trash' => 1, 'expungeButton' => 1, - 'moveButton' => 1 + 'moveButton' => 1, + 'copyButton' => 1 ); + /* user prefs control */ $aUserControl = array ( - 'markUnflagged' => $show_flag_buttons, 'markFlagged' => $show_flag_buttons, + 'markUnflagged' => $show_flag_buttons, 'markRead' => 1, 'markUnread' => 1, 'forward' => 1, @@ -1021,7 +1029,8 @@ function showMessagesForMailbox($imapConnection, &$aMailbox,$aProps, &$iError) { 'undeleteButton'=> 1, 'bypass_trash' => 1, 'expungeButton' => 1, - 'moveButton' => 1 + 'moveButton' => 1, + 'copyButton' => $show_copy_buttons ); @@ -1036,6 +1045,8 @@ function showMessagesForMailbox($imapConnection, &$aMailbox,$aProps, &$iError) { $showMove = ($aMailbox['RIGHTS'] != 'READ-ONLY') ? true : false; $showExpunge = (!$aMailbox['AUTO_EXPUNGE'] && $aMailbox['RIGHTS'] != 'READ-ONLY' && in_array('\\deleted',$aMailbox['PERMANENTFLAGS'], true)) ? true : false; + + /* Button options that depend on IMAP server and selected folder */ $aImapControl = array ( 'markUnflagged' => in_array('\\flagged',$aMailbox['PERMANENTFLAGS'], true), 'markFlagged' => in_array('\\flagged',$aMailbox['PERMANENTFLAGS'], true), @@ -1046,19 +1057,42 @@ function showMessagesForMailbox($imapConnection, &$aMailbox,$aProps, &$iError) { 'undeleteButton'=> $showUndelete, 'bypass_trash' => $showByPassTrash, 'expungeButton' => $showExpunge, - 'moveButton' => $showMove + 'moveButton' => $showMove, + 'copyButton' => 1 ); + /* Button strings */ $aButtonStrings = array( - 'markUnflagged' => _("Unflag"), - 'markFlagged' => _("Flag"), - 'markRead' => _("Read"), - 'markUnread' => _("Unread"), - 'forward' => _("Forward"), - 'delete' => _("Delete"), - 'undeleteButton' => _("Undelete"), - 'bypass_trash' => _("Bypass Trash"), - 'expungeButton' => _("Expunge"), - 'moveButton' => _("Move") + 'markFlagged' => _("Flag"), + 'markUnflagged' => _("Unflag"), + 'markRead' => _("Read"), + 'markUnread' => _("Unread"), + 'forward' => _("Forward"), + 'delete' => _("Delete"), + 'undeleteButton' => _("Undelete"), + 'bypass_trash' => _("Bypass Trash"), + 'expungeButton' => _("Expunge"), + 'moveButton' => _("Move"), + 'copyButton' => _("Copy") + ); + /* Button access keys */ + global $accesskey_mailbox_flag, $accesskey_mailbox_unflag, + $accesskey_mailbox_read, $accesskey_mailbox_unread, + $accesskey_mailbox_forward, $accesskey_mailbox_delete, + $accesskey_mailbox_undelete, $accesskey_mailbox_bypass_trash, + $accesskey_mailbox_expunge, $accesskey_mailbox_move, + $accesskey_mailbox_copy, $accesskey_mailbox_move_to; + $aButtonAccessKeys = array( + 'markFlagged' => $accesskey_mailbox_flag, + 'markUnflagged' => $accesskey_mailbox_unflag, + 'markRead' => $accesskey_mailbox_read, + 'markUnread' => $accesskey_mailbox_unread, + 'forward' => $accesskey_mailbox_forward, + 'delete' => $accesskey_mailbox_delete, + 'undeleteButton' => $accesskey_mailbox_undelete, + 'bypass_trash' => $accesskey_mailbox_bypass_trash, + 'expungeButton' => $accesskey_mailbox_expunge, + 'moveButton' => $accesskey_mailbox_move, + 'copyButton' => $accesskey_mailbox_copy, ); @@ -1070,30 +1104,39 @@ function showMessagesForMailbox($imapConnection, &$aMailbox,$aProps, &$iError) { foreach($aAdminControl as $k => $v) { if ($v & $aUserControl[$k] & $aImapControl[$k]) { switch ($k) { - case 'markUnflagged': case 'markFlagged': + case 'markUnflagged': case 'markRead': case 'markUnread': case 'delete': case 'undeleteButton': case 'expungeButton': case 'forward': - $aFormElements[$k] = array($aButtonStrings[$k],'submit'); + $aFormElements[$k] + = array('value' => $aButtonStrings[$k], 'type' => 'submit', 'accesskey' => (isset($aButtonAccessKeys[$k]) ? $aButtonAccessKeys[$k] : 'NONE')); break; case 'bypass_trash': - $aFormElements[$k] = array($aButtonStrings[$k],'checkbox'); + $aFormElements[$k] + = array('value' => $aButtonStrings[$k], 'type' => 'checkbox', 'accesskey' => (isset($aButtonAccessKeys[$k]) ? $aButtonAccessKeys[$k] : 'NONE')); break; case 'moveButton': - $aFormElements['targetMailbox'] = - array(sqimap_mailbox_option_list($imapConnection, array(strtolower($lastTargetMailbox)), 0, $boxes),'select'); - $aFormElements['mailbox'] = array($aMailbox['NAME'],'hidden'); - $aFormElements['startMessage'] = array($aMailbox['PAGEOFFSET'],'hidden'); - $aFormElements[$k] = array($aButtonStrings[$k],'submit'); + case 'copyButton': + $aFormElements['targetMailbox'] + = array('options_list' => sqimap_mailbox_option_list($imapConnection, array(strtolower($lastTargetMailbox)), 0, $boxes), + 'type' => 'select', + 'accesskey' => $accesskey_mailbox_move_to); + $aFormElements['mailbox'] + = array('value' => $aMailbox['NAME'], 'type' => 'hidden'); + $aFormElements['startMessage'] + = array('value' => $aMailbox['PAGEOFFSET'], 'type' => 'hidden'); + $aFormElements[$k] + = array('value' => $aButtonStrings[$k], 'type' => 'submit', 'accesskey' => (isset($aButtonAccessKeys[$k]) ? $aButtonAccessKeys[$k] : 'NONE')); break; } } - $aFormElements['account'] = array($iAccount,'hidden'); + $aFormElements['account'] = array('value' => $iAccount,'type' => 'hidden'); } + do_hook('message_list_controls', $aFormElements); /* * This is the beginning of the message list table. @@ -1109,7 +1152,8 @@ function showMessagesForMailbox($imapConnection, &$aMailbox,$aProps, &$iError) { /* finally set the template vars */ - // FIX ME, before we support multiple templates we must review the names of the vars +// FIXME, before we support multiple templates we must review the names of the vars +// BUMP! $aTemplate['color'] = $color; @@ -1131,9 +1175,11 @@ function showMessagesForMailbox($imapConnection, &$aMailbox,$aProps, &$iError) { $aTemplate['trash_folder'] = $trash_folder; $aTemplate['sent_folder'] = $sent_folder; $aTemplate['draft_folder'] = $draft_folder; - $aTemplate['thread_link_str'] = $thread_link_str; + $aTemplate['thread_link_uri'] = $thread_link_uri; + $aTemplate['thread_name'] = $thread_name; $aTemplate['php_self'] = str_replace('&','&',$php_self); $aTemplate['mailbox'] = $sMailbox; +//FIXME: javascript_on is always assigned to the template object in places like init.php; is there some reason to reassign it here? is there some chance that it was changed? if not, please remove this line! $aTemplate['javascript_on'] = (isset($aProps['config']['javascript_on'])) ? $aProps['config']['javascript_on'] : false; $aTemplate['enablesort'] = (isset($aProps['config']['enablesort'])) ? $aProps['config']['enablesort'] : false; $aTemplate['icon_theme'] = (isset($aProps['config']['icon_theme'])) ? $aProps['config']['icon_theme'] : false; @@ -1142,102 +1188,103 @@ function showMessagesForMailbox($imapConnection, &$aMailbox,$aProps, &$iError) { $aTemplate['fancy_index_highlite'] = $fancy_index_highlite; - return $aTemplate; -} - - -/** - * Truncates a string and take care of html encoded characters - * - * @param string $s string to truncate - * @param int $iTrimAt Trim at nn characters - * @return string Trimmed string - */ -function truncateWithEntities($s, $iTrimAt) { - global $languages, $squirrelmail_language; - - $ent_strlen = strlen($s); - if (($iTrimAt <= 0) || ($ent_strlen <= $iTrimAt)) - return $s; - - if (isset($languages[$squirrelmail_language]['XTRA_CODE']) && - function_exists($languages[$squirrelmail_language]['XTRA_CODE'] . '_strimwidth')) { - return call_user_func($languages[$squirrelmail_language]['XTRA_CODE'] . '_strimwidth', $s, $iTrimAt); + /** + * Set up sort possibilities; one could argue that this is best + * placed in the template, but most template authors won't understand + * or need to understand it, so some advanced templates can override + * it if they do something different. + */ + if (!($aTemplate['sort'] & SQSORT_THREAD) && $aTemplate['enablesort']) { + $aTemplate['aSortSupported'] + = array(SQM_COL_SUBJ => array(SQSORT_SUBJ_ASC , SQSORT_SUBJ_DESC), + SQM_COL_DATE => array(SQSORT_DATE_DESC , SQSORT_DATE_ASC), + SQM_COL_INT_DATE => array(SQSORT_INT_DATE_DESC, SQSORT_INT_DATE_ASC), + SQM_COL_FROM => array(SQSORT_FROM_ASC , SQSORT_FROM_DESC), + SQM_COL_TO => array(SQSORT_TO_ASC , SQSORT_TO_DESC), + SQM_COL_CC => array(SQSORT_CC_ASC , SQSORT_CC_DESC), + SQM_COL_SIZE => array(SQSORT_SIZE_ASC , SQSORT_SIZE_DESC)); } else { - /* - * see if this is entities-encoded string - * If so, Iterate through the whole string, find out - * the real number of characters, and if more - * than $iTrimAt, substr with an updated trim value. - */ - $trim_val = $iTrimAt; - $ent_offset = 0; - $ent_loc = 0; - while ( $ent_loc < $trim_val && (($ent_loc = strpos($s, '&', $ent_offset)) !== false) && - (($ent_loc_end = strpos($s, ';', $ent_loc+3)) !== false) ) { - $trim_val += ($ent_loc_end-$ent_loc); - $ent_offset = $ent_loc_end+1; - } + $aTemplate['aSortSupported'] = array(); + } - if (($trim_val > $iTrimAt) && ($ent_strlen > $trim_val) && (strpos($s,';',$trim_val) < ($trim_val + 6))) { - $i = strpos($s,';',$trim_val); - if ($i !== false) { - $trim_val = strpos($s,';',$trim_val)+1; + + /** + * Figure out which columns should serve as labels for checkbox: + * we try to grab the two columns before and after the checkbox, + * except the subject column, since it is the link that opens + * the message view + * + * if $javascript_on is set, then the highlighting code takes + * care of this; just skip it + * + * This code also might be more appropriate in a template file, but + * we are moving this complex stuff out of the way of template + * authors; advanced template sets are always free to override + * the resultant values. + * + */ + $show_label_columns = array(); + $index_order_part = array(); + if (!($aTemplate['javascript_on'] && $aTemplate['fancy_index_highlite'])) { + $get_next_two = 0; + $last_order_part = 0; + $last_last_order_part = 0; + foreach ($aTemplate['aOrder'] as $index_order_part) { + if ($index_order_part == SQM_COL_CHECK) { + $get_next_two = 1; + if ($last_last_order_part != SQM_COL_SUBJ) + $show_label_columns[] = $last_last_order_part; + if ($last_order_part != SQM_COL_SUBJ) + $show_label_columns[] = $last_order_part; + + } else if ($get_next_two > 0 && $get_next_two < 3 && $index_order_part != SQM_COL_SUBJ) { + $show_label_columns[] = $index_order_part; + $get_next_two++; } + $last_last_order_part = $last_order_part; + $last_order_part = $index_order_part; } - // only print '...' when we're actually dropping part of the subject - if ($ent_strlen <= $trim_val) - return $s; } - return substr_replace($s, '...', $trim_val); -} - - -/** - * This should go in imap_mailbox.php - * @param string $mailbox - */ -function handleAsSent($mailbox) { - global $handleAsSent_result; + $aTemplate['show_label_columns'] = $show_label_columns; - /* 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); + return $aTemplate; - /* And return the result. */ - return $handleAsSent_result; } + /** * Process messages list form and handle the cache gracefully. If $sButton and * $aUid are provided as argument then you can fake a message list submit and * use it i.e. in read_body.php for del move next and update the cache * * @param resource $imapConnection imap connection - * @param array $aMailbox (reference) cached mailbox - * @param string $sButton fake a submit button - * @param array $aUid fake the $msg array + * @param array $aMailbox (reference) cached mailbox + * @param string $sButton fake a submit button + * @param array $aUid fake the $msg array + * @param string $targetMailbox fake the target mailbox for move operations + * @param boolean $bypass_trash fake the bypass trash checkbox for delete operations * @return string $sError error string in case of an error * @since 1.5.1 * @author Marc Groot Koerkamp */ -function handleMessageListForm($imapConnection,&$aMailbox,$sButton='',$aUid = array()) { +function handleMessageListForm($imapConnection, &$aMailbox, $sButton='', + $aUid = array(), $targetMailbox='', $bypass_trash=NULL) { /* incoming formdata */ - $sButton = (sqgetGlobalVar('moveButton', $sTmp, SQ_POST)) ? 'move' : $sButton; - $sButton = (sqgetGlobalVar('expungeButton', $sTmp, SQ_POST)) ? 'expunge' : $sButton; - $sButton = (sqgetGlobalVar('forward', $sTmp, SQ_POST)) ? 'forward' : $sButton; - $sButton = (sqgetGlobalVar('delete', $sTmp, SQ_POST)) ? 'setDeleted' : $sButton; - $sButton = (sqgetGlobalVar('undeleteButton', $sTmp, SQ_POST)) ? 'unsetDeleted' : $sButton; - $sButton = (sqgetGlobalVar('markRead', $sTmp, SQ_POST)) ? 'setSeen' : $sButton; - $sButton = (sqgetGlobalVar('markUnread', $sTmp, SQ_POST)) ? 'unsetSeen' : $sButton; - $sButton = (sqgetGlobalVar('markFlagged', $sTmp, SQ_POST)) ? 'setFlagged' : $sButton; - $sButton = (sqgetGlobalVar('markUnflagged', $sTmp, SQ_POST)) ? 'unsetFlagged' : $sButton; - sqgetGlobalVar('targetMailbox', $targetMailbox, SQ_POST); - sqgetGlobalVar('bypass_trash', $bypass_trash, SQ_POST); - sqgetGlobalVar('msg', $msg, SQ_POST); - if (sqgetGlobalVar('account', $iAccount, SQ_POST) === false) { + $sButton = (sqgetGlobalVar('moveButton', $sTmp, SQ_FORM)) ? 'move' : $sButton; + $sButton = (sqgetGlobalVar('copyButton', $sTmp, SQ_FORM)) ? 'copy' : $sButton; + $sButton = (sqgetGlobalVar('expungeButton', $sTmp, SQ_FORM)) ? 'expunge' : $sButton; + $sButton = (sqgetGlobalVar('forward', $sTmp, SQ_FORM)) ? 'forward' : $sButton; + $sButton = (sqgetGlobalVar('delete', $sTmp, SQ_FORM)) ? 'setDeleted' : $sButton; + $sButton = (sqgetGlobalVar('undeleteButton', $sTmp, SQ_FORM)) ? 'unsetDeleted' : $sButton; + $sButton = (sqgetGlobalVar('markRead', $sTmp, SQ_FORM)) ? 'setSeen' : $sButton; + $sButton = (sqgetGlobalVar('markUnread', $sTmp, SQ_FORM)) ? 'unsetSeen' : $sButton; + $sButton = (sqgetGlobalVar('markFlagged', $sTmp, SQ_FORM)) ? 'setFlagged' : $sButton; + $sButton = (sqgetGlobalVar('markUnflagged', $sTmp, SQ_FORM)) ? 'unsetFlagged' : $sButton; + if (empty($targetMailbox)) sqgetGlobalVar('targetMailbox', $targetMailbox, SQ_FORM); + if (is_null($bypass_trash)) sqgetGlobalVar('bypass_trash', $bypass_trash, SQ_FORM); + sqgetGlobalVar('msg', $msg, SQ_FORM); + if (sqgetGlobalVar('account', $iAccount, SQ_FORM) === false) { $iAccount = 0; } $sError = ''; @@ -1246,6 +1293,16 @@ function handleMessageListForm($imapConnection,&$aMailbox,$sButton='',$aUid = ar /* retrieve the check boxes */ $aUid = (isset($msg) && is_array($msg)) ? array_values($msg) : $aUid; if (count($aUid) && $sButton != 'expunge') { + + // don't do anything to any messages until we have done security check + // FIXME: not sure this code really belongs here, but there's nowhere else to put it with this architecture + sqgetGlobalVar('smtoken', $submitted_token, SQ_FORM, ''); + sm_validate_security_token($submitted_token, 3600, TRUE); + + // make sure message UIDs are sanitized (BIGINT) + foreach ($aUid as $i => $uid) + $aUid[$i] = (preg_match('/^[0-9]+$/', $uid) ? $uid : '0'); + $aUpdatedMsgs = false; $bExpunge = false; switch ($sButton) { @@ -1274,6 +1331,12 @@ function handleMessageListForm($imapConnection,&$aMailbox,$sButton='',$aUid = ar sqsession_register($targetMailbox,'lastTargetMailbox'); $bExpunge = true; break; + case 'copy': + // sqimap_msgs_list_copy returns true or false. + // If error happens - fourth argument handles it inside function. + sqimap_msgs_list_copy($imapConnection,$aUid,$targetMailbox,true); + sqsession_register($targetMailbox,'lastTargetMailbox'); + break; case 'forward': $aMsgHeaders = array(); foreach ($aUid as $iUid) { @@ -1282,18 +1345,20 @@ function handleMessageListForm($imapConnection,&$aMailbox,$sButton='',$aUid = ar if (count($aMsgHeaders)) { $composesession = attachSelectedMessages($imapConnection,$aMsgHeaders); // dirty hack, add info to $aMailbox - $aMailbox['FORWARD_SESSION'] = $composesession; + $aMailbox['FORWARD_SESSION']['SESSION_NUMBER'] = $composesession; + $aMailbox['FORWARD_SESSION']['UIDS'] = $aUid; } break; default: // Hook for plugin buttons - do_hook_function('mailbox_display_button_action', $aUid); + $temp = array(&$sButton, &$aMailbox, $iAccount, $aMailbox['NAME'], &$aUid); + do_hook('mailbox_display_button_action', $temp); break; } /** - * Updates messages is an array containing the result of the untagged + * $aUpdatedMsgs is an array containing the result of the untagged * fetch responses send by the imap server due to a flag change. That - * response is parsed in a array with msg arrays by the parseFetch function + * response is parsed in an array with msg arrays by the parseFetch function */ if ($aUpdatedMsgs) { // Update the message headers cache @@ -1307,6 +1372,34 @@ function handleMessageListForm($imapConnection,&$aMailbox,$sButton='',$aUid = ar if (isset($aMailbox['MSG_HEADERS'][$iUid])) { $aMailbox['MSG_HEADERS'][$iUid]['FLAGS'] = $aMsg['FLAGS']; } + /** + * Also update flags in message object + */ +//FIXME: WHY are we keeping flags in TWO places?!? This is error-prone and some core code uses the is_xxxx message object values while other code uses the flags array above. That's a mess. + if (isset($aMailbox['MSG_HEADERS'][$iUid]['MESSAGE_OBJECT'])) { + $message = $aMailbox['MSG_HEADERS'][$iUid]['MESSAGE_OBJECT']; + $message->is_seen = false; + $message->is_answered = false; + $message->is_forwarded = false; + $message->is_deleted = false; + $message->is_flagged = false; + $message->is_mdnsent = false; + foreach ($aMsg['FLAGS'] as $flag => $value) { + if (strtolower($flag) == '\\seen' && $value) + $message->is_seen = true; + else if (strtolower($flag) == '\\answered' && $value) + $message->is_answered = true; + else if (strtolower($flag) == '$forwarded' && $value) + $message->is_forwarded = true; + else if (strtolower($flag) == '\\deleted' && $value) + $message->is_deleted = true; + else if (strtolower($flag) == '\\flagged' && $value) + $message->is_flagged = true; + else if (strtolower($flag) == '$mdnsent' && $value) + $message->is_mdnsent = true; + } + $aMailbox['MSG_HEADERS'][$iUid]['MESSAGE_OBJECT'] = $message; + } /** * Count the messages with the \Delete flag set so we can determine * if the number of expunged messages equals the number of flagged @@ -1371,7 +1464,15 @@ function handleMessageListForm($imapConnection,&$aMailbox,$sButton='',$aUid = ar sqimap_run_command($imapConnection,'CLOSE',false,$result,$message); $aMailbox = sqm_api_mailbox_select($imapConnection,$iAccount, $aMailbox['NAME'],array(),array()); } else { - if ($sButton) { + // this is the same hook as above, but here it is called in the + // context of not having had any messages selected and if any + // plugin handles the situation, it should return TRUE so we + // know this was not an erroneous user action + // + global $null; + $temp = array(&$sButton, &$aMailbox, $iAccount, $aMailbox['NAME'], $null); + if (!boolean_hook_function('mailbox_display_button_action', $temp, 1) + && $sButton) { $sError = _("No messages were selected."); } } @@ -1388,9 +1489,6 @@ function handleMessageListForm($imapConnection,&$aMailbox,$sButton='',$aUid = ar * @author Marc Groot Koerkamp */ function attachSelectedMessages($imapConnection,$aMsgHeaders) { - global $username, $attachment_dir, - $data_dir; - sqgetGlobalVar('composesession', $composesession, SQ_SESSION); sqgetGlobalVar('compose_messages', $compose_messages, SQ_SESSION); @@ -1407,8 +1505,6 @@ function attachSelectedMessages($imapConnection,$aMsgHeaders) { sqsession_register($composesession,'composesession'); } - $hashed_attachment_dir = getHashedDir($username, $attachment_dir); - $composeMessage = new Message(); $rfc822_header = new Rfc822Header(); $composeMessage->rfc822_header = $rfc822_header; @@ -1428,14 +1524,25 @@ function attachSelectedMessages($imapConnection,$aMsgHeaders) { $body = implode('', $body_a); $body .= "\r\n"; - $localfilename = GenerateRandomString(32, 'FILE', 7); - $full_localfilename = "$hashed_attachment_dir/$localfilename"; - - $fp = fopen( $full_localfilename, 'wb'); + global $username, $attachment_dir; + $filename = sq_get_attach_tempfile(); + $fullpath = getHashedDir($username, $attachment_dir) . '/' . $filename; + $fp = fopen($fullpath, 'wb'); fwrite ($fp, $body); fclose($fp); - $composeMessage->initAttachment('message/rfc822',$subject.'.msg', - $full_localfilename); + + $composeMessage->initAttachment('message/rfc822', $subject . '.eml', $filename); + + // create subject for new message + // + $subject = decodeHeader($subject,false,false,true); + $subject = str_replace('"', "'", $subject); + $subject = trim($subject); + if (substr(strtolower($subject), 0, 4) != 'fwd:') { + $subject = 'Fwd: ' . $subject; + } + $composeMessage->rfc822_header->subject = $subject; + } } @@ -1444,4 +1551,3 @@ function attachSelectedMessages($imapConnection,$aMsgHeaders) { return $composesession; } -?>