add a has_attr() method to rwhoisobject
[python-rwhoisd.git] / rwhoisd / Rwhois.py
1 # This modules contains classes that are fairly general to RWhois
2 # server operation.
3
4 class RwhoisError(Exception):
5     pass
6
7 # The RWhois error codes.  Most of these won't ever be used.
8 error_codes = { 120 : "Registration Deferred",
9                 130 : "Object Not Authoritative",
10                 230 : "No Objects Found",
11                 320 : "Invalid Attribute",
12                 321 : "Invalid Attribute Syntax",
13                 322 : "Required Attribute Missing",
14                 323 : "Object Reference Not Found",
15                 324 : "Primary Key Not Unique",
16                 325 : "Failed to Update Stale Object",
17                 330 : "Exceeded Response Limit",
18                 331 : "Invalid Limit",
19                 332 : "Nothing To Transfer",
20                 333 : "Not Master for Authority Area",
21                 336 : "Object Not Found",
22                 338 : "Invalid Directive Syntax",
23                 340 : "Invalid Authority Area",
24                 341 : "Invalid Class",
25                 342 : "Invalid Host/Port",
26                 350 : "Invalid Query Syntax",
27                 351 : "Query Too Complex",
28                 352 : "Invalid Security Method",
29                 353 : "Authentication Failed",
30                 354 : "Encryption Failed",
31                 360 : "Corrupt Data. Keyadd Failed",
32                 400 : "Directive Not Available",
33                 401 : "Not Authorized For Directive",
34                 402 : "Unidentified Error",
35                 420 : "Registration Not Authorized",
36                 436 : "Invalid Display Format",
37                 500 : "Memory Allocation Problem",
38                 501 : "Service Not Available",
39                 502 : "Unrecoverable Error",
40                 503 : "Idle Time Exceeded",
41                 560 : ""
42                 }
43
44 def error_message(value):
45     try:
46         code, msg = value
47         code = int(code)
48     except (TypeError, ValueError):
49         try:
50             code = int(value)
51             msg  = None
52         except ValueError:
53             msg  = value
54             code = 402
55     if msg:
56         return "%%error %d %s: %s\r\n" % \
57                (code, error_codes.get(code, 402), msg)
58     else:
59         return "%%error %d %s\r\n" % (code, error_codes.get(code, 402))
60
61 def ok():
62     return "%ok\r\n"
63
64 class rwhoisobject:
65     """This is the standard class for RWhois data objects."""
66
67     def __init__(self):
68         self.data = {}
69         self.attr_order = []
70
71     def get_attr(self, attr, default=None):
72         """This returns a list of values associated with a particular
73         attribute.  The default value, if supplied, must be a single
74         (non-sequence) value."""
75         
76         if default:
77             return self.data.get(attr.strip().lower(), [default])
78         return self.data.get(attr.strip().lower(), [])
79
80     def get_attr_value(self, attr, default=None):
81         """This returns a single value associated with the attribute.
82         If the attribute has multiple values, the first is
83         returned."""
84         
85         return self.data.get(attr.strip().lower(), [default])[0]
86
87     def has_attr(self, attr):
88         return self.data.has_key(attr.strip().lower())
89     
90     def getid(self):
91         """Return the RWhois ID of this object."""
92         
93         return self.get_attr_value("id")
94
95     def add_attr(self, attr, value):
96         """Adds an attribute to the object."""
97         
98         attr = attr.strip().lower()
99         if self.data.has_key(attr): self.data[attr].append(value)
100         else:
101             self.attr_order.append(attr)
102             self.data.setdefault(attr, []).append(value)
103
104     def add_attrs(self, attr_list):
105         """Adds a list of (attribute, value) tuples to the object."""
106         for attr, value in attr_list:
107             self.add_attr(attr, value)
108         
109     def items(self):
110         """Returns the list of (attribute, value) tuples (actually 2
111         elements lists).  Attributes with multiple values produce
112         multiple tuples.  The items are returned in the same order
113         they were added to the object."""
114         
115         return [ [x, y] for x in self.attr_order for y in self.data[x] ]
116
117     def values(self):
118         """Return the list of values in this object."""
119         
120         return [ x for y in self.data.values() for x in y ]
121     
122     def __str__(self):
123         """A convenient string representation of this object"""
124         return '\n'.join([':'.join(x) for x in self.items()])
125
126     def __repr__(self):
127         return "<rwhoisobject: " + self.getid() + ">"
128     
129     def attrs_to_wire_str(self, attrs, prefix=None):
130         """Return specific attributes in a response formatted string
131         (classname:attr:value)"""
132
133         cn = self.get_attr_value("class-name", "unknown-class")
134         items = [ [cn, x, y] for x in attrs for y in self.data[x] ]
135
136         if prefix:
137             res = '\r\n'.join([ prefix + ':'.join(x) for x in items ])
138         else:
139             res = '\r\n'.join([ ':'.join(x) for x in items ])
140             
141         return res;
142
143     def to_wire_str(self, prefix=None):
144         """Return the response formatted string (classname:attr:value)"""
145
146         return self.attrs_to_wire_str(self.attr_order, prefix)
147     
148
149
150 ## A basic test driver
151 if __name__ == '__main__':
152
153     obj = rwhoisobject()
154     obj.add_attr('id', '001')
155     obj.add_attr("class-name", 'contact')
156     obj.add_attr("class-name", "foo")
157     obj.add_attr('name', 'Aiden Quinn')
158     obj.add_attr('email', 'aquin@yahoo.com')
159     obj.add_attr('org-name', 'YoYoDyne Inc.')
160     obj.add_attr('email', 'aq@aol.net')
161     obj.add_attr('First-Name', 'Aiden ')
162
163     print "obj:\n", obj
164     print "wire:\n", obj.to_wire_str()