summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core.h8
-rw-r--r--netcore.cpp6
-rw-r--r--python_client.py126
-rw-r--r--window.cpp116
4 files changed, 248 insertions, 8 deletions
diff --git a/core.h b/core.h
index 2696032..7d2f052 100644
--- a/core.h
+++ b/core.h
@@ -155,9 +155,15 @@ struct Packet {
B2C_WINDOW_ADD = 0x100,
B2C_WINDOW_REMOVE = 0x101,
B2C_WINDOW_MESSAGE = 0x102,
+ B2C_WINDOW_RENAME = 0x103,
C2B_WINDOW_INPUT = 0x102,
+ B2C_CHANNEL_USER_ADD = 0x120,
+ B2C_CHANNEL_USER_REMOVE = 0x121,
+ B2C_CHANNEL_USER_RENAME = 0x122,
+ B2C_CHANNEL_USER_MODES = 0x123,
+
C2B_OOB_LOGIN = 0x8001,
B2C_OOB_LOGIN_SUCCESS = 0x8001,
@@ -317,6 +323,8 @@ public:
int clientCount;
int serverCount;
+ void sendToClients(Packet::Type type, const Buffer &data);
+
std::list<Window *> windows;
int nextWindowID;
diff --git a/netcore.cpp b/netcore.cpp
index 4341787..7082f9b 100644
--- a/netcore.cpp
+++ b/netcore.cpp
@@ -296,6 +296,12 @@ Window *NetCore::findWindow(int id) const {
}
+void NetCore::sendToClients(Packet::Type type, const Buffer &data) {
+ for (int i = 0; i < clientCount; i++)
+ if (clients[i]->isAuthed())
+ clients[i]->sendPacket(type, data);
+}
+
Client *Bouncer::constructClient() {
diff --git a/python_client.py b/python_client.py
index 88ac307..39411c5 100644
--- a/python_client.py
+++ b/python_client.py
@@ -137,6 +137,7 @@ class WindowTab(QtWidgets.QWidget):
self.input = QtWidgets.QLineEdit(self)
self.input.returnPressed.connect(self.handleLineEntered)
+ def makeLayout(self):
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.output)
layout.addWidget(self.input)
@@ -160,6 +161,105 @@ class WindowTab(QtWidgets.QWidget):
if isAtEnd:
self.output.setTextCursor(cursor)
+class ChannelTab(WindowTab):
+ def __init__(self, parent=None):
+ WindowTab.__init__(self, parent)
+
+ self.userList = QtWidgets.QListWidget(self)
+
+ def makeLayout(self):
+ sublayout = QtWidgets.QVBoxLayout()
+ sublayout.addWidget(self.output)
+ sublayout.addWidget(self.input)
+
+ layout = QtWidgets.QHBoxLayout(self)
+ layout.addLayout(sublayout)
+ layout.addWidget(self.userList)
+
+ def readJunk(self, pdata, pos):
+ userCount = u32.unpack_from(pdata, pos)[0]
+ pos += 4
+
+ users = []
+ for i in range(userCount):
+ #prefix = pdata[pos]
+ #pos += 1
+ nicklen = u32.unpack_from(pdata, pos)[0]
+ pos += 4
+ nick = pdata[pos:pos+nicklen].decode('utf-8', 'replace')
+ pos += nicklen
+ modes = u32.unpack_from(pdata, pos)[0]
+ pos += 4
+ users.append(nick)
+ #self.userList.addItem(chr(prefix)+nick)
+ self.userList.addItem(nick)
+
+ self.users = users
+
+ topiclen = u32.unpack_from(pdata, pos)[0]
+ pos += 4
+ self.topic = pdata[pos:pos+topiclen].decode('utf-8', 'replace')
+ pos += topiclen
+
+ return pos
+
+ def addUsers(self, pdata):
+ userCount = u32.unpack_from(pdata, 4)[0]
+ pos = 8
+
+ for i in range(userCount):
+ nicklen = u32.unpack_from(pdata, pos)[0]
+ pos += 4
+ nick = pdata[pos:pos+nicklen].decode('utf-8', 'replace')
+ pos += nicklen
+ modes = u32.unpack_from(pdata, pos)[0]
+ pos += 4
+ self.users.append(nick)
+ self.userList.addItem(nick)
+
+ def removeUsers(self, pdata):
+ userCount = u32.unpack_from(pdata, 4)[0]
+ pos = 8
+ if userCount == 0:
+ self.users = []
+ self.userList.clear()
+ else:
+ for i in range(userCount):
+ nicklen = u32.unpack_from(pdata, pos)[0]
+ pos += 4
+ nick = pdata[pos:pos+nicklen].decode('utf-8', 'replace')
+ pos += nicklen
+ print('Removing [%s]' % repr(nick))
+
+ self.users.remove(nick)
+ items = self.userList.findItems(nick, QtCore.Qt.MatchExactly)
+ self.userList.takeItem(self.userList.row(items[0]))
+
+ def renameUser(self, pdata):
+ pos = 4
+ nicklen = u32.unpack_from(pdata, pos)[0]
+ pos += 4
+ fromnick = pdata[pos:pos+nicklen].decode('utf-8', 'replace')
+ pos += nicklen
+ nicklen = u32.unpack_from(pdata, pos)[0]
+ pos += 4
+ tonick = pdata[pos:pos+nicklen].decode('utf-8', 'replace')
+
+ try:
+ idx = self.users.index(fromnick)
+ except ValueError:
+ self.pushMessage('Crap, [%s] was not found in the users list!' % fromnick)
+ return
+
+ self.users[idx] = tonick
+
+ items = self.userList.findItems(fromnick, QtCore.Qt.MatchExactly)
+ items[0].setText(tonick)
+
+ def changeUserMode(self, pdata):
+ # boop
+ pass
+
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
@@ -177,6 +277,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.setCentralWidget(self.tabs)
self.debugTab = WindowTab(self)
+ self.debugTab.makeLayout()
self.debugTab.enteredMessage.connect(self.handleDebug)
self.tabs.addTab(self.debugTab, 'Debug')
@@ -211,7 +312,13 @@ class MainWindow(QtWidgets.QMainWindow):
pos += msglen
msgs.append(msg)
- tab = WindowTab(self)
+ if wtype == 1:
+ tab = WindowTab(self)
+ elif wtype == 2:
+ tab = ChannelTab(self)
+ pos = tab.readJunk(pdata, pos)
+
+ tab.makeLayout()
tab.winID = wid
tab.enteredMessage.connect(self.handleWindowInput)
self.tabs.addTab(tab, wtitle)
@@ -223,6 +330,23 @@ class MainWindow(QtWidgets.QMainWindow):
msg = pdata[8:8+msglen].decode('utf-8', 'replace')
self.tabLookup[wndID].pushMessage(msg)
+ elif ptype == 0x120:
+ # Add users to channel
+ wndID = u32.unpack_from(pdata, 0)[0]
+ self.tabLookup[wndID].addUsers(pdata)
+ elif ptype == 0x121:
+ # Remove users from channel
+ wndID = u32.unpack_from(pdata, 0)[0]
+ self.tabLookup[wndID].removeUsers(pdata)
+ elif ptype == 0x122:
+ # Rename user in channel
+ wndID = u32.unpack_from(pdata, 0)[0]
+ self.tabLookup[wndID].renameUser(pdata)
+ elif ptype == 0x123:
+ # Change user modes in channel
+ wndID = u32.unpack_from(pdata, 0)[0]
+ self.tabLookup[wndID].changeUserMode(pdata)
+
return True
else:
return QtWidgets.QMainWindow.event(self, event)
diff --git a/window.cpp b/window.cpp
index 00e3e22..c971046 100644
--- a/window.cpp
+++ b/window.cpp
@@ -99,14 +99,62 @@ int Channel::getType() const {
}
void Channel::handleUserInput(const char *str) {
+ char msgBuf[16384];
+
if (str[0] == '/') {
+ if (strncmp(str, "/me ", 4) == 0) {
+ // The duplication of code between here and
+ // handlePrivmsg is ugly. TODO: fixme.
+ char prefix[2];
+ prefix[0] = getEffectivePrefixChar(server->currentNick);
+ prefix[1] = 0;
+
+ snprintf(msgBuf, sizeof(msgBuf),
+ "* %s%s %s",
+ prefix,
+ server->currentNick,
+ &str[4]);
+ pushMessage(msgBuf);
+
+ snprintf(msgBuf, sizeof(msgBuf),
+ "PRIVMSG %s :\x01" "ACTION %s\x01",
+ name.c_str(),
+ &str[4]);
+ server->sendLine(msgBuf);
+ }
} else {
- server->sendLine(str);
+ // Aaaand this is also pretty ugly ><;;
+ // TODO: fixme.
+ char prefix[2];
+ prefix[0] = getEffectivePrefixChar(server->currentNick);
+ prefix[1] = 0;
+
+ snprintf(msgBuf, sizeof(msgBuf),
+ "<%s%s> %s",
+ prefix,
+ server->currentNick,
+ str);
+ pushMessage(msgBuf);
+
+ snprintf(msgBuf, sizeof(msgBuf),
+ "PRIVMSG %s :%s",
+ name.c_str(),
+ str);
+ server->sendLine(msgBuf);
}
}
void Channel::syncStateForClient(Buffer &output) {
Window::syncStateForClient(output);
+
+ output.writeU32(users.size());
+
+ for (auto &i : users) {
+ output.writeStr(i.first.c_str());
+ output.writeU32(i.second);
+ }
+
+ output.writeStr(topic.c_str());
}
@@ -118,6 +166,12 @@ void Channel::handleNameReply(const char *str) {
char *strtok_var;
char *name = strtok_r(copy, " ", &strtok_var);
+ int nameCount = 0;
+
+ Buffer packet;
+ packet.writeU32(id);
+ packet.writeU32(0); // Dummy value..!
+
while (name) {
uint32_t modes = 0;
@@ -141,21 +195,49 @@ void Channel::handleNameReply(const char *str) {
// Got it!
users[name] = modes;
- // TODO: push add command
+ nameCount++;
+ //packet.writeU8(getEffectivePrefixChar(name));
+ packet.writeStr(name);
+ packet.writeU32(modes);
// Get the next name
name = strtok_r(NULL, " ", &strtok_var);
}
+
+ if (nameCount > 0) {
+ uint32_t nameCountU32 = nameCount;
+ memcpy(&packet.data()[4], &nameCountU32, sizeof(uint32_t));
+
+ server->bouncer->sendToClients(
+ Packet::B2C_CHANNEL_USER_ADD, packet);
+ }
}
void Channel::handleJoin(const UserRef &user) {
if (user.isSelf) {
+ Buffer packet;
+ packet.writeU32(id);
+ packet.writeU32(0);
+
+ server->bouncer->sendToClients(
+ Packet::B2C_CHANNEL_USER_REMOVE, packet);
+
+
users.clear();
+
inChannel = true;
pushMessage("You have joined the channel!");
} else {
+ Buffer packet;
+ packet.writeU32(id);
+ packet.writeU32(1);
+ packet.writeStr(user.nick.c_str());
+ packet.writeU32(0);
+
+ server->bouncer->sendToClients(
+ Packet::B2C_CHANNEL_USER_ADD, packet);
+
users[user.nick] = 0;
- // TODO: push add command
char buf[1024];
snprintf(buf, 1024,
@@ -172,7 +254,14 @@ void Channel::handlePart(const UserRef &user, const char *message) {
auto i = users.find(user.nick);
if (i != users.end()) {
users.erase(i);
- // TODO: push remove command
+
+ Buffer packet;
+ packet.writeU32(id);
+ packet.writeU32(1);
+ packet.writeStr(user.nick.c_str());
+
+ server->bouncer->sendToClients(
+ Packet::B2C_CHANNEL_USER_REMOVE, packet);
}
char buf[1024];
@@ -205,8 +294,14 @@ void Channel::handleQuit(const UserRef &user, const char *message) {
return;
users.erase(i);
- // TODO: push remove command
- pushMessage("Removed from users");
+
+ Buffer packet;
+ packet.writeU32(id);
+ packet.writeU32(1);
+ packet.writeStr(user.nick.c_str());
+
+ server->bouncer->sendToClients(
+ Packet::B2C_CHANNEL_USER_REMOVE, packet);
char buf[1024];
@@ -227,7 +322,14 @@ void Channel::handleNick(const UserRef &user, const char *newNick) {
users[newNick] = i->second;
users.erase(i);
- // TODO: push rename command
+
+ Buffer packet;
+ packet.writeU32(id);
+ packet.writeStr(user.nick.c_str());
+ packet.writeStr(newNick);
+
+ server->bouncer->sendToClients(
+ Packet::B2C_CHANNEL_USER_RENAME, packet);
char buf[1024];
snprintf(buf, 1024,