123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480 |
- #!/usr/bin/ruby
- # vim: expandtab tabstop=2 shiftwidth=2 softtabstop=2 autoindent:
-
- require 'rubygems'
- require 'stomp'
- require 'digest/md5'
- # .. allowed commands .. ROLES = CAPABILITIES
- # normal users have ROLE broadcast. Roles are defined on a per-user basis .. in a config.
- $version = "0.11big_yadda"
- $debug = 0
- $role_commands = Hash[
- "everyone" => ["PING", "WHO", "C", "PART"],
-
- "broadcast_admin" => ["BC_ID", "BC", "BC_ENDCOUNT"],
- "broadcast" => ["REQ_BC", "BC_RE"],
-
- "specbot_admin" => ["REQ_ASSIGN", "REQ_UNASSIGN", "REQ_PING", "REQ_ASSIGNMENTS"],
- "specbot" => ["ASSIGN_RE", "UNASSIGN_RE", "PING_RE", "ASSIGNMENTS_RE"],
- ]
- $default_role = "everyone"
- # which role is talking to which role?
- # effectively it says: this (local) command is sent to that (remote) topic .. that certain topic is read by that user with that role.
- $role_dialogs = Hash[
- "everyone" => ["everyone"],
-
- "broadcast_admin" => ["broadcast"],
- "broadcast" => ["broadcast_admin"],
-
- "specbot_admin" => ["specbot"],
- "specbot" => ["specbot_admin"],
- ]
- $user_roles = Hash[
- "paul_dev_eggdrop" => ["everyone", "broadcast"],
- "paul_eggdrop" => ["everyone", "broadcast"],
-
- "paul_dev_specbot" => ["everyone", "broadcast", "specbot"],
- "paul_specbot" => ["everyone", "broadcast", "specbot"],
-
- "qw.nu" => ["everyone", "broadcast"],
- "qw.nu_poster" => ["everyone", "broadcast"],
-
- "mihawk_dev_specbot" => ["everyone", "broadcast", "specbot"],
- "mihawk_specbot" => ["everyone", "broadcast", "specbot"],
-
- "central_brain" => ["everyone", "broadcast_admin", "specbot_admin"],
- ]
- STDOUT.sync = true
-
- def put_debug(msg)
-
- if $debug == 1
- puts msg
- end
- end
- def put_log(msg)
- puts "#{Time.now.strftime("%Y-%m-%d %H:%M:%S %z")}: #{msg}"
- end
- def my_subscribe(client, topic)
- put_debug "Subscribing to #{topic}"
- client.subscribe("/topic/#{topic}")
- end
- # check if current text is readable for user
- def check_allow_processing(text, user)
-
- ok = false
- if not text =~ /^from:#{user}:/
- put_debug "may be a command: #{text}"
- ok = true
- end
-
- if text =~ /^!to:#{user}:/
- put_debug "not for #{user} #{text}"
- ok = false
- elsif text =~ /^to:#{user}:/
- put_debug "it is for #{user} #{text}"
- ok = true
- end
-
- return ok
- end
- # consuming process with a loop
- def consuming()
- put_debug "SYS Starting consuming/reading thread\n"
- client = Stomp::Connection.new("", "", "localhost", 61613, true)
-
- user = $user
-
- my_subscribe(client, "messages")
- my_subscribe(client, "#{user}-replies")
-
- # for each of our own roles, we subscribe
- $my_roles.each {
- |role|
- my_subscribe(client, "#{role}")
- }
-
- loop do
- begin
- msg = client.receive
-
- if check_allow_processing(msg.body, $user)
-
- #put_debug "msg.headers #{msg.headers["reply-to"]}\n"
- #put_debug "msg_array #{msg_array}\n"
-
- #put_log "RECEIVED_DBG: #{msg.body}"
- message = msg.body
- #from:#{$user}: #{cmd} #{payload}
-
- #put_log "message #{message}"
-
- message =~ /^([!fromto]+):([a-zA-Z\._]+): (.+)$/
- if not $& == nil
- m_sentmode = $1
- m_user = $2
- message = $3
-
- #put_log "sentmode #{m_sentmode}"
- #put_log "m_user #{m_user}"
- #put_log "message #{message}"
- end
-
- message =~ /^([A-Z_]+) (.*)/
- if not $& == nil
- m_cmd = $1
- m_pload = $2
- end
- if m_cmd =~ /^JOIN$/
- put_log "SYS User '#{m_user}' just joined the party."
- elsif m_cmd =~ /^C$/
- put_log "C #{m_user}: #{m_pload}"
-
- elsif m_cmd =~ /^WHO$/
- reply_to_msg(msg, "WHO_RE", "'#{$user}' on '#{$version}' ROLES: #{$user_roles[$user].join(", ")}")
- elsif m_cmd =~ /^PART$/
- put_log "PARTED User '#{m_user}' just left the party."
-
- elsif m_cmd =~ /^REQ_BC$/
- # this is for central_brain to process... so central needs to know from who.
- put_log "from:#{m_user}: #{m_cmd} #{m_pload}"
-
- else
- # general output of received commands on stomp on this connection (ssh)
- put_log "#{m_cmd} #{m_pload}"
-
- if m_cmd =~ /^BC$/
- #sending a fake reply.
- if user == "paul_dev_eggdrop"
- put_log "debug: sending fake reply based on #{msg.headers["reply-to"]}"
- m_pload =~ /^(.+?) /
- bcid = $1
- reply_to_msg(msg, "BC_RE", "#{bcid} Squirrels=2,Nuts=5")
- end
- end
-
- end
- else # of check_allow_processing
- put_debug "RECEIVED from myself. Ignoring."
- end # of check_allow_processing
- rescue
- put_debug "hum?"
- retry
-
- end
- end
- end
- def send(path, inputmsg, *header)
- begin
- finalmessage = ""
- Timeout::timeout(2) do
- stomp = Stomp::Client.new("", "", "localhost", 61613)
- finalmessage = "%s" % [inputmsg]
- if header != ""
- stomp.publish(path, finalmessage, *header)
- else
- stomp.publish(path, finalmessage)
- end
- stomp.close
- end
- rescue Timeout::Error
- put_debug "Failed to send within the 2 second timeout"
- exit 1
- else
- put_debug "SENT to #{path}: #{finalmessage}"
- end
- end
- def allowed_cmd(inputmessage)
-
- $my_cmds.each{|c|
- #print "A #{c} B #{inputmessage}\n"
- if inputmessage =~ /^#{c}/
- return true
- end
- }
- return false
-
- end
- def find_role_by_cmd(cmd)
-
- $my_roles.each {
- |role|
-
- #print "wah: #{role}"
- $role_commands[role].each {
- |c|
- if c == cmd
- #print "wOOh: #{role}"
- return role
- end
- }
-
- }
- return false
- end
- def find_dest_by_role(role)
-
- $role_dialogs.each {
- |srcrole, dstrole|
- if srcrole == role
- return dstrole
- end
- }
- return false
- end
- def send_cmd(cmd, payload, system=false, sendmode="from", to_user=$user)
- #find role by cmd
- #$role_commands.each
- #$my_cmds = $my_roles.collect {|v| $role_commands[v]}
- if system
- role = $default_role
- else
- role = find_role_by_cmd(cmd)
- end
- dest = find_dest_by_role(role)
-
- put_debug "cmd: #{cmd}"
- put_debug "role: #{role}"
- put_debug "dest: #{dest}"
- put_debug "payload: #{payload}"
-
- if sendmode == "from"
- send("/topic/#{dest}", "from:#{to_user}: #{cmd} #{payload}","reply-to" => "/topic/#{$user}-replies")
-
- elsif sendmode == "to" && to_user != ""
-
- dest = "#{to_user}-replies"
- send("/topic/#{dest}", "#{cmd} #{payload}","reply-to" => "/topic/#{$user}-replies")
-
- elsif sendmode == "!to" && to_user != ""
- send("/topic/#{dest}", "!to:#{to_user}: #{cmd} #{payload}","reply-to" => "/topic/#{$user}-replies")
-
- end
-
- end
- def reply_to_msg(msg, cmd, payload)
- if msg.headers["reply-to"]
- send(msg.headers["reply-to"], "from:#{$user}: #{cmd} #{payload}")
- end
- end
-
- def main
-
- raise "ARGV[0] must be a userstring - no numbers!" unless ARGV[0] =~ /^[a-zA-Z\._]+$/
-
- $user = "%s" % [ARGV[0]]
-
- if not $user_roles.any? {|k, v| k.include? $user}
- put_log "SYS User unknown to me."
- exit
- end
- $my_roles = $user_roles[$user]
- $my_cmds = $my_roles.collect {|v| $role_commands[v]}.flatten
- $broadcasts = Hash.new
-
- put_log "HELLO Hi user '#{$user}'! How are you? I'm #{$version}"
- put_log "ROLES #{$my_roles.join(", ")}"
- put_log "COMMANDS #{$my_cmds.join(", ")}"
-
- send_cmd("JOIN", "Hi, I'm all in.", true)
- thread_consuming = Thread.new {consuming}
- #put_log "SYS Going into input loop"
- inputmessage = ""
- while inputmessage != "PART"
- inputmessage = ""
- cmd = ""
- payload = ""
- sendmode = ""
- to_user = ""
-
- inputmessage = STDIN.gets.chomp
-
- if check_allow_processing(inputmessage, $user)
-
- if inputmessage =~ /^([!]?to):([a-zA-Z_\.]+): (.+)/
- sendmode = $1
- to_user = $2
- inputmessage = $3
- put_debug "sendmode: #{sendmode}"
- put_debug "to_user: #{to_user}"
- end
- if inputmessage =~ /^([A-Z_]+)/
- cmd = $1
- end
- # now we have the cmd .. or not ;)
-
- if inputmessage =~ /^[A-Z_]+ (.+)/
- payload = $1
- end
- # now we can use payload
-
- if allowed_cmd(cmd)
- if cmd == "PING"
- put_log "PONG"
- elsif cmd == "REQ_BC"
- # help with format .. but send the raw payload
- if payload =~ /^(.+),(.+),(.+),'(.+)','(.+)'$/
- # n f s ni txt
- error = 0
- # $&
- # The string matched by the last successful pattern match in this scope, or nil if the last pattern match failed. (Mnemonic: like & in some editors.) This variable is r
- network = $1
- freqname = $2
- source = $3
- nickname = $4
- text = $5
-
-
- if not network =~ /^(QWalt)|(QDEV)/
- put_log "SYS Network name #{network} is unknown: QWalt or QDEV allowed."
- error = 1
- end
- if not freqname =~ /^(-qw-)|(-spam-)|(-dev-)/
- put_log "SYS Frequency name is unknown #{freqname}"
- error = 1
- end
- if not source =~ /^(#.+)|(qw:\/\/)|(http:\/\/)/
- put_log "SYS Source string is not in the form ^(#.+)|(qw:\/\/)|(http:\/\/) was: #{source}"
- error = 1
- end
- if not nickname =~ /^.+/
- put_log "SYS Nickname string is not in the form ^.+ #{nickname}"
- error = 1
- end
- if not text =~ /^.+/
- put_log "SYS Message string is not in the form ^.+ #{text}"
- error = 1
- end
-
- else # of check syntax
- put_log "SYS Command format is REQ_BC <network>,<frequency>,<source/channel>,'<nickname>','<message>'"
- error = 1
- end
- if error == 0
-
- payload = "%s,%s,%s,'%s','%s'" % [network, freqname, source, nickname, text]
- send_cmd(cmd, payload)
- # send REQ_BC to the corresponding role.
-
- end
- elsif cmd == "BC_RE"
-
- if payload =~ /^(.+) (.+)=(\d+),(.+)=(\d+)$/
-
- bcid = $1
- user_string = $2
- user_count = $3
- item_string = $4
- item_count = $5
-
- payload = "%s %s=%d,%s=%d" % [bcid, user_string, user_count, item_string, item_count]
- # according bcid it is possible to get the originating user.. so send only to his topic!
-
- if $broadcasts[bcid]
- to_user = $broadcasts[bcid]
- put_log "SYS Broadcast reply bcid: #{bcid} underway. To: '#{to_user}'."
- send("/topic/#{to_user}-replies", "#{cmd} #{payload}")
- #send_cmd(cmd, payload) .. and thus: central_brain has to collect the BC_REs
- else
- put_log "SYS Broadcast reply bcid: #{bcid} underway."
- send("/topic/broadcast", "#{cmd} #{payload}")
- #send_cmd(cmd, payload) .. and thus: central_brain has to collect the BC_REs
- end
-
- else
- put_log "SYS Format is BC_RE <bcid> <userstring>=<usercount>,<itemstring>=<itemcount>"
- end
-
- elsif cmd == "C"
-
- if payload =~ /^(.+)$/
- put_log "C #{$user}: #{$1}"
- send_cmd("C", "#{$1}")
- else
- put_log "SYS Format is C <chattext>"
- end
-
- elsif cmd == "WHO"
-
- put_log "SYS Asking who's here."
- send_cmd("WHO", "is here?")
- elsif cmd == "PART"
- put_log "SYS Goodbye '#{$user}'."
- send_cmd("PART", "The party was fun.")
-
- else
- # universal sender for other allowed commands.
- if sendmode && to_user
- put_debug "sendmode: #{sendmode} to_user: #{to_user}"
- send_cmd(cmd, payload, false, sendmode, to_user)
-
- else
-
- send_cmd(cmd, payload)
-
- end
-
- end # of if command == xyz
-
-
- else # of if allowed command
- put_log "SYS Command #{inputmessage} not allowed, your commands are: #{$my_cmds.join(", ")}."
- end # of if allowed command
-
- end # of if we should process it
-
- end # of while input != "part"
-
-
- end # of main
- main
|