cims_interconnect.tcl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. # CIMS: Community IRC Messaging Service
  2. # CIMS formerly known as MNET (Message Network)
  3. # Multiple Network Interconnection MASTER Script
  4. # Copyright (C) 2004 Paul-Dieter Klumpp
  5. #
  6. # This program is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License
  8. # as published by the Free Software Foundation; either version 2
  9. # of the License, or (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program; if not, write to the Free Software
  18. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. # vim: expandtab tabstop=2 shiftwidth=2 softtabstop=2 autoindent:
  20. namespace eval ::cims::interconnect {
  21. variable layout
  22. variable sshcommand {ssh}
  23. variable host {stomp@b4r.org}
  24. variable mnet_interconnect_version "ic!0.1"
  25. }
  26. proc ::cims::interconnect::connect {} {
  27. variable sshcommand
  28. variable host
  29. variable pipe
  30. set command $sshcommand
  31. lappend command $host
  32. putlog "command is $command"
  33. if {[catch {
  34. if {![info exists pipe] || $pipe == ""} {
  35. set pipe [open "|$command" r+]
  36. fconfigure $pipe -translation binary -blocking 0 -buffering line
  37. } else {
  38. putlog "already connected here: $pipe"
  39. }
  40. } error]} {
  41. set pipe ""
  42. putlog "error $error"
  43. #conect again in a time
  44. } else {
  45. # read from console input
  46. ::cims::interconnect::readloop
  47. # check if connection is alive.. if not, reset it.
  48. ::cims::interconnect::pingloop
  49. }
  50. }
  51. proc ::cims::interconnect::connect_from_bind {nick mask hand chan text} {
  52. ::cims::interconnect::connect
  53. }
  54. proc ::cims::interconnect::disconnect {} {
  55. variable pipe
  56. ::cims::interconnect::send "PART"
  57. close $pipe
  58. set pipe ""
  59. }
  60. proc ::cims::interconnect::disconnect_from_bind {nick mask hand chan text} {
  61. ::cims::interconnect::disconnect
  62. }
  63. proc ::cims::interconnect::reconnect {} {
  64. ::cims::interconnect::disconnect
  65. ::cims::interconnect::connect
  66. }
  67. proc ::cims::interconnect::reconnect_from_bind {nick mask hand chan text} {
  68. ::cims::interconnect::reconnect
  69. }
  70. proc ::cims::interconnect::send {msg} {
  71. variable pipe
  72. if {$msg != "" && $pipe != ""} {
  73. putlog "writing $msg to pipe '$pipe'"
  74. if {[catch {
  75. puts $pipe "$msg"
  76. } error]} {
  77. close $pipe
  78. set pipe ""
  79. # well, it seems, our connection is broken, let's reconnect in 2 seconds.
  80. utimer 2 "::cims::interconnect::connect"
  81. }
  82. }
  83. }
  84. proc ::cims::interconnect::send_from_bind {nick mask hand chan text} {
  85. ::cims::interconnect::send "$text"
  86. }
  87. proc ::cims::timeout_reply_from_ic_for_netbot {netbot network freqname source} {
  88. set bcid $::cims::interconnect::sources($freqname,$source)
  89. if {[info exists ::cims::interconnect::receive_count($bcid)]} {
  90. set count_list $::cims::interconnect::receive_count($bcid)
  91. set output_for_netbot "And to "
  92. foreach {item count} $count_list {
  93. set output_for_netbot "$output_for_netbot $count ${item}, "
  94. }
  95. set output_for_netbot "[string range $output_for_netbot 0 [expr [string length $output_for_netbot] - 2]"
  96. set output_for_netbot "${output_for_netbot}."
  97. putlog "w000000t: $output_for_netbot"
  98. # Give him a reply.
  99. ::cims::put_bot $netbot "mnet_interconnect_answer $network $freqname $source $output_for_netbot"
  100. }
  101. }
  102. proc ::cims::timeout_reply_from_local_for_ic {bcid network freqname source} {
  103. variable mnet_reached_users
  104. variable mnet_reached_userlist
  105. variable mnet_reached_chans
  106. # clean $name and $source
  107. set freqname [::putils::kill_spaces $freqname]
  108. #set source [::putils::kill_spaces $source]
  109. putlog "source: $source"
  110. # easify variables
  111. set userlist $mnet_reached_userlist($freqname,$source)
  112. set user_cnt [llength $userlist]
  113. set mnet_reached_users($freqname,$source) $user_cnt
  114. set chan_cnt $mnet_reached_chans($freqname,$source)
  115. # inzwischen drfte auch die antwort gekommen sein.. also jetzt mnet_reached_* auswerten nach timeout..
  116. # make stats channel-dependent
  117. #putlog "::cims:: * userlist is finally: $userlist "
  118. putlog "::cims:: * After ALL: Count_Users: $user_cnt Count_Channels: $mnet_reached_chans($freqname,$source)"
  119. # Give me some reply.
  120. ::cims::interconnect::send "BC_RE $bcid Users=$user_cnt,Channels=$chan_cnt"
  121. }
  122. # this proc is a new proc for cims.
  123. # the message came from interconnect and injects into the netbots and own channels
  124. proc ::cims::message_from_interconnect {network freqname source nick text} {
  125. variable mnet_reached_users
  126. variable mnet_reached_userlist
  127. variable mnet_reached_chans
  128. #putlog "freqname: $freqname"
  129. putlog "source: $source"
  130. #putlog "nick: $nick"
  131. #putlog "text: $text"
  132. # reset stats .. because he is just freshly sending
  133. set mnet_reached_users($freqname,$source) "0"
  134. set mnet_reached_userlist($freqname,$source) ""
  135. set mnet_reached_chans($freqname,$source) "0"
  136. ::cims::history_queue $network,$freqname $nick $source $text
  137. # send them first, we await a reply!
  138. # single sends TO ALL REMOTE BOTS with their remote CHANNELS...
  139. # let's see which mode for sending is used...
  140. ::cims::message_to_netbots $network $freqname $source $nick $text
  141. # SEND TO ALL OWN CHANNELS...
  142. # send to all own channels, except to the channel the message originating from:
  143. ::cims::message_to_own_channels $network $freqname $source $nick $text
  144. }
  145. proc ::cims::interconnect::add_up {bcid item count} {
  146. variable receive_count
  147. # schon drin?
  148. if {![info exists receive_count($bcid)]} {
  149. set receive_count($bcid) ""
  150. }
  151. set position [lsearch $receive_count($bcid) $item]
  152. if {$position > -1} {
  153. #putlog "item: $item is drin, weil posi $position"
  154. set the_old_count [lindex $receive_count($bcid) [expr $position + 1]]
  155. # the_old_count gets increased by $count
  156. incr the_old_count $count
  157. # we set it ..
  158. lset receive_count($bcid) [expr $position + 1] $the_old_count
  159. } else {
  160. #putlog "item: $item nicht drin, weil posi $position"
  161. lappend receive_count($bcid) "$item" "$count"
  162. }
  163. #putlog "hum: $receive_count($bcid)"
  164. }
  165. # called right before the output...
  166. proc ::cims::timeout_reply_from_local_for_netbots_plugin {freqname source} {
  167. upvar output output
  168. set bcid $::cims::interconnect::sources($freqname,$source)
  169. if {[info exists ::cims::interconnect::receive_count($bcid)]} {
  170. set output "$output $::cims::interconnect::receive_count($bcid)"
  171. }
  172. }
  173. # this is the stuff we read on the console.
  174. proc ::cims::interconnect::work {inputline} {
  175. variable broadcasts
  176. variable sources
  177. variable receive_count
  178. #putlog "work that out: $inputline"
  179. regexp -lineanchor {^.*\d: (.*)} $inputline matched sub
  180. putlog "subline: $sub"
  181. if {[regexp -all {^PONG} $sub] > 0} {
  182. #putlog "interconnect pong received"
  183. } elseif {[regexp -lineanchor -all {^(BC_ID) (.+) for: (.+),(.+),(.+)$} $sub whole command bcid network freqname source] > 0} {
  184. # this tells us, we sent a REQ_BC before.
  185. set broadcasts($bcid) [list "$network" "$freqname" "$source"]
  186. set ::cims::interconnect::sources($freqname,$source) "$bcid"
  187. #putlog "bcid vars saved: $broadcasts($bcid) "
  188. # reset receive counters.
  189. set receive_user_count($bcid) 0
  190. set receive_item_count($bcid) 0
  191. } elseif {[regexp -lineanchor -all {^(BC_RE) (.+) (.+)=(\d+),(.+)=(\d+)$} $sub whole command bcid user_string user_count item_string item_count] > 0} {
  192. #BC_RE f4k3h4sh 5,3
  193. # central does some routing over central to make sure, the BC_RE message is only sent to me
  194. # ok cool .. i hope we sent a message with that $bcid before. And
  195. #.. we check on $bcid - find out the correct cims-vars (chan, freq, etc)
  196. # and add user_count, item_count to them.
  197. # now, let's validate that bcid .. we check if that bcid exists.. so the originating message is from me.
  198. if {[info exists broadcasts($bcid)] == 1} {
  199. set that $broadcasts($bcid)
  200. set network [join [lindex $that 0]]
  201. set freqname [join [lindex $that 1]]
  202. set source [join [lindex $that 2]]
  203. # count up
  204. ::cims::interconnect::add_up "$bcid" "$user_string" "$user_count"
  205. ::cims::interconnect::add_up "$bcid" "$item_string" "$item_count"
  206. # ready the variable, so it can be read from the plugin.
  207. set ::cims::interconnect::receive_count($bcid) "$::cims::interconnect::receive_count($bcid)"
  208. }
  209. } elseif {[regexp -lineanchor -all {^(BC) (.+) (.+),(.+),(.+),'(.+)','(.+)'$} $sub whole command bcid network freqname source nick text] > 0} {
  210. # THIS IS FRESH INPUT. ESCAPE IT.
  211. set freqname [split $freqname]
  212. set source [split $source]
  213. set nick [split $nick]
  214. set text [split $text]
  215. putlog "freqname: $freqname"
  216. putlog "source: $source"
  217. putlog "nick: $nick"
  218. putlog "text: $text"
  219. # parse here above.. or just use:
  220. #set network "QDEV"
  221. #set freqname "-dev-"
  222. #set source "http://qwnu"
  223. #set nick "testnickname"
  224. #set text "testmessage"
  225. # here, we read a message from central and put it to all local channels and netbots.
  226. ::cims::message_from_interconnect $network $freqname $source $nick $text
  227. # in the meantime, we even get all replies and counts (by ::cims::).
  228. # Now, we should get that count and send it to the central as a reply. Hitting the original sender.
  229. utimer 4 "::cims::timeout_reply_from_local_for_ic $bcid $network $freqname [list $source]"
  230. } elseif {[regexp -all {^WHO.*} $sub whole] > 0} {
  231. # ignore this one - it's fully handled by central.
  232. } elseif {[regexp -all -nocase {^C (.*): (.*)} $sub whole sub1 sub2] > 0} {
  233. # received, with command "C "
  234. if {"$sub2" != ""} {
  235. ::putils::put_local_msg "#aztest" "C $sub1: $sub2"
  236. }
  237. } else {
  238. # received, but it has no command
  239. #::putils::put_local_msg "#aztest" "not handled: $sub"
  240. }
  241. }
  242. proc ::cims::interconnect::read {} {
  243. variable pipe
  244. #putlog "into read"
  245. if {$pipe != ""} {
  246. #while { ![eof $pipe] } {
  247. gets $pipe inputline
  248. if {$inputline != ""} {
  249. ::cims::interconnect::work "$inputline"
  250. }
  251. #}
  252. }
  253. #putlog "ending of read"
  254. }
  255. proc ::cims::interconnect::readloop {} {
  256. variable pipe
  257. # check timers.. if old is running, don't start a new one
  258. set timerlist [utimers]
  259. set matched 0
  260. foreach {timerinfo} $timerlist {
  261. set timer_proc [join [lindex $timerinfo 1]]
  262. set timer_id [join [lindex $timerinfo 2]]
  263. if {[string match -nocase "::cims::interconnect::readloop" $timer_proc] == 1} {
  264. set matched 1
  265. }
  266. }
  267. if {$matched == 0 && $pipe != ""} {
  268. utimer 1 "::cims::interconnect::readloop"
  269. }
  270. # read a line
  271. ::cims::interconnect::read
  272. }
  273. proc ::cims::interconnect::ping {} {
  274. #putlog "into read"
  275. ::cims::interconnect::send "PING"
  276. }
  277. proc ::cims::interconnect::pingloop {} {
  278. variable pipe
  279. # check timers.. if old is running, don't start a new one
  280. set timerlist [utimers]
  281. set matched 0
  282. foreach {timerinfo} $timerlist {
  283. set timer_proc [join [lindex $timerinfo 1]]
  284. set timer_id [join [lindex $timerinfo 2]]
  285. if {[string match -nocase "::cims::interconnect::pingloop" $timer_proc] == 1} {
  286. set matched 1
  287. }
  288. }
  289. if {$matched == 0 && $pipe != ""} {
  290. utimer 120 "::cims::interconnect::pingloop"
  291. }
  292. # start a ping
  293. ::cims::interconnect::ping
  294. }
  295. # this proc is a plugin proc for cims. it only gets executed if it exists.
  296. # the message came from our bot.
  297. proc ::cims::message_from_local_plugin {network freqname source nick text} {
  298. # send the message into central
  299. putlog "wo bin ich da? $source"
  300. ::cims::interconnect::send "REQ_BC $network,$freqname,$source,'$nick','$text'"
  301. # save BC_ID for this combination of parameters - is done in the above "::work"
  302. # receive answers from the other networks
  303. # prepare stats so that the local stats-counter takes it. the local stats are getting put out
  304. # at the end of ::cims::messaging_public_from_bind by ::cims::reply_timeout
  305. }
  306. # this proc is a plugin proc for cims. it only gets executed if it exists.
  307. # we received a message from a netbot
  308. proc ::cims::message_from_netbot_to_plugin {netbot network freqname source nick text} {
  309. # send the message into central
  310. ::cims::interconnect::send "REQ_BC $network,$freqname,$source,'$nick','$text'"
  311. # receive answers from the other networks
  312. # in the meantime, we get all the BC_RE replies and counts.
  313. # Now, we should get that count and send it to originating netbot.
  314. utimer 5 "::cims::timeout_reply_from_ic_for_netbot $netbot $network $freqname $source"
  315. # send an own answer to the originating netbot
  316. }
  317. proc ::cims::interconnect::bindings {} {
  318. bind pub - !mnet_connect ::cims::interconnect::connect_from_bind
  319. bind pub - !mnet_disconnect ::cims::interconnect::disconnect_from_bind
  320. bind pub - !mnet_reconnect ::cims::interconnect::reconnect_from_bind
  321. bind pub - !mnet_input ::cims::interconnect::send_from_bind
  322. }
  323. proc ::cims::interconnect::main {} {
  324. variable mnet_interconnect_version
  325. variable pipe
  326. putlog "mnet! = mnet interconnection MASTER script loaded: $mnet_interconnect_version"
  327. ::cims::interconnect::bindings
  328. ::cims::interconnect::connect
  329. }
  330. namespace eval ::cims::interconnect {
  331. # timer weil $botnet-nick nicht sofort von eggdrop gesetzt wird
  332. utimer 3 "::cims::interconnect::main"
  333. }