Still work in progress, of course. At least we have a sorta working nick list now,
even though only joins are handled by now.
Oh, and timestamps and stuff.
connect(coreProxy, SIGNAL(gsRequestConnect(QStringList)), this, SLOT(connectToIrc(QStringList)));
connect(coreProxy, SIGNAL(gsUserInput(QString, QString, QString)), this, SIGNAL(msgFromGUI(QString, QString, QString)));
- connect(this, SIGNAL(sendMessage(QString, QString, Message)), coreProxy, SLOT(csSendMessage(QString, QString, Message)));
- connect(this, SIGNAL(sendStatusMsg(QString, QString)), coreProxy, SLOT(csSendStatusMsg(QString, QString)));
+ connect(this, SIGNAL(displayMsg(QString, QString, Message)), coreProxy, SLOT(csDisplayMsg(QString, QString, Message)));
+ connect(this, SIGNAL(displayStatusMsg(QString, QString)), coreProxy, SLOT(csDisplayStatusMsg(QString, QString)));
// Read global settings from config file
QSettings s;
connect(this, SIGNAL(connectToIrc(QString)), server, SLOT(connectToIrc(QString)));
connect(this, SIGNAL(disconnectFromIrc(QString)), server, SLOT(disconnectFromIrc(QString)));
connect(this, SIGNAL(msgFromGUI(QString, QString, QString)), server, SLOT(userInput(QString, QString, QString)));
- connect(server, SIGNAL(sendMessage(QString, Message)), this, SLOT(recvMessageFromServer(QString, Message)));
- connect(server, SIGNAL(sendStatusMsg(QString)), this, SLOT(recvStatusMsgFromServer(QString)));
- connect(server, SIGNAL(setTopic(QString, QString, QString)), coreProxy, SLOT(csSetTopic(QString, QString, QString)));
+ connect(server, SIGNAL(displayMsg(QString, Message)), this, SLOT(recvMessageFromServer(QString, Message)));
+ connect(server, SIGNAL(displayStatusMsg(QString)), this, SLOT(recvStatusMsgFromServer(QString)));
+ connect(server, SIGNAL(modeSet(QString, QString, QString)), coreProxy, SLOT(csModeSet(QString, QString, QString)));
+ connect(server, SIGNAL(topicSet(QString, QString, QString)), coreProxy, SLOT(csTopicSet(QString, QString, QString)));
connect(server, SIGNAL(setNicks(QString, QString, QStringList)), coreProxy, SLOT(csSetNicks(QString, QString, QStringList)));
+ connect(server, SIGNAL(nickAdded(QString, QString, VarMap)), coreProxy, SLOT(csNickAdded(QString, QString, VarMap)));
+ connect(server, SIGNAL(nickRemoved(QString, QString)), coreProxy, SLOT(csNickRemoved(QString, QString)));
+ connect(server, SIGNAL(nickUpdated(QString, QString, VarMap)), coreProxy, SLOT(csNickUpdated(QString, QString, VarMap)));
+ connect(server, SIGNAL(ownNickSet(QString, QString)), coreProxy, SLOT(csOwnNickSet(QString, QString)));
// add error handling
server->start();
}
}
+// ALL messages coming pass through these functions before going to the GUI.
+// So this is the perfect place for storing the backlog and log stuff.
void Core::recvMessageFromServer(QString buf, Message msg) {
Q_ASSERT(sender());
QString net = qobject_cast<Server*>(sender())->getNetwork();
- emit sendMessage(net, buf, msg);
+ emit displayMsg(net, buf, msg);
}
void Core::recvStatusMsgFromServer(QString msg) {
Q_ASSERT(sender());
QString net = qobject_cast<Server*>(sender())->getNetwork();
- emit sendStatusMsg(net, msg);
+ emit displayStatusMsg(net, msg);
}
signals:
void msgFromGUI(QString network, QString channel, QString message);
- void sendMessage(QString network, QString channel, Message message);
- void sendStatusMsg(QString, QString);
+ void displayMsg(QString network, QString channel, Message message);
+ void displayStatusMsg(QString, QString);
void connectToIrc(QString net);
void disconnectFromIrc(QString net);
#include "proxy_common.h"
#include "message.h"
+#include "global.h"
#include <QtCore>
#include <QTcpSocket>
public slots:
inline void csUpdateGlobalData(QString key, QVariant data) { send(CS_UPDATE_GLOBAL_DATA, key, data); }
- inline void csSendMessage(QString net, QString buf, Message msg) { send(CS_SEND_MESSAGE, net, buf, QVariant::fromValue(msg)); }
- inline void csSendStatusMsg(QString net, QString msg) { send(CS_SEND_STATUS_MSG, net, msg); }
- inline void csSetTopic(QString net, QString buf, QString topic) { send(CS_SET_TOPIC, net, buf, topic); }
+ inline void csDisplayMsg(QString net, QString buf, Message msg) { send(CS_DISPLAY_MSG, net, buf, QVariant::fromValue(msg)); }
+ inline void csDisplayStatusMsg(QString net, QString msg) { send(CS_DISPLAY_STATUS_MSG, net, msg); }
+ inline void csModeSet(QString net, QString target, QString mode) { send(CS_MODE_SET, net, target, mode); }
+ inline void csTopicSet(QString net, QString buf, QString topic) { send(CS_TOPIC_SET, net, buf, topic); }
inline void csSetNicks(QString net, QString buf, QStringList nicks) { send(CS_SET_NICKS, net, buf, nicks); }
+ inline void csNickAdded(QString net, QString nick, VarMap props) { send(CS_NICK_ADDED, net, nick, props); }
+ inline void csNickRemoved(QString net, QString nick) { send(CS_NICK_REMOVED, net, nick); }
+ inline void csNickUpdated(QString net, QString nick, VarMap props) { send(CS_NICK_UPDATED, net, nick, props); }
+ inline void csOwnNickSet(QString net, QString nick) { send(CS_OWN_NICK_SET, net, nick); }
signals:
void gsPutGlobalData(QString, QVariant);
#include <QtGui>
#include <iostream>
-ChannelWidget::ChannelWidget(QString netname, QString bufname, QWidget *parent) : QWidget(parent) {
+ChannelWidget::ChannelWidget(QString netname, QString bufname, QString own, QWidget *parent) : QWidget(parent) {
ui.setupUi(this);
_networkName = netname;
_bufferName = bufname;
+ ui.ownNick->clear();
+ ui.ownNick->addItem(own);
+ if(bufname.isEmpty()) {
+ // Server Buffer
+ ui.nickTree->hide();
+ ui.topicEdit->hide();
+ ui.chanSettingsButton->hide();
+ }
connect(ui.inputEdit, SIGNAL(returnPressed()), this, SLOT(enterPressed()));
//ui.inputEdit->setFocus();
}
void ChannelWidget::enterPressed() {
- emit sendMessage(networkName(), bufferName(), ui.inputEdit->text());
+ emit sendInput(networkName(), bufferName(), ui.inputEdit->text());
ui.inputEdit->clear();
}
QString s;
QColor c = stdCol;
switch(msg.type) {
+ case Message::Msg:
+ c = stdCol; s = QString("<%1> %2").arg(msg.sender).arg(msg.msg);
+ break;
case Message::Server:
c = serverCol; s = msg.msg;
break;
case Message::Error:
c = errorCol; s = msg.msg;
break;
+ case Message::Join:
+ c = joinCol; s = msg.msg;
+ break;
default:
c = stdCol; s = QString("[%1] %2").arg(msg.sender).arg(msg.msg);
break;
}
ui.chatWidget->setTextColor(c);
- ui.chatWidget->insertPlainText(QString("%1\n").arg(s));
+ ui.chatWidget->insertPlainText(QString("[%2] %1\n").arg(s).arg(msg.timeStamp.toLocalTime().toString("hh:mm:ss")));
+ //ui.chatWidget->insertHtml(QString("<table><tr><td>[12:13]</td><td width=20><div align=right>[nickname]</div></td><td>This is the Message!</td></tr>"
+ // "<tr><td>[12:13]</td><td><div align=right>[nick]</div></td><td>This is the Message!</td></tr>"
+ // "<tr><td>[12:13]</td><td><div align=right>[looongnickname]</div></td><td>This is the Message!</td></tr>"
+ // "<tr><td>[12:13]</td><td><div align=right>[nickname]</div></td><td>This is the Message!</td></tr></table>"
+ // ));
ui.chatWidget->ensureCursorVisible();
}
}
+void ChannelWidget::addNick(QString nick, VarMap props) {
+ nicks[nick] = props;
+ updateNickList();
+}
+
+void ChannelWidget::updateNick(QString nick, VarMap props) {
+ nicks[nick] = props;
+ updateNickList();
+}
+
+void ChannelWidget::removeNick(QString nick) {
+ nicks[nick].toMap().remove(nick);
+ updateNickList();
+}
+
+void ChannelWidget::setOwnNick(QString nick) {
+ ui.ownNick->clear();
+ ui.ownNick->addItem(nick);
+}
+
+void ChannelWidget::updateNickList() {
+ ui.nickTree->clear();
+ if(nicks.count() != 1) ui.nickTree->setHeaderLabel(tr("%1 Users").arg(nicks.count()));
+ else ui.nickTree->setHeaderLabel(tr("1 User"));
+ QTreeWidgetItem *ops = new QTreeWidgetItem();
+ QTreeWidgetItem *voiced = new QTreeWidgetItem();
+ QTreeWidgetItem *users = new QTreeWidgetItem();
+ // To sort case-insensitive, we have to put all nicks in a map which is sorted by (lowercase) key...
+ QMap<QString, QString> sorted;
+ foreach(QString n, nicks.keys()) { sorted[n.toLower()] = n; }
+ foreach(QString n, sorted.keys()) {
+ QString nick = sorted[n];
+ QString mode = nicks[nick].toMap()["Channels"].toMap()[bufferName()].toMap()["Mode"].toString();
+ if(mode.contains('o')) { new QTreeWidgetItem(ops, QStringList(QString("@%1").arg(nick))); }
+ else if(mode.contains('v')) { new QTreeWidgetItem(voiced, QStringList(QString("+%1").arg(nick))); }
+ else new QTreeWidgetItem(users, QStringList(nick));
+ }
+ if(ops->childCount()) {
+ ops->setText(0, tr("%1 Operators").arg(ops->childCount()));
+ ui.nickTree->addTopLevelItem(ops);
+ ops->setExpanded(true);
+ } else delete ops;
+ if(voiced->childCount()) {
+ voiced->setText(0, tr("%1 Voiced").arg(voiced->childCount()));
+ ui.nickTree->addTopLevelItem(voiced);
+ voiced->setExpanded(true);
+ } else delete voiced;
+ if(users->childCount()) {
+ users->setText(0, tr("%1 Users").arg(users->childCount()));
+ ui.nickTree->addTopLevelItem(users);
+ users->setExpanded(true);
+ } else delete users;
+}
/**********************************************************************************************/
ui.setupUi(this);
ui.tabWidget->removeTab(0);
- connect(guiProxy, SIGNAL(csSendMessage(QString, QString, Message)), this, SLOT(recvMessage(QString, QString, Message)));
- connect(guiProxy, SIGNAL(csSendStatusMsg(QString, QString)), this, SLOT(recvStatusMsg(QString, QString)));
- connect(guiProxy, SIGNAL(csSetTopic(QString, QString, QString)), this, SLOT(setTopic(QString, QString, QString)));
+ connect(guiProxy, SIGNAL(csDisplayMsg(QString, QString, Message)), this, SLOT(recvMessage(QString, QString, Message)));
+ connect(guiProxy, SIGNAL(csDisplayStatusMsg(QString, QString)), this, SLOT(recvStatusMsg(QString, QString)));
+ connect(guiProxy, SIGNAL(csTopicSet(QString, QString, QString)), this, SLOT(setTopic(QString, QString, QString)));
connect(guiProxy, SIGNAL(csSetNicks(QString, QString, QStringList)), this, SLOT(setNicks(QString, QString, QStringList)));
- connect(this, SIGNAL(sendMessage( QString, QString, QString )), guiProxy, SLOT(gsUserInput(QString, QString, QString)));
+ connect(guiProxy, SIGNAL(csNickAdded(QString, QString, VarMap)), this, SLOT(addNick(QString, QString, VarMap)));
+ connect(guiProxy, SIGNAL(csNickRemoved(QString, QString)), this, SLOT(removeNick(QString, QString)));
+ connect(guiProxy, SIGNAL(csNickUpdated(QString, QString, VarMap)), this, SLOT(updateNick(QString, QString, VarMap)));
+ connect(guiProxy, SIGNAL(csOwnNickSet(QString, QString)), this, SLOT(setOwnNick(QString, QString)));
+ connect(this, SIGNAL(sendInput( QString, QString, QString )), guiProxy, SLOT(gsUserInput(QString, QString, QString)));
}
ChannelWidget * IrcWidget::getBuffer(QString net, QString buf) {
QString key = net + buf;
if(!buffers.contains(key)) {
- ChannelWidget *cw = new ChannelWidget(net, buf);
- connect(cw, SIGNAL(sendMessage(QString, QString, QString)), this, SLOT(userInput(QString, QString, QString)));
+ ChannelWidget *cw = new ChannelWidget(net, buf, ownNick);
+ connect(cw, SIGNAL(sendInput(QString, QString, QString)), this, SLOT(userInput(QString, QString, QString)));
ui.tabWidget->addTab(cw, net+buf);
ui.tabWidget->setCurrentWidget(cw);
//cw->setFocus();
}
void IrcWidget::userInput(QString net, QString buf, QString msg) {
- emit sendMessage(net, buf, msg);
+ emit sendInput(net, buf, msg);
}
void IrcWidget::setTopic(QString net, QString buf, QString topic) {
cw->setNicks(nicks);
}
+void IrcWidget::addNick(QString net, QString nick, VarMap props) {
+ nicks[net].toMap()[nick] = props;
+ VarMap chans = props["Channels"].toMap();
+ QStringList c = chans.keys();
+ foreach(QString bufname, c) {
+ getBuffer(net, bufname)->addNick(nick, props);
+ }
+}
+
+void IrcWidget::updateNick(QString net, QString nick, VarMap props) {
+ QStringList oldchans = nicks[net].toMap()[nick].toMap()["Channels"].toMap().keys();
+ QStringList newchans = props["Channels"].toMap().keys();
+ foreach(QString c, newchans) {
+ if(oldchans.contains(c)) getBuffer(net, c)->updateNick(nick, props);
+ else getBuffer(net, c)->addNick(nick, props);
+ }
+ foreach(QString c, oldchans) {
+ if(!newchans.contains(c)) getBuffer(net, c)->removeNick(nick);
+ }
+ nicks[net].toMap()[nick] = props;
+}
+
+void IrcWidget::removeNick(QString net, QString nick) {
+ VarMap chans = nicks[net].toMap()[nick].toMap()["Channels"].toMap();
+ foreach(QString bufname, chans.keys()) {
+ getBuffer(net, bufname)->removeNick(nick);
+ }
+ qDebug() << nicks;
+ nicks[net].toMap().remove(nick);
+ qDebug() << nicks;
+}
+
+void IrcWidget::setOwnNick(QString net, QString nick) {
+ ownNick = nick;
+ foreach(ChannelWidget *cw, buffers.values()) {
+ if(cw->networkName() == net) cw->setOwnNick(nick);
+ }
+}
+
#include "ui_channelwidget.h"
#include "ui_ircwidget.h"
+#include "global.h"
#include "message.h"
class ChannelWidget : public QWidget {
Q_OBJECT
public:
- ChannelWidget(QString netname, QString bufname, QWidget *parent = 0);
+ ChannelWidget(QString netname, QString bufname, QString ownNick, QWidget *parent = 0);
QString bufferName() { return _bufferName; }
QString networkName() { return _networkName; }
signals:
- void sendMessage(QString, QString, QString);
+ void sendInput(QString, QString, QString);
public slots:
void recvMessage(Message);
void recvStatusMsg(QString msg);
void setTopic(QString);
void setNicks(QStringList);
+ void addNick(QString nick, VarMap props);
+ void removeNick(QString nick);
+ void updateNick(QString nick, VarMap props);
+ void setOwnNick(QString nick);
+
private slots:
void enterPressed();
+ void updateNickList();
private:
Ui::ChannelWidget ui;
QColor stdCol, errorCol, noticeCol, joinCol, quitCol, partCol, serverCol;
QString _networkName;
QString _bufferName;
+ VarMap nicks;
};
/** Temporary widget for displaying a set of ChannelWidgets. */
void recvStatusMsg(QString network, QString message);
void setTopic(QString, QString, QString);
void setNicks(QString, QString, QStringList);
+ void addNick(QString net, QString nick, VarMap props);
+ void removeNick(QString net, QString nick);
+ void updateNick(QString net, QString nick, VarMap props);
+ void setOwnNick(QString net, QString nick);
signals:
- void sendMessage(QString network, QString buffer, QString message);
+ void sendInput(QString network, QString buffer, QString message);
private slots:
void userInput(QString, QString, QString);
private:
Ui::IrcWidget ui;
QHash<QString, ChannelWidget *> buffers;
+ VarMap nicks;
+ QString ownNick;
ChannelWidget * getBuffer(QString net, QString buf);
};
<property name="textElideMode" >
<enum>Qt::ElideRight</enum>
</property>
+ <property name="rootIsDecorated" >
+ <bool>true</bool>
+ </property>
<property name="sortingEnabled" >
<bool>false</bool>
</property>
</property>
<item>
<widget class="QComboBox" name="ownNick" >
- <item>
- <property name="text" >
- <string>mainNick</string>
- </property>
- </item>
- <item>
- <property name="text" >
- <string>altNick</string>
- </property>
- </item>
+ <property name="sizeAdjustPolicy" >
+ <enum>QComboBox::AdjustToContents</enum>
+ </property>
</widget>
</item>
<item>
case CS_CORE_STATE: emit csCoreState(arg1); break;
case CS_UPDATE_GLOBAL_DATA: emit csUpdateGlobalData(arg1.toString(), arg2); break;
//case CS_GLOBAL_DATA_CHANGED: emit csGlobalDataChanged(arg1.toString()); break;
- case CS_SEND_MESSAGE: emit csSendMessage(arg1.toString(), arg2.toString(), arg3.value<Message>()); break;
- case CS_SEND_STATUS_MSG: emit csSendStatusMsg(arg1.toString(), arg2.toString()); break;
- case CS_SET_TOPIC: emit csSetTopic(arg1.toString(), arg2.toString(), arg3.toString()); break;
+ case CS_DISPLAY_MSG: emit csDisplayMsg(arg1.toString(), arg2.toString(), arg3.value<Message>()); break;
+ case CS_DISPLAY_STATUS_MSG: emit csDisplayStatusMsg(arg1.toString(), arg2.toString()); break;
+ case CS_MODE_SET: emit csModeSet(arg1.toString(), arg2.toString(), arg3.toString()); break;
+ case CS_TOPIC_SET: emit csTopicSet(arg1.toString(), arg2.toString(), arg3.toString()); break;
case CS_SET_NICKS: emit csSetNicks(arg1.toString(), arg2.toString(), arg3.toStringList()); break;
+ case CS_NICK_ADDED: emit csNickAdded(arg1.toString(), arg2.toString(), arg3.toMap()); break;
+ case CS_NICK_REMOVED: emit csNickRemoved(arg1.toString(), arg2.toString()); break;
+ case CS_NICK_UPDATED: emit csNickUpdated(arg1.toString(), arg2.toString(), arg3.toMap()); break;
+ case CS_OWN_NICK_SET: emit csOwnNickSet(arg1.toString(), arg2.toString()); break;
default: qWarning() << "Unknown signal in GUIProxy::recv: " << sig;
}
#include "proxy_common.h"
#include "message.h"
+#include "global.h"
#include <QObject>
#include <QVariant>
signals:
void csCoreState(QVariant);
- void csSendMessage(QString, QString, Message);
- void csSendStatusMsg(QString, QString);
+ void csDisplayMsg(QString, QString, Message);
+ void csDisplayStatusMsg(QString, QString);
void csUpdateGlobalData(QString key, QVariant data);
void csGlobalDataChanged(QString key);
- void csSetTopic(QString, QString, QString);
+ void csModeSet(QString, QString, QString);
+ void csTopicSet(QString, QString, QString);
void csSetNicks(QString, QString, QStringList);
+ void csNickAdded(QString, QString, VarMap);
+ void csNickRemoved(QString, QString);
+ void csNickUpdated(QString, QString, VarMap);
+ void csOwnNickSet(QString, QString);
void coreConnected();
void coreDisconnected();
#include <QDataStream>
QDataStream &operator<<(QDataStream &out, const Message &msg) {
- out << (quint8)msg.type << (quint8)msg.flags << msg.sender << msg.msg;
+ out << (quint8)msg.type << (quint8)msg.flags << msg.sender << msg.msg << (quint32)msg.timeStamp.toTime_t();
return out;
}
QDataStream &operator>>(QDataStream &in, Message &msg) {
quint8 t, f;
- in >> t >> f >> msg.sender >> msg.msg;
+ quint32 ts;
+ in >> t >> f >> msg.sender >> msg.msg >> ts;
msg.type = (Message::Type)t;
msg.flags = (Message::Flags)f;
+ msg.timeStamp = QDateTime::fromTime_t(ts);
return in;
}
Flags flags;
QString sender;
QString msg;
+ QDateTime timeStamp;
Message(QString _msg = "", QString _sender = "", Type _type = Msg, Flags _flags = None)
- : msg(_msg), sender(_sender), type(_type), flags(_flags) {};
+ : msg(_msg), sender(_sender), type(_type), flags(_flags) { timeStamp = QDateTime::currentDateTime().toUTC(); };
};
};
-enum CoreSignal { CS_CORE_STATE, CS_SEND_MESSAGE, CS_SEND_STATUS_MSG, CS_UPDATE_GLOBAL_DATA,
- CS_SET_TOPIC, CS_SET_NICKS,
+enum CoreSignal { CS_CORE_STATE, CS_DISPLAY_MSG, CS_DISPLAY_STATUS_MSG, CS_UPDATE_GLOBAL_DATA,
+ CS_MODE_SET, CS_TOPIC_SET, CS_SET_NICKS, CS_NICK_ADDED, CS_NICK_REMOVED, CS_NICK_UPDATED,
+ CS_OWN_NICK_SET,
};
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
+/* THIS CODE IS OBSOLETE! */
+
#include <QtGlobal>
//#include "message.h"
#include "cmdcodes.h"
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
+/* THIS CODE IS OBSOLETE! */
+
#ifndef _CMDCODES_H_
#define _CMDCODES_H_
#include "message.h"
#include <QMetaObject>
+#include <QDateTime>
Server::Server(QString net) : network(net) {
void Server::connectToIrc(QString net) {
if(net != network) return; // not me!
- QList<QVariant> servers = global->getData("Networks").toMap()[net].toMap()["Servers"].toList();
- qDebug() << "Connecting to"<< servers[0].toMap();
+ networkSettings = global->getData("Networks").toMap()[net].toMap();
+ identity = global->getData("Identities").toMap()[networkSettings["Identity"].toString()].toMap();
+ QList<QVariant> servers = networkSettings["Servers"].toList();
QString host = servers[0].toMap()["Address"].toString();
quint16 port = servers[0].toMap()["Port"].toUInt();
- sendStatusMsg(QString("Connecting to %1:%2...").arg(host).arg(port));
+ displayStatusMsg(QString("Connecting to %1:%2...").arg(host).arg(port));
socket.connectToHost(host, port);
}
}
void Server::socketConnected( ) {
- qDebug() << "Socket connected!";
- putRawLine("NICK :QuasselDev");
- putRawLine("USER Sputnick 8 * :Using Quassel IRC (WiP Version)");
+ putRawLine(QString("NICK :%1").arg(identity["NickList"].toStringList()[0]));
+ putRawLine(QString("USER %1 8 * :%2").arg(identity["Ident"].toString()).arg(identity["RealName"].toString()));
}
void Server::socketDisconnected( ) {
//qDebug() << "Socket state changed: " << state;
}
+QString Server::nickFromMask(QString mask) {
+ return mask.section('!', 0, 0);
+}
+
+QString Server::userFromMask(QString mask) {
+ QString userhost = mask.section('!', 1);
+ if(userhost.isEmpty()) return QString();
+ return userhost.section('@', 0, 0);
+}
+
+QString Server::hostFromMask(QString mask) {
+ QString userhost = mask.section('!', 1);
+ if(userhost.isEmpty()) return QString();
+ return userhost.section('@', 1);
+}
+
void Server::userInput(QString net, QString buf, QString msg) {
if(net != network) return; // not me!
msg = msg.trimmed(); // remove whitespace from start and end
if(!trailing.isEmpty()) {
params << trailing;
}
+ // numeric replies usually have our own nick as first param. Remove this!
+ // BTW, this behavior is not in the RFC.
+ uint num = cmd.toUInt();
+ if(num > 1 && params.count() > 0) { // 001 sets our nick, so we shouldn't remove anything
+ if(params[0] == currentNick) params.removeFirst();
+ else qWarning((QString("First param NOT nick: %1:%2 %3").arg(prefix).arg(cmd).arg(params.join(" "))).toAscii());
+ }
// Now we try to find a handler for this message. BTW, I do love the Trolltech guys ;-)
QString hname = cmd.toLower();
hname[0] = hname[0].toUpper();
defaultServerHandler(cmd, prefix, params);
}
} catch(Exception e) {
- emit sendMessage("", Message(e.msg(), "", Message::Error));
+ emit displayMsg("", Message(e.msg(), "", Message::Error));
}
}
void Server::defaultServerHandler(QString cmd, QString prefix, QStringList params) {
uint num = cmd.toUInt();
if(num) {
- if(params.count() > 0) {
- if(params[0] == currentNick) params.removeFirst(); // remove nick if it is first arg
- else qWarning((QString("First param NOT nick: %1:%2 %3").arg(prefix).arg(cmd).arg(params.join(" "))).toAscii());
- }
// A lot of server messages don't really need their own handler because they don't do much.
// Catch and handle these here.
switch(num) {
// Welcome, status, info messages. Just display these.
case 2: case 3: case 4: case 5: case 251: case 252: case 253: case 254: case 255: case 372: case 375:
- emit sendMessage("", Message(params.join(" "), prefix, Message::Server));
+ emit displayMsg("", Message(params.join(" "), prefix, Message::Server));
break;
// Ignore these commands.
- case 376:
+ case 366: case 376:
break;
// Everything else will be marked in red, so we can add them somewhere.
default:
- emit sendMessage("", Message(cmd + " " + params.join(" "), prefix, Message::Error));
+ emit displayMsg("", Message(cmd + " " + params.join(" "), prefix, Message::Error));
}
//qDebug() << prefix <<":"<<cmd<<params;
} else {
- emit sendMessage("", Message(QString("Unknown: ") + cmd + " " + params.join(" "), prefix, Message::Error));
+ emit displayMsg("", Message(QString("Unknown: ") + cmd + " " + params.join(" "), prefix, Message::Error));
//qDebug() << prefix <<":"<<cmd<<params;
}
}
defaultUserHandler(cmd, msg, buffer);
}
} catch(Exception e) {
- emit sendMessage("", Message(e.msg(), "", Message::Error));
+ emit displayMsg("", Message(e.msg(), "", Message::Error));
}
}
void Server::defaultUserHandler(QString cmd, QString msg, Buffer *buf) {
- emit sendMessage("", Message(QString("Error: %1 %2").arg(cmd).arg(msg), "", Message::Error));
+ emit displayMsg("", Message(QString("Error: %1 %2").arg(cmd).arg(msg), "", Message::Error));
}
QStringList params;
params << buf->name() << msg;
putCmd("PRIVMSG", params);
+ emit displayMsg(params[0], Message(msg, currentNick, Message::Msg, Message::Self));
}
/**********************************************************************************/
void Server::handleServerJoin(QString prefix, QStringList params) {
Q_ASSERT(params.count() == 1);
- QString bufname = params[0];
- if(!buffers.contains(bufname)) {
- Buffer *buf = new Buffer(bufname);
- buffers[bufname] = buf;
+ QString nick = nickFromMask(prefix);
+ if(nick == currentNick) {
+ Q_ASSERT(!buffers.contains(params[0])); // cannot join a buffer twice!
+ Buffer *buf = new Buffer(params[0]);
+ buffers[params[0]] = buf;
+ } else {
+ VarMap n;
+ if(nicks.contains(nick)) {
+ n = nicks[nick].toMap();
+ VarMap chans = n["Channels"].toMap();
+ // Q_ASSERT(!chans.keys().contains(params[0])); TODO uncomment
+ chans[params[0]] = VarMap();
+ n["Channels"] = chans;
+ nicks[nick] = n;
+ emit nickUpdated(network, nick, n);
+ } else {
+ VarMap chans;
+ chans[params[0]] = VarMap();
+ n["Channels"] = chans;
+ n["Nick"] = nick;
+ n["User"] = userFromMask(prefix);
+ n["Host"] = hostFromMask(prefix);
+ nicks[nick] = n;
+ emit nickAdded(network, nick, n);
+ }
+ QString user = n["User"].toString(); QString host = n["Host"].toString();
+ if(user.isEmpty() || host.isEmpty()) emit displayMsg(params[0], Message(tr("%1 has joined %2").arg(nick).arg(params[0]), "", Message::Join));
+ else emit displayMsg(params[0], Message(tr("%1 (%2@%3) has joined %4").arg(nick).arg(user).arg(host).arg(params[0]), "", Message::Join));
}
- // handle user joins!
}
+
+
void Server::handleServerNotice(QString prefix, QStringList params) {
Message msg(params[1], prefix, Message::Notice);
- if(prefix == currentServer) emit sendMessage("", Message(params[1], prefix, Message::Server));
- else emit sendMessage("", Message(params[1], prefix, Message::Notice));
+ if(prefix == currentServer) emit displayMsg("", Message(params[1], prefix, Message::Server));
+ else emit displayMsg("", Message(params[1], prefix, Message::Notice));
}
void Server::handleServerPing(QString prefix, QStringList params) {
}
void Server::handleServerPrivmsg(QString prefix, QStringList params) {
- emit sendMessage(params[0], Message(params[1], prefix, Message::Msg));
+ emit displayMsg(params[0], Message(params[1], nickFromMask(prefix), Message::Msg));
}
void Server::handleServer001(QString prefix, QStringList params) {
currentServer = prefix;
currentNick = params[0];
- emit sendMessage("", Message(params[1], prefix, Message::Server));
+ emit ownNickSet(network, currentNick);
+ emit displayMsg("", Message(params[1], prefix, Message::Server));
}
/* RPL_NOTOPIC */
void Server::handleServer331(QString prefix, QStringList params) {
- if(params[0] == currentNick) params.removeFirst();
- emit setTopic(network, params[0], "");
+ emit topicSet(network, params[0], "");
}
/* RPL_TOPIC */
void Server::handleServer332(QString prefix, QStringList params) {
- if(params[0] == currentNick) params.removeFirst();
- emit setTopic(network, params[0], params[1]);
+ emit topicSet(network, params[0], params[1]);
+ emit displayMsg(params[0], Message(tr("Topic for %1 is \"%2\"").arg(params[0]).arg(params[1]), "", Message::Server));
}
+/* Topic set by... */
+void Server::handleServer333(QString prefix, QStringList params) {
+ emit displayMsg(params[0], Message(tr("Topic set by %1 on %2").arg(params[1]).arg(QDateTime::fromTime_t(params[2].toUInt()).toString()), "", Message::Server));
+}
+
+/* RPL_NAMREPLY */
+void Server::handleServer353(QString prefix, QStringList params) {
+ params.removeFirst(); // = or *
+ QString buf = params.takeFirst();
+ foreach(QString nick, params[0].split(' ')) {
+ // TODO: parse more prefix characters! use 005?
+ QString mode = "";
+ if(nick.startsWith('@')) { mode = "o"; nick.remove(0,1); }
+ else if(nick.startsWith('+')) { mode = "v"; nick.remove(0,1); }
+ VarMap c; c["Mode"] = mode;
+ if(nicks.contains(nick)) {
+ VarMap n = nicks[nick].toMap();
+ VarMap chans = n["Channels"].toMap();
+ chans[buf] = c;
+ n["Channels"] = chans;
+ nicks[nick] = n;
+ emit nickUpdated(network, nick, n);
+ } else {
+ VarMap n; VarMap c; VarMap chans;
+ c["Mode"] = mode;
+ chans[buf] = c;
+ n["Channels"] = chans;
+ n["Nick"] = nick;
+ nicks[nick] = n;
+ emit nickAdded(network, nick, n);
+ }
+ }
+}
/***********************************************************************************/
/* Exception classes for message handling */
signals:
void recvRawServerMsg(QString);
- void sendStatusMsg(QString);
- void sendMessage(QString buffer, Message msg);
+ void displayStatusMsg(QString);
+ void displayMsg(QString buffer, Message msg);
void disconnected();
- void setTopic(QString network, QString buffer, QString topic);
+ void nickAdded(QString network, QString nick, VarMap props);
+ void nickRemoved(QString network, QString nick);
+ void nickUpdated(QString network, QString nick, VarMap props);
+ void modeSet(QString network, QString target, QString mode);
+ void topicSet(QString network, QString buffer, QString topic);
void setNicks(QString network, QString buffer, QStringList nicks);
+ void ownNickSet(QString network, QString newNick);
private slots:
void handleServer001(QString, QStringList); // RPL_WELCOME
void handleServer331(QString, QStringList); // RPL_NOTOPIC
void handleServer332(QString, QStringList); // RPL_TOPIC
+ void handleServer333(QString, QStringList); // Topic set by...
+ void handleServer353(QString, QStringList); // RPL_NAMREPLY
void defaultServerHandler(QString cmd, QString prefix, QStringList params);
void defaultUserHandler(QString cmd, QString msg, Buffer *buf);
QString currentNick;
QString currentServer;
+ VarMap networkSettings;
+ VarMap identity;
+ VarMap nicks; // stores all known nicks for the server
void handleServerMsg(QString rawMsg);
void handleUserMsg(QString buffer, QString usrMsg);
+ QString nickFromMask(QString mask);
+ QString userFromMask(QString mask);
+ QString hostFromMask(QString mask);
+
class ParseError : public Exception {
public:
ParseError(QString cmd, QString prefix, QStringList params);