# 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
    }

    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}
        *coccinella*						{set icon clients/coccinella}
        *emess*                             {set icon clients/emess}
        *exodus*							{set icon clients/exodus}
        *fatal-bot*                         -
        *fatal-dev.ru/bot*			        {set icon clients/fatal-bot}
        *stranger.kiev.ua*                  {set icon clients/fj}
        *gajim*								{set icon clients/gajim}
        *code.google.com/p/vacuum-im*       -
        *vacuum*							{set icon clients/vacuum}
        *gmail*                             -
        *google.com*						{set icon clients/google.com}
        *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}
        *japyt*								{set icon clients/japyt}
        *jimm*								{set icon clients/jimm-aspro}
        *jbot*								{set icon clients/jbother}
        *kopete*							{set icon clients/kopete}
        *leechcraft*						{set icon clients/leechcraft}
        *mchat*								{set icon clients/mchat}
        *miranda*							{set icon clients/miranda}
        *mail.google.com*					{set icon clients/mail.google.com}
        *mcabber*							{set icon clients/mcabber}
        *mrim*                              -
        *svn.xmpp.ru*                       -
        *none*								{set icon clients/mailruagent}
        *mandarin*                          {set icon clients/mandarin}
        *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}
        *process-one.net*					{set icon clients/oneteamiphone}
        *qutim*								{set icon clients/qutim}
        "*siemens native jabber client*"    -
        *siejc*								{set icon clients/siejc}
        "*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}
        *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}
        *bot*   							{set icon clients/bot}
        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
    variable roster

    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]

    if {$sjid != [lindex $group 1]} {
        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 {$type != "metajid"} {
                        if {[info exists roster(jidcollapsed,$group,$jid)] && !$roster(jidcollapsed,$group,$jid)} {
                            continue
                        }
                    } else {
                        if {[info exists roster(metacollapsed,$group,$metajids)] && !$roster(metacollapsed,$group,$metajids)} {
                            continue
                        }
                    }

                    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% [chat::chatid $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
}
