@@ -336,6 +336,8 @@ class LdapError < StandardError; end
336336
337337  module  LDAPControls 
338338    PAGED_RESULTS  =  "1.2.840.113556.1.4.319"  # Microsoft evil from RFC 2696 
339+     SORT_REQUEST   =  "1.2.840.113556.1.4.473" 
340+     SORT_RESPONSE  =  "1.2.840.113556.1.4.474" 
339341    DELETE_TREE    =  "1.2.840.113556.1.4.805" 
340342  end 
341343
@@ -1328,6 +1330,35 @@ def bind_gss_spnego(auth)
13281330  end 
13291331  private  :bind_gss_spnego 
13301332
1333+ 
1334+   #-- 
1335+   # Allow the caller to specify a sort control 
1336+   # 
1337+   # The format of the sort control needs to be: 
1338+   # 
1339+   # :sort_control => ["cn"]  # just a string 
1340+   # or 
1341+   # :sort_control => [["cn", "matchingRule", true]] #attribute, matchingRule, direction (true / false) 
1342+   # or 
1343+   # :sort_control => ["givenname","sn"] #multiple strings or arrays 
1344+   # 
1345+   def  encode_sort_controls ( sort_definitions ) 
1346+     return  sort_definitions  unless  sort_definitions 
1347+ 
1348+     sort_control_values  =  sort_definitions . map  do  |control |
1349+       control  =  Array ( control )  # if there is only an attribute name as a string then infer the orderinrule and reverseorder 
1350+       control [ 0 ]  =  String ( control [ 0 ] ) . to_ber , 
1351+       control [ 1 ]  =  String ( control [ 1 ] ) . to_ber , 
1352+       control [ 2 ]  =  ( control [ 2 ]  == true ) . to_ber 
1353+       control . to_ber_sequence 
1354+     end 
1355+     sort_control  =  [ 
1356+       Net ::LDAP ::LDAPControls ::SORT_REQUEST . to_ber , 
1357+       false . to_ber , 
1358+       sort_control_values . to_ber_sequence . to_s . to_ber 
1359+     ] . to_ber_sequence 
1360+   end 
1361+ 
13311362  #-- 
13321363  # Alternate implementation, this yields each search entry to the caller as 
13331364  # it are received. 
@@ -1353,6 +1384,7 @@ def search(args = {})
13531384    scope  =  args [ :scope ]  || Net ::LDAP ::SearchScope_WholeSubtree 
13541385    raise  Net ::LDAP ::LdapError ,  "invalid search scope"  unless  Net ::LDAP ::SearchScopes . include? ( scope ) 
13551386
1387+     sort_control  =  encode_sort_controls ( args . fetch ( :sort_controls ) {  false  } ) 
13561388    # An interesting value for the size limit would be close to A/D's 
13571389    # built-in page limit of 1000 records, but openLDAP newer than version 
13581390    # 2.2.0 chokes on anything bigger than 126. You get a silent error that 
@@ -1408,6 +1440,8 @@ def search(args = {})
14081440          false . to_ber , 
14091441          rfc2696_cookie . map {  |v | v . to_ber } . to_ber_sequence . to_s . to_ber 
14101442        ] . to_ber_sequence  if  paged_searches_supported 
1443+ 
1444+       controls  << sort_control  if  sort_control 
14111445      controls  =  controls . to_ber_contextspecific ( 0 ) 
14121446
14131447      pkt  =  [ next_msgid . to_ber ,  request ,  controls ] . to_ber_sequence 
0 commit comments