Completed
Push — master ( 5840b0...fcc03f )
by Frederik
04:51
created

DataCapability::manifest()   C

Complexity

Conditions 9
Paths 21

Size

Total Lines 50
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 28
CRAP Score 9

Importance

Changes 0
Metric Value
dl 0
loc 50
ccs 28
cts 28
cp 1
rs 6
c 0
b 0
f 0
cc 9
eloc 29
nc 21
nop 2
crap 9
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 6
    public function __construct(
42
        BackendInterface $backend,
43
        SpamScoreInterface $spamScore,
44
        GreyListInterface $greyListing,
45
        SpamDecideScore $spamDecideScore
46
    ) {
47 6
        $this->backend = $backend;
48 6
        $this->spamScore = $spamScore;
49 6
        $this->spamDecideScore = $spamDecideScore;
50 6
        $this->greyListing = $greyListing;
51 6
    }
52
53
    /**
54
     * @param ConnectionInterface $connection
55
     * @param Session $session
56
     * @return Session
57
     */
58 5
    public function manifest(ConnectionInterface $connection, Session $session): Session
59
    {
60 5
        $connection->send('354 Enter message, ending with "." on a line by itself');
61 5
        $data = [];
62
63 5
        while (true) {
64 5
            $line = $connection->receive();
65
66 5
            if ($line === '.') {
67 5
                break;
68
            }
69
70 5
            $data[] = $line;
71
        }
72
73
        try {
74 5
            $message = GenericMessage::fromString(implode("\r\n", $data));
75 1
        } catch (\InvalidArgumentException $e) {
76 1
            $connection->send('500 Malformed message');
77 1
            return $session;
78
        }
79
80 4
        $spamScore = $this->spamScore->calculate($message);
81
82 4
        if ($this->spamDecideScore->isSpam($spamScore)) {
83 1
            $connection->send('550 Message discarded as high-probability spam');
84 1
            return $session;
85
        }
86
87 3
        if ($this->spamDecideScore->isLikelySpam($spamScore) && !$this->greyListing->contains($message)) {
88 2
            $this->greyListing->attach($message);
89 2
            $connection->send('421 Please try again later');
90 2
            return $session;
91
        }
92
93 2
        $this->greyListing->detach($message);
94
95 2
        $folder = 'INBOX';
96
97 2
        if ($this->spamDecideScore->isLikelySpam($spamScore)) {
98 1
            $folder = 'JUNK';
99
        }
100
101 2
        foreach ($session->getRecipients() as $recipient) {
102 1
            $this->backend->store($recipient, $message, $folder);
103
        }
104
105 2
        $connection->send('250 Message received, queue for delivering');
106 2
        return $session->withMessage($message);
107
    }
108
109
    /**
110
     * @return string
111
     */
112 1
    public function advertise(): string
113
    {
114 1
        return 'DATA';
115
    }
116
}