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