| \/>))*\s*<\/div>/sU', $message, $possibleHeaders, PREG_OFFSET_CAPTURE );
if ( count( $possibleHeaders ) )
{
foreach ( array_reverse( $possibleHeaders[0] ) as $header )
{
if ( $header[1] < $matches[0][1] and mb_strpos( mb_substr( $message, $header[1], $matches[0][1] - $header[1] ), "\n" ) === FALSE )
{
$matches[0][1] = $header[1];
break;
}
}
}
preg_match( '/
]*?quote[^>]*?[\'"]>(.*?):(
| \/>))?\s*
/s', $message, $header, PREG_OFFSET_CAPTURE );
if( !empty($header) AND $header[1][1] < $matches[0][1] )
{
$matches[0][1] = $header[1][1];
}
/* Now take everything between these positions and move into the quoted content. substr() rather than mb_substr() because the regex we used to get the offset isn't multibyte aware */
$quote = \substr( $message, $matches[0][1], ( $_lastClosingBlockquote - $matches[0][1] ) );
/* And finally, remove the quoted stuff from our email message. substr() rather than mb_substr() because the regex we used to get the offset isn't multibyte aware */
$message = \substr( $message, 0, $matches[0][1] ) . mb_substr( $message, $_lastClosingBlockquote );
}
}
/* Make sure each section is valid HTML */
$body = $message;
if ( $quote )
{
/* Because we have already parsed the body we have to swap these back otherwise HTMLPurifier will think they're invalid
HTML. The reparsing we do below will put them back automatically. */
$body = str_replace( '<___base_url___>', '{___base_url___}', $body );
$quote = str_replace( '<___base_url___>', '{___base_url___}', $quote );
/* Parse */
$body = \IPS\Text\Parser::parseStatic( $body, FALSE, NULL, \IPS\Member::load( $this->from, 'email' ) );
$quote = \IPS\Text\Parser::parseStatic( $quote, FALSE, NULL, \IPS\Member::load( $this->from, 'email' ) );
}
/* Return */
return $quote;
}
/* !Routing */
/**
* Route the email and pass off to the appropriate handler
*
* @return void
*/
public function route()
{
/* Ignore auto-responder messages */
if( $this->isAutoreply() )
{
return;
}
/* Initialize some vars */
$routed = FALSE;
/* Get our filter rules from the database */
foreach ( \IPS\Db::i()->select( '*', 'core_incoming_emails' ) as $row )
{
/* Reset some vars */
$analyze = NULL;
$match = FALSE;
/* Field to check */
switch ( $row['rule_criteria_field'] )
{
case 'to':
$analyse = implode( ',', $this->to );
break;
case 'from':
$analyse = $this->from;
break;
case 'sbjt':
$analyse = $this->subject;
break;
case 'body':
$analyse = $this->message;
break;
}
/* Now check if we match the supplied rule */
switch ( $row['rule_criteria_type'] )
{
case 'ctns':
$match = (bool) ( mb_strpos( $analyse, $row['rule_criteria_value'] ) !== FALSE );
break;
case 'eqls':
if ( mb_strpos( $analyse, ',' ) !== FALSE )
{
$match = (bool) in_array( $analyse, explode( ',', $analyse ) );
}
else
{
$match = (bool) ( $analyse == $row['rule_criteria_value'] );
}
break;
case 'regx':
$match = (bool) ( preg_match( "/{$row['rule_criteria_value']}/", $analyse ) == 1 );
break;
}
/* Do we have a match? */
if ( $match === TRUE )
{
$routed = TRUE;
break;
}
}
/* If we are still here, check each app to see if it wants to handle this unrouted incoming email */
if ( !$routed )
{
/* Loop over all apps that have an incoming email extension */
foreach ( \IPS\Application::appsWithExtension( 'core', 'IncomingEmail', FALSE ) as $dir => $app )
{
/* Get all IncomingEmail extension classes for the app */
$extensions = $app->extensions( 'core', 'IncomingEmail' );
if( count( $extensions ) )
{
/* Loop over the extensions */
foreach( $extensions as $_instance )
{
/* And if it returns true, the unrouted email has now been handled. We can break. */
if( $routed = $_instance->process( $this ) )
{
break;
}
}
}
}
}
/* If we are still here, send an "unrouted email" email to the sender */
if ( !$routed )
{
if ( \IPS\Email::hasTemplate( 'core', 'unrouted' ) )
{
\IPS\Email::buildFromTemplate( 'core', 'unrouted', $this )->send( $this->from );
}
}
}
/**
* Is this an auto-reply? Try to detect to prevent auto-reply loops.
*
* @return bool
* @link https://github.com/opennorth/multi_mail/wiki/Detecting-autoresponders
*/
protected function isAutoreply()
{
/* RFC http://tools.ietf.org/html/rfc3834 */
if( !empty( $this->headers['auto-submitted'] ) AND mb_strtolower( $this->headers['auto-submitted'] ) != 'no' )
{
return TRUE;
}
/* If any of these headers are present with any values, ignore the email */
if( !empty( $this->headers['x-auto-response-suppress'] ) OR
!empty( $this->headers['x-autorespond'] ) OR
!empty( $this->headers['x-autoreply'] ) OR
!empty( $this->headers['x-autoreply-From'] ) OR
!empty( $this->headers['x-mail-autoreply'] )
)
{
return TRUE;
}
/* Now we check for a null return-path (which is considered the "proper" way to prevent auto-responses) */
if( !empty( $this->headers['return-path'] ) AND $this->headers['return-path'] == '<>' )
{
return TRUE;
}
/* Now check for specific headers with specific values */
if( !empty( $this->headers['x-autogenerated'] ) AND in_array( mb_strtolower( $this->headers['x-autogenerated'] ), array( 'forward', 'group', 'letter', 'mirror', 'redirect', 'reply' ) ) )
{
return TRUE;
}
if( !empty( $this->headers['precedence'] ) AND in_array( mb_strtolower( $this->headers['precedence'] ), array( 'auto_reply', 'list', 'bulk' ) ) )
{
return TRUE;
}
if( !empty( $this->headers['x-precedence'] ) AND in_array( mb_strtolower( $this->headers['x-precedence'] ), array( 'auto_reply', 'list', 'bulk' ) ) )
{
return TRUE;
}
if( !empty( $this->headers['x-fc-machinegenerated'] ) AND mb_strtolower( $this->headers['x-fc-machinegenerated'] ) == 'true' )
{
return TRUE;
}
if( !empty( $this->headers['x-post-messageclass'] ) AND mb_strtolower( $this->headers['x-post-messageclass'] ) == '9; autoresponder' )
{
return TRUE;
}
if ( !empty( $this->headers['delivered-to'] ) AND is_array( $this->headers['delivered-to'] ) )
{
foreach( $this->headers['delivered-to'] AS $deliveredTo )
{
if ( mb_strtolower( $deliveredTo ) == 'autoresponder' )
{
return TRUE;
}
}
}
if( !empty( $this->headers['delivered-to'] ) AND is_string( $this->headers['delivered-to'] ) AND mb_strtolower( $this->headers['delivered-to'] ) == 'autoresponder' )
{
return TRUE;
}
/* And finally, some basic checks on the subject line */
if( mb_stripos( $this->headers['subject'], "out of office: " ) === 0 OR
mb_stripos( $this->headers['subject'], "out of office autoreply:" ) === 0 OR
mb_stripos( $this->headers['subject'], "automatic reply: " ) === 0 OR
mb_strtolower( $this->headers['subject'] ) === "out of office"
)
{
return TRUE;
}
return FALSE;
}
}