internal IRCConnector(ChannelState cs)
        {
            // Prepare network interface

            m_tcp    = null;
            m_writer = null;
            m_reader = null;

            // Setup IRC session parameters

            m_server        = cs.Server;
            m_password      = cs.Password;
            m_baseNick      = cs.BaseNickname;
            m_randomizeNick = cs.RandomizeNickname;
            m_ircChannel    = cs.IrcChannel;
            m_port          = cs.Port;
            m_user          = cs.User;

            if (m_watchdog == null)
            {
                // Non-differentiating

                ICCD_PERIOD = cs.ConnectDelay;
                PING_PERIOD = cs.PingDelay;

                // Smaller values are not reasonable

                if (ICCD_PERIOD < 5)
                {
                    ICCD_PERIOD = 5;
                }

                if (PING_PERIOD < 5)
                {
                    PING_PERIOD = 5;
                }

                _icc_ = ICCD_PERIOD;    // get started right away!
            }

            // The last line of defense

            if (m_server == null || m_baseNick == null || m_ircChannel == null || m_user == null)
            {
                throw new Exception("Invalid connector configuration");
            }

            // Generate an initial nickname if randomizing is enabled

            if (m_randomizeNick)
            {
                m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
            }

            m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn);
        }
Example #2
0
        // Determine whether or not this is a 'new' channel. Only those
        // attributes that uniquely distinguish an IRC connection should
        // be included here (and only those attributes should really be
        // in the ChannelState structure)

        private bool IsAConnectionMatchFor(ChannelState cs)
        {
            return(
                Server == cs.Server &&
                IrcChannel == cs.IrcChannel &&
                Port == cs.Port &&
                BaseNickname == cs.BaseNickname &&
                User == cs.User
                );
        }
Example #3
0
        internal ChannelState UpdateRelayOut(RegionState rs, string channel)
        {
            RemoveRegion(rs);
            ChannelState cs = new ChannelState(this);

            cs.RelayChannelOut = Convert.ToInt32(channel);
            cs = Integrate(rs, cs);
            cs.AddRegion(rs);
            return(cs);
        }
Example #4
0
        internal ChannelState UpdateClientReporting(RegionState rs, string cr)
        {
            RemoveRegion(rs);
            ChannelState cs = new ChannelState(this);

            cs.ClientReporting = Convert.ToBoolean(cr);
            cs = Integrate(rs, cs);
            cs.AddRegion(rs);
            return(cs);
        }
Example #5
0
        internal ChannelState UpdateNickname(RegionState rs, string nickname)
        {
            RemoveRegion(rs);
            ChannelState cs = new ChannelState(this);

            cs.BaseNickname = nickname;
            cs = Integrate(rs, cs);
            cs.AddRegion(rs);
            return(cs);
        }
Example #6
0
        internal ChannelState UpdateChannel(RegionState rs, string channel)
        {
            RemoveRegion(rs);
            ChannelState cs = new ChannelState(this);

            cs.IrcChannel = channel;
            cs            = Integrate(rs, cs);
            cs.AddRegion(rs);
            return(cs);
        }
Example #7
0
        internal ChannelState UpdatePort(RegionState rs, string port)
        {
            RemoveRegion(rs);
            ChannelState cs = new ChannelState(this);

            cs.Port = Convert.ToUInt32(port);
            cs      = Integrate(rs, cs);
            cs.AddRegion(rs);
            return(cs);
        }
Example #8
0
        // These routines allow differentiating changes to
        // the underlying channel state. If necessary, a
        // new channel state will be created.

        internal ChannelState UpdateServer(RegionState rs, string server)
        {
            RemoveRegion(rs);
            ChannelState cs = new ChannelState(this);

            cs.Server = server;
            cs        = Integrate(rs, cs);
            cs.AddRegion(rs);
            return(cs);
        }
        // Setup runtime variable values

        public RegionState(Scene p_scene, IConfig p_config)
        {
            scene  = p_scene;
            config = p_config;

            Region = scene.RegionInfo.RegionName;
            Host   = scene.RegionInfo.ExternalHostName;
            LocX   = Convert.ToString(scene.RegionInfo.RegionLocX);
            LocY   = Convert.ToString(scene.RegionInfo.RegionLocY);
            IDK    = Convert.ToString(_idk_++);

            showAlert = config.GetBoolean("alert_show", false);
            string alertServerInfo = String.Empty;

            if (showAlert)
            {
                bool showAlertServerInfo = config.GetBoolean("alert_show_serverinfo", true);

                if (showAlertServerInfo)
                {
                    alertServerInfo = String.Format("\nServer: {0}\nPort: {1}\nChannel: {2}\n\n",
                                                    config.GetString("server", ""), config.GetString("port", ""), config.GetString("channel", ""));
                }

                string alertPreMessage  = config.GetString("alert_msg_pre", "This region is linked to Irc.");
                string alertPostMessage = config.GetString("alert_msg_post", "Everything you say in public chat can be listened.");

                alertMessage = String.Format("{0}\n{1}{2}", alertPreMessage, alertServerInfo, alertPostMessage);

                dialogModule = scene.RequestModuleInterface <IDialogModule>();
            }

            // OpenChannel conditionally establishes a connection to the
            // IRC server. The request will either succeed, or it will
            // throw an exception.

            ChannelState.OpenChannel(this, config);

            // Connect channel to world events

            scene.EventManager.OnChatFromWorld  += OnSimChat;
            scene.EventManager.OnChatFromClient += OnSimChat;
            scene.EventManager.OnMakeRootAgent  += OnMakeRootAgent;
            scene.EventManager.OnMakeChildAgent += OnMakeChildAgent;

            m_log.InfoFormat("[IRC-Region {0}] Initialization complete", Region);
        }
Example #10
0
        // This level of obsessive matching allows us to produce
        // a minimal overhead int he case of a server which does
        // need to differentiate IRC at a region level.

        private bool IsAPerfectMatchFor(ChannelState cs)
        {
            return(IsAConnectionMatchFor(cs) &&
                   RelayChannelOut == cs.RelayChannelOut &&
                   PrivateMessageFormat == cs.PrivateMessageFormat &&
                   NoticeMessageFormat == cs.NoticeMessageFormat &&
                   RandomizeNickname == cs.RandomizeNickname &&
                   AccessPassword == cs.AccessPassword &&
                   CommandsEnabled == cs.CommandsEnabled &&
                   CommandChannel == cs.CommandChannel &&
                   DefaultZone == cs.DefaultZone &&
                   RelayPrivateChannels == cs.RelayPrivateChannels &&
                   RelayChannel == cs.RelayChannel &&
                   RelayChat == cs.RelayChat &&
                   ClientReporting == cs.ClientReporting
                   );
        }
Example #11
0
        public void BroadcastSim(string sender, string format, params string[] args)
        {
            try
            {
                OSChatMessage c = new OSChatMessage();
                c.From       = sender;
                c.Message    = String.Format(format, args);
                c.Type       = ChatTypeEnum.Region; // ChatTypeEnum.Say;
                c.Position   = CenterOfRegion;
                c.Sender     = null;
                c.SenderUUID = UUID.Zero;

                ChannelState.OSChat(this, c, true);
            }
            catch (Exception ex) // IRC gate should not crash Sim
            {
                m_log.ErrorFormat("[IRC-Connector-{0}]: BroadcastSim Exception Trap: {1}\n{2}", idn, ex.Message, ex.StackTrace);
            }
        }
Example #12
0
        // This constructor is used by the Update* methods. A copy of the
        // existing channel state is created, and distinguishing characteristics
        // are copied across.

        internal ChannelState(ChannelState model)
        {
            Server               = model.Server;
            Password             = model.Password;
            IrcChannel           = model.IrcChannel;
            Port                 = model.Port;
            BaseNickname         = model.BaseNickname;
            RandomizeNickname    = model.RandomizeNickname;
            User                 = model.User;
            CommandsEnabled      = model.CommandsEnabled;
            CommandChannel       = model.CommandChannel;
            RelayChat            = model.RelayChat;
            RelayPrivateChannels = model.RelayPrivateChannels;
            RelayChannelOut      = model.RelayChannelOut;
            RelayChannel         = model.RelayChannel;
            ValidInWorldChannels = model.ValidInWorldChannels;
            PrivateMessageFormat = model.PrivateMessageFormat;
            NoticeMessageFormat  = model.NoticeMessageFormat;
            ClientReporting      = model.ClientReporting;
            AccessPassword       = model.AccessPassword;
            DefaultZone          = model.DefaultZone;
            ConnectDelay         = model.ConnectDelay;
            PingDelay            = model.PingDelay;
        }
        // This level of obsessive matching allows us to produce
        // a minimal overhead int he case of a server which does 
        // need to differentiate IRC at a region level.

        private bool IsAPerfectMatchFor(ChannelState cs)
        {
            return (IsAConnectionMatchFor(cs) &&
                     RelayChannelOut == cs.RelayChannelOut &&
                     PrivateMessageFormat == cs.PrivateMessageFormat &&
                     NoticeMessageFormat == cs.NoticeMessageFormat &&
                     RandomizeNickname == cs.RandomizeNickname &&
                     AccessPassword == cs.AccessPassword &&
                     CommandsEnabled == cs.CommandsEnabled &&
                     CommandChannel == cs.CommandChannel &&
                     DefaultZone == cs.DefaultZone &&
                     RelayPrivateChannels == cs.RelayPrivateChannels &&
                     RelayChannel == cs.RelayChannel &&
                     RelayChat == cs.RelayChat &&
                     ClientReporting == cs.ClientReporting
            );
        }
        // Determine whether or not this is a 'new' channel. Only those
        // attributes that uniquely distinguish an IRC connection should
        // be included here (and only those attributes should really be
        // in the ChannelState structure)

        private bool IsAConnectionMatchFor(ChannelState cs)
        {
            return (
                Server == cs.Server && 
                IrcChannel == cs.IrcChannel &&
                Port == cs.Port &&
                BaseNickname == cs.BaseNickname &&
                User == cs.User
            );
        }
 internal ChannelState UpdateRelayOut(RegionState rs, string channel)
 {
     RemoveRegion(rs);
     ChannelState cs = new ChannelState(this);
     cs.RelayChannelOut = Convert.ToInt32(channel);
     cs = Integrate(rs, cs);
     cs.AddRegion(rs);
     return cs;
 }
 internal ChannelState UpdateClientReporting(RegionState rs, string cr)
 {
     RemoveRegion(rs);
     ChannelState cs = new ChannelState(this);
     cs.ClientReporting = Convert.ToBoolean(cr);
     cs = Integrate(rs, cs);
     cs.AddRegion(rs);
     return cs;
 }
 internal ChannelState UpdateNickname(RegionState rs, string nickname)
 {
     RemoveRegion(rs);
     ChannelState cs = new ChannelState(this);
     cs.BaseNickname = nickname;
     cs = Integrate(rs, cs);
     cs.AddRegion(rs);
     return cs;
 }
 internal ChannelState UpdateChannel(RegionState rs, string channel)
 {
     RemoveRegion(rs);
     ChannelState cs = new ChannelState(this);
     cs.IrcChannel = channel;
     cs = Integrate(rs, cs);
     cs.AddRegion(rs);
     return cs;
 }
Example #19
0
        // An initialized channel state instance is passed in. If an identical
        // channel state instance already exists, then the existing instance
        // is used to replace the supplied value.
        // If the instance matches with respect to IRC, then the underlying
        // IRCConnector is assigned to the supplied channel state and the
        // updated value is returned.
        // If there is no match, then the supplied instance is completed by
        // creating and assigning an instance of an IRC connector.

        private static ChannelState Integrate(RegionState rs, ChannelState p_cs)
        {
            ChannelState cs = p_cs;

            // Check to see if we have an existing server/channel setup that can be used
            // In the absence of variable substitution this will always resolve to the
            // same ChannelState instance, and the table will only contains a single
            // entry, so the performance considerations for the existing behavior are
            // zero. Only the IRC connector is shared, the ChannelState still contains
            // values that, while independent of the IRC connetion, do still distinguish
            // this region's behavior.

            lock (IRCBridgeModule.m_channels)
            {
                foreach (ChannelState xcs in IRCBridgeModule.m_channels)
                {
                    if (cs.IsAPerfectMatchFor(xcs))
                    {
                        m_log.DebugFormat("[IRC-Channel-{0}]  Channel state matched", cs.idn);
                        cs = xcs;
                        break;
                    }
                    if (cs.IsAConnectionMatchFor(xcs))
                    {
                        m_log.DebugFormat("[IRC-Channel-{0}]  Channel matched", cs.idn);
                        cs.irc = xcs.irc;
                        break;
                    }
                }
            }

            // No entry was found, so this is going to be a new entry.

            if (cs.irc == null)
            {
                m_log.DebugFormat("[IRC-Channel-{0}]  New channel required", cs.idn);

                if ((cs.irc = new IRCConnector(cs)) != null)
                {
                    IRCBridgeModule.m_channels.Add(cs);

                    m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}",
                                     cs.idn, rs.Region, cs.DefaultZone,
                                     cs.CommandsEnabled ? "enabled" : "not enabled",
                                     cs.RelayPrivateChannels ? "relayed" : "not relayed");
                }
                else
                {
                    string txt = String.Format("[IRC-Channel-{0}] Region {1} failed to connect to channel {2} on server {3}:{4}",
                                               cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);
                    m_log.Error(txt);
                    throw new Exception(txt);
                }
            }
            else
            {
                m_log.InfoFormat("[IRC-Channel-{0}] Region {1} reusing existing connection to channel {2} on server {3}:{4}",
                                 cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);
            }

            m_log.InfoFormat("[IRC-Channel-{0}] Region {1} associated with channel {2} on server {3}:{4}",
                             cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);

            // We're finally ready to commit ourselves


            return(cs);
        }
        // These routines allow differentiating changes to 
        // the underlying channel state. If necessary, a
        // new channel state will be created.

        internal ChannelState UpdateServer(RegionState rs, string server)
        {
            RemoveRegion(rs);
            ChannelState cs = new ChannelState(this);
            cs.Server = server;
            cs = Integrate(rs, cs);
            cs.AddRegion(rs);
            return cs;
        }
        // An initialized channel state instance is passed in. If an identical
        // channel state instance already exists, then the existing instance
        // is used to replace the supplied value.
        // If the instance matches with respect to IRC, then the underlying
        // IRCConnector is assigned to the supplied channel state and the
        // updated value is returned.
        // If there is no match, then the supplied instance is completed by
        // creating and assigning an instance of an IRC connector.

        private static ChannelState Integrate(RegionState rs, ChannelState p_cs)
        {

            ChannelState cs = p_cs;

            // Check to see if we have an existing server/channel setup that can be used
            // In the absence of variable substitution this will always resolve to the 
            // same ChannelState instance, and the table will only contains a single 
            // entry, so the performance considerations for the existing behavior are 
            // zero. Only the IRC connector is shared, the ChannelState still contains
            // values that, while independent of the IRC connetion, do still distinguish 
            // this region's behavior.

            lock (IRCBridgeModule.m_channels)
            {

                foreach (ChannelState xcs in IRCBridgeModule.m_channels)
                {
                    if (cs.IsAPerfectMatchFor(xcs))
                    {
                        m_log.DebugFormat("[IRC-Channel-{0}]  Channel state matched", cs.idn);
                        cs = xcs;
                        break;
                    }
                    if (cs.IsAConnectionMatchFor(xcs))
                    {
                        m_log.DebugFormat("[IRC-Channel-{0}]  Channel matched", cs.idn);
                        cs.irc = xcs.irc;
                        break;
                    }
                }

            }

            // No entry was found, so this is going to be a new entry.

            if (cs.irc == null)
            {

                m_log.DebugFormat("[IRC-Channel-{0}]  New channel required", cs.idn);

                if ((cs.irc = new IRCConnector(cs)) != null)
                {

                    IRCBridgeModule.m_channels.Add(cs);

                    m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}", 
                                 cs.idn, rs.Region, cs.DefaultZone, 
                                 cs.CommandsEnabled ? "enabled" : "not enabled",
                                 cs.RelayPrivateChannels ? "relayed" : "not relayed");
                }
                else
                {
                    string txt = String.Format("[IRC-Channel-{0}] Region {1} failed to connect to channel {2} on server {3}:{4}",
                            cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);
                    m_log.Error(txt);
                    throw new Exception(txt);
                }
            }
            else
            {
                m_log.InfoFormat("[IRC-Channel-{0}] Region {1} reusing existing connection to channel {2} on server {3}:{4}",
                        cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);
            }

            m_log.InfoFormat("[IRC-Channel-{0}] Region {1} associated with channel {2} on server {3}:{4}",
                        cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);

            // We're finally ready to commit ourselves


            return cs;

        }
        // Read the configuration file, performing variable substitution and any
        // necessary aliasing. See accompanying documentation for how this works.
        // If you don't need variables, then this works exactly as before.
        // If either channel or server are not specified, the request fails.

        internal static void OpenChannel(RegionState rs, IConfig config)
        {

            // Create a new instance of a channel. This may not actually
            // get used if an equivalent channel already exists.

            ChannelState cs = new ChannelState();

            // Read in the configuration file and filter everything for variable
            // subsititution.

            m_log.DebugFormat("[IRC-Channel-{0}] Initial request by Region {1} to connect to IRC", cs.idn, rs.Region);

            cs.Server               = Substitute(rs, config.GetString("server", null));
            m_log.DebugFormat("[IRC-Channel-{0}] Server : <{1}>", cs.idn, cs.Server);
            cs.Password             = Substitute(rs, config.GetString("password", null));
            // probably not a good idea to put a password in the log file
            cs.User                 = Substitute(rs, config.GetString("user", null));
            cs.IrcChannel           = Substitute(rs, config.GetString("channel", null));
            m_log.DebugFormat("[IRC-Channel-{0}] IrcChannel : <{1}>", cs.idn, cs.IrcChannel);
            cs.Port                 = Convert.ToUInt32(Substitute(rs, config.GetString("port", Convert.ToString(cs.Port))));
            m_log.DebugFormat("[IRC-Channel-{0}] Port : <{1}>", cs.idn, cs.Port);
            cs.BaseNickname         = Substitute(rs, config.GetString("nick", cs.BaseNickname));
            m_log.DebugFormat("[IRC-Channel-{0}] BaseNickname : <{1}>", cs.idn, cs.BaseNickname);
            cs.RandomizeNickname    = Convert.ToBoolean(Substitute(rs, config.GetString("randomize_nick", Convert.ToString(cs.RandomizeNickname))));
            m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
            cs.RandomizeNickname    = Convert.ToBoolean(Substitute(rs, config.GetString("nicknum", Convert.ToString(cs.RandomizeNickname))));
            m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
            cs.User                 = Substitute(rs, config.GetString("username", cs.User));
            m_log.DebugFormat("[IRC-Channel-{0}] User : <{1}>", cs.idn, cs.User);
            cs.CommandsEnabled      = Convert.ToBoolean(Substitute(rs, config.GetString("commands_enabled", Convert.ToString(cs.CommandsEnabled))));
            m_log.DebugFormat("[IRC-Channel-{0}] CommandsEnabled : <{1}>", cs.idn, cs.CommandsEnabled);
            cs.CommandChannel       = Convert.ToInt32(Substitute(rs, config.GetString("commandchannel", Convert.ToString(cs.CommandChannel))));
            m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
            cs.CommandChannel       = Convert.ToInt32(Substitute(rs, config.GetString("command_channel", Convert.ToString(cs.CommandChannel))));
            m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
            cs.RelayChat            = Convert.ToBoolean(Substitute(rs, config.GetString("relay_chat", Convert.ToString(cs.RelayChat))));
            m_log.DebugFormat("[IRC-Channel-{0}] RelayChat           : <{1}>", cs.idn, cs.RelayChat);
            cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("relay_private_channels", Convert.ToString(cs.RelayPrivateChannels))));
            m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
            cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("useworldcomm", Convert.ToString(cs.RelayPrivateChannels))));
            m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
            cs.RelayChannelOut      = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_out", Convert.ToString(cs.RelayChannelOut))));
            m_log.DebugFormat("[IRC-Channel-{0}] RelayChannelOut : <{1}>", cs.idn, cs.RelayChannelOut);
            cs.RelayChannel         = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_in", Convert.ToString(cs.RelayChannel))));
            m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
            cs.RelayChannel         = Convert.ToInt32(Substitute(rs, config.GetString("inchannel", Convert.ToString(cs.RelayChannel))));
            m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
            cs.PrivateMessageFormat = Substitute(rs, config.GetString("msgformat", cs.PrivateMessageFormat));
            m_log.DebugFormat("[IRC-Channel-{0}] PrivateMessageFormat : <{1}>", cs.idn, cs.PrivateMessageFormat);
            cs.NoticeMessageFormat = Substitute(rs, config.GetString("noticeformat", cs.NoticeMessageFormat));
            m_log.DebugFormat("[IRC-Channel-{0}] NoticeMessageFormat : <{1}>", cs.idn, cs.NoticeMessageFormat);
            cs.ClientReporting      = Convert.ToInt32(Substitute(rs, config.GetString("verbosity", cs.ClientReporting?"1":"0"))) > 0;
            m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
            cs.ClientReporting      = Convert.ToBoolean(Substitute(rs, config.GetString("report_clients", Convert.ToString(cs.ClientReporting))));
            m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
            cs.DefaultZone          = Substitute(rs, config.GetString("fallback_region", cs.DefaultZone));
            m_log.DebugFormat("[IRC-Channel-{0}] DefaultZone : <{1}>", cs.idn, cs.DefaultZone);
            cs.ConnectDelay      = Convert.ToInt32(Substitute(rs, config.GetString("connect_delay", Convert.ToString(cs.ConnectDelay))));
            m_log.DebugFormat("[IRC-Channel-{0}] ConnectDelay : <{1}>", cs.idn, cs.ConnectDelay);
            cs.PingDelay      = Convert.ToInt32(Substitute(rs, config.GetString("ping_delay", Convert.ToString(cs.PingDelay))));
            m_log.DebugFormat("[IRC-Channel-{0}] PingDelay : <{1}>", cs.idn, cs.PingDelay);
            cs.AccessPassword = Substitute(rs, config.GetString("access_password", cs.AccessPassword));
            m_log.DebugFormat("[IRC-Channel-{0}] AccessPassword : <{1}>", cs.idn, cs.AccessPassword);
            string[] excludes = config.GetString("exclude_list", "").Trim().Split(new Char[] { ',' });
            cs.ExcludeList = new List<string>(excludes.Length);
            foreach (string name in excludes)
            {
                cs.ExcludeList.Add(name.Trim().ToLower());
            }
            
            // Fail if fundamental information is still missing

            if (cs.Server == null || cs.IrcChannel == null || cs.BaseNickname == null || cs.User == null)
                throw new Exception(String.Format("[IRC-Channel-{0}] Invalid configuration for region {1}", cs.idn, rs.Region));

            m_log.InfoFormat("[IRC-Channel-{0}] Configuration for Region {1} is valid", cs.idn, rs.Region);
            m_log.InfoFormat("[IRC-Channel-{0}]    Server = {1}", cs.idn, cs.Server);
            m_log.InfoFormat("[IRC-Channel-{0}]   Channel = {1}", cs.idn, cs.IrcChannel);
            m_log.InfoFormat("[IRC-Channel-{0}]      Port = {1}", cs.idn, cs.Port);
            m_log.InfoFormat("[IRC-Channel-{0}]  Nickname = {1}", cs.idn, cs.BaseNickname);
            m_log.InfoFormat("[IRC-Channel-{0}]      User = {1}", cs.idn, cs.User);

            // Set the channel state for this region

            if (cs.RelayChat)
            {
                cs.ValidInWorldChannels.Add(0);
                cs.ValidInWorldChannels.Add(DEBUG_CHANNEL);
            }

            if (cs.RelayPrivateChannels)
                cs.ValidInWorldChannels.Add(cs.RelayChannelOut);

            rs.cs = Integrate(rs, cs);

        }
        // This constructor is used by the Update* methods. A copy of the
        // existing channel state is created, and distinguishing characteristics
        // are copied across.

        internal ChannelState(ChannelState model)
        {
            Server               = model.Server;
            Password             = model.Password;
            IrcChannel           = model.IrcChannel;
            Port                 = model.Port;
            BaseNickname         = model.BaseNickname;
            RandomizeNickname    = model.RandomizeNickname;
            User                 = model.User;
            CommandsEnabled      = model.CommandsEnabled;
            CommandChannel       = model.CommandChannel;
            RelayChat            = model.RelayChat;
            RelayPrivateChannels = model.RelayPrivateChannels;
            RelayChannelOut      = model.RelayChannelOut;
            RelayChannel         = model.RelayChannel;
            ValidInWorldChannels = model.ValidInWorldChannels;
            PrivateMessageFormat = model.PrivateMessageFormat;
            NoticeMessageFormat  = model.NoticeMessageFormat;
            ClientReporting      = model.ClientReporting;
            AccessPassword       = model.AccessPassword;
            DefaultZone          = model.DefaultZone;
            ConnectDelay         = model.ConnectDelay;
            PingDelay            = model.PingDelay;
        }
Example #24
0
        internal IRCConnector(ChannelState cs)
        {

            // Prepare network interface

            m_tcp = null;
            m_writer = null;
            m_reader = null;

            // Setup IRC session parameters

            m_server = cs.Server;
            m_password = cs.Password;
            m_baseNick = cs.BaseNickname;
            m_randomizeNick = cs.RandomizeNickname;
            m_ircChannel = cs.IrcChannel;
            m_port = cs.Port;
            m_user = cs.User;

            if (m_watchdog == null)
            {
                // Non-differentiating

                ICCD_PERIOD = cs.ConnectDelay;
                PING_PERIOD = cs.PingDelay;

                // Smaller values are not reasonable

                if (ICCD_PERIOD < 5)
                    ICCD_PERIOD = 5;

                if (PING_PERIOD < 5)
                    PING_PERIOD = 5;

                _icc_ = ICCD_PERIOD;    // get started right away!

            }

            // The last line of defense

            if (m_server == null || m_baseNick == null || m_ircChannel == null || m_user == null)
                throw new Exception("Invalid connector configuration");

            // Generate an initial nickname

            if (m_randomizeNick)
                m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
            else
                m_nick = m_baseNick;

            m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn);

        }
Example #25
0
        // Read the configuration file, performing variable substitution and any
        // necessary aliasing. See accompanying documentation for how this works.
        // If you don't need variables, then this works exactly as before.
        // If either channel or server are not specified, the request fails.

        internal static void OpenChannel(RegionState rs, IConfig config)
        {
            // Create a new instance of a channel. This may not actually
            // get used if an equivalent channel already exists.

            ChannelState cs = new ChannelState();

            // Read in the configuration file and filter everything for variable
            // subsititution.

            m_log.DebugFormat("[IRC-Channel-{0}] Initial request by Region {1} to connect to IRC", cs.idn, rs.Region);

            cs.Server    = Substitute(rs, config.GetString("server", null));
            cs.fromwhere = Substitute(rs, config.GetString("fromwhere", null));
            m_log.DebugFormat("[IRC-Channel-{0}] Server : <{1}>", cs.idn, cs.Server);
            cs.Password = Substitute(rs, config.GetString("password", null));
            // probably not a good idea to put a password in the log file
            cs.User       = Substitute(rs, config.GetString("user", null));
            cs.IrcChannel = Substitute(rs, config.GetString("channel", null));
            m_log.DebugFormat("[IRC-Channel-{0}] IrcChannel : <{1}>", cs.idn, cs.IrcChannel);
            cs.Port = Convert.ToUInt32(Substitute(rs, config.GetString("port", Convert.ToString(cs.Port))));
            m_log.DebugFormat("[IRC-Channel-{0}] Port : <{1}>", cs.idn, cs.Port);
            cs.BaseNickname = Substitute(rs, config.GetString("nick", cs.BaseNickname));
            m_log.DebugFormat("[IRC-Channel-{0}] BaseNickname : <{1}>", cs.idn, cs.BaseNickname);
            cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("randomize_nick", Convert.ToString(cs.RandomizeNickname))));
            m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
            cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("nicknum", Convert.ToString(cs.RandomizeNickname))));
            m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
            cs.User = Substitute(rs, config.GetString("username", cs.User));
            m_log.DebugFormat("[IRC-Channel-{0}] User : <{1}>", cs.idn, cs.User);
            cs.CommandsEnabled = Convert.ToBoolean(Substitute(rs, config.GetString("commands_enabled", Convert.ToString(cs.CommandsEnabled))));
            m_log.DebugFormat("[IRC-Channel-{0}] CommandsEnabled : <{1}>", cs.idn, cs.CommandsEnabled);
            cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("commandchannel", Convert.ToString(cs.CommandChannel))));
            m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
            cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("command_channel", Convert.ToString(cs.CommandChannel))));
            m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
            cs.RelayChat = Convert.ToBoolean(Substitute(rs, config.GetString("relay_chat", Convert.ToString(cs.RelayChat))));
            m_log.DebugFormat("[IRC-Channel-{0}] RelayChat           : <{1}>", cs.idn, cs.RelayChat);
            cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("relay_private_channels", Convert.ToString(cs.RelayPrivateChannels))));
            m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
            cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("useworldcomm", Convert.ToString(cs.RelayPrivateChannels))));
            m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
            cs.RelayChannelOut = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_out", Convert.ToString(cs.RelayChannelOut))));
            m_log.DebugFormat("[IRC-Channel-{0}] RelayChannelOut : <{1}>", cs.idn, cs.RelayChannelOut);
            cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_in", Convert.ToString(cs.RelayChannel))));
            m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
            cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("inchannel", Convert.ToString(cs.RelayChannel))));
            m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
            cs.PrivateMessageFormat = Substitute(rs, config.GetString("msgformat", cs.PrivateMessageFormat));
            m_log.DebugFormat("[IRC-Channel-{0}] PrivateMessageFormat : <{1}>", cs.idn, cs.PrivateMessageFormat);
            cs.NoticeMessageFormat = Substitute(rs, config.GetString("noticeformat", cs.NoticeMessageFormat));
            m_log.DebugFormat("[IRC-Channel-{0}] NoticeMessageFormat : <{1}>", cs.idn, cs.NoticeMessageFormat);
            cs.ClientReporting = Convert.ToInt32(Substitute(rs, config.GetString("verbosity", cs.ClientReporting ? "1" : "0"))) > 0;
            m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
            cs.ClientReporting = Convert.ToBoolean(Substitute(rs, config.GetString("report_clients", Convert.ToString(cs.ClientReporting))));
            m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
            cs.DefaultZone = Substitute(rs, config.GetString("fallback_region", cs.DefaultZone));
            m_log.DebugFormat("[IRC-Channel-{0}] DefaultZone : <{1}>", cs.idn, cs.DefaultZone);
            cs.ConnectDelay = Convert.ToInt32(Substitute(rs, config.GetString("connect_delay", Convert.ToString(cs.ConnectDelay))));
            m_log.DebugFormat("[IRC-Channel-{0}] ConnectDelay : <{1}>", cs.idn, cs.ConnectDelay);
            cs.PingDelay = Convert.ToInt32(Substitute(rs, config.GetString("ping_delay", Convert.ToString(cs.PingDelay))));
            m_log.DebugFormat("[IRC-Channel-{0}] PingDelay : <{1}>", cs.idn, cs.PingDelay);
            cs.AccessPassword = Substitute(rs, config.GetString("access_password", cs.AccessPassword));
            m_log.DebugFormat("[IRC-Channel-{0}] AccessPassword : <{1}>", cs.idn, cs.AccessPassword);
            string[] excludes = config.GetString("exclude_list", "").Trim().Split(new Char[] { ',' });
            cs.ExcludeList = new List <string>(excludes.Length);
            foreach (string name in excludes)
            {
                cs.ExcludeList.Add(name.Trim().ToLower());
            }

            // Fail if fundamental information is still missing

            if (cs.Server == null)
            {
                throw new Exception(String.Format("[IRC-Channel-{0}] Invalid configuration for region {1}: server missing", cs.idn, rs.Region));
            }
            else if (cs.IrcChannel == null)
            {
                throw new Exception(String.Format("[IRC-Channel-{0}] Invalid configuration for region {1}: channel missing", cs.idn, rs.Region));
            }
            else if (cs.BaseNickname == null)
            {
                throw new Exception(String.Format("[IRC-Channel-{0}] Invalid configuration for region {1}: nick missing", cs.idn, rs.Region));
            }
            else if (cs.User == null)
            {
                throw new Exception(String.Format("[IRC-Channel-{0}] Invalid configuration for region {1}: user missing", cs.idn, rs.Region));
            }

            m_log.InfoFormat("[IRC-Channel-{0}] Configuration for Region {1} is valid", cs.idn, rs.Region);
            m_log.InfoFormat("[IRC-Channel-{0}]    Server = {1}", cs.idn, cs.Server);
            m_log.InfoFormat("[IRC-Channel-{0}]   Channel = {1}", cs.idn, cs.IrcChannel);
            m_log.InfoFormat("[IRC-Channel-{0}]      Port = {1}", cs.idn, cs.Port);
            m_log.InfoFormat("[IRC-Channel-{0}]  Nickname = {1}", cs.idn, cs.BaseNickname);
            m_log.InfoFormat("[IRC-Channel-{0}]      User = {1}", cs.idn, cs.User);

            // Set the channel state for this region

            if (cs.RelayChat)
            {
                cs.ValidInWorldChannels.Add(0);
                cs.ValidInWorldChannels.Add(DEBUG_CHANNEL);
            }

            if (cs.RelayPrivateChannels)
            {
                cs.ValidInWorldChannels.Add(cs.RelayChannelOut);
            }

            rs.cs = Integrate(rs, cs);
        }
Example #26
0
        // This handler detects chat events int he virtual world.

        public void OnSimChat(Object sender, OSChatMessage msg)
        {

            // early return if this comes from the IRC forwarder

            if (cs.irc.Equals(sender)) return;

            // early return if nothing to forward

            if (msg.Message.Length == 0) return;

            // check for commands coming from avatars or in-world
            // object (if commands are enabled)

            if (cs.CommandsEnabled && msg.Channel == cs.CommandChannel)
            {

                m_log.DebugFormat("[IRC-Region {0}] command on channel {1}: {2}", Region, msg.Channel, msg.Message);

                string[] messages = msg.Message.Split(' ');
                string command = messages[0].ToLower();

                try
                {
                    switch (command)
                    {

                        // These commands potentially require a change in the
                        // underlying ChannelState.

                        case "server":
                            cs.Close(this);
                            cs = cs.UpdateServer(this, messages[1]);
                            cs.Open(this);
                            break;
                        case "port":
                            cs.Close(this);
                            cs = cs.UpdatePort(this, messages[1]);
                            cs.Open(this);
                            break;
                        case "channel":
                            cs.Close(this);
                            cs = cs.UpdateChannel(this, messages[1]);
                            cs.Open(this);
                            break;
                        case "nick":
                            cs.Close(this);
                            cs = cs.UpdateNickname(this, messages[1]);
                            cs.Open(this);
                            break;

                        // These may also (but are less likely) to require a
                        // change in ChannelState.

                        case "client-reporting":
                            cs = cs.UpdateClientReporting(this, messages[1]);
                            break;
                        case "in-channel":
                            cs = cs.UpdateRelayIn(this, messages[1]);
                            break;
                        case "out-channel":
                            cs = cs.UpdateRelayOut(this, messages[1]);
                            break;

                        // These are all taken to be temporary changes in state
                        // so the underlying connector remains intact. But note
                        // that with regions sharing a connector, there could
                        // be interference.

                        case "close":
                            enabled = false;
                            cs.Close(this);
                            break;

                        case "connect":
                            enabled = true;
                            cs.Open(this);
                            break;

                        case "reconnect":
                            enabled = true;
                            cs.Close(this);
                            cs.Open(this);
                            break;

                        // This one is harmless as far as we can judge from here.
                        // If it is not, then the complaints will eventually make
                        // that evident.

                        default:
                            m_log.DebugFormat("[IRC-Region {0}] Forwarding unrecognized command to IRC : {1}", 
                                            Region, msg.Message);
                            cs.irc.Send(msg.Message);
                            break;
                    }
                }
                catch (Exception ex)
                { 
                    m_log.WarnFormat("[IRC-Region {0}] error processing in-world command channel input: {1}",
                                    Region, ex.Message);
                    m_log.Debug(ex);
                }

                return;

            }

            // The command channel remains enabled, even if we have otherwise disabled the IRC
            // interface.

            if (!enabled)
                return;

            // drop messages unless they are on a valid in-world
            // channel as configured in the ChannelState

            if (!cs.ValidInWorldChannels.Contains(msg.Channel))
            {
                m_log.DebugFormat("[IRC-Region {0}] dropping message {1} on channel {2}", Region, msg, msg.Channel);
                return;
            }

            ScenePresence avatar = null;
            string fromName = msg.From;

            if (msg.Sender != null)
            {
                avatar = scene.GetScenePresence(msg.Sender.AgentId);
                if (avatar != null) fromName = avatar.Name;
            }

            if (!cs.irc.Connected)
            {
                m_log.WarnFormat("[IRC-Region {0}] IRCConnector not connected: dropping message from {1}", Region, fromName);
                return;
            }

            m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message);

            if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL)) 
            {
                string txt = msg.Message;
                if (txt.StartsWith("/me "))
                    txt = String.Format("{0} {1}", fromName, msg.Message.Substring(4));

                cs.irc.PrivMsg(cs.PrivateMessageFormat, fromName, Region, txt);
                return;
            }

            if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword && 
                msg.Channel == cs.RelayChannelOut)
            {
                Match m = cs.AccessPasswordRegex.Match(msg.Message);
                if (null != m)
                {
                    m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(), 
                                      m.Groups["message"].ToString());
                    cs.irc.PrivMsg(cs.PrivateMessageFormat, m.Groups["avatar"].ToString(),
                                   scene.RegionInfo.RegionName, m.Groups["message"].ToString());
                }
            }
        }
Example #27
0
        public void ListenerRun()
        {
            string inputLine;
            int    resetk = m_resetk;

            try
            {
                while (m_enabled && m_connected)
                {
                    if ((inputLine = m_reader.ReadLine()) == null)
                    {
                        throw new Exception("Listener input socket closed");
                    }

                    // m_log.Info("[IRCConnector]: " + inputLine);

                    if (inputLine.Contains("PRIVMSG"))
                    {
                        Dictionary <string, string> data = ExtractMsg(inputLine);

                        // Any chat ???
                        if (data != null)
                        {
                            OSChatMessage c = new OSChatMessage();
                            c.Message    = data["msg"];
                            c.Type       = ChatTypeEnum.Region;
                            c.Position   = CenterOfRegion;
                            c.From       = data["nick"];
                            c.Sender     = null;
                            c.SenderUUID = UUID.Zero;

                            // Is message "\001ACTION foo bar\001"?
                            // Then change to: "/me foo bar"

                            if ((1 == c.Message[0]) && c.Message.Substring(1).StartsWith("ACTION"))
                            {
                                c.Message = String.Format("/me {0}", c.Message.Substring(8, c.Message.Length - 9));
                            }

                            ChannelState.OSChat(this, c, false);
                        }
                    }
                    else
                    {
                        ProcessIRCCommand(inputLine);
                    }
                }
            }
            catch (Exception /*e*/)
            {
                // m_log.ErrorFormat("[IRC-Connector-{0}]: ListenerRun exception trap: {1}", idn, e.Message);
                // m_log.Debug(e);
            }

            // This is potentially circular, but harmless if so.
            // The connection is marked as not connected the first time
            // through reconnect.

            if (m_enabled && (m_resetk == resetk))
            {
                Reconnect();
            }
        }
 internal ChannelState UpdatePort(RegionState rs, string port)
 {
     RemoveRegion(rs);
     ChannelState cs = new ChannelState(this);
     cs.Port = Convert.ToUInt32(port);
     cs = Integrate(rs, cs);
     cs.AddRegion(rs);
     return cs;
 }
        // This handler detects chat events int he virtual world.
        public void OnSimChat(Object sender, OSChatMessage msg)
        {
            // early return if this comes from the IRC forwarder

            if (cs.irc.Equals(sender))
            {
                return;
            }

            // early return if nothing to forward

            if (msg.Message.Length == 0)
            {
                return;
            }

            // check for commands coming from avatars or in-world
            // object (if commands are enabled)

            if (cs.CommandsEnabled && msg.Channel == cs.CommandChannel)
            {
                m_log.DebugFormat("[IRC-Region {0}] command on channel {1}: {2}", Region, msg.Channel, msg.Message);

                string[] messages = msg.Message.Split(' ');
                string   command  = messages[0].ToLower();

                try
                {
                    switch (command)
                    {
                    // These commands potentially require a change in the
                    // underlying ChannelState.

                    case "server":
                        cs.Close(this);
                        cs = cs.UpdateServer(this, messages[1]);
                        cs.Open(this);
                        break;

                    case "port":
                        cs.Close(this);
                        cs = cs.UpdatePort(this, messages[1]);
                        cs.Open(this);
                        break;

                    case "channel":
                        cs.Close(this);
                        cs = cs.UpdateChannel(this, messages[1]);
                        cs.Open(this);
                        break;

                    case "nick":
                        cs.Close(this);
                        cs = cs.UpdateNickname(this, messages[1]);
                        cs.Open(this);
                        break;

                    // These may also (but are less likely) to require a
                    // change in ChannelState.

                    case "client-reporting":
                        cs = cs.UpdateClientReporting(this, messages[1]);
                        break;

                    case "in-channel":
                        cs = cs.UpdateRelayIn(this, messages[1]);
                        break;

                    case "out-channel":
                        cs = cs.UpdateRelayOut(this, messages[1]);
                        break;

                    // These are all taken to be temporary changes in state
                    // so the underlying connector remains intact. But note
                    // that with regions sharing a connector, there could
                    // be interference.

                    case "close":
                        enabled = false;
                        cs.Close(this);
                        break;

                    case "connect":
                        enabled = true;
                        cs.Open(this);
                        break;

                    case "reconnect":
                        enabled = true;
                        cs.Close(this);
                        cs.Open(this);
                        break;

                    // This one is harmless as far as we can judge from here.
                    // If it is not, then the complaints will eventually make
                    // that evident.

                    default:
                        m_log.DebugFormat("[IRC-Region {0}] Forwarding unrecognized command to IRC : {1}",
                                          Region, msg.Message);
                        cs.irc.Send(msg.Message);
                        break;
                    }
                }
                catch (Exception ex)
                {
                    m_log.WarnFormat("[IRC-Region {0}] error processing in-world command channel input: {1}",
                                     Region, ex.Message);
                    m_log.Debug(ex);
                }

                return;
            }

            // The command channel remains enabled, even if we have otherwise disabled the IRC
            // interface.

            if (!enabled)
            {
                return;
            }

            // drop messages unless they are on a valid in-world
            // channel as configured in the ChannelState

            if (!cs.ValidInWorldChannels.Contains(msg.Channel))
            {
                m_log.DebugFormat("[IRC-Region {0}] dropping message {1} on channel {2}", Region, msg, msg.Channel);
                return;
            }

            ScenePresence avatar   = null;
            string        fromName = msg.From;

            if (msg.Sender != null)
            {
                avatar = scene.GetScenePresence(msg.Sender.AgentId);
                if (avatar != null)
                {
                    fromName = avatar.Name;
                }
            }

            if (!cs.irc.Connected)
            {
                m_log.WarnFormat("[IRC-Region {0}] IRCConnector not connected: dropping message from {1}", Region, fromName);
                return;
            }

            m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message);

            if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL))
            {
                string txt = msg.Message;
                if (txt.StartsWith("/me "))
                {
                    txt = String.Format("{0} {1}", fromName, msg.Message.Substring(4));
                }

                cs.irc.PrivMsg(cs.PrivateMessageFormat, fromName, Region, txt);
                return;
            }

            if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword &&
                msg.Channel == cs.RelayChannelOut)
            {
                Match m = cs.AccessPasswordRegex.Match(msg.Message);
                if (null != m)
                {
                    m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(),
                                      m.Groups["message"].ToString());
                    cs.irc.PrivMsg(cs.PrivateMessageFormat, m.Groups["avatar"].ToString(),
                                   scene.RegionInfo.RegionName, m.Groups["message"].ToString());
                }
            }
        }