fixed the url parser so all urlhandlers have ^ tacked to the start
[glcas.git] / plugins / repo.php
1 <?php
2 $URL_HANDLERS["*"] = "GLCASRepo";
3 global $CRON_CLASSES;
4 $CRON_CLASSES["GLCASRepo"] = "GLCASRepo";
5
6 class GLCASRepo {
7         function __construct($config)
8         {
9                 $this->config = $config;
10                 if($this->config->getConfigVar("storagelocation") == false) {
11                         global $WEB_ROOT_FS;
12                         $storloc = "$WEB_ROOT_FS/../var/glcas/cache/";
13                         if(!file_exists($storloc)) mkdir($storloc);
14                         $this->config->setConfigVar("storagelocation", realpath($storloc));
15                         $this->config->saveConfig();
16                         error_log("set storage location, $storloc");
17                 }
18         }
19         
20         function cron()
21         {
22                 //echo "<pre>";
23                 $uconf = unserialize($this->config->getConfigVar("repodata"));
24                 $repostore = $this->config->getConfigVar("storagelocation");
25                 //print_r($uconf);
26                 //echo "</pre>";
27                 
28                 foreach($uconf as $rkey => $repo) {
29                         echo "Repo $rkey: ".$repo["desc"]."<br>";
30                         if(!isset($repo["expiretime"])) {
31                                 echo " - Expire time not set, setting to 2 days by default<br>";
32                                 $uconf[$rkey]["expiretime"] = 2;
33                                 $repo["expiretime"] = 2;
34                                 $this->config->setConfigVar("repodata", serialize($uconf));
35                                 $this->config->saveConfig();                            
36                         }
37                         
38                         if(file_exists("$repostore/$rkey/repodata/repoupdate.lock")) {
39                                 echo " - <font color=\"red\">Repo locked for update</font><br>";
40                                 
41                         }
42                         
43                         // we still do this next bit, even if its locked because it may be a stray file
44                         echo " - Expire time is ".$repo["expiretime"]." days, checking repo<br>";
45                         error_log("checking $repostore/$rkey/repodata/repomd.xml");
46                         $tdiff = time() - filemtime("$repostore/$rkey/repodata/repomd.xml");
47                         $maxtdiff = $repo["expiretime"] * 24 * 3600;
48                         if($tdiff > $maxtdiff) {
49                                 echo " - <font color=\"green\">updating repo</font><br>";
50                                 $this->updateRepo($rkey);
51                         } else {
52                                 echo " - not updating repo<br>";
53                         }
54                 }
55         }
56
57         function go($url)
58         {
59                 error_log("repo:go called");
60
61                 // figure out what we're doing
62                 switch($url) {
63                         case "list":
64                                 GLCASpageBuilder($this, "body");
65                                 break;
66                         default:
67                                 $this->getRepoForUrl($url);
68                 }
69         }
70
71         function body($url)
72         {
73                 // this is how this will work
74                 //$this->decodeUrl();
75                 if(strncasecmp("list", $url, 4)==0) {
76                         echo "i am the repo list";
77                         return;
78                 }
79                 echo "i am the repo, $url";
80         }
81
82
83         // TODO: rework this function
84         /*
85         * What i need to do is have a downloader function
86         * that can cope with lots of different shit
87         * but thats a pipe dream
88         *
89         * what *THIS* function needs to do is
90         * 1) figure out the repo
91         * 2) figure out the file in the repo
92         * 2.1) if its a directory, go to print directory
93         * 3) if the file exists, give it to the user (if a range is specified give the user the range)
94         * 4) if the file does not exist
95         *    - check if a tmp file exists
96         *    - attempt to get an exclusive flock
97         *    - if flock fails, donwload in progress
98         *    - if flock succeeds, truncate file and re-start download
99         *    - if a range request was made, send the range once available
100         *    - if range not available, sleep for 5 and check again.
101         *
102         * I dont want to code this from scratch, but i probably need to
103         */
104         function getRepoForUrl($url)
105         {
106                 $xurl = split("[/,]", $url);
107
108                 // first get the config
109                 $uconf = unserialize($this->config->getConfigVar("repodata"));
110                 $repostore = $this->config->getConfigVar("storagelocation");
111
112                 // preset matched to -1
113                 $matched = -1;
114
115                 // first we check for /repo/repoid as a url
116                 $startat = 0;
117                 if($xurl[0] == "repo") {
118                         $repid = $xurl[1];
119                         error_log("trying to get repo for repoid, $repid");
120                         if(isset($uconf[$repid])) {
121                                 $matched = ((int)($repid));
122                                 error_log("set matched, $matched, $repid");
123                                 $startat +=2;
124                         }
125                 }
126
127                 // now check for a prefix match
128                 $prematch = false;
129                 if($matched < 0) foreach($uconf as $key => $var) {
130                         $pre = $var["prefix"];
131                                 
132                         if($pre!="") {
133                                 //echo "Checking pre $pre against ".$xurl[0]."\n";
134                                 if(strcasecmp($pre, $xurl[0])==0) {
135                                         //echo "Matched pre\n";
136                                         $prematch = true;
137                                         $startat++;
138                                 }
139                         }
140                 }
141
142                 // next, check for a short url match
143                 if($matched < 0) foreach($uconf as $key => $var) {
144                         // if we matched a pre, then we check against the second url component
145                                 
146                         $short = $var["shorturl"];
147                                 
148                         if($short!="") {
149                                 //echo "Checking short $short against ".$xurl[$startat]."\n";
150                                 if(strcasecmp($xurl[$startat], $short)==0) {
151                                         //echo "Matched\n";
152                                         $matched = $key;
153                                         $startat++;
154                                 }
155                         }
156                 }
157
158                 // TODO: this deterministic bit
159                 // so far nothing has matched - what this next bit needs to do is try and "Determine" a repo from url
160                 // for eg, if a user gets /fedora/x86_64/os we need to return something appropriate
161                 if($matched < 0) {
162                         echo "No such repo<br>";
163                         header("HTTP/1.0 404 Not Found");
164                         return;
165                 }
166
167
168                 // something was matched, so now we reconstruct the file component of the url
169                 $file = "/";
170                 if(count($xurl) > $startat) for($i=$startat; $i < count($xurl); $i++) {
171                         $file .= "/".$xurl[$i];
172                 }
173
174                 // so, the ultimate url for the file we need is:
175                 $actualfile = "$repostore/$matched/$file";
176                 error_log("Atcualfile is $actualfile");
177
178                 // if its a directory, lets do a print
179                 if(is_dir($actualfile)) {
180                         $this->printDir($actualfile, $file, $url);
181                         return;
182                 }
183
184                 // check if the file exists and serve it up
185                 if(file_exists($actualfile) && !file_exists("$actualfile.size")) {
186                         $this->serveUpFile($actualfile, $matched);
187                         return;
188                 } else {
189                         // the file does not exist, we now need to go into "download" mode
190                         $remoteurl = $uconf[$matched]["url"]."/$file";
191                         $this->downloadAndServe($actualfile, $matched, $remoteurl);
192                         return;
193                 }
194         }
195
196         function serveUpFile($actualfile, $repoid)
197         {
198                 $uconf = unserialize($this->config->getConfigVar("repodata"));
199                 $repostore = $this->config->getConfigVar("storagelocation");
200
201                 // figure out the range header garbage that centos/redhat send
202                 if(isset($_SERVER["HTTP_RANGE"])) {
203                         // we're using ranges - screw you stupid installer
204                         $pr_range = preg_split("/[:\-=, ]+/", $_SERVER["HTTP_RANGE"]);
205                                 
206                         // cut up ranges
207                         $rangestart = $pr_range[1];
208                         $rangelength = $pr_range[2] - $pr_range[1] +1;
209                         $rangestr = $pr_range[1]."-".$pr_range[2];
210                         error_log("going ranges at $rangestart, $rangelength,".$rangesa[1].",".$rangesb[0]);
211                                 
212                         // now spit some headers
213                         header("HTTP/1.1 206 Partial Content");
214                         header("Content-Length: ".$rangelength);
215                                 
216
217                         header("Content-Range: bytes $rangestr/".filesize($actualfile));
218                                 
219                         // determine mime type
220                         $type = mime_content_type($actualfile);
221                                 
222                         // set mime type header
223                         header("Content-type: $type");
224                                 
225                         // open the local file (TODO: error check)
226                         $localfile = fopen($actualfile, "r");
227                         fseek($localfile, $rangestart, SEEK_SET);
228                                 
229                         // read in the data, god i hope its not big
230                         $data = fread($localfile, $rangelength);
231                                 
232                         // lastly, send data
233                         echo $data;
234                         flush();
235                                 
236                         // and close the file
237                         fclose($localfile);
238                         return;
239                 } else {
240
241                         // we're not using range's - good on you installer thingy
242                         header("Content-Length: ".filesize($actualfile));
243
244                         // set the mime type header
245                         $type = mime_content_type($actualfile);
246                         header("Content-type: $type");
247                                 
248                         // open the local file
249                         $localfile = fopen($actualfile, "r");
250                         if(!$localfile) {
251                                 error_log("normal upload went barf");
252                                 return;
253                         }
254                                 
255                         // iterate over its length, send 8k at a time
256                         while(!feof($localfile)) {
257                                 // read and send data
258                                 $data = fread($localfile, 32768);
259                                 echo $data;
260
261                                 // flush so the client sees the data
262                                 flush();
263                         }
264                                 
265                         // close the file
266                         fclose($localfile);
267                         return;
268                 }
269         }
270
271         // TODO: this is the function im working on
272         // the alternative to this function is that if a file is in the process of being
273         // downloaded, we simply serve from upstream... not a good idea tho unless we create
274         // a local proxy right here - this function is a race condition waiting to be had
275         // lets hope its a good one!
276         function downloadAndServe($filename, $repoid, $remoteurl)
277         {
278
279                 $this->startDownload($filename, $remoteurl);
280
281                 // give the proc a minute to get going
282                 sleep(2);
283                 clearstatcache();
284
285                 // get the configurations we need
286                 $uconf = unserialize($this->config->getConfigVar("repodata"));
287                 $repostore = $this->config->getConfigVar("storagelocation");
288
289
290
291                 // determine if we're ranged
292                 $ranged = false;
293                 $rangestart = 0;
294                 $rangelength = 0;
295                 $rangestr="";
296                 if(isset($_SERVER["HTTP_RANGE"])) {
297                         // we're using ranges - screw you stupid installer
298                                 
299                         $pr_range = preg_split("/[:\-=, ]+/", $_SERVER["HTTP_RANGE"]);
300                         error_log("got range ".$_SERVER["HTTP_RANGE"]." and ".print_r($pr_range, true));
301                                 
302                         // cut up ranges
303                         $rangestart = $pr_range[1];
304                         $rangelength = $pr_range[2] - $pr_range[1] +1;
305                         $rangestr = $pr_range[1]."-".$pr_range[2];
306                         error_log("going ranges at $rangestart, $rangelength, $rangestr");
307                         $ranged = true;
308                 }
309
310                 // open the local files
311
312                 // now, lets determine what state we're in
313                 // we're either - getting and sending
314                 // watching and sending
315                 // or a range (Getting and sending)
316                 // or a range (watching and sending)
317                 // TODO: it may be advicable to start the download as a seperate cli process rather then something goin on here
318                 // so it definitely cant be interrupted.
319                 
320                 // check for a 404 file and wait 2 if it exists - i should really check the timestamp for an updated
321                 // file, but thats too much effort for now: TODO: check timestamp on 404 file
322                 $slept = 0;
323                 while(!file_exists("$filename")) {
324                         clearstatcache();
325                         sleep(1);
326                         $slept += 1;
327                         error_log("Sleeping waiting for file");
328                         
329                         // if 404 file exists, we wait much less time
330                         if(file_exists("$filename.404") && $slept > 2) {
331                                 header("HTTP/1.0 404 Not Found");
332                                 return;
333                         }
334                         if($slept > 10) {
335                                 header("HTTP/1.0 404 Not Found");
336                                 return;
337                         } 
338                 }
339                 
340                 clearstatcache();
341                 if(is_dir($filename)) {
342                         
343                         header("Location: ".$_SERVER["REQUEST_URI"]."/");
344                         return;
345                 }
346                         
347
348                 // first, getting and sending - this is easy.
349                 if (!$ranged) {
350                                 
351                         $localfile = fopen($filename, "r");
352                                 
353                         // this is where the fun starts - but this one isnt too bad.
354                         error_log("OTHERDOWNLOAD: im another downloader, please work");
355                         if(file_exists("$filename.size")) $fsize = file_get_contents("$filename.size");
356                         else $fsize = filesize($filename);
357                         header("Content-Length: $fsize");
358                         $sgotten = 0;
359                         while(!feof($localfile)) {
360                                 $data = fread($localfile, 2048);
361                                 if(!$data) {
362                                         error_log("dollardata is pair shaped");
363                                 } else {
364                                         $sgotten += strlen($data);
365                                         if($sgotten > $fsize) {
366                                                 error_log("went plop at sgotten, $sgotten, $fsize");
367                                                 return;
368                                         }
369                                         echo $data;
370                                         flush();
371                                 }
372                         }
373                         fclose($localfile);
374                                 
375                         // need to think about this in pseudo code.
376                         // 1. close the file and wait for it to get to $sgotten + 2048 or $fsize
377                         $cursize = filesize($filename);                         
378                                 
379                         $upload_finished = false;
380                         while(!$upload_finished) {
381                                 while($cursize < $fsize && $cursize < ($sgotten+2048)) {
382                                         clearstatcache();
383                                         error_log("OTHERDOWNLOAD: halt, $cursize, $sgotten, $fsize");
384                                         // sleep until the the filesize is greater then what we're up to, or until the file is finished
385                                         sleep(1);
386                                         $cursize = filesize($filename);
387                                 }
388
389                                 error_log("OTHERDOWNLOAD: continue, $sgotten, $fsize");
390                                 // reopen local file - if it stopped existing, we need to deal with that
391                                 $localfile = fopen($filename, "r");
392
393                                 // UG, we need to ff, how could i forget that
394                                 fseek($localfile, $sgotten);
395
396                                 if(!$localfile) {
397                                         error_log("OTHERDOWNLOAD: something went plop");
398                                         return;
399                                 }
400
401                                 // now loop on the file until we have it at an eof
402                                 while(!feof($localfile)) {
403                                         $data = fread($localfile, 512);
404                                         if(!$data) {
405                                                 error_log("OTHERDOWNLOAD: dollar data went plop");
406                                         } else {
407                                                 $sgotten += strlen($data);
408                                                 echo $data;
409                                                 flush();
410                                         }
411                                 }
412                                 fclose($localfile);
413
414                                 if($sgotten >= $fsize) {
415                                         if($sgotten > $fsize) error_log("OTHERDOWNLOADER: finished but $sgotten, $fsize doesnt make senze");
416                                         $upload_finished = true;
417                                 }
418                                 // and we're done
419
420                         }
421                         error_log("OTHERDOWNLOADER: done with");
422                                 
423                         return;
424
425
426                                 
427                                 
428                         // Next painful bit
429                 } else {
430                         // and here too, yay, someone else is doing the
431                         // download, but we're the retards getting a range
432                         $sgotten = 0;
433                                 
434                         $sgatlen = $rangestart+$rangelength;
435                                 
436                         // the problem is here
437                         error_log("Downloader: going ranged as other");
438                         clearstatcache();
439                         if(file_exists($filename.".tmp.data.deleteme.size")) $contentlen = file_get_contents($filename.".tmp.data.deleteme.size");
440                         else $contentlen = filesize($filename);
441                         $contenttype = mime_content_type($filename);
442                         header("HTTP/1.1 206 Partial Content");
443                         header("Content-Length: $rangelength");
444                         header("Content-Range: bytes $rangestr/$contentlen");
445                         $contenttype = "Content-Type: application/x-rpm";
446                         
447                         error_log("$contenttype");
448                         header("$contenttype");
449                         
450                         
451                         clearstatcache();
452                                 
453                                 
454                         // first we wait until the file reaches $rangestart
455                         while(filesize("$filename") < $rangestart) {
456                                 sleep(1);
457                         }
458                                 
459                         // then we open the file and ff to rangestart
460                         $localfile = fopen($filename, "r");
461                         fseek($localfile, $rangestart);
462                                 
463                         $sgotten = 0;
464                         // need to think about this in pseudo code.
465                         // 1. close the file and wait for it to get to $sgotten + 2048 or $fsize
466                         $cursize = filesize($filename);
467                                 
468                                 
469                         $upload_finished = false;
470                         while(!$upload_finished) {
471                                 while($cursize < $sgatlen && $cursize < ($sgotten+2048)) {
472                                         clearstatcache();
473                                         error_log("OTHERDOWNLOAD: halt, $cursize, $sgotten, $contentlen");
474                                         // sleep until the the filesize is greater then what we're up to, or until the file is finished
475                                         sleep(1);
476                                         $cursize = filesize($filename);
477                                 }
478
479                                 error_log("OTHERDOWNLOAD: continue, $sgotten, $contentlen");
480                                 // reopen local file - if it stopped existing, we need to deal with that
481                                 $localfile = fopen($filename, "r");
482
483                                 // UG, we need to ff, how could i forget that
484                                 fseek($localfile, $sgotten+$rangestart);
485
486                                 if(!$localfile) {
487                                         error_log("OTHERDOWNLOAD: something went plop");
488                                         return;
489                                 }
490
491                                 // now loop on the file until we have it at sgatlen
492                                 while(!feof($localfile) && $sgotten < $rangelength) {
493                                         $left = $rangelength - $sgotten;
494                                         if($left > 512) $lenget = 512;
495                                         else $lenget = $left;
496                                         $data = fread($localfile, $lenget);
497                                         if(!$data) {
498                                                 error_log("OTHERDOWNLOAD: dollar data went plop");
499                                         } else {
500                                                 $sgotten += strlen($data);
501                                                 echo $data;
502                                                 flush();
503                                         }
504                                 }
505                                 fclose($localfile);
506
507                                 if($sgotten >= $rangelength) {
508                                         if($sgotten > $rangelength) error_log("OTHERDOWNLOADER: finished but $sgotten, $fsize doesnt make senze");
509                                         $upload_finished = true;
510                                 }
511                                 // and we're done
512
513                         }
514                         error_log("OTHERDOWNLOADER: done with");
515                                 
516                         return;
517                                 
518                 }
519
520
521                 return;
522         }
523
524         function startDownload($file, $url)
525         {
526                 
527                 error_log("background downloader, start");
528                 global $WEB_ROOT_FS, $URL_HANDLERS, $BASE_URL;
529                 if(file_exists("$WEB_ROOT_FS/../bin/downloadfile.php")) {
530                         $scall = "/usr/bin/php $WEB_ROOT_FS/../bin/downloadfile.php '$url' '$file' > /tmp/dllog 2>&1 &";
531                         system($scall);
532                 } else {
533                         error_log("cant find download helper... dieing");
534                 }
535         }
536
537         // this is a nightmare
538         function getRepoForUrlOld($url)
539         {
540                 // the way we breakdown a url is to explode it
541                 $xurl = split("[/,]", $url);
542
543                 // we first check if [0] is a prefix
544                 // if now, we check for it being a shorturl (lets just do that for now)
545                 $uconf = unserialize($this->config->getConfigVar("repodata"));
546                 $repostore = $this->config->getConfigVar("storagelocation");
547
548                 $matched = -1;
549
550                 // first we check for /repo/repoid as a url
551                 $startat = 0;
552                 if($xurl[0] == "repo") {
553                         $repid = $xurl[1];
554                         error_log("trying to get repo for repoid, $repid");
555                         if(isset($uconf[$repid])) {
556                                 $matched = ((int)($repid));
557                                 error_log("set matched, $matched, $repid");
558                                 $startat +=2;
559                         }
560                 }
561
562
563                 $prematch = false;
564                 if($matched < 0) foreach($uconf as $key => $var) {
565                         $pre = $var["prefix"];
566                                 
567                         if($pre!="") {
568                                 //echo "Checking pre $pre against ".$xurl[0]."\n";
569                                 if(strcasecmp($pre, $xurl[0])==0) {
570                                         //echo "Matched pre\n";
571                                         $prematch = true;
572                                         $startat++;
573                                 }
574                         }
575                 }
576
577
578                 if($matched < 0) foreach($uconf as $key => $var) {
579                         // if we matched a pre, then we check against the second url component
580                                 
581                         $short = $var["shorturl"];
582                                 
583                         if($short!="") {
584                                 //echo "Checking short $short against ".$xurl[$startat]."\n";
585                                 if(strcasecmp($xurl[$startat], $short)==0) {
586                                         //echo "Matched\n";
587                                         $matched = $key;
588                                         $startat++;
589                                 }
590                         }
591                 }
592
593                 if($matched < 0) {
594                         echo "No such repo<br>";
595                         return;
596                 }
597
598
599                 // now we find an actual file
600                 $file = "/";
601                 if(count($xurl) > $startat) for($i=$startat; $i < count($xurl); $i++) {
602                         $file .= "/".$xurl[$i];
603                 }
604
605                 // now we want to find repostore/$matched/$file;
606                 $actualfile = "$repostore/$matched/$file";
607                 error_log("Atcualfile is $actualfile");
608                 //echo "Start file for $actualfile\n";
609
610                 // first check any directories in $file are in existence
611                 $splfile = explode("/", $file);
612                 if(count($splfile) > 1) {
613                         $tomake = "$repostore/$matched/";
614                         for($i = 0; $i < count($splfile)-1; $i++) {
615                                 $tomake .= "/".$splfile[$i];
616                                 //error_log("making directory $tomake");
617                                 if(!is_dir($tomake)) mkdir($tomake);
618                         }
619                 }
620
621                 $reqhead = print_r($_REQUEST, true);
622                 $sevhead = print_r($_SERVER, true);
623
624                 error_log("req $reqhead");
625                 error_log("sev $sevhead");
626
627                 $rangestart = -1;
628                 $rangelength = -1;
629                 $rangesstr = "";
630                 if(isset($_SERVER["HTTP_RANGE"])) {
631                         // oh shit
632                         $rangesa = explode("=", $_SERVER["HTTP_RANGE"]);
633                         $rangesb = explode(",", $rangesa[1]);
634                         $rangesstr = $rangesb[0];
635                         $ranges = explode("-", $rangesb[0]);
636                         $rangestart = $ranges[0];
637                         $rangelength = $ranges[1] - $ranges[0] +1;
638                         error_log("going ranges at $rangestart, $rangelength,".$rangesa[1].",".$rangesb[0]);
639                 }
640
641                 // i have to support http_range cause REDHAT/CENTOS IS annoying as all hell. christ, why do this?
642                 if(is_file($actualfile)) {
643                         // file is stored locally, away we go
644                         if($rangelength != -1) {
645                                 header("HTTP/1.1 206 Partial Content");
646                                 header("Content-Length: ".$rangelength);
647                                 header("Content-Range: bytes $rangesstr/".filesize($actualfile));
648                                 //header("Content-Length: ".filesize($actualfile));
649                         } else {
650                                 header("Content-Length: ".filesize($actualfile));
651                         }
652                         $type = mime_content_type($actualfile);
653                         header("Content-type: $type");
654                         $localfile = fopen($actualfile, "r");
655                         if($rangestart!=-1) fseek($localfile, $rangestart, SEEK_SET);
656                         while(!feof($localfile)) {
657                                 // cant make this high cause centos is crap
658                                 if($rangelength!=-1) {
659                                         $data = fread($localfile, $rangelength);
660                                         error_log("data size was ".strlen($data));
661                                 } else {
662                                         $data = fread($localfile, 2048);
663                                 }
664
665                                 echo $data;
666                                 flush();
667
668                                 if($rangelength!=-1) {
669                                         fclose($localfile);
670                                         exit(0);
671                                 }
672                         }
673                         fclose($localfile);
674                 } else if(is_dir($actualfile)) {
675                         //echo "in dir for $actualfile\n";
676                         // here we print the contents of the directory
677                         $this->printDir($actualfile, $file, $url);
678                 } else {
679                         // ok, get the file
680                         //echo "in getcheck\n";
681                         $remotefile = $uconf[$matched]["url"]."/$file";
682                                 
683                         // TODO: i should get remote contents with fopen/fread/fwrite as
684                         // it should be more memory conservative and we can push to the end client
685                         // straight away
686                         ignore_user_abort(true);
687                         $rf = fopen($remotefile, "r");
688                         error_log("attempting to get remote file $remotefile");
689
690                                 
691                         // hopefully this works. if we get a 30x message, it means we tried to get a directory
692                         // i cant think of another way of dealing with it - but this is UGLY
693                         // also get content length and content type
694                         $clen = 0;
695                         foreach($http_response_header as $key => $val) {
696                                 if(preg_match("/HTTP.*30[1-9].*/", $val)) {
697                                         error_log("got a 30x, must be a directory");
698                                         mkdir($actualfile);
699                                         header("Location: ".$_SERVER["REQUEST_URI"]."/");
700                                         return;
701                                 }
702                                 // get content length form upstream and print
703                                 if(preg_match("/^Content-Length:.*/", $val)) {
704                                         $clen = $val;
705                                         header($val);
706                                 }
707                                 // get content type from upstream and print
708                                 if(preg_match("/^Content-Type:.*/", $val)) {
709                                         header($val);
710                                 }
711                         }
712                         //error_log("repsonse: $http_response_header");
713                         if(!$rf) {
714                                 // return 404
715                                 header("HTTP/1.0 404 Not Found");
716                         } else {
717                                 $localfile = fopen($actualfile.".tmp.data.deleteme", "w");
718                                 $localsizefile = fopen($actualfile.".tmp.data.deleteme.size", "w");
719                                 fwrite($localsizefile, "$clen");
720                                 fclose($localsizefile);
721                                 while(!feof($rf)) {
722                                         $data = fread($rf, 8192);
723                                         echo $data;
724                                         fwrite($localfile, $data);
725                                         flush();
726                                 }
727                                 fclose($localfile);
728                                 fclose($rf);
729                                 rename($actualfile.".tmp.data.deleteme", $actualfile);
730                                 //error_log("got actualfile, tried to save as $actualfile, did it work?");
731                         }
732                 }
733
734                 //echo "got ".$file." for $url which is $actualfile\n";
735
736                 //echo "</html></pre>";
737         }
738
739         function printDir($dir, $localfile, $baseurl)
740         {
741                 $localfile = preg_replace("/\/\/+/", "/", $localfile);
742                 $uri = $_SERVER["REQUEST_URI"];
743                 $content = "";
744                 if(is_dir($dir)) {
745                         $content .= "<html><head><title>Index of $localfile</title></head><body><h1>Index of $localfile</h1>";
746                         $content .= "<table>";
747                         $dh = opendir($dir);
748                         while(($file = readdir($dh))!==false) {
749                                 if($file != "." && $file != "..") {
750                                         if(is_dir("$dir/$file")) {
751                                                 $fsize = "";
752                                                 $icon = "/icons/folder.png";
753                                         } else {
754                                                 $fsize = filesize("$dir/$file");
755                                                 $icon = "/icons/text.png";
756                                         }
757                                         $content .= "<tr><td><img src=\"$icon\"></td><td><a href=\"$uri/$file\">$file</a></td><td>$fsize</td></tr>";
758                                 }
759                         }
760                         $content .= "</table></body></html>";
761                                 
762                         GLCASpageBuilder(null, null, $content);
763                                 
764                 } else return false;
765         }
766         
767         function getRepoDetailsApt($url)
768         {
769                 $action1 = $url."/dists";
770                 
771                 // we just want to make sure it exists really
772                 error_log("in repo details apt for $url");
773                 if(!glcas_isRemoteDir($action1)) {
774                         //echo "I cant find any valid APT dists's at $url<br>";
775                         return false;
776                 }
777                 
778                 // ok, now scan for ubuntu dists as
779                 $kos = getKnownOSList();
780                 
781                 $repos = 0;
782                 $existing_repo["isrepo"] = true;
783                 foreach($kos["apt"] as $key => $val) {
784                         //echo "<br>$key, $val<br>";
785                         //echo "now check, $action1/$key";
786                         if(glcas_isRemoteDir($action1."/$key")) {
787                                 $existing_repos["knownrepo"][$repos] = $key;
788                                 $repos++;
789                                 //echo "Found Distro $val<br>";
790                         }
791                 }
792                 $existing_repos["nrepos"] = $repos;
793                 
794                 // TODO: these need to be "calculated"
795                 $existing_repos["distros"] = "Ubuntu, Debian";
796                 $existing_repos["versions"] = "8.04LTS, 9.10, 10.04LTS, 10.10, 11.04, 11.10";
797                 $existing_repos["arch"] = "x86_64, i386";
798                 
799                 
800                 return $existing_repos;
801
802         }
803
804         function getRepoDetailsYum($url, $ismirrorlist=false)
805         {
806                 $actionurl = $url."/repodata/repomd.xml";
807
808                 error_log("Getting for action of $actionurl");
809
810                 $ld = file_get_contents($actionurl);
811
812                 // so here we try and get what this repository provides (os, version, arch), for yum this
813                 // should come straight off the url... i.e. centos/6.0/os/x86_64/ (centos, 6.0, base os, 64bit arch)
814
815                 if(!$ld) return false;
816
817                 // ok, now we tokenize the url and try and guess at the content
818                 $spurl = explode("/", $url);
819
820                 // first, find the OS
821                 $kos = getKnownOSList();
822                 $glt["OS"] = "unknown";
823                 $glt["verison"] = "unknown";
824                 $glt["arch"] = "unknown";
825                 $glt["other"] = "unknown";
826                 foreach($spurl as $comp) {
827                                 
828                         // find a name
829                         foreach($kos["os"]["short"] as $kosname => $koslong) {
830                                 //error_log("Comparing $kosname and $koslong with $comp");
831                                 if(strcasecmp($kosname, $comp) == 0) {
832                                         //error_log("got $kosname, $koslong for $comp in $url");
833                                         //echo "<pre>inone\n"; print_r($koslong); echo "</pre>";
834                                         $glt["OS"] = $koslong;
835                                 }
836                         }
837                                 
838                         // find a version, we assume its going to be something [numbers] and a . (optional)
839                         if(preg_match("/^[0-9.]+$/", $comp)>0) {
840                                 //error_log("version match of $comp");
841                                 $glt["version"] = $comp;
842                         }
843                                 
844                         // now architecture, this can be either i?86 or x86_64 - can also be arm or otherwise, but lets just go with this for now
845                         foreach($kos["arch"] as $archinter => $archname ) {
846                                 //error_log("Comparing $archinter, $archname with $comp");
847                                 if(strcasecmp($archname, $comp) == 0) {
848                                         //error_log("arch match of $archname with $comp");
849                                         $glt["arch"] = $archname;
850                                 }
851                         }
852                                 
853                         // other is a bt harder, we really have to guess at this one
854                         if(strcasecmp("os", $comp) == 0) $glt["other"] = "OS";
855                         if(strcasecmp("update", $comp) == 0) $glt["other"] = "Updates";
856                         if(strcasecmp("updates", $comp) == 0) $glt["other"] = "Updates";
857                         if(strcasecmp("everything", $comp) == 0) $glt["other"] = "OS";
858                 }
859
860                         
861                 return $glt;
862         }
863
864         function deleteRepo($rkey)
865         {
866                 $uconf = $this->config->getConfigVar("repodata");
867                 $repostore = $this->config->getConfigVar("storagelocation");
868
869                 if($uconf !== false) {
870                         $conf = unserialize($uconf);
871                         foreach($conf as $key => $vla) {
872                                 if($key == $rkey) {
873                                         unset($conf["$rkey"]);
874                                         $nconf = serialize($conf);
875                                         system("rm -rf $repostore/$key");
876                                         error_log("remove repo as $rkey");
877                                         $this->config->setConfigVar("repodata", $nconf);
878                                         $this->config->saveConfig();
879                                 }
880                         }
881                 }
882         }
883
884         function addRepo($desc, $os, $version, $arch, $other, $shorturl, $prefix, $repurl, $repotype, $init, $expiretime)
885         {
886                 $uconf = $this->config->getConfigVar("repodata");
887
888                 $cs["desc"] = $desc;
889                 $cs["os"] = $os;
890                 $cs["version"] = $version;
891                 $cs["arch"] = $arch;
892                 $cs["other"] = $other;
893                 $cs["shorturl"] = $shorturl;
894                 $cs["prefix"] = $prefix;
895                 $cs["url"] = $repurl;
896                 $cs["repotype"] = $repotype;
897                 $cs["expiretime"] = $expiretime;
898
899
900                 $ckey = 0;
901                 if($uconf !== false) {
902                         $conf = unserialize($uconf);
903                         foreach($conf as $key => $val) {
904                                 $ckey = $key;
905                         }
906                         $ckey++;
907                 }
908
909                 $conf[$ckey] = $cs;
910
911                 $nconf = serialize($conf);
912
913                 error_log("add repo as $ckey");
914                 $this->config->setConfigVar("repodata", $nconf);
915                 $this->config->saveConfig();
916
917                 // now create the base structure in the repo
918                 $repostore = $this->config->getConfigVar("storagelocation");
919
920
921                 // now call update repo
922                 if($init) $this->updateRepoYum($ckey);
923         }
924
925         function updateRepo($repokey)
926         {
927                 // we only do yum yet
928                 $this->updateRepoYum($repokey);
929         }
930
931         function updateRepoYum($repokey)
932         {
933                 $repostore = $this->config->getConfigVar("storagelocation");
934
935                 $repod = $this->getRepo($repokey);
936
937                 $repourl = $repod["url"];
938
939                 if(!file_exists("$repostore/$repokey")) {
940                         mkdir("$repostore/$repokey");
941                 }
942
943                 if(!file_exists("$repostore/$repokey/repodata")) {
944                         mkdir("$repostore/$repokey/repodata");
945                 }
946                 
947                 error_log("background yum repo update, start");
948                 global $WEB_ROOT_FS, $URL_HANDLERS, $BASE_URL;
949                 if(file_exists("$WEB_ROOT_FS/../bin/downloadfile.php")) {
950                         $scall = "/usr/bin/php $WEB_ROOT_FS/../bin/updateyumrepo.php '$repourl' '$repostore/$repokey/' > /tmp/updateyumrepo.$repokey.log 2>&1 &";
951                         system($scall);
952                 } else {
953                         error_log("cant find download yum helper... dieing");
954                 }
955                 
956
957                 //ignore_user_abort(true);
958         }
959
960         function getRepo($id)
961         {
962                 $uconf = $this->config->getConfigVar("repodata");
963                 if($uconf !== false) {
964                         $lconf = unserialize($uconf);
965                         return $lconf[$id];
966                 } else return false;
967
968         }
969
970         function getRepos()
971         {
972                 $uconf = $this->config->getConfigVar("repodata");
973                 if($uconf !== false) {
974                         return unserialize($uconf);
975                 } else return false;
976
977         }
978
979         private $config;
980 }
981
982 ?>