80 columns, spacing and line continuations.
[pyTivo/wgw.git] / httpserver.py
blobbd7bfc74b97298d3b494307bcab6ae043da4efde
1 import time, os, BaseHTTPServer, SocketServer, socket, re
2 from urllib import unquote_plus, quote, unquote
3 from urlparse import urlparse
4 from cgi import parse_qs
5 from Cheetah.Template import Template
6 from plugin import GetPlugin
7 import config
8 from xml.sax.saxutils import escape
9 import logging
11 SCRIPTDIR = os.path.dirname(__file__)
13 class TivoHTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
14 containers = {}
16 def __init__(self, server_address, RequestHandlerClass):
17 BaseHTTPServer.HTTPServer.__init__(self, server_address,
18 RequestHandlerClass)
19 self.daemon_threads = True
21 def add_container(self, name, settings):
22 if self.containers.has_key(name) or name == 'TiVoConnect':
23 raise "Container Name in use"
24 try:
25 settings['content_type'] = GetPlugin(settings['type']).CONTENT_TYPE
26 self.containers[name] = settings
27 except KeyError:
28 print 'Unable to add container', name
30 def reset(self):
31 self.containers.clear()
32 for section, settings in config.getShares():
33 self.add_container(section, settings)
35 def set_beacon(self, beacon):
36 self.beacon = beacon
38 class TivoHTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
39 tivos = {}
40 tivo_names = {}
42 def address_string(self):
43 host, port = self.client_address[:2]
44 return host
46 def do_GET(self):
47 tsn = self.headers.getheader('TiVo_TCD_ID',
48 self.headers.getheader('tsn', ''))
49 if tsn:
50 ip = self.address_string()
51 self.tivos[tsn] = ip
53 if not tsn in self.tivo_names:
54 self.tivo_names[tsn] = self.server.beacon.get_name(ip)
56 basepath = unquote_plus(self.path).split('/')[1]
58 ## Get File
59 for name, container in self.server.containers.items():
60 if basepath == name:
61 plugin = GetPlugin(container['type'])
62 plugin.send_file(self, container, name)
63 return
65 ## Not a file not a TiVo command fuck them
66 if not self.path.startswith('/TiVoConnect'):
67 self.infopage()
68 return
70 o = urlparse("http://fake.host" + self.path)
71 query = parse_qs(o[4])
73 mname = False
74 if query.has_key('Command') and len(query['Command']) >= 1:
76 command = query['Command'][0]
78 # If we are looking at the root container
79 if command == "QueryContainer" and \
80 (not query.has_key('Container') or query['Container'][0] == '/'):
81 self.root_container()
82 return
84 if query.has_key('Container'):
85 # Dispatch to the container plugin
86 basepath = unquote(query['Container'][0].split('/')[0])
87 for name, container in self.server.containers.items():
88 if basepath == name:
89 plugin = GetPlugin(container['type'])
90 if hasattr(plugin, command):
91 method = getattr(plugin, command)
92 method(self, query)
93 return
94 else:
95 break
97 # If we made it here it means we couldn't match the request to
98 # anything.
99 self.unsupported(query)
101 def root_container(self):
102 tsn = self.headers.getheader('TiVo_TCD_ID', '')
103 tsnshares = config.getShares(tsn)
104 tsncontainers = {}
105 for section, settings in tsnshares:
106 try:
107 settings['content_type'] = \
108 GetPlugin(settings['type']).CONTENT_TYPE
109 tsncontainers[section] = settings
110 except Exception, msg:
111 print section, '-', msg
112 t = Template(file=os.path.join(SCRIPTDIR, 'templates',
113 'root_container.tmpl'))
114 t.containers = tsncontainers
115 t.hostname = socket.gethostname()
116 t.escape = escape
117 t.quote = quote
118 self.send_response(200)
119 self.end_headers()
120 self.wfile.write(t)
122 def infopage(self):
123 self.send_response(200)
124 self.send_header('Content-type', 'text/html')
125 self.end_headers()
126 t = Template(file=os.path.join(SCRIPTDIR, 'templates',
127 'info_page.tmpl'))
128 t.admin = ''
129 for section, settings in config.getShares():
130 if 'type' in settings and settings['type'] == 'admin':
131 t.admin += '<a href="/TiVoConnect?Command=Admin&Container=' + \
132 quote(section) + \
133 '">pyTivo Web Configuration</a><br>' + \
134 '<a href="/TiVoConnect?Command=NPL&Container=' + \
135 quote(section) + '">pyTivo ToGo</a><br>'
136 if t.admin == '':
137 t.admin = '<br><b>No Admin plugin installed in pyTivo.conf</b>' + \
138 '<br> If you wish to use the admin plugin add the ' + \
139 'following lines to pyTivo.conf<br><br>' + \
140 '[Admin]<br>type=admin'
142 t.shares = 'Video shares:<br/>'
143 for section, settings in config.getShares():
144 if settings.get('type') == 'video':
145 t.shares += '<a href="TiVoConnect?Command=QueryContainer&' + \
146 'Container=' + quote(section) + '">' + section + \
147 '</a><br/>'
149 self.wfile.write(t)
151 def unsupported(self, query):
152 self.send_response(404)
153 self.send_header('Content-type', 'text/html')
154 self.end_headers()
155 t = Template(file=os.path.join(SCRIPTDIR, 'templates',
156 'unsupported.tmpl'))
157 t.query = query
158 self.wfile.write(t)
160 if __name__ == '__main__':
161 def start_server():
162 httpd = TivoHTTPServer(('', 9032), TivoHTTPHandler)
163 httpd.add_container('test', 'x-container/tivo-videos',
164 r'C:\Documents and Settings\Armooo' +
165 r'\Desktop\pyTivo\test')
166 httpd.serve_forever()
168 start_server()