get some more actions to work

This commit is contained in:
Klaus Leithoff 2013-03-05 14:09:35 +00:00
parent 93710e09e1
commit 9c830f7461
5 changed files with 1043 additions and 20 deletions

View File

@ -50,6 +50,13 @@ class mail_bo
*/ */
var $htmlOptions; var $htmlOptions;
/**
* Active mimeType
*
* @var string
*/
var $activeMimeType;
/** /**
* Active incomming (IMAP) Server Object * Active incomming (IMAP) Server Object
* *
@ -886,16 +893,21 @@ class mail_bo
if (!is_array($folderInfo[0])) 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 // 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(), $folderInfo = array(0 => (is_array($folderInfo)?$folderInfo:array('HIERACHY_DELIMITER'=>$this->getHierarchyDelimiter(),
'ATTRIBUTES' => '')); '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])) { #if(!is_array($folderInfo[0])) {
# return false; # return false;
#} #}
$retValue['delimiter'] = $folderInfo[0]['HIERACHY_DELIMITER']; $retValue['delimiter'] = ($folderInfo[0]['HIERACHY_DELIMITER']?$folderInfo[0]['HIERACHY_DELIMITER']:$folderInfo[0]['delimiter']);
$retValue['attributes'] = $folderInfo[0]['ATTRIBUTES']; $retValue['attributes'] = ($folderInfo[0]['ATTRIBUTES']?$folderInfo[0]['ATTRIBUTES']:$folderInfo[0]['attributes']);
$shortNameParts = explode($retValue['delimiter'], $_folderName); $shortNameParts = explode($retValue['delimiter'], $_folderName);
$retValue['shortName'] = array_pop($shortNameParts); $retValue['shortName'] = array_pop($shortNameParts);
$retValue['displayName'] = $this->encodeFolderName($_folderName); $retValue['displayName'] = $this->encodeFolderName($_folderName);
@ -911,7 +923,7 @@ class mail_bo
} }
if (!($folderInfo instanceof PEAR_Error)) $folderBasicInfo[$this->profileID][$_folderName]=$retValue; 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); 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; 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']; 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); //error_log(__METHOD__.__LINE__.'->'.array2string($_messageUID).','.$_folder.'/'.$this->sessionData['mailbox'].' Option:'.$deleteOptions);
$trashFolder = $this->getTrashFolder(); $trashFolder = $this->getTrashFolder();
$draftFolder = $this->getDraftFolder(); //$GLOBALS['egw_info']['user']['preferences']['felamimail']['draftFolder']; $draftFolder = $this->getDraftFolder(); //$GLOBALS['egw_info']['user']['preferences']['mail']['draftFolder'];
$templateFolder = $this->getTemplateFolder(); //$GLOBALS['egw_info']['user']['preferences']['felamimail']['templateFolder']; $templateFolder = $this->getTemplateFolder(); //$GLOBALS['egw_info']['user']['preferences']['mail']['templateFolder'];
if(($_folder == $trashFolder && $deleteOptions == "move_to_trash") || if(($_folder == $trashFolder && $deleteOptions == "move_to_trash") ||
($_folder == $draftFolder)) { ($_folder == $draftFolder)) {
$deleteOptions = "remove_immediately"; $deleteOptions = "remove_immediately";
@ -2613,10 +2625,124 @@ class mail_bo
if ($_charset===false) $_charset = self::$displayCharset; if ($_charset===false) $_charset = self::$displayCharset;
$_stringORG = $_string; $_stringORG = $_string;
$_string = @htmlentities($_string,ENT_QUOTES,$_charset, false); $_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; 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;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
//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 * Header and Bodystructure stuff
*/ */
@ -2653,6 +2779,599 @@ class mail_bo
return $structure[$this->icServer->ImapServerId][$_folder][$_uid]; 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;amp;','<DIV><BR></DIV>',"<DIV>&nbsp;</DIV>",'<div>&nbsp;</div>'),array('&amp;','<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 * getMessageRawHeader
* get parsed headers from message * 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 * Hook stuff
*/ */

View File

@ -812,7 +812,7 @@ class mail_hooks
// Destination div for folder tree // Destination div for folder tree
$file[] = array( $file[] = array(
'no_lang' => true, 'no_lang' => true,
'text'=>'<span id="tree_target" class="dtree"/>', 'text'=>'<span id="tree_target" class="dtree" style="width:100%;"/>',
'link'=>false, 'link'=>false,
'icon' => false 'icon' => false
); );

View File

@ -25,6 +25,7 @@ class mail_ui
'index' => True, 'index' => True,
'displayHeader' => True, 'displayHeader' => True,
'saveMessage' => True, 'saveMessage' => True,
'vfsSaveMessage' => True,
'TestConnection' => True, 'TestConnection' => True,
); );
@ -504,7 +505,7 @@ class mail_ui
if ($_nodeID) if ($_nodeID)
{ {
$node = self::findNode($out,$_nodeID); $node = self::findNode($out,$_nodeID);
error_log(__METHOD__.__LINE__.array2string($node)); //error_log(__METHOD__.__LINE__.array2string($node));
return $node; return $node;
} }
return ($c?$out:array('id'=>0, 'item'=>array('text'=>'INBOX','tooltip'=>'INBOX'.' '.lang('(not connected)'),'im0'=>'kfm_home.png'))); 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 * @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) * @return array populated named result array (accountID,profileID,folder,msgUID)
*/ */
function splitRowID($_rowID) static function splitRowID($_rowID)
{ {
$res = explode(self::$delimiter,$_rowID); $res = explode(self::$delimiter,$_rowID);
// as a rowID is perceeded by app::, we ignore the first part // as a rowID is perceeded by app::, should be mail!
return array('accountID'=>$res[1], 'profileID'=>$res[2], 'folder'=>base64_decode($res[3]), 'msgUID'=>$res[4]); 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['id'])) $rowID = $_GET['id'];
if(isset($_GET['part'])) $partID = $_GET['part']; if(isset($_GET['part'])) $partID = $_GET['part'];
$hA = $this->splitRowID($rowID); $hA = self::splitRowID($rowID);
$uid = $hA['msgUID']; $uid = $hA['msgUID'];
$mailbox = $hA['folder']; $mailbox = $hA['folder'];
@ -1434,7 +1435,7 @@ unset($query['actions']);
if(isset($_GET['part'])) $partID = $_GET['part']; if(isset($_GET['part'])) $partID = $_GET['part'];
if (isset($_GET['location'])&& ($_GET['location']=='display'||$_GET['location']=='filemanager')) $display = $_GET['location']; if (isset($_GET['location'])&& ($_GET['location']=='display'||$_GET['location']=='filemanager')) $display = $_GET['location'];
$hA = $this->splitRowID($rowID); $hA = self::splitRowID($rowID);
$uid = $hA['msgUID']; $uid = $hA['msgUID'];
$mailbox = $hA['folder']; $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) * 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) * gets the counters and sets the text of a treenode if needed (unread Messages found)
@ -1578,12 +1614,12 @@ unset($query['actions']);
} }
else 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 $folder = $uidA['folder']; // all messages in one set are supposed to be within the same folder
} }
foreach($_messageList['msg'] as $rowID) foreach($_messageList['msg'] as $rowID)
{ {
$hA = $this->splitRowID($rowID); $hA = self::splitRowID($rowID);
$messageList[] = $hA['msgUID']; $messageList[] = $hA['msgUID'];
} }
$this->mail_bo->flagMessages($_flag, ($_messageList=='all' ? 'all':$messageList),$folder); $this->mail_bo->flagMessages($_flag, ($_messageList=='all' ? 'all':$messageList),$folder);
@ -1624,12 +1660,12 @@ unset($query['actions']);
} }
else 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 $folder = $uidA['folder']; // all messages in one set are supposed to be within the same folder
} }
foreach($_messageList['msg'] as $rowID) foreach($_messageList['msg'] as $rowID)
{ {
$hA = $this->splitRowID($rowID); $hA = self::splitRowID($rowID);
$messageList[] = $hA['msgUID']; $messageList[] = $hA['msgUID'];
} }
$this->mail_bo->deleteMessages(($_messageList=='all' ? 'all':$messageList),$folder); $this->mail_bo->deleteMessages(($_messageList=='all' ? 'all':$messageList),$folder);

View File

@ -350,6 +350,78 @@ function mail_mailsource(_action, _elems)
mail_displayHeaderLines(url); 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 * mail_getFormData
* *

View File

@ -1,3 +1,9 @@
textarea
{
font-family: monospace, sans-serif;
font-size: 110%;
}
.defaultProfile { color:#000000; font-weight:bold !important; } .defaultProfile { color:#000000; font-weight:bold !important; }
@ -217,6 +223,9 @@ pre {
color: #666; color: #666;
white-space: nowrap; white-space: nowrap;
} }
.dtree div {
width: 100%;
}
.dtree img { .dtree img {
border: 0px; border: 0px;
vertical-align: middle; vertical-align: middle;
@ -254,12 +263,14 @@ pre {
} }
/* /*
avoid the vertical scrollbar within the sidebox section (triggered by the vertical dimension of the tree) avoid the vertical scrollbar within the sidebox section (triggered by the vertical dimension of the tree)
*/.divSidebox { */
.divSidebox {
overflow: hidden; overflow: hidden;
} }
/* /*
avoid the vertical scrollbar within the actual tablecontainer (of the tree) avoid the vertical scrollbar within the actual tablecontainer (of the tree)
*/ */
.containerTableStyle { .containerTableStyle {
width: 100%;
overflow: hidden; overflow: hidden;
} }