Index: repositories.list
===================================================================
--- repositories.list	(revision 0)
+++ repositories.list	(revision 1)
@@ -0,0 +1,10 @@
+# This file lists data (tri, tga, wav, ogg, ...) repositories.
+# Listed servers must run R3S (Raydium Server Side Scripts) files.
+
+# you can only use http and https protocols:
+# http://host.tld/path
+
+# main:
+http://repository.cqfd-corp.org/raydium/
+
+# we needs "contrib" servers
Index: getfile.php
===================================================================
--- getfile.php	(revision 0)
+++ getfile.php	(revision 1)
@@ -0,0 +1,76 @@
+<?
+// gets file from repositories listed in repositories.list
+
+// params: $filename (string, input), $force (integer, input),
+// 	   $status (integer, output)
+
+// This script must be placed in "rayphp" sub-directory.
+
+require("libfile.php");
+
+function getfile($file,$repos,$local)
+{
+global $force;
+
+//echo "trying: $repos/$file : ";
+$file=rawurlencode($file);
+
+$req="$repos?file=$file&type=getDate";
+$d=@file($req);
+if($d!=false) $d=$d[0];
+
+$ld=@filemtime($local);
+
+if($ld>=$d && !$force && $d!=false && $ld!=false)
+    {
+    echo "Local file is the same or newer, abording. ($repos)";
+    return false;
+    }
+
+$req="$repos?file=$file&type=getGzip";
+$data=@file($req);
+if($data==false)
+    return false;
+
+if(substr($data[0],0,6)=="FAILED")
+    {
+    echo $data[0]." ($repos)";
+    return false;
+    }
+
+$data=implode("",$data);
+echo "Found at '$repos'";
+return $data;
+}
+
+$status=0; // sets status to "error", by default
+
+
+filename_cut($filename,$file,$path);
+
+echo "Using repositories to get '$file' file:";
+
+$repos=read_repositories_file("rayphp/repositories.list");
+
+for($i=0;$i<count($repos);$i++)
+  {
+  $r=trim($repos[$i]);
+    if(valid_entry($r))
+	if( ($data=getfile($file,$r,$path.$file)) )
+	    {
+	    $status=-1;
+	    break;
+	    }
+  }
+	
+if($status==0)
+    die("No valid repository found for this file, abording.");
+
+$data=gzdecode($data);
+$fp=@fopen($path.$file,"wb");
+if(!$fp)
+    die("Cannot create output file '$path$file', abording.");
+fwrite($fp,$data);
+fclose($fp);
+$status=1;
+?>
\ No newline at end of file
Index: r3s/index.php
===================================================================
--- r3s/index.php	(revision 0)
+++ r3s/index.php	(revision 1)
@@ -0,0 +1,137 @@
+<?
+// Raydium Server Side repository script
+// name this file "index.php", and place data in $data_dir directory.
+require("config.inc.php");
+
+
+function decompress_file($gz,$final)
+{
+$fp=gzopen($gz,"r");
+if(!$fp) die("FAILED: Cannot open gz file");
+while(!gzeof($fp))
+    {
+    $data.=gzread($fp,128);
+    }
+gzclose($fp);
+
+$fp=fopen($final,"wb");
+if(!$fp)
+    {
+    echo "FAILED: Cannot create file '$final' on this server";
+    return false;
+    }
+fwrite($fp,$data);
+fclose($fp);
+unlink($gz);
+return true;
+}
+
+function home()
+{
+global $data_dir,$upload_accept,$QUERY_STRING;
+
+echo "<h2>R3S Raydium data repository</h2>\n";
+echo "<h3>Available files:</h3>\n";
+echo "<table border=0 cellpadding=2>";
+
+ if ($dh = opendir($data_dir)) 
+ {
+    while (($file = readdir($dh)) !== false) 
+    {
+	if($file[0]==".") continue;
+	$size=filesize($data_dir.$file);
+	$total_size+=$size;
+	echo "<tr><td><b> $file </b></td><td align=right>$size byte(s)</td><td>&nbsp;</td><td>".date("Y-m-d H:i:s",filemtime($data_dir.$file))."</td></tr>";
+    }
+  closedir($dh);
+ }
+echo "<tr><td>&nbsp;</td></tr>";
+echo "<tr><td><b>Total size</b></td><td align=right>".sprintf("%.2f",$total_size/1024/1024)." MB</td></tr";
+echo "</table><br>";
+echo "You can add this URL in your <i>rayphp/repositories.*</i> files.<br>";
+if($upload_accept) $up="supports"; else $up="does not supports";
+echo "This server $up data uploading.<br><br>";
+echo "Yes, we needs a CSS file ;)<br>";
+echo "Note: files are not sorted.<br>";
+}
+
+
+
+function main($file,$type,$username,$password,$data)
+{
+global $data_dir,$upload,$upload_accept,$brute_force_delay;
+global $HTTP_POST_FILES;
+
+if($type=="")
+    {
+    home();
+    return;
+    }
+
+if($file=="") return;
+$file=rawurldecode($file);
+$file=str_replace("/","",$file);
+$file=$data_dir.$file;
+
+if($type=="putGzip")
+{
+if(!$upload_accept)
+    {
+    echo "FAILED: Upload is not activated on this server !";
+    return;
+    }
+
+sleep($brute_force_delay);
+
+$username=rawurldecode($username);
+$password=rawurldecode($password);
+
+if($username!=$upload["user"] || $password!=$upload["pass"])
+    {
+    echo "FAILED: invalid user/pass ($username/$password)";
+    return;
+    }
+$filegz=$file.".tmp.gz";
+if(file_exists($HTTP_POST_FILES["data"]["tmp_name"]))
+ {
+ move_uploaded_file($HTTP_POST_FILES["data"]["tmp_name"], $filegz);
+ }
+else die("FAILED: Cannot find data in this request");
+
+if(!decompress_file($filegz,$file)) return;
+chmod($file,0664);
+
+echo "+ SUCCESS: file uploaded";
+return;
+}
+
+if(!file_exists($file)) die("FAILED: file not found");
+
+if($type=="getGzip")
+{
+$fp=fopen($file,"rb");
+if(!$fp) die("FAILED: file not found");
+$data=fread($fp,filesize($file));
+fclose($fp);
+
+$tmp=tempnam("./","delme");
+$fp=gzopen($tmp,"wb");
+if(!$fp) return;
+gzwrite($fp,$data);
+gzclose($fp);
+//$dat=gzencode($data);
+//echo $dat;
+//echo date("s");
+readfile($tmp);
+unlink($tmp);
+//echo $tmp;
+}
+
+if($type=="getDate")
+{
+echo filemtime($file);
+}
+} // end main()
+
+main($file,$type,$username,$password,$data);
+?>
\ No newline at end of file
Index: r3s/README
===================================================================
--- r3s/README	(revision 0)
+++ r3s/README	(revision 1)
@@ -0,0 +1,23 @@
+R3S: Raydium Server Side Scripts
+--------------------------------
+
+With this files and a HTTP/PHP server, you can build very
+quickly a data repository server, allowing clients to get new files
+(and refresh old ones) from this server.
+Files are all stored in the same directory, since
+the client will rebuilt directory structure by itself.
+
+R3S support uploading, but you can also use a FTP server since Raydium
+client applications allows this.
+
+With R3S, FTP is slower than HTTP since no compression is used (R3S protocol
+is using gzip with HTTP) but is the only correct solution with big files, since
+most HTTP servers and proxies limits requests size.
+
+See configuration file, and place data in $data_dir directory.
+
+Please, note that Apache (or any other HTTP server) must have write rights
+in $data_dir directory:
+# chgrp apache files/
+# chown g+w files/
+(You may have to change "apache" to "httpd", "www-data" or something else).
Index: r3s/config.inc.php
===================================================================
--- r3s/config.inc.php	(revision 0)
+++ r3s/config.inc.php	(revision 1)
@@ -0,0 +1,16 @@
+<?
+// Raydium Server Side repository Scripts (R3S) configuration file.
+
+// files directory:
+$data_dir="files/";
+
+# Upload params:
+# Note: You can also use an FTP server.
+$upload_accept=true;
+$upload["user"]="anonymous";
+$upload["pass"]="nopass";
+
+// Minimum delay (in seconds) for each upload request:
+$brute_force_delay=1;
+
+?>
\ No newline at end of file
Index: libdeps.php
===================================================================
--- libdeps.php	(revision 0)
+++ libdeps.php	(revision 1)
@@ -0,0 +1,83 @@
+<?
+
+// supported files : (depends_xxx style)
+
+function depends_tri($filename)
+{
+//$f=@file($filename);
+$fp=fopen($filename,"rt");
+if($fp==false)
+    {
+    echo "Cannot open $filename";
+    }
+
+fgets($fp, 4096); // skip first line (version number)
+
+while (!feof($fp)) 
+    {
+    $line = trim(fgets($fp, 4096));
+    $line=explode(" ",$line);
+    $tex=trim($line[count($line)-1]);
+    if(substr($tex,0,4)!="rgb(")
+	{
+	$tex=trim($tex);
+	$texs=explode(";",$tex);
+	if(strlen($texs[0])) $ret[]=$texs[0];
+	if(strlen($texs[1])) 
+	    {
+	    if(strpos($texs[1],"|")!==false)
+		{
+		$lm=explode("|",$texs[1]);
+		$ret[]=$lm[2];
+		}
+	    else
+		$ret[]=$texs[1];
+	    }
+	$ret=array_values(array_unique($ret));
+	}
+    }
+fclose($fp);
+$ret[]=$filename;
+
+return $ret;
+}
+
+function depends_prt($filename)
+{
+$f=@file($filename);
+for($i=0;$i<count($f);$i++)
+    {
+    $line=trim($f[$i]);
+    if($line[0]=='/' && $line[1]=='/') continue;
+    
+    if(strpos($line,"texture") === false) continue;
+
+    echo $line;
+    $t=explode('=',$line);
+    $t=trim($t[1]);
+    $t=str_replace('"',"",$t);
+    $t=str_replace(';',"",$t);
+    $ret[]=$t;
+    }
+
+$ret[]=$filename;
+return $ret;
+}
+
+
+// -----------------------------------------------
+
+function depends_find($filename)
+{
+$tbl=explode(".",$filename);
+$ext=trim($tbl[count($tbl)-1]);
+if($ext=="tri") return depends_tri($filename);
+if($ext=="prt") return depends_prt($filename);
+
+// else ..
+$ret[]=$filename;
+return $ret;
+}
+
+
+?>
Index: repositories.upload
===================================================================
--- repositories.upload	(revision 0)
+++ repositories.upload	(revision 1)
@@ -0,0 +1,12 @@
+# This file lists all repositories used for uploading:
+# You can use http/https URL (R3S servers) or ftp/ftps servers (classic FTP).
+
+# Only first valid server will be used in this list.
+# No test is done to see if your file is newer than server side one.
+# Warning ! Be carefull with "/" at the end of urls since Raydium client
+# do not supports redirections !
+
+http://anonymous:nopass@repository.cqfd-corp.org/raydium/
+ftp://raydium:none@ftp.cqfd-corp.org:29/
+#http://anonymous:nopass@localhost/raydium/repository/
+#http://anonymous:nopass@localhost/
Index: libfile.php
===================================================================
--- libfile.php	(revision 0)
+++ libfile.php	(revision 1)
@@ -0,0 +1,49 @@
+<?
+
+function read_repositories_file($repos)
+{
+$ret=@file($repos);
+if(count($ret)==0)
+    die("Cannot open $repos");
+
+// may make $ret array "uniq"
+
+return $ret;
+}
+
+
+function filename_cut($filename,&$file,&$path)
+{
+$t=explode("/",$filename);
+$file=$t[count($t)-1];
+$t[count($t)-1]="";
+$path=implode("/",$t);
+}
+
+function valid_entry($r)
+{
+if($r[0]!='#' && strlen(trim($r))>0)
+    return true;
+return false;
+}
+
+function gzdecode($in)
+{
+$tmp="tmp.tmp";
+$fp=fopen($tmp,"wb");
+if(!$fp) return false;
+fwrite($fp,$in);
+fclose($fp);
+
+$fp=gzopen($tmp,"rb");
+if(!$fp) return false;
+while(!gzeof($fp))
+    {
+    $data.=gzread($fp,128);
+    }
+gzclose($fp);
+unlink($tmp);
+return $data;
+}
+
+?>
\ No newline at end of file
Index: README
===================================================================
--- README	(revision 0)
+++ README	(revision 1)
@@ -0,0 +1,4 @@
+This directory contains client PHP scripts for Raydium.
+
+Some of the most interesting files of this directory are "repositories.*" ones,
+describing wich data servers are available for your applications data.
Index: putfile.php
===================================================================
--- putfile.php	(revision 0)
+++ putfile.php	(revision 1)
@@ -0,0 +1,206 @@
+<?
+// gets file from repositories listed in repositories.list
+
+// params: $filename (string, input), $depends (integer, input)
+// 	   $status (integer, output)
+
+// This script must be placed in "rayphp" sub-directory.
+
+require("libfile.php");
+require("libdeps.php");
+
+$status=0; // sets status to "error", by default
+
+//$filename="buggy.tri"; // used when debugging outside of Raydium
+
+// I use a "static" value for now, may randomly generate it in the future ...
+$boundary="BREAKmessageHEREthisISaBOUNDARY";
+
+
+// search first data line in $packer (HTTP server answer)
+function http_search_data($packet,&$first)
+{
+$data_start=1;
+$packet=explode("\n",$packet);
+
+$first=trim($packet[0]);
+for($i=0;$i<count($packet);$i++)
+    if(trim($packet[$i])=="")
+	break;
+
+for($j=0;$j<$i;$j++)
+    if(trim($packet[$j]) == "Transfer-Encoding: chunked")
+	$data_start=2;
+
+return trim($packet[$i+$data_start]);
+}
+
+function http_make_part($name,$value,$binary=false)
+{
+global $boundary;
+
+if($binary)
+    $filename="; filename=\"data.bin\"";
+else $filename="";
+
+$ret ="--$boundary\r\n";
+$ret.="Content-Disposition: form-data; name=\"$name\"$filename\r\n";
+if($binary)
+$ret.="Content-Type: application/octet-stream\r\n";
+$ret.="\r\n";
+$ret.="$value";
+$ret.="\r\n";
+
+return $ret;
+}
+
+function ftp_upload($repos,$local,$distant)
+{
+/*
+$ret=@copy($local,"$repos/$distant");
+if($ret==false)
+    {
+    echo "Failed contacting $repos";
+    return false;
+    }
+echo "$repos: SUCCESS";
+return true;
+*/
+$url=parse_url($repos);
+
+$conn_id = ftp_connect($url["host"],$url["port"]);
+$login_result = ftp_login($conn_id, $url["user"], $url["pass"]);
+ftp_pasv($conn_id, true);
+//echo ".";
+if (ftp_put($conn_id,$url["path"].$distant, $local, FTP_ASCII))
+ {
+ echo "$repos: SUCCESS";
+ return true;
+ }
+else
+ {
+ echo "Failed contacting $repos";
+ return false;
+ }
+ftp_close($conn_id);
+}
+
+function http_upload($repos,$local,$distant)
+{
+global $boundary,$depends;
+$data=@file($local);
+$data=implode("",$data);
+$data=gzencode($data);
+
+$url=parse_url($repos);
+$distant=rawurlencode($distant);
+$user=rawurlencode($url["user"]);
+$pass=rawurlencode($url["pass"]);
+
+$path=$url["path"];
+if($url["port"]=="") $url["port"]=80;
+$req="POST $path HTTP/1.1\r\n";
+
+$fp = @fsockopen($url["host"],$url["port"]);
+if(!$fp) 
+    {
+    echo "Failed contacting $repos";
+    return false;
+    }
+$ret="";
+fputs($fp,$req);
+fputs($fp,"Host: ".$url["host"]."\r\n");
+fputs($fp,"User-Agent: Raydium PHP Upload Script\r\n");
+
+fputs($fp,"Content-Type: multipart/form-data; boundary=$boundary\r\n");
+
+$packet =http_make_part("file",$distant);
+$packet.=http_make_part("type","putGzip");
+$packet.=http_make_part("data",$data,true);
+$packet.=http_make_part("username",$user);
+$packet.=http_make_part("password",$pass);
+
+$packet.="--$boundary--\r\n";
+
+$len=strlen($packet);
+fputs($fp,"Content-Length: $len\r\n");
+fputs($fp,"Connection: Close\r\n");
+fputs($fp,"\r\n");
+fputs($fp,$packet);
+
+while(!feof($fp)) 
+    {
+    $ret.=fgets($fp,128);
+    }
+fclose($fp);
+
+$ret=http_search_data($ret,$first);
+echo "$repos: $ret";
+if($ret[0]=='+') return true;
+echo "HTTP reply: $first";
+return false;
+}
+
+
+$repos=read_repositories_file("rayphp/repositories.upload");
+
+if($depends)
+$deps=depends_find($filename);
+else $deps[]=$filename;
+
+for($j=0;$j<count($deps);$j++)
+{
+filename_cut($deps[$j],$file,$path);
+
+if(!file_exists($path.$file) || !is_readable($path.$file))
+    {
+    echo "Cannot upload '$path$file': file not exists or invalid rights";
+    continue;
+    }
+
+echo "Using repositories to upload '$file' file:";
+
+ for($i=0;$i<count($repos);$i++)
+  {
+  $r=trim($repos[$i]);
+    if(valid_entry($r))
+	{
+	// http or ftp ?
+	$type=parse_url($r);
+	$type=$type["scheme"];
+	
+	if(($type=="ftp" ||
+	    $type=="ftps" )
+	    && ftp_upload($r,$file.$path,$file))
+	    {
+	    touch($path.$file);
+	    $status++;
+	    break;
+	    }
+	
+	if(($type=="http" ||
+	    $type=="https" )
+	&& http_upload($r,$file.$path,$file))
+	    {
+	    touch($path.$file);
+	    $status++;
+	    break;
+	    }	
+	}
+  }
+}
+
+if($status==count($deps))
+    {
+    echo "All files uploaded ($status)";
+    return;
+    }    
+
+if($status==0)
+    {
+    echo "No file uploaded";
+    return;
+    }    
+
+echo "Only $status/".count($deps)." file(s) uploaded";
+?>