<?php 
 | 
/** 
 | 
 * Klasa konwertuje wiadomość ({@link BotMsg}) do formatu specyficznego dla Gadu-Gadu 
 | 
 */ 
 | 
class BotMsgGG implements BotMsgInterface { 
 | 
    private $parser; 
 | 
    private $html = ''; 
 | 
    private $old = ''; 
 | 
    private $format = ''; 
 | 
     
 | 
    private $images = array(); 
 | 
     
 | 
    private $f_handl = FALSE; 
 | 
    private $f_old = ''; 
 | 
    private $f_type = 0x00; 
 | 
    private $f_color = ''; 
 | 
     
 | 
    const FORMAT_BOLD =    0x01; 
 | 
    const FORMAT_ITALIC =    0x02; 
 | 
    const FORMAT_UNDERLINE =0x04; 
 | 
    const FORMAT_COLOR =    0x08; 
 | 
    const FORMAT_IMAGE =    0x80; 
 | 
     
 | 
    const COLOR_RED =    0x00010000; 
 | 
    const COLOR_GREEN =    0x00000100; 
 | 
    const COLOR_BLUE =    0x00000001; 
 | 
     
 | 
    /** 
 | 
     * @param BotMsg $msg Wiadomość do przekonwertowania 
 | 
     */ 
 | 
    function __construct(BotMsg $msg) { 
 | 
        $parser = $msg->getParser(); 
 | 
        unset($msg); 
 | 
         
 | 
        $this->parser = new DOMDocument('1.0', 'utf-8'); 
 | 
        $this->parser->loadHTML('<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body></body></html>'); 
 | 
         
 | 
        $this->rewrite( $parser->getElementsByTagName('body')->item(0), $this->parser->getElementsByTagName('body')->item(0) ); 
 | 
        unset($parser); 
 | 
         
 | 
        $this->parse( $this->parser->getElementsByTagName('body')->item(0) ); 
 | 
         
 | 
        $this->html = strtr( 
 | 
            (string)substr($this->parser->saveXML( $this->parser->getElementsByTagName('body')->item(0) ), 6, -7), 
 | 
            array('/>' => '>') // Tak! GG nie lubi XML! 
 | 
        ); 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * Zwraca wiadomość zgodną z BotAPI Gadu-Gadu, którą można przekazać bezpośrednio do BotMastera 
 | 
     * @param NULL|bool $img Czy dołączać obrazki? 
 | 
     * @return string 
 | 
     */ 
 | 
    function getGG($image = NULL) { 
 | 
        if($image === FALSE) { 
 | 
            $image = ''; 
 | 
        } 
 | 
        elseif($image === TRUE) { 
 | 
            $last = array_pop($this->images); 
 | 
            if(count($this->images) > 0) { 
 | 
                $push = new BotAPIGG(); 
 | 
                foreach($this->images as $data) { 
 | 
                    $push->putImage($image[3]); 
 | 
                } 
 | 
            } 
 | 
             
 | 
            $image = $last[2].file_get_contents($last[3]); 
 | 
        } 
 | 
        else 
 | 
        { 
 | 
            if(count($this->images) > 0) { 
 | 
                $push = new BotAPIGG(); 
 | 
                foreach($this->images as $image) { 
 | 
                    if(!$push->existsImage($image[2])) { 
 | 
                        $push->putImage($image[3]); 
 | 
                    } 
 | 
                } 
 | 
            } 
 | 
             
 | 
            $image = ''; 
 | 
        } 
 | 
         
 | 
        $format = $this->getFormat(); 
 | 
         
 | 
        return pack('VVVV', strlen($this->html)+1, strlen($this->old)+1, strlen($image), strlen($format)).$this->html."\0".$this->old."\0".$image.$format; 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * Zwraca wiadomość zgodną z BotAPI Gadu-Gadu, którą można przekazać bezpośrednio do BotMastera 
 | 
     * @return string 
 | 
     */ 
 | 
    function __toString() { 
 | 
        return $this->getGG(); 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * Zwraca wiadomość w formacie HTML przekonwertowaną tak, by zawierała jedynie dozwolone tagi. 
 | 
     * @return string 
 | 
     */ 
 | 
    function getHTML() { 
 | 
        return $this->html; 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * Zwraca wiadomość jako tekst 
 | 
     * @return string 
 | 
     */ 
 | 
    function getText() { 
 | 
        return $this->old; 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * Zwraca formatowanie wiadomości tekstowej zgodne z BotAPI Gadu-Gadu 
 | 
     * @see BotMsgGG::getText() 
 | 
     * @return string 
 | 
     */ 
 | 
    function getFormat() { 
 | 
        if($this->format == '') { 
 | 
            return ''; 
 | 
        } 
 | 
        else 
 | 
        { 
 | 
            return pack('Cv', 0x02, strlen($this->format)).$this->format; 
 | 
        } 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * Wyślij wiadomość na standardowe wyjście w sposób właściwy dla BotAPI 
 | 
     */ 
 | 
    function sendPullResponse() { 
 | 
        header('Content-Type: application/x-gadu-gadu; charset=utf-8'); 
 | 
        echo $this->getGG(); 
 | 
    } 
 | 
     
 | 
    private function rewriteOne($node, $saveto) { 
 | 
         
 | 
    } 
 | 
     
 | 
    private function rewrite($dom, $saveto, $top = TRUE) { 
 | 
        if(!($dom instanceof DOMElement)) { 
 | 
            throw new BotMsgException('Nieznany element DOM: '.get_class($dom)); 
 | 
        } 
 | 
         
 | 
        foreach($dom->childNodes as $node) { 
 | 
            if($node instanceof DOMElement) { 
 | 
                switch(strtolower($node->tagName)) { 
 | 
                    case 'b': 
 | 
                    case 'i': 
 | 
                    case 'u': 
 | 
                    case 'sup': 
 | 
                    case 'sub': 
 | 
                    case 'span': 
 | 
                        $tag = DOMHelper::cloneNode($node, $saveto); 
 | 
                        $this->rewrite($node, $tag, FALSE); 
 | 
                        $saveto->appendChild($tag); 
 | 
                    break; 
 | 
                     
 | 
                    case 'strong': 
 | 
                        $tag = DOMHelper::cloneNode($node, $saveto, 'b'); 
 | 
                        $this->rewrite($node, $tag, FALSE); 
 | 
                        $saveto->appendChild($tag); 
 | 
                    break; 
 | 
                     
 | 
                    case 'script': 
 | 
                    case 'style': 
 | 
                    break; 
 | 
                     
 | 
                    case 'p': 
 | 
                        DOMHelper::rtrim($saveto); 
 | 
                        DOMHelper::insertElement('br', $saveto); 
 | 
                        DOMHelper::insertElement('br', $saveto); 
 | 
                         
 | 
                        $tag = DOMHelper::cloneNode($node, $saveto, 'span'); 
 | 
                        $this->rewrite($node, $tag, FALSE); 
 | 
                        $saveto->appendChild($tag); 
 | 
                         
 | 
                         
 | 
                        DOMHelper::insertElement('br', $saveto); 
 | 
                        DOMHelper::insertElement('br', $saveto); 
 | 
                    break; 
 | 
                    case 'a': 
 | 
                        $tag = DOMHelper::cloneNode($node, $saveto, 'span'); 
 | 
                         
 | 
                        $this->rewrite($node, $tag, FALSE); 
 | 
                        if($node->getAttribute('href') != $node->textContent) { 
 | 
                            $tag->appendChild($tag->ownerDocument->createTextNode(' ('.$node->getAttribute('href').')')); 
 | 
                        } 
 | 
                         
 | 
                        $saveto->appendChild($tag); 
 | 
                    break; 
 | 
                     
 | 
                    case 'h1': 
 | 
                        DOMHelper::rtrim($saveto); 
 | 
                        DOMHelper::insertElement('br', $saveto); 
 | 
                        DOMHelper::insertElement('br', $saveto); 
 | 
                         
 | 
                        $tag = DOMHelper::cloneNode($node, $saveto, 'b'); 
 | 
                        $tag2 = $tag->ownerDocument->createElement('u'); 
 | 
                        $tag->appendChild($tag2); 
 | 
                         
 | 
                        $this->rewrite($node, $tag2, FALSE); 
 | 
                         
 | 
                        $saveto->appendChild($tag); 
 | 
                         
 | 
                        DOMHelper::insertElement('br', $saveto); 
 | 
                    break; 
 | 
                    case 'h2': 
 | 
                        DOMHelper::rtrim($saveto); 
 | 
                        DOMHelper::insertElement('br', $saveto); 
 | 
                        DOMHelper::insertElement('br', $saveto); 
 | 
                         
 | 
                        $tag = DOMHelper::cloneNode($node, $saveto, 'b'); 
 | 
                        $this->rewrite($node, $tag, FALSE); 
 | 
                        $saveto->appendChild($tag); 
 | 
                         
 | 
                         
 | 
                        DOMHelper::insertElement('br', $saveto); 
 | 
                    break; 
 | 
                    case 'h3': 
 | 
                        DOMHelper::rtrim($saveto); 
 | 
                        DOMHelper::insertElement('br', $saveto); 
 | 
                        DOMHelper::insertElement('br', $saveto); 
 | 
                         
 | 
                        $tag = DOMHelper::cloneNode($node, $saveto, 'b'); 
 | 
                        $this->rewrite($node, $tag, FALSE); 
 | 
                        $saveto->appendChild($tag); 
 | 
                         
 | 
                         
 | 
                        DOMHelper::insertElement('br', $saveto); 
 | 
                    break; 
 | 
                     
 | 
                    case 'ul': 
 | 
                        DOMHelper::rtrim($saveto); 
 | 
                        DOMHelper::insertElement('br', $saveto); 
 | 
                         
 | 
                        $tag = DOMHelper::cloneNode($node, $saveto, 'span'); 
 | 
                        $this->rewrite($node, $tag, FALSE); 
 | 
                        $saveto->appendChild($tag); 
 | 
                    break; 
 | 
                    case 'ol': 
 | 
                        DOMHelper::rtrim($saveto); 
 | 
                        DOMHelper::insertElement('br', $saveto); 
 | 
                         
 | 
                        if(!$node->hasAttribute('start') || !ctype_digit($node->getAttribute('start'))) { 
 | 
                            $node->setAttribute('start', 1); 
 | 
                        } 
 | 
                         
 | 
                        $tag = DOMHelper::cloneNode($node, $saveto, 'span'); 
 | 
                        $this->rewrite($node, $tag, FALSE); 
 | 
                        $saveto->appendChild($tag); 
 | 
                    break; 
 | 
                    case 'li': 
 | 
                        $tag = DOMHelper::cloneNode($node, $saveto, 'span'); 
 | 
                         
 | 
                        if(strtolower($dom->tagName) == 'ul') { 
 | 
                            $tag->appendChild($tag->ownerDocument->createTextNode('- ')); 
 | 
                        } 
 | 
                        elseif(strtolower($dom->tagName) == 'ol') { 
 | 
                            $tag->appendChild($tag->ownerDocument->createTextNode($dom->getAttribute('start').'. ')); 
 | 
                             
 | 
                            $dom->setAttribute('start', $dom->getAttribute('start')+1); 
 | 
                        } 
 | 
                         
 | 
                        $this->rewrite($node, $tag, FALSE); 
 | 
                        $saveto->appendChild($tag); 
 | 
                         
 | 
                        $saveto->appendChild($saveto->ownerDocument->createElement('br')); 
 | 
                    break; 
 | 
                     
 | 
                    case 'br': 
 | 
                    case 'img': 
 | 
                        $tag = DOMHelper::cloneNode($node, $saveto); 
 | 
                        $saveto->appendChild($tag); 
 | 
                    break; 
 | 
                     
 | 
                    default: 
 | 
                        $tag = DOMHelper::cloneNode($node, $saveto, 'span'); 
 | 
                        $this->rewrite($node, $tag, FALSE); 
 | 
                        $saveto->appendChild($tag); 
 | 
                    break; 
 | 
                } 
 | 
            } 
 | 
            elseif($node instanceof DOMText) { 
 | 
                $val = strtr($node->nodeValue, array("\n" => '', "\r" => '')); 
 | 
                if($val) { 
 | 
                    $saveto->appendChild($saveto->ownerDocument->createTextNode($val)); 
 | 
                } 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                $saveto->appendChild($saveto->ownerDocument->importNode($node, TRUE)); 
 | 
            } 
 | 
        } 
 | 
         
 | 
        if($top) { 
 | 
            DOMHelper::trim($saveto); 
 | 
        } 
 | 
         
 | 
        foreach($saveto->childNodes as $node) { 
 | 
            if(($node instanceof DOMElement) && $node->tagName == 'span' && $node->attributes->length == 0) { 
 | 
                while($node->hasChildNodes()) { 
 | 
                    $node->parentNode->insertBefore($node->firstChild, $node); 
 | 
                } 
 | 
                $node->parentNode->removeChild($node); 
 | 
            } 
 | 
        } 
 | 
         
 | 
        foreach($saveto->childNodes as $node) { 
 | 
            if(($node instanceof DOMElement) && $node->hasAttribute('auto')) { 
 | 
                $node->removeAttribute('auto'); 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
     
 | 
    private function image($node) { 
 | 
        if($node->hasAttribute('src')) { 
 | 
            $src = $node->getAttribute('src'); 
 | 
            $node->removeAttribute('src'); 
 | 
             
 | 
            if(!is_file($src)) { 
 | 
                return; 
 | 
            } 
 | 
             
 | 
            if(isset($this->images[$src])) { 
 | 
                list($crc, $size, $name) = $this->images[$src]; 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                $size = filesize($src); 
 | 
                if($size<0 || $size>262144) { 
 | 
                    return; 
 | 
                } 
 | 
                 
 | 
                $crc = hash_file('crc32b', $src); 
 | 
                $name = sprintf('%08s%08x', $crc, $size); 
 | 
                 
 | 
                $this->images[$src] = array($crc, $size, $name, $src); 
 | 
            } 
 | 
             
 | 
            $node->setAttribute('name', $name); 
 | 
             
 | 
            $this->format .= pack('vC', mb_strlen($this->old), self::FORMAT_IMAGE) 
 | 
                    .pack('CCVV', 0x09, 0x01, $size, hexdec($crc)); 
 | 
        } 
 | 
    } 
 | 
     
 | 
    private function format(&$node) { 
 | 
        $node->setAttribute('beforeFormatType', ord($this->f_type)); 
 | 
        $node->setAttribute('beforeFormatColor', base64_encode($this->f_color)); 
 | 
         
 | 
        if($node->hasAttribute('color')) { 
 | 
            $color = trim($node->getAttribute('color')); 
 | 
            if(substr($color, 0, 1)=='#' AND (strlen($color)==4 OR strlen($color)==7) AND ctype_xdigit(substr($color, 1))) { 
 | 
                $node->setAttribute('style', 'color:'.$color.';'.$node->getAttribute('style')); 
 | 
                 
 | 
                $R = $G = $B = 0; 
 | 
                if(strlen($color)==4) { 
 | 
                    $R = hexdec(str_repeat(substr($color, 1, 1), 2)); 
 | 
                    $G = hexdec(str_repeat(substr($color, 2, 1), 2)); 
 | 
                    $B = hexdec(str_repeat(substr($color, 3, 1), 2)); 
 | 
                } 
 | 
                else 
 | 
                { 
 | 
                    $R = hexdec(substr($color, 1, 2)); 
 | 
                    $G = hexdec(substr($color, 3, 2)); 
 | 
                    $B = hexdec(substr($color, 5, 2)); 
 | 
                } 
 | 
                 
 | 
                $this->f_color = chr($R).chr($G).chr($B); 
 | 
                $this->f_type |= self::FORMAT_COLOR; 
 | 
            } 
 | 
            $node->removeAttribute('color'); 
 | 
        } 
 | 
         
 | 
        switch(strtolower($node->tagName)) { 
 | 
            case 'b': 
 | 
                $this->f_type |= self::FORMAT_BOLD; 
 | 
            break; 
 | 
            case 'i': 
 | 
                $this->f_type |= self::FORMAT_ITALIC; 
 | 
            break; 
 | 
            case 'u': 
 | 
                $this->f_type |= self::FORMAT_UNDERLINE; 
 | 
            break; 
 | 
        } 
 | 
    } 
 | 
     
 | 
    private function unformat($node) { 
 | 
        $this->f_type = chr($node->getAttribute('beforeFormatType')); 
 | 
        $node->removeAttribute('beforeFormatType'); 
 | 
         
 | 
        $this->f_color = base64_decode($node->getAttribute('beforeFormatColor')); 
 | 
        $node->removeAttribute('beforeFormatColor'); 
 | 
         
 | 
        return TRUE; 
 | 
    } 
 | 
     
 | 
    private function cf() { 
 | 
        $format = pack('C', $this->f_type).$this->f_color; 
 | 
         
 | 
        if($this->f_old != $format) { 
 | 
            $this->format .= pack('v', mb_strlen($this->old)).$format; 
 | 
            $this->f_old = $format; 
 | 
        } 
 | 
    } 
 | 
     
 | 
    private function parse($dom) { 
 | 
        if(!($dom instanceof DOMElement)) { 
 | 
            throw new BotMsgException('Nieznany element DOM: '.$dom); 
 | 
        } 
 | 
         
 | 
        foreach($dom->childNodes as $node) { 
 | 
            if($node instanceof DOMText || $node instanceof DOMEntity) { 
 | 
                $this->cf(); 
 | 
                $this->old .= $node->nodeValue; 
 | 
            } 
 | 
            elseif($node instanceof DOMElement) { 
 | 
                if($node->tagName == 'br') { 
 | 
                    $this->old .= "\r\n"; 
 | 
                    continue; 
 | 
                } 
 | 
                elseif($node->tagName == 'img') { 
 | 
                    $this->image($node); 
 | 
                    continue; 
 | 
                } 
 | 
                 
 | 
                $this->format($node); 
 | 
                $this->parse($node); 
 | 
                $this->unformat($node); 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                throw new BotMsgException('Nieznany element DOM: '.$node); 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
} 
 | 
?> 
 |