diff --git a/Package.swift b/Package.swift index f77da9e..252b730 100644 --- a/Package.swift +++ b/Package.swift @@ -12,8 +12,8 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/PerfectSideRepos/Perfect-ICONV.git", from: "3.0.0"), - .package(url: "https://github.com/PerfectlySoft/Perfect-libSASL.git", from: "1.0.0"), - .package(url: "https://github.com/PerfectlySoft/Perfect-OpenLDAP.git", from: "1.0.0"), + .package(url: "https://github.com/Altarix/Perfect-libSASL.git", from: "1.0.0"), + .package(url: "https://github.com/Altarix/Perfect-OpenLDAP.git", from: "1.0.0"), ], targets: [ .target( diff --git a/Sources/PerfectLDAP/PerfectLDAP.swift b/Sources/PerfectLDAP/PerfectLDAP.swift index 19385a7..7bd39b2 100644 --- a/Sources/PerfectLDAP/PerfectLDAP.swift +++ b/Sources/PerfectLDAP/PerfectLDAP.swift @@ -665,8 +665,122 @@ public class LDAP { throw Exception.message(LDAP.error(r)) }//end search + + + + /// asynchronized search with sync result + /// - parameters: + /// - base: String, search base domain (dn), default = "" + /// - filter: String, the filter of query, default = "(objectclass=*)", means all possible results + /// - scope: See Scope, BASE, SINGLE_LEVEL, SUBTREE or CHILDREN + /// - attributes: filter for output attributes + /// - sortedBy: a sorting string, may be generated by LDAP.sortingString() + /// - sizeLimit: max count of result search. Max limit is 1000. + /// - returns: + /// ResultSet. See ResultSet + /// - throws: + /// Exception.message + public func asyncSearch(base:String = "", filter:String = "(objectclass=*)", scope:Scope = .BASE, attributes: [String] = [], sortedBy: String = "", sizeLimit: Int = 1000) throws -> [String:[ + String:Any]] + { + + var realSizeLimit : Int32 = Int32(sizeLimit) + + // This is limit of space + if realSizeLimit > 1000 { + realSizeLimit = 1000 + } + + var result = [String:[String:Any]]() + + var serverControl = UnsafeMutablePointer(bitPattern: 0) + + if !sortedBy.isEmpty { + var sortKeyList = UnsafeMutablePointer?>(bitPattern: 0) + let sortString = ber_strdup(sortedBy) + var r = ldap_create_sort_keylist(&sortKeyList, sortString) + defer { ber_memfree(sortString) } + guard r == 0 else { + throw Exception.message(LDAP.error(r)) + }//end if + + r = ldap_create_sort_control(self.ldap, sortKeyList, 0, &serverControl) + defer { ldap_free_sort_keylist(sortKeyList) } + guard r == 0 else { + throw Exception.message(LDAP.error(r)) + }//end if + }//end if + + // prepare the return set + var msgid : Int32 = 0 + + var t = timeval(tv_sec: 10, tv_usec: 10) + + let r = withCArrayOfString(array: attributes) { pAttribute -> Int32 in + + + + // perform the search + let result = ldap_search_ext(self.ldap, base, scope.rawValue, filter, pAttribute, 0, &serverControl, nil, &t, realSizeLimit, &msgid) + + if serverControl != nil { + ldap_control_free(serverControl) + } + return result + }//end + + var msgtype = LDAP_RES_SEARCH_ENTRY + var msgcount = 0; + while(msgtype != LDAP_RES_SEARCH_RESULT && realSizeLimit > msgcount) + { + var res = OpaquePointer(bitPattern: 0) + msgcount += 1 + // retrieves result + var err = ldap_result(ldap, msgid, 0, &t, &res); + switch(err) + { + case -1: + ldap_get_option(ldap, LDAP_OPT_RESULT_CODE, &err) + print(stderr, "ldap_result(): %s\n", ldap_err2string(err)) + throw Exception.message(LDAP.error(err)) + case 0: + print(stderr, "ldap_result(): timeout expired\n") + ldap_abandon_ext(ldap, msgid, nil, nil) + ldap_unbind_ext_s(ldap, nil, nil) + default: + break; + }; + + if let m = res { + // determines result type + msgtype = UInt(ldap_msgtype(m)) + + if (msgtype != LDAP_RES_SEARCH_ENTRY) { + ldap_msgfree(m) + } else { + // process the result set + let rs = ResultSet(ldap: self, chain: m) + + // release the memory + ldap_msgfree(m) + let dictionary = rs.dictionary + for key in dictionary.keys { + result[key] = dictionary[key] + } + } + } + } + + if result.count < 1 { + throw Exception.message(LDAP.error(r)) + } + + return result + + }//end asyncSearch + - /// asynchronized search + /// synchronized search but in seporated Thread /// - parameters: /// - base: String, search base domain (dn), default = "" /// - filter: String, the filter of query, default = "(objectclass=*)", means all possible results