From 642ff92e4f6d7ba781b2ef0d369678426454c35f Mon Sep 17 00:00:00 2001 From: Matvey Aksenov Date: Wed, 8 Apr 2015 20:14:53 +0000 Subject: [PATCH] Update haddock documentation --- Ldap-Asn1-FromAsn1.html | 38 +- Ldap-Asn1-ToAsn1.html | 47 +- Ldap-Asn1-Type.html | 94 ++-- Ldap-Client-Add.html | 5 +- Ldap-Client-Bind.html | 11 +- Ldap-Client-Compare.html | 6 +- Ldap-Client-Delete.html | 5 +- Ldap-Client-Extended.html | 5 +- Ldap-Client-Internal.html | 8 +- Ldap-Client-Modify.html | 11 +- Ldap-Client-Search.html | 5 +- Ldap-Client.html | 2 +- doc-index-A.html | 2 +- doc-index-All.html | 2 +- doc-index-D.html | 2 +- doc-index-F.html | 2 +- doc-index-I.html | 2 +- doc-index-N.html | 2 +- doc-index-P.html | 2 +- doc-index-U.html | 2 +- ldap-client.haddock | Bin 56754 -> 78863 bytes mini_Ldap-Asn1-FromAsn1.html | 2 +- mini_Ldap-Client-Bind.html | 2 +- mini_Ldap-Client-Internal.html | 2 +- mini_Ldap-Client.html | 2 +- src/Ldap-Asn1-FromAsn1.html | 779 +++++++++++++++--------------- src/Ldap-Asn1-ToAsn1.html | 836 +++++++++++++++++---------------- src/Ldap-Asn1-Type.html | 383 ++++++++------- src/Ldap-Client-Add.html | 106 +++-- src/Ldap-Client-Bind.html | 132 +++--- src/Ldap-Client-Compare.html | 112 +++-- src/Ldap-Client-Delete.html | 100 ++-- src/Ldap-Client-Extended.html | 144 +++--- src/Ldap-Client-Internal.html | 161 ++++--- src/Ldap-Client-Modify.html | 210 +++++---- src/Ldap-Client-Search.html | 377 ++++++++------- src/Ldap-Client.html | 454 ++++++++++-------- 37 files changed, 2206 insertions(+), 1849 deletions(-) diff --git a/Ldap-Asn1-FromAsn1.html b/Ldap-Asn1-FromAsn1.html index 1375283..ea03f07 100644 --- a/Ldap-Asn1-FromAsn1.html +++ b/Ldap-Asn1-FromAsn1.html @@ -1,17 +1,17 @@ Ldap.Asn1.FromAsn1

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Asn1.FromAsn1

Documentation

class FromAsn1 a where Source

Methods

fromAsn1 :: Parser [ASN1] a Source

Instances

FromAsn1 LdapOid Source
LDAPOID ::= OCTET STRING -- Constrained to <numericoid>
-
FromAsn1 LdapString Source
LDAPString ::= OCTET STRING -- UTF-8 encoded,
-
FromAsn1 Uri Source
URI ::= LDAPString
-
FromAsn1 ReferralUris Source
Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI
-
FromAsn1 LdapDn Source
LDAPDN ::= LDAPString
-
FromAsn1 PartialAttribute Source
PartialAttribute ::= SEQUENCE {
+

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Asn1.FromAsn1

Description

This module contains convertions from ASN.1 to LDAP types.

Synopsis

Documentation

parseAsn1 :: FromAsn1 a => [ASN1] -> Maybe ([ASN1], a) Source

Convert a part of ASN.1 stream to a LDAP type returning the remainder of the stream.

class FromAsn1 a Source

ASN.1 stream parsers.

When it's relevant, instances include the part of RFC describing the encoding.

Minimal complete definition

fromAsn1

Instances

FromAsn1 LdapOid Source
LDAPOID ::= OCTET STRING -- Constrained to <numericoid>
+
FromAsn1 LdapString Source
LDAPString ::= OCTET STRING -- UTF-8 encoded,
+
FromAsn1 Uri Source
URI ::= LDAPString
+
FromAsn1 ReferralUris Source
Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI
+
FromAsn1 LdapDn Source
LDAPDN ::= LDAPString
+
FromAsn1 PartialAttribute Source
PartialAttribute ::= SEQUENCE {
      type       AttributeDescription,
      vals       SET OF value AttributeValue }
-
FromAsn1 AttributeValue Source
AttributeValue ::= OCTET STRING
-
FromAsn1 AttributeDescription Source
AttributeDescription ::= LDAPString
-
FromAsn1 LdapResult Source
LDAPResult ::= SEQUENCE {
+
FromAsn1 AttributeValue Source
AttributeValue ::= OCTET STRING
+
FromAsn1 AttributeDescription Source
AttributeDescription ::= LDAPString
+
FromAsn1 LdapResult Source
LDAPResult ::= SEQUENCE {
      resultCode         ENUMERATED {
           success                      (0),
           operationsError              (1),
@@ -63,20 +63,30 @@ window.onload = function () {pageLoad();setSynopsis("mini_Ldap-Asn1-FromAsn1.htm
      matchedDN          LDAPDN,
      diagnosticMessage  LDAPString,
      referral           [3] Referral OPTIONAL }
-
FromAsn1 PartialAttributeList Source
PartialAttributeList ::= SEQUENCE OF partialAttribute PartialAttribute
-
FromAsn1 ProtocolServerOp Source
BindResponse ::= [APPLICATION 1] SEQUENCE {
+
FromAsn1 PartialAttributeList Source
PartialAttributeList ::= SEQUENCE OF partialAttribute PartialAttribute
+
FromAsn1 ProtocolServerOp Source
BindResponse ::= [APPLICATION 1] SEQUENCE {
      COMPONENTS OF LDAPResult,
      serverSaslCreds    [7] OCTET STRING OPTIONAL }
 
SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
      objectName      LDAPDN,
      attributes      PartialAttributeList }
+
SearchResultReference ::= [APPLICATION 19] SEQUENCE
+                          SIZE (1..MAX) OF uri URI
 
SearchResultDone ::= [APPLICATION 5] LDAPResult
 
ModifyResponse ::= [APPLICATION 7] LDAPResult
 
AddResponse ::= [APPLICATION 9] LDAPResult
 
DelResponse ::= [APPLICATION 11] LDAPResult
+
ModifyDNResponse ::= [APPLICATION 13] LDAPResult
 
CompareResponse ::= [APPLICATION 15] LDAPResult
-
FromAsn1 Id Source
MessageID ::= INTEGER (0 ..  maxInt)
-
FromAsn1 op => FromAsn1 (LdapMessage op) Source
LDAPMessage ::= SEQUENCE {
+
ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+     COMPONENTS OF LDAPResult,
+     responseName     [10] LDAPOID OPTIONAL,
+     responseValue    [11] OCTET STRING OPTIONAL }
+
IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+     responseName     [0] LDAPOID OPTIONAL,
+     responseValue    [1] OCTET STRING OPTIONAL }
+
FromAsn1 Id Source
MessageID ::= INTEGER (0 ..  maxInt)
+
FromAsn1 op => FromAsn1 (LdapMessage op) Source
LDAPMessage ::= SEQUENCE {
      messageID       MessageID,
      protocolOp      CHOICE {
           bindRequest           BindRequest,
@@ -90,4 +100,4 @@ window.onload = function () {pageLoad();setSynopsis("mini_Ldap-Asn1-FromAsn1.htm
           addResponse           AddResponse,
           ... },
      controls       [0] Controls OPTIONAL }
-
(FromAsn1 a, FromAsn1 b) => FromAsn1 (a, b) Source 

parseAsn1 :: FromAsn1 a => [ASN1] -> Maybe ([ASN1], a) Source

parse :: Parser s a -> s -> Maybe (s, a) Source

next :: Parser [s] s Source

\ No newline at end of file +
(FromAsn1 a, FromAsn1 b) => FromAsn1 (a, b) Source 
\ No newline at end of file diff --git a/Ldap-Asn1-ToAsn1.html b/Ldap-Asn1-ToAsn1.html index a5742e0..8e7c9ec 100644 --- a/Ldap-Asn1-ToAsn1.html +++ b/Ldap-Asn1-ToAsn1.html @@ -1,43 +1,46 @@ Ldap.Asn1.ToAsn1

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Asn1.ToAsn1

Documentation

class ToAsn1 a where Source

Methods

toAsn1 :: a -> Endo [ASN1] Source

Instances

ToAsn1 LdapOid Source
LDAPOID ::= OCTET STRING -- Constrained to <numericoid>
-
ToAsn1 LdapString Source
LDAPString ::= OCTET STRING -- UTF-8 encoded
-
ToAsn1 RelativeLdapDn Source
RelativeLDAPDN ::= LDAPString -- Constrained to <name-component>
-
ToAsn1 LdapDn Source
LDAPDN ::= LDAPString -- Constrained to <distinguishedName>
-
ToAsn1 PartialAttribute Source
PartialAttribute ::= SEQUENCE {
+

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Asn1.ToAsn1

Description

This module contains convertions from LDAP types to ASN.1.

Various hacks are employed because "asn1-encoding" only encodes to DER, but + LDAP demands BER-encoding. So, when a definition looks suspiciously different + from the spec in the comment, that's why. I hope all that will be fixed + eventually.

Synopsis

Documentation

class ToAsn1 a where Source

Convert a LDAP type to ASN.1.

When it's relevant, instances include the part of RFC describing the encoding.

Methods

toAsn1 :: a -> Endo [ASN1] Source

Instances

ToAsn1 LdapOid Source
LDAPOID ::= OCTET STRING -- Constrained to <numericoid>
+
ToAsn1 LdapString Source
LDAPString ::= OCTET STRING -- UTF-8 encoded
+
ToAsn1 RelativeLdapDn Source
RelativeLDAPDN ::= LDAPString -- Constrained to <name-component>
+
ToAsn1 LdapDn Source
LDAPDN ::= LDAPString -- Constrained to <distinguishedName>
+
ToAsn1 PartialAttribute Source
PartialAttribute ::= SEQUENCE {
      type       AttributeDescription,
      vals       SET OF value AttributeValue }
-
ToAsn1 Attribute Source
Attribute ::= PartialAttribute(WITH COMPONENTS {
+
ToAsn1 Attribute Source
Attribute ::= PartialAttribute(WITH COMPONENTS {
      ...,
      vals (SIZE(1..MAX))})
-
ToAsn1 AssertionValue Source
AssertionValue ::= OCTET STRING
-
ToAsn1 AttributeValueAssertion Source
AttributeValueAssertion ::= SEQUENCE {
+
ToAsn1 AssertionValue Source
AssertionValue ::= OCTET STRING
+
ToAsn1 AttributeValueAssertion Source
AttributeValueAssertion ::= SEQUENCE {
      attributeDesc   AttributeDescription,
      assertionValue  AssertionValue }
-
ToAsn1 AttributeValue Source
AttributeValue ::= OCTET STRING
-
ToAsn1 AttributeDescription Source
AttributeDescription ::= LDAPString
-
ToAsn1 Control Source
Control ::= SEQUENCE {
+
ToAsn1 AttributeValue Source
AttributeValue ::= OCTET STRING
+
ToAsn1 AttributeDescription Source
AttributeDescription ::= LDAPString
+
ToAsn1 Control Source
Control ::= SEQUENCE {
      controlType             LDAPOID,
      criticality             BOOLEAN DEFAULT FALSE,
      controlValue            OCTET STRING OPTIONAL }
-
ToAsn1 Controls Source
Controls ::= SEQUENCE OF control Control
-
ToAsn1 AttributeList Source
AttributeList ::= SEQUENCE OF attribute Attribute
-
ToAsn1 AttributeSelection Source
AttributeSelection ::= SEQUENCE OF selector LDAPString
-
ToAsn1 MatchingRuleId Source
MatchingRuleId ::= LDAPString
-
ToAsn1 MatchingRuleAssertion Source
MatchingRuleAssertion ::= SEQUENCE {
+
ToAsn1 Controls Source
Controls ::= SEQUENCE OF control Control
+
ToAsn1 AttributeList Source
AttributeList ::= SEQUENCE OF attribute Attribute
+
ToAsn1 AttributeSelection Source
AttributeSelection ::= SEQUENCE OF selector LDAPString
+
ToAsn1 MatchingRuleId Source
MatchingRuleId ::= LDAPString
+
ToAsn1 MatchingRuleAssertion Source
MatchingRuleAssertion ::= SEQUENCE {
      matchingRule    [1] MatchingRuleId OPTIONAL,
      type            [2] AttributeDescription OPTIONAL,
      matchValue      [3] AssertionValue,
      dnAttributes    [4] BOOLEAN DEFAULT FALSE }
-
ToAsn1 SubstringFilter Source
SubstringFilter ::= SEQUENCE {
+
ToAsn1 SubstringFilter Source
SubstringFilter ::= SEQUENCE {
      type           AttributeDescription,
      substrings     SEQUENCE SIZE (1..MAX) OF substring CHOICE {
           initial [0] AssertionValue,  -- can occur at most once
           any     [1] AssertionValue,
           final   [2] AssertionValue } -- can occur at most once
      }
-
ToAsn1 Filter Source
Filter ::= CHOICE {
+
ToAsn1 Filter Source
Filter ::= CHOICE {
      and             [0] SET SIZE (1..MAX) OF filter Filter,
      or              [1] SET SIZE (1..MAX) OF filter Filter,
      not             [2] Filter,
@@ -49,10 +52,10 @@ window.onload = function () {pageLoad();setSynopsis("mini_Ldap-Asn1-ToAsn1.html"
      approxMatch     [8] AttributeValueAssertion,
      extensibleMatch [9] MatchingRuleAssertion,
      ...  }
-
ToAsn1 AuthenticationChoice Source
AuthenticationChoice ::= CHOICE {
+
ToAsn1 AuthenticationChoice Source
AuthenticationChoice ::= CHOICE {
      simple                  [0] OCTET STRING,
      ...  }
-
ToAsn1 ProtocolClientOp Source
BindRequest ::= [APPLICATION 0] SEQUENCE {
+
ToAsn1 ProtocolClientOp Source
BindRequest ::= [APPLICATION 0] SEQUENCE {
      version                 INTEGER (1 ..  127),
      name                    LDAPDN,
      authentication          AuthenticationChoice }
@@ -98,8 +101,8 @@ window.onload = function () {pageLoad();setSynopsis("mini_Ldap-Asn1-ToAsn1.html"
 
ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
      requestName      [0] LDAPOID,
      requestValue     [1] OCTET STRING OPTIONAL }
-
ToAsn1 Id Source
MessageID ::= INTEGER (0 ..  maxInt)
-
ToAsn1 a => ToAsn1 [a] Source 
ToAsn1 a => ToAsn1 (NonEmpty a) Source 
ToAsn1 op => ToAsn1 (LdapMessage op) Source
LDAPMessage ::= SEQUENCE {
+
ToAsn1 Id Source
MessageID ::= INTEGER (0 ..  maxInt)
+
ToAsn1 a => ToAsn1 [a] Source 
ToAsn1 a => ToAsn1 (NonEmpty a) Source 
ToAsn1 op => ToAsn1 (LdapMessage op) Source
LDAPMessage ::= SEQUENCE {
      messageID       MessageID,
      protocolOp      CHOICE {
           bindRequest           BindRequest,
diff --git a/Ldap-Asn1-Type.html b/Ldap-Asn1-Type.html
index 00408d8..a122659 100644
--- a/Ldap-Asn1-Type.html
+++ b/Ldap-Asn1-Type.html
@@ -1,7 +1,7 @@
 Ldap.Asn1.Type

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellSafe
LanguageHaskell2010

Ldap.Asn1.Type

Synopsis

Documentation

data LdapMessage op Source

Instances

Eq op => Eq (LdapMessage op) Source 
Ord op => Ord (LdapMessage op) Source 
Show op => Show (LdapMessage op) Source 
ToAsn1 op => ToAsn1 (LdapMessage op) Source
LDAPMessage ::= SEQUENCE {
+

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellSafe
LanguageHaskell2010

Ldap.Asn1.Type

Synopsis

Documentation

data LdapMessage op Source

Message envelope. (Section 4.1.1.)

Instances

Eq op => Eq (LdapMessage op) Source 
Show op => Show (LdapMessage op) Source 
ToAsn1 op => ToAsn1 (LdapMessage op) Source
LDAPMessage ::= SEQUENCE {
      messageID       MessageID,
      protocolOp      CHOICE {
           bindRequest           BindRequest,
@@ -15,7 +15,7 @@ window.onload = function () {pageLoad();setSynopsis("mini_Ldap-Asn1-Type.html");
           addResponse           AddResponse,
           ... },
      controls       [0] Controls OPTIONAL }
-
FromAsn1 op => FromAsn1 (LdapMessage op) Source
LDAPMessage ::= SEQUENCE {
+
FromAsn1 op => FromAsn1 (LdapMessage op) Source
LDAPMessage ::= SEQUENCE {
      messageID       MessageID,
      protocolOp      CHOICE {
           bindRequest           BindRequest,
@@ -29,9 +29,10 @@ window.onload = function () {pageLoad();setSynopsis("mini_Ldap-Asn1-Type.html");
           addResponse           AddResponse,
           ... },
      controls       [0] Controls OPTIONAL }
-

newtype Id Source

Constructors

Id 

Fields

unId :: Int32
 

Instances

Eq Id Source 
Ord Id Source 
Show Id Source 
ToAsn1 Id Source
MessageID ::= INTEGER (0 ..  maxInt)
-
FromAsn1 Id Source
MessageID ::= INTEGER (0 ..  maxInt)
-

newtype Id Source

Every message being processed has a unique non-zero integer ID. (Section 4.1.1.1.)

Constructors

Id 

Fields

unId :: Int32
 

Instances

Eq Id Source 
Ord Id Source 
Show Id Source 
ToAsn1 Id Source
MessageID ::= INTEGER (0 ..  maxInt)
+
FromAsn1 Id Source
MessageID ::= INTEGER (0 ..  maxInt)
+

data ProtocolClientOp Source

Client requests. The RFC doesn't make a difference between ProtocolClientOp + and ProtocolServerOp but it's useful to distinguish between them in Haskell.

Instances

Eq ProtocolClientOp Source 
Show ProtocolClientOp Source 
ToAsn1 ProtocolClientOp Source
BindRequest ::= [APPLICATION 0] SEQUENCE {
      version                 INTEGER (1 ..  127),
      name                    LDAPDN,
      authentication          AuthenticationChoice }
@@ -77,21 +78,32 @@ window.onload = function () {pageLoad();setSynopsis("mini_Ldap-Asn1-Type.html");
 
ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
      requestName      [0] LDAPOID,
      requestValue     [1] OCTET STRING OPTIONAL }
-

data ProtocolServerOp Source

Server responses. The RFC doesn't make a difference between ProtocolClientOp + and ProtocolServerOp but it's useful to distinguish between them in Haskell.

Instances

Eq ProtocolServerOp Source 
Show ProtocolServerOp Source 
FromAsn1 ProtocolServerOp Source
BindResponse ::= [APPLICATION 1] SEQUENCE {
      COMPONENTS OF LDAPResult,
      serverSaslCreds    [7] OCTET STRING OPTIONAL }
 
SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
      objectName      LDAPDN,
      attributes      PartialAttributeList }
+
SearchResultReference ::= [APPLICATION 19] SEQUENCE
+                          SIZE (1..MAX) OF uri URI
 
SearchResultDone ::= [APPLICATION 5] LDAPResult
 
ModifyResponse ::= [APPLICATION 7] LDAPResult
 
AddResponse ::= [APPLICATION 9] LDAPResult
 
DelResponse ::= [APPLICATION 11] LDAPResult
+
ModifyDNResponse ::= [APPLICATION 13] LDAPResult
 
CompareResponse ::= [APPLICATION 15] LDAPResult
-

data AuthenticationChoice Source

Constructors

Simple ByteString 

Instances

Eq AuthenticationChoice Source 
Ord AuthenticationChoice Source 
Show AuthenticationChoice Source 
ToAsn1 AuthenticationChoice Source
AuthenticationChoice ::= CHOICE {
+
ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+     COMPONENTS OF LDAPResult,
+     responseName     [10] LDAPOID OPTIONAL,
+     responseValue    [11] OCTET STRING OPTIONAL }
+
IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+     responseName     [0] LDAPOID OPTIONAL,
+     responseValue    [1] OCTET STRING OPTIONAL }
+

newtype AuthenticationChoice Source

Constructors

Simple ByteString 

Instances

Eq AuthenticationChoice Source 
Show AuthenticationChoice Source 
ToAsn1 AuthenticationChoice Source
AuthenticationChoice ::= CHOICE {
      simple                  [0] OCTET STRING,
      ...  }
-

data Filter Source

Instances

Eq Filter Source 
Show Filter Source 
ToAsn1 Filter Source
Filter ::= CHOICE {
      and             [0] SET SIZE (1..MAX) OF filter Filter,
      or              [1] SET SIZE (1..MAX) OF filter Filter,
      not             [2] Filter,
@@ -103,28 +115,31 @@ window.onload = function () {pageLoad();setSynopsis("mini_Ldap-Asn1-Type.html");
      approxMatch     [8] AttributeValueAssertion,
      extensibleMatch [9] MatchingRuleAssertion,
      ...  }
-

data SubstringFilter Source

Instances

Eq SubstringFilter Source 
Show SubstringFilter Source 
ToAsn1 SubstringFilter Source
SubstringFilter ::= SEQUENCE {
      type           AttributeDescription,
      substrings     SEQUENCE SIZE (1..MAX) OF substring CHOICE {
           initial [0] AssertionValue,  -- can occur at most once
           any     [1] AssertionValue,
           final   [2] AssertionValue } -- can occur at most once
      }
-

data MatchingRuleAssertion Source

Instances

Eq MatchingRuleAssertion Source 
Show MatchingRuleAssertion Source 
ToAsn1 MatchingRuleAssertion Source
MatchingRuleAssertion ::= SEQUENCE {
      matchingRule    [1] MatchingRuleId OPTIONAL,
      type            [2] AttributeDescription OPTIONAL,
      matchValue      [3] AssertionValue,
      dnAttributes    [4] BOOLEAN DEFAULT FALSE }
-

newtype AttributeList Source

Constructors

AttributeList [Attribute] 

Instances

Eq AttributeList Source 
Ord AttributeList Source 
Show AttributeList Source 
ToAsn1 AttributeList Source
AttributeList ::= SEQUENCE OF attribute Attribute
-

newtype Controls Source

Constructors

Controls [Control] 

Instances

Eq Controls Source 
Ord Controls Source 
Show Controls Source 
ToAsn1 Controls Source
Controls ::= SEQUENCE OF control Control
-

newtype MatchingRuleId Source

Matching rules are defined in Section 4.1.3 of [RFC4512]. A matching + rule is identified in the protocol by the printable representation of + either its numericoid or one of its short name descriptors + [RFC4512], e.g., caseIgnoreMatch or '2.5.13.2'. (Section 4.1.8.)

Instances

newtype AttributeSelection Source

Instances

Eq AttributeSelection Source 
Show AttributeSelection Source 
ToAsn1 AttributeSelection Source
AttributeSelection ::= SEQUENCE OF selector LDAPString
+

newtype AttributeList Source

Constructors

AttributeList [Attribute] 

Instances

Eq AttributeList Source 
Show AttributeList Source 
ToAsn1 AttributeList Source
AttributeList ::= SEQUENCE OF attribute Attribute
+

newtype PartialAttributeList Source

Instances

Eq PartialAttributeList Source 
Show PartialAttributeList Source 
FromAsn1 PartialAttributeList Source
PartialAttributeList ::= SEQUENCE OF partialAttribute PartialAttribute
+

newtype Controls Source

Constructors

Controls [Control] 

Instances

Eq Controls Source 
Show Controls Source 
ToAsn1 Controls Source
Controls ::= SEQUENCE OF control Control
+

data Control Source

Instances

Eq Control Source 
Show Control Source 
ToAsn1 Control Source
Control ::= SEQUENCE {
      controlType             LDAPOID,
      criticality             BOOLEAN DEFAULT FALSE,
      controlValue            OCTET STRING OPTIONAL }
-

data LdapResult Source

Instances

Eq LdapResult Source 
Show LdapResult Source 
FromAsn1 LdapResult Source
LDAPResult ::= SEQUENCE {
      resultCode         ENUMERATED {
           success                      (0),
           operationsError              (1),
@@ -176,33 +191,40 @@ window.onload = function () {pageLoad();setSynopsis("mini_Ldap-Asn1-Type.html");
      matchedDN          LDAPDN,
      diagnosticMessage  LDAPString,
      referral           [3] Referral OPTIONAL }
-

newtype AttributeValue Source

Instances

Eq AttributeValue Source 
Ord AttributeValue Source 
Show AttributeValue Source 
ToAsn1 AttributeValue Source
AttributeValue ::= OCTET STRING
-
FromAsn1 AttributeValue Source
AttributeValue ::= OCTET STRING
-

newtype AttributeValue Source

Instances

Eq AttributeValue Source 
Show AttributeValue Source 
ToAsn1 AttributeValue Source
AttributeValue ::= OCTET STRING
+
FromAsn1 AttributeValue Source
AttributeValue ::= OCTET STRING
+

data AttributeValueAssertion Source

Instances

Eq AttributeValueAssertion Source 
Show AttributeValueAssertion Source 
ToAsn1 AttributeValueAssertion Source
AttributeValueAssertion ::= SEQUENCE {
      attributeDesc   AttributeDescription,
      assertionValue  AssertionValue }
-

data Attribute Source

Instances

Eq Attribute Source 
Ord Attribute Source 
Show Attribute Source 
ToAsn1 Attribute Source
Attribute ::= PartialAttribute(WITH COMPONENTS {
+

data Attribute Source

Instances

Eq Attribute Source 
Show Attribute Source 
ToAsn1 Attribute Source
Attribute ::= PartialAttribute(WITH COMPONENTS {
      ...,
      vals (SIZE(1..MAX))})
-

data PartialAttribute Source

Instances

Eq PartialAttribute Source 
Show PartialAttribute Source 
ToAsn1 PartialAttribute Source
PartialAttribute ::= SEQUENCE {
      type       AttributeDescription,
      vals       SET OF value AttributeValue }
-
FromAsn1 PartialAttribute Source
PartialAttribute ::= SEQUENCE {
+
FromAsn1 PartialAttribute Source
PartialAttribute ::= SEQUENCE {
      type       AttributeDescription,
      vals       SET OF value AttributeValue }
-

newtype LdapDn Source

Constructors

LdapDn LdapString 

Instances

Eq LdapDn Source 
Ord LdapDn Source 
Show LdapDn Source 
ToAsn1 LdapDn Source
LDAPDN ::= LDAPString -- Constrained to <distinguishedName>
-
FromAsn1 LdapDn Source
LDAPDN ::= LDAPString
-

newtype RelativeLdapDn Source

Instances

Eq RelativeLdapDn Source 
Ord RelativeLdapDn Source 
Show RelativeLdapDn Source 
ToAsn1 RelativeLdapDn Source
RelativeLDAPDN ::= LDAPString -- Constrained to <name-component>
-

newtype ReferralUris Source

Constructors

ReferralUris (NonEmpty Uri) 

Instances

Eq ReferralUris Source 
Ord ReferralUris Source 
Show ReferralUris Source 
FromAsn1 ReferralUris Source
Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI
-

newtype Uri Source

Constructors

Uri LdapString 

Instances

newtype LdapString Source

The LDAPString is a notational convenience to indicate that, although +

newtype LdapDn Source

An LDAPDN is defined to be the representation of a Distinguished Name + (DN) after encoding according to the specification in [RFC4514].

Constructors

LdapDn LdapString 

Instances

Eq LdapDn Source 
Show LdapDn Source 
ToAsn1 LdapDn Source
LDAPDN ::= LDAPString -- Constrained to <distinguishedName>
+
FromAsn1 LdapDn Source
LDAPDN ::= LDAPString
+

newtype RelativeLdapDn Source

A RelativeLDAPDN is defined to be the representation of a Relative + Distinguished Name (RDN) after encoding according to the + specification in [RFC4514].

Instances

Eq RelativeLdapDn Source 
Show RelativeLdapDn Source 
ToAsn1 RelativeLdapDn Source
RelativeLDAPDN ::= LDAPString -- Constrained to <name-component>
+

newtype ReferralUris Source

Constructors

ReferralUris (NonEmpty Uri) 

Instances

Eq ReferralUris Source 
Show ReferralUris Source 
FromAsn1 ReferralUris Source
Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI
+

newtype Uri Source

Constructors

Uri LdapString 

Instances

Eq Uri Source 
Show Uri Source 
FromAsn1 Uri Source
URI ::= LDAPString
+

newtype LdapString Source

The LDAPString is a notational convenience to indicate that, although strings of LDAPString type encode as ASN.1 OCTET STRING types, the [ISO10646] character set (a superset of [Unicode]) is used, encoded - following the UTF-8 [RFC3629] algorithm.

Constructors

LdapString Text 

Instances

Eq LdapString Source 
Ord LdapString Source 
Show LdapString Source 
ToAsn1 LdapString Source
LDAPString ::= OCTET STRING -- UTF-8 encoded
-
FromAsn1 LdapString Source
LDAPString ::= OCTET STRING -- UTF-8 encoded,
-

newtype LdapOid Source

Constructors

LdapOid ByteString 

Instances

Eq LdapOid Source 
Ord LdapOid Source 
Show LdapOid Source 
ToAsn1 LdapOid Source
LDAPOID ::= OCTET STRING -- Constrained to <numericoid>
-
FromAsn1 LdapOid Source
LDAPOID ::= OCTET STRING -- Constrained to <numericoid>
+ following the UTF-8 [RFC3629] algorithm. (Section 4.1.2.)

Constructors

LdapString Text 

Instances

Eq LdapString Source 
Show LdapString Source 
ToAsn1 LdapString Source
LDAPString ::= OCTET STRING -- UTF-8 encoded
+
FromAsn1 LdapString Source
LDAPString ::= OCTET STRING -- UTF-8 encoded,
+

newtype LdapOid Source

The LDAPOID is a notational convenience to indicate that the + permitted value of this string is a (UTF-8 encoded) dotted-decimal + representation of an OBJECT IDENTIFIER. Although an LDAPOID is + encoded as an OCTET STRING, values are limited to the definition of + <numericoid> given in Section 1.4 of [RFC4512].

Constructors

LdapOid Text 

Instances

Eq LdapOid Source 
Show LdapOid Source 
ToAsn1 LdapOid Source
LDAPOID ::= OCTET STRING -- Constrained to <numericoid>
+
FromAsn1 LdapOid Source
LDAPOID ::= OCTET STRING -- Constrained to <numericoid>
 
\ No newline at end of file diff --git a/Ldap-Client-Add.html b/Ldap-Client-Add.html index ad51456..19133a0 100644 --- a/Ldap-Client-Add.html +++ b/Ldap-Client-Add.html @@ -1,4 +1,7 @@ Ldap.Client.Add

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client.Add

\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client.Add

Description

Add operation.

This operation comes in four flavours:

Of those, the first one (add) is probably the most useful for the typical usecase.

Documentation

add :: Ldap -> Dn -> AttrList NonEmpty -> IO () Source

Perform the Add operation synchronously. Raises ResponseError on failures.

addEither :: Ldap -> Dn -> AttrList NonEmpty -> IO (Either ResponseError ()) Source

Perform the Add operation synchronously. Returns Left e where + e is a ResponseError on failures.

addAsync :: Ldap -> Dn -> AttrList NonEmpty -> IO (Async ()) Source

Perform the Add operation asynchronously. Call wait to wait + for its completion.

addAsyncSTM :: Ldap -> Dn -> AttrList NonEmpty -> STM (Async ()) Source

Perform the Add operation asynchronously.

Don't wait for its completion (with waitSTM) in the + same transaction you've performed it in.

\ No newline at end of file diff --git a/Ldap-Client-Bind.html b/Ldap-Client-Bind.html index df16968..f42491d 100644 --- a/Ldap-Client-Bind.html +++ b/Ldap-Client-Bind.html @@ -1,10 +1,7 @@ Ldap.Client.Bind

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client.Bind

Synopsis

Documentation

bind :: Ldap -> Dn -> Password -> IO () Source

unbindAsync :: Ldap -> IO () Source

Note that unbindAsync does not return an Async, - because LDAP server never responds to UnbindRequests, hence - a call to wait on a hypothetical Async would have resulted - in an exception anyway.

unbindAsyncSTM :: Ldap -> STM () Source

Note that unbindAsyncSTM does not return an Async, - because LDAP server never responds to UnbindRequests, hence - a call to wait on a hypothetical Async would have resulted - in an exception anyway.

\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client.Bind

Description

Bind operation.

This operation comes in four flavours:

Of those, the first one (bind) is probably the most useful for the typical usecase.

Synopsis

Documentation

bind :: Ldap -> Dn -> Password -> IO () Source

Perform the Bind operation synchronously. Raises ResponseError on failures.

bindEither :: Ldap -> Dn -> Password -> IO (Either ResponseError ()) Source

Perform the Bind operation synchronously. Returns Left e where + e is a ResponseError on failures.

bindAsync :: Ldap -> Dn -> Password -> IO (Async ()) Source

Perform the Bind operation asynchronously. Call wait to wait + for its completion.

bindAsyncSTM :: Ldap -> Dn -> Password -> STM (Async ()) Source

Perform the Bind operation asynchronously.

Don't wait for its completion (with waitSTM) in the + same transaction you've performed it in.

\ No newline at end of file diff --git a/Ldap-Client-Compare.html b/Ldap-Client-Compare.html index b20272c..06780bb 100644 --- a/Ldap-Client-Compare.html +++ b/Ldap-Client-Compare.html @@ -1,4 +1,8 @@ Ldap.Client.Compare

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client.Compare

\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client.Compare

Description

Compare operation.

This operation comes in four flavours:

Of those, the first one (compare) is probably the most useful for the + typical usecase.

Documentation

compare :: Ldap -> Dn -> Attr -> AttrValue -> IO Bool Source

Perform the Compare operation synchronously. Raises ResponseError on failures.

compareEither :: Ldap -> Dn -> Attr -> AttrValue -> IO (Either ResponseError Bool) Source

Perform the Compare operation synchronously. Returns Left e where + e is a ResponseError on failures.

compareAsync :: Ldap -> Dn -> Attr -> AttrValue -> IO (Async Bool) Source

Perform the Compare operation asynchronously. Call wait to wait + for its completion.

compareAsyncSTM :: Ldap -> Dn -> Attr -> AttrValue -> STM (Async Bool) Source

Perform the Compare operation asynchronously.

Don't wait for its completion (with waitSTM) in the + same transaction you've performed it in.

\ No newline at end of file diff --git a/Ldap-Client-Delete.html b/Ldap-Client-Delete.html index 375d5b8..63c44f9 100644 --- a/Ldap-Client-Delete.html +++ b/Ldap-Client-Delete.html @@ -1,4 +1,7 @@ Ldap.Client.Delete

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client.Delete

Documentation

delete :: Ldap -> Dn -> IO () Source

\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client.Delete

Description

Delete operation.

This operation comes in four flavours:

Of those, the first one (delete) is probably the most useful for the typical usecase.

Synopsis

Documentation

delete :: Ldap -> Dn -> IO () Source

Perform the Delete operation synchronously. Raises ResponseError on failures.

deleteEither :: Ldap -> Dn -> IO (Either ResponseError ()) Source

Perform the Delete operation synchronously. Returns Left e where + e is a ResponseError on failures.

deleteAsync :: Ldap -> Dn -> IO (Async ()) Source

Perform the Delete operation asynchronously. Call wait to wait + for its completion.

deleteAsyncSTM :: Ldap -> Dn -> STM (Async ()) Source

Perform the Delete operation asynchronously.

Don't wait for its completion (with waitSTM) in the + same transaction you've performed it in.

\ No newline at end of file diff --git a/Ldap-Client-Extended.html b/Ldap-Client-Extended.html index a44b004..e30031b 100644 --- a/Ldap-Client-Extended.html +++ b/Ldap-Client-Extended.html @@ -1,4 +1,7 @@ Ldap.Client.Extended

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client.Extended

\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client.Extended

Description

Extended operation.

This operation comes in four flavours:

Of those, the first one (extended) is probably the most useful for the typical usecase.

Documentation

extended :: Ldap -> Oid -> Maybe ByteString -> IO () Source

Perform the Extended operation synchronously. Raises ResponseError on failures.

extendedEither :: Ldap -> Oid -> Maybe ByteString -> IO (Either ResponseError ()) Source

Perform the Extended operation synchronously. Returns Left e where + e is a ResponseError on failures.

extendedAsync :: Ldap -> Oid -> Maybe ByteString -> IO (Async ()) Source

Perform the Extended operation asynchronously. Call wait to wait + for its completion.

extendedAsyncSTM :: Ldap -> Oid -> Maybe ByteString -> STM (Async ()) Source

Perform the Extended operation asynchronously.

Don't wait for its completion (with waitSTM) in the + same transaction you've performed it in.

\ No newline at end of file diff --git a/Ldap-Client-Internal.html b/Ldap-Client-Internal.html index 7418adb..830532a 100644 --- a/Ldap-Client-Internal.html +++ b/Ldap-Client-Internal.html @@ -1,4 +1,10 @@ Ldap.Client.Internal

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client.Internal

Synopsis

Documentation

data Ldap Source

Constructors

Ldap 

Fields

client :: TQueue ClientMessage
 

Instances

data Async a Source

Instances

newtype Oid Source

Constructors

Oid ByteString 

Instances

type AttrList f = [(Attr, f ByteString)] Source

Waiting for Request Completion

Misc

type Response = NonEmpty InMessage Source

raise :: Exception e => Either e a -> IO a Source

newtype Dn Source

Constructors

Dn Text 

Instances

newtype RelativeDn Source

Constructors

RelativeDn Text 

newtype Attr Source

Constructors

Attr Text 

unAttr :: Attr -> Text Source

\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client.Internal

Synopsis

Documentation

data Ldap Source

Constructors

Ldap 

Fields

client :: TQueue ClientMessage
 

Instances

data Async a Source

Instances

newtype Oid Source

Constructors

Oid Text 

Instances

type AttrList f = [(Attr, f AttrValue)] Source

Waiting for Request Completion

unbindAsync :: Ldap -> IO () Source

Note that unbindAsync does not return an Async, + because LDAP server never responds to UnbindRequests, hence + a call to wait on a hypothetical Async would have resulted + in an exception anyway.

unbindAsyncSTM :: Ldap -> STM () Source

Note that unbindAsyncSTM does not return an Async, + because LDAP server never responds to UnbindRequests, hence + a call to wait on a hypothetical Async would have resulted + in an exception anyway.

Misc

type Response = NonEmpty InMessage Source

raise :: Exception e => Either e a -> IO a Source

newtype Dn Source

Constructors

Dn Text 

Instances

newtype RelativeDn Source

Constructors

RelativeDn Text 

newtype Attr Source

Constructors

Attr Text 

unAttr :: Attr -> Text Source

\ No newline at end of file diff --git a/Ldap-Client-Modify.html b/Ldap-Client-Modify.html index 82abc30..7f47c6e 100644 --- a/Ldap-Client-Modify.html +++ b/Ldap-Client-Modify.html @@ -1,4 +1,13 @@ Ldap.Client.Modify

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client.Modify

\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client.Modify

Description

Modify and + Modify DN operations.

These operations come in four flavours:

Of those, the first one (modify / modifyDn) is probably the most + useful for the typical usecase.

Documentation

data Operation Source

Type of modification being performed.

Constructors

Delete Attr [AttrValue]

Delete values from the attribute. Deletes the attribute if the list is empty or all current values are listed.

Add Attr [AttrValue]

Add values to the attribute, creating it if necessary.

Replace Attr [AttrValue]

Replace all existing values of the attribute with the new list. Deletes the attribute if the list is empty.

modify :: Ldap -> Dn -> [Operation] -> IO () Source

Perform the Modify operation synchronously. Raises ResponseError on failures.

modifyEither :: Ldap -> Dn -> [Operation] -> IO (Either ResponseError ()) Source

Perform the Modify operation synchronously. Returns Left e where + e is a ResponseError on failures.

modifyAsync :: Ldap -> Dn -> [Operation] -> IO (Async ()) Source

Perform the Modify operation asynchronously. Call wait to wait + for its completion.

modifyAsyncSTM :: Ldap -> Dn -> [Operation] -> STM (Async ()) Source

Perform the Modify operation asynchronously.

Don't wait for its completion (with waitSTM) in the + same transaction you've performed it in.

modifyDn :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> IO () Source

Perform the Modify DN operation synchronously. Raises ResponseError on failures.

modifyDnEither :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> IO (Either ResponseError ()) Source

Perform the Modify DN operation synchronously. Returns Left e where + e is a ResponseError on failures.

modifyDnAsync :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> IO (Async ()) Source

Perform the Modify DN operation asynchronously. Call wait to wait + for its completion.

modifyDnAsyncSTM :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> STM (Async ()) Source

Perform the Modify DN operation asynchronously.

Don't wait for its completion (with waitSTM) in the + same transaction you've performed it in.

\ No newline at end of file diff --git a/Ldap-Client-Search.html b/Ldap-Client-Search.html index 8fd4ef9..62c9739 100644 --- a/Ldap-Client-Search.html +++ b/Ldap-Client-Search.html @@ -1,4 +1,7 @@ Ldap.Client.Search

ldap-client-0.1.0: Pure Haskell LDAP Client Library

\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client.Search

Description

Search operation.

This operation comes in four flavours:

Of those, the first one (search) is probably the most useful for the typical usecase.

Documentation

search :: Ldap -> Dn -> Mod Search -> Filter -> [Attr] -> IO [SearchEntry] Source

Perform the Search operation synchronously. Raises ResponseError on failures.

searchEither :: Ldap -> Dn -> Mod Search -> Filter -> [Attr] -> IO (Either ResponseError [SearchEntry]) Source

Perform the Search operation synchronously. Returns Left e where + e is a ResponseError on failures.

searchAsync :: Ldap -> Dn -> Mod Search -> Filter -> [Attr] -> IO (Async [SearchEntry]) Source

Perform the Search operation asynchronously. Call wait to wait + for its completion.

searchAsyncSTM :: Ldap -> Dn -> Mod Search -> Filter -> [Attr] -> STM (Async [SearchEntry]) Source

Perform the Search operation asynchronously.

Don't wait for its completion (with waitSTM) in the + same transaction you've performed it in.

data Mod a Source

Instances

Monoid (Mod a) Source 
Semigroup (Mod a) Source 
\ No newline at end of file diff --git a/Ldap-Client.html b/Ldap-Client.html index f7035dd..2c52051 100644 --- a/Ldap-Client.html +++ b/Ldap-Client.html @@ -1,4 +1,4 @@ Ldap.Client

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client

Synopsis

Documentation

data Ldap Source

Instances

data Async a Source

Instances

with :: Host -> PortNumber -> (Ldap -> IO a) -> IO (Either LdapError a) Source

The entrypoint into LDAP.

Bind

bind :: Ldap -> Dn -> Password -> IO () Source

Search

Search modifiers

data Mod a Source

Instances

Monoid (Mod a) Source 
Semigroup (Mod a) Source 

Modify

modify :: Ldap -> Dn -> [Operation] -> IO () Source

Add

Delete

delete :: Ldap -> Dn -> IO () Source

ModifyDn

modifyDn :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> IO () Source

Compare

Extended

Waiting for completion

Miscellanous

newtype Dn Source

Constructors

Dn Text 

Instances

newtype RelativeDn Source

Constructors

RelativeDn Text 

newtype Oid Source

Constructors

Oid ByteString 

Instances

type AttrList f = [(Attr, f ByteString)] Source

newtype Attr Source

Constructors

Attr Text 

Re-exports

data NonEmpty a :: * -> *

Instances

Monad NonEmpty 
Functor NonEmpty 
MonadFix NonEmpty 
Applicative NonEmpty 
Foldable NonEmpty 
Traversable NonEmpty 
Generic1 NonEmpty 
MonadZip NonEmpty 
IsList (NonEmpty a) 
Eq a => Eq (NonEmpty a) 
Data a => Data (NonEmpty a) 
Ord a => Ord (NonEmpty a) 
Read a => Read (NonEmpty a) 
Show a => Show (NonEmpty a) 
Generic (NonEmpty a) 
NFData a => NFData (NonEmpty a) 
Hashable a => Hashable (NonEmpty a) 
ToAsn1 a => ToAsn1 (NonEmpty a) 
Semigroup (NonEmpty a) 
type Rep1 NonEmpty = D1 D1NonEmpty (C1 C1_0NonEmpty ((:*:) (S1 NoSelector Par1) (S1 NoSelector (Rec1 [])))) 
type Rep (NonEmpty a) = D1 D1NonEmpty (C1 C1_0NonEmpty ((:*:) (S1 NoSelector (Rec0 a)) (S1 NoSelector (Rec0 [a])))) 
type Item (NonEmpty a) = a 
\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Safe HaskellNone
LanguageHaskell2010

Ldap.Client

Synopsis

Documentation

data Ldap Source

Instances

data Async a Source

Instances

with :: Host -> PortNumber -> (Ldap -> IO a) -> IO (Either LdapError a) Source

The entrypoint into LDAP.

Bind

bind :: Ldap -> Dn -> Password -> IO () Source

Perform the Bind operation synchronously. Raises ResponseError on failures.

Search

search :: Ldap -> Dn -> Mod Search -> Filter -> [Attr] -> IO [SearchEntry] Source

Perform the Search operation synchronously. Raises ResponseError on failures.

Search modifiers

data Mod a Source

Instances

Monoid (Mod a) Source 
Semigroup (Mod a) Source 

Modify

modify :: Ldap -> Dn -> [Operation] -> IO () Source

Perform the Modify operation synchronously. Raises ResponseError on failures.

data Operation Source

Type of modification being performed.

Constructors

Delete Attr [AttrValue]

Delete values from the attribute. Deletes the attribute if the list is empty or all current values are listed.

Add Attr [AttrValue]

Add values to the attribute, creating it if necessary.

Replace Attr [AttrValue]

Replace all existing values of the attribute with the new list. Deletes the attribute if the list is empty.

Add

add :: Ldap -> Dn -> AttrList NonEmpty -> IO () Source

Perform the Add operation synchronously. Raises ResponseError on failures.

Delete

delete :: Ldap -> Dn -> IO () Source

Perform the Delete operation synchronously. Raises ResponseError on failures.

ModifyDn

modifyDn :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> IO () Source

Perform the Modify DN operation synchronously. Raises ResponseError on failures.

Compare

compare :: Ldap -> Dn -> Attr -> AttrValue -> IO Bool Source

Perform the Compare operation synchronously. Raises ResponseError on failures.

Extended

extended :: Ldap -> Oid -> Maybe ByteString -> IO () Source

Perform the Extended operation synchronously. Raises ResponseError on failures.

Waiting for completion

Miscellanous

newtype Dn Source

Constructors

Dn Text 

Instances

newtype RelativeDn Source

Constructors

RelativeDn Text 

newtype Oid Source

Constructors

Oid Text 

Instances

type AttrList f = [(Attr, f AttrValue)] Source

newtype Attr Source

Constructors

Attr Text 

Re-exports

data NonEmpty a :: * -> *

Instances

Monad NonEmpty 
Functor NonEmpty 
MonadFix NonEmpty 
Applicative NonEmpty 
Foldable NonEmpty 
Traversable NonEmpty 
Generic1 NonEmpty 
MonadZip NonEmpty 
IsList (NonEmpty a) 
Eq a => Eq (NonEmpty a) 
Data a => Data (NonEmpty a) 
Ord a => Ord (NonEmpty a) 
Read a => Read (NonEmpty a) 
Show a => Show (NonEmpty a) 
Generic (NonEmpty a) 
NFData a => NFData (NonEmpty a) 
Hashable a => Hashable (NonEmpty a) 
ToAsn1 a => ToAsn1 (NonEmpty a) 
Semigroup (NonEmpty a) 
type Rep1 NonEmpty = D1 D1NonEmpty (C1 C1_0NonEmpty ((:*:) (S1 NoSelector Par1) (S1 NoSelector (Rec1 [])))) 
type Rep (NonEmpty a) = D1 D1NonEmpty (C1 C1_0NonEmpty ((:*:) (S1 NoSelector (Rec0 a)) (S1 NoSelector (Rec0 [a])))) 
type Item (NonEmpty a) = a 
\ No newline at end of file diff --git a/doc-index-A.html b/doc-index-A.html index 83b816b..cc1ecc1 100644 --- a/doc-index-A.html +++ b/doc-index-A.html @@ -1,4 +1,4 @@ ldap-client-0.1.0: Pure Haskell LDAP Client Library (Index - A)

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Index - A

Add 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Modify, Ldap.Client
addLdap.Client.Add, Ldap.Client
addAsyncLdap.Client.Add
addAsyncSTMLdap.Client.Add
addEitherLdap.Client.Add
AddRequestLdap.Asn1.Type
AddResponseLdap.Asn1.Type
AdminLimitExceededLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
AffectsMultipleDSAsLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
AliasDereferencingProblemLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
AliasProblemLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
And 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Search, Ldap.Client
AnyLdap.Asn1.Type
ApproxMatchLdap.Asn1.Type
AssertionValue 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AsyncLdap.Client.Internal, Ldap.Client
Attr 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal, Ldap.Client
Attribute 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeDescription 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeList 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeOrValueExistsLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
AttributeSelection 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeValue 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeValueAssertion 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttrListLdap.Client.Internal, Ldap.Client
AuthenticationChoiceLdap.Asn1.Type
AuthMethodNotSupportedLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Index - A

Add 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Modify, Ldap.Client
addLdap.Client.Add, Ldap.Client
addAsyncLdap.Client.Add
addAsyncSTMLdap.Client.Add
addEitherLdap.Client.Add
AddRequestLdap.Asn1.Type
AddResponseLdap.Asn1.Type
AdminLimitExceededLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
AffectsMultipleDSAsLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
AliasDereferencingProblemLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
AliasProblemLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
And 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Search, Ldap.Client
AnyLdap.Asn1.Type
ApproxMatchLdap.Asn1.Type
AssertionValue 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AsyncLdap.Client.Internal, Ldap.Client
Attr 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal, Ldap.Client
Attribute 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeDescription 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeList 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeOrValueExistsLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
AttributeSelection 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeValue 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeValueAssertion 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttrListLdap.Client.Internal, Ldap.Client
AttrValueLdap.Client.Internal, Ldap.Client
AuthenticationChoiceLdap.Asn1.Type
AuthMethodNotSupportedLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
\ No newline at end of file diff --git a/doc-index-All.html b/doc-index-All.html index 200d2cc..3a297d7 100644 --- a/doc-index-All.html +++ b/doc-index-All.html @@ -1,4 +1,4 @@ ldap-client-0.1.0: Pure Haskell LDAP Client Library (Index)

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Index

::=Ldap.Client.Search, Ldap.Client
:<=Ldap.Client.Search, Ldap.Client
:=Ldap.Client.Search, Ldap.Client
:=*Ldap.Client.Search, Ldap.Client
:>=Ldap.Client.Search, Ldap.Client
:~=Ldap.Client.Search, Ldap.Client
Add 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Modify, Ldap.Client
addLdap.Client.Add, Ldap.Client
addAsyncLdap.Client.Add
addAsyncSTMLdap.Client.Add
addEitherLdap.Client.Add
AddRequestLdap.Asn1.Type
AddResponseLdap.Asn1.Type
AdminLimitExceededLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
AffectsMultipleDSAsLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
AliasDereferencingProblemLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
AliasProblemLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
And 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Search, Ldap.Client
AnyLdap.Asn1.Type
ApproxMatchLdap.Asn1.Type
AssertionValue 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AsyncLdap.Client.Internal, Ldap.Client
Attr 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal, Ldap.Client
Attribute 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeDescription 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeList 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeOrValueExistsLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
AttributeSelection 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeValue 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeValueAssertion 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttrListLdap.Client.Internal, Ldap.Client
AuthenticationChoiceLdap.Asn1.Type
AuthMethodNotSupportedLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
BaseObjectLdap.Asn1.Type, Ldap.Client.Search, Ldap.Client
bindLdap.Client.Bind, Ldap.Client
bindAsyncLdap.Client.Bind
bindAsyncSTMLdap.Client.Bind
bindEitherLdap.Client.Bind
BindRequestLdap.Asn1.Type
BindResponseLdap.Asn1.Type
BusyLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
clientLdap.Client.Internal
ClientMessageLdap.Client.Internal
compareLdap.Client.Compare, Ldap.Client
compareAsyncLdap.Client.Compare
compareAsyncSTMLdap.Client.Compare
compareEitherLdap.Client.Compare
CompareFalseLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
CompareRequestLdap.Asn1.Type
CompareResponseLdap.Asn1.Type
CompareTrueLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ConfidentialityRequiredLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ConstraintViolationLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
Control 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
Controls 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
Delete 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Modify, Ldap.Client
deleteLdap.Client.Delete, Ldap.Client
deleteAsyncLdap.Client.Delete
deleteAsyncSTMLdap.Client.Delete
deleteEitherLdap.Client.Delete
DeleteRequestLdap.Asn1.Type
DeleteResponseLdap.Asn1.Type
DerefAliasesLdap.Asn1.Type
derefAliasesLdap.Client.Search, Ldap.Client
DerefAlwaysLdap.Asn1.Type
DerefFindingBaseObjectLdap.Asn1.Type
DerefInSearchingLdap.Asn1.Type
Dn 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal, Ldap.Client
EntryAlreadyExistsLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
EqualityMatchLdap.Asn1.Type
extendedLdap.Client.Extended, Ldap.Client
extendedAsyncLdap.Client.Extended
extendedAsyncSTMLdap.Client.Extended
extendedEitherLdap.Client.Extended
ExtendedRequestLdap.Asn1.Type
ExtendedResponseLdap.Asn1.Type
ExtensibleMatchLdap.Asn1.Type
Filter 
1 (Type/Class)Ldap.Asn1.Type
2 (Type/Class)Ldap.Client.Search, Ldap.Client
FinalLdap.Asn1.Type
FromAsn1Ldap.Asn1.FromAsn1
fromAsn1Ldap.Asn1.FromAsn1
GreaterOrEqualLdap.Asn1.Type
HostLdap.Client.Internal, Ldap.Client
Id 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
InappropriateAuthenticationLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
InappropriateMatchingLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
InitialLdap.Asn1.Type
InsecureLdap.Client.Internal, Ldap.Client
InsufficientAccessRightsLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
InvalidAttributeSyntaxLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
InvalidCredentialsLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
InvalidDNSyntaxLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
IOErrorLdap.Client
Ldap 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal
LdapDn 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
LdapErrorLdap.Client
LdapMessage 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
ldapMessageControlsLdap.Asn1.Type
ldapMessageIdLdap.Asn1.Type
ldapMessageOpLdap.Asn1.Type
LdapOid 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
LdapResult 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
LdapString 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
LessOrEqualLdap.Asn1.Type
LoopDetectLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
MatchingRuleAssertion 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
MatchingRuleId 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
ModLdap.Client.Search, Ldap.Client
modifyLdap.Client.Modify, Ldap.Client
modifyAsyncLdap.Client.Modify
modifyAsyncSTMLdap.Client.Modify
modifyDnLdap.Client.Modify, Ldap.Client
modifyDnAsyncLdap.Client.Modify
modifyDnAsyncSTMLdap.Client.Modify
modifyDnEitherLdap.Client.Modify
ModifyDnRequestLdap.Asn1.Type
ModifyDnResponseLdap.Asn1.Type
modifyEitherLdap.Client.Modify
ModifyRequestLdap.Asn1.Type
ModifyResponseLdap.Asn1.Type
NamingViolationLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
NeverDerefAliasesLdap.Asn1.Type
NewLdap.Client.Internal
nextLdap.Asn1.FromAsn1
NonEmptyLdap.Client
NoSuchAttributeLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
NoSuchObjectLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
Not 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Search, Ldap.Client
NotAllowedOnNonLeafLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
NotAllowedOnRDNLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ObjectClassModsProhibitedLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ObjectClassViolationLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
Oid 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal, Ldap.Client
Operation 
1 (Type/Class)Ldap.Asn1.Type
2 (Type/Class)Ldap.Client.Modify, Ldap.Client
OperationErrorLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
Or 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Search, Ldap.Client
OtherLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
parseLdap.Asn1.FromAsn1
parseAsn1Ldap.Asn1.FromAsn1
ParseErrorLdap.Client
ParserLdap.Asn1.FromAsn1
PartialAttribute 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
PartialAttributeList 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
Password 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal, Ldap.Client
PlainLdap.Client.Internal, Ldap.Client
PortNumberLdap.Client.Internal, Ldap.Client
Present 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Search, Ldap.Client
ProtocolClientOpLdap.Asn1.Type
ProtocolErrorLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ProtocolServerOpLdap.Asn1.Type
raiseLdap.Client.Internal
ReferralLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ReferralUris 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
RelativeDn 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal, Ldap.Client
RelativeLdapDn 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
Replace 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Modify, Ldap.Client
RequestLdap.Client.Internal
ResponseLdap.Client.Internal
ResponseError 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client
ResponseErrorCodeLdap.Client.Internal, Ldap.Client
ResponseInvalidLdap.Client.Internal, Ldap.Client
ResultCodeLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
SaslBindInProgressLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ScopeLdap.Asn1.Type, Ldap.Client.Search, Ldap.Client
scopeLdap.Client.Search, Ldap.Client
SearchLdap.Client.Search, Ldap.Client
searchLdap.Client.Search, Ldap.Client
searchAsyncLdap.Client.Search
searchAsyncSTMLdap.Client.Search
searchEitherLdap.Client.Search
SearchEntry 
1 (Type/Class)Ldap.Client.Search, Ldap.Client
2 (Data Constructor)Ldap.Client.Search, Ldap.Client
SearchRequestLdap.Asn1.Type
SearchResultDoneLdap.Asn1.Type
SearchResultEntryLdap.Asn1.Type
SearchResultReferenceLdap.Asn1.Type
SecureLdap.Client.Internal, Ldap.Client
sendRequestLdap.Client.Internal
SimpleLdap.Asn1.Type
SingleLevelLdap.Asn1.Type, Ldap.Client.Search, Ldap.Client
sizeLdap.Client.Search, Ldap.Client
SizeLimitExceededLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
startTlsLdap.Client.Extended
startTlsAsyncLdap.Client.Extended
startTlsAsyncSTMLdap.Client.Extended
startTlsEitherLdap.Client.Extended
StrongerAuthRequiredLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
SubstringLdap.Asn1.Type
SubstringFilter 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
SubstringsLdap.Asn1.Type
SuccessLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
timeLdap.Client.Search, Ldap.Client
TimeLimitExceededLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ToAsn1Ldap.Asn1.ToAsn1
toAsn1Ldap.Asn1.ToAsn1
typesOnlyLdap.Client.Search, Ldap.Client
unAttrLdap.Client.Internal
UnavailableLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
UnavailableCriticalExtensionLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
unbindAsyncLdap.Client.Bind
unbindAsyncSTMLdap.Client.Bind
UnbindRequestLdap.Asn1.Type
UndefinedAttributeTypeLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
unIdLdap.Asn1.Type
UnwillingToPerformLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
Uri 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
waitLdap.Client.Internal, Ldap.Client
waitSTMLdap.Client.Internal
WholeSubtreeLdap.Asn1.Type, Ldap.Client.Search, Ldap.Client
withLdap.Client
\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Index

::=Ldap.Client.Search, Ldap.Client
:<=Ldap.Client.Search, Ldap.Client
:=Ldap.Client.Search, Ldap.Client
:=*Ldap.Client.Search, Ldap.Client
:>=Ldap.Client.Search, Ldap.Client
:~=Ldap.Client.Search, Ldap.Client
Add 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Modify, Ldap.Client
addLdap.Client.Add, Ldap.Client
addAsyncLdap.Client.Add
addAsyncSTMLdap.Client.Add
addEitherLdap.Client.Add
AddRequestLdap.Asn1.Type
AddResponseLdap.Asn1.Type
AdminLimitExceededLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
AffectsMultipleDSAsLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
AliasDereferencingProblemLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
AliasProblemLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
And 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Search, Ldap.Client
AnyLdap.Asn1.Type
ApproxMatchLdap.Asn1.Type
AssertionValue 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AsyncLdap.Client.Internal, Ldap.Client
Attr 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal, Ldap.Client
Attribute 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeDescription 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeList 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeOrValueExistsLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
AttributeSelection 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeValue 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttributeValueAssertion 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
AttrListLdap.Client.Internal, Ldap.Client
AttrValueLdap.Client.Internal, Ldap.Client
AuthenticationChoiceLdap.Asn1.Type
AuthMethodNotSupportedLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
BaseObjectLdap.Asn1.Type, Ldap.Client.Search, Ldap.Client
bindLdap.Client.Bind, Ldap.Client
bindAsyncLdap.Client.Bind
bindAsyncSTMLdap.Client.Bind
bindEitherLdap.Client.Bind
BindRequestLdap.Asn1.Type
BindResponseLdap.Asn1.Type
BusyLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
clientLdap.Client.Internal
ClientMessageLdap.Client.Internal
compareLdap.Client.Compare, Ldap.Client
compareAsyncLdap.Client.Compare
compareAsyncSTMLdap.Client.Compare
compareEitherLdap.Client.Compare
CompareFalseLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
CompareRequestLdap.Asn1.Type
CompareResponseLdap.Asn1.Type
CompareTrueLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ConfidentialityRequiredLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ConstraintViolationLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
Control 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
Controls 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
Delete 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Modify, Ldap.Client
deleteLdap.Client.Delete, Ldap.Client
deleteAsyncLdap.Client.Delete
deleteAsyncSTMLdap.Client.Delete
deleteEitherLdap.Client.Delete
DeleteRequestLdap.Asn1.Type
DeleteResponseLdap.Asn1.Type
DerefAliasesLdap.Asn1.Type
derefAliasesLdap.Client.Search, Ldap.Client
DerefAlwaysLdap.Asn1.Type
DerefFindingBaseObjectLdap.Asn1.Type
DerefInSearchingLdap.Asn1.Type
DisconnectErrorLdap.Client
Dn 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal, Ldap.Client
EntryAlreadyExistsLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
EqualityMatchLdap.Asn1.Type
extendedLdap.Client.Extended, Ldap.Client
extendedAsyncLdap.Client.Extended
extendedAsyncSTMLdap.Client.Extended
extendedEitherLdap.Client.Extended
ExtendedRequestLdap.Asn1.Type
ExtendedResponseLdap.Asn1.Type
ExtensibleMatchLdap.Asn1.Type
Filter 
1 (Type/Class)Ldap.Asn1.Type
2 (Type/Class)Ldap.Client.Search, Ldap.Client
FinalLdap.Asn1.Type
FromAsn1Ldap.Asn1.FromAsn1
GreaterOrEqualLdap.Asn1.Type
HostLdap.Client.Internal, Ldap.Client
Id 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
InappropriateAuthenticationLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
InappropriateMatchingLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
InitialLdap.Asn1.Type
InsecureLdap.Client.Internal, Ldap.Client
InsufficientAccessRightsLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
IntermediateResponseLdap.Asn1.Type
InvalidAttributeSyntaxLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
InvalidCredentialsLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
InvalidDNSyntaxLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
IOErrorLdap.Client
Ldap 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal
LdapDn 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
LdapErrorLdap.Client
LdapMessage 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
ldapMessageControlsLdap.Asn1.Type
ldapMessageIdLdap.Asn1.Type
ldapMessageOpLdap.Asn1.Type
LdapOid 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
LdapResult 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
LdapString 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
LessOrEqualLdap.Asn1.Type
LoopDetectLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
MatchingRuleAssertion 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
MatchingRuleId 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
ModLdap.Client.Search, Ldap.Client
modifyLdap.Client.Modify, Ldap.Client
modifyAsyncLdap.Client.Modify
modifyAsyncSTMLdap.Client.Modify
modifyDnLdap.Client.Modify, Ldap.Client
modifyDnAsyncLdap.Client.Modify
modifyDnAsyncSTMLdap.Client.Modify
modifyDnEitherLdap.Client.Modify
ModifyDnRequestLdap.Asn1.Type
ModifyDnResponseLdap.Asn1.Type
modifyEitherLdap.Client.Modify
ModifyRequestLdap.Asn1.Type
ModifyResponseLdap.Asn1.Type
NamingViolationLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
NeverDerefAliasesLdap.Asn1.Type
NewLdap.Client.Internal
NonEmptyLdap.Client
NoSuchAttributeLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
NoSuchObjectLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
Not 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Search, Ldap.Client
NotAllowedOnNonLeafLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
NotAllowedOnRDNLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ObjectClassModsProhibitedLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ObjectClassViolationLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
Oid 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal, Ldap.Client
Operation 
1 (Type/Class)Ldap.Asn1.Type
2 (Type/Class)Ldap.Client.Modify, Ldap.Client
OperationErrorLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
Or 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Search, Ldap.Client
OtherLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
parseAsn1Ldap.Asn1.FromAsn1
ParseErrorLdap.Client
PartialAttribute 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
PartialAttributeList 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
Password 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal, Ldap.Client
PlainLdap.Client.Internal, Ldap.Client
PortNumberLdap.Client.Internal, Ldap.Client
Present 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Search, Ldap.Client
ProtocolClientOpLdap.Asn1.Type
ProtocolErrorLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ProtocolServerOpLdap.Asn1.Type
raiseLdap.Client.Internal
ReferralLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ReferralUris 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
RelativeDn 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal, Ldap.Client
RelativeLdapDn 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
Replace 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Modify, Ldap.Client
RequestLdap.Client.Internal
ResponseLdap.Client.Internal
ResponseError 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client
ResponseErrorCodeLdap.Client.Internal, Ldap.Client
ResponseInvalidLdap.Client.Internal, Ldap.Client
ResultCodeLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
SaslBindInProgressLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ScopeLdap.Asn1.Type, Ldap.Client.Search, Ldap.Client
scopeLdap.Client.Search, Ldap.Client
SearchLdap.Client.Search, Ldap.Client
searchLdap.Client.Search, Ldap.Client
searchAsyncLdap.Client.Search
searchAsyncSTMLdap.Client.Search
searchEitherLdap.Client.Search
SearchEntry 
1 (Type/Class)Ldap.Client.Search, Ldap.Client
2 (Data Constructor)Ldap.Client.Search, Ldap.Client
SearchRequestLdap.Asn1.Type
SearchResultDoneLdap.Asn1.Type
SearchResultEntryLdap.Asn1.Type
SearchResultReferenceLdap.Asn1.Type
SecureLdap.Client.Internal, Ldap.Client
sendRequestLdap.Client.Internal
SimpleLdap.Asn1.Type
SingleLevelLdap.Asn1.Type, Ldap.Client.Search, Ldap.Client
sizeLdap.Client.Search, Ldap.Client
SizeLimitExceededLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
startTlsLdap.Client.Extended
startTlsAsyncLdap.Client.Extended
startTlsAsyncSTMLdap.Client.Extended
startTlsEitherLdap.Client.Extended
StrongerAuthRequiredLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
SubstringLdap.Asn1.Type
SubstringFilter 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
SubstringsLdap.Asn1.Type
SuccessLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
timeLdap.Client.Search, Ldap.Client
TimeLimitExceededLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ToAsn1Ldap.Asn1.ToAsn1
toAsn1Ldap.Asn1.ToAsn1
typesOnlyLdap.Client.Search, Ldap.Client
unAttrLdap.Client.Internal
UnavailableLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
UnavailableCriticalExtensionLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
unbindAsyncLdap.Client.Internal
unbindAsyncSTMLdap.Client.Internal
UnbindRequestLdap.Asn1.Type
UndefinedAttributeTypeLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
unIdLdap.Asn1.Type
UnwillingToPerformLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
Uri 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
waitLdap.Client.Internal, Ldap.Client
waitSTMLdap.Client.Internal
WholeSubtreeLdap.Asn1.Type, Ldap.Client.Search, Ldap.Client
withLdap.Client
\ No newline at end of file diff --git a/doc-index-D.html b/doc-index-D.html index 47b33ad..aef5395 100644 --- a/doc-index-D.html +++ b/doc-index-D.html @@ -1,4 +1,4 @@ ldap-client-0.1.0: Pure Haskell LDAP Client Library (Index - D)

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Index - D

Delete 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Modify, Ldap.Client
deleteLdap.Client.Delete, Ldap.Client
deleteAsyncLdap.Client.Delete
deleteAsyncSTMLdap.Client.Delete
deleteEitherLdap.Client.Delete
DeleteRequestLdap.Asn1.Type
DeleteResponseLdap.Asn1.Type
DerefAliasesLdap.Asn1.Type
derefAliasesLdap.Client.Search, Ldap.Client
DerefAlwaysLdap.Asn1.Type
DerefFindingBaseObjectLdap.Asn1.Type
DerefInSearchingLdap.Asn1.Type
Dn 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal, Ldap.Client
\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Index - D

Delete 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Modify, Ldap.Client
deleteLdap.Client.Delete, Ldap.Client
deleteAsyncLdap.Client.Delete
deleteAsyncSTMLdap.Client.Delete
deleteEitherLdap.Client.Delete
DeleteRequestLdap.Asn1.Type
DeleteResponseLdap.Asn1.Type
DerefAliasesLdap.Asn1.Type
derefAliasesLdap.Client.Search, Ldap.Client
DerefAlwaysLdap.Asn1.Type
DerefFindingBaseObjectLdap.Asn1.Type
DerefInSearchingLdap.Asn1.Type
DisconnectErrorLdap.Client
Dn 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal, Ldap.Client
\ No newline at end of file diff --git a/doc-index-F.html b/doc-index-F.html index c2364f2..15aafd1 100644 --- a/doc-index-F.html +++ b/doc-index-F.html @@ -1,4 +1,4 @@ ldap-client-0.1.0: Pure Haskell LDAP Client Library (Index - F)

ldap-client-0.1.0: Pure Haskell LDAP Client Library

\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

\ No newline at end of file diff --git a/doc-index-I.html b/doc-index-I.html index 4ca0f6e..5fc8993 100644 --- a/doc-index-I.html +++ b/doc-index-I.html @@ -1,4 +1,4 @@ ldap-client-0.1.0: Pure Haskell LDAP Client Library (Index - I)

ldap-client-0.1.0: Pure Haskell LDAP Client Library

\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

\ No newline at end of file diff --git a/doc-index-N.html b/doc-index-N.html index 95f5559..fc2f894 100644 --- a/doc-index-N.html +++ b/doc-index-N.html @@ -1,4 +1,4 @@ ldap-client-0.1.0: Pure Haskell LDAP Client Library (Index - N)

ldap-client-0.1.0: Pure Haskell LDAP Client Library

\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

\ No newline at end of file diff --git a/doc-index-P.html b/doc-index-P.html index 09bd77b..b12db76 100644 --- a/doc-index-P.html +++ b/doc-index-P.html @@ -1,4 +1,4 @@ ldap-client-0.1.0: Pure Haskell LDAP Client Library (Index - P)

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Index - P

parseLdap.Asn1.FromAsn1
parseAsn1Ldap.Asn1.FromAsn1
ParseErrorLdap.Client
ParserLdap.Asn1.FromAsn1
PartialAttribute 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
PartialAttributeList 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
Password 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal, Ldap.Client
PlainLdap.Client.Internal, Ldap.Client
PortNumberLdap.Client.Internal, Ldap.Client
Present 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Search, Ldap.Client
ProtocolClientOpLdap.Asn1.Type
ProtocolErrorLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ProtocolServerOpLdap.Asn1.Type
\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

Index - P

parseAsn1Ldap.Asn1.FromAsn1
ParseErrorLdap.Client
PartialAttribute 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
PartialAttributeList 
1 (Type/Class)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Asn1.Type
Password 
1 (Type/Class)Ldap.Client.Internal, Ldap.Client
2 (Data Constructor)Ldap.Client.Internal, Ldap.Client
PlainLdap.Client.Internal, Ldap.Client
PortNumberLdap.Client.Internal, Ldap.Client
Present 
1 (Data Constructor)Ldap.Asn1.Type
2 (Data Constructor)Ldap.Client.Search, Ldap.Client
ProtocolClientOpLdap.Asn1.Type
ProtocolErrorLdap.Asn1.Type, Ldap.Client.Internal, Ldap.Client
ProtocolServerOpLdap.Asn1.Type
\ No newline at end of file diff --git a/doc-index-U.html b/doc-index-U.html index 0961a58..a80ee7c 100644 --- a/doc-index-U.html +++ b/doc-index-U.html @@ -1,4 +1,4 @@ ldap-client-0.1.0: Pure Haskell LDAP Client Library (Index - U)

ldap-client-0.1.0: Pure Haskell LDAP Client Library

\ No newline at end of file +

ldap-client-0.1.0: Pure Haskell LDAP Client Library

\ No newline at end of file diff --git a/ldap-client.haddock b/ldap-client.haddock index df2ff38acc3eaad802bb87c3075f6491d53d8a9b..da7f89974cc574d5b9e476712e62d2a1e260294e 100644 GIT binary patch literal 78863 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.Asn1.FromAsn1

Ldap.Asn1.FromAsn1

\ No newline at end of file +

Ldap.Asn1.FromAsn1

\ No newline at end of file diff --git a/mini_Ldap-Client-Bind.html b/mini_Ldap-Client-Bind.html index 7ed621a..834210c 100644 --- a/mini_Ldap-Client-Bind.html +++ b/mini_Ldap-Client-Bind.html @@ -1,4 +1,4 @@ Ldap.Client.Bind

Ldap.Client.Bind

\ No newline at end of file +

Ldap.Client.Bind

\ No newline at end of file diff --git a/mini_Ldap-Client-Internal.html b/mini_Ldap-Client-Internal.html index 9229263..510ec9f 100644 --- a/mini_Ldap-Client-Internal.html +++ b/mini_Ldap-Client-Internal.html @@ -1,4 +1,4 @@ Ldap.Client.Internal

Ldap.Client.Internal

data Host

data Ldap

data Async a

data Oid

type AttrList f

Waiting for Request Completion

Misc

type Request

data Dn

data Attr

\ No newline at end of file +

Ldap.Client.Internal

data Host

data Ldap

data Async a

data Oid

type AttrList f

Waiting for Request Completion

Misc

type Request

data Dn

data Attr

\ No newline at end of file diff --git a/mini_Ldap-Client.html b/mini_Ldap-Client.html index 7165334..bcbb978 100644 --- a/mini_Ldap-Client.html +++ b/mini_Ldap-Client.html @@ -1,4 +1,4 @@ Ldap.Client

Ldap.Client

data Host

data Ldap

data Async a

Bind

Search

Search modifiers

data Search

data Mod a

data Scope

data Filter

Modify

Add

Delete

ModifyDn

Compare

Extended

Waiting for completion

Miscellanous

data Dn

data Oid

type AttrList f

data Attr

Re-exports

data NonEmpty a

\ No newline at end of file +

Ldap.Client

data Host

data Ldap

data Async a

Bind

Search

Search modifiers

data Search

data Mod a

data Scope

data Filter

Modify

Add

Delete

ModifyDn

Compare

Extended

Waiting for completion

Miscellanous

data Dn

data Oid

type AttrList f

data Attr

Re-exports

data NonEmpty a

\ No newline at end of file diff --git a/src/Ldap-Asn1-FromAsn1.html b/src/Ldap-Asn1-FromAsn1.html index b526d8a..ab3b825 100644 --- a/src/Ldap-Asn1-FromAsn1.html +++ b/src/Ldap-Asn1-FromAsn1.html @@ -8,382 +8,427 @@
{-# LANGUAGE CPP #-}
-module Ldap.Asn1.FromAsn1
-  ( FromAsn1(..)
-  , Parser
-  , parseAsn1
-  , parse
-  , next
-  ) where
-
-#if __GLASGOW_HASKELL__ >= 710
-import           Control.Applicative (Alternative(..), liftA2, optional)
-#else
-import           Control.Applicative (Applicative(..), Alternative(..), liftA2, optional)
-#endif
-import           Control.Monad (MonadPlus(..), (>=>), guard)
-import           Data.ASN1.Types (ASN1)
-import qualified Data.ASN1.Types as Asn1
-import           Data.Foldable (asum)
-import           Data.List.NonEmpty (some1)
-import qualified Data.Text.Encoding as Text
+-- | This module contains convertions from ASN.1 to LDAP types.
+module Ldap.Asn1.FromAsn1
+  ( parseAsn1
+  , FromAsn1
+  ) where
+
+#if __GLASGOW_HASKELL__ >= 710
+import           Control.Applicative (Alternative(..), liftA2, optional)
+#else
+import           Control.Applicative (Applicative(..), Alternative(..), liftA2, optional)
+#endif
+import           Control.Monad (MonadPlus(..), (>=>), guard)
+import           Data.ASN1.Types (ASN1)
+import qualified Data.ASN1.Types as Asn1
+import           Data.Foldable (asum)
+import           Data.List.NonEmpty (some1)
+import qualified Data.Text.Encoding as Text
+
+import           Ldap.Asn1.Type
 
-import           Ldap.Asn1.Type
-
-{-# ANN module "HLint: ignore Use const" #-}
-{-# ANN module "HLint: ignore Avoid lambda" #-}
-
-
-class FromAsn1 a where
-  fromAsn1 :: Parser [ASN1] a
-
-{- |
-@
-LDAPMessage ::= SEQUENCE {
-     messageID       MessageID,
-     protocolOp      CHOICE {
-          bindRequest           BindRequest,
-          bindResponse          BindResponse,
-          unbindRequest         UnbindRequest,
-          searchRequest         SearchRequest,
-          searchResEntry        SearchResultEntry,
-          searchResDone         SearchResultDone,
-          searchResRef          SearchResultReference,
-          addRequest            AddRequest,
-          addResponse           AddResponse,
-          ... },
-     controls       [0] Controls OPTIONAL }
-@
--}
-instance FromAsn1 op =>  FromAsn1 (LdapMessage op) where
-  fromAsn1 = do
-    Asn1.Start Asn1.Sequence <- next
-    i  <- fromAsn1
-    op <- fromAsn1
-    Asn1.End Asn1.Sequence <- next
-    return (LdapMessage i op Nothing)
-
-{- |
-@
-MessageID ::= INTEGER (0 ..  maxInt)
-@
--}
-instance FromAsn1 Id where
-  fromAsn1 = do
-    Asn1.IntVal i <- next
-    return (Id (fromIntegral i))
-
-{- |
-@
-LDAPString ::= OCTET STRING -- UTF-8 encoded,
-@
--}
-instance FromAsn1 LdapString where
-  fromAsn1 = do
-    Asn1.OctetString s <- next
-    case Text.decodeUtf8' s of
-      Right t -> return (LdapString t)
-      Left  _ -> empty
-
-{- |
-@
-LDAPOID ::= OCTET STRING -- Constrained to \<numericoid\>
-@
--}
-instance FromAsn1 LdapOid where
-  fromAsn1 = do
-    Asn1.OctetString s <- next
-    return (LdapOid s)
-
-{- |
-@
-LDAPDN ::= LDAPString
-@
--}
-instance FromAsn1 LdapDn where
-  fromAsn1 = fmap LdapDn fromAsn1
-
-{- |
-@
-AttributeDescription ::= LDAPString
-@
--}
-instance FromAsn1 AttributeDescription where
-  fromAsn1 = fmap AttributeDescription fromAsn1
-
-{- |
-@
-AttributeValue ::= OCTET STRING
-@
--}
-instance FromAsn1 AttributeValue where
-  fromAsn1 = do
-    Asn1.OctetString s <- next
-    return (AttributeValue s)
-
-{- |
-@
-PartialAttribute ::= SEQUENCE {
-     type       AttributeDescription,
-     vals       SET OF value AttributeValue }
-@
--}
-instance FromAsn1 PartialAttribute where
-  fromAsn1 = do
-    Asn1.Start Asn1.Sequence <- next
-    d  <- fromAsn1
-    Asn1.Start Asn1.Set <- next
-    vs <- many fromAsn1
-    Asn1.End Asn1.Set <- next
-    Asn1.End Asn1.Sequence <- next
-    return (PartialAttribute d vs)
-
-{- |
-@
-LDAPResult ::= SEQUENCE {
-     resultCode         ENUMERATED {
-          success                      (0),
-          operationsError              (1),
-          protocolError                (2),
-          timeLimitExceeded            (3),
-          sizeLimitExceeded            (4),
-          compareFalse                 (5),
-          compareTrue                  (6),
-          authMethodNotSupported       (7),
-          strongerAuthRequired         (8),
-          -- 9 reserved --
-          referral                     (10),
-          adminLimitExceeded           (11),
-          unavailableCriticalExtension (12),
-          confidentialityRequired      (13),
-          saslBindInProgress           (14),
-          noSuchAttribute              (16),
-          undefinedAttributeType       (17),
-          inappropriateMatching        (18),
-          constraintViolation          (19),
-          attributeOrValueExists       (20),
-          invalidAttributeSyntax       (21),
-          -- 22-31 unused --
-          noSuchObject                 (32),
-          aliasProblem                 (33),
-          invalidDNSyntax              (34),
-          -- 35 reserved for undefined isLeaf --
-          aliasDereferencingProblem    (36),
-          -- 37-47 unused --
-          inappropriateAuthentication  (48),
-          invalidCredentials           (49),
-          insufficientAccessRights     (50),
-          busy                         (51),
-          unavailable                  (52),
-          unwillingToPerform           (53),
-          loopDetect                   (54),
-          -- 55-63 unused --
-          namingViolation              (64),
-          objectClassViolation         (65),
-          notAllowedOnNonLeaf          (66),
-          notAllowedOnRDN              (67),
-          entryAlreadyExists           (68),
-          objectClassModsProhibited    (69),
-          -- 70 reserved for CLDAP --
-          affectsMultipleDSAs          (71),
-          -- 72-79 unused --
-          other                        (80),
-          ...  },
-     matchedDN          LDAPDN,
-     diagnosticMessage  LDAPString,
-     referral           [3] Referral OPTIONAL }
-@
--}
-instance FromAsn1 LdapResult where
-  fromAsn1 = do
-    resultCode <- do
-      Asn1.Enumerated x <- next
-      case x of
-        0  -> pure Success
-        1  -> pure OperationError
-        2  -> pure ProtocolError
-        3  -> pure TimeLimitExceeded
-        4  -> pure SizeLimitExceeded
-        5  -> pure CompareFalse
-        6  -> pure CompareTrue
-        7  -> pure AuthMethodNotSupported
-        8  -> pure StrongerAuthRequired
-        10 -> pure Referral
-        11 -> pure AdminLimitExceeded
-        12 -> pure UnavailableCriticalExtension
-        13 -> pure ConfidentialityRequired
-        14 -> pure SaslBindInProgress
-        16 -> pure NoSuchAttribute
-        17 -> pure UndefinedAttributeType
-        18 -> pure InappropriateMatching
-        19 -> pure ConstraintViolation
-        20 -> pure AttributeOrValueExists
-        21 -> pure InvalidAttributeSyntax
-        32 -> pure NoSuchObject
-        33 -> pure AliasProblem
-        34 -> pure InvalidDNSyntax
-        36 -> pure AliasDereferencingProblem
-        48 -> pure InappropriateAuthentication
-        49 -> pure InvalidCredentials
-        50 -> pure InsufficientAccessRights
-        51 -> pure Busy
-        52 -> pure Unavailable
-        53 -> pure UnwillingToPerform
-        54 -> pure LoopDetect
-        64 -> pure NamingViolation
-        65 -> pure ObjectClassViolation
-        66 -> pure NotAllowedOnNonLeaf
-        67 -> pure NotAllowedOnRDN
-        68 -> pure EntryAlreadyExists
-        69 -> pure ObjectClassModsProhibited
-        71 -> pure AffectsMultipleDSAs
-        80 -> pure Other
-        _  -> empty
-    matchedDn  <- fromAsn1
-    diagnosticMessage
-               <- fromAsn1
-    referral   <- optional $ do
-      Asn1.Start (Asn1.Container Asn1.Context 0) <- next
-      x <- fromAsn1
-      Asn1.End (Asn1.Container Asn1.Context 0) <- next
-      return x
-    return (LdapResult resultCode matchedDn diagnosticMessage referral)
-
-{- |
-@
-Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI
-@
--}
-instance FromAsn1 ReferralUris where
-  fromAsn1 = do
-    Asn1.Start Asn1.Sequence <- next
-    xs <- some1 fromAsn1
-    Asn1.End Asn1.Sequence <- next
-    return (ReferralUris xs)
-
-{- |
-@
-URI ::= LDAPString
-@
--}
-instance FromAsn1 Uri where
-  fromAsn1 = fmap Uri fromAsn1
-
-{- |
-@
-BindResponse ::= [APPLICATION 1] SEQUENCE {
-     COMPONENTS OF LDAPResult,
-     serverSaslCreds    [7] OCTET STRING OPTIONAL }
-@
+{-# ANN module "HLint: ignore Use const" #-}
+{-# ANN module "HLint: ignore Avoid lambda" #-}
+
+
+-- | Convert a part of ASN.1 stream to a LDAP type returning the remainder of the stream.
+parseAsn1 :: FromAsn1 a => [ASN1] -> Maybe ([ASN1], a)
+parseAsn1 = parse fromAsn1
+
+-- | ASN.1 stream parsers.
+--
+-- When it's relevant, instances include the part of RFC describing the encoding.
+class FromAsn1 a where
+  fromAsn1 :: Parser [ASN1] a
+
+{- |
+@
+LDAPMessage ::= SEQUENCE {
+     messageID       MessageID,
+     protocolOp      CHOICE {
+          bindRequest           BindRequest,
+          bindResponse          BindResponse,
+          unbindRequest         UnbindRequest,
+          searchRequest         SearchRequest,
+          searchResEntry        SearchResultEntry,
+          searchResDone         SearchResultDone,
+          searchResRef          SearchResultReference,
+          addRequest            AddRequest,
+          addResponse           AddResponse,
+          ... },
+     controls       [0] Controls OPTIONAL }
+@
+-}
+instance FromAsn1 op =>  FromAsn1 (LdapMessage op) where
+  fromAsn1 = do
+    Asn1.Start Asn1.Sequence <- next
+    i  <- fromAsn1
+    op <- fromAsn1
+    Asn1.End Asn1.Sequence <- next
+    return (LdapMessage i op Nothing)
+
+{- |
+@
+MessageID ::= INTEGER (0 ..  maxInt)
+@
+-}
+instance FromAsn1 Id where
+  fromAsn1 = do
+    Asn1.IntVal i <- next
+    return (Id (fromIntegral i))
+
+{- |
+@
+LDAPString ::= OCTET STRING -- UTF-8 encoded,
+@
+-}
+instance FromAsn1 LdapString where
+  fromAsn1 = do
+    Asn1.OctetString s <- next
+    case Text.decodeUtf8' s of
+      Right t -> return (LdapString t)
+      Left  _ -> empty
+
+{- |
+@
+LDAPOID ::= OCTET STRING -- Constrained to \<numericoid\>
+@
+-}
+instance FromAsn1 LdapOid where
+  fromAsn1 = do
+    Asn1.OctetString s <- next
+    case Text.decodeUtf8' s of
+      Right t -> return (LdapOid t)
+      Left  _ -> empty
+
+{- |
+@
+LDAPDN ::= LDAPString
+@
+-}
+instance FromAsn1 LdapDn where
+  fromAsn1 = fmap LdapDn fromAsn1
+
+{- |
+@
+AttributeDescription ::= LDAPString
+@
+-}
+instance FromAsn1 AttributeDescription where
+  fromAsn1 = fmap AttributeDescription fromAsn1
+
+{- |
+@
+AttributeValue ::= OCTET STRING
+@
+-}
+instance FromAsn1 AttributeValue where
+  fromAsn1 = do
+    Asn1.OctetString s <- next
+    return (AttributeValue s)
+
+{- |
+@
+PartialAttribute ::= SEQUENCE {
+     type       AttributeDescription,
+     vals       SET OF value AttributeValue }
+@
+-}
+instance FromAsn1 PartialAttribute where
+  fromAsn1 = do
+    Asn1.Start Asn1.Sequence <- next
+    d  <- fromAsn1
+    Asn1.Start Asn1.Set <- next
+    vs <- many fromAsn1
+    Asn1.End Asn1.Set <- next
+    Asn1.End Asn1.Sequence <- next
+    return (PartialAttribute d vs)
+
+{- |
+@
+LDAPResult ::= SEQUENCE {
+     resultCode         ENUMERATED {
+          success                      (0),
+          operationsError              (1),
+          protocolError                (2),
+          timeLimitExceeded            (3),
+          sizeLimitExceeded            (4),
+          compareFalse                 (5),
+          compareTrue                  (6),
+          authMethodNotSupported       (7),
+          strongerAuthRequired         (8),
+          -- 9 reserved --
+          referral                     (10),
+          adminLimitExceeded           (11),
+          unavailableCriticalExtension (12),
+          confidentialityRequired      (13),
+          saslBindInProgress           (14),
+          noSuchAttribute              (16),
+          undefinedAttributeType       (17),
+          inappropriateMatching        (18),
+          constraintViolation          (19),
+          attributeOrValueExists       (20),
+          invalidAttributeSyntax       (21),
+          -- 22-31 unused --
+          noSuchObject                 (32),
+          aliasProblem                 (33),
+          invalidDNSyntax              (34),
+          -- 35 reserved for undefined isLeaf --
+          aliasDereferencingProblem    (36),
+          -- 37-47 unused --
+          inappropriateAuthentication  (48),
+          invalidCredentials           (49),
+          insufficientAccessRights     (50),
+          busy                         (51),
+          unavailable                  (52),
+          unwillingToPerform           (53),
+          loopDetect                   (54),
+          -- 55-63 unused --
+          namingViolation              (64),
+          objectClassViolation         (65),
+          notAllowedOnNonLeaf          (66),
+          notAllowedOnRDN              (67),
+          entryAlreadyExists           (68),
+          objectClassModsProhibited    (69),
+          -- 70 reserved for CLDAP --
+          affectsMultipleDSAs          (71),
+          -- 72-79 unused --
+          other                        (80),
+          ...  },
+     matchedDN          LDAPDN,
+     diagnosticMessage  LDAPString,
+     referral           [3] Referral OPTIONAL }
+@
+-}
+instance FromAsn1 LdapResult where
+  fromAsn1 = do
+    resultCode <- do
+      Asn1.Enumerated x <- next
+      case x of
+        0  -> pure Success
+        1  -> pure OperationError
+        2  -> pure ProtocolError
+        3  -> pure TimeLimitExceeded
+        4  -> pure SizeLimitExceeded
+        5  -> pure CompareFalse
+        6  -> pure CompareTrue
+        7  -> pure AuthMethodNotSupported
+        8  -> pure StrongerAuthRequired
+        10 -> pure Referral
+        11 -> pure AdminLimitExceeded
+        12 -> pure UnavailableCriticalExtension
+        13 -> pure ConfidentialityRequired
+        14 -> pure SaslBindInProgress
+        16 -> pure NoSuchAttribute
+        17 -> pure UndefinedAttributeType
+        18 -> pure InappropriateMatching
+        19 -> pure ConstraintViolation
+        20 -> pure AttributeOrValueExists
+        21 -> pure InvalidAttributeSyntax
+        32 -> pure NoSuchObject
+        33 -> pure AliasProblem
+        34 -> pure InvalidDNSyntax
+        36 -> pure AliasDereferencingProblem
+        48 -> pure InappropriateAuthentication
+        49 -> pure InvalidCredentials
+        50 -> pure InsufficientAccessRights
+        51 -> pure Busy
+        52 -> pure Unavailable
+        53 -> pure UnwillingToPerform
+        54 -> pure LoopDetect
+        64 -> pure NamingViolation
+        65 -> pure ObjectClassViolation
+        66 -> pure NotAllowedOnNonLeaf
+        67 -> pure NotAllowedOnRDN
+        68 -> pure EntryAlreadyExists
+        69 -> pure ObjectClassModsProhibited
+        71 -> pure AffectsMultipleDSAs
+        80 -> pure Other
+        _  -> empty
+    matchedDn  <- fromAsn1
+    diagnosticMessage
+               <- fromAsn1
+    referral   <- optional $ do
+      Asn1.Start (Asn1.Container Asn1.Context 0) <- next
+      x <- fromAsn1
+      Asn1.End (Asn1.Container Asn1.Context 0) <- next
+      return x
+    return (LdapResult resultCode matchedDn diagnosticMessage referral)
+
+{- |
+@
+Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI
+@
+-}
+instance FromAsn1 ReferralUris where
+  fromAsn1 = do
+    Asn1.Start Asn1.Sequence <- next
+    xs <- some1 fromAsn1
+    Asn1.End Asn1.Sequence <- next
+    return (ReferralUris xs)
+
+{- |
+@
+URI ::= LDAPString
+@
+-}
+instance FromAsn1 Uri where
+  fromAsn1 = fmap Uri fromAsn1
 
-@
-SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
-     objectName      LDAPDN,
-     attributes      PartialAttributeList }
-@
-
-@
-SearchResultDone ::= [APPLICATION 5] LDAPResult
-@
-
-@
-ModifyResponse ::= [APPLICATION 7] LDAPResult
-@
-
-@
-AddResponse ::= [APPLICATION 9] LDAPResult
+{- |
+@
+BindResponse ::= [APPLICATION 1] SEQUENCE {
+     COMPONENTS OF LDAPResult,
+     serverSaslCreds    [7] OCTET STRING OPTIONAL }
+@
+
+@
+SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+     objectName      LDAPDN,
+     attributes      PartialAttributeList }
+@
+
+@
+SearchResultReference ::= [APPLICATION 19] SEQUENCE
+                          SIZE (1..MAX) OF uri URI
 @
 
 @
-DelResponse ::= [APPLICATION 11] LDAPResult
+SearchResultDone ::= [APPLICATION 5] LDAPResult
 @
 
 @
-CompareResponse ::= [APPLICATION 15] LDAPResult
+ModifyResponse ::= [APPLICATION 7] LDAPResult
 @
--}
-instance FromAsn1 ProtocolServerOp where
-  fromAsn1 = asum
-    [ fmap (\res -> BindResponse res Nothing) (app 1)
-    , fmap (uncurry SearchResultEntry) (app 4)
-    , fmap SearchResultDone (app 5)
-    , fmap ModifyResponse (app 7)
-    , fmap AddResponse (app 9)
-    , fmap DeleteResponse (app 11)
-    , fmap ModifyDnResponse (app 13)
-    , fmap CompareResponse (app 15)
-    , do
-      Asn1.Start (Asn1.Container Asn1.Application 24) <- next
-      res <- fromAsn1
-      name <- optional $ do
-        Asn1.Other Asn1.Context 0 s <- next
-        return s
-      value <- optional $ do
-        Asn1.Other Asn1.Context 1 s <- next
-        return s
-      Asn1.End (Asn1.Container Asn1.Application 24) <- next
-      return (ExtendedResponse res (fmap LdapOid name) value)
-    ]
-   where
-    app l = do
-      Asn1.Start (Asn1.Container Asn1.Application x) <- next
-      guard (x == l)
-      res <- fromAsn1
-      Asn1.End (Asn1.Container Asn1.Application y) <- next
-      guard (y == l)
-      return res
-
-{- |
-@
-PartialAttributeList ::= SEQUENCE OF partialAttribute PartialAttribute
-@
--}
-instance FromAsn1 PartialAttributeList where
-  fromAsn1 = do
-    Asn1.Start Asn1.Sequence <- next
-    xs <- many fromAsn1
-    Asn1.End Asn1.Sequence <- next
-    return (PartialAttributeList xs)
-
-instance (FromAsn1 a, FromAsn1 b) => FromAsn1 (a, b) where
-  fromAsn1 = liftA2 (,) fromAsn1 fromAsn1
+
+@
+AddResponse ::= [APPLICATION 9] LDAPResult
+@
+
+@
+DelResponse ::= [APPLICATION 11] LDAPResult
+@
+
+@
+ModifyDNResponse ::= [APPLICATION 13] LDAPResult
+@
+
+@
+CompareResponse ::= [APPLICATION 15] LDAPResult
+@
+
+@
+ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+     COMPONENTS OF LDAPResult,
+     responseName     [10] LDAPOID OPTIONAL,
+     responseValue    [11] OCTET STRING OPTIONAL }
+@
+
+@
+IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+     responseName     [0] LDAPOID OPTIONAL,
+     responseValue    [1] OCTET STRING OPTIONAL }
+@
+-}
+instance FromAsn1 ProtocolServerOp where
+  fromAsn1 = asum
+    [ fmap (\res -> BindResponse res Nothing) (app 1)
+    , fmap (uncurry SearchResultEntry) (app 4)
+    , fmap SearchResultDone (app 5)
+    , fmap ModifyResponse (app 7)
+    , fmap AddResponse (app 9)
+    , fmap DeleteResponse (app 11)
+    , fmap ModifyDnResponse (app 13)
+    , fmap CompareResponse (app 15)
+
+    , do
+      Asn1.Start (Asn1.Container Asn1.Application 19) <- next
+      uris <- some1 fromAsn1
+      Asn1.End (Asn1.Container Asn1.Application 19) <- next
+      return (SearchResultReference uris)
 
-
-newtype Parser s a = Parser { unParser :: s -> Maybe (s, a) }
-
-instance Functor (Parser s) where
-  fmap f (Parser g) = Parser (fmap (fmap f) . g)
-
-instance Applicative (Parser s) where
-  pure x = Parser (\s -> pure (s, x))
-  Parser mf <*> Parser mx = Parser $ \s -> do
-    (s', f)  <- mf s
-    (s'', x) <- mx s'
-    pure (s'', f x)
-
-instance Alternative (Parser s) where
-  empty = Parser (\_ -> empty)
-  Parser ma <|> Parser mb =
-    Parser (\s -> ma s <|> mb s)
-
-instance Monad (Parser s) where
-  return x = Parser (\s -> return (s, x))
-  Parser mx >>= k =
-    Parser (mx >=> \(s', x) -> unParser (k x) s')
-  fail _ = empty
-
-instance MonadPlus (Parser s) where
-  mzero = Parser (\_ -> mzero)
-  Parser ma `mplus` Parser mb =
-    Parser (\s -> ma s `mplus` mb s)
-
-parseAsn1 :: FromAsn1 a => [ASN1] -> Maybe ([ASN1], a)
-parseAsn1 = parse fromAsn1
-
-parse :: Parser s a -> s -> Maybe (s, a)
-parse = unParser
-
-next :: Parser [s] s
-next = Parser (\s -> case s of [] -> Nothing; x : xs -> Just (xs, x))
+    , do
+      Asn1.Start (Asn1.Container Asn1.Application 24) <- next
+      res <- fromAsn1
+      utf8Name <- optional $ do
+        Asn1.Other Asn1.Context 10 s <- next
+        return s
+      name <- maybe (return Nothing) (\n -> case Text.decodeUtf8' n of
+        Left  _    -> empty
+        Right name -> return (Just name)) utf8Name
+      value <- optional $ do
+        Asn1.Other Asn1.Context 11 s <- next
+        return s
+      Asn1.End (Asn1.Container Asn1.Application 24) <- next
+      return (ExtendedResponse res (fmap LdapOid name) value)
+
+    , do
+      Asn1.Start (Asn1.Container Asn1.Application 25) <- next
+      name  <- optional fromAsn1
+      value <- optional $ do
+        Asn1.OctetString s <- next
+        return s
+      Asn1.End (Asn1.Container Asn1.Application 25) <- next
+      return (IntermediateResponse name value)
+    ]
+   where
+    app l = do
+      Asn1.Start (Asn1.Container Asn1.Application x) <- next
+      guard (x == l)
+      res <- fromAsn1
+      Asn1.End (Asn1.Container Asn1.Application y) <- next
+      guard (y == l)
+      return res
+
+{- |
+@
+PartialAttributeList ::= SEQUENCE OF partialAttribute PartialAttribute
+@
+-}
+instance FromAsn1 PartialAttributeList where
+  fromAsn1 = do
+    Asn1.Start Asn1.Sequence <- next
+    xs <- many fromAsn1
+    Asn1.End Asn1.Sequence <- next
+    return (PartialAttributeList xs)
+
+instance (FromAsn1 a, FromAsn1 b) => FromAsn1 (a, b) where
+  fromAsn1 = liftA2 (,) fromAsn1 fromAsn1
+
+
+newtype Parser s a = Parser { unParser :: s -> Maybe (s, a) }
+
+instance Functor (Parser s) where
+  fmap f (Parser g) = Parser (fmap (fmap f) . g)
+
+instance Applicative (Parser s) where
+  pure x = Parser (\s -> pure (s, x))
+  Parser mf <*> Parser mx = Parser $ \s -> do
+    (s', f)  <- mf s
+    (s'', x) <- mx s'
+    pure (s'', f x)
+
+instance Alternative (Parser s) where
+  empty = Parser (\_ -> empty)
+  Parser ma <|> Parser mb =
+    Parser (\s -> ma s <|> mb s)
+
+instance Monad (Parser s) where
+  return x = Parser (\s -> return (s, x))
+  Parser mx >>= k =
+    Parser (mx >=> \(s', x) -> unParser (k x) s')
+  fail _ = empty
+
+instance MonadPlus (Parser s) where
+  mzero = Parser (\_ -> mzero)
+  Parser ma `mplus` Parser mb =
+    Parser (\s -> ma s `mplus` mb s)
+
+parse :: Parser s a -> s -> Maybe (s, a)
+parse = unParser
+
+next :: Parser [s] s
+next = Parser (\s -> case s of [] -> Nothing; x : xs -> Just (xs, x))
 
diff --git a/src/Ldap-Asn1-ToAsn1.html b/src/Ldap-Asn1-ToAsn1.html index 90e7770..412ffc0 100644 --- a/src/Ldap-Asn1-ToAsn1.html +++ b/src/Ldap-Asn1-ToAsn1.html @@ -7,426 +7,434 @@ -
module Ldap.Asn1.ToAsn1
-  ( ToAsn1(toAsn1)
-  ) where
-
-import           Data.ASN1.Types (ASN1, ASN1Class, ASN1Tag, ASN1ConstructionType)
-import qualified Data.ASN1.Types as Asn1
-import           Data.ByteString (ByteString)
-import           Data.Foldable (fold, foldMap)
-import           Data.List.NonEmpty (NonEmpty)
-import           Data.Maybe (Maybe, maybe)
-import           Data.Monoid (Endo(Endo), (<>), mempty)
-import qualified Data.Text.Encoding as Text
-import           Prelude (Integer, (.), fromIntegral)
-
-import           Ldap.Asn1.Type
-
-
-class ToAsn1 a where
-  toAsn1 :: a -> Endo [ASN1]
+
-- | This module contains convertions from LDAP types to ASN.1.
+--
+-- Various hacks are employed because "asn1-encoding" only encodes to DER, but
+-- LDAP demands BER-encoding.  So, when a definition looks suspiciously different
+-- from the spec in the comment, that's why.  I hope all that will be fixed
+-- eventually.
+module Ldap.Asn1.ToAsn1
+  ( ToAsn1(toAsn1)
+  ) where
+
+import           Data.ASN1.Types (ASN1, ASN1Class, ASN1Tag, ASN1ConstructionType)
+import qualified Data.ASN1.Types as Asn1
+import           Data.ByteString (ByteString)
+import           Data.Foldable (fold, foldMap)
+import           Data.List.NonEmpty (NonEmpty)
+import           Data.Maybe (maybe)
+import           Data.Monoid (Endo(Endo), (<>), mempty)
+import qualified Data.Text.Encoding as Text
+import           Prelude (Integer, (.), fromIntegral)
 
-{- |
-@
-LDAPMessage ::= SEQUENCE {
-     messageID       MessageID,
-     protocolOp      CHOICE {
-          bindRequest           BindRequest,
-          bindResponse          BindResponse,
-          unbindRequest         UnbindRequest,
-          searchRequest         SearchRequest,
-          searchResEntry        SearchResultEntry,
-          searchResDone         SearchResultDone,
-          searchResRef          SearchResultReference,
-          addRequest            AddRequest,
-          addResponse           AddResponse,
-          ... },
-     controls       [0] Controls OPTIONAL }
-@
--}
-instance ToAsn1 op => ToAsn1 (LdapMessage op) where
-  toAsn1 (LdapMessage i op mc) =
-    sequence (toAsn1 i <> toAsn1 op <> maybe mempty (context 0 . toAsn1) mc)
-
-{- |
-@
-MessageID ::= INTEGER (0 ..  maxInt)
+import           Ldap.Asn1.Type
+
+
+-- | Convert a LDAP type to ASN.1.
+--
+-- When it's relevant, instances include the part of RFC describing the encoding.
+class ToAsn1 a where
+  toAsn1 :: a -> Endo [ASN1]
+
+{- |
+@
+LDAPMessage ::= SEQUENCE {
+     messageID       MessageID,
+     protocolOp      CHOICE {
+          bindRequest           BindRequest,
+          bindResponse          BindResponse,
+          unbindRequest         UnbindRequest,
+          searchRequest         SearchRequest,
+          searchResEntry        SearchResultEntry,
+          searchResDone         SearchResultDone,
+          searchResRef          SearchResultReference,
+          addRequest            AddRequest,
+          addResponse           AddResponse,
+          ... },
+     controls       [0] Controls OPTIONAL }
 @
 -}
-instance ToAsn1 Id where
-  toAsn1 (Id i) = single (Asn1.IntVal (fromIntegral i))
-
-{- |
-@
-LDAPString ::= OCTET STRING -- UTF-8 encoded
-@
--}
-instance ToAsn1 LdapString where
-  toAsn1 (LdapString s) = single (Asn1.OctetString (Text.encodeUtf8 s))
-
-{- |
-@
-LDAPOID ::= OCTET STRING -- Constrained to \<numericoid\>
-@
--}
-instance ToAsn1 LdapOid where
-  toAsn1 (LdapOid s) = single (Asn1.OctetString s)
-
-{- |
-@
-LDAPDN ::= LDAPString -- Constrained to \<distinguishedName\>
-@
--}
-instance ToAsn1 LdapDn where
-  toAsn1 (LdapDn s) = toAsn1 s
-
-{- |
-@
-RelativeLDAPDN ::= LDAPString -- Constrained to \<name-component\>
-@
--}
-instance ToAsn1 RelativeLdapDn where
-  toAsn1 (RelativeLdapDn s) = toAsn1 s
-
-{- |
-@
-AttributeDescription ::= LDAPString
-@
--}
-instance ToAsn1 AttributeDescription where
-  toAsn1 (AttributeDescription s) = toAsn1 s
-
-{- |
-@
-AttributeValue ::= OCTET STRING
-@
--}
-instance ToAsn1 AttributeValue where
-  toAsn1 (AttributeValue s) = single (Asn1.OctetString s)
-
-{- |
-@
-AttributeValueAssertion ::= SEQUENCE {
-     attributeDesc   AttributeDescription,
-     assertionValue  AssertionValue }
-@
--}
-instance ToAsn1 AttributeValueAssertion where
-  toAsn1 (AttributeValueAssertion d v) = toAsn1 d <> toAsn1 v
-
-{- |
-@
-AssertionValue ::= OCTET STRING
-@
--}
-instance ToAsn1 AssertionValue where
-  toAsn1 (AssertionValue s) = single (Asn1.OctetString s)
-
+instance ToAsn1 op => ToAsn1 (LdapMessage op) where
+  toAsn1 (LdapMessage i op mc) =
+    sequence (toAsn1 i <> toAsn1 op <> maybe mempty (context 0 . toAsn1) mc)
+
+{- |
+@
+MessageID ::= INTEGER (0 ..  maxInt)
+@
+-}
+instance ToAsn1 Id where
+  toAsn1 (Id i) = single (Asn1.IntVal (fromIntegral i))
+
+{- |
+@
+LDAPString ::= OCTET STRING -- UTF-8 encoded
+@
+-}
+instance ToAsn1 LdapString where
+  toAsn1 (LdapString s) = single (Asn1.OctetString (Text.encodeUtf8 s))
+
+{- |
+@
+LDAPOID ::= OCTET STRING -- Constrained to \<numericoid\>
+@
+-}
+instance ToAsn1 LdapOid where
+  toAsn1 (LdapOid s) = single (Asn1.OctetString (Text.encodeUtf8 s))
+
+{- |
+@
+LDAPDN ::= LDAPString -- Constrained to \<distinguishedName\>
+@
+-}
+instance ToAsn1 LdapDn where
+  toAsn1 (LdapDn s) = toAsn1 s
+
+{- |
+@
+RelativeLDAPDN ::= LDAPString -- Constrained to \<name-component\>
+@
+-}
+instance ToAsn1 RelativeLdapDn where
+  toAsn1 (RelativeLdapDn s) = toAsn1 s
+
+{- |
+@
+AttributeDescription ::= LDAPString
+@
+-}
+instance ToAsn1 AttributeDescription where
+  toAsn1 (AttributeDescription s) = toAsn1 s
+
+{- |
+@
+AttributeValue ::= OCTET STRING
+@
+-}
+instance ToAsn1 AttributeValue where
+  toAsn1 (AttributeValue s) = single (Asn1.OctetString s)
+
+{- |
+@
+AttributeValueAssertion ::= SEQUENCE {
+     attributeDesc   AttributeDescription,
+     assertionValue  AssertionValue }
+@
+-}
+instance ToAsn1 AttributeValueAssertion where
+  toAsn1 (AttributeValueAssertion d v) = toAsn1 d <> toAsn1 v
 
-{- |
+{- |
 @
-PartialAttribute ::= SEQUENCE {
-     type       AttributeDescription,
-     vals       SET OF value AttributeValue }
-@
--}
-instance ToAsn1 PartialAttribute where
-  toAsn1 (PartialAttribute d xs) = sequence (toAsn1 d <> set (toAsn1 xs))
-
-{- |
-@
-Attribute ::= PartialAttribute(WITH COMPONENTS {
-     ...,
-     vals (SIZE(1..MAX))})
-@
--}
-instance ToAsn1 Attribute where
-  toAsn1 (Attribute d xs) = sequence (toAsn1 d <> set (toAsn1 xs))
-
-{- |
-@
-MatchingRuleId ::= LDAPString
-@
--}
-instance ToAsn1 MatchingRuleId where
-  toAsn1 (MatchingRuleId s) = toAsn1 s
-
-{- |
-@
-Controls ::= SEQUENCE OF control Control
-@
--}
-instance ToAsn1 Controls where
-  toAsn1 (Controls cs) = sequence (toAsn1 cs)
-
-{- |
-@
-Control ::= SEQUENCE {
-     controlType             LDAPOID,
-     criticality             BOOLEAN DEFAULT FALSE,
-     controlValue            OCTET STRING OPTIONAL }
-@
--}
-instance ToAsn1 Control where
-  toAsn1 (Control t c v) =
-    sequence (fold
-      [ toAsn1 t
-      , single (Asn1.Boolean c)
-      , maybe mempty (single . Asn1.OctetString) v
-      ])
-
-{- |
-@
-BindRequest ::= [APPLICATION 0] SEQUENCE {
-     version                 INTEGER (1 ..  127),
-     name                    LDAPDN,
-     authentication          AuthenticationChoice }
-@
-
-@
-UnbindRequest ::= [APPLICATION 2] NULL
+AssertionValue ::= OCTET STRING
+@
+-}
+instance ToAsn1 AssertionValue where
+  toAsn1 (AssertionValue s) = single (Asn1.OctetString s)
+
+
+{- |
+@
+PartialAttribute ::= SEQUENCE {
+     type       AttributeDescription,
+     vals       SET OF value AttributeValue }
+@
+-}
+instance ToAsn1 PartialAttribute where
+  toAsn1 (PartialAttribute d xs) = sequence (toAsn1 d <> set (toAsn1 xs))
+
+{- |
+@
+Attribute ::= PartialAttribute(WITH COMPONENTS {
+     ...,
+     vals (SIZE(1..MAX))})
+@
+-}
+instance ToAsn1 Attribute where
+  toAsn1 (Attribute d xs) = sequence (toAsn1 d <> set (toAsn1 xs))
+
+{- |
+@
+MatchingRuleId ::= LDAPString
+@
+-}
+instance ToAsn1 MatchingRuleId where
+  toAsn1 (MatchingRuleId s) = toAsn1 s
+
+{- |
+@
+Controls ::= SEQUENCE OF control Control
+@
+-}
+instance ToAsn1 Controls where
+  toAsn1 (Controls cs) = sequence (toAsn1 cs)
+
+{- |
+@
+Control ::= SEQUENCE {
+     controlType             LDAPOID,
+     criticality             BOOLEAN DEFAULT FALSE,
+     controlValue            OCTET STRING OPTIONAL }
+@
+-}
+instance ToAsn1 Control where
+  toAsn1 (Control t c v) =
+    sequence (fold
+      [ toAsn1 t
+      , single (Asn1.Boolean c)
+      , maybe mempty (single . Asn1.OctetString) v
+      ])
+
+{- |
 @
-
-@
-SearchRequest ::= [APPLICATION 3] SEQUENCE {
-     baseObject      LDAPDN,
-     scope           ENUMERATED {
-          baseObject              (0),
-          singleLevel             (1),
-          wholeSubtree            (2),
-          ...  },
-     derefAliases    ENUMERATED {
-          neverDerefAliases       (0),
-          derefInSearching        (1),
-          derefFindingBaseObj     (2),
-          derefAlways             (3) },
-     sizeLimit       INTEGER (0 ..  maxInt),
-     timeLimit       INTEGER (0 ..  maxInt),
-     typesOnly       BOOLEAN,
-     filter          Filter,
-     attributes      AttributeSelection }
-@
-
-@
-ModifyRequest ::= [APPLICATION 6] SEQUENCE {
-     object          LDAPDN,
-     changes         SEQUENCE OF change SEQUENCE {
-          operation       ENUMERATED {
-               add     (0),
-               delete  (1),
-               replace (2),
-               ...  },
-          modification    PartialAttribute } }
-@
-
-@
-AddRequest ::= [APPLICATION 8] SEQUENCE {
-     entry           LDAPDN,
-     attributes      AttributeList }
-@
-
-@
-DelRequest ::= [APPLICATION 10] LDAPDN
-@
-
-@
-ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
-     entry           LDAPDN,
-     newrdn          RelativeLDAPDN,
-     deleteoldrdn    BOOLEAN,
-     newSuperior     [0] LDAPDN OPTIONAL }
-@
-
-@
-CompareRequest ::= [APPLICATION 14] SEQUENCE {
-     entry           LDAPDN,
-     ava             AttributeValueAssertion }
-@
-
-@
-ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
-     requestName      [0] LDAPOID,
-     requestValue     [1] OCTET STRING OPTIONAL }
-@
--}
-instance ToAsn1 ProtocolClientOp where
-  toAsn1 (BindRequest v n a) =
-    application 0 (single (Asn1.IntVal (fromIntegral v)) <> toAsn1 n <> toAsn1 a)
-  toAsn1 UnbindRequest =
-    other Asn1.Application 2 mempty
-  toAsn1 (SearchRequest bo s da sl tl to f a) =
-    application 3 (fold
-      [ toAsn1 bo
-      , enum s'
-      , enum da'
-      , single (Asn1.IntVal (fromIntegral sl))
-      , single (Asn1.IntVal (fromIntegral tl))
-      , single (Asn1.Boolean to)
-      , toAsn1 f
-      , toAsn1 a
-      ])
-   where
-    s' = case s of
-      BaseObject   -> 0
-      SingleLevel  -> 1
-      WholeSubtree -> 2
-    da' = case da of
-      NeverDerefAliases      -> 0
-      DerefInSearching       -> 1
-      DerefFindingBaseObject -> 2
-      DerefAlways            -> 3
-  toAsn1 (ModifyRequest dn xs) =
-    application 6 (fold
-      [ toAsn1 dn
-      , sequence (foldMap (\(op, pa) -> sequence (enum (case op of
-          Add     -> 0
-          Delete  -> 1
-          Replace -> 2) <> toAsn1 pa)) xs)
-      ])
-  toAsn1 (AddRequest dn as) =
-    application 8 (toAsn1 dn <> toAsn1 as)
-  toAsn1 (DeleteRequest (LdapDn (LdapString dn))) =
-    other Asn1.Application 10 (Text.encodeUtf8 dn)
-  toAsn1 (ModifyDnRequest dn rdn del new) =
-    application 12 (fold
-      [ toAsn1 dn
-      , toAsn1 rdn
-      , single (Asn1.Boolean del)
-      , maybe mempty
-              (\(LdapDn (LdapString dn')) -> other Asn1.Context 0 (Text.encodeUtf8 dn'))
-              new
-      ])
-  toAsn1 (CompareRequest dn av) =
-    application 14 (toAsn1 dn <> sequence (toAsn1 av))
-  toAsn1 (ExtendedRequest (LdapOid oid) mv) =
-    application 23 (fold
-     [ other Asn1.Context 0 oid
-     , maybe mempty (other Asn1.Context 1) mv
-     ])
-
-{- |
-@
-AuthenticationChoice ::= CHOICE {
-     simple                  [0] OCTET STRING,
-     ...  }
-@
--}
-instance ToAsn1 AuthenticationChoice where
-  toAsn1 (Simple s) = other Asn1.Context 0 s
-
-{- |
-@
-AttributeSelection ::= SEQUENCE OF selector LDAPString
-@
--}
-instance ToAsn1 AttributeSelection where
-  toAsn1 (AttributeSelection as) = sequence (toAsn1 as)
-
-{- |
-@
-Filter ::= CHOICE {
-     and             [0] SET SIZE (1..MAX) OF filter Filter,
-     or              [1] SET SIZE (1..MAX) OF filter Filter,
-     not             [2] Filter,
-     equalityMatch   [3] AttributeValueAssertion,
-     substrings      [4] SubstringFilter,
-     greaterOrEqual  [5] AttributeValueAssertion,
-     lessOrEqual     [6] AttributeValueAssertion,
-     present         [7] AttributeDescription,
-     approxMatch     [8] AttributeValueAssertion,
-     extensibleMatch [9] MatchingRuleAssertion,
-     ...  }
-@
--}
-instance ToAsn1 Filter where
-  toAsn1 f = case f of
-    And xs            -> context 0 (toAsn1 xs)
-    Or xs             -> context 1 (toAsn1 xs)
-    Not x             -> context 2 (toAsn1 x)
-    EqualityMatch x   -> context 3 (toAsn1 x)
-    Substrings x      -> context 4 (toAsn1 x)
-    GreaterOrEqual x  -> context 5 (toAsn1 x)
-    LessOrEqual x     -> context 6 (toAsn1 x)
-    Present (AttributeDescription (LdapString x))
-                      -> other Asn1.Context 7 (Text.encodeUtf8 x)
-    ApproxMatch x     -> context 8 (toAsn1 x)
-    ExtensibleMatch x -> context 9 (toAsn1 x)
-
-{- |
-@
-SubstringFilter ::= SEQUENCE {
-     type           AttributeDescription,
-     substrings     SEQUENCE SIZE (1..MAX) OF substring CHOICE {
-          initial [0] AssertionValue,  -- can occur at most once
-          any     [1] AssertionValue,
-          final   [2] AssertionValue } -- can occur at most once
-     }
-@
--}
-instance ToAsn1 SubstringFilter where
-  toAsn1 (SubstringFilter ad ss) =
-    toAsn1 ad <> sequence (foldMap (\s -> case s of
-      Initial (AssertionValue v) -> other Asn1.Context 0 v
-      Any (AssertionValue v)     -> other Asn1.Context 1 v
-      Final (AssertionValue v)   -> other Asn1.Context 2 v) ss)
-
-{- |
-@
-MatchingRuleAssertion ::= SEQUENCE {
-     matchingRule    [1] MatchingRuleId OPTIONAL,
-     type            [2] AttributeDescription OPTIONAL,
-     matchValue      [3] AssertionValue,
-     dnAttributes    [4] BOOLEAN DEFAULT FALSE }
-@
--}
-instance ToAsn1 MatchingRuleAssertion where
-  toAsn1 (MatchingRuleAssertion mmr mad av b) = sequence (fold
-    [ context 1 (optional mmr)
-    , context 2 (optional mad)
-    , context 3 (toAsn1 av)
-    , context 4 (single (Asn1.Boolean b))
-    ])
-
-{- |
-@
-AttributeList ::= SEQUENCE OF attribute Attribute
-@
--}
-instance ToAsn1 AttributeList where
-  toAsn1 (AttributeList xs) = sequence (toAsn1 xs)
-
-instance ToAsn1 a => ToAsn1 [a] where
-  toAsn1 = foldMap toAsn1
+BindRequest ::= [APPLICATION 0] SEQUENCE {
+     version                 INTEGER (1 ..  127),
+     name                    LDAPDN,
+     authentication          AuthenticationChoice }
+@
+
+@
+UnbindRequest ::= [APPLICATION 2] NULL
+@
+
+@
+SearchRequest ::= [APPLICATION 3] SEQUENCE {
+     baseObject      LDAPDN,
+     scope           ENUMERATED {
+          baseObject              (0),
+          singleLevel             (1),
+          wholeSubtree            (2),
+          ...  },
+     derefAliases    ENUMERATED {
+          neverDerefAliases       (0),
+          derefInSearching        (1),
+          derefFindingBaseObj     (2),
+          derefAlways             (3) },
+     sizeLimit       INTEGER (0 ..  maxInt),
+     timeLimit       INTEGER (0 ..  maxInt),
+     typesOnly       BOOLEAN,
+     filter          Filter,
+     attributes      AttributeSelection }
+@
+
+@
+ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+     object          LDAPDN,
+     changes         SEQUENCE OF change SEQUENCE {
+          operation       ENUMERATED {
+               add     (0),
+               delete  (1),
+               replace (2),
+               ...  },
+          modification    PartialAttribute } }
+@
+
+@
+AddRequest ::= [APPLICATION 8] SEQUENCE {
+     entry           LDAPDN,
+     attributes      AttributeList }
+@
+
+@
+DelRequest ::= [APPLICATION 10] LDAPDN
+@
+
+@
+ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
+     entry           LDAPDN,
+     newrdn          RelativeLDAPDN,
+     deleteoldrdn    BOOLEAN,
+     newSuperior     [0] LDAPDN OPTIONAL }
+@
+
+@
+CompareRequest ::= [APPLICATION 14] SEQUENCE {
+     entry           LDAPDN,
+     ava             AttributeValueAssertion }
+@
+
+@
+ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+     requestName      [0] LDAPOID,
+     requestValue     [1] OCTET STRING OPTIONAL }
+@
+-}
+instance ToAsn1 ProtocolClientOp where
+  toAsn1 (BindRequest v n a) =
+    application 0 (single (Asn1.IntVal (fromIntegral v)) <> toAsn1 n <> toAsn1 a)
+  toAsn1 UnbindRequest =
+    other Asn1.Application 2 mempty
+  toAsn1 (SearchRequest bo s da sl tl to f a) =
+    application 3 (fold
+      [ toAsn1 bo
+      , enum s'
+      , enum da'
+      , single (Asn1.IntVal (fromIntegral sl))
+      , single (Asn1.IntVal (fromIntegral tl))
+      , single (Asn1.Boolean to)
+      , toAsn1 f
+      , toAsn1 a
+      ])
+   where
+    s' = case s of
+      BaseObject   -> 0
+      SingleLevel  -> 1
+      WholeSubtree -> 2
+    da' = case da of
+      NeverDerefAliases      -> 0
+      DerefInSearching       -> 1
+      DerefFindingBaseObject -> 2
+      DerefAlways            -> 3
+  toAsn1 (ModifyRequest dn xs) =
+    application 6 (fold
+      [ toAsn1 dn
+      , sequence (foldMap (\(op, pa) -> sequence (enum (case op of
+          Add     -> 0
+          Delete  -> 1
+          Replace -> 2) <> toAsn1 pa)) xs)
+      ])
+  toAsn1 (AddRequest dn as) =
+    application 8 (toAsn1 dn <> toAsn1 as)
+  toAsn1 (DeleteRequest (LdapDn (LdapString dn))) =
+    other Asn1.Application 10 (Text.encodeUtf8 dn)
+  toAsn1 (ModifyDnRequest dn rdn del new) =
+    application 12 (fold
+      [ toAsn1 dn
+      , toAsn1 rdn
+      , single (Asn1.Boolean del)
+      , maybe mempty
+              (\(LdapDn (LdapString dn')) -> other Asn1.Context 0 (Text.encodeUtf8 dn'))
+              new
+      ])
+  toAsn1 (CompareRequest dn av) =
+    application 14 (toAsn1 dn <> sequence (toAsn1 av))
+  toAsn1 (ExtendedRequest (LdapOid oid) mv) =
+    application 23 (fold
+     [ other Asn1.Context 0 (Text.encodeUtf8 oid)
+     , maybe mempty (other Asn1.Context 1) mv
+     ])
+
+{- |
+@
+AuthenticationChoice ::= CHOICE {
+     simple                  [0] OCTET STRING,
+     ...  }
+@
+-}
+instance ToAsn1 AuthenticationChoice where
+  toAsn1 (Simple s) = other Asn1.Context 0 s
+
+{- |
+@
+AttributeSelection ::= SEQUENCE OF selector LDAPString
+@
+-}
+instance ToAsn1 AttributeSelection where
+  toAsn1 (AttributeSelection as) = sequence (toAsn1 as)
+
+{- |
+@
+Filter ::= CHOICE {
+     and             [0] SET SIZE (1..MAX) OF filter Filter,
+     or              [1] SET SIZE (1..MAX) OF filter Filter,
+     not             [2] Filter,
+     equalityMatch   [3] AttributeValueAssertion,
+     substrings      [4] SubstringFilter,
+     greaterOrEqual  [5] AttributeValueAssertion,
+     lessOrEqual     [6] AttributeValueAssertion,
+     present         [7] AttributeDescription,
+     approxMatch     [8] AttributeValueAssertion,
+     extensibleMatch [9] MatchingRuleAssertion,
+     ...  }
+@
+-}
+instance ToAsn1 Filter where
+  toAsn1 f = case f of
+    And xs            -> context 0 (toAsn1 xs)
+    Or xs             -> context 1 (toAsn1 xs)
+    Not x             -> context 2 (toAsn1 x)
+    EqualityMatch x   -> context 3 (toAsn1 x)
+    Substrings x      -> context 4 (toAsn1 x)
+    GreaterOrEqual x  -> context 5 (toAsn1 x)
+    LessOrEqual x     -> context 6 (toAsn1 x)
+    Present (AttributeDescription (LdapString x))
+                      -> other Asn1.Context 7 (Text.encodeUtf8 x)
+    ApproxMatch x     -> context 8 (toAsn1 x)
+    ExtensibleMatch x -> context 9 (toAsn1 x)
+
+{- |
+@
+SubstringFilter ::= SEQUENCE {
+     type           AttributeDescription,
+     substrings     SEQUENCE SIZE (1..MAX) OF substring CHOICE {
+          initial [0] AssertionValue,  -- can occur at most once
+          any     [1] AssertionValue,
+          final   [2] AssertionValue } -- can occur at most once
+     }
+@
+-}
+instance ToAsn1 SubstringFilter where
+  toAsn1 (SubstringFilter ad ss) =
+    toAsn1 ad <> sequence (foldMap (\s -> case s of
+      Initial (AssertionValue v) -> other Asn1.Context 0 v
+      Any (AssertionValue v)     -> other Asn1.Context 1 v
+      Final (AssertionValue v)   -> other Asn1.Context 2 v) ss)
+
+{- |
+@
+MatchingRuleAssertion ::= SEQUENCE {
+     matchingRule    [1] MatchingRuleId OPTIONAL,
+     type            [2] AttributeDescription OPTIONAL,
+     matchValue      [3] AssertionValue,
+     dnAttributes    [4] BOOLEAN DEFAULT FALSE }
+@
+-}
+instance ToAsn1 MatchingRuleAssertion where
+  toAsn1 (MatchingRuleAssertion mmr mad (AssertionValue av) _) = fold
+    [ maybe mempty f mmr
+    , maybe mempty g mad
+    , other Asn1.Context 3 av
+    ]
+   where
+    f (MatchingRuleId (LdapString x)) = other Asn1.Context 1 (Text.encodeUtf8 x)
+    g (AttributeDescription (LdapString x)) = other Asn1.Context 2 (Text.encodeUtf8 x)
 
-instance ToAsn1 a => ToAsn1 (NonEmpty a) where
-  toAsn1 = foldMap toAsn1
-
-sequence :: Endo [ASN1] -> Endo [ASN1]
-sequence = construction Asn1.Sequence
-
-set :: Endo [ASN1] -> Endo [ASN1]
-set = construction Asn1.Set
-
-application :: ASN1Tag -> Endo [ASN1] -> Endo [ASN1]
-application = construction . Asn1.Container Asn1.Application
-
-context :: ASN1Tag -> Endo [ASN1] -> Endo [ASN1]
-context = construction . Asn1.Container Asn1.Context
-
-construction :: ASN1ConstructionType -> Endo [ASN1] -> Endo [ASN1]
-construction t x = single (Asn1.Start t) <> x <> single (Asn1.End t)
-
-other :: ASN1Class -> ASN1Tag -> ByteString -> Endo [ASN1]
-other c t = single . Asn1.Other c t
-
-optional :: ToAsn1 a => Maybe a -> Endo [ASN1]
-optional = maybe mempty toAsn1
-
-enum :: Integer -> Endo [ASN1]
-enum = single . Asn1.Enumerated
-
-single :: a -> Endo [a]
-single x = Endo (x :)
+{- |
+@
+AttributeList ::= SEQUENCE OF attribute Attribute
+@
+-}
+instance ToAsn1 AttributeList where
+  toAsn1 (AttributeList xs) = sequence (toAsn1 xs)
+
+instance ToAsn1 a => ToAsn1 [a] where
+  toAsn1 = foldMap toAsn1
+
+instance ToAsn1 a => ToAsn1 (NonEmpty a) where
+  toAsn1 = foldMap toAsn1
+
+sequence :: Endo [ASN1] -> Endo [ASN1]
+sequence = construction Asn1.Sequence
+
+set :: Endo [ASN1] -> Endo [ASN1]
+set = construction Asn1.Set
+
+application :: ASN1Tag -> Endo [ASN1] -> Endo [ASN1]
+application = construction . Asn1.Container Asn1.Application
+
+context :: ASN1Tag -> Endo [ASN1] -> Endo [ASN1]
+context = construction . Asn1.Container Asn1.Context
+
+construction :: ASN1ConstructionType -> Endo [ASN1] -> Endo [ASN1]
+construction t x = single (Asn1.Start t) <> x <> single (Asn1.End t)
+
+other :: ASN1Class -> ASN1Tag -> ByteString -> Endo [ASN1]
+other c t = single . Asn1.Other c t
+
+enum :: Integer -> Endo [ASN1]
+enum = single . Asn1.Enumerated
+
+single :: a -> Endo [a]
+single x = Endo (x :)
 
diff --git a/src/Ldap-Asn1-Type.html b/src/Ldap-Asn1-Type.html index 26e7fb2..2d2cb70 100644 --- a/src/Ldap-Asn1-Type.html +++ b/src/Ldap-Asn1-Type.html @@ -15,188 +15,211 @@ import Data.Text (Text) -data LdapMessage op = LdapMessage - { ldapMessageId :: !Id - , ldapMessageOp :: !op - , ldapMessageControls :: !(Maybe Controls) - } deriving (Show, Eq, Ord) - -newtype Id = Id { unId :: Int32 } - deriving (Show, Eq, Ord) - -data ProtocolClientOp = - BindRequest Int8 LdapDn AuthenticationChoice - | UnbindRequest - | SearchRequest LdapDn Scope DerefAliases Int32 Int32 Bool Filter AttributeSelection - | ModifyRequest LdapDn [(Operation, PartialAttribute)] - | AddRequest LdapDn AttributeList - | DeleteRequest LdapDn - | ModifyDnRequest LdapDn RelativeLdapDn Bool (Maybe LdapDn) - | CompareRequest LdapDn AttributeValueAssertion - | ExtendedRequest LdapOid (Maybe ByteString) - deriving (Show, Eq, Ord) - -data ProtocolServerOp = - BindResponse LdapResult (Maybe ByteString) - | SearchResultEntry LdapDn PartialAttributeList - | SearchResultReference (NonEmpty Uri) - | SearchResultDone (LdapResult) - | ModifyResponse LdapResult - | AddResponse LdapResult - | DeleteResponse LdapResult - | ModifyDnResponse LdapResult - | CompareResponse LdapResult - | ExtendedResponse LdapResult (Maybe LdapOid) (Maybe ByteString) - deriving (Show, Eq, Ord) - -data AuthenticationChoice = Simple ByteString - deriving (Show, Eq, Ord) - -data Scope = - BaseObject - | SingleLevel - | WholeSubtree - deriving (Show, Eq, Ord) - -data DerefAliases = - NeverDerefAliases - | DerefInSearching - | DerefFindingBaseObject - | DerefAlways - deriving (Show, Eq, Ord) +-- | Message envelope. (Section 4.1.1.) +data LdapMessage op = LdapMessage + { ldapMessageId :: !Id + , ldapMessageOp :: !op + , ldapMessageControls :: !(Maybe Controls) + } deriving (Show, Eq) + +-- | Every message being processed has a unique non-zero integer ID. (Section 4.1.1.1.) +newtype Id = Id { unId :: Int32 } + deriving (Show, Eq, Ord) + +-- | Client requests. The RFC doesn't make a difference between 'ProtocolClientOp' +-- and 'ProtocolServerOp' but it's useful to distinguish between them in Haskell. +data ProtocolClientOp = + BindRequest !Int8 !LdapDn !AuthenticationChoice + | UnbindRequest + | SearchRequest !LdapDn !Scope !DerefAliases !Int32 !Int32 !Bool !Filter !AttributeSelection + | ModifyRequest !LdapDn ![(Operation, PartialAttribute)] + | AddRequest !LdapDn !AttributeList + | DeleteRequest !LdapDn + | ModifyDnRequest !LdapDn !RelativeLdapDn !Bool !(Maybe LdapDn) + | CompareRequest !LdapDn !AttributeValueAssertion + | ExtendedRequest !LdapOid !(Maybe ByteString) + deriving (Show, Eq) + +-- | Server responses. The RFC doesn't make a difference between 'ProtocolClientOp' +-- and 'ProtocolServerOp' but it's useful to distinguish between them in Haskell. +data ProtocolServerOp = + BindResponse !LdapResult !(Maybe ByteString) + | SearchResultEntry !LdapDn !PartialAttributeList + | SearchResultReference !(NonEmpty Uri) + | SearchResultDone !(LdapResult) + | ModifyResponse !LdapResult + | AddResponse !LdapResult + | DeleteResponse !LdapResult + | ModifyDnResponse !LdapResult + | CompareResponse !LdapResult + | ExtendedResponse !LdapResult !(Maybe LdapOid) !(Maybe ByteString) + | IntermediateResponse !(Maybe LdapOid) !(Maybe ByteString) + deriving (Show, Eq) + +newtype AuthenticationChoice = Simple ByteString + deriving (Show, Eq) + +data Scope = + BaseObject + | SingleLevel + | WholeSubtree + deriving (Show, Eq) -data Filter = - And (NonEmpty Filter) - | Or (NonEmpty Filter) - | Not Filter - | EqualityMatch AttributeValueAssertion - | Substrings SubstringFilter - | GreaterOrEqual AttributeValueAssertion - | LessOrEqual AttributeValueAssertion - | Present AttributeDescription - | ApproxMatch AttributeValueAssertion - | ExtensibleMatch MatchingRuleAssertion - deriving (Show, Eq, Ord) - -data SubstringFilter = SubstringFilter AttributeDescription (NonEmpty Substring) - deriving (Show, Eq, Ord) - -data Substring = - Initial AssertionValue - | Any AssertionValue - | Final AssertionValue - deriving (Show, Eq, Ord) - -data MatchingRuleAssertion = MatchingRuleAssertion (Maybe MatchingRuleId) (Maybe AttributeDescription) AssertionValue Bool - deriving (Show, Eq, Ord) - -newtype MatchingRuleId = MatchingRuleId LdapString - deriving (Show, Eq, Ord) - -newtype AttributeSelection = AttributeSelection [LdapString] - deriving (Show, Eq, Ord) - -newtype AttributeList = AttributeList [Attribute] - deriving (Show, Eq, Ord) - -newtype PartialAttributeList = PartialAttributeList [PartialAttribute] - deriving (Show, Eq, Ord) - -newtype Controls = Controls [Control] - deriving (Show, Eq, Ord) - -data Control = Control LdapOid Bool (Maybe ByteString) - deriving (Show, Eq, Ord) - -data LdapResult = LdapResult ResultCode LdapDn LdapString (Maybe ReferralUris) - deriving (Show, Eq, Ord) - -data ResultCode = - Success - | OperationError - | ProtocolError - | TimeLimitExceeded - | SizeLimitExceeded - | CompareFalse - | CompareTrue - | AuthMethodNotSupported - | StrongerAuthRequired - | Referral - | AdminLimitExceeded - | UnavailableCriticalExtension - | ConfidentialityRequired - | SaslBindInProgress - | NoSuchAttribute - | UndefinedAttributeType - | InappropriateMatching - | ConstraintViolation - | AttributeOrValueExists - | InvalidAttributeSyntax - | NoSuchObject - | AliasProblem - | InvalidDNSyntax - | AliasDereferencingProblem - | InappropriateAuthentication - | InvalidCredentials - | InsufficientAccessRights - | Busy - | Unavailable - | UnwillingToPerform - | LoopDetect - | NamingViolation - | ObjectClassViolation - | NotAllowedOnNonLeaf - | NotAllowedOnRDN - | EntryAlreadyExists - | ObjectClassModsProhibited - | AffectsMultipleDSAs - | Other - deriving (Show, Eq, Ord) - -newtype AttributeDescription = AttributeDescription LdapString - deriving (Show, Eq, Ord) - -newtype AttributeValue = AttributeValue ByteString - deriving (Show, Eq, Ord) - -data AttributeValueAssertion = AttributeValueAssertion AttributeDescription AssertionValue - deriving (Show, Eq, Ord) - -newtype AssertionValue = AssertionValue ByteString - deriving (Show, Eq, Ord) - -data Attribute = Attribute AttributeDescription (NonEmpty AttributeValue) - deriving (Show, Eq, Ord) - -data PartialAttribute = PartialAttribute AttributeDescription [AttributeValue] - deriving (Show, Eq, Ord) - -newtype LdapDn = LdapDn LdapString - deriving (Show, Eq, Ord) - -newtype RelativeLdapDn = RelativeLdapDn LdapString - deriving (Show, Eq, Ord) - -newtype ReferralUris = ReferralUris (NonEmpty Uri) - deriving (Show, Eq, Ord) - -newtype Uri = Uri LdapString - deriving (Show, Eq, Ord) +data DerefAliases = + NeverDerefAliases + | DerefInSearching + | DerefFindingBaseObject + | DerefAlways + deriving (Show, Eq) + +data Filter = + And (NonEmpty Filter) + | Or (NonEmpty Filter) + | Not Filter + | EqualityMatch AttributeValueAssertion + | Substrings SubstringFilter + | GreaterOrEqual AttributeValueAssertion + | LessOrEqual AttributeValueAssertion + | Present AttributeDescription + | ApproxMatch AttributeValueAssertion + | ExtensibleMatch MatchingRuleAssertion + deriving (Show, Eq) + +data SubstringFilter = SubstringFilter AttributeDescription (NonEmpty Substring) + deriving (Show, Eq) + +data Substring = + Initial AssertionValue + | Any AssertionValue + | Final AssertionValue + deriving (Show, Eq) + +data MatchingRuleAssertion = MatchingRuleAssertion (Maybe MatchingRuleId) (Maybe AttributeDescription) AssertionValue Bool + deriving (Show, Eq) + +-- | Matching rules are defined in Section 4.1.3 of [RFC4512]. A matching +-- rule is identified in the protocol by the printable representation of +-- either its <numericoid> or one of its short name descriptors +-- [RFC4512], e.g., 'caseIgnoreMatch' or '2.5.13.2'. (Section 4.1.8.) +newtype MatchingRuleId = MatchingRuleId LdapString + deriving (Show, Eq) + +newtype AttributeSelection = AttributeSelection [LdapString] + deriving (Show, Eq) + +newtype AttributeList = AttributeList [Attribute] + deriving (Show, Eq) + +newtype PartialAttributeList = PartialAttributeList [PartialAttribute] + deriving (Show, Eq) + +newtype Controls = Controls [Control] + deriving (Show, Eq) + +data Control = Control LdapOid Bool (Maybe ByteString) + deriving (Show, Eq) + +data LdapResult = LdapResult ResultCode LdapDn LdapString (Maybe ReferralUris) + deriving (Show, Eq) + +data ResultCode = + Success + | OperationError + | ProtocolError + | TimeLimitExceeded + | SizeLimitExceeded + | CompareFalse + | CompareTrue + | AuthMethodNotSupported + | StrongerAuthRequired + | Referral + | AdminLimitExceeded + | UnavailableCriticalExtension + | ConfidentialityRequired + | SaslBindInProgress + | NoSuchAttribute + | UndefinedAttributeType + | InappropriateMatching + | ConstraintViolation + | AttributeOrValueExists + | InvalidAttributeSyntax + | NoSuchObject + | AliasProblem + | InvalidDNSyntax + | AliasDereferencingProblem + | InappropriateAuthentication + | InvalidCredentials + | InsufficientAccessRights + | Busy + | Unavailable + | UnwillingToPerform + | LoopDetect + | NamingViolation + | ObjectClassViolation + | NotAllowedOnNonLeaf + | NotAllowedOnRDN + | EntryAlreadyExists + | ObjectClassModsProhibited + | AffectsMultipleDSAs + | Other + deriving (Show, Eq) + +newtype AttributeDescription = AttributeDescription LdapString + deriving (Show, Eq) + +newtype AttributeValue = AttributeValue ByteString + deriving (Show, Eq) + +data AttributeValueAssertion = AttributeValueAssertion AttributeDescription AssertionValue + deriving (Show, Eq) + +newtype AssertionValue = AssertionValue ByteString + deriving (Show, Eq) + +data Attribute = Attribute AttributeDescription (NonEmpty AttributeValue) + deriving (Show, Eq) + +data PartialAttribute = PartialAttribute AttributeDescription [AttributeValue] + deriving (Show, Eq) + -data Operation = - Add - | Delete - | Replace - deriving (Show, Eq, Ord) + +-- | An LDAPDN is defined to be the representation of a Distinguished Name +-- (DN) after encoding according to the specification in [RFC4514]. +newtype LdapDn = LdapDn LdapString + deriving (Show, Eq) --- | The LDAPString is a notational convenience to indicate that, although --- strings of LDAPString type encode as ASN.1 OCTET STRING types, the --- [ISO10646] character set (a superset of [Unicode]) is used, encoded --- following the UTF-8 [RFC3629] algorithm. -newtype LdapString = LdapString Text - deriving (Show, Eq, Ord) - -newtype LdapOid = LdapOid ByteString - deriving (Show, Eq, Ord) +-- | A RelativeLDAPDN is defined to be the representation of a Relative +-- Distinguished Name (RDN) after encoding according to the +-- specification in [RFC4514]. +newtype RelativeLdapDn = RelativeLdapDn LdapString + deriving (Show, Eq) + +newtype ReferralUris = ReferralUris (NonEmpty Uri) + deriving (Show, Eq) + +newtype Uri = Uri LdapString + deriving (Show, Eq) + +data Operation = + Add + | Delete + | Replace + deriving (Show, Eq) + +-- | The LDAPString is a notational convenience to indicate that, although +-- strings of LDAPString type encode as ASN.1 OCTET STRING types, the +-- [ISO10646] character set (a superset of [Unicode]) is used, encoded +-- following the UTF-8 [RFC3629] algorithm. (Section 4.1.2.) +newtype LdapString = LdapString Text + deriving (Show, Eq) + +-- | The LDAPOID is a notational convenience to indicate that the +-- permitted value of this string is a (UTF-8 encoded) dotted-decimal +-- representation of an OBJECT IDENTIFIER. Although an LDAPOID is +-- encoded as an OCTET STRING, values are limited to the definition of +-- \<numericoid\> given in Section 1.4 of [RFC4512]. +newtype LdapOid = LdapOid Text + deriving (Show, Eq)
diff --git a/src/Ldap-Client-Add.html b/src/Ldap-Client-Add.html index 4337346..270ab9f 100644 --- a/src/Ldap-Client-Add.html +++ b/src/Ldap-Client-Add.html @@ -7,49 +7,71 @@ -
module Ldap.Client.Add
-  ( add
-  , addEither
-  , addAsync
-  , addAsyncSTM
-  ) where
-
-import           Control.Monad.STM (STM, atomically)
-import           Data.List.NonEmpty (NonEmpty((:|)))
-
-import qualified Ldap.Asn1.Type as Type
-import           Ldap.Client.Internal
-
-
-add :: Ldap -> Dn -> AttrList NonEmpty -> IO ()
-add l dn as =
-  raise =<< addEither l dn as
-
-addEither :: Ldap -> Dn -> AttrList NonEmpty -> IO (Either ResponseError ())
-addEither l dn as =
-  wait =<< addAsync l dn as
-
-addAsync :: Ldap -> Dn -> AttrList NonEmpty -> IO (Async ())
-addAsync l dn as =
-  atomically (addAsyncSTM l dn as)
+
-- | <https://tools.ietf.org/html/rfc4511#section-4.7 Add> operation.
+--
+-- This operation comes in four flavours:
+--
+--   * synchronous, exception throwing ('add')
+--
+--   * synchronous, returning 'Either' 'ResponseError' @()@ ('addEither')
+--
+--   * asynchronous, 'IO' based ('addAsync')
+--
+--   * asynchronous, 'STM' based ('addAsyncSTM')
+--
+-- Of those, the first one ('add') is probably the most useful for the typical usecase.
+module Ldap.Client.Add
+  ( add
+  , addEither
+  , addAsync
+  , addAsyncSTM
+  ) where
+
+import           Control.Monad.STM (STM, atomically)
+import           Data.List.NonEmpty (NonEmpty((:|)))
+
+import qualified Ldap.Asn1.Type as Type
+import           Ldap.Client.Internal
 
-addAsyncSTM :: Ldap -> Dn -> AttrList NonEmpty -> STM (Async ())
-addAsyncSTM l dn as =
-  let req = addRequest dn as in sendRequest l (addResult req) req
-
-addRequest :: Dn -> AttrList NonEmpty -> Request
-addRequest (Dn dn) as =
-  Type.AddRequest (Type.LdapDn (Type.LdapString dn))
-                  (Type.AttributeList (map f as))
- where
-  f (Attr x, xs) = Type.Attribute (Type.AttributeDescription (Type.LdapString x))
-                                  (fmap Type.AttributeValue xs)
+
+-- | Perform the Add operation synchronously. Raises 'ResponseError' on failures.
+add :: Ldap -> Dn -> AttrList NonEmpty -> IO ()
+add l dn as =
+  raise =<< addEither l dn as
+
+-- | Perform the Add operation synchronously. Returns @Left e@ where
+-- @e@ is a 'ResponseError' on failures.
+addEither :: Ldap -> Dn -> AttrList NonEmpty -> IO (Either ResponseError ())
+addEither l dn as =
+  wait =<< addAsync l dn as
 
-addResult :: Request -> Response -> Either ResponseError ()
-addResult req (Type.AddResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn))
-                                                      (Type.LdapString msg) _) :| [])
-  | Type.Success <- code = Right ()
-  | otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
-addResult req res = Left (ResponseInvalid req res)
+-- | Perform the Add operation asynchronously. Call 'Ldap.Client.wait' to wait
+-- for its completion.
+addAsync :: Ldap -> Dn -> AttrList NonEmpty -> IO (Async ())
+addAsync l dn as =
+  atomically (addAsyncSTM l dn as)
+
+-- | Perform the Add operation asynchronously.
+--
+-- Don't wait for its completion (with 'Ldap.Client.waitSTM') in the
+-- same transaction you've performed it in.
+addAsyncSTM :: Ldap -> Dn -> AttrList NonEmpty -> STM (Async ())
+addAsyncSTM l dn as =
+  let req = addRequest dn as in sendRequest l (addResult req) req
+
+addRequest :: Dn -> AttrList NonEmpty -> Request
+addRequest (Dn dn) as =
+  Type.AddRequest (Type.LdapDn (Type.LdapString dn))
+                  (Type.AttributeList (map f as))
+ where
+  f (Attr x, xs) = Type.Attribute (Type.AttributeDescription (Type.LdapString x))
+                                  (fmap Type.AttributeValue xs)
+
+addResult :: Request -> Response -> Either ResponseError ()
+addResult req (Type.AddResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn))
+                                                      (Type.LdapString msg) _) :| [])
+  | Type.Success <- code = Right ()
+  | otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
+addResult req res = Left (ResponseInvalid req res)
 
diff --git a/src/Ldap-Client-Bind.html b/src/Ldap-Client-Bind.html index af963cd..aed3193 100644 --- a/src/Ldap-Client-Bind.html +++ b/src/Ldap-Client-Bind.html @@ -7,71 +7,71 @@ -
module Ldap.Client.Bind
-  ( bind
-  , bindEither
-  , bindAsync
-  , bindAsyncSTM
-  , unbindAsync
-  , unbindAsyncSTM
-  ) where
-
-import           Control.Monad (void)
-import           Control.Monad.STM (STM, atomically)
-import           Data.List.NonEmpty (NonEmpty((:|)))
-
-import qualified Ldap.Asn1.Type as Type
-import           Ldap.Client.Internal
-
-
-bind :: Ldap -> Dn -> Password -> IO ()
-bind l username password =
-  raise =<< bindEither l username password
-
-bindEither :: Ldap -> Dn -> Password -> IO (Either ResponseError ())
-bindEither l username password =
-  wait =<< bindAsync l username password
-
-bindAsync :: Ldap -> Dn -> Password -> IO (Async ())
-bindAsync l username password =
-  atomically (bindAsyncSTM l username password)
-
-bindAsyncSTM :: Ldap -> Dn -> Password -> STM (Async ())
-bindAsyncSTM l username password =
-  let req = bindRequest username password in sendRequest l (bindResult req) req
-
-bindRequest :: Dn -> Password -> Request
-bindRequest (Dn username) (Password password) =
-  Type.BindRequest ldapVersion
-                   (Type.LdapDn (Type.LdapString username))
-                   (Type.Simple password)
- where
-  ldapVersion = 3
-
-bindResult :: Request -> Response -> Either ResponseError ()
-bindResult req (Type.BindResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn))
-                                                        (Type.LdapString msg) _) _ :| [])
-  | Type.Success <- code = Right ()
-  | otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
-bindResult req res = Left (ResponseInvalid req res)
-
-
--- | Note that 'unbindAsync' does not return an 'Async',
--- because LDAP server never responds to @UnbindRequest@s, hence
--- a call to 'wait' on a hypothetical 'Async' would have resulted
--- in an exception anyway.
-unbindAsync :: Ldap -> IO ()
-unbindAsync =
-  atomically . unbindAsyncSTM
-
--- | Note that 'unbindAsyncSTM' does not return an 'Async',
--- because LDAP server never responds to @UnbindRequest@s, hence
--- a call to 'wait' on a hypothetical 'Async' would have resulted
--- in an exception anyway.
-unbindAsyncSTM :: Ldap -> STM ()
-unbindAsyncSTM l =
-  void (sendRequest l die Type.UnbindRequest)
- where
-  die = error "Ldap.Client: do not wait for the response to UnbindRequest"
+
-- | <https://tools.ietf.org/html/rfc4511#section-4.2 Bind> operation.
+--
+-- This operation comes in four flavours:
+--
+--   * synchronous, exception throwing ('bind')
+--
+--   * synchronous, returning 'Either' 'ResponseError' @()@ ('bindEither')
+--
+--   * asynchronous, 'IO' based ('bindAsync')
+--
+--   * asynchronous, 'STM' based ('bindAsyncSTM')
+--
+-- Of those, the first one ('bind') is probably the most useful for the typical usecase.
+module Ldap.Client.Bind
+  ( bind
+  , bindEither
+  , bindAsync
+  , bindAsyncSTM
+  ) where
+
+import           Control.Monad.STM (STM, atomically)
+import           Data.List.NonEmpty (NonEmpty((:|)))
+
+import qualified Ldap.Asn1.Type as Type
+import           Ldap.Client.Internal
+
+
+-- | Perform the Bind operation synchronously. Raises 'ResponseError' on failures.
+bind :: Ldap -> Dn -> Password -> IO ()
+bind l username password =
+  raise =<< bindEither l username password
+
+-- | Perform the Bind operation synchronously. Returns @Left e@ where
+-- @e@ is a 'ResponseError' on failures.
+bindEither :: Ldap -> Dn -> Password -> IO (Either ResponseError ())
+bindEither l username password =
+  wait =<< bindAsync l username password
+
+-- | Perform the Bind operation asynchronously. Call 'Ldap.Client.wait' to wait
+-- for its completion.
+bindAsync :: Ldap -> Dn -> Password -> IO (Async ())
+bindAsync l username password =
+  atomically (bindAsyncSTM l username password)
+
+-- | Perform the Bind operation asynchronously.
+--
+-- Don't wait for its completion (with 'Ldap.Client.waitSTM') in the
+-- same transaction you've performed it in.
+bindAsyncSTM :: Ldap -> Dn -> Password -> STM (Async ())
+bindAsyncSTM l username password =
+  let req = bindRequest username password in sendRequest l (bindResult req) req
+
+bindRequest :: Dn -> Password -> Request
+bindRequest (Dn username) (Password password) =
+  Type.BindRequest ldapVersion
+                   (Type.LdapDn (Type.LdapString username))
+                   (Type.Simple password)
+ where
+  ldapVersion = 3
+
+bindResult :: Request -> Response -> Either ResponseError ()
+bindResult req (Type.BindResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn))
+                                                        (Type.LdapString msg) _) _ :| [])
+  | Type.Success <- code = Right ()
+  | otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
+bindResult req res = Left (ResponseInvalid req res)
 
diff --git a/src/Ldap-Client-Compare.html b/src/Ldap-Client-Compare.html index a883caf..6f63061 100644 --- a/src/Ldap-Client-Compare.html +++ b/src/Ldap-Client-Compare.html @@ -7,51 +7,73 @@ -
module Ldap.Client.Compare
-  ( compare
-  , compareEither
-  , compareAsync
-  , compareAsyncSTM
-  ) where
-
-import           Control.Monad.STM (STM, atomically)
-import           Data.ByteString (ByteString)
-import           Data.List.NonEmpty (NonEmpty((:|)))
-import           Prelude hiding (compare)
-
-import           Ldap.Client.Internal
-import qualified Ldap.Asn1.Type as Type
-
-
-compare :: Ldap -> Dn -> Attr -> ByteString -> IO Bool
-compare l dn k v =
-  raise =<< compareEither l dn k v
-
-compareEither :: Ldap -> Dn -> Attr -> ByteString -> IO (Either ResponseError Bool)
-compareEither l dn k v =
-  wait =<< compareAsync l dn k v
-
-compareAsync :: Ldap -> Dn -> Attr -> ByteString -> IO (Async Bool)
-compareAsync l dn k v =
-  atomically (compareAsyncSTM l dn k v)
+
-- | <https://tools.ietf.org/html/rfc4511#section-4.10 Compare> operation.
+--
+-- This operation comes in four flavours:
+--
+--   * synchronous, exception throwing ('compare')
+--
+--   * synchronous, returning 'Either' 'ResponseError' @()@ ('compareEither')
+--
+--   * asynchronous, 'IO' based ('compareAsync')
+--
+--   * asynchronous, 'STM' based ('compareAsyncSTM')
+--
+-- Of those, the first one ('compare') is probably the most useful for the
+-- typical usecase.
+module Ldap.Client.Compare
+  ( compare
+  , compareEither
+  , compareAsync
+  , compareAsyncSTM
+  ) where
+
+import           Control.Monad.STM (STM, atomically)
+import           Data.List.NonEmpty (NonEmpty((:|)))
+import           Prelude hiding (compare)
+
+import           Ldap.Client.Internal
+import qualified Ldap.Asn1.Type as Type
 
-compareAsyncSTM :: Ldap -> Dn -> Attr -> ByteString -> STM (Async Bool)
-compareAsyncSTM l dn k v =
-  let req = compareRequest dn k v in sendRequest l (compareResult req) req
-
-compareRequest :: Dn -> Attr -> ByteString -> Request
-compareRequest (Dn dn) (Attr k) v =
-  Type.CompareRequest (Type.LdapDn (Type.LdapString dn))
-                      (Type.AttributeValueAssertion
-                        (Type.AttributeDescription (Type.LdapString k))
-                        (Type.AssertionValue v))
-
-compareResult :: Request -> Response -> Either ResponseError Bool
-compareResult req (Type.CompareResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn))
-                                                              (Type.LdapString msg) _) :| [])
-  | Type.CompareTrue  <- code = Right True
-  | Type.CompareFalse <- code = Right False
-  | otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
-compareResult req res = Left (ResponseInvalid req res)
+
+-- | Perform the Compare operation synchronously. Raises 'ResponseError' on failures.
+compare :: Ldap -> Dn -> Attr -> AttrValue -> IO Bool
+compare l dn k v =
+  raise =<< compareEither l dn k v
+
+-- | Perform the Compare operation synchronously. Returns @Left e@ where
+-- @e@ is a 'ResponseError' on failures.
+compareEither :: Ldap -> Dn -> Attr -> AttrValue -> IO (Either ResponseError Bool)
+compareEither l dn k v =
+  wait =<< compareAsync l dn k v
+
+-- | Perform the Compare operation asynchronously. Call 'Ldap.Client.wait' to wait
+-- for its completion.
+compareAsync :: Ldap -> Dn -> Attr -> AttrValue -> IO (Async Bool)
+compareAsync l dn k v =
+  atomically (compareAsyncSTM l dn k v)
+
+-- | Perform the Compare operation asynchronously.
+--
+-- Don't wait for its completion (with 'Ldap.Client.waitSTM') in the
+-- same transaction you've performed it in.
+compareAsyncSTM :: Ldap -> Dn -> Attr -> AttrValue -> STM (Async Bool)
+compareAsyncSTM l dn k v =
+  let req = compareRequest dn k v in sendRequest l (compareResult req) req
+
+compareRequest :: Dn -> Attr -> AttrValue -> Request
+compareRequest (Dn dn) (Attr k) v =
+  Type.CompareRequest (Type.LdapDn (Type.LdapString dn))
+                      (Type.AttributeValueAssertion
+                        (Type.AttributeDescription (Type.LdapString k))
+                        (Type.AssertionValue v))
+
+compareResult :: Request -> Response -> Either ResponseError Bool
+compareResult req (Type.CompareResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn))
+                                                              (Type.LdapString msg) _) :| [])
+  | Type.CompareTrue  <- code = Right True
+  | Type.CompareFalse <- code = Right False
+  | otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
+compareResult req res = Left (ResponseInvalid req res)
 
diff --git a/src/Ldap-Client-Delete.html b/src/Ldap-Client-Delete.html index c10197e..de4b288 100644 --- a/src/Ldap-Client-Delete.html +++ b/src/Ldap-Client-Delete.html @@ -7,45 +7,67 @@ -
module Ldap.Client.Delete
-  ( delete
-  , deleteEither
-  , deleteAsync
-  , deleteAsyncSTM
-  ) where
-
-import           Control.Concurrent.STM (STM, atomically)
-import           Data.List.NonEmpty (NonEmpty((:|)))
-
-import qualified Ldap.Asn1.Type as Type
-import           Ldap.Client.Internal
-
-
-delete :: Ldap -> Dn -> IO ()
-delete l dn =
-  raise =<< deleteEither l dn
-
-deleteEither :: Ldap -> Dn -> IO (Either ResponseError ())
-deleteEither l dn =
-  wait =<< deleteAsync l dn
-
-deleteAsync :: Ldap -> Dn -> IO (Async ())
-deleteAsync l dn =
-  atomically (deleteAsyncSTM l dn)
+
-- | <https://tools.ietf.org/html/rfc4511#section-4.8 Delete> operation.
+--
+-- This operation comes in four flavours:
+--
+--   * synchronous, exception throwing ('delete')
+--
+--   * synchronous, returning 'Either' 'ResponseError' @()@ ('deleteEither')
+--
+--   * asynchronous, 'IO' based ('deleteAsync')
+--
+--   * asynchronous, 'STM' based ('deleteAsyncSTM')
+--
+-- Of those, the first one ('delete') is probably the most useful for the typical usecase.
+module Ldap.Client.Delete
+  ( delete
+  , deleteEither
+  , deleteAsync
+  , deleteAsyncSTM
+  ) where
+
+import           Control.Concurrent.STM (STM, atomically)
+import           Data.List.NonEmpty (NonEmpty((:|)))
+
+import qualified Ldap.Asn1.Type as Type
+import           Ldap.Client.Internal
 
-deleteAsyncSTM :: Ldap -> Dn -> STM (Async ())
-deleteAsyncSTM l dn =
-  let req = deleteRequest dn in sendRequest l (deleteResult req) req
-
-deleteRequest :: Dn -> Request
-deleteRequest (Dn dn) =
-  Type.DeleteRequest (Type.LdapDn (Type.LdapString dn))
-
-deleteResult :: Request -> Response -> Either ResponseError ()
-deleteResult req (Type.DeleteResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn))
-                                                            (Type.LdapString msg) _) :| [])
-  | Type.Success <- code = Right ()
-  | otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
-deleteResult req res = Left (ResponseInvalid req res)
+
+-- | Perform the Delete operation synchronously. Raises 'ResponseError' on failures.
+delete :: Ldap -> Dn -> IO ()
+delete l dn =
+  raise =<< deleteEither l dn
+
+-- | Perform the Delete operation synchronously. Returns @Left e@ where
+-- @e@ is a 'ResponseError' on failures.
+deleteEither :: Ldap -> Dn -> IO (Either ResponseError ())
+deleteEither l dn =
+  wait =<< deleteAsync l dn
+
+-- | Perform the Delete operation asynchronously. Call 'Ldap.Client.wait' to wait
+-- for its completion.
+deleteAsync :: Ldap -> Dn -> IO (Async ())
+deleteAsync l dn =
+  atomically (deleteAsyncSTM l dn)
+
+-- | Perform the Delete operation asynchronously.
+--
+-- Don't wait for its completion (with 'Ldap.Client.waitSTM') in the
+-- same transaction you've performed it in.
+deleteAsyncSTM :: Ldap -> Dn -> STM (Async ())
+deleteAsyncSTM l dn =
+  let req = deleteRequest dn in sendRequest l (deleteResult req) req
+
+deleteRequest :: Dn -> Request
+deleteRequest (Dn dn) =
+  Type.DeleteRequest (Type.LdapDn (Type.LdapString dn))
+
+deleteResult :: Request -> Response -> Either ResponseError ()
+deleteResult req (Type.DeleteResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn))
+                                                            (Type.LdapString msg) _) :| [])
+  | Type.Success <- code = Right ()
+  | otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
+deleteResult req res = Left (ResponseInvalid req res)
 
diff --git a/src/Ldap-Client-Extended.html b/src/Ldap-Client-Extended.html index ca12d31..d41ef2d 100644 --- a/src/Ldap-Client-Extended.html +++ b/src/Ldap-Client-Extended.html @@ -8,68 +8,90 @@
{-# LANGUAGE OverloadedStrings #-}
-module Ldap.Client.Extended
-  ( extended
-  , extendedEither
-  , extendedAsync
-  , extendedAsyncSTM
-  , startTls
-  , startTlsEither
-  , startTlsAsync
-  , startTlsAsyncSTM
-  ) where
-
-import           Control.Monad ((<=<))
-import           Control.Monad.STM (STM, atomically)
-import           Data.ByteString (ByteString)
-import           Data.List.NonEmpty (NonEmpty((:|)))
-
-import qualified Ldap.Asn1.Type as Type
-import           Ldap.Client.Internal
-
-
-extended :: Ldap -> Oid -> Maybe ByteString -> IO ()
-extended l oid mv =
-  raise =<< extendedEither l oid mv
+-- | <https://tools.ietf.org/html/rfc4511#section-4.12 Extended> operation.
+--
+-- This operation comes in four flavours:
+--
+--   * synchronous, exception throwing ('extended')
+--
+--   * synchronous, returning 'Either' 'ResponseError' @()@ ('extendedEither')
+--
+--   * asynchronous, 'IO' based ('extendedAsync')
+--
+--   * asynchronous, 'STM' based ('extendedAsyncSTM')
+--
+-- Of those, the first one ('extended') is probably the most useful for the typical usecase.
+module Ldap.Client.Extended
+  ( extended
+  , extendedEither
+  , extendedAsync
+  , extendedAsyncSTM
+  , startTls
+  , startTlsEither
+  , startTlsAsync
+  , startTlsAsyncSTM
+  ) where
 
-extendedEither :: Ldap -> Oid -> Maybe ByteString -> IO (Either ResponseError ())
-extendedEither l oid mv =
-  wait =<< extendedAsync l oid mv
-
-extendedAsync :: Ldap -> Oid -> Maybe ByteString -> IO (Async ())
-extendedAsync l oid mv =
-  atomically (extendedAsyncSTM l oid mv)
+import           Control.Monad ((<=<))
+import           Control.Monad.STM (STM, atomically)
+import           Data.ByteString (ByteString)
+import           Data.List.NonEmpty (NonEmpty((:|)))
+
+import qualified Ldap.Asn1.Type as Type
+import           Ldap.Client.Internal
 
-extendedAsyncSTM :: Ldap -> Oid -> Maybe ByteString -> STM (Async ())
-extendedAsyncSTM l oid mv =
-  let req = extendedRequest oid mv in sendRequest l (extendedResult req) req
-
-extendedRequest :: Oid -> Maybe ByteString -> Request
-extendedRequest (Oid oid) =
-  Type.ExtendedRequest (Type.LdapOid oid)
-
-extendedResult :: Request -> Response -> Either ResponseError ()
-extendedResult req (Type.ExtendedResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn))
-                                                                (Type.LdapString msg) _) _ _ :| [])
-  | Type.Success <- code = Right ()
-  | otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
-extendedResult req res = Left (ResponseInvalid req res)
-
-
-startTls :: Ldap -> IO ()
-startTls =
-  raise <=< startTlsEither
-
-startTlsEither :: Ldap -> IO (Either ResponseError ())
-startTlsEither =
-  wait <=< startTlsAsync
-
-startTlsAsync :: Ldap -> IO (Async ())
-startTlsAsync =
-  atomically . startTlsAsyncSTM
-
-startTlsAsyncSTM :: Ldap -> STM (Async ())
-startTlsAsyncSTM l =
-  extendedAsyncSTM l (Oid "1.3.6.1.4.1.1466.20037") Nothing
+
+-- | Perform the Extended operation synchronously. Raises 'ResponseError' on failures.
+extended :: Ldap -> Oid -> Maybe ByteString -> IO ()
+extended l oid mv =
+  raise =<< extendedEither l oid mv
+
+-- | Perform the Extended operation synchronously. Returns @Left e@ where
+-- @e@ is a 'ResponseError' on failures.
+extendedEither :: Ldap -> Oid -> Maybe ByteString -> IO (Either ResponseError ())
+extendedEither l oid mv =
+  wait =<< extendedAsync l oid mv
+
+-- | Perform the Extended operation asynchronously. Call 'Ldap.Client.wait' to wait
+-- for its completion.
+extendedAsync :: Ldap -> Oid -> Maybe ByteString -> IO (Async ())
+extendedAsync l oid mv =
+  atomically (extendedAsyncSTM l oid mv)
+
+-- | Perform the Extended operation asynchronously.
+--
+-- Don't wait for its completion (with 'Ldap.Client.waitSTM') in the
+-- same transaction you've performed it in.
+extendedAsyncSTM :: Ldap -> Oid -> Maybe ByteString -> STM (Async ())
+extendedAsyncSTM l oid mv =
+  let req = extendedRequest oid mv in sendRequest l (extendedResult req) req
+
+extendedRequest :: Oid -> Maybe ByteString -> Request
+extendedRequest (Oid oid) =
+  Type.ExtendedRequest (Type.LdapOid oid)
+
+extendedResult :: Request -> Response -> Either ResponseError ()
+extendedResult req (Type.ExtendedResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn))
+                                                                (Type.LdapString msg) _) _ _ :| [])
+  | Type.Success <- code = Right ()
+  | otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
+extendedResult req res = Left (ResponseInvalid req res)
+
+
+startTls :: Ldap -> IO ()
+startTls =
+  raise <=< startTlsEither
+
+startTlsEither :: Ldap -> IO (Either ResponseError ())
+startTlsEither =
+  wait <=< startTlsAsync
+
+startTlsAsync :: Ldap -> IO (Async ())
+startTlsAsync =
+  atomically . startTlsAsyncSTM
+
+startTlsAsyncSTM :: Ldap -> STM (Async ())
+startTlsAsyncSTM l =
+  extendedAsyncSTM l (Oid "1.3.6.1.4.1.1466.20037") Nothing
 
diff --git a/src/Ldap-Client-Internal.html b/src/Ldap-Client-Internal.html index 733dde5..4bc9031 100644 --- a/src/Ldap-Client-Internal.html +++ b/src/Ldap-Client-Internal.html @@ -21,92 +21,92 @@ -- * Waiting for Request Completion , wait , waitSTM - -- * Misc - , Response - , ResponseError(..) - , Request - , raise - , sendRequest - , Dn(..) - , RelativeDn(..) - , Password(..) - , Attr(..) - , unAttr - ) where - -import Control.Concurrent.STM (STM, atomically) -import Control.Concurrent.STM.TMVar (TMVar, newEmptyTMVar, readTMVar) -import Control.Concurrent.STM.TQueue (TQueue, writeTQueue) -import Control.Exception (Exception, throwIO) -import Data.ByteString (ByteString) -import Data.List.NonEmpty (NonEmpty) -import Data.Text (Text) -import Data.Typeable (Typeable) -import Network (PortNumber) - -import qualified Ldap.Asn1.Type as Type - - -data Host = - Plain String - | Secure String - | Insecure String - deriving (Show, Eq, Ord) - -data Ldap = Ldap - { client :: TQueue ClientMessage - } deriving (Eq) + , unbindAsync + , unbindAsyncSTM + -- * Misc + , Response + , ResponseError(..) + , Request + , raise + , sendRequest + , Dn(..) + , RelativeDn(..) + , Password(..) + , Attr(..) + , AttrValue + , unAttr + ) where + +import Control.Concurrent.STM (STM, atomically) +import Control.Concurrent.STM.TMVar (TMVar, newEmptyTMVar, readTMVar) +import Control.Concurrent.STM.TQueue (TQueue, writeTQueue) +import Control.Exception (Exception, throwIO) +import Control.Monad (void) +import Data.ByteString (ByteString) +import Data.List.NonEmpty (NonEmpty) +import Data.Text (Text) +import Data.Typeable (Typeable) +import Network (PortNumber) + +import qualified Ldap.Asn1.Type as Type + + +data Host = + Plain String + | Secure String + | Insecure String + deriving (Show, Eq, Ord) -data ClientMessage = New Request (TMVar (NonEmpty Type.ProtocolServerOp)) -type Request = Type.ProtocolClientOp -type InMessage = Type.ProtocolServerOp -type Response = NonEmpty InMessage - -data Async a = Async (STM (Either ResponseError a)) - -instance Functor Async where - fmap f (Async stm) = Async (fmap (fmap f) stm) - +data Ldap = Ldap + { client :: TQueue ClientMessage + } deriving (Eq) + +data ClientMessage = New Request (TMVar (NonEmpty Type.ProtocolServerOp)) +type Request = Type.ProtocolClientOp +type InMessage = Type.ProtocolServerOp +type Response = NonEmpty InMessage + +data Async a = Async (STM (Either ResponseError a)) -newtype Dn = Dn Text - deriving (Show, Eq) +instance Functor Async where + fmap f (Async stm) = Async (fmap (fmap f) stm) -newtype RelativeDn = RelativeDn Text +newtype Dn = Dn Text deriving (Show, Eq) -newtype Oid = Oid ByteString +newtype RelativeDn = RelativeDn Text deriving (Show, Eq) -newtype Password = Password ByteString +newtype Oid = Oid Text deriving (Show, Eq) - -data ResponseError = - ResponseInvalid Request Response - | ResponseErrorCode Request Type.ResultCode Dn Text - deriving (Show, Eq, Typeable) - -instance Exception ResponseError +newtype Password = Password ByteString + deriving (Show, Eq) + +data ResponseError = + ResponseInvalid Request Response + | ResponseErrorCode Request Type.ResultCode Dn Text + deriving (Show, Eq, Typeable) - +instance Exception ResponseError newtype Attr = Attr Text deriving (Show, Eq) -type AttrList f = [(Attr, f ByteString)] +type AttrValue = ByteString --- 'Attr' unwrapper. This is a separate function not to turn 'Attr''s --- 'Show' instance into complete and utter shit. -unAttr :: Attr -> Text -unAttr (Attr a) = a - - -wait :: Async a -> IO (Either ResponseError a) -wait = atomically . waitSTM - -waitSTM :: Async a -> STM (Either ResponseError a) -waitSTM (Async stm) = stm - +type AttrList f = [(Attr, f AttrValue)] + +-- 'Attr' unwrapper. This is a separate function not to turn 'Attr''s +-- 'Show' instance into complete and utter shit. +unAttr :: Attr -> Text +unAttr (Attr a) = a + +wait :: Async a -> IO (Either ResponseError a) +wait = atomically . waitSTM + +waitSTM :: Async a -> STM (Either ResponseError a) +waitSTM (Async stm) = stm sendRequest :: Ldap -> (Response -> Either ResponseError a) -> Request -> STM (Async a) sendRequest l p msg = @@ -119,5 +119,24 @@ raise :: Exception e => Either e a -> IO a raise = either throwIO return + + +-- | Note that 'unbindAsync' does not return an 'Async', +-- because LDAP server never responds to @UnbindRequest@s, hence +-- a call to 'wait' on a hypothetical 'Async' would have resulted +-- in an exception anyway. +unbindAsync :: Ldap -> IO () +unbindAsync = + atomically . unbindAsyncSTM + +-- | Note that 'unbindAsyncSTM' does not return an 'Async', +-- because LDAP server never responds to @UnbindRequest@s, hence +-- a call to 'wait' on a hypothetical 'Async' would have resulted +-- in an exception anyway. +unbindAsyncSTM :: Ldap -> STM () +unbindAsyncSTM l = + void (sendRequest l die Type.UnbindRequest) + where + die = error "Ldap.Client: do not wait for the response to UnbindRequest"
diff --git a/src/Ldap-Client-Modify.html b/src/Ldap-Client-Modify.html index 9c4e286..e88eab1 100644 --- a/src/Ldap-Client-Modify.html +++ b/src/Ldap-Client-Modify.html @@ -7,96 +7,130 @@ -
module Ldap.Client.Modify
-  ( Operation(..)
-  , modify
-  , modifyEither
-  , modifyAsync
-  , modifyAsyncSTM
-  , modifyDn
-  , modifyDnEither
-  , modifyDnAsync
-  , modifyDnAsyncSTM
-  ) where
-
-import           Control.Monad.STM (STM, atomically)
-import           Data.ByteString (ByteString)
-import           Data.List.NonEmpty (NonEmpty((:|)))
-
-import qualified Ldap.Asn1.Type as Type
-import           Ldap.Client.Internal
-
-
-data Operation =
-    Delete Attr [ByteString]
-  | Add Attr [ByteString]
-  | Replace Attr [ByteString]
-    deriving (Show, Eq)
-
-modify :: Ldap -> Dn -> [Operation] -> IO ()
-modify l dn as =
-  raise =<< modifyEither l dn as
-
-modifyEither :: Ldap -> Dn -> [Operation] -> IO (Either ResponseError ())
-modifyEither l dn as =
-  wait =<< modifyAsync l dn as
+
-- | <https://tools.ietf.org/html/rfc4511#section-4.6 Modify> and
+-- <https://tools.ietf.org/html/rfc4511#section-4.9 Modify DN> operations.
+--
+-- These operations come in four flavours:
+--
+--   * synchronous, exception throwing ('modify' / 'modifyDn')
+--
+--   * synchronous, returning 'Either' 'ResponseError' @()@
+--     ('modifyEither' / 'modifyDnEither')
+--
+--   * asynchronous, 'IO' based ('modifyAsync' / 'modifyDnAsync')
+--
+--   * asynchronous, 'STM' based ('modifyAsyncSTM' / 'modifyDnAsyncSTM')
+--
+-- Of those, the first one ('modify' / 'modifyDn') is probably the most
+-- useful for the typical usecase.
+module Ldap.Client.Modify
+  ( Operation(..)
+  , modify
+  , modifyEither
+  , modifyAsync
+  , modifyAsyncSTM
+  , modifyDn
+  , modifyDnEither
+  , modifyDnAsync
+  , modifyDnAsyncSTM
+  ) where
+
+import           Control.Monad.STM (STM, atomically)
+import           Data.List.NonEmpty (NonEmpty((:|)))
+
+import qualified Ldap.Asn1.Type as Type
+import           Ldap.Client.Internal
 
-modifyAsync :: Ldap -> Dn -> [Operation] -> IO (Async ())
-modifyAsync l dn as =
-  atomically (modifyAsyncSTM l dn as)
-
-modifyAsyncSTM :: Ldap -> Dn -> [Operation] -> STM (Async ())
-modifyAsyncSTM l dn xs =
-  let req = modifyRequest dn xs in sendRequest l (modifyResult req) req
+
+-- | Type of modification being performed.
+data Operation =
+    Delete Attr [AttrValue] -- ^ Delete values from the attribute. Deletes the attribute if the list is empty or all current values are listed.
+  | Add Attr [AttrValue] -- ^ Add values to the attribute, creating it if necessary.
+  | Replace Attr [AttrValue] -- ^ Replace all existing values of the attribute with the new list. Deletes the attribute if the list is empty.
+    deriving (Show, Eq)
 
-modifyRequest :: Dn -> [Operation] -> Request
-modifyRequest (Dn dn) xs =
-  Type.ModifyRequest (Type.LdapDn (Type.LdapString dn)) (map f xs)
- where
-  f (Delete (Attr k) vs) =
-    (Type.Delete, Type.PartialAttribute (Type.AttributeDescription (Type.LdapString k))
-                                        (map Type.AttributeValue vs))
-  f (Add (Attr k) vs) =
-    (Type.Add, Type.PartialAttribute (Type.AttributeDescription (Type.LdapString k))
-                                     (map Type.AttributeValue vs))
-  f (Replace (Attr k) vs) =
-    (Type.Replace, Type.PartialAttribute (Type.AttributeDescription (Type.LdapString k))
-                                         (map Type.AttributeValue vs))
-
-modifyResult :: Request -> Response -> Either ResponseError ()
-modifyResult req (Type.ModifyResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn)) (Type.LdapString msg) _) :| [])
-  | Type.Success <- code = Right ()
-  | otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
-modifyResult req res = Left (ResponseInvalid req res)
-
-
-modifyDn :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> IO ()
-modifyDn l dn rdn del new =
-  raise =<< modifyDnEither l dn rdn del new
+-- | Perform the Modify operation synchronously. Raises 'ResponseError' on failures.
+modify :: Ldap -> Dn -> [Operation] -> IO ()
+modify l dn as =
+  raise =<< modifyEither l dn as
+
+-- | Perform the Modify operation synchronously. Returns @Left e@ where
+-- @e@ is a 'ResponseError' on failures.
+modifyEither :: Ldap -> Dn -> [Operation] -> IO (Either ResponseError ())
+modifyEither l dn as =
+  wait =<< modifyAsync l dn as
+
+-- | Perform the Modify operation asynchronously. Call 'Ldap.Client.wait' to wait
+-- for its completion.
+modifyAsync :: Ldap -> Dn -> [Operation] -> IO (Async ())
+modifyAsync l dn as =
+  atomically (modifyAsyncSTM l dn as)
+
+-- | Perform the Modify operation asynchronously.
+--
+-- Don't wait for its completion (with 'Ldap.Client.waitSTM') in the
+-- same transaction you've performed it in.
+modifyAsyncSTM :: Ldap -> Dn -> [Operation] -> STM (Async ())
+modifyAsyncSTM l dn xs =
+  let req = modifyRequest dn xs in sendRequest l (modifyResult req) req
 
-modifyDnEither :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> IO (Either ResponseError ())
-modifyDnEither l dn rdn del new =
-  wait =<< modifyDnAsync l dn rdn del new
-
-modifyDnAsync :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> IO (Async ())
-modifyDnAsync l dn rdn del new =
-  atomically (modifyDnAsyncSTM l dn rdn del new)
-
-modifyDnAsyncSTM :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> STM (Async ())
-modifyDnAsyncSTM l dn rdn del new =
-  let req = modifyDnRequest dn rdn del new in sendRequest l (modifyDnResult req) req
-
-modifyDnRequest :: Dn -> RelativeDn -> Bool -> Maybe Dn -> Request
-modifyDnRequest (Dn dn) (RelativeDn rdn) del new =
-  Type.ModifyDnRequest (Type.LdapDn (Type.LdapString dn))
-                       (Type.RelativeLdapDn (Type.LdapString rdn))
-                       del
-                       (fmap (\(Dn dn') -> Type.LdapDn (Type.LdapString dn')) new)
-
-modifyDnResult :: Request -> Response -> Either ResponseError ()
-modifyDnResult req (Type.ModifyDnResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn)) (Type.LdapString msg) _) :| [])
-  | Type.Success <- code = Right ()
-  | otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
-modifyDnResult req res = Left (ResponseInvalid req res)
+modifyRequest :: Dn -> [Operation] -> Request
+modifyRequest (Dn dn) xs =
+  Type.ModifyRequest (Type.LdapDn (Type.LdapString dn)) (map f xs)
+ where
+  f (Delete (Attr k) vs) =
+    (Type.Delete, Type.PartialAttribute (Type.AttributeDescription (Type.LdapString k))
+                                        (map Type.AttributeValue vs))
+  f (Add (Attr k) vs) =
+    (Type.Add, Type.PartialAttribute (Type.AttributeDescription (Type.LdapString k))
+                                     (map Type.AttributeValue vs))
+  f (Replace (Attr k) vs) =
+    (Type.Replace, Type.PartialAttribute (Type.AttributeDescription (Type.LdapString k))
+                                         (map Type.AttributeValue vs))
+
+modifyResult :: Request -> Response -> Either ResponseError ()
+modifyResult req (Type.ModifyResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn)) (Type.LdapString msg) _) :| [])
+  | Type.Success <- code = Right ()
+  | otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
+modifyResult req res = Left (ResponseInvalid req res)
+
+
+-- | Perform the Modify DN operation synchronously. Raises 'ResponseError' on failures.
+modifyDn :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> IO ()
+modifyDn l dn rdn del new =
+  raise =<< modifyDnEither l dn rdn del new
+
+-- | Perform the Modify DN operation synchronously. Returns @Left e@ where
+-- @e@ is a 'ResponseError' on failures.
+modifyDnEither :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> IO (Either ResponseError ())
+modifyDnEither l dn rdn del new =
+  wait =<< modifyDnAsync l dn rdn del new
+
+-- | Perform the Modify DN operation asynchronously. Call 'Ldap.Client.wait' to wait
+-- for its completion.
+modifyDnAsync :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> IO (Async ())
+modifyDnAsync l dn rdn del new =
+  atomically (modifyDnAsyncSTM l dn rdn del new)
+
+-- | Perform the Modify DN operation asynchronously.
+--
+-- Don't wait for its completion (with 'Ldap.Client.waitSTM') in the
+-- same transaction you've performed it in.
+modifyDnAsyncSTM :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> STM (Async ())
+modifyDnAsyncSTM l dn rdn del new =
+  let req = modifyDnRequest dn rdn del new in sendRequest l (modifyDnResult req) req
+
+modifyDnRequest :: Dn -> RelativeDn -> Bool -> Maybe Dn -> Request
+modifyDnRequest (Dn dn) (RelativeDn rdn) del new =
+  Type.ModifyDnRequest (Type.LdapDn (Type.LdapString dn))
+                       (Type.RelativeLdapDn (Type.LdapString rdn))
+                       del
+                       (fmap (\(Dn dn') -> Type.LdapDn (Type.LdapString dn')) new)
+
+modifyDnResult :: Request -> Response -> Either ResponseError ()
+modifyDnResult req (Type.ModifyDnResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn)) (Type.LdapString msg) _) :| [])
+  | Type.Success <- code = Right ()
+  | otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
+modifyDnResult req res = Left (ResponseInvalid req res)
 
diff --git a/src/Ldap-Client-Search.html b/src/Ldap-Client-Search.html index adced5e..fe98327 100644 --- a/src/Ldap-Client-Search.html +++ b/src/Ldap-Client-Search.html @@ -9,181 +9,208 @@
{-# LANGUAGE CPP #-}
 {-# LANGUAGE NamedFieldPuns #-}
-module Ldap.Client.Search
-  ( search
-  , searchEither
-  , searchAsync
-  , searchAsyncSTM
-  , Search
-  , Mod
-  , Type.Scope(..)
-  , scope
-  , size
-  , time
-  , typesOnly
-  , derefAliases
-  , Filter(..)
-  , SearchEntry(..)
-  ) where
-
-import           Control.Monad.STM (STM, atomically)
-import           Data.ByteString (ByteString)
-import           Data.Int (Int32)
-import           Data.List.NonEmpty (NonEmpty((:|)))
-import qualified Data.List.NonEmpty as NonEmpty
-import           Data.Maybe (mapMaybe)
-#if __GLASGOW_HASKELL__ >= 710
-import           Data.Semigroup (Semigroup(..))
-#else
-import           Data.Semigroup (Semigroup(..), Monoid(..))
-#endif
-
-import qualified Ldap.Asn1.Type as Type
-import           Ldap.Client.Internal
-
-
-search :: Ldap -> Dn -> Mod Search -> Filter -> [Attr] -> IO [SearchEntry]
-search l base opts flt attributes =
-  raise =<< searchEither l base opts flt attributes
-
-searchEither
-  :: Ldap
-  -> Dn
-  -> Mod Search
-  -> Filter
-  -> [Attr]
-  -> IO (Either ResponseError [SearchEntry])
-searchEither l base opts flt attributes =
-  wait =<< searchAsync l base opts flt attributes
-
-searchAsync :: Ldap -> Dn -> Mod Search -> Filter -> [Attr] -> IO (Async [SearchEntry])
-searchAsync l base opts flt attributes =
-  atomically (searchAsyncSTM l base opts flt attributes)
-
-searchAsyncSTM :: Ldap -> Dn -> Mod Search -> Filter -> [Attr] -> STM (Async [SearchEntry])
-searchAsyncSTM l base opts flt attributes =
-  let req = searchRequest base opts flt attributes in sendRequest l (searchResult req) req
-
-searchRequest :: Dn -> Mod Search -> Filter -> [Attr] -> Request
-searchRequest (Dn base) (Mod m) flt attributes =
-  Type.SearchRequest (Type.LdapDn (Type.LdapString base))
-                     _scope
-                     _derefAliases
-                     _size
-                     _time
-                     _typesOnly
-                     (fromFilter flt)
-                     (Type.AttributeSelection (map (Type.LdapString . unAttr) attributes))
- where
-  Search { _scope, _derefAliases, _size, _time, _typesOnly } =
-    m defaultSearch
-  fromFilter (Not x) = Type.Not (fromFilter x)
-  fromFilter (And xs) = Type.And (fmap fromFilter xs)
-  fromFilter (Or xs) = Type.Or (fmap fromFilter xs)
-  fromFilter (Present (Attr x)) =
-    Type.Present (Type.AttributeDescription (Type.LdapString x))
-  fromFilter (Attr x := y) =
-    Type.EqualityMatch
-      (Type.AttributeValueAssertion (Type.AttributeDescription (Type.LdapString x))
-                                    (Type.AssertionValue y))
-  fromFilter (Attr x :>= y) =
-    Type.GreaterOrEqual
-      (Type.AttributeValueAssertion (Type.AttributeDescription (Type.LdapString x))
-                                    (Type.AssertionValue y))
-  fromFilter (Attr x :<= y) =
-    Type.LessOrEqual
-      (Type.AttributeValueAssertion (Type.AttributeDescription (Type.LdapString x))
-                                    (Type.AssertionValue y))
-  fromFilter (Attr x :~= y) =
-    Type.ApproxMatch
-      (Type.AttributeValueAssertion (Type.AttributeDescription (Type.LdapString x))
-                                    (Type.AssertionValue y))
-  fromFilter (Attr x :=* (mi, xs, mf)) =
-    Type.Substrings
-      (Type.SubstringFilter (Type.AttributeDescription (Type.LdapString x))
-                            (NonEmpty.fromList (concat
-                              [ maybe [] (\i -> [Type.Initial (Type.AssertionValue i)]) mi
-                              , fmap (Type.Any . Type.AssertionValue) xs
-                              , maybe [] (\f -> [Type.Final (Type.AssertionValue f)]) mf
-                              ])))
-  fromFilter ((mx, mr, b) ::= y) =
-    Type.ExtensibleMatch
-      (Type.MatchingRuleAssertion (fmap (\(Attr r) -> Type.MatchingRuleId (Type.LdapString r)) mr)
-                                  (fmap (\(Attr x) -> Type.AttributeDescription (Type.LdapString x)) mx)
-                                  (Type.AssertionValue y)
-                                  b)
-
-searchResult :: Request -> Response -> Either ResponseError [SearchEntry]
-searchResult req (Type.SearchResultDone (Type.LdapResult code (Type.LdapDn (Type.LdapString dn'))
-                                                              (Type.LdapString msg) _) :| xs)
-  | Type.Success <- code = Right (mapMaybe g xs)
-  | Type.AdminLimitExceeded <- code = Right (mapMaybe g xs)
-  | Type.SizeLimitExceeded <- code = Right (mapMaybe g xs)
-  | otherwise = Left (ResponseErrorCode req code (Dn dn') msg)
- where
-  g (Type.SearchResultEntry (Type.LdapDn (Type.LdapString dn))
-                            (Type.PartialAttributeList ys)) =
-    Just (SearchEntry (Dn dn) (map h ys))
-  g _ = Nothing
-  h (Type.PartialAttribute (Type.AttributeDescription (Type.LdapString x))
-                           y) = (Attr x, fmap j y)
-  j (Type.AttributeValue x) = x
-searchResult req res = Left (ResponseInvalid req res)
-
-data Search = Search
-  { _scope        :: Type.Scope
-  , _derefAliases :: Type.DerefAliases
-  , _size         :: Int32
-  , _time         :: Int32
-  , _typesOnly    :: Bool
-  } deriving (Show, Eq)
-
-defaultSearch :: Search
-defaultSearch = Search
-  { _scope        = Type.BaseObject
-  , _size         = 0
-  , _time         = 0
-  , _typesOnly    = False
-  , _derefAliases = Type.NeverDerefAliases
-  }
-
-scope :: Type.Scope -> Mod Search
-scope x = Mod (\y -> y { _scope = x })
-
-size :: Int32 -> Mod Search
-size x = Mod (\y -> y { _size = x })
-
-time :: Int32 -> Mod Search
-time x = Mod (\y -> y { _time = x })
-
-typesOnly :: Bool -> Mod Search
-typesOnly x = Mod (\y -> y { _typesOnly = x })
-
-derefAliases :: Type.DerefAliases -> Mod Search
-derefAliases x = Mod (\y -> y { _derefAliases = x })
-
-newtype Mod a = Mod (a -> a)
-
-instance Semigroup (Mod a) where
-  Mod f <> Mod g = Mod (g . f)
-
-instance Monoid (Mod a) where
-  mempty = Mod id
-  mappend = (<>)
-
-data Filter =
-    Not Filter
-  | And (NonEmpty Filter)
-  | Or (NonEmpty Filter)
-  | Present Attr
-  | Attr := ByteString
-  | Attr :>= ByteString
-  | Attr :<= ByteString
-  | Attr :~= ByteString
-  | Attr :=* (Maybe ByteString, [ByteString], Maybe ByteString)
-  | (Maybe Attr, Maybe Attr, Bool) ::= ByteString
+-- | <https://tools.ietf.org/html/rfc4511#section-4.5 Search> operation.
+--
+-- This operation comes in four flavours:
+--
+--   * synchronous, exception throwing ('search')
+--
+--   * synchronous, returning 'Either' 'ResponseError' @()@ ('searchEither')
+--
+--   * asynchronous, 'IO' based ('searchAsync')
+--
+--   * asynchronous, 'STM' based ('searchAsyncSTM')
+--
+-- Of those, the first one ('search') is probably the most useful for the typical usecase.
+module Ldap.Client.Search
+  ( search
+  , searchEither
+  , searchAsync
+  , searchAsyncSTM
+  , Search
+  , Mod
+  , Type.Scope(..)
+  , scope
+  , size
+  , time
+  , typesOnly
+  , derefAliases
+  , Filter(..)
+  , SearchEntry(..)
+  ) where
+
+import           Control.Monad.STM (STM, atomically)
+import           Data.Int (Int32)
+import           Data.List.NonEmpty (NonEmpty((:|)))
+import qualified Data.List.NonEmpty as NonEmpty
+import           Data.Maybe (mapMaybe)
+#if __GLASGOW_HASKELL__ >= 710
+import           Data.Semigroup (Semigroup(..))
+#else
+import           Data.Semigroup (Semigroup(..), Monoid(..))
+#endif
+
+import qualified Ldap.Asn1.Type as Type
+import           Ldap.Client.Internal
+
+
+-- | Perform the Search operation synchronously. Raises 'ResponseError' on failures.
+search :: Ldap -> Dn -> Mod Search -> Filter -> [Attr] -> IO [SearchEntry]
+search l base opts flt attributes =
+  raise =<< searchEither l base opts flt attributes
+
+-- | Perform the Search operation synchronously. Returns @Left e@ where
+-- @e@ is a 'ResponseError' on failures.
+searchEither
+  :: Ldap
+  -> Dn
+  -> Mod Search
+  -> Filter
+  -> [Attr]
+  -> IO (Either ResponseError [SearchEntry])
+searchEither l base opts flt attributes =
+  wait =<< searchAsync l base opts flt attributes
+
+-- | Perform the Search operation asynchronously. Call 'Ldap.Client.wait' to wait
+-- for its completion.
+searchAsync :: Ldap -> Dn -> Mod Search -> Filter -> [Attr] -> IO (Async [SearchEntry])
+searchAsync l base opts flt attributes =
+  atomically (searchAsyncSTM l base opts flt attributes)
+
+-- | Perform the Search operation asynchronously.
+--
+-- Don't wait for its completion (with 'Ldap.Client.waitSTM') in the
+-- same transaction you've performed it in.
+searchAsyncSTM
+  :: Ldap
+  -> Dn
+  -> Mod Search
+  -> Filter
+  -> [Attr]
+  -> STM (Async [SearchEntry])
+searchAsyncSTM l base opts flt attributes =
+  let req = searchRequest base opts flt attributes in sendRequest l (searchResult req) req
+
+searchRequest :: Dn -> Mod Search -> Filter -> [Attr] -> Request
+searchRequest (Dn base) (Mod m) flt attributes =
+  Type.SearchRequest (Type.LdapDn (Type.LdapString base))
+                     _scope
+                     _derefAliases
+                     _size
+                     _time
+                     _typesOnly
+                     (fromFilter flt)
+                     (Type.AttributeSelection (map (Type.LdapString . unAttr) attributes))
+ where
+  Search { _scope, _derefAliases, _size, _time, _typesOnly } =
+    m defaultSearch
+  fromFilter (Not x) = Type.Not (fromFilter x)
+  fromFilter (And xs) = Type.And (fmap fromFilter xs)
+  fromFilter (Or xs) = Type.Or (fmap fromFilter xs)
+  fromFilter (Present (Attr x)) =
+    Type.Present (Type.AttributeDescription (Type.LdapString x))
+  fromFilter (Attr x := y) =
+    Type.EqualityMatch
+      (Type.AttributeValueAssertion (Type.AttributeDescription (Type.LdapString x))
+                                    (Type.AssertionValue y))
+  fromFilter (Attr x :>= y) =
+    Type.GreaterOrEqual
+      (Type.AttributeValueAssertion (Type.AttributeDescription (Type.LdapString x))
+                                    (Type.AssertionValue y))
+  fromFilter (Attr x :<= y) =
+    Type.LessOrEqual
+      (Type.AttributeValueAssertion (Type.AttributeDescription (Type.LdapString x))
+                                    (Type.AssertionValue y))
+  fromFilter (Attr x :~= y) =
+    Type.ApproxMatch
+      (Type.AttributeValueAssertion (Type.AttributeDescription (Type.LdapString x))
+                                    (Type.AssertionValue y))
+  fromFilter (Attr x :=* (mi, xs, mf)) =
+    Type.Substrings
+      (Type.SubstringFilter (Type.AttributeDescription (Type.LdapString x))
+                            (NonEmpty.fromList (concat
+                              [ maybe [] (\i -> [Type.Initial (Type.AssertionValue i)]) mi
+                              , fmap (Type.Any . Type.AssertionValue) xs
+                              , maybe [] (\f -> [Type.Final (Type.AssertionValue f)]) mf
+                              ])))
+  fromFilter ((mx, mr, b) ::= y) =
+    Type.ExtensibleMatch
+      (Type.MatchingRuleAssertion (fmap (\(Attr r) -> Type.MatchingRuleId (Type.LdapString r)) mr)
+                                  (fmap (\(Attr x) -> Type.AttributeDescription (Type.LdapString x)) mx)
+                                  (Type.AssertionValue y)
+                                  b)
+
+searchResult :: Request -> Response -> Either ResponseError [SearchEntry]
+searchResult req (Type.SearchResultDone (Type.LdapResult code (Type.LdapDn (Type.LdapString dn'))
+                                                              (Type.LdapString msg) _) :| xs)
+  | Type.Success <- code = Right (mapMaybe g xs)
+  | Type.AdminLimitExceeded <- code = Right (mapMaybe g xs)
+  | Type.SizeLimitExceeded <- code = Right (mapMaybe g xs)
+  | otherwise = Left (ResponseErrorCode req code (Dn dn') msg)
+ where
+  g (Type.SearchResultEntry (Type.LdapDn (Type.LdapString dn))
+                            (Type.PartialAttributeList ys)) =
+    Just (SearchEntry (Dn dn) (map h ys))
+  g _ = Nothing
+  h (Type.PartialAttribute (Type.AttributeDescription (Type.LdapString x))
+                           y) = (Attr x, fmap j y)
+  j (Type.AttributeValue x) = x
+searchResult req res = Left (ResponseInvalid req res)
+
+data Search = Search
+  { _scope        :: Type.Scope
+  , _derefAliases :: Type.DerefAliases
+  , _size         :: Int32
+  , _time         :: Int32
+  , _typesOnly    :: Bool
+  } deriving (Show, Eq)
+
+defaultSearch :: Search
+defaultSearch = Search
+  { _scope        = Type.BaseObject
+  , _size         = 0
+  , _time         = 0
+  , _typesOnly    = False
+  , _derefAliases = Type.NeverDerefAliases
+  }
+
+scope :: Type.Scope -> Mod Search
+scope x = Mod (\y -> y { _scope = x })
+
+size :: Int32 -> Mod Search
+size x = Mod (\y -> y { _size = x })
+
+time :: Int32 -> Mod Search
+time x = Mod (\y -> y { _time = x })
 
-data SearchEntry = SearchEntry Dn (AttrList [])
-    deriving (Show, Eq)
+typesOnly :: Bool -> Mod Search
+typesOnly x = Mod (\y -> y { _typesOnly = x })
+
+derefAliases :: Type.DerefAliases -> Mod Search
+derefAliases x = Mod (\y -> y { _derefAliases = x })
+
+newtype Mod a = Mod (a -> a)
+
+instance Semigroup (Mod a) where
+  Mod f <> Mod g = Mod (g . f)
+
+instance Monoid (Mod a) where
+  mempty = Mod id
+  mappend = (<>)
+
+data Filter =
+    Not Filter
+  | And (NonEmpty Filter)
+  | Or (NonEmpty Filter)
+  | Present Attr
+  | Attr := AttrValue
+  | Attr :>= AttrValue
+  | Attr :<= AttrValue
+  | Attr :~= AttrValue
+  | Attr :=* (Maybe AttrValue, [AttrValue], Maybe AttrValue)
+  | (Maybe Attr, Maybe Attr, Bool) ::= AttrValue
+
+data SearchEntry = SearchEntry Dn (AttrList [])
+    deriving (Show, Eq)
 
diff --git a/src/Ldap-Client.html b/src/Ldap-Client.html index af6edfb..b91e5f0 100644 --- a/src/Ldap-Client.html +++ b/src/Ldap-Client.html @@ -9,208 +9,258 @@
{-# LANGUAGE CPP #-}
 {-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE NamedFieldPuns #-}
-module Ldap.Client
-  ( Host(..)
-  , Ldap
-  , LdapError(..)
-  , ResponseError(..)
-  , Type.ResultCode(..)
-  , Async
-  , with
-    -- * Bind
-  , bind
-    -- * Search
-  , search
-  , SearchEntry(..)
-    -- ** Search modifiers
-  , Search
-  , Mod
-  , scope
-  , Type.Scope(..)
-  , size
-  , time
-  , typesOnly
-  , derefAliases
-  , Filter(..)
-    -- * Modify
-  , modify
-  , Operation(..)
-    -- * Add
-  , add
-    -- * Delete
-  , delete
-    -- * ModifyDn
-  , modifyDn
-    -- * Compare
-  , compare
-    -- * Extended
-  , extended
-    -- * Waiting for completion
-  , wait
-    -- * Miscellanous
-  , Dn(..)
-  , RelativeDn(..)
-  , Oid(..)
-  , Password(..)
-  , AttrList
-  , Attr(..)
-    -- * Re-exports
-  , NonEmpty
-  , PortNumber
-  ) where
-
-#if __GLASGOW_HASKELL__ < 710
-import           Control.Applicative ((<$>))
-#endif
-import qualified Control.Concurrent.Async as Async
-import           Control.Concurrent.STM (atomically)
-import           Control.Concurrent.STM.TMVar (putTMVar)
-import           Control.Concurrent.STM.TQueue (TQueue, newTQueueIO, writeTQueue, readTQueue)
-import           Control.Exception (Handler(..), bracket, throwIO, catches)
-import           Control.Monad (forever)
-import qualified Data.ASN1.BinaryEncoding as Asn1
-import qualified Data.ASN1.Encoding as Asn1
-import qualified Data.ASN1.Error as Asn1
-import qualified Data.ByteString as ByteString
-import qualified Data.ByteString.Lazy as ByteString.Lazy
-import           Data.Foldable (traverse_, asum)
-import           Data.Function (fix)
-import           Data.List.NonEmpty (NonEmpty((:|)))
-import qualified Data.Map.Strict as Map
-import           Data.Monoid (Endo(appEndo))
-import           Network.Connection (Connection)
-import qualified Network.Connection as Conn
-import qualified System.IO.Error as IO
-import           Prelude hiding (compare)
-
-import           Ldap.Asn1.ToAsn1 (ToAsn1(toAsn1))
-import           Ldap.Asn1.FromAsn1 (FromAsn1, parseAsn1)
-import qualified Ldap.Asn1.Type as Type
-import           Ldap.Client.Internal
-import           Ldap.Client.Bind (bind, unbindAsync)
-import           Ldap.Client.Search
-  ( search
-  , Search
-  , Mod
-  , scope
-  , size
-  , time
-  , typesOnly
-  , derefAliases
-  , Filter(..)
-  , SearchEntry(..)
-  )
-import           Ldap.Client.Modify (Operation(..), modify, modifyDn)
-import           Ldap.Client.Add (add)
-import           Ldap.Client.Delete (delete)
-import           Ldap.Client.Compare (compare)
-import           Ldap.Client.Extended (extended)
-
-
-newLdap :: IO Ldap
-newLdap = Ldap
-  <$> newTQueueIO
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE NamedFieldPuns #-}
+module Ldap.Client
+  ( Host(..)
+  , Ldap
+  , LdapError(..)
+  , ResponseError(..)
+  , Type.ResultCode(..)
+  , Async
+  , with
+    -- * Bind
+  , bind
+    -- * Search
+  , search
+  , SearchEntry(..)
+    -- ** Search modifiers
+  , Search
+  , Mod
+  , scope
+  , Type.Scope(..)
+  , size
+  , time
+  , typesOnly
+  , derefAliases
+  , Filter(..)
+    -- * Modify
+  , modify
+  , Operation(..)
+    -- * Add
+  , add
+    -- * Delete
+  , delete
+    -- * ModifyDn
+  , modifyDn
+    -- * Compare
+  , compare
+    -- * Extended
+  , extended
+    -- * Waiting for completion
+  , wait
+    -- * Miscellanous
+  , Dn(..)
+  , RelativeDn(..)
+  , Oid(..)
+  , Password(..)
+  , AttrList
+  , Attr(..)
+  , AttrValue
+    -- * Re-exports
+  , NonEmpty
+  , PortNumber
+  ) where
+
+#if __GLASGOW_HASKELL__ < 710
+import           Control.Applicative ((<$>))
+#endif
+import qualified Control.Concurrent.Async as Async
+import           Control.Concurrent.STM (atomically, throwSTM)
+import           Control.Concurrent.STM.TMVar (putTMVar)
+import           Control.Concurrent.STM.TQueue (TQueue, newTQueueIO, writeTQueue, readTQueue)
+import           Control.Exception (Exception, Handler(..), bracket, throwIO, catch, catches)
+import           Control.Monad (forever)
+import qualified Data.ASN1.BinaryEncoding as Asn1
+import qualified Data.ASN1.Encoding as Asn1
+import qualified Data.ASN1.Error as Asn1
+import qualified Data.ByteString as ByteString
+import qualified Data.ByteString.Lazy as ByteString.Lazy
+import           Data.Foldable (asum)
+import           Data.Function (fix)
+import           Data.List.NonEmpty (NonEmpty((:|)))
+import qualified Data.Map.Strict as Map
+import           Data.Monoid (Endo(appEndo))
+import           Data.String (fromString)
+import           Data.Text (Text)
+import           Data.Typeable (Typeable)
+import           Network.Connection (Connection)
+import qualified Network.Connection as Conn
+import           Prelude hiding (compare)
+import qualified System.IO.Error as IO
+
+import           Ldap.Asn1.ToAsn1 (ToAsn1(toAsn1))
+import           Ldap.Asn1.FromAsn1 (FromAsn1, parseAsn1)
+import qualified Ldap.Asn1.Type as Type
+import           Ldap.Client.Internal
+import           Ldap.Client.Bind (bind)
+import           Ldap.Client.Search
+  ( search
+  , Search
+  , Mod
+  , scope
+  , size
+  , time
+  , typesOnly
+  , derefAliases
+  , Filter(..)
+  , SearchEntry(..)
+  )
+import           Ldap.Client.Modify (Operation(..), modify, modifyDn)
+import           Ldap.Client.Add (add)
+import           Ldap.Client.Delete (delete)
+import           Ldap.Client.Compare (compare)
+import           Ldap.Client.Extended (extended)
 
-data LdapError =
-    IOError IOError
-  | ParseError Asn1.ASN1Error
-  | ResponseError ResponseError
-    deriving (Show, Eq)
-
--- | The entrypoint into LDAP.
-with :: Host -> PortNumber -> (Ldap -> IO a) -> IO (Either LdapError a)
-with host port f = do
-  context <- Conn.initConnectionContext
-  bracket (Conn.connectTo context params) Conn.connectionClose (\conn ->
-    bracket newLdap unbindAsync (\l -> do
-      inq  <- newTQueueIO
-      outq <- newTQueueIO
-      Async.withAsync (input inq conn) $ \i ->
-        Async.withAsync (output outq conn) $ \o ->
-          Async.withAsync (dispatch l inq outq) $ \d ->
-            Async.withAsync (f l) $ \u ->
-              fmap (Right . snd) (Async.waitAnyCancel [i, o, d, u])))
- `catches`
-  [ Handler (return . Left . IOError)
-  , Handler (return . Left . ParseError)
-  , Handler (return . Left . ResponseError)
-  ]
- where
-  params = Conn.ConnectionParams
-    { Conn.connectionHostname =
-        case host of
-          Plain    h -> h
-          Secure   h -> h
-          Insecure h -> h
-    , Conn.connectionPort = port
-    , Conn.connectionUseSecure =
-        case host of
-          Plain  _ -> Nothing
-          Secure _ -> Just Conn.TLSSettingsSimple
-            { Conn.settingDisableCertificateValidation = False
-            , Conn.settingDisableSession = False
-            , Conn.settingUseServerName = False
-            }
-          Insecure _ -> Just Conn.TLSSettingsSimple
-            { Conn.settingDisableCertificateValidation = True
-            , Conn.settingDisableSession = False
-            , Conn.settingUseServerName = False
-            }
-    , Conn.connectionUseSocks = Nothing
-    }
-
-input :: FromAsn1 a => TQueue a -> Connection -> IO b
-input inq conn = flip fix [] $ \loop chunks -> do
-  chunk <- Conn.connectionGet conn 8192
-  case ByteString.length chunk of
-    0 -> throwIO (IO.mkIOError IO.eofErrorType "Ldap.Client.input" Nothing Nothing)
-    _ -> do
-      let chunks' = chunk : chunks
-      case Asn1.decodeASN1 Asn1.DER (ByteString.Lazy.fromChunks (reverse chunks')) of
-        Left  Asn1.ParsingPartial
-                   -> loop chunks'
-        Left  e    -> throwIO e
-        Right asn1 -> do
-          flip fix asn1 $ \loop' asn1' ->
-            case parseAsn1 asn1' of
-              Nothing -> return ()
-              Just (asn1'', a) -> do
-                atomically (writeTQueue inq a)
-                loop' asn1''
-          loop []
-
-output :: ToAsn1 a => TQueue a -> Connection -> IO b
-output out conn = forever $ do
-  msg <- atomically (readTQueue out)
-  Conn.connectionPut conn (encode (toAsn1 msg))
- where
-  encode x = Asn1.encodeASN1' Asn1.DER (appEndo x [])
-
-dispatch
-  :: Ldap
-  -> TQueue (Type.LdapMessage Type.ProtocolServerOp)
-  -> TQueue (Type.LdapMessage Request)
-  -> IO a
-dispatch Ldap { client } inq outq =
-  flip fix (Map.empty, Map.empty, 1) $ \loop (!got, !results, !counter) ->
-    loop =<< atomically (asum
-      [ do New new var <- readTQueue client
-           writeTQueue outq (Type.LdapMessage (Type.Id counter) new Nothing)
-           return (got, Map.insert (Type.Id counter) var results, counter + 1)
-      , do Type.LdapMessage mid op _ <- readTQueue inq
-           case op of
-             Type.SearchResultEntry {} ->
-               return (Map.insertWith (++) mid [op] got, results, counter)
-             Type.SearchResultReference {} ->
-               return (got, results, counter)
-             Type.SearchResultDone {} -> do
-               let stack = Map.findWithDefault [] mid got
-               traverse_ (\var -> putTMVar var (op :| stack)) (Map.lookup mid results)
-               return (Map.delete mid got, Map.delete mid results, counter)
-             _ -> do
-               traverse_ (\var -> putTMVar var (op :| [])) (Map.lookup mid results)
-               return (Map.delete mid got, Map.delete mid results, counter)
-      ])
+{-# ANN module "HLint: ignore Use first" #-}
+
+
+newLdap :: IO Ldap
+newLdap = Ldap
+  <$> newTQueueIO
+
+data LdapError =
+    IOError IOError
+  | ParseError Asn1.ASN1Error
+  | ResponseError ResponseError
+  | DisconnectError Disconnect
+    deriving (Show, Eq)
+
+newtype WrappedIOError = WrappedIOError IOError
+    deriving (Show, Eq, Typeable)
+
+instance Exception WrappedIOError
+
+data Disconnect = Disconnect Type.ResultCode Dn Text
+    deriving (Show, Eq, Typeable)
+
+instance Exception Disconnect
+
+-- | The entrypoint into LDAP.
+with :: Host -> PortNumber -> (Ldap -> IO a) -> IO (Either LdapError a)
+with host port f = do
+  context <- Conn.initConnectionContext
+  bracket (Conn.connectTo context params) Conn.connectionClose (\conn ->
+    bracket newLdap unbindAsync (\l -> do
+      inq  <- newTQueueIO
+      outq <- newTQueueIO
+      Async.withAsync (input inq conn) $ \i ->
+        Async.withAsync (output outq conn) $ \o ->
+          Async.withAsync (dispatch l inq outq) $ \d ->
+            Async.withAsync (f l) $ \u ->
+              fmap (Right . snd) (Async.waitAnyCancel [i, o, d, u])))
+ `catches`
+  [ Handler (\(WrappedIOError e) -> return (Left (IOError e)))
+  , Handler (return . Left . ParseError)
+  , Handler (return . Left . ResponseError)
+  ]
+ where
+  params = Conn.ConnectionParams
+    { Conn.connectionHostname =
+        case host of
+          Plain    h -> h
+          Secure   h -> h
+          Insecure h -> h
+    , Conn.connectionPort = port
+    , Conn.connectionUseSecure =
+        case host of
+          Plain  _ -> Nothing
+          Secure _ -> Just Conn.TLSSettingsSimple
+            { Conn.settingDisableCertificateValidation = False
+            , Conn.settingDisableSession = False
+            , Conn.settingUseServerName = False
+            }
+          Insecure _ -> Just Conn.TLSSettingsSimple
+            { Conn.settingDisableCertificateValidation = True
+            , Conn.settingDisableSession = False
+            , Conn.settingUseServerName = False
+            }
+    , Conn.connectionUseSocks = Nothing
+    }
+
+input :: FromAsn1 a => TQueue a -> Connection -> IO b
+input inq conn = wrap . flip fix [] $ \loop chunks -> do
+  chunk <- Conn.connectionGet conn 8192
+  case ByteString.length chunk of
+    0 -> throwIO (IO.mkIOError IO.eofErrorType "Ldap.Client.input" Nothing Nothing)
+    _ -> do
+      let chunks' = chunk : chunks
+      case Asn1.decodeASN1 Asn1.DER (ByteString.Lazy.fromChunks (reverse chunks')) of
+        Left  Asn1.ParsingPartial
+                   -> loop chunks'
+        Left  e    -> throwIO e
+        Right asn1 -> do
+          flip fix asn1 $ \loop' asn1' ->
+            case parseAsn1 asn1' of
+              Nothing -> return ()
+              Just (asn1'', a) -> do
+                atomically (writeTQueue inq a)
+                loop' asn1''
+          loop []
+
+output :: ToAsn1 a => TQueue a -> Connection -> IO b
+output out conn = wrap . forever $ do
+  msg <- atomically (readTQueue out)
+  Conn.connectionPut conn (encode (toAsn1 msg))
+ where
+  encode x = Asn1.encodeASN1' Asn1.DER (appEndo x [])
+
+dispatch
+  :: Ldap
+  -> TQueue (Type.LdapMessage Type.ProtocolServerOp)
+  -> TQueue (Type.LdapMessage Request)
+  -> IO a
+dispatch Ldap { client } inq outq =
+  flip fix (Map.empty, 1) $ \loop (!req, !counter) ->
+    loop =<< atomically (asum
+      [ do New new var <- readTQueue client
+           writeTQueue outq (Type.LdapMessage (Type.Id counter) new Nothing)
+           return (Map.insert (Type.Id counter) ([], var) req, counter + 1)
+      , do Type.LdapMessage mid op _
+               <- readTQueue inq
+           res <- case op of
+             Type.BindResponse {}          -> done mid op req
+             Type.SearchResultEntry {}     -> saveUp mid op req
+             Type.SearchResultReference {} -> return req
+             Type.SearchResultDone {}      -> done mid op req
+             Type.ModifyResponse {}        -> done mid op req
+             Type.AddResponse {}           -> done mid op req
+             Type.DeleteResponse {}        -> done mid op req
+             Type.ModifyDnResponse {}      -> done mid op req
+             Type.CompareResponse {}       -> done mid op req
+             Type.ExtendedResponse {}      -> probablyDisconnect mid op req
+             Type.IntermediateResponse {}  -> saveUp mid op req
+           return (res, counter)
+      ])
+ where
+  saveUp mid op res =
+    return (Map.adjust (\(stack, var) -> (op : stack, var)) mid res)
+
+  done mid op req =
+    case Map.lookup mid req of
+      Nothing -> return req
+      Just (stack, var) -> do
+        putTMVar var (op :| stack)
+        return (Map.delete mid req)
+
+  probablyDisconnect (Type.Id 0)
+                     (Type.ExtendedResponse
+                       (Type.LdapResult code
+                                        (Type.LdapDn (Type.LdapString dn))
+                                        (Type.LdapString reason)
+                                        _)
+                       moid _)
+                     req =
+    case moid of
+      Just (Type.LdapOid oid)
+        | oid == noticeOfDisconnection -> throwSTM (Disconnect code (Dn dn) reason)
+      _ -> return req
+  probablyDisconnect mid op req = done mid op req
+
+  noticeOfDisconnection :: Text
+  noticeOfDisconnection = fromString "1.3.6.1.4.1.1466.20036"
+
+wrap :: IO a -> IO a
+wrap m = m `catch` (throwIO . WrappedIOError)