aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs125
-rw-r--r--OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs19
-rw-r--r--bin/OpenSim.ini.example13
3 files changed, 128 insertions, 29 deletions
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs
index 0a111c2..e992862 100644
--- a/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs
+++ b/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs
@@ -61,6 +61,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
61 internal object m_syncLogout = new object(); 61 internal object m_syncLogout = new object();
62 62
63 private IConfig m_config; 63 private IConfig m_config;
64
64 #region IRegionModule Members 65 #region IRegionModule Members
65 66
66 public void Initialise(Scene scene, IConfigSource config) 67 public void Initialise(Scene scene, IConfigSource config)
@@ -173,14 +174,14 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
173 174
174 public void OnSimChat(Object sender, OSChatMessage e) 175 public void OnSimChat(Object sender, OSChatMessage e)
175 { 176 {
177 m_log.DebugFormat("[IRC] heard on channel {0}: {1}", e.Channel.ToString(), e.Message);
178
176 // We only want to relay stuff on channel 0 179 // We only want to relay stuff on channel 0
177 if (e.Channel == m_irc.m_commandChannel) 180 if (e.Channel == m_irc.m_commandChannel)
178 { 181 {
179 string[] messages = e.Message.Split(' '); 182 string[] messages = e.Message.Split(' ');
180 string command = messages[0].ToLower(); 183 string command = messages[0].ToLower();
181 184
182 m_log.Debug("IRC: Got command on channel: " + e.Channel.ToString() + " message: " + e.Message);
183
184 try 185 try
185 { 186 {
186 switch (command) 187 switch (command)
@@ -206,6 +207,15 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
206 case "server": 207 case "server":
207 m_irc.m_server = messages[1]; 208 m_irc.m_server = messages[1];
208 break; 209 break;
210 case "verbosity":
211 m_irc.m_verbosity = Convert.ToInt32(messages[1]);
212 break;
213 case "in-channel":
214 m_irc.m_messageOutChannel = Convert.ToInt32(messages[1]);
215 break;
216 case "out-channel":
217 m_irc.m_messageInChannel = Convert.ToInt32(messages[1]);
218 break;
209 219
210 default: 220 default:
211 m_irc.Send(e.Message); 221 m_irc.Send(e.Message);
@@ -215,7 +225,8 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
215 catch 225 catch
216 { } 226 { }
217 } 227 }
218 if (e.Channel != 0) return; 228
229 if (e.Channel != m_irc.m_messageOutChannel) return;
219 if (e.Message.Length == 0) return; 230 if (e.Message.Length == 0) return;
220 231
221 // not interested in our own babblings 232 // not interested in our own babblings
@@ -269,7 +280,27 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
269 280
270 // this is to keep objects from talking to IRC 281 // this is to keep objects from talking to IRC
271 if (m_irc.Connected && (avatar != null)) 282 if (m_irc.Connected && (avatar != null))
272 m_irc.PrivMsg(fromName, scene.RegionInfo.RegionName, e.Message); 283 m_irc.PrivMsg(fromName, scene.RegionInfo.RegionName, e.Message);
284
285 // Handle messages from objects
286 if (m_irc.Connected && (null == avatar))
287 {
288 //Message came from an object
289 char[] splits = { ',' };
290 string[] tokens = e.Message.Split(splits,3); // This is certainly wrong
291 if (tokens.Length == 3)
292 {
293 if (tokens[0] == m_irc.m_accessPassword) // This is my really simple check
294 {
295 m_log.DebugFormat("[IRC] message from object {0}, {1}", tokens[0], tokens[1]);
296 m_irc.PrivMsg(tokens[1], scene.RegionInfo.RegionName, tokens[2]);
297 }
298 else
299 {
300 m_log.WarnFormat("[IRC] prim security key mismatch <{0}> not <{1}>", tokens[0], m_irc.m_accessPassword);
301 }
302 }
303 }
273 } 304 }
274 305
275 #endregion 306 #endregion
@@ -284,7 +315,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
284 315
285 if (client.Name != m_last_new_user) 316 if (client.Name != m_last_new_user)
286 { 317 {
287 if ((m_irc.Enabled) && (m_irc.Connected)) 318 if ((m_irc.Enabled) && (m_irc.Connected) && (m_irc.m_verbosity >= 1))
288 { 319 {
289 m_log.DebugFormat("[IRC] {0} logging on", client.Name); 320 m_log.DebugFormat("[IRC] {0} logging on", client.Name);
290 m_irc.PrivMsg(m_irc.Nick, "Sim", 321 m_irc.PrivMsg(m_irc.Nick, "Sim",
@@ -303,7 +334,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
303 { 334 {
304 try 335 try
305 { 336 {
306 if ((m_irc.Enabled) && (m_irc.Connected)) 337 if ((m_irc.Enabled) && (m_irc.Connected) && (m_irc.m_verbosity >= 2))
307 { 338 {
308 string regionName = presence.Scene.RegionInfo.RegionName; 339 string regionName = presence.Scene.RegionInfo.RegionName;
309 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname); 340 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname);
@@ -320,7 +351,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
320 { 351 {
321 try 352 try
322 { 353 {
323 if ((m_irc.Enabled) && (m_irc.Connected)) 354 if ((m_irc.Enabled) && (m_irc.Connected) && (m_irc.m_verbosity >= 2))
324 { 355 {
325 string regionName = presence.Scene.RegionInfo.RegionName; 356 string regionName = presence.Scene.RegionInfo.RegionName;
326 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname); 357 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname);
@@ -340,16 +371,16 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
340 { 371 {
341 try 372 try
342 { 373 {
343 if ((m_irc.Enabled) && (m_irc.Connected)) 374 if ((m_irc.Enabled) && (m_irc.Connected) && (m_irc.m_verbosity >= 1))
344 { 375 {
345 // handles simple case. May not work for hundred connecting in per second. 376 // handles simple case. May not work for hundred connecting in per second.
346 // and the NewClients calles getting interleved 377 // and the NewClients calles getting interleved
347 // but filters out multiple reports 378 // but filters out multiple reports
348 if (client.Name != m_last_leaving_user) 379 if (client.Name != m_last_leaving_user)
349 { 380 {
350 Console.WriteLine("Avatar was seen logging out."); 381 // Console.WriteLine("Avatar was seen logging out.");
351 //Console.ReadLine(); 382 // Console.ReadLine();
352 Console.WriteLine(); 383 // Console.WriteLine();
353 m_last_leaving_user = client.Name; 384 m_last_leaving_user = client.Name;
354 m_irc.PrivMsg(m_irc.Nick, "Sim", String.Format("notices {0} logging out", client.Name)); 385 m_irc.PrivMsg(m_irc.Nick, "Sim", String.Format("notices {0} logging out", client.Name));
355 m_log.InfoFormat("[IRC]: {0} logging out", client.Name); 386 m_log.InfoFormat("[IRC]: {0} logging out", client.Name);
@@ -412,6 +443,13 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
412 private bool m_connected = false; 443 private bool m_connected = false;
413 private bool m_enabled = false; 444 private bool m_enabled = false;
414 public int m_commandChannel = -1; 445 public int m_commandChannel = -1;
446
447 public int m_verbosity = 1;
448 public int m_messageOutChannel = 0; // Will be the message channel we listen to
449 public int m_messageInChannel = 0; // Will be the message channel where we forward msgs
450 public string m_accessPassword = "badkitty";
451 public bool m_useWorldComm = false; // true if we want chat to be localized, false if we want to broadcast to the entire region
452
415 public List<Scene> m_last_scenes = null; 453 public List<Scene> m_last_scenes = null;
416 public string m_nick = null; 454 public string m_nick = null;
417 public uint m_port = 6668; 455 public uint m_port = 6668;
@@ -469,6 +507,13 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
469 m_user = config.Configs["IRC"].GetString("username", m_user); 507 m_user = config.Configs["IRC"].GetString("username", m_user);
470 m_privmsgformat = config.Configs["IRC"].GetString("msgformat", m_privmsgformat); 508 m_privmsgformat = config.Configs["IRC"].GetString("msgformat", m_privmsgformat);
471 m_commandChannel = config.Configs["IRC"].GetInt("commandchannel", m_commandChannel); 509 m_commandChannel = config.Configs["IRC"].GetInt("commandchannel", m_commandChannel);
510
511 m_verbosity = config.Configs["IRC"].GetInt("verbosity", m_verbosity);
512 m_messageOutChannel = config.Configs["IRC"].GetInt("outchannel", m_messageOutChannel);
513 m_messageInChannel = config.Configs["IRC"].GetInt("inchannel", m_messageInChannel);
514 m_accessPassword = config.Configs["IRC"].GetString("access_password",m_accessPassword);
515 m_useWorldComm = config.Configs["IRC"].GetBoolean("useworldcomm", m_useWorldComm);
516
472 if (m_server != null && m_nick != null && m_channel != null) 517 if (m_server != null && m_nick != null && m_channel != null)
473 { 518 {
474 if (m_nrnick == true) 519 if (m_nrnick == true)
@@ -480,7 +525,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
480 } 525 }
481 catch (Exception ex) 526 catch (Exception ex)
482 { 527 {
483 m_log.Info("[IRC]: Incomplete IRC configuration, skipping IRC bridge configuration"); 528 m_log.Error("[IRC]: Incomplete IRC configuration, skipping IRC bridge configuration");
484 m_log.DebugFormat("[IRC] Incomplete IRC configuration: {0}", ex.ToString()); 529 m_log.DebugFormat("[IRC] Incomplete IRC configuration: {0}", ex.ToString());
485 } 530 }
486 } 531 }
@@ -515,12 +560,12 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
515 } 560 }
516 561
517 m_tcp = new TcpClient(m_server, (int)m_port); 562 m_tcp = new TcpClient(m_server, (int)m_port);
518 m_log.Info("[IRC]: Connecting...");
519 m_stream = m_tcp.GetStream(); 563 m_stream = m_tcp.GetStream();
520 m_log.Info("[IRC]: Connected to " + m_server);
521 m_reader = new StreamReader(m_stream); 564 m_reader = new StreamReader(m_stream);
522 m_writer = new StreamWriter(m_stream); 565 m_writer = new StreamWriter(m_stream);
523 566
567 m_log.DebugFormat("[IRC]: Connected to {0}:{1}", m_server, m_port);
568
524 pingSender = new Thread(new ThreadStart(PingRun)); 569 pingSender = new Thread(new ThreadStart(PingRun));
525 pingSender.Name = "PingSenderThread"; 570 pingSender.Name = "PingSenderThread";
526 pingSender.IsBackground = true; 571 pingSender.IsBackground = true;
@@ -547,6 +592,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
547 m_log.ErrorFormat("[IRC] cannot connect to {0}:{1}: {2}", 592 m_log.ErrorFormat("[IRC] cannot connect to {0}:{1}: {2}",
548 m_server, m_port, e.Message); 593 m_server, m_port, e.Message);
549 } 594 }
595 m_log.Debug("[IRC] Connected");
550 return m_connected; 596 return m_connected;
551 } 597 }
552 } 598 }
@@ -574,6 +620,8 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
574 620
575 public void PrivMsg(string from, string region, string msg) 621 public void PrivMsg(string from, string region, string msg)
576 { 622 {
623 m_log.DebugFormat("[IRC] Sending message to IRC from {0}: {1}", from, msg);
624
577 // One message to the IRC server 625 // One message to the IRC server
578 try 626 try
579 { 627 {
@@ -686,7 +734,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
686 { 734 {
687 while ((m_connected == true) && ((inputLine = m_reader.ReadLine()) != null)) 735 while ((m_connected == true) && ((inputLine = m_reader.ReadLine()) != null))
688 { 736 {
689 //Console.WriteLine("IRC: " + inputLine); 737 m_log.Info("[IRC]: " + inputLine);
690 if (inputLine.Contains(m_channel)) 738 if (inputLine.Contains(m_channel))
691 { 739 {
692 Dictionary<string, string> data = ExtractMsg(inputLine); 740 Dictionary<string, string> data = ExtractMsg(inputLine);
@@ -696,7 +744,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
696 OSChatMessage c = new OSChatMessage(); 744 OSChatMessage c = new OSChatMessage();
697 c.Message = data["msg"]; 745 c.Message = data["msg"];
698 c.Type = ChatTypeEnum.Say; 746 c.Type = ChatTypeEnum.Say;
699 c.Channel = 0; 747 c.Channel = m_messageInChannel;
700 c.Position = pos; 748 c.Position = pos;
701 c.From = data["nick"]; 749 c.From = data["nick"];
702 c.Sender = null; 750 c.Sender = null;
@@ -707,10 +755,20 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
707 if ((1 == c.Message[0]) && c.Message.Substring(1).StartsWith("ACTION")) 755 if ((1 == c.Message[0]) && c.Message.Substring(1).StartsWith("ACTION"))
708 c.Message = String.Format("/me {0}", c.Message.Substring(8, c.Message.Length - 9)); 756 c.Message = String.Format("/me {0}", c.Message.Substring(8, c.Message.Length - 9));
709 757
758 m_log.DebugFormat("[IRC] ListenerRun from: {0}, {1}", c.From, c.Message);
759
710 foreach (Scene scene in m_scenes) 760 foreach (Scene scene in m_scenes)
711 { 761 {
712 c.Scene = scene; 762 if (m_useWorldComm)
713 scene.EventManager.TriggerOnChatBroadcast(this, c); 763 {
764 IWorldComm wComm = scene.RequestModuleInterface<IWorldComm>();
765 wComm.DeliverMessage(ChatTypeEnum.Region, m_messageInChannel, c.From, UUID.Zero, c.Message);
766 }
767 else
768 {
769 c.Scene = scene;
770 scene.EventManager.TriggerOnChatBroadcast(this, c);
771 }
714 } 772 }
715 } 773 }
716 774
@@ -744,16 +802,24 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
744 OSChatMessage c = new OSChatMessage(); 802 OSChatMessage c = new OSChatMessage();
745 c.From = sender; 803 c.From = sender;
746 c.Message = String.Format(format, args); 804 c.Message = String.Format(format, args);
747 c.Type = ChatTypeEnum.Say; 805 c.Type = ChatTypeEnum.Region; // ChatTypeEnum.Say;
748 c.Channel = 0; 806 c.Channel = m_messageInChannel;
749 c.Position = new Vector3(128, 128, 20); 807 c.Position = new Vector3(128, 128, 20);
750 c.Sender = null; 808 c.Sender = null;
751 c.SenderUUID = UUID.Zero; 809 c.SenderUUID = UUID.Zero;
752 810
811 m_log.DebugFormat("[IRC] BroadcastSim from {0}: {1}", c.From, c.Message);
812
753 foreach (Scene m_scene in m_scenes) 813 foreach (Scene m_scene in m_scenes)
754 { 814 {
755 c.Scene = m_scene; 815 c.Scene = m_scene;
756 m_scene.EventManager.TriggerOnChatBroadcast(this, c); 816 // m_scene.EventManager.TriggerOnChatBroadcast(this, c);
817 // m_scene.EventManager.TriggerOnChatFromWorld(this, c);
818 IWorldComm wComm = m_scene.RequestModuleInterface<IWorldComm>();
819 wComm.DeliverMessage(ChatTypeEnum.Region, m_messageInChannel, sender, UUID.Zero, c.Message);
820 //IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
821 //wComm.DeliverMessage(ChatTypeEnum.Region, channelID, m_host.Name, m_host.UUID, text);
822
757 } 823 }
758 } 824 }
759 catch (Exception ex) // IRC gate should not crash Sim 825 catch (Exception ex) // IRC gate should not crash Sim
@@ -764,7 +830,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
764 830
765 public void ProcessIRCCommand(string command) 831 public void ProcessIRCCommand(string command)
766 { 832 {
767 //m_log.Info("[IRC]: ProcessIRCCommand:" + command); 833 m_log.Debug("[IRC]: ProcessIRCCommand:" + command);
768 834
769 string[] commArgs = new string[command.Split(' ').Length]; 835 string[] commArgs = new string[command.Split(' ').Length];
770 string c_server = m_server; 836 string c_server = m_server;
@@ -866,14 +932,16 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
866 if (IrcChannel.StartsWith(":")) 932 if (IrcChannel.StartsWith(":"))
867 IrcChannel = IrcChannel.Substring(1); 933 IrcChannel = IrcChannel.Substring(1);
868 string IrcUser = commArgs[0].Split('!')[0]; 934 string IrcUser = commArgs[0].Split('!')[0];
869 BroadcastSim(IrcUser, "/me joins {0}", IrcChannel); 935 if (m_verbosity >= 1)
936 BroadcastSim(IrcUser, "/me joins {0}", IrcChannel);
870 } 937 }
871 938
872 public void eventIrcPart(string[] commArgs) 939 public void eventIrcPart(string[] commArgs)
873 { 940 {
874 string IrcChannel = commArgs[2]; 941 string IrcChannel = commArgs[2];
875 string IrcUser = commArgs[0].Split('!')[0]; 942 string IrcUser = commArgs[0].Split('!')[0];
876 BroadcastSim(IrcUser, "/me parts {0}", IrcChannel); 943 if (m_verbosity >= 2)
944 BroadcastSim(IrcUser, "/me parts {0}", IrcChannel);
877 } 945 }
878 946
879 public void eventIrcMode(string[] commArgs) 947 public void eventIrcMode(string[] commArgs)
@@ -894,7 +962,8 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
894 { 962 {
895 string UserOldNick = commArgs[0].Split('!')[0]; 963 string UserOldNick = commArgs[0].Split('!')[0];
896 string UserNewNick = commArgs[2].Remove(0, 1); 964 string UserNewNick = commArgs[2].Remove(0, 1);
897 BroadcastSim(UserOldNick, "/me is now known as {0}", UserNewNick); 965 if (m_verbosity >= 2)
966 BroadcastSim(UserOldNick, "/me is now known as {0}", UserNewNick);
898 } 967 }
899 968
900 public void eventIrcKick(string[] commArgs) 969 public void eventIrcKick(string[] commArgs)
@@ -907,7 +976,8 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
907 { 976 {
908 KickMessage += commArgs[i] + " "; 977 KickMessage += commArgs[i] + " ";
909 } 978 }
910 BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage); 979 if (m_verbosity >= 1)
980 BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage);
911 if (UserKicked == m_nick) 981 if (UserKicked == m_nick)
912 { 982 {
913 BroadcastSim(m_nick, "Hey, that was me!!!"); 983 BroadcastSim(m_nick, "Hey, that was me!!!");
@@ -923,7 +993,8 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
923 { 993 {
924 QuitMessage += commArgs[i] + " "; 994 QuitMessage += commArgs[i] + " ";
925 } 995 }
926 BroadcastSim(IrcUser, "/me quits saying \"{0}\"", QuitMessage); 996 if (m_verbosity >= 1)
997 BroadcastSim(IrcUser, "/me quits saying \"{0}\"", QuitMessage);
927 } 998 }
928 999
929 public void Close() 1000 public void Close()
diff --git a/OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs b/OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs
index f5ec389..f8e933d 100644
--- a/OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs
+++ b/OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs
@@ -222,10 +222,25 @@ namespace OpenSim.Region.Environment.Modules.Scripting.WorldComm
222 else { 222 else {
223 avatar = m_scene.GetScenePresence(id); 223 avatar = m_scene.GetScenePresence(id);
224 if (avatar != null) 224 if (avatar != null)
225 {
225 position = avatar.AbsolutePosition; 226 position = avatar.AbsolutePosition;
227 }
226 else 228 else
227 // bail out early, given source could not be found 229 {
228 return; 230 // This is potentially problematic, though I don't
231 // see how to take advantage of it, basically a request
232 // to send a message to the region does not have to come
233 // from something in the region (eg a plugin can send it)
234 if (type == ChatTypeEnum.Region)
235 {
236 position = new Vector3(128, 128, 20);
237 }
238 else
239 {
240 // bail out early, given source could not be found
241 return;
242 }
243 }
229 } 244 }
230 245
231 // Determine which listen event filters match the given set of arguments, this results 246 // Determine which listen event filters match the given set of arguments, this results
diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example
index 6a56853..9772b3f 100644
--- a/bin/OpenSim.ini.example
+++ b/bin/OpenSim.ini.example
@@ -389,7 +389,20 @@ flush-on-error=true
389;nick = OpenSimBotNameProbablyMakeThisShorter 389;nick = OpenSimBotNameProbablyMakeThisShorter
390;channel = #the_irc_channel_you_want_to_connect_to 390;channel = #the_irc_channel_you_want_to_connect_to
391;port = 6667 391;port = 6667
392;; channel to listen for configuration updates
393;commandchannel = 2777
394;; 0 for no control messages, 2 for all control messages
395;verbosity = 1
396;; bridging connections
397;; outchannel -- channel to send messages out to the IRC bridge
398;; inchannel -- channel to receive message from the IRC bridge
399;; access_password -- simple security device
400;inchannel = 2226
401;outchannel = 2225
402;access_password = foobar
392;fallback_region = name of "default" region 403;fallback_region = name of "default" region
404;;useworldcomm = true will send IRC chat over the inchannel, false (default) will broadcast to all agents in the region
405;useworldcomm = true
393;MSGformat fields : 0=botnick, 1=user, 2=region, 3=message 406;MSGformat fields : 0=botnick, 1=user, 2=region, 3=message
394; must start with "PRIVMSG {0} : " or irc server will get upset 407; must start with "PRIVMSG {0} : " or irc server will get upset
395;for <bot>:<user in region> :<message> 408;for <bot>:<user in region> :<message>