1<?php
2namespace Egulias\EmailValidator\Parser;
3
4use Egulias\EmailValidator\EmailLexer;
5use Egulias\EmailValidator\Parser\Parser;
6use Egulias\EmailValidator\Result\ValidEmail;
7use Egulias\EmailValidator\Result\InvalidEmail;
8use Egulias\EmailValidator\Warning\CFWSWithFWS;
9use Egulias\EmailValidator\Warning\QuotedString;
10use Egulias\EmailValidator\Result\Reason\ExpectingATEXT;
11use Egulias\EmailValidator\Result\Reason\UnclosedQuotedString;
12use Egulias\EmailValidator\Result\Result;
13
14class DoubleQuote extends PartParser
15{
16    public function parse() : Result
17    {
18
19        $validQuotedString = $this->checkDQUOTE();
20        if($validQuotedString->isInvalid()) return $validQuotedString;
21
22        $special = array(
23            EmailLexer::S_CR => true,
24            EmailLexer::S_HTAB => true,
25            EmailLexer::S_LF => true
26        );
27
28        $invalid = array(
29            EmailLexer::C_NUL => true,
30            EmailLexer::S_HTAB => true,
31            EmailLexer::S_CR => true,
32            EmailLexer::S_LF => true
33        );
34        $setSpecialsWarning = true;
35
36        $this->lexer->moveNext();
37
38        while ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE && null !== $this->lexer->token['type']) {
39            if (isset($special[$this->lexer->token['type']]) && $setSpecialsWarning) {
40                $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
41                $setSpecialsWarning = false;
42            }
43            if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH && $this->lexer->isNextToken(EmailLexer::S_DQUOTE)) {
44                $this->lexer->moveNext();
45            }
46
47            $this->lexer->moveNext();
48
49            if (!$this->escaped() && isset($invalid[$this->lexer->token['type']])) {
50                return new InvalidEmail(new ExpectingATEXT("Expecting ATEXT between DQUOTE"), $this->lexer->token['value']);
51            }
52        }
53
54        $prev = $this->lexer->getPrevious();
55
56        if ($prev['type'] === EmailLexer::S_BACKSLASH) {
57            $validQuotedString = $this->checkDQUOTE();
58            if($validQuotedString->isInvalid()) return $validQuotedString;
59        }
60
61        if (!$this->lexer->isNextToken(EmailLexer::S_AT) && $prev['type'] !== EmailLexer::S_BACKSLASH) {
62            return new InvalidEmail(new ExpectingATEXT("Expecting ATEXT between DQUOTE"), $this->lexer->token['value']);
63        }
64
65        return new ValidEmail();
66    }
67
68    protected function checkDQUOTE() : Result
69    {
70        $previous = $this->lexer->getPrevious();
71
72        if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] === EmailLexer::GENERIC) {
73            $description = 'https://tools.ietf.org/html/rfc5322#section-3.2.4 - quoted string should be a unit';
74            return new InvalidEmail(new ExpectingATEXT($description), $this->lexer->token['value']);
75        }
76
77        try {
78            $this->lexer->find(EmailLexer::S_DQUOTE);
79        } catch (\Exception $e) {
80            return new InvalidEmail(new UnclosedQuotedString(), $this->lexer->token['value']);
81        }
82        $this->warnings[QuotedString::CODE] = new QuotedString($previous['value'], $this->lexer->token['value']);
83
84        return new ValidEmail();
85    }
86
87}