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 }
|