Initial commit.
[oddments/ddns.git] / ddns / providers.py
CommitLineData
f22ab085
MT
1#!/usr/bin/python
2
3# Import all possible exception types.
4from .errors import *
5
6class DDNSProvider(object):
7 INFO = {
8 # A short string that uniquely identifies
9 # this provider.
10 "handle" : None,
11
12 # The full name of the provider.
13 "name" : None,
14
15 # A weburl to the homepage of the provider.
16 # (Where to register a new account?)
17 "website" : None,
18
19 # A list of supported protocols.
20 "protocols" : ["ipv6", "ipv4"],
21 }
22
23 DEFAULT_SETTINGS = {}
24
25 def __init__(self, core, **settings):
26 self.core = core
27
28 # Copy a set of default settings and
29 # update them by those from the configuration file.
30 self.settings = self.DEFAULT_SETTINGS.copy()
31 self.settings.update(settings)
32
33 def __repr__(self):
34 return "<DDNS Provider %s (%s)>" % (self.name, self.handle)
35
36 def __cmp__(self, other):
37 return cmp(self.hostname, other.hostname)
38
39 @property
40 def name(self):
41 """
42 Returns the name of the provider.
43 """
44 return self.INFO.get("name")
45
46 @property
47 def website(self):
48 """
49 Returns the website URL of the provider
50 or None if that is not available.
51 """
52 return self.INFO.get("website", None)
53
54 @property
55 def handle(self):
56 """
57 Returns the handle of this provider.
58 """
59 return self.INFO.get("handle")
60
61 def get(self, key, default=None):
62 """
63 Get a setting from the settings dictionary.
64 """
65 return self.settings.get(key, default)
66
67 @property
68 def hostname(self):
69 """
70 Fast access to the hostname.
71 """
72 return self.get("hostname")
73
74 @property
75 def username(self):
76 """
77 Fast access to the username.
78 """
79 return self.get("username")
80
81 @property
82 def password(self):
83 """
84 Fast access to the password.
85 """
86 return self.get("password")
87
88 def __call__(self):
89 raise NotImplementedError
90
91 def send_request(self, *args, **kwargs):
92 """
93 Proxy connection to the send request
94 method.
95 """
96 return self.core.system.send_request(*args, **kwargs)
97
98 def get_address(self, proto):
99 """
100 Proxy method to get the current IP address.
101 """
102 return self.core.system.get_address(proto)
103
104
105class DDNSProviderNOIP(DDNSProvider):
106 INFO = {
107 "handle" : "no-ip.com",
108 "name" : "No-IP",
109 "website" : "http://www.no-ip.com/",
110 "protocols" : ["ipv4",]
111 }
112
113 # Information about the format of the HTTP request is to be found
114 # here: http://www.no-ip.com/integrate/request and
115 # here: http://www.no-ip.com/integrate/response
116
117 url = "http://%(username)s:%(password)s@dynupdate.no-ip.com/nic/update?hostname=%(hostname)s&myip=%(address)s"
118
119 def __call__(self):
120 url = self.url % {
121 "hostname" : self.hostname,
122 "username" : self.username,
123 "password" : self.password,
124 "address" : self.get_address("ipv4"),
125 }
126
127 # Send update to the server.
128 response = self.send_request(url)
129
130 # Get the full response message.
131 output = response.read()
132
133 # Handle success messages.
134 if output.startswith("good") or output.startswith("nochg"):
135 return
136
137 # Handle error codes.
138 if output == "badauth":
139 raise DDNSAuthenticationError
140 elif output == "aduse":
141 raise DDNSAbuseError
142 elif output == "911":
143 raise DDNSInternalServerError
144
145 # If we got here, some other update error happened.
146 raise DDNSUpdateError
147
148
149class DDNSProviderSelfhost(DDNSProvider):
150 INFO = {
151 "handle" : "selfhost.de",
152 "name" : "Selfhost.de",
153 "website" : "http://www.selfhost.de/",
154 "protocols" : ["ipv4",],
155 }
156
157 url = "https://carol.selfhost.de/update?username=%(username)s&password=%(password)s&textmodi=1"
158
159 def __call__(self):
160 url = self.url % { "username" : self.username, "password" : self.password }
161
162 response = self.send_request(url)
163
164 match = re.search("status=20(0|4)", response.read())
165 if not match:
166 raise DDNSUpdateError