Codebase list ocamldap / debian/2.1.8-4 ldap_ooclient.mli
debian/2.1.8-4

Tree @debian/2.1.8-4 (Download .tar.gz)

ldap_ooclient.mli @debian/2.1.8-4raw · history · blame

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
(* an object oriented interface to ldap

   Copyright (C) 2004 Eric Stokes, and The California State University
   at Northridge

   This library is free software; you can redistribute it and/or               
   modify it under the terms of the GNU Lesser General Public                  
   License as published by the Free Software Foundation; either                
   version 2.1 of the License, or (at your option) any later version.          
   
   This library is distributed in the hope that it will be useful,             
   but WITHOUT ANY WARRANTY; without even the implied warranty of              
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU           
   Lesser General Public License for more details.                             
   
   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
   USA
*)

(** an object oriented ldap client interface *)

open Ldap_types

(** {2 Basic Data Types} *)

(** the type of an operation, eg. [("cn", ["foo";"bar"])] *)
type op = string * string list
type op_lst = op list

(** The policy the client should take when it encounteres a
    referral. This is currently not used *)
type referral_policy = [ `FOLLOW | `RETURN ]

(** The change type of an ldapentry. This controls some aspects of
    it's behavior *)
type changetype = [ `ADD | `DELETE | `MODDN | `MODIFY | `MODRDN ]

(** {2 Local Representation of LDAP Objects} *)

(** The base type of an ldap entry represented in memory. *)
class type ldapentry_t =
object
  method add : op_lst -> unit
  method attributes : string list
  method changes : (Ldap_types.modify_optype * string * string list) list
  method changetype : changetype
  method delete : op_lst -> unit
  method dn : string
  method diff : ldapentry_t -> (modify_optype * string * string list) list
  method exists : string -> bool
  method flush_changes : unit
  method get_value : string -> string list
  method modify :
    (Ldap_types.modify_optype * string * string list) list -> unit
  method print : unit
  method replace : op_lst -> unit
  method set_changetype : changetype -> unit
  method set_dn : string -> unit
end

(** this object represents a remote object within local memory. It
    records all local changes made to it (if it's changetype is set to
    `MODIFY), and can commit them to the server at a later time via
    {!Ldap_ooclient.ldapcon.update_entry}. *)
class ldapentry :
object
  (** add values to an attribute (or create a new attribute). Does
      not change the server until you update *)
    method add : op_lst -> unit

    (** return a list of the type (name) of all the attributes present
    on the object *)
    method attributes : string list

    (** return a list of changes made to the object in a the format of
	a modify operation. For example, you can apply the changes to another
	ldapentry object using the {!Ldap_ooclient.ldapentry.modify}
	method *)
    method changes : (Ldap_types.modify_optype * string * string list) list

    (** return the changetype of the object *)
    method changetype : changetype

    (** delete attributes from the object, does not change the
    directory until you update *)
    method delete : op_lst -> unit

    (** return the dn of the object *)
    method dn : string

    (** given an ldapentry, return the differences between the current
	entry and the specified entry in the form of a modify
	operation which would make the specified entry the same as the
	current entry. *)
    method diff : ldapentry_t -> (modify_optype * string * string list) list

    (** query whether the attribute type (name) exists in the object *)
    method exists : string -> bool

    (** clear all accumulated changes *)
    method flush_changes : unit

    (** get the value of an attribute @raise Not_found If the
	attribute does not exist. *)
    method get_value : string -> string list

    (** Apply modifications to object in memory, does not change the
	database until you update using
	{!Ldap_ooclient.ldapcon.update_entry} *)
    method modify :
      (Ldap_types.modify_optype * string * string list) list -> unit

    (** @deprecated print an ldif like representation of the object to stdout, see
	Ldif_oo for standards compliant ldif. Usefull for toplevel
	sessions. *)
    method print : unit

    (** replace values in the object, does not change the database
    until you call update *)
    method replace : op_lst -> unit

    (** set the changetype of the object *)
    method set_changetype : changetype -> unit

    (** set the dn of the object *)
    method set_dn : string -> unit
  end

(** {1 Miscallaneous} *)

(** toplevel formatter for ldapentry, prints the whole entry with a
    nice structure. Each attribute is in the correct syntax to be
    copied and pasted into a modify operation. *)
val format_entry :
  < attributes : string list; dn : string;
 get_value : string -> string list; .. > ->
   unit

(** format lists of entries, in this case only print the dn *)
val format_entries :
  < attributes : string list; dn : string;
 get_value : string -> string list; .. > list ->
   unit

(** The type of an ldap change record, used by extended LDIF *)
type changerec = 
    [`Modification of string * ((Ldap_types.modify_optype * string * string list) list)
    | `Addition of ldapentry
    | `Delete of string
    | `Modrdn of string * int * string]

(** {0 Communication With {!Ldap_funclient}} *)

(** given a search_result_entry as returned by ldap_funclient, produce an
    ldapentry containing either the entry, or the referral object *)
val to_entry : 
  [< `Entry of Ldap_types.search_result_entry | `Referral of string list ] 
  -> ldapentry

(** given an ldapentry as returned by ldapcon, or constructed manually,
    produce a search_result_entry suitable for ldap_funclient, or
    ldap_funserver. *)
val of_entry : ldapentry -> search_result_entry

(** {2 Interacting with LDAP Servers} *)

(** This class abstracts a connection to an LDAP server (or servers),
    an instance will be connected to the server you specify and can be
    used to perform operations on that server. 

    {0 Example} 

    [new ldapcon ~connect_timeout:5 ~version:3
    ["ldap://first.ldap.server";"ldap://second.ldap.server"]]. 

    In addition to specifying multiple urls, if DNS names are given,
    and those names are bound to multiple addresses, then all possible
    addresses will be tried.

    {0 Example}

    [new ldapcon ["ldaps://rrldap.csun.edu"]] 

    is equivelant to 
    
    [new ldapcon ["ldap://130.166.1.30";"ldap://130.166.1.31";"ldap://130.166.1.32"]]

    This means that if any host in the rr fails, the ldapcon will
    transparently move on to the next host, and you will never know
    the difference. 

    @raise LDAP_Failure All methods raise {!Ldap_types.LDAP_Failure} on error

    @param connect_timeout Default [1], an integer which specifies how
    long to wait for any given server in the list to respond before
    trying the next one. After all the servers have been tried for
    [connect_timeout] seconds [LDAP_Failure (`SERVER_DOWN, ...)]  will
    be raised.

    @param referral_policy In a future version of ocamldap this will
    be used to specify what you would like to do in the event of a
    referral. Currently it does nothing and is ignored see
    {!Ldap_ooclient.referral_policy}.

    @param version The protocol version to use, the default is [3],
    the other recognized value is [2].
*)
class ldapcon :
  ?connect_timeout:int ->
  ?referral_policy:[> `RETURN ] ->
  ?version:int ->
  string list ->
object
  (** {2 Authentication} *)

  (** bind to the database using dn. 

      {0 Simple Bind Example}

      [ldap#bind ~cred:"password" "cn=foo,ou=people,ou=auth,o=bar"]

      To bind anonymously, omit ~cred, and leave dn blank eg.

      {0 Example}

      [ldap#bind ""]

      @param cred The credentials to provide for binding. Default [""]. 

      @param meth The method to use when binding See
      {!Ldap_funclient.authmethod} the default is [`SIMPLE]. If
      [`SASL] is used then [dn] and [~cred] Are interperted according
      to the chosen SASL mechanism. SASL binds have not been tested
      extensively. *)
  method bind :
    ?cred:string -> ?meth:Ldap_funclient.authmethod -> string -> unit

  (** Deauthenticate and close the connection to the server *)
  method unbind : unit

  (** {2 Searching} *)

  (** Search the directory syncronously for an entry which matches the
      search criteria.

      {0 Example}

      [ldap#search ~base:"dc=foo,dc=bar" ~attrs:["cn"] "uid=*"]

      @param scope Default [`SUBTREE], defines the scope of the
      search. see {!Ldap_types.search_scope} 

      @param attrs Default [[]] (means all attributes) 

      @param attrsonly Default [false] If true, asks the server to return
      only the attribute names, not their values. 

      @param base Default [""], The search base, which is the dn of the
      object from which you want to start your search. Only that
      object, and it's children will be included in the
      search. Further controlled by [~scope]. 

      @param timelimit The time limit (in seconds) to allow the search
      to run for. Default [0l], which means there is no user specified
      time limit, the server may still impose one.

      @param sizelimit The max number of entries to return from the
      search (in number of entries) *)
  method search :
    ?scope:Ldap_types.search_scope ->
    ?attrs:string list ->
    ?attrsonly:bool -> ?base:string -> 
    ?sizelimit:Int32.t -> ?timelimit:Int32.t -> 
    string -> ldapentry list

  (** Search the directory asyncronously, otherwise the same as
      search. *)
  method search_a :
    ?scope:Ldap_types.search_scope ->
    ?attrs:string list ->
    ?attrsonly:bool -> ?base:string -> 
    ?sizelimit:Int32.t -> ?timelimit:Int32.t -> 
    string -> (?abandon:bool -> unit -> ldapentry)

  (** Fetch the raw (unparsed) schema from the directory using the
      standard mechanism (requires protocol version 3) *)
  method rawschema : ldapentry

  (** Fetch and parse the schema from the directory via the standard
      mechanism (requires version 3). Return a structured
      representation of the schema indexed by canonical name, and oid. *)
  method schema : Ldap_schemaparser.schema

  (** {2 Making Modifications} *)

  (** add an entry to the database *)
  method add : ldapentry -> unit

  (** Delete the object named by dn from the database *)
  method delete : string -> unit

  (** Modify the entry named by dn, applying mods 

      {0 Example}

      [ldap#modify "uid=foo,ou=people,dc=bar,dc=baz" [(`DELETE, "cn", ["foo";"bar"])]]
  *)
  method modify :
    string ->
    (Ldap_types.modify_optype * string * string list) list -> unit

  (** Syncronize changes made locally to an ldapentry with the
      directory. *)
  method update_entry : ldapentry -> unit

  (** Modify the rdn of the object named by dn, if the protocol
      version is 3 you may additionally change the superior, the rdn
      will be changed to the attribute represented (as a string) by
      newrdn, 

      {0 Example With New Superior}

      [ldap#modrdn ~newsup:(Some "o=csun") "cn=bob,ou=people,o=org" "uid=bperson"]

      After this example "cn=bob,ou=people,o=org" will end up as "uid=bperson,o=csun".

      @param deleteoldrdn Default [true], delete
      the old rdn value as part of the modrdn. 

      @param newsup Default [None], only valid when the protocol
      version is 3, change the object's location in the tree, making
      its superior equal to the specified object. *)
  method modrdn : string -> ?deleteoldrdn:bool -> ?newsup:string option -> string -> unit
end

(** {1 Iterators Over Streams of ldapentry Objects} *)

(** given a source of ldapentry objects (unit -> ldapentry), such as
    the return value of ldapcon#search_a, apply f (first arg) to each entry
    See List.iter *)
val iter : (ldapentry -> unit) -> (?abandon:bool -> unit -> ldapentry) -> unit

(** given a source of ldapentry objects (unit -> ldapentry), such as
  the return value of ldapcon#search_a apply f (first arg) to each
  entry in reverse, and return a list containing the result of each
  application. See List.map *)
val rev_map : (ldapentry -> 'a) -> (?abandon:bool -> unit -> ldapentry) -> 'a list

(** same as rev_map, but does it in order *)
val map : (ldapentry -> 'a) -> (?abandon:bool -> unit -> ldapentry) -> 'a list

(** given a source of ldapentry objects (unit -> ldapentry), such as
  the return value of ldapcon#search_a compute (f eN ... (f e2 (f e1
  intial))) see List.fold_right. *)
val fold : (ldapentry -> 'a -> 'a) -> 'a -> (?abandon:bool -> unit -> ldapentry) -> 'a

(** {2 Schema Aware ldapentry Derivatives} *)

(** {1 General Schema Aware Entry} {!Ldap_ooclient.scldapentry}, A
    schema aware derivative of {!Ldap_ooclient.ldapentry}. It contains
    an rfc2252 schema checker, and given the database schema, it can
    be used to garentee that operations performed in memory are valid
    against a standards compliant database. It has numerious uses,
    translation between two databases with different schemas an
    example of where it finds natural usage. For an example
    application @see <http://tdir.sourceforge.net> tdir *)

(** an ordered oid type, for placing oids in sets *)
module OrdOid :
sig
  type t = Ldap_schemaparser.Oid.t
  val compare : t -> t -> int
end

(** A set of Oids @deprecated the name is historical, and may be changed *)
module Setstr :
sig
  type elt = OrdOid.t
  type t = Set.Make(OrdOid).t
  val empty : t
  val is_empty : t -> bool
  val mem : elt -> t -> bool
  val add : elt -> t -> t
  val singleton : elt -> t
  val remove : elt -> t -> t
  val union : t -> t -> t
  val inter : t -> t -> t
  val diff : t -> t -> t
  val compare : t -> t -> int
  val equal : t -> t -> bool
  val subset : t -> t -> bool
  val iter : (elt -> unit) -> t -> unit
  val fold : (elt -> 'a -> 'a) -> t -> 'a -> 'a
  val for_all : (elt -> bool) -> t -> bool
  val exists : (elt -> bool) -> t -> bool
  val filter : (elt -> bool) -> t -> t
  val partition : (elt -> bool) -> t -> t * t
  val cardinal : t -> int
  val elements : t -> elt list
  val min_elt : t -> elt
  val max_elt : t -> elt
  val choose : t -> elt
  val split : elt -> t -> t * bool * t
end

(** The type of schema checking to perform in
    {!Ldap_ooclient.scldapentry}. Normally this is picked
    automatically, however it can be overridden in some cases. *)
type scflavor = 
    Optimistic 
      (** Add missing attributes to make the object consistant, or add
	  objectclasses in order to make illegal attribues legal *)
  | Pessimistic
      (** Delete objectclasses which must attributes which are
	  missing, and delete illegal attributes. *)

(** given a name of an attribute name (canonical or otherwise), return
    its oid @raise Invalid_attribute If the attribute is not found in the schema. *)
val attrToOid :
  Ldap_schemaparser.schema ->
  Ldap_schemaparser.Lcstring.t -> Ldap_schemaparser.Oid.t

(** given the oid of an attribute, return its canonical name @raise
    Invalid_attribute If the attribute is not found in the schema. *)
val oidToAttr : Ldap_schemaparser.schema -> Ldap_schemaparser.Oid.t -> string

(** given a name of an objectclass (canonical or otherwise), return
    its oid. @raise Invalid_objectclass If the objectclass is not
    found in the schema. *)
val ocToOid :
  Ldap_schemaparser.schema ->
  Ldap_schemaparser.Lcstring.t -> Ldap_schemaparser.Oid.t

(** given the oid of an objectclass, return its canonical name @raise
    Invalid_objectclass If the objectclass is not found in the
    schema. *)
val oidToOc : Ldap_schemaparser.schema -> Ldap_schemaparser.Oid.t -> string

(** get an objectclass structure by one of its names (canonical or
    otherwise, however getting it by canonical name is currently much
    faster) @raise Invalid_objectclass If the objectclass is not found
    in the schema. *)
val getOc :
  Ldap_schemaparser.schema ->
  Ldap_schemaparser.Lcstring.t -> Ldap_schemaparser.objectclass

(** get an attr structure by one of its names (canonical or otherwise,
    however getting it by canonical name is currently much faster)
    @raise Invalid_attribute If the attribute is not found in the
    schema. *)
val getAttr :
  Ldap_schemaparser.schema ->
  Ldap_schemaparser.Lcstring.t -> Ldap_schemaparser.attribute

(** equate attributes by oid. This allows non canonical names to be
    handled correctly, for example "uid" and "userID" are actually the
    same attribute. @raise Invalid_attribute If either attribute is
    not found in the schema. *)
val equateAttrs :
  Ldap_schemaparser.schema ->
  Ldap_schemaparser.Lcstring.t -> Ldap_schemaparser.Lcstring.t -> bool
 
exception Invalid_objectclass of string
exception Invalid_attribute of string
exception Single_value of string
exception Objectclass_is_required

class scldapentry :
  Ldap_schemaparser.schema ->
object
  (** {2 New Methods} *)

  (** Returns true if the attributed specified is allowed by the
      current set of objectclasses present on the entry. *)
  method is_allowed : string -> bool

  (** Returns true if the attribute specified is a must, but is not
      currently present. *)
  method is_missing : string -> bool

  (** Return a list of all attributes allowed on the entry (by oid) *)
  method list_allowed : Setstr.elt list

  (** Return a list of all missing attributes (by oid) *)
  method list_missing : Setstr.elt list

  (** Return a list of all present attributes. In contrast to the
      [attributes] method, this method ignores missing required
      attributes and just returns those attributes which are actually
      present. *)
  method list_present : Setstr.elt list

  (** Given an {!Ldap_ooclient.ldapentry} copy all of it's data into
      the current object, and perform a schema check.

      @param scflavor Default [Pessimistic] The schema checking
      bias, see {!Ldap_ooclient.scflavor} *)
  method of_entry : ?scflavor:scflavor -> ldapentry -> unit

  (** {2 Inherited Methods} *)

  (** Add values to the entry, just as
      {!Ldap_ooclient.ldapentry.add}, However, after the add is
      complete the schema checker is run in [Optimistic] mode. see
      {!Ldap_ooclient.scflavor} *)
  method add : op_lst -> unit

  (** Same as {!Ldap_ooclient.ldapentry.add}, except that the schema
      checker is run in [Pessimistic] mode after the operation is
      complete. see {!Ldap_ooclient.scflavor} *)
  method delete : op_lst -> unit

  (** Same as {!Ldap_ooclient.ldapentry.replace} except that once
      the replace has completed the schema checker is run again in
      [Optimistic] mode. See {!Ldap_ooclient.scflavor} *)
  method replace : op_lst -> unit

  (** Same as {!Ldap_ooclient.ldapentry.attributes}, except that the
      returned list contains attributes which may not yet exist on
      the entry. For example musts which are not yet present will be
      listed. *)
  method attributes : string list

  (** Same as {!Ldap_ooclient.ldapentry.exists} except that it
      refrences attributes which may not yet exist. For example musts
      which are not yet present. *)
  method exists : string -> bool

  (** Same as {!Ldap_ooclient.ldapentry.get_value}, except that
      attributes which do not yet exists may be referenced. For example
      a must which has not yet been satisfied will return [["required"]]
      when [get_value] is called on it. *)
  method get_value : string -> string list

  (** Same as {!Ldap_ooclient.ldapentry.modify} except that the
      schema checker is run in [Pessimistic] mode after the
      modification is applied. see {!Ldap_ooclient.scflavor}. *)
  method modify :
    (Ldap_types.modify_optype * string * string list) list -> unit

  (** Same as {!Ldap_ooclient.ldapentry.changes} except that changes
      made by the schema checker may also be listed. *)
  method changes : (Ldap_types.modify_optype * string * string list) list

  (** Same as {!Ldap_ooclient.ldapentry.changetype} *)
  method changetype : changetype

  (** Same as {!Ldap_ooclient.ldapentry.dn} *)
  method dn : string

  (** Same as {!Ldap_ooclient.ldapentry.flush_changes} *)
  method flush_changes : unit

  (** Same as {!Ldap_ooclient.ldapentry.diff} *)
  method diff : ldapentry_t -> (Ldap_types.modify_optype * string * string list) list

  (** @deprecated Same as {!Ldap_ooclient.ldapentry.print}, except
      that it prints attributes which may not yet be present on the
      object. For example, if the object has unsatisfied musts, it will
      print "attrname: required" for that attribute. *)
  method print : unit 

  (** Same as {!Ldap_ooclient.ldapentry.set_changetype} *)
  method set_changetype : changetype -> unit

  (** Same as {!Ldap_ooclient.ldapentry.set_dn} *)
  method set_dn : string -> unit
end

(** {1 Schema Aware Entry for Account Managment} A derivative of
    {!Ldap_ooclient.scldapentry} which includes abstractions for
    managing user accounts in the directory. This class is
    experimantal, and may be drastically changed in the next version. 
    As with all experimental code, use with caution. A few of its features.

    {ul 
    {- Loosely dependant attributes: Many attributes are derived
    from others via a function. ldapaccount allows you to codify
    that relationship by providing an attribute generator
    ({!Ldap_ooclient.generator}) for the attribute, which will
    be used to derive it's value except in the case that it is
    specified explicitly}
    {- Attribute and Generator Grouping: via the service abstraction.
    Allows you to group attributes together with generators and
    default values in interesting ways. You can then assign the
    whole grouping a name, and refer to it by that name. See 
    {!Ldap_ooclient.service}}
    {- Difference Based: Service operations are difference based,
    all applications of service operations compute the delta between
    the current object, and what the service requires. The minumum set
    of changes necessary to satisfy the service are applied to the object.}
    {- Idempotentcy: As a result of being difference based, 
    Service operations are itempotent. For example, 
    adding a service twice has no effect on the object. It will 
    not queue changes for modification to the directory, and it 
    will not change the object in memory. Deleting a service
    twice has no effect...etc}}

*)

(** The structure of a generator *)
type generator = {
  (** The name of the generator, this should also be its key in the hashtbl *)
  gen_name : string; 

  (** A list of names of attributes which are required by this
      generator. The names need not be canonical. *)
  required : string list;

  (** A function which returns a list of values for the attribute,
      given the entire object. *)
  genfun : ldapentry_t -> string list;
}

(** The structure of a service *)
type service = {
  (** The name of the service, should also be its key in the hashtbl. *)
  svc_name : string;

  (** A list of attributes and values which must be present for the
      service to be satisfied. *)
  static_attrs : (string * string list) list;

  (** A list of attributes to generate. *)
  generate_attrs : string list;

  (** A list of services on which this service depends. *)
  depends : string list;
}

(** The type of error raised by attribute generators *)
type generation_error =
    Missing_required of string list
  | Generator_error of string

(** You've asked it to generate an attribute (in a service) which
    doesn't have a generator *)
exception No_generator of string

(** Generator has failed because of some kind of error *)
exception Generation_failed of generation_error

(** The service you're talking about doesn't exist *)
exception No_service of string

(** A service which the one you tried to add depends on doesn't exists *)
exception Service_dep_unsatisfiable of string

(** Your generator depends on an attribute which isn't in the schema *)
exception Generator_dep_unsatisfiable of string * string

(** You have detached cycles in your generator dependancy lists *)
exception Cannot_sort_dependancies of string list

class ldapaccount :
  Ldap_schemaparser.schema ->
    (string, generator) Hashtbl.t ->
    (string, service) Hashtbl.t ->
object

  (** {2 Account Manipulation Methods} *)

  (** add the named service to the object, this also adds all the
      services depended upon by the named service. *)
  method add_service : string -> unit

  (** Delete the named service. This will also delete all services
      which depend on it, either directly or indirectly *)
  method delete_service : string -> unit

  (** Run service through the delta engine to find out what changes
      would actually be applied to this object *)
  method adapt_service : service -> service

  (** Tests whether the named service is satisfied by the current
      entry. A service is satisfied if no changes would result from
      adding it to the entry. *)
  method service_exists : string -> bool

  (** Return a list of all the named services which are satisfied by
      the current entry. *)
  method services_present : string list

  (** add the named attribute to the list of attributes to be generated *)
  method add_generate : string -> unit

  (** Delete the named attribute from the list of attributes to generate *)
  method delete_generate : string -> unit

  (** Run the generation functions on the list of attributes to be
      generated, saving the results in the entry. You must run this
      method in order to run any generators at all.  *)
  method generate : unit

  (** {2 Inherited Methods} Unless explicitly stated, these methods
      do exactly the same thing as in {!Ldap_ooclient.scldapentry} *)

  (** Missing attributes may be marked for generation. *)
  method add : op_lst -> unit
  method attributes : string list
  method changes : (Ldap_types.modify_optype * string * string list) list
  method changetype : changetype
  method delete : op_lst -> unit
  method dn : string
  method diff : ldapentry_t -> (Ldap_types.modify_optype * string * string list) list
  method exists : string -> bool
  method flush_changes : unit

  (** If a missing attribute is marked for generation its value will
      be ["generate"] instead of ["required"] *)
  method get_value : string -> string list
  method is_allowed : string -> bool
  method is_missing : string -> bool
  method list_allowed : Setstr.elt list
  method list_missing : Setstr.elt list
  method list_present : Setstr.elt list
  method modify :
    (Ldap_types.modify_optype * string * string list) list -> unit
  method of_entry : ?scflavor:scflavor -> ldapentry -> unit

  (** @deprecated Missing required attributes which will be
      generated are shown as "attrname: generate" instead of
      "attrname: required" *)
  method print : unit
  method replace : op_lst -> unit
  method set_changetype : changetype -> unit
  method set_dn : string -> unit      
end