Completed
Pull Request — master (#17)
by Frederik
13:03
created

DataCapability::manifest()   C

Complexity

Conditions 9
Paths 21

Size

Total Lines 48
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
dl 0
loc 48
ccs 0
cts 37
cp 0
rs 5.5102
c 0
b 0
f 0
cc 9
eloc 28
nc 21
nop 2
crap 90
1
<?php
2
declare(strict_types=1);
3
4
namespace Genkgo\Mail\Protocol\Smtp\Capability;
5
6
use Genkgo\Mail\GenericMessage;
7
use Genkgo\Mail\Protocol\ConnectionInterface;
8
use Genkgo\Mail\Protocol\Smtp\BackendInterface;
9
use Genkgo\Mail\Protocol\Smtp\CapabilityInterface;
10
use Genkgo\Mail\Protocol\Smtp\GreyListInterface;
11
use Genkgo\Mail\Protocol\Smtp\Session;
12
use Genkgo\Mail\Protocol\Smtp\SpamDecideScore;
13
use Genkgo\Mail\Protocol\Smtp\SpamScoreInterface;
14
15
final class DataCapability implements CapabilityInterface
16
{
17
    /**
18
     * @var BackendInterface
19
     */
20
    private $backend;
21
    /**
22
     * @var SpamScoreInterface
23
     */
24
    private $spamScore;
25
    /**
26
     * @var SpamDecideScore
27
     */
28
    private $spamDecideScore;
29
    /**
30
     * @var GreyListInterface
31
     */
32
    private $greyListing;
33
34
    /**
35
     * DataCapability constructor.
36
     * @param BackendInterface $backend
37
     * @param SpamScoreInterface $spamScore
38
     * @param GreyListInterface $greyListing
39
     * @param SpamDecideScore $spamDecideScore
40
     */
41
    public function __construct(
42
        BackendInterface $backend,
43
        SpamScoreInterface $spamScore,
44
        GreyListInterface $greyListing,
45
        SpamDecideScore $spamDecideScore
46
    ) {
47
        $this->backend = $backend;
48
        $this->spamScore = $spamScore;
49
        $this->spamDecideScore = $spamDecideScore;
50
        $this->greyListing = $greyListing;
51
    }
52
53
    /**
54
     * @param ConnectionInterface $connection
55
     * @param Session $session
56
     * @return Session
57
     */
58
    public function manifest(ConnectionInterface $connection, Session $session): Session
59
    {
60
        $connection->send('354 Enter message, ending with "." on a line by itself');
61
        $data = [];
62
63
        while (true) {
64
            $line = $connection->receive();
65
66
            if ($line === '.') {
67
                break;
68
            }
69
70
            $data[] = $line;
71
        }
72
73
        try {
74
            $message = GenericMessage::fromString(implode("\r\n", $data));
75
        } catch (\InvalidArgumentException $e) {
76
            $connection->send('500 Malformed message');
77
            return $session;
78
        }
79
80
        $spamScore = $this->spamScore->calculate($message);
81
82
        if ($this->spamDecideScore->isSpam($spamScore)) {
83
            $connection->send('550 Message discarded as high-probability spam');
84
            return $session;
85
        }
86
87
        if ($this->spamDecideScore->isLikelySpam($spamScore) && !$this->greyListing->contains($message)) {
88
            $this->greyListing->attach($message);
89
            $connection->send('421 Please try again later');
90
            return $session;
91
        }
92
93
        $folder = 'INBOX';
94
95
        if ($this->spamDecideScore->isLikelySpam($spamScore)) {
96
            $folder = 'JUNK';
97
        }
98
99
        foreach ($session->getRecipients() as $recipient) {
100
            $this->backend->store($recipient, $message, $folder);
101
        }
102
103
        $connection->send('250 Message received, queue for delivering');
104
        return $session->withMessage($message);
105
    }
106
107
    /**
108
     * @return string
109
     */
110
    public function advertise(): string
111
    {
112
        return 'DATA';
113
    }
114
}