irc client fixes

This commit is contained in:
Vadim Lopatin 2016-03-15 15:41:52 +03:00
parent 437391c7de
commit 6d0c8d83b3
3 changed files with 155 additions and 18 deletions

View File

@ -409,6 +409,12 @@
<filesToClean>*.obj;*.cmd;*.build;*.json;*.dep</filesToClean>
</Config>
<Folder name="d3d">
<Folder name="dminer">
<Folder name="core">
<File path="src\dminer\core\minetypes.d" />
<File path="src\dminer\core\world.d" />
</Folder>
</Folder>
<File path="src\d3d.d" />
</Folder>
</DProject>

View File

@ -2,8 +2,10 @@ module ircclient.net.client;
public import dlangui.core.asyncsocket;
import dlangui.core.logger;
import std.string : empty, format;
import dlangui.core.collections;
import std.string : empty, format, startsWith;
import std.conv : to;
import std.utf : toUTF32, toUTF8;
interface IRCClientCallback {
void onIRCConnect(IRCClient client);
@ -16,6 +18,10 @@ interface IRCClientCallback {
enum IRCCommand : int {
UNKNOWN,
CHANNEL_TOPIC = 332,
CHANNEL_TOPIC_SET_BY = 333,
CHANNEL_NAMES_LIST = 353,
CHANNEL_NAMES_LIST_END = 366,
USER = 1000,
PRIVMSG, // :source PRIVMSG <target> :Message
NOTICE, // :source NOTICE <target> :Message
@ -101,6 +107,16 @@ class IRCMessage {
if (params.length > 0)
target = params[0];
break;
case CHANNEL_TOPIC:
case CHANNEL_TOPIC_SET_BY:
case CHANNEL_NAMES_LIST_END:
if (params.length > 1)
target = params[1];
break;
case CHANNEL_NAMES_LIST:
if (params.length > 2 && params[1] == "=")
target = params[2];
break;
default:
break;
}
@ -114,6 +130,8 @@ class IRCAddress {
string channel;
string nick;
string username;
this() {
}
this(string s) {
full = s;
string s1 = parseDelimitedParameter(s, '!');
@ -134,6 +152,75 @@ class IRCAddress {
}
}
class IRCUser {
string nick;
int flags;
this(string s) {
nick = s;
}
}
class UserList {
Collection!IRCUser _users;
@property int length() { return _users.length; }
@property IRCUser opIndex(int index) { return _users[index]; }
void fromList(string userList) {
_users.clear();
for(;;) {
string s = parseDelimitedParameter(userList);
if (s.empty)
break;
IRCUser u = new IRCUser(s);
_users.add(u);
}
}
}
class IRCChannel {
string name;
string topic;
string topicSetBy;
long topicSetWhen;
UserList users;
this(string name) {
this.name = name;
users = new UserList();
}
char[] userListBuffer;
void setUserList(string userList) {
users.fromList(userList);
}
@property dstring[] userNames() {
dstring[] res;
for(int i = 0; i < users.length; i++) {
res ~= toUTF32(users[i].nick);
}
return res;
}
void handleMessage(IRCMessage msg) {
switch (msg.commandId) with (IRCCommand) {
case CHANNEL_TOPIC:
topic = msg.message;
break;
case CHANNEL_TOPIC_SET_BY:
topicSetBy = msg.params.length == 3 ? msg.params[1] : null;
break;
case CHANNEL_NAMES_LIST:
if (userListBuffer.length > 0)
userListBuffer ~= " ";
userListBuffer ~= msg.message;
break;
case CHANNEL_NAMES_LIST_END:
setUserList(userListBuffer.dup);
Log.d("user list for " ~ name ~ " : " ~ userListBuffer);
userListBuffer = null;
break;
default:
break;
}
}
}
/// IRC Client connection implementation
class IRCClient : AsyncSocketCallback {
protected:
@ -143,6 +230,7 @@ protected:
string _host;
ushort _port;
string _nick;
IRCChannel[string] _channels;
void onDataReceived(AsyncSocket socket, ubyte[] data) {
_readbuf ~= cast(char[])data;
// split by lines
@ -182,6 +270,16 @@ protected:
case NOTICE:
_callback.onIRCNotice(this, msg.sourceAddress, msg.target, msg.message);
break;
case CHANNEL_TOPIC:
case CHANNEL_TOPIC_SET_BY:
case CHANNEL_NAMES_LIST:
case CHANNEL_NAMES_LIST_END:
if (msg.target.startsWith("#")) {
auto channel = channelByName(msg.target, true);
channel.handleMessage(msg);
_callback.onIRCMessage(this, msg);
}
break;
default:
_callback.onIRCMessage(this, msg);
break;
@ -206,6 +304,23 @@ public:
if (_socket)
destroy(_socket);
}
IRCChannel removeChannel(string name) {
if (auto p = name in _channels) {
_channels.remove(name);
return *p;
}
return null;
}
IRCChannel channelByName(string name, bool createIfNotExist = false) {
if (auto p = name in _channels) {
return *p;
}
if (!createIfNotExist)
return null;
IRCChannel res = new IRCChannel(name);
_channels[name] = res;
return res;
}
@property string host() { return _host; }
@property ushort port() { return _port; }
@property string hostPort() { return "%s:%d".format(_host, _port); }

View File

@ -207,21 +207,32 @@ class IRCFrame : AppFrame, IRCClientCallback {
void onIRCMessage(IRCClient client, IRCMessage message) {
IRCWindow w = getOrCreateWindowFor(client.hostPort);
if (message.commandId < 1000) {
// custom server messages
w.addLine(message.message);
return;
}
if (message.commandId == IRCCommand.JOIN || message.commandId == IRCCommand.PART) {
if (message.sourceAddress && !message.sourceAddress.nick.empty && message.target.startsWith("#")) {
w = getOrCreateWindowFor(message.target);
if (message.commandId == IRCCommand.JOIN) {
w.addLine("* " ~ message.sourceAddress.longName ~ " has joined " ~ message.target);
} else {
w.addLine("* " ~ message.sourceAddress.longName ~ " has left " ~ message.target ~ (message.message.empty ? "" : ("(Reason: " ~ message.message ~ ")")));
switch (message.commandId) with (IRCCommand) {
case JOIN:
case PART:
if (message.sourceAddress && !message.sourceAddress.nick.empty && message.target.startsWith("#")) {
w = getOrCreateWindowFor(message.target);
if (message.commandId == JOIN) {
w.addLine("* " ~ message.sourceAddress.longName ~ " has joined " ~ message.target);
} else {
w.addLine("* " ~ message.sourceAddress.longName ~ " has left " ~ message.target ~ (message.message.empty ? "" : ("(Reason: " ~ message.message ~ ")")));
}
}
}
return;
return;
case CHANNEL_NAMES_LIST_END:
if (message.target.startsWith("#")) {
w = getOrCreateWindowFor(message.target);
IRCChannel channel = _client.channelByName(message.target);
w.updateUserList(channel);
}
return;
default:
if (message.commandId < 1000) {
// custom server messages
w.addLine(message.message);
return;
}
break;
}
w.addLine(message.msg);
}
@ -258,7 +269,7 @@ class IRCWindow : VerticalLayout, EditorActionHandler {
_listBox.minWidth = 100;
_listBox.maxWidth = 200;
_listBox.orientation = Orientation.Vertical;
_listBox.items = ["Nick1"d, "Nick2"d];
//_listBox.items = ["Nick1"d, "Nick2"d];
hlayout.addChild(new ResizerWidget(null, Orientation.Horizontal));
hlayout.addChild(_listBox);
_kind = IRCWindowKind.Channel;
@ -278,6 +289,10 @@ class IRCWindow : VerticalLayout, EditorActionHandler {
if (visible)
window.update();
}
void updateUserList(IRCChannel channel) {
_listBox.items = channel.userNames;
window.update();
}
bool onEditorAction(const Action action) {
if (!_editLine.text.empty) {
string s = toUTF8(_editLine.text);
@ -288,8 +303,8 @@ class IRCWindow : VerticalLayout, EditorActionHandler {
string cmd = parseDelimitedParameter(s);
if (cmd == "/quit") {
_client.quit(param);
return;
_client.quit(s);
return true;
}
string param = parseDelimitedParameter(s);
@ -303,6 +318,7 @@ class IRCWindow : VerticalLayout, EditorActionHandler {
_client.privMsg(param, s);
} else {
Log.d("Unknown command: " ~ cmd);
addLine("Supported commands: /nick /join /part /msg /quit");
}
} else {
// message