| 
00001	class UBrowserIRCLink expands UBrowserBufferedTCPLink;
00002	
00003	var IpAddr			ServerIpAddr;
00004	
00005	var string			ServerAddress;
00006	var int				ServerPort;
00007	
00008	var string			NickName;
00009	var string			UserIdent;
00010	var string			FullName;
00011	var string			DefaultChannel;
00012	
00013	var localized string InvalidAddressText;
00014	var localized string ErrorBindingText;
00015	var localized string ResolveFailedText;
00016	var localized string ConnectedText;
00017	var localized string ConnectingToText;
00018	var localized string TimeOutError;
00019	var localized string InviteString;
00020	
00021	var UBrowserIRCSystemPage SystemPage; 
00022	
00023	var string DisconnectReason;
00024	var string VersionString;
00025	
00026	function PostBeginPlay()
00027	{
00028		Super.PostBeginPlay();
00029		Disable('Tick');
00030	}
00031	
00032	function Connect(UBrowserIRCSystemPage InSystemPage, string InServer, string InNickName, string InUserIdent, string InFullName, string InDefaultChannel)
00033	{
00034		local int i;
00035	
00036		SystemPage = InSystemPage;
00037		NickName = InNickName;
00038		FullName = InFullName;
00039		UserIdent = InUserIdent;
00040		DefaultChannel = InDefaultChannel;
00041	
00042		i = InStr(InServer, ":");
00043		if(i == -1)
00044		{
00045			ServerAddress = InServer;
00046			ServerPort = 6667;
00047		}
00048		else
00049		{
00050			ServerAddress = Left(InServer, i);
00051			ServerPort = Int(Mid(InServer, i+1));
00052		}
00053	
00054		ResetBuffer();
00055		ServerIpAddr.Port = ServerPort;
00056		SetTimer(20, False);
00057		SystemPage.SystemText( ConnectingToText@ServerAddress );
00058		Resolve( ServerAddress );
00059	}
00060	
00061	function string ChopLeft(string Text)
00062	{
00063		while(Text != "" && InStr(": !", Left(Text, 1)) != -1)
00064			Text = Mid(Text, 1);
00065		return Text;
00066	}
00067	
00068	function string RemoveNickPrefix(string Nick)
00069	{
00070		while(Nick != "" && InStr(":@+", Left(Nick, 1)) != -1)
00071			Nick = Mid(Nick, 1);
00072		return Nick;
00073	}
00074	
00075	function string Chop(string Text)
00076	{
00077		while(Text != "" && InStr(": !", Left(Text, 1)) != -1)
00078			Text = Mid(Text, 1);
00079		while(Text != "" && InStr(": !", Right(Text, 1)) != -1)
00080			Text = Left(Text, Len(Text)-1);
00081	
00082		return Text;
00083	}
00084	
00085	function Resolved( IpAddr Addr )
00086	{
00087		// Set the address
00088		ServerIpAddr.Addr = Addr.Addr;
00089	
00090		// Handle failure.
00091		if( ServerIpAddr.Addr == 0 )
00092		{
00093			if(SystemPage != None)
00094			{
00095				SystemPage.SystemText( InvalidAddressText );
00096				SystemPage.Disconnect();
00097			}
00098			return;
00099		}
00100	
00101		// Display success message.
00102		Log( "UBrowserIRCLink: Server is "$ServerAddress$":"$ServerIpAddr.Port );
00103	
00104		// Bind the local port.
00105		if( BindPort() == 0 )
00106		{
00107			if(SystemPage != None)
00108			{
00109				SystemPage.SystemText( ErrorBindingText );
00110				SystemPage.Disconnect();
00111			}
00112			return;
00113		}
00114	
00115		Open( ServerIpAddr );
00116	}
00117	
00118	event Closed()
00119	{
00120		if(SystemPage != None)
00121			SystemPage.Disconnect();
00122	}
00123	
00124	// Host resolution failue.
00125	function ResolveFailed()
00126	{
00127		if(SystemPage != None)
00128		{
00129			SystemPage.SystemText(ResolveFailedText);
00130			SystemPage.Disconnect();
00131		}
00132	}
00133	
00134	event Timer()
00135	{
00136		if(SystemPage != None)
00137		{
00138			SystemPage.SystemText( TimeOutError );
00139			SystemPage.Disconnect();
00140		}
00141		return;
00142	}
00143	
00144	event Opened()
00145	{
00146		SetTimer(0, False);
00147		if(SystemPage != None)
00148			SystemPage.SystemText(ConnectedText);
00149		Enable('Tick');
00150		GotoState('LoggingIn');
00151	}
00152	
00153	function Tick(float DeltaTime)
00154	{
00155		local string Line;
00156	
00157		DoBufferQueueIO();
00158		if(ReadBufferedLine(Line))
00159			ProcessInput(Line);
00160	}
00161	
00162	function SendCommandText(string Text)
00163	{
00164		local int i, j;
00165		local string Cmd, Temp, Temp2;
00166	
00167		// Process fake commands like /MSG
00168		if(Left(Text, 4) ~= "MSG ")
00169			Text = "PRIVMSG "$Mid(Text, 4);
00170		if(Left(Text, 6) ~= "LEAVE ")
00171			Text = "PART "$Mid(Text, 6);
00172	
00173		// Add colons for commands: PRIVMSG, QUIT, KILL, KICK, NOTICE
00174		i = InStr(Text, " ");
00175		if(i != -1)
00176		{
00177			Cmd = Caps(Left(Text, i));
00178			Text = Cmd$Mid(Text, i);
00179	
00180			switch(Cmd)
00181			{
00182			// CMD nick :message
00183			case "PRIVMSG":
00184			case "NOTICE":
00185			case "KILL":
00186				Temp = ChopLeft(Mid(Text, i+1));
00187				i = InStr(Temp, " ");
00188				if(i != -1)
00189					Text = Cmd@Left(Temp, i)$" :"$ChopLeft(Mid(Temp, i+1));
00190				break;
00191			// hack for CTCP
00192			case "CTCP":
00193				Temp = ChopLeft(Mid(Text, i+1));
00194				i = InStr(Temp, " ");
00195				if(i != -1)
00196					Text = "PRIVMSG "$Left(Temp, i)$" :"$Chr(1)$ChopLeft(Mid(Temp, i+1))$Chr(1);
00197				break;
00198			// CMD #channel nick :message
00199			case "KICK":
00200				Temp = ChopLeft(Mid(Text, i+1));
00201				i = InStr(Temp, " ");
00202				if(i != -1)
00203				{
00204					Temp2 = ChopLeft(Mid(Temp, i+1));
00205					j = InStr(Temp2, " ");
00206					if(j != -1)
00207						Text = Cmd@Left(Temp, i)@Left(Temp2, j)$" :"$ChopLeft(Mid(Temp2, j+1));
00208				}
00209				break;
00210			// CMD :message
00211			case "QUIT":
00212				Text = Cmd$" :"$ChopLeft(Mid(Text, i+1));
00213				break;
00214			}
00215		}
00216		else
00217			Text = Caps(Text);	
00218	
00219		SendBufferedData(Text$CRLF);
00220	}
00221	
00222	function SendChannelText(string Channel, string Text)
00223	{
00224		SendBufferedData("PRIVMSG "$Channel$" :"$Text$CRLF);
00225	}
00226	
00227	function SendChannelAction(string Channel, string Text)
00228	{
00229		SendBufferedData("PRIVMSG "$Channel$" :"$Chr(1)$"ACTION "$Text$Chr(1)$CRLF);
00230	}
00231	
00232	function ProcessInput(string Line)
00233	{
00234		// Respond to PING
00235		if(Left(Line, 5) == "PING ")
00236			SendBufferedData("PONG "$Mid(Line, 5)$CRLF);
00237	}
00238	
00239	state LoggingIn
00240	{
00241		function ProcessInput(string Line)
00242		{
00243			local string Temp;
00244			
00245			Temp = ParseDelimited(Line, " ", 2);
00246	
00247			if(ParseDelimited(Line, " ", 1)== "ERROR")
00248				SystemPage.SystemText(ChopLeft(ParseDelimited(Line, ":", 2, True)));
00249	
00250			// Handle nick already in use on connect...
00251			if(Temp == "433")
00252			{
00253				SystemPage.SystemText(ChopLeft(ParseDelimited(Line, " ", 3, True)));
00254			}
00255			else
00256			if(Int(Temp) != 0)
00257			{
00258				SystemPage.SystemText(ChopLeft(ParseDelimited(Line, " ", 3, True)));
00259				GotoState('LoggedIn');
00260			}
00261	
00262			Global.ProcessInput(Line);
00263		}
00264	
00265		function SendCommandText(string Text)
00266		{
00267			Global.SendCommandText(Text);
00268			if(ParseDelimited(Text, " ", 1) ~= "NICK")
00269			{
00270				SystemPage.ChangedNick(NickName, Chop(ParseDelimited(Text, " ", 2)));
00271			}
00272		}
00273	
00274	Begin:
00275		SendBufferedData("USER "$UserIdent$" localhost "$ServerAddress$" :"$FullName$CRLF);
00276		SendBufferedData("NICK "$NickName$CRLF);
00277	}
00278	
00279	state LoggedIn
00280	{
00281		function ProcessInput(string Line)
00282		{
00283			local string Temp, Temp2, Temp3;
00284			local bool bAddModifier;
00285			local int i;
00286			local string Command;
00287	
00288			Global.ProcessInput(Line);
00289			
00290			Command = ParseDelimited(Line, " ", 2);
00291	
00292			if(ParseDelimited(Line, " ", 1) == "ERROR")
00293			{
00294				SystemPage.SystemText(ChopLeft(ParseDelimited(Line, ":", 2, True)));
00295			}
00296			else if(Command == "JOIN")
00297			{
00298				Temp = ParseDelimited(Line, ":!", 2);
00299				if(Temp ~= NickName)
00300					Temp = "";
00301				SystemPage.JoinedChannel(Chop(ParseDelimited(Line, " ", 3)), Temp);
00302			}
00303			else if(Command == "PART")
00304			{
00305				Temp = ParseDelimited(Line, ":!", 2);
00306				if(Temp ~= NickName)
00307					Temp = "";
00308				SystemPage.PartedChannel(Chop(ParseDelimited(Line, " ", 3)), Temp);
00309			}
00310			else if(Command == "NICK")
00311			{
00312				SystemPage.ChangedNick(ParseDelimited(Line, ":!", 2), Chop(ParseDelimited(Line, " ", 3)));
00313			}
00314			else if(Command == "QUIT")
00315			{
00316				SystemPage.UserQuit(ParseDelimited(Line, ":!", 2), ChopLeft(ParseDelimited(Line, " ", 3, True)));
00317			}
00318			else if(Command == "353")	// NAMES
00319			{
00320				Temp2 = ParseDelimited(Line, "#", 2);
00321				Temp2 = ParseDelimited(Temp2, " :", 1);
00322	
00323				Temp = ParseDelimited(Line, ":", 3, True);
00324				while(Temp != "")
00325				{
00326					// Nickname
00327					Temp3 = ParseDelimited(Temp, " ", 1);
00328	
00329					SystemPage.UserInChannel("#"$Temp2, RemoveNickPrefix(Temp3));
00330	
00331					if(Left(Temp3, 1) == "@")
00332						SystemPage.ChangeOp("#"$Temp2, RemoveNickPrefix(Temp3), True);
00333					else
00334					if(Left(Temp3, 1) == "+")
00335						SystemPage.ChangeVoice("#"$Temp2, RemoveNickPrefix(Temp3), True);
00336	
00337					Temp = ParseDelimited(Temp, " ", 2, True);
00338				}	
00339			}
00340			else if(Command == "333")	// Channel formed info
00341			{
00342			}
00343			else if(Command == "366")	// End of NAMES
00344			{
00345			}
00346			else if(Command == "331")	// RPL_NOTOPIC
00347			{
00348			}
00349			else if(Command == "332")	// RPL_TOPIC
00350			{
00351			}
00352			else if(Command == "341")   // RPL_INVITING
00353			{
00354			}
00355			else if(Command == "301")	// RPL_AWAY
00356			{
00357				SystemPage.IsAway(Chop(ParseDelimited(Line, " ", 4)), ChopLeft(ParseDelimited(Line, ":", 3, True)));
00358			}
00359			else if(Command == "NOTICE")
00360			{
00361				Temp = ParseDelimited(Line, ": ", 2);
00362				Temp2 = ParseDelimited(Line, ":! ", 2);
00363	
00364				if(InStr(Temp, "!") != -1 && InStr(Temp2, ".") == -1)
00365				{
00366					// it's a Nick.
00367					Temp = ChopLeft(ParseDelimited(Line, " ", 4, True));
00368					if(Asc(Left(Temp, 1)) == 1 && Asc(Right(Temp, 1)) == 1)
00369						SystemPage.CTCP("", Temp2, Mid(Temp, 1, Len(Temp) - 2));
00370					else
00371						SystemPage.UserNotice(Temp2, Temp);
00372				}
00373				else
00374					SystemPage.SystemText(ChopLeft(ParseDelimited(Line, " ", 4, True)));
00375			}
00376			else if(Int(Command)!= 0)
00377			{
00378				SystemPage.SystemText(ChopLeft(ParseDelimited(Line, " ", 4, True)));
00379			}
00380			else if(Command == "MODE")
00381			{
00382				// channel mode
00383				Temp = Chop(ParseDelimited(Line, " ", 4));
00384				// channel
00385				Temp3 = Chop(ParseDelimited(Line, " ", 3));
00386				i = 5;
00387				bAddModifier = True;
00388				while(Temp != "")
00389				{
00390					Temp2 = Left(Temp, 1);
00391					if(Temp2 == "+")
00392						bAddModifier = True;
00393					if(Temp2 == "-")
00394						bAddModifier = False;
00395	
00396					if(Temp2 == "o")
00397					{
00398						SystemPage.ChangeOp(Temp3, Chop(ParseDelimited(Line, " ", i)), bAddModifier);
00399						i++;
00400					}
00401						
00402					if(Temp2 == "v")
00403					{
00404						SystemPage.ChangeVoice(Temp3, Chop(ParseDelimited(Line, " ", i)), bAddModifier);
00405						i++;
00406					}
00407	
00408					Temp = Mid(Temp, 1);
00409				}
00410				 
00411				SystemPage.ChangeMode(Temp3, ParseDelimited(Line, ":!", 2), ChopLeft(ParseDelimited(Line, " ", 4, True)));
00412	
00413			}
00414			else if(Command == "KICK")
00415			{
00416				// FIXME: handle multiple kicks in a single message
00417				SystemPage.KickUser(Chop(ParseDelimited(Line, " ", 3)), Chop(ParseDelimited(Line, " ", 4)), ParseDelimited(Line, ":!", 2), ChopLeft(ParseDelimited(Line, ":", 3, True)));
00418			}
00419			else if(Command == "INVITE")
00420			{
00421				SystemPage.SystemText(ParseDelimited(Line, ":!", 2)@InviteString@ParseDelimited(Line, ":", 3));	
00422			}
00423			else if(Command == "PRIVMSG")
00424			{
00425				Temp = Chop(ParseDelimited(Line, " ", 3));
00426				Temp2 = ChopLeft(ParseDelimited(Line, " ", 4, True));
00427	
00428				if(Mid(Temp2, 1, 7) == "ACTION " && Asc(Left(Temp2, 1))==1 && Asc(Right(Temp2, 1))==1)
00429				{
00430					Temp2 = Mid(Temp2, 8);
00431					Temp2 = Left(Temp2, Len(Temp2) - 1);
00432	
00433					if(Temp != "" && InStr("&#@", Left(Temp, 1)) != -1)
00434						SystemPage.ChannelAction(Temp, ParseDelimited(Line, ":!", 2), Temp2);
00435					else
00436						SystemPage.PrivateAction(ParseDelimited(Line, ":!", 2), Temp2);
00437				}
00438				else
00439				if(Asc(Left(Temp2, 1))==1 && Asc(Right(Temp2, 1))==1)
00440				{
00441					Temp2 = Mid(Temp2, 1, Len(Temp2) - 2);
00442					
00443					switch(Temp2)
00444					{
00445					case "VERSION":
00446						SendBufferedData("NOTICE "$ParseDelimited(Line, ":!", 2)$" :"$Chr(1)$"VERSION "$VersionString$Level.EngineVersion$Chr(1)$CRLF);
00447						SystemPage.CTCP(Temp, ParseDelimited(Line, ":!", 2), Temp2);
00448						break;
00449					default:
00450						SystemPage.CTCP(Temp, ParseDelimited(Line, ":!", 2), Temp2);
00451						break;
00452					}
00453				}
00454				else
00455				{
00456					if(Temp != "" && InStr("&#@", Left(Temp, 1)) != -1)
00457						SystemPage.ChannelText(Temp, ParseDelimited(Line, ":!", 2), Temp2);
00458					else
00459						SystemPage.PrivateText(ParseDelimited(Line, ":!", 2), Temp2);
00460				}
00461			}
00462		}
00463	Begin:
00464		JoinChannel(DefaultChannel);
00465	}
00466	
00467	function JoinChannel(string Channel)
00468	{
00469		if(Left(Channel, 1) == "#")
00470			SendBufferedData("JOIN "$Channel$CRLF);
00471	}
00472	
00473	function PartChannel(string Channel)
00474	{
00475		if(Left(Channel, 1) == "#")
00476			SendBufferedData("PART "$Channel$CRLF);
00477	}
00478	
00479	function SetNick(string NewNick)
00480	{
00481		SendBufferedData("NICK "$NewNick$CRLF);
00482	}
00483	
00484	function SetAway(string AwayText)
00485	{
00486		SendBufferedData("AWAY :"$AwayText$CRLF);
00487	}
00488	
00489	function DestroyLink()
00490	{
00491		SystemPage = None;
00492		if(IsConnected())
00493		{
00494			SendText("QUIT :"$DisconnectReason$CRLF);
00495			Close();
00496		}
00497		else
00498			Destroy();
00499	}
00500	
00501	defaultproperties
00502	{
00503	     InvalidAddressText="Invalid server address, aborting."
00504	     ErrorBindingText="Error binding local port, aborting."
00505	     ResolveFailedText="Failed to resolve server address, aborting."
00506	     ConnectedText="Connected."
00507	     ConnectingToText="Connecting to"
00508	     TimeOutError="Timeout connecting to server."
00509	     InviteString="invites you to join"
00510	     DisconnectReason="Disconnected"
00511	     VersionString="UBrowser IRC Client version "
00512	}
 |