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