Files
rspamd-cgp/rspamc/rspamc.go
T

164 lines
3.7 KiB
Go

package rspamc
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"git.vsu.ru/ai/rspamd-cgp/cgp"
"git.vsu.ru/ai/rspamd-cgp/config"
)
const (
headerCase string = "X-Rspamd-Case: "
headerJunkG string = "X-Junk-Score: [XX]"
headerJunkA string = "X-Junk-Score: [XXXX]"
headerJunkR string = "X-Junk-Score: [XXXXXXXXXX]"
)
func Scan(conf *config.Config, seq int, filename string) {
tr := &http.Transport{
DisableCompression: true,
}
client := &http.Client{
Timeout: conf.Timeout,
Transport: tr,
}
from, rcpts, auth, ip, helo, hostname, qid, body, seen, err := cgp.Message(filename)
if err != nil {
cgp.Failure(seq, qid, err)
return
}
if seen {
cgp.OkSeen(seq, qid)
return
}
req, err := http.NewRequest("POST", conf.Host, bytes.NewReader(body))
if err != nil {
cgp.Failure(seq, qid, err)
return
}
req.Header.Add("MTA-Tag", conf.AuthservId)
req.Header.Add("User-Agent", "rspamd-cgp")
req.Header.Add("From", from)
req.Header.Add("Queue-ID", strconv.Itoa(qid))
if len(auth) > 0 {
req.Header.Add("User", auth)
}
if len(ip) > 0 {
req.Header.Add("IP", ip)
}
if len(helo) > 0 {
req.Header.Add("Helo", helo)
}
if len(hostname) > 0 {
req.Header.Add("Hostname", hostname)
}
for _, rcpt := range rcpts {
req.Header.Add("Rcpt", rcpt)
}
resp, err := client.Do(req)
if err != nil {
cgp.Failure(seq, qid, err)
return
}
defer resp.Body.Close()
rbody, err := ioutil.ReadAll(resp.Body)
if err != nil {
cgp.Failure(seq, qid, err)
return
}
var res map[string]interface{}
if err := json.Unmarshal(rbody, &res); err != nil {
cgp.Failure(seq, qid, err)
return
}
if conf.Debug {
printMsgInfo(from, rcpts, auth, ip, helo, hostname, qid, seen)
printResponse(res)
}
action := res["action"].(string)
opsum, caseinfo, casework, desc := makeOpSum(conf, res, action)
headers := make([]string, 0, 8)
if conf.Outbound {
headers = makeHeadersOutbound(res)
} else {
headers = makeHeaders(res)
}
cgp.Putline("* %d [%d]: Action: %s; Score: %.2f/%.2f; Time elapsed: %.3fs\n",
seq, qid, action, res["score"], res["required_score"], res["time_real"])
var hci string
if opsum != nil {
cgp.Putline("* %d [%d]: Case: %s; %s\n", seq, qid, caseinfo, casework)
hci = headerCase + caseinfo
if !conf.Outbound {
headers = append(headers, hci)
}
}
switch action {
case "no action":
procAction(seq, qid, opsum, res, headers, hci, from, rcpts, body, conf.NotifyFrom, desc, conf.Outbound, 0)
case "discard":
if !conf.Outbound {
headers = append(headers, headerJunkR)
}
procAction(seq, qid, opsum, res, headers, hci, from, rcpts, body, conf.NotifyFrom, desc, conf.Outbound, 2)
case "quarantine":
fallthrough
case "reject":
if !conf.Outbound {
headers = append(headers, headerJunkR)
}
procAction(seq, qid, opsum, res, headers, hci, from, rcpts, body, conf.NotifyFrom, desc, conf.Outbound, 1)
case "rewrite subject":
if subject, ok := res["subject"]; ok {
procActionRS(seq, qid, opsum, res, headers, hci, subject.(string), from, rcpts, body, conf.NotifyFrom, desc, conf.Outbound)
} else {
if !conf.Outbound {
headers = append(headers, headerJunkA)
}
procAction(seq, qid, opsum, res, headers, hci, from, rcpts, body, conf.NotifyFrom, desc, conf.Outbound, 1)
}
case "add header":
if !conf.Outbound {
headers = append(headers, headerJunkA)
}
procAction(seq, qid, opsum, res, headers, hci, from, rcpts, body, conf.NotifyFrom, desc, conf.Outbound, 1)
case "greylist":
fallthrough
case "soft reject":
if !conf.Outbound {
headers = append(headers, headerJunkG)
}
procAction(seq, qid, opsum, res, headers, hci, from, rcpts, body, conf.NotifyFrom, desc, conf.Outbound, 1)
default:
cgp.Failure(seq, qid, fmt.Errorf("Unknown action: %v", action))
}
}