s4:setup: Added script to parse Microsoft DisplaySpecifiers document.
[nivanova/samba-autobuild/.git] / source4 / scripting / python / samba / ms_display_specifiers.py
1 #!/usr/bin/python
2 #
3 # Create DisplaySpecifiers LDIF (as a string) from the documents provided by
4 # Microsoft under the WSPP.
5 #
6 # Copyright (C) Andrew Kroeger <andrew@id10ts.net> 2009
7 #
8 # Based on ms_schema.py
9 #
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 3 of the License, or
13 # (at your option) any later version.
14 #
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 # GNU General Public License for more details.
19 #
20 # You should have received a copy of the GNU General Public License
21 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
23 import re
24
25 def __read_folded_line(f, buffer):
26     """Read a line from an LDIF file, unfolding it"""
27     line = buffer
28
29     while True:
30         l = f.readline()
31
32         if l[:1] == " ":
33             # continued line
34
35             # cannot fold an empty line
36             assert(line != "" and line != "\n")
37
38             # preserves '\n '
39             line = line + l
40         else:
41             # non-continued line
42             if line == "":
43                 line = l
44
45                 if l == "":
46                     # eof, definitely won't be folded
47                     break
48             else:
49                 # marks end of a folded line
50                 # line contains the now unfolded line
51                 # buffer contains the start of the next possibly folded line
52                 buffer = l
53                 break
54
55     return (line, buffer)
56
57 # Only compile regexp once.
58 # Will not match options after the attribute type.
59 attr_type_re = re.compile("^([A-Za-z][A-Za-z0-9-]*):")
60
61 def __read_raw_entries(f):
62     """Read an LDIF entry, only unfolding lines"""
63
64     buffer = ""
65
66     while True:
67         entry = []
68
69         while True:
70             (l, buffer) = __read_folded_line(f, buffer)
71
72             if l[:1] == "#":
73                 continue
74
75             if l == "\n" or l == "":
76                 break
77
78             m = attr_type_re.match(l)
79
80             if m:
81                 if l[-1:] == "\n":
82                     l = l[:-1]
83
84                 entry.append(l)
85             else:
86                 print >>sys.stderr, "Invalid line: %s" % l,
87                 sys.exit(1)
88
89         if len(entry):
90             yield entry
91
92         if l == "":
93             break
94
95 def fix_dn(dn):
96     """Fix a string DN to use ${CONFIGDN}"""
97
98     if dn.find("<Configuration NC Distinguished Name>") != -1:
99         dn = dn.replace("\n ", "")
100         return dn.replace("<Configuration NC Distinguished Name>", "${CONFIGDN}")
101     else:
102         return dn
103
104 def __write_ldif_one(entry):
105     """Write out entry as LDIF"""
106     out = []
107
108     for l in entry:
109         if l[2] == 0:
110             out.append("%s: %s" % (l[0], l[1]))
111         else:
112             # This is a base64-encoded value
113             out.append("%s:: %s" % (l[0], l[1]))
114
115     return "\n".join(out)
116
117 def __transform_entry(entry):
118     """Perform required transformations to the Microsoft-provided LDIF"""
119
120     temp_entry = []
121
122     for l in entry:
123         t = []
124
125         if l.find("::") != -1:
126             # This is a base64-encoded value
127             t = l.split(":: ", 1)
128             t.append(1)
129         else:
130             t = l.split(": ", 1)
131             t.append(0)
132
133         key = t[0].lower()
134
135         if key == "changetype":
136             continue
137
138         if key == "distinguishedname":
139             continue
140
141         if key == "instancetype":
142             continue
143
144         if key == "name":
145             continue
146
147         if key == "cn":
148             continue
149
150         if key == "objectcategory":
151             continue
152
153         if key == "showinadvancedviewonly":
154             value = t[1].upper().lstrip().rstrip()
155             if value == "TRUE":
156                 # Remove showInAdvancedViewOnly attribute if it is set to the
157                 # default value of TRUE
158                 continue
159
160         t[1] = fix_dn(t[1])
161
162         temp_entry.append(t)
163
164     entry = temp_entry
165
166     return entry
167
168 def read_ms_ldif(filename):
169     """Read and transform Microsoft-provided LDIF file."""
170
171     out = []
172
173     f = open(filename, "rU")
174     for entry in __read_raw_entries(f):
175         out.append(__write_ldif_one(__transform_entry(entry)))
176
177     return "\n\n".join(out) + "\n\n"
178
179 if __name__ == '__main__':
180     import sys
181
182     try:
183         display_specifiers_file = sys.argv[1]
184     except IndexError:
185         print >>sys.stderr, "Usage: %s display-specifiers-ldif-file.txt" % (sys.argv[0])
186         sys.exit(1)
187
188     print read_ms_ldif(display_specifiers_file)
189