|
@@ -24,6 +24,11 @@
|
|
* @since 1.3.0
|
|
* @since 1.3.0
|
|
*/
|
|
*/
|
|
class Rfc822Header {
|
|
class Rfc822Header {
|
|
|
|
+ /**
|
|
|
|
+ * All headers, unparsed
|
|
|
|
+ * @var array
|
|
|
|
+ */
|
|
|
|
+ var $raw_headers = array();
|
|
/**
|
|
/**
|
|
* Date header
|
|
* Date header
|
|
* @var mixed
|
|
* @var mixed
|
|
@@ -166,6 +171,7 @@ class Rfc822Header {
|
|
foreach ($hdr as $line) {
|
|
foreach ($hdr as $line) {
|
|
$pos = strpos($line, ':');
|
|
$pos = strpos($line, ':');
|
|
if ($pos > 0) {
|
|
if ($pos > 0) {
|
|
|
|
+ $this->raw_headers[] = $line;
|
|
$field = substr($line, 0, $pos);
|
|
$field = substr($line, 0, $pos);
|
|
if (!strstr($field,' ')) { /* valid field */
|
|
if (!strstr($field,' ')) { /* valid field */
|
|
$value = trim(substr($line, $pos+1));
|
|
$value = trim(substr($line, $pos+1));
|
|
@@ -350,6 +356,7 @@ class Rfc822Header {
|
|
$this->mlist('id', $value);
|
|
$this->mlist('id', $value);
|
|
break;
|
|
break;
|
|
case 'x-spam-status':
|
|
case 'x-spam-status':
|
|
|
|
+ case 'x-spam-score':
|
|
$this->x_spam_status = $this->parseSpamStatus($value);
|
|
$this->x_spam_status = $this->parseSpamStatus($value);
|
|
break;
|
|
break;
|
|
case 'x-sm-flag-reply':
|
|
case 'x-sm-flag-reply':
|
|
@@ -812,45 +819,60 @@ class Rfc822Header {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Parses the X-Spam-Status header
|
|
|
|
|
|
+ * Parses the X-Spam-Status or X-Spam-Score header
|
|
* @param string $value
|
|
* @param string $value
|
|
*/
|
|
*/
|
|
function parseSpamStatus($value) {
|
|
function parseSpamStatus($value) {
|
|
// Header value looks like this:
|
|
// Header value looks like this:
|
|
// No, score=1.5 required=5.0 tests=MSGID_FROM_MTA_ID,NO_REAL_NAME,UPPERCASE_25_50 autolearn=disabled version=3.1.0-gr0
|
|
// No, score=1.5 required=5.0 tests=MSGID_FROM_MTA_ID,NO_REAL_NAME,UPPERCASE_25_50 autolearn=disabled version=3.1.0-gr0
|
|
|
|
+ // Update circa 2018, this header can also be simply:
|
|
|
|
+ // No, score=1.5
|
|
|
|
+ // So we make the rest of the line optional (there are likely other permutations, so
|
|
|
|
+ // each element is made optional except the first two... maybe even that's not flexible enough)
|
|
|
|
+ //
|
|
|
|
+ // Also now allow parsing of X-Spam-Score header, whose value is just a float
|
|
|
|
|
|
$spam_status = array();
|
|
$spam_status = array();
|
|
|
|
|
|
- if (preg_match ('/^(No|Yes),\s+score=(-?\d+\.\d+)\s+required=(-?\d+\.\d+)\s+tests=(.*?)\s+autolearn=(.*?)\s+version=(.+?)$/', $value, $matches)) {
|
|
|
|
|
|
+ if (preg_match ('/^(?:(No|Yes),\s+score=)?(-?\d+\.\d+)(?:\s+required=(-?\d+\.\d+))?(?:\s+tests=(.*?))?(?:\s+autolearn=(.*?))?(?:\s+version=(.+?))?$/i', $value, $matches)) {
|
|
|
|
+
|
|
// full header
|
|
// full header
|
|
$spam_status['bad_format'] = 0;
|
|
$spam_status['bad_format'] = 0;
|
|
$spam_status['value'] = $matches[0];
|
|
$spam_status['value'] = $matches[0];
|
|
|
|
+
|
|
// is_spam
|
|
// is_spam
|
|
- if (isset($matches[1])
|
|
|
|
- && strtolower($matches[1]) == 'yes') {
|
|
|
|
- $spam_status['is_spam'] = true;
|
|
|
|
- } else {
|
|
|
|
- $spam_status['is_spam'] = false;
|
|
|
|
|
|
+ if (!empty($matches[1])) {
|
|
|
|
+ if (strtolower($matches[1]) == 'yes')
|
|
|
|
+ $spam_status['is_spam'] = true;
|
|
|
|
+ else
|
|
|
|
+ $spam_status['is_spam'] = false;
|
|
}
|
|
}
|
|
|
|
|
|
// score
|
|
// score
|
|
- $spam_status['score'] = $matches[2];
|
|
|
|
|
|
+ if (!empty($matches[2]))
|
|
|
|
+ $spam_status['score'] = $matches[2];
|
|
|
|
|
|
// required
|
|
// required
|
|
- $spam_status['required'] = $matches[3];
|
|
|
|
|
|
+ if (!empty($matches[3]))
|
|
|
|
+ $spam_status['required'] = $matches[3];
|
|
|
|
|
|
// tests
|
|
// tests
|
|
- $tests = array();
|
|
|
|
- $tests = explode(',', $matches[4]);
|
|
|
|
- foreach ($tests as $test) {
|
|
|
|
- $spam_status['tests'][] = trim($test);
|
|
|
|
|
|
+ if (isset($matches[4])) {
|
|
|
|
+ $tests = array();
|
|
|
|
+ $tests = explode(',', $matches[4]);
|
|
|
|
+ foreach ($tests as $test) {
|
|
|
|
+ $spam_status['tests'][] = trim($test);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
// autolearn
|
|
// autolearn
|
|
- $spam_status['autolearn'] = $matches[5];
|
|
|
|
|
|
+ if (isset($matches[5]))
|
|
|
|
+ $spam_status['autolearn'] = $matches[5];
|
|
|
|
|
|
// version
|
|
// version
|
|
- $spam_status['version'] = $matches[6];
|
|
|
|
|
|
+ if (isset($matches[6]))
|
|
|
|
+ $spam_status['version'] = $matches[6];
|
|
|
|
+
|
|
} else {
|
|
} else {
|
|
$spam_status['bad_format'] = 1;
|
|
$spam_status['bad_format'] = 1;
|
|
$spam_status['value'] = $value;
|
|
$spam_status['value'] = $value;
|