# ibb.tcl --
#
#       This file is a part of Jidlink Tkabber plugin. It implements
#       inband-bytestream protocol.

package require base64

namespace eval ibb {}

proc ibb::load {} {
    ::xmpp::iq::register set query jabber:iq:ibb \
                         [namespace current]::iq_set_handler
    ::xmpp::iq::register set query jabber:iq:inband \
                         [namespace current]::iq_inband_set_handler

    jidlink::register_transport inband-bytestream inband-bytestream \
                                75 enabled \
                                [namespace current]::connect \
                                [namespace current]::send_data \
                                [namespace current]::close
}

proc ibb::unload {} {
    ::xmpp::iq::unregister set query jabber:iq:ibb
    ::xmpp::iq::unregister set query jabber:iq:inband

    #jidlink::unregister_transport inband-bytestream

    namespace delete [namespace current]
}

proc ibb::connect {xlib jid key} {
    variable connection

    set_status [::msgcat::mc "Opening IBB connection"]

    ::xmpp::sendIQ $xlib set \
        -query [::xmpp::xml::create query \
                    -xmlns jabber:iq:ibb \
                    -subelement [::xmpp::xml::create comment \
                                    -subelement [::xmpp::xml::create key \
                                                        -cdata $key]]] \
        -to $jid \
        -command [list [namespace current]::recv_connect_response \
                       $xlib $jid $key]

    vwait [namespace current]::connection(status,$key)
}

proc ibb::recv_connect_response {xlib jid key status xml} {
    variable connection

    if {$status != "ok"} {
        # TODO
        set connection(status,$key) 0
        return
    }

    ::xmpp::xml::split $xml tag xmlns attrs cdata subels

    if {$tag == "query"} {
        foreach item $subels {
            ::xmpp::xml::split $item stag sxmlns sattrs scdata ssubels
            if {$stag == "streamid"} {
                set streamid $scdata
                debugmsg jidlink "STREAMID: $streamid"
            }
        }

        if {[info exists streamid]} {
            variable stream_key
            variable key_stream

            set stream_key($streamid) $key
            set key_stream($key) $streamid

            set connection(xlib,$key) $xlib
            set connection(jid,$key) $jid
            set connection(status,$key) 1

        } else {
            # TODO
        }
    } else {
        # TODO
    }
    set connection(status,$key) 0
}

proc ibb::send_data {key data} {
    variable connection
    variable key_stream

    debugmsg jidlink [array get stream_key]

    ::xmpp::sendIQ $connection(xlib,$key) set \
        -query [::xmpp::xml::create query \
                    -xmlns jabber:iq:inband \
                    -subelement [::xmpp::xml::create streamid \
                                        -cdata $key_stream($key)] \
                    -subelement [::xmpp::xml::create data \
                                        -cdata [base64::encode $data]]] \
        -to $connection(jid,$key) \
        -command [list [namespace current]::send_data_ack $key]

    vwait [namespace current]::connection(ack,$key)

    return $connection(ack,$key)
}

proc ibb::send_data_ack {key status xml} {
    variable connection
    if {$status != "ok"} {
        # TODO
        set connection(ack,$key) 0
        return
    }
    set connection(ack,$key) 1
}

proc ibb::close {key} {
    variable connection
    variable key_stream

    ::xmpp::sendIQ $connection(xlib,$key) set \
        -query [::xmpp::xml::create query \
                    -xmlns jabber:iq:inband \
                    -subelement [::xmpp::xml::create streamid \
                                        -cdata $key_stream($key)] \
                    -subelement [::xmpp::xml::create close]] \
        -to $connection(jid,$key)
}

proc ibb::iq_set_handler {xlib from xml args} {
    ::xmpp::xml::split $xml tag xmlns attrs cdata subels

    if {$tag == "query"} {
        foreach item $subels {
            ::xmpp::xml::split $item stag sxmlns sattrs scdata ssubels
            if {$stag == "comment"} {
                foreach sitem $ssubels {
                    ::xmpp::xml::split $sitem \
                                sstag ssxmlns ssattrs sscdata sssubels
                    if {$sstag == "key"} {
                        set key $sscdata
                        debugmsg jidlink "KEY: $key"
                    }
                }
            }
        }

        if {[info exists key]} {
            variable stream_key
            variable key_stream

            set streamid [rand 1000000000]
            set stream_key($streamid) $key
            set key_stream($key) $streamid

            set res [::xmpp::xml::create query \
                         -xmlns jabber:iq:ibb \
                         -subelement [::xmpp::xml::create streamid \
                                             -cdata $streamid]]
            return [list result $res]
        } else {
            # TODO
        }
    } else {
        # TODO
    }
}

proc ibb::iq_inband_set_handler {xlib from xml args} {
    variable stream_key

    ::xmpp::xml::split $xml tag xmlns attrs cdata subels

    if {$tag == "query"} {
        foreach item $subels {
            ::xmpp::xml::split $item stag sxmlns sattrs scdata ssubels
            switch -- $stag {
                streamid {
                    set streamid $scdata
                }
                data {
                    set data $scdata
                }
                close {
                    set close 1
                }
            }
        }

        if {[info exists streamid] && [info exists stream_key($streamid)]} {
            if {[info exists data]} {
                if {[catch {set decoded [base64::decode $data]}]} {
                    # TODO
                    debugmsg jidlink "IBB: WRONG DATA"
                } else {
                    debugmsg jidlink "IBB: RECV DATA [list $data]"
                    jidlink::recv_data $stream_key($streamid) $decoded
                }
            }

            if {[info exists close]} {
                jidlink::closed $stream_key($streamid)
            }

            return [list result ""]
        } else {
            # TODO
        }
    } else {
        # TODO
    }
}

# vim:ft=tcl:ts=8:sw=4:sts=4:et
