1<?php
2/**
3 * This file is part of the FreeDSx LDAP package.
4 *
5 * (c) Chad Sikorra <Chad.Sikorra@gmail.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11namespace FreeDSx\Ldap\Control\Vlv;
12
13use FreeDSx\Asn1\Asn1;
14use FreeDSx\Asn1\Type\AbstractType;
15use FreeDSx\Asn1\Type\EnumeratedType;
16use FreeDSx\Asn1\Type\IntegerType;
17use FreeDSx\Asn1\Type\OctetStringType;
18use FreeDSx\Asn1\Type\SequenceType;
19use FreeDSx\Ldap\Control\Control;
20use FreeDSx\Ldap\Exception\ProtocolException;
21
22/**
23 * Represents a VLV Response. draft-ietf-ldapext-ldapv3-vlv-09
24 *
25 * VirtualListViewResponse ::= SEQUENCE {
26 *     targetPosition    INTEGER (0 .. maxInt),
27 *     contentCount     INTEGER (0 .. maxInt),
28 *     virtualListViewResult ENUMERATED {
29 *         success (0),
30 *         operationsError (1),
31 *         protocolError (3),
32 *         unwillingToPerform (53),
33 *         insufficientAccessRights (50),
34 *         timeLimitExceeded (3),
35 *         adminLimitExceeded (11),
36 *         innapropriateMatching (18),
37 *         sortControlMissing (60),
38 *         offsetRangeError (61),
39 *         other(80),
40 *         ... },
41 *     contextID     OCTET STRING OPTIONAL }
42 *
43 * @author Chad Sikorra <Chad.Sikorra@gmail.com>
44 */
45class VlvResponseControl extends Control
46{
47    use VlvTrait;
48
49    /**
50     * @var int
51     */
52    protected $result;
53
54    /**
55     * @param int $offset
56     * @param int $count
57     * @param int $result
58     * @param null|string $contextId
59     */
60    public function __construct(int $offset, int $count, int $result, ?string $contextId = null)
61    {
62        $this->offset = $offset;
63        $this->count = $count;
64        $this->result = $result;
65        $this->contextId = $contextId;
66        parent::__construct(self::OID_VLV_RESPONSE);
67    }
68
69    /**
70     * @return int
71     */
72    public function getResult(): int
73    {
74        return $this->result;
75    }
76
77    /**
78     * {@inheritdoc}
79     */
80    public static function fromAsn1(AbstractType $type)
81    {
82        $vlv = self::decodeEncodedValue($type);
83
84        if (!$vlv instanceof SequenceType) {
85            throw new ProtocolException('The VLV response value contains an unexpected ASN1 type.');
86        }
87        $offset = $vlv->getChild(0);
88        $count = $vlv->getChild(1);
89        $result = $vlv->getChild(2);
90        $contextId = $vlv->getChild(3);
91
92        if (!$offset instanceof IntegerType) {
93            throw new ProtocolException('The VLV response value contains an unexpected ASN1 type.');
94        }
95        if (!$count instanceof IntegerType) {
96            throw new ProtocolException('The VLV response value contains an unexpected ASN1 type.');
97        }
98        if (!$result instanceof EnumeratedType) {
99            throw new ProtocolException('The VLV response value contains an unexpected ASN1 type.');
100        }
101        if ($contextId !== null && !$contextId instanceof OctetStringType) {
102            throw new ProtocolException('The VLV response value contains an unexpected ASN1 type.');
103        }
104
105        $response = new self(
106            $offset->getValue(),
107            $count->getValue(),
108            $result->getValue()
109        );
110        if ($contextId !== null) {
111            $response->contextId = $contextId->getValue();
112        }
113
114        return parent::mergeControlData($response, $type);
115    }
116
117    /**
118     * {@inheritdoc}
119     */
120    public function toAsn1(): AbstractType
121    {
122        $this->controlValue = Asn1::sequence(
123            Asn1::integer((int) $this->offset),
124            Asn1::integer((int) $this->count),
125            Asn1::enumerated($this->result)
126        );
127        if ($this->contextId !== null) {
128            $this->controlValue->addChild(new OctetStringType($this->contextId));
129        }
130
131        return parent::toAsn1();
132    }
133}
134