Initial import
[ldd.git] / ldd / dn.py
1 #    ldd - DNS implementation in Python
2 #    Copyright (C) 2006 Fredrik Tolf <fredrik@dolda2000.com>
3 #
4 #    This program is free software; you can redistribute it and/or modify
5 #    it under the terms of the GNU General Public License as published by
6 #    the Free Software Foundation; either version 2 of the License, or
7 #    (at your option) any later version.
8 #
9 #    This program is distributed in the hope that it will be useful,
10 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 #    GNU General Public License for more details.
13 #
14 #    You should have received a copy of the GNU General Public License
15 #    along with this program; if not, write to the Free Software
16 #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 class DNNotIn(Exception):
19     def __init__(self, a, b):
20         self.a = a
21         self.b = b
22
23     def __str__(self):
24         return str(self.a) + " not in " + str(self.b)
25
26 class domainname:
27     "A class for abstract representations of domain names"
28     
29     def __init__(self, parts, rooted):
30         self.parts = parts
31         self.rooted = rooted
32     
33     def __repr__(self):
34         ret = ""
35         if len(self.parts) > 0:
36             for p in self.parts[:-1]:
37                 ret = ret + p + '.'
38             ret = ret + self.parts[-1]
39         if self.rooted:
40             ret = ret + '.'
41         return ret
42
43     def __add__(self, y):
44         if self.rooted:
45             raise Exception("cannot append to a rooted domain name")
46         return(domainname(self.parts + y.parts, y.rooted))
47
48     def __getitem__(self, y):
49         return domainname([self.parts[y]], self.rooted and (y == -1 or y == len(self.parts) - 1))
50
51     def __getslice__(self, i, j):
52         return domainname(self.parts[i:j], self.rooted and j >= len(self.parts))
53
54     def __len__(self):
55         return len(self.parts)
56
57     def __eq__(self, y):
58         if type(y) == str:
59             y = fromstring(y)
60         if self.rooted != y.rooted:
61             return False
62         if len(self.parts) != len(y.parts):
63             return False
64         for i in range(len(self.parts)):
65             if self.parts[i].lower() != y.parts[i].lower():
66                 return False
67         return True
68
69     def __ne__(self, y):
70         return not self.__eq__(y)
71     
72     def __contains__(self, y):
73         if len(self) > len(y):
74             return False
75         if len(self) == 0:
76             return self.rooted == y.rooted
77         return y[-len(self):] == self
78
79     def __sub__(self, y):
80         if self not in y:
81             raise DNNotIn(self, y)
82         return self[:len(self) - len(y)]
83
84     def __hash__(self):
85         ret = 0
86         for part in self.parts:
87             ret = ret ^ hash(part)
88         if self.rooted:
89             ret = ret ^ -1
90         return ret
91
92     def canonwire(self):
93         ret = ""
94         for p in self.parts:
95             ret += chr(len(p))
96             ret += p.lower()
97         ret += chr(0)
98         return ret
99     
100 class DNError(Exception):
101     emptypart = 1
102     illegalchar = 2
103     def __init__(self, kind):
104         self.kind = kind
105     def __str__(self):
106         return {1: "empty part",
107                 2: "illegal character"}[self.kind]
108
109 def fromstring(name):
110     parts = []
111     if name == ".":
112         return domainname([], True)
113     if name == "":
114         return domainname([], False)
115     while name.find('.') >= 0:
116         cur = name.find('.')
117         if cur == 0:
118             raise DNError(DNError.emptypart)
119         part = name[:cur]
120         for c in part:
121             if ord(c) < 33:
122                 raise DNError(DNError.illegalchar)
123         parts.append(part)
124         name = name[cur + 1:]
125     if len(name) > 0:
126         parts.append(name)
127         rooted = False
128     else:
129         rooted = True
130     return domainname(parts, rooted)
131