aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDr Scofield2008-10-20 17:31:54 +0000
committerDr Scofield2008-10-20 17:31:54 +0000
commit72a388a7b6dfba8f93ffc5c5c45db4c44bb46480 (patch)
treedb9ab06f6820806d8c2b3fc32029383971e955b7
parentMantis #2438 (diff)
downloadopensim-SC_OLD-72a388a7b6dfba8f93ffc5c5c45db4c44bb46480.zip
opensim-SC_OLD-72a388a7b6dfba8f93ffc5c5c45db4c44bb46480.tar.gz
opensim-SC_OLD-72a388a7b6dfba8f93ffc5c5c45db4c44bb46480.tar.bz2
opensim-SC_OLD-72a388a7b6dfba8f93ffc5c5c45db4c44bb46480.tar.xz
cleaning up IRCBridgeModule to allow for configuration from in-world,
chat relaying via private channels, and old IRCBridgeModule behaviour. also cleaning up IRCBridgeModule's OpenSim.ini configuration variable names (still supporting "old" variable names). refactored IRCChatModule into IRCConnector and incorporating watchdog from IRCBridgeModule into IRCConnector. enabling ChatModule to be used as a super-class and utilizing it in ConciergeModule.
-rw-r--r--OpenSim/Region/Environment/ModuleLoader.cs18
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs198
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs841
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs710
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeModule.cs181
-rw-r--r--OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs71
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs3
-rw-r--r--bin/OpenSim.ini.example23
8 files changed, 1127 insertions, 918 deletions
diff --git a/OpenSim/Region/Environment/ModuleLoader.cs b/OpenSim/Region/Environment/ModuleLoader.cs
index 09f2dda..f06fa0f 100644
--- a/OpenSim/Region/Environment/ModuleLoader.cs
+++ b/OpenSim/Region/Environment/ModuleLoader.cs
@@ -93,15 +93,15 @@ namespace OpenSim.Region.Environment
93 m_loadedSharedModules.Add(dynamicModule.Name, dynamicModule); 93 m_loadedSharedModules.Add(dynamicModule.Name, dynamicModule);
94 } 94 }
95 95
96 ChatModule chat = new ChatModule(); 96 // ChatModule chat = new ChatModule();
97 if (m_loadedSharedModules.ContainsKey(chat.Name)) 97 // if (m_loadedSharedModules.ContainsKey(chat.Name))
98 { 98 // {
99 m_log.ErrorFormat("[MODULES]: Module name \"{0}\" already exists in module list. Module type {1} not added!", chat.Name, "ChatModule"); 99 // m_log.ErrorFormat("[MODULES]: Module name \"{0}\" already exists in module list. Module type {1} not added!", chat.Name, "ChatModule");
100 } 100 // }
101 else 101 // else
102 { 102 // {
103 m_loadedSharedModules.Add(chat.Name, chat); 103 // m_loadedSharedModules.Add(chat.Name, chat);
104 } 104 // }
105 105
106 InstantMessageModule imMod = new InstantMessageModule(); 106 InstantMessageModule imMod = new InstantMessageModule();
107 if (m_loadedSharedModules.ContainsKey(imMod.Name)) 107 if (m_loadedSharedModules.ContainsKey(imMod.Name))
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs
index 34a604e..5ee07ff 100644
--- a/OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs
+++ b/OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs
@@ -48,6 +48,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
48 48
49 private const int DEBUG_CHANNEL = 2147483647; 49 private const int DEBUG_CHANNEL = 2147483647;
50 50
51 private bool m_enabled = true;
51 private int m_saydistance = 30; 52 private int m_saydistance = 30;
52 private int m_shoutdistance = 100; 53 private int m_shoutdistance = 100;
53 private int m_whisperdistance = 10; 54 private int m_whisperdistance = 10;
@@ -56,23 +57,15 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
56 internal object m_syncInit = new object(); 57 internal object m_syncInit = new object();
57 58
58 #region IRegionModule Members 59 #region IRegionModule Members
59 public void Initialise(Scene scene, IConfigSource config) 60 public virtual void Initialise(Scene scene, IConfigSource config)
60 { 61 {
61 lock (m_syncInit)
62 {
63 if (!m_scenes.Contains(scene))
64 {
65 m_scenes.Add(scene);
66 scene.EventManager.OnNewClient += OnNewClient;
67 scene.EventManager.OnChatFromWorld += OnChatFromWorld;
68 scene.EventManager.OnChatBroadcast += OnChatBroadcast;
69 }
70 }
71
72 // wrap this in a try block so that defaults will work if 62 // wrap this in a try block so that defaults will work if
73 // the config file doesn't specify otherwise. 63 // the config file doesn't specify otherwise.
74 try 64 try
75 { 65 {
66 m_enabled = config.Configs["Chat"].GetBoolean("enabled", m_enabled);
67 if (!m_enabled) return;
68
76 m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance); 69 m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance);
77 m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance); 70 m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance);
78 m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance); 71 m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance);
@@ -80,23 +73,35 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
80 catch (Exception) 73 catch (Exception)
81 { 74 {
82 } 75 }
76
77 lock (m_syncInit)
78 {
79 if (!m_scenes.Contains(scene))
80 {
81 m_scenes.Add(scene);
82 scene.EventManager.OnNewClient += OnNewClient;
83 scene.EventManager.OnChatFromWorld += OnChatFromWorld;
84 scene.EventManager.OnChatBroadcast += OnChatBroadcast;
85 }
86 }
87
83 m_log.InfoFormat("[CHAT] initialized for {0} w:{1} s:{2} S:{3}", scene.RegionInfo.RegionName, 88 m_log.InfoFormat("[CHAT] initialized for {0} w:{1} s:{2} S:{3}", scene.RegionInfo.RegionName,
84 m_whisperdistance, m_saydistance, m_shoutdistance); 89 m_whisperdistance, m_saydistance, m_shoutdistance);
85 } 90 }
86 public void PostInitialise() 91 public virtual void PostInitialise()
87 { 92 {
88 } 93 }
89 94
90 public void Close() 95 public virtual void Close()
91 { 96 {
92 } 97 }
93 98
94 public string Name 99 public virtual string Name
95 { 100 {
96 get { return "ChatModule"; } 101 get { return "ChatModule"; }
97 } 102 }
98 103
99 public bool IsSharedModule 104 public virtual bool IsSharedModule
100 { 105 {
101 get { return true; } 106 get { return true; }
102 } 107 }
@@ -104,16 +109,9 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
104 #endregion 109 #endregion
105 110
106 111
107 public void OnNewClient(IClientAPI client) 112 public virtual void OnNewClient(IClientAPI client)
108 { 113 {
109 try 114 client.OnChatFromClient += OnChatFromClient;
110 {
111 client.OnChatFromClient += OnChatFromClient;
112 }
113 catch (Exception ex)
114 {
115 m_log.Error("[CHAT]: NewClient exception trap:" + ex.ToString());
116 }
117 } 115 }
118 116
119 public virtual void OnChatFromClient(Object sender, OSChatMessage e) 117 public virtual void OnChatFromClient(Object sender, OSChatMessage e)
@@ -132,45 +130,76 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
132 return; 130 return;
133 } 131 }
134 132
135 string message = e.Message; 133 // string message = e.Message;
136 if (e.Channel == DEBUG_CHANNEL) e.Type = ChatTypeEnum.DebugChannel; 134 // if (e.Channel == DEBUG_CHANNEL) e.Type = ChatTypeEnum.DebugChannel;
137 135
138 ScenePresence avatar = scene.GetScenePresence(e.Sender.AgentId); 136 // ScenePresence avatar = scene.GetScenePresence(e.Sender.AgentId);
139 Vector3 fromPos = avatar.AbsolutePosition; 137 // Vector3 fromPos = avatar.AbsolutePosition;
140 Vector3 regionPos = new Vector3(scene.RegionInfo.RegionLocX * Constants.RegionSize, 138 // Vector3 regionPos = new Vector3(scene.RegionInfo.RegionLocX * Constants.RegionSize,
141 scene.RegionInfo.RegionLocY * Constants.RegionSize, 0); 139 // scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
142 string fromName = avatar.Firstname + " " + avatar.Lastname; 140 // string fromName = avatar.Firstname + " " + avatar.Lastname;
143 UUID fromID = e.Sender.AgentId; 141 // UUID fromID = e.Sender.AgentId;
144 142
145 DeliverChatToAvatars(fromPos, regionPos, fromID, fromName, e.Type, ChatSourceType.Agent, message); 143 // DeliverChatToAvatars(fromPos, regionPos, fromID, fromName, e.Type, ChatSourceType.Agent, message);
144 DeliverChatToAvatars(ChatSourceType.Agent, e);
146 } 145 }
147 146
148 public void OnChatFromWorld(Object sender, OSChatMessage e) 147 public virtual void OnChatFromWorld(Object sender, OSChatMessage e)
149 { 148 {
150 Scene scene = (Scene) e.Scene;
151
152 // early return if not on public or debug channel 149 // early return if not on public or debug channel
153 if (e.Channel != 0 && e.Channel != DEBUG_CHANNEL) return; 150 if (e.Channel != 0 && e.Channel != DEBUG_CHANNEL) return;
154 151
155 // Filled in since it's easier than rewriting right now. 152 // // Filled in since it's easier than rewriting right now.
156 Vector3 fromPos = e.Position; 153 // Vector3 fromPos = e.Position;
157 Vector3 regionPos = new Vector3(scene.RegionInfo.RegionLocX * Constants.RegionSize, 154 // Vector3 regionPos = new Vector3(scene.RegionInfo.RegionLocX * Constants.RegionSize,
158 scene.RegionInfo.RegionLocY * Constants.RegionSize, 0); 155 // scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
159 156
160 string fromName = e.From; 157 // string fromName = e.From;
161 string message = e.Message; 158 // string message = e.Message;
162 UUID fromID = e.SenderUUID; 159 // UUID fromID = e.SenderUUID;
163 160
164 if (e.Channel == DEBUG_CHANNEL) 161 // if (e.Channel == DEBUG_CHANNEL)
165 e.Type = ChatTypeEnum.DebugChannel; 162 // e.Type = ChatTypeEnum.DebugChannel;
166 163
167 DeliverChatToAvatars(fromPos, regionPos, fromID, fromName, e.Type, ChatSourceType.Object, message); 164 // DeliverChatToAvatars(fromPos, regionPos, fromID, fromName, e.Type, ChatSourceType.Object, message);
165 DeliverChatToAvatars(ChatSourceType.Object, e);
168 } 166 }
169 167
170 protected void DeliverChatToAvatars(Vector3 pos, Vector3 regionPos, UUID uuid, string name, 168 protected virtual void DeliverChatToAvatars(ChatSourceType sourceType, OSChatMessage c)
171 ChatTypeEnum chatType, ChatSourceType sourceType, string message)
172 { 169 {
173 // iterate over message 170 string fromName = c.From;
171 UUID fromID = UUID.Zero;
172 string message = c.Message;
173 IScene scene = c.Scene;
174 Vector3 fromPos = c.Position;
175 Vector3 regionPos = new Vector3(scene.RegionInfo.RegionLocX * Constants.RegionSize,
176 scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
177
178 if (c.Channel == DEBUG_CHANNEL) c.Type = ChatTypeEnum.DebugChannel;
179
180 switch (sourceType)
181 {
182 case ChatSourceType.Agent:
183 if (!(scene is Scene))
184 {
185 m_log.WarnFormat("[CHAT] scene {0} is not a Scene object, cannot obtain scene presence for {1}",
186 scene.RegionInfo.RegionName, c.Sender.AgentId);
187 return;
188 }
189 ScenePresence avatar = (scene as Scene).GetScenePresence(c.Sender.AgentId);
190 fromPos = avatar.AbsolutePosition;
191 fromName = avatar.Firstname + " " + avatar.Lastname;
192 fromID = c.Sender.AgentId;
193
194 break;
195
196 case ChatSourceType.Object:
197 fromID = c.SenderUUID;
198
199 break;
200 }
201
202 // TODO: iterate over message
174 if (message.Length >= 1000) // libomv limit 203 if (message.Length >= 1000) // libomv limit
175 message = message.Substring(0, 1000); 204 message = message.Substring(0, 1000);
176 205
@@ -178,20 +207,42 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
178 { 207 {
179 s.ForEachScenePresence(delegate(ScenePresence presence) 208 s.ForEachScenePresence(delegate(ScenePresence presence)
180 { 209 {
181 TrySendChatMessage(presence, pos, regionPos, uuid, name, 210 TrySendChatMessage(presence, fromPos, regionPos, fromID, fromName,
182 chatType, message, sourceType); 211 c.Type, message, sourceType);
183 }); 212 });
184 } 213 }
185 } 214 }
186 215
187 216 // protected virtual void DeliverChatToAvatars(Vector3 pos, Vector3 regionPos, UUID uuid, string name,
188 public void OnChatBroadcast(Object sender, OSChatMessage c) 217 // ChatTypeEnum chatType, ChatSourceType sourceType, string message)
218 // {
219 // // iterate over message
220 // if (message.Length >= 1000) // libomv limit
221 // message = message.Substring(0, 1000);
222
223 // foreach (Scene s in m_scenes)
224 // {
225 // s.ForEachScenePresence(delegate(ScenePresence presence)
226 // {
227 // TrySendChatMessage(presence, pos, regionPos, uuid, name,
228 // chatType, message, sourceType);
229 // });
230 // }
231 // }
232
233
234 public virtual void OnChatBroadcast(Object sender, OSChatMessage c)
189 { 235 {
190 // We only want to relay stuff on channel 0 and on the debug channel 236 // unless the chat to be broadcast is of type Region, we
191 if (c.Channel != 0 && c.Channel != DEBUG_CHANNEL) return; 237 // drop it if its channel is neither 0 nor DEBUG_CHANNEL
238 if (c.Channel != 0 && c.Channel != DEBUG_CHANNEL && c.Type != ChatTypeEnum.Region) return;
192 239
240 ChatTypeEnum cType = c.Type;
193 if (c.Channel == DEBUG_CHANNEL) 241 if (c.Channel == DEBUG_CHANNEL)
194 c.Type = ChatTypeEnum.DebugChannel; 242 cType = ChatTypeEnum.DebugChannel;
243
244 if (cType == ChatTypeEnum.Region)
245 cType = ChatTypeEnum.Say;
195 246
196 if (c.Message.Length > 1100) 247 if (c.Message.Length > 1100)
197 c.Message = c.Message.Substring(0, 1000); 248 c.Message = c.Message.Substring(0, 1000);
@@ -199,6 +250,15 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
199 // broadcast chat works by redistributing every incoming chat 250 // broadcast chat works by redistributing every incoming chat
200 // message to each avatar in the scene. 251 // message to each avatar in the scene.
201 Vector3 pos = new Vector3(128, 128, 30); 252 Vector3 pos = new Vector3(128, 128, 30);
253
254 UUID fromID = UUID.Zero;
255 ChatSourceType sourceType = ChatSourceType.Object;
256 if (null != c.Sender)
257 {
258 fromID = c.Sender.AgentId;
259 sourceType = ChatSourceType.Agent;
260 }
261
202 ((Scene)c.Scene).ForEachScenePresence( 262 ((Scene)c.Scene).ForEachScenePresence(
203 delegate(ScenePresence presence) 263 delegate(ScenePresence presence)
204 { 264 {
@@ -214,29 +274,15 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
214 (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId)) 274 (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId))
215 return; 275 return;
216 276
217 if (null == c.SenderObject) 277 client.SendChatMessage(c.Message, (byte)cType, pos, c.From, fromID,
218 { 278 (byte)sourceType, (byte)ChatAudibleLevel.Fully);
219 // chat from agent (avatar)
220 client.SendChatMessage(c.Message, (byte)c.Type,
221 pos, c.From, UUID.Zero,
222 (byte)ChatSourceType.Agent,
223 (byte)ChatAudibleLevel.Fully);
224 }
225 else
226 {
227 // chat from object
228 client.SendChatMessage(c.Message, (byte)c.Type,
229 pos, c.From, UUID.Zero,
230 (byte)ChatSourceType.Object,
231 (byte)ChatAudibleLevel.Fully);
232 }
233 }); 279 });
234 } 280 }
235 281
236 282
237 private void TrySendChatMessage(ScenePresence presence, Vector3 fromPos, Vector3 regionPos, 283 protected virtual void TrySendChatMessage(ScenePresence presence, Vector3 fromPos, Vector3 regionPos,
238 UUID fromAgentID, string fromName, ChatTypeEnum type, 284 UUID fromAgentID, string fromName, ChatTypeEnum type,
239 string message, ChatSourceType src) 285 string message, ChatSourceType src)
240 { 286 {
241 // don't send stuff to child agents 287 // don't send stuff to child agents
242 if (presence.IsChildAgent) return; 288 if (presence.IsChildAgent) return;
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs
index e992862..05718d8 100644
--- a/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs
+++ b/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs
@@ -48,10 +48,8 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
48 48
49 private const int DEBUG_CHANNEL = 2147483647; 49 private const int DEBUG_CHANNEL = 2147483647;
50 50
51 private string m_defaultzone = null;
52 51
53 private IRCChatModule m_irc = null; 52 private IRCConnector m_irc = null;
54 private Thread m_irc_connector = null;
55 53
56 private string m_last_leaving_user = null; 54 private string m_last_leaving_user = null;
57 private string m_last_new_user = null; 55 private string m_last_new_user = null;
@@ -61,6 +59,12 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
61 internal object m_syncLogout = new object(); 59 internal object m_syncLogout = new object();
62 60
63 private IConfig m_config; 61 private IConfig m_config;
62 private string m_defaultzone = null;
63 private bool m_commandsEnabled = false;
64 private int m_commandChannel = -1;
65 private bool m_relayPrivateChannels = false;
66 private int m_relayChannelOut = -1;
67 private bool m_clientReporting = true;
64 68
65 #region IRegionModule Members 69 #region IRegionModule Members
66 70
@@ -86,6 +90,15 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
86 return; 90 return;
87 } 91 }
88 92
93 m_commandsEnabled = m_config.GetBoolean("commands_enabled", m_commandsEnabled);
94 m_commandChannel = m_config.GetInt("commandchannel", m_commandChannel); // compat
95 m_commandChannel = m_config.GetInt("command_channel", m_commandChannel);
96
97 m_relayPrivateChannels = m_config.GetBoolean("relay_private_channels", m_relayPrivateChannels);
98 m_relayChannelOut = m_config.GetInt("relay_private_channel_out", m_relayChannelOut);
99
100 m_clientReporting = m_config.GetBoolean("report_clients", m_clientReporting);
101
89 lock (m_syncInit) 102 lock (m_syncInit)
90 { 103 {
91 104
@@ -110,43 +123,21 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
110 // setup IRC Relay 123 // setup IRC Relay
111 if (m_irc == null) 124 if (m_irc == null)
112 { 125 {
113 m_irc = new IRCChatModule(config); 126 m_irc = new IRCConnector(config);
114 } 127 }
115 128 m_irc.AddScene(scene);
116 if (m_irc_connector == null) 129
117 { 130 m_log.InfoFormat("[IRC] initialized for {0}, nick: {1}, commands {2}, private channels {3}",
118 m_irc_connector = new Thread(IRCConnectRun); 131 scene.RegionInfo.RegionName, m_defaultzone,
119 m_irc_connector.Name = "IRCConnectorThread"; 132 m_commandsEnabled ? "enabled" : "not enabled",
120 m_irc_connector.IsBackground = true; 133 m_relayPrivateChannels ? "relayed" : "not relayed");
121 }
122 m_log.InfoFormat("[IRC] initialized for {0}, nick: {1} ", scene.RegionInfo.RegionName,
123 m_defaultzone);
124 } 134 }
125 } 135 }
126 136
127 public void PostInitialise() 137 public void PostInitialise()
128 { 138 {
129 if (null == m_irc || !m_irc.Enabled) return; 139 if (null == m_irc || !m_irc.Enabled) return;
130 140 m_irc.Start();
131 try
132 {
133 //m_irc.Connect(m_scenes);
134 if (m_irc_connector == null)
135 {
136 m_irc_connector = new Thread(IRCConnectRun);
137 m_irc_connector.Name = "IRCConnectorThread";
138 m_irc_connector.IsBackground = true;
139 }
140
141 if (!m_irc_connector.IsAlive)
142 {
143 m_irc_connector.Start();
144 ThreadTracker.Add(m_irc_connector);
145 }
146 }
147 catch (Exception)
148 {
149 }
150 } 141 }
151 142
152 public void Close() 143 public void Close()
@@ -172,14 +163,21 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
172 163
173 #region ISimChat Members 164 #region ISimChat Members
174 165
175 public void OnSimChat(Object sender, OSChatMessage e) 166 public void OnSimChat(Object sender, OSChatMessage c)
176 { 167 {
177 m_log.DebugFormat("[IRC] heard on channel {0}: {1}", e.Channel.ToString(), e.Message); 168 // early return if nothing to forward
169 if (c.Message.Length == 0) return;
170
171 // early return if this comes from the IRC forwarder
172 if (m_irc.Equals(sender)) return;
173
174 m_log.DebugFormat("[IRC] heard on channel {0}: {1}", c.Channel, c.Message);
178 175
179 // We only want to relay stuff on channel 0 176 // check for commands coming from avatars or in-world
180 if (e.Channel == m_irc.m_commandChannel) 177 // object (if commands are enabled)
178 if (m_commandsEnabled && c.Channel == m_commandChannel)
181 { 179 {
182 string[] messages = e.Message.Split(' '); 180 string[] messages = c.Message.Split(' ');
183 string command = messages[0].ToLower(); 181 string command = messages[0].ToLower();
184 182
185 try 183 try
@@ -187,146 +185,135 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
187 switch (command) 185 switch (command)
188 { 186 {
189 case "channel": 187 case "channel":
190 m_irc.m_channel = messages[1]; 188 m_irc.IrcChannel = messages[1];
191 break; 189 break;
192 case "close": 190 case "close":
193 m_irc.Close(); 191 m_irc.Close();
194 break; 192 break;
195 case "connect": 193 case "connect":
196 m_irc.Connect(m_scenes); 194 m_irc.Connect();
197 break; 195 break;
198 case "nick": 196 case "nick":
199 m_irc.m_nick = messages[1]; 197 m_irc.Nick = messages[1];
200 break; 198 break;
201 case "port": 199 case "port":
202 m_irc.m_port = Convert.ToUInt32(messages[1]); 200 m_irc.Port = Convert.ToUInt32(messages[1]);
203 break; 201 break;
204 case "reconnect": 202 case "reconnect":
205 m_irc.Reconnect(); 203 m_irc.Reconnect();
206 break; 204 break;
207 case "server": 205 case "server":
208 m_irc.m_server = messages[1]; 206 m_irc.Server = messages[1];
209 break; 207 break;
210 case "verbosity": 208 case "client-reporting":
211 m_irc.m_verbosity = Convert.ToInt32(messages[1]); 209 m_irc.ClientReporting = Convert.ToBoolean(messages[1]);
210
212 break; 211 break;
213 case "in-channel": 212 case "in-channel":
214 m_irc.m_messageOutChannel = Convert.ToInt32(messages[1]); 213 m_irc.RelayChannel = Convert.ToInt32(messages[1]);
215 break; 214 break;
216 case "out-channel": 215 case "out-channel":
217 m_irc.m_messageInChannel = Convert.ToInt32(messages[1]); 216 m_relayChannelOut = Convert.ToInt32(messages[1]);
218 break; 217 break;
219 218
220 default: 219 default:
221 m_irc.Send(e.Message); 220 m_irc.Send(c.Message);
222 break; 221 break;
223 } 222 }
224 } 223 }
225 catch 224 catch(Exception ex)
226 { } 225 {
226 m_log.DebugFormat("[IRC] error processing in-world command channel input: {0}", ex);
227 }
227 } 228 }
228 229
229 if (e.Channel != m_irc.m_messageOutChannel) return; 230 // drop all messages coming in on a private channel,
230 if (e.Message.Length == 0) return; 231 // except if we are relaying private channels, in which
231 232 // case we drop if the private channel is not the
232 // not interested in our own babblings 233 // configured m_relayChannelOut
233 if (m_irc.Equals(sender)) return; 234 if (m_relayPrivateChannels)
235 {
236 if (c.Channel != 0 && c.Channel != DEBUG_CHANNEL && c.Channel != m_relayChannelOut)
237 {
238 m_log.DebugFormat("[IRC] dropping message {0} on channel {1}", c, c.Channel);
239 return;
240 }
241 }
242 else if (c.Channel != 0 && c.Channel != DEBUG_CHANNEL)
243 {
244 m_log.DebugFormat("[IRC] dropping message {0} on channel {1}", c, c.Channel);
245 return;
246 }
234 247
235 ScenePresence avatar = null; 248 ScenePresence avatar = null;
236 Scene scene = (Scene)e.Scene; 249 Scene scene = (Scene)c.Scene;
237 250
238 if (scene == null) 251 if (scene == null)
239 scene = m_scenes[0]; 252 scene = m_scenes[0];
240 253
241 // Filled in since it's easier than rewriting right now. 254 string fromName = c.From;
242 string fromName = e.From;
243 255
244 if (e.Sender != null) 256 if (c.Sender != null)
245 { 257 {
246 avatar = scene.GetScenePresence(e.Sender.AgentId); 258 avatar = scene.GetScenePresence(c.Sender.AgentId);
259 if (avatar != null) fromName = avatar.Name;
247 } 260 }
248 261
249 if (avatar != null) 262 if (!m_irc.Connected)
250 { 263 {
251 fromName = avatar.Name; 264 m_log.WarnFormat("[IRC] IRCConnector not connected: dropping message from {0}", fromName);
265 return;
252 } 266 }
253 267
254 // Try to reconnect to server if not connected 268 if (null != avatar)
255 if (m_irc.Enabled && !m_irc.Connected)
256 { 269 {
257 // In a non-blocking way. Eventually the connector will get it started 270 string msg = c.Message;
258 try 271 if (msg.StartsWith("/me "))
272 msg = String.Format("{0} {1}", fromName, c.Message.Substring(4));
273
274 m_irc.PrivMsg(fromName, scene.RegionInfo.RegionName, msg);
275 }
276 else
277 {
278 //Message came from an object
279 char[] splits = { ',' };
280 string[] tokens = c.Message.Split(splits,3); // This is certainly wrong
281 if (tokens.Length == 3)
259 { 282 {
260 if (m_irc_connector == null) 283 if (tokens[0] == m_irc.m_accessPassword) // This is my really simple check
261 { 284 {
262 m_irc_connector = new Thread(IRCConnectRun); 285 m_log.DebugFormat("[IRC] message from object {0}, {1}", tokens[0], tokens[1]);
263 m_irc_connector.Name = "IRCConnectorThread"; 286 m_irc.PrivMsg(tokens[1], scene.RegionInfo.RegionName, tokens[2]);
264 m_irc_connector.IsBackground = true;
265 } 287 }
266 288 else
267 if (!m_irc_connector.IsAlive)
268 { 289 {
269 m_irc_connector.Start(); 290 m_log.WarnFormat("[IRC] prim security key mismatch <{0}> not <{1}>", tokens[0], m_irc.m_accessPassword);
270 ThreadTracker.Add(m_irc_connector);
271 } 291 }
272 } 292 }
273 catch (Exception)
274 {
275 }
276 } 293 }
277
278 if (e.Message.StartsWith("/me ") && (null != avatar))
279 e.Message = String.Format("{0} {1}", fromName, e.Message.Substring(4));
280
281 // this is to keep objects from talking to IRC
282 if (m_irc.Connected && (avatar != null))
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 }
304 } 294 }
305
306 #endregion 295 #endregion
307 296
308 public void OnNewClient(IClientAPI client) 297 public void OnNewClient(IClientAPI client)
309 { 298 {
310 try 299 try
311 { 300 {
312 // client.OnChatFromViewer += OnSimChat;
313 client.OnLogout += OnClientLoggedOut; 301 client.OnLogout += OnClientLoggedOut;
314 client.OnConnectionClosed += OnClientLoggedOut; 302 client.OnConnectionClosed += OnClientLoggedOut;
315 303
316 if (client.Name != m_last_new_user) 304 if (client.Name != m_last_new_user)
317 { 305 {
318 if ((m_irc.Enabled) && (m_irc.Connected) && (m_irc.m_verbosity >= 1)) 306 if ((m_irc.Enabled) && (m_irc.Connected) && (m_clientReporting))
319 { 307 {
320 m_log.DebugFormat("[IRC] {0} logging on", client.Name); 308 m_log.DebugFormat("[IRC] {0} logging on", client.Name);
321 m_irc.PrivMsg(m_irc.Nick, "Sim", 309 m_irc.PrivMsg(m_irc.Nick, "Sim", String.Format("notices {0} logging on", client.Name));
322 String.Format("notices {0} logging on", client.Name));
323 } 310 }
324 m_last_new_user = client.Name; 311 m_last_new_user = client.Name;
325 } 312 }
326 } 313 }
327 catch (Exception ex) 314 catch (Exception ex)
328 { 315 {
329 m_log.Error("[IRC]: NewClient exception trap:" + ex.ToString()); 316 m_log.Error("[IRC]: OnNewClient exception trap:" + ex.ToString());
330 } 317 }
331 } 318 }
332 319
@@ -334,7 +321,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
334 { 321 {
335 try 322 try
336 { 323 {
337 if ((m_irc.Enabled) && (m_irc.Connected) && (m_irc.m_verbosity >= 2)) 324 if ((m_irc.Enabled) && (m_irc.Connected) && (m_clientReporting))
338 { 325 {
339 string regionName = presence.Scene.RegionInfo.RegionName; 326 string regionName = presence.Scene.RegionInfo.RegionName;
340 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname); 327 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname);
@@ -351,7 +338,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
351 { 338 {
352 try 339 try
353 { 340 {
354 if ((m_irc.Enabled) && (m_irc.Connected) && (m_irc.m_verbosity >= 2)) 341 if ((m_irc.Enabled) && (m_irc.Connected) && (m_clientReporting))
355 { 342 {
356 string regionName = presence.Scene.RegionInfo.RegionName; 343 string regionName = presence.Scene.RegionInfo.RegionName;
357 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname); 344 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname);
@@ -371,16 +358,14 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
371 { 358 {
372 try 359 try
373 { 360 {
374 if ((m_irc.Enabled) && (m_irc.Connected) && (m_irc.m_verbosity >= 1)) 361 if ((m_irc.Enabled) && (m_irc.Connected) && (m_clientReporting))
375 { 362 {
376 // handles simple case. May not work for hundred connecting in per second. 363 // handles simple case. May not work for
377 // and the NewClients calles getting interleved 364 // hundred connecting in per second. and
378 // but filters out multiple reports 365 // OnNewClients calle getting interleaved but
366 // filters out multiple reports
379 if (client.Name != m_last_leaving_user) 367 if (client.Name != m_last_leaving_user)
380 { 368 {
381 // Console.WriteLine("Avatar was seen logging out.");
382 // Console.ReadLine();
383 // Console.WriteLine();
384 m_last_leaving_user = client.Name; 369 m_last_leaving_user = client.Name;
385 m_irc.PrivMsg(m_irc.Nick, "Sim", String.Format("notices {0} logging out", client.Name)); 370 m_irc.PrivMsg(m_irc.Nick, "Sim", String.Format("notices {0} logging out", client.Name));
386 m_log.InfoFormat("[IRC]: {0} logging out", client.Name); 371 m_log.InfoFormat("[IRC]: {0} logging out", client.Name);
@@ -396,623 +381,5 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
396 } 381 }
397 } 382 }
398 } 383 }
399
400 // if IRC is enabled then just keep trying using a monitor thread
401 public void IRCConnectRun()
402 {
403 while (m_irc.Enabled)
404 {
405 if (!m_irc.Connected)
406 {
407 m_irc.Connect(m_scenes);
408 }
409 Thread.Sleep(15000);
410 }
411 }
412 }
413
414 internal class IRCChatModule
415 {
416 #region ErrorReplies enum
417
418 public enum ErrorReplies
419 {
420 NotRegistered = 451, // ":You have not registered"
421 NicknameInUse = 433 // "<nick> :Nickname is already in use"
422 }
423
424 #endregion
425
426 #region Replies enum
427
428 public enum Replies
429 {
430 MotdStart = 375, // ":- <server> Message of the day - "
431 Motd = 372, // ":- <text>"
432 EndOfMotd = 376 // ":End of /MOTD command"
433 }
434
435 #endregion
436
437 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
438 private Thread listener;
439
440 private string m_basenick = null;
441 public string m_channel = null;
442 private bool m_nrnick = false;
443 private bool m_connected = false;
444 private bool m_enabled = false;
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
453 public List<Scene> m_last_scenes = null;
454 public string m_nick = null;
455 public uint m_port = 6668;
456 private string m_privmsgformat = "PRIVMSG {0} :<{1} in {2}>: {3}";
457 private StreamReader m_reader;
458 private List<Scene> m_scenes = null;
459 public string m_server = null;
460
461 private NetworkStream m_stream = null;
462 internal object m_syncConnect = new object();
463 private TcpClient m_tcp;
464 private string m_user = "USER OpenSimBot 8 * :I'm an OpenSim to IRC bot";
465 private StreamWriter m_writer;
466
467 private Thread pingSender;
468
469 public IRCChatModule(IConfigSource config)
470 {
471 m_nick = "OSimBot" + Util.RandomClass.Next(1, 99);
472 m_tcp = null;
473 m_writer = null;
474 m_reader = null;
475
476 // configuration in OpenSim.ini
477 // [IRC]
478 // server = chat.freenode.net
479 // nick = OSimBot_mysim
480 // nicknum = true
481 // ;nicknum set to true appends a 2 digit random number to the nick
482 // ;username = USER OpenSimBot 8 * :I'm a OpenSim to irc bot
483 // ; username is the IRC command line sent
484 // ; USER <irc_user> <visible=8,invisible=0> * : <IRC_realname>
485 // channel = #opensim-regions
486 // port = 6667
487 // ;MSGformat fields : 0=botnick, 1=user, 2=region, 3=message
488 // ;for <bot>:<user in region> :<message>
489 // ;msgformat = "PRIVMSG {0} :<{1} in {2}>: {3}"
490 // ;for <bot>:<message> - <user of region> :
491 // ;msgformat = "PRIVMSG {0} : {3} - {1} of {2}"
492 // ;for <bot>:<message> - from <user> :
493 // ;msgformat = "PRIVMSG {0} : {3} - from {1}"
494 // Traps I/O disconnects so it does not crash the sim
495 // Trys to reconnect if disconnected and someone says something
496 // Tells IRC server "QUIT" when doing a close (just to be nice)
497 // Default port back to 6667
498
499 try
500 {
501 m_server = config.Configs["IRC"].GetString("server");
502 m_nick = config.Configs["IRC"].GetString("nick");
503 m_basenick = m_nick;
504 m_nrnick = config.Configs["IRC"].GetBoolean("nicknum", true);
505 m_channel = config.Configs["IRC"].GetString("channel");
506 m_port = (uint)config.Configs["IRC"].GetInt("port", (int)m_port);
507 m_user = config.Configs["IRC"].GetString("username", m_user);
508 m_privmsgformat = config.Configs["IRC"].GetString("msgformat", m_privmsgformat);
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
517 if (m_server != null && m_nick != null && m_channel != null)
518 {
519 if (m_nrnick == true)
520 {
521 m_nick = m_nick + Util.RandomClass.Next(1, 99);
522 }
523 m_enabled = true;
524 }
525 }
526 catch (Exception ex)
527 {
528 m_log.Error("[IRC]: Incomplete IRC configuration, skipping IRC bridge configuration");
529 m_log.DebugFormat("[IRC] Incomplete IRC configuration: {0}", ex.ToString());
530 }
531 }
532
533 public bool Enabled
534 {
535 get { return m_enabled; }
536 }
537
538 public bool Connected
539 {
540 get { return m_connected; }
541 }
542
543 public string Nick
544 {
545 get { return m_nick; }
546 }
547
548 public bool Connect(List<Scene> scenes)
549 {
550 lock (m_syncConnect)
551 {
552 try
553 {
554 if (m_connected) return true;
555
556 m_scenes = scenes;
557 if (m_last_scenes == null)
558 {
559 m_last_scenes = scenes;
560 }
561
562 m_tcp = new TcpClient(m_server, (int)m_port);
563 m_stream = m_tcp.GetStream();
564 m_reader = new StreamReader(m_stream);
565 m_writer = new StreamWriter(m_stream);
566
567 m_log.DebugFormat("[IRC]: Connected to {0}:{1}", m_server, m_port);
568
569 pingSender = new Thread(new ThreadStart(PingRun));
570 pingSender.Name = "PingSenderThread";
571 pingSender.IsBackground = true;
572 pingSender.Start();
573 ThreadTracker.Add(pingSender);
574
575 listener = new Thread(new ThreadStart(ListenerRun));
576 listener.Name = "IRCChatModuleListenerThread";
577 listener.IsBackground = true;
578 listener.Start();
579 ThreadTracker.Add(listener);
580
581 m_writer.WriteLine(m_user);
582 m_writer.Flush();
583 m_writer.WriteLine(String.Format("NICK {0}", m_nick));
584 m_writer.Flush();
585 m_writer.WriteLine(String.Format("JOIN {0}", m_channel));
586 m_writer.Flush();
587 m_log.Info("[IRC]: Connection fully established");
588 m_connected = true;
589 }
590 catch (Exception e)
591 {
592 m_log.ErrorFormat("[IRC] cannot connect to {0}:{1}: {2}",
593 m_server, m_port, e.Message);
594 }
595 m_log.Debug("[IRC] Connected");
596 return m_connected;
597 }
598 }
599
600 public void Reconnect()
601 {
602 m_connected = false;
603 try
604 {
605 listener.Abort();
606 pingSender.Abort();
607 m_writer.Close();
608 m_reader.Close();
609 m_tcp.Close();
610 }
611 catch (Exception)
612 {
613 }
614
615 if (m_enabled)
616 {
617 Connect(m_last_scenes);
618 }
619 }
620
621 public void PrivMsg(string from, string region, string msg)
622 {
623 m_log.DebugFormat("[IRC] Sending message to IRC from {0}: {1}", from, msg);
624
625 // One message to the IRC server
626 try
627 {
628 m_writer.WriteLine(m_privmsgformat, m_channel, from, region, msg);
629 m_writer.Flush();
630 m_log.InfoFormat("[IRC]: PrivMsg {0} in {1}: {2}", from, region, msg);
631 }
632 catch (IOException)
633 {
634 m_log.Error("[IRC]: Disconnected from IRC server.(PrivMsg)");
635 Reconnect();
636 }
637 catch (Exception ex)
638 {
639 m_log.ErrorFormat("[IRC]: PrivMsg exception trap: {0}", ex.ToString());
640 }
641 }
642
643 public void Send(string msg)
644 {
645 try
646 {
647 m_writer.WriteLine(msg);
648 m_writer.Flush();
649 m_log.Info("IRC: Sent command string: " + msg);
650 }
651 catch (IOException)
652 {
653 m_log.Error("[IRC]: Disconnected from IRC server.(PrivMsg)");
654 Reconnect();
655 }
656 catch (Exception ex)
657 {
658 m_log.ErrorFormat("[IRC]: PrivMsg exception trap: {0}", ex.ToString());
659 }
660
661 }
662
663
664 private Dictionary<string, string> ExtractMsg(string input)
665 {
666 //examines IRC commands and extracts any private messages
667 // which will then be reboadcast in the Sim
668
669 m_log.Info("[IRC]: ExtractMsg: " + input);
670 Dictionary<string, string> result = null;
671 //string regex = @":(?<nick>\w*)!~(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)";
672 string regex = @":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)";
673 Regex RE = new Regex(regex, RegexOptions.Multiline);
674 MatchCollection matches = RE.Matches(input);
675
676 // Get some direct matches $1 $4 is a
677 if ((matches.Count == 0) || (matches.Count != 1) || (matches[0].Groups.Count != 5))
678 {
679 m_log.Info("[IRC]: Number of matches: " + matches.Count);
680 if (matches.Count > 0)
681 {
682 m_log.Info("[IRC]: Number of groups: " + matches[0].Groups.Count);
683 }
684 return null;
685 }
686
687 result = new Dictionary<string, string>();
688 result.Add("nick", matches[0].Groups[1].Value);
689 result.Add("user", matches[0].Groups[2].Value);
690 result.Add("channel", matches[0].Groups[3].Value);
691 result.Add("msg", matches[0].Groups[4].Value);
692
693 return result;
694 }
695
696 public void PingRun()
697 {
698 // IRC keep alive thread
699 // send PING ever 15 seconds
700 while (m_enabled)
701 {
702 try
703 {
704 if (m_connected == true)
705 {
706 m_writer.WriteLine(String.Format("PING :{0}", m_server));
707 m_writer.Flush();
708 Thread.Sleep(15000);
709 }
710 }
711 catch (IOException)
712 {
713 if (m_enabled)
714 {
715 m_log.Error("[IRC]: Disconnected from IRC server.(PingRun)");
716 Reconnect();
717 }
718 }
719 catch (Exception ex)
720 {
721 m_log.ErrorFormat("[IRC]: PingRun exception trap: {0}\n{1}", ex.ToString(), ex.StackTrace);
722 }
723 }
724 }
725
726 static private Vector3 pos = new Vector3(128, 128, 20);
727 public void ListenerRun()
728 {
729 string inputLine;
730
731 while (m_enabled)
732 {
733 try
734 {
735 while ((m_connected == true) && ((inputLine = m_reader.ReadLine()) != null))
736 {
737 m_log.Info("[IRC]: " + inputLine);
738 if (inputLine.Contains(m_channel))
739 {
740 Dictionary<string, string> data = ExtractMsg(inputLine);
741 // Any chat ???
742 if (data != null)
743 {
744 OSChatMessage c = new OSChatMessage();
745 c.Message = data["msg"];
746 c.Type = ChatTypeEnum.Say;
747 c.Channel = m_messageInChannel;
748 c.Position = pos;
749 c.From = data["nick"];
750 c.Sender = null;
751 c.SenderUUID = UUID.Zero;
752
753 // is message "\001ACTION foo
754 // bar\001"? -> "/me foo bar"
755 if ((1 == c.Message[0]) && c.Message.Substring(1).StartsWith("ACTION"))
756 c.Message = String.Format("/me {0}", c.Message.Substring(8, c.Message.Length - 9));
757
758 m_log.DebugFormat("[IRC] ListenerRun from: {0}, {1}", c.From, c.Message);
759
760 foreach (Scene scene in m_scenes)
761 {
762 if (m_useWorldComm)
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 }
772 }
773 }
774
775 Thread.Sleep(150);
776 continue;
777 }
778
779 ProcessIRCCommand(inputLine);
780 Thread.Sleep(150);
781 }
782 }
783 catch (IOException)
784 {
785 if (m_enabled)
786 {
787 m_log.Error("[IRC]: ListenerRun IOException. Disconnected from IRC server ??? (ListenerRun)");
788 Reconnect();
789 }
790 }
791 catch (Exception ex)
792 {
793 m_log.ErrorFormat("[IRC]: ListenerRun exception trap: {0}\n{1}", ex.ToString(), ex.StackTrace);
794 }
795 }
796 }
797
798 public void BroadcastSim(string sender, string format, params string[] args)
799 {
800 try
801 {
802 OSChatMessage c = new OSChatMessage();
803 c.From = sender;
804 c.Message = String.Format(format, args);
805 c.Type = ChatTypeEnum.Region; // ChatTypeEnum.Say;
806 c.Channel = m_messageInChannel;
807 c.Position = new Vector3(128, 128, 20);
808 c.Sender = null;
809 c.SenderUUID = UUID.Zero;
810
811 m_log.DebugFormat("[IRC] BroadcastSim from {0}: {1}", c.From, c.Message);
812
813 foreach (Scene m_scene in m_scenes)
814 {
815 c.Scene = m_scene;
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
823 }
824 }
825 catch (Exception ex) // IRC gate should not crash Sim
826 {
827 m_log.ErrorFormat("[IRC]: BroadcastSim Exception Trap: {0}\n{1}", ex.ToString(), ex.StackTrace);
828 }
829 }
830
831 public void ProcessIRCCommand(string command)
832 {
833 m_log.Debug("[IRC]: ProcessIRCCommand:" + command);
834
835 string[] commArgs = new string[command.Split(' ').Length];
836 string c_server = m_server;
837
838 commArgs = command.Split(' ');
839 if (commArgs[0].Substring(0, 1) == ":")
840 {
841 commArgs[0] = commArgs[0].Remove(0, 1);
842 }
843
844 if (commArgs[1] == "002")
845 {
846 // fetch the correct servername
847 // ex: irc.freenode.net -> brown.freenode.net/kornbluth.freenode.net/...
848 // irc.bluewin.ch -> irc1.bluewin.ch/irc2.bluewin.ch
849
850 c_server = (commArgs[6].Split('['))[0];
851 m_server = c_server;
852 }
853
854 if (commArgs[0] == "ERROR")
855 {
856 m_log.ErrorFormat("[IRC]: IRC SERVER ERROR: {0}", command);
857 }
858
859 if (commArgs[0] == "PING")
860 {
861 string p_reply = "";
862
863 for (int i = 1; i < commArgs.Length; i++)
864 {
865 p_reply += commArgs[i] + " ";
866 }
867
868 m_writer.WriteLine(String.Format("PONG {0}", p_reply));
869 m_writer.Flush();
870 }
871 else if (commArgs[0] == c_server)
872 {
873 // server message
874 try
875 {
876 Int32 commandCode = Int32.Parse(commArgs[1]);
877 switch (commandCode)
878 {
879 case (int)ErrorReplies.NicknameInUse:
880 // Gen a new name
881 m_nick = m_basenick + Util.RandomClass.Next(1, 99);
882 m_log.ErrorFormat("[IRC]: IRC SERVER reports NicknameInUse, trying {0}", m_nick);
883 // Retry
884 m_writer.WriteLine(String.Format("NICK {0}", m_nick));
885 m_writer.Flush();
886 m_writer.WriteLine(String.Format("JOIN {0}", m_channel));
887 m_writer.Flush();
888 break;
889 case (int)ErrorReplies.NotRegistered:
890 break;
891 case (int)Replies.EndOfMotd:
892 break;
893 }
894 }
895 catch (Exception)
896 {
897 }
898 }
899 else
900 {
901 // Normal message
902 string commAct = commArgs[1];
903 switch (commAct)
904 {
905 case "JOIN":
906 eventIrcJoin(commArgs);
907 break;
908 case "PART":
909 eventIrcPart(commArgs);
910 break;
911 case "MODE":
912 eventIrcMode(commArgs);
913 break;
914 case "NICK":
915 eventIrcNickChange(commArgs);
916 break;
917 case "KICK":
918 eventIrcKick(commArgs);
919 break;
920 case "QUIT":
921 eventIrcQuit(commArgs);
922 break;
923 case "PONG":
924 break; // that's nice
925 }
926 }
927 }
928
929 public void eventIrcJoin(string[] commArgs)
930 {
931 string IrcChannel = commArgs[2];
932 if (IrcChannel.StartsWith(":"))
933 IrcChannel = IrcChannel.Substring(1);
934 string IrcUser = commArgs[0].Split('!')[0];
935 if (m_verbosity >= 1)
936 BroadcastSim(IrcUser, "/me joins {0}", IrcChannel);
937 }
938
939 public void eventIrcPart(string[] commArgs)
940 {
941 string IrcChannel = commArgs[2];
942 string IrcUser = commArgs[0].Split('!')[0];
943 if (m_verbosity >= 2)
944 BroadcastSim(IrcUser, "/me parts {0}", IrcChannel);
945 }
946
947 public void eventIrcMode(string[] commArgs)
948 {
949 string UserMode = "";
950 for (int i = 3; i < commArgs.Length; i++)
951 {
952 UserMode += commArgs[i] + " ";
953 }
954
955 if (UserMode.Substring(0, 1) == ":")
956 {
957 UserMode = UserMode.Remove(0, 1);
958 }
959 }
960
961 public void eventIrcNickChange(string[] commArgs)
962 {
963 string UserOldNick = commArgs[0].Split('!')[0];
964 string UserNewNick = commArgs[2].Remove(0, 1);
965 if (m_verbosity >= 2)
966 BroadcastSim(UserOldNick, "/me is now known as {0}", UserNewNick);
967 }
968
969 public void eventIrcKick(string[] commArgs)
970 {
971 string UserKicker = commArgs[0].Split('!')[0];
972 string UserKicked = commArgs[3];
973 string IrcChannel = commArgs[2];
974 string KickMessage = "";
975 for (int i = 4; i < commArgs.Length; i++)
976 {
977 KickMessage += commArgs[i] + " ";
978 }
979 if (m_verbosity >= 1)
980 BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage);
981 if (UserKicked == m_nick)
982 {
983 BroadcastSim(m_nick, "Hey, that was me!!!");
984 }
985 }
986
987 public void eventIrcQuit(string[] commArgs)
988 {
989 string IrcUser = commArgs[0].Split('!')[0];
990 string QuitMessage = "";
991
992 for (int i = 2; i < commArgs.Length; i++)
993 {
994 QuitMessage += commArgs[i] + " ";
995 }
996 if (m_verbosity >= 1)
997 BroadcastSim(IrcUser, "/me quits saying \"{0}\"", QuitMessage);
998 }
999
1000 public void Close()
1001 {
1002 m_writer.WriteLine(String.Format("QUIT :{0} to {1} wormhole to {2} closing",
1003 m_nick, m_channel, m_server));
1004 m_writer.Flush();
1005
1006 m_connected = false;
1007 m_enabled = false;
1008
1009 //listener.Abort();
1010 //pingSender.Abort();
1011
1012 m_writer.Close();
1013 m_reader.Close();
1014 m_stream.Close();
1015 m_tcp.Close();
1016 }
1017 } 384 }
1018} 385}
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs b/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs
new file mode 100644
index 0000000..0eb303c
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs
@@ -0,0 +1,710 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Net.Sockets;
32using System.Reflection;
33using System.Text.RegularExpressions;
34using System.Threading;
35using OpenMetaverse;
36using log4net;
37using Nini.Config;
38using OpenSim.Framework;
39using OpenSim.Region.Environment.Interfaces;
40using OpenSim.Region.Environment.Scenes;
41
42namespace OpenSim.Region.Environment.Modules.Avatar.Chat
43{
44 public class IRCConnector
45 {
46 #region ErrorReplies enum
47
48 public enum ErrorReplies
49 {
50 NotRegistered = 451, // ":You have not registered"
51 NicknameInUse = 433 // "<nick> :Nickname is already in use"
52 }
53
54 #endregion
55
56 #region Replies enum
57
58 public enum Replies
59 {
60 MotdStart = 375, // ":- <server> Message of the day - "
61 Motd = 372, // ":- <text>"
62 EndOfMotd = 376 // ":End of /MOTD command"
63 }
64
65 #endregion
66
67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
68
69 private Thread m_listener = null;
70 private Thread m_watchdog = null;
71 private Thread m_pinger = null;
72
73 private bool m_randomizeNick = true;
74
75 public string m_baseNick = null;
76 private string m_nick = null;
77 public string Nick
78 {
79 get { return m_baseNick; }
80 set { m_baseNick = value; }
81 }
82
83 private bool m_enabled = false;
84 public bool Enabled
85 {
86 get { return m_enabled; }
87 }
88
89 private bool m_connected = false;
90 public bool Connected
91 {
92 get { return m_connected; }
93 }
94
95 private string m_ircChannel;
96 public string IrcChannel
97 {
98 get { return m_ircChannel; }
99
100 set { m_ircChannel = value; }
101 }
102
103 private bool m_relayPrivateChannels = false;
104 public bool RelayPrivateChannels
105 {
106 get { return m_relayPrivateChannels; }
107 set { m_relayPrivateChannels = value; }
108 }
109
110 private int m_relayChannel = 0;
111 public int RelayChannel
112 {
113 get { return m_relayChannel; }
114 set { m_relayChannel = value; }
115 }
116
117 private bool m_clientReporting = true;
118 public bool ClientReporting
119 {
120 get { return m_clientReporting; }
121 set { m_clientReporting = value; }
122 }
123
124 private uint m_port = 6667;
125 public uint Port
126 {
127 get { return m_port; }
128 set { m_port = value; }
129 }
130
131 private string m_server = null;
132 public string Server
133 {
134 get { return m_server; }
135 set { m_server = value; }
136 }
137
138 public string m_accessPassword = "badkitty";
139
140 private string m_privmsgformat = "PRIVMSG {0} :<{1} in {2}>: {3}";
141 private StreamReader m_reader;
142 private List<Scene> m_scenes = new List<Scene>();
143
144 private NetworkStream m_stream = null;
145 internal object m_syncConnect = new object();
146 private TcpClient m_tcp;
147 private string m_user = "USER OpenSimBot 8 * :I'm an OpenSim to IRC bot";
148 private StreamWriter m_writer;
149
150
151 public IRCConnector(IConfigSource config)
152 {
153 m_tcp = null;
154 m_writer = null;
155 m_reader = null;
156
157 // configuration in OpenSim.ini
158 // [IRC]
159 // server = chat.freenode.net
160 // nick = OSimBot_mysim
161 // nicknum = true
162 // ;nicknum set to true appends a 2 digit random number to the nick
163 // ;username = USER OpenSimBot 8 * :I'm a OpenSim to irc bot
164 // ; username is the IRC command line sent
165 // ; USER <irc_user> <visible=8,invisible=0> * : <IRC_realname>
166 // channel = #opensim-regions
167 // port = 6667
168 // ;MSGformat fields : 0=botnick, 1=user, 2=region, 3=message
169 // ;for <bot>:<user in region> :<message>
170 // ;msgformat = "PRIVMSG {0} :<{1} in {2}>: {3}"
171 // ;for <bot>:<message> - <user of region> :
172 // ;msgformat = "PRIVMSG {0} : {3} - {1} of {2}"
173 // ;for <bot>:<message> - from <user> :
174 // ;msgformat = "PRIVMSG {0} : {3} - from {1}"
175 // Traps I/O disconnects so it does not crash the sim
176 // Trys to reconnect if disconnected and someone says something
177 // Tells IRC server "QUIT" when doing a close (just to be nice)
178 // Default port back to 6667
179
180 try
181 {
182 m_server = config.Configs["IRC"].GetString("server");
183 m_baseNick = config.Configs["IRC"].GetString("nick", "OSimBot");
184
185 m_randomizeNick = config.Configs["IRC"].GetBoolean("randomize_nick", m_randomizeNick);
186 m_randomizeNick = config.Configs["IRC"].GetBoolean("nicknum", m_randomizeNick); // compat
187 m_ircChannel = config.Configs["IRC"].GetString("channel");
188 m_port = (uint)config.Configs["IRC"].GetInt("port", (int)m_port);
189 m_user = config.Configs["IRC"].GetString("username", m_user);
190 m_privmsgformat = config.Configs["IRC"].GetString("msgformat", m_privmsgformat);
191 // m_commandChannel = config.Configs["IRC"].GetInt("commandchannel", m_commandChannel);
192
193 // m_verbosity = config.Configs["IRC"].GetInt("verbosity", m_verbosity);
194 m_clientReporting = config.Configs["IRC"].GetInt("verbosity", 2) > 0;
195 m_clientReporting = config.Configs["IRC"].GetBoolean("report_clients", m_clientReporting);
196
197 // m_messageOutChannel = config.Configs["IRC"].GetInt("outchannel", m_messageOutChannel);
198 // m_messageInChannel = config.Configs["IRC"].GetInt("inchannel", m_messageInChannel);
199 m_relayPrivateChannels = config.Configs["IRC"].GetBoolean("relay_private_channels", m_relayPrivateChannels);
200 m_relayPrivateChannels = config.Configs["IRC"].GetBoolean("useworldcomm", m_relayPrivateChannels); //compat
201 m_relayChannel = config.Configs["IRC"].GetInt("relay_private_channel_in", m_relayChannel);
202 m_relayChannel = config.Configs["IRC"].GetInt("inchannel", m_relayChannel);
203 m_accessPassword = config.Configs["IRC"].GetString("access_password",m_accessPassword);
204 // m_useWorldComm = config.Configs["IRC"].GetBoolean("useworldcomm", m_useWorldComm);
205
206 if (m_server != null && m_baseNick != null && m_ircChannel != null)
207 {
208 if (m_randomizeNick)
209 {
210 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
211 }
212 m_enabled = true;
213 }
214 }
215 catch (Exception ex)
216 {
217 m_log.Error("[IRCConnector]: Incomplete IRC configuration, skipping IRC bridge configuration");
218 m_log.DebugFormat("[IRCConnector] Incomplete IRC configuration: {0}", ex.ToString());
219 }
220
221 if (null == m_watchdog)
222 {
223 m_watchdog = new Thread(WatchdogRun);
224 m_watchdog.Name = "IRCWatchdog";
225 m_watchdog.IsBackground = true;
226 }
227 }
228
229 public void Start()
230 {
231 if (!m_watchdog.IsAlive)
232 {
233 m_watchdog.Start();
234 ThreadTracker.Add(m_watchdog);
235 }
236 }
237
238 public void AddScene(Scene scene)
239 {
240 lock(m_syncConnect) m_scenes.Add(scene);
241 }
242
243 public bool Connect()
244 {
245 lock (m_syncConnect)
246 {
247 try
248 {
249 if (m_connected) return true;
250
251 m_tcp = new TcpClient(m_server, (int)m_port);
252 m_stream = m_tcp.GetStream();
253 m_reader = new StreamReader(m_stream);
254 m_writer = new StreamWriter(m_stream);
255
256 m_log.DebugFormat("[IRCConnector]: Connected to {0}:{1}", m_server, m_port);
257
258 m_pinger = new Thread(new ThreadStart(PingRun));
259 m_pinger.Name = "PingSenderThread";
260 m_pinger.IsBackground = true;
261 m_pinger.Start();
262 ThreadTracker.Add(m_pinger);
263
264 m_listener = new Thread(new ThreadStart(ListenerRun));
265 m_listener.Name = "IRCConnectorListenerThread";
266 m_listener.IsBackground = true;
267 m_listener.Start();
268 ThreadTracker.Add(m_listener);
269
270 m_writer.WriteLine(m_user);
271 m_writer.Flush();
272 m_writer.WriteLine(String.Format("NICK {0}", m_nick));
273 m_writer.Flush();
274 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel));
275 m_writer.Flush();
276 m_log.Info("[IRCConnector]: Connection fully established");
277 m_connected = true;
278 }
279 catch (Exception e)
280 {
281 m_log.ErrorFormat("[IRCConnector] cannot connect to {0}:{1}: {2}",
282 m_server, m_port, e.Message);
283 }
284 m_log.Debug("[IRCConnector] Connected");
285 return m_connected;
286 }
287 }
288
289 public void Reconnect()
290 {
291 m_connected = false;
292 try
293 {
294 m_listener.Abort();
295 m_pinger.Abort();
296
297 m_writer.Close();
298 m_reader.Close();
299
300 m_tcp.Close();
301 }
302 catch (Exception)
303 {
304 }
305
306 if (m_enabled)
307 {
308 Connect();
309 }
310 }
311
312 public void PrivMsg(string from, string region, string msg)
313 {
314 m_log.DebugFormat("[IRCConnector] Sending message to IRC from {0}: {1}", from, msg);
315
316 // One message to the IRC server
317 try
318 {
319 m_writer.WriteLine(m_privmsgformat, m_ircChannel, from, region, msg);
320 m_writer.Flush();
321 m_log.InfoFormat("[IRCConnector]: PrivMsg {0} in {1}: {2}", from, region, msg);
322 }
323 catch (IOException)
324 {
325 m_log.Error("[IRCConnector]: Disconnected from IRC server.(PrivMsg)");
326 Reconnect();
327 }
328 catch (Exception ex)
329 {
330 m_log.ErrorFormat("[IRCConnector]: PrivMsg exception trap: {0}", ex.ToString());
331 }
332 }
333
334 public void Send(string msg)
335 {
336 try
337 {
338 m_writer.WriteLine(msg);
339 m_writer.Flush();
340 m_log.Info("IRC: Sent command string: " + msg);
341 }
342 catch (IOException)
343 {
344 m_log.Error("[IRCConnector]: Disconnected from IRC server.(PrivMsg)");
345 Reconnect();
346 }
347 catch (Exception ex)
348 {
349 m_log.ErrorFormat("[IRCConnector]: PrivMsg exception trap: {0}", ex.ToString());
350 }
351
352 }
353
354
355 private Dictionary<string, string> ExtractMsg(string input)
356 {
357 //examines IRC commands and extracts any private messages
358 // which will then be reboadcast in the Sim
359
360 m_log.Info("[IRCConnector]: ExtractMsg: " + input);
361 Dictionary<string, string> result = null;
362 string regex = @":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)";
363 Regex RE = new Regex(regex, RegexOptions.Multiline);
364 MatchCollection matches = RE.Matches(input);
365
366 // Get some direct matches $1 $4 is a
367 if ((matches.Count == 0) || (matches.Count != 1) || (matches[0].Groups.Count != 5))
368 {
369 // m_log.Info("[IRCConnector]: Number of matches: " + matches.Count);
370 // if (matches.Count > 0)
371 // {
372 // m_log.Info("[IRCConnector]: Number of groups: " + matches[0].Groups.Count);
373 // }
374 return null;
375 }
376
377 result = new Dictionary<string, string>();
378 result.Add("nick", matches[0].Groups[1].Value);
379 result.Add("user", matches[0].Groups[2].Value);
380 result.Add("channel", matches[0].Groups[3].Value);
381 result.Add("msg", matches[0].Groups[4].Value);
382
383 return result;
384 }
385
386 public void PingRun()
387 {
388 // IRC keep alive thread
389 // send PING ever 15 seconds
390 while (m_enabled)
391 {
392 try
393 {
394 if (m_connected == true)
395 {
396 m_writer.WriteLine(String.Format("PING :{0}", m_server));
397 m_writer.Flush();
398 Thread.Sleep(15000);
399 }
400 }
401 catch (IOException)
402 {
403 if (m_enabled)
404 {
405 m_log.Error("[IRCConnector]: Disconnected from IRC server.(PingRun)");
406 Reconnect();
407 }
408 }
409 catch (Exception ex)
410 {
411 m_log.ErrorFormat("[IRCConnector]: PingRun exception trap: {0}\n{1}", ex.ToString(), ex.StackTrace);
412 }
413 }
414 }
415
416 static private Vector3 pos = new Vector3(128, 128, 20);
417 public void ListenerRun()
418 {
419 string inputLine;
420
421 while (m_enabled)
422 {
423 try
424 {
425 while ((m_connected) && ((inputLine = m_reader.ReadLine()) != null))
426 {
427 // m_log.Info("[IRCConnector]: " + inputLine);
428
429 if (inputLine.Contains(m_ircChannel))
430 {
431 Dictionary<string, string> data = ExtractMsg(inputLine);
432 // Any chat ???
433 if (data != null)
434 {
435 OSChatMessage c = new OSChatMessage();
436 c.Message = data["msg"];
437 c.Type = ChatTypeEnum.Region;
438 c.Position = pos;
439 c.Channel = m_relayPrivateChannels ? m_relayChannel : 0;
440 c.From = data["nick"];
441 c.Sender = null;
442 c.SenderUUID = UUID.Zero;
443
444 // is message "\001ACTION foo
445 // bar\001"? -> "/me foo bar"
446 if ((1 == c.Message[0]) && c.Message.Substring(1).StartsWith("ACTION"))
447 c.Message = String.Format("/me {0}", c.Message.Substring(8, c.Message.Length - 9));
448
449 m_log.DebugFormat("[IRCConnector] ListenerRun from: {0}, {1}", c.From, c.Message);
450
451 foreach (Scene scene in m_scenes)
452 {
453 c.Scene = scene;
454 scene.EventManager.TriggerOnChatBroadcast(this, c);
455 }
456 }
457
458 Thread.Sleep(150);
459 continue;
460 }
461
462 ProcessIRCCommand(inputLine);
463 Thread.Sleep(150);
464 }
465 }
466 catch (IOException)
467 {
468 if (m_enabled)
469 {
470 m_log.Error("[IRCConnector]: ListenerRun IOException. Disconnected from IRC server ??? (ListenerRun)");
471 Reconnect();
472 }
473 }
474 catch (Exception ex)
475 {
476 m_log.ErrorFormat("[IRCConnector]: ListenerRun exception trap: {0}\n{1}", ex.ToString(), ex.StackTrace);
477 }
478 }
479 }
480
481 public void BroadcastSim(string sender, string format, params string[] args)
482 {
483 try
484 {
485 OSChatMessage c = new OSChatMessage();
486 c.From = sender;
487 c.Message = String.Format(format, args);
488 c.Type = ChatTypeEnum.Region; // ChatTypeEnum.Say;
489 c.Channel = m_relayPrivateChannels ? m_relayChannel : 0;
490 c.Position = new Vector3(128, 128, 20);
491 c.Sender = null;
492 c.SenderUUID = UUID.Zero;
493
494 m_log.DebugFormat("[IRCConnector] BroadcastSim from {0}: {1}", c.From, c.Message);
495
496 foreach (Scene scene in m_scenes)
497 {
498 c.Scene = scene;
499 scene.EventManager.TriggerOnChatBroadcast(this, c);
500 // // m_scene.EventManager.TriggerOnChatFromWorld(this, c);
501 // IWorldComm wComm = m_scene.RequestModuleInterface<IWorldComm>();
502 // wComm.DeliverMessage(ChatTypeEnum.Region, m_messageInChannel, sender, UUID.Zero, c.Message);
503 // //IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
504 // //wComm.DeliverMessage(ChatTypeEnum.Region, channelID, m_host.Name, m_host.UUID, text);
505
506 }
507 }
508 catch (Exception ex) // IRC gate should not crash Sim
509 {
510 m_log.ErrorFormat("[IRCConnector]: BroadcastSim Exception Trap: {0}\n{1}", ex.ToString(), ex.StackTrace);
511 }
512 }
513
514 public void ProcessIRCCommand(string command)
515 {
516 // m_log.Debug("[IRCConnector]: ProcessIRCCommand:" + command);
517
518 string[] commArgs = new string[command.Split(' ').Length];
519 string c_server = m_server;
520
521 commArgs = command.Split(' ');
522 if (commArgs[0].Substring(0, 1) == ":")
523 {
524 commArgs[0] = commArgs[0].Remove(0, 1);
525 }
526
527 if (commArgs[1] == "002")
528 {
529 // fetch the correct servername
530 // ex: irc.freenode.net -> brown.freenode.net/kornbluth.freenode.net/...
531 // irc.bluewin.ch -> irc1.bluewin.ch/irc2.bluewin.ch
532
533 c_server = (commArgs[6].Split('['))[0];
534 m_server = c_server;
535 }
536
537 if (commArgs[0] == "ERROR")
538 {
539 m_log.ErrorFormat("[IRCConnector]: IRC SERVER ERROR: {0}", command);
540 }
541
542 if (commArgs[0] == "PING")
543 {
544 string p_reply = "";
545
546 for (int i = 1; i < commArgs.Length; i++)
547 {
548 p_reply += commArgs[i] + " ";
549 }
550
551 m_writer.WriteLine(String.Format("PONG {0}", p_reply));
552 m_writer.Flush();
553 }
554 else if (commArgs[0] == c_server)
555 {
556 // server message
557 try
558 {
559 Int32 commandCode = Int32.Parse(commArgs[1]);
560 switch (commandCode)
561 {
562 case (int)ErrorReplies.NicknameInUse:
563 // Gen a new name
564 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
565 m_log.ErrorFormat("[IRCConnector]: IRC SERVER reports NicknameInUse, trying {0}", m_nick);
566 // Retry
567 m_writer.WriteLine(String.Format("NICK {0}", m_nick));
568 m_writer.Flush();
569 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel));
570 m_writer.Flush();
571 break;
572 case (int)ErrorReplies.NotRegistered:
573 break;
574 case (int)Replies.EndOfMotd:
575 break;
576 }
577 }
578 catch (Exception)
579 {
580 }
581 }
582 else
583 {
584 // Normal message
585 string commAct = commArgs[1];
586 switch (commAct)
587 {
588 case "JOIN":
589 eventIrcJoin(commArgs);
590 break;
591 case "PART":
592 eventIrcPart(commArgs);
593 break;
594 case "MODE":
595 eventIrcMode(commArgs);
596 break;
597 case "NICK":
598 eventIrcNickChange(commArgs);
599 break;
600 case "KICK":
601 eventIrcKick(commArgs);
602 break;
603 case "QUIT":
604 eventIrcQuit(commArgs);
605 break;
606 case "PONG":
607 break; // that's nice
608 }
609 }
610 }
611
612 public void eventIrcJoin(string[] commArgs)
613 {
614 string IrcChannel = commArgs[2];
615 if (IrcChannel.StartsWith(":"))
616 IrcChannel = IrcChannel.Substring(1);
617 string IrcUser = commArgs[0].Split('!')[0];
618 if (m_clientReporting)
619 BroadcastSim(IrcUser, "/me joins {0}", IrcChannel);
620 }
621
622 public void eventIrcPart(string[] commArgs)
623 {
624 string IrcChannel = commArgs[2];
625 string IrcUser = commArgs[0].Split('!')[0];
626 if (m_clientReporting)
627 BroadcastSim(IrcUser, "/me parts {0}", IrcChannel);
628 }
629
630 public void eventIrcMode(string[] commArgs)
631 {
632 string UserMode = "";
633 for (int i = 3; i < commArgs.Length; i++)
634 {
635 UserMode += commArgs[i] + " ";
636 }
637
638 if (UserMode.Substring(0, 1) == ":")
639 {
640 UserMode = UserMode.Remove(0, 1);
641 }
642 }
643
644 public void eventIrcNickChange(string[] commArgs)
645 {
646 string UserOldNick = commArgs[0].Split('!')[0];
647 string UserNewNick = commArgs[2].Remove(0, 1);
648 if (m_clientReporting)
649 BroadcastSim(UserOldNick, "/me is now known as {0}", UserNewNick);
650 }
651
652 public void eventIrcKick(string[] commArgs)
653 {
654 string UserKicker = commArgs[0].Split('!')[0];
655 string UserKicked = commArgs[3];
656 string IrcChannel = commArgs[2];
657 string KickMessage = "";
658 for (int i = 4; i < commArgs.Length; i++)
659 {
660 KickMessage += commArgs[i] + " ";
661 }
662 if (m_clientReporting)
663 BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage);
664 if (UserKicked == m_nick)
665 {
666 BroadcastSim(m_nick, "Hey, that was me!!!");
667 }
668 }
669
670 public void eventIrcQuit(string[] commArgs)
671 {
672 string IrcUser = commArgs[0].Split('!')[0];
673 string QuitMessage = "";
674
675 for (int i = 2; i < commArgs.Length; i++)
676 {
677 QuitMessage += commArgs[i] + " ";
678 }
679 if (m_clientReporting)
680 BroadcastSim(IrcUser, "/me quits saying \"{0}\"", QuitMessage);
681 }
682
683 public void Close()
684 {
685 m_writer.WriteLine(String.Format("QUIT :{0} to {1} wormhole to {2} closing",
686 m_nick, m_ircChannel, m_server));
687 m_writer.Flush();
688
689 m_connected = false;
690 m_enabled = false;
691
692 //listener.Abort();
693 //pingSender.Abort();
694
695 m_writer.Close();
696 m_reader.Close();
697 m_stream.Close();
698 m_tcp.Close();
699 }
700
701 protected void WatchdogRun()
702 {
703 while (m_enabled)
704 {
705 if (!m_connected) Connect();
706 Thread.Sleep(15000);
707 }
708 }
709 }
710} \ No newline at end of file
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeModule.cs
index d9730dd..6cc622e 100644
--- a/OpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeModule.cs
+++ b/OpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeModule.cs
@@ -38,24 +38,28 @@ using OpenMetaverse;
38using OpenSim.Framework; 38using OpenSim.Framework;
39using OpenSim.Region.Environment.Interfaces; 39using OpenSim.Region.Environment.Interfaces;
40using OpenSim.Region.Environment.Scenes; 40using OpenSim.Region.Environment.Scenes;
41using OpenSim.Region.Environment.Modules.Avatar.Chat;
41 42
42namespace OpenSim.Region.Environment.Modules.Avatar.Concierge 43namespace OpenSim.Region.Environment.Modules.Avatar.Concierge
43{ 44{
44 public class ConciergeModule : IRegionModule 45 public class ConciergeModule : ChatModule, IRegionModule
45 { 46 {
46 private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47 48
48 private const int DEBUG_CHANNEL = 2147483647; 49 private const int DEBUG_CHANNEL = 2147483647;
49 50
50 private int _conciergeChannel = 42; 51 private int _conciergeChannel = 42;
51 private List<Scene> _scenes = new List<Scene>(); 52 private List<IScene> _scenes = new List<IScene>();
53 private List<IScene> _conciergedScenes = new List<IScene>();
52 private IConfig _config; 54 private IConfig _config;
53 private string _whoami = "conferencier"; 55 private string _whoami = "conferencier";
56 private bool _replacingChatModule = false;
57 private Regex _regions = null;
54 58
55 internal object _syncy = new object(); 59 internal object _syncy = new object();
56 60
57 #region IRegionModule Members 61 #region IRegionModule Members
58 public void Initialise(Scene scene, IConfigSource config) 62 public override void Initialise(Scene scene, IConfigSource config)
59 { 63 {
60 try 64 try
61 { 65 {
@@ -78,25 +82,58 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Concierge
78 return; 82 return;
79 } 83 }
80 84
81 if (_config != null) 85 // check whether ChatModule has been disabled: if yes,
86 // then we'll "stand in"
87 try
88 {
89 if (config.Configs["Chat"] == null)
90 {
91 _replacingChatModule = false;
92 }
93 else
94 {
95 _replacingChatModule = !config.Configs["Chat"].GetBoolean("enabled", true);
96 }
97 }
98 catch (Exception)
82 { 99 {
83 _conciergeChannel = config.Configs["Concierge"].GetInt("concierge_channel", _conciergeChannel); 100 _replacingChatModule = false;
84 _whoami = _config.GetString("whoami", "conferencier");
85 } 101 }
102 _log.InfoFormat("[Concierge] {0} ChatModule", _replacingChatModule ? "replacing" : "not replacing");
103
104
105 // take note of concierge channel and of identity
106 _conciergeChannel = config.Configs["Concierge"].GetInt("concierge_channel", _conciergeChannel);
107 _whoami = _config.GetString("whoami", "conferencier");
86 _log.InfoFormat("[Concierge] reporting as \"{0}\" to our users", _whoami); 108 _log.InfoFormat("[Concierge] reporting as \"{0}\" to our users", _whoami);
87 109
110 // calculate regions Regex
111 if (_regions == null)
112 {
113 string regions = _config.GetString("regions", String.Empty);
114 if (!String.IsNullOrEmpty(regions))
115 {
116 _regions = new Regex(regions, RegexOptions.Compiled | RegexOptions.IgnoreCase);
117 }
118 }
119
88 lock (_syncy) 120 lock (_syncy)
89 { 121 {
90 if (!_scenes.Contains(scene)) 122 if (!_scenes.Contains(scene))
91 { 123 {
92 _scenes.Add(scene); 124 _scenes.Add(scene);
125
126 if (_regions.IsMatch(scene.RegionInfo.RegionName))
127 _conciergedScenes.Add(scene);
128
93 // subscribe to NewClient events 129 // subscribe to NewClient events
94 scene.EventManager.OnNewClient += OnNewClient; 130 scene.EventManager.OnNewClient += OnNewClient;
95 scene.EventManager.OnNewClient += OnNewClient;
96 131
97 // subscribe to *Chat events and FilterChat* events 132 // subscribe to *Chat events
98 scene.EventManager.OnChatFromWorld += OnSimChat; 133 scene.EventManager.OnChatFromWorld += OnChatFromWorld;
99 scene.EventManager.OnChatBroadcast += OnSimBroadcast; 134 if (!_replacingChatModule)
135 scene.EventManager.OnChatFromClient += OnChatFromClient;
136 scene.EventManager.OnChatBroadcast += OnChatBroadcast;
100 137
101 // subscribe to agent change events 138 // subscribe to agent change events
102 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; 139 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
@@ -106,20 +143,20 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Concierge
106 _log.InfoFormat("[Concierge] initialized for {0}", scene.RegionInfo.RegionName); 143 _log.InfoFormat("[Concierge] initialized for {0}", scene.RegionInfo.RegionName);
107 } 144 }
108 145
109 public void PostInitialise() 146 public override void PostInitialise()
110 { 147 {
111 } 148 }
112 149
113 public void Close() 150 public override void Close()
114 { 151 {
115 } 152 }
116 153
117 public string Name 154 public override string Name
118 { 155 {
119 get { return "ConciergeModule"; } 156 get { return "ConciergeModule"; }
120 } 157 }
121 158
122 public bool IsSharedModule 159 public override bool IsSharedModule
123 { 160 {
124 get { return true; } 161 get { return true; }
125 } 162 }
@@ -127,44 +164,90 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Concierge
127 #endregion 164 #endregion
128 165
129 #region ISimChat Members 166 #region ISimChat Members
130 public void OnSimBroadcast(Object sender, OSChatMessage c) 167 public override void OnChatBroadcast(Object sender, OSChatMessage c)
131 { 168 {
132 // log to buffer? 169 if (_replacingChatModule)
170 {
171 // distribute chat message to each and every avatar in
172 // the region
173 base.OnChatBroadcast(sender, c);
174 }
175
176 // TODO: capture logic
133 return; 177 return;
134 } 178 }
135 179
136 public void OnSimChat(Object sender, OSChatMessage c) 180 public override void OnChatFromClient(Object sender, OSChatMessage c)
137 { 181 {
138 if (_conciergeChannel == c.Channel) 182 if (_replacingChatModule)
139 {
140 // concierge request: interpret
141 return;
142 }
143
144 if (0 == c.Channel || DEBUG_CHANNEL == c.Channel)
145 { 183 {
146 // if (_amplify) 184 if (_conciergedScenes.Contains(c.Scene))
147 // { 185 {
148 186 // replacing ChatModule: need to redistribute
149 // } 187 // ChatFromClient to interested subscribers
188 Scene scene = (Scene)c.Scene;
189 scene.EventManager.TriggerOnChatFromClient(sender, c);
190
191 // when we are replacing ChatModule, we treat
192 // OnChatFromClient like OnChatBroadcast for
193 // concierged regions, effectively extending the
194 // range of chat to cover the whole
195 // region. however, we don't do this for whisper
196 // (got to have some privacy)
197 if (c.Type != ChatTypeEnum.Whisper)
198 {
199 base.OnChatBroadcast(sender, c);
200 return;
201 }
202 }
150 203
151 // log as avatar/prim chat 204 // redistribution will be done by base class
152 return; 205 base.OnChatFromClient(sender, c);
153 } 206 }
154 207
208 // TODO: capture chat
155 return; 209 return;
156 } 210 }
157 211
212 public override void OnChatFromWorld(Object sender, OSChatMessage c)
213 {
214 if (_replacingChatModule)
215 {
216 if (_conciergedScenes.Contains(c.Scene))
217 {
218 // when we are replacing ChatModule, we treat
219 // OnChatFromClient like OnChatBroadcast for
220 // concierged regions, effectively extending the
221 // range of chat to cover the whole
222 // region. however, we don't do this for whisper
223 // (got to have some privacy)
224 if (c.Type != ChatTypeEnum.Whisper)
225 {
226 base.OnChatBroadcast(sender, c);
227 return;
228 }
229 }
230
231 base.OnChatFromWorld(sender, c);
232 }
233 return;
234 }
158 #endregion 235 #endregion
159 236
160 237
161 public void OnNewClient(IClientAPI client) 238 public override void OnNewClient(IClientAPI client)
162 { 239 {
163 client.OnLogout += OnClientLoggedOut; 240 client.OnLogout += OnClientLoggedOut;
164 client.OnConnectionClosed += OnClientLoggedOut; 241 client.OnConnectionClosed += OnClientLoggedOut;
242 if (_replacingChatModule)
243 client.OnChatFromClient += OnChatFromClient;
165 244
166 _log.DebugFormat("[Concierge] {0} logs on to {1}", client.Name, client.Scene.RegionInfo.RegionName); 245 if (_conciergedScenes.Contains(client.Scene))
167 AnnounceToAgentsRegion(client, String.Format("{0} logs on to {1}", client.Name, client.Scene.RegionInfo.RegionName)); 246 {
247 _log.DebugFormat("[Concierge] {0} logs on to {1}", client.Name, client.Scene.RegionInfo.RegionName);
248 AnnounceToAgentsRegion(client, String.Format("{0} logs on to {1}", client.Name,
249 client.Scene.RegionInfo.RegionName));
250 }
168 } 251 }
169 252
170 public void OnClientLoggedOut(IClientAPI client) 253 public void OnClientLoggedOut(IClientAPI client)
@@ -172,32 +255,46 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Concierge
172 client.OnLogout -= OnClientLoggedOut; 255 client.OnLogout -= OnClientLoggedOut;
173 client.OnConnectionClosed -= OnClientLoggedOut; 256 client.OnConnectionClosed -= OnClientLoggedOut;
174 257
175 _log.DebugFormat("[Concierge] {0} logs off from {1}", client.Name, client.Scene.RegionInfo.RegionName); 258 if (_conciergedScenes.Contains(client.Scene))
176 AnnounceToAgentsRegion(client, String.Format("{0} logs off from {1}", client.Name, client.Scene.RegionInfo.RegionName)); 259 {
260 _log.DebugFormat("[Concierge] {0} logs off from {1}", client.Name, client.Scene.RegionInfo.RegionName);
261 AnnounceToAgentsRegion(client, String.Format("{0} logs off from {1}", client.Name,
262 client.Scene.RegionInfo.RegionName));
263 }
177 } 264 }
178 265
179 266
180 public void OnMakeRootAgent(ScenePresence agent) 267 public void OnMakeRootAgent(ScenePresence agent)
181 { 268 {
182 _log.DebugFormat("[Concierge] {0} enters {1}", agent.Name, agent.Scene.RegionInfo.RegionName); 269 if (_conciergedScenes.Contains(agent.Scene))
183 AnnounceToAgentsRegion(agent, String.Format("{0} enters {1}", agent.Name, agent.Scene.RegionInfo.RegionName)); 270 {
271 _log.DebugFormat("[Concierge] {0} enters {1}", agent.Name, agent.Scene.RegionInfo.RegionName);
272 AnnounceToAgentsRegion(agent, String.Format("{0} enters {1}", agent.Name,
273 agent.Scene.RegionInfo.RegionName));
274 }
184 } 275 }
185 276
186 277
187 public void OnMakeChildAgent(ScenePresence agent) 278 public void OnMakeChildAgent(ScenePresence agent)
188 { 279 {
189 _log.DebugFormat("[Concierge] {0} leaves {1}", agent.Name, agent.Scene.RegionInfo.RegionName); 280 if (_conciergedScenes.Contains(agent.Scene))
190 AnnounceToAgentsRegion(agent, String.Format("{0} leaves {1}", agent.Name, agent.Scene.RegionInfo.RegionName)); 281 {
282 _log.DebugFormat("[Concierge] {0} leaves {1}", agent.Name, agent.Scene.RegionInfo.RegionName);
283 AnnounceToAgentsRegion(agent, String.Format("{0} leaves {1}", agent.Name,
284 agent.Scene.RegionInfo.RegionName));
285 }
191 } 286 }
192 287
193 288
194 public void ClientLoggedOut(IClientAPI client) 289 public void ClientLoggedOut(IClientAPI client)
195 { 290 {
196 _log.DebugFormat("[Concierge] {0} logs out of {1}", client.Name, client.Scene.RegionInfo.RegionName); 291 if (_conciergedScenes.Contains(client.Scene))
197 AnnounceToAgentsRegion(client, String.Format("{0} logs out of {1}", client.Name, client.Scene.RegionInfo.RegionName)); 292 {
293 _log.DebugFormat("[Concierge] {0} logs out of {1}", client.Name, client.Scene.RegionInfo.RegionName);
294 AnnounceToAgentsRegion(client, String.Format("{0} logs out of {1}", client.Name, client.Scene.RegionInfo.RegionName));
295 }
198 } 296 }
199 297
200
201 static private Vector3 posOfGod = new Vector3(128, 128, 9999); 298 static private Vector3 posOfGod = new Vector3(128, 128, 9999);
202 299
203 protected void AnnounceToAgentsRegion(IClientAPI client, string msg) 300 protected void AnnounceToAgentsRegion(IClientAPI client, string msg)
diff --git a/OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs b/OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs
index f8e933d..36add06 100644
--- a/OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs
+++ b/OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs
@@ -34,6 +34,10 @@ using OpenSim.Framework;
34using OpenSim.Region.Environment.Interfaces; 34using OpenSim.Region.Environment.Interfaces;
35using OpenSim.Region.Environment.Scenes; 35using OpenSim.Region.Environment.Scenes;
36 36
37// using log4net;
38// using System.Reflection;
39
40
37/***************************************************** 41/*****************************************************
38 * 42 *
39 * WorldCommModule 43 * WorldCommModule
@@ -83,6 +87,9 @@ namespace OpenSim.Region.Environment.Modules.Scripting.WorldComm
83{ 87{
84 public class WorldCommModule : IRegionModule, IWorldComm 88 public class WorldCommModule : IRegionModule, IWorldComm
85 { 89 {
90 // private static readonly ILog m_log =
91 // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
92
86 private ListenerManager m_listenerManager; 93 private ListenerManager m_listenerManager;
87 private Queue m_pending; 94 private Queue m_pending;
88 private Queue m_pendingQ; 95 private Queue m_pendingQ;
@@ -117,6 +124,7 @@ namespace OpenSim.Region.Environment.Modules.Scripting.WorldComm
117 m_scene.RegisterModuleInterface<IWorldComm>(this); 124 m_scene.RegisterModuleInterface<IWorldComm>(this);
118 m_listenerManager = new ListenerManager(maxlisteners, maxhandles); 125 m_listenerManager = new ListenerManager(maxlisteners, maxhandles);
119 m_scene.EventManager.OnChatFromClient += DeliverClientMessage; 126 m_scene.EventManager.OnChatFromClient += DeliverClientMessage;
127 m_scene.EventManager.OnChatBroadcast += DeliverClientMessage;
120 m_pendingQ = new Queue(); 128 m_pendingQ = new Queue();
121 m_pending = Queue.Synchronized(m_pendingQ); 129 m_pending = Queue.Synchronized(m_pendingQ);
122 } 130 }
@@ -197,6 +205,22 @@ namespace OpenSim.Region.Environment.Modules.Scripting.WorldComm
197 m_listenerManager.DeleteListener(itemID); 205 m_listenerManager.DeleteListener(itemID);
198 } 206 }
199 207
208 public void DeliverMessage(ChatTypeEnum type, int channel, string name, UUID id, string msg)
209 {
210 Vector3 position;
211 SceneObjectPart source;
212 ScenePresence avatar;
213
214 if ((source = m_scene.GetSceneObjectPart(id)) != null)
215 position = source.AbsolutePosition;
216 else if ((avatar = m_scene.GetScenePresence(id)) != null)
217 position = avatar.AbsolutePosition;
218 else
219 return;
220
221 DeliverMessage(type, channel, name, id, msg, position);
222 }
223
200 /// <summary> 224 /// <summary>
201 /// This method scans over the objects which registered an interest in listen callbacks. 225 /// This method scans over the objects which registered an interest in listen callbacks.
202 /// For everyone it finds, it checks if it fits the given filter. If it does, then 226 /// For everyone it finds, it checks if it fits the given filter. If it does, then
@@ -210,39 +234,8 @@ namespace OpenSim.Region.Environment.Modules.Scripting.WorldComm
210 /// <param name="name">name of sender (object or avatar)</param> 234 /// <param name="name">name of sender (object or avatar)</param>
211 /// <param name="id">key of sender (object or avatar)</param> 235 /// <param name="id">key of sender (object or avatar)</param>
212 /// <param name="msg">msg to sent</param> 236 /// <param name="msg">msg to sent</param>
213 public void DeliverMessage(ChatTypeEnum type, int channel, string name, UUID id, string msg) 237 public void DeliverMessage(ChatTypeEnum type, int channel, string name, UUID id, string msg, Vector3 position)
214 { 238 {
215 SceneObjectPart source = null;
216 ScenePresence avatar = null;
217 Vector3 position;
218
219 source = m_scene.GetSceneObjectPart(id);
220 if (source != null)
221 position = source.AbsolutePosition;
222 else {
223 avatar = m_scene.GetScenePresence(id);
224 if (avatar != null)
225 {
226 position = avatar.AbsolutePosition;
227 }
228 else
229 {
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 }
244 }
245
246 // Determine which listen event filters match the given set of arguments, this results 239 // Determine which listen event filters match the given set of arguments, this results
247 // in a limited set of listeners, each belonging a host. If the host is in range, add them 240 // in a limited set of listeners, each belonging a host. If the host is in range, add them
248 // to the pending queue. 241 // to the pending queue.
@@ -326,11 +319,6 @@ namespace OpenSim.Region.Environment.Modules.Scripting.WorldComm
326 319
327 #endregion 320 #endregion
328 321
329 // private void NewClient(IClientAPI client)
330 // {
331 // client.OnChatFromViewer += DeliverClientMessage;
332 // }
333
334 /******************************************************************** 322 /********************************************************************
335 * 323 *
336 * Listener Stuff 324 * Listener Stuff
@@ -339,11 +327,10 @@ namespace OpenSim.Region.Environment.Modules.Scripting.WorldComm
339 327
340 private void DeliverClientMessage(Object sender, OSChatMessage e) 328 private void DeliverClientMessage(Object sender, OSChatMessage e)
341 { 329 {
342 DeliverMessage(e.Type, 330 if (null != e.Sender)
343 e.Channel, 331 DeliverMessage(e.Type, e.Channel, e.Sender.Name, e.Sender.AgentId, e.Message, e.Position);
344 e.Sender.Name, 332 else
345 e.Sender.AgentId, 333 DeliverMessage(e.Type, e.Channel, e.From, UUID.Zero, e.Message, e.Position);
346 e.Message);
347 } 334 }
348 335
349 public Object[] GetSerializationData(UUID itemID) 336 public Object[] GetSerializationData(UUID itemID)
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index b3f7ba7..4c4d173 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -7238,7 +7238,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7238 { 7238 {
7239 m_host.AddScriptLPS(1); 7239 m_host.AddScriptLPS(1);
7240 7240
7241 World.SimChatBroadcast(Utils.StringToBytes(msg), ChatTypeEnum.Owner, 0, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false); 7241 World.SimChatBroadcast(Utils.StringToBytes(msg), ChatTypeEnum.Owner, 0,
7242 m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
7242// IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>(); 7243// IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
7243// wComm.DeliverMessage(ChatTypeEnum.Owner, 0, m_host.Name, m_host.UUID, msg); 7244// wComm.DeliverMessage(ChatTypeEnum.Owner, 0, m_host.Name, m_host.UUID, msg);
7244 } 7245 }
diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example
index 970bad1..16caa0c 100644
--- a/bin/OpenSim.ini.example
+++ b/bin/OpenSim.ini.example
@@ -398,20 +398,21 @@ flush-on-error=true
398;nick = OpenSimBotNameProbablyMakeThisShorter 398;nick = OpenSimBotNameProbablyMakeThisShorter
399;channel = #the_irc_channel_you_want_to_connect_to 399;channel = #the_irc_channel_you_want_to_connect_to
400;port = 6667 400;port = 6667
401;; channel to listen for configuration updates 401;; channel to listen for configuration commands
402;commandchannel = 2777 402;commands_enabled = false
403;; 0 for no control messages, 2 for all control messages 403;command_channel = 2777
404;verbosity = 1 404;report_clients = true
405;; bridging connections 405;; relay private chat connections
406;; outchannel -- channel to send messages out to the IRC bridge 406;; relay_private_channels = true: will relay IRC chat from/to private in-world channels
407;; inchannel -- channel to receive message from the IRC bridge 407;; relay_channel_out -- channel to send messages out to the IRC bridge
408;; relay_channel_in -- channel to receive message from the IRC bridge
408;; access_password -- simple security device 409;; access_password -- simple security device
409;inchannel = 2226 410;relay_private_channels = false
410;outchannel = 2225 411;relay_channel_in = 2226
412;relay_channel_out = 2225
411;access_password = foobar 413;access_password = foobar
414
412;fallback_region = name of "default" region 415;fallback_region = name of "default" region
413;;useworldcomm = true will send IRC chat over the inchannel, false (default) will broadcast to all agents in the region
414;useworldcomm = true
415;MSGformat fields : 0=botnick, 1=user, 2=region, 3=message 416;MSGformat fields : 0=botnick, 1=user, 2=region, 3=message
416; must start with "PRIVMSG {0} : " or irc server will get upset 417; must start with "PRIVMSG {0} : " or irc server will get upset
417;for <bot>:<user in region> :<message> 418;for <bot>:<user in region> :<message>