Add support for shell scripts and auto-executed scripts.
[noxon-gateway.git] / www / index.php
1 <?php
2 set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__ . '/../src/');
3 $fullUri = $_SERVER['REQUEST_URI'];
4 if (isset($_SERVER['REDIRECT_URL'])) {
5     $path    = $_SERVER['REDIRECT_URL'];
6 } else {
7     $path = '/';
8 }
9 $dataDir = __DIR__ . '/../data/';
10 $varDir  = realpath(__DIR__ . '/../var') . '/';
11 $host1 = 'http://radio567.vtuner.com/';
12 $host2 = 'http://radio5672.vtuner.com/';
13 if ($_SERVER['HTTP_HOST'] !== '') {
14     $host1 = 'http://' . $_SERVER['HTTP_HOST'] . '/';
15     $host2 = 'http://' . $_SERVER['HTTP_HOST'] . '/';
16 }
17 $cfgFile = $dataDir . 'config.php';
18 if (file_exists($cfgFile)) {
19     include $cfgFile;
20 }
21
22 if (strtolower($fullUri) == '/setupapp/radio567/asp/browsexpa/loginxml.asp?token=0') {
23     //initial login for "internet radio" and podcasts
24     //lowercase tags
25     header('Content-type: text/html');
26     readfile($dataDir . 'initial-login.xml');
27     exit();
28 } else if ($fullUri == '/RadioNativeLogin.php') {
29     //initial login for "My noxon"
30     //this one wants CamelCased tags
31     header('Content-type: text/html');
32     readfile($dataDir . 'login-mynoxon.xml');
33     exit();
34 } else if ($path == '/setupapp/radio567/asp/BrowseXPA/LoginXML.asp') {
35     //"Internet Radio"
36     $path = '/internetradio/';
37 } else if ($path == '/setupapp/radio567/asp/BrowseXPA/navXML.asp') {
38     //"Podcasts"
39     $path = '/podcasts/';
40 } else if ($path == '/RadioNative.php') {
41     //"My Noxon"
42     $path = '/mynoxon/';
43     $path = '/internetradio/';
44 } else if ($path == '/setupapp/radio567/asp/BrowseXML/FavXML.asp') {
45     //Internet Radio Station favorites favorited on device
46     sendMessage('Unsupported');
47 } else if ($path == '/RadioNativeFavorites.php') {
48     //Favorites, defined via web interface
49     sendMessage('Unsupported');
50 } else if (substr($path, 0, 9) == '/play-url') {
51     //play a given URL, but first follow all redirects
52     //noxon iRadio Cube does not like too many redirections
53     // 3 redirects did not work.
54     $url = $_GET['url'];
55     header('HTTP/1.0 301 Moved Permanently');
56     header('Location: ' . getFinalUrl($url));
57     exit();
58 }
59
60 handleRequest(ltrim($path, '/'));
61
62 function handleRequest($path)
63 {
64     global $varDir;
65     if (strpos($path, '..') !== false) {
66         sendMessage('No');
67         return;
68     }
69
70     if (substr($path, 0, 14) == 'internetradio/') {
71         require_once 'mediatomb.php';
72         handleRequestMediatomb($path, 'internetradio/');
73         return;
74     }
75
76
77     $fullPath = $varDir . $path;
78     if (!file_exists($fullPath)) {
79         sendMessage('Not found: ' . $path);
80         return;
81     }
82
83     $ext = pathinfo($path, PATHINFO_EXTENSION);
84     if (is_dir($fullPath)) {
85         sendDir($path);
86     } else if ($ext == 'url') {
87         require_once 'podcasts.php';
88         sendPodcast($path);
89     } else if ($ext == 'txt') {
90         sendTextFile($path);
91     } else if ($ext == 'sh') {
92         sendScript($path);
93     } else {
94         sendMessage('Unknown file type');
95     }
96 }
97
98 function pathEncode($urlPath)
99 {
100     return str_replace('%2F', '/', rawurlencode($urlPath));
101 }
102
103 function sendDir($path)
104 {
105     global $varDir;
106
107     $listItems = array();
108     addPreviousItem($listItems, $path);
109
110     $entries = glob(str_replace('//', '/', $varDir . rtrim($path, '/') . '/*'));
111     $count = 0;
112     foreach ($entries as $entry) {
113         $urlPath = pathEncode(substr($entry, strlen($varDir)));
114         $ext = pathinfo($entry, PATHINFO_EXTENSION);
115         if (is_dir($entry)) {
116             ++$count;
117             $listItems[] = getDirItem(basename($entry), $urlPath . '/');
118         } else if ($ext == 'url') {
119             //podcast
120             ++$count;
121             $listItems[] = getPodcastItem(basename($entry, '.url'), $urlPath);
122         } else if (substr($entry, -8) == '.auto.sh') {
123             //automatically execute script while listing this directory
124             addScriptOutput($listItems, $entry);
125         } else if ($ext == 'txt' || $ext == 'sh') {
126             //plain text file
127             ++$count;
128             $listItems[] = getDirItem(basename($entry, '.' . $ext), $urlPath);
129         }
130     }
131     if (!$count) {
132         $listItems[] = getMessageItem('No files or folders');
133     }
134     sendListItems($listItems);
135 }
136
137 function sendScript($path)
138 {
139     global $varDir;
140
141     $listItems = array();
142     addPreviousItem($listItems, $path);
143
144     $fullPath = $varDir . $path;
145     addScriptOutput($listItems, $fullPath);
146     sendListItems($listItems);
147 }
148
149 function addScriptOutput(&$listItems, $fullPath)
150 {
151     exec($fullPath . ' 2>&1', $output, $retVal);
152
153     if ($retVal == 0) {
154         addTextLines($listItems, $output);
155     } else {
156         $listItems[] = getMessageItem('Error executing script');
157         addTextLines($listItems, $output);
158     }
159 }
160
161 function sendTextFile($path)
162 {
163     global $varDir;
164     $listItems = array();
165     addPreviousItem($listItems, $path);
166
167     $lines = file($varDir . $path);
168     addTextLines($listItems, $lines);
169     sendListItems($listItems);
170 }
171
172 function addTextLines(&$listItems, $lines)
173 {
174     foreach ($lines as $line) {
175         $line = trim($line);
176         if ($line != '') {
177             $listItems[] = getDisplayItem($line);
178         }
179     }
180 }
181
182 function getDisplayItem($line)
183 {
184     $line = preg_replace('#\s+#', ' ', $line);
185     return '<Item>'
186         . '<ItemType>Display</ItemType>'
187         . '<Display>' . utf8_decode(htmlspecialchars($line)) . '</Display>'
188         . '</Item>';
189 }
190
191 function getDirItem($title, $urlPath)
192 {
193     global $host1, $host2;
194     return '<Item>'
195         . '<ItemType>Dir</ItemType>'
196         . '<Title>' . utf8_decode(htmlspecialchars($title)) . '</Title>'
197         . '<UrlDir>' . $host1 . utf8_decode(htmlspecialchars($urlPath)) . '</UrlDir>'
198         . '<UrlDirBackUp>' . $host2 . utf8_decode(htmlspecialchars($urlPath)) . '</UrlDirBackUp>'
199         . '</Item>';
200 }
201
202 function getEpisodeItem($title, $fullUrl, $desc, $type)
203 {
204     return '<Item>'
205         . '<ItemType>ShowEpisode</ItemType>'
206         . '<ShowEpisodeName>' . utf8_decode(htmlspecialchars($title)) . '</ShowEpisodeName>'
207         . '<ShowEpisodeURL>' . $fullUrl . '</ShowEpisodeURL>'
208         . '<ShowDesc>' . utf8_decode(htmlspecialchars($desc)) . '</ShowDesc>'
209         . '<ShowMime>' . $type . '</ShowMime>'
210         . '</Item>';
211 }
212
213 function getPodcastItem($title, $urlPath)
214 {
215     global $host1;
216     return '<Item>'
217         . '<ItemType>ShowOnDemand</ItemType>'
218         . '<ShowOnDemandName>' . utf8_decode(htmlspecialchars($title)) . '</ShowOnDemandName>'
219         . '<ShowOnDemandURL>' . $host1 . utf8_decode(htmlspecialchars($urlPath)) . '</ShowOnDemandURL>'
220         . '</Item>';
221 }
222
223 function getMessageItem($msg)
224 {
225     return '<Item>'
226         . '<ItemType>Message</ItemType>'
227         . '<Message>' . utf8_decode(htmlspecialchars($msg)) . '</Message>'
228         . '</Item>';
229 }
230
231 function getPreviousItem($urlPath)
232 {
233     global $host1, $host2;
234     return '<Item>'
235         . '<ItemType>Previous</ItemType>'
236         . '<UrlPrevious>' . $host1 . utf8_decode(htmlspecialchars($urlPath)) . '</UrlPrevious>'
237         . '<UrlPreviousBackUp>' . $host1 . utf8_decode(htmlspecialchars($urlPath)) . '</UrlPreviousBackUp>'
238         . '</Item>';
239 }
240
241 function addPreviousItem(&$listItems, $urlPath)
242 {
243     $parentDir = dirname($urlPath) . '/';
244     if ($parentDir == '/') {
245         return;
246     }
247     $listItems[] = getPreviousItem($parentDir);
248 }
249
250 function getFinalUrl($url)
251 {
252     $ctx = stream_context_set_default(
253         array('http' => array('method' => 'HEAD'))
254     );
255     //get_headers follows redirects automatically
256     $headers = get_headers($url, 1);
257     if ($headers !== false && isset($headers['Location'])) {
258         return end($headers['Location']);
259     }
260     return $url;
261 }
262
263 function sendMessage($msg)
264 {
265     sendListItems(array(getMessageItem($msg)));
266 }
267
268 function sendListItems($listItems)
269 {
270     $startitems = 1;
271     $enditems = 10;
272     if (isset($_GET['startitems'])) {
273         $startitems = (int) $_GET['startitems'];
274     }
275     if (isset($_GET['enditems'])) {
276         $enditems = (int) $_GET['enditems'];
277     }
278     //TODO: limit list
279
280     $xml = '<?xml version="1.0" encoding="iso-8859-1"?>' . "\n";
281     $xml .= '<?xml-stylesheet type="text/xsl" href="/html.xsl"?>' . "\n";
282     $xml .= '<ListOfItems>' . "\n";
283     foreach ($listItems as $item) {
284         $xml .= $item . "\n";
285     }
286     $xml .= "</ListOfItems>\n";
287
288     header('Content-type: text/xml');
289     echo $xml;
290 }
291 ?>