* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
/**
* FeLaMiMail worker class
* -provides backend functionality for all classes in FeLaMiMail
* -provides classes that may be used by other apps too
*/
class felamimail_bo
{
var $public_functions = array
(
'flagMessages' => True,
);
static $debug = false; //true; // sometimes debuging is quite handy, to see things. check with the error log to see results
// define some constants
// message types
var $type = array("text", "multipart", "message", "application", "audio", "image", "video", "other");
/**
* static used to configure tidy - if tidy is loadable, this config is used with tidy to straighten out html, instead of using purifiers tidy mode
*
* @array
*/
static $tidy_config = array('clean'=>true,'output-html'=>true,'join-classes'=>true,'join-styles'=>true,'show-body-only'=>"auto",'word-2000'=>true,'wrap'=>0);
/**
* static used to configure htmLawed, for use with emails
*
* @array
*/
static $htmLawed_config = array('comment'=>1, //remove comments
'make_tag_strict' => 3, // 3 is a new own config value, to indicate that transformation is to be performed, but don't transform font as size transformation of numeric sizes to keywords alters the intended result too much
'keep_bad'=>2, //remove tags but keep element content (4 and 6 keep element content only if text (pcdata) is valid in parent element as per specs, this may lead to textloss if balance is switched on)
'balance'=>1,//turn off tag-balancing (config['balance']=>0). That will not introduce any security risk; only standards-compliant tag nesting check/filtering will be turned off (basic tag-balance will remain; i.e., there won't be any unclosed tag, etc., after filtering)
'direct_list_nest' => 1,
'allow_for_inline' => array('table','li'),//block elements allowed for nesting when only inline is allowed; Example span does not allow block elements as table; table is the only element tested so far
'tidy'=>1,
'elements' => "* -script",
'deny_attribute' => 'on*',
'schemes'=>'href: file, ftp, http, https, mailto; src: cid, data, file, ftp, http, https; *:file, http, https',
'hook_tag' =>"hl_email_tag_transform",
);
/**
* static used define abbrevations for common access rights
*
* @array
*/
static $aclShortCuts = array('' => array('label'=>'none','title'=>'The user has no rights whatsoever.'),
'lrs' => array('label'=>'readable','title'=>'Allows a user to read the contents of the mailbox.'),
'lprs' => array('label'=>'post','title'=>'Allows a user to read the mailbox and post to it through the delivery system by sending mail to the submission address of the mailbox.'),
'ilprs' => array('label'=>'append','title'=>'Allows a user to read the mailbox and append messages to it, either via IMAP or through the delivery system.'),
'cdilprsw' => array('label'=>'write','title'=>'Allows a user to read the maibox, post to it, append messages to it, and delete messages or the mailbox itself. The only right not given is the right to change the ACL of the mailbox.'),
'acdilprsw' => array('label'=>'all','title'=>'The user has all possible rights on the mailbox. This is usually granted to users only on the mailboxes they own.'),
'custom' => array('label'=>'custom','title'=>'User defined combination of rights for the ACL'),
);
/**
* errorMessage
*
* @var string $errorMessage
*/
var $errorMessage;
// message encodings
var $encoding = array("7bit", "8bit", "binary", "base64", "quoted-printable", "other");
static $displayCharset;
/**
* Instance of bopreference
*
* @var bopreferences
*/
var $bopreferences;
/**
* Active preferences
*
* @var array
*/
var $mailPreferences;
// set to true, if php is compiled with multi byte string support
var $mbAvailable = FALSE;
// what type of mimeTypes do we want from the body(text/html, text/plain)
var $htmlOptions;
/**
* Active mimeType
*
* @var string
*/
var $activeMimeType;
var $sessionData;
// the current selected user profile
var $profileID = 0;
/**
* Folders that get automatic created AND get translated to the users language
* their creation is also controlled by users mailpreferences. if set to none / dont use folder
* the folder will not be automatically created. This is controlled in bofelamimail->getFolderObjects
* so changing names here, must include a change of keywords there as well. Since these
* foldernames are subject to translation, keep that in mind too, if you change names here.
* ActiveSync:
* Outbox is needed by Nokia Clients to be able to send Mails
* @var array
*/
static $autoFolders = array('Drafts', 'Templates', 'Sent', 'Trash', 'Junk', 'Outbox');
/**
* Autoload classes from emailadmin, 'til they get autoloading conform names
*
* @param string $class
*/
static function autoload($class)
{
if (strlen($class)<100)
{
if (file_exists($file=EGW_INCLUDE_ROOT.'/emailadmin/inc/class.'.$class.'.inc.php'))
{
include_once($file);
//error_log(__METHOD__."($class) included $file");
}
elseif (file_exists($file=EGW_INCLUDE_ROOT.'/felamimail/inc/class.'.$class.'.inc.php'))
{
include_once($file);
}
else
{
#error_log(__METHOD__."($class) failed!");
}
}
}
/**
* Hold instances by profileID for getInstance() singleton
*
* @var array
*/
private static $instances = array();
/**
* Singleton for felamimail_bo
*
* @param boolean $_restoreSession=true
* @param int $_profileID=0
* @param boolean $_validate=true - flag wether the profileid should be validated or not, if validation is true, you may receive a profile
* not matching the input profileID, if we can not find a profile matching the given ID
* @return object instance of felamimail_bo
*/
public static function getInstance($_restoreSession=true, $_profileID=0, $_validate=true)
{
if ($_profileID == 0)
{
$profileID = emailadmin_bo::getUserDefaultProfileID();
if ($profileID!=$_profileID) $_restoreSession==false;
$_profileID=$profileID;
if (self::$debug) error_log(__METHOD__.__LINE__.' called with profileID==0 using '.$profileID.' instead->'.function_backtrace());
}
if ($_profileID != 0 && $_validate)
{
$profileID = self::validateProfileID($_restoreSession, $_profileID);
if ($profileID != $_profileID)
{
error_log(__METHOD__.__LINE__.' Validation of profile with ID:'.$_profileID.' failed. Using '.$profileID.' instead.');
error_log(__METHOD__.__LINE__.' # Instance='.$GLOBALS['egw_info']['user']['domain'].', User='.$GLOBALS['egw_info']['user']['account_lid']);
$_profileID = $profileID;
$GLOBALS['egw']->preferences->add('felamimail','ActiveProfileID',$_profileID,'user');
// save prefs
$GLOBALS['egw']->preferences->save_repository(true);
egw_cache::setSession('felamimail','activeProfileID',$_profileID);
}
}
//error_log(__METHOD__.__LINE__.' RestoreSession:'.$_restoreSession.' ProfileId:'.$_profileID.' called from:'.function_backtrace());
if (!isset(self::$instances[$_profileID]) || $_restoreSession===false)
{
self::$instances[$_profileID] = new felamimail_bo('utf-8',$_restoreSession,$_profileID);
}
else
{
// make sure the prefs are up to date for the profile to load
$loadfailed = false;
self::$instances[$_profileID]->mailPreferences = self::$instances[$_profileID]->bopreferences->getPreferences(true,$_profileID);
//error_log(__METHOD__.__LINE__." ReRead the Prefs for ProfileID ".$_profileID.' called from:'.function_backtrace());
if (self::$instances[$_profileID]->mailPreferences) {
self::$instances[$_profileID]->icServer = self::$instances[$_profileID]->mailPreferences->getIncomingServer($_profileID);
// if we do not get an icServer object, session restore failed on bopreferences->getPreferences
if (!self::$instances[$_profileID]->icServer) $loadfailed=true;
if ($_profileID != 0) self::$instances[$_profileID]->mailPreferences->setIncomingServer(self::$instances[$_profileID]->icServer,0);
self::$instances[$_profileID]->ogServer = self::$instances[$_profileID]->mailPreferences->getOutgoingServer($_profileID);
if ($_profileID != 0) self::$instances[$_profileID]->mailPreferences->setOutgoingServer(self::$instances[$_profileID]->ogServer,0);
self::$instances[$_profileID]->htmlOptions = self::$instances[$_profileID]->mailPreferences->preferences['htmlOptions'];
}
else
{
$loadfailed=true;
}
if ($loadfailed)
{
error_log(__METHOD__.__LINE__." ReRead of the Prefs for ProfileID ".$_profileID.' failed for icServer; trigger new instance. called from:'.function_backtrace());
// restore session seems to provide an incomplete session
self::$instances[$_profileID] = new felamimail_bo('utf-8',false,$_profileID);
}
}
self::$instances[$_profileID]->profileID = $_profileID;
//if ($_profileID==0); error_log(__METHOD__.__LINE__.' RestoreSession:'.$_restoreSession.' ProfileId:'.$_profileID);
return self::$instances[$_profileID];
}
/**
* unset the private static instances by profileID
*
* @param int $_profileID=0
* @return void
*/
public static function unsetInstance($_profileID=0)
{
if (isset(self::$instances[$_profileID])) unset(self::$instances[$_profileID]);
}
/**
* validate the given profileId to make sure it is valid for the active user
*
* @param boolean $_restoreSession=true - needed to pass on to getInstance
* @param int $_profileID=0
* @return int validated profileID -> either the profileID given, or a valid one
*/
public static function validateProfileID($_restoreSession=true, $_profileID=0)
{
$identities = array();
$mail = felamimail_bo::getInstance($_restoreSession, $_profileID, $validate=false); // we need an instance of felamimail_bo
$selectedID = $mail->getIdentitiesWithAccounts($identities);
if (is_object($mail->mailPreferences)) $activeIdentity =& $mail->mailPreferences->getIdentity($_profileID, true);
// if you use user defined accounts you may want to access the profile defined with the emailadmin available to the user
// as we validate the profile in question and may need to return an emailadminprofile, we fetch this one all the time
$boemailadmin = new emailadmin_bo();
$defaultProfile = $boemailadmin->getUserProfile() ;
//error_log(__METHOD__.__LINE__.array2string($defaultProfile));
$identitys =& $defaultProfile->identities;
$icServers =& $defaultProfile->ic_server;
foreach ($identitys as $tmpkey => $identity)
{
if (empty($icServers[$tmpkey]->host)) continue;
$identities[$identity->id] = $identity->realName.' '.$identity->organization.' <'.$identity->emailAddress.'>';
}
//error_log(__METHOD__.__LINE__.array2string($identities));
if (array_key_exists($_profileID,$identities))
{
// everything seems to be in order self::$profileID REMAINS UNCHANGED
}
else
{
if (array_key_exists($selectedID,$identities))
{
$_profileID = $selectedID;
}
else
{
foreach (array_keys((array)$identities) as $k => $ident)
{
//error_log(__METHOD__.__LINE__.' Testing Identity with ID:'.$ident.' for being provided by emailadmin.');
if ($ident <0) $_profileID = $ident;
}
if (self::$debug) error_log(__METHOD__.__LINE__.' Profile Selected (after trying to fetch DefaultProfile):'.array2string($_profileID));
if (!array_key_exists($_profileID,$identities))
{
// everything failed, try first profile found
$keys = array_keys((array)$identities);
if (count($keys)>0) $_profileID = array_shift($keys);
else $_profileID = 0;
}
}
}
if (self::$debug) error_log(__METHOD__.'::'.__LINE__.' ProfileSelected:'.$_profileID.' -> '.$identities[$_profileID]);
return $_profileID;
}
/**
* Private constructor, use felamimail_bo::getInstance() instead
*
* @param string $_displayCharset='utf-8'
* @param boolean $_restoreSession=true
* @param int $_profileID=0
*/
private function __construct($_displayCharset='utf-8',$_restoreSession=true, $_profileID=0)
{
$this->profileID = $_profileID;
if ($_restoreSession)
{
//error_log(__METHOD__." Session restore ".function_backtrace());
$this->restoreSessionData();
$lv_mailbox = $this->sessionData['mailbox'];
$firstMessage = $this->sessionData['previewMessage'];
}
else
{
$this->restoreSessionData();
$lv_mailbox = $this->sessionData['mailbox'];
$firstMessage = $this->sessionData['previewMessage'];
$this->sessionData = array();
$this->forcePrefReload();
}
//error_log(array2string(array($firstMessage,$lv_mailbox)));
// FIXME: this->foldername seems to be unused
//$this->foldername = $this->sessionData['mailbox'];
$this->accountid = $GLOBALS['egw_info']['user']['account_id'];
$this->bopreferences = CreateObject('felamimail.bopreferences',$_restoreSession);
$this->mailPreferences = $this->bopreferences->getPreferences(true,$this->profileID);
//error_log(__METHOD__.__LINE__." ProfileID ".$this->profileID.' called from:'.function_backtrace());
if ($this->mailPreferences) {
$this->icServer = $this->mailPreferences->getIncomingServer($this->profileID);
if ($this->profileID != 0) $this->mailPreferences->setIncomingServer($this->icServer,0);
$this->ogServer = $this->mailPreferences->getOutgoingServer($this->profileID);
if ($this->profileID != 0) $this->mailPreferences->setOutgoingServer($this->ogServer,0);
$this->htmlOptions = $this->mailPreferences->preferences['htmlOptions'];
if (isset($this->icServer->ImapServerId) && !empty($this->icServer->ImapServerId))
{
$_profileID = $this->profileID = $GLOBALS['egw_info']['user']['preferences']['felamimail']['ActiveProfileID'] = $this->icServer->ImapServerId;
}
}
//_debug_array($this->mailPreferences->preferences);
$this->imapBaseDir = '';
self::$displayCharset = $_displayCharset;
if(function_exists(mb_decode_mimeheader)) {
mb_internal_encoding(self::$displayCharset);
}
// set some defaults
if(empty($this->sessionData))
{
// this should be under user preferences
// sessionData empty
// store active profileID
$this->sessionData['profileID'] = $_profileID;
// no filter active
$this->sessionData['activeFilter'] = "-1";
// default mailbox INBOX
$this->sessionData['mailbox'] = (($lv_mailbox && self::folderExists($lv_mailbox,true)) ? $lv_mailbox : "INBOX");
$this->sessionData['previewMessage'] = ($firstMessage >0 ? $firstMessage : 0);
// default start message
$this->sessionData['startMessage'] = 1;
// default mailbox for preferences pages
$this->sessionData['preferences']['mailbox'] = "INBOX";
$this->sessionData['messageFilter'] = array(
'string' => '',
'type' => 'quick',
'status' => 'any',
);
// default sorting
switch($GLOBALS['egw_info']['user']['preferences']['felamimail']['sortOrder']) {
case 1:
$this->sessionData['sort'] = SORTDATE;
$this->sessionData['sortReverse'] = false;
break;
case 2:
$this->sessionData['sort'] = SORTFROM;
$this->sessionData['sortReverse'] = true;
break;
case 3:
$this->sessionData['sort'] = SORTFROM;
$this->sessionData['sortReverse'] = false;
break;
case 4:
$this->sessionData['sort'] = SORTSUBJECT;
$this->sessionData['sortReverse'] = true;
break;
case 5:
$this->sessionData['sort'] = SORTSUBJECT;
$this->sessionData['sortReverse'] = false;
break;
case 6:
$this->sessionData['sort'] = SORTSIZE;
$this->sessionData['sortReverse'] = true;
break;
case 7:
$this->sessionData['sort'] = SORTSIZE;
$this->sessionData['sortReverse'] = false;
break;
default:
$this->sessionData['sort'] = SORTDATE;
$this->sessionData['sortReverse'] = true;
break;
}
$this->saveSessionData();
}
if (function_exists('mb_convert_encoding')) {
$this->mbAvailable = TRUE;
}
}
/**
* forceEAProfileLoad
* used to force the load of a specific emailadmin profile; we assume administrative use only (as of now)
* @param int $_profile_id must be a value lower than 0 (emailadmin profile)
* @return object instance of felamimail_bo (by reference)
*/
public static function &forceEAProfileLoad($_profile_id)
{
$bofelamimail = felamimail_bo::getInstance(false, $_profile_id,false);
//_debug_array( $_profile_id);
$bofelamimail->mailPreferences = $bofelamimail->bopreferences->getPreferences(false,$_profile_id,'felamimail',$_profile_id);
$bofelamimail->icServer = $bofelamimail->mailPreferences->getIncomingServer($_profile_id);
$bofelamimail->ogServer = $bofelamimail->mailPreferences->getOutgoingServer($_profile_id);
return $bofelamimail;
}
public static function forcePrefReload()
{
// unset the fm_preferences session object, to force the reload/rebuild
$GLOBALS['egw']->session->appsession('fm_preferences','felamimail',serialize(array()));
$GLOBALS['egw']->session->appsession('session_data','emailadmin',serialize(array()));
}
function _getNameSpaces()
{
static $nameSpace;
$foldersNameSpace = array();
$delimiter = $this->getHierarchyDelimiter();
// TODO: cache by $this->icServer->ImapServerId
if (is_null($nameSpace)) $nameSpace = $this->icServer->getNameSpaces();
if (is_array($nameSpace)) {
foreach($nameSpace as $type => $singleNameSpace) {
$prefix_present = false;
if($type == 'personal' && ($singleNameSpace[2]['name'] == '#mh/' || count($nameSpace) == 1) && ($this->folderExists('Mail')||$this->folderExists('INBOX')))
{
$foldersNameSpace[$type]['prefix_present'] = 'forced';
// uw-imap server with mailbox prefix or dovecot maybe
$foldersNameSpace[$type]['prefix'] = ($this->folderExists('Mail')?'Mail':(!empty($singleNameSpace[0]['name'])?$singleNameSpace[0]['name']:''));
}
elseif($type == 'personal' && ($singleNameSpace[2]['name'] == '#mh/' || count($nameSpace) == 1) && $this->folderExists('mail'))
{
$foldersNameSpace[$type]['prefix_present'] = 'forced';
// uw-imap server with mailbox prefix or dovecot maybe
$foldersNameSpace[$type]['prefix'] = 'mail';
} else {
$foldersNameSpace[$type]['prefix_present'] = true;
$foldersNameSpace[$type]['prefix'] = $singleNameSpace[0]['name'];
}
$foldersNameSpace[$type]['delimiter'] = $delimiter;
//echo "############## $type->".print_r($foldersNameSpace[$type],true)." ###################
";
}
}
//error_log(__METHOD__.__LINE__.array2string($foldersNameSpace));
return $foldersNameSpace;
}
function getFolderPrefixFromNamespace($nameSpace, $folderName)
{
foreach($nameSpace as $type => $singleNameSpace)
{
//if (substr($singleNameSpace['prefix'],0,strlen($folderName))==$folderName) return $singleNameSpace['prefix'];
if (substr($folderName,0,strlen($singleNameSpace['prefix']))==$singleNameSpace['prefix']) return $singleNameSpace['prefix'];
}
return "";
}
function setACL($_folderName, $_accountName, $_acl, $_recursive=false)
{
//$_recursive=true;
//error_log(__METHOD__.__LINE__.'-> called with:'."$_folderName, $_accountName, $_acl, $_recursive");
if ( PEAR::isError($this->icServer->setACL($_folderName, $_accountName, $_acl)) ) {
return false;
}
if ($_recursive)
{
$delimiter = $this->getHierarchyDelimiter();
$nameSpace = $this->_getNameSpaces();
$prefix = $this->getFolderPrefixFromNamespace($nameSpace, $_folderName);
//error_log(__METHOD__.__LINE__.'->'."$_folderName, $delimiter, $prefix");
$subFolders = $this->getMailBoxesRecursive($_folderName, $delimiter, $prefix);
//error_log(__METHOD__.__LINE__.' Fetched Subfolders->'.array2string($subFolders));
foreach ($subFolders as $k => $folder)
{
// we do not monitor failure or success on subfolders
if ($folder <> $_folderName) $this->icServer->setACL($folder, $_accountName, $_acl);
}
}
return TRUE;
}
function deleteACL($_folderName, $_accountName, $_recursive=false)
{
//$_recursive=true;
//error_log(__METHOD__.__LINE__." calledv with: $_folderName, $_accountName, $_recursive");
if ( PEAR::isError($this->icServer->deleteACL($_folderName, $_accountName)) ) {
return false;
}
if ($_recursive)
{
$delimiter = $this->getHierarchyDelimiter();
$nameSpace = $this->_getNameSpaces();
$prefix = $this->getFolderPrefixFromNamespace($nameSpace, $_folderName);
//error_log(__METHOD__.__LINE__.'->'."$_folderName, $delimiter, $prefix");
$subFolders = $this->getMailBoxesRecursive($_folderName, $delimiter, $prefix);
//error_log(__METHOD__.__LINE__.' Fetched Subfolders->'.array2string($subFolders));
foreach ($subFolders as $k => $folder)
{
// we do not monitor failure or success on subfolders
if ($folder <> $_folderName) $this->icServer->deleteACL($folder, $_accountName);
}
}
return TRUE;
}
/**
* hook to add account
*
* this function is a wrapper function for emailadmin
*
* @param _hookValues contains the hook values as array
* @return nothing
*/
function addAccount($_hookValues)
{
if ($this->mailPreferences) {
$icServer = $this->mailPreferences->getIncomingServer($this->profileID);
if(($icServer instanceof defaultimap)) {
// if not connected, try opening an admin connection
if (!$icServer->_connected) $this->openConnection($this->profileID,true);
$icServer->addAccount($_hookValues);
if ($icServer->_connected) $this->closeConnection(); // close connection afterwards
}
$ogServer = $this->mailPreferences->getOutgoingServer($this->profileID);
if(($ogServer instanceof emailadmin_smtp)) {
$ogServer->addAccount($_hookValues);
}
}
}
/**
* save a message in folder
* throws exception on failure
* @todo set flags again
*
* @param string _folderName the foldername
* @param string _header the header of the message
* @param string _body the body of the message
* @param string _flags the imap flags to set for the saved message
*
* @return the id of the message appended or exception
*/
function appendMessage($_folderName, $_header, $_body, $_flags)
{
$header = ltrim(str_replace("\n","\r\n",$_header));
$body = str_replace("\n","\r\n",$_body);
$messageid = $this->icServer->appendMessage("$header"."$body", $_folderName, $_flags);
if ( PEAR::isError($messageid)) {
if (self::$debug) error_log("Could not append Message:".print_r($messageid->message,true));
throw new egw_exception_wrong_userinput(lang("Could not append Message:".array2string($messageid->message)));
//return false;
}
//error_log(__METHOD__.__LINE__.' appended UID:'.$messageid);
//$messageid = true; // for debug reasons only
if ($messageid === true) // try to figure out the message uid
{
$list = $this->getHeaders($_folderName, $_startMessage=1, $_numberOfMessages=1, $_sort='INTERNALDATE', $_reverse=true, $_filter=array(),$_thisUIDOnly=null, $_cacheResult=false);
if ($list)
{
if (self::$debug) error_log(__METHOD__.__LINE__.' MessageUid:'.$messageid.' but found:'.array2string($list));
$messageid = $list['header'][0]['uid'];
}
}
return $messageid;
}
function closeConnection() {
//if ($icServer->_connected) error_log(__METHOD__.__LINE__.' disconnect from Server');
if ($icServer->_connected) $this->icServer->disconnect();
}
/**
* remove any messages which are marked as deleted or
* remove any messages from the trashfolder
*
* @param string _folderName the foldername
* @return nothing
*/
function compressFolder($_folderName = false)
{
$folderName = ($_folderName ? $_folderName : $this->sessionData['mailbox']);
$deleteOptions = $GLOBALS['egw_info']['user']['preferences']['felamimail']['deleteOptions'];
$trashFolder = $this->mailPreferences->preferences['trashFolder']; //$GLOBALS['egw_info']['user']['preferences']['felamimail']['trashFolder'];
$this->icServer->selectMailbox($folderName);
if($folderName == $trashFolder && $deleteOptions == "move_to_trash") {
$this->icServer->deleteMessages('1:*');
$this->icServer->expunge();
} else {
$this->icServer->expunge();
}
}
/**
* create a new folder under given parent folder
*
* @param string _parent the parent foldername
* @param string _folderName the new foldername
* @param bool _subscribe subscribe to the new folder
*
* @return mixed name of the newly created folder or false on error
*/
function createFolder($_parent, $_folderName, $_subscribe=false)
{
if (self::$debug) error_log(__METHOD__.__LINE__."->"."$_parent, $_folderName, $_subscribe");
$parent = $this->_encodeFolderName($_parent);
$folderName = $this->_encodeFolderName($_folderName);
if(empty($parent)) {
$newFolderName = $folderName;
} else {
$HierarchyDelimiter = $this->getHierarchyDelimiter();
$newFolderName = $parent . $HierarchyDelimiter . $folderName;
}
if (self::$debug) error_log(__METHOD__.__LINE__.'->'.$newFolderName);
if (self::folderExists($newFolderName,true))
{
error_log(__METHOD__.__LINE__." Folder $newFolderName already exists.");
return $newFolderName;
}
$rv = $this->icServer->createMailbox($newFolderName);
if ( PEAR::isError($rv ) ) {
error_log(__METHOD__.__LINE__.' create Folder '.$newFolderName.'->'.$rv->message.' Namespace:'.array2string($this->icServer->getNameSpaces()));
return false;
}
$srv = $this->icServer->subscribeMailbox($newFolderName);
if ( PEAR::isError($srv ) ) {
error_log(__METHOD__.__LINE__.' subscribe to new folder '.$newFolderName.'->'.$srv->message);
return false;
}
return $newFolderName;
}
function createIMAPFilter($_folder, $_criterias)
{
$all = 'ALL UNDELETED'; //'ALL'
//_debug_array($_criterias);
if (self::$debug) error_log(__METHOD__.__LINE__.' Criterias:'.(!is_array($_criterias)?" none -> returning $all":array2string($_criterias)));
if(!is_array($_criterias)) {
return $all;
}
#error_log(print_r($_criterias, true));
$imapFilter = '';
#foreach($_criterias as $criteria => $parameter) {
if(!empty($_criterias['string'])) {
$criteria = strtoupper($_criterias['type']);
switch ($criteria) {
case 'QUICK':
if($this->isSentFolder($_folder)) {
$imapFilter .= 'OR SUBJECT "'. $_criterias['string'] .'" TO "'. $_criterias['string'] .'" ';
} else {
$imapFilter .= 'OR SUBJECT "'. $_criterias['string'] .'" FROM "'. $_criterias['string'] .'" ';
}
break;
case 'BCC':
case 'BODY':
case 'CC':
case 'FROM':
case 'KEYWORD':
case 'SUBJECT':
case 'TEXT':
case 'TO':
$imapFilter .= $criteria .' "'. $_criterias['string'] .'" ';
break;
case 'SINCE':
case 'BEFORE':
case 'ON':
$imapFilter .= $criteria .' '. $_criterias['string'].' ';
break;
}
}
foreach((array)$_criterias['status'] as $k => $criteria) {
$criteria = strtoupper($criteria);
switch ($criteria) {
case 'ANSWERED':
case 'DELETED':
case 'FLAGGED':
case 'NEW':
case 'OLD':
case 'RECENT':
case 'SEEN':
case 'UNANSWERED':
case 'UNDELETED':
case 'UNFLAGGED':
case 'UNSEEN':
$imapFilter .= $criteria .' ';
break;
case 'KEYWORD1':
case 'KEYWORD2':
case 'KEYWORD3':
case 'KEYWORD4':
case 'KEYWORD5':
$imapFilter .= "KEYWORD ".'$label'.substr(trim($criteria),strlen('KEYWORD')).' ';
break;
}
}
if (isset($_criterias['range']) && !empty($_criterias['range']))
{
$imapFilter .= $_criterias['range'].' ';
}
if (self::$debug) error_log(__METHOD__.__LINE__." Filter: ".($imapFilter?$imapFilter:$all));
if($imapFilter == '') {
return $all;
} else {
return trim($imapFilter);
#return 'CHARSET '. strtoupper(self::$displayCharset) .' '. trim($imapFilter);
}
}
/**
* convert a mailboxname from displaycharset to urf7-imap
*
* @param string _folderName the foldername
*
* @return string the converted foldername
*/
function decodeFolderName($_folderName)
{
return translation::convert($_folderName, self::$displayCharset, 'UTF7-IMAP');
}
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;
}
}
/**
* decode header (or envelope information)
* if array given, note that only values will be converted
* @param mixed $_string input to be converted, if array call decode_header recursively on each value
* @return mixed - based on the input type
*/
static function decode_header($_string)
{
if (is_array($_string))
{
foreach($_string as $k=>$v)
{
$_string[$k] = self::decode_header($v);
}
return $_string;
}
else
{
return translation::decodeMailHeader($_string,self::$displayCharset);
}
}
function decode_subject($_string,$decode=true)
{
#$string = $_string;
if($_string=='NIL')
{
return 'No Subject';
}
if ($decode) $_string = self::decode_header($_string);
return $_string;
}
/**
* decodes winmail.dat attachments
*
* @param int $_uid
* @param string $_partID
* @param int $_filenumber
* @return array
*/
function decode_winmail( $_uid, $_partID, $_filenumber=0 )
{
$attachment = $this->getAttachment( $_uid, $_partID );
$dirname = $this->accountid.'_'.$this->profileID.'_'.$this->sessionData['mailbox'].'_'.$_uid.'_'.$_partID;
if (self::$debug) error_log(__METHOD__.__LINE__.' Dirname:'.$dirname);
$dirname = md5($dirname);
$dir = $GLOBALS['egw_info']['server']['temp_dir']."/fmail_winmail/$dirname";
if (self::$debug) error_log(__METHOD__.__LINE__.' Dir to save winmail.dat to:'.$dir);
$mime = CreateObject('phpgwapi.mime_magic');
if ( $attachment['type'] == 'APPLICATION/MS-TNEF' && $attachment['filename'] == 'winmail.dat' )
{
// decode winmail.dat
if ( !file_exists( "$dir/winmail.dat" ) )
{
@mkdir( $dir, 0700, true );
file_put_contents( "$dir/winmail.dat", $attachment['attachment'] );
}
//if (self::$debug) unset($attachment['attachment']);
if (self::$debug) error_log(__METHOD__.__LINE__." Saving Attachment to $dir. ->".array2string($attachment));
if (file_exists('/usr/bin/tnef'))
{
exec( "cd $dir && /usr/bin/tnef --save-body --overwrite -C $dir -f ./winmail.dat" );
}
elseif (exec("which tnef")) // use tnef if exsting, as it gives better results..
{
exec( "cd $dir && tnef --save-body --overwrite -C $dir -f ./winmail.dat" );
}
elseif (exec("which ytnef"))
{
exec( "cd $dir && ytnef -f . winmail.dat" );
}
// list contents
$files = scandir( $dir );
foreach ( $files as $num => $file )
{
if ( filetype( "$dir/$file" ) != 'file' || $file == 'winmail.dat' ) continue;
if ( $_filenumber > 0 && $_filenumber != $num ) continue;
$type = $mime->filename2mime($file);
$attachments[] = array(
'is_winmail' => $num,
'name' => self::decode_header($file),
'size' => filesize( "$dir/$file"),
'partID' => $_partID,
'mimeType' => $type,
'type' => $type,
'attachment' => $_filenumber > 0 ? file_get_contents("$dir/$file") : '',
);
unlink($dir."/".$file);
}
if (file_exists($dir."/winmail.dat")) unlink($dir."/winmail.dat");
if (file_exists($dir)) @rmdir($dir);
return $_filenumber > 0 ? $attachments[0] : $attachments;
}
return false;
}
function deleteAccount($_hookValues)
{
if ($this->mailPreferences) {
$icServer = $this->mailPreferences->getIncomingServer($this->profileID);
if(($icServer instanceof defaultimap)) {
//try to connect with admin rights, when not connected
if (!$icServer->_connected) $this->openConnection($this->profileID,true);
$icServer->deleteAccount($_hookValues);
if ($icServer->_connected) $this->closeConnection(); // close connection
}
$ogServer = $this->mailPreferences->getOutgoingServer($this->profileID);
if(($ogServer instanceof emailadmin_smtp)) {
$ogServer->deleteAccount($_hookValues);
}
}
}
/**
* delete a existing folder
*
* @param string _folderName the name of the folder to be deleted
*
* @return bool true on success, false on failure
*/
function deleteFolder($_folderName)
{
$folderName = $this->_encodeFolderName($_folderName);
$this->icServer->unsubscribeMailbox($folderName);
if ( PEAR::isError($this->icServer->deleteMailbox($folderName)) ) {
return false;
}
return true;
}
function deleteMessages($_messageUID, $_folder=NULL, $_forceDeleteMethod='no')
{
//error_log(__METHOD__.__LINE__.'->'.array2string($_messageUID).','.$_folder);
$msglist = '';
$oldMailbox = '';
if (is_null($_folder) || empty($_folder)) $_folder = $this->sessionData['mailbox'];
if(!is_array($_messageUID) || count($_messageUID) === 0)
{
if ($_messageUID=='all')
{
$_messageUID= null;
}
else
{
if (self::$debug) error_log(__METHOD__." no messages Message(s): ".implode(',',$_messageUID));
return false;
}
}
$deleteOptions = $_forceDeleteMethod; // use forceDeleteMethod if not "no", or unknown method
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->mailPreferences->preferences['trashFolder'];
$draftFolder = $this->mailPreferences->preferences['draftFolder']; //$GLOBALS['egw_info']['user']['preferences']['felamimail']['draftFolder'];
$templateFolder = $this->mailPreferences->preferences['templateFolder']; //$GLOBALS['egw_info']['user']['preferences']['felamimail']['templateFolder'];
if(($_folder == $trashFolder && $deleteOptions == "move_to_trash") ||
($_folder == $draftFolder)) {
$deleteOptions = "remove_immediately";
}
if($this->icServer->getCurrentMailbox() != $_folder) {
$oldMailbox = $this->icServer->getCurrentMailbox();
$this->icServer->selectMailbox($_folder);
}
$updateCache = false;
switch($deleteOptions) {
case "move_to_trash":
$updateCache = true;
if(!empty($trashFolder)) {
if (self::$debug) error_log(implode(' : ', $_messageUID));
if (self::$debug) error_log("$trashFolder <= ". $this->sessionData['mailbox']);
// copy messages
$retValue = $this->icServer->copyMessages($trashFolder, $_messageUID, $_folder, true);
if ( PEAR::isError($retValue) ) {
if (self::$debug) error_log(__METHOD__." failed to copy Message(s) to $trashFolder: ".implode(',',$_messageUID));
throw new egw_exception("failed to copy Message(s) to $trashFolder: ".implode(',',$_messageUID).' due to:'.array2string($retValue->message));
return false;
}
// mark messages as deleted
$retValue = $this->icServer->deleteMessages($_messageUID, true);
if ( PEAR::isError($retValue)) {
if (self::$debug) error_log(__METHOD__." failed to delete Message(s): ".implode(',',$_messageUID).' due to:'.$retValue->message);
throw new egw_exception("failed to delete Message(s): ".implode(',',$_messageUID).' due to:'.array2string($retValue->message));
return false;
}
// delete the messages finaly
$rv = $this->icServer->expunge();
if ( PEAR::isError($rv)) error_log(__METHOD__." failed to expunge Message(s) from Folder: ".$_folder.' due to:'.$rv->message);
}
break;
case "mark_as_deleted":
// mark messages as deleted
foreach((array)$_messageUID as $key =>$uid)
{
//flag messages, that are flagged for deletion as seen too
$this->flagMessages('read', $uid, $_folder);
$flags = $this->getFlags($uid);
//error_log(__METHOD__.__LINE__.array2string($flags));
if (strpos( array2string($flags),'Deleted')!==false) $undelete[] = $uid;
unset($flags);
}
$retValue = PEAR::isError($this->icServer->deleteMessages($_messageUID, true));
foreach((array)$undelete as $key =>$uid)
{
$this->flagMessages('undelete', $uid, $_folder);
}
if ( PEAR::isError($retValue)) {
if (self::$debug) error_log(__METHOD__." failed to mark as deleted for Message(s): ".implode(',',$_messageUID));
throw new egw_exception("failed to mark as deleted for Message(s): ".implode(',',$_messageUID).' due to:'.array2string($retValue->message));
return false;
}
break;
case "remove_immediately":
$updateCache = true;
// mark messages as deleted
$retValue = $this->icServer->deleteMessages($_messageUID, true);
if ( PEAR::isError($retValue)) {
if (self::$debug) error_log(__METHOD__." failed to remove immediately Message(s): ".implode(',',$_messageUID));
throw new egw_exception("failed to remove immediately Message(s): ".implode(',',$_messageUID).' due to:'.array2string($retValue->message));
return false;
}
// delete the messages finaly
$this->icServer->expunge();
break;
}
if ($updateCache)
{
$structure = egw_cache::getCache(egw_cache::INSTANCE,'email','structureCache'.trim($GLOBALS['egw_info']['user']['account_id']),$callback=null,$callback_params=array(),$expiration=60*60*1);
$cachemodified = false;
foreach ((array)$_messageUID as $k => $_uid)
{
if (isset($structure[$this->icServer->ImapServerId][$_folder][$_uid]) || $_uid=='all')
{
$cachemodified = true;
if ($_uid=='all')
unset($structure[$this->icServer->ImapServerId][$_folder]);
else
unset($structure[$this->icServer->ImapServerId][$_folder][$_uid]);
}
}
if ($cachemodified) egw_cache::setCache(egw_cache::INSTANCE,'email','structureCache'.trim($GLOBALS['egw_info']['user']['account_id']),$structure,$expiration=60*60*1);
}
if($oldMailbox != '') {
$this->icServer->selectMailbox($oldMailbox);
}
return true;
}
/**
* convert a mailboxname from utf7-imap to displaycharset
*
* @param string _folderName the foldername
*
* @return string the converted string
*/
function encodeFolderName($_folderName)
{
return translation::convert($_folderName, 'UTF7-IMAP', self::$displayCharset);
}
# function encodeHeader($_string, $_encoding='q')
# {
# switch($_encoding) {
# case "q":
# if(!preg_match("/[\x80-\xFF]/",$_string)) {
# // nothing to quote, only 7 bit ascii
# return $_string;
# }
#
# $string = imap_8bit($_string);
# $stringParts = explode("=\r\n",$string);
# while(list($key,$value) = each($stringParts)) {
# if(!empty($retString)) $retString .= " ";
# $value = str_replace(" ","_",$value);
# // imap_8bit does not convert "?"
# // it does not need, but it should
# $value = str_replace("?","=3F",$value);
# $retString .= "=?".strtoupper(self::$displayCharset). "?Q?". $value. "?=";
# }
# #exit;
# return $retString;
# break;
# default:
# return $_string;
# }
# }
function getFlags ($_messageUID) {
$flags = $this->icServer->getFlags($_messageUID, true);
if (PEAR::isError($flags)) {
error_log(__METHOD__.__LINE__.'Failed to retrieve Flags for Messages with UID(s)'.array2string($_messageUID).' Server returned:'.$flags->message);
return null;
}
return $flags;
}
function getNotifyFlags ($_messageUID, $flags=null)
{
if($flags===null) $flags = $this->icServer->getFlags($_messageUID, true);
if (self::$debug) error_log(__METHOD__.$_messageUID.' Flags:'.array2string($flags));
if (PEAR::isError($flags)) {
return null;
}
if ( stripos( array2string($flags),'MDNSent')!==false)
return true;
if ( stripos( array2string($flags),'MDNnotSent')!==false)
return false;
return null;
}
/**
* flag a Message
*
* @param string _flag (readable name)
* @param mixed array/string _messageUID array of ids to flag, or 'all'
* @param string _folder foldername
*
* @todo handle handle icserver->setFlags returnValue
*
* @return bool true, as we do not handle icserver->setFlags returnValue
*/
function flagMessages($_flag, $_messageUID,$_folder=NULL)
{
//error_log(__METHOD__.__LINE__.'->' .$_flag." ".array2string($_messageUID).",$_folder /".$this->sessionData['mailbox']);
if(!is_array($_messageUID)) {
#return false;
if ($_messageUID=='all')
{
//all is an allowed value to be passed
}
else
{
$_messageUID=array($_messageUID);
}
}
$this->icServer->selectMailbox(($_folder?$_folder:$this->sessionData['mailbox']));
switch($_flag) {
case "undelete":
$ret = $this->icServer->setFlags($_messageUID, '\\Deleted', 'remove', true);
break;
case "flagged":
$ret = $this->icServer->setFlags($_messageUID, '\\Flagged', 'add', true);
break;
case "read":
$ret = $this->icServer->setFlags($_messageUID, '\\Seen', 'add', true);
break;
case "forwarded":
$ret = $this->icServer->setFlags($_messageUID, '$Forwarded', 'add', true);
case "answered":
$ret = $this->icServer->setFlags($_messageUID, '\\Answered', 'add', true);
break;
case "unflagged":
$ret = $this->icServer->setFlags($_messageUID, '\\Flagged', 'remove', true);
break;
case "unread":
$ret = $this->icServer->setFlags($_messageUID, '\\Seen', 'remove', true);
$ret = $this->icServer->setFlags($_messageUID, '\\Answered', 'remove', true);
$ret = $this->icServer->setFlags($_messageUID, '$Forwarded', 'remove', true);
break;
case "mdnsent":
$ret = $this->icServer->setFlags($_messageUID, 'MDNSent', 'add', true);
break;
case "mdnnotsent":
$ret = $this->icServer->setFlags($_messageUID, 'MDNnotSent', 'add', true);
break;
case "label1":
$ret = $this->icServer->setFlags($_messageUID, '$label1', 'add', true);
break;
case "unlabel1":
$this->icServer->setFlags($_messageUID, '$label1', 'remove', true);
break;
case "label2":
$ret = $this->icServer->setFlags($_messageUID, '$label2', 'add', true);
break;
case "unlabel2":
$ret = $this->icServer->setFlags($_messageUID, '$label2', 'remove', true);
break;
case "label3":
$ret = $this->icServer->setFlags($_messageUID, '$label3', 'add', true);
break;
case "unlabel3":
$ret = $this->icServer->setFlags($_messageUID, '$label3', 'remove', true);
break;
case "label4":
$ret = $this->icServer->setFlags($_messageUID, '$label4', 'add', true);
break;
case "unlabel4":
$ret = $this->icServer->setFlags($_messageUID, '$label4', 'remove', true);
break;
case "label5":
$ret = $this->icServer->setFlags($_messageUID, '$label5', 'add', true);
break;
case "unlabel5":
$ret = $this->icServer->setFlags($_messageUID, '$label5', 'remove', true);
break;
}
if (PEAR::isError($ret))
{
if (stripos($ret->message,'Too long argument'))
{
$c = count($_messageUID);
$h =ceil($c/2);
error_log(__METHOD__.__LINE__.$ret->message." $c messages given for flagging. Trying with chunks of $h");
$this->flagMessages($_flag, array_slice($_messageUID,0,$h),($_folder?$_folder:$this->sessionData['mailbox']));
$this->flagMessages($_flag, array_slice($_messageUID,$h),($_folder?$_folder:$this->sessionData['mailbox']));
}
}
$this->sessionData['folderStatus'][$this->profileID][$this->sessionData['mailbox']]['uidValidity'] = 0;
$this->saveSessionData();
//error_log(__METHOD__.__LINE__.'->' .$_flag." ".array2string($_messageUID).",".($_folder?$_folder:$this->sessionData['mailbox']));
return true; // as we do not catch/examine setFlags returnValue
}
function _getStatus($folderName,$ignoreStatusCache=false)
{
static $folderStatus;
if (!$ignoreStatusCache && isset($folderStatus[$this->icServer->ImapServerId][$folderName]))
{
//error_log(__METHOD__.__LINE__.' Using cache for status on Server:'.$this->icServer->ImapServerId.' for folder:'.$folderName.'->'.array2string($folderStatus[$this->icServer->ImapServerId][$folderName]));
return $folderStatus[$this->icServer->ImapServerId][$folderName];
}
$folderStatus[$this->icServer->ImapServerId][$folderName] = $this->icServer->getStatus($folderName);
return $folderStatus[$this->icServer->ImapServerId][$folderName];
}
function _getStructure($_uid, $byUid=true, $_ignoreCache=false, $_folder = '')
{
static $structure;
if (empty($_folder)) $_folder = ($this->sessionData['mailbox']? $this->sessionData['mailbox'] : $this->icServer->getCurrentMailbox());
//error_log(__METHOD__.__LINE__.'User:'.trim($GLOBALS['egw_info']['user']['account_id'])." UID: $_uid, ".$this->icServer->ImapServerId.','.$_folder);
if (is_null($structure)) $structure = egw_cache::getCache(egw_cache::INSTANCE,'email','structureCache'.trim($GLOBALS['egw_info']['user']['account_id']),$callback=null,$callback_params=array(),$expiration=60*60*1);
//error_log(__METHOD__.__LINE__." UID: $_uid, ".$this->icServer->ImapServerId.','.$_folder.'->'.array2string(array_keys($structure)));
if (isset($structure[$this->icServer->ImapServerId]) && !empty($structure[$this->icServer->ImapServerId]) &&
isset($structure[$this->icServer->ImapServerId][$_folder]) && !empty($structure[$this->icServer->ImapServerId][$_folder]) &&
isset($structure[$this->icServer->ImapServerId][$_folder][$_uid]) && !empty($structure[$this->icServer->ImapServerId][$_folder][$_uid]))
{
if ($_ignoreCache===false)
{
//error_log(__METHOD__.__LINE__.' Using cache for structure on Server:'.$this->icServer->ImapServerId.' for uid:'.$_uid." in Folder:".$_folder.'->'.array2string($structure[$this->icServer->ImapServerId][$_folder][$_uid]));
return $structure[$this->icServer->ImapServerId][$_folder][$_uid];
}
}
$structure[$this->icServer->ImapServerId][$_folder][$_uid] = $this->icServer->getStructure($_uid, $byUid);
egw_cache::setCache(egw_cache::INSTANCE,'email','structureCache'.trim($GLOBALS['egw_info']['user']['account_id']),$structure,$expiration=60*60*1);
//error_log(__METHOD__.__LINE__.' Using query for structure on Server:'.$this->icServer->ImapServerId.' for uid:'.$_uid." in Folder:".$_folder.'->'.array2string($structure[$this->icServer->ImapServerId][$_folder][$_uid]));
return $structure[$this->icServer->ImapServerId][$_folder][$_uid];
}
function _getSubStructure($_structure, $_partID)
{
$tempID = '';
$structure = $_structure;
if (empty($_partID)) $_partID=1;
$imapPartIDs = explode('.',$_partID);
#error_log(print_r($structure,true));
#error_log(print_r($_partID,true));
if($_partID != 1) {
foreach($imapPartIDs as $imapPartID) {
if(!empty($tempID)) {
$tempID .= '.';
}
$tempID .= $imapPartID;
#error_log(print_r( "TEMPID: $tempID
",true));
//_debug_array($structure);
if($structure->subParts[$tempID]->type == 'MESSAGE' && $structure->subParts[$tempID]->subType == 'RFC822' &&
count($structure->subParts[$tempID]->subParts) == 1 &&
$structure->subParts[$tempID]->subParts[$tempID]->type == 'MULTIPART' &&
($structure->subParts[$tempID]->subParts[$tempID]->subType == 'MIXED' ||
$structure->subParts[$tempID]->subParts[$tempID]->subType == 'ALTERNATIVE' ||
$structure->subParts[$tempID]->subParts[$tempID]->subType == 'RELATED' ||
$structure->subParts[$tempID]->subParts[$tempID]->subType == 'REPORT'))
{
$structure = $structure->subParts[$tempID]->subParts[$tempID];
} else {
$structure = $structure->subParts[$tempID];
}
}
}
if($structure->partID != $_partID) {
foreach($imapPartIDs as $imapPartID) {
if(!empty($tempID)) {
$tempID .= '.';
}
$tempID .= $imapPartID;
//print "TEMPID: $tempID
";
//_debug_array($structure);
if($structure->subParts[$tempID]->type == 'MESSAGE' && $structure->subParts[$tempID]->subType == 'RFC822' &&
count($structure->subParts[$tempID]->subParts) == 1 &&
$structure->subParts[$tempID]->subParts[$tempID]->type == 'MULTIPART' &&
($structure->subParts[$tempID]->subParts[$tempID]->subType == 'MIXED' ||
$structure->subParts[$tempID]->subParts[$tempID]->subType == 'ALTERNATIVE' ||
$structure->subParts[$tempID]->subParts[$tempID]->subType == 'RELATED' ||
$structure->subParts[$tempID]->subParts[$tempID]->subType == 'REPORT')) {
$structure = $structure->subParts[$tempID]->subParts[$tempID];
} else {
$structure = $structure->subParts[$tempID];
}
}
if($structure->partID != $_partID) {
error_log(__METHOD__."(". __LINE__ .") partID's don't match");
return false;
}
}
return $structure;
}
/*
* 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);
}
static function getCleanHTML(&$_html, $usepurify = false, $cleanTags=true)
{
// remove CRLF and TAB as it is of no use in HTML.
// but they matter in
, 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('&','',"",'','','',' '),array('&','
','
','
','','',''),$_html); //$_html = str_replace(array('&'),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,'')!==false) self::replaceTagsCompletley($_html,'!\[if','',false); // Strip out stuff in ifs if (stripos($_html,'!--[if')!==false && stripos($_html,'')!==false) self::replaceTagsCompletley($_html,'!--\[if','',false); // Strip out stuff in ifs //error_log($_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']['felamimail']['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('`( ]*>)(.+?)(