This commit is contained in:
@@ -37,12 +37,17 @@ scripts = {
|
||||
"greylist": [
|
||||
"config.sieve",
|
||||
"greylist.sieve"
|
||||
],
|
||||
"train": [
|
||||
"config.sieve",
|
||||
"train.sieve"
|
||||
]
|
||||
}
|
||||
script_names = {
|
||||
"spam-filter" : "Spam Filter",
|
||||
"track-replies" : "Track Replies",
|
||||
"greylist" : "Greylisting"
|
||||
"greylist" : "Greylisting",
|
||||
"train": "Train Bayes Classifier"
|
||||
}
|
||||
|
||||
maps = ["spam_config.map",
|
||||
@@ -69,7 +74,7 @@ def read_file(file):
|
||||
return f.read() + "\n"
|
||||
|
||||
def build_spam_filters(scripts):
|
||||
spam_filter = "[version]\nspam-filter = \"1.0\"\n\n"
|
||||
spam_filter = "[version]\nspam-filter = \"1.1\"\n\n"
|
||||
for script_name, file_list in scripts.items():
|
||||
script_content = read_and_concatenate(file_list).replace("'''", "\\'\\'\\'")
|
||||
script_description = script_names[script_name]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[version]
|
||||
spam-filter = "1.0"
|
||||
spam-filter = "1.1"
|
||||
|
||||
[sieve.trusted.scripts.spam-filter]
|
||||
name = "Spam Filter"
|
||||
@@ -17,7 +17,7 @@ let "ADD_HEADER_SPAM_RESULT" "key_get('spam-config', 'add-spam-result')";
|
||||
let "AUTOLEARN_REPLIES_HAM" "key_get('spam-config', 'learn-ham-replies')";
|
||||
|
||||
# Whether the bayes classifier should be trained automatically
|
||||
let "AUTOLEARN_ENABLE" "key_get('spam-config', 'learn-enable')";
|
||||
let "AUTOLEARN_ENABLE" "key_get('spam-config', 'learn-enable') && !env.test";
|
||||
|
||||
# When to learn ham (score >= threshold)
|
||||
let "AUTOLEARN_HAM_THRESHOLD" "key_get('spam-config', 'learn-ham-threshold')";
|
||||
@@ -61,7 +61,7 @@ let "urls" "dedup(tokenize(header.subject, 'uri') + body_urls + html_body_urls)"
|
||||
# Obtain thread name and subject
|
||||
let "subject_lc" "to_lowercase(header.subject)";
|
||||
let "subject_clean" "thread_name(header.subject)";
|
||||
let "body_and_subject" "subject_clean + text_body";
|
||||
let "body_and_subject" "subject_clean + ' ' + text_body";
|
||||
|
||||
# Obtain all recipients
|
||||
let "recipients" "to_lowercase(header.to:cc:bcc[*].addr[*])";
|
||||
@@ -2257,7 +2257,7 @@ while "i > 0" {
|
||||
|
||||
if eval "is_empty(token_rep)" {
|
||||
# Set reputation
|
||||
eval "key_set(SPAM_DB, token_id, [score, 1], 2592000)";
|
||||
eval "!env.test && key_set(SPAM_DB, token_id, [score, 1], 2592000)";
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2265,7 +2265,7 @@ while "i > 0" {
|
||||
let "token_score" "token_rep[0]";
|
||||
let "token_count" "token_rep[1]";
|
||||
let "updated_score" "(token_count + 1) * (score + 0.98 * token_score) / (0.98 * token_count + 1)";
|
||||
eval "key_set(SPAM_DB, token_id, [updated_score, token_count + 1], 2592000)";
|
||||
eval "!env.test && key_set(SPAM_DB, token_id, [updated_score, token_count + 1], 2592000)";
|
||||
|
||||
# Assign weight
|
||||
let "weight" "";
|
||||
@@ -2343,7 +2343,7 @@ let "ADD_HEADER_SPAM_RESULT" "key_get('spam-config', 'add-spam-result')";
|
||||
let "AUTOLEARN_REPLIES_HAM" "key_get('spam-config', 'learn-ham-replies')";
|
||||
|
||||
# Whether the bayes classifier should be trained automatically
|
||||
let "AUTOLEARN_ENABLE" "key_get('spam-config', 'learn-enable')";
|
||||
let "AUTOLEARN_ENABLE" "key_get('spam-config', 'learn-enable') && !env.test";
|
||||
|
||||
# When to learn ham (score >= threshold)
|
||||
let "AUTOLEARN_HAM_THRESHOLD" "key_get('spam-config', 'learn-ham-threshold')";
|
||||
@@ -2403,7 +2403,7 @@ let "ADD_HEADER_SPAM_RESULT" "key_get('spam-config', 'add-spam-result')";
|
||||
let "AUTOLEARN_REPLIES_HAM" "key_get('spam-config', 'learn-ham-replies')";
|
||||
|
||||
# Whether the bayes classifier should be trained automatically
|
||||
let "AUTOLEARN_ENABLE" "key_get('spam-config', 'learn-enable')";
|
||||
let "AUTOLEARN_ENABLE" "key_get('spam-config', 'learn-enable') && !env.test";
|
||||
|
||||
# When to learn ham (score >= threshold)
|
||||
let "AUTOLEARN_HAM_THRESHOLD" "key_get('spam-config', 'learn-ham-threshold')";
|
||||
@@ -2444,6 +2444,66 @@ if eval "!key_exists(SPAM_DB, triplet)" {
|
||||
|
||||
'''
|
||||
|
||||
[sieve.trusted.scripts.train]
|
||||
name = "Train Bayes Classifier"
|
||||
contents = '''
|
||||
|
||||
#### Script config.sieve ####
|
||||
|
||||
# Whether to add an X-Spam-Status header
|
||||
let "ADD_HEADER_SPAM" "key_get('spam-config', 'add-spam')";
|
||||
|
||||
# Whether to add an X-Spam-Result header
|
||||
let "ADD_HEADER_SPAM_RESULT" "key_get('spam-config', 'add-spam-result')";
|
||||
|
||||
# Whether message replies from authenticated users should be learned as ham
|
||||
let "AUTOLEARN_REPLIES_HAM" "key_get('spam-config', 'learn-ham-replies')";
|
||||
|
||||
# Whether the bayes classifier should be trained automatically
|
||||
let "AUTOLEARN_ENABLE" "key_get('spam-config', 'learn-enable') && !env.test";
|
||||
|
||||
# When to learn ham (score >= threshold)
|
||||
let "AUTOLEARN_HAM_THRESHOLD" "key_get('spam-config', 'learn-ham-threshold')";
|
||||
|
||||
# When to learn spam (score <= threshold)
|
||||
let "AUTOLEARN_SPAM_THRESHOLD" "key_get('spam-config', 'learn-spam-threshold')";
|
||||
|
||||
# Keep difference for spam/ham learns for at least this value
|
||||
let "AUTOLEARN_SPAM_HAM_BALANCE" "key_get('spam-config', 'learn-balance')";
|
||||
|
||||
# If ADD_HEADER_SPAM is enabled, mark as SPAM messages with a score above this threshold
|
||||
let "SCORE_SPAM_THRESHOLD" "key_get('spam-config', 'threshold-spam')";
|
||||
|
||||
# Discard messages with a score above this threshold
|
||||
let "SCORE_DISCARD_THRESHOLD" "key_get('spam-config', 'threshold-discard')";
|
||||
|
||||
# Reject messages with a score above this threshold
|
||||
let "SCORE_REJECT_THRESHOLD" "key_get('spam-config', 'threshold-reject')";
|
||||
|
||||
# Directory name to use for local domain lookups (leave empty for default)
|
||||
let "DOMAIN_DIRECTORY" "key_get('spam-config', 'directory')";
|
||||
|
||||
# Store to use for Bayes tokens and ids (leave empty for default)
|
||||
let "SPAM_DB" "key_get('spam-config', 'lookup')";
|
||||
|
||||
|
||||
#### Script train.sieve ####
|
||||
|
||||
|
||||
|
||||
# Obtain thread name and subject
|
||||
let "contents" "thread_name(header.subject) + ' ' + body.to_text";
|
||||
|
||||
if eval "env.train == 'spam'" {
|
||||
eval "bayes_train(SPAM_DB, contents, true)";
|
||||
} elsif eval "env.train == 'ham'" {
|
||||
eval "bayes_train(SPAM_DB, contents, false)";
|
||||
} else {
|
||||
reject "Missing variable 'train'";
|
||||
}
|
||||
|
||||
'''
|
||||
|
||||
|
||||
[lookup]
|
||||
spam-config = {
|
||||
|
||||
@@ -8,7 +8,7 @@ let "ADD_HEADER_SPAM_RESULT" "key_get('spam-config', 'add-spam-result')";
|
||||
let "AUTOLEARN_REPLIES_HAM" "key_get('spam-config', 'learn-ham-replies')";
|
||||
|
||||
# Whether the bayes classifier should be trained automatically
|
||||
let "AUTOLEARN_ENABLE" "key_get('spam-config', 'learn-enable')";
|
||||
let "AUTOLEARN_ENABLE" "key_get('spam-config', 'learn-enable') && !env.test";
|
||||
|
||||
# When to learn ham (score >= threshold)
|
||||
let "AUTOLEARN_HAM_THRESHOLD" "key_get('spam-config', 'learn-ham-threshold')";
|
||||
|
||||
@@ -13,7 +13,7 @@ let "urls" "dedup(tokenize(header.subject, 'uri') + body_urls + html_body_urls)"
|
||||
# Obtain thread name and subject
|
||||
let "subject_lc" "to_lowercase(header.subject)";
|
||||
let "subject_clean" "thread_name(header.subject)";
|
||||
let "body_and_subject" "subject_clean + text_body";
|
||||
let "body_and_subject" "subject_clean + ' ' + text_body";
|
||||
|
||||
# Obtain all recipients
|
||||
let "recipients" "to_lowercase(header.to:cc:bcc[*].addr[*])";
|
||||
|
||||
@@ -41,7 +41,7 @@ while "i > 0" {
|
||||
|
||||
if eval "is_empty(token_rep)" {
|
||||
# Set reputation
|
||||
eval "key_set(SPAM_DB, token_id, [score, 1], 2592000)";
|
||||
eval "!env.test && key_set(SPAM_DB, token_id, [score, 1], 2592000)";
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ while "i > 0" {
|
||||
let "token_score" "token_rep[0]";
|
||||
let "token_count" "token_rep[1]";
|
||||
let "updated_score" "(token_count + 1) * (score + 0.98 * token_score) / (0.98 * token_count + 1)";
|
||||
eval "key_set(SPAM_DB, token_id, [updated_score, token_count + 1], 2592000)";
|
||||
eval "!env.test && key_set(SPAM_DB, token_id, [updated_score, token_count + 1], 2592000)";
|
||||
|
||||
# Assign weight
|
||||
let "weight" "";
|
||||
|
||||
12
resources/config/spamfilter/scripts/train.sieve
Normal file
12
resources/config/spamfilter/scripts/train.sieve
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
|
||||
# Obtain thread name and subject
|
||||
let "contents" "thread_name(header.subject) + ' ' + body.to_text";
|
||||
|
||||
if eval "env.train == 'spam'" {
|
||||
eval "bayes_train(SPAM_DB, contents, true)";
|
||||
} elsif eval "env.train == 'ham'" {
|
||||
eval "bayes_train(SPAM_DB, contents, false)";
|
||||
} else {
|
||||
reject "Missing variable 'train'";
|
||||
}
|
||||
Reference in New Issue
Block a user