Completed
Pull Request — master (#17)
by Frederik
02:00
created

Server::handleCommand()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 13
c 0
b 0
f 0
ccs 0
cts 11
cp 0
rs 9.4285
cc 3
eloc 7
nc 3
nop 2
crap 12
1
<?php
2
declare(strict_types=1);
3
4
namespace Genkgo\Mail\Protocol\Smtp;
5
6
use Genkgo\Mail\Exception\ConnectionTimeoutException;
7
use Genkgo\Mail\Exception\UnknownSmtpCommandException;
8
use Genkgo\Mail\Protocol\AppendCrlfConnection;
9
use Genkgo\Mail\Protocol\ConnectionInterface;
10
use Genkgo\Mail\Protocol\ConnectionListenerInterface;
11
use Genkgo\Mail\Protocol\Smtp\Capability\EhloCapability;
12
use Genkgo\Mail\Protocol\Smtp\Capability\QuitCapability;
13
use Genkgo\Mail\Protocol\Smtp\Capability\ResetCapability;
14
use Genkgo\Mail\Protocol\TrimCrlfConnection;
15
16
final class Server
17
{
18
    /**
19
     * @var ConnectionListenerInterface
20
     */
21
    private $listener;
22
    /**
23
     * @var CapabilityInterface[]
24
     */
25
    private $capabilities = [];
26
    /**
27
     * @var string
28
     */
29
    private $serverName;
30
31
    /**
32
     * Client constructor.
33
     * @param ConnectionListenerInterface $connection
34
     * @param array $capabilities
35
     * @param string $serverName
36
     */
37
    public function __construct(ConnectionListenerInterface $connection, array $capabilities, string $serverName) {
38
        $this->listener = $connection;
39
        $this->serverName = $serverName;
40
41
        $this->capabilities = array_merge(
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge($capabilitie...ity\ResetCapability())) of type array is incompatible with the declared type array<integer,object<Gen...p\CapabilityInterface>> of property $capabilities.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
42
            $capabilities,
43
            [
44
                new EhloCapability($this->serverName, $capabilities),
45
                new QuitCapability(),
46
                new ResetCapability()
47
            ]
48
        );
49
    }
50
51
    /**
52
     *
53
     */
54
    public function start(): void
55
    {
56
        while ($connection = $this->listener->listen()) {
57
            $connection = new TrimCrlfConnection(new AppendCrlfConnection($connection));
58
            $connection->send('220 Welcome to Genkgo Mail Server');
59
60
            try {
61
                $session = new Session();
62
63
                while ($session = $session->withCommand($connection->receive())) {
64
                    try {
65
                        $session = $this->handleCommand($connection, $session);
66
                    } catch (UnknownSmtpCommandException $e) {
67
                        $connection->send('500 unrecognized command');
68
                    }
69
70
                    if ($session->getState() === Session::STATE_DISCONNECT) {
71
                        break;
72
                    }
73
                }
74
            } catch (ConnectionTimeoutException $e) {
75
                $connection->send('421 command timeout - closing connection');
76
                $connection->disconnect();
77
            }
78
        }
79
    }
80
81
    /**
82
     * @param ConnectionInterface $connection
83
     * @param Session $session
84
     * @return Session
85
     * @throws UnknownSmtpCommandException
86
     */
87
    private function handleCommand(ConnectionInterface $connection, Session $session): Session
88
    {
89
        $command = $session->getCommand();
90
91
        foreach ($this->capabilities as $capability) {
92
            $advertised = $capability->advertise();
93
            if (substr($command, 0, strlen($advertised)) === $advertised) {
94
                return $capability->manifest($connection, $session);
95
            }
96
        }
97
98
        throw new UnknownSmtpCommandException('Cannot handle command');
99
    }
100
}