<?php

/*

PCB_Usernet is used to read/write the PCBoard USERNET.XXX node status file.

sample usage :

$unet = new PCB_Usernet(PCBDIR . "/MAIN/USERNET.XXX");
$node1 = $unet->Get_Node_Record(1);
$node2 = $unet->Get_Node_Record(2);
echo "node1 caller is {$node1->name}, node2 status is {$node2->status}";
$node2->Set_Status(" ");
echo "node2 status is now : waiting for caller";

*/

class PCB_Usernet {

    private 
$f;

    public 
$version;
    public 
$nodes;
    public 
$recsize;
    
    public function 
__construct($filename NULL) {

        if (!isset(
$filename)) $filename "USERNET.XXX";
        
        
$this->fopen($filename"r+");

        list(, 
$this->version$this->nodes$this->recsize) = unpack("v3"fread($this->f6));

    }

    private function 
Seek_Node($nodenum$offset 0) {

        if (!
is_numeric($nodenum)) {

            throw new 
Exception("node number must be a number (duh!)");

        } else if (
$nodenum 1) {

            throw new 
Exception("node number must be > 0");

        }
        
        
$nfsize ceil($this->nodes 4);
        if (
$this->nodes 0$nfsize++;
        
        
$hsize $nfsize;
        
        
fseek($this->f$hsize + (($nodenum 1) * $this->recsize) + $offsetSEEK_SET);
    
    }
    
    public function 
Read_Raw_Record($nodenum) {

        
$this->Seek_Node($nodenum);
        
        return 
fread($this->f$this->recsize);
    
    }
    
    public function 
Write_Raw_Data($nodenum$data$offset 0) {

        
$this->Seek_Node($nodenum$offset);

        return 
fwrite($this->f$data);
    
    }
    
    public function 
Get_Node_Record($nodenum) {

        return new 
PCB_Usernet_Record($this$nodenum);
    
    }
    
    public function 
__destruct() {

        
fclose($this->f);

    }

}

class 
PCB_Usernet_Record {

    private 
$unet;
    private 
$fpos;

    public 
$node;
    public 
$status;
    public 
$mailwaiting;
    public 
$pager;
    public 
$name;
    public 
$city;
    public 
$operation;
    public 
$message;
    public 
$channel;
    public 
$lastupdate;

    static private function 
From_Cstr($cstr) {

        
$ret "";
        
$len strlen($cstr);
        
        for (
$i 0$i $len$i++) {

            if (
$cstr[$i] === chr(0)) return $ret;

            
$ret .= $cstr[$i];
        
        }

        return 
$ret;
    
    }
    
    public function 
__construct(PCB_Usernet $unet$node 1) {

        
$this->unet $unet;
        
$this->node $node;

        
$this->Refresh_Data();
    
    }

    public function 
Refresh_Data() {

        
$data $this->unet->Read_Raw_Record($this->node);

        
$tmp unpack("Cstatus/Cmailwaiting/vpager"substr($data04));

        
$this->status chr($tmp["status"]);
        
$this->mailwaiting $tmp["mailwaiting"];
        
$this->pager $tmp["pager"];
        
        
$this->name self::From_Cstr(substr($data426));
        
$this->city self::From_Cstr(substr($data3025));
        
$this->operation self::From_Cstr(substr($data5549));
        
$this->message self::From_Cstr(substr($data10480));

        
$tmp unpack("Cchannel/Vlastupdate"substr($data1845));
        
        
$this->channel $tmp["channel"];
        
$this->lastupdate $tmp["lastupdate"];
    
    }

    public function 
Set_Status($c) {

        if (!
is_string($c)) {

            throw new 
Exception("status must be a string");

        } else if (
strlen($c) !== 1) {

            throw new 
Exception("status must be exactly one char");

        }

        
$ret $this->unet->Write_Raw_Data($this->node$c0);

        
$this->Refresh_Data();

        return 
$ret;
    
    }

}

/*

stripatx() is identical to the PPL function. returns string without @X color codes

*/

function stripatx($str) {

    return 
preg_replace("/@X[0-9A-F][0-9A-F]/"""$str);

}

/*

pcb2html() converts a string containing PCBoard @Xxx color codes to html.
classes are used instead of colors so CSS is needed (see below).
other PCBoard @codes@ are also stripped, as well as DOS EOF character if found.
returns an UTF-8 encoded string

sample usage :

echo pcb2html(file_get_contents(PCBDIR . "/GEN/BRDM"));

you have to include the following CSS rules for this to work :

span.black {
    color: #000;
}
span.blue {
    color: #00a;
}
span.green {
    color: #0a0;
}
span.cyan {
    color: #0aa;
}
span.red {
    color: #a00;
}
span.pink {
    color: #a0a;
}
span.yellow {
    color: #0aa;
}
span.lightgrey {
    color: #aaa;
}
span.grey {
    color: #666;
}
span.lightblue {
    color: #00f;
}
span.lightgreen {
    color: #0f0;
}
span.lightcyan {
    color: #0ff;
}
span.lightred {
    color: #f00;
}
span.lightpink {
    color: #f0f;
}
span.lightyellow {
    color: #0ff;
}
span.white {
    color: #fff;
}
span.bg_black {
    background-color: #000;
}
span.bg_blue {
    background-color: #00a;
}
span.bg_green {
    background-color: #0a0;
}
span.bg_cyan {
    background-color: #0aa;
}
span.bg_red {
    background-color: #a00;
}
span.bg_pink {
    background-color: #a0a;
}
span.bg_yellow {
    background-color: #0aa;
}
span.bg_lightgrey {
    background-color: #aaa;
}
span.bg_grey {
    background-color: #666;
}
span.bg_lightblue {
    background-color: #00f;
}
span.bg_lightgreen {
    background-color: #0f0;
}
span.bg_lightcyan {
    background-color: #0ff;
}
span.bg_lightred {
    background-color: #f00;
}
span.bg_lightpink {
    background-color: #f0f;
}
span.bg_lightyellow {
    background-color: #0ff;
}
span.bg_white {
    background-color: #fff;
}

*/

function pcb2html($s) {

    if (
substr($s, -1) === chr(26)) {

        
$s substr($s0, -1);
    
    }
    
    
$pcb2css = array(    "0" => "black",
                        
"1" => "blue",
                        
"2" => "green",
                        
"3" => "cyan",
                        
"4" => "red",
                        
"5" => "pink",
                        
"6" => "yellow",
                        
"7" => "lightgrey",
                        
"8" => "grey",
                        
"9" => "lightblue",
                        
"A" => "lightgreen",
                        
"B" => "lightcyan",
                        
"C" => "lightred",
                        
"D" => "lightpink",
                        
"E" => "lightyellow",
                        
"F" => "white");
    
    
$s str_replace("<""&lt;"$s);
    
$s str_replace(">""&gt;"$s);
    
$s str_replace(" ""&nbsp;"$s);

    if (
preg_match_all("/@X[0-9A-F][0-9A-F]/"$s$resPREG_OFFSET_CAPTURE)) {

        
$ret substr($s0$res[0][0][1]);
        
        foreach (
$res[0] as $k => $tmp) {

            list(
$pcbcode$offset) = $tmp;

            
$ret .= "<span class='";
            
            if (
$pcbcode[2] !== "0"$ret .= "bg_{$pcb2css[$pcbcode[2]]} ";
            
            
$ret .= "{$pcb2css[$pcbcode[3]]}'>";
            
$ret .= substr($s$offset 4$res[0][$k+1] ? $res[0][$k+1][1] - $offset strlen($s) - $offset 4);
            
$ret .= "</span>";
            
        }
    
    } else {

        
$ret $s;

    }

    
$ret preg_replace("/@[^@]{1,32}@/"""$ret);
    
$ret iconv("cp437""utf-8"$ret);
    
$ret nl2br($ret);
    
    return 
$ret;

}

?>