## Why this? # There was some nifty bot on QuakeNet which forwarded messages to other bots. # Its main purpose was to simplify match-organisation for 3d-shooter games. # # When a clan wanted to play a game, they simply had to do something like: # .qw let's play 4on4, come to 194.162.154.124:27500 # so every bot on the botnet received that message and forwarded it to other # clanchannels. # # The technology was first made by someone, but was not released by him. As far # as I can remember, it was a Q3-Urban Terror player. # The QuakeWorld-scene was interested in his script, but since the Q3-UT guy didn't # want to opensource his script a QW-player made a re-engineering. But still, # he didn't release the source. The QW-scene still uses the re-engineered script. # # When I asked the QW-scene guys for it, they didn't want THEIR re-engineered # project open sourced or even given to me. So..... # # ... now, I made a re-engineering from scratch too AND released the source. # Free for all. # # Man, you all suck. # # # This script is not yet as complete as their "so super secret technology" is, but # I wrote the core of it in about two nightly hours. More to come. # # 23.05.2004 Haudrauf of Quadaver # contact me if you want to contribute code snippets: #quadaver on QuakeNet ## CONFIG AND SOMEHOW README-SECTION FOLLOWS # You just have to connect your bots in a common eggdrop-botnet. Of course, every bot # has to have the same script installed. # The script uses "putallbots" to send messages to all linked bots on the botnet. Except # stated otherwhise here... but default is "0" to send to all bots. # A bot which doesn't have the script installed simply ignores the message though.. so, # who cares? set mnet(defined_bots) "0" # So here, you can chose the bots, where to send the messages to, by name. # You need to have mnet(defined_bots) "1", if you want to use the botlist below. # If you accidently added a bot here, which doesn't exist, it's no problem at all.. a small # errormessage will appear on the partyline. # WARNING: Recommendation is to have mnet(defined_bots) "0"! set mnet(bots) {"QUADAVER" "AQ2_01" "MyOwnBot"} # Here you set the channels of THIS bot, where you want received messages # to post to: set mnet(ownchannels) {"#pickup.aq2" "#quad.aq2"} #set mnet(ownchannels) {"#narf" "#action.dac" "#duel.aq2" "#we>you" "#[pulse]" "#action-nt.ger" "#mobsters" "#refugees" "#ace.aq2" "#only_human" "#akuh" "#q-aq2" "#mif" "#clan-duel" "#s4p" "#clan.fwd" "#sumpen" "#stener" "#dipunishment"} #set mnet(ownchannels) {"#extacy" "#cold!" "#aq2.cup" "#dpl.aq2" "#aq2world" "#clan-raw" "#attention!" "#rip" "#clan-Xk" "#clan-end"} # Set a Loglevel: 1 or 2 # 1 means: who, where, from # 2 means: who, where, from, what(text) set mnet(loglevel) "2" ###### Now, here are some important settings. Every bot in your network should have the same! ###### otherwise it sucks.. # banlist of ppl who are not allowed to use this bot. # this suxx... need a centralized version of this set mnetbans(1) {"*!*@*.quakenet.org" ""} # When a user wants to send a message, does he have to use .aq2 or .qw or something else? :) # Easily specify your public command: set mnet(public_cmd) ".aq2" # Set 1 or 0 here, whether you want to answer a posting request by the number of reached users. # nice idea to set to 1, thx. :) set mnet(answer) "1" # Here, you set the message layout. The prefix is how your messages begin with set mnet(prefix) "-AQ2-" # Display a nice helpmessage if someone only typed the public_cmd without arguments. set mnet(usage) "dot$mnet(prefix): Usage: '$mnet(public_cmd) need 4on4 at 20:00.' Rules: ONLY $mnet(prefix)related, only english and no replies over the bot! Use query or join their channel!" # Set the color.. 02 blue, 03 green, 05, red .. and so on, easy irc-colors. set mnet(color) "03" ############################################################################# # Now, hands away pls :) except you know what you are doing. set mnet(version) "mnet 0.666haui" set mnet(reached) "0" set mnet(reached_channels) "0" bind pub - $mnet(public_cmd) mnet:messaging_public bind bot - mnet_send mnet:receive_message bind bot - mnet_answer mnet:receive_answer proc mnet:get_data {n} { if {[string range $n 0 0] == "\{"} { set n "\\$n" } return $n } proc mnet:put_local_message {chan rec_nickname rec_channel rec_text} { global mnet puthelp "PRIVMSG $chan :$mnet(prefix) \003$mnet(color)$rec_nickname - $rec_channel : $rec_text" if {$mnet(loglevel) == "1"} { putlog "mnet: + local message from $rec_nickname @ $rec_channel to $chan" } elseif {$mnet(loglevel) == "2"} { putlog "mnet: + local message from $rec_nickname @ $rec_channel to $chan : $rec_text" } } proc mnet:put_nick {nick msg} { putserv "NOTICE $nick :$msg" } proc mnet:put_bot {botnick data} { set testlink [islinked $botnick] if {$testlink == "1"} { putbot $botnick $data } else { putlog "mnet: + Message couldn't be delivered. Bot $botnick is not linked" } } proc mnet:chanstat_users {chan users} { set ch_users [chanlist $chan] set ch_users_count [llength $ch_users] set users [expr $users + $ch_users_count] return $users } ## procs which are executed remotely follow: proc mnet:receive_message {rec_botnick cmd rec_data} { global mnet set rec_nickname [mnet:get_data [lindex $rec_data 0]] set rec_channel [lindex $rec_data 1] set rec_text [lrange $rec_data 2 end] set rec_text [mnet:clean_txt $rec_text] if {$mnet(loglevel) == "1"} { putlog "mnet: + Relaying Message from: $rec_nickname @ $rec_botnick @ $rec_channel" } elseif {$mnet(loglevel) == "2"} { putlog "mnet: + Relaying Message from: $rec_nickname @ $rec_botnick @ $rec_channel: $rec_text" } set users 0 set count_channels 0 foreach chan $mnet(ownchannels) { if {[mnet:botonchannel $chan] == "1"} { incr count_channels set users [mnet:chanstat_users $chan $users] putlog "mnet: * Remote counting $chan users: $users" mnet:put_local_message $chan $rec_nickname $rec_channel $rec_text } else { putlog "mnet: + Can't relay a message to '$chan' since I am not there." } } # ANSWER! SEND! if {$mnet(answer) == "1"} { mnet:put_bot $rec_botnick "mnet_answer $users $count_channels" } return 0 } proc mnet:receive_answer {rec_botnick cmd rec_data} { global mnet set rec_usercount [lindex $rec_data 0] set rec_chancount [lindex $rec_data 1] # set rec_text [lrange $rec_data 2 end] # get this bots results to our global variable: set mnet(reached) [expr $mnet(reached) + $rec_usercount] set mnet(reached_channels) [expr $mnet(reached_channels) + $rec_chancount] putlog "mnet: * $rec_botnick told me he sent its message to $rec_usercount people in $rec_chancount channels!" putlog "mnet: * Users reached since .aq2: $mnet(reached) in channels: $mnet(reached_channels)" } proc mnet:clean_txt {text} { regsub "{" $text "" text regsub "}" $text "" text regsub -all "\003\[0-9\]\[0-9\]" $text "" text regsub -all "\003\[0-9\]" $text "" text regsub -all "\003" $text "" text regsub -all "\002" $text "" text # putlog "test: $text" set text [string trim $text] return $text } proc mnet:botonchannel {chan} { # safe "bot-knows-the-channel-and-is-in-there"-function if {[validchan $chan] == "1" && [botonchan $chan] == "1"} { return 1 } else { return 0 } } proc mnet:messaging_public {nick mask hand chan text} { # proc triggered by .aq2 and calling the following (internal) one global mnet botnick putlog "mnet: = triggered by $nick ($mask) in $chan" # the command must be from a channel of "ownchannels" set found 0 foreach _trigger_chan $mnet(ownchannels) { # putlog "mnet: = trying $_trigger_chan" if {$_trigger_chan == $chan} { # putlog "mnet: = found channel: $_trigger_chan" set found 1 } else { # putlog "mnet: = not in list: $chan" } } if {$found == 0} { putlog "mnet: = not allowed in: $chan" return invalid_channel } set snd_nick [mnet:get_data $nick] if {![isop $nick $chan] && $nick != $botnick} { putlog "mnet: = allowed in $chan, but $nick is no op" mnet:put_nick $nick "Sorry $nick, you need to be op." return not_an_op } # check here if we have some text or not.. :) # cleaning string... set text [mnet:clean_txt $text] if {$text == "" || $text == "{}"} { # output some help: putlog "mnet: = gave him some help" puthelp "PRIVMSG $chan :$mnet(usage)" } else { set mnet(reached) "0" set mnet(reached_channels) "0" # send them first, we await a reply! # single sends TO ALL REMOTE BOTS with their remote CHANNELS... # let's see which mode for sending is used... if {$mnet(defined_bots) == "1"} { foreach _botnick $mnet(bots) { if {$_botnick == $botnick} { } else { # if not myself! # safe put_bot function.. mnet:put_bot $_botnick "mnet_send $snd_nick $chan $text" if {$mnet(loglevel) == "1"} { putlog "mnet: + Sending a message to $_botnick" } elseif {$mnet(loglevel) == "2"} { putlog "mnet: + Sending a message to $_botnick : $text" } } } } else { # if not "defined_bots" putallbots "mnet_send $snd_nick $chan $text" if {$mnet(loglevel) == "1"} { putlog "mnet: + Sending a message to all linked bots!" } elseif {$mnet(loglevel) == "2"} { putlog "mnet: + Sending a message to all linked bots: $text" } } # SEND TO ALL OWN CHANNELS... # send to all own channels, except to the channel the message originating from: foreach _ownchan $mnet(ownchannels) { if {$_ownchan == $chan} { } else { # if not own channel! if {[mnet:botonchannel $_ownchan] == "1"} { putlog "mnet: = i am on $_ownchan" # userstats local set mnet(reached) [mnet:chanstat_users $_ownchan $mnet(reached)] putlog "mnet: * Localcounting up $_ownchan users: $mnet(reached)" # channel count local incr mnet(reached_channels) mnet:put_local_message $_ownchan $snd_nick $chan $text } else { putlog "mnet: + Can't send a local message to '$_ownchan' since I am not there." } } } # wait here some more! (10 seconds with utimer) utimer 5 "mnet:reply_timeout {$chan}" # notice: better would be to go into the "reply" when all known bots already answered.. # then, if a bot is missing, but it was a known bot, just use a timeout with about 5-10 seconds.. # if the bot still didn't answer, then just go into "reply". } } proc mnet:reply_timeout {chan} { global mnet # inzwischen dürfte auch die antwort gekommen sein.. also jetzt mnet(reached) auswerten nach timeout.. putlog "mnet: * After all: Count_Users: $mnet(reached) Count_Channels: $mnet(reached_channels)" # Give me some reply. puthelp "PRIVMSG $chan :Message sent to $mnet(reached) users in $mnet(reached_channels) channels." } proc mnet:check_ban {nick mask} { global mnet(banlist) foreach bmask $banmask { if {[string match [string tolower $bmask] [string tolower $bmask_check]]} { newchanban $chan $bmask_host BanMask "$bmask_reason" $bmask_time sendnote BanMask $bmask_notify "÷ banned $bmask_check on $chan, [ctime [unixtime]] ÷" if {[botisop $chan]} { putserv "MODE $chan -o+b $nick $bmask_host" putserv "KICK $chan $nick :$bmask_reason" } break } } } putlog "mnet: = Messaging Network ($mnet(version)) loaded"