1# $Id$
2
3namespace eval conferenceinfo {
4    custom::defgroup ConferenceInfo \
5	[::msgcat::mc "Options for Conference Info module, that allows you\
6		       to see list of participants in roster popup,\
7		       regardless of whether you are currently joined\
8		       with the conference."] \
9	-group Plugins \
10	-tag "Conference Info"
11
12    custom::defvar options(autoask) 0 \
13	[::msgcat::mc "Use this module"] -group ConferenceInfo -type boolean \
14	-command [namespace current]::ask
15    custom::defvar options(interval) 2 \
16	[::msgcat::mc "Interval (in minutes) between requests of participants list."] \
17	-type integer -group ConferenceInfo
18    custom::defvar options(err_interval) 60 \
19	[::msgcat::mc "Interval (in minutes) after error reply on request of participants list."] \
20	-type integer -group ConferenceInfo
21}
22
23
24# TODO: xlib
25proc conferenceinfo::add_user_popup_info {infovar xlib jid} {
26    variable data
27    variable options
28    upvar 0 $infovar info
29
30    if {!$options(autoask)} return
31    if {[chat::is_opened [chat::chatid $xlib $jid]]} return
32
33    if {![info exists data(error_browse,$jid)] || \
34	    ![info exists data(error_disco,$jid)]} return
35
36    if {$data(error_disco,$jid) != "" && $data(error_browse,$jid) != ""} {
37	if {$data(error_browse_code,$jid) != "feature-not-implemented" && \
38		$data(error_browse_code,$jid) != "service-unavailable"} {
39	    set errstr $data(error_browse,$jid)
40	} else {
41	    set errstr $data(error_disco,$jid)
42	}
43	append info [::msgcat::mc "\n\tCan't browse: %s" $errstr]
44    } else {
45	if {$data(error_browse,$jid) == ""} {
46	    set mech browse
47	} else {
48	    set mech disco
49	}
50	if {$data(users_$mech,$jid) != {}} {
51	    append info \
52		[::msgcat::mc "\nRoom participants at %s:" \
53		     [clock format $data(time_$mech,$jid) -format %R]]
54	    foreach name $data(users_$mech,$jid) {
55		append info "\n\t$name"
56	    }
57	} else {
58	    append info \
59		[::msgcat::mc "\nRoom is empty at %s" \
60		     [clock format $data(time_$mech,$jid) -format %R]]
61	}
62    }
63}
64hook::add roster_user_popup_info_hook \
65    [namespace current]::conferenceinfo::add_user_popup_info
66
67
68proc conferenceinfo::ask {args} {
69    variable options
70    variable data
71
72    if {!$options(autoask)} return
73
74    foreach xlib [connections] {
75	if {[catch { set roster::roster(jids,$xlib) } jids]} {
76	    continue
77	}
78	foreach jid $jids {
79	    lassign [roster::get_category_and_subtype $xlib $jid] \
80		category type
81	    if {$category == "conference" && [::xmpp::jid::node $jid] != "" && \
82		    ![chat::is_opened [chat::chatid $xlib $jid]]} {
83
84		set sec [clock seconds]
85
86		if {![info exists data(error_browse,$jid)] || \
87			$data(error_browse,$jid) == "" || \
88			$sec - $data(time_browse,$jid) >= $options(err_interval) * 60} {
89
90		    ::xmpp::sendIQ $xlib get \
91			-query [::xmpp::xml::create query \
92					-xmlns jabber:iq:browse] \
93			-to $jid \
94			-command [list [namespace current]::receive $jid browse]
95		}
96
97		if {![info exists data(error_disco,$jid)] || \
98			$data(error_disco,$jid) == "" || \
99			$sec - $data(time_disco,$jid) >= $options(err_interval) * 60} {
100
101		    ::disco::request_items $xlib $jid \
102			-command [list [namespace current]::receive $jid disco]
103		}
104	    }
105	}
106    }
107
108    after cancel [list [namespace current]::ask]
109    after [expr {$options(interval) * 60 * 1000}] [list [namespace current]::ask]
110}
111
112proc conferenceinfo::receive {jid mech status xml} {
113    variable options
114    variable data
115
116    set data(error_$mech,$jid) ""
117    set data(error_${mech}_code,$jid) ""
118    set data(time_$mech,$jid) [clock seconds]
119    set data(users_$mech,$jid) {}
120
121    if {$status != "ok"} {
122	set data(error_${mech}_code,$jid) [lindex [error_type_condition $xml] 1]
123	set data(error_$mech,$jid) [error_to_string $xml]
124	return
125    }
126
127    switch -- $mech {
128	browse {
129	    ::xmpp::xml::split $xml tag xmlns attrs cdata subels
130
131	    foreach item $subels {
132		::xmpp::xml::split $item stag sxmlns sattrs scdata ssubels
133		set category [::xmpp::xml::getAttr $sattrs category]
134		set name [::xmpp::xml::getAttr $sattrs name]
135		if {$stag == "user" || ($stag == "item" && $category == "user")} {
136		    if {$name != ""} {
137			lappend data(users_browse,$jid) $name
138		    }
139		}
140	    }
141	}
142	disco {
143	    foreach item $xml {
144		set name [::xmpp::xml::getAttr $item name]
145		set node [::xmpp::xml::getAttr $item node]
146		if {$name != "" && $node == ""} {
147		    lappend data(users_disco,$jid) $name
148		}
149	    }
150	}
151    }
152    set data(users_$mech,$jid) [lsort -dictionary $data(users_$mech,$jid)]
153}
154
155proc conferenceinfo::stop {args} {
156    if {[connections] == {}} {
157	after cancel [list [namespace current]::ask]
158    }
159}
160
161hook::add roster_end_hook [namespace current]::conferenceinfo::ask
162hook::add disconnected_hook [namespace current]::conferenceinfo::stop
163
164proc conferenceinfo::setup_menu {} {
165    set m [.mainframe getmenu roster]
166
167    $m add checkbutton \
168	-label [::msgcat::mc "Periodically browse roster conferences"] \
169	-variable [namespace current]::options(autoask)
170}
171hook::add finload_hook [namespace current]::conferenceinfo::setup_menu
172
173