\n";
@@ -703,33 +698,102 @@
echo "\n";
echo "
\n";
- echo "| \n";
+ echo " | \n";
echo " ".$text['label-greeting']."\n";
echo " | \n";
+ echo " | \n";
+ echo "
\n";
+ echo "
\n";
echo "| \n";
- echo " | \n";
diff --git a/app/switch/sounds.php b/app/switch/sounds.php
new file mode 100644
index 0000000000..a054c901f3
--- /dev/null
+++ b/app/switch/sounds.php
@@ -0,0 +1,191 @@
+
+ * Portions created by the Initial Developer are Copyright (C) 2023
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mark J Crane
+ */
+
+//set the max php execution time
+ ini_set('max_execution_time', 7200);
+
+//includes files
+ require_once dirname(__DIR__, 2) . "/resources/require.php";
+ require_once "resources/check_auth.php";
+
+//check the permission
+ if (permission_exists('recording_play') || permission_exists('recording_download')) {
+ //access granted
+ }
+ else {
+ echo "access denied";
+ exit;
+ }
+
+//set additional variables
+ $action = $_REQUEST["action"] ?? '';
+
+//download the sound
+ if ($action == "download") {
+
+ //get first installed language (like en/us/callie)
+ $language_paths = glob($_SESSION["switch"]['sounds']['dir']."/*/*/*");
+ foreach ($language_paths as $key => $path) {
+ $path = str_replace($_SESSION["switch"]['sounds']['dir'].'/', "", $path);
+ $path_array = explode('/', $path);
+ if (count($path_array) <> 3 || strlen($path_array[0]) <> 2 || strlen($path_array[1]) <> 2) {
+ unset($language_paths[$key]);
+ }
+ $language_paths[$key] = str_replace($_SESSION["switch"]['sounds']['dir']."/","",$language_paths[$key] ?? '');
+ if (empty($language_paths[$key])) {
+ unset($language_paths[$key]);
+ }
+ }
+ $language_path = $language_paths[0];
+
+ //determine the path for sound file
+ $filename_parts = explode('/', str_replace('..', '', $_GET['filename']));
+ if (!is_array($filename_parts) || @sizeof($filename_parts) != 2) { exit; }
+ $path = $_SESSION['switch']['sounds']['dir'].'/'.$language_path.'/'.$filename_parts[0].'/8000/';
+
+ //set sound filename
+ $sound_filename = $filename_parts[1];
+
+ //build full path
+ $full_sound_path = $path.$sound_filename;
+
+ //send the headers and then the data stream
+ if (file_exists($full_sound_path)) {
+
+ $fd = fopen($full_sound_path, "rb");
+ switch (pathinfo($sound_filename, PATHINFO_EXTENSION)) {
+ case "wav" : header("Content-Type: audio/x-wav"); break;
+ case "mp3" : header("Content-Type: audio/mpeg"); break;
+ case "ogg" : header("Content-Type: audio/ogg"); break;
+ }
+ header('Content-Disposition: attachment; filename="'.$filename_parts[0].'_'.$filename_parts[1].'"');
+ header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
+ header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
+
+ ob_clean();
+
+ //content-range
+ if (isset($_SERVER['HTTP_RANGE']) && (empty($_GET['t']) || $_GET['t'] != "bin")) {
+ range_download($full_sound_path);
+ }
+
+ fpassthru($fd);
+ }
+
+ }
+
+//define the download function (helps safari play audio sources)
+ function range_download($file) {
+ $fp = @fopen($file, 'rb');
+
+ $size = filesize($file); // File size
+ $length = $size; // Content length
+ $start = 0; // Start byte
+ $end = $size - 1; // End byte
+ // Now that we've gotten so far without errors we send the accept range header
+ /* At the moment we only support single ranges.
+ * Multiple ranges requires some more work to ensure it works correctly
+ * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
+ *
+ * Multirange support annouces itself with:
+ * header('Accept-Ranges: bytes');
+ *
+ * Multirange content must be sent with multipart/byteranges mediatype,
+ * (mediatype = mimetype)
+ * as well as a boundry header to indicate the various chunks of data.
+ */
+ header("Accept-Ranges: 0-$length");
+ // header('Accept-Ranges: bytes');
+ // multipart/byteranges
+ // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
+ if (isset($_SERVER['HTTP_RANGE'])) {
+
+ $c_start = $start;
+ $c_end = $end;
+ // Extract the range string
+ list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
+ // Make sure the client hasn't sent us a multibyte range
+ if (strpos($range, ',') !== false) {
+ // (?) Shoud this be issued here, or should the first
+ // range be used? Or should the header be ignored and
+ // we output the whole content?
+ header('HTTP/1.1 416 Requested Range Not Satisfiable');
+ header("Content-Range: bytes $start-$end/$size");
+ // (?) Echo some info to the client?
+ exit;
+ }
+ // If the range starts with an '-' we start from the beginning
+ // If not, we forward the file pointer
+ // And make sure to get the end byte if spesified
+ if ($range == '-') {
+ // The n-number of the last bytes is requested
+ $c_start = $size - substr($range, 1);
+ }
+ else {
+ $range = explode('-', $range);
+ $c_start = $range[0];
+ $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
+ }
+ /* Check the range and make sure it's treated according to the specs.
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
+ */
+ // End bytes can not be larger than $end.
+ $c_end = ($c_end > $end) ? $end : $c_end;
+ // Validate the requested range and return an error if it's not correct.
+ if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
+
+ header('HTTP/1.1 416 Requested Range Not Satisfiable');
+ header("Content-Range: bytes $start-$end/$size");
+ // (?) Echo some info to the client?
+ exit;
+ }
+ $start = $c_start;
+ $end = $c_end;
+ $length = $end - $start + 1; // Calculate new content length
+ fseek($fp, $start);
+ header('HTTP/1.1 206 Partial Content');
+ }
+ // Notify the client the byte range we'll be outputting
+ header("Content-Range: bytes $start-$end/$size");
+ header("Content-Length: $length");
+
+ // Start buffered download
+ $buffer = 1024 * 8;
+ while(!feof($fp) && ($p = ftell($fp)) <= $end) {
+ if ($p + $buffer > $end) {
+ // In case we're only outputtin a chunk, make sure we don't
+ // read past the length
+ $buffer = $end - $p + 1;
+ }
+ set_time_limit(0); // Reset time limit for big files
+ echo fread($fp, $buffer);
+ flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit.
+ }
+
+ fclose($fp);
+ }
+
+?>
\ No newline at end of file