2 if not text:
3 return None
4 l = text.split(None, 1)
5 word = l[0]
6 try:
7 text = l[1]
8 except IndexError:
9 text = ''
10 return word, text
11
13 if not text:
14 return None
15 return text.split(None, 1)[0]
16
19 """Split text into $-separated list."""
20 r=[]
21 for x in text.split("$"):
22 x = x.strip()
23 assert x
24 r.append(x)
25 return tuple(r)
26
28 """Split ''-quoted strings into list."""
29 r=[]
30 while text:
31 text = text.lstrip()
32 if not text:
33 break
34 assert text[0]=="'", "Text %s must start with a single quote."%repr(text)
35 text=text[1:]
36 end=text.index("'")
37 r.append(text[:end])
38 text=text[end+1:]
39 return tuple(r)
40
42 s = ' '.join([self._str(x) for x in l])
43 if len(l) > 1:
44 s = '( %s )' % s
45 return s
46
48 s = ' $ '.join([x for x in l])
49 if len(l) > 1:
50 s = '( %s )' % s
51 return s
52
55
57 """
58 ASN Syntax::
59
60 d = "0" / "1" / "2" / "3" / "4" /
61 "5" / "6" / "7" / "8" / "9"
62
63 numericstring = 1*d
64
65 numericoid = numericstring *( "." numericstring )
66
67 space = 1*" "
68
69 whsp = [ space ]
70
71 descr = keystring
72
73 qdescr = whsp "'" descr "'" whsp
74
75 qdescrlist = [ qdescr *( qdescr ) ]
76
77 ; object descriptors used as schema element names
78 qdescrs = qdescr / ( whsp "(" qdescrlist ")" whsp )
79
80 dstring = 1*utf8
81
82 qdstring = whsp "'" dstring "'" whsp
83
84 descr = keystring
85
86 oid = descr / numericoid
87
88 woid = whsp oid whsp
89
90 ; set of oids of either form
91 oids = woid / ( "(" oidlist ")" )
92
93 ObjectClassDescription = "(" whsp
94 numericoid whsp ; ObjectClass identifier
95 [ "NAME" qdescrs ]
96 [ "DESC" qdstring ]
97 [ "OBSOLETE" whsp ]
98 [ "SUP" oids ] ; Superior ObjectClasses
99 [ ( "ABSTRACT" / "STRUCTURAL" / "AUXILIARY" ) whsp ]
100 ; default structural
101 [ "MUST" oids ] ; AttributeTypes
102 [ "MAY" oids ] ; AttributeTypes
103 whsp ")"
104 """
105
106
108 self.oid=None
109 self.name=None
110 self.desc=None
111 self.obsolete=0
112 self.sup=[]
113 self.type=None
114 self.must=[]
115 self.may=[]
116
117 if text is not None:
118 self._parse(text)
119
121 assert text[0]=='(', "Text %s must be in parentheses."%repr(text)
122 assert text[-1]==')', "Text %s must be in parentheses."%repr(text)
123 text=text[1:-1]
124 text = text.lstrip()
125
126
127 self.oid, text = extractWord(text)
128
129 text = text.lstrip()
130
131 if peekWord(text) == "NAME":
132 text=text[len("NAME "):]
133 text = text.lstrip()
134 if text[0]=="'":
135 text=text[1:]
136 end=text.index("'")
137 self.name=(text[:end],)
138 text=text[end+1:]
139 elif text[0]=="(":
140 text=text[1:]
141 text = text.lstrip()
142 end=text.index(")")
143 self.name=self._strings_to_list(text[:end])
144 text=text[end+1:]
145 else:
146 raise NotImplementedError("TODO")
147
148
149 text = text.lstrip()
150
151 if peekWord(text) == "DESC":
152 text=text[len("DESC "):]
153 text = text.lstrip()
154 assert text[0]=="'"
155 text=text[1:]
156 end=text.index("'")
157 self.desc=text[:end]
158 text=text[end+1:]
159
160 text = text.lstrip()
161
162 if peekWord(text) == "OBSOLETE":
163 self.obsolete=1
164 text=text[len("OBSOLETE "):]
165
166 text = text.lstrip()
167
168 if peekWord(text) == "SUP":
169 text=text[len("SUP "):]
170 text = text.lstrip()
171 if text[0]=="(":
172 text=text[1:]
173 text = text.lstrip()
174 end=text.index(")")
175 self.sup=self._to_list(text[:end])
176 text=text[end+1:]
177 else:
178 s, text = extractWord(text)
179 self.sup=[s]
180
181 text = text.lstrip()
182
183 if peekWord(text) == "ABSTRACT":
184 assert self.type is None
185 self.type="ABSTRACT"
186 text=text[len("ABSTRACT "):]
187
188 text = text.lstrip()
189
190 if peekWord(text) == "STRUCTURAL":
191 assert self.type is None
192 self.type="STRUCTURAL"
193 text=text[len("STRUCTURAL "):]
194
195 text = text.lstrip()
196
197 if peekWord(text) == "AUXILIARY":
198 assert self.type is None
199 self.type="AUXILIARY"
200 text=text[len("AUXILIARY "):]
201
202 text = text.lstrip()
203
204 if peekWord(text) == "MUST":
205 text=text[len("MUST "):]
206 text = text.lstrip()
207 if text[0]=="(":
208 text=text[1:]
209 text = text.lstrip()
210 end=text.index(")")
211 self.must.extend(self._to_list(text[:end]))
212 text=text[end+1:]
213 else:
214 s, text = extractWord(text)
215 self.must.append(s)
216
217 text = text.lstrip()
218
219 if peekWord(text) == "MAY":
220 text=text[len("MAY "):]
221 text = text.lstrip()
222 if text[0]=="(":
223 text=text[1:]
224 text = text.lstrip()
225 end=text.index(")")
226 self.may.extend(self._to_list(text[:end]))
227 text=text[end+1:]
228 else:
229 s, text = extractWord(text)
230 self.may.append(s)
231
232 text = text.lstrip()
233
234 assert text=="", "Text was not empty: %s"%repr(text)
235
236 if not self.type:
237 self.type="STRUCTURAL"
238
239 assert self.oid
240 for c in self.oid:
241 assert c in "0123456789."
242 assert self.name is None or self.name
243 assert self.type in ("ABSTRACT", "STRUCTURAL", "AUXILIARY")
244
246 nice = {}
247 for k,v in self.__dict__.items():
248 nice[k]=repr(v)
249 return ("<%s instance at 0x%x"%(self.__class__.__name__, id(self))
250 +(" oid=%(oid)s name=%(name)s desc=%(desc)s"
251 +" obsolete=%(obsolete)s sup=%(sup)s type=%(type)s"
252 +" must=%(must)s may=%(may)s>")%nice)
253
255 r=[]
256 if self.name is not None:
257 r.append('NAME %s' % self._str_list(self.name))
258 if self.desc is not None:
259 r.append('DESC %s' % self._str(self.desc))
260 if self.obsolete:
261 r.append('OBSOLETE')
262 if self.sup:
263 r.append('SUP %s' % self._list(self.sup))
264 r.append('%s' % self.type)
265 if self.must:
266 r.append('MUST %s' % self._list(self.must))
267 if self.may:
268 r.append('MAY %s' % self._list(self.may))
269 return ('( %s ' % self.oid
270 + '\n '.join(r)
271 + ' )')
272
280
288
291
294
306
308 return not (self == other)
309
311 """
312 ASN Syntax::
313
314 AttributeTypeDescription = "(" whsp
315 numericoid whsp ; AttributeType identifier
316 [ "NAME" qdescrs ] ; name used in AttributeType
317 [ "DESC" qdstring ] ; description
318 [ "OBSOLETE" whsp ]
319 [ "SUP" woid ] ; derived from this other AttributeType
320 [ "EQUALITY" woid ; Matching Rule name
321 [ "ORDERING" woid ; Matching Rule name
322 [ "SUBSTR" woid ] ; Matching Rule name
323 [ "SYNTAX" whsp noidlen whsp ] ; see section 4.3
324 [ "SINGLE-VALUE" whsp ] ; default multi-valued
325 [ "COLLECTIVE" whsp ] ; default not collective
326 [ "NO-USER-MODIFICATION" whsp ]; default user modifiable
327 [ "USAGE" whsp AttributeUsage ]; default userApplications
328 whsp ")"
329
330 AttributeUsage =
331 "userApplications" /
332 "directoryOperation" /
333 "distributedOperation" / ; DSA-shared
334 "dSAOperation" ; DSA-specific, value depends on server
335
336 noidlen = numericoid [ "{" len "}" ]
337
338 len = numericstring
339 """
340
342 self.oid=None
343 self.name=None
344 self.desc=None
345 self.obsolete=0
346 self.sup=None
347 self.equality=None
348 self.ordering=None
349 self.substr=None
350 self.syntax=None
351 self.single_value=None
352 self.collective=None
353 self.no_user_modification=None
354 self.usage=None
355
356 if text is not None:
357 self._parse(text)
358
360 assert text[0]=='(', "Text %s must be in parentheses."%repr(text)
361 assert text[-1]==')', "Text %s must be in parentheses."%repr(text)
362 text=text[1:-1]
363 text = text.lstrip()
364
365
366 self.oid, text = extractWord(text)
367
368 text = text.lstrip()
369
370 if peekWord(text) == "NAME":
371 text=text[len("NAME "):]
372 text = text.lstrip()
373 if text[0]=="'":
374 text=text[1:]
375 end=text.index("'")
376 self.name=(text[:end],)
377 text=text[end+1:]
378 elif text[0]=="(":
379 text=text[1:]
380 text = text.lstrip()
381 end=text.index(")")
382 self.name=self._strings_to_list(text[:end])
383 text=text[end+1:]
384 else:
385 raise NotImplementedError("TODO")
386
387
388 text = text.lstrip()
389
390 if peekWord(text) == "DESC":
391 text=text[len("DESC "):]
392 text = text.lstrip()
393 assert text[0]=="'"
394 text=text[1:]
395 end=text.index("'")
396 self.desc=text[:end]
397 text=text[end+1:]
398
399 text = text.lstrip()
400
401 if peekWord(text) == "OBSOLETE":
402 self.obsolete=1
403 text=text[len("OBSOLETE "):]
404
405 text = text.lstrip()
406
407 if peekWord(text) == "SUP":
408 text=text[len("SUP "):]
409 text = text.lstrip()
410 self.sup, text = extractWord(text)
411
412 text = text.lstrip()
413
414 if peekWord(text) == "EQUALITY":
415 text=text[len("EQUALITY "):]
416 text = text.lstrip()
417 self.equality, text = extractWord(text)
418
419 text = text.lstrip()
420
421 if peekWord(text) == "ORDERING":
422 text=text[len("ORDERING "):]
423 text = text.lstrip()
424 self.ordering, text = extractWord(text)
425
426 text = text.lstrip()
427
428 if peekWord(text) == "SUBSTR":
429 text=text[len("SUBSTR "):]
430 text = text.lstrip()
431 self.substr, text = extractWord(text)
432
433 text = text.lstrip()
434
435 if peekWord(text) == "SYNTAX":
436 text=text[len("SYNTAX "):]
437 text = text.lstrip()
438 self.syntax, text = extractWord(text)
439
440 text = text.lstrip()
441
442 if peekWord(text) == "SINGLE-VALUE":
443 assert self.single_value is None
444 self.single_value=1
445 text=text[len("SINGLE-VALUE "):]
446
447 text = text.lstrip()
448
449 if peekWord(text) == "COLLECTIVE":
450 assert self.collective is None
451 self.collective=1
452 text=text[len("COLLECTIVE "):]
453
454 text = text.lstrip()
455
456 if peekWord(text) == "NO-USER-MODIFICATION":
457 assert self.no_user_modification is None
458 self.no_user_modification=1
459 text=text[len("NO-USER-MODIFICATION "):]
460
461 text = text.lstrip()
462
463 if peekWord(text) == "USAGE":
464 assert self.usage is None
465 text=text[len("USAGE "):]
466 text = text.lstrip()
467 self.usage, text = extractWord(text)
468
469 text = text.lstrip()
470
471 assert text=="", "Text was not empty: %s"%repr(text)
472
473 if self.single_value is None:
474 self.single_value=0
475
476 if self.collective is None:
477 self.collective=0
478
479 if self.no_user_modification is None:
480 self.no_user_modification=0
481
482 assert self.oid
483 for c in self.oid:
484 assert c in "0123456789."
485 assert self.name is None or self.name
486 assert self.usage is None or self.usage in (
487 "userApplications",
488 "directoryOperation",
489 "distributedOperation",
490 "dSAOperation",
491 )
492
494 nice = {}
495 for k,v in self.__dict__.items():
496 nice[k]=repr(v)
497 return ("<%s instance at 0x%x"%(self.__class__.__name__, id(self))
498 +(" oid=%(oid)s name=%(name)s desc=%(desc)s"
499 +" obsolete=%(obsolete)s sup=%(sup)s"
500 +" equality=%(equality)s ordering=%(ordering)s"
501 +" substr=%(substr)s syntax=%(syntax)s"
502 +" single_value=%(single_value)s"
503 +" collective=%(collective)s"
504 +" no_user_modification=%(no_user_modification)s"
505 +" usage=%(usage)s>")%nice)
506
508 r=[]
509 if self.name is not None:
510 r.append('NAME %s' % self._str_list(self.name))
511 if self.desc is not None:
512 r.append('DESC %s' % self._str(self.desc))
513 if self.obsolete:
514 r.append('OBSOLETE')
515 if self.sup is not None:
516 r.append('SUP %s' % self.sup)
517 if self.equality is not None:
518 r.append('EQUALITY %s' % self.equality)
519 if self.ordering is not None:
520 r.append('ORDERING %s' % self.ordering)
521 if self.substr is not None:
522 r.append('SUBSTR %s' % self.substr)
523 if self.syntax is not None:
524 r.append('SYNTAX %s' % self.syntax)
525 if self.single_value:
526 r.append('SINGLE-VALUE')
527 if self.collective:
528 r.append('COLLECTIVE')
529 if self.no_user_modification:
530 r.append('NO-USER-MODIFICATION')
531 if self.usage is not None:
532 r.append('USAGE %s' % self.usage)
533 return ('( %s ' % self.oid
534 + '\n '.join(r)
535 + ' )')
536
538 """
539 ASN Syntax::
540
541 SyntaxDescription = "(" whsp
542 numericoid whsp
543 [ "DESC" qdstring ]
544 whsp ")"
545 """
546
548 self.oid=None
549 self.desc=None
550
551 assert text[0]=='('
552 assert text[-1]==')'
553 text=text[1:-1]
554 text = text.lstrip()
555
556
557 self.oid, text = extractWord(text)
558
559 text = text.lstrip()
560
561 if peekWord(text) == "DESC":
562 text=text[len("DESC "):]
563 text = text.lstrip()
564 assert text[0]=="'"
565 text=text[1:]
566 end=text.index("'")
567 self.desc=text[:end]
568 text=text[end+1:]
569
570 text = text.lstrip()
571
572 if peekWord(text) == "X-BINARY-TRANSFER-REQUIRED":
573 text=text[len("X-BINARY-TRANSFER-REQUIRED "):]
574 text = text.lstrip()
575 assert text[0]=="'"
576 text=text[1:]
577 end=text.index("'")
578 self.desc=text[:end]
579 text=text[end+1:]
580
581 text = text.lstrip()
582
583 if peekWord(text) == "X-NOT-HUMAN-READABLE":
584 text=text[len("X-NOT-HUMAN-READABLE "):]
585 text = text.lstrip()
586 assert text[0]=="'"
587 text=text[1:]
588 end=text.index("'")
589 self.desc=text[:end]
590 text=text[end+1:]
591
592 text = text.lstrip()
593
594 assert text=="", "Text was not empty: %s"%repr(text)
595
596 assert self.oid
597 for c in self.oid:
598 assert c in "0123456789."
599
601 nice = {}
602 for k,v in self.__dict__.items():
603 nice[k]=repr(v)
604 return ("<%s instance at 0x%x"%(self.__class__.__name__, id(self))
605 +(" oid=%(oid)s desc=%(desc)s>")%nice)
606
607
608
610 """
611 ASN Syntax::
612
613 MatchingRuleDescription = "(" whsp
614 numericoid whsp ; MatchingRule identifier
615 [ "NAME" qdescrs ]
616 [ "DESC" qdstring ]
617 [ "OBSOLETE" whsp ]
618 "SYNTAX" numericoid
619 whsp ")"
620 """
621
623 self.oid=None
624 self.name=None
625 self.desc=None
626 self.obsolete=None
627 self.syntax=None
628
629 assert text[0]=='('
630 assert text[-1]==')'
631 text=text[1:-1]
632 text = text.lstrip()
633
634
635 self.oid, text = extractWord(text)
636
637 text = text.lstrip()
638
639 if peekWord(text) == "NAME":
640 text=text[len("NAME "):]
641 text = text.lstrip()
642 if text[0]=="'":
643 text=text[1:]
644 end=text.index("'")
645 self.name=(text[:end],)
646 text=text[end+1:]
647 elif text[0]=="(":
648 text=text[1:]
649 text = text.lstrip()
650 end=text.index(")")
651 self.name=self._strings_to_list(text[:end])
652 text=text[end+1:]
653 else:
654 raise NotImplementedError("TODO")
655
656 text = text.lstrip()
657
658 if peekWord(text) == "DESC":
659 text=text[len("DESC "):]
660 text = text.lstrip()
661 assert text[0]=="'"
662 text=text[1:]
663 end=text.index("'")
664 self.desc=text[:end]
665 text=text[end+1:]
666
667 text = text.lstrip()
668
669 if peekWord(text) == "OBSOLETE":
670 self.obsolete=1
671 text=text[len("OBSOLETE "):]
672
673 text = text.lstrip()
674
675 if peekWord(text) == "SYNTAX":
676 text=text[len("SYNTAX "):]
677 text = text.lstrip()
678 self.syntax, text = extractWord(text)
679
680 text = text.lstrip()
681
682 assert text=="", "Text was not empty: %s"%repr(text)
683
684 if self.obsolete is None:
685 self.obsolete=0
686 assert self.oid
687 for c in self.oid:
688 assert c in "0123456789."
689 assert self.syntax
690
692 nice = {}
693 for k,v in self.__dict__.items():
694 nice[k]=repr(v)
695 return ("<%s instance at 0x%x"%(self.__class__.__name__, id(self))
696 +(" oid=%(oid)s desc=%(desc)s>")%nice)
697