]> jfr.im git - irc/quakenet/snircd.git/blob - tools/convert-conf.py
import of 2.10.12.07
[irc/quakenet/snircd.git] / tools / convert-conf.py
1 #!/usr/bin/env python
2 #
3 # IRC - Internet Relay Chat, tools/convert-conf.py
4 # Copyright (C) 2002 Alex Badea <vampire@p16.pub.ro>
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 1, or (at your option)
9 # any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #
20 #
21 # Configuration file converter from 2.10.11 to 2.10.12 format
22 # Usage:
23 # convert-conf.py < old.conf > new.conf
24 #
25 # $Id: convert-conf.py,v 1.8 2005/04/25 04:04:17 isomer Exp $
26 #
27
28 import sys
29 from string import *
30 import re
31
32 if len(sys.argv) > 1:
33 f = open(sys.argv[1], "r")
34 else:
35 f = sys.stdin
36
37 connects = {}
38 jupes = []
39 feats = [ ("OPLEVELS","FALSE")]
40 opers = []
41 quarintines = []
42
43 useable_features = [
44 "LOG", "DOMAINNAME", "RELIABLE_CLOCK", "BUFFERPOOL",
45 "HAS_FERGUNSON_FLUSHER", "CLIENT_FLOOD", "SERVER_PORT", "NODEFAULTMOTD",
46 "MOTD_BANNER", "KILL_IPMISMATCH", "IDLE_FROM_MSG", "HUB",
47 "WALLOPS_OPER_ONLY", "NODNS", "RANDOM_SEED", "DEFAULT_LIST_PARAM",
48 "NICKNAMEHISTORYLENGTH", "NETWORK", "HOST_HIDING", "HIDDEN_HOST",
49 "HIDDEN_IP", "KILLCHASETIMELIMIT", "MAXCHANNELSPERUSER", "NICKLEN",
50 "AVBANLEN", "MAXBANS", "MAXSILES", "HANGONGOODLINK", "HANGONRETRYDELAY",
51 "CONNECTTIMEOUT", "MAXIMUM_LINKS", "PINGFREQUENCY", "CONNECTFREQUENCY",
52 "DEFAULTMAXSENDQLENGTH", "GLINEMAXUSERCOUNT", "MPATH", "RPATH", "PPATH",
53 "TOS_SERVER", "TOS_CLIENT", "POLLS_PER_LOOP", "IRCD_RES_TIMEOUT",
54 "IRCD_RES_RETRIES", "AUTH_TIMEOUT", "IPCHECK_CLONE_LIMIT",
55 "IPCHECK_CLONE_PERIOD", "IPCHECK_CLONE_DELAY", "CONFIG_OPERCMDS",
56 "OPLEVELS", "LOCAL_CHANNELS", "ANNOUNCE_INVITES", "HIS_SNOTICES",
57 "HIS_DEBUG_OPER_ONLY", "HIS_WALLOPS", "HIS_MAP", "HIS_LINKS",
58 "HIS_TRACE", "HIS_STATS_a", "HIS_STATS_c", "HIS_STATS_d", "HIS_STATS_e",
59 "HIS_STATS_f", "HIS_STATS_g", "HIS_STATS_i", "HIS_STATS_j",
60 "HIS_STATS_J", "HIS_STATS_k", "HIS_STATS_l", "HIS_STATS_L",
61 "HIS_STATS_m", "HIS_STATS_M", "HIS_STATS_o", "HIS_STATS_p",
62 "HIS_STATS_q", "HIS_STATS_r", "HIS_STATS_R", "HIS_STATS_t",
63 "HIS_STATS_T", "HIS_STATS_u", "HIS_STATS_U", "HIS_STATS_v",
64 "HIS_STATS_v", "HIS_STATS_w", "HIS_STATS_x", "HIS_STATS_z",
65 "HIS_WHOIS_SERVERNAME", "HIS_WHOIS_IDLETIME", "HIS_WHOIS_LOCALCHAN",
66 "HIS_WHO_SERVERNAME", "HIS_WHO_HOPCOUNT"," HIS_BANWHO", "HIS_KILLWHO",
67 "HIS_REWRITE", "HIS_REMOTE", "HIS_NETSPLIT", "HIS_SERVERNAME",
68 "HIS_SERVERINFO", "HIS_URLSERVERS"
69 ]
70 deprecated_features = [
71 "VIRTUAL_HOST",
72 ]
73
74 # [ "old feature" => ( local oper priv, global oper priv ) ]
75 # None means don't add this
76 feature_to_priv = {
77 "UNLIMIT_OPER_QUERY" : ("unlimit_query","unlimit_query"),
78 "OPER_WALK_THROUGH_LMODES" : (None, "walk_lchan"),
79 "NO_OPER_DEOP_LCHAN" : (None, "deop_lchan"),
80 }
81
82 def qstr(s):
83 return replace(s,'"','\\"')
84
85 def istr(s):
86 return str(int(strip(s)))
87
88
89 def do_uline(parts):
90 print "Uworld {"
91 print "\tname = \"%s\";" % qstr(parts[1])
92 print "};"
93 print
94 if len(parts[2]):
95 for i in split(parts[2],","):
96 jupes.append(i)
97
98 def do_hline(parts):
99 if not connects.has_key(lower(parts[3])):
100 connects[lower(parts[3])]={
101 "name" : lower(parts[3])
102 }
103 connects[lower(parts[3])]["hub"] = parts[1]
104
105 def do_lline(parts):
106 if not connects.has_key(lower(parts[3])):
107 connects[lower(parts[3])]={
108 "name" : lower(parts[3])
109 }
110 del connects[lower(parts[3])]["hub"]
111
112 def do_pline(parts):
113 print "Port {"
114 print "\tport = %s;" % istr(parts[4])
115 if len(parts[1]):
116 print "\tmask = \"%s\";" % qstr(parts[1])
117 if len(parts[2]):
118 print "\tvhost = \"%s\";" % qstr(parts[2])
119 if count(parts[3], 'S'):
120 print "\tserver = yes;"
121 if count(parts[3], 'H'):
122 print "\thidden = yes;"
123 print "};"
124 print
125
126 def do_fline(parts):
127 feats.append((parts[1], parts[2]))
128
129 def do_kline(parts):
130 if len(parts)!=4:
131 sys.stderr.write("WARNING: Wrong number of parameters on line %i\n" % lno)
132 return
133 letter,host,reason,user=parts
134 print "Kill {"
135 if host[:2]=="$R":
136 if host=="$R":
137 sys.stderr.write("WARNING: Empty realname kline on line %i\n" % lno)
138 if user!="*":
139 print '\thost = "%s@*";' % qstr(user)
140 print "\trealname = \"%s\";" % qstr(host[2:])
141 else:
142 print "\thost = \"%s@%s\";" % (qstr(user),qstr(host))
143 if reason[:1]=="!":
144 print "\tfile = \"%s\";" % qstr(reason[1:])
145 else:
146 print "\treason = \"%s\";" % qstr(reason)
147 print "};"
148 print
149
150 def do_iline(parts):
151 if len(parts)!=6:
152 sys.stderr.write("WARNING: I:line doesn't have enough fields on line %i\n" % lno)
153 return
154 iline,ip,password,hostname,dummy,clss = parts
155 for i in [0,1]:
156 mask = [ip,hostname][i]
157 # Ignore things that aren't masks
158 if "." not in mask and "*" not in mask and "@" not in mask:
159 continue
160 if "@" in mask:
161 user,host = split(mask,"@")
162 else:
163 user,host = "",mask
164 if i==0 and not re.match("^[0-9\.\*]+$",host):
165 sys.stderr.write("WARNING: Bad IP mask in line %s (%s)\n" % (lno,repr(mask)))
166 continue
167 print "Client {"
168 if re.match("^[1-9][1-9]?$",password):
169 print "\tmaxlinks = %s;" % int(password)
170 elif password:
171 print "\tpassword = \"%s\";" % qstr(password)
172 print "\tclass = \"%s\";" % clss
173 if i == 0:
174 print "\tip = \"%s\";" % qstr(host)
175 else:
176 print "\thost = \"%s\";" % qstr(host)
177 if user!="":
178 print "\tusername = \"%s\";" % qstr(user)
179 print "};"
180 print
181
182 def do_cline(parts):
183 name=lower(parts[3])
184 if not connects.has_key(name):
185 connects[name]={}
186 connects[name]["host"]=parts[1]
187 connects[name]["password"]=parts[2]
188 connects[name]["name"]=parts[3]
189 if parts[4].strip()!="":
190 connects[name]["port"]=parts[4]
191 connects[name]["class"]=parts[5]
192
193 def do_qline(parts):
194 print "Quarintine {"
195 print '\t"%s" = "%s";' % (qstr(parts[1]),qstr(parts[2]))
196 print "}"
197
198 def do_oline(parts):
199 opers.append(parts)
200
201 cvtmap = {
202 'M': ('General', ('name', 'vhost', 'description', '-', '!numeric'), ''),
203 'A': ('Admin', ('location', 'contact', 'contact'), ''),
204 'Y': ('Class', ('name', '!pingfreq', '!connectfreq', '!maxlinks', '!sendq'), ''),
205 'I': do_iline,
206 'T': ('motd', ('host', 'file'), ''),
207 'U': do_uline,
208 'H': do_hline,
209 'L': do_lline,
210 'K': do_kline,
211 'k': do_kline,
212 'C': do_cline,
213 'D': ('CRULE', ('server', '', 'rule'), '\tall = yes;'),
214 'd': ('CRULE', ('server', '', 'rule'), ''),
215 'O': do_oline,
216 'o': do_oline,
217 'Q': ('Quarintine', ('channel','reason', '', '', ''), ''),
218 'P': do_pline,
219 'F': do_fline
220 }
221
222 lno=0
223 for line in f.readlines():
224 lno=lno+1
225 line = strip(line)
226 if line=="":
227 continue
228 if line[0]=="#":
229 print "#"+line
230 continue
231 print "#",line
232 parts = split(line, ":")
233 parts=['']
234 # This statemachine is pretty much directly stolen from ircu
235 # to give an "authentic" parser :)
236 state=0 # normal
237 quoted=0
238 for i in line:
239 if state==0:
240 if i=="\\":
241 state=1 # escaped
242 elif i=='"':
243 quoted=not quoted
244 elif i==':':
245 if quoted:
246 parts[-1]=parts[-1]+i
247 else:
248 parts.append("")
249 elif i=='#':
250 break
251 else:
252 parts[-1]=parts[-1]+i
253 elif state==1:
254 if i in "bfnrtv":
255 parts[-1]=parts[-1]+"\b\f\n\r\t\v"[index("bfnrtv",i)]
256 else:
257 parts[-1]=parts[-1]+i
258 state=0
259 if quoted:
260 sys.stderr.write("WARNING: No closing quote on line %i\n"%lno)
261 if not len(parts):
262 continue
263 if not cvtmap.has_key(parts[0]):
264 print "#Unknown:",line
265 continue
266 if callable(cvtmap[parts[0]]):
267 cvtmap[parts[0]](parts)
268 continue
269 (block, items, extra) = cvtmap[parts[0]]
270
271 print block, "{"
272 idx = 1
273 for item in items:
274 if idx >= len(parts):
275 break
276 # This field is ignored
277 if parts[idx]=="-":
278 continue
279 if len(parts[idx]) and not len(item):
280 sys.stderr.write("WARNING: Unknown field %i on line %i\n" % (idx,lno))
281 if len(parts[idx]) and len(item):
282 if item[0] == '!':
283 print "\t%s = %s;" % (item[1:], istr(parts[idx]))
284 else:
285 print "\t%s = \"%s\";" % (item, qstr(parts[idx]))
286 idx = idx + 1
287 if len(extra):
288 print extra
289 print "};"
290 print
291
292 if len(opers):
293 for i in opers:
294 print 'Operator {'
295 print '\tname = "%s";' % qstr(i[3])
296 print '\thost = "%s";' % qstr(i[1])
297 print '\tpassword = "%s";' % qstr(i[2])
298 print '\tclass = "%s";' % qstr(i[5])
299 if i[0]=='O':
300 print '\tlocal = no;'
301 else:
302 print '\tlocal = yes;'
303 for j in feats:
304 if (j[0].startswith("LOCOP_") and i[0]=='o'):
305 print "#",i
306 if j[1].lower()=="true":
307 print '\t%s = yes;'% (j[0][6:].lower())
308 else:
309 print '\t%s = no;' % (j[0][6:].lower())
310 if (j[0].startswith("OPER_") and i[0]=='O'):
311 if j[1].lower()=="true":
312 print '\t%s = yes;'% (j[0][5:].lower())
313 else:
314 print '\t%s = no;' % (j[0][5:].lower())
315 if feature_to_priv.has_key(j[0]):
316 if i[0]=="o" and feature_to_priv[j[0]][0]:
317 if j[1].lower()=="true":
318 print '\t%s = yes;' % feature_to_priv[j[0]][0]
319 else:
320 print '\t%s = yes;' % feature_to_priv[j[0]][0]
321 if i[0]=="O" and feature_to_priv[j[0]][1]:
322 if j[1].lower()=="true":
323 print '\t%s = yes;' % feature_to_priv[j[0]][1]
324 else:
325 print '\t%s = yes;' % feature_to_priv[j[0]][1]
326 print '};'
327 print
328
329 if len(jupes):
330 print "Jupe {"
331 for nick in jupes:
332 print "\tnick = \"%s\";" % qstr(nick)
333 print "};"
334 print
335
336 if len(connects.keys()):
337 for i in connects.keys():
338 print "Connect {"
339 print "\tname = \"%s\";" % qstr(connects[i]["name"])
340 print "\thost = \"%s\";" % qstr(connects[i]["host"])
341 print "\tpassword = \"%s\";" % qstr(connects[i]["password"])
342 if connects[i].has_key("port"):
343 print "\tport = %s;" % connects[i]["port"]
344 print "\tclass = \"%s\";" % qstr(connects[i]["class"])
345 if connects[i].has_key("hub"):
346 print "\thub = \"%s\";" % qstr(connects[i]["hub"])
347 else:
348 print "\tleaf;"
349 if not connects[i].has_key("port"):
350 print "# You can now specify ports without implying autoconnect"
351 print "#\tport = 4400;"
352 print "\tautoconnect = no;"
353 sys.stderr.write("NOTE: You should add a port for \"%s\", autoconnect is now specified seperately\n" % qstr(connects[i]["name"]))
354 print "};"
355 print
356
357 if len(feats):
358 print "features {"
359 for (name, value) in feats:
360 if name in useable_features:
361 print "\t\"%s\" = \"%s\";" % (qstr(name), qstr(value))
362 else:
363 if feature_to_priv.has_key(name):
364 print '# Option converted to privilege "%s"' % \
365 qstr(feature_to_priv[name][1])
366 elif name.startswith("LOCOP_"):
367 print "# Option converted to locop privilege"
368 elif name.startswith("OPER_"):
369 print "# Option converted to oper privilege"
370 elif name in deprecated_features:
371 print "# Option is deprecated"
372 else:
373 print "# Unknown option"
374 sys.stderr.write("WARNING: Unknown option \"%s\"\n" % qstr(name))
375 print "#\t\"%s\" = \"%s\";" % (qstr(name), qstr(value))
376 print "};"
377 print