Tkabber

Artifact [b0d4057b7b]
Login

Artifact b0d4057b7b3612fce71f5b05f524562deea51a89:


# $Id$
#
# Bookmarks (XEP-0048) support (conference bookmarks in roster)
#
# In addition to XEP-0048, Tkabber stores roster groups using
# proprietory namespace tkabber:bookmarks:groups inside
# jabber:iq:private storage (XEP-0049)
#
#   tkabber:bookmarks:groups description:
#
#   setting:
#   <iq type='set' id='setgroups'>
#	<query xmlns='jabber:iq:private'>
#	    <storage xmlns='tkabber:bookmarks:groups'>
#		<conference jid='talks@conference.jabber.ru'>
#		    <group>Conferences</group>
#		    <group>jabber.ru</group>
#		</conference>
#	    </storage>
#	</query>
#   </iq>
#
#   getting:
#   <iq type='get' id='getgroups'>
#	<query xmlns='jabber:iq:private'>
#	    <storage xmlns='tkabber:bookmarks:groups'/>
#	</query>
#   </iq>
#

namespace eval conferences {
    # variable to store roster conference bookmarks
    array set bookmarks {}

    set ::NS(bookmarks) "storage:bookmarks"
    set ::NS(tkabber:groups) "tkabber:bookmarks:groups"
}

###############################################################################
#
#   Free bookmarks on disconnect
#

proc conferences::free_bookmarks {connid} {
    variable bookmarks

    array unset bookmarks $connid,*
}

hook::add disconnected_hook [namespace current]::conferences::free_bookmarks

###############################################################################
#
#   Retrieve bookmarks on connect
#

proc conferences::request_bookmarks {connid} {
    variable bookmarks
    variable responds

    set responds($connid) 0
    array unset bookmarks $connid,*

    private::retrieve [list [jlib::wrapper:createtag storage \
				 -vars [list xmlns $::NS(bookmarks)]]] \
	-command [list [namespace current]::process_bookmarks $connid] \
	-connection $connid

    private::retrieve [list [jlib::wrapper:createtag storage \
				 -vars [list xmlns $::NS(tkabber:groups)]]] \
	-command [list [namespace current]::process_bookmarks $connid] \
	-connection $connid
}

hook::add connected_hook [namespace current]::conferences::request_bookmarks 20

proc conferences::process_bookmarks {connid res child} {
    variable bookmarks
    variable responds
    global NS

    if {$res != "OK"} return

    incr responds($connid)

    foreach ch $child {
	jlib::wrapper:splitxml $ch tag1 vars1 isempty1 cdata1 children1

	switch -- [jlib::wrapper:getattr $vars1 xmlns] \
	    $NS(bookmarks) {
		foreach bookmark $children1 {
		    create_muc_bookmark $connid $bookmark
		}
	    } \
	    $NS(tkabber:groups) {
		foreach bookmark $children1 {
		    create_muc_bmgroup $connid $bookmark
		}
	    }
    }

    if {$responds($connid) < 2} return

    push_bookmarks_to_roster $connid
    after idle [list [namespace current]::autojoin_groups $connid]
}

proc conferences::create_muc_bookmark {connid xmldata args} {
    variable bookmarks

    set merge 0
    foreach {opt val} $args {
	switch -- $opt {
	    -merge { set merge $val }
	    default {
		return -code error "Bad option \"$opt\":\
		    must be -merge"
	    }
	}
    }

    jlib::wrapper:splitxml $xmldata btag bvars bisempty bcdata bchildren

    if {![string equal $btag conference]} { return 0 }

    set jid [string tolower [jlib::wrapper:getattr $bvars jid]]

    if {$merge && [info exists bookmarks($connid,jid,$jid)]} {
	return 0
    } else {
	set bookmarks($connid,jid,$jid) $jid

	set bookmarks($connid,name,$jid) [jlib::wrapper:getattr $bvars name]
	set bookmarks($connid,nick,$jid) ""
	set bookmarks($connid,password,$jid) ""
	if {![info exists bookmarks($connid,groups,$jid)]} {
	    set bookmarks($connid,groups,$jid) {}
	    set bookmarks($connid,hasgroups,$jid) 0
	} else {
	    set bookmarks($connid,hasgroups,$jid) 1
	}

	set autojoin [jlib::wrapper:getattr $bvars autojoin]
	switch -- $autojoin {
	    1 -
	    true { set bookmarks($connid,autojoin,$jid) 1 }
	    default { set bookmarks($connid,autojoin,$jid) 0 }
	}
	
	foreach bch $bchildren {
	    jlib::wrapper:splitxml \
		$bch tag2 vars2 isempty2 cdata2 children2
	    switch -- $tag2 {
		nick { set bookmarks($connid,nick,$jid) $cdata2 }
		password { set bookmarks($connid,password,$jid) $cdata2 }
	    }
	}
	return 1
    }
}

proc conferences::create_muc_bmgroup {connid xmldata args} {
    variable bookmarks

    set merge 0
    foreach {opt val} $args {
	switch -- $opt {
	    -merge { set merge $val }
	    default {
		return -code error "Bad option \"$opt\":\
		    must be -merge"
	    }
	}
    }

    jlib::wrapper:splitxml $xmldata btag bvars bisempty bcdata bchildren

    if {![string equal $btag conference]} return

    set jid [string tolower [jlib::wrapper:getattr $bvars jid]]

    set groups [list]
    foreach bch $bchildren {
	jlib::wrapper:splitxml $bch tag2 vars2 isempty2 cdata2 children2
	if {[string equal $tag2 group]} {
	    lappend groups $cdata2
	}
    }

    if {$merge && [info exists bookmarks($connid,jid,$jid)]
		&& $bookmarks($connid,hasgroups,$jid)} {
	return 0
    } else {
	set bookmarks($connid,groups,$jid) $groups
	set bookmarks($connid,hasgroups,$jid) 1
	return 1
    }
}

proc conferences::push_bookmarks_to_roster {connid} {
    variable bookmarks

    foreach idx [array names bookmarks $connid,jid,*] {
	set jid $bookmarks($idx)
	client:roster_push $connid $jid $bookmarks($connid,name,$jid) \
			   $bookmarks($connid,groups,$jid) \
			   bookmark ""
	roster::override_category_and_subtype $connid $jid conference ""
    }
}

###############################################################################
#
#   Store bookmarks
#

proc conferences::serialize_bookmarks {connid} {
    variable bookmarks

    set bookmarklist {}
    set grouplist {}
    foreach idx [array names bookmarks $connid,jid,*] {
	set jid $bookmarks($idx)
	set name $bookmarks($connid,name,$jid)
	set autojoin $bookmarks($connid,autojoin,$jid)
	
	set vars [list jid $jid name $name autojoin $autojoin]
	set subtags {}
	if {$bookmarks($connid,nick,$jid) != ""} {
	    lappend subtags [jlib::wrapper:createtag nick \
				 -chdata $bookmarks($connid,nick,$jid)]
	}
	if {$bookmarks($connid,password,$jid) != ""} {
	    lappend subtags [jlib::wrapper:createtag password \
				 -chdata $bookmarks($connid,password,$jid)]
	}
	lappend bookmarklist [jlib::wrapper:createtag conference \
				  -vars $vars \
				  -subtags $subtags]
	set vars [list jid $jid]
	set groups {}
	foreach group $bookmarks($connid,groups,$jid) {
	    lappend groups [jlib::wrapper:createtag group \
				-chdata $group]
	}
	lappend grouplist [jlib::wrapper:createtag conference \
			       -vars $vars \
			       -subtags $groups]
    }

    list [jlib::wrapper:createtag storage \
	    -vars [list xmlns $::NS(bookmarks)] \
	    -subtags $bookmarklist] \
	[jlib::wrapper:createtag storage \
	    -vars [list xmlns $::NS(tkabber:groups)] \
	    -subtags $grouplist]
}

proc conferences::store_bookmarks {connid} {
    foreach item [serialize_bookmarks $connid] {
	private::store [list $item] \
	    -command [list [namespace current]::store_bookmarks_result $connid] \
	    -connection $connid
    }
}

proc conferences::store_bookmarks_result {connid res child} {

    if {$res == "OK"} return

    if {[winfo exists .store_bookmarks_error]} {
	return
    }

    MessageDlg .store_bookmarks_error -aspect 50000 -icon error \
	-message [format [::msgcat::mc "Storing conferences failed: %s"] \
			 [error_to_string $child]] \
	-type user -buttons ok -default 0 -cancel 0
}

###############################################################################
#
#   Menu item for conference window
#

proc conferences::add_conference_menu_item {m connid jid} {
    set chatid [chat::chatid $connid $jid]

    if {[info exists ::muc::muc_password($chatid)]} {
	set password $::muc::muc_password($chatid)
    } else {
	set password ""
    }

    $m add command -label [::msgcat::mc "Add conference to roster..."] \
	-command [list [namespace current]::add_conference_dialog \
		       -group [node_from_jid $jid] \
		       -server [server_from_jid $jid] \
		       -password $password \
		       -connection $connid]
}

hook::add chat_create_conference_menu_hook \
    [namespace current]::conferences::add_conference_menu_item 35

###############################################################################
#
#   Add conference to roster dialog
#

proc conferences::add_conference_dialog {args} {
    variable gra_group
    variable gra_server
    variable gra_nick
    variable gra_password
    variable gra_autojoin
    variable gra_connid
    variable gra_rostergroup

    if {[lempty [jlib::connections]]} return

    set gw .addgroup
    catch { destroy $gw }

    set connid [lindex [jlib::connections] 0]
    set gra_server conference.[jlib::connection_server $connid]
    set gra_group ""
    set gra_password ""
    set gra_autojoin 0
    set gra_rostergroup [::msgcat::mc "Conferences"]
    catch { unset gra_nick }

    foreach {key val} $args {
	switch -- $key {
	    -group { set gra_group $val }
	    -server { set gra_server $val }
	    -nick { set gra_nick $val }
	    -password { set gra_password $val }
	    -autojoin { set gra_autojoin $val }
	    -connection { set connid $val }
	}
    }

    if {![info exists gra_nick]} {
	set gra_nick [get_group_nick ${gra_group}@$gra_server ""]
    }
    set gra_connid [jlib::connection_jid $connid]

    Dialog $gw -title [::msgcat::mc "Add Conference to Roster"] -separator 1 -anchor e \
	    -default 0 -cancel 1 -parent . -modal none

    set gf [$gw getframe]
    grid columnconfigure $gf 0 -weight 0
    grid columnconfigure $gf 1 -weight 1

    label $gf.lgroup -text [::msgcat::mc "Conference:"]
    entry $gf.group -textvariable [namespace current]::gra_group
    label $gf.lserver -text [::msgcat::mc "Server:"]
    entry $gf.server -textvariable [namespace current]::gra_server
    label $gf.lnick -text [::msgcat::mc "Nick:"]
    entry $gf.nick -textvariable [namespace current]::gra_nick
    label $gf.lpassword -text [::msgcat::mc "Password:"]
    entry $gf.password -show * -textvariable [namespace current]::gra_password
    checkbutton $gf.autojoin -text [::msgcat::mc "Automatically join conference upon connect"] \
	-variable [namespace current]::gra_autojoin
    label $gf.lrostergroup -text [::msgcat::mc "Roster group:"]
    ComboBox $gf.rostergroup -textvariable [namespace current]::gra_rostergroup \
	-values [get_groups $connid]

    grid $gf.lgroup  -row 0 -column 0 -sticky e
    grid $gf.group   -row 0 -column 1 -sticky ew
    grid $gf.lserver -row 1 -column 0 -sticky e
    grid $gf.server  -row 1 -column 1 -sticky ew
    grid $gf.lnick -row 2 -column 0 -sticky e
    grid $gf.nick  -row 2 -column 1 -sticky ew
    grid $gf.lpassword -row 3 -column 0 -sticky e
    grid $gf.password  -row 3 -column 1 -sticky ew
    grid $gf.autojoin -row 4 -column 0 -sticky w -columnspan 2
    grid $gf.lrostergroup  -row 5 -column 0 -sticky e
    grid $gf.rostergroup   -row 5 -column 1 -sticky ew

    if {[llength [jlib::connections]] > 1} {
	foreach c [jlib::connections] {
	    lappend connections [jlib::connection_jid $c]
	}
	label $gf.lconnection -text [::msgcat::mc "Connection:"]
	ComboBox $gf.connection -textvariable [namespace current]::gra_connid \
				-values $connections -editable 0 \
				-modifycmd [list [namespace current]::change_groups \
						 $gf.rostergroup]

	grid $gf.lconnection -row 6 -column 0 -sticky e
	grid $gf.connection  -row 6 -column 1 -sticky ew
    }
    

    $gw add -text [::msgcat::mc "Add"] -command [list [namespace current]::add_conference $gw]
    $gw add -text [::msgcat::mc "Cancel"] -command [list destroy $gw]

    $gw draw $gf.group
}

proc conferences::change_groups {combo args} {
    variable gra_connid

    foreach connid [jlib::connections] {
        if {[jlib::connection_jid $connid] == $gra_connid} {
	    $combo configure -values [get_groups $connid]
	    return
	}
    }
}

proc conferences::get_groups {connid} {
    return [roster::get_groups $connid \
		-nested $::ifacetk::roster::options(nested) \
		-delimiter $::ifacetk::roster::options(nested_delimiter) \
		-undefined 0]
}

proc conferences::add_conference {gw} {
    variable bookmarks
    variable gra_group
    variable gra_server
    variable gra_nick
    variable gra_password
    variable gra_autojoin
    variable gra_connid
    variable gra_rostergroup

    destroy $gw

    set jid [string tolower ${gra_group}@$gra_server]
    if {$gra_rostergroup == ""} {
	set groups {}
    } else {
	set groups [list $gra_rostergroup]
    }

    foreach c [jlib::connections] {
	if {[jlib::connection_jid $c] == $gra_connid} {
	    set connid $c
	}
    }
    if {![info exists connid]} {
	# Disconnect while dialog is opened
	return
    }

    if {[info exists bookmarks($connid,jid,$jid)]} {
	update_bookmark $connid $jid -name $gra_group -nick $gra_nick \
			-password $gra_password -autojoin $gra_autojoin \
			-groups $groups
    } else {
	add_bookmark $connid $jid -name $gra_group -nick $gra_nick \
		     -password $gra_password -autojoin $gra_autojoin \
		     -groups $groups
    }
}

###############################################################################
#
#   Add bookmark to roster
#

proc conferences::add_bookmark {connid jid args} {
    variable bookmarks

    if {[info exists bookmarks($connid,jid,$jid)]} return

    foreach {key val} $args {
	switch -- $key {
	    -name { set name $val }
	    -nick { set nick $val }
	    -password { set password $val }
	    -autojoin { set autojoin $val }
	    -groups { set groups $val }
	}
    }

    if {![info exists name]} {
	set name [node_from_jid $jid]
    }
    if {![info exists nick]} {
	set nick [get_group_nick $jid ""]
    }
    if {![info exists password]} {
	set password ""
    }
    if {![info exists autojoin]} {
	set autojoin 0
    }
    if {![info exists groups]} {
	set groups {}
    }

    set bookmarks($connid,jid,$jid) $jid
    set bookmarks($connid,name,$jid) $name
    set bookmarks($connid,nick,$jid) $nick
    set bookmarks($connid,password,$jid) $password
    set bookmarks($connid,autojoin,$jid) $autojoin
    set bookmarks($connid,groups,$jid) $groups
    set bookmarks($connid,hasgroups,$jid) 1

    # TODO should we remove $jid from the roster if it is here?
    client:roster_push $connid $jid $name $groups bookmark ""
    roster::override_category_and_subtype $connid $jid conference ""
    store_bookmarks $connid
}

###############################################################################
#
#   Update bookmark in roster
#

proc conferences::update_bookmark {connid jid args} {
    variable bookmarks

    set store 0

    foreach {key val} $args {
	switch -- $key {
	    -name { set name $val }
	    -nick { set nick $val }
	    -password { set password $val }
	    -autojoin { set autojoin $val }
	    -groups { set groups $val }
	}
    }

    if {[info exists name] && $name != $bookmarks($connid,name,$jid)} {
	set bookmarks($connid,name,$jid) $name
	set store 1
    }
    if {[info exists nick] && $nick != $bookmarks($connid,nick,$jid)} {
	set bookmarks($connid,nick,$jid) $nick
	set store 1
    }
    if {[info exists password] && $password != $bookmarks($connid,password,$jid)} {
	set bookmarks($connid,password,$jid) $password
	set store 1
    }
    if {[info exists autojoin] && $autojoin != $bookmarks($connid,autojoin,$jid)} {
	set bookmarks($connid,autojoin,$jid) $autojoin
	set store 1
    }
    if {[info exists groups] && [lsort $groups] != [lsort $bookmarks($connid,groups,$jid)]} {
	set bookmarks($connid,groups,$jid) $groups
	set store 1
    }
    if {$store} {
	client:roster_push $connid $jid $bookmarks($connid,name,$jid) \
	    $bookmarks($connid,groups,$jid) bookmark ""
	roster::override_category_and_subtype $connid $jid conference ""
	store_bookmarks $connid
    }
}

###############################################################################
#
#   Add or update item in roster
#

proc conferences::send_bookmark {connid jid} {

    if {[roster::itemconfig $connid $jid -subsc] != "bookmark"} return

    set groups [roster::itemconfig $connid $jid -group]

    add_bookmark $connid $jid -groups $groups
    update_bookmark $connid $jid -groups $groups

    return stop
}

hook::add roster_send_item_hook [namespace current]::conferences::send_bookmark

###############################################################################
#
#   Remove bookmark from roster
#

proc conferences::remove_bookmark {connid jid} {
    variable bookmarks

    if {[roster::itemconfig $connid $jid -subsc] != "bookmark"} return

    if {![info exists bookmarks($connid,jid,$jid)]} return

    client:roster_push $connid $jid $bookmarks($connid,name,$jid) \
		       $bookmarks($connid,groups,$jid) \
		       remove ""

    catch { unset bookmarks($connid,jid,$jid) }
    catch { unset bookmarks($connid,name,$jid) }
    catch { unset bookmarks($connid,nick,$jid) }
    catch { unset bookmarks($connid,password,$jid) }
    catch { unset bookmarks($connid,autojoin,$jid) }
    catch { unset bookmarks($connid,groups,$jid) }
    catch { unset bookmarks($connid,hasgroups,$jid) }

    store_bookmarks $connid

    return stop
}

hook::add roster_remove_item_hook \
    [namespace current]::conferences::remove_bookmark

###############################################################################
#
#   Rename group in roster bookmarks
#

proc conferences::rename_group {connid name new_name} {
    variable bookmarks
    
    set store 0
    foreach idx [array names bookmarks $connid,jid,*] {
	set jid $bookmarks($idx)
   
	set groups $bookmarks($connid,groups,$jid)
	if {[lcontain $groups $name] || \
		($name == $roster::undef_group_name && $groups == {})} {
	    set idx [lsearch -exact $groups $name]
	    if {$new_name != ""} {
		set groups [lreplace $groups $idx $idx $new_name]
	    } else {
		set groups [lreplace $groups $idx $idx]
	    }
	    set groups [lrmdups $groups]
	    client:roster_push $connid $jid $bookmarks($connid,name,$jid) \
			       $groups bookmark ""
	    roster::override_category_and_subtype $connid $jid conference ""
	    set bookmarks($connid,groups,$jid) $groups
	    set store 1
	}
    }
    if {$store} {
	store_bookmarks $connid
    }
}

hook::add roster_rename_group_hook \
    [namespace current]::conferences::rename_group

###############################################################################
#
#   Remove group name from roster bookmarks
#

proc conferences::remove_bookmarks_group {connid name} {
    variable bookmarks

    set store 0
    foreach idx [array names bookmarks $connid,jid,*] {
	set jid $bookmarks($idx)

	set groups $bookmarks($connid,groups,$jid)
	if {(([llength $groups] == 1) && [lcontain $groups $name]) || \
		(($name == $roster::undef_group_name) && ($groups == {}))} {
	    
	    client:roster_push $connid $jid $bookmarks($connid,name,$jid) \
			       $groups remove ""

	    catch { unset bookmarks($connid,jid,$jid) }
	    catch { unset bookmarks($connid,name,$jid) }
	    catch { unset bookmarks($connid,nick,$jid) }
	    catch { unset bookmarks($connid,password,$jid) }
	    catch { unset bookmarks($connid,autojoin,$jid) }
	    catch { unset bookmarks($connid,groups,$jid) }
	    
	    set store 1
	} elseif {[lcontain $groups $name]} {
	    set idx [lsearch -exact $groups $name]
	    set groups [lreplace $groups $idx $idx]
	    
	    client:roster_push $connid $jid $bookmarks($connid,name,$jid) \
			       $groups bookmark ""
	    roster::override_category_and_subtype $connid $jid conference ""
	    set bookmarks($connid,groups,$jid) $groups
	    
	    set store 1
	}
    }
    if {$store} {
	store_bookmarks $connid
    }
}

hook::add roster_remove_users_group_hook \
    [namespace current]::conferences::remove_bookmarks_group

###############################################################################
#
#   Join group on roster item doubleclick
#

proc conferences::join_group {connid jid} {
    variable bookmarks
    
    set args {}
    if {$bookmarks($connid,nick,$jid) != ""} {
	lappend args -nick $bookmarks($connid,nick,$jid)
    }
    if {$bookmarks($connid,password,$jid) != ""} {
	lappend args -password $bookmarks($connid,password,$jid)
    }
    eval [list ::join_group $jid -connection $connid] $args
}

###############################################################################
#
#   Join group during autojoin
#

proc conferences::autojoin_group {connid jid} {
    variable bookmarks
    global gr_nick
    
    if {$bookmarks($connid,nick,$jid) != ""} {
	set nick $bookmarks($connid,nick,$jid)
    } else {
	set nick [get_group_nick $jid $gr_nick]
    }
    if {$bookmarks($connid,password,$jid) != ""} {
	set password $bookmarks($connid,password,$jid)
    } else {
	set password ""
    }
    after idle [list muc::join_group $connid $jid $nick $password]
}

###############################################################################
#
#   Autojoin groups
#

proc conferences::autojoin_groups {connid} {
    variable bookmarks

    foreach idx [array names bookmarks $connid,jid,*] {
	set jid $bookmarks($idx)
	set chatid [chat::chatid $connid $jid]
	if {$bookmarks($connid,autojoin,$jid) && ![chat::is_opened $chatid]} {
	    autojoin_group $connid $jid
	}
    }
}

###############################################################################
#
#   "Join" item in roster conference popup menu
#

proc conferences::popup_menu {m connid jid} {
    variable bookmarks

    set args {}
    if {[roster::itemconfig $connid $jid -subsc] == "bookmark"} {
	if {$bookmarks($connid,nick,$jid) != ""} {
	    lappend args -nick $bookmarks($connid,nick,$jid)
	}
	if {$bookmarks($connid,password,$jid) != ""} {
	    lappend args -password $bookmarks($connid,password,$jid)
	}
    }

    $m add command -label [::msgcat::mc "Join..."] \
	-command [list eval [list join_group_dialog \
				  -server [server_from_jid $jid] \
				  -group [node_from_jid $jid] \
				  -connection $connid] \
				  $args]
}   

hook::add roster_conference_popup_menu_hook \
    [namespace current]::conferences::popup_menu 20

###############################################################################
#
#   Roster doubleclick
#

proc conferences::roster_doubleclick {connid jid category subtype} {
    switch -- $category {
	conference {
	    if {[roster::itemconfig $connid $jid -subsc] == "bookmark"} {
		join_group $connid $jid
	    } else {
		global gr_nick
		::join_group $jid \
		    -nick [get_group_nick $jid $gr_nick] \
		    -connection $connid
	    }
	    return stop
	}
    }
}

hook::add roster_jid_doubleclick \
    [namespace current]::conferences::roster_doubleclick

###############################################################################
#
#   Main menu setup
#

proc conferences::main_menu {} {
    set m [.mainframe getmenu services]
    $m insert 2 command -label [::msgcat::mc "Add conference to roster..."] \
	-command [list [namespace current]::add_conference_dialog]
}

hook::add finload_hook [namespace current]::conferences::main_menu

###############################################################################
#
#   Edit roster item
#

proc conferences::edit_item_setup {f connid jid} {
    variable egra_name
    variable egra_nick
    variable egra_password
    variable egra_autojoin
    variable bookmarks

    if {[roster::itemconfig $connid $jid -subsc] != "bookmark"} return

    set tf [TitleFrame $f.prop \
		-text [::msgcat::mc "Edit properties for %s" $jid]]
    set slaves [pack slaves $f]
    if {$slaves == ""} {
	pack $tf -side top -expand yes -fill both
    } else {
	pack $tf -side top -expand yes -fill both -before [lindex $slaves 0]
    }
    set g [$tf getframe]

    set egra_name $bookmarks($connid,name,$jid)
    set egra_autojoin $bookmarks($connid,autojoin,$jid)
    if {[info exists bookmarks($connid,nick,$jid)]} {
        set egra_nick $bookmarks($connid,nick,$jid)
    } else {
        set egra_nick ""
    }
    if {[info exists bookmarks($connid,password,$jid)]} {
        set egra_password $bookmarks($connid,password,$jid)
    } else {
        set egra_password ""
    }

    label $g.lname -text [string trim [::msgcat::mc "Name: "]]
    entry $g.name -textvariable [namespace current]::egra_name
    label $g.lnick -text [::msgcat::mc "Nick:"]
    entry $g.nick -textvariable [namespace current]::egra_nick
    label $g.lpassword -text [::msgcat::mc "Password:"]
    entry $g.password -show * -textvariable [namespace current]::egra_password
    checkbutton $g.autojoin \
	-text [::msgcat::mc "Automatically join conference upon connect"] \
        -variable [namespace current]::egra_autojoin
    grid columnconfigure $g 0 -weight 0
    grid columnconfigure $g 1 -weight 1

    grid $g.lname  -row 0 -column 0 -sticky e
    grid $g.name   -row 0 -column 1 -sticky ew
    grid $g.lnick -row 1 -column 0 -sticky e
    grid $g.nick  -row 1 -column 1 -sticky ew
    grid $g.lpassword -row 2 -column 0 -sticky e
    grid $g.password  -row 2 -column 1 -sticky ew
    grid $g.autojoin -row 3 -column 0 -sticky w -columnspan 2

    return stop
}

hook::add roster_itemedit_setup_hook \
    [namespace current]::conferences::edit_item_setup

proc conferences::commit_bookmark_changes {connid jid groups} {
    variable egra_name
    variable egra_nick
    variable egra_password
    variable egra_autojoin

    if {[roster::itemconfig $connid $jid -subsc] != "bookmark"} return

    plugins::conferences::update_bookmark $connid $jid \
	-name $egra_name -nick $egra_nick -password $egra_password \
	-autojoin $egra_autojoin -groups $groups

    return stop
}

hook::add roster_itemedit_commit_hook \
    [namespace current]::conferences::commit_bookmark_changes

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

proc conferences::disco_node_menu_setup {m bw tnode data parentdata} {
    lassign $data type connid jid node
    lassign $parentdata ptype pconnid pjid pnode
    switch -- $type {
	item {
	    set identities [disco::get_jid_identities $connid $jid $node]
	    set pidentities [disco::get_jid_identities $pconnid $pjid $pnode]

	    # JID with resource is not a room JID
	    if {[node_and_server_from_jid $jid] != $jid} return

	    if {[lempty $identities]} {
		set identities $pidentities
	    }

	    foreach id $identities {
		if {[jlib::wrapper:getattr $id category] == "conference"} {
		    $m add command -label [::msgcat::mc "Add conference to roster..."] \
			-command [list [namespace current]::add_conference_dialog \
				       -group [node_from_jid $jid] \
				       -server [server_from_jid $jid] \
				       -connection $connid]
		    break
		}
	    }
	}
    }
}

hook::add disco_node_menu_hook \
	  [namespace current]::conferences::disco_node_menu_setup 50

# vim:ts=8:sw=4:sts=4:noet