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