/// <summary> /// Checks to see if this registered user can authenticate by the host. /// </summary> /// <param name="host">The host to check for.</param> /// <returns>Yes or no</returns> public bool HasHost(IRCHost host) { foreach ( IRCHost i in hostList ) if ( host.CompareTo( i ) == 0 ) return true; return false; }
/// <summary> /// Creates a server from a ServerConfig with a parameter /// to provide an interface for logging. /// </summary> /// <param name="config">The configuration to build the Server from.</param> /// <param name="logFunction">The function to call to log text for the application.</param> public Server(Configuration.ServerConfig config, Project2QService.WriteLogFunction logFunction) { //Instantiate and load databases uc = new UserCollection(); cc = new ChannelCollection(); uc.LoadRegisteredUsers( "userdb\\" + config.Name + ".udb" ); //Rip up this little guy to help us out :D currentHost = new IRCHost(); currentIP = null; this.authmode = !File.Exists( "userdb\\" + config.Name + ".udb" ); this.writeLogFunction = logFunction; //Assign a Server ID this.serverId = Server.NextServerId; if ( this.serverId == -1 ) throw new OverflowException( "Too many servers created." ); servers[serverId] = this; //Save the configuration. this.config = config; //Tie default static handlers together for this instance of IRCEvents. irce = new IRCEvents(); //Initialize the socket pipe before the modules. Modules are scary. state = State.Disconnected; socketPipe = new SocketPipe( this.serverId, config.RetryTimeout, config.OperationTimeout, config.SendInhibit, config.SocketBufferSize ); //Default values for now, get them from config later plz. socketPipe.OnDisconnect += new SocketPipe.NoParams( this.OnDisconnect ); socketPipe.OnReceive += new SocketPipe.ReceiveData( this.OnReceive ); }
/// <summary> /// Adds a host to the registered user's host list. /// </summary> /// <param name="host">The host to add.</param> /// <returns>True or false.</returns> public bool AddHost(IRCHost host) { if ( host.Equals( new IRCHost( "*!*@*" ) ) ) return false; hostList.Add( host ); return true; }
/// <summary> /// Adds a host to a user. /// </summary> /// <param name="repnick">The user that initiated the command.</param> /// <param name="host">The host to add.</param> /// <param name="user">The user to add the host to.</param> public void AddHost(string repnick, string host, string user) { User u = null; UserCollection uc = (UserCollection)mp.RequestVariable( Request.UserCollection, channelMessageData.sid ); try { u = uc[user]; } catch ( KeyNotFoundException ) { BoldNickNotice( repnick, "Error(Invalid User):", " User not in active user database." ); return; } if ( u.UserAttributes == null ) { BoldNickNotice( repnick, "Error(Invalid User):", " User not in user database." ); return; } IRCHost irch = null; try { irch = new IRCHost( host ); } catch ( FormatException ) { BoldNickNotice( repnick, "Error(Invalid Host):", " The host must be in the form [nick]![username]@[host] where all fields can contain wildcard characters '?' and '*'." ); return; } if ( uc.HasHost( irch ) ) { BoldNickNotice( repnick, "Error(Host Exists):", " The host specified already exists. Please use a wider subset of the host you require." ); return; } if ( !u.UserAttributes.AddHost( irch ) ) { BoldNickNotice( repnick, "Error(Invalid Host):", " The host specified was rejected. Try a more specific subset of the host you require." ); return; } BoldNickNotice( repnick, "Host Added:", " " + irch.ToString() + " to " + ( ( repnick.Equals( u.Nickname ) ) ? "your account." : u.Nickname ) ); }
/// <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; }
/// <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; } }
/// <summary> /// Removes a host from the registered user's host list. /// </summary> /// <param name="host">The host to remove.</param> /// <returns>True or false.</returns> public bool RemoveHost(IRCHost host) { return hostList.Remove( host ); }
/// <summary> /// Removes a host from a user. /// </summary> /// <param name="repnick">The user that initiated the command.</param> /// <param name="host">The host to remove.</param> /// <param name="user">The user to remove the host from.</param> public void RemoveHost(string repnick, string host, string user) { User u = null; UserCollection uc = (UserCollection)mp.RequestVariable( Request.UserCollection, channelMessageData.sid ); try { u = uc[user]; } catch ( KeyNotFoundException ) { BoldNickNotice( repnick, "Error(Invalid User):", " User not in active user database." ); return; } if ( u.UserAttributes == null ) { BoldNickNotice( repnick, "Error(Invalid User):", " User not in user database." ); return; } if ( u.UserAttributes.HostList.Count <= 1 ) { BoldNickNotice( repnick, "Error(Invalid Operation):", " User will have no hosts remaining if you remove this one. (Try " + Configuration.ModuleConfig.ModulePrefix + "rmusr." ); return; } IRCHost irch = null; try { irch = new IRCHost( host ); } catch ( FormatException ) { BoldNickNotice( repnick, "Error(Invalid Host):", " The host must be in the form [nick]![username]@[host] where all fields can contain wildcard characters '?' and '*'." ); return; } if ( !u.UserAttributes.RemoveHost( irch ) ) { BoldNickNotice( repnick, "Error(Host not Found):", " The host specified was not found on this user." ); return; } BoldNickNotice( repnick, "Host Removed:", " " + irch.ToString() + " from " + ( ( repnick.Equals( u.Nickname ) ) ? "your account." : u.Nickname ) ); }
/// <summary> /// Fires the Who event. /// </summary> /// <param name="sid">The server on which the part happened.</param> /// <param name="c">The Channel that was who'd.</param> /// <param name="user">The user that was parsed out.</param> /// <returns>The raw data to be sent to the server.</returns> public string[][] OnWho(int sid, Channel c, IRCHost user) { if ( Who != null ) return InvocationTunnel( this.Who.GetInvocationList(), sid, c, user ); return null; }
/// <summary> /// Creates a User associated with a Registered User. /// </summary> /// <param name="current">The current hostname of this user.</param> /// <param name="ru">The associated registered user.</param> public User(IRCHost current, RegisteredUser ru) { this.ru = ru; currentHost = current; }
/// <summary> /// Creates a User. /// </summary> /// <param name="current">The current hostname of this user.</param> public User(IRCHost current) { ru = null; currentHost = current; }