# Client Icons plugin (52 clients) 02-07-2009 r5 (Jet <megaxbit@xmpp.ru>) 
# Modifications, extentions etc. (c) 2010 ancestor <xmpp:ancestor@jabber.org>
# This plugin contains some portions of Psi+ <http://psi-dev.googlecode.com>
# and Gajim <http://gajim.org> free jabber clients.

namespace eval clienticons {
    if {[catch {package require Img}]} {
        return
    }

	variable jidnodes
	variable icondir
    variable aicsdir

    ::msgcat::mcload [file join [file dirname [info script]] msgs]

    if {![::plugins::is_registered clienticons]} {
        ::plugins::register clienticons \
            -namespace [namespace current] \
            -source [info script] \
            -description [::msgcat::mc "Client icons."] \
            -loadcommand [namespace code load] \
            -unloadcommand [namespace code unload]
        return
    }

    custom::defgroup Plugins [::msgcat::mc "Plugins options."] -group Tkabber

    custom::defvar options(show_clienticons) 1 \
        [::msgcat::mc "Show client icons."] \
        -type boolean -group {Client Icons}

    custom::defvar options(show_afficons) 1 \
        [::msgcat::mc "Show affiliation icons (only groupchats)."] \
        -type boolean -group {Client Icons}

	set icondir "[file dirname [info script]]/pixmap"
    set aicsdir "[file dirname [info script]]/afficons"
}

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

proc clienticons::caps_collector {xlib jid type x args} {
	variable jidnodes
	variable jidver
	if {$type == "unavailable"} {
		catch {unset jidnodes($jid)}
		catch {unset jidver($jid)}
		return
	}
	foreach xdata $x {
		if {[::xmpp::xml::getAttr $xdata c] == "http://jabber.org/protocol/caps"} {
			::xmpp::xml::split $xdata tag xmlns attrs cdata subels
			set jidnodes($jid) [::xmpp::xml::getAttr $attrs node]
			set jidver($jid) [::xmpp::xml::getAttr $attrs ver]
			return
		}
	}
}

proc ::get_client_from_jid {jid} {
	if {[info exists ::plugins::clienticons::jidnodes($jid)]} {
		return $::plugins::clienticons::jidnodes($jid)
	} else {
		return
	}
}

proc ::get_client_icon {jid} {
    if {$jid == "juick@juick.com" || [regexp ".*juick.com.*" $jid]} {
        set icon clients/juick
        return $icon
    } elseif {$jid == "psto@psto.net" || [regexp ".*psto.net.*" $jid]} {
        set icon clients/psto
        return $icon
    } elseif {$jid == "stoat@jabber.ru" || [regexp "stoat%jabber.ru.*" $jid]} {
        set icon clients/bot
        return $icon
    } elseif {[regexp ".*twitter.tweet.im.*" $jid]} {
        set icon clients/twitter
        return $icon
    } elseif {[regexp ".*@vk\..*" $jid]} {
        set icon clients/vk
        return $icon
    } elseif {[regexp ".*@facebook\..*" $jid]} {
        set icon clients/facebook
        return $icon
    }

	set node [::get_client_from_jid $jid]
    
	switch -glob -- [string tolower $node] {
		*adium*								{set icon clients/adium}
		*bitlbee*							{set icon clients/bitlbee}
		*bayanicq* -
		*barobin.com*						{set icon clients/bayanicq}
		*barracuda.com* -
		"*barracuda im client*"				{set icon clients/barracuda-im}
		*bombusmod.net.ru*					{set icon clients/bombusmod}
		*bombusmod-qd.wen.ru*				{set icon clients/bombusqd}	
		*bombus-im.org/ng* -
		*bombus-ng*							{set icon clients/bombusng}
		*bombus.pl*							{set icon clients/bombuspl}
		*bombus+* -
		*voffk.org.ru*						{set icon clients/bombusplus}
		*bombus-im.org/java*				{set icon clients/bombus}
		*bombus-im.org/android*				{set icon clients/bombuslime}
		*coccinella*						{set icon clients/coccinella}
		*exodus*							{set icon clients/exodus}
		*emess*								{set icon clients/emess}
		*fatal-bot*					        {set icon clients/fatal-bot}
		*freize*					        {set icon clients/freize-web-chat}
		*stranger.kiev.ua*                  {set icon clients/fj}
		*gajim*								{set icon clients/gajim}
		*code.google.com/p/vacuum-im* -
		*vacuum*							{set icon clients/vacuum}
		*glu.net*							{set icon clients/glu}
		*gluxibot*							{set icon clients/gluxibot}
		*gizmo*								{set icon clients/gizmo}
		*hotcoffee*							{set icon clients/mirandahotcoffee}
		*ichat*								{set icon clients/ichat}
		*isida-bot.com*						{set icon clients/isida-bot}
		*jabbim*							{set icon clients/jabbim}
		"*jabber weather.com transport*"	{set icon clients/weather.com}
		*jabber.el*							{set icon clients/jabber.el}
		*jajc* -
		"*just another jabber client*"		{set icon clients/jajc}
		*magnet2.py*						{set icon clients/magnet}
		*japyt*								{set icon clients/japyt}
		*jasmineicq*						{set icon clients/jasmine}
		*jimm*								{set icon clients/jimm-aspro}
		*jbot*								{set icon clients/jbother}
		*jtalk*								{set icon clients/jtalk}
		*kopete*							{set icon clients/kopete}
		*leechcraft*						{set icon clients/leechcraft}
		*mandarin_im*						{set icon clients/mandarin}
		*mchat*								{set icon clients/mchat}
		*miranda*							{set icon clients/miranda}
		*mail.google.com*					{set icon clients/mail.google.com}
		*talkgadget.google.com*				{set icon clients/google-talkwidget}
		*mcabber*							{set icon clients/mcabber}
		*mrim* -
		*svn.xmpp.ru* -
		*none*								{set icon clients/mailruagent}
		*nimbuzz*							{set icon clients/nimbuzz}
		*omnipresence* -
		*home.gna.org*						{set icon clients/omnipresence}
		*beeonline*							{set icon clients/om.beeonline.ru}
		*pandion*							{set icon clients/pandion}
		*psi+* -
		*psi-dev.googlecode.com*			{set icon clients/psiplus}
		*psi-im.org*						{set icon clients/psi}
		*pidgin*							{set icon clients/pidgin}
		*pyicqt.googlecode.com* -
		"*icq transport*"					{set icon clients/pyicq-t}
		"*vkontakte.ru transport*" -
		*pyvk-t*							{set icon clients/pyvk-t}
		*oneteam.im*						{set icon clients/oneteam}
		*oneteam_iphone*					{set icon clients/oneteamiphone}
		*qutim*								{set icon clients/qutim}
		"*siemens native jabber client*" -
		*siejc*								{set icon clients/siejc}
		*smack*								{set icon clients/smack-api}
		"*spark im client*"					{set icon clients/spark}
		*talkonaut*							{set icon clients/talkonaut}
		*talkgadget.google.com*				{set icon clients/talkgadget.google.com}
		*talk.google.com*					{set icon clients/talk.google.com}
		*tkabber*							{set icon clients/tkabber}
		*telepathy.freedesktop.org*			{set icon clients/telepathy.freedesktop.org}
		*online.yandex.ru*					{set icon clients/yaonline}
		*ya.online*							{set icon clients/yaonlinej2me}
		*yaonline*							{set icon clients/yaonlinesymbian}
        *juick.com*							{set icon clients/juick}
		*bluendo.com*						{set icon clients/lampiro}
		*pjc.googlecode.com*				{set icon clients/pjc_lib}
		*delx.net.au/projects/pymsnt*		{set icon clients/pymsnt}
		*msn-transport.jabberstudio.org*	{set icon clients/msn}
		*osiris-bot*						{set icon clients/osiris}
		*chat.ovi.com* - 
		"*ovi contacts*"					{set icon clients/ovi-chat}
		"*yabber instant messenger*"		{set icon clients/yabber}
		*trillian*							{set icon clients/trillian}
		*swift*								{set icon clients/swift}
		*sim*								{set icon clients/sim}
		"*sapo messenger mac*" -
		*messenger.sapo.pt*					{set icon clients/sapo}
		*xmpp4moz* -
		*hyperstruct.net*					{set icon clients/sameplace}
		*apps.radio-t.com*					{set icon clients/radio-t}
		*pda.qip.ru* -
		"*qip pda*"							{set icon clients/qippda}
        *qip*								{set icon clients/qipinfium}
		"*google talk user account*"		{set icon clients/android}
		"*www.android.com/gtalk/client*"	{set icon clients/android}
		*aqq*								{set icon clients/aqq}
		*asterisk*							{set icon clients/asterisk}
		*avalon*							{set icon clients/bombus-avalon}
		*klub54.wen.ru* -
		*bombusklub*						{set icon clients/bombus-klub}
		*talisman*							{set icon clients/bot}
		*buddydroid*						{set icon clients/buddydroid}
		*centerim*							{set icon clients/centerim}
		*freqbot*							{set icon clients/freqbot}
		"*google.com 1.0.0.66*"				{set icon clients/fring}
		*gismeteo.ru*						{set icon clients/gismeteo}
		*imov*								{set icon clients/imov}
		*jabbin*							{set icon clients/jabbin}
		*jabiru*							{set icon clients/jabiru}
		*jappix*							{set icon clients/jappix}
		*pjc*								{set icon clients/jubo}
		*mobileagent*						{set icon clients/mailruagent.sis}
		*meebo*								{set icon clients/meebo}
        "*blogger-bot*"						{set icon clients/blogger-bot}
        "*forum-bot*"						{set icon clients/forum-bot}
        *bot*storm* -
        *storm*bot*							{set icon clients/storm-bot}
        "*blacksmith-2*"					{set icon clients/blacksmith-bot}
		"*jame-bot*"   						{set icon clients/jame-bot}
        "*snapi-bot*"   					{set icon clients/snapi-bot}
        *bot*   							{set icon clients/unknown-bot}
		*gmail* -
		*google.com*						{set icon clients/google.com}
		default								{set icon clients/unknown}
	}
	return $icon
}

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

proc clienticons::popupinfo {var xlib user} {
	variable jidnodes
	variable jidver
	upvar 0 $var info
	if {[info exists jidnodes($user)]} {
		append info "\n\t$jidnodes($user) $jidver($user)"
	}
}

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

rename ::ifacetk::roster::addline ::ifacetk::roster::addline_old

proc ::ifacetk::roster::addline {w type text jid group metajids indent {jids {}} {icon ""} {foreground ""}} {
	variable iroster
	variable config

	set c $w.canvas

	set tag [jid_to_tag $jid]
	set grouptag [jid_to_tag $group]
	set metatag [jid_to_tag $metajids]
	
	set ypad 1
	set linespace [font metric $::RosterFont -linespace]
	set lineheight [expr {$linespace + $ypad}]
	
	set uy $iroster($w,ypos)
	set ly [expr {$uy + $lineheight + $config(textuppad) + $config(textdownpad)}]

	::ifacetk::roster::addline_old $w $type $text $jid $group $metajids $indent $jids $icon $foreground
	
	set xlib [lindex $jid 0]
	set mjid [lindex $jid 1]
	set sjid [::xmpp::jid::stripResource $mjid]

	lassign [::roster::get_category_and_subtype $xlib $sjid] category subtype	

	if {$type == "jid" || $type == "jid2" || $type == "metajid"} {
		if {$category == "conference" && $w == ".roster"} return
			set y [expr {($uy + $ly)/2}]		
			set x [expr [winfo width $c] - 2]
			
			if {$w == ".roster"} {set cjids $jids} else {set cjids [list $mjid]}
            
			if {$type == "metajid"} {
				foreach barejid $cjids {
					foreach fjid [::get_jids_of_user $xlib $barejid] {
						lappend tmpjlist $fjid
					}				
				}
				catch {set cjids $tmpjlist}
				catch {unset tmpjlist}
			}
            
			foreach j $cjids {
				if {[::get_jid_status $xlib $j] != "unavailable"} {
					set icon [::get_client_icon $j]
                    
                    if {$category == "conference"} {
                        if {$::plugins::clienticons::options(show_afficons)} {
                            set offset 7
                            
                            if {$::plugins::clienticons::options(show_clienticons)} {
                                set offset [expr $offset + 10]
                            }
                            
                            set role [::muc::get_role $xlib $j]
                            set aff [::muc::get_affiliation $xlib $j]
                            
                            if {$role == "visitor"} {
                                set affi visitor
                            } elseif {$aff == "owner"} {
                                set affi owner
                            } else {
                                set affi $aff
                            }
                            
                            $c create image [expr $x - $offset] $y -image afficons/$affi \
                                -anchor e \
                                -tag [list jid$tag group$grouptag meta$metatag $type icon afficon]
                        }
                    }
                        
                    if {[lsearch [image names] $icon] == -1} {
                        set icon clients/unknown
                    }
                       
                    if {$::plugins::clienticons::options(show_clienticons)} {
                        $c create image $x $y -image $icon \
                            -anchor e \
                            -tags [list jid$tag group$grouptag meta$metatag $type icon clienticon]
                    }
                    
					incr x [expr ([image height $icon] + 1) * -1]
				}
			}
            
		if {[bind $c <Expose>] == ""} {
			if {$w != ".roster" && $category == "conference"} {
				bind $c <Expose> [list ::chat::redraw_roster \
				[double% "$xlib $sjid"]]
			} else {
				bind $c <Expose> ::ifacetk::roster::redraw
			}
		}
	}
}

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

proc clienticons::load_images {xdata} {
	variable icondir
    variable aicsdir
	::xmpp::xml::split $xdata tag xmlns attrs cdata subels

	set csubels $subels
	foreach s $csubels {
		::xmpp::xml::split $s tag xmlns attrs cdata subels
		switch $tag {
			x		{set iconame [::xmpp::xml::getCdata $s]}
			object	{set filename "$icondir/[::xmpp::xml::getCdata $s]"}	
		}	
	}

    if {[file exists "$filename"]} {
        image create photo $iconame -file $filename
    }

    foreach ai {visitor none member admin owner outcast} {
        set affi "$aicsdir/${ai}.png"
        image create photo afficons/$ai -file $affi
    }
}

proc clienticons::parse_xml {xdata} {
	::xmpp::xml::split $xdata tag xmlns attrs cdata subels
	set csubels $subels
	foreach subel $csubels {
		::xmpp::xml::split $subel tag xmlns attrs cdata subels
		if {$tag == "icon"} {
			catch {[namespace current]::load_images $subel}
		}
    }
}

proc clienticons::load_client_icons {} {
	variable icondir
	if {![file exists "$icondir/icondef.xml"]} continue
	set fileid [open "$icondir/icondef.xml" r]
	set buffer [read $fileid]
	close $fileid
	catch {::xmpp::xml::parseData $buffer [list [namespace current]::parse_xml]}
}

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

proc clienticons::load {} {
    custom::defgroup {Client Icons} [::msgcat::mc "Client icons options."] -group Plugins -type visible

	[namespace current]::load_client_icons
	hook::add client_presence_hook [namespace current]::caps_collector
	hook::add roster_user_popup_info_hook [namespace current]::popupinfo 99
	::ifacetk::roster::redraw
}

proc clienticons::unload {} {
	hook::remove client_presence_hook	[namespace current]::caps_collector
	hook::remove roster_user_popup_info_hook [namespace current]::popupinfo 99
	rename ::ifacetk::roster::addline {}
	rename ::ifacetk::roster::addline_old ::ifacetk::roster::addline
	bind .roster.canvas <Expose>
	::ifacetk::roster::redraw

    custom::defgroup {Client Icons} [::msgcat::mc "Client icons options."] -group Plugins -type hidden
}