*
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
*
*/
/* $Id$ */
class uidisplay
{
var $public_functions = array
(
'display' => True,
'displayBody' => True,
'displayHeader' => True,
'displayImage' => True,
'displayAttachments' => True,
'printMessage' => True,
'saveMessage' => True,
'showHeader' => True,
'getAttachment' => True,
'getdisplayableBody' => True,
);
var $icServerID=0;
// the object storing the data about the incoming imap server
var $icServer=0;
// the non permanent id of the message
var $id;
// partid of the current mail to be displayed
var $partID;
// the permanent id of the message
var $uid;
/**
* Reference to felamimail_bo
*
* @var felamimail_bo
*/
var $bofelamimail;
/**
* Reference to bopreference instance of felamimail_bo
*
* @var bopreferences
*/
var $bopreferences;
function uidisplay()
{
/* Having this defined in just one spot could help when changes need
* to be made to the pattern
* Make sure that the expression is evaluated case insensitively
*
* RFC2822 (and RFC822) defines the left side of an email address as (roughly):
* 1*atext *("." 1*atext)
* where atext is: a-zA-Z0-9!#$%&'*+-/=?^_`{|}~
*
* Here's pretty sophisticated IP matching:
* $IPMatch = '(2[0-5][0-9]|1?[0-9]{1,2})';
* $IPMatch = '\[?' . $IPMatch . '(\.' . $IPMatch . '){3}\]?';
*/
/* Here's enough: */
global $IP_RegExp_Match, $Host_RegExp_Match, $Email_RegExp_Match;
$IP_RegExp_Match = '\\[?[0-9]{1,3}(\\.[0-9]{1,3}){3}\\]?';
$Host_RegExp_Match = '('.$IP_RegExp_Match.'|[0-9a-z]([-.]?[0-9a-z])*\\.[a-z][a-z]+)';
#$atext = '([a-z0-9!#$&%*+/=?^_`{|}~-]|&)';
$atext = '([a-zA-Z0-9_\-\.])';
$dot_atom = $atext.'+(\.'.$atext.'+)*';
$Email_RegExp_Match = '~'.$dot_atom.'(%'.$Host_RegExp_Match.')?@'.$Host_RegExp_Match.'~i';
$this->t = CreateObject('phpgwapi.Template',EGW_APP_TPL);
$this->displayCharset = $GLOBALS['egw']->translation->charset();
if (isset($GLOBALS['egw_info']['user']['preferences']['felamimail']['ActiveProfileID']))
$this->icServerID = (int)$GLOBALS['egw_info']['user']['preferences']['felamimail']['ActiveProfileID'];
$this->bofelamimail = felamimail_bo::getInstance(true,$this->icServerID);
$this->bopreferences =& $this->bofelamimail->bopreferences;
$this->mailPreferences =& $this->bofelamimail->mailPreferences;//bopreferences->getPreferences();
$this->bofelamimail->openConnection($this->icServerID);
$this->mailbox = $this->bofelamimail->sessionData['mailbox'];
if (!empty($_GET['mailbox'])) $this->mailbox = base64_decode($_GET['mailbox']);
$this->sort = $this->bofelamimail->sessionData['sort'];
if(isset($_GET['uid'])) {
$this->uid = (int)$_GET['uid'];
}
if(isset($_GET['id'])) {
$this->id = (int)$_GET['id'];
}
/* this one (idToUid) does not exist (anymore)
if(isset($this->id) && !isset($this->uid)) {
if($uid = $this->bofelamimail->idToUid($this->mailbox, $this->id)) {
$this->uid = $uid;
}
}
*/
if(isset($_GET['part'])) {
$this->partID = (int)$_GET['part'];
}
$this->rowColor[0] = $GLOBALS['egw_info']["theme"]["bg01"];
$this->rowColor[1] = $GLOBALS['egw_info']["theme"]["bg02"];
}
/**
* Parses a body and converts all found email addresses to clickable links.
*
* @param string body the body to process, by ref
* @return int the number of unique addresses found
*/
function parseEmail (&$body) {
global $Email_RegExp_Match;
$sbody = $body;
$addresses = array();
$i = 0;
/* Find all the email addresses in the body */
// stop cold after 100 adresses, as this is very time consuming
while(preg_match($Email_RegExp_Match, $sbody, $regs) && $i<=100) {
//_debug_array($regs);
$addresses[$regs[0]] = strtr($regs[0], array('&' => '&'));
$start = strpos($sbody, $regs[0]) + strlen($regs[0]);
$sbody = substr($sbody, $start);
$i++;
}
/* Replace each email address with a compose URL */
$lmail='';
if (is_array($addresses)) ksort($addresses);
foreach ($addresses as $text => $email) {
if ($lmail == $email) next($addresses);
//echo __METHOD__.' Text:'.$text."#
";
//echo $email."#
";
$comp_uri = $this->makeComposeLink($email, $text);
//echo __METHOD__.' Uri:'.$comp_uri.'#
';
$body = str_replace($text, $comp_uri, $body);
$lmail=$email;
}
/* Return number of unique addresses found */
return count($addresses);
}
function parseHREF (&$body) {
#echo __METHOD__."called
";
$webserverURL = $GLOBALS['egw_info']['server']['webserver_url'];
$alnum = 'a-z0-9';
#$domain = "(http(s?):\/\/)*";
#$domain .= "([$alnum]([-$alnum]*[$alnum]+)?)";
#$domain = "^(http|https|ftp)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\-\._\?\,\'/\\\+&%\$#\=~])*[^\.\,\)\(\s]$ ";
$domain = "(http(s?):\/\/)+([[:alpha:]][-[:alnum:]]*[[:alnum:]])(\.[[:alpha:]][-[:alnum:]]*[[:alpha:]])*(\.[[:alpha:]][-[:alnum:]]*[[:alpha:]])+";
#$dir = "(/[[:alpha:]][-[:alnum:]]*[[:alnum:]])*";
#$trailingslash = "(\/?)";
#$page = "(/[[:alpha:]][-[:alnum:]]*\.[[:alpha:]]{3,5})?";
#$getstring = "(\?([[:alnum:]][-_%[:alnum:]]*=[-_%[:alnum:]]+)
# (&([[:alnum:]][-_%[:alnum:]]*=[-_%[:alnum:]]+))*)?";
#$pattern = "^".$domain.$dir.$trailingslash.$page.$getstring."$";
$pattern = "~\ $link) {
if (empty($link)) continue;
if ($llink == $link) next($addresses);
#echo $text."#
";
#echo $link."#
\n";
$link = str_replace("\n","",$link);
$comp_uri = "');
//error_log( __METHOD__." text:".$text.'#
');
// create links for email addresses
$linkData = array
(
'menuaction' => 'felamimail.uicompose.compose',
'send_to' => base64_encode($email)
);
$link = $GLOBALS['egw']->link('/index.php',$linkData);
//error_log(__METHOD__." link:".$link.'#
');
//return "".$text."";
return "".$text."";
}
function highlightQuotes($text, $level = 5)
{
// Use a global var since the class is called statically.
$GLOBALS['_tmp_maxQuoteChars'] = 0;
// Tack a newline onto the beginning of the string so that we
// correctly highlight when the first character in the string
// is a quote character.
$text = "\n$text";
preg_replace_callback("/^\s*((>\s?)+)/m", array(&$this, '_countQuoteChars'), $text);
// Go through each level of quote block and put the
// appropriate style around it. Important to work downwards so
// blocks with fewer quote chars aren't matched until their
// turn.
for ($i = $GLOBALS['_tmp_maxQuoteChars']; $i > 0; $i--)
{
$text = preg_replace(
// Finds a quote block across multiple newlines.
"/(\n)( *(>\s?)\{$i}(?! ?>).*?)(\n|$)(?! *(> ?)\{$i})/s",
'\1\2\4',$text);
}
/* Unset the global variable. */
unset($GLOBALS['_tmp_maxQuoteChars']);
/* Remove the leading newline we added above. */
return substr($text, 1);
}
function _countQuoteChars($matches)
{
$num = count(preg_split('/>\s?/', $matches[1])) - 1;
if ($num > $GLOBALS['_tmp_maxQuoteChars'])
{
$GLOBALS['_tmp_maxQuoteChars'] = $num;
}
}
function display()
{
$partID = $this->partID = $_GET['part'];
if (!empty($_GET['mailbox'])) $this->mailbox = base64_decode($_GET['mailbox']);
//$transformdate =& CreateObject('felamimail.transformdate');
//$htmlFilter =& CreateObject('felamimail.htmlfilter');
$uiWidgets = CreateObject('felamimail.uiwidgets');
// (regis) seems to be necessary to reopen...
$this->bofelamimail->reopen($this->mailbox);
// retrieve the flags of the message, before touching it.
if (!empty($this->uid)) $flags = $this->bofelamimail->getFlags($this->uid);
#print "$this->mailbox, $this->uid, $partID
";
$headers = $this->bofelamimail->getMessageHeader($this->uid, $partID);
if (PEAR::isError($headers)) {
print lang("ERROR: Message could not be displayed.")."
";
print "In Mailbox: $this->mailbox, with ID: $this->uid, and PartID: $partID
";
print $headers->message."
";
_debug_array($headers->backtrace[0]);
exit;
}
#_debug_array($headers);exit;
$rawheaders = $this->bofelamimail->getMessageRawHeader($this->uid, $partID);
//_debug_array($rawheaders);exit;
$fetchEmbeddedImages = false;
if ($this->bofelamimail->htmlOptions !='always_display') $fetchEmbeddedImages = true;
$attachments = $this->bofelamimail->getMessageAttachments($this->uid, $partID, '',$fetchEmbeddedImages);
//_debug_array($attachments); //exit;
$envelope = $this->bofelamimail->getMessageEnvelope($this->uid, $partID,true);
//_debug_array($envelope); exit;
// if not using iFrames, we need to retrieve the messageBody here
// by now this is a fixed value and controls the use/loading of the template and how the vars are set.
// Problem is: the iFrame Layout provides the scrollbars.
#$bodyParts = $this->bofelamimail->getMessageBody($this->uid,'',$partID);
#_debug_array($bodyParts); exit;
#_debug_array($this->uid);
#_debug_array($this->bofelamimail->getFlags($this->uid)); #exit;
// flag the message as read/seen (if not already flagged)
if (!empty($this->uid) && strpos( array2string($flags),'Seen')===false) $this->bofelamimail->flagMessages('read', $this->uid);
$nextMessage = $this->bofelamimail->getNextMessage($this->mailbox, $this->uid);
$webserverURL = $GLOBALS['egw_info']['server']['webserver_url'];
$nonDisplayAbleCharacters = array('[\016]','[\017]',
'[\020]','[\021]','[\022]','[\023]','[\024]','[\025]','[\026]','[\027]',
'[\030]','[\031]','[\032]','[\033]','[\034]','[\035]','[\036]','[\037]');
#print "
";print_r($rawheaders);print"";exit; // add line breaks to $rawheaders $newRawHeaders = explode("\n",$rawheaders); reset($newRawHeaders); if(isset($headers['ORGANIZATION'])) { $organization = $this->bofelamimail->decode_header(trim($headers['ORGANIZATION'])); } if ( isset($headers['DISPOSITION-NOTIFICATION-TO']) ) { $sent_not = $this->bofelamimail->decode_header(trim($headers['DISPOSITION-NOTIFICATION-TO'])); } else if ( isset($headers['RETURN-RECEIPT-TO']) ) { $sent_not = $this->bofelamimail->decode_header(trim($headers['RETURN-RECEIPT-TO'])); } else if ( isset($headers['X-CONFIRM-READING-TO']) ) { $sent_not = $this->bofelamimail->decode_header(trim($headers['X-CONFIRM-READING-TO'])); } else $sent_not = ""; // reset $rawheaders $rawheaders = ""; // create it new, with good line breaks reset($newRawHeaders); while(list($key,$value) = @each($newRawHeaders)) { $rawheaders .= wordwrap($value, 90, "\n "); } $this->display_app_header(); if(!isset($_GET['printable'])) { $this->t->set_file(array("displayMsg" => "view_message.tpl")); } else { $this->t->set_file(array("displayMsg" => "view_message_printable.tpl")); $this->t->set_var('charset',$GLOBALS['egw']->translation->charset()); } // only notify when requested, notify flag (MDNSent/MDNnotSent) not set, and message not already seen (some servers do not support the MDNSent/MDNnotSent flag) if ( $sent_not != "" && $this->bofelamimail->getNotifyFlags($this->uid) === null && strpos( array2string($flags),'Seen')===false) { $this->t->set_var('sentNotify','sendNotify("'.$this->uid.'");'); $this->t->set_var('lang_sendnotify',lang('The message sender has requested a response to indicate that you have read this message. Would you like to send a receipt?')); } else { $this->t->set_var('sentNotify',''); $this->t->set_var('lang_sendnotify',''); } $this->t->set_block('displayMsg','message_main'); $this->t->set_block('displayMsg','message_main_attachment'); $this->t->set_block('displayMsg','message_header'); $this->t->set_block('displayMsg','message_raw_header'); $this->t->set_block('displayMsg','message_navbar'); $this->t->set_block('displayMsg','message_onbehalfof'); $this->t->set_block('displayMsg','message_cc'); $this->t->set_block('displayMsg','message_bcc'); $this->t->set_block('displayMsg','message_attachement_row'); $this->t->set_block('displayMsg','previous_message_block'); $this->t->set_block('displayMsg','next_message_block'); //$this->t->set_block('displayMsg','message_org'); $this->t->egroupware_hack = False; $this->translate(); // navBar buttons $headerData = array('uid'=>$this->uid); if($partID != '') { $headerData['partid'] = $partID; } if (strpos( array2string($flags),'Deleted')!==false) { $headerData['deleted']=1; } $this->t->set_var('navbarButtonsLeft',$uiWidgets->displayMessageActions($headerData, $this->mailbox, $this->icServer)); $navbarButtons = ''; $navbarImages = array(); #_debug_array($nextMessage); exit; if($nextMessage['previous']) { $linkData = array ( 'menuaction' => 'felamimail.uidisplay.display', 'showHeader' => 'false', 'uid' => $nextMessage['previous'], 'mailbox' => base64_encode($this->mailbox) ); $previousURL = $GLOBALS['egw']->link('/index.php',$linkData); $previousURL = "goToMessage('$previousURL')"; $navbarImages['up.button'] = array( 'action' => $previousURL, 'tooltip' => lang('previous message'), ); } else { $previousURL = '#'; $navbarImages['up.grey'] = array( 'action' => $previousURL, 'tooltip' => lang('previous message'), ); } if($nextMessage['next']) { $linkData = array ( 'menuaction' => 'felamimail.uidisplay.display', 'showHeader' => 'false', 'uid' => $nextMessage['next'], 'mailbox' => base64_encode($this->mailbox) ); $nextURL = $GLOBALS['egw']->link('/index.php',$linkData); $nextURL = "goToMessage('$nextURL')"; $navbarImages['down.button'] = array( 'action' => $nextURL, 'tooltip' => lang('next message'), ); } else { $nextURL = '#'; $navbarImages['down.grey'] = array( #'action' => $nextURL, 'tooltip' => lang('next message'), ); } foreach($navbarImages as $buttonName => $buttonData) { $navbarButtons .= $uiWidgets->navbarButton($buttonName, $buttonData['action'], $buttonData['tooltip'], 'right'); } $this->t->set_var('navbarButtonsRight',$navbarButtons); $this->t->parse('navbar','message_navbar',True); // navbar end // header // sent by a mailinglist?? // parse the from header if($envelope['FROM'][0] != $envelope['SENDER'][0]) { $senderAddress = self::emailAddressToHTML($envelope['SENDER'],'',false,true,false); $fromAddress = self::emailAddressToHTML($envelope['FROM'], $organization,false,true,false); $this->t->set_var("from_data",$senderAddress); $this->t->set_var("onbehalfof_data",$fromAddress); $this->t->parse('on_behalf_of_part','message_onbehalfof',True); } else { $fromAddress = self::emailAddressToHTML($envelope['FROM'], $organization,false,true,false); $this->t->set_var("from_data", $fromAddress); $this->t->set_var('on_behalf_of_part',''); } // parse the to header $toAddress = self::emailAddressToHTML($envelope['TO'],'',false,true,false); $this->t->set_var("to_data",$toAddress); // parse the cc header if(count($envelope['CC'])) { $ccAddress = self::emailAddressToHTML($envelope['CC'],'',false,true,false); $this->t->set_var("cc_data",$ccAddress); $this->t->parse('cc_data_part','message_cc',True); } else { $this->t->set_var("cc_data_part",''); } // parse the bcc header if(count($envelope['BCC'])) { $bccAddress = self::emailAddressToHTML($envelope['BCC'],'',false,true,false); $this->t->set_var("bcc_data",$bccAddress); $this->t->parse('bcc_data_part','message_bcc',True); } else { $this->t->set_var("bcc_data_part",''); } $this->t->set_var("date_received", @htmlspecialchars(felamimail_bo::_strtotime($headers['DATE'],$GLOBALS['egw_info']['user']['preferences']['common']['dateformat'],true).' - '.felamimail_bo::_strtotime($headers['DATE'],($GLOBALS['egw_info']['user']['preferences']['common']['timeformat']==12?'h:i:s a':'H:i:s'),true), ENT_QUOTES,$this->displayCharset)); //echo 'Envelope:'.preg_replace($nonDisplayAbleCharacters,'',$envelope['SUBJECT']).'#0
'; $EndBody = ' |