Index: trunk/FACT++/www/showlog/index.css
===================================================================
--- trunk/FACT++/www/showlog/index.css	(revision 15375)
+++ trunk/FACT++/www/showlog/index.css	(revision 15375)
@@ -0,0 +1,81 @@
+.up {
+    cursor:pointer;
+    padding:0 5px 4px 7px;
+    position:fixed;
+    top:0;
+    right:0;
+    text-decoration:underline;
+    color:navy;
+    background-color:#ebe7e6;
+}
+
+.dn {
+    cursor:pointer;
+    padding:0 5px 4px 7px;
+    padding-top:0px;
+    position:fixed;
+    bottom:0;
+    right:0;
+    text-decoration:underline;
+    color:navy;
+    background-color:#ebe7e6;
+}
+
+#nav {
+    position:fixed;
+    right:80px;
+    top:0;
+    background-color:#ebe7e6;
+}
+
+#nav ul {
+    list-style-type:none;
+    margin:0;
+    padding:0;
+}
+
+#nav li {
+    float:left;
+    padding:0;
+    margin:0;
+}
+
+#nav li a {
+    padding:0 9px 4px 11px;
+    display:block;
+    color:#000; 
+    color:navy;
+    text-decoration:none; 
+    solid #ccc; 
+}
+
+#nav li a:hover { 
+    color:#f00; 
+}
+
+#nav ul ul {
+    display:none; 
+    position:absolute; 
+    z-index:999; 
+}
+
+#nav li li { 
+    float:none; 
+}
+
+#nav li li a { 
+    background:#EBE7E6!important; 
+    text-align:left; 
+    height:auto; 
+    line-height:1; 
+    width:auto; 
+    padding:4px 20px 4px 22px; 
+    border:1px solid #D0D0D0; 
+    border-top:none; 
+    margin-right:0; 
+}
+
+/* IE6 Bugfix... */
+* html li li { 
+    display:inline; 
+} 
Index: trunk/FACT++/www/showlog/index.php
===================================================================
--- trunk/FACT++/www/showlog/index.php	(revision 15375)
+++ trunk/FACT++/www/showlog/index.php	(revision 15375)
@@ -0,0 +1,427 @@
+<?php
+
+require_once("../smartfact/config.php");
+
+function login()
+{
+    global $ldaphost;
+    global $baseDN;
+    global $groupDN;
+
+    $username = $_SERVER['PHP_AUTH_USER'];
+    $password = $_SERVER['PHP_AUTH_PW'];
+
+    $con = @ldap_connect($ldaphost);
+    if (!$con)
+        return "ldap_connect failed to ".$ldaphost;
+
+    //------------------ Look for user common name
+    $attributes = array('cn', 'mail');
+    $dn         = 'ou=People,'.$baseDN;
+    $filter     = '(uid='.$username.')';
+
+    $sr = @ldap_search($con, $dn, $filter, $attributes);
+    if (!$sr)
+        return "ldap_search failed for dn=".$dn.": ".ldap_error($con);
+
+    $srData = @ldap_get_entries($con, $sr);
+    if ($srData["count"]==0)
+        return "No results returned by ldap_get_entries for dn=".$dn.".";
+
+    $email         =$srData[0]['mail'][0];
+    $userCommonName=$srData[0]['cn'][0];
+    $userDN        =$srData[0]['dn'];
+
+    //------------------ Authenticate user
+    if (!@ldap_bind($con, $userDN, $password))
+        return "ldap_bind failed: ".ldap_error($con);
+
+    //------------------ Check if the user is in FACT ldap group
+    $attributes= array("member");
+    $filter= '(objectClass=*)';
+
+    // Get all members of the group.
+    $sr = @ldap_read($con, $groupDN, $filter, $attributes);
+    if (!$sr)
+        return "ldap_read failed for dn=".$groupDN.": ".ldap_error($con);
+
+    // retrieve the corresponding data
+    $srData = @ldap_get_entries($con, $sr);
+    if ($srData["count"]==0)
+        return "No results returned by ldap_get_entries for dn=".$dn.".";
+
+    @ldap_unbind($con);
+
+    $found = false;
+    foreach ($srData[0]['member'] as $member)
+        if (strpos($member, "cn=".$userCommonName.",")===0)
+            return "";
+
+    return "Sorry, your credentials don't match!";
+}
+
+/*
+function ascii2entities($string)
+{
+    for ($i=128; $i<256; $i++)
+    {
+        $entity  = htmlentities(chr($i), ENT_QUOTES, 'cp1252');
+        $temp    = substr($entity, 0, 1);
+        $temp   .= substr($entity, -1, 1);
+        $string  = str_replace(chr($i), $temp!='&;'?'':$entity, $string);
+    }
+    return $string;
+}
+*/
+
+function ansi_decode($matches)
+{
+    static $colors =
+        array(
+              'black',
+              'maroon',
+              'green',
+              'olive',
+              'navy',
+              'purple',
+              'teal',
+              'silver',
+              'gray',
+              'red',
+              'lime',
+              'yellow',
+              'blue',
+              'fuchsia',
+              'aqua',
+              'white'
+             );
+
+    // Default styles.
+    static $styles =
+        array(
+              'background'   => null,  // Default is defined by the stylesheet.
+              'blink'        => false,
+              'bold'         => false,
+              'color'        => null,  // Default is defined by the stylesheet.
+              //'inverse'      => false, // Cannot be expressed in terms of CSS!
+              'italic'       => false, // Not supported by DarkOwl's ANSI.
+              'line-through' => false, // Not supported by DarkOwl's ANSI.
+              'underline'    => false,
+             );
+
+    static $css = '';
+
+    // Copy the previous styles.
+    $newstyles = $styles;
+    // Extract the codes from the escape sequences.
+    preg_match_all('/\d+/', $matches[0], $matches);
+
+    // Walk through the codes.
+    foreach ($matches[0] as $code)
+    {
+        switch ($code)
+        {
+        case '0':
+            // Reset all styles.
+            $newstyles['background']   = null;
+            $newstyles['blink']        = false;
+            $newstyles['bold']         = false;
+            $newstyles['color']        = null;
+            //              $newstyles['inverse']      = false;
+            $newstyles['italic']       = false;
+            $newstyles['line-through'] = false;
+            $newstyles['underline']    = false;
+            break;
+
+        case '1':
+            // Set the bold style.
+            $newstyles['bold'] = true;
+            break;
+
+        case '3':
+            // Set the italic style.
+            $newstyles['italic'] = true;
+            break;
+
+        case '4':
+        case '21': // Actually double underline, but CSS doesn't support that yet.
+            // Set the underline style.
+            $newstyles['underline'] = true;
+            break;
+
+        case '5':
+        case '6': // Actually rapid blinking, but CSS doesn't support that.
+            // Set the blink style.
+            $newstyles['blink'] = true;
+            break;
+
+//          case '7':
+//              // Set the inverse style.
+//              $newstyles['inverse'] = true;
+//              break;
+
+        case '9':
+            // Set the line-through style.
+            $newstyles['line-through'] = true;
+            break;
+
+        case '2': // Previously incorrectly interpreted by Pueblo/UE as cancel bold, now still supported for backward compatibility.
+        case '22':
+            // Reset the bold style.
+            $newstyles['bold'] = false;
+            break;
+
+        case '23':
+            // Reset the italic style.
+            $newstyles['italic'] = false;
+            break;
+
+        case '24':
+            // Reset the underline style.
+            $newstyles['underline'] = false;
+            break;
+
+        case '25':
+            // Reset the blink style.
+            $newstyles['blink'] = false;
+            break;
+
+//          case '27':
+//              // Reset the inverse style.
+//              $newstyles['inverse'] = false;
+//              break;
+
+        case '29':
+            // Reset the line-through style.
+            $newstyles['line-through'] = false;
+            break;
+
+        case '30': case '31': case '32': case '33': case '34': case '35': case '36': case '37':
+            // Set the foreground color.
+            $newstyles['color'] = $code - 30;
+            break;
+
+        case '39':
+            // Reset the foreground color.
+            $newstyles['color'] = null;
+            break;
+
+        case '40': case '41': case '42': case '43': case '44': case '45': case '46': case '47':
+            // Set the background color.
+            $newstyles['background'] = $code - 40;
+            break;
+
+        case '49':
+            // Reset the background color.
+            $newstyles['background'] = null;
+            break;
+
+        default:
+            // Unsupported code; simply ignore.
+            break;
+        }
+    }
+
+    // Styles are effectively unchanged; return nothing.
+    if ($newstyles === $styles)
+        return '';
+
+    // Copy the new styles.
+    $styles = $newstyles;
+    // If there's a previous CSS in effect, close the <span>.
+    $html = $css ? '</span>' : '';
+    // Generate CSS.
+    $css = '';
+
+    // background-color property.
+    if (!is_null($styles['background']))
+        $css .= ($css ? ';' : '') . "background-color:{$colors[$styles['background']]}";
+
+    // text-decoration property.
+    if ($styles['blink'] || $styles['line-through'] || $styles['underline'])
+    {
+        $css .= ($css ? ';' : '') . 'text-decoration:';
+
+        if ($styles['blink'])
+            $css .= 'blink';
+
+        if ($styles['line-through'])
+            $css .= 'line-through';
+
+        if ($styles['underline'])
+            $css .= 'underline';
+    }
+
+    // font-weight property.
+    if ($styles['bold'] && is_null($styles['color']))
+        $css .= ($css ? ';' : '') . 'font-weight:bold';
+
+    // color property.
+    if (!is_null($styles['color']))
+        $css .= ($css ? ';' : '') . "color:{$colors[$styles['color'] | $styles['bold'] << 3]}";
+
+    // font-style property.
+    if ($styles['italic'])
+        $css .= ($css ? ';' : '') . 'font-style:italic';
+
+    // Generate and return the HTML.
+    if ($css)
+        $html .= "<span style=\"$css\">";
+
+    return $html;
+}
+
+function ansi2html($str)
+{
+    // Replace database strings
+    $str = preg_replace("/\ (([[:word:].-]+)(:[^ ]+)?(@))?([[:word:].-]+)(:([[:digit:]]+))?(\/([[:word:].-]+))/", " $2$4$5$8", $str);
+
+    // Replace special characters to their corresponding HTML entities
+    //$str = ascii2entities($str);
+    $str = htmlentities($str, ENT_NOQUOTES);
+
+    // Replace ANSI codes.
+    $str = preg_replace_callback('/(?:\e\[\d+(?:;\d+)*m)+/', 'ansi_decode', "$str\033[0m");
+
+    // Strip ASCII bell.
+    // $str = str_replace("\007", '', $str);
+
+    // Replace \n
+    // $str = str_replace("\n", "<br/>\n", $str);
+
+    // Return the parsed string.
+    return $str;
+}
+
+if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW']))
+{
+    header('WWW-Authenticate: Basic realm="SmartFACT++"');
+    header('HTTP/1.0 401 Unauthorized');
+    return;
+}
+
+$rc = login();
+if ($rc!="")
+    return header('HTTP/1.0 401 '.$rc);
+
+$refresh = isset($_GET['refresh']) ? $_GET['refresh'] : -1;
+if ($refresh>0 && $refresh<60)
+   $refresh = 60;
+
+unset($_GET['refresh']);
+
+$prg = empty($_GET['log']) ? "dimserver" : $_GET['log'];
+$dir = $_GET['dir'];
+
+if (!strpos($prg, "/")===false || !strpos($dir, "/")===false)
+    return header('HTTP/1.0 403 Access forbidden.');
+
+if (empty($dir))
+{
+    if ($prg=="schedule")
+        $prg = "scripts/schedule.js";
+
+    $filename = "/users/fact/operation/".$prg;
+    if (is_link($filename))
+        $filename = "/users/fact/operation/".dirname(readlink($filename))."/".$prg.".log";
+}
+
+if (empty($filename))
+    $filename = "/users/fact/".$dir."/".$prg.".log";
+
+$size = filesize($filename);
+if ($size>30000000) // 30MB
+    return header('HTTP/1.0 403 File too large.');
+
+// FIXME: Reading the file line by line avoids any danger that
+//        something yields a problem if files grow too large
+$file = file($filename);
+if ($file===false)
+    return header('HTTP/1.0 403 Access forbidden.');
+
+$max = 10000;
+$pos = 500;
+$n = count($file);
+if ($n>$max)
+{
+    $file[$pos] = "\n<b>[...]</b>\n\n";
+    array_splice($file, $pos+1, $n-$max);
+}
+
+$dir  = basename(dirname($filename));
+$name = basename($filename);
+
+?>
+<!DOCTYPE HTML>
+<html>
+<head>
+<?php
+if ($refresh>0)
+   print("<meta http-equiv='refresh' content='".$refresh."'>\n");
+?>
+<meta charset="UTF-8">
+<title><?php print($dir." - ".$name);?></title>
+<link rel="stylesheet" type="text/css" href="showlog.css" />
+<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" type="text/javascript"></script>
+<script>
+function scroll(top)
+{
+   document.getElementById(top?'top':'bottom').scrollIntoView(top);
+}
+$(document).ready(function() {
+	$("#nav li:has(ul)").hover(function(){
+		$(this).find("ul").slideDown(200);
+	}, function(){
+		$(this).find("ul").hide();
+	});
+});
+</script>
+</head>
+<body onload="setTimeout(function(){scroll(false);},1);">
+<span onclick="scroll(true);" class="up">go to top &uarr;</span>
+<span id="nav">
+   <ul>
+      <li>
+	 <a>Logs</a>
+            <ul>
+	       <li><a href="?log=biasctrl">biasctrl</a></li>
+	       <li><a href="?log=agilentctrl">agilentctrl</a></li>
+	       <li><a href="?log=chatserv">chatserv</a></li>
+	       <li><a href="?log=datalogger">datalogger</a></li>
+	       <li><a href="?log=dimserver"><b>dimserver</b></a></li>
+	       <li><a href="?log=dimctrl">dimctrl</a></li>
+	       <li><a href="?log=drivectrl">drivectrl</a></li>
+	       <li><a href="?log=fadctrl">fadctrl</a></li>
+	       <li><a href="?log=feedback">feedback</a></li>
+	       <li><a href="?log=fscctrl">fscctrl</a></li>
+	       <li><a href="?log=ftmctrl">ftmctrl</a></li>
+	       <li><a href="?log=lidctrl">lidctrl</a></li>
+	       <li><a href="?log=magiclidar">magiclidar</a></li>
+	       <li><a href="?log=magicweather">magicweather</a></li>
+	       <li><a href="?log=mcp">mcp</a></li>
+	       <li><a href="?log=pwrctrl">pwrctrl</a></li>
+	       <li><a href="?log=ratecontrol">ratecontrol</a></li>
+	       <li><a href="?log=ratescan">ratescan</a></li>
+	       <li><a href="?log=temperature">temperature</a></li>
+	       <li><a href="?log=timecheck">timecheck</a></li>
+	       <li><a href="?log=tngweather">tngweather</a></li>
+            </ul>
+      </li>
+   </ul>
+</span>
+</span>
+<span onclick="scroll(false);" class="dn">go to bottom &darr;</span>
+
+
+<H2 id="top"><?php printf("%s - %s   (%dkB)", $dir, $name, $size/1000);?></H2>
+
+<pre style="font-size:small;font-family:'Lucida Console',Monaco,monospace">
+<?php
+foreach ($file as $line)
+    print(ansi2html(substr($line, 0, -1))."\n");
+?>
+
+</pre>
+<span id="bottom"></span>
+</body>
+</html>
