From cc847c2f7c8678c169a83c5b553d3d073ad869a4 Mon Sep 17 00:00:00 2001 From: Treeki Date: Sat, 25 Jan 2014 07:22:54 +0100 Subject: add query windows --- bouncer/core.h | 20 +++++++++ bouncer/ircserver.cpp | 67 +++++++++++++++++++++++++-- bouncer/window.cpp | 122 ++++++++++++++++++++++++++++++++++++++++++++++++-- python_client.py | 9 +++- 4 files changed, 209 insertions(+), 9 deletions(-) diff --git a/bouncer/core.h b/bouncer/core.h index 6b73067..5a43215 100644 --- a/bouncer/core.h +++ b/bouncer/core.h @@ -111,6 +111,24 @@ public: void disconnected(); }; +class Query : public Window { +public: + Query(IRCServer *_server, const char *_partner); + + IRCServer *server; + std::string partner; + + virtual const char *getTitle() const; + virtual int getType() const; + virtual void handleUserInput(const char *str); + + void handleQuit(const char *message); + void handlePrivmsg(const char *str); + + void showNickChange(const UserRef &user, const char *newNick); + void renamePartner(const char *_partner); +}; + class SocketRWCommon { @@ -295,6 +313,7 @@ public: StatusWindow status; std::map channels; + std::map queries; IRCNetworkConfig config; @@ -326,6 +345,7 @@ private: void processISupport(const char *str); Channel *findChannel(const char *name, bool createIfNeeded); + Query *findQuery(const char *name, bool createIfNeeded); }; diff --git a/bouncer/ircserver.cpp b/bouncer/ircserver.cpp index 19bea9d..b1e541a 100644 --- a/bouncer/ircserver.cpp +++ b/bouncer/ircserver.cpp @@ -14,6 +14,11 @@ IRCServer::~IRCServer() { bouncer->deregisterWindow(i.second); delete i.second; } + + for (auto &i : queries) { + bouncer->deregisterWindow(i.second); + delete i.second; + } } void IRCServer::attachedToCore() { @@ -50,6 +55,22 @@ Channel *IRCServer::findChannel(const char *name, bool createIfNeeded) { return check->second; } } +Query *IRCServer::findQuery(const char *name, bool createIfNeeded) { + std::map::iterator + check = queries.find(name); + + if (check == queries.end()) { + if (createIfNeeded) { + Query *q = new Query(this, name); + queries[name] = q; + return q; + } else { + return 0; + } + } else { + return check->second; + } +} @@ -210,6 +231,9 @@ void IRCServer::lineReceivedEvent(char *line, int size) { } else if (strcmp(cmdBuf, "QUIT") == 0) { for (auto &i : channels) i.second->handleQuit(user, allParams); + + if (Query *q = findQuery(user.nick.c_str(), false)) + q->handleQuit(allParams); return; } else if (strcmp(cmdBuf, "KICK") == 0) { @@ -238,10 +262,37 @@ void IRCServer::lineReceivedEvent(char *line, int size) { char buf[1024]; snprintf(buf, 1024, "You are now known as %s", currentNick); status.pushMessage(buf); + + for (auto &it : queries) + it.second->showNickChange(user, allParams); + } + + if (Query *q = findQuery(user.nick.c_str(), false)) { + if (!user.isSelf) + q->showNickChange(user, allParams); + + // Should we *rename* the query window, or not? + Query *check = findQuery(allParams, false); + if (check) { + // If we already have one with the destination + // nick, we shouldn't replace it.. + // ...but we should still show a notification there. + if (!user.isSelf) + check->showNickChange(user, allParams); + } else { + // We didn't have one, so it's safe to move! + auto iter = queries.find(user.nick); + queries.erase(iter); + + queries[allParams] = q; + + q->renamePartner(allParams); + } } for (auto &i : channels) i.second->handleNick(user, allParams); + return; } else if (strcmp(cmdBuf, "MODE") == 0) { @@ -259,10 +310,18 @@ void IRCServer::lineReceivedEvent(char *line, int size) { } } else if (strcmp(cmdBuf, "PRIVMSG") == 0) { - Channel *c = findChannel(targetBuf, true); - if (c) { - c->handlePrivmsg(user, paramsAfterFirst); - return; + if (strcmp(targetBuf, currentNick) == 0) { + Query *q = findQuery(user.nick.c_str(), true); + if (q) { + q->handlePrivmsg(paramsAfterFirst); + return; + } + } else { + Channel *c = findChannel(targetBuf, true); + if (c) { + c->handlePrivmsg(user, paramsAfterFirst); + return; + } } } else if (strcmp(cmdBuf, "001") == 0) { diff --git a/bouncer/window.cpp b/bouncer/window.cpp index 01849e2..dd22e7e 100644 --- a/bouncer/window.cpp +++ b/bouncer/window.cpp @@ -374,10 +374,16 @@ void Channel::handleNick(const UserRef &user, const char *newNick) { Packet::B2C_CHANNEL_USER_RENAME, packet); char buf[1024]; - snprintf(buf, 1024, - "%s is now known as %s", - user.nick.c_str(), - newNick); + if (user.isSelf) { + snprintf(buf, 1024, + "You are now known as %s", + newNick); + } else { + snprintf(buf, 1024, + "%s is now known as %s", + user.nick.c_str(), + newNick); + } pushMessage(buf); } @@ -539,3 +545,111 @@ void Channel::disconnected() { pushMessage("You have been disconnected."); } } + + + + + + +Query::Query(IRCServer *_server, const char *_partner) : + Window(_server->bouncer), + server(_server), + partner(_partner) +{ + server->bouncer->registerWindow(this); +} + +const char *Query::getTitle() const { + return partner.c_str(); +} + +int Query::getType() const { + return 3; +} + +void Query::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. + + snprintf(msgBuf, sizeof(msgBuf), + "* %s %s", + server->currentNick, + &str[4]); + pushMessage(msgBuf); + + snprintf(msgBuf, sizeof(msgBuf), + "PRIVMSG %s :\x01" "ACTION %s\x01", + partner.c_str(), + &str[4]); + server->sendLine(msgBuf); + } + } else { + // Aaaand this is also pretty ugly ><;; + // TODO: fixme. + + snprintf(msgBuf, sizeof(msgBuf), + "<%s> %s", + server->currentNick, + str); + pushMessage(msgBuf); + + snprintf(msgBuf, sizeof(msgBuf), + "PRIVMSG %s :%s", + partner.c_str(), + str); + server->sendLine(msgBuf); + } +} + +void Query::handleQuit(const char *message) { + char buf[1024]; + + snprintf(buf, 1024, + "%s has quit (%s)", + partner.c_str(), + message); + + pushMessage(buf); +} + +void Query::showNickChange(const UserRef &user, const char *newNick) { + char buf[1024]; + + if (user.isSelf) { + snprintf(buf, 1024, + "You are now known as %s", + newNick); + } else { + snprintf(buf, 1024, + "%s is now known as %s", + user.nick.c_str(), + newNick); + } + + pushMessage(buf); +} + +void Query::handlePrivmsg(const char *str) { + char buf[15000]; + snprintf(buf, 15000, + "<%s> %s", + partner.c_str(), + str); + + pushMessage(buf); +} + +void Query::renamePartner(const char *_partner) { + Buffer packet; + packet.writeU32(id); + packet.writeStr(_partner); + + server->bouncer->sendToClients( + Packet::B2C_WINDOW_RENAME, packet); + + partner = _partner; +} diff --git a/python_client.py b/python_client.py index 4e7f1a3..5a82031 100644 --- a/python_client.py +++ b/python_client.py @@ -346,7 +346,7 @@ class MainWindow(QtWidgets.QMainWindow): pos += msglen msgs.append(msg) - if wtype == 1: + if wtype == 1 or wtype == 3: tab = WindowTab(self) elif wtype == 2: tab = ChannelTab(self) @@ -363,6 +363,13 @@ class MainWindow(QtWidgets.QMainWindow): wndID, msglen = struct.unpack_from('