aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/Avatar/Chat/ChannelState.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Environment/Modules/Avatar/Chat/ChannelState.cs')
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Chat/ChannelState.cs628
1 files changed, 0 insertions, 628 deletions
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Chat/ChannelState.cs b/OpenSim/Region/Environment/Modules/Avatar/Chat/ChannelState.cs
deleted file mode 100644
index dfa1caa..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Chat/ChannelState.cs
+++ /dev/null
@@ -1,628 +0,0 @@
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.Reflection;
31using System.Text.RegularExpressions;
32using log4net;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37
38namespace OpenSim.Region.Environment.Modules.Avatar.Chat
39{
40
41 // An instance of this class exists for each unique combination of
42 // IRC chat interface characteristics, as determined by the supplied
43 // configuration file.
44
45 internal class ChannelState
46 {
47
48 private static readonly ILog m_log =
49 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 private static Regex arg = new Regex(@"\[[^\[\]]*\]");
52 private static int _idk_ = 0;
53 private static int DEBUG_CHANNEL = 2147483647;
54
55 // These are the IRC Connector configurable parameters with hard-wired
56 // default values (retained for compatability).
57
58 internal string Server = null;
59 internal string Password = null;
60 internal string IrcChannel = null;
61 internal string BaseNickname = "OSimBot";
62 internal uint Port = 6667;
63 internal string User = "USER OpenSimBot 8 * :I'm an OpenSim to IRC bot";
64
65 internal bool ClientReporting = true;
66 internal bool RelayChat = true;
67 internal bool RelayPrivateChannels = false;
68 internal int RelayChannel = 1;
69 internal List<int> ValidInWorldChannels = new List<int>();
70
71 // Connector agnostic parameters. These values are NOT shared with the
72 // connector and do not differentiate at an IRC level
73
74 internal string PrivateMessageFormat = "PRIVMSG {0} :<{2}> {1} {3}";
75 internal string NoticeMessageFormat = "PRIVMSG {0} :<{2}> {3}";
76 internal int RelayChannelOut = -1;
77 internal bool RandomizeNickname = true;
78 internal bool CommandsEnabled = false;
79 internal int CommandChannel = -1;
80 internal int ConnectDelay = 10;
81 internal int PingDelay = 15;
82 internal string DefaultZone = "Sim";
83
84 internal string _accessPassword = String.Empty;
85 internal Regex AccessPasswordRegex = null;
86 internal string AccessPassword
87 {
88 get { return _accessPassword; }
89 set
90 {
91 _accessPassword = value;
92 AccessPasswordRegex = new Regex(String.Format(@"^{0},\s*(?<avatar>[^,]+),\s*(?<message>.+)$", _accessPassword),
93 RegexOptions.Compiled);
94 }
95 }
96
97
98
99 // IRC connector reference
100
101 internal IRCConnector irc = null;
102
103 internal int idn = _idk_++;
104
105 // List of regions dependent upon this connection
106
107 internal List<RegionState> clientregions = new List<RegionState>();
108
109 // Needed by OpenChannel
110
111 internal ChannelState()
112 {
113 }
114
115 // This constructor is used by the Update* methods. A copy of the
116 // existing channel state is created, and distinguishing characteristics
117 // are copied across.
118
119 internal ChannelState(ChannelState model)
120 {
121 Server = model.Server;
122 Password = model.Password;
123 IrcChannel = model.IrcChannel;
124 Port = model.Port;
125 BaseNickname = model.BaseNickname;
126 RandomizeNickname = model.RandomizeNickname;
127 User = model.User;
128 CommandsEnabled = model.CommandsEnabled;
129 CommandChannel = model.CommandChannel;
130 RelayChat = model.RelayChat;
131 RelayPrivateChannels = model.RelayPrivateChannels;
132 RelayChannelOut = model.RelayChannelOut;
133 RelayChannel = model.RelayChannel;
134 ValidInWorldChannels = model.ValidInWorldChannels;
135 PrivateMessageFormat = model.PrivateMessageFormat;
136 NoticeMessageFormat = model.NoticeMessageFormat;
137 ClientReporting = model.ClientReporting;
138 AccessPassword = model.AccessPassword;
139 DefaultZone = model.DefaultZone;
140 ConnectDelay = model.ConnectDelay;
141 PingDelay = model.PingDelay;
142 }
143
144 // Read the configuration file, performing variable substitution and any
145 // necessary aliasing. See accompanying documentation for how this works.
146 // If you don't need variables, then this works exactly as before.
147 // If either channel or server are not specified, the request fails.
148
149 internal static void OpenChannel(RegionState rs, IConfig config)
150 {
151
152 // Create a new instance of a channel. This may not actually
153 // get used if an equivalent channel already exists.
154
155 ChannelState cs = new ChannelState();
156
157 // Read in the configuration file and filter everything for variable
158 // subsititution.
159
160 m_log.DebugFormat("[IRC-Channel-{0}] Initial request by Region {1} to connect to IRC", cs.idn, rs.Region);
161
162 cs.Server = Substitute(rs, config.GetString("server", null));
163 m_log.DebugFormat("[IRC-Channel-{0}] Server : <{1}>", cs.idn, cs.Server);
164 cs.Password = Substitute(rs, config.GetString("password", null));
165 // probably not a good idea to put a password in the log file
166 cs.IrcChannel = Substitute(rs, config.GetString("channel", null));
167 m_log.DebugFormat("[IRC-Channel-{0}] IrcChannel : <{1}>", cs.idn, cs.IrcChannel);
168 cs.Port = Convert.ToUInt32(Substitute(rs, config.GetString("port", Convert.ToString(cs.Port))));
169 m_log.DebugFormat("[IRC-Channel-{0}] Port : <{1}>", cs.idn, cs.Port);
170 cs.BaseNickname = Substitute(rs, config.GetString("nick", cs.BaseNickname));
171 m_log.DebugFormat("[IRC-Channel-{0}] BaseNickname : <{1}>", cs.idn, cs.BaseNickname);
172 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("randomize_nick", Convert.ToString(cs.RandomizeNickname))));
173 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
174 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("nicknum", Convert.ToString(cs.RandomizeNickname))));
175 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
176 cs.User = Substitute(rs, config.GetString("username", cs.User));
177 m_log.DebugFormat("[IRC-Channel-{0}] User : <{1}>", cs.idn, cs.User);
178 cs.CommandsEnabled = Convert.ToBoolean(Substitute(rs, config.GetString("commands_enabled", Convert.ToString(cs.CommandsEnabled))));
179 m_log.DebugFormat("[IRC-Channel-{0}] CommandsEnabled : <{1}>", cs.idn, cs.CommandsEnabled);
180 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("commandchannel", Convert.ToString(cs.CommandChannel))));
181 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
182 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("command_channel", Convert.ToString(cs.CommandChannel))));
183 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
184 cs.RelayChat = Convert.ToBoolean(Substitute(rs, config.GetString("relay_chat", Convert.ToString(cs.RelayChat))));
185 m_log.DebugFormat("[IRC-Channel-{0}] RelayChat : <{1}>", cs.idn, cs.RelayChat);
186 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("relay_private_channels", Convert.ToString(cs.RelayPrivateChannels))));
187 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
188 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("useworldcomm", Convert.ToString(cs.RelayPrivateChannels))));
189 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
190 cs.RelayChannelOut = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_out", Convert.ToString(cs.RelayChannelOut))));
191 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannelOut : <{1}>", cs.idn, cs.RelayChannelOut);
192 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_in", Convert.ToString(cs.RelayChannel))));
193 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
194 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("inchannel", Convert.ToString(cs.RelayChannel))));
195 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
196 cs.PrivateMessageFormat = Substitute(rs, config.GetString("msgformat", cs.PrivateMessageFormat));
197 m_log.DebugFormat("[IRC-Channel-{0}] PrivateMessageFormat : <{1}>", cs.idn, cs.PrivateMessageFormat);
198 cs.NoticeMessageFormat = Substitute(rs, config.GetString("noticeformat", cs.NoticeMessageFormat));
199 m_log.DebugFormat("[IRC-Channel-{0}] NoticeMessageFormat : <{1}>", cs.idn, cs.NoticeMessageFormat);
200 cs.ClientReporting = Convert.ToInt32(Substitute(rs, config.GetString("verbosity", cs.ClientReporting?"1":"0"))) > 0;
201 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
202 cs.ClientReporting = Convert.ToBoolean(Substitute(rs, config.GetString("report_clients", Convert.ToString(cs.ClientReporting))));
203 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
204 cs.DefaultZone = Substitute(rs, config.GetString("fallback_region", cs.DefaultZone));
205 m_log.DebugFormat("[IRC-Channel-{0}] DefaultZone : <{1}>", cs.idn, cs.DefaultZone);
206 cs.ConnectDelay = Convert.ToInt32(Substitute(rs, config.GetString("connect_delay", Convert.ToString(cs.ConnectDelay))));
207 m_log.DebugFormat("[IRC-Channel-{0}] ConnectDelay : <{1}>", cs.idn, cs.ConnectDelay);
208 cs.PingDelay = Convert.ToInt32(Substitute(rs, config.GetString("ping_delay", Convert.ToString(cs.PingDelay))));
209 m_log.DebugFormat("[IRC-Channel-{0}] PingDelay : <{1}>", cs.idn, cs.PingDelay);
210 cs.AccessPassword = Substitute(rs, config.GetString("access_password", cs.AccessPassword));
211 m_log.DebugFormat("[IRC-Channel-{0}] AccessPassword : <{1}>", cs.idn, cs.AccessPassword);
212
213
214 // Fail if fundamental information is still missing
215
216 if (cs.Server == null || cs.IrcChannel == null || cs.BaseNickname == null || cs.User == null)
217 throw new Exception(String.Format("[IRC-Channel-{0}] Invalid configuration for region {1}", cs.idn, rs.Region));
218
219 m_log.InfoFormat("[IRC-Channel-{0}] Configuration for Region {1} is valid", cs.idn, rs.Region);
220 m_log.InfoFormat("[IRC-Channel-{0}] Server = {1}", cs.idn, cs.Server);
221 m_log.InfoFormat("[IRC-Channel-{0}] Channel = {1}", cs.idn, cs.IrcChannel);
222 m_log.InfoFormat("[IRC-Channel-{0}] Port = {1}", cs.idn, cs.Port);
223 m_log.InfoFormat("[IRC-Channel-{0}] Nickname = {1}", cs.idn, cs.BaseNickname);
224 m_log.InfoFormat("[IRC-Channel-{0}] User = {1}", cs.idn, cs.User);
225
226 // Set the channel state for this region
227
228 if (cs.RelayChat)
229 {
230 cs.ValidInWorldChannels.Add(0);
231 cs.ValidInWorldChannels.Add(DEBUG_CHANNEL);
232 }
233
234 if (cs.RelayPrivateChannels)
235 cs.ValidInWorldChannels.Add(cs.RelayChannelOut);
236
237 rs.cs = Integrate(rs, cs);
238
239 }
240
241 // An initialized channel state instance is passed in. If an identical
242 // channel state instance already exists, then the existing instance
243 // is used to replace the supplied value.
244 // If the instance matches with respect to IRC, then the underlying
245 // IRCConnector is assigned to the supplied channel state and the
246 // updated value is returned.
247 // If there is no match, then the supplied instance is completed by
248 // creating and assigning an instance of an IRC connector.
249
250 private static ChannelState Integrate(RegionState rs, ChannelState p_cs)
251 {
252
253 ChannelState cs = p_cs;
254
255 // Check to see if we have an existing server/channel setup that can be used
256 // In the absence of variable substitution this will always resolve to the
257 // same ChannelState instance, and the table will only contains a single
258 // entry, so the performance considerations for the existing behavior are
259 // zero. Only the IRC connector is shared, the ChannelState still contains
260 // values that, while independent of the IRC connetion, do still distinguish
261 // this region's behavior.
262
263 lock (IRCBridgeModule.m_channels)
264 {
265
266 foreach (ChannelState xcs in IRCBridgeModule.m_channels)
267 {
268 if (cs.IsAPerfectMatchFor(xcs))
269 {
270 m_log.DebugFormat("[IRC-Channel-{0}] Channel state matched", cs.idn);
271 cs = xcs;
272 break;
273 }
274 if (cs.IsAConnectionMatchFor(xcs))
275 {
276 m_log.DebugFormat("[IRC-Channel-{0}] Channel matched", cs.idn);
277 cs.irc = xcs.irc;
278 break;
279 }
280 }
281
282 }
283
284 // No entry was found, so this is going to be a new entry.
285
286 if (cs.irc == null)
287 {
288
289 m_log.DebugFormat("[IRC-Channel-{0}] New channel required", cs.idn);
290
291 if ((cs.irc = new IRCConnector(cs)) != null)
292 {
293
294 IRCBridgeModule.m_channels.Add(cs);
295
296 m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}",
297 cs.idn, rs.Region, cs.DefaultZone,
298 cs.CommandsEnabled ? "enabled" : "not enabled",
299 cs.RelayPrivateChannels ? "relayed" : "not relayed");
300 }
301 else
302 {
303 string txt = String.Format("[IRC-Channel-{0}] Region {1} failed to connect to channel {2} on server {3}:{4}",
304 cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);
305 m_log.Error(txt);
306 throw new Exception(txt);
307 }
308 }
309 else
310 {
311 m_log.InfoFormat("[IRC-Channel-{0}] Region {1} reusing existing connection to channel {2} on server {3}:{4}",
312 cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);
313 }
314
315 m_log.InfoFormat("[IRC-Channel-{0}] Region {1} associated with channel {2} on server {3}:{4}",
316 cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);
317
318 // We're finally ready to commit ourselves
319
320
321 return cs;
322
323 }
324
325 // These routines allow differentiating changes to
326 // the underlying channel state. If necessary, a
327 // new channel state will be created.
328
329 internal ChannelState UpdateServer(RegionState rs, string server)
330 {
331 RemoveRegion(rs);
332 ChannelState cs = new ChannelState(this);
333 cs.Server = server;
334 cs = Integrate(rs, cs);
335 cs.AddRegion(rs);
336 return cs;
337 }
338
339 internal ChannelState UpdatePort(RegionState rs, string port)
340 {
341 RemoveRegion(rs);
342 ChannelState cs = new ChannelState(this);
343 cs.Port = Convert.ToUInt32(port);
344 cs = Integrate(rs, cs);
345 cs.AddRegion(rs);
346 return cs;
347 }
348
349 internal ChannelState UpdateChannel(RegionState rs, string channel)
350 {
351 RemoveRegion(rs);
352 ChannelState cs = new ChannelState(this);
353 cs.IrcChannel = channel;
354 cs = Integrate(rs, cs);
355 cs.AddRegion(rs);
356 return cs;
357 }
358
359 internal ChannelState UpdateNickname(RegionState rs, string nickname)
360 {
361 RemoveRegion(rs);
362 ChannelState cs = new ChannelState(this);
363 cs.BaseNickname = nickname;
364 cs = Integrate(rs, cs);
365 cs.AddRegion(rs);
366 return cs;
367 }
368
369 internal ChannelState UpdateClientReporting(RegionState rs, string cr)
370 {
371 RemoveRegion(rs);
372 ChannelState cs = new ChannelState(this);
373 cs.ClientReporting = Convert.ToBoolean(cr);
374 cs = Integrate(rs, cs);
375 cs.AddRegion(rs);
376 return cs;
377 }
378
379 internal ChannelState UpdateRelayIn(RegionState rs, string channel)
380 {
381 RemoveRegion(rs);
382 ChannelState cs = new ChannelState(this);
383 cs.RelayChannel = Convert.ToInt32(channel);
384 cs = Integrate(rs, cs);
385 cs.AddRegion(rs);
386 return cs;
387 }
388
389 internal ChannelState UpdateRelayOut(RegionState rs, string channel)
390 {
391 RemoveRegion(rs);
392 ChannelState cs = new ChannelState(this);
393 cs.RelayChannelOut = Convert.ToInt32(channel);
394 cs = Integrate(rs, cs);
395 cs.AddRegion(rs);
396 return cs;
397 }
398
399 // Determine whether or not this is a 'new' channel. Only those
400 // attributes that uniquely distinguish an IRC connection should
401 // be included here (and only those attributes should really be
402 // in the ChannelState structure)
403
404 private bool IsAConnectionMatchFor(ChannelState cs)
405 {
406 return (
407 Server == cs.Server &&
408 IrcChannel == cs.IrcChannel &&
409 Port == cs.Port &&
410 BaseNickname == cs.BaseNickname &&
411 User == cs.User
412 );
413 }
414
415 // This level of obsessive matching allows us to produce
416 // a minimal overhead int he case of a server which does
417 // need to differentiate IRC at a region level.
418
419 private bool IsAPerfectMatchFor(ChannelState cs)
420 {
421 return ( IsAConnectionMatchFor(cs) &&
422 RelayChannelOut == cs.RelayChannelOut &&
423 PrivateMessageFormat == cs.PrivateMessageFormat &&
424 NoticeMessageFormat == cs.NoticeMessageFormat &&
425 RandomizeNickname == cs.RandomizeNickname &&
426 AccessPassword == cs.AccessPassword &&
427 CommandsEnabled == cs.CommandsEnabled &&
428 CommandChannel == cs.CommandChannel &&
429 DefaultZone == cs.DefaultZone &&
430 RelayPrivateChannels == cs.RelayPrivateChannels &&
431 RelayChannel == cs.RelayChannel &&
432 RelayChat == cs.RelayChat &&
433 ClientReporting == cs.ClientReporting
434 );
435 }
436
437 // This function implements the variable substitution mechanism
438 // for the configuration values. Each string read from the
439 // configuration file is scanned for '[...]' enclosures. Each
440 // one that is found is replaced by either a runtime variable
441 // (%xxx) or an existing configuration key. When no further
442 // substitution is possible, the remaining string is returned
443 // to the caller. This allows for arbitrarily nested
444 // enclosures.
445
446 private static string Substitute(RegionState rs, string instr)
447 {
448
449 string result = instr;
450
451 if (result == null || result.Length == 0)
452 return result;
453
454 // Repeatedly scan the string until all possible
455 // substitutions have been performed.
456
457 // m_log.DebugFormat("[IRC-Channel] Parse[1]: {0}", result);
458
459 while (arg.IsMatch(result))
460 {
461
462 string vvar = arg.Match(result).ToString();
463 string var = vvar.Substring(1,vvar.Length-2).Trim();
464
465 switch (var.ToLower())
466 {
467 case "%region" :
468 result = result.Replace(vvar, rs.Region);
469 break;
470 case "%host" :
471 result = result.Replace(vvar, rs.Host);
472 break;
473 case "%master1" :
474 result = result.Replace(vvar, rs.MA1);
475 break;
476 case "%master2" :
477 result = result.Replace(vvar, rs.MA2);
478 break;
479 case "%locx" :
480 result = result.Replace(vvar, rs.LocX);
481 break;
482 case "%locy" :
483 result = result.Replace(vvar, rs.LocY);
484 break;
485 case "%k" :
486 result = result.Replace(vvar, rs.IDK);
487 break;
488 default :
489 result = result.Replace(vvar, rs.config.GetString(var,var));
490 break;
491 }
492 // m_log.DebugFormat("[IRC-Channel] Parse[2]: {0}", result);
493 }
494
495 // m_log.DebugFormat("[IRC-Channel] Parse[3]: {0}", result);
496 return result;
497
498 }
499
500 public void Close()
501 {
502 m_log.InfoFormat("[IRC-Channel-{0}] Closing channel <{1}> to server <{2}:{3}>",
503 idn, IrcChannel, Server, Port);
504 m_log.InfoFormat("[IRC-Channel-{0}] There are {1} active clients",
505 idn, clientregions.Count);
506 irc.Close();
507 }
508
509 public void Open()
510 {
511 m_log.InfoFormat("[IRC-Channel-{0}] Opening channel <{1}> to server <{2}:{3}>",
512 idn, IrcChannel, Server, Port);
513
514 irc.Open();
515
516 }
517
518 // These are called by each region that attaches to this channel. The call affects
519 // only the relationship of the region with the channel. Not the channel to IRC
520 // relationship (unless it is closed and we want it open).
521
522 public void Open(RegionState rs)
523 {
524 AddRegion(rs);
525 Open();
526 }
527
528 // Close is called to ensure that the IRC session is terminated if this is the
529 // only client.
530
531 public void Close(RegionState rs)
532 {
533 RemoveRegion(rs);
534 lock (IRCBridgeModule.m_channels)
535 {
536 if (clientregions.Count == 0)
537 {
538 Close();
539 IRCBridgeModule.m_channels.Remove(this);
540 m_log.InfoFormat("[IRC-Channel-{0}] Region {1} is last user of channel <{2}> to server <{3}:{4}>",
541 idn, rs.Region, IrcChannel, Server, Port);
542 m_log.InfoFormat("[IRC-Channel-{0}] Removed", idn);
543 }
544 }
545 }
546
547 // Add a client region to this channel if it is not already known
548
549 public void AddRegion(RegionState rs)
550 {
551 m_log.InfoFormat("[IRC-Channel-{0}] Adding region {1} to channel <{2}> to server <{3}:{4}>",
552 idn, rs.Region, IrcChannel, Server, Port);
553 if (!clientregions.Contains(rs))
554 {
555 clientregions.Add(rs);
556 lock (irc) irc.depends++;
557 }
558 }
559
560 // Remove a client region from the channel. If this is the last
561 // region, then clean up the channel. The connector will clean itself
562 // up if it finds itself about to be GC'd.
563
564 public void RemoveRegion(RegionState rs)
565 {
566
567 m_log.InfoFormat("[IRC-Channel-{0}] Removing region {1} from channel <{2} to server <{3}:{4}>",
568 idn, rs.Region, IrcChannel, Server, Port);
569
570 if (clientregions.Contains(rs))
571 {
572 clientregions.Remove(rs);
573 lock (irc) irc.depends--;
574 }
575
576 }
577
578 // This function is lifted from the IRCConnector because it
579 // contains information that is not differentiating from an
580 // IRC point-of-view.
581
582 public static void OSChat(IRCConnector p_irc, OSChatMessage c, bool cmsg)
583 {
584
585 // m_log.DebugFormat("[IRC-OSCHAT] from {0}:{1}", p_irc.Server, p_irc.IrcChannel);
586
587 try
588 {
589
590 // Scan through the set of unique channel configuration for those
591 // that belong to this connector. And then forward the message to
592 // all regions known to those channels.
593 // Note that this code is responsible for completing some of the
594 // settings for the inbound OSChatMessage
595
596 lock (IRCBridgeModule.m_channels)
597 {
598 foreach (ChannelState cs in IRCBridgeModule.m_channels)
599 {
600 if ( p_irc == cs.irc)
601 {
602
603 // This non-IRC differentiator moved to here
604
605 if (cmsg && !cs.ClientReporting)
606 continue;
607
608 // This non-IRC differentiator moved to here
609
610 c.Channel = (cs.RelayPrivateChannels ? cs.RelayChannel : 0);
611
612 foreach (RegionState region in cs.clientregions)
613 {
614 region.OSChat(cs.irc, c);
615 }
616
617 }
618 }
619 }
620 }
621 catch (Exception ex)
622 {
623 m_log.ErrorFormat("[IRC-OSCHAT]: BroadcastSim Exception: {0}", ex.Message);
624 m_log.Debug(ex);
625 }
626 }
627 }
628}