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>
|
||||
</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>
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue