Преглед изворни кода

central and connection overhaul

Paul Klumpp пре 12 година
родитељ
комит
7f20afefd5
2 измењених фајлова са 534 додато и 486 уклоњено
  1. 136 284
      central.rb
  2. 398 202
      connection.rb

+ 136 - 284
central.rb

@@ -1,56 +1,15 @@
 #!/usr/bin/ruby
+# vim: expandtab tabstop=2 shiftwidth=2 softtabstop=2 autoindent:
  
 require 'rubygems'
-require 'stomp'
 require 'digest/md5'
+require 'open3'
 
-
-#users = [ "mihawksrv", "qwnu", "qwnuposter", "pauldevqw", "paulkibito" ]
-
-
-# WRITE COMMANDS as ROLE everyone:
-# PING		- reply from central: PONG
-# WHO		- reply from everyone: WHO_RE
-# C		- reply from central: C 
-# PART		- reply from central: SYS Goodbye
-
-
-# WRITE COMMANDS as ROLE broadcast:
-# REQ_BC	- reply from central: BC_ID
-# BC_RE
-
-# WRITE COMMANDS as ROLE adminspecbots:
-# REQ_ASSIGN	- reply from specbot: assign_re..
-# REQ_UNASSIGN	- reply from specbot: unassign_re..
-# REQ_PING	- reply from specbots: ping_re..
-# REQ_ASSIGNMENTS	- reply from specbot: assignments_re..
-
-# WRITE COMMANDS as ROLE specbot:
-# ASSIGN_RE
-# UNASSIGN_RE
-# PING_RE
-# ASSIGNMENTS_RE
-
-# USERS: ROLE
-# paulkibito: broadcast
-# qwnu: broadcast
-# mihawk: broadcast specbot
-# pauldevqw: broadcast specbot
-# qwsbalance: adminspecbots
-#
-# .. allowed commands .. ROLES = CAPABILITIES
-# normal users have ROLE broadcast. Roles are defined on a per-user basis .. in a config.
-
-
+#STDIN.sync = true
 STDOUT.sync = true
- 
-raise "ARGV[0] must be a userstring - no numbers!" unless ARGV[0] =~ /^[a-zA-Z]+$/
-
-$user = "%s" % [ARGV[0]]
 
-$broadcasts = Hash.new
+$role_receives = ["ASSIGN_RE", "UNASSIGN_RE", "PING_RE", "ASSIGNMENTS_RE", "REQ_BC", "BC_RE"]
 
-$debug = 0
 
 def put_debug(msg)
 	
@@ -60,269 +19,162 @@ def put_debug(msg)
 end
 
 def put_log(msg)
-	puts "#{Time.now.strftime("%Y-%m-%d %H:%M:%S %z")}: #{msg}"
+	puts "Z #{Time.now.strftime("%Y-%m-%d %H:%M:%S %z")}: #{msg}"
 end
 
-# consuming process with a loop
-def consuming(user)
-	put_log "SYS Starting consuming/reading thread\n"
-	client = Stomp::Connection.new("", "", "localhost", 61613, true)
-	client.subscribe("/topic/messages")
-	client.subscribe("/topic/#{user}-replies")
-	loop do
-		begin
-			msg = client.receive
-			if not msg.body =~ /^[\d]+ #{user}:/
-				put_debug "DEBUG: #{msg.body}"
-				message = msg.body
-
-				regex = Regexp.new('^(\d+) ([a-zA-Z]+):[ ,](([a-zA-Z_]+)[ ,](.*))$')
-				msg_array = message.scan(regex)
-				put_debug "msg.headers #{msg.headers["reply-to"]}"
-				put_debug "msg_array #{msg_array}"
-
-				m_time = msg_array[0][0]
-				m_user = msg_array[0][1]
-				m_msg  = msg_array[0][2]
-				m_cmd  = msg_array[0][3]
-				m_pload= msg_array[0][4]
-
-				if m_cmd =~ /^JOIN/
-					put_log "JOINED User '#{m_user}' just joined the party."
-
-				elsif m_cmd =~ /^C/
-					put_log "C #{m_user}: #{m_pload}"
-
-				elsif m_cmd =~ /^BC_RE/
-					put_log "BC_RE #{m_pload}"
-
-				elsif m_cmd =~ /^BC/
-					# we received a broadcast from #{m_user} with a hash. save it for later.
-					m_pload =~ /^(.+?) /
-					bcid = $1
-					#put_log "bcid #{bcid}"
-					$broadcasts[bcid] = m_user
-
-					# give sth to the client to process.
-					put_log "BC #{m_pload}"
-
-					#sending a fake reply.
-					if $user == "paulfakereply"
-						put_log "debug: sending fake reply to #{m_user}"
-						send("/topic/#{m_user}-replies", "BC_RE #{bcid} Squirrels=2,Nuts=5")
-					end
-
-				elsif m_cmd =~ /^WHO_RE/
-					put_log "WHO_RE '#{m_user}' with ROLES: xyz,xyz in the house."
-
-				elsif m_cmd =~ /^WHO/
-					reply_to_msg(msg, "WHO_RE #{user} is online.")
-
-				elsif m_cmd =~ /^PART/
-					put_log "PARTED User '#{m_user}' just left the party."
-
-				else
-					put_log "dbg: #{m_cmd}"
-
-				end
-
-			else
-				put_debug "RECEIVED from myself. Ignoring."
-			end
-
-			rescue
-				put_debug "hum?"
-			retry
+def allowed(inputcmd)
 	
+	$role_receives.each{
+		|c|
+	#print "A #{c} B #{inputcmd}\n"
+	if inputcmd =~ /^#{c}/
+			return true
 		end
-	end
-end
+	}
+	return false
 
-def reply_to_msg(msg, payload)
-	if msg.headers["reply-to"]
-		send(msg.headers["reply-to"], payload)
-	end
 end
 
-def send(path, inputmsg, *header)
-	begin
-	finalmessage = ""
-	  Timeout::timeout(2) do
-	    stomp = Stomp::Client.new("", "", "localhost", 61613)
-	    finalmessage = "%d %s: %s" % [Time.now.utc.to_i, $user, 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: #{finalmessage}"
+def put_to(to, cmd, payload)
+	
+	if to && cmd && payload
+		puts "to:#{to}: #{cmd} #{payload}"
+		$s.puts "to:#{to}: #{cmd} #{payload}"
 	end
+	
 end
 
+def put_not_to(to, cmd, payload)
+	puts "!to:#{to}: #{cmd} #{payload}"
+	$s.puts "!to:#{to}: #{cmd} #{payload}"
+end
 
-
-put_log "HELLO Hi user '#{$user}'! How are you?"
-send("/topic/messages", "JOIN Hi guys, I'm user '#{$user}'.")
-
-
-thread_consuming = Thread.new {consuming $user}
-
-#put_log "SYS Going into input loop"
-
-inputmessage = ""
-while inputmessage != "PART" 
-	inputmessage = ""
-	inputmessage = STDIN.gets.chomp
-
-	if inputmessage =~ /^(PING)$/
-		put_log "PONG"
-
-	elsif inputmessage =~ /^(REQ_BC)/
-
-		inputmessage =~ /^(REQ_BC)[ ,](.+),(.+),(.+),'(.+)','(.+)'$/
-		#                            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 read-only.
-		if $& == nil
-			put_log "SYS Command format is REQ_BC <network>,<frequency>,<source/channel>,'<nickname>','<message>'"
-			error = 1
-		else
-			command = "BC"
-			network = $2
-			freqname = $3
-			source = $4
-			nickname = $5
-			text = $6
-
-			if network =~ /^(QWalt)|(QDEV)/
-			else
-				put_log "SYS Network name #{network} is unknown: QWalt or QDEV allowed."
-				error = 1
-			end
-
-			if freqname =~ /^(-qw-)|(-spam-)|(-dev-)/
-			else
-				put_log "SYS Frequency name is unknown #{freqname}"
-				error = 1
-			end
-
-			if source =~ /^(#.+)|(qw:\/\/)|(http:\/\/)/
-			else
-				put_log "SYS Source string is not in the form ^(#.+)|(qw:\/\/)|(http:\/\/)  was: #{source}"
-				error = 1
-			end
-
-			if nickname =~ /^.+/ 
-			else
-				put_log "SYS Nickname string is not in the form ^.+  #{nickname}"
-				error = 1
-			end
-
-			if text =~ /^.+/
-			else
-				put_log "SYS Message string is not in the form ^.+ #{text}"
-				error = 1
-			end
-		end
-
-		if error == 0
-			finalmessage = "%s network:%s frequency:%s source:%s nickname:%s message:%s" % [command, network, freqname, source, nickname, text]
-
-			# building hash here (bcid)
-			bcid = Digest::MD5.hexdigest("%d %s %s %s %s %s" % [Time.now.utc.to_i, network, freqname, source, nickname, text])
-			#bcid = OpenSSL::Digest::MD5.hexdigest("%d %s %s %s %s %s" % [Time.now.utc.to_i, network, freqname, source, nickname, text])
-
-			finalmessage = "%s %s %s,%s,%s,'%s','%s'" % [command, bcid, network, freqname, source, nickname, text]
-			#finalmessage = "%s" % [inputmessage]
-			send("/topic/messages", finalmessage)
-			put_log "BC_ID #{bcid} for: #{network},#{freqname},#{source}"
-
-		end
+def work(line)
+	put_log "GOT LINE: #{line}"
 	
+	line =~ /^\d+-\d+-\d+ \d+:\d+:\d+ \+\d+: (.+)$/
 	
-	elsif inputmessage =~ /^(BC_RE)/ 
-
-		inputmessage =~ /^(BC_RE) (.+) (.+)=(\d+),(.+)=(\d+)$/
-		if $& == nil
-			put_log "SYS Format is BC_RE <bcid> <userstring>=<usercount>,<itemstring>=<itemcount>"
-		else
-			command = $1
-			bcid = $2
-			user_string = $3
-			user_count = $4
-			item_string = $5
-			item_count = $6
-
-
-			finalmessage = "%s %s %s=%d,%s=%d" % [command, 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", finalmessage)
-			else
-				put_log "SYS Broadcast reply bcid: #{bcid} underway."
-				send("/topic/messages", finalmessage)
-			end
-
-
+	fromto = ""
+	from = ""
+	cmd = ""
+	payload = ""
+	
+	if not $& == nil
+		line = $1
+		
+		if line =~ /^(from|to):([a-zA-Z_]+): (.+)/
+			fromto = $1
+			from = $2
+			line = $3
 		end
 		
+		if line =~ /^([A-Z_]+)/
+			cmd = $1
+		end
+		
+		if allowed(cmd)	
+			
+			put_log "from: #{from}"
+			put_log "cmd: #{cmd}"
+			put_log "line: #{line}"
+
+			payload = ""
+			if line =~ /^[A-Z_]+ (.+)/
+				payload = $1
+			end
+			
+			# an allowed commands with a seemingly valid payload has been received
+			puts cmd
+			puts payload
+			
+			if cmd == "REQ_BC"
+				
+				payload =~ /^(.+),(.+),(.+),'(.+)','(.+)'$/
+				#             n    f    s     ni     txt
+				# $&
+				# 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 read-only.
+				if not $& == nil
+					network = $1
+					freqname = $2
+					source = $3
+					nickname = $4
+					text = $5
+					
+					# we can fiddle with source here!
+					
+					bcid = Digest::MD5.hexdigest("%d %s %s %s %s %s" % [Time.now.utc.to_i, network, freqname, source, nickname, text])
+					
+					# so it only reaches the issuer of REQ_BC
+					put_to(from, "BC_ID", "#{bcid} for: #{network},#{freqname},#{source}")
+					#$broadcasts[bcid] = m_user
+					
+					finalmessage = "%s %s,%s,%s,'%s','%s'" % [bcid, network, freqname, source, nickname, text]
+					put_not_to(from, "BC", finalmessage)
+					
+				end # of match not nil
+
+			end # of REQ_BC
 
-	elsif inputmessage =~ /^(C)/ 
-
-		inputmessage =~ /^(C) (.+)$/
-		error = 0
-		if $& == nil
-			put_log "SYS Format is C <chattext>"
-			error = 1
 		else
-			put_log "C #{$user}: #{$2}"
-			send("/topic/messages", "C #{$2}")
+			put_log "UH '#{line}'"
 		end
+	end
+	
+end
 
 
-	elsif inputmessage =~ /^(PART)$/
-		put_log "SYS Goodbye '#{$user}'."
-		send("/topic/messages", "PART The party was fun.")
+def consuming()
+	put_log "SYS Starting reading thread\n"
+	loop do
+		
+		begin
+			line = $s.gets.chomp
+			work(line)
+		rescue
+		end
+		
+		
+	end
+end
 
-	elsif inputmessage =~ /^(WHO)/
-		put_log "SYS Asking who's here."
-		send("/topic/messages", "WHO is here?", "reply-to" => "/topic/#{$user}-replies")
-	else
-		put_log "SYS Not a known command, #{inputmessage}, possible commands are:"
-		put_log "SYS 'C' 'REQ_BC' 'BC_RE' 'WHO' 'PING' or 'PART'"
+def giving
+	inputmessage = ""
+	while inputmessage != "PART" 
+		
+		inputmessage = ""
+		inputmessage = STDIN.gets.chomp
+		
+		# put to ssh
+		$s.puts inputmessage
 	end
+end
 
-#	puts "%d: " % [Time.now.utc.to_i]
-	#frequency = "-qw-" #inputmessage
-	#channel = "#qwnet" #inputmessage
-	#nickname = user
-	#message = inputmessage
-	#find type of message?
-	#validate message against that type ..
-	#then send in a format.
 
-	#client sending message and awaiting replies
-	#stomp.subscribe("/temp-queue/random_replies")
-	#stomp.publish("/queue/random_generator", "random", {"reply-to" => "/temp-queue/random_replies"})
-	#Timeout::timeout(2) do
-	#  msg = stomp.receive
-	#  puts "Got the response: #{msg.body}"    
-	#end
-	#
-	#stomp.publish(msg.headers["reply-to"], number)
-	#
-	#
+def main
+	
+	raise "ARGV[0] must be valid ssh commands with the uri (user@host) in the beginning!" unless ARGV[0] =~ /^.+@.+\..+$/
+	sshcmd = "%s" % [ARGV[0]] 
+	
+	$s = IO.popen("ssh #{sshcmd}", "r+")
+	
+	thread_consuming = Thread.new {consuming}
+	
+	giving
 
 end
 
+main
+
+=begin
+		#client sending message and awaiting replies
+		#stomp.subscribe("/temp-queue/random_replies")
+		#stomp.publish("/queue/random_generator", "random", {"reply-to" => "/temp-queue/random_replies"})
+		#Timeout::timeout(2) do
+		#  msg = stomp.receive
+		#  puts "Got the response: #{msg.body}"    
+		#end
+		#
+		#stomp.publish(msg.headers["reply-to"], number)
+		#
+		#
+=end

+ 398 - 202
connection.rb

@@ -1,4 +1,5 @@
 #!/usr/bin/ruby
+# vim: expandtab tabstop=2 shiftwidth=2 softtabstop=2 autoindent:
  
 require 'rubygems'
 require 'stomp'
@@ -14,7 +15,6 @@ require 'digest/md5'
 # C		- reply from central: C 
 # PART		- reply from central: SYS Goodbye
 
-
 # WRITE COMMANDS as ROLE broadcast:
 # REQ_BC	- reply from central: BC_ID
 # BC_RE
@@ -41,16 +41,49 @@ require 'digest/md5'
 # .. allowed commands .. ROLES = CAPABILITIES
 # normal users have ROLE broadcast. Roles are defined on a per-user basis .. in a config.
 
+$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"],
+]
 
-STDOUT.sync = true
- 
-raise "ARGV[0] must be a userstring - no numbers!" unless ARGV[0] =~ /^[a-zA-Z]+$/
+$default_role = "everyone"
 
-$user = "%s" % [ARGV[0]]
+# 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"],
+]
 
-$broadcasts = Hash.new
+$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"],
+]
 
-$debug = 0
+
+STDOUT.sync = true
+ 
 
 def put_debug(msg)
 	
@@ -63,67 +96,111 @@ 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(user)
-	put_log "SYS Starting consuming/reading thread\n"
+def consuming()
+	put_debug "SYS Starting consuming/reading thread\n"
 	client = Stomp::Connection.new("", "", "localhost", 61613, true)
-	client.subscribe("/topic/messages")
-	client.subscribe("/topic/#{user}-replies")
+	
+	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 not msg.body =~ /^[\d]+ #{user}:/
-				put_debug "DEBUG: #{msg.body}"
+			
+			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
 
-				regex = Regexp.new('^(\d+) ([a-zA-Z]+):[ ,](([a-zA-Z_]+)[ ,](.*))$')
-				msg_array = message.scan(regex)
-				put_debug "msg.headers #{msg.headers["reply-to"]}"
-				put_debug "msg_array #{msg_array}"
-
-				m_time = msg_array[0][0]
-				m_user = msg_array[0][1]
-				m_msg  = msg_array[0][2]
-				m_cmd  = msg_array[0][3]
-				m_pload= msg_array[0][4]
+				#from:#{$user}: #{cmd} #{payload}
+				
+				#put_log "msg #{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 "JOINED User '#{m_user}' just joined the party."
+				if m_cmd =~ /^JOIN$/
+					put_log "SYS User '#{m_user}' just joined the party."
 
-				elsif m_cmd =~ /^C/
+				elsif m_cmd =~ /^C$/
 					put_log "C #{m_user}: #{m_pload}"
+					
+				elsif m_cmd =~ /^WHO$/
+					reply_to_msg(msg, "WHO_RE", "#{$user}' ROLES: #{$user_roles[$user].join(", ")}")
 
-				elsif m_cmd =~ /^BC_RE/
-					put_log "BC_RE #{m_pload}"
-
-				elsif m_cmd =~ /^BC/
-					# we received a broadcast from #{m_user} with a hash. save it for later.
-					m_pload =~ /^(.+?) /
-					bcid = $1
-					#put_log "bcid #{bcid}"
-					$broadcasts[bcid] = m_user
-
-					# give sth to the client to process.
-					put_log "BC #{m_pload}"
-
-					#sending a fake reply.
-					if $user == "paulfakereply"
-						put_log "debug: sending fake reply to #{m_user}"
-						send("/topic/#{m_user}-replies", "BC_RE #{bcid} Squirrels=2,Nuts=5")
-					end
-
-				elsif m_cmd =~ /^WHO_RE/
-					put_log "WHO_RE '#{m_user}' with ROLES: xyz,xyz in the house."
-
-				elsif m_cmd =~ /^WHO/
-					reply_to_msg(msg, "WHO_RE #{user} is online.")
-
-				elsif m_cmd =~ /^PART/
+				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
-					put_log "dbg: #{m_cmd}"
+					# 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
@@ -138,22 +215,16 @@ def consuming(user)
 	end
 end
 
-def reply_to_msg(msg, payload)
-	if msg.headers["reply-to"]
-		send(msg.headers["reply-to"], payload)
-	end
-end
-
 def send(path, inputmsg, *header)
 	begin
 	finalmessage = ""
 	  Timeout::timeout(2) do
 	    stomp = Stomp::Client.new("", "", "localhost", 61613)
-	    finalmessage = "%d %s: %s" % [Time.now.utc.to_i, $user, inputmsg]
-            if header != ""
-	    	stomp.publish(path, finalmessage, *header)
-            else
-	    	stomp.publish(path, finalmessage)
+	    finalmessage = "%s" % [inputmsg]
+			if header != ""
+				stomp.publish(path, finalmessage, *header)
+	    else
+				stomp.publish(path, finalmessage)
 	    end
 	    stomp.close
 	  end
@@ -161,168 +232,293 @@ def send(path, inputmsg, *header)
 	    put_debug "Failed to send within the 2 second timeout"
 	    exit 1
 	  else
-	    put_debug "SENT: #{finalmessage}"
+	    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
 
-put_log "HELLO Hi user '#{$user}'! How are you?"
-send("/topic/messages", "JOIN Hi guys, I'm user '#{$user}'.")
-
-
-thread_consuming = Thread.new {consuming $user}
+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
 
-#put_log "SYS Going into input loop"
+end
 
-inputmessage = ""
-while inputmessage != "PART" 
-	inputmessage = ""
-	inputmessage = STDIN.gets.chomp
-
-	if inputmessage =~ /^(PING)$/
-		put_log "PONG"
-
-	elsif inputmessage =~ /^(REQ_BC)/
-
-		inputmessage =~ /^(REQ_BC)[ ,](.+),(.+),(.+),'(.+)','(.+)'$/
-		#                            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 read-only.
-		if $& == nil
-			put_log "SYS Command format is REQ_BC <network>,<frequency>,<source/channel>,'<nickname>','<message>'"
-			error = 1
-		else
-			command = "BC"
-			network = $2
-			freqname = $3
-			source = $4
-			nickname = $5
-			text = $6
-
-			if network =~ /^(QWalt)|(QDEV)/
-			else
-				put_log "SYS Network name #{network} is unknown: QWalt or QDEV allowed."
-				error = 1
-			end
 
-			if freqname =~ /^(-qw-)|(-spam-)|(-dev-)/
-			else
-				put_log "SYS Frequency name is unknown #{freqname}"
-				error = 1
-			end
+def find_dest_by_role(role)
+	
+	$role_dialogs.each {
+		|srcrole, dstrole|
+		if srcrole == role
+			return dstrole
+		end
+	}
+	return false
+end
 
-			if source =~ /^(#.+)|(qw:\/\/)|(http:\/\/)/
-			else
-				put_log "SYS Source string is not in the form ^(#.+)|(qw:\/\/)|(http:\/\/)  was: #{source}"
-				error = 1
-			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
 
-			if nickname =~ /^.+/ 
-			else
-				put_log "SYS Nickname string is not in the form ^.+  #{nickname}"
-				error = 1
-			end
 
-			if text =~ /^.+/
-			else
-				put_log "SYS Message string is not in the form ^.+ #{text}"
-				error = 1
-			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
 
-		if error == 0
-			finalmessage = "%s network:%s frequency:%s source:%s nickname:%s message:%s" % [command, network, freqname, source, nickname, text]
+	
 
-			# building hash here (bcid)
-			bcid = Digest::MD5.hexdigest("%d %s %s %s %s %s" % [Time.now.utc.to_i, network, freqname, source, nickname, text])
-			#bcid = OpenSSL::Digest::MD5.hexdigest("%d %s %s %s %s %s" % [Time.now.utc.to_i, network, freqname, source, nickname, text])
+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
 
-			finalmessage = "%s %s %s,%s,%s,'%s','%s'" % [command, bcid, network, freqname, source, nickname, text]
-			#finalmessage = "%s" % [inputmessage]
-			send("/topic/messages", finalmessage)
-			put_log "BC_ID #{bcid} for: #{network},#{freqname},#{source}"
+	$my_roles = $user_roles[$user]
+	$my_cmds = $my_roles.collect {|v| $role_commands[v]}.flatten
 
-		end
+	$debug = 0
 	
+	$broadcasts = Hash.new
 	
-	elsif inputmessage =~ /^(BC_RE)/ 
-
-		inputmessage =~ /^(BC_RE) (.+) (.+)=(\d+),(.+)=(\d+)$/
-		if $& == nil
-			put_log "SYS Format is BC_RE <bcid> <userstring>=<usercount>,<itemstring>=<itemcount>"
-		else
-			command = $1
-			bcid = $2
-			user_string = $3
-			user_count = $4
-			item_string = $5
-			item_count = $6
-
-
-			finalmessage = "%s %s %s=%d,%s=%d" % [command, 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", finalmessage)
-			else
-				put_log "SYS Broadcast reply bcid: #{bcid} underway."
-				send("/topic/messages", finalmessage)
-			end
+	put_log "HELLO Hi user '#{$user}'! How are you?"
+	put_log "ROLES #{$my_roles.join(", ")}"
+	put_log "COMMANDS #{$my_cmds.join(", ")}"
+	
+	send_cmd("JOIN", "Hi, I'm all in.", true)
 
 
-		end
-		
+	thread_consuming = Thread.new {consuming}
+	#put_log "SYS Going into input loop"
 
-	elsif inputmessage =~ /^(C)/ 
+	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
 
-		inputmessage =~ /^(C) (.+)$/
-		error = 0
-		if $& == nil
-			put_log "SYS Format is C <chattext>"
-			error = 1
-		else
-			put_log "C #{$user}: #{$2}"
-			send("/topic/messages", "C #{$2}")
-		end
+			if inputmessage =~ /^([A-Z_]+)/
+				cmd = $1
+			end
+			
+			if allowed_cmd(cmd)
 
+				
+				if inputmessage =~ /^[a-zA-Z_]+ (.+)/
+					payload = $1
+				end
 
-	elsif inputmessage =~ /^(PART)$/
-		put_log "SYS Goodbye '#{$user}'."
-		send("/topic/messages", "PART The party was fun.")
+				if cmd == "PING"
+					put_log "PONG"
+
+				elsif inputmessage =~ /^(REQ_BC)/
+
+					inputmessage =~ /^(REQ_BC) (.+),(.+),(.+),'(.+)','(.+)'$/
+					#                           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 read-only.
+					if $& == nil
+						put_log "SYS Command format is REQ_BC <network>,<frequency>,<source/channel>,'<nickname>','<message>'"
+						error = 1
+					else
+						command = "BC"
+						network = $2
+						freqname = $3
+						source = $4
+						nickname = $5
+						text = $6
+
+						if network =~ /^(QWalt)|(QDEV)/
+						else
+							put_log "SYS Network name #{network} is unknown: QWalt or QDEV allowed."
+							error = 1
+						end
+
+						if freqname =~ /^(-qw-)|(-spam-)|(-dev-)/
+						else
+							put_log "SYS Frequency name is unknown #{freqname}"
+							error = 1
+						end
+
+						if source =~ /^(#.+)|(qw:\/\/)|(http:\/\/)/
+						else
+							put_log "SYS Source string is not in the form ^(#.+)|(qw:\/\/)|(http:\/\/)  was: #{source}"
+							error = 1
+						end
+
+						if nickname =~ /^.+/ 
+						else
+							put_log "SYS Nickname string is not in the form ^.+  #{nickname}"
+							error = 1
+						end
+
+						if text =~ /^.+/
+						else
+							put_log "SYS Message string is not in the form ^.+ #{text}"
+							error = 1
+						end
+					end
 
-	elsif inputmessage =~ /^(WHO)/
-		put_log "SYS Asking who's here."
-		send("/topic/messages", "WHO is here?", "reply-to" => "/topic/#{$user}-replies")
-	else
-		put_log "SYS Not a known command, #{inputmessage}, possible commands are:"
-		put_log "SYS 'C' 'REQ_BC' 'BC_RE' 'WHO' 'PING' or 'PART'"
-	end
+					if error == 0
+						# building hash here (bcid)
+						#bcid = Digest::MD5.hexdigest("%d %s %s %s %s %s" % [Time.now.utc.to_i, network, freqname, source, nickname, text])
+
+						#finalmessage = "%s %s %s,%s,%s,'%s','%s'" % [command, bcid, network, freqname, source, nickname, text]
+						#send("/topic/messages", finalmessage)
+						#put_log "BC_ID #{bcid} for: #{network},#{freqname},#{source}"
+						
+						finalmessage = "%s,%s,%s,'%s','%s'" % [network, freqname, source, nickname, text]
+						send_cmd("REQ_BC", finalmessage)
+					
+					end
 
-#	puts "%d: " % [Time.now.utc.to_i]
-	#frequency = "-qw-" #inputmessage
-	#channel = "#qwnet" #inputmessage
-	#nickname = user
-	#message = inputmessage
-	#find type of message?
-	#validate message against that type ..
-	#then send in a format.
-
-	#client sending message and awaiting replies
-	#stomp.subscribe("/temp-queue/random_replies")
-	#stomp.publish("/queue/random_generator", "random", {"reply-to" => "/temp-queue/random_replies"})
-	#Timeout::timeout(2) do
-	#  msg = stomp.receive
-	#  puts "Got the response: #{msg.body}"    
-	#end
-	#
-	#stomp.publish(msg.headers["reply-to"], number)
-	#
-	#
+				elsif inputmessage =~ /^(BC_RE)/ 
+					
+					inputmessage =~ /^(BC_RE) (.+) (.+)=(\d+),(.+)=(\d+)$/
+					if $& == nil
+						put_log "SYS Format is BC_RE <bcid> <userstring>=<usercount>,<itemstring>=<itemcount>"
+					else
+						command = $1
+						bcid = $2
+						user_string = $3
+						user_count = $4
+						item_string = $5
+						item_count = $6
+						
+						
+						finalmessage = "%s %s %s=%d,%s=%d" % [command, 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", finalmessage)
+						else
+							put_log "SYS Broadcast reply bcid: #{bcid} underway."
+							send("/topic/messages", finalmessage)
+						end
+					end
 
+					
+				elsif inputmessage =~ /^(C)/ 
+					
+					inputmessage =~ /^(C) (.+)$/
+					error = 0
+					if $& == nil
+						put_log "SYS Format is C <chattext>"
+						error = 1
+					else
+						put_log "C #{$user}: #{$2}"
+						send_cmd("C", "#{$2}")
+					end
+					
+				elsif inputmessage =~ /^(WHO)/
+					put_log "SYS Asking who's here."
+					send_cmd("WHO", "is here?")
+
+				elsif inputmessage =~ /^(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
+			
+			
+			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