예제 #1
0
        /// <summary>
        /// Determines if a user is known by the internal databases. If not
        /// it will create and authenticate the user. If so, it will simply look up the user.
        /// </summary>
        /// <param name="s">The server to check for the user on.</param>
        /// <param name="irch">The irc host to check for.</param>
        /// <returns>The new or old user.</returns>
        private static User UpdateUserDB(Server s, IRCHost irch)
        {
            User u;
            try {
                u = s.UserDatabase[irch.Nick];

                if ( !u.CurrentHost.Equals( irch ) )
                    u.CurrentHost = irch;
            }
            catch ( KeyNotFoundException ) {
                u = new User( irch );
                s.UserDatabase.AddUser( u );
                s.UserDatabase.Authenticate( u );
            }

            return u;
        }
예제 #2
0
        /// <summary>
        /// Retrieves a ChannelUser from the database.
        /// </summary>
        /// <param name="s">The server to check for the ChannelUser.</param>
        /// <param name="channelname">The channel to check.</param>
        /// <param name="usernick">The nick of a definetely existing user.</param>
        /// <param name="uflag">If the channel user does not exist he must be created with a userflag. This is that flag.</param>
        /// <returns>The new or old ChannelUser.</returns>
        private static ChannelUser UpdateBothDB(Server s, string channelname, string usernick, Nullable<char> uflag)
        {
            ChannelUser cu;
            try {
                cu = s.ChannelDatabase[channelname][usernick]; //Check if ChannelUser exists.
            }
            catch ( KeyNotFoundException ) {
                //ChannelUser does not exist.
                cu = new ChannelUser();

                User internalu;
                try {
                    internalu = s.UserDatabase[usernick];
                }
                catch ( KeyNotFoundException ) {
                    cu.UserFlag = uflag;
                    s.ChannelDatabase[channelname].AddUser( usernick, cu );
                    return cu;
                }

                cu.InternalUser = internalu;
                cu.UserFlag = uflag;
                s.ChannelDatabase[channelname].AddUser( cu );
                return cu;
            }

            //Make certain that if the usernick exists in the database that we attach it to it's user counterpart.
            if ( cu.InternalUser == null ) {
                User internalu;
                try {
                    internalu = s.UserDatabase[usernick];
                    cu.InternalUser = internalu;
                }
                catch ( KeyNotFoundException ) {
                    //throw new ExecutionEngineException( "PLACEHOLDER FOR DESTRUCTION THIS SHOULD NEVER HAPPEN" );
                }
            }

            return cu;
        }
예제 #3
0
 /// <summary>
 /// Determines if a channel is known by the internal databases. If not
 /// it will create the channel. If so, it will simply look up the channel..
 /// </summary>
 /// <param name="s">The server to check for the channel on.</param>
 /// <param name="channelname">The channel name to check for.</param>
 /// <returns>The new or old user.</returns>
 private static Channel UpdateChanDB(Server s, string channelname)
 {
     Channel c;
     try {
         c = s.ChannelDatabase[channelname];
     }
     catch ( KeyNotFoundException ) {
         c = new Channel( channelname );
         s.ChannelDatabase.AddChannel( c );
     }
     return c;
 }
예제 #4
0
 /// <summary>
 /// Retrieves a ChannelUser from the database.
 /// </summary>
 /// <param name="s">The server to check for the ChannelUser.</param>
 /// <param name="channelname">The channel to check.</param>
 /// <param name="usernick">The nick of a definetely existing user.</param>
 /// <returns>The new or old ChannelUser.</returns>
 private static ChannelUser UpdateBothDB(Server s, string channelname, string usernick)
 {
     return UpdateBothDB( s, channelname, usernick, null );
 }
예제 #5
0
 /// <summary>
 /// Invokes the Parsers.
 /// </summary>
 /// <param name="s">The server object.</param>
 /// <param name="c">The channel triggered on.</param>
 /// <param name="u">The user triggered from.</param>
 /// <param name="cu">The channeluser triggered from.</param>
 /// <param name="text">The offending text.</param>
 /// <param name="pt">The Parse Types to invoke on.</param>
 private static void InvokeParsers(Server s, Channel c, User u, ChannelUser cu, string text, IRCEvents.ParseTypes pt)
 {
     bool pcount = s.EventObject.Parses.Count > 0;
     bool wcount = s.EventObject.WildcardParses.Count > 0;
     if ( pcount || wcount ) {
         IRCEvents.ParseReturns pr = CreateParseReturns( s.ServerID, c, u, cu, text );
         if ( pcount )
             s.QueueData( ParseInvocation( pr.Text, s.EventObject, pr, pt, false ) );
         if ( wcount )
             s.QueueData( ParseInvocation( pr.Text, s.EventObject, pr, pt, true ) );
     }
 }
예제 #6
0
        /// <summary>
        /// This method parses all raw data for each packet of data that
        /// a Server object might receive. It then uses the events defined
        /// in IRCEvents and fires them through the appropriate server object.
        /// </summary>
        /// <param name="s">The Server which the data was received on.</param>
        /// <param name="raw">The raw text from the socket.</param>
        public static void Parse(Server s, string raw)
        {
            //TODO: IMPLEMENT THE REST :D

            int spacestring = 0;
            int lastchar = 0;
            int firstchar = 0;

            //Remove excessive spaces from everything.
            StringBuilder sb = new StringBuilder();

            for ( int i = 0; i < raw.Length; i++ ) {
                if ( raw[i] == ' ' ) {
                    if ( spacestring++ == 0 )
                        lastchar = i;
                }
                else if ( spacestring > 1 ) {
                    sb.Append( raw, firstchar, lastchar - firstchar + 1 );
                    spacestring = 0;
                    firstchar = i;
                    lastchar = i;
                }
                else {
                    spacestring = 0;
                    lastchar = i;
                }
            }

            if ( sb.Length > 0 || ( lastchar != firstchar && firstchar != 0 && lastchar != raw.Length - 1 ) ) {
                sb.Append( raw, firstchar, lastchar - firstchar + 1 );
            }
            if ( sb.Length > 0 )
                raw = sb.ToString();

            //Make sure this excessive space is handled with care. (For all instances where text is preceeded by a space)
            raw = raw.Replace( ": ", ":" );

            //Replies to ping handler
            if ( raw.StartsWith( "PING :" ) ) {
                string[] parsed = raw.Split( ':' );
                s.QueueData( s.EventObject.OnPing( s.ServerID, parsed[1] ) );
            }

            if ( raw.StartsWith( "ERROR :" ) ) {
                Console.WriteLine( "[Error: whatsit]" );
            }

            //All that work above for this?
            string[] spaceSplit = raw.Split( ' ' );

            if ( spaceSplit.Length <= 1 ) return; //Nothing below here takes only one spaceSplit arg.
            switch ( spaceSplit[1] ) {
                case "001": {
                        string welcome = raw.Substring( spaceSplit[0].Length + spaceSplit[1].Length + 4 + spaceSplit[2].Length );
                        s.QueueData( s.EventObject.OnWelcome( s.ServerID, welcome ) );
                    }
                    break;
                case "352": {
                        //spaceSplit[5] = spaceSplit[5].Substring( 1 ); //Get rid of the : on the first name.
                        //
                        //                0                  1   2         3    4               5                        6          7  8  9   10
                        //":TechConnect.NL.EU.GameSurge.net 352 P2Q #phishcave ~2q d75-155-184-58.bchsia.telus.net *.GameSurge.net P2Q H :0 2Q Beta"
                        IRCHost ir = new IRCHost(spaceSplit[7], spaceSplit[4], spaceSplit[5]); //fix on debug.
                        Channel c = UpdateChanDB(s, spaceSplit[3]);
                        UpdateUserDB(s, ir);
                        //UpdateBothDB(s, spaceSplit[3], spaceSplit[7]);

                        //This should blank add all the users

                        if (spaceSplit[8].Contains("@"))
                            UpdateBothDB(s, spaceSplit[3], spaceSplit[7], '@');  //NO Simple. hah
                        else if (spaceSplit[8].Contains("+"))
                            UpdateBothDB(s, spaceSplit[3], spaceSplit[7], '+');
                        else
                            UpdateBothDB(s, spaceSplit[3], spaceSplit[7], null);

                        //Invoke the event.
                        s.QueueData(s.EventObject.OnNames(s.ServerID, c));
                    }
                    break;
                case "353": {
                        spaceSplit[5] = spaceSplit[5].Substring( 1 ); //Get rid of the : on the first name.

                        //if ( spaceSplit[2] == s.Config.NickName ) //Do we need to parse ourself? ~fish
                        //    break;

                        Channel c = UpdateChanDB( s, spaceSplit[4] );

                        //This should blank add all the users
                        for ( int i = 5; i < spaceSplit.Length; i++ ) {
                            if ( spaceSplit[i][0] == '@' || spaceSplit[i][0] == '+' )
                                UpdateBothDB( s, spaceSplit[4], spaceSplit[i].Substring( 1 ), spaceSplit[i][0] );
                            else
                                UpdateBothDB( s, spaceSplit[4], spaceSplit[i], null );
                        }

                        //Invoke the event.
                        s.QueueData( s.EventObject.OnNames( s.ServerID, c ) );
                    }
                    break;
                case "433": {
                        //:SERVER 433 * THENICK :Nickname is already in use.
                        s.QueueData( s.EventObject.OnErr_NickNameInUse( s.ServerID, spaceSplit[3] ) );
                    }
                    break;
                case "MODE": {

                        //SERVERMODE:
                        //:USERHOST MODE RECIPIENT :MODESTRING
                        if ( spaceSplit[3][0] == ':' ) {
                            IRCHost irch = new IRCHost( spaceSplit[0].Substring( 1 ) );
                            User u = new User( irch );
                            s.QueueData( s.EventObject.OnServerModeMessage( s.ServerID, u, spaceSplit[2], spaceSplit[3].TrimStart( ':' ) ) );
                        }
                        else {
                            //:USERMODE //TODO: HANDLE THIS
                            //:USERHOST MODE MODESTRING MODEAFFECTUSER MODEAFFECTUSER MODEAFFECTUSER
                        }

                    }
                    break;
                case "JOIN": {
                        IRCHost irch = new IRCHost( spaceSplit[0].Substring( 1 ) );
                        Channel c = UpdateChanDB( s, spaceSplit[2] );
                        if ( irch.Nick.Equals( s.CurrentNickName ) ) {
                            //We joined the channel.
                            s.QueueData( s.EventObject.OnBotJoin( s.ServerID, c ) );
                        }
                        else {
                            //Someone joined the channel.
                            //Update the user first.
                            UpdateUserDB( s, irch );
                            //Now update the channel.
                            ChannelUser cu = UpdateBothDB( s, spaceSplit[2], irch.Nick );
                            s.QueueData( s.EventObject.OnJoin( s.ServerID, c, cu ) );
                        }
                    }
                    break;
                case "PRIVMSG": {
                        string privmsgtxt = raw.Substring(
                        spaceSplit[0].Length + spaceSplit[1].Length + spaceSplit[2].Length + 4 );
                        //:USERHOST PRIVMSG RECIPIENT :TEXT
                        //  length    length  length + 4 (3 spaces & a :)

                        IRCHost irch = new IRCHost( spaceSplit[0].Substring( 1 ) );
                        User u = UpdateUserDB( s, irch );

                        //Replies to Channel/User CTCP Messages.
                        if ( spaceSplit.Length > 4 && spaceSplit[3].Length > 2 &&
                            spaceSplit[3][1] == (char)1 && raw.EndsWith( ( (char)1 ).ToString() ) ) {

                            if ( spaceSplit[2].Length >= 1 && ( spaceSplit[2][0] == '#' || spaceSplit[2][0] == '&' ) ) {
                                Channel c = UpdateChanDB( s, spaceSplit[2] );
                                ChannelUser cu = UpdateBothDB( s, spaceSplit[2], irch.Nick );
                                s.QueueData( s.EventObject.OnChannelCTCPMessage( s.ServerID, c, cu, privmsgtxt.Trim( (char)1 ) ) );
                            }
                            else
                                s.QueueData( s.EventObject.OnUserCTCPMessage( s.ServerID, spaceSplit[2], u, privmsgtxt.Trim( (char)1 ) ) );

                        }

                        //TODO: Evaluate if these can be moved up above the CTCP messages once it's converted.

                        else if ( spaceSplit[2][0] == '#' || spaceSplit[2][0] == '&' ) {
                            Channel c = UpdateChanDB( s, spaceSplit[2] );
                            ChannelUser cu = UpdateBothDB( s, spaceSplit[2], irch.Nick );
                            InvokeParsers( s, c, u, cu, privmsgtxt, IRCEvents.ParseTypes.ChannelMessage );
                            s.QueueData( s.EventObject.OnChannelMessage( s.ServerID, c, cu, privmsgtxt ) );
                        }
                        else {
                            InvokeParsers( s, null, u, null, privmsgtxt, IRCEvents.ParseTypes.PrivateMessage );
                            s.QueueData( s.EventObject.OnUserMessage( s.ServerID, spaceSplit[2], u, privmsgtxt ) );
                        }
                    }
                    break;
                case "NOTICE": {
                        // user notice
                        // :HOST NOTICE ME :MSG
                        // channel notice
                        // :HOST NOTICE CHANNEL :MSG
                        IRCHost irch;
                        string text = raw.Substring(
                        spaceSplit[0].Length + spaceSplit[1].Length + spaceSplit[2].Length + 4 );

                        try { irch = new IRCHost( spaceSplit[0].Substring( 1 ) ); }
                        catch ( FormatException ) { // looks like this is a server notice.
                            InvokeParsers( s, null, null, null, text, IRCEvents.ParseTypes.ServerNotice );
                            s.QueueData( s.EventObject.OnServerNotice( s.ServerID, text ) );
                            break;
                        }

                        User u = UpdateUserDB( s, irch );
                        if ( spaceSplit[2][0] == '#' || spaceSplit[2][0] == '&' ) {
                            Channel c = UpdateChanDB( s, spaceSplit[2] );
                            InvokeParsers( s, c, u, null, text, IRCEvents.ParseTypes.ChannelNotice );
                            s.QueueData( s.EventObject.OnChannelNotice( s.ServerID, c, u, text ) );
                        }
                        else {
                            InvokeParsers( s, null, u, null, text, IRCEvents.ParseTypes.PrivateNotice );
                            s.QueueData( s.EventObject.OnPrivateNotice( s.ServerID, u, text ) );
                        }
                    }
                    break;
                case "QUIT": {
                        //:USERHOST QUIT :MESSAGE
                        IRCHost irch = new IRCHost( spaceSplit[0].Substring( 1 ) );
                        User u = UpdateUserDB( s, irch );
                        //Premature call of event.
                        s.QueueData( s.EventObject.OnQuit( s.ServerID, u, raw.Substring(
                            spaceSplit[0].Length + spaceSplit[1].Length + 3 ) ) );
                        foreach ( Channel c in s.ChannelDatabase )
                            c.RemoveUser( u.Nickname );
                        s.UserDatabase.RemoveUser( u );
                    }
                    break;
                case "PART": {
                        //:USERHOST PART CHANNELNAME :MESSAGE
                        IRCHost irch = new IRCHost( spaceSplit[0].Substring( 1 ) );
                        if ( irch.Nick.Equals( s.CurrentNickName ) ) {
                            s.QueueData( s.EventObject.OnBotPart( s.ServerID, s.ChannelDatabase[spaceSplit[2]], spaceSplit.Length > 3 ? spaceSplit[3] : null ) );
                            s.ChannelDatabase.RemoveChannel( spaceSplit[2] );
                        }
                        else {
                            User u = UpdateUserDB( s, irch );
                            ChannelUser cu = UpdateBothDB( s, spaceSplit[2], u.Nickname );
                            //Premature call of event.
                            s.QueueData( s.EventObject.OnPart( s.ServerID, cu, s.ChannelDatabase[spaceSplit[2]], spaceSplit.Length > 3 ? spaceSplit[3] : null ) );
                            s.ChannelDatabase[spaceSplit[2]].RemoveUser( u );
                            bool stillOnAChannel = false;
                            foreach ( Channel c in s.ChannelDatabase )
                                if ( c.HasNick( u.Nickname ) )
                                    stillOnAChannel = true;
                            if ( stillOnAChannel == false )
                                s.UserDatabase.RemoveUser( u );
                        }
                    }
                    break;
                case "NICK": {
                        //:USERHOST NICK :NEWNICK
                        IRCHost irch = new IRCHost( spaceSplit[0].Substring( 1 ) );

                        string newNick = spaceSplit[2].Substring( 1 );
                        string oldNick = irch.Nick;

                        if ( oldNick == s.CurrentNickName ) { //We need to update.
                            s.CurrentNickName = newNick;
                            s.QueueData( s.EventObject.OnBotNickName( s.ServerID, newNick, oldNick ) );
                        }
                        else {
                            User oldUser = null;
                            try {
                                oldUser = s.UserDatabase[irch.Nick];//Get the old user. Remove him from the DB.
                            }
                            catch ( KeyNotFoundException ) {
                                //see below.
                            }

                            if ( oldUser == null ) {
                                //This means he wasn't in our user database.. WEIRD. Add him, add him to the db, but still
                                //broadcast it as a nick message.
                                oldUser = new User( irch );
                                s.UserDatabase.AddUser( oldUser );
                                s.UserDatabase.Authenticate( oldUser );
                            }
                            else {
                                s.UserDatabase.RemoveUser( oldUser ); //Removed him.
                                oldUser.CurrentHost.Nick = newNick; //Change his nick in the local User variable.
                                s.UserDatabase.AddUser( oldUser ); //Re-Add him to the database.
                                s.UserDatabase.Authenticate( oldUser );
                            }

                            ChannelUser cu = null;
                            foreach ( Channel c in s.ChannelDatabase ) { //Replace nick in all channels that had the old nick identifier.
                                try {
                                    cu = c[oldNick]; //Preserve his channel settings by retrieving this piece of info.
                                }
                                catch ( KeyNotFoundException ) { continue; }
                                cu.InternalUser = oldUser; //Set the new internal user. (nick matches might change authentication)
                                c.ReplaceUser( oldNick, cu ); //Replace the user in the database, remove oldNick, add the channeluser.
                            }

                            s.QueueData( s.EventObject.OnNickName( s.ServerID, oldUser, oldNick ) );
                        }
                    }
                    break;
            }
        }
예제 #7
0
 public ServerThread(Server s, Thread t)
 {
     server = s;
     thread = t;
 }
예제 #8
0
        /// <summary>
        /// Takes the configuration info, and begins the threading
        /// model to take care of all the Server objects created.
        /// </summary>
        private void StartServerThreads()
        {
            //Make sure the file system environment is set up for the servers:
            if ( !Directory.Exists( "userdb" ) )
                Directory.CreateDirectory( "userdb" );
            if ( !Directory.Exists( "logs" ) )
                Directory.CreateDirectory( "logs" );
            if ( !Directory.Exists( "modules" ) )
                Directory.CreateDirectory( "modules" );

            Configuration.ServerConfig[] list = config.Servers;

            WriteLogFunction wlf = new WriteLogFunction( WriteLog );

            bool allServersReady = true;

            //Loads & Initializes all servers.
            for ( int i = 0; i < list.Length; i++ ) {
                Server s = new Server( list[i], wlf );
                Thread t = new Thread( s.Connect );
                servers[i] = new ServerThread( s, t );
                servers[i].LoadModules = s.Init();
                allServersReady = allServersReady && servers[i].LoadModules;
            }

            //Load all modules.
            WriteLog( "Loading Modules..." );
            LoadModules( config.Modules );

            //Activate all the modules.
            for ( int m = 0; m < MaxModules; m++ ) {
                if ( modules[m] == null ) continue;

                WriteLog( "  Module Loaded: " + modules[m].ModuleConfig.FullName );

                for ( int s = 0; s < MaxServers; s++ ) {
                    if ( servers[s] == null || !servers[s].LoadModules ||
                        !modules[m].ModuleConfig.QueryServerList( servers[s].Server.Config.Name ) ) continue;

                    modules[m].Activate( s );
                    WriteLog( "    Activated Link: " + servers[s].Server.Config.Name + "." + modules[m].ModuleConfig.FullName );
                }

                if ( allServersReady ) {
                    WriteLog( "    Activation Completed: " + modules[m].ModuleConfig.FullName );
                    modules[m].ActivationComplete();
                }
            }

            foreach ( ServerThread st in servers )
                if ( st == null ) continue;
                else st.Thread.Start();
        }