summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeki <treeki@gmail.com>2014-01-25 07:22:54 +0100
committerTreeki <treeki@gmail.com>2014-01-25 07:22:54 +0100
commitcc847c2f7c8678c169a83c5b553d3d073ad869a4 (patch)
tree445d5f97c8fa9e11db8a0d5efbbc800d8d74eaa9
parentd67fdae167bf5118b17d3bfaeb5f91929dfa812d (diff)
downloadbounce4-cc847c2f7c8678c169a83c5b553d3d073ad869a4.tar.gz
bounce4-cc847c2f7c8678c169a83c5b553d3d073ad869a4.zip
add query windows
-rw-r--r--bouncer/core.h20
-rw-r--r--bouncer/ircserver.cpp67
-rw-r--r--bouncer/window.cpp122
-rw-r--r--python_client.py9
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<std::string, Channel *> channels;
+ std::map<std::string, Query *> 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<std::string, Query *>::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('<II', pdata, 0)
msg = pdata[8:8+msglen].decode('utf-8', 'replace')
self.tabLookup[wndID].pushMessage(msg)
+ elif ptype == 0x103:
+ # WINDOW RENAME
+ wndID, msglen = struct.unpack_from('<II', pdata, 0)
+ title = pdata[8:8+msglen].decode('utf-8', 'replace')
+
+ tabObj = self.tabLookup[wndID]
+ self.tabs.setTabText(self.tabs.indexOf(tabObj), title)
elif ptype == 0x120:
# Add users to channel