mirror of https://github.com/buggins/dlangui.git
irc client fixes
This commit is contained in:
parent
437391c7de
commit
6d0c8d83b3
|
@ -409,6 +409,12 @@
|
||||||
<filesToClean>*.obj;*.cmd;*.build;*.json;*.dep</filesToClean>
|
<filesToClean>*.obj;*.cmd;*.build;*.json;*.dep</filesToClean>
|
||||||
</Config>
|
</Config>
|
||||||
<Folder name="d3d">
|
<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" />
|
<File path="src\d3d.d" />
|
||||||
</Folder>
|
</Folder>
|
||||||
</DProject>
|
</DProject>
|
||||||
|
|
|
@ -2,8 +2,10 @@ module ircclient.net.client;
|
||||||
|
|
||||||
public import dlangui.core.asyncsocket;
|
public import dlangui.core.asyncsocket;
|
||||||
import dlangui.core.logger;
|
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.conv : to;
|
||||||
|
import std.utf : toUTF32, toUTF8;
|
||||||
|
|
||||||
interface IRCClientCallback {
|
interface IRCClientCallback {
|
||||||
void onIRCConnect(IRCClient client);
|
void onIRCConnect(IRCClient client);
|
||||||
|
@ -16,6 +18,10 @@ interface IRCClientCallback {
|
||||||
|
|
||||||
enum IRCCommand : int {
|
enum IRCCommand : int {
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
|
CHANNEL_TOPIC = 332,
|
||||||
|
CHANNEL_TOPIC_SET_BY = 333,
|
||||||
|
CHANNEL_NAMES_LIST = 353,
|
||||||
|
CHANNEL_NAMES_LIST_END = 366,
|
||||||
USER = 1000,
|
USER = 1000,
|
||||||
PRIVMSG, // :source PRIVMSG <target> :Message
|
PRIVMSG, // :source PRIVMSG <target> :Message
|
||||||
NOTICE, // :source NOTICE <target> :Message
|
NOTICE, // :source NOTICE <target> :Message
|
||||||
|
@ -101,6 +107,16 @@ class IRCMessage {
|
||||||
if (params.length > 0)
|
if (params.length > 0)
|
||||||
target = params[0];
|
target = params[0];
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -114,6 +130,8 @@ class IRCAddress {
|
||||||
string channel;
|
string channel;
|
||||||
string nick;
|
string nick;
|
||||||
string username;
|
string username;
|
||||||
|
this() {
|
||||||
|
}
|
||||||
this(string s) {
|
this(string s) {
|
||||||
full = s;
|
full = s;
|
||||||
string s1 = parseDelimitedParameter(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
|
/// IRC Client connection implementation
|
||||||
class IRCClient : AsyncSocketCallback {
|
class IRCClient : AsyncSocketCallback {
|
||||||
protected:
|
protected:
|
||||||
|
@ -143,6 +230,7 @@ protected:
|
||||||
string _host;
|
string _host;
|
||||||
ushort _port;
|
ushort _port;
|
||||||
string _nick;
|
string _nick;
|
||||||
|
IRCChannel[string] _channels;
|
||||||
void onDataReceived(AsyncSocket socket, ubyte[] data) {
|
void onDataReceived(AsyncSocket socket, ubyte[] data) {
|
||||||
_readbuf ~= cast(char[])data;
|
_readbuf ~= cast(char[])data;
|
||||||
// split by lines
|
// split by lines
|
||||||
|
@ -182,6 +270,16 @@ protected:
|
||||||
case NOTICE:
|
case NOTICE:
|
||||||
_callback.onIRCNotice(this, msg.sourceAddress, msg.target, msg.message);
|
_callback.onIRCNotice(this, msg.sourceAddress, msg.target, msg.message);
|
||||||
break;
|
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:
|
default:
|
||||||
_callback.onIRCMessage(this, msg);
|
_callback.onIRCMessage(this, msg);
|
||||||
break;
|
break;
|
||||||
|
@ -206,6 +304,23 @@ public:
|
||||||
if (_socket)
|
if (_socket)
|
||||||
destroy(_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 string host() { return _host; }
|
||||||
@property ushort port() { return _port; }
|
@property ushort port() { return _port; }
|
||||||
@property string hostPort() { return "%s:%d".format(_host, _port); }
|
@property string hostPort() { return "%s:%d".format(_host, _port); }
|
||||||
|
|
|
@ -207,21 +207,32 @@ class IRCFrame : AppFrame, IRCClientCallback {
|
||||||
|
|
||||||
void onIRCMessage(IRCClient client, IRCMessage message) {
|
void onIRCMessage(IRCClient client, IRCMessage message) {
|
||||||
IRCWindow w = getOrCreateWindowFor(client.hostPort);
|
IRCWindow w = getOrCreateWindowFor(client.hostPort);
|
||||||
if (message.commandId < 1000) {
|
switch (message.commandId) with (IRCCommand) {
|
||||||
// custom server messages
|
case JOIN:
|
||||||
w.addLine(message.message);
|
case PART:
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (message.commandId == IRCCommand.JOIN || message.commandId == IRCCommand.PART) {
|
|
||||||
if (message.sourceAddress && !message.sourceAddress.nick.empty && message.target.startsWith("#")) {
|
if (message.sourceAddress && !message.sourceAddress.nick.empty && message.target.startsWith("#")) {
|
||||||
w = getOrCreateWindowFor(message.target);
|
w = getOrCreateWindowFor(message.target);
|
||||||
if (message.commandId == IRCCommand.JOIN) {
|
if (message.commandId == JOIN) {
|
||||||
w.addLine("* " ~ message.sourceAddress.longName ~ " has joined " ~ message.target);
|
w.addLine("* " ~ message.sourceAddress.longName ~ " has joined " ~ message.target);
|
||||||
} else {
|
} else {
|
||||||
w.addLine("* " ~ message.sourceAddress.longName ~ " has left " ~ message.target ~ (message.message.empty ? "" : ("(Reason: " ~ message.message ~ ")")));
|
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);
|
w.addLine(message.msg);
|
||||||
}
|
}
|
||||||
|
@ -258,7 +269,7 @@ class IRCWindow : VerticalLayout, EditorActionHandler {
|
||||||
_listBox.minWidth = 100;
|
_listBox.minWidth = 100;
|
||||||
_listBox.maxWidth = 200;
|
_listBox.maxWidth = 200;
|
||||||
_listBox.orientation = Orientation.Vertical;
|
_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(new ResizerWidget(null, Orientation.Horizontal));
|
||||||
hlayout.addChild(_listBox);
|
hlayout.addChild(_listBox);
|
||||||
_kind = IRCWindowKind.Channel;
|
_kind = IRCWindowKind.Channel;
|
||||||
|
@ -278,6 +289,10 @@ class IRCWindow : VerticalLayout, EditorActionHandler {
|
||||||
if (visible)
|
if (visible)
|
||||||
window.update();
|
window.update();
|
||||||
}
|
}
|
||||||
|
void updateUserList(IRCChannel channel) {
|
||||||
|
_listBox.items = channel.userNames;
|
||||||
|
window.update();
|
||||||
|
}
|
||||||
bool onEditorAction(const Action action) {
|
bool onEditorAction(const Action action) {
|
||||||
if (!_editLine.text.empty) {
|
if (!_editLine.text.empty) {
|
||||||
string s = toUTF8(_editLine.text);
|
string s = toUTF8(_editLine.text);
|
||||||
|
@ -288,8 +303,8 @@ class IRCWindow : VerticalLayout, EditorActionHandler {
|
||||||
string cmd = parseDelimitedParameter(s);
|
string cmd = parseDelimitedParameter(s);
|
||||||
|
|
||||||
if (cmd == "/quit") {
|
if (cmd == "/quit") {
|
||||||
_client.quit(param);
|
_client.quit(s);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
string param = parseDelimitedParameter(s);
|
string param = parseDelimitedParameter(s);
|
||||||
|
@ -303,6 +318,7 @@ class IRCWindow : VerticalLayout, EditorActionHandler {
|
||||||
_client.privMsg(param, s);
|
_client.privMsg(param, s);
|
||||||
} else {
|
} else {
|
||||||
Log.d("Unknown command: " ~ cmd);
|
Log.d("Unknown command: " ~ cmd);
|
||||||
|
addLine("Supported commands: /nick /join /part /msg /quit");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// message
|
// message
|
||||||
|
|
Loading…
Reference in New Issue