<?
// command.php
//
// Copyright, Exolution GmbH / Michael Kerrisk, Sep 2000
// http://www.exolution.com/wapsh   mailto:wapsh@exolution.de
// 
// This software is Open Source licensed under the terms of the Trolltech QPL
// version 1.0.  See http://www.exolution.de/wapsh for further information.
//
// -------------------------------------------------------------------
//
// This is the main page for displaying shell output and reading shell input.
//
//
    require("common.inc");
    require("getloginhosts.inc");

    if (isset($ctype)) {
        $clientType = $ctype;
    }

    // Produce header dependent on client type

    if ($clientType == "http") {
        header("Content-type: text/html");
    } else {
        header("Content-type: text/vnd.wap.wml");
    }  
    require("displayfuncs.inc");
    if ($clientType == "http") {
        require("command_html.inc");
        require("common_html.inc");
?>
<html>
<head>
        <title><? echo SYSTEM_NAME; ?> Command</title>
</head>

<body bgcolor="<? echo BODY_BGCOLOR; ?>">

<?
    } else {	// "wap"
        require("common_wml.inc");
    
    echo '<?xml version="1.0" encoding="iso-8859-1"?>';
?><!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">

<wml>

<card title="<? echo SYSTEM_NAME; ?> <? echo isUpPhone() ? "output" : "main"; ?>" 
        newcontext="true" id="main">

<?
        //print sParaBlk("User agent is " . $GLOBALS["HTTP_USER_AGENT"]);
        //print sParaBlk("isUpPhone: " . isUpPhone());
   } // if 
/*
    foreach ($GLOBALS as $k => $v) {
        //if (ereg("[a-z]", $k))
        print "<p>$k=$v</p>";
    }
*/
    //print sParaBlk("Client type is /" . $clientType . "/");
    //print sParaBlk("Ctype is /" . $ctype . "/");
    //print sParaBlk("SID is " . SID);
    //print sParaBlk("Snid is " . session_name() . " = " . session_id());

    //
    // Apache(?) uses backslashes to quote incoming parameter values
    // Remove them.
    //
    if (isset($shCmd))
        $shCmd = stripslashes($shCmd);
    if (isset($shPwd))
        $shPwd = stripslashes($shPwd);
    if (isset($srchStr))
        $srchStr = stripslashes($srchStr);
    if (isset($ctrlChar))
        $ctrlChar = stripslashes($ctrlChar);
    
    //
    // If $username is set, then this is an attempt to login, so send username
    // plus password to MCS, and then check response to
    // see whether we were authenticated
    //
    $justLoggedIn = false;	// Set true on login to force us to fetch 
                                // initial shell output (from startup scripts, 
    				// initial shell prompt)

    if (isset($username)) { 

        $authenticated = 0;
        $cmdNum = 0;
        $socketPort = 0;
        $authKey = "";
        $shellTimeout = 0;
        $setOptions = 0;
        $numSc = 0;
        $outputBuf = "";
        $outputBufLen = 0;
        $outputPos = 0;
        $lastOutputBlockSize = 0;
        $lastSearchPos = INVALID_POS;
        unset($lastSrchStr);
        $outputBufferLimit = DEF_OUTPUT_BUFFER_LIMIT;
        $outputWindowSize = DEF_OUTPUT_WINDOW_SIZE;
        $historyBlockSize = DEF_HISTORY_BLOCK_SIZE;
        $shortcutBlockSize = DEF_SHORTCUT_BLOCK_SIZE;
        unset($hostAddress);
    
        // Get list of loginhosts
        // If there is no list, then user can only log in on localhost
        // (i.e. HTTP Server must be on same machine as htshd).  If list
        // contains just one host, then user must login on that host,
        // so we ignore any hhostname specified with the HTTP request.
        // If more than one host is supplied in host list, then
        // we must check that the one supplied in the HTTP request 
        // is part of the list.
            
        getLoginHosts($numHosts, $loginHostList, $loginAddressList);
    
        switch ($numHosts) {
    
        case 0:
            $hostAddress = "localhost";
            break;
    
        case 1:
            $hostAddress = $loginAddressList[0];
            break;
    
        default:
            if (!isset($host)) $host = "localhost";
            
            for ($j = 0; $j < $numHosts; $j++) {
                //echo "<P>checking $loginHostList[$j]</p>";
                if ($host == $loginHostList[$j]) {
                    $hostAddress = $loginAddressList[$j];
                    break;
                } // if
            } // for 
            break;
        } // switch  
    
        //$hostAddress = $hostAddr;
    
        if (!isset($hostAddress)) {
            echo sParaBlk(sBoldBlk(sFontBlk('size="+1" color="red"', 
                            "Logins not permitted on '" . $host . "'")));
        } else {
    
            // Open a socket to the Login Server, send login credentials
            
            $portNum = getservbyname(SERVICE_NAME, "tcp");
            //print sParaBlk("Port for " . SYSTEM_NAME . " is $portNum");
            if ($portNum == false) 
                echo sParaBlk(sBoldBlk(sFontBlk('size="+1" color="red"', 
                                "'" . SYSTEM_NAME . 
                                "' is not defined in /etc/services")));
            
            $fd = fsockopen($hostAddress, $portNum, &$errno, &$errstr);
            if (!$fd) {
                echo sParaBlk(sBoldBlk(sFontBlk('size="+1" color="red"',  
                                'Cannot login because access to the remote ' . 
                                'server failed (reason: "' . 
                                escBrowserSpecialChars($errstr) . 
                                '"). Contact your system administrator to ' . 
                                'check that ' .  sEmphBlk(SYSTEM_NAME) .  
                                ' is currently installed and running. ' 
                            )));
            } else {
    
                // Send username + password + clientType + user agent, and read 
                // complete response string into $buf
                
                fputs($fd, $username . "\0" . $password . "\0" . 
                        $clientType . "\0" . $GLOBALS["HTTP_USER_AGENT"]);
        
                $buf = "";
                while (!feof($fd)) {
                    $buf .= fread($fd, 300);
                } // while
                /*
                print "<p>" . str_replace("\0", sBreak(), 
                                escBrowserSpecialChars($buf)) . "</p>";
                */
                fclose($fd);
    
                // Each line of output is of the form "name=string", getNext()
                // breaks line into these two parts
                
                function getNext(&$buf, &$name, &$value) {
        		    list($nl, $buf) = explode("\0", $buf, 2);
        		    list($name, $value) = explode("=", $nl, 2);
                } 
    
                // First line of output tells us if we logged in successfully
                
                getNext($buf, $name, $loginStatus);
    
                if ($loginStatus < 0) {
                    getNext($buf, $name, $msg);
            	    echo sParaBlk(sFontBlk('size="+2" color="red"',
                                "Login failed: " . newline2break($msg)));
                    $authenticated = 0;	// Make sure
    
                    logMsg("$username login on $hostAddress failed: $msg");
                } else {
                
                    logMsg("$username login on $hostAddress succeeded");
    
                    $authenticated = 1;
                    // echo sParaBlk(sBoldBlk("Welcome to " . SYSTEM_NAME));
                    // Following lines of response contain:
                    //
                    //	Socket port number (*)
                    //	Authorisation key (*)
                    //	(Octal) bitmask indicating options set by "set" command
                    //		in the initialisation file (*)
                    //	Counter of number of command shortcuts (*)
                    //	Series of lines, containing one shortcut 
                    //		name per line (The number of these lines
                    //		is specified by previous parameter) (*)
                    //	'set' variables (from the .htshrc file), one per line 
                    //		(terminated by end of buffer)
                    //
                    // Although each of the lines of the response is of the form
                    // NAME=VALUE, the names are of the options marked (*)
                    // are (currently) ignored - the lines are expected 
                    // in fixed order.
                    
                    getNext($buf, $name, $socketPort);
                    //print "<p>socketPort=$socketPort</p>";
    
                    getNext($buf, $name, $authKey);
                    //print "<p>authKey=$authKey</p>";
    
                    getNext($buf, $name, $shellTimeout);
                    //print "<p>shellTimeout=$shellTimeout</p>";
    
                    getNext($buf, $name, $so);
                    list($setOptions) = sscanf($so, "%o");
                    //print "<p>setOptions=$setOptions</p>";
    
                    // Next come shortcuts.  numSc tells us how many there are
                    
                    getNext($buf, $name, $numSc);
                    //print "<p>numSc=$numSc</p>";
    
                    for ($j = 0; $j < $numSc; $j++) {
                        getNext($buf, $name, $scName[$j]);
                        //print "<p>scName[$j]=$scName[$j]</p>";
                    } // for 
    
                    // Now come settings of option values
                    // Here, we do take account of the name part of line
                    
                    while ($buf != "") {
                        getNext($buf, $name, $value);
                        //print "<p>Got name-val pair: $name=$value</p>";
                        if ($name == SN_OUTPUTWINDOWSIZE) 
                            $outputWindowSize = $value;
                        else if ($name == SN_HISTORYBLOCKSIZE) 
                            $historyBlockSize = $value;
                        else if ($name == SN_SHORTCUTBLOCKSIZE) 
                            $shortcutBlockSize = $value;
                        else if ($name == SN_OUTPUTBUFFERLIMIT) 
                            $outputBufferLimit = $value;
                        else if ($name == SN_CSMAXTRANSFERSIZE) 
                            $csMaxTransferSize = $value;
                        else if ($name == SN_CSOUTPUTTIMEOUT) 
                            $csOutputTimeout = $value;
                        else if ($name == SN_WAPBROWSERSTYLE) 
                            $wapBrowserStyle = $value;
                        else if ($name == SN_SHELLTIMEOUT) 
                            $shellTimeout = $value;
                        else if ($name == SN_ALLOWEDPROTOCOLS) 
                            $allowedProtocols = $value;
                        else 
                            echo sParaBlk(
                                    SYSTEM_NAME . ": Ignoring unrecognised " . 
                                    "name-value pair: " . $name);
                    } // while

		    if ($setOptions & OPT_SESSIONLOGGING) 
                        echo sParaBlk(sBoldBlk(SYSTEM_NAME . 
				    ": This session is being logged"));
    
                    //print sParaBlk("We just logged in");
                } // if 
            } // if 
        } // if

        if ($authenticated)
    	    $justLoggedIn = true;
    } // if 

    //
    // Once we are authenticated, then user is allowed to do things!
    //
    
    if ($authenticated) {
    
        if (isset($clrHist)) {		// From history_*.php page
            $cmdNum = 0;
    
    	} else if (isset($cmdForm) || $justLoggedIn) {

            $outputPos += $lastOutputBlockSize;
            $expectResponse = true;	// Indicates that we expect some
            				// output from CCS in response to 
            				// this command

            // We have a form which requires sending output to remote CCS
            
            // print "<p>Command form submitted</p>";

            // First we must establish a socket connection to the CCS.
            // If this fails, we're in trouble - either the
            // remote CCS went down, or the the entire system has crashed
            //
            //print "<p>Port: $socketPort</p>";
            
            $fd = fsockopen($hostAddress, $socketPort, &$errno, &$errstr);

            if (!$fd) {
                echo sParaBlk(sBoldBlk(
                        sFontBlk('size="+1" color="red"', 
                        'Input could not be transmitted to ' .
                        'to the remote shell at "' . $hostAddress . '"' . 
                        ' (reason: "' . 
                        escBrowserSpecialChars($errstr) . '"). ' . 
                        'This is probably because your login session timed ' . 
                        'out (the timeout is ' . $shellTimeout . ' seconds), ' .
                        'or may be because the remote server has died. ' .
                        sBreak() . sBreak() . 
                        'If this problem recurs, try ' .
                        sAnchor(loginPage(), "logging in") .  ' again'
                        )));
                
            } else {	// Successfuly established socket connection

                if (isset($sendCmd) || isset($repPrev)) {
                    
                    // We've got input to send to the CCS shell
                    
                    // If we are asked to repeat a previous command,
                    // fetch it from history.  If there is no history,
                    // we should never get here, but in case, we will just send 
                    // a null input.

                    if (isset($repPrev)) {
                        //print "<p>Repeat previous command</p>";
                        if ($cmdNum >= 1 && ($setOptions & OPT_HISTORY) != 0) {
                            // print "<p>Repeat previous</p>";
                            $shCmd = $histCmd[$cmdNum];
                            $silent = $histSilent[$cmdNum];
                            $addNl = $histAddNl[$cmdNum];
                        } else {
                            $shCmd = "";
                            $silent = false;
                            $addNl = false;
                        } // if
                    } // if
                    
                    //
                    // Take the shell command and "cook" it if necessary,
                    // by adding " > /dev/null " if the 'silent' option
                    // was specified, and a trailing newline,
                    // unless the 'Add newline' option was unchecked.
                    
                    if (isset($shPwd) && $shPwd != "") 
                        $cookedShCmd = $shPwd;
                    else
                        $cookedShCmd = $shCmd;
                    //print "<p>Raw shell command: $cookedShCmd</p>";

                    // For those phones with a limited input character set,
                    // we can do trigraphs!

                    if ($setOptions & OPT_ALLOWTRIGRAPHS) {
                        $cookedShCmd = 
                            	str_replace("??=", "#",
                            	str_replace("??(", "[",
                            	str_replace("??)", "]",
                            	str_replace("??/", "\\",
                            	str_replace("??'", "^",
                            	str_replace("??<", "{",
                            	str_replace("??>", "}",
                            	str_replace("??!", "|",
                            	str_replace("??-", "~", $cookedShCmd)))))))));
                    } // if
                    
                    if (isset($silent) && $silent == "y" && 
                            	strlen($shCmd) > 0)
            	        $cookedShCmd .= " > /dev/null";
                    if (isset($addNl) && $addNl == "y") 
            	        $cookedShCmd .= "\n";
                    
                    if (strlen($cookedShCmd) == 0) {
                        echo sParaBlk(sBoldBlk(SYSTEM_NAME . 
                                    ": Ignoring empty input"));
                        $expectResponse = false;
                    } else {
                        //
                        // Send the command to the CCS
                        //
                        
                        $len = strlen($cookedShCmd);
                        $sl = sprintf("%04d", $len);
                        //print "<p>Shell command cmdNum=$cmdNum: " . 
                        //	escBrowserSpecialChars($cookedShCmd) . " $sl</p>";
    
                        fwrite($fd, $authKey . CMD_SHELLCMD . $sl . 
                                $cookedShCmd);
            
                        //
                        // If the command wasn't empty, and it wasn't a repeat
                        // of the previous command, add it to our history
                        //
                        if (strlen($shCmd) > 0 && 
                                ($cmdNum == 0 || $shCmd != $histCmd[$cmdNum])) {
                            $cmdNum++;
                            $histCmd[$cmdNum] = $shCmd;
                            $histSilent[$cmdNum] = $silent;
                            $histAddNl[$cmdNum] = $addNl;
                        } /* if */
                    } /* if */

                } else if (isset($chkOut) || $justLoggedIn) {
                    //
                    // Send a null message to CCS, so that we can get 
                    // any buffered output 
                    //
                    //print "<p>Checking for output.</p>";
                    fwrite($fd, $authKey . CMD_NULL);

                } else if (isset($logout)) {

                    // Send a logout message to the CCS
                
                    echo sParaBlk("Thanks and bye.");
                    $authenticated = 0;
                    fwrite($fd, $authKey . CMD_CLOSE);
                
                } else if (isset($doShCut)) {

                    // User selected a shortcut command.  Send the shortcut 
                    // command number to the CCS.
                
                    if ($shortcutCmd == "") {
                    	echo sParaBlk(sBoldBlk(SYSTEM_NAME . 
                                    ": Invalid shortcut"));
                        $expectResponse = false;
                    } else {
                        $sl = sprintf("%04d", $shortcutCmd);
                        //print "<p>Executing shortcut: " . escBrowserSpecialChars($sl) . "</p>";
                        fwrite($fd, $authKey . CMD_SHORTCUT . ($sl));
                    } // if
/* CURRENTLY UNUSED - this functionality is provided by sending
   appropriate control chars to the Login Host

                } else if (isset($sigquit) || isset($sigint) || 
            		    isset($sigstop)) {

                    // Send a signal to the CCS

                    $sl = sprintf("%04d", isset($sigstop) ? 20 : 
            				        (isset($sigquit) ? 3 : 2));
                    //print "<p>Sending signal: $sl</p>";
                    fwrite($fd, $authKey . CMD_SIGNAL . ($sl));
END UNUSED */
                } else if (($setOptions & OPT_ALLOWCONTROLCHARS) && 
                                isset($eofChar)) {
                    //print "<p>Sending EOF</p>";
                    fwrite($fd, $authKey . CMD_CONTROL . "D");

                } else if (($setOptions & OPT_ALLOWCONTROLCHARS) && 
                                isset($suspChar)) {
                    //print "<p>Sending SUSPEND</p>";
                    fwrite($fd, $authKey . CMD_CONTROL . "Z");
                    
                } else if (($setOptions & OPT_ALLOWCONTROLCHARS) && 
                                isset($escChar)) {
                    //print "<p>Sending ESCAPE</p>";
                    fwrite($fd, $authKey . CMD_CONTROL . "[");

                } else if (($setOptions & OPT_ALLOWCONTROLCHARS) && 
                                isset($quitChar)) {
                    //print "<p>Sending QUIT</p>";
                    fwrite($fd, $authKey . CMD_CONTROL . "\\");

                } else if (($setOptions & OPT_ALLOWCONTROLCHARS) && 
                                isset($intChar)) {
                    //print "<p>Sending INTERRUPT</p>";
                    fwrite($fd, $authKey . CMD_CONTROL . "C");

                } else if (($setOptions & OPT_ALLOWCONTROLCHARS) && 
                                isset($sendCtrl)) {
                    if (isset($ctrlChar))
                        $ctrlChar = strtoupper($ctrlChar);
                    if (!isset($ctrlChar) || ord($ctrlChar) < 0x40 || 
                    		ord($ctrlChar) >= 0x5f) {
                    	echo sParaBlk(sBoldBlk(SYSTEM_NAME . 
                                    ": No such control character"));
                        $expectResponse = false;
                    } else {
                        //print "<p>Sending " . 
                        //	escBrowserSpecialChars("^" . $ctrlChar) . "</p>";
                        fwrite($fd, $authKey . CMD_CONTROL . $ctrlChar);
                    } // if
                } else {
                    // Should never happen, but say sth in case it does
                    echo sParaBlk(sBoldBlk( SYSTEM_NAME . 
                                ": Unimplemented or unallowed command " . 
                    		"form button"));
                    $expectResponse = false;
                } // if 
        
                //
                // Collect response from CCS
                // Since we make a fresh connection with each
                // shell input, then all we need to do is read until EOF
                //
                
                if ($authenticated && $expectResponse) {

                    //print "<p>Reading response</p>";

                    getShellOutput($fd, $outputBuf, $outputBufLen, 
                            $authenticated);

                    if ($outputBufLen > $outputBufferLimit) {
                        $truncPos = $outputBufLen - $outputBufferLimit;
                        if ($truncPos > $outputPos)
                            $truncPos = $outputPos;
                        //print "<p>Truncating to pos $truncPos</p>";

                        $outputBuf = substr($outputBuf, $truncPos);
                        $outputPos -= $truncPos;
                        $outputBufLen -= $truncPos;
                    } // if 
                    
                } // if
    
                fclose($fd);
            } // if 
            
        } else if (isset($scrForm)) {

            //
            // A scrolling action just requires us to move through the
            // buffer maintained on the HTTP server (i.e. no connection
            // with the CCS is required).
            //
        
            //print "<p>Scroll form submitted</p>";

            $tryAdjust = false;		// Set true if we should try to adjust
            				// start of next output block to 
                                        // a newline boundary 

            if (isset($scrPrev)) {

                $outputPos -= $outputWindowSize;
                if ($outputPos < 0)
                    $outputPos = 0;
                else 
            	    $tryAdjust = true;

            } else if (isset($scrNext)) {

                // Move past previous output 

                $outputPos += $lastOutputBlockSize;

            } else if (isset($scrTop)) {

                $outputPos = 0;

            } else if (isset($scrBot)) {

                // 
                // Jump to the bottom of the output buffer, unless a simple
                // scroll-next would take us there anyway
                
                if ($outputPos + $lastOutputBlockSize + 
                                $outputWindowSize < $outputBufLen) {
                    $outputPos = $outputBufLen - $outputWindowSize;
            	    $tryAdjust = true;
                } else {
                    $outputPos += $lastOutputBlockSize;
                } // if

            } else if (isset($fwdSrch) || isset($backSrch)) {

                $lastSrchStr = $srchStr;
                performSearch(isset($fwdSrch), $srchStr, $lastSearchPos, 
                    $outputPos, $outputBuf, $outputBufLen, $outputWindowSize);

            } else {
                
            	echo sParaBlk(sBoldBlk(SYSTEM_NAME . 
                            ": Unexpected scroll command"));

            } // if 

            //print "<p>Raw new outputPos = $outputPos; " . 
            //		"outputBufLen=$outputBufLen</p>";

            // If required, adjust start of next output block to the 
            // next following newline boundary

            if ($tryAdjust) {
                $nextEol = strpos($outputBuf, "\n", $outputPos);
                if ($nextEol != false && 
                        (($nextEol - $outputPos) < ($outputWindowSize / 2))) {
                    $outputPos = $nextEol + 1;
                    //print "<p>Adjusted outputPos = $outputPos</p>";
                } // if 
            } // 
        } // if 


        // Calculate size of next block of output

        $lastOutputBlockSize = 0;

        if ($outputPos < $outputBufLen) {
            
            $nextBlock = substr($outputBuf, $outputPos, $outputWindowSize);
            
            // Where possible, truncate output to a line boundary
              
            if ($outputPos < $outputBufLen - $outputWindowSize) {
                $lastEol = strrpos($nextBlock, "\n");
                //
                // If we find a newline in the last 3rd of the block, we'll
                // truncate back to that point
                //
                if ($lastEol !== false && 
                        $lastEol > ($outputWindowSize * 2) / 3) {
                    $nextBlock = substr($nextBlock, 0, $lastEol - 1);
                } /* if */
            } /* if */

            $printableNextBlock = $nextBlock;

            if ($setOptions & OPT_FILTERANSIESC) 
                $printableNextBlock = filterAnsiEscapes($printableNextBlock);

            // Remove non-printable characters (which Web browsers
            // typically don't display, and to which WAP gateways/clients
            // object)
            //
            
            $printableNextBlock = ereg_replace("[--]", "", 
                    $printableNextBlock);

            $lastOutputBlockSize += strlen($nextBlock);
        } // if

        if (!(isset($fwdSrch) || isset($backSrch))) 
            $lastSearchPos = INVALID_POS;
    } // if ($authenticated) 
?>
<?
// *********************** Forms *********************

    if ($authenticated) {
        //print sParaBlk("Output window time: $outputBufLen");
        if ($clientType == "http") {
            if ($outputBufLen > 0) 
                displayShellOutputWindow($printableNextBlock, $outputBufLen, 
                        $outputPos, $lastOutputBlockSize, 
                        $outputWindowSize, $srchStr);

            displayShellInputForm($setOptions, $cmdNum, $numSc, $scName);
        } else {
            require("command_wml.inc");
        }
    } // if 

    if (!$authenticated) {
        echo sParaBlk(sAnchor(
		    loginPage() . "?u=" . $username . "&amp;h=" . $host, 
                    SYSTEM_NAME . " login"));
    }
?>
<?
    if ($clientType == "http") {
?>
</body>

</html>
<?
    } else {
?>
</card>
</wml>
<?
    }
?>


<?


function getShellOutput($fd, &$outputBuf, &$outputBufLen, &$authenticated) {

    $ccsResponse = "";
    while (!feof($fd)) 
        $ccsResponse .= fread($fd, 100);
        
    $statusChar = substr($ccsResponse, 0, 1);
    $ccsResponse = substr($ccsResponse, 1);
       
    //print "<p>Status char = $statusChar</p>";
    if ($statusChar == RESP_NORMAL) {
        $outputBuf .= $ccsResponse;
        $outputBufLen += strlen($ccsResponse);
        //print 	"<p>Got " . strlen($ccsResponse) . " more chars, ";
    } else if ($statusChar == RESP_ERROR) {

        $ccsResponse = "\n" . SYSTEM_NAME . " SERVER ERROR: " . 
            	$ccsResponse . "\n";
        $outputBuf .= $ccsResponse;
        $outputBufLen += strlen($ccsResponse);
    } else if ($statusChar == RESP_FATAL) {
        echo sParaBlk(sBoldBlk(sFontBlk('size="+1" color="red"', 
                    'The remote Command Server returned the ' .
                    'following fatal error: ' . 
                    sEmphBlk(escBrowserSpecialChars($ccsResponse)) .
                    sBreak() .  'You have been logged out')));
        $authenticated = 0;
    } else { /* UNKNOWN!! */
        echo sParaBlk(sBoldBlk(sFontBlk('size="+1" color="red"', 
                    'The remote Command Server returned the ' .
                    'following unexpected status character: "' .
                    escBrowserSpecialChars($statusChar) . '" and message: ' . 
                    sEmphBlk(escBrowserSpecialChars($ccsResponse)))));
        $authenticated = 0;
    } // if 
} // getShellOutput



function filterAnsiEscapes($str) {

    // Filter ANSI escape sequences
    // XXX This is far from complete - currently only common 
    // sequences are filtered
    //
    $str = ereg_replace("\[([0-9]*;)+[0-9]*m", "", $str);
    $str = ereg_replace("\[[0-9]*;[0-9]*[a-zA-Z]", "", $str);
    $str = ereg_replace("\[[0-9]*[a-zA-Z]", "", $str);
    $str = ereg_replace("\[=([0-9]*;7|0*|\?7)[hl]", "", $str);
    $str = ereg_replace("#[0-9]", "", $str);
    $str = ereg_replace("\[\?[0-9][a-zA-Z]", "", $str);
    $str = ereg_replace("\[\?[0-9]*", "", $str);

    //$str = ereg_replace("\[\?[0-9]*[a-zA-Z]", "", $str);
    // $str = ereg_replace("\[.", "", $str);
    
    $str = ereg_replace(".", "", $str);
    $str = ereg_replace("", "", $str);

    return $str;
} // filterAnsiEscapes



function performSearch($isForwardSearch, $srchStr, &$lastSearchPos, 
                &$outputPos, $outputBuf, $outputBufLen, $outputWindowSize) {

    if (!isset($srchStr) || $srchStr == "") {
        
    	echo sParaBlk(sBoldBlk(SYSTEM_NAME . ": No search string provided"));
        
    } else {
        if ($lastSearchPos == INVALID_POS) 
            $lastSearchPos = $outputPos;

        if ($isForwardSearch) {
            //print sParaBlk("Fwdsearch: lastSearchPos=$lastSearchPos: str=$srchStr");
            $pos = strpos($outputBuf, $srchStr, $lastSearchPos+1);
        } else { // Back Search
            // Back search is not straightforward, because there is
            // no true reverse search equivalent of strpos() 
            // (strrpos() can only search for a single char)
            // Our hack is to reverse outputBuf,
            // reverse the search string, and then use strpos()
                
            $rob = strrev($outputBuf);
            $rss = strrev($srchStr);
            $rpos = $outputBufLen - $lastSearchPos;

            //print sParaBlk("Revsearch: lastSearchPos=$lastSearchPos, rpos=$rpos");
            $pos = strpos($rob, $rss, $rpos);
        } // if
                    
        if ($pos == false) {
            echo sParaBlk(sBoldBlk(SYSTEM_NAME . ": not found"));

        } else {
            if ($isForwardSearch)
                $lastSearchPos = $pos;
            else
                $lastSearchPos = $outputBufLen - $pos - strlen($rss);
            echo sParaBlk(sBoldBlk(SYSTEM_NAME . 
                        ": fnd at: $lastSearchPos"));
                        
            // Set outputPos to the start of the line containing
            // the string we found

            $p = $lastSearchPos - min(SEARCH_PRIOR_DISP_WINDOW, 
                    round($outputWindowSize / 4));
            if ($p < 0) $p = 0;
            $startp = $p;

            unset($oldp);

            for (;;) {
                $p = strpos($outputBuf, "\n", $p+1);
                if ($p == false || $p > $lastSearchPos) break;
                $oldp = $p;
            } // for
            $p = isset($oldp) ? ($oldp + 1) : $startp;
            //print sParaBlk("Adjusted pos would be $p");
            $outputPos = $p;
                        
            // $pos = strpos($outputBuf, $srchStr, $lastSearchPos+1);
        } // if
    } // if
} // performSearch


?>
