-rw-r--r-- | noncore/net/opieirc/ircchannellist.cpp | 2 | ||||
-rw-r--r-- | noncore/net/opieirc/ircchanneltab.cpp | 17 | ||||
-rw-r--r-- | noncore/net/opieirc/ircchanneltab.h | 3 | ||||
-rw-r--r-- | noncore/net/opieirc/ircmessage.cpp | 35 | ||||
-rw-r--r-- | noncore/net/opieirc/ircmessage.h | 6 | ||||
-rw-r--r-- | noncore/net/opieirc/ircmessageparser.cpp | 158 | ||||
-rw-r--r-- | noncore/net/opieirc/ircmessageparser.h | 10 | ||||
-rw-r--r-- | noncore/net/opieirc/ircserver.cpp | 13 | ||||
-rw-r--r-- | noncore/net/opieirc/ircservereditor.cpp | 8 | ||||
-rw-r--r-- | noncore/net/opieirc/ircservertab.cpp | 39 | ||||
-rw-r--r-- | noncore/net/opieirc/ircservertab.h | 1 | ||||
-rw-r--r-- | noncore/net/opieirc/ircsession.cpp | 56 | ||||
-rw-r--r-- | noncore/net/opieirc/ircsession.h | 7 |
13 files changed, 276 insertions, 79 deletions
diff --git a/noncore/net/opieirc/ircchannellist.cpp b/noncore/net/opieirc/ircchannellist.cpp index 6bef318..c32c535 100644 --- a/noncore/net/opieirc/ircchannellist.cpp +++ b/noncore/net/opieirc/ircchannellist.cpp @@ -30,36 +30,36 @@ void IRCChannelList::update() { bool IRCChannelList::hasPerson(QString nick) { for (unsigned int i=0; i<count(); i++) { if (text(i) == nick) return TRUE; } return FALSE; } bool IRCChannelList::removePerson(QString nick) { for (unsigned int i=0; i<count(); i++) { if (text(i) == nick){ removeItem(i); return TRUE; } } return FALSE; } void IRCChannelList::adjustNicks() { QString txt; QPixmap pm; for(unsigned int i=0; i<count(); i++) { txt = text(i).remove(0,1); if(pixmap(i)) { pm = *pixmap(i); removeItem(i); insertItem(pm, txt, i); } else { removeItem(i); - insertItem(txt,i); + insertItem(txt, i); } } } diff --git a/noncore/net/opieirc/ircchanneltab.cpp b/noncore/net/opieirc/ircchanneltab.cpp index 581f9a5..4a35929 100644 --- a/noncore/net/opieirc/ircchanneltab.cpp +++ b/noncore/net/opieirc/ircchanneltab.cpp @@ -1,87 +1,96 @@ #include <qpe/resource.h> #include <qwhatsthis.h> #include <qhbox.h> +#include <qdict.h> #include "ircchanneltab.h" #include "ircservertab.h" #include "ircmessageparser.h" +QDict<QString> IRCChannelTab::m_queuedMessages (17); + IRCChannelTab::IRCChannelTab(IRCChannel *channel, IRCServerTab *parentTab, MainWindow *mainWindow, QWidget *parent, const char *name, WFlags f) : IRCTab(parent, name, f) { m_mainWindow = mainWindow; m_parentTab = parentTab; m_channel = channel; m_description->setText(tr("Talking on channel") + " <b>" + channel->channelname() + "</b>"); QHBox *hbox = new QHBox(this); m_textview = new QTextView(hbox); m_textview->setHScrollBarMode(QScrollView::AlwaysOff); m_textview->setVScrollBarMode(QScrollView::AlwaysOn); m_listVisible = TRUE; m_listButton = new QPushButton(">", m_textview); m_listButton->setFlat( true ); m_textview->setCornerWidget(m_listButton); m_textview->setTextFormat(RichText); QWhatsThis::add(m_textview, tr("Channel discussion")); connect(m_listButton, SIGNAL(clicked()), this, SLOT(toggleList())); m_list = new IRCChannelList(m_channel, hbox); m_list->update(); m_list->setMaximumWidth(LISTWIDTH); m_field = new IRCHistoryLineEdit(this); connect(m_field, SIGNAL(nextTab()), this, SIGNAL(nextTab())); connect(m_field, SIGNAL(prevTab()), this, SIGNAL(prevTab())); connect(m_field, SIGNAL(closeTab()), this, SLOT(remove())); connect(this, SIGNAL(editFocus()), m_field, SLOT(setEditFocus())); QWhatsThis::add(m_field, tr("Type your message here to participate in the channel discussion")); m_popup = new QPopupMenu(m_list); m_lines = 0; /* Required so that embedded-style "right" clicks work */ QPEApplication::setStylusOperation(m_list->viewport(), QPEApplication::RightOnHold); connect(m_list, SIGNAL(mouseButtonPressed(int,QListBoxItem*,const QPoint&)), this, SLOT(mouseButtonPressed(int,QListBoxItem*,const QPoint&))); /* Construct the popup menu */ QPopupMenu *ctcpMenu = new QPopupMenu(m_list); m_popup->insertItem(Resource::loadPixmap("opieirc/query"), tr("Query"), this, SLOT(popupQuery())); ctcpMenu->insertItem(Resource::loadPixmap("opieirc/ping"), tr("Ping"), this, SLOT(popupPing())); ctcpMenu->insertItem(Resource::loadPixmap("opieirc/version"), tr("Version"), this, SLOT(popupVersion())); ctcpMenu->insertItem(Resource::loadPixmap("opieirc/whois"), tr("Whois"), this, SLOT(popupWhois())); connect(m_mainWindow, SIGNAL(updateScroll()), this, SLOT(scrolling())); m_layout->add(hbox); hbox->show(); m_layout->add(m_field); m_field->setFocus(); m_field->setActiveWindow(); connect(m_field, SIGNAL(returnPressed()), this, SLOT(processCommand())); connect(m_list, SIGNAL(doubleClicked ( QListBoxItem * ) ), this, SLOT(popupQuery( QListBoxItem * ) )); settingsChanged(); + + if(m_queuedMessages[m_channel->channelname()]) { + appendText(*m_queuedMessages[m_channel->channelname()]); + delete m_queuedMessages[m_channel->channelname()]; + m_queuedMessages.remove(m_channel->channelname()); + } } void IRCChannelTab::scrolling(){ m_textview->ensureVisible(0, m_textview->contentsHeight()); } void IRCChannelTab::appendText(QString text) { /* not using append because it creates layout problems */ QString txt = m_textview->text() + IRCTab::appendTimestamp( text ); if (m_maxLines > 0 && m_lines >= m_maxLines) { int firstBreak = txt.find('\n'); if (firstBreak != -1) { txt = "<qt bgcolor=\"" + m_backgroundColor + "\"/>" + txt.right(txt.length() - (firstBreak + 1)); } } else { m_lines++; } m_textview->ensureVisible(0, m_textview->contentsHeight()); m_textview->setText(txt); m_textview->ensureVisible(0, m_textview->contentsHeight()); int p1, p2; if ( text.contains( IRCMessageParser::tr("Received a CTCP PING from ") ) ) emit ping( title() ); else if ( (p1 = text.find("ping", 0, false) )!= -1 && (p2 = text.find( m_parentTab->server()->nick(), 0,false )) != -1 ) { int col = text.findRev("color", -1, false); if ( col < p2 ) emit ping( title() ); } emit changed(this); @@ -153,39 +162,47 @@ void IRCChannelTab::popupQuery( QListBoxItem *item) { void IRCChannelTab::popupQuery() { if ( m_list->currentItem() != -1 ) popupQuery( m_list->item(m_list->currentItem())); } void IRCChannelTab::popupPing() { //HAHA, no wonder these don't work } void IRCChannelTab::popupVersion() { } void IRCChannelTab::popupWhois() { } QString IRCChannelTab::title() { return m_channel->channelname(); } IRCSession *IRCChannelTab::session() { return m_parentTab->session(); } void IRCChannelTab::remove() { if (session()->isSessionActive()) { session()->part(m_channel); } else { m_mainWindow->killTab(this); } } +void IRCChannelTab::enqueue(const QString &channel, const QString &message) { + if (m_queuedMessages.count() == (m_queuedMessages.size() - 1) ) + /* 17 messages max */ + return; + m_queuedMessages.insert(channel, new QString(message)); +} + IRCChannel *IRCChannelTab::channel() { return m_channel; } IRCChannelList *IRCChannelTab::list() { return m_list; } + diff --git a/noncore/net/opieirc/ircchanneltab.h b/noncore/net/opieirc/ircchanneltab.h index 70b212c..ffd1d5f 100644 --- a/noncore/net/opieirc/ircchanneltab.h +++ b/noncore/net/opieirc/ircchanneltab.h @@ -2,74 +2,77 @@ OpieIRC - An embedded IRC client Copyright (C) 2002 Wenzel Jakob 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 __IRCCHANNELTAB_H #define __IRCCHANNELTAB_H #include <qpopupmenu.h> #include <qpushbutton.h> #include "irctab.h" #include "ircsession.h" #include "ircmisc.h" #include "mainwindow.h" #include "ircchannellist.h" #define LISTWIDTH 70 +template <class T> class QDict; class IRCServerTab; class IRCChannelTab : public IRCTab { Q_OBJECT public: /* IRCTab implementation */ IRCChannelTab(IRCChannel *channel, IRCServerTab *parentTab, MainWindow *mainWindow, QWidget *parent = 0, const char *name = 0, WFlags f = 0); ~IRCChannelTab(); QString title(); IRCSession *session(); IRCChannel *channel(); IRCChannelList *list(); public: void appendText(QString text); + static void enqueue(const QString &channel, const QString &message); public slots: void remove(); void settingsChanged(); void scrolling(); protected slots: void processCommand(); void toggleList(); void mouseButtonPressed(int mouse, QListBoxItem *item, const QPoint &point); /* Popup slots */ void popupQuery(QListBoxItem*); void popupQuery(); void popupPing(); void popupVersion(); void popupWhois(); protected: IRCServerTab *m_parentTab; IRCChannel *m_channel; IRCChannelList *m_list; QPushButton *m_listButton; MainWindow *m_mainWindow; QTextView *m_textview; IRCHistoryLineEdit *m_field; QPopupMenu *m_popup; bool m_listVisible; int m_lines; + static QDict<QString> m_queuedMessages; }; #endif /* __IRCCHANNELTAB_H */ diff --git a/noncore/net/opieirc/ircmessage.cpp b/noncore/net/opieirc/ircmessage.cpp index d823ad1..d0b2652 100644 --- a/noncore/net/opieirc/ircmessage.cpp +++ b/noncore/net/opieirc/ircmessage.cpp @@ -1,33 +1,36 @@ #include <qtextstream.h> +#include <qstring.h> +#include <qstringlist.h> + #include "ircmessage.h" /* * Create a new IRCMessage by evaluating * a received string */ IRCMessage::IRCMessage(QString line) { /* Remove CRs from the message */ while((line.right(1) == "\n") || (line.right(1) == "\r")) line = line.left(line.length() - 1); QTextIStream stream(&line); QString temp; stream >> temp; if (temp.startsWith(":")) { /* extract the prefix */ m_prefix = temp.right(temp.length()-1); stream >> temp; m_command = temp.upper(); m_allParameters = line.right(line.length() - m_prefix.length() - m_command.length() - 3); } else { m_command = temp.upper(); m_allParameters = line.right(line.length() - m_command.length() - 1); } /* Create a list of all parameters */ while(!(stream.atEnd())) { stream >> temp; if (temp.startsWith(":")) { /* last parameter */ m_trailing = line.right(line.length() - line.find(QChar(':'), 1) - 1); @@ -35,84 +38,110 @@ IRCMessage::IRCMessage(QString line) { break; } else { m_parameters << temp; } } m_commandNumber = m_command.toInt(&m_isNumerical); /* Is this a CTCP command */ if ((m_command == "PRIVMSG" || m_command == "NOTICE") && m_trailing.length()>0 && m_trailing.left(1) == QChar(1)) { m_ctcp = TRUE; /* Strip CTCP \001 characters */ m_allParameters = m_allParameters.replace(QRegExp(QChar(1)), ""); QTextIStream ctcpStream(&m_allParameters); if (m_command == "PRIVMSG") ctcpStream >> m_ctcpDestination; ctcpStream >> temp; m_ctcpCommand = temp.upper().right(temp.length()-1); m_parameters.clear(); int length = m_allParameters.length() - m_ctcpCommand.length() - 1; if (m_command == "PRIVMSG") length -= m_ctcpDestination.length() + 1; if (length <= 0) { m_allParameters = ""; } else { m_allParameters = m_allParameters.right(length); m_parameters << m_allParameters; } } else { m_ctcp = FALSE; } - /* - -- Uncomment to debug -- + /* + //-- Uncomment to debug -- printf("Parsed : '%s'\n", line.ascii()); printf("Prefix : '%s'\n", m_prefix.ascii()); printf("Command : '%s'\n", m_command.ascii()); printf("Allparameters : '%s'\n", m_allParameters.ascii()); for (unsigned int i=0; i<m_parameters.count(); i++) { printf("Parameter %i : '%s'\n", i, m_parameters[i].ascii()); } printf("CTCP Command : '%s'\n", m_ctcpCommand.latin1()); printf("CTCP Destination : '%s'\n", m_ctcpDestination.latin1()); - printf("CTCP param count is : '%i'\n", m_parameters.count()); + printf("CTCP param count is : '%i'\n", m_parameters.count()); + */ } QString IRCMessage::param(int param) { return m_parameters[param]; } +QStringList IRCMessage::params(const QString ¶mstring) const { + QStringList params, retvalue; + params = QStringList::split(',', paramstring); + QStringList::Iterator end = params.end(); + + for (QStringList::Iterator it = params.begin(); it != end; ++it) { + int pos = (*it).find(':'); + if(pos < 0) { + if((*it).toInt() < m_parameters.count()) + retvalue << m_parameters[(*it).toInt()]; + } + + else { + int start, end; + start = (*it).left(pos).toInt(); + end = (*it).mid(pos+1).toInt(); + for (int i=start;i<=end && i < m_parameters.count() ;++i) { + retvalue << m_parameters[i]; + } + } + } + + return retvalue; +} + QString IRCMessage::prefix() { return m_prefix; } QString IRCMessage::command() { return m_command; } QString IRCMessage::ctcpCommand() { return m_ctcpCommand; } QString IRCMessage::ctcpDestination() { return m_ctcpDestination; } unsigned short IRCMessage::commandNumber() { return m_commandNumber; } bool IRCMessage::isNumerical() { return m_isNumerical; } bool IRCMessage::isCTCP() { return m_ctcp; } QString IRCMessage::trailing() { return m_trailing; } diff --git a/noncore/net/opieirc/ircmessage.h b/noncore/net/opieirc/ircmessage.h index 0c5c879..10ba450 100644 --- a/noncore/net/opieirc/ircmessage.h +++ b/noncore/net/opieirc/ircmessage.h @@ -1,68 +1,70 @@ /* OpieIRC - An embedded IRC client Copyright (C) 2002 Wenzel Jakob 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 __IRCMESSAGE_H #define __IRCMESSAGE_H -#include <qstring.h> -#include <qstringlist.h> +class QString; +class QStringList; /* IRCMessage objects are used to encapsulate information which the IRC server sent to us. */ class IRCMessage { public: /* Parse an IRC message and create the IRCMessage object */ IRCMessage(QString line); /* Return the IRC message prefix (usually sender etc) */ QString prefix(); /* Check if this IRCMessage's command is literal or numerical */ bool isNumerical(); /* CHeck if this IRCMessage is a CTCP message */ bool isCTCP(); /* Return the IRC command (literal commands) */ QString command(); /* Return the CTCP command */ QString ctcpCommand(); /* Return the CTCP destination if applicable (channel/person) */ QString ctcpDestination(); /* Return the IRC command (numerical commands) */ unsigned short commandNumber(); /* Return the trailing parameter string */ QString trailing(); /* Return the complete parameter string */ QString allParameters(); /* Return one parameter */ QString param(int param); + /* Return some parameters */ + QStringList params(const QString ¶mstring) const; protected: QString m_prefix; QString m_command; QString m_ctcpCommand; QString m_ctcpDestination; unsigned short m_commandNumber; QString m_allParameters; QString m_trailing; QStringList m_parameters; bool m_isNumerical; bool m_ctcp; }; #endif diff --git a/noncore/net/opieirc/ircmessageparser.cpp b/noncore/net/opieirc/ircmessageparser.cpp index f8ccbb6..fde156c 100644 --- a/noncore/net/opieirc/ircmessageparser.cpp +++ b/noncore/net/opieirc/ircmessageparser.cpp @@ -1,130 +1,193 @@ #include <qtextstream.h> +#include <qdatetime.h> + #include "ircmessageparser.h" #include "ircversion.h" /* Lookup table for literal commands */ IRCLiteralMessageParserStruct IRCMessageParser::literalParserProcTable[] = { { "PING", FUNC(parseLiteralPing) }, { "NOTICE", FUNC(parseLiteralNotice) }, { "JOIN", FUNC(parseLiteralJoin) }, { "PRIVMSG", FUNC(parseLiteralPrivMsg) }, { "NICK", FUNC(parseLiteralNick) }, { "PART", FUNC(parseLiteralPart) }, { "QUIT", FUNC(parseLiteralQuit) }, { "ERROR", FUNC(parseLiteralError) }, { "ERROR:", FUNC(parseLiteralError) }, { "MODE", FUNC(parseLiteralMode) }, { "KICK", FUNC(parseLiteralKick) }, { "TOPIC", FUNC(parseLiteralTopic) }, { 0 , 0 } }; /* Lookup table for literal commands */ IRCCTCPMessageParserStruct IRCMessageParser::ctcpParserProcTable[] = { { "PING", FUNC(parseCTCPPing) }, { "VERSION", FUNC(parseCTCPVersion) }, { "ACTION", FUNC(parseCTCPAction) }, { 0 , 0 } }; -/* Lookup table for numerical commands */ +/* Lookup table for numerical commands + * According to: + * http://www.faqs.org/rfcs/rfc1459.html + * http://www.faqs.org/rfcs/rfc2812.html +*/ + IRCNumericalMessageParserStruct IRCMessageParser::numericalParserProcTable[] = { - { 1, FUNC(parseNumericalSecondParam) }, // RPL_WELCOME - { 2, FUNC(parseNumericalSecondParam) }, // RPL_YOURHOST - { 3, FUNC(parseNumericalSecondParam) }, // RPL_CREATED - { 4, FUNC(parseNumericalAllParams) }, // RPL_MYINFO - { 5, FUNC(parseNumericalSecondParam) }, // RPL_BOUNCE, RPL_PROTOCTL - { 250, FUNC(parseNumericalAllParams) }, // RPL_STATSCONN - { 251, FUNC(parseNumericalSecondParam) }, // RPL_LUSERCLIENT - { 252, FUNC(parseNumericalAllParams) }, // RPL_LUSEROP - { 253, FUNC(parseNumericalAllParams) }, // RPL_LUSERUNKNOWN - { 254, FUNC(parseNumericalAllParams) }, // RPL_LUSERCHANNELS - { 255, FUNC(parseNumericalSecondParam) }, // RPL_LUSERME - { 265, FUNC(parseNumericalAllParams) }, // RPL_LOCALUSERS - { 266, FUNC(parseNumericalAllParams) }, // RPL_GLOBALUSERS - { 332, FUNC(parseNumericalTopic) }, // RPL_TOPIC - { 333, FUNC(parseNumericalTopicWhoTime) }, // RPL_TOPICWHOTIME - { 353, FUNC(parseNumericalNames) }, // RPL_NAMREPLY - { 366, FUNC(parseNumericalEndOfNames) }, // RPL_ENDOFNAMES - { 372, FUNC(parseNumericalSecondParam) }, // RPL_MOTD - { 375, FUNC(parseNumericalSecondParam) }, // RPL_MOTDSTART - { 376, FUNC(parseNumericalSecondParam) }, // RPL_ENDOFMOTD - { 377, FUNC(parseNumericalSecondParam) }, // RPL_MOTD2 - { 378, FUNC(parseNumericalSecondParam) }, // RPL_MOTD3 - { 401, FUNC(parseNumericalNoSuchNick) }, // ERR_NOSUCHNICK - { 406, FUNC(parseNumericalNoSuchNick) }, // ERR_WASNOSUCHNICK - { 412, FUNC(parseNumericalSecondParam) }, // ERR_NOTEXTTOSEND - { 422, FUNC(parseNumericalSecondParam) }, // ERR_NOMOTD - { 433, FUNC(parseNumericalNicknameInUse) }, // ERR_NICKNAMEINUSE - { 0, 0 } + { 1, "%1", "1", FUNC(parseNumericalServerName) }, // RPL_WELCOME + { 2, "%1", "1", 0 }, // RPL_YOURHOST + { 3, "%1", "1", 0 }, // RPL_CREATED + { 4, QT_TR_NOOP("Server %1 version %2 supports usermodes '%3' and channelmodes '%4'"), "1:4", FUNC(parseNumericalServerFeatures) }, // RPL_MYINFO + { 5, 0, 0, FUNC(parseNumericalServerProtocol) }, // RPL_BOUNCE, RPL_PROTOCTL + { 250, "%1", "1", 0 }, // RPL_STATSCONN + { 251, "%1", "1", 0 }, // RPL_LUSERCLIENT + { 252, QT_TR_NOOP("There are %1 operators connected"), "1", 0 }, // RPL_LUSEROP + { 253, QT_TR_NOOP("There are %1 unknown connection(s)"), "1", 0 }, // RPL_LUSERUNKNOWN + { 254, QT_TR_NOOP("There are %1 channels formed"), "1", 0 }, // RPL_LUSERCHANNELS + { 255, "%1", "1", 0 }, // RPL_LUSERME + { 263, QT_TR_NOOP("Please wait a while and try again"), 0, 0 }, // RPL_TRYAGAIN + { 265, "%1", "1", 0 }, // RPL_LOCALUSERS + { 266, "%1", "1", 0 }, // RPL_GLOBALUSERS + { 311, QT_TR_NOOP("Whois %1 (%2@%3)\nReal name: %4"), "1:3,5" }, // RPL_WHOISUSER + { 312, QT_TR_NOOP("%1 is using server %2"), "1,2", 0 }, // RPL_WHOISSERVER + { 317, 0, 0, FUNC(parseNumericalWhoisIdle) }, // RPL_WHOISIDLE + { 318, "%1 :%2", "1,2", 0 }, // RPL_ENDOFWHOIS + { 320, "%1 %2", "1,2", 0}, // RPL_WHOISVIRT + { 332, 0, 0, FUNC(parseNumericalTopic) }, // RPL_TOPIC + { 333, 0, 0, FUNC(parseNumericalTopicWhoTime) }, // RPL_TOPICWHOTIME*/ + { 353, QT_TR_NOOP("Names for %1: %2"), "2,3", FUNC(parseNumericalNames) }, // RPL_NAMREPLY + { 366, "%1 :%2", "1,2", FUNC(parseNumericalEndOfNames) }, // RPL_ENDOFNAMES + { 369, "%1 :%2", "1,2", 0 }, // RPL_ENDOFWHOWAS + { 372, "%1", "1", 0 }, // RPL_MOTD + { 375, "%1", "1", 0 }, // RPL_MOTDSTART + { 376, "%1", "1", 0 }, // RPL_ENDOFMOTD + { 377, "%1", "1", 0 }, // RPL_MOTD2 + { 378, "%1", "1", 0 }, // RPL_MOTD3 + { 391, QT_TR_NOOP("Time on server %1 is %2"), "1,2", 0 }, // RPL_TIME + { 401, QT_TR_NOOP("Channel or nick %1 doesn't exists"), "1", 0 }, // ERR_NOSUCHNICK + { 406, QT_TR_NOOP("There is no history information for %1"), "1" }, // ERR_WASNOSUCHNICK + { 409, "%1", "1", 0 }, // ERR_NOORIGIN + { 411, "%1", "1", 0 }, // ERR_NORECIPIENT + { 412, "%1", "1", 0 }, // ERR_NOTEXTTOSEND + { 421, QT_TR_NOOP("Unknown command: %1"), "1", 0 }, // ERR_NOMOTD + { 422, QT_TR_NOOP("You're not on channel %1"), "1", 0}, // ERR_NOTONCHANNEL + { 422, "%1", "1", 0 }, // ERR_NOMOTD + { 433, QT_TR_NOOP("Can't change nick to %1: %2"), "1,2", FUNC(parseNumericalNicknameInUse) }, // ERR_NICKNAMEINUSE + { 477, "%1", "1", 0 }, // ERR_NOCHANMODES || ERR_NEEDREGGEDNICK + { 482, QT_TR_NOOP("[%1] Operation not permitted, you don't have enough channel privileges"), "1", 0 }, //ERR_CHANOPRIVSNEEDED + { 0, 0, 0, 0 } }; IRCMessageParser::IRCMessageParser(IRCSession *session) { m_session = session; } void IRCMessageParser::parse(IRCMessage *message) { /* Find out what kind of message we have here and call the appropriate handler using the parser tables. If no handler can be found, print out an error message */ if (message->isNumerical()) { for (int i=0; i<numericalParserProcTable[i].commandNumber; i++) { if (message->commandNumber() == numericalParserProcTable[i].commandNumber) { - (this->*(numericalParserProcTable[i].proc))(message); + parseNumerical(message, i); return; } } emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Received unhandled numeric command: %1").arg( QString::number(message->commandNumber()) ))); } else if (message->isCTCP()) { for (int i=0; ctcpParserProcTable[i].commandName; i++) { if (message->ctcpCommand() == ctcpParserProcTable[i].commandName) { (this->*(ctcpParserProcTable[i].proc))(message); return; } } emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Received unhandled ctcp command: %1").arg( message->ctcpCommand())) ); } else { for (int i=0; literalParserProcTable[i].commandName; i++) { if (message->command() == literalParserProcTable[i].commandName) { (this->*(literalParserProcTable[i].proc))(message); return; } } emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Received unhandled literal command: %1").arg( message->command()) )); } } -void IRCMessageParser::nullFunc(IRCMessage *) { - /* Do nothing */ +void IRCMessageParser::parseNumerical(IRCMessage *message, int position) { + QString out = tr(numericalParserProcTable[position].message); + QString paramString = numericalParserProcTable[position].params; + + if(!out.isEmpty() && !paramString.isEmpty()) { + QStringList params = message->params(numericalParserProcTable[position].params); + + QStringList::Iterator end = params.end(); + for (QStringList::Iterator it = params.begin(); it != end; ++it) { + out = out.arg(*it); + } + + emit outputReady(IRCOutput(OUTPUT_SERVERMESSAGE, out)); + } + + if(numericalParserProcTable[position].proc) + (this->*(numericalParserProcTable[position].proc))(message); +} + +void IRCMessageParser::parseNumericalServerName(IRCMessage *message) { + emit outputReady(IRCOutput(OUTPUT_TITLE, tr("Connected to")+" <b>" + message->prefix() + "</b>")); +} + +void IRCMessageParser::parseNumericalServerFeatures(IRCMessage *message) { + m_session->setValidUsermodes(message->param(2)); + m_session->setValidChannelmodes(message->param(3)); + +} + +void IRCMessageParser::parseNumericalServerProtocol(IRCMessage *message) { + /* XXX: Add some usefull features here */ + QString out = message->allParameters(); + out = out.mid(out.find(' ')+1); + emit outputReady(IRCOutput(OUTPUT_SERVERMESSAGE, out)); +} +void IRCMessageParser::parseNumericalWhoisIdle(IRCMessage *message) { + QDateTime dt; + QTime t; + t = t.addSecs(message->param(2).toInt()); + dt.setTime_t(message->param(3).toInt()); + + emit outputReady(IRCOutput(OUTPUT_SERVERMESSAGE, tr("%1 has been idle for %2").arg(message->param(1)).arg(t.toString()))); + emit outputReady(IRCOutput(OUTPUT_SERVERMESSAGE, tr("%1 signed on %2").arg(message->param(1)).arg(dt.toString()))); + } void IRCMessageParser::parseLiteralPing(IRCMessage *message) { m_session->m_connection->sendLine("PONG " + message->allParameters()); } void IRCMessageParser::parseLiteralNotice(IRCMessage *message) { emit outputReady(IRCOutput(OUTPUT_SERVERMESSAGE, message->allParameters())); } void IRCMessageParser::parseLiteralJoin(IRCMessage *message) { QString channelName = message->param(0).lower(); IRCPerson mask(message->prefix()); IRCChannel *channel = m_session->getChannel(channelName); if (!channel) { /* We joined */ if (mask.nick() == m_session->m_server->nick()) { channel = new IRCChannel(channelName); m_session->addChannel(channel); } else { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Nonexistant channel join - desynchronized?"))); } } else { /* Someone else joined */ if (mask.nick() != m_session->m_server->nick()) { if (!channel->getPerson(mask.nick())) { IRCChannelPerson *chanperson = new IRCChannelPerson(); IRCPerson *person = m_session->getPerson(mask.nick()); if (!person) { person = new IRCPerson(message->prefix()); m_session->addPerson(person); } @@ -180,97 +243,97 @@ void IRCMessageParser::parseLiteralPrivMsg(IRCMessage *message) { IRCPerson *person = m_session->getPerson(mask.nick()); if (!person) { /* Person not yet known, create and add to the current session */ person = new IRCPerson(message->prefix()); m_session->addPerson(person); } IRCOutput output(OUTPUT_QUERYPRIVMSG, message->param(1)); output.addParam(person); emit outputReady(output); } else if (message->param(0).at(0) == '#' || message->param(0).at(0) == '+') { /* IRC Channel message detected, verify sender, channel and display it */ IRCChannel *channel = m_session->getChannel(message->param(0).lower()); if (channel) { IRCPerson mask(message->prefix()); IRCChannelPerson *person = channel->getPerson(mask.nick()); if (person) { IRCOutput output(OUTPUT_CHANPRIVMSG, message->param(1)); output.addParam(channel); output.addParam(person); emit outputReady(output); } else { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Channel message with unknown sender"))); } } else { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Channel message with unknown channel %1").arg(message->param(0).lower()) )); } } else { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Received PRIVMSG of unknown type"))); } } void IRCMessageParser::parseLiteralNick(IRCMessage *message) { - IRCPerson mask(message->prefix()); - /* this way of handling nick changes really sucks */ + m_session->updateNickname(mask.nick(), message->param(0)); + /* this way of handling nick changes really sucks if (mask.nick() == m_session->m_server->nick()) { - /* We are changing our nickname */ + We are changing our nickname m_session->m_server->setNick(message->param(0)); IRCOutput output(OUTPUT_NICKCHANGE, tr("You are now known as %1").arg( message->param(0))); output.addParam(0); emit outputReady(output); } else { - /* Someone else is */ - IRCPerson *person = m_session->getPerson(mask.nick()); + Someone else is + RCPerson *person = m_session->getPerson(mask.nick()); if (person) { //IRCOutput output(OUTPUT_NICKCHANGE, tr("%1 is now known as %2").arg( mask.nick() ).arg( message->param(0))); - /* new code starts here -- this removes the person from all channels */ + new code starts here -- this removes the person from all channels QList<IRCChannel> channels; m_session->getChannelsByPerson(person, channels); QListIterator<IRCChannel> it(channels); for (;it.current(); ++it) { IRCChannelPerson *chanperson = it.current()->getPerson(mask.nick()); it.current()->removePerson(chanperson); chanperson->person->setNick(message->param(0)); it.current()->addPerson(chanperson); IRCOutput output(OUTPUT_NICKCHANGE, tr("%1 is now known as %2").arg( mask.nick() ).arg( message->param(0))); output.addParam(person); emit outputReady(output); } - /* new code ends here */ + new code ends here } else { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Nickname change of an unknown person"))); } - } + }*/ } void IRCMessageParser::parseLiteralQuit(IRCMessage *message) { IRCPerson mask(message->prefix()); IRCPerson *person = m_session->getPerson(mask.nick()); if (person) { QList<IRCChannel> channels; m_session->getChannelsByPerson(person, channels); QListIterator<IRCChannel> it(channels); for (;it.current(); ++it) { IRCChannelPerson *chanperson = it.current()->getPerson(mask.nick()); it.current()->removePerson(chanperson); delete chanperson; } m_session->removePerson(person); IRCOutput output(OUTPUT_QUIT, tr("%1 has quit (%2)" ).arg( mask.nick() ).arg( message->param(0) )); output.addParam(person); emit outputReady(output); delete person; } else { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Unknown person quit - desynchronized?"))); } } void IRCMessageParser::parseLiteralTopic(IRCMessage *message) { IRCPerson mask(message->prefix()); IRCChannel *channel = m_session->getChannel(message->param(0).lower()); if (channel) { IRCOutput output(OUTPUT_TOPIC, mask.nick() + tr(" changed topic to ") + "\"" + message->param(1) + "\""); output.addParam(channel); emit outputReady(output); } else { @@ -295,65 +358,65 @@ void IRCMessageParser::parseCTCPPing(IRCMessage *message) { IRCChannelPerson *person = channel->getPerson(mask.nick()); if (person) { IRCOutput output(OUTPUT_CHANACTION, tr("Received a CTCP PING from ")+ mask.nick()) ; output.addParam(channel); output.addParam(person); emit outputReady(output); } else { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("CTCP PING with unknown person - Desynchronized?"))); } } else { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("CTCP PING with unknown channel - Desynchronized?"))); } } else { if (message->ctcpDestination() == m_session->m_server->nick()) { IRCPerson *person = m_session->getPerson(mask.nick()); if (!person) { /* Person not yet known, create and add to the current session */ person = new IRCPerson(message->prefix()); m_session->addPerson(person); } IRCOutput output(OUTPUT_QUERYACTION, tr("Received a CTCP PING from ")+ mask.nick() ); output.addParam(person); emit outputReady(output); } else { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("CTCP PING with bad recipient"))); } } } void IRCMessageParser::parseCTCPVersion(IRCMessage *message) { IRCPerson mask(message->prefix()); - m_session->m_connection->sendCTCP(mask.nick(), APP_VERSION " " APP_COPYSTR); + m_session->m_connection->sendCTCP(mask.nick(), "VERSION " APP_VERSION " " APP_COPYSTR); emit outputReady(IRCOutput(OUTPUT_CTCP, tr("Received a CTCP VERSION from ")+mask.nick())); } void IRCMessageParser::parseCTCPAction(IRCMessage *message) { IRCPerson mask(message->prefix()); QString dest = message->ctcpDestination(); if (dest.startsWith("#")) { IRCChannel *channel = m_session->getChannel(dest.lower()); if (channel) { IRCChannelPerson *person = channel->getPerson(mask.nick()); if (person) { IRCOutput output(OUTPUT_CHANACTION, "*" + mask.nick() + message->param(0)); output.addParam(channel); output.addParam(person); emit outputReady(output); } else { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("CTCP ACTION with unknown person - Desynchronized?"))); } } else { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("CTCP ACTION with unknown channel - Desynchronized?"))); } } else { if (message->ctcpDestination() == m_session->m_server->nick()) { IRCPerson *person = m_session->getPerson(mask.nick()); if (!person) { /* Person not yet known, create and add to the current session */ person = new IRCPerson(message->prefix()); m_session->addPerson(person); } IRCOutput output(OUTPUT_QUERYACTION, "*" + mask.nick() + message->param(0)); output.addParam(person); emit outputReady(output); @@ -434,126 +497,121 @@ void IRCMessageParser::parseLiteralMode(IRCMessage *message) { } else { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("User modes not supported yet"))); } } void IRCMessageParser::parseLiteralKick(IRCMessage *message) { IRCPerson mask(message->prefix()); IRCChannel *channel = m_session->getChannel(message->param(0).lower()); if (channel) { IRCChannelPerson *person = channel->getPerson(message->param(1)); if (person) { if (person->person->nick() == m_session->m_server->nick()) { m_session->removeChannel(channel); IRCOutput output(OUTPUT_SELFKICK, tr("You were kicked from ") + channel->channelname() + tr(" by ") + mask.nick() + " (" + message->param(2) + ")"); output.addParam(channel); emit outputReady(output); } else { /* someone else got kicked */ channel->removePerson(person); IRCOutput output(OUTPUT_OTHERKICK, person->person->nick() + tr(" was kicked from ") + channel->channelname() + tr(" by ") + mask.nick()+ " (" + message->param(2) + ")"); output.addParam(channel); output.addParam(person); emit outputReady(output); } } else { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Unknown person kick - desynchronized?"))); } } else { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Unknown channel kick - desynchronized?"))); } } - -void IRCMessageParser::parseNumericalSecondParam(IRCMessage *message) { - emit outputReady(IRCOutput(OUTPUT_SERVERMESSAGE, message->param(1))); -} - -void IRCMessageParser::parseNumericalAllParams(IRCMessage *message) { - emit outputReady(IRCOutput(OUTPUT_SERVERMESSAGE, message->allParameters())); -} - void IRCMessageParser::parseNumericalNames(IRCMessage *message) { /* Name list sent when joining a channel */ IRCChannel *channel = m_session->getChannel(message->param(2).lower()); if (channel != 0) { QString people = message->param(3); QTextIStream stream(&people); QString temp; while (!stream.atEnd()) { stream >> temp; char flagch = temp.at(0).latin1(); int flag = 0; QString nick; /* Parse person flags */ if (flagch == '@' || flagch == '+' || flagch=='%' || flagch == '*') { nick = temp.right(temp.length()-1); switch (flagch) { case '@': flag = PERSON_FLAG_OP; break; case '+': flag = PERSON_FLAG_VOICE; break; case '%': flag = PERSON_FLAG_HALFOP; break; default : flag = 0; break; } } else { nick = temp; } IRCChannelPerson *chan_person = new IRCChannelPerson(); IRCPerson *person = m_session->getPerson(nick); if (person == 0) { person = new IRCPerson(); person->setNick(nick); m_session->addPerson(person); } chan_person->person = person; chan_person->flags = flag; channel->addPerson(chan_person); } } else { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Server message with unknown channel"))); } } void IRCMessageParser::parseNumericalEndOfNames(IRCMessage *message) { /* Done syncing to channel */ IRCChannel *channel = m_session->getChannel(message->param(1).lower()); if (channel) { channel->setHasPeople(TRUE); /* Yes, we want the names before anything happens inside the GUI */ IRCOutput output(OUTPUT_SELFJOIN, tr("You joined channel ") + channel->channelname()); output.addParam(channel); emit outputReady(output); } else { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Server message with unknown channel"))); } } void IRCMessageParser::parseNumericalNicknameInUse(IRCMessage *) { + /* If we are connnected this error is not critical */ + if(m_session->isLoggedIn()) + return; + emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Nickname is in use, please reconnect with a different nickname"))); m_session->endSession(); } void IRCMessageParser::parseNumericalNoSuchNick(IRCMessage *) { emit outputReady(IRCOutput(OUTPUT_ERROR, tr("No such nickname"))); } void IRCMessageParser::parseNumericalTopic(IRCMessage *message) { IRCChannel *channel = m_session->getChannel(message->param(1).lower()); if (channel) { IRCOutput output(OUTPUT_TOPIC, tr("Topic for channel " + channel->channelname() + " is \"" + message->param(2) + "\"")); output.addParam(channel); emit outputReady(output); } else { IRCOutput output(OUTPUT_TOPIC, tr("Topic for channel " + message->param(1) + " is \"" + message->param(2) + "\"")); output.addParam(0); emit outputReady(output); } } void IRCMessageParser::parseNumericalTopicWhoTime(IRCMessage *) { } diff --git a/noncore/net/opieirc/ircmessageparser.h b/noncore/net/opieirc/ircmessageparser.h index 5412f5f..2fca61e 100644 --- a/noncore/net/opieirc/ircmessageparser.h +++ b/noncore/net/opieirc/ircmessageparser.h @@ -17,79 +17,83 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __IRCMESSAGEPARSER_H #define __IRCMESSAGEPARSER_H #include "ircsession.h" /* Macro to facilitate the parser table's creation */ #define FUNC(__proc) &IRCMessageParser::__proc class IRCMessageParser; /* Typedef representing a parser function */ typedef void (IRCMessageParser::*IRCMessageParseProc)(IRCMessage *); /* Struct representing a literal command handler */ typedef struct IRCLiteralMessageParserStruct { char *commandName; IRCMessageParseProc proc; }; /* Struct representing a ctcp command handler */ typedef struct IRCCTCPMessageParserStruct { char *commandName; IRCMessageParseProc proc; }; /* Struct representing a numerical command handler */ typedef struct IRCNumericalMessageParserStruct { unsigned short commandNumber; + char *message; + char *params; IRCMessageParseProc proc; }; class IRCMessageParser : public QObject { Q_OBJECT public: /* Create an IRCMessageParser object */ IRCMessageParser(IRCSession *session); /* Parse a server message and take the appropriate actions */ void parse(IRCMessage *message); signals: /* Used to send commands to the UI (such as displaying text etc) */ void outputReady(IRCOutput output); private: /* Parser functions */ - void nullFunc(IRCMessage *message); void parseLiteralPing(IRCMessage *message); void parseLiteralNotice(IRCMessage *message); void parseLiteralJoin(IRCMessage *message); void parseLiteralPrivMsg(IRCMessage *message); void parseLiteralNick(IRCMessage *message); void parseLiteralPart(IRCMessage *message); void parseLiteralQuit(IRCMessage *message); void parseLiteralError(IRCMessage *message); void parseLiteralMode(IRCMessage *message); void parseLiteralKick(IRCMessage *message); void parseLiteralTopic(IRCMessage *message); - void parseNumericalSecondParam(IRCMessage *message); - void parseNumericalAllParams(IRCMessage *message); + void parseNumerical(IRCMessage *message, int position); + void parseNumericalServerName(IRCMessage *message); + void parseNumericalServerFeatures(IRCMessage *message); + void parseNumericalServerProtocol(IRCMessage *message); + void parseNumericalWhoisIdle(IRCMessage *message); void parseNumericalNames(IRCMessage *message); void parseNumericalEndOfNames(IRCMessage *message); void parseNumericalNicknameInUse(IRCMessage *message); void parseNumericalNoSuchNick(IRCMessage *message); void parseNumericalTopic(IRCMessage *message); void parseNumericalTopicWhoTime(IRCMessage *message); void parseCTCPPing(IRCMessage *message); void parseCTCPVersion(IRCMessage *message); void parseCTCPAction(IRCMessage *message); protected: IRCSession *m_session; /* Parser tables */ static IRCLiteralMessageParserStruct literalParserProcTable[]; static IRCNumericalMessageParserStruct numericalParserProcTable[]; static IRCCTCPMessageParserStruct ctcpParserProcTable[]; }; #endif /* __IRCMESSAGEPARSER_H */ diff --git a/noncore/net/opieirc/ircserver.cpp b/noncore/net/opieirc/ircserver.cpp index e27e41d..7e7e412 100644 --- a/noncore/net/opieirc/ircserver.cpp +++ b/noncore/net/opieirc/ircserver.cpp @@ -1,74 +1,83 @@ #include "ircserver.h" +#include "ircversion.h" + +#include <qobject.h> IRCServer::IRCServer() { m_port = 6667; } /* Setter implementations */ void IRCServer::setHostname(QString hostname) { m_hostname = hostname; } void IRCServer::setName(QString name) { m_name = name; } void IRCServer::setPort(int port) { m_port = port; } void IRCServer::setUsername(QString username) { m_username = username; } void IRCServer::setPassword(QString password) { m_password = password; } void IRCServer::setNick(QString nick) { m_nick = nick; } void IRCServer::setRealname(QString realname) { m_realname = realname; } void IRCServer::setChannels(QString channels) { m_channels = channels; } /* Getter implementations */ QString IRCServer::hostname() { return m_hostname; } QString IRCServer::name() { return m_name; } unsigned short int IRCServer::port() { - return m_port; + if(m_port) + return m_port; + + return 6667; } QString IRCServer::username() { return m_username; } QString IRCServer::password() { return m_password; } QString IRCServer::nick() { return m_nick; } QString IRCServer::realname() { - return m_realname; + if(!m_realname.isEmpty()) + return m_realname; + + return QString(QObject::tr("Using")) + " " + QString(APP_VERSION); } QString IRCServer::channels() { return m_channels; } diff --git a/noncore/net/opieirc/ircservereditor.cpp b/noncore/net/opieirc/ircservereditor.cpp index 2d11bf0..1fda868 100644 --- a/noncore/net/opieirc/ircservereditor.cpp +++ b/noncore/net/opieirc/ircservereditor.cpp @@ -29,64 +29,64 @@ IRCServerEditor::IRCServerEditor(IRCServer server, QWidget* parent, const char* label = new QLabel(tr("Nickname :"), this); m_nickname = new QLineEdit(server.nick(), this); QWhatsThis::add(m_nickname, tr("Your nick name on the IRC network")); layout->addWidget(label, 3, 0); layout->addWidget(m_nickname, 3, 1); label = new QLabel(tr("Realname :"), this); m_realname = new QLineEdit(server.realname(), this); QWhatsThis::add(m_realname, tr("Your real name")); layout->addWidget(label, 4, 0); layout->addWidget(m_realname, 4, 1); label = new QLabel(tr("Password :"), this); m_password = new QLineEdit(server.password(), this); m_password->setEchoMode( QLineEdit::Password ); QWhatsThis::add(m_password, tr("Password to connect to the server (if required)")); layout->addWidget(label, 5, 0); layout->addWidget(m_password, 5, 1); label = new QLabel(tr("Channels :"), this); m_channels = new QLineEdit(server.channels(), this); QWhatsThis::add(m_channels, tr("Comma-Separated list of all channels you would like to join automatically")); layout->addWidget(label, 6, 0); layout->addWidget(m_channels, 6, 1); setCaption(tr("Edit server information")); QPEApplication::showDialog( this ); } void IRCServerEditor::accept() { if (m_name->text().length()==0) QMessageBox::critical(this, tr("Error"), tr("Profile name required")); else if (m_hostname->text().length()==0) QMessageBox::critical(this, tr("Error"), tr("Host name required")); - else if (m_port->text().toInt()<=0) - QMessageBox::critical(this, tr("Error"), tr("Port required")); + //else if (m_port->text().toInt()<=0) + // QMessageBox::critical(this, tr("Error"), tr("Port required")); else if (m_nickname->text().length()==0) QMessageBox::critical(this, tr("Error"), tr("Nickname required")); - else if (m_realname->text().length()==0) - QMessageBox::critical(this, tr("Error"), tr("Realname required")); + //else if (m_realname->text().length()==0) + // QMessageBox::critical(this, tr("Error"), tr("Realname required")); else { /* Now verify whether the channel list has a valid format */ QStringList channels = QStringList::split(QChar(','), m_channels->text()); for (QStringList::Iterator it = channels.begin(); it != channels.end(); ++it) { QString channelName = (*it).stripWhiteSpace(); if (!channelName.startsWith("#") && !channelName.startsWith("+")) { QMessageBox::critical(this, tr("Error"), tr("The channel list needs to contain a\ncomma separated list of channel\n names which start with either '#' or '+'")); return; } } QDialog::accept(); } } IRCServer IRCServerEditor::getServer() { IRCServer server; server.setName(m_name->text()); server.setHostname(m_hostname->text()); server.setPort(m_port->text().toInt()); server.setNick(m_nickname->text()); server.setRealname(m_realname->text()); server.setUsername(m_nickname->text()); server.setPassword(m_password->text()); server.setChannels(m_channels->text()); return server; } diff --git a/noncore/net/opieirc/ircservertab.cpp b/noncore/net/opieirc/ircservertab.cpp index e031d4d..90353f2 100644 --- a/noncore/net/opieirc/ircservertab.cpp +++ b/noncore/net/opieirc/ircservertab.cpp @@ -1,69 +1,70 @@ #include <qtextstream.h> #include <qwhatsthis.h> #include "ircservertab.h" #include "ircmessageparser.h" bool IRCServerTab::containsPing( const QString& text, IRCServerTab* tab ) { return (text.contains(IRCMessageParser::tr("Received a CTCP PING from "))) || (text.find("ping") != -1 && text.find( tab->server()->nick() != -1)); } IRCServerTab::IRCServerTab(IRCServer server, MainWindow *mainWindow, QWidget *parent, const char *name, WFlags f) : IRCTab(parent, name, f) { m_server = server; m_session = new IRCSession(&m_server); m_mainWindow = mainWindow; m_close = FALSE; m_lines = 0; - m_description->setText(tr("Connection to")+" <b>" + server.hostname() + ":" + QString::number(server.port()) + "</b>"); + m_description->setText(tr("Connecting to")+" <b>" + server.hostname() + ":" + QString::number(server.port()) + "</b>"); m_textview = new QTextView(this); m_textview->setHScrollBarMode(QScrollView::AlwaysOff); m_textview->setVScrollBarMode(QScrollView::AlwaysOn); m_textview->setTextFormat(RichText); QWhatsThis::add(m_textview, tr("Server messages")); m_layout->add(m_textview); m_field = new IRCHistoryLineEdit(this); connect(m_field, SIGNAL(nextTab()), this, SIGNAL(nextTab())); connect(m_field, SIGNAL(prevTab()), this, SIGNAL(prevTab())); connect(m_field, SIGNAL(closeTab()), this, SIGNAL(closeTab())); connect(this, SIGNAL(editFocus()), m_field, SLOT(setEditFocus())); QWhatsThis::add(m_field, tr("Type commands here. A list of available commands can be found inside the OpieIRC help")); m_layout->add(m_field); connect(m_field, SIGNAL(returnPressed()), this, SLOT(processCommand())); connect(m_session, SIGNAL(outputReady(IRCOutput)), this, SLOT(display(IRCOutput))); connect(m_mainWindow, SIGNAL(updateScroll()), this, SLOT(scrolling())); + connect(m_session, SIGNAL(updateChannels()), this, SLOT(slotUpdateChannels())); settingsChanged(); m_field->setFocus(); m_field->setActiveWindow(); } void IRCServerTab::scrolling(){ m_textview->ensureVisible(0, m_textview->contentsHeight()); } void IRCServerTab::appendText(QString text) { /* not using append because it creates layout problems */ QString txt = m_textview->text() + IRCTab::appendTimestamp( text ); if (m_maxLines > 0 && m_lines >= m_maxLines) { int firstBreak = txt.find('\n'); if (firstBreak != -1) { txt = "<qt bgcolor=\"" + m_backgroundColor + "\"/>" + txt.right(txt.length() - (firstBreak + 1)); } } else { m_lines++; } m_textview->setText(txt); m_textview->ensureVisible(0, m_textview->contentsHeight()); emit changed(this); } IRCServerTab::~IRCServerTab() { @@ -84,65 +85,71 @@ void IRCServerTab::addQueryTab(IRCQueryTab *tab) { QString IRCServerTab::title() { return "Server"; } IRCSession *IRCServerTab::session() { return m_session; } /* QString *IRCServerTab::mynick() { return (*m_server->nick()); } */ IRCServer *IRCServerTab::server() { return &m_server; } void IRCServerTab::settingsChanged() { m_textview->setText("<qt bgcolor=\"" + m_backgroundColor + "\"/>"); m_lines = 0; } void IRCServerTab::executeCommand(IRCTab *tab, QString line) { QTextIStream stream(&line); QString command; stream >> command; command = command.upper().right(command.length()-1); //JOIN if (command == "JOIN" || command == "J") { QString channel; stream >> channel; - if (channel.length() > 0 && (channel.startsWith("#") || channel.startsWith("+"))) { + /* According to RFC 1459 */ + if (channel.length() > 0 && channel.length() < 200 && + channel.find(",") == -1 && channel.find("") == -1) { + + if (!channel.startsWith("#") && !channel.startsWith("&")) { + channel = channel.prepend("#"); + } m_session->join(channel); } else { tab->appendText("<font color=\"" + m_errorColor + "\">Unknown channel format!</font><br>"); } } //KICK else if (command == "KICK"){ QString nickname; stream >> nickname; if (nickname.length() > 0) { if (line.length() > 7 + nickname.length()) { QString text = line.right(line.length()-nickname.length()-7); IRCPerson person; person.setNick(nickname); m_session->kick(((IRCChannelTab *)tab)->channel(), &person, text); } else { IRCPerson person; person.setNick(nickname); m_session->kick(((IRCChannelTab *)tab)->channel(), &person); } } } else if (command == "OP"){ QString nickname; stream >> nickname; if (nickname.length() > 0) { QString text = line.right(line.length()-nickname.length()-5); IRCPerson person; person.setNick(nickname); m_session->op(((IRCChannelTab *)tab)->channel(), &person); @@ -316,78 +323,92 @@ void IRCServerTab::display(IRCOutput output) { m_mainWindow->addTab(queryTab); } queryTab->display(output); } break; case OUTPUT_SELFPART: { IRCChannelTab *channelTab = getTabForChannel((IRCChannel *)output.getParam(0)); if (channelTab) m_mainWindow->killTab(channelTab, true); } break; case OUTPUT_SELFKICK: { appendText("<font color=\"" + m_errorColor + "\">" + output.htmlMessage() + "</font><br>"); IRCChannelTab *channelTab = getTabForChannel((IRCChannel *)output.getParam(0)); if (channelTab) m_mainWindow->killTab(channelTab, true); } break; case OUTPUT_CHANACTION: { IRCChannelTab *channelTab = getTabForChannel((IRCChannel *)output.getParam(0)); channelTab->appendText("<font color=\"" + m_otherColor + "\">"+output.htmlMessage()+"</font><br>"); } break; case OUTPUT_TOPIC: { IRCChannel *channel = (IRCChannel *) output.getParam(0); if (channel) { IRCChannelTab *channelTab = getTabForChannel(channel); if (channelTab) { channelTab->appendText("<font color=\"" + m_notificationColor + "\">"+output.htmlMessage()+"</font><br>"); return; } } - appendText("<font color=\"" + m_notificationColor + "\">"+output.htmlMessage()+"</font><br>"); + IRCChannelTab::enqueue(channel->channelname(), "<font color=\"" + m_notificationColor + "\">"+output.htmlMessage()+"</font><br>"); } break; case OUTPUT_QUIT: { QString nick = ((IRCPerson *)output.getParam(0))->nick(); QListIterator<IRCChannelTab> it(m_channelTabs); for (; it.current(); ++it) { if (it.current()->list()->hasPerson(nick)) { it.current()->appendText("<font color=\"" + m_notificationColor + "\">"+output.htmlMessage()+"</font><br>"); it.current()->list()->update(); } } } break; -/* case OUTPUT_NICKCHANGE: { - //WAS HERE - QString nick = ((IRCPerson *)output.getParam(0))->nick(); + case OUTPUT_NICKCHANGE: { + QString *nick = static_cast<QString*>(output.getParam(0)); + if(!nick) { + appendText("<font color=\"" + m_notificationColor + "\">"+output.htmlMessage()+"</font><br>"); + break; + } QListIterator<IRCChannelTab> it(m_channelTabs); for (; it.current(); ++it) { - if (it.current()->list()->hasPerson(nick)) { + if (it.current()->list()->hasPerson(*nick)) { it.current()->appendText("<font color=\"" + m_notificationColor + "\">"+output.htmlMessage()+"</font><br>"); - it.current()->list()->update(); } } + delete nick; } break; - */ case OUTPUT_OTHERJOIN: + case OUTPUT_OTHERJOIN: case OUTPUT_OTHERKICK: case OUTPUT_CHANPERSONMODE: case OUTPUT_OTHERPART: { IRCChannelTab *channelTab = getTabForChannel((IRCChannel *)output.getParam(0)); channelTab->appendText("<font color=\"" + m_notificationColor + "\">"+output.htmlMessage()+"</font><br>"); channelTab->list()->update(); } break; case OUTPUT_CTCP: appendText("<font color=\"" + m_notificationColor + "\">" + output.htmlMessage() + "</font><br>"); break; case OUTPUT_ERROR: appendText("<font color=\"" + m_errorColor + "\">" + output.htmlMessage() + "</font><br>"); break; + case OUTPUT_TITLE: + m_description->setText(output.message()); + break; default: appendText("<font color=\"" + m_serverColor + "\">" + output.htmlMessage() + "</font><br>"); break; } } + +void IRCServerTab::slotUpdateChannels() { + QListIterator<IRCChannelTab> it(m_channelTabs); + for (; it.current(); ++it) { + it.current()->list()->update(); + } +} + diff --git a/noncore/net/opieirc/ircservertab.h b/noncore/net/opieirc/ircservertab.h index 69543fc..42f6f57 100644 --- a/noncore/net/opieirc/ircservertab.h +++ b/noncore/net/opieirc/ircservertab.h @@ -33,49 +33,50 @@ class IRCServerTab : public IRCTab { Q_OBJECT public: static bool containsPing(const QString& text, IRCServerTab *tab); /* IRCTab implementation */ IRCServerTab(IRCServer server, MainWindow *mainWindow, QWidget *parent = 0, const char *name = 0, WFlags f = 0); ~IRCServerTab(); QString title(); IRCSession *session(); IRCServer *server(); /* Start the server session */ void doConnect(); // QString *mynick(); /* Remove tabs from the internal tab lists */ void removeChannelTab(IRCChannelTab *tab); void removeQueryTab(IRCQueryTab *tab); /* Return tabs from the internal tab lists */ IRCChannelTab *getTabForChannel(IRCChannel *channel); IRCQueryTab *getTabForQuery(IRCPerson *person); /* Add tabs to the internal tab lists */ void addQueryTab(IRCQueryTab *tab); /* Execute a user command such as /join, /msg etc */ void executeCommand(IRCTab *tab, QString line); protected: void appendText(QString text); public slots: void scrolling(); void remove(); void processCommand(); void settingsChanged(); + void slotUpdateChannels(); protected slots: void display(IRCOutput output); protected: int m_lines; bool m_close; IRCServer m_server; IRCSession *m_session; MainWindow *m_mainWindow; QTextView *m_textview; IRCHistoryLineEdit *m_field; /* Channel tabs associated with this server tab */ QList<IRCChannelTab> m_channelTabs; /* Query tabs associated with this server tab */ QList<IRCQueryTab> m_queryTabs; }; #endif /* __IRCSERVERTAB_H */ diff --git a/noncore/net/opieirc/ircsession.cpp b/noncore/net/opieirc/ircsession.cpp index 3b176d0..ca0df50 100644 --- a/noncore/net/opieirc/ircsession.cpp +++ b/noncore/net/opieirc/ircsession.cpp @@ -1,133 +1,179 @@ #include "ircsession.h" #include "ircmessageparser.h" #include "ircversion.h" IRCSession::IRCSession(IRCServer *server) { m_server = server; m_connection = new IRCConnection(m_server); m_parser = new IRCMessageParser(this); connect(m_connection, SIGNAL(messageArrived(IRCMessage*)), this, SLOT(handleMessage(IRCMessage*))); connect(m_parser, SIGNAL(outputReady(IRCOutput)), this, SIGNAL(outputReady(IRCOutput))); connect(m_connection, SIGNAL(outputReady(IRCOutput)), this, SIGNAL(outputReady(IRCOutput))); } IRCSession::~IRCSession() { /* We want this to get deleted automatically */ m_channels.setAutoDelete(TRUE); m_people.setAutoDelete(TRUE); delete m_parser; delete m_connection; } void IRCSession::beginSession() { m_connection->doConnect(); } void IRCSession::join(QString channelname) { - m_connection->sendLine("JOIN "+channelname); + m_connection->sendLine("JOIN " + channelname); } void IRCSession::quit(){ m_connection->sendLine("QUIT :[OI] I'm too good to need a reason"); } void IRCSession::quit(QString message){ m_connection->sendLine("QUIT :" + message); } void IRCSession::topic(IRCChannel *channel, QString message){ m_connection->sendLine("TOPIC :" + channel->channelname() + " " + message); } void IRCSession::mode(IRCChannel *channel, QString message){ m_connection->sendLine("MODE " + channel->channelname() + " " + message); } void IRCSession::mode(IRCPerson *person, QString message){ m_connection->sendLine("MODE " + person->nick() + " " + message); } void IRCSession::mode(QString message){ m_connection->sendLine("MODE " + message); } void IRCSession::raw(QString message){ m_connection->sendLine(message); } void IRCSession::kick(IRCChannel *channel, IRCPerson *person) { - m_connection->sendLine("KICK "+ channel->channelname() + " " + person->nick() +" :0wn3d - no reason"); + m_connection->sendLine("KICK " + channel->channelname() + " " + person->nick() +" :0wn3d - no reason"); } void IRCSession::op(IRCChannel *channel, IRCPerson *person) { - m_connection->sendLine("MODE "+ channel->channelname() + " +ooo " + person->nick()); + m_connection->sendLine("MODE " + channel->channelname() + " +ooo " + person->nick()); } void IRCSession::kick(IRCChannel *channel, IRCPerson *person, QString message) { - m_connection->sendLine("KICK "+ channel->channelname() + " " + person->nick() +" :" + message); + m_connection->sendLine("KICK " + channel->channelname() + " " + person->nick() +" :" + message); } void IRCSession::sendMessage(IRCPerson *person, QString message) { m_connection->sendLine("PRIVMSG " + person->nick() + " :" + message); } void IRCSession::sendMessage(IRCChannel *channel, QString message) { m_connection->sendLine("PRIVMSG " + channel->channelname() + " :" + message); } void IRCSession::sendAction(IRCChannel *channel, QString message) { m_connection->sendLine("PRIVMSG " + channel->channelname() + " :\001ACTION " + message + "\001"); } void IRCSession::sendAction(IRCPerson *person, QString message) { m_connection->sendLine("PRIVMSG " + person->nick() + " :\001ACTION " + message + "\001"); } bool IRCSession::isSessionActive() { return m_connection->isConnected(); } +bool IRCSession::isLoggedIn() { + return m_connection->isLoggedIn(); +} + void IRCSession::endSession() { if (m_connection->isLoggedIn()) - m_connection->sendLine("QUIT :" APP_VERSION); + quit(APP_VERSION); else m_connection->close(); } void IRCSession::part(IRCChannel *channel) { m_connection->sendLine("PART " + channel->channelname() + " :" + APP_VERSION); } +void IRCSession::setValidUsermodes(const QString &modes) { + m_validUsermodes = modes; +} + +void IRCSession::setValidChannelmodes(const QString &modes) { + m_validChannelmodes = modes; +} + +void IRCSession::updateNickname(const QString &oldNickname, const QString &newNickname) { + QList<IRCChannel> channels; + IRCOutput output; + + if (oldNickname == m_server->nick()) { + m_server->setNick(newNickname); + output = IRCOutput(OUTPUT_NICKCHANGE, tr("You are now known as %1").arg(newNickname)); + channels = m_channels; + } + + else { + IRCPerson *person = getPerson(oldNickname); + + if(!person) { + emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Nickname change of an unknown person"))); + return; + } + + getChannelsByPerson(person, channels); + output = IRCOutput(OUTPUT_NICKCHANGE, tr("%1 is now known as %2").arg(oldNickname).arg(newNickname)); + } + + QListIterator<IRCChannel> it(channels); + for (;it.current(); ++it) { + IRCChannelPerson *chanperson = it.current()->getPerson(oldNickname); + it.current()->removePerson(chanperson); + chanperson->person->setNick(newNickname); + it.current()->addPerson(chanperson); + } + + emit updateChannels(); + output.addParam(new QString(newNickname)); + emit outputReady(output); +} IRCChannel *IRCSession::getChannel(QString channelname) { QListIterator<IRCChannel> it(m_channels); for (; it.current(); ++it) { if (it.current()->channelname() == channelname) { return it.current(); } } return 0; } IRCPerson *IRCSession::getPerson(QString nickname) { QListIterator<IRCPerson> it(m_people); for (; it.current(); ++it) { if (it.current()->nick() == nickname) { return it.current(); } } return 0; } void IRCSession::getChannelsByPerson(IRCPerson *person, QList<IRCChannel> &channels) { QListIterator<IRCChannel> it(m_channels); for (; it.current(); ++it) { if (it.current()->getPerson(person->nick()) != 0) { channels.append(it.current()); } } } void IRCSession::addPerson(IRCPerson *person) { m_people.append(person); diff --git a/noncore/net/opieirc/ircsession.h b/noncore/net/opieirc/ircsession.h index f6330d8..96de3e4 100644 --- a/noncore/net/opieirc/ircsession.h +++ b/noncore/net/opieirc/ircsession.h @@ -28,57 +28,64 @@ #include "ircmessage.h" #include "ircchannel.h" #include "ircoutput.h" class IRCMessageParser; /* The IRCSession stores all information relating to the connection to one IRC server. IRCSession makes it possible to run multiple IRC server connections from within the same program */ class IRCSession : public QObject { friend class IRCMessageParser; Q_OBJECT public: IRCSession(IRCServer *server); ~IRCSession(); void join(QString channel); void quit(QString message); void quit(); void raw(QString message); void topic(IRCChannel *channel, QString message); void mode(IRCChannel *channel, QString message); void mode(IRCPerson *person, QString message); void mode(QString message); void part(IRCChannel *channel); void op(IRCChannel *channel, IRCPerson *person); void kick(IRCChannel *channel, IRCPerson *person); void kick(IRCChannel *channel, IRCPerson *person, QString message); void beginSession(); bool isSessionActive(); void endSession(); + bool isLoggedIn(); void sendMessage(IRCPerson *person, QString message); void sendMessage(IRCChannel *channel, QString message); void sendAction(IRCPerson *person, QString message); void sendAction(IRCChannel *channel, QString message); + void updateNickname(const QString &oldNickname, const QString &newNickname); + void setValidUsermodes(const QString &modes); + void setValidChannelmodes(const QString &modes); IRCChannel *getChannel(QString channelname); IRCPerson *getPerson(QString nickname); protected: void addPerson(IRCPerson *person); void addChannel(IRCChannel *channel); void removeChannel(IRCChannel *channel); void removePerson(IRCPerson *person); void getChannelsByPerson(IRCPerson *person, QList<IRCChannel> &channels); protected slots: void handleMessage(IRCMessage *message); signals: void outputReady(IRCOutput output); + void updateChannels(); protected: IRCServer *m_server; IRCConnection *m_connection; IRCMessageParser *m_parser; QList<IRCChannel> m_channels; QList<IRCPerson> m_people; + QString m_validUsermodes; + QString m_validChannelmodes; }; #endif /* __IRCSESSION_H */ |