From: Manuel Nickschas Date: Sat, 28 Oct 2006 21:27:46 +0000 (+0000) Subject: Time for another update. Most significantly, I implemented most user commands. X-Git-Tag: 0.1.0~258 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=11ee1cf78677b51d8fea2749e8501216a831dfd7 Time for another update. Most significantly, I implemented most user commands. So rather than using /quote, you might now use standard IRC commands for most tasks. Also, work has been done for further prettifiying the output. --- diff --git a/Quassel.kdevelop.filelist b/Quassel.kdevelop.filelist index 0db635e6..0080ef1d 100644 --- a/Quassel.kdevelop.filelist +++ b/Quassel.kdevelop.filelist @@ -45,3 +45,6 @@ gui/identities.cpp gui/identities.h network/buffer.cpp network/buffer.h +gui/channelwidgetinput.h +gui/channelwidgetinput.cpp +plugins/plugin.h diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index d83476c5..abe989b2 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -1,6 +1,7 @@ -SET(gui_SRCS channelwidget.cpp mainwin.cpp serverlist.cpp identities.cpp coreconnectdlg.cpp guiproxy.cpp) +SET(gui_SRCS channelwidget.cpp channelwidgetinput.cpp mainwin.cpp serverlist.cpp + identities.cpp coreconnectdlg.cpp guiproxy.cpp) SET(gui_HDRS ) -SET(gui_MOCS channelwidget.h mainwin.h serverlist.h identities.h coreconnectdlg.h guiproxy.h) +SET(gui_MOCS channelwidget.h channelwidgetinput.h mainwin.h serverlist.h identities.h coreconnectdlg.h guiproxy.h) SET(gui_UICS channelwidget.ui identitiesdlg.ui identitieseditdlg.ui networkeditdlg.ui nickeditdlg.ui serverlistdlg.ui servereditdlg.ui coreconnectdlg.ui ircwidget.ui) diff --git a/gui/channelwidget.cpp b/gui/channelwidget.cpp index 09879361..84e81b1d 100644 --- a/gui/channelwidget.cpp +++ b/gui/channelwidget.cpp @@ -38,8 +38,13 @@ ChannelWidget::ChannelWidget(QString netname, QString bufname, QString own, QWid ui.topicEdit->hide(); ui.chanSettingsButton->hide(); } + connect(ui.nickTree, SIGNAL(itemExpanded(QTreeWidgetItem *)), this, SLOT(itemExpansionChanged(QTreeWidgetItem*))); + connect(ui.nickTree, SIGNAL(itemCollapsed(QTreeWidgetItem *)), this, SLOT(itemExpansionChanged(QTreeWidgetItem*))); connect(ui.inputEdit, SIGNAL(returnPressed()), this, SLOT(enterPressed())); - //ui.inputEdit->setFocus(); + connect(this, SIGNAL(nickListChanged(QStringList)), ui.inputEdit, SLOT(updateNickList(QStringList))); + ui.inputEdit->setFocus(); + + opsExpanded = voicedExpanded = usersExpanded = true; // Define standard colors stdCol = "black"; @@ -52,10 +57,15 @@ ChannelWidget::ChannelWidget(QString netname, QString bufname, QString own, QWid kickCol = "firebrick"; nickCol = "magenta"; + completer = 0; } void ChannelWidget::enterPressed() { - emit sendInput(networkName(), bufferName(), ui.inputEdit->text()); + QStringList lines = ui.inputEdit->text().split('\n', QString::SkipEmptyParts); + foreach(QString msg, lines) { + if(msg.isEmpty()) continue; + emit sendInput(networkName(), bufferName(), msg); + } ui.inputEdit->clear(); } @@ -77,55 +87,52 @@ void ChannelWidget::recvMessage(Message msg) { break; case Message::Join: c = joinCol; - s = QString(tr("--> %1 (%2@%3) has joined %4")).arg(nick).arg(user).arg(host).arg(bufferName()); + s = QString(tr("--> %1 (%2@%3) has joined %4")).arg(nick).arg(user).arg(host).arg(bufferName()); break; case Message::Part: c = partCol; - s = QString(tr("<-- %1 (%2@%3) has left %4")).arg(nick).arg(user).arg(host).arg(bufferName()); + s = QString(tr("<-- %1 (%2@%3) has left %4")).arg(nick).arg(user).arg(host).arg(bufferName()); if(!msg.msg.isEmpty()) s = QString("%1 (%2)").arg(s).arg(msg.msg); break; case Message::Kick: { c = kickCol; QString victim = msg.msg.section(" ", 0, 0); + if(victim == ui.ownNick->currentText()) victim = tr("you"); QString kickmsg = msg.msg.section(" ", 1); - s = QString(tr("--> %1 has kicked %2 from %3")).arg(nick).arg(victim).arg(bufferName()); + s = QString(tr("--> %1 has kicked %2 from %3")).arg(nick).arg(victim).arg(bufferName()); if(!kickmsg.isEmpty()) s = QString("%1 (%2)").arg(s).arg(kickmsg); } break; case Message::Quit: c = quitCol; - s = QString(tr("<-- %1 (%2@%3) has quit")).arg(nick).arg(user).arg(host); + s = QString(tr("<-- %1 (%2@%3) has quit")).arg(nick).arg(user).arg(host); if(!msg.msg.isEmpty()) s = QString("%1 (%2)").arg(s).arg(msg.msg); break; case Message::Nick: c = nickCol; - if(nick == msg.msg) s = QString(tr("<-> You are now known as %1")).arg(msg.msg); - else s = QString(tr("<-> %1 is now known as %2")).arg(nick).arg(msg.msg); + if(nick == msg.msg) s = QString(tr("<-> You are now known as %1")).arg(msg.msg); + else s = QString(tr("<-> %1 is now known as %2")).arg(nick).arg(msg.msg); + break; + case Message::Mode: + c = serverCol; + if(nick.isEmpty()) s = tr("* User mode: %1").arg(msg.msg); + else s = tr("* Mode %1 by %2").arg(msg.msg).arg(nick); break; default: c = stdCol; n = QString("[%1]").arg(msg.sender); s = msg.msg; break; } + s.replace('&', "&"); s.replace('<', "<"); s.replace('>', ">"); QString html = QString("" "") .arg(msg.timeStamp.toLocalTime().toString("hh:mm:ss")).arg("darkblue"); if(!n.isEmpty()) html += QString("") - .arg(n).arg("mediumseagreen"); - html += QString("""
[%1]
%1
%1
") - .arg(s).arg(c); + .arg(n).arg("royalblue"); + html += QString("
%1
""").arg(s).arg(c); ui.chatWidget->append(html); //ui.chatWidget->append(QString("
%1
%2
 %3
") //.arg(msg.timeStamp.toLocalTime().toString("hh:mm:ss")).arg(nick).arg(s)); - //ui.chatWidget->setTextColor(stdCol); - //ui.chatWidget->append(QString("[%1] ").arg(msg.timeStamp.toLocalTime().toString("hh:mm:ss"))); - //ui.chatWidget->setTextColor(c); - //ui.chatWidget->append(s + "\n"); - //ui.chatWidget->insertHtml(QString("" - // "" - // "" - // "
[12:13]
[nickname]
This is the Message!
[12:13]
[nick]
This is the Message!
[12:13]
[looongnickname]
This is the Message!
[12:13]
[nickname]
This is the Message!
" - // )); ui.chatWidget->ensureCursorVisible(); } @@ -146,6 +153,9 @@ void ChannelWidget::setNicks(QStringList nicks) { void ChannelWidget::addNick(QString nick, VarMap props) { nicks[nick] = props; updateNickList(); + if(completer) delete completer; + completer = new QCompleter(nicks.keys()); + ui.inputEdit->setCompleter(completer); } void ChannelWidget::updateNick(QString nick, VarMap props) { @@ -189,19 +199,26 @@ void ChannelWidget::updateNickList() { if(ops->childCount()) { ops->setText(0, tr("%1 Operators").arg(ops->childCount())); ui.nickTree->addTopLevelItem(ops); - ops->setExpanded(true); + ops->setExpanded(opsExpanded); } else delete ops; if(voiced->childCount()) { voiced->setText(0, tr("%1 Voiced").arg(voiced->childCount())); ui.nickTree->addTopLevelItem(voiced); - voiced->setExpanded(true); + voiced->setExpanded(voicedExpanded); } else delete voiced; if(users->childCount()) { users->setText(0, tr("%1 Users").arg(users->childCount())); ui.nickTree->addTopLevelItem(users); - users->setExpanded(true); + users->setExpanded(usersExpanded); } else delete users; } + +void ChannelWidget::itemExpansionChanged(QTreeWidgetItem *item) { + if(item->child(0)->text(0).startsWith('@')) opsExpanded = item->isExpanded(); + else if(item->child(0)->text(0).startsWith('+')) voicedExpanded = item->isExpanded(); + else usersExpanded = item->isExpanded(); +} + /**********************************************************************************************/ @@ -228,7 +245,7 @@ ChannelWidget * IrcWidget::getBuffer(QString net, QString buf) { 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(); + cw->setFocus(); buffers[key] = cw; } return buffers[key]; @@ -301,9 +318,7 @@ void IrcWidget::updateNick(QString net, QString nick, VarMap props) { void IrcWidget::removeNick(QString net, QString nick) { VarMap chans = nicks[net].toMap()[nick].toMap()["Channels"].toMap(); - qDebug() << "REMOVE" << nick; foreach(QString bufname, chans.keys()) { - qDebug() << "remove from"<removeNick(nick); } VarMap netnicks = nicks[net].toMap(); diff --git a/gui/channelwidget.h b/gui/channelwidget.h index a9b33287..936cf5f4 100644 --- a/gui/channelwidget.h +++ b/gui/channelwidget.h @@ -35,8 +35,10 @@ class ChannelWidget : public QWidget { QString bufferName() { return _bufferName; } QString networkName() { return _networkName; } + signals: void sendInput(QString, QString, QString); + void nickListChanged(QStringList); public slots: void recvMessage(Message); @@ -54,6 +56,8 @@ class ChannelWidget : public QWidget { void enterPressed(); void updateNickList(); + void itemExpansionChanged(QTreeWidgetItem *); + private: Ui::ChannelWidget ui; @@ -62,6 +66,10 @@ class ChannelWidget : public QWidget { QString _networkName; QString _bufferName; VarMap nicks; + + QCompleter *completer; + + bool opsExpanded, voicedExpanded, usersExpanded; }; /** Temporary widget for displaying a set of ChannelWidgets. */ diff --git a/gui/channelwidget.ui b/gui/channelwidget.ui index dee46454..e1831c55 100644 --- a/gui/channelwidget.ui +++ b/gui/channelwidget.ui @@ -236,7 +236,7 @@ p, li { white-space: pre-wrap; } - + 3 @@ -251,6 +251,13 @@ p, li { white-space: pre-wrap; } + + + ChannelWidgetInput + QLineEdit +
channelwidgetinput.h
+
+
inputEdit ownNick diff --git a/gui/channelwidgetinput.cpp b/gui/channelwidgetinput.cpp new file mode 100644 index 00000000..c029bdd7 --- /dev/null +++ b/gui/channelwidgetinput.cpp @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2005/06 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "channelwidgetinput.h" + +ChannelWidgetInput::ChannelWidgetInput(QWidget *parent) : QLineEdit(parent) { + idx = 0; + connect(this, SIGNAL(returnPressed()), this, SLOT(enter())); +} + +void ChannelWidgetInput::keyPressEvent(QKeyEvent * event) { + if(event->key() == Qt::Key_Up) { + if(idx > 0) { idx--; setText(history[idx]); } + event->accept(); + } else if(event->key() == Qt::Key_Down) { + if(idx < history.count()) idx++; + if(idx < history.count()) setText(history[idx]); + else setText(""); + event->accept(); + } else if(event->key() == Qt::Key_Tab) { + // Tabcomplete + if(cursorPosition() == text().length()) { + + + } + event->accept(); + } else { + QLineEdit::keyPressEvent(event); + } +} + +bool ChannelWidgetInput::event(QEvent *e) { + if(e->type() == QEvent::KeyPress) { + keyPressEvent(dynamic_cast(e)); + return true; + } + return QLineEdit::event(e); +} + +void ChannelWidgetInput::enter() { + history << text(); + idx = history.count(); +} + +void ChannelWidgetInput::updateNickList(QStringList l) { + nickList = l; +} diff --git a/gui/channelwidgetinput.h b/gui/channelwidgetinput.h new file mode 100644 index 00000000..4d848e64 --- /dev/null +++ b/gui/channelwidgetinput.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2005/06 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _CHANNELWIDGETINPUT_H_ +#define _CHANNELWIDGETINPUT_H_ + +#include +#include + +class ChannelWidgetInput : public QLineEdit { + Q_OBJECT + + public: + ChannelWidgetInput(QWidget *parent = 0); + + public slots: + void updateNickList(QStringList); + + protected: + virtual bool event(QEvent *); + virtual void keyPressEvent(QKeyEvent * event); + + private slots: + void enter(); + + private: + qint32 idx; + QStringList history; + QStringList nickList; + +}; + +#endif diff --git a/main/message.cpp b/main/message.cpp index e89d1a1c..53b81702 100644 --- a/main/message.cpp +++ b/main/message.cpp @@ -22,14 +22,14 @@ #include QDataStream &operator<<(QDataStream &out, const Message &msg) { - out << (quint8)msg.type << (quint8)msg.flags << msg.sender << msg.msg << (quint32)msg.timeStamp.toTime_t(); + out << (quint32)msg.timeStamp.toTime_t() << (quint8)msg.type << (quint8)msg.flags << msg.sender << msg.msg; return out; } QDataStream &operator>>(QDataStream &in, Message &msg) { quint8 t, f; quint32 ts; - in >> t >> f >> msg.sender >> msg.msg >> ts; + in >> ts >> t >> f >> msg.sender >> msg.msg; msg.type = (Message::Type)t; msg.flags = (Message::Flags)f; msg.timeStamp = QDateTime::fromTime_t(ts); diff --git a/main/util.cpp b/main/util.cpp index c0ef888a..e4c6478d 100644 --- a/main/util.cpp +++ b/main/util.cpp @@ -38,6 +38,10 @@ QString hostFromMask(QString mask) { return userhost.section('@', 1); } +bool isChannelName(QString str) { + return QString("#&!+").contains(str[0]); +} + void writeDataToDevice(QIODevice *dev, const QVariant &item) { QByteArray block; QDataStream out(&block, QIODevice::WriteOnly); diff --git a/main/util.h b/main/util.h index e7b74f9b..1a6d889f 100644 --- a/main/util.h +++ b/main/util.h @@ -29,6 +29,8 @@ QString nickFromMask(QString mask); QString userFromMask(QString mask); QString hostFromMask(QString mask); +bool isChannelName(QString str); + /** * Writes a QVariant to a device. The data item is prefixed with the resulting blocksize, * so the corresponding function readDataFromDevice() can check if enough data is available diff --git a/network/server.cpp b/network/server.cpp index 66475a90..7e0d7490 100644 --- a/network/server.cpp +++ b/network/server.cpp @@ -114,7 +114,7 @@ void Server::userInput(QString net, QString buf, QString msg) { if(!msg.startsWith('/')) { msg = QString("/SAY ") + msg; } - handleUserMsg(buf, msg); + handleUserInput(buf, msg); } void Server::putRawLine(QString s) { @@ -154,8 +154,14 @@ void Server::handleServerMsg(QString msg) { } cmd = msg.section(' ', 0, 0).toUpper(); msg = msg.section(' ', 1); - QString left = msg.section(':', 0, 0); - QString trailing = msg.section(':', 1); + QString left, trailing; + // RPL_ISUPPORT (005) can contain colons, so don't treat it like the rest of the commands + if(cmd.toUInt() == 5) { + left = msg.remove(QString(":are supported by this server")); + } else { + left = msg.section(':', 0, 0); + trailing = msg.section(':', 1); + } if(!left.isEmpty()) { params << left.split(' ', QString::SkipEmptyParts); } @@ -192,6 +198,12 @@ void Server::defaultServerHandler(QString cmd, QString prefix, QStringList param case 2: case 3: case 4: case 5: case 251: case 252: case 253: case 254: case 255: case 372: case 375: emit displayMsg("", Message(Message::Server, params.join(" "), prefix)); break; + // Server error messages, display them in red. First param will be appended. + case 401: case 402: case 403: case 404: + { QString p = params.takeFirst(); + emit displayMsg("", Message(Message::Error, params.join(" ") + " " + p, prefix)); + break; + } // Ignore these commands. case 366: case 376: break; @@ -207,28 +219,30 @@ void Server::defaultServerHandler(QString cmd, QString prefix, QStringList param } } -void Server::handleUserMsg(QString bufname, QString usrMsg) { +void Server::handleUserInput(QString bufname, QString usrMsg) { try { + /* Looks like we don't need core-side buffers... Buffer *buffer = 0; if(!bufname.isEmpty()) { Q_ASSERT(buffers.contains(bufname)); buffer = buffers[bufname]; } + */ QString cmd = usrMsg.section(' ', 0, 0).remove(0, 1).toUpper(); QString msg = usrMsg.section(' ', 1).trimmed(); QString hname = cmd.toLower(); hname[0] = hname[0].toUpper(); hname = "handleUser" + hname; - if(!QMetaObject::invokeMethod(this, hname.toAscii(), Q_ARG(QString, msg), Q_ARG(Buffer*, buffer))) { + if(!QMetaObject::invokeMethod(this, hname.toAscii(), Q_ARG(QString, bufname), Q_ARG(QString, msg))) { // Ok. Default handler it is. - defaultUserHandler(cmd, msg, buffer); + defaultUserHandler(bufname, cmd, msg); } } catch(Exception e) { emit displayMsg("", Message(Message::Error, e.msg())); } } -void Server::defaultUserHandler(QString cmd, QString msg, Buffer *buf) { +void Server::defaultUserHandler(QString bufname, QString cmd, QString msg) { emit displayMsg("", Message(Message::Error, QString("Error: %1 %2").arg(cmd).arg(msg))); } @@ -236,38 +250,117 @@ void Server::defaultUserHandler(QString cmd, QString msg, Buffer *buf) { /**********************************************************************************/ /* -void Server::handleUser(QString msg, Buffer *buf) { +void Server::handleUser(QString bufname, QString msg) { } */ -void Server::handleUserJoin(QString msg, Buffer *buf) { +void Server::handleUserAway(QString bufname, QString msg) { + putCmd("AWAY", QStringList(msg)); +} + +void Server::handleUserDeop(QString bufname, QString msg) { + QStringList nicks = msg.split(' ', QString::SkipEmptyParts); + QString m = "-"; for(int i = 0; i < nicks.count(); i++) m += 'o'; + QStringList params; + params << bufname << m << nicks; + putCmd("MODE", params); +} + +void Server::handleUserDevoice(QString bufname, QString msg) { + QStringList nicks = msg.split(' ', QString::SkipEmptyParts); + QString m = "-"; for(int i = 0; i < nicks.count(); i++) m += 'v'; + QStringList params; + params << bufname << m << nicks; + putCmd("MODE", params); +} + +void Server::handleUserInvite(QString bufname, QString msg) { + QStringList params; + params << msg << bufname; + putCmd("INVITE", params); +} + +void Server::handleUserJoin(QString bufname, QString msg) { putCmd("JOIN", QStringList(msg)); +} + +void Server::handleUserKick(QString bufname, QString msg) { + QStringList params; + params << bufname << msg.split(' ', QString::SkipEmptyParts); + putCmd("KICK", params); +} + +void Server::handleUserList(QString bufname, QString msg) { + putCmd("LIST", msg.split(' ', QString::SkipEmptyParts)); +} + +void Server::handleUserMode(QString bufname, QString msg) { + putCmd("MODE", msg.split(' ', QString::SkipEmptyParts)); +} + +void Server::handleUserMsg(QString bufname, QString msg) { + QString nick = msg.section(" ", 0, 0); + msg = msg.section(" ", 1).trimmed(); + if(nick.isEmpty() || msg.isEmpty()) return; + QStringList params; + params << nick << msg; + putCmd("PRIVMSG", params); +} + +void Server::handleUserNick(QString bufname, QString msg) { + QString nick = msg.section(' ', 0, 0); + putCmd("NICK", QStringList(nick)); +} + +void Server::handleUserOp(QString bufname, QString msg) { + QStringList nicks = msg.split(' ', QString::SkipEmptyParts); + QString m = "+"; for(int i = 0; i < nicks.count(); i++) m += 'o'; + QStringList params; + params << bufname << m << nicks; + putCmd("MODE", params); +} + +void Server::handleUserPart(QString bufname, QString msg) { + QStringList params; + params << bufname << msg; + putCmd("PART", params); +} +void Server::handleUserQuit(QString bufname, QString msg) { + putCmd("QUIT", QStringList(msg)); } -void Server::handleUserQuote(QString msg, Buffer *buf) { +void Server::handleUserQuote(QString bufname, QString msg) { putRawLine(msg); } -void Server::handleUserSay(QString msg, Buffer *buf) { - if(!buf) return; // server buffer +void Server::handleUserSay(QString bufname, QString msg) { + if(bufname.isEmpty()) return; // server buffer QStringList params; - params << buf->name() << msg; + params << bufname << msg; putCmd("PRIVMSG", params); emit displayMsg(params[0], Message(Message::Msg, msg, currentNick, Message::Self)); } +void Server::handleUserVoice(QString bufname, QString msg) { + QStringList nicks = msg.split(' ', QString::SkipEmptyParts); + QString m = "+"; for(int i = 0; i < nicks.count(); i++) m += 'v'; + QStringList params; + params << bufname << m << nicks; + putCmd("MODE", params); +} + /**********************************************************************************/ void Server::handleServerJoin(QString prefix, QStringList params) { Q_ASSERT(params.count() == 1); QString nick = updateNickFromMask(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; + // 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)) { @@ -312,6 +405,40 @@ void Server::handleServerKick(QString prefix, QStringList params) { } } +void Server::handleServerMode(QString prefix, QStringList params) { + if(isChannelName(params[0])) { + // TODO only channel-user modes supported by now + QString prefixes = serverSupports["PrefixModes"].toString(); + QString modes = params[1]; + int p = 2; + int m = 0; + bool add = true; + while(m < modes.length()) { + if(modes[m] == '+') { add = true; m++; continue; } + if(modes[m] == '-') { add = false; m++; continue; } + if(prefixes.contains(modes[m])) { // it's a user channel mode + Q_ASSERT(params.count() > m && nicks.contains(params[p])); + QString nick = params[p++]; + VarMap n = nicks[nick].toMap(); VarMap clist = n["Channels"].toMap(); VarMap chan = clist[params[0]].toMap(); + QString mstr = chan["Mode"].toString(); + add ? mstr += modes[m] : mstr.remove(modes[m]); + chan["Mode"] = mstr; clist[params[0]] = chan; n["Channels"] = clist; nicks[nick] = n; + emit nickUpdated(network, nick, n); + m++; + } else { + // TODO add more modes + m++; + } + } + emit displayMsg(params[0], Message(Message::Mode, params.join(" "), prefix)); + } else { + //Q_ASSERT(nicks.contains(params[0])); + //VarMap n = nicks[params[0]].toMap(); + //QString mode = n["Mode"].toString(); + emit displayMsg("", Message(Message::Mode, params.join(" "))); + } +} + void Server::handleServerNick(QString prefix, QStringList params) { QString oldnick = updateNickFromMask(prefix); QString newnick = params[0]; @@ -388,6 +515,31 @@ void Server::handleServer001(QString prefix, QStringList params) { emit displayMsg("", Message(Message::Server, params[1], prefix)); } +/* RPL_ISUPPORT */ +void Server::handleServer005(QString prefix, QStringList params) { + foreach(QString p, params) { + QString key = p.section("=", 0, 0); + QString val = p.section("=", 1); + serverSupports[key] = val; + // handle some special cases + if(key == "PREFIX") { + VarMap foo; QString modes, prefixes; + Q_ASSERT(val.contains(')') && val.startsWith('(')); + int m = 1, p; + for(p = 2; p < val.length(); p++) if(val[p] == ')') break; + p++; + for(; val[m] != ')'; m++, p++) { + Q_ASSERT(p < val.length()); + foo[QString(val[m])] = QString(val[p]); + modes += val[m]; prefixes += val[p]; + } + serverSupports["PrefixModes"] = modes; serverSupports["Prefixes"] = prefixes; + serverSupports["ModePrefixMap"] = foo; + } + } +} + + /* RPL_NOTOPIC */ void Server::handleServer331(QString prefix, QStringList params) { emit topicSet(network, params[0], ""); @@ -409,12 +561,16 @@ void Server::handleServer333(QString prefix, QStringList params) { void Server::handleServer353(QString prefix, QStringList params) { params.removeFirst(); // = or * QString buf = params.takeFirst(); + QString prefixes = serverSupports["Prefixes"].toString(); 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; + QString mode = "", pfx = ""; + if(prefixes.contains(nick[0])) { + pfx = nick[0]; + for(int i = 0;; i++) + if(prefixes[i] == nick[0]) { mode = serverSupports["PrefixModes"].toString()[i]; break; } + nick.remove(0,1); + } + VarMap c; c["Mode"] = mode; c["Prefix"] = pfx; if(nicks.contains(nick)) { VarMap n = nicks[nick].toMap(); VarMap chans = n["Channels"].toMap(); diff --git a/network/server.h b/network/server.h index 48bce3ed..03e33aab 100644 --- a/network/server.h +++ b/network/server.h @@ -86,15 +86,28 @@ class Server : public QThread { /* Message Handlers */ - /* void handleUser(QString, Buffer *) */ - void handleUserJoin(QString, Buffer *); - void handleUserQuote(QString, Buffer *); - void handleUserSay(QString, Buffer *); - + /* void handleUser(QString, QString); */ + void handleUserAway(QString, QString); + void handleUserDeop(QString, QString); + void handleUserDevoice(QString, QString); + void handleUserInvite(QString, QString); + void handleUserJoin(QString, QString); + void handleUserKick(QString, QString); + void handleUserList(QString, QString); + void handleUserMode(QString, QString); + void handleUserMsg(QString, QString); + void handleUserNick(QString, QString); + void handleUserOp(QString, QString); + void handleUserPart(QString, QString); + void handleUserQuit(QString, QString); + void handleUserQuote(QString, QString); + void handleUserSay(QString, QString); + void handleUserVoice(QString, QString); /* void handleServer(QString, QStringList); */ void handleServerJoin(QString, QStringList); void handleServerKick(QString, QStringList); + void handleServerMode(QString, QStringList); void handleServerNick(QString, QStringList); void handleServerNotice(QString, QStringList); void handleServerPart(QString, QStringList); @@ -103,27 +116,29 @@ class Server : public QThread { void handleServerQuit(QString, QStringList); void handleServer001(QString, QStringList); // RPL_WELCOME + void handleServer005(QString, QStringList); // RPL_ISUPPORT 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); + void defaultUserHandler(QString buf, QString cmd, QString msg); private: QString network; QTcpSocket socket; - QHash buffers; + //QHash buffers; QString currentNick; QString currentServer; VarMap networkSettings; VarMap identity; VarMap nicks; // stores all known nicks for the server + VarMap serverSupports; // stores results from RPL_ISUPPORT void handleServerMsg(QString rawMsg); - void handleUserMsg(QString buffer, QString usrMsg); + void handleUserInput(QString buffer, QString usrMsg); QString updateNickFromMask(QString mask);