{
Delphi IMC3 Client - Core code and types
Based on client code by Samson of Alsherok.
$Id: imc3_core.pas,v 1.4 2004/03/14 11:54:22 druid Exp $
}
unit imc3_core;
interface
uses
Classes,
dtypes,
socket,
imc3_chan,
imc3_mud,
imc3_packet,
imc3_const;
type
GInterMud = class(TThread)
private
this_mud : GMud_I3;
router : GRouter_I3;
packet : GPacket_I3;
socket : GSocket;
connected : boolean;
debugLevel : integer;
reconattempts : integer;
_wait : integer;
outputBuffer : string;
inputBuffer : array[0..MAX_IPS - 1] of char;
inputPointer : integer;
procedure handleError(packet : GPacket_I3);
procedure handleStartupReply(packet : GPacket_I3);
procedure handleMudList(packet : GPacket_I3);
procedure handleChanList(packet : GPacket_I3);
procedure handleChannelMessage(packet : GPacket_I3);
procedure handleChannelEmote(packet : GPacket_I3);
procedure handleLocateReply(packet : GPacket_I3);
procedure handleLocateRequest(packet : GPacket_I3);
procedure handleTell(packet : GPacket_I3);
procedure handleBeep(packet : GPacket_I3);
procedure handleWhoReq(packet : GPacket_I3);
procedure handleWhoReply(packet : GPacket_I3);
procedure handleFingerReq(packet : GPacket_I3);
procedure handleFingerReply(packet : GPacket_I3);
procedure handlePacket(packet : GPacket_I3);
procedure startup();
procedure debug(msg : string; level : integer = 1);
procedure writePacket(msg : string);
published
procedure connect();
procedure disconnect();
procedure sendPacket();
procedure writeBuffer(msg : string);
procedure writeHeader(identifier, originator_mudname, originator_username, target_mudname, target_username : string);
procedure sendError(mud, user, code, msg : string);
procedure sendChannelListen(user : string; channel : GChannel_I3; lconnect : boolean);
procedure sendChannelMessage(channel : GChannel_I3; name, msg : string);
procedure sendChannelEmote(channel : GChannel_I3; name, msg : string);
procedure sendChannelTarget(channel : GChannel_I3; name, tmud, tuser, msg_o, msg_t, tvis : string);
procedure sendLocateRequest(originator, user : string);
procedure sendTell(from_user, to_user : string; mud : GMud_I3; msg : string);
procedure sendBeep(from_user, to_user : string; mud : GMud_I3);
procedure sendWhoReq(from_user : string; mud : GMud_I3);
procedure sendFingerReq(from_user, to_user : string; mud : GMud_I3);
procedure shutdown();
constructor Create(debugLevel : integer = 0);
destructor Destroy; override;
procedure setDebugLevel(debugLevel : integer = 0);
procedure Execute(); override;
property connectedRouter : GRouter_I3 read router;
property isConnected : boolean read connected;
end;
implementation
uses
{$IFDEF WIN32}
WinSock2,
{$ENDIF}
{$IFDEF LINUX}
Libc,
{$ENDIF}
SysUtils,
FastStrings,
Channels,
imc3_util,
constants,
console,
chars,
player,
conns,
mudsystem,
util;
constructor GInterMud.Create(debugLevel : integer = 0);
begin
inherited Create(false);
connected := false;
Self.debugLevel := debugLevel;
this_mud := GMud_I3.Create();
this_mud.readConfig();
socket := GSocket4.Create();
reconattempts := 0;
_wait := 0;
end;
destructor GInterMud.Destroy();
begin
socket.Free();
this_mud.Free();
inherited Destroy();
end;
procedure GInterMud.connect();
begin
if (isConnected) then
exit;
_wait := 2;
end;
procedure GInterMud.disconnect();
begin
if (not isConnected) then
exit;
debug('Disconnecting from server');
connected := false;
shutdown();
socket.disconnect();
end;
// bool I3_write_packet( char *msg )
procedure GInterMud.writePacket(msg : string);
var
oldsize, size, x : integer;
s : array of char;
begin
size := length(msg);
oldsize := size;
SetLength(s, size + 8);
s[3] := chr(size mod 256);
size := size shr 8;
s[2] := chr(size mod 256);
size := size shr 8;
s[1] := chr(size mod 256);
size := size shr 8;
s[0] := chr(size mod 256);
StrPCopy(@s[4], msg);
{ Scan for \r used in Diku client packets and change to NULL }
for x := 4 to oldsize + 4 do
begin
if (s[x] = #13) then
begin
s[x] := #0;
end;
end;
x := socket.send(s[0], oldsize + 4);
if (x <= 0) then
raise Exception.Create('Write error on socket');
debug('Sent packet: ' + msg, 2);
outputBuffer := '';
end;
// void I3_send_packet( void )
procedure GInterMud.sendPacket();
begin
writePacket(outputBuffer);
end;
// void I3_write_buffer( const char *msg )
procedure GInterMud.writeBuffer(msg : string);
begin
outputBuffer := outputBuffer + msg;
end;
// void I3_write_header( char *identifier, char *originator_mudname, char *originator_username, char *target_mudname, char *target_username )
procedure GInterMud.writeHeader(identifier, originator_mudname, originator_username, target_mudname, target_username : string);
begin
writeBuffer('({"');
writeBuffer(identifier);
writeBuffer('",5,');
if (originator_mudname <> '') then
begin
writeBuffer('"');
writeBuffer(originator_mudname);
writeBuffer('",');
end
else
begin
writeBuffer('0,');
end;
if (originator_username <> '') then
begin
writeBuffer('"');
writeBuffer(originator_username);
writeBuffer('",');
end
else
begin
writeBuffer('0,');
end;
if (target_mudname <> '') then
begin
writeBuffer('"');
writeBuffer(target_mudname);
writeBuffer('",');
end
else
begin
writeBuffer('0,');
end;
if (target_username <> '') then
begin
writeBuffer('"');
writeBuffer(target_username);
writeBuffer('",');
end
else
begin
writeBuffer('0,');
end;
end;
// void I3_startup_packet( void )
procedure GInterMud.startup();
begin
(* char s[SMST];
if( !I3_is_connected() )
return;
I3_output_pointer = 4;
I3_output_buffer[0] = '\0';
i3log( "Sending startup_packet to %s", this_mud->routerName ); *)
writeHeader('startup-req-3', this_mud.name, '', router.name, '');
writeBuffer(IntToStr(this_mud.password));
writeBuffer(',');
writeBuffer(IntToStr(this_mud.mudlist_id));
writeBuffer(',');
writeBuffer(IntToStr(this_mud.chanlist_id));
writeBuffer(',');
writeBuffer(IntToStr(this_mud.player_port));
writeBuffer(',0,0,"');
writeBuffer(this_mud.mudlib);
writeBuffer('","');
writeBuffer(this_mud.base_mudlib);
writeBuffer('","');
writeBuffer(this_mud.driver);
writeBuffer('","');
writeBuffer(this_mud.mud_type);
writeBuffer('","');
writeBuffer(this_mud.open_status);
writeBuffer('","');
writeBuffer(this_mud.admin_email);
writeBuffer('",');
{ Begin first mapping set }
writeBuffer('([');
if (this_mud.emoteto) then
writeBuffer('"emoteto":1,');
if (this_mud.news) then
writeBuffer('"news":1,');
if (this_mud.ucache) then
writeBuffer('"ucache":1,');
if (this_mud.auth) then
writeBuffer('"auth":1,');
if (this_mud.locate) then
writeBuffer('"locate":1,');
if (this_mud.finger) then
writeBuffer('"finger":1,');
if (this_mud.channel) then
writeBuffer('"channel":1,');
if (this_mud.who) then
writeBuffer('"who":1,');
if (this_mud.tell) then
writeBuffer('"tell":1,');
if (this_mud.beep) then
writeBuffer('"beep":1,');
if (this_mud.mail) then
writeBuffer('"mail":1,');
if (this_mud.mfile) then
writeBuffer('"file":1,');
if (this_mud.http > 0) then
writeBuffer('"http":' + IntToStr(this_mud.http) + ',');
if (this_mud.smtp > 0) then
writeBuffer('"smtp":' + IntToStr(this_mud.smtp) + ',');
if (this_mud.pop3 > 0) then
writeBuffer('"pop3":' + IntToStr(this_mud.pop3) + ',');
if (this_mud.ftp > 0) then
writeBuffer('"ftp":' + IntToStr(this_mud.ftp) + ',');
if (this_mud.nntp > 0) then
writeBuffer('"nntp":' + IntToStr(this_mud.nntp) + ',');
if (this_mud.rcp > 0) then
writeBuffer('"rcp":' + IntToStr(this_mud.rcp) + ',');
if (this_mud.amrcp > 0) then
writeBuffer('"amrcp":' + IntToStr(this_mud.amrcp) + ',');
writeBuffer(']),([');
{ END first set of "mappings", start of second set }
if (this_mud.web <> '') then
writeBuffer('"url":"' + this_mud.web + '",');
writeBuffer('"time":"' + DateTimeToStr(Now) + '",');
writeBuffer(']),})' + #13);
sendPacket();
end;
procedure GInterMud.handleError(packet : GPacket_I3);
var
code, msg, error : string;
pl : GPlayer;
begin
code := GString(packet.fields[6]).value;
msg := GString(packet.fields[7]).value;
pl := GPlayer(findPlayerWorldEx(nil, packet.target_username));
error := Format('Error: from %s to %s@%s: %s (%s)', [packet.originator_mudname, packet.target_username, packet.target_mudname, msg, code]);
debug(error);
if (pl <> nil) then
pl.sendBuffer(error + #13#10);
end;
procedure GInterMud.handleStartupReply(packet : GPacket_I3);
begin
debug('Accepted by router', 1);
end;
procedure GInterMud.handleMudList(packet : GPacket_I3);
var
mud : GMud_I3;
i, j : integer;
child, list : TList;
name : string;
begin
list := TList(packet.fields[7]);
debug(IntToStr(list.count div 2) + ' muds in packet', 2);
i := 0;
while (i < list.count) do
begin
name := GString(list[i]).value;
mud := GMud_I3(mudList.get(name));
if (mud = nil) then
begin
debug('New mud: ' + name, 2);
mud := GMud_I3.Create();
mud.name := name;
mudList.put(mud.name, mud);
end
else
debug('Updating mud: ' + name, 2);
if (GString(list[i + 1]).value = '0') then
begin
debug(name + ' is down', 2);
mud.status := 0;
end
else
begin
child := TList(list[i + 1]);
if (child.count < 13) then
debug('Illegal mud: ' + name, 1)
else
begin
mud.status := StrToIntDef(GString(child[0]).value, 0);
mud.ipaddress := GString(child[1]).value;
mud.player_port := StrToIntDef(GString(child[2]).value, 0);
mud.imud_tcp_port := StrToIntDef(GString(child[3]).value, 0);
mud.imud_udp_port := StrToIntDef(GString(child[4]).value, 0);
mud.mudlib := GString(child[5]).value;
mud.base_mudlib := GString(child[6]).value;
mud.driver := GString(child[7]).value;
mud.mud_type := GString(child[8]).value;
mud.open_status := GString(child[9]).value;
mud.admin_email := GString(child[10]).value;
child := TList(child[11]);
j := 0;
while (j < child.count) do
begin
if (GString(child[j]).value = 'tell') then
mud.tell := (StrToIntDef(GString(child[j + 1]).value, 0) = 1)
else
if (GString(child[j]).value = 'beep') then
mud.beep := (StrToIntDef(GString(child[j + 1]).value, 0) = 1)
else
if (GString(child[j]).value = 'emoteto') then
mud.emoteto := (StrToIntDef(GString(child[j + 1]).value, 0) = 1)
else
if (GString(child[j]).value = 'who') then
mud.who := (StrToIntDef(GString(child[j + 1]).value, 0) = 1)
else
if (GString(child[j]).value = 'finger') then
mud.finger := (StrToIntDef(GString(child[j + 1]).value, 0) = 1)
else
if (GString(child[j]).value = 'locate') then
mud.locate := (StrToIntDef(GString(child[j + 1]).value, 0) = 1)
else
if (GString(child[j]).value = 'channel') then
mud.channel := (StrToIntDef(GString(child[j + 1]).value, 0) = 1)
else
if (GString(child[j]).value = 'news') then
mud.news := (StrToIntDef(GString(child[j + 1]).value, 0) = 1)
else
if (GString(child[j]).value = 'mail') then
mud.mail := (StrToIntDef(GString(child[j + 1]).value, 0) = 1)
else
if (GString(child[j]).value = 'file') then
mud.mfile := (StrToIntDef(GString(child[j + 1]).value, 0) = 1)
else
if (GString(child[j]).value = 'auth') then
mud.auth := (StrToIntDef(GString(child[j + 1]).value, 0) = 1)
else
if (GString(child[j]).value = 'ucache') then
mud.ucache := (StrToIntDef(GString(child[j + 1]).value, 0) = 1)
else
if (GString(child[j]).value = 'http') then
mud.http := StrToIntDef(GString(child[j + 1]).value, 0)
else
if (GString(child[j]).value = 'ftp') then
mud.ftp := StrToIntDef(GString(child[j + 1]).value, 0)
else
if (GString(child[j]).value = 'nntp') then
mud.nntp := StrToIntDef(GString(child[j + 1]).value, 0)
else
if (GString(child[j]).value = 'smtp') then
mud.smtp := StrToIntDef(GString(child[j + 1]).value, 0)
else
if (GString(child[j]).value = 'rcp') then
mud.rcp := StrToIntDef(GString(child[j + 1]).value, 0)
else
if (GString(child[j]).value = 'amrcp') then
mud.amrcp := StrToIntDef(GString(child[j + 1]).value, 0);
inc(j, 2);
end;
end;
end;
inc(i, 2);
end;
end;
procedure GInterMud.handleChanList(packet : GPacket_I3);
var
chan : GChannel_I3;
name : string;
i : integer;
child, list : TList;
begin
list := TList(packet.fields[7]);
i := 0;
while (i < list.count) do
begin
name := GString(list[i]).value;
chan := GChannel_I3(chanList.get(name));
if (chan = nil) then
begin
chan := GChannel_I3.Create();
chan.I3_name := name;
chanList.put(chan.I3_name, chan);
debug('New channel: ' + name, 2);
end
else
debug('Updating channel: ' + name, 2);
child := TList(list[i + 1]);
chan.host_mud := GString(child[0]).value;
chan.status := StrToIntDef(GString(child[1]).value, 0);
inc(i, 2);
end;
end;
procedure GInterMud.handleChannelMessage(packet : GPacket_I3);
var
channel_name, visname, message, text : string;
channel : GChannel_I3;
begin
channel_name := GString(packet.fields[6]).value;
visname := GString(packet.fields[7]).value;
message := GString(packet.fields[8]).value;
text := Format('[%s] %s@%s: %s$7', [channel_name, visname, packet.originator_mudname, message]);
channel := GChannel_I3(chanList[channel_name]);
if (channel <> nil) then
channel.updateHistory(text);
to_channel(nil, text, CHANNEL_ALL, AT_ECHO);
end;
procedure GInterMud.handleChannelEmote(packet : GPacket_I3);
var
channel_name, visname, message, text : string;
channel : GChannel_I3;
begin
channel_name := GString(packet.fields[6]).value;
visname := GString(packet.fields[7]).value;
message := GString(packet.fields[8]).value;
visname := Format('%s@%s', [visname, packet.originator_mudname]);
message := FastReplace(message, '$N', visname);
text := Format('[%s] %s$7', [channel_name, message]);
channel := GChannel_I3(chanList[channel_name]);
if (channel <> nil) then
channel.updateHistory(text);
to_channel(nil, text, CHANNEL_ALL, AT_ECHO);
end;
procedure GInterMud.handleLocateRequest(packet : GPacket_I3);
var
username : string;
pl : GCharacter;
begin
username := GString(packet.fields[6]).value;
if (existsPlayer(username)) then
begin
pl := findPlayerWorldEx(nil, username);
writeHeader('locate-reply', this_mud.name, '', packet.originator_mudname, packet.originator_username);
writeBuffer('"');
writeBuffer(this_mud.name);
writeBuffer('","');
writeBuffer(pl.name);
writeBuffer('",0,"');
if (pl <> nil) then
writeBuffer('Online')
else
writeBuffer('Offline');
writeBuffer('",})'#13);
sendPacket();
end;
end;
procedure GInterMud.handleLocateReply(packet : GPacket_I3);
var
mudname, visname, status : string;
pl : GPlayer;
begin
pl := GPlayer(findPlayerWorldEx(nil, packet.target_username));
mudname := GString(packet.fields[6]).value;
visname := GString(packet.fields[7]).value;
status := GString(packet.fields[9]).value;
if (pl = nil) then
begin
if (not existsPlayer(packet.target_username)) then
sendError(packet.originator_mudname, packet.originator_username, 'unk-user', 'No such player.')
else
sendError(packet.originator_mudname, packet.originator_username, 'unk-user', 'That player is offline.');
exit;
end;
pl.sendBuffer('Player "' + visname + '" was located on "' + mudname + '" (' + status + ').'#13#10);
end;
procedure GInterMud.handleTell(packet : GPacket_I3);
var
visname, msg : string;
pl : GPlayer;
begin
pl := GPlayer(findPlayerWorldEx(nil, packet.target_username));
visname := GString(packet.fields[6]).value;
msg := GString(packet.fields[7]).value;
if (pl = nil) then
begin
if (not existsPlayer(packet.target_username)) then
sendError(packet.originator_mudname, packet.originator_username, 'unk-user', 'No such player.')
else
sendError(packet.originator_mudname, packet.originator_username, 'unk-user', 'That player is offline.');
exit;
end;
if ((pl.fields['i3flag'] as GBitVector).isBitSet(I3_TELL)) then
begin
sendError(packet.originator_mudname, packet.originator_username, 'unk-user', pl.name + ' is not accepting tells.');
exit;
end;
pl.sendBuffer(Format('%s@%s tells you: %s' + #13#10, [visname, packet.originator_mudname, msg]))
end;
procedure GInterMud.handleBeep(packet : GPacket_I3);
var
visname : string;
pl : GPlayer;
begin
pl := GPlayer(findPlayerWorldEx(nil, packet.target_username));
visname := GString(packet.fields[6]).value;
if (pl = nil) then
begin
if (not existsPlayer(packet.target_username)) then
sendError(packet.originator_mudname, packet.originator_username, 'unk-user', 'No such player.')
else
sendError(packet.originator_mudname, packet.originator_username, 'unk-user', 'That player is offline.');
exit;
end;
if ((pl.fields['i3flag'] as GBitVector).isBitSet(I3_BEEP)) then
begin
sendError(packet.originator_mudname, packet.originator_username, 'unk-user', pl.name + ' is not accepting beeps.');
exit;
end;
pl.sendBuffer(Format('%s@%s beeps you.'#7 + #13#10, [visname, packet.originator_mudname]))
end;
procedure GInterMud.handleWhoReq(packet : GPacket_I3);
var
conn : GPlayerConnection;
iterator : GIterator;
begin
writeHeader('who-reply', this_mud.name, '', packet.originator_mudname, packet.originator_username);
writeBuffer('({');
iterator := connection_list.iterator();
while (iterator.hasNext()) do
begin
conn := GPlayerConnection(iterator.next());
if (conn.isPlaying()) and (not conn.ch.IS_INVIS) then
writeBuffer('({"' + escape(conn.ch.name) + '",0,"",}),');
end;
iterator.Free();
writeBuffer('}),})'#13);
sendPacket();
end;
procedure GInterMud.handleWhoReply(packet : GPacket_I3);
var
pl : GPlayer;
list, child : TList;
i : integer;
name, title : string;
begin
pl := GPlayer(findPlayerWorldEx(nil, packet.target_username));
if (pl = nil) then
begin
if (not existsPlayer(packet.target_username)) then
sendError(packet.originator_mudname, packet.originator_username, 'unk-user', 'No such player.')
else
sendError(packet.originator_mudname, packet.originator_username, 'unk-user', 'That player is offline.');
exit;
end;
list := TList(packet.fields[6]);
i := 0;
pl.sendBuffer('Who list from "' + packet.originator_mudname + '":'#13#10#13#10);
while (i < list.count) do
begin
child := TList(list[i]);
name := GString(child[0]).value;
title := GString(child[2]).value;
sendToPlayer(pl, Format('%s %s' + #13#10, [name, title]));
inc(i);
end;
end;
procedure GInterMud.handleFingerReq(packet : GPacket_I3);
var
username : string;
pl : GPlayer;
begin
username := GString(packet.fields[6]).value;
pl := GPlayer(findPlayerWorldEx(nil, username));
if (pl = nil) then
begin
if (not existsPlayer(username)) then
sendError(packet.originator_mudname, packet.originator_username, 'unk-user', 'No such player.')
else
sendError(packet.originator_mudname, packet.originator_username, 'unk-user', 'That player is offline.');
exit;
end;
if (pl.IS_INVIS) then
begin
sendError(packet.originator_mudname, packet.originator_username, 'unk-user', 'That player is offline.');
exit;
end;
if ((pl.fields['i3flag'] as GBitVector).isBitSet(I3_DENYFINGER)) or ((pl.fields['i3flag'] as GBitVector).isBitSet(I3_PRIVACY)) then
begin
sendError(packet.originator_mudname, packet.originator_username, 'unk-user', pl.name + ' is not accepting fingers.');
exit;
end;
pl.sendBuffer(Format('%s@%s just requested your i3 finger information.'#13#10, [packet.originator_mudname, packet.originator_username]));
writeHeader('finger-reply', this_mud.name, '', packet.originator_mudname, packet.originator_username);
writeBuffer('"');
writeBuffer(escape(pl.name));
writeBuffer('","');
writeBuffer(escape(pl.name + ' ' + pl.title));
writeBuffer('","","');
// No email info in Grendel (yet)
writeBuffer('Not supported');
writeBuffer('","');
writeBuffer('-1');
writeBuffer('",');
writeBuffer('-1');
writeBuffer(',"');
writeBuffer('[PRIVATE]');
writeBuffer('","');
if (pl.IS_IMMORT) then
writeBuffer(imm_types[pl.level])
else
writeBuffer(pl.rank);
writeBuffer('","Not supported",})'#13);
sendPacket();
end;
procedure GInterMud.handleFingerReply(packet : GPacket_I3);
var
pl : GPlayer;
visname, title, realname, email, last, level, extra : string;
begin
visname := GString(packet.fields[6]).value;
title := GString(packet.fields[7]).value;
realname := GString(packet.fields[8]).value;
email := GString(packet.fields[9]).value;
last := GString(packet.fields[10]).value;
level := GString(packet.fields[13]).value;
extra := GString(packet.fields[14]).value;
pl := GPlayer(findPlayerWorldEx(nil, packet.target_username));
if (pl = nil) then
begin
if (not existsPlayer(packet.target_username)) then
sendError(packet.originator_mudname, packet.originator_username, 'unk-user', 'No such player.')
else
sendError(packet.originator_mudname, packet.originator_username, 'unk-user', 'That player is offline.');
exit;
end;
sendToPlayer(pl, Format('I3 finger information for %s@%s:'#13#10#13#10, [visname, packet.originator_mudname]));
sendToPlayer(pl, 'Title: ' + title + #13#10);
sendToPlayer(pl, 'Real name: ' + realname + #13#10);
sendToPlayer(pl, 'Level: ' + level + #13#10);
sendToPlayer(pl, 'E-mail: ' + email + #13#10);
sendToPlayer(pl, 'Extra info: ' + extra + #13#10);
sendToPlayer(pl, 'Last on: ' + last + #13#10);
end;
procedure GInterMud.handlePacket(packet : GPacket_I3);
begin
if (packet.packet_type = 'startup-reply') then
handleStartupReply(packet)
else
if (packet.packet_type = 'mudlist') then
handleMudList(packet)
else
if (packet.packet_type = 'chanlist-reply') then
handleChanList(packet)
else
if (packet.packet_type = 'channel-m') then
handleChannelMessage(packet)
else
if (packet.packet_type = 'channel-e') then
handleChannelEmote(packet)
else
if (packet.packet_type = 'locate-req') then
handleLocateRequest(packet)
else
if (packet.packet_type = 'locate-reply') then
handleLocateReply(packet)
else
if (packet.packet_type = 'tell') then
handleTell(packet)
else
if (packet.packet_type = 'beep') then
handleBeep(packet)
else
if (packet.packet_type = 'who-req') then
handleWhoReq(packet)
else
if (packet.packet_type = 'who-reply') then
handleWhoReply(packet)
else
if (packet.packet_type = 'finger-req') then
handleFingerReq(packet)
else
if (packet.packet_type = 'finger-reply') then
handleFingerReply(packet)
else
if (packet.packet_type = 'error') then
handleError(packet)
else
begin
debug('unknown packet "' + packet.packet_type + '"', 0);
debug(packet.toString(), 0);
end;
end;
procedure GInterMud.shutdown();
begin
saveMudList();
saveChanList();
writeHeader('shutdown', this_mud.name, '', router.name, '');
writeBuffer('0');
writeBuffer(',})' + #13);
sendPacket();
end;
procedure GInterMud.Execute();
var
ret : integer;
size : integer;
msg : string;
buf : array[0..MAX_READ - 1] of char;
begin
Sleep(2500);
inputPointer := 0;
if (this_mud.name = 'Your Mud Name Here') then
begin
writeConsole('I3: Refusing to connect with default values. Please change ' + I3_CONFIG_FILE);
Terminate();
end;
if (this_mud.preferredRouter = nil) then
begin
writeConsole('I3: Impossible to connect to non-existing router');
exit;
end;
router := this_mud.preferredRouter;
if (this_mud.autoconnect) then
connect();
while (not Terminated) do
begin
if (_wait > 0) then
dec(_wait);
Sleep(100);
try
if (not connected) and (_wait = 1) then
begin
debug('Trying to connect to ' + router.name);
if (socket.connect(router.ipaddress, router.port)) then
begin
writeConsole('I3: Connected to ' + router.ipaddress + ' port ' + IntToStr(router.port));
connected := true;
startup();
end
else
begin
writeConsole('I3: Could not connect to ' + router.ipaddress + ' port ' + IntToStr(router.port));
inc(reconattempts);
if (reconattempts <= 5) then
_wait := 10
else
if (reconattempts <= 20) then
_wait := 500
else
begin
_wait := -2; { Abandon attempts - probably an ISP failure anyway if this happens :) }
writeConsole('Abandoning attempts to reconnect to Intermud-3 router. Too many failures.');
end;
end;
end
else
if (connected) then
begin
if (socket.canRead()) then
begin
ret := socket.read(buf, MAX_READ);
if (ret > 0) then
begin
if (inputPointer + ret > MAX_IPS) then
debug('Buffer is growing beyond ' + IntToStr(MAX_IPS), 0);
//debug('Read ' + IntToStr(ret) + ' bytes');
StrMove(@inputBuffer[inputPointer], @buf[0], ret);
inc(inputPointer, ret);
end;
end;
if (inputPointer > 0) then
begin
StrMove(@size, @inputBuffer[0], 4);
size := ntohl(size);
//debug('Need ' + IntToStr(size + 4) + ' bytes, currently ' + IntToStr(inputPointer) + ' in buffer');
{ SetLength(msg, inputPointer);
StrMove(@msg[1], @inputBuffer[4], inputPointer);
for ret := 1 to inputPointer do
if (msg[ret] = #0) then
msg[ret] := ' ';
//debug('Packet received so far: ' + msg); }
if (inputPointer >= size + 4) then
begin
SetLength(msg, size);
for ret := 4 to size + 4 do
if (inputBuffer[ret] = #10) then
inputBuffer[ret] := ' ';
StrMove(@msg[1], @inputBuffer[4], size);
packet := parsePacket(msg);
debug(msg, 2);
debug(packet.toString(), 2);
debug('Got packet: ' + packet.packet_type, 1);
debug('Removing head ' + IntToStr(size + 4) + ' bytes from buffer', 2);
StrMove(@inputBuffer[0], @inputBuffer[size+4], inputPointer - (size + 4));
dec(inputPointer, size + 4);
debug('Pointer at ' + IntToStr(inputPointer), 2);
handlePacket(packet);
packet.Free();
end;
end;
end;
except
on E : Exception do
begin
debug(E.Message);
connected := socket.isValid();
if (not connected) then
begin
debug('Connection lost, waiting for reconnect');
_wait := 500;
end;
end;
end;
end;
if (connected) then
disconnect();
end;
// void I3_send_error( char *mud, char *user, char *code, char *message )
procedure GInterMud.sendError(mud, user, code, msg : string);
begin
writeHeader('error', this_mud.name, '', mud, user);
writeBuffer('"');
writeBuffer(code);
writeBuffer('","');
writeBuffer(msg);
writeBuffer('",0,})'#13);
sendPacket();
end;
// void I3_send_channel_message( I3_CHANNEL *channel, char *name, char *message )
procedure GInterMud.sendChannelMessage(channel : GChannel_I3; name, msg : string);
begin
writeHeader('channel-m', this_mud.name, name, '', '');
writeBuffer('"');
writeBuffer(channel.I3_name);
writeBuffer('","');
writeBuffer(name);
writeBuffer('","');
writeBuffer(escape(msg));
writeBuffer('",})'#13);
sendPacket();
end;
// void I3_send_channel_emote( I3_CHANNEL *channel, char *name, char *message )
procedure GInterMud.sendChannelEmote(channel : GChannel_I3; name, msg : string);
begin
if (Pos('$N', msg) = 0) then
msg := '$N ' + msg;
writeHeader('channel-e', this_mud.name, name, '', '');
writeBuffer('"');
writeBuffer(channel.I3_name);
writeBuffer('","');
writeBuffer(name);
writeBuffer('","');
writeBuffer(escape(msg));
writeBuffer('",})'#13);
sendPacket();
end;
// void I3_send_channel_t( I3_CHANNEL *channel, char *name, char *tmud, char *tuser, char *msg_o, char *msg_t, char *tvis )
procedure GInterMud.sendChannelTarget(channel : GChannel_I3; name, tmud, tuser, msg_o, msg_t, tvis : string);
begin
writeHeader('channel-t', this_mud.name, name, '', '');
writeBuffer('"');
writeBuffer(channel.I3_name);
writeBuffer('","');
writeBuffer(tmud);
writeBuffer('","');
writeBuffer(tuser);
writeBuffer('","');
writeBuffer(escape(msg_o));
writeBuffer('","');
writeBuffer(escape(msg_t));
writeBuffer('","');
writeBuffer(name);
writeBuffer('","');
writeBuffer(tvis);
writeBuffer('",})'#13);
sendPacket();
end;
// void I3_send_channel_listen( I3_CHANNEL *channel, bool lconnect )
procedure GInterMud.sendChannelListen(user : string; channel : GChannel_I3; lconnect : boolean);
begin
writeHeader('channel-listen', this_mud.name, user, router.name, '');
writeBuffer('"');
writeBuffer(channel.I3_name);
writeBuffer('",');
if (lconnect) then
writeBuffer('1,})'#13)
else
writeBuffer('0,})'#13);
sendPacket();
end;
// void I3_send_locate( CHAR_DATA *ch, char *user )
procedure GInterMud.sendLocateRequest(originator, user : string);
begin
writeHeader('locate-req', this_mud.name, originator, '', '');
writeBuffer('"');
writeBuffer(user);
writeBuffer('",})'#13);
sendPacket();
end;
// void I3_send_tell( CHAR_DATA *ch, char *to, I3_MUD *mud, char *message )
procedure GInterMud.sendTell(from_user, to_user : string; mud : GMud_I3; msg : string);
begin
writeHeader('tell', this_mud.name, from_user, mud.name, escape(to_user));
writeBuffer('"');
writeBuffer(from_user);
writeBuffer('","');
writeBuffer(escape(msg));
writeBuffer('",})'#13);
sendPacket();
end;
// void I3_send_beep( CHAR_DATA *ch, char *to, I3_MUD *mud )
procedure GInterMud.sendBeep(from_user, to_user : string; mud : GMud_I3);
begin
writeHeader('beep', this_mud.name, from_user, mud.name, to_user);
writeBuffer('"');
writeBuffer(from_user);
writeBuffer('",})'#13);
sendPacket();
end;
// void I3_send_who( CHAR_DATA *ch, char *mud )
procedure GInterMud.sendWhoReq(from_user : string; mud : GMud_I3);
begin
writeHeader('who-req', this_mud.name, from_user, mud.name, '');
writeBuffer('})'#13);
sendPacket();
end;
// void I3_send_finger( CHAR_DATA *ch, char *user, char *mud )
procedure GInterMud.sendFingerReq(from_user, to_user : string; mud : GMud_I3);
begin
writeHeader('finger-req', this_mud.name, from_user, mud.name, '');
writeBuffer('"');
writeBuffer(escape(to_user));
writeBuffer('",');
writeBuffer('})'#13);
sendPacket();
end;
procedure GInterMud.debug(msg : string; level : integer = 1);
begin
if (level <= debugLevel) then
writeConsole('I3: ' + msg);
end;
procedure GInterMud.setDebugLevel(debugLevel : integer = 0);
begin
Self.debugLevel := debugLevel;
end;
end.