get preview working

This commit is contained in:
Klaus Leithoff 2013-04-12 13:10:27 +00:00
parent ea175ca89d
commit ccc75e2bc7
5 changed files with 691 additions and 37 deletions

View File

@ -312,6 +312,7 @@ class mail_bo
*/
private function __construct($_displayCharset='utf-8',$_restoreSession=true, $_profileID=0)
{
if (!empty($_displayCharset)) self::$displayCharset = $_displayCharset;
if ($_restoreSession)
{
//error_log(__METHOD__." Session restore ".function_backtrace());
@ -2721,18 +2722,6 @@ class mail_bo
return $_string;
}
/**
* strip tags out of the message completely with their content
* param $_body is the text to be processed
* param $tag is the tagname which is to be removed. Note, that only the name of the tag is to be passed to the function
* without the enclosing brackets
* param $endtag can be different from tag but should be used only, if begin and endtag are known to be different e.g.: <!-- -->
*/
static function replaceTagsCompletley(&$_body,$tag,$endtag='',$addbracesforendtag=true)
{
translation::replaceTagsCompletley($_body,$tag,$endtag,$addbracesforendtag);
}
/**
* clean a message from elements regarded as potentially harmful
* param string/reference $_html is the text to be processed
@ -2751,10 +2740,10 @@ class mail_bo
$_html = str_replace(array('&amp;amp;','<DIV><BR></DIV>',"<DIV>&nbsp;</DIV>",'<div>&nbsp;</div>','</td></font>','<br><td>','<tr></tr>','<o:p></o:p>','<o:p>','</o:p>'),
array('&amp;', '<BR>', '<BR>', '<BR>', '</font></td>','<td>', '', '', '', ''),$_html);
//$_html = str_replace(array('&amp;amp;'),array('&amp;'),$_html);
if (stripos($_html,'style')!==false) self::replaceTagsCompletley($_html,'style'); // clean out empty or pagewide style definitions / left over tags
if (stripos($_html,'head')!==false) self::replaceTagsCompletley($_html,'head'); // Strip out stuff in head
//if (stripos($_html,'![if')!==false && stripos($_html,'<![endif]>')!==false) self::replaceTagsCompletley($_html,'!\[if','<!\[endif\]>',false); // Strip out stuff in ifs
//if (stripos($_html,'!--[if')!==false && stripos($_html,'<![endif]-->')!==false) self::replaceTagsCompletley($_html,'!--\[if','<!\[endif\]-->',false); // Strip out stuff in ifs
if (stripos($_html,'style')!==false) translation::replaceTagsCompletley($_html,'style'); // clean out empty or pagewide style definitions / left over tags
if (stripos($_html,'head')!==false) translation::replaceTagsCompletley($_html,'head'); // Strip out stuff in head
//if (stripos($_html,'![if')!==false && stripos($_html,'<![endif]>')!==false) translation::replaceTagsCompletley($_html,'!\[if','<!\[endif\]>',false); // Strip out stuff in ifs
//if (stripos($_html,'!--[if')!==false && stripos($_html,'<![endif]-->')!==false) translation::replaceTagsCompletley($_html,'!--\[if','<!\[endif\]-->',false); // Strip out stuff in ifs
//error_log(__METHOD__.__LINE__.$_html);
// force the use of kses, as it is still have the edge over purifier with some stuff
$usepurify = true;
@ -2763,10 +2752,10 @@ class mail_bo
// we need a customized config, as we may allow external images, $GLOBALS['egw_info']['user']['preferences']['mail']['allowExternalIMGs']
if (get_magic_quotes_gpc() === 1) $_html = stripslashes($_html);
// Strip out doctype in head, as htmlLawed cannot handle it TODO: Consider extracting it and adding it afterwards
if (stripos($_html,'!doctype')!==false) self::replaceTagsCompletley($_html,'!doctype');
if (stripos($_html,'?xml:namespace')!==false) self::replaceTagsCompletley($_html,'\?xml:namespace','/>',false);
if (stripos($_html,'?xml version')!==false) self::replaceTagsCompletley($_html,'\?xml version','\?>',false);
if (strpos($_html,'!CURSOR')!==false) self::replaceTagsCompletley($_html,'!CURSOR');
if (stripos($_html,'!doctype')!==false) translation::replaceTagsCompletley($_html,'!doctype');
if (stripos($_html,'?xml:namespace')!==false) translation::replaceTagsCompletley($_html,'\?xml:namespace','/>',false);
if (stripos($_html,'?xml version')!==false) translation::replaceTagsCompletley($_html,'\?xml version','\?>',false);
if (strpos($_html,'!CURSOR')!==false) translation::replaceTagsCompletley($_html,'!CURSOR');
// htmLawed filter only the 'body'
//preg_match('`(<htm.+?<body[^>]*>)(.+?)(</body>.*?</html>)`ims', $_html, $matches);
//if ($matches[2])
@ -3565,6 +3554,70 @@ class mail_bo
return $retValue;
}
/**
* getStyles - extracts the styles from the given bodyparts
* @param array $bodyParts with the bodyparts
* @return string a preformatted string with the mails converted to text
*/
static function &getStyles($_bodyParts)
{
$style = '';
if (empty($_bodyParts)) return "";
foreach((array)$_bodyParts as $singleBodyPart) {
if (!isset($singleBodyPart['body'])) {
$singleBodyPart['body'] = self::getStyles($singleBodyPart);
$style .= $singleBodyPart['body'];
continue;
}
if ($singleBodyPart['charSet']===false) $singleBodyPart['charSet'] = translation::detect_encoding($singleBodyPart['body']);
$singleBodyPart['body'] = translation::convert(
$singleBodyPart['body'],
strtolower($singleBodyPart['charSet'])
);
$ct = 0;
if (stripos($singleBodyPart['body'],'<style')!==false) $ct = preg_match_all('#<style(?:\s.*)?>(.+)</style>#isU', $singleBodyPart['body'], $newStyle);
if ($ct>0)
{
//error_log(__METHOD__.__LINE__.array2string($newStyle[0]));
$style2buffer = implode('',$newStyle[0]);
}
if ($style2buffer && strtoupper(self::$displayCharset) == 'UTF-8')
{
//error_log(__METHOD__.__LINE__.array2string($style2buffer));
$test = json_encode($style2buffer);
//error_log(__METHOD__.__LINE__.'#'.$test.'# ->'.strlen($style2buffer).' Error:'.json_last_error());
//if (json_last_error() != JSON_ERROR_NONE && strlen($style2buffer)>0)
if ($test=="null" && strlen($style2buffer)>0)
{
// this should not be needed, unless something fails with charset detection/ wrong charset passed
error_log(__METHOD__.__LINE__.' Found Invalid sequence for utf-8 in CSS:'.$style2buffer.' Charset Reported:'.$singleBodyPart['charSet'].' Carset Detected:'.translation::detect_encoding($style2buffer));
$style2buffer = utf8_encode($style2buffer);
}
}
$style .= $style2buffer;
}
// clean out comments and stuff
$search = array(
'@url\(http:\/\/[^\)].*?\)@si', // url calls e.g. in style definitions
// '@<!--[\s\S]*?[ \t\n\r]*-->@', // Strip multi-line comments including CDATA
// '@<!--[\s\S]*?[ \t\n\r]*--@', // Strip broken multi-line comments including CDATA
);
$style = preg_replace($search,"",$style);
// CSS Security
// http://code.google.com/p/browsersec/wiki/Part1#Cascading_stylesheets
$css = preg_replace('/(javascript|expession|-moz-binding)/i','',$style);
if (stripos($css,'script')!==false) translation::replaceTagsCompletley($css,'script'); // Strip out script that may be included
// we need this, as styledefinitions are enclosed with curly brackets; and template stuff tries to replace everything between curly brackets that is having no horizontal whitespace
// as the comments as <!-- styledefinition --> in stylesheet are outdated, and ck-editor does not understand it, we remove it
$css = str_replace(array(':','<!--','-->'),array(': ','',''),$css);
//error_log(__METHOD__.__LINE__.$css);
// TODO: we may have to strip urls and maybe comments and ifs
return $css;
}
/**
* getMessageRawBody
* get the message raw body
@ -3952,6 +4005,120 @@ class mail_bo
return $attachmentData;
}
/**
* Fetch a specific attachment from a message by it's cid
*
* this function is based on a on "Building A PHP-Based Mail Client"
* http://www.devshed.com
*
* @param string|int $_uid
* @param string $_cid
* @param string $_part
* @return array with values for keys 'type', 'filename' and 'attachment'
*/
function getAttachmentByCID($_uid, $_cid, $_part)
{
// some static variables to avoid fetching the same mail multiple times
static $uid,$part,$attachments,$structure;
//error_log("getAttachmentByCID:$_uid, $_cid, $_part");
if(empty($_cid)) return false;
if ($_uid != $uid || $_part != $part)
{
$attachments = $this->getMessageAttachments($uid=$_uid, $part=$_part);
$structure = null;
}
$partID = false;
foreach($attachments as $attachment)
{
//error_log(print_r($attachment,true));
if(isset($attachment['cid']) && (strpos($attachment['cid'], $_cid) !== false || strpos($_cid, $attachment['cid']) !== false))
{
$partID = $attachment['partID'];
break;
}
}
if ($partID == false)
{
foreach($attachments as $attachment)
{
// if the former did not match try matching the cid to the name of the attachment
if(isset($attachment['cid']) && isset($attachment['name']) && (strpos($attachment['name'], $_cid) !== false || strpos($_cid, $attachment['name']) !== false))
{
$partID = $attachment['partID'];
break;
}
}
}
if ($partID == false)
{
foreach($attachments as $attachment)
{
// if the former did not match try matching the cid to the name of the attachment, AND there is no mathing attachment with cid
if(isset($attachment['name']) && (strpos($attachment['name'], $_cid) !== false || strpos($_cid, $attachment['name']) !== false))
{
$partID = $attachment['partID'];
break;
}
}
}
//error_log( "Cid:$_cid PARTID:$partID<bR>"); #exit;
if($partID == false) {
return false;
}
// parse message structure
if (is_null($structure))
{
$structure = $this->_getStructure($_uid, true);
}
$part_structure = $this->_getSubStructure($structure, $partID);
$filename = $this->getFileNameFromStructure($part_structure, $_uid, $_uid, $part_structure->partID);
$attachment = $this->icServer->getBodyPart($_uid, $partID, true);
if (PEAR::isError($attachment))
{
error_log(__METHOD__.__LINE__.' failed:'.$attachment->message);
return array('type' => 'text/plain',
'filename' => 'error.txt',
'attachment' =>__METHOD__.' failed:'.$attachment->message
);
}
if (PEAR::isError($attachment))
{
error_log(__METHOD__.__LINE__.' failed:'.$attachment->message);
return array('type' => 'text/plain',
'filename' => 'error.txt',
'attachment' =>__METHOD__.' failed:'.$attachment->message
);
}
switch ($part_structure->encoding) {
case 'BASE64':
// use imap_base64 to decode
$attachment = imap_base64($attachment);
break;
case 'QUOTED-PRINTABLE':
// use imap_qprint to decode
#$attachment = imap_qprint($attachment);
$attachment = quoted_printable_decode($attachment);
break;
default:
// it is either not encoded or we don't know about it
}
$attachmentData = array(
'type' => $part_structure->type .'/'. $part_structure->subType,
'filename' => $filename,
'attachment' => $attachment
);
// try guessing the mimetype, if we get the application/octet-stream
if (strtolower($attachmentData['type']) == 'application/octet-stream') $attachmentData['type'] = mime_magic::filename2mime($attachmentData['filename']);
return $attachmentData;
}
/**
* functions to allow access to mails through other apps to fetch content

View File

@ -10,6 +10,8 @@
* @version $Id$
*/
include_once(EGW_INCLUDE_ROOT.'/etemplate/inc/class.etemplate.inc.php');
/**
* Mail Interface class
*/
@ -26,6 +28,7 @@ class mail_ui
'displayHeader' => True,
'saveMessage' => True,
'vfsSaveMessage' => True,
'loadEmailBody' => True,
'importMessage' => True,
'TestConnection' => True,
);
@ -183,7 +186,7 @@ class mail_ui
$sel_options['cat_id'] = array(1=>'none');
if (!isset($content['nm']['cat_id'])) $content['nm']['cat_id'] = 'All';
$etpl = new etemplate('mail.index');
$etpl = new etemplate_new('mail.index');
// Set tree actions
$etpl->set_cell_attribute('nm[foldertree]','actions', array(
@ -1504,6 +1507,453 @@ unset($query['actions']);
return $err.'window.close();';
}
function get_load_email_data($uid, $partID, $mailbox)
{
// seems to be needed, as if we open a mail from notification popup that is
// located in a different folder, we experience: could not parse message
$this->mail_bo->reopen($mailbox);
$this->mailbox = $mailbox;
$this->uid = $uid;
$this->partID = $partID;
$bodyParts = $this->mail_bo->getMessageBody($uid, '', $partID, '', false, $mailbox);
//error_log(__METHOD__.__LINE__.array2string($bodyParts));
$meetingRequest = false;
$fetchEmbeddedImages = false;
if ($this->mail_bo->htmlOptions !='always_display') $fetchEmbeddedImages = true;
$attachments = $this->mail_bo->getMessageAttachments($uid, $partID, '',$fetchEmbeddedImages,true);
foreach ((array)$attachments as $key => $attach)
{
if (strtolower($attach['mimeType']) == 'text/calendar' &&
(strtolower($attach['method']) == 'request' || strtolower($attach['method']) == 'reply') &&
isset($GLOBALS['egw_info']['user']['apps']['calendar']) &&
($attachment = $this->mail_bo->getAttachment($uid, $attach['partID'])))
{
egw_cache::setSession('calendar', 'ical', array(
'charset' => $attach['charset'] ? $attach['charset'] : 'utf-8',
'attachment' => $attachment['attachment'],
'method' => $attach['method'],
'sender' => $sender,
));
return array("src"=>egw::link('/index.php',array(
'menuaction' => 'calendar.calendar_uiforms.meeting',
'ical' => 'session',
)));
}
}
// Compose the content of the frame
$frameHtml =
$this->get_email_header($this->mail_bo->getStyles($bodyParts)).
$this->showBody($this->getdisplayableBody($bodyParts), false);
//IE10 eats away linebreaks preceeded by a whitespace in PRE sections
$frameHtml = str_replace(" \r\n","\r\n",$frameHtml);
return $frameHtml;
}
static function get_email_header($additionalStyle='')
{
//error_log(__METHOD__.__LINE__.$additionalStyle);
return '
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<style>
body, td, textarea {
font-family: Verdana, Arial, Helvetica,sans-serif;
font-size: 11px;
}
</style>'.$additionalStyle.'
<script type="text/javascript">
function GoToAnchor(aname)
{
window.location.hash=aname;
}
</script>
</head>
<body>
';
}
function showBody(&$body, $print=true)
{
$BeginBody = '<style type="text/css">
body,html {
height:100%;
width:100%;
padding:0px;
margin:0px;
}
.td_display {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 120%;
color: black;
background-color: #FFFFFF;
}
pre {
white-space: pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
width: 99%;
}
blockquote[type=cite] {
margin: 0;
border-left: 2px solid blue;
padding-left: 10px;
margin-left: 0;
color: blue;
}
</style>
<div style="height:100%;width:100%; background-color:white; padding:0px; margin:0px;">
<table width="100%" style="table-layout:fixed"><tr><td class="td_display">';
$EndBody = '</td></tr></table></div>';
$EndBody .= "</body></html>";
if ($print) {
print $BeginBody. $body .$EndBody;
} else {
return $BeginBody. $body .$EndBody;
}
}
function &getdisplayableBody($_bodyParts,$modifyURI=true)
{
$bodyParts = $_bodyParts;
$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]');
$body = '';
//error_log(__METHOD__.array2string($bodyParts)); //exit;
if (empty($bodyParts)) return "";
foreach((array)$bodyParts as $singleBodyPart) {
if (!isset($singleBodyPart['body'])) {
$singleBodyPart['body'] = $this->getdisplayableBody($singleBodyPart,$modifyURI);
$body .= $singleBodyPart['body'];
continue;
}
if(!empty($body)) {
$body .= '<hr style="border:dotted 1px silver;">';
}
//_debug_array($singleBodyPart['charSet']);
//_debug_array($singleBodyPart['mimeType']);
//error_log($singleBodyPart['body']);
//error_log(__METHOD__.__LINE__.' CharSet:'.$singleBodyPart['charSet'].' mimeType:'.$singleBodyPart['mimeType']);
// some characterreplacements, as they fail to translate
$sar = array(
'@(\x84|\x93|\x94)@',
'@(\x96|\x97|\x1a)@',
'@(\x82|\x91|\x92)@',
'@(\x85)@',
'@(\x86)@',
'@(\x99)@',
'@(\xae)@',
);
$rar = array(
'"',
'-',
'\'',
'...',
'&',
'(TM)',
'(R)',
);
if(($singleBodyPart['mimeType'] == 'text/html' || $singleBodyPart['mimeType'] == 'text/plain') &&
strtoupper($singleBodyPart['charSet']) != 'UTF-8')
{
$singleBodyPart['body'] = preg_replace($sar,$rar,$singleBodyPart['body']);
}
if ($singleBodyPart['charSet']===false) $singleBodyPart['charSet'] = translation::detect_encoding($singleBodyPart['body']);
$singleBodyPart['body'] = $GLOBALS['egw']->translation->convert(
$singleBodyPart['body'],
strtolower($singleBodyPart['charSet'])
);
// in a way, this tests if we are having real utf-8 (the displayCharset) by now; we should if charsets reported (or detected) are correct
if (strtoupper(mail_bo::$displayCharset) == 'UTF-8')
{
$test = @json_encode($singleBodyPart['body']);
//error_log(__METHOD__.__LINE__.' ->'.strlen($singleBodyPart['body']).' Error:'.json_last_error().'<- BodyPart:#'.$test.'#');
//if (json_last_error() != JSON_ERROR_NONE && strlen($singleBodyPart['body'])>0)
if (($test=="null" || $test === false || is_null($test)) && strlen($singleBodyPart['body'])>0)
{
// this should not be needed, unless something fails with charset detection/ wrong charset passed
error_log(__METHOD__.__LINE__.' Charset Reported:'.$singleBodyPart['charSet'].' Charset Detected:'.felamimail_bo::detect_encoding($singleBodyPart['body']));
$singleBodyPart['body'] = utf8_encode($singleBodyPart['body']);
}
}
//error_log($singleBodyPart['body']);
#$CharSetUsed = mb_detect_encoding($singleBodyPart['body'] . 'a' , strtoupper($singleBodyPart['charSet']).','.strtoupper(mail_bo::$displayCharset).',UTF-8, ISO-8859-1');
if($singleBodyPart['mimeType'] == 'text/plain')
{
//$newBody = $singleBodyPart['body'];
$newBody = @htmlentities($singleBodyPart['body'],ENT_QUOTES, strtoupper(mail_bo::$displayCharset));
// if empty and charset is utf8 try sanitizing the string in question
if (empty($newBody) && strtolower($singleBodyPart['charSet'])=='utf-8') $newBody = @htmlentities(iconv('utf-8', 'utf-8', $singleBodyPart['body']),ENT_QUOTES, strtoupper(mail_bo::$displayCharset));
// if the conversion to htmlentities fails somehow, try without specifying the charset, which defaults to iso-
if (empty($newBody)) $newBody = htmlentities($singleBodyPart['body'],ENT_QUOTES);
#$newBody = $this->bofelamimail->wordwrap($newBody, 90, "\n");
// search http[s] links and make them as links available again
// to understand what's going on here, have a look at
// http://www.php.net/manual/en/function.preg-replace.php
// create links for websites
if ($modifyURI) $newBody = html::activate_links($newBody);
// redirect links for websites if you use no cookies
#if (!($GLOBALS['egw_info']['server']['usecookies']))
# $newBody = preg_replace("/href=(\"|\')((http(s?):\/\/)|(www\.))([\w,\-,\/,\?,\=,\.,&amp;,!\n,\%,@,\(,\),\*,#,:,~,\+]+)(\"|\')/ie",
# "'href=\"$webserverURL/redirect.php?go='.@htmlentities(urlencode('http$4://$5$6'),ENT_QUOTES,\"mail_bo::$displayCharset\").'\"'", $newBody);
// create links for email addresses
//TODO:if ($modifyURI) $this->parseEmail($newBody);
// create links for inline images
if ($modifyURI)
{
$newBody = preg_replace_callback("/\[cid:(.*)\]/iU",array($this,'image_callback_plain'),$newBody);
}
//TODO:$newBody = $this->highlightQuotes($newBody);
// to display a mailpart of mimetype plain/text, may be better taged as preformatted
#$newBody = nl2br($newBody);
// since we do not display the message as HTML anymore we may want to insert good linebreaking (for visibility).
//error_log($newBody);
// dont break lines that start with > (&gt; as the text was processed with htmlentities before)
//TODO:$newBody = "<pre>".felamimail_bo::wordwrap($newBody,90,"\n",'&gt;')."</pre>";
//$newBody = "<pre>".$newBody."</pre>";
}
else
{
$newBody = $singleBodyPart['body'];
//TODO:$newBody = $this->highlightQuotes($newBody);
#error_log(print_r($newBody,true));
// do the cleanup, set for the use of purifier
$usepurifier = true;
$newBodyBuff = $newBody;
mail_bo::getCleanHTML($newBody,$usepurifier);
// in a way, this tests if we are having real utf-8 (the displayCharset) by now; we should if charsets reported (or detected) are correct
if (strtoupper(mail_bo::$displayCharset) == 'UTF-8')
{
$test = @json_encode($newBody);
//error_log(__METHOD__.__LINE__.' ->'.strlen($singleBodyPart['body']).' Error:'.json_last_error().'<- BodyPart:#'.$test.'#');
//if (json_last_error() != JSON_ERROR_NONE && strlen($singleBodyPart['body'])>0)
if (($test=="null" || $test === false || is_null($test)) && strlen($newBody)>0)
{
$newBody = $newBodyBuff;
$tv = mail_bo::$htmLawed_config['tidy'];
mail_bo::$htmLawed_config['tidy'] = 0;
mail_bo::getCleanHTML($newBody,$usepurifier);
mail_bo::$htmLawed_config['tidy'] = $tv;
}
}
// removes stuff between http and ?http
$Protocol = '(http:\/\/|(ftp:\/\/|https:\/\/))'; // only http:// gets removed, other protocolls are shown
$newBody = preg_replace('~'.$Protocol.'[^>]*\?'.$Protocol.'~sim','$1',$newBody); // removes stuff between http:// and ?http://
// TRANSFORM MAILTO LINKS TO EMAILADDRESS ONLY, WILL BE SUBSTITUTED BY parseEmail TO CLICKABLE LINK
$newBody = preg_replace('/(?<!"|href=|href\s=\s|href=\s|href\s=)'.'mailto:([a-z0-9._-]+)@([a-z0-9_-]+)\.([a-z0-9._-]+)/i',
"\\1@\\2.\\3",
$newBody);
// redirect links for websites if you use no cookies
#if (!($GLOBALS['egw_info']['server']['usecookies'])) { //do it all the time, since it does mask the mailadresses in urls
//TODO:if ($modifyURI) $this->parseHREF($newBody);
#}
// create links for inline images
if ($modifyURI)
{
$newBody = preg_replace_callback("/src=(\"|\')cid:(.*)(\"|\')/iU",array($this,'image_callback'),$newBody);
$newBody = preg_replace_callback("/url\(cid:(.*)\);/iU",array($this,'image_callback_url'),$newBody);
$newBody = preg_replace_callback("/background=(\"|\')cid:(.*)(\"|\')/iU",array($this,'image_callback_background'),$newBody);
}
// create links for email addresses
if ($modifyURI)
{
$link = $GLOBALS['egw']->link('/index.php',array('menuaction' => 'felamimail.uicompose.compose'));
$newBody = preg_replace("/href=(\"|\')mailto:([\w,\-,\/,\?,\=,\.,&amp;,!\n,\%,@,\*,#,:,~,\+]+)(\"|\')/ie",
"'href=\"$link&send_to='.base64_encode('$2').'\"'.' target=\"compose\" onclick=\"window.open(this,this.target,\'dependent=yes,width=700,height=egw_getWindowOuterHeight(),location=no,menubar=no,toolbar=no,scrollbars=yes,status=yes\'); return false;\"'", $newBody);
//print "<pre>".htmlentities($newBody)."</pre><hr>";
}
// replace emails within the text with clickable links.
//TODO:$this->parseEmail($newBody);
}
$body .= $newBody;
#print "<hr><pre>$body</pre><hr>";
}
// create links for windows shares
// \\\\\\\\ == '\\' in real life!! :)
$body = preg_replace("/(\\\\\\\\)([\w,\\\\,-]+)/i",
"<a href=\"file:$1$2\" target=\"_blank\"><font color=\"blue\">$1$2</font></a>", $body);
$body = preg_replace($nonDisplayAbleCharacters,'',$body);
return $body;
}
/**
* preg_replace callback to replace image cid url's
*
* @param array $matches matches from preg_replace("/src=(\"|\')cid:(.*)(\"|\')/iU",...)
* @return string src attribute to replace
*/
function image_callback($matches)
{
static $cache = array(); // some caching, if mails containing the same image multiple times
$this->icServer->currentMailbox;
$linkData = array (
'menuaction' => 'felamimail.uidisplay.displayImage',
'uid' => $this->uid,
'mailbox' => base64_encode($this->mailbox),
'cid' => base64_encode($matches[2]),
'partID' => $this->partID,
);
$imageURL = $GLOBALS['egw']->link('/index.php', $linkData);
// to test without data uris, comment the if close incl. it's body
if (html::$user_agent != 'msie' || html::$ua_version >= 8)
{
if (!isset($cache[$imageURL]))
{
$attachment = $this->mail_bo->getAttachmentByCID($this->uid, $matches[2], $this->partID);
// only use data uri for "smaller" images, as otherwise the first display of the mail takes to long
if (bytes($attachment['attachment']) < 8192) // msie=8 allows max 32k data uris
{
$cache[$imageURL] = 'data:'.$attachment['type'].';base64,'.base64_encode($attachment['attachment']);
}
else
{
$cache[$imageURL] = $imageURL;
}
}
$imageURL = $cache[$imageURL];
}
return 'src="'.$imageURL.'"';
}
/**
* preg_replace callback to replace image cid url's
*
* @param array $matches matches from preg_replace("/src=(\"|\')cid:(.*)(\"|\')/iU",...)
* @return string src attribute to replace
*/
function image_callback_plain($matches)
{
static $cache = array(); // some caching, if mails containing the same image multiple times
//error_log(__METHOD__.__LINE__.array2string($matches));
$linkData = array (
'menuaction' => 'felamimail.uidisplay.displayImage',
'uid' => $this->uid,
'mailbox' => base64_encode($this->mailbox),
'cid' => base64_encode($matches[1]),
'partID' => $this->partID,
);
$imageURL = $GLOBALS['egw']->link('/index.php', $linkData);
// to test without data uris, comment the if close incl. it's body
if (html::$user_agent != 'msie' || html::$ua_version >= 8)
{
if (!isset($cache[$imageURL]))
{
$attachment = $this->mail_bo->getAttachmentByCID($this->uid, $matches[1], $this->partID);
// only use data uri for "smaller" images, as otherwise the first display of the mail takes to long
if (bytes($attachment['attachment']) < 8192) // msie=8 allows max 32k data uris
{
$cache[$imageURL] = 'data:'.$attachment['type'].';base64,'.base64_encode($attachment['attachment']);
}
else
{
$cache[$imageURL] = $imageURL;
}
}
$imageURL = $cache[$imageURL];
}
return '<img src="'.$imageURL.'" />';
}
/**
* preg_replace callback to replace image cid url's
*
* @param array $matches matches from preg_replace("/src=(\"|\')cid:(.*)(\"|\')/iU",...)
* @return string src attribute to replace
*/
function image_callback_url($matches)
{
static $cache = array(); // some caching, if mails containing the same image multiple times
//error_log(__METHOD__.__LINE__.array2string($matches));
$linkData = array (
'menuaction' => 'felamimail.uidisplay.displayImage',
'uid' => $this->uid,
'mailbox' => base64_encode($this->mailbox),
'cid' => base64_encode($matches[1]),
'partID' => $this->partID,
);
$imageURL = $GLOBALS['egw']->link('/index.php', $linkData);
// to test without data uris, comment the if close incl. it's body
if (html::$user_agent != 'msie' || html::$ua_version >= 8)
{
if (!isset($cache[$imageURL]))
{
$attachment = $this->mail_bo->getAttachmentByCID($this->uid, $matches[1], $this->partID);
// only use data uri for "smaller" images, as otherwise the first display of the mail takes to long
if (bytes($attachment['attachment']) < 8192) // msie=8 allows max 32k data uris
{
$cache[$imageURL] = 'data:'.$attachment['type'].';base64,'.base64_encode($attachment['attachment']);
}
else
{
$cache[$imageURL] = $imageURL;
}
}
$imageURL = $cache[$imageURL];
}
return 'url('.$imageURL.');';
}
/**
* preg_replace callback to replace image cid url's
*
* @param array $matches matches from preg_replace("/src=(\"|\')cid:(.*)(\"|\')/iU",...)
* @return string src attribute to replace
*/
function image_callback_background($matches)
{
static $cache = array(); // some caching, if mails containing the same image multiple times
$linkData = array (
'menuaction' => 'felamimail.uidisplay.displayImage',
'uid' => $this->uid,
'mailbox' => base64_encode($this->mailbox),
'cid' => base64_encode($matches[2]),
'partID' => $this->partID,
);
$imageURL = $GLOBALS['egw']->link('/index.php', $linkData);
// to test without data uris, comment the if close incl. it's body
if (html::$user_agent != 'msie' || html::$ua_version >= 8)
{
if (!isset($cache[$imageURL]))
{
$cache[$imageURL] = $imageURL;
}
$imageURL = $cache[$imageURL];
}
return 'background="'.$imageURL.'"';
}
/**
* importMessage
*/
@ -1661,6 +2111,26 @@ unset($query['actions']);
*/
}
/**
* loadEmailBody
*
* @param string _messageID UID
*
* @return xajax response
*/
function loadEmailBody($_messageID)
{
if (!$_messageID) $_messageID = $_GET['_messageID'];
if(mail_bo::$debug); error_log(__METHOD__."->".$_flag.':'.print_r($_messageID,true));
$uidA = self::splitRowID($_messageID);
$folder = $uidA['folder']; // all messages in one set are supposed to be within the same folder
$messageID = $uidA['msgUID'];
$bodyResponse = $this->get_load_email_data($messageID,'',$folder);
//error_log(array2string($bodyResponse));
echo $bodyResponse;
}
/**
* ajax_setFolderStatus - its called via json, so the function must start with ajax (or the class-name must contain ajax)
* gets the counters and sets the text of a treenode if needed (unread Messages found)

View File

@ -47,13 +47,13 @@ mail_open: function(_action, _senders) {
},
/**
* mail_preview - implementation of the copy action
* mail_preview - implementation of the preview action
*
* @param nextmatch et2_nextmatch The widget whose row was selected
* @param selected Array Selected row IDs. May be empty if user unselected all rows.
*/
mail_preview: function(nextmatch, selected) {
//console.log("mail_preview",_action, _senders);
//console.log("mail_preview",nextmatch, selected);
// Empty values, just in case selected is empty (user cleared selection)
var dataElem = {data:{subject:"",fromaddress:"",toaddress:"",date:"",subject:""}};
@ -62,12 +62,27 @@ mail_preview: function(nextmatch, selected) {
var _id = selected[0];
dataElem = egw.dataGetUIDdata(_id);
}
else
{
return;
}
console.log("mail_preview",dataElem);
var subject =dataElem.data.subject;
etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('previewFromAddress').set_value(dataElem.data.fromaddress);
etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('previewToAddress').set_value(dataElem.data.toaddress);
etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('previewDate').set_value(dataElem.data.date);
etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('previewSubject').set_value(subject);
var IframeHandle = etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('messageIFRAME');
IframeHandle.set_src(egw.link('/index.php',{menuaction:'mail.mail_ui.loadEmailBody',_messageID:_id}));
// var request = new egw_json_request('mail.mail_ui.ajax_loadEmailBody',[_id]);
// request.sendRequest(false);
},
mail_setMailBody: function(content) {
console.log('mail_setMailBody',content);
var IframeHandle = etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('messageIFRAME');
IframeHandle.set_value('');
},
/**
@ -230,7 +245,7 @@ mail_delete: function(_action,_elems)
{
var msg = this.mail_getFormData(_elems);
//alert(_action.id+','+ msg);
app_refresh(egw.lang('delete messages'), 'mail');
app.mail.app_refresh(egw.lang('delete messages'), 'mail');
this.mail_setRowClass(_elems,'deleted');
var request = new egw_json_request('mail.mail_ui.ajax_deleteMessages',[msg]);
request.sendRequest(false);
@ -262,7 +277,7 @@ mail_undeleteMessages: function(_messageList) {
* mail_emptyTrash
*/
mail_emptyTrash: function() {
app_refresh(egw.lang('empty trash'), 'mail');
app.mail.app_refresh(egw.lang('empty trash'), 'mail');
var request = new egw_json_request('mail.mail_ui.ajax_emptyTrash');
request.sendRequest();
},
@ -271,7 +286,7 @@ mail_emptyTrash: function() {
* mail_compressFolder
*/
mail_compressFolder: function() {
app_refresh(egw.lang('compress folder'), 'mail');
app.mail.app_refresh(egw.lang('compress folder'), 'mail');
var request = new egw_json_request('mail.mail_ui.ajax_compressFolder');
request.sendRequest();
},
@ -297,7 +312,7 @@ mail_changeProfile: function(folder,_widget) {
*/
mail_changeFolder: function(folder,_widget) {
//alert('change Folder called:'+folder);
app_refresh(egw.lang('change folder')+'...', 'mail');
app.mail.app_refresh(egw.lang('change folder')+'...', 'mail');
var img = _widget.getSelectedNode().images[0]; // fetch first image
if (!(img.search(eval('/'+'NoSelect'+'/'))<0) || !(img.search(eval('/'+'thunderbird'+'/'))<0))
{
@ -334,7 +349,7 @@ mail_changeFolder: function(folder,_widget) {
if (outBraket!=-1) displayname = displayname.replace(/\((.*?)\)/,"");
}
myMsg = (displayname?displayname:folder)+' '+egw.lang('selected');
app_refresh(myMsg, 'mail');
app.mail.app_refresh(myMsg, 'mail');
}
//mail_refreshMessageGrid();
this.mail_refreshFolderStatus(folder,'forced');
@ -363,7 +378,7 @@ mail_flag: function(_action, _elems)
*/
mail_flagMessages: function(_flag, _elems)
{
app_refresh(egw.lang('flag messages'), 'mail');
app.mail.app_refresh(egw.lang('flag messages'), 'mail');
var request = new egw_json_request('mail.mail_ui.ajax_flagMessages',[_flag, _elems]);
request.sendRequest(false);
this.mail_refreshMessageGrid()

View File

@ -2,7 +2,7 @@
/**
* EGroupware - eTemplates for Application mail
* http://www.egroupware.org
* generated by soetemplate::dump4setup() 2013-04-09 15:37
* generated by soetemplate::dump4setup() 2013-04-12 14:54
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package mail
@ -12,7 +12,9 @@
$templ_version=1;
$templ_data[] = array('name' => 'mail.index','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:4:{i:0;a:5:{s:7:"onclick";s:56:"app.mail.mail_changeFolder(widget.event_args[0],widget);";s:4:"name";s:14:"nm[foldertree]";s:4:"type";s:4:"tree";s:11:"parent_node";s:11:"tree_target";s:11:"autoloading";s:28:"mail.mail_ui.ajax_foldertree";}i:1;a:2:{s:4:"type";s:4:"html";s:4:"name";s:3:"msg";}i:2;a:3:{s:4:"name";s:2:"nm";s:4:"size";s:15:"mail.index.rows";s:4:"type";s:9:"nextmatch";}i:3;a:3:{s:4:"type";s:8:"template";s:4:"name";s:7:"preview";s:4:"size";s:12:"mail.preview";}}','size' => '','style' => '','modified' => '1365514624',);
$templ_data[] = array('name' => 'mail.importMessage','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:2:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:1:{s:4:"type";s:5:"label";}}}s:4:"rows";i:1;s:4:"cols";i:1;}}','size' => '','style' => '','modified' => '1365666381',);
$templ_data[] = array('name' => 'mail.index','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:3:{i:0;a:5:{s:11:"autoloading";s:28:"mail.mail_ui.ajax_foldertree";s:7:"onclick";s:56:"app.mail.mail_changeFolder(widget.event_args[0],widget);";s:11:"parent_node";s:11:"tree_target";s:4:"name";s:14:"nm[foldertree]";s:4:"type";s:4:"tree";}i:1;a:2:{s:4:"name";s:3:"msg";s:4:"type";s:4:"html";}i:2;a:7:{s:9:"dock_side";s:10:"bottomDock";s:11:"orientation";s:1:"h";s:4:"name";s:8:"splitter";s:4:"type";s:5:"split";s:4:"size";s:1:"2";i:1;a:4:{s:8:"onselect";s:21:"app.mail.mail_preview";s:4:"name";s:2:"nm";s:4:"type";s:9:"nextmatch";s:4:"size";s:15:"mail.index.rows";}i:2;a:4:{s:4:"name";s:18:"spanMessagePreview";s:4:"type";s:4:"vbox";s:4:"size";s:1:"1";i:1;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:1:{s:2:"c2";s:19:"previewDataArea,top";}i:1;a:1:{s:1:"A";a:4:{s:4:"type";s:4:"grid";s:4:"data";a:2:{i:0;a:0:{}i:1;a:2:{s:1:"A";a:4:{s:4:"type";s:4:"grid";s:4:"data";a:5:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"3";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:4:"From";}i:2;a:2:{s:4:"type";s:5:"label";s:5:"label";s:1:":";}i:3;a:3:{s:8:"readonly";s:4:"true";s:4:"name";s:18:"previewFromAddress";s:4:"type";s:9:"url-email";}}}i:2;a:1:{s:1:"A";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"3";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:2:"To";}i:2;a:2:{s:4:"type";s:5:"label";s:5:"label";s:1:":";}i:3;a:3:{s:8:"readonly";s:4:"true";s:4:"name";s:16:"previewToAddress";s:4:"type";s:9:"url-email";}}}i:3;a:1:{s:1:"A";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"3";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:4:"Date";}i:2;a:2:{s:4:"type";s:5:"label";s:5:"label";s:1:":";}i:3;a:4:{s:5:"align";s:4:"left";s:8:"readonly";s:4:"true";s:4:"name";s:11:"previewDate";s:4:"type";s:9:"date-time";}}}i:4;a:1:{s:1:"A";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"3";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:7:"Subject";}i:2;a:2:{s:4:"type";s:5:"label";s:5:"label";s:1:":";}i:3;a:4:{s:5:"align";s:4:"left";s:8:"readonly";s:4:"true";s:4:"name";s:14:"previewSubject";s:4:"type";s:5:"label";}}}}s:4:"cols";i:1;s:4:"rows";i:4;}s:1:"B";a:4:{s:5:"width";s:5:"275px";s:4:"type";s:4:"hbox";s:4:"size";s:1:"1";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:12:"Action Icons";}}}}s:4:"cols";i:2;s:4:"rows";i:1;}}i:2;a:1:{s:1:"A";a:6:{s:11:"frameborder";s:1:"1";s:6:"height";s:4:"auto";s:5:"width";s:4:"100%";s:9:"scrolling";s:4:"auto";s:4:"name";s:13:"messageIFRAME";s:4:"type";s:6:"iframe";}}}s:4:"cols";i:1;s:4:"rows";i:2;}}}}','size' => '','style' => '','modified' => '1365771294',);
$templ_data[] = array('name' => 'mail.index.rows','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:9:{s:2:"c1";s:2:"th";s:1:"A";s:2:"25";s:1:"F";s:3:"120";s:1:"E";s:2:"95";s:2:"c2";s:16:"$row_cont[class]";s:1:"G";s:3:"120";s:1:"H";s:2:"50";s:1:"C";s:2:"20";s:1:"B";s:2:"20";}i:1;a:8:{s:1:"A";a:4:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:2:"ID";s:4:"name";s:3:"uid";s:8:"readonly";s:1:"1";}s:1:"B";a:4:{s:4:"type";s:16:"nextmatch-header";s:4:"name";s:6:"status";s:5:"label";s:3:"St.";s:4:"help";s:6:"Status";}s:1:"C";a:4:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:3:"...";s:4:"name";s:11:"attachments";s:4:"help";s:16:"attachments, ...";}s:1:"D";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:4:"name";s:7:"subject";s:5:"label";s:7:"subject";}s:1:"E";a:4:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:4:"date";s:4:"name";s:4:"date";s:5:"align";s:6:"center";}s:1:"F";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:2:"to";s:4:"name";s:9:"toaddress";}s:1:"G";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:4:"from";s:4:"name";s:11:"fromaddress";}s:1:"H";a:4:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:4:"size";s:4:"name";s:4:"size";s:5:"align";s:6:"center";}}i:2;a:8:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"name";s:11:"${row}[uid]";s:8:"readonly";s:1:"1";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:4:"span";s:12:"1,status_img";}s:1:"C";a:2:{s:4:"type";s:4:"html";s:4:"name";s:19:"${row}[attachments]";}s:1:"D";a:2:{s:4:"type";s:5:"label";s:4:"name";s:15:"${row}[subject]";}s:1:"E";a:4:{s:4:"type";s:15:"date-time_today";s:4:"name";s:12:"${row}[date]";s:8:"readonly";s:1:"1";s:5:"align";s:6:"center";}s:1:"F";a:3:{s:4:"type";s:9:"url-email";s:4:"name";s:17:"${row}[toaddress]";s:8:"readonly";s:1:"1";}s:1:"G";a:3:{s:4:"type";s:9:"url-email";s:4:"name";s:19:"${row}[fromaddress]";s:8:"readonly";s:1:"1";}s:1:"H";a:5:{s:4:"type";s:8:"vfs-size";s:4:"name";s:12:"${row}[size]";s:7:"no_lang";s:1:"1";s:8:"readonly";s:1:"1";s:5:"align";s:5:"right";}}}s:4:"rows";i:2;s:4:"cols";i:8;}}','size' => '','style' => '','modified' => '1360252030',);

View File

@ -41,22 +41,22 @@
<tree autoloading="mail.mail_ui.ajax_foldertree" id="nm[foldertree]" onclick="app.mail.mail_changeFolder(widget.event_args[0],widget);" parent_node="tree_target"/>
<html id="msg"/>
<split dock_side="bottomDock" id="splitter" orientation="h">
<nextmatch id="nm" template="mail.index.rows" onselect="app.mail.mail_preview"/>
<nextmatch id="nm" onselect="app.mail.mail_preview" template="mail.index.rows"/>
<vbox id="spanMessagePreview">
<grid>
<grid width="100%">
<columns>
<column/>
</columns>
<rows>
<row>
<grid>
<grid width="100%">
<columns>
<column/>
<column/>
</columns>
<rows>
<row>
<grid>
<grid width="100%">
<columns>
<column/>
</columns>
@ -91,7 +91,7 @@
</row>
</rows>
</grid>
<hbox>
<hbox width="275px">
<description value="Action Icons"/>
</hbox>
</row>
@ -99,7 +99,7 @@
</grid>
</row>
<row class="previewDataArea" valign="top">
<iframe frameborder="1" height="auto" id="messageIFRAME" scrolling="auto"/>
<iframe frameborder="1" height="auto" id="messageIFRAME" scrolling="auto" width="100%"/>
</row>
</rows>
</grid>