mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-26 16:48:49 +01:00
get some more actions to work
This commit is contained in:
parent
93710e09e1
commit
9c830f7461
@ -50,6 +50,13 @@ class mail_bo
|
||||
*/
|
||||
var $htmlOptions;
|
||||
|
||||
/**
|
||||
* Active mimeType
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $activeMimeType;
|
||||
|
||||
/**
|
||||
* Active incomming (IMAP) Server Object
|
||||
*
|
||||
@ -886,16 +893,21 @@ class mail_bo
|
||||
if (!is_array($folderInfo[0]))
|
||||
{
|
||||
// no folder info, but there is a status returned for the folder: something is wrong, try to cope with it
|
||||
$folderInfo = array(0 => array('HIERACHY_DELIMITER'=>$this->getHierarchyDelimiter(),
|
||||
'ATTRIBUTES' => ''));
|
||||
$folderInfo = array(0 => (is_array($folderInfo)?$folderInfo:array('HIERACHY_DELIMITER'=>$this->getHierarchyDelimiter(),
|
||||
'ATTRIBUTES' => '')));
|
||||
if (empty($folderInfo[0]['HIERACHY_DELIMITER']) || (isset($folderInfo[0]['delimiter']) && empty($folderInfo[0]['delimiter'])))
|
||||
{
|
||||
//error_log(__METHOD__.__LINE__.array2string($folderInfo));
|
||||
$folderInfo[0]['HIERACHY_DELIMITER'] = $this->getHierarchyDelimiter();
|
||||
}
|
||||
}
|
||||
}
|
||||
#if(!is_array($folderInfo[0])) {
|
||||
# return false;
|
||||
#}
|
||||
|
||||
$retValue['delimiter'] = $folderInfo[0]['HIERACHY_DELIMITER'];
|
||||
$retValue['attributes'] = $folderInfo[0]['ATTRIBUTES'];
|
||||
$retValue['delimiter'] = ($folderInfo[0]['HIERACHY_DELIMITER']?$folderInfo[0]['HIERACHY_DELIMITER']:$folderInfo[0]['delimiter']);
|
||||
$retValue['attributes'] = ($folderInfo[0]['ATTRIBUTES']?$folderInfo[0]['ATTRIBUTES']:$folderInfo[0]['attributes']);
|
||||
$shortNameParts = explode($retValue['delimiter'], $_folderName);
|
||||
$retValue['shortName'] = array_pop($shortNameParts);
|
||||
$retValue['displayName'] = $this->encodeFolderName($_folderName);
|
||||
@ -911,7 +923,7 @@ class mail_bo
|
||||
}
|
||||
if (!($folderInfo instanceof PEAR_Error)) $folderBasicInfo[$this->profileID][$_folderName]=$retValue;
|
||||
egw_cache::setCache(egw_cache::INSTANCE,'email','folderBasicInfo'.trim($GLOBALS['egw_info']['user']['account_id']),$folderBasicInfo,$expiration=60*60*1);
|
||||
if ($basicInfoOnly || stripos(array2string($retValue['attributes']),'noselect')!==false)
|
||||
if ($basicInfoOnly || (isset($retValue['attributes']) && stripos(array2string($retValue['attributes']),'noselect')!==false))
|
||||
{
|
||||
return $retValue;
|
||||
}
|
||||
@ -2360,8 +2372,8 @@ class mail_bo
|
||||
if ($_forceDeleteMethod === 'no' || !in_array($_forceDeleteMethod,array('move_to_trash',"mark_as_deleted","remove_immediately"))) $deleteOptions = $this->mailPreferences->preferences['deleteOptions'];
|
||||
//error_log(__METHOD__.__LINE__.'->'.array2string($_messageUID).','.$_folder.'/'.$this->sessionData['mailbox'].' Option:'.$deleteOptions);
|
||||
$trashFolder = $this->getTrashFolder();
|
||||
$draftFolder = $this->getDraftFolder(); //$GLOBALS['egw_info']['user']['preferences']['felamimail']['draftFolder'];
|
||||
$templateFolder = $this->getTemplateFolder(); //$GLOBALS['egw_info']['user']['preferences']['felamimail']['templateFolder'];
|
||||
$draftFolder = $this->getDraftFolder(); //$GLOBALS['egw_info']['user']['preferences']['mail']['draftFolder'];
|
||||
$templateFolder = $this->getTemplateFolder(); //$GLOBALS['egw_info']['user']['preferences']['mail']['templateFolder'];
|
||||
if(($_folder == $trashFolder && $deleteOptions == "move_to_trash") ||
|
||||
($_folder == $draftFolder)) {
|
||||
$deleteOptions = "remove_immediately";
|
||||
@ -2613,10 +2625,124 @@ class mail_bo
|
||||
if ($_charset===false) $_charset = self::$displayCharset;
|
||||
$_stringORG = $_string;
|
||||
$_string = @htmlentities($_string,ENT_QUOTES,$_charset, false);
|
||||
if (empty($_string) && !empty($_stringORG)) $_string = @htmlentities(translation::convert($_stringORG,self::detect_encoding($_stringORG),$_charset),ENT_QUOTES | ENT_IGNORE,$_charset, false);
|
||||
if (empty($_string) && !empty($_stringORG)) $_string = @htmlentities(translation::convert($_stringORG,translation::detect_encoding($_stringORG),$_charset),ENT_QUOTES | ENT_IGNORE,$_charset, false);
|
||||
return $_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* htmlspecialchars
|
||||
* helperfunction to cope with wrong encoding in strings
|
||||
* @param string $_string input to be converted
|
||||
* @param mixed $charset false or string -> Target charset, if false mail displayCharset will be used
|
||||
* @return string
|
||||
*/
|
||||
static function htmlspecialchars($_string, $_charset=false)
|
||||
{
|
||||
//setting the charset (if not given)
|
||||
if ($_charset===false) $_charset = self::$displayCharset;
|
||||
$_stringORG = $_string;
|
||||
$_string = @htmlspecialchars($_string,ENT_QUOTES,$_charset, false);
|
||||
if (empty($_string) && !empty($_stringORG)) $_string = @htmlspecialchars(translation::convert($_stringORG,self::detect_encoding($_stringORG),$_charset),ENT_QUOTES | ENT_IGNORE,$_charset, false);
|
||||
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
|
||||
* param boolean $usepurify - obsolet, as we always use htmlLawed
|
||||
* param boolean $cleanTags - use tidy (if available) to clean/balance tags
|
||||
* return nothing
|
||||
*/
|
||||
static function getCleanHTML(&$_html, $usepurify = false, $cleanTags=true)
|
||||
{
|
||||
// remove CRLF and TAB as it is of no use in HTML.
|
||||
// but they matter in <pre>, so we rather don't
|
||||
//$_html = str_replace("\r\n",' ',$_html);
|
||||
//$_html = str_replace("\t",' ',$_html);
|
||||
//error_log($_html);
|
||||
//repair doubleencoded ampersands, and some stuff htmLawed stumbles upon with balancing switched on
|
||||
$_html = str_replace(array('&amp;','<DIV><BR></DIV>',"<DIV> </DIV>",'<div> </div>','</td></font>','<br><td>','<tr></tr>','<o:p></o:p>','<o:p>','</o:p>'),
|
||||
array('&', '<BR>', '<BR>', '<BR>', '</font></td>','<td>', '', '', '', ''),$_html);
|
||||
//$_html = str_replace(array('&amp;'),array('&'),$_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
|
||||
//error_log(__METHOD__.__LINE__.$_html);
|
||||
// force the use of kses, as it is still have the edge over purifier with some stuff
|
||||
$usepurify = true;
|
||||
if ($usepurify)
|
||||
{
|
||||
// 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');
|
||||
// htmLawed filter only the 'body'
|
||||
//preg_match('`(<htm.+?<body[^>]*>)(.+?)(</body>.*?</html>)`ims', $_html, $matches);
|
||||
//if ($matches[2])
|
||||
//{
|
||||
// $hasOther = true;
|
||||
// $_html = $matches[2];
|
||||
//}
|
||||
// purify got switched to htmLawed
|
||||
// some testcode to test purifying / htmlawed
|
||||
//$_html = "<BLOCKQUOTE>hi <div> there </div> kram <br> </blockquote>".$_html;
|
||||
$_html = html::purify($_html,self::$htmLawed_config,array(),true);
|
||||
//if ($hasOther) $_html = $matches[1]. $_html. $matches[3];
|
||||
// clean out comments , should not be needed as purify should do the job.
|
||||
$search = array(
|
||||
'@url\(http:\/\/[^\)].*?\)@si', // url calls e.g. in style definitions
|
||||
'@<!--[\s\S]*?[ \t\n\r]*-->@', // Strip multi-line comments including CDATA
|
||||
);
|
||||
$_html = preg_replace($search,"",$_html);
|
||||
// remove non printable chars
|
||||
$_html = preg_replace('/([\000-\012])/','',$_html);
|
||||
//error_log(__METHOD__.':'.__LINE__.':'.$_html);
|
||||
}
|
||||
// using purify above should have tidied the tags already sufficiently
|
||||
if ($usepurify == false && $cleanTags==true)
|
||||
{
|
||||
if (extension_loaded('tidy'))
|
||||
{
|
||||
$tidy = new tidy();
|
||||
$cleaned = $tidy->repairString($_html, self::$tidy_config,'utf8');
|
||||
// Found errors. Strip it all so there's some output
|
||||
if($tidy->getStatus() == 2)
|
||||
{
|
||||
error_log(__METHOD__.__LINE__.' ->'.$tidy->errorBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
$_html = $cleaned;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//$to = ini_get('max_execution_time');
|
||||
//@set_time_limit(10);
|
||||
$htmLawed = new egw_htmLawed();
|
||||
$_html = $htmLawed->egw_htmLawed($_html);
|
||||
//error_log(__METHOD__.__LINE__.$_html);
|
||||
//@set_time_limit($to);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Header and Bodystructure stuff
|
||||
*/
|
||||
@ -2653,6 +2779,599 @@ class mail_bo
|
||||
return $structure[$this->icServer->ImapServerId][$_folder][$_uid];
|
||||
}
|
||||
|
||||
/**
|
||||
* getMimePartCharset - fetches the charset mimepart if it exists
|
||||
* @param $_mimePartObject structure object
|
||||
* @return mixed mimepart or false if no CHARSET is found, the missing charset has to be handled somewhere else,
|
||||
* as we cannot safely assume any charset as we did earlier
|
||||
*/
|
||||
function getMimePartCharset($_mimePartObject)
|
||||
{
|
||||
//$charSet = 'iso-8859-1';//self::$displayCharset; //'iso-8859-1'; // self::displayCharset seems to be asmarter fallback than iso-8859-1
|
||||
$CharsetFound=false;
|
||||
//echo "#".$_mimePartObject->encoding.'#<br>';
|
||||
if(is_array($_mimePartObject->parameters)) {
|
||||
if(isset($_mimePartObject->parameters['CHARSET'])) {
|
||||
$charSet = $_mimePartObject->parameters['CHARSET'];
|
||||
$CharsetFound=true;
|
||||
}
|
||||
}
|
||||
// this one is dirty, but until I find something that does the trick of detecting the encoding, ....
|
||||
//if ($CharsetFound == false && $_mimePartObject->encoding == "QUOTED-PRINTABLE") $charSet = 'iso-8859-1'; //assume quoted-printable to be ISO
|
||||
//if ($CharsetFound == false && $_mimePartObject->encoding == "BASE64") $charSet = 'utf-8'; // assume BASE64 to be UTF8
|
||||
return ($CharsetFound ? $charSet : $CharsetFound);
|
||||
}
|
||||
|
||||
/**
|
||||
* decodeMimePart - fetches the charset mimepart if it exists
|
||||
* @param string $_mimeMessage - the message to be decoded
|
||||
* @param string $_encoding - the encoding used BASE64 and QUOTED-PRINTABLE is supported
|
||||
* @param string $_charset - not used
|
||||
* @return string decoded mimePart
|
||||
*/
|
||||
function decodeMimePart($_mimeMessage, $_encoding, $_charset = '')
|
||||
{
|
||||
// decode the part
|
||||
if (self::$debug) error_log(__METHOD__."() with $_encoding and $_charset:".print_r($_mimeMessage,true));
|
||||
switch (strtoupper($_encoding))
|
||||
{
|
||||
case 'BASE64':
|
||||
// use imap_base64 to decode, not any longer, as it is strict, and fails if it encounters invalid chars
|
||||
return base64_decode($_mimeMessage); //imap_base64($_mimeMessage);
|
||||
break;
|
||||
case 'QUOTED-PRINTABLE':
|
||||
// use imap_qprint to decode
|
||||
return quoted_printable_decode($_mimeMessage);
|
||||
break;
|
||||
default:
|
||||
// it is either not encoded or we don't know about it
|
||||
return $_mimeMessage;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* getMultipartAlternative
|
||||
* get part of the message, if its stucture is indicating its of multipart alternative style
|
||||
* a wrapper for multipartmixed
|
||||
* @param string/int $_uid the messageuid,
|
||||
* @param array $_structure='', if given use structure for parsing
|
||||
* @param string $_htmlMode, how to display a message, html, plain text, ...
|
||||
* @param boolean $_preserveSeen flag to preserve the seenflag by using body.peek
|
||||
* @return array containing the desired part
|
||||
*/
|
||||
function getMultipartAlternative($_uid, $_structure, $_htmlMode, $_preserveSeen = false)
|
||||
{
|
||||
// a multipart/alternative has exactly 2 parts (text and html OR text and something else)
|
||||
// sometimes there are 3 parts, when there is an ics/ical attached/included-> we want to show that
|
||||
// as attachment AND as abstracted ical information (we use our notification style here).
|
||||
$partText = false;
|
||||
$partHTML = false;
|
||||
if (self::$debug) _debug_array(array("METHOD"=>__METHOD__,"LINE"=>__LINE__,"STRUCTURE"=>$_structure));
|
||||
foreach($_structure as $mimePart) {
|
||||
if($mimePart->type == 'TEXT' && ($mimePart->subType == 'PLAIN' || $mimePart->subType == 'CALENDAR') && $mimePart->bytes > 0) {
|
||||
if ($mimePart->subType == 'CALENDAR' && $partText === false) $partText = $mimePart; // only if there is no partText set already
|
||||
if ($mimePart->subType == 'PLAIN') $partText = $mimePart;
|
||||
} elseif($mimePart->type == 'TEXT' && $mimePart->subType == 'HTML' && $mimePart->bytes > 0) {
|
||||
$partHTML = $mimePart;
|
||||
} elseif ($mimePart->type == 'MULTIPART' && ($mimePart->subType == 'RELATED' || $mimePart->subType == 'MIXED') && is_array($mimePart->subParts)) {
|
||||
// in a multipart alternative we treat the multipart/related as html part
|
||||
#$partHTML = array($mimePart);
|
||||
if (self::$debug) error_log(__METHOD__." process MULTIPART/RELATED with array as subparts");
|
||||
$partHTML = $mimePart;
|
||||
} elseif ($mimePart->type == 'MULTIPART' && $mimePart->subType == 'ALTERNATIVE' && is_array($mimePart->subParts)) {
|
||||
//cascading multipartAlternative structure, assuming only the first one is to be used
|
||||
return $this->getMultipartAlternative($_uid,$mimePart->subParts,$_htmlMode, $_preserveSeen);
|
||||
}
|
||||
}
|
||||
//error_log(__METHOD__.__LINE__.$_htmlMode);
|
||||
switch($_htmlMode) {
|
||||
case 'html_only':
|
||||
case 'always_display':
|
||||
if(is_object($partHTML)) {
|
||||
if($partHTML->subType == 'RELATED') {
|
||||
return $this->getMultipartRelated($_uid, $partHTML, $_htmlMode, $_preserveSeen);
|
||||
} elseif($partHTML->subType == 'MIXED') {
|
||||
return $this->getMultipartMixed($_uid, $partHTML, $_htmlMode, $_preserveSeen);
|
||||
} else {
|
||||
return $this->getTextPart($_uid, $partHTML, $_htmlMode, $_preserveSeen);
|
||||
}
|
||||
} elseif(is_object($partText) && $_htmlMode=='always_display') {
|
||||
return $this->getTextPart($_uid, $partText, $_htmlMode, $_preserveSeen);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'only_if_no_text':
|
||||
if(is_object($partText)) {
|
||||
return $this->getTextPart($_uid, $partText, $_htmlMode, $_preserveSeen);
|
||||
} elseif(is_object($partHTML)) {
|
||||
if($partHTML->type) {
|
||||
return $this->getMultipartRelated($_uid, $partHTML, $_htmlMode, $_preserveSeen);
|
||||
} else {
|
||||
return $this->getTextPart($_uid, $partHTML, 'always_display', $_preserveSeen);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
if(is_object($partText)) {
|
||||
return $this->getTextPart($_uid, $partText, $_htmlMode, $_preserveSeen);
|
||||
} else {
|
||||
$bodyPart = array(
|
||||
'body' => lang("no plain text part found"),
|
||||
'mimeType' => 'text/plain',
|
||||
'charSet' => self::$displayCharset,
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return $bodyPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* getMultipartMixed
|
||||
* get part of the message, if its stucture is indicating its of multipart mixed style
|
||||
* @param string/int $_uid the messageuid,
|
||||
* @param array $_structure='', if given use structure for parsing
|
||||
* @param string $_htmlMode, how to display a message, html, plain text, ...
|
||||
* @param boolean $_preserveSeen flag to preserve the seenflag by using body.peek
|
||||
* @return array containing the desired part
|
||||
*/
|
||||
function getMultipartMixed($_uid, $_structure, $_htmlMode, $_preserveSeen = false)
|
||||
{
|
||||
if (self::$debug) echo __METHOD__."$_uid, $_htmlMode<br>";
|
||||
$bodyPart = array();
|
||||
if (self::$debug) _debug_array($_structure);
|
||||
if (!is_array($_structure)) $_structure = array($_structure);
|
||||
foreach($_structure as $part) {
|
||||
if (self::$debug) echo $part->type."/".$part->subType."<br>";
|
||||
switch($part->type) {
|
||||
case 'MULTIPART':
|
||||
switch($part->subType) {
|
||||
case 'ALTERNATIVE':
|
||||
$bodyPart[] = $this->getMultipartAlternative($_uid, $part->subParts, $_htmlMode, $_preserveSeen);
|
||||
break;
|
||||
|
||||
case 'MIXED':
|
||||
case 'SIGNED':
|
||||
$bodyPart = array_merge($bodyPart, $this->getMultipartMixed($_uid, $part->subParts, $_htmlMode, $_preserveSeen));
|
||||
break;
|
||||
|
||||
case 'RELATED':
|
||||
$bodyPart = array_merge($bodyPart, $this->getMultipartRelated($_uid, $part->subParts, $_htmlMode, $_preserveSeen));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'TEXT':
|
||||
switch($part->subType) {
|
||||
case 'PLAIN':
|
||||
case 'HTML':
|
||||
case 'CALENDAR': // inline ics/ical files
|
||||
if($part->disposition != 'ATTACHMENT') {
|
||||
$bodyPart[] = $this->getTextPart($_uid, $part, $_htmlMode, $_preserveSeen);
|
||||
}
|
||||
//error_log(__METHOD__.__LINE__.' ->'.$part->type."/".$part->subType.' -> BodyPart:'.array2string($bodyPart[count($bodyPart)-1]));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'MESSAGE':
|
||||
if($part->subType == 'delivery-status') {
|
||||
$bodyPart[] = $this->getTextPart($_uid, $part, $_htmlMode, $_preserveSeen);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// do nothing
|
||||
// the part is a attachment
|
||||
#$bodyPart[] = $this->getMessageBody($_uid, $_htmlMode, $part->partID, $part);
|
||||
#if (!($part->type == 'TEXT' && ($part->subType == 'PLAIN' || $part->subType == 'HTML'))) {
|
||||
# $bodyPart[] = $this->getMessageAttachments($_uid, $part->partID, $part);
|
||||
#}
|
||||
}
|
||||
}
|
||||
|
||||
return $bodyPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* getMultipartRelated
|
||||
* get part of the message, if its stucture is indicating its of multipart related style
|
||||
* a wrapper for multipartmixed
|
||||
* @param string/int $_uid the messageuid,
|
||||
* @param array $_structure='', if given use structure for parsing
|
||||
* @param string $_htmlMode, how to display a message, html, plain text, ...
|
||||
* @param boolean $_preserveSeen flag to preserve the seenflag by using body.peek
|
||||
* @return array containing the desired part
|
||||
*/
|
||||
function getMultipartRelated($_uid, $_structure, $_htmlMode, $_preserveSeen = false)
|
||||
{
|
||||
return $this->getMultipartMixed($_uid, $_structure, $_htmlMode, $_preserveSeen);
|
||||
}
|
||||
|
||||
/**
|
||||
* getTextPart
|
||||
* get Body from message
|
||||
* @param string/int $_uid the messageuid,
|
||||
* @param array $_structure='', if given use structure for parsing
|
||||
* @param string $_htmlMode, how to display a message, html, plain text, ...
|
||||
* @param boolean $_preserveSeen flag to preserve the seenflag by using body.peek
|
||||
* @return array containing the desired text part, mimeType and charset
|
||||
*/
|
||||
function getTextPart($_uid, $_structure, $_htmlMode = '', $_preserveSeen = false)
|
||||
{
|
||||
//error_log(__METHOD__.__LINE__.'->'.$_uid.':'.array2string($_structure).' '.function_backtrace());
|
||||
$bodyPart = array();
|
||||
if (self::$debug) _debug_array(array($_structure,function_backtrace()));
|
||||
$partID = $_structure->partID;
|
||||
$mimePartBody = $this->icServer->getBodyPart($_uid, $partID, true, $_preserveSeen);
|
||||
if (PEAR::isError($mimePartBody))
|
||||
{
|
||||
error_log(__METHOD__.__LINE__.' failed:'.$mimePartBody->message);
|
||||
return false;
|
||||
}
|
||||
//_debug_array($mimePartBody);
|
||||
//error_log(__METHOD__.__LINE__.' UID:'.$_uid.' PartID:'.$partID.' HTMLMode:'.$_htmlMode.' ->'.array2string($_structure).' body:'.array2string($mimePartBody));
|
||||
if (empty($mimePartBody)) return array(
|
||||
'body' => '',
|
||||
'mimeType' => ($_structure->type == 'TEXT' && $_structure->subType == 'HTML') ? 'text/html' : 'text/plain',
|
||||
'charSet' => self::$displayCharset,
|
||||
);
|
||||
//_debug_array(preg_replace('/PropertyFile___$/','',$this->decodeMimePart($mimePartBody, $_structure->encoding)));
|
||||
if($_structure->subType == 'HTML' && $_htmlMode!= 'html_only' && $_htmlMode != 'always_display' && $_htmlMode != 'only_if_no_text') {
|
||||
$bodyPart = array(
|
||||
'error' => 1,
|
||||
'body' => lang("displaying html messages is disabled"),
|
||||
'mimeType' => 'text/html',
|
||||
'charSet' => self::$displayCharset,
|
||||
);
|
||||
} elseif ($_structure->subType == 'PLAIN' && $_htmlMode == 'html_only') {
|
||||
$bodyPart = array(
|
||||
'error' => 1,
|
||||
'body' => lang("displaying plain messages is disabled"),
|
||||
'mimeType' => 'text/plain', // make sure we do not return mimeType text/html
|
||||
'charSet' => self::$displayCharset,
|
||||
);
|
||||
} else {
|
||||
// some Servers append PropertyFile___ ; strip that here for display
|
||||
$bodyPart = array(
|
||||
'body' => preg_replace('/PropertyFile___$/','',$this->decodeMimePart($mimePartBody, $_structure->encoding, $this->getMimePartCharset($_structure))),
|
||||
'mimeType' => ($_structure->type == 'TEXT' && $_structure->subType == 'HTML') ? 'text/html' : 'text/plain',
|
||||
'charSet' => $this->getMimePartCharset($_structure),
|
||||
);
|
||||
if ($_structure->type == 'TEXT' && $_structure->subType == 'PLAIN' &&
|
||||
is_array($_structure->parameters) && isset($_structure->parameters['FORMAT']) &&
|
||||
trim(strtolower($_structure->parameters['FORMAT']))=='flowed'
|
||||
)
|
||||
{
|
||||
if (self::$debug) error_log(__METHOD__.__LINE__." detected TEXT/PLAIN Format:flowed -> removing leading blank ('\r\n ') per line");
|
||||
$bodyPart['body'] = str_replace("\r\n ","\r\n", $bodyPart['body']);
|
||||
}
|
||||
if ($_structure->subType == 'CALENDAR')
|
||||
{
|
||||
// we get an inline CALENDAR ical/ics, we display it using the calendar notification style
|
||||
$calobj = new calendar_ical;
|
||||
$calboupdate = new calendar_boupdate;
|
||||
// timezone stuff
|
||||
$tz_diff = $GLOBALS['egw_info']['user']['preferences']['common']['tz_offset'] - $this->common_prefs['tz_offset'];
|
||||
// form an event out of ical
|
||||
$event = $calobj->icaltoegw($bodyPart['body']);
|
||||
$event= $event[0];
|
||||
// preset the olddate
|
||||
$olddate = $calboupdate->format_date($event['start']+$tz_diff);
|
||||
// search egw, if we can find it
|
||||
$eventid = $calobj->find_event(array('uid'=>$event['uid']));
|
||||
if ((int)$eventid[0]>0)
|
||||
{
|
||||
// we found an event, we use the first one
|
||||
$oldevent = $calobj->read($eventid);
|
||||
// we set the olddate, to comply with the possible merge params for the notification message
|
||||
if($oldevent != False && $oldevent[$eventid[0]]['start']!=$event[$eventid[0]]['start']) {
|
||||
$olddate = $calboupdate->format_date($oldevent[$eventid[0]]['start']+$tz_diff);
|
||||
}
|
||||
// we merge the changes and the original event
|
||||
$event = array_merge($oldevent[$eventid[0]],$event);
|
||||
// for some strange reason, the title of the old event is not replaced with the new title
|
||||
// if you klick on the ics and import it into egw, so we dont show the title here.
|
||||
// so if it is a mere reply, we dont use the new title (more detailed info/work needed here)
|
||||
if ($_structure->parameters['METHOD']=='REPLY') $event['title'] = $oldevent[$eventid[0]]['title'];
|
||||
}
|
||||
// we prepare the message
|
||||
$details = $calboupdate->_get_event_details($event,$action,$event_arr);
|
||||
$details['olddate']=$olddate;
|
||||
//_debug_array($_structure);
|
||||
list($subject,$info) = $calboupdate->get_update_message($event,($_structure->parameters['METHOD']=='REPLY'?false:true));
|
||||
$info = $GLOBALS['egw']->preferences->parse_notify($info,$details);
|
||||
// we set the bodyPart, we only show the event, we dont actually do anything, as we expect the user to
|
||||
// click on the attached ics to update his own eventstore
|
||||
$bodyPart['body'] = $subject;
|
||||
$bodyPart['body'] .= "\n".$info;
|
||||
$bodyPart['body'] .= "\n\n".lang('Event Details follow').":\n";
|
||||
foreach($event_arr as $key => $val)
|
||||
{
|
||||
if(strlen($details[$key])) {
|
||||
switch($key){
|
||||
case 'access':
|
||||
case 'priority':
|
||||
case 'link':
|
||||
break;
|
||||
default:
|
||||
$bodyPart['body'] .= sprintf("%-20s %s\n",$val['field'].':',$details[$key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//_debug_array($bodyPart);
|
||||
return $bodyPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* getMessageBody
|
||||
* get Body from message
|
||||
* @param string/int $_uid the messageuid,
|
||||
* @param string $_htmlOptions, how to display a message, html, plain text, ...
|
||||
* @param string/int $_partID='' , the partID, may be omitted
|
||||
* @param array $_structure='', if given use structure for parsing
|
||||
* @param boolean $_preserveSeen flag to preserve the seenflag by using body.peek
|
||||
* @return array containing the message body, mimeType and charset
|
||||
*/
|
||||
function getMessageBody($_uid, $_htmlOptions='', $_partID='', $_structure = '', $_preserveSeen = false, $_folder = '')
|
||||
{
|
||||
if (self::$debug) echo __METHOD__."$_uid, $_htmlOptions, $_partID<br>";
|
||||
if($_htmlOptions != '') {
|
||||
$this->htmlOptions = $_htmlOptions;
|
||||
}
|
||||
if(is_object($_structure)) {
|
||||
$structure = $_structure;
|
||||
} else {
|
||||
$this->icServer->_cmd_counter = rand($this->icServer->_cmd_counter+1,$this->icServer->_cmd_counter+100);
|
||||
$structure = $this->_getStructure($_uid, true, false, $_folder);
|
||||
if($_partID != '') {
|
||||
$structure = $this->_getSubStructure($structure, $_partID);
|
||||
}
|
||||
}
|
||||
if (self::$debug) _debug_array($structure);
|
||||
switch($structure->type) {
|
||||
case 'APPLICATION':
|
||||
return array(
|
||||
array(
|
||||
'body' => '',
|
||||
'mimeType' => 'text/plain',
|
||||
'charSet' => 'iso-8859-1',
|
||||
)
|
||||
);
|
||||
break;
|
||||
case 'MULTIPART':
|
||||
switch($structure->subType) {
|
||||
case 'ALTERNATIVE':
|
||||
$bodyParts = array($this->getMultipartAlternative($_uid, $structure->subParts, $this->htmlOptions, $_preserveSeen));
|
||||
|
||||
break;
|
||||
|
||||
case 'NIL': // multipart with no Alternative
|
||||
case 'MIXED':
|
||||
case 'REPORT':
|
||||
case 'SIGNED':
|
||||
$bodyParts = $this->getMultipartMixed($_uid, $structure->subParts, $this->htmlOptions, $_preserveSeen);
|
||||
break;
|
||||
|
||||
case 'RELATED':
|
||||
$bodyParts = $this->getMultipartRelated($_uid, $structure->subParts, $this->htmlOptions, $_preserveSeen);
|
||||
break;
|
||||
}
|
||||
return self::normalizeBodyParts($bodyParts);
|
||||
break;
|
||||
case 'VIDEO':
|
||||
case 'AUDIO': // some servers send audiofiles and imagesfiles directly, without any stuff surround it
|
||||
case 'IMAGE': // they are displayed as Attachment NOT INLINE
|
||||
return array(
|
||||
array(
|
||||
'body' => '',
|
||||
'mimeType' => $structure->subType,
|
||||
),
|
||||
);
|
||||
break;
|
||||
case 'TEXT':
|
||||
$bodyPart = array();
|
||||
if ( $structure->disposition != 'ATTACHMENT') {
|
||||
switch($structure->subType) {
|
||||
case 'CALENDAR':
|
||||
// this is handeled in getTextPart
|
||||
case 'HTML':
|
||||
case 'PLAIN':
|
||||
default:
|
||||
$bodyPart = array($this->getTextPart($_uid, $structure, $this->htmlOptions, $_preserveSeen));
|
||||
}
|
||||
} else {
|
||||
// what if the structure->disposition is attachment ,...
|
||||
}
|
||||
return self::normalizeBodyParts($bodyPart);
|
||||
break;
|
||||
case 'ATTACHMENT':
|
||||
case 'MESSAGE':
|
||||
switch($structure->subType) {
|
||||
case 'RFC822':
|
||||
$newStructure = array_shift($structure->subParts);
|
||||
if (self::$debug) {echo __METHOD__." Message -> RFC -> NewStructure:"; _debug_array($newStructure);}
|
||||
return self::normalizeBodyParts($this->getMessageBody($_uid, $_htmlOptions, $newStructure->partID, $newStructure));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (self::$debug) _debug_array($structure);
|
||||
return array(
|
||||
array(
|
||||
'body' => lang('The mimeparser can not parse this message.'),
|
||||
'mimeType' => 'text/plain',
|
||||
'charSet' => 'iso-8859-1',
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* normalizeBodyParts - function to gather and normalize all body Information
|
||||
* @param _bodyParts - Body Array
|
||||
* @return array - a normalized Bodyarray
|
||||
*/
|
||||
static function normalizeBodyParts($_bodyParts)
|
||||
{
|
||||
if (is_array($_bodyParts))
|
||||
{
|
||||
foreach($_bodyParts as $singleBodyPart)
|
||||
{
|
||||
if (!isset($singleBodyPart['body'])) {
|
||||
$buff = self::normalizeBodyParts($singleBodyPart);
|
||||
foreach ((array)$buff as $val) $body2return[] = $val;
|
||||
continue;
|
||||
}
|
||||
$body2return[] = $singleBodyPart;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$body2return = $_bodyParts;
|
||||
}
|
||||
return $body2return;
|
||||
}
|
||||
|
||||
/**
|
||||
* getdisplayableBody - creates the bodypart of the email as textual representation
|
||||
* @param object $mailClass the mailClass object to be used
|
||||
* @param array $bodyParts with the bodyparts
|
||||
* @return string a preformatted string with the mails converted to text
|
||||
*/
|
||||
static function &getdisplayableBody(&$mailClass, $bodyParts, $preserveHTML = false)
|
||||
{
|
||||
for($i=0; $i<count($bodyParts); $i++)
|
||||
{
|
||||
if (!isset($bodyParts[$i]['body'])) {
|
||||
$bodyParts[$i]['body'] = self::getdisplayableBody($mailClass, $bodyParts[$i], $preserveHTML);
|
||||
$message .= empty($bodyParts[$i]['body'])?'':$bodyParts[$i]['body'];
|
||||
continue;
|
||||
}
|
||||
if (isset($bodyParts[$i]['error'])) continue;
|
||||
if (empty($bodyParts[$i]['body'])) continue;
|
||||
// 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(($bodyParts[$i]['mimeType'] == 'text/html' || $bodyParts[$i]['mimeType'] == 'text/plain') &&
|
||||
strtoupper($bodyParts[$i]['charSet']) != 'UTF-8')
|
||||
{
|
||||
$bodyParts[$i]['body'] = preg_replace($sar,$rar,$bodyParts[$i]['body']);
|
||||
}
|
||||
|
||||
if ($bodyParts[$i]['charSet']===false) $bodyParts[$i]['charSet'] = translation::detect_encoding($bodyParts[$i]['body']);
|
||||
// add line breaks to $bodyParts
|
||||
//error_log(__METHOD__.__LINE__.' Charset:'.$bodyParts[$i]['charSet'].'->'.$bodyParts[$i]['body']);
|
||||
$newBody = translation::convert($bodyParts[$i]['body'], $bodyParts[$i]['charSet']);
|
||||
//error_log(__METHOD__.__LINE__.' MimeType:'.$bodyParts[$i]['mimeType'].'->'.$newBody);
|
||||
/*
|
||||
// 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(self::$displayCharset) == 'UTF-8')
|
||||
{
|
||||
$test = json_encode($newBody);
|
||||
//error_log(__METHOD__.__LINE__.'#'.$test.'# ->'.strlen($newBody).' Error:'.json_last_error());
|
||||
if (json_last_error() != JSON_ERROR_NONE && strlen($newBody)>0)
|
||||
{
|
||||
// this should not be needed, unless something fails with charset detection/ wrong charset passed
|
||||
error_log(__METHOD__.__LINE__.' Charset Reported:'.$bodyParts[$i]['charSet'].' Carset Detected:'.translation::detect_encoding($bodyParts[$i]['body']));
|
||||
$newBody = utf8_encode($newBody);
|
||||
}
|
||||
}
|
||||
*/
|
||||
//error_log(__METHOD__.__LINE__.' before purify:'.$newBody);
|
||||
$mailClass->activeMimeType = 'text/plain';
|
||||
if ($bodyParts[$i]['mimeType'] == 'text/html') {
|
||||
$mailClass->activeMimeType = $bodyParts[$i]['mimeType'];
|
||||
// as translation::convert reduces \r\n to \n and purifier eats \n -> peplace it with a single space
|
||||
$newBody = str_replace("\n"," ",$newBody);
|
||||
// convert HTML to text, as we dont want HTML in infologs
|
||||
if (extension_loaded('tidy'))
|
||||
{
|
||||
$tidy = new tidy();
|
||||
$cleaned = $tidy->repairString($newBody, self::$tidy_config,'utf8');
|
||||
// Found errors. Strip it all so there's some output
|
||||
if($tidy->getStatus() == 2)
|
||||
{
|
||||
error_log(__METHOD__.__LINE__.' ->'.$tidy->errorBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
$newBody = $cleaned;
|
||||
}
|
||||
if (!$preserveHTML)
|
||||
{
|
||||
// filter only the 'body', as we only want that part, if we throw away the html
|
||||
preg_match('`(<htm.+?<body[^>]*>)(.+?)(</body>.*?</html>)`ims', $newBody, $matches);
|
||||
if ($matches[2])
|
||||
{
|
||||
$hasOther = true;
|
||||
$newBody = $matches[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// htmLawed filter only the 'body'
|
||||
preg_match('`(<htm.+?<body[^>]*>)(.+?)(</body>.*?</html>)`ims', $newBody, $matches);
|
||||
if ($matches[2])
|
||||
{
|
||||
$hasOther = true;
|
||||
$newBody = $matches[2];
|
||||
}
|
||||
$htmLawed = new egw_htmLawed();
|
||||
// the next line should not be needed
|
||||
$newBody = str_replace(array('&amp;','<DIV><BR></DIV>',"<DIV> </DIV>",'<div> </div>'),array('&','<BR>','<BR>','<BR>'),$newBody);
|
||||
$newBody = $htmLawed->egw_htmLawed($newBody);
|
||||
if ($hasOther && $preserveHTML) $newBody = $matches[1]. $newBody. $matches[3];
|
||||
}
|
||||
//error_log(__METHOD__.__LINE__.' after purify:'.$newBody);
|
||||
if ($preserveHTML==false) $newBody = $mailClass->convertHTMLToText($newBody,true);
|
||||
//error_log(__METHOD__.__LINE__.' after convertHTMLToText:'.$newBody);
|
||||
if ($preserveHTML==false) $newBody = nl2br($newBody); // we need this, as htmLawed removes \r\n
|
||||
$mailClass->getCleanHTML($newBody,false,$preserveHTML); // remove stuff we regard as unwanted
|
||||
if ($preserveHTML==false) $newBody = str_replace("<br />","\r\n",$newBody);
|
||||
//error_log(__METHOD__.__LINE__.' after getClean:'.$newBody);
|
||||
$message .= $newBody;
|
||||
continue;
|
||||
}
|
||||
$newBody =self::htmlspecialchars($newBody);
|
||||
//error_log(__METHOD__.__LINE__.' Body(after specialchars):'.$newBody);
|
||||
$newBody = strip_tags($newBody); //we need to fix broken tags (or just stuff like "<800 USD/p" )
|
||||
//error_log(__METHOD__.__LINE__.' Body(after strip tags):'.$newBody);
|
||||
$newBody = htmlspecialchars_decode($newBody,ENT_QUOTES);
|
||||
//error_log(__METHOD__.__LINE__.' Body (after hmlspc_decode):'.$newBody);
|
||||
$message .= $newBody;
|
||||
//continue;
|
||||
}
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* getMessageRawHeader
|
||||
* get parsed headers from message
|
||||
@ -3012,6 +3731,191 @@ class mail_bo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* functions to allow access to mails through other apps to fetch content
|
||||
* used in infolog, tracker
|
||||
*/
|
||||
|
||||
/**
|
||||
* get_mailcontent - fetches the actual mailcontent, and returns it as well defined array
|
||||
* @param object mailClass the mailClassobject to be used
|
||||
* @param uid the uid of the email to be processed
|
||||
* @param partid the partid of the email
|
||||
* @param mailbox the mailbox, that holds the message
|
||||
* @param preserveHTML flag to pass through to getdisplayableBody
|
||||
* @return array with 'mailaddress'=>$mailaddress,
|
||||
* 'subject'=>$subject,
|
||||
* 'message'=>$message,
|
||||
* 'attachments'=>$attachments,
|
||||
* 'headers'=>$headers,
|
||||
*/
|
||||
static function get_mailcontent(&$mailClass,$uid,$partid='',$mailbox='', $preserveHTML = false)
|
||||
{
|
||||
//echo __METHOD__." called for $uid,$partid <br>";
|
||||
$headers = $mailClass->getMessageHeader($uid,$partid,true);
|
||||
// dont force retrieval of the textpart, let mailClass preferences decide
|
||||
$bodyParts = $mailClass->getMessageBody($uid,($preserveHTML?'always_display':'only_if_no_text'),$partid);
|
||||
//error_log(array2string($bodyParts));
|
||||
$attachments = $mailClass->getMessageAttachments($uid,$partid);
|
||||
|
||||
if ($mailClass->isSentFolder($mailbox)) $mailaddress = $headers['TO'];
|
||||
elseif (isset($headers['FROM'])) $mailaddress = $headers['FROM'];
|
||||
elseif (isset($headers['SENDER'])) $mailaddress = $headers['SENDER'];
|
||||
if (isset($headers['CC'])) $mailaddress .= ','.$headers['CC'];
|
||||
//_debug_array($headers);
|
||||
$subject = $headers['SUBJECT'];
|
||||
|
||||
$message = self::getdisplayableBody($mailClass, $bodyParts, $preserveHTML);
|
||||
if ($preserveHTML && $mailClass->activeMimeType == 'text/plain') $message = '<pre>'.$message.'</pre>';
|
||||
$headdata = self::createHeaderInfoSection($headers, '',$preserveHTML);
|
||||
$message = $headdata.$message;
|
||||
//echo __METHOD__.'<br>';
|
||||
//_debug_array($attachments);
|
||||
if (is_array($attachments))
|
||||
{
|
||||
foreach ($attachments as $num => $attachment)
|
||||
{
|
||||
if ($attachment['mimeType'] == 'MESSAGE/RFC822')
|
||||
{
|
||||
//_debug_array($mailClass->getMessageHeader($uid, $attachment['partID']));
|
||||
//_debug_array($mailClass->getMessageBody($uid,'', $attachment['partID']));
|
||||
//_debug_array($mailClass->getMessageAttachments($uid, $attachment['partID']));
|
||||
$mailcontent = self::get_mailcontent($mailClass,$uid,$attachment['partID']);
|
||||
$headdata ='';
|
||||
if ($mailcontent['headers'])
|
||||
{
|
||||
$headdata = self::createHeaderInfoSection($mailcontent['headers'],'',$preserveHTML);
|
||||
}
|
||||
if ($mailcontent['message'])
|
||||
{
|
||||
$tempname =tempnam($GLOBALS['egw_info']['server']['temp_dir'],$GLOBALS['egw_info']['flags']['currentapp']."_");
|
||||
$attachedMessages[] = array(
|
||||
'type' => 'TEXT/PLAIN',
|
||||
'name' => $mailcontent['subject'].'.txt',
|
||||
'tmp_name' => $tempname,
|
||||
);
|
||||
$tmpfile = fopen($tempname,'w');
|
||||
fwrite($tmpfile,$headdata.$mailcontent['message']);
|
||||
fclose($tmpfile);
|
||||
}
|
||||
foreach($mailcontent['attachments'] as $tmpattach => $tmpval)
|
||||
{
|
||||
$attachedMessages[] = $tmpval;
|
||||
}
|
||||
unset($attachments[$num]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$attachments[$num] = array_merge($attachments[$num],$mailClass->getAttachment($uid, $attachment['partID']));
|
||||
if (isset($attachments[$num]['charset'])) {
|
||||
if ($attachments[$num]['charset']===false) $attachments[$num]['charset'] = translation::detect_encoding($attachments[$num]['attachment']);
|
||||
translation::convert($attachments[$num]['attachment'],$attachments[$num]['charset']);
|
||||
}
|
||||
$attachments[$num]['type'] = $attachments[$num]['mimeType'];
|
||||
$attachments[$num]['tmp_name'] = tempnam($GLOBALS['egw_info']['server']['temp_dir'],$GLOBALS['egw_info']['flags']['currentapp']."_");
|
||||
$tmpfile = fopen($attachments[$num]['tmp_name'],'w');
|
||||
fwrite($tmpfile,$attachments[$num]['attachment']);
|
||||
fclose($tmpfile);
|
||||
unset($attachments[$num]['attachment']);
|
||||
}
|
||||
}
|
||||
if (is_array($attachedMessages)) $attachments = array_merge($attachments,$attachedMessages);
|
||||
}
|
||||
return array(
|
||||
'mailaddress'=>$mailaddress,
|
||||
'subject'=>$subject,
|
||||
'message'=>$message,
|
||||
'attachments'=>$attachments,
|
||||
'headers'=>$headers,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* createHeaderInfoSection - creates a textual headersection from headerobject
|
||||
* @param array header headerarray may contain SUBJECT,FROM,SENDER,TO,CC,BCC,DATE,PRIORITY,IMPORTANCE
|
||||
* @param string headline Text tom use for headline
|
||||
* @param bool createHTML do it with HTML breaks
|
||||
* @return string a preformatted string with the information of the header worked into it
|
||||
*/
|
||||
static function createHeaderInfoSection($header,$headline='', $createHTML = false)
|
||||
{
|
||||
$headdata = null;
|
||||
if ($header['SUBJECT']) $headdata = lang('subject').': '.$header['SUBJECT'].($createHTML?"<br />":"\n");
|
||||
if ($header['FROM']) $headdata .= lang('from').': '.self::convertAddressArrayToString($header['FROM'], $createHTML).($createHTML?"<br />":"\n");
|
||||
if ($header['SENDER']) $headdata .= lang('sender').': '.self::convertAddressArrayToString($header['SENDER'], $createHTML).($createHTML?"<br />":"\n");
|
||||
if ($header['TO']) $headdata .= lang('to').': '.self::convertAddressArrayToString($header['TO'], $createHTML).($createHTML?"<br />":"\n");
|
||||
if ($header['CC']) $headdata .= lang('cc').': '.self::convertAddressArrayToString($header['CC'], $createHTML).($createHTML?"<br />":"\n");
|
||||
if ($header['BCC']) $headdata .= lang('bcc').': '.self::convertAddressArrayToString($header['BCC'], $createHTML).($createHTML?"<br />":"\n");
|
||||
if ($header['DATE']) $headdata .= lang('date').': '.$header['DATE'].($createHTML?"<br />":"\n");
|
||||
if ($header['PRIORITY'] && $header['PRIORITY'] != 'normal') $headdata .= lang('priority').': '.$header['PRIORITY'].($createHTML?"<br />":"\n");
|
||||
if ($header['IMPORTANCE'] && $header['IMPORTANCE'] !='normal') $headdata .= lang('importance').': '.$header['IMPORTANCE'].($createHTML?"<br />":"\n");
|
||||
//if ($mailcontent['headers']['ORGANIZATION']) $headdata .= lang('organization').': '.$mailcontent['headers']['ORGANIZATION']."\
|
||||
if (!empty($headdata))
|
||||
{
|
||||
if (!empty($headline)) $headdata = "---------------------------- $headline ----------------------------".($createHTML?"<br />":"\n").$headdata;
|
||||
if (empty($headline)) $headdata = "--------------------------------------------------------".($createHTML?"<br />":"\n").$headdata;
|
||||
$headdata .= "--------------------------------------------------------".($createHTML?"<br />":"\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
$headdata = "--------------------------------------------------------".($createHTML?"<br />":"\n");
|
||||
}
|
||||
return $headdata;
|
||||
}
|
||||
|
||||
/**
|
||||
* convertAddressArrayToString - converts an mail envelope Address Array To String
|
||||
* @param array $rfcAddressArray an addressarray as provided by mail retieved via egw_pear....
|
||||
* @return string a comma separated string with the mailaddress(es) converted to text
|
||||
*/
|
||||
static function convertAddressArrayToString($rfcAddressArray, $createHTML = false)
|
||||
{
|
||||
//error_log(__METHOD__.__LINE__.array2string($rfcAddressArray));
|
||||
$returnAddr ='';
|
||||
if (is_array($rfcAddressArray))
|
||||
{
|
||||
foreach((array)$rfcAddressArray as $addressData) {
|
||||
//error_log(__METHOD__.__LINE__.array2string($addressData));
|
||||
if($addressData['MAILBOX_NAME'] == 'NIL') {
|
||||
continue;
|
||||
}
|
||||
if(strtolower($addressData['MAILBOX_NAME']) == 'undisclosed-recipients') {
|
||||
continue;
|
||||
}
|
||||
if ($addressData['RFC822_EMAIL'])
|
||||
{
|
||||
$addressObjectA = imap_rfc822_parse_adrlist((get_magic_quotes_gpc()?stripslashes($addressData['RFC822_EMAIL']):$addressData['RFC822_EMAIL']),'');
|
||||
}
|
||||
else
|
||||
{
|
||||
$emailaddress = ($addressData['PERSONAL_NAME']?$addressData['PERSONAL_NAME'].' <'.$addressData['EMAIL'].'>':$addressData['EMAIL']);
|
||||
$addressObjectA = imap_rfc822_parse_adrlist((get_magic_quotes_gpc()?stripslashes($emailaddress):$emailaddress),'');
|
||||
}
|
||||
$addressObject = $addressObjectA[0];
|
||||
//error_log(__METHOD__.__LINE__.array2string($addressObject));
|
||||
if ($addressObject->host == '.SYNTAX-ERROR.') continue;
|
||||
//$mb =(string)$addressObject->mailbox;
|
||||
//$h = (string)$addressObject->host;
|
||||
//$p = (string)$addressObject->personal;
|
||||
$returnAddr .= (strlen($returnAddr)>0?',':'');
|
||||
//error_log(__METHOD__.__LINE__.$p.' <'.$mb.'@'.$h.'>');
|
||||
$buff = imap_rfc822_write_address($addressObject->mailbox, self::$idna2->decode($addressObject->host), $addressObject->personal);
|
||||
$buff = str_replace(array('<','>'),array('[',']'),$buff);
|
||||
if ($createHTML) $buff = mail_bo::htmlspecialchars($buff);
|
||||
//error_log(__METHOD__.__LINE__.' Address: '.$returnAddr);
|
||||
$returnAddr .= $buff;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// do not mess with strings, return them untouched /* ToDo: validate string as Address */
|
||||
$rfcAddressArray = self::decode_header($rfcAddressArray,true);
|
||||
$rfcAddressArray = str_replace(array('<','>'),array('[',']'),$rfcAddressArray);
|
||||
if (is_string($rfcAddressArray)) return ($createHTML ? mail_bo::htmlspecialchars($rfcAddressArray) : $rfcAddressArray);
|
||||
}
|
||||
return $returnAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook stuff
|
||||
*/
|
||||
|
@ -812,7 +812,7 @@ class mail_hooks
|
||||
// Destination div for folder tree
|
||||
$file[] = array(
|
||||
'no_lang' => true,
|
||||
'text'=>'<span id="tree_target" class="dtree"/>',
|
||||
'text'=>'<span id="tree_target" class="dtree" style="width:100%;"/>',
|
||||
'link'=>false,
|
||||
'icon' => false
|
||||
);
|
||||
|
@ -25,6 +25,7 @@ class mail_ui
|
||||
'index' => True,
|
||||
'displayHeader' => True,
|
||||
'saveMessage' => True,
|
||||
'vfsSaveMessage' => True,
|
||||
'TestConnection' => True,
|
||||
);
|
||||
|
||||
@ -504,7 +505,7 @@ class mail_ui
|
||||
if ($_nodeID)
|
||||
{
|
||||
$node = self::findNode($out,$_nodeID);
|
||||
error_log(__METHOD__.__LINE__.array2string($node));
|
||||
//error_log(__METHOD__.__LINE__.array2string($node));
|
||||
return $node;
|
||||
}
|
||||
return ($c?$out:array('id'=>0, 'item'=>array('text'=>'INBOX','tooltip'=>'INBOX'.' '.lang('(not connected)'),'im0'=>'kfm_home.png')));
|
||||
@ -1057,11 +1058,11 @@ unset($query['actions']);
|
||||
* @param string $_rowID, string - a colon separated string in the form accountID:profileID:folder:message_uid
|
||||
* @return array populated named result array (accountID,profileID,folder,msgUID)
|
||||
*/
|
||||
function splitRowID($_rowID)
|
||||
static function splitRowID($_rowID)
|
||||
{
|
||||
$res = explode(self::$delimiter,$_rowID);
|
||||
// as a rowID is perceeded by app::, we ignore the first part
|
||||
return array('accountID'=>$res[1], 'profileID'=>$res[2], 'folder'=>base64_decode($res[3]), 'msgUID'=>$res[4]);
|
||||
// as a rowID is perceeded by app::, should be mail!
|
||||
return array('app'=>$res[0], 'accountID'=>$res[1], 'profileID'=>$res[2], 'folder'=>base64_decode($res[3]), 'msgUID'=>$res[4]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1385,7 +1386,7 @@ unset($query['actions']);
|
||||
if(isset($_GET['id'])) $rowID = $_GET['id'];
|
||||
if(isset($_GET['part'])) $partID = $_GET['part'];
|
||||
|
||||
$hA = $this->splitRowID($rowID);
|
||||
$hA = self::splitRowID($rowID);
|
||||
$uid = $hA['msgUID'];
|
||||
$mailbox = $hA['folder'];
|
||||
|
||||
@ -1434,7 +1435,7 @@ unset($query['actions']);
|
||||
if(isset($_GET['part'])) $partID = $_GET['part'];
|
||||
if (isset($_GET['location'])&& ($_GET['location']=='display'||$_GET['location']=='filemanager')) $display = $_GET['location'];
|
||||
|
||||
$hA = $this->splitRowID($rowID);
|
||||
$hA = self::splitRowID($rowID);
|
||||
$uid = $hA['msgUID'];
|
||||
$mailbox = $hA['folder'];
|
||||
|
||||
@ -1471,6 +1472,41 @@ unset($query['actions']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save an Message in the vfs
|
||||
*
|
||||
* @param string|array $ids use splitRowID, to separate values
|
||||
* @param string $path path in vfs (no egw_vfs::PREFIX!), only directory for multiple id's ($ids is an array)
|
||||
* @return string javascript eg. to close the selector window
|
||||
*/
|
||||
function vfsSaveMessage($ids,$path)
|
||||
{
|
||||
return "alert('".__METHOD__.'("'.array2string($id).'","'.$path."\")'); window.close();";
|
||||
/*
|
||||
if (is_array($ids) && !egw_vfs::is_writable($path) || !is_array($ids) && !egw_vfs::is_writable(dirname($path)))
|
||||
{
|
||||
return 'alert("'.addslashes(lang('%1 is NOT writable by you!',$path)).'"); window.close();';
|
||||
}
|
||||
foreach((array)$ids as $id)
|
||||
{
|
||||
$hA = self::splitRowID($id);
|
||||
$uid = $hA['msgUID'];
|
||||
$mailbox = $hA['folder'];
|
||||
if ($mb != $this->mail_bo->mailbox) $this->mail_bo->reopen($mb = $mailbox);
|
||||
$message = $this->mail_bo->getMessageRawBody($uid, $partID='');
|
||||
if (!($fp = egw_vfs::fopen($file=$path.($name ? '/'.$name : ''),'wb')) ||
|
||||
!fwrite($fp,$message))
|
||||
{
|
||||
$err .= 'alert("'.addslashes(lang('Error saving %1!',$file)).'");';
|
||||
}
|
||||
if ($fp) fclose($fp);
|
||||
}
|
||||
$this->mail_bo->closeConnection();
|
||||
|
||||
return $err.'window.close();';
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* getFolderStatus - 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)
|
||||
@ -1578,12 +1614,12 @@ unset($query['actions']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$uidA = $this->splitRowID($_messageList['msg'][0]);
|
||||
$uidA = self::splitRowID($_messageList['msg'][0]);
|
||||
$folder = $uidA['folder']; // all messages in one set are supposed to be within the same folder
|
||||
}
|
||||
foreach($_messageList['msg'] as $rowID)
|
||||
{
|
||||
$hA = $this->splitRowID($rowID);
|
||||
$hA = self::splitRowID($rowID);
|
||||
$messageList[] = $hA['msgUID'];
|
||||
}
|
||||
$this->mail_bo->flagMessages($_flag, ($_messageList=='all' ? 'all':$messageList),$folder);
|
||||
@ -1624,12 +1660,12 @@ unset($query['actions']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$uidA = $this->splitRowID($_messageList['msg'][0]);
|
||||
$uidA = self::splitRowID($_messageList['msg'][0]);
|
||||
$folder = $uidA['folder']; // all messages in one set are supposed to be within the same folder
|
||||
}
|
||||
foreach($_messageList['msg'] as $rowID)
|
||||
{
|
||||
$hA = $this->splitRowID($rowID);
|
||||
$hA = self::splitRowID($rowID);
|
||||
$messageList[] = $hA['msgUID'];
|
||||
}
|
||||
$this->mail_bo->deleteMessages(($_messageList=='all' ? 'all':$messageList),$folder);
|
||||
|
@ -350,6 +350,78 @@ function mail_mailsource(_action, _elems)
|
||||
mail_displayHeaderLines(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a message
|
||||
*
|
||||
* @param _action
|
||||
* @param _elems _elems[0].id is the row-id
|
||||
*/
|
||||
function mail_save(_action, _elems)
|
||||
{
|
||||
//alert('mail_save('+_elems[0].id+')');
|
||||
var url = window.egw_webserverUrl+'/index.php?';
|
||||
url += 'menuaction=mail.mail_ui.saveMessage'; // todo compose for Draft folder
|
||||
url += '&id='+_elems[0].id;
|
||||
//window.open(url,'_blank','dependent=yes,width=100,height=100,scrollbars=yes,status=yes')
|
||||
document.location = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a message to filemanager
|
||||
*
|
||||
* @param _action
|
||||
* @param _elems _elems[0].id is the row-id
|
||||
*/
|
||||
function mail_save2fm(_action, _elems)
|
||||
{
|
||||
var _id = _elems[0].id;
|
||||
var dataElem = egw.dataGetUIDdata(_id);
|
||||
var url = window.egw_webserverUrl+'/index.php?';
|
||||
url += 'menuaction=filemanager.filemanager_select.select'; // todo compose for Draft folder
|
||||
url += '&mode=saveas';
|
||||
var filename =dataElem.data.subject.replace(/[\f\n\t\v/\\:*#?<>\|]/g,"_");
|
||||
url += '&name='+encodeURIComponent(filename+'.eml');
|
||||
url += '&mime=message'+encodeURIComponent('/')+'rfc822';
|
||||
url += '&method=mail.mail_ui.vfsSaveMessage'
|
||||
url += '&id='+_elems[0].id;
|
||||
url += '&label=Save';
|
||||
//window.open(url,'_blank','dependent=yes,width=100,height=100,scrollbars=yes,status=yes')
|
||||
//document.location = url;
|
||||
egw_openWindowCentered(url,'vfs_save_message_'+_elems[0].id,'640','570',window.outerWidth/2,window.outerHeight/2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Save message as InfoLog
|
||||
*
|
||||
* @param _action
|
||||
* @param _elems _elems[0].id is the row-id
|
||||
*/
|
||||
function mail_infolog(_action, _elems)
|
||||
{
|
||||
//alert('mail_infolog('+_elems[0].id+')');return;
|
||||
var url = window.egw_webserverUrl+'/index.php?';
|
||||
url += 'menuaction=infolog.infolog_ui.import_mail'; // todo compose for Draft folder
|
||||
url += '&rowid='+_elems[0].id;
|
||||
egw_openWindowCentered(url,'import_mail_'+_elems[0].id,_action.data.width,_action.data.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save message as ticket
|
||||
*
|
||||
* @param _action _action.id is 'read', 'unread', 'flagged' or 'unflagged'
|
||||
* @param _elems
|
||||
*/
|
||||
function mail_tracker(_action, _elems)
|
||||
{
|
||||
//alert('mail_tracker('+_elems[0].id+')');
|
||||
var url = window.egw_webserverUrl+'/index.php?';
|
||||
url += 'menuaction=tracker.tracker_ui.import_mail'; // todo compose for Draft folder
|
||||
url += '&rowid='+_elems[0].id;
|
||||
egw_openWindowCentered(url,'import_tracker_'+_elems[0].id,_action.data.width,_action.data.height);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* mail_getFormData
|
||||
*
|
||||
|
@ -1,3 +1,9 @@
|
||||
textarea
|
||||
{
|
||||
font-family: monospace, sans-serif;
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
.defaultProfile { color:#000000; font-weight:bold !important; }
|
||||
|
||||
|
||||
@ -217,6 +223,9 @@ pre {
|
||||
color: #666;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.dtree div {
|
||||
width: 100%;
|
||||
}
|
||||
.dtree img {
|
||||
border: 0px;
|
||||
vertical-align: middle;
|
||||
@ -254,12 +263,14 @@ pre {
|
||||
}
|
||||
/*
|
||||
avoid the vertical scrollbar within the sidebox section (triggered by the vertical dimension of the tree)
|
||||
*/.divSidebox {
|
||||
*/
|
||||
.divSidebox {
|
||||
overflow: hidden;
|
||||
}
|
||||
/*
|
||||
avoid the vertical scrollbar within the actual tablecontainer (of the tree)
|
||||
*/
|
||||
.containerTableStyle {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user