#  jlibcomponent.tcl --
#  
#      This file is part of the jabberlib. It provides support for the
#      jabber:component:accept protocol (XEP-0114).
#      
#  Copyright (c) 2005 Sergei Golovan <sgolovan@nes.ru>
#  
# $Id: jlibcomponent.tcl 1488 2008-08-25 10:14:35Z sergei $
#
# SYNOPSIS
#   jlibcomponent::new connid args
#	creates handshake token
#	args: -sessionid   sessionid
#	      -secret      secret
#	      -command     callback
#
#   token configure args
#	configures token parameters
#	args: the same as in jlibcomponent::new
#
#   token handshake args
#	starts handshake procedure
#	args: the same as in jlibcomponent::new
#
#   token free
#	frees token resourses
#
# Note that this package is not loaded automatically with jabberlib.
# You have to require it explicitly.
#

##########################################################################

package require sha1

package provide jlibcomponent 1.0

##########################################################################

namespace eval jlibcomponent {
    variable uid 0
}

##########################################################################

proc jlibcomponent::new {connid args} {
    variable uid

    set token [namespace current]::[incr uid]
    variable $token
    upvar 0 $token state

    ::LOG "(jlibcomponent::new $connid) $token"

    set state(-connid) $connid

    proc $token {cmd args} \
	"eval {[namespace current]::\$cmd} {$token} \$args"

    eval [list configure $token] $args

    jlib::register_element $state(-connid) handshake \
	[namespace code [list parse $token]]
    jlib::register_element $state(-connid) error \
	[namespace code [list parse $token]]
    
    return $token
}

##########################################################################

proc jlibcomponent::free {token} {
    variable $token
    upvar 0 $token state

    ::LOG "(jlibcomponent::free $token)"

    jlib::unregister_element $state(-connid) handshake
    jlib::unregister_element $state(-connid) error

    catch { unset state }
    catch { rename $token "" }
}

##########################################################################

proc jlibcomponent::configure {token args} {
    variable $token
    upvar 0 $token state

    foreach {key val} $args {
	switch -- $key {
	    -sessionid -
	    -secret -
	    -command {
		set state($key) $val
	    }
	    default {
		return -code error "Illegal option \"$key\""
	    }
	}
    }
}

##########################################################################

proc jlibcomponent::parse {token xmldata} {
    variable $token
    upvar 0 $token state

    jlib::wrapper:splitxml $xmldata tag vars isempty cdata children

    switch -- $tag {
	handshake {
	    finish $token OK {}
	}
	error {
	    if {[wrapper:getattr $vars xmlns] = $::NS(stream)} {
		finish $token ERR [streamerror:message $xmldata]
	    }
	}
    }
}

##########################################################################

proc jlibcomponent::handshake {token args} {
    variable $token
    upvar 0 $token state

    ::LOG "(jlibcomponent::handshake $token)"

    eval [list configure $token] $args

    foreach key [list -sessionid \
		      -secret] {
	if {![info exists state($key)]} {
	    return -code error "Handshake error: missing option \"$key\""
	}
    }

    set secret [encoding convertto utf-8 $state(-sessionid)]
    append secret [encoding convertto utf-8 $state(-secret)]
    set digest [sha1::sha1 $secret]
    set data [jlib::wrapper:createtag handshake -chdata $digest]

    jlib::client status [::msgcat::mc "Waiting for handshake results"]
    outmsg [jlib::wrapper:createxml $data] -connection $state(-connid)
}

##########################################################################

proc jlibcomponent::finish {token res msg} {
    variable $token
    upvar 0 $token state

    ::LOG "(jlibcomponent::finish $token) $res"

    if {$res != "OK"} {
	jlib::client status [::msgcat::mc "Handshake failed"]
    } else {
	jlib::client status [::msgcat::mc "Handshake successful"]
    }

    # Unregister elements after handshake
    jlib::unregister_element $state(-connid) handshake
    jlib::unregister_element $state(-connid) error

    if {[info exists state(-command)]} {
	uplevel #0 $state(-command) [list $res $msg]
    }
}

##########################################################################

