Update TODO based on work for 0.4.1
[python-rwhoisd.git] / rwhoisd / DirectiveProcessor.py
1 # This file is part of python-rwhoisd
2 #
3 # Copyright (C) 2003, David E. Blacka
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18 # USA
19
20 import re
21 import Rwhois, config
22
23 class DirectiveProcessor:
24
25     rwhois_dir_exp = re.compile(r"V-(\d+\.\d+)", re.I)
26
27     def __init__(self, db):
28         self.db = db
29         self.directives = {
30             "rwhois" : self.rwhois_directive,
31             "limit"  : self.limit_directive,
32             "holdconnect" : self.hold_directive,
33             "directive" : self.directive_directive,
34             "xfer" : self.xfer_directive,
35             "status" : self.status_directive
36             }
37
38     def process_directive(self, session, line):
39         d_args = line.lstrip("-").split()
40
41         if not self.directives.has_key(d_args[0]):
42             session.wfile.write(Rwhois.error_message(400))
43             return
44
45         self.directives[d_args[0]](session, d_args[1:])
46
47
48     def rwhois_directive(self, session, arglist):
49         if not arglist:
50             session.wfile.write(Rwhois.error_message(338))
51             return
52         
53         mo = DirectiveProcessor.rwhois_dir_exp.match(arglist[0])
54         if not mo:
55             session.wfile.write(Rwhois.error_message(338))
56             return
57
58         # normally we would make sure that the version given was
59         # sufficiently great.
60
61         session.wfile.write(config.banner_string)
62         session.wfile.write("\r\n")
63
64     def limit_directive(self, session, arglist):
65         try:
66             limit = int(arglist[0])
67         except (IndexError, ValueError):
68             session.wfile.write(Rwhois.error_message(338))
69             return
70         
71         if limit > config.max_limit:
72             limit = config.max_limit
73         elif limit < config.min_limit:
74             limit = config.min_limit
75         session.limit = limit
76
77         session.wfile.write(Rwhois.ok())
78
79     def hold_directive(self, session, arglist):
80         if not arglist:
81             session.wfile.write(Rwhois.error_message(338))
82             return
83         
84         arg = arglist[0].lower()
85         if arg == "on":
86             session.holdconnect = True
87         elif arg == "off":
88             session.holdconnect = False
89         else:
90             session.wfile.write(Rwhois.error_message(338))
91             return
92         
93         session.wfile.write(Rwhois.ok())
94
95     def directive_directive(self, session, arglist):
96         if not arglist:
97             reslist = []
98             dirs = self.directives.keys()
99             dirs.sort()
100             for dir in dirs:
101                 desc = dir.capitalize()
102                 reslist.append("%%directive directive:%s" % dir)
103                 reslist.append("%%directive description:%s directive" % desc)
104             session.wfile.write("\r\n".join(reslist))
105             session.wfile.write("\r\n")
106             session.wfile.write(Rwhois.ok())
107             return
108         if self.directives.has_key(arglist[0]):
109             dir = arglist[0]
110             desc = dir.capitalize()
111             session.wfile.write("%%directive directive:%s\r\n" % dir)
112             session.wfile.write("%%directive description:%s directive\r\n"
113                                 % desc)
114         else:
115             session.wfile.write(Rwhois.error_message(400))
116             return
117         session.wfile.write(Rwhois.ok())
118
119
120     def status_directive(self, session, arglist):
121         if session.holdconnect:
122             hc_str = "on"
123         else:
124             hc_str = "off"
125
126         session.wfile.write("%%status limit: %d\r\n" % session.limit)
127         session.wfile.write("%%status holdconnect: %s\r\n" % hc_str)
128         session.wfile.write("%status forward: off\r\n")
129         session.wfile.write("%%status objects: %d\r\n" 
130                             % len(self.db.main_index))
131         session.wfile.write("%status display: dump\r\n")
132         session.wfile.write("%status contact: N/A\r\n")
133         session.wfile.write(Rwhois.ok())
134         
135     def xfer_directive(self, session, arglist):
136         if not arglist:
137             session.wfile.write(Rwhois.error_message(338))
138             return
139         
140         aa = arglist[0].lower()
141
142         oc = None
143         attr_list = []
144         for arg in arglist[1:]:
145             if arg.startswith("class="):
146                 oc = arg[6:].lower()
147             elif arg.startswith("attribute="):
148                 attr = arg[10:].lower()
149                 if attr: attr_list.append(attr)
150
151         # check the constraints
152         if not self.db.is_autharea(aa):
153             session.wfile.write(Rwhois.error_message((340, aa)))
154             return
155         if oc and not self.db.is_objectclass(oc):
156             session.wfile.write(Rwhois.error_message((341, oc)))
157             return
158
159         for attr in attr_list:
160             if not self.db.is_attribute(attr):
161                 session.wfile.write(Rwhois.error_message((342, attr)))
162                 return
163
164         # now iterate over the entire dataset looking for objects that
165         # match our criteria.
166
167         objs = self.db.object_iterator()
168
169         for obj in objs:
170             # Note: in theory, we should leverage QueryProcessors
171             # filtering code.
172             if obj.get_attr_value("auth-area").lower() != aa:
173                 continue
174             if oc and obj.get_attr_value("class-name").lower() != oc:
175                 continue
176
177             if attr_list:
178                 session.wfile.write(obj.attrs_to_wire_str(attr_list, "%xfer "))
179             else:
180                 session.wfile.write(obj.to_wire_str("%xfer "))
181             session.wfile.write("\r\n%xfer \r\n");
182             
183         session.wfile.write(Rwhois.ok())
184         
185
186 if __name__ == '__main__':
187
188     import sys
189     import MemDB
190     
191     session = Session.Context()
192     session.wfile = sys.stdout
193
194     db = MemDB.MemDB()
195
196     db.init_schema(sys.argv[1])
197     for data_file in sys.argv[2:]:
198         db.load_data(data_file)
199     db.index_data()
200
201     dp = DirectiveProcessor(db)
202
203     directives = [ "-rwhois",
204                    "-rwhois foo bar baz",
205                    "-rwhois V-1.6 noise blah",
206                    "-limit",
207                    "-limit a",
208                    "-limit 20",
209                    "-holdconnect",
210                    "-holdconnect on",
211                    "-holdconnect foo",
212                    "-directive",
213                    "-directive limit",
214                    "-directive foo",
215                    "-xfer",
216                    "-xfer a.com",
217                    "-xfer a.com class=contact",
218                    "-xfer a.com class=domain attribute=domain-name",
219                    "-xfer foo class=bar",
220                    "-xfer foo class=bar attribute=baz attribute=boo",
221                    "-foo baz bar" ]
222
223     for dir in directives:
224         print "trying %r:" % dir
225         print dp.process_directive(session, dir)
226