Browse Source

Initial Import

Niklas Boelter 12 years ago
commit
f96b1e5299
17 changed files with 1180 additions and 0 deletions
  1. 122 0
      Connection.cpp
  2. 61 0
      Connection.h
  3. 85 0
      ConnectionManager.cpp
  4. 34 0
      ConnectionManager.h
  5. 41 0
      HistoryLineEdit.cpp
  6. 31 0
      HistoryLineEdit.h
  7. 134 0
      MainWindow.cpp
  8. 44 0
      MainWindow.h
  9. 136 0
      MainWindow.ui
  10. 215 0
      Numerics.h
  11. 137 0
      Parser.cpp
  12. 51 0
      Parser.h
  13. 6 0
      README
  14. 40 0
      images/orb_green.xpm
  15. 19 0
      main.cpp
  16. 18 0
      nirc.pro
  17. 6 0
      pixmaps.qrc

+ 122 - 0
Connection.cpp

@@ -0,0 +1,122 @@
+/*
+ *  Connection.cpp
+ *  nirc
+ *
+ *  Created by Niklas Bölter on 02.02.10.
+ *  Copyright 2010 Frubar Corporation. All rights reserved.
+ *
+ */
+
+#include "Connection.h"
+#include <QDebug>
+
+Connection::Connection(ConnectionSettings settings)
+{
+	socket = new QSslSocket(this);
+	connect(socket, SIGNAL( connected() ), this, SLOT( connected() ));
+	connect(socket, SIGNAL( disconnected() ), this, SLOT( disconnected() ));
+	connect(socket, SIGNAL( error(QAbstractSocket::SocketError) ), this, SLOT( socketError() ));
+	connect(socket, SIGNAL( sslErrors(QList<QSslError>) ), this, SLOT( sslErrors(QList<QSslError>) ));
+	connect(socket, SIGNAL( encrypted() ), this, SLOT( encrypted() ));
+	connect(socket, SIGNAL( readyRead() ), this, SLOT( readyRead() ));
+	this->settings = settings;
+	registered = false;
+	this->open();
+}
+void Connection::open()
+{
+	qWarning("Opening Connection...");
+	if(settings.isSSL)
+	{
+		socket->connectToHostEncrypted(settings.host, settings.port);
+	}
+	else
+	{
+		socket->connectToHost(settings.host, settings.port);
+	}
+
+}
+void Connection::connected()
+{
+	qWarning() << "Connected to" << settings.host;
+	if(settings.isSSL) return; // Wait for SSL Handshake
+	_register();
+}
+void Connection::encrypted()
+{
+	qWarning() << "SSL Handshake with" << settings.host << "completed";
+	_register();
+}
+void Connection::disconnected()
+{
+	qWarning() << "Disconnected from" << settings.host;
+}
+void Connection::socketError()
+{
+	qWarning() << socket->errorString();
+}
+void Connection::sslErrors(QList<QSslError> error)
+{
+	for(int i = 0; i < error.size(); i++)
+	{
+		qWarning() << error.at(i).errorString();
+	}
+	if (settings.ignoreSSLErrors)
+	{
+		socket->ignoreSslErrors();
+	}
+}
+void Connection::sendLine(QString cmd)
+{
+	QString line = QString("%1\r\n").arg(cmd);
+	socket->write(line.toUtf8(), line.size());
+}
+void Connection::_register()
+{
+	/* TODO */
+	QString nickname = "nirc-testuser";
+	QString username = "niklas";
+	QString realname = "Niklas Boelter";
+	
+	/* END TODO */
+	QString nick = QString("NICK %1").arg(nickname);
+	QString user = QString("USER %1 %2 %3 :%4").arg(username).arg(QHostInfo::localHostName()).arg(settings.host).arg(realname);
+	sendLine(nick);
+	sendLine(user);
+}
+void Connection::readyRead()
+{
+	QByteArray buf = socket->readAll();
+	readBuffer.append(buf);
+	emit dataReady(settings.id);
+}
+void Connection::_splitLines()
+{
+	if(readBuffer.indexOf("\n") == -1) return;
+	QStringList linebuffer = readBuffer.split("\n");
+	QString line;
+	int size = (linebuffer.size() - 1); // Do not touch last element, it is not yet terminated by a newline
+
+	for(int i = 0; i < size; i++) 
+	{
+		line = linebuffer.at(i).trimmed();
+		if(line.size() == 0) continue;
+		lines.enqueue(line);
+	}
+	
+	readBuffer = linebuffer.at(size); // Remove all parsed lines from the buffer
+}
+bool Connection::hasLines()
+{
+	_splitLines();
+	return !lines.isEmpty();
+}
+QString Connection::nextLine()
+{
+	_splitLines();
+	return lines.dequeue();
+}
+quint16 Connection::getID()
+{
+	return settings.id;
+}

+ 61 - 0
Connection.h

@@ -0,0 +1,61 @@
+/*
+ *  Connection.h
+ *  nirc
+ *
+ *  Created by Niklas Bölter on 02.02.10.
+ *  Copyright 2010 Frubar Corporation. All rights reserved.
+ *
+ */
+
+#ifndef NIRC_CONNECTION_H
+#define NIRC_CONNECTION_H
+
+#include <QObject>
+#include <QSslSocket>
+#include <QSslError>
+#include <QString>
+#include <QStringList>
+#include <QQueue>
+#include <QHostInfo>
+
+struct ConnectionSettings {
+	int id;
+	QString host;
+	quint16 port;
+	QString name;
+	bool isSSL;
+	bool ignoreSSLErrors;
+};
+
+class Connection : public QObject
+{
+	Q_OBJECT
+public:
+	Connection(ConnectionSettings settings);
+	quint16 getID();
+	void open();
+	bool hasLines();
+	void sendLine(QString line);
+	QString nextLine();
+private:
+	void _register();
+	void _splitLines();
+	bool registered;
+	ConnectionSettings settings;
+	QSslSocket *socket;
+	QString readBuffer;
+	QString writeBuffer;
+	QQueue<QString> lines;
+private slots:
+	void readyRead();
+	void encrypted();
+	void connected();
+	void disconnected();
+	void socketError();
+	void sslErrors(QList<QSslError> error);
+signals:
+	void dataReady(int cid);
+};
+
+
+#endif

+ 85 - 0
ConnectionManager.cpp

@@ -0,0 +1,85 @@
+/*
+ *  ConnectionManager.cpp
+ *  nirc
+ *
+ *  Created by Niklas Bölter on 02.02.10.
+ *  Copyright 2010 Frubar Corporation. All rights reserved.
+ *
+ */
+
+#include "ConnectionManager.h"
+
+ConnectionManager::ConnectionManager()
+{
+	/*
+	QSettings settings;
+	QList<ConnectionSettings> connections;
+	settings.clear();
+	ConnectionSettings xchannel;
+	xchannel.host = "irc.xchannel.org";
+	xchannel.port = 6667;
+	xchannel.name = "XChannel";
+	xchannel.isSSL = false;
+	xchannel.ignoreSSLErrors = false;
+	connections.append(xchannel);
+	ConnectionSettings megworld;
+	megworld.host = "irc.megworld.co.uk";
+	megworld.port = 6667;
+	megworld.name = "Megworld";
+	megworld.isSSL = false;
+	megworld.ignoreSSLErrors = false;
+	connections.append(megworld);
+	settings.beginWriteArray("connections", connections.size());
+	for(int i = 0; i < connections.size(); i++)
+	{
+		settings.setArrayIndex(i);
+		settings.setValue("host", connections.at(i).host);
+		settings.setValue("port", connections.at(i).port);
+		settings.setValue("name", connections.at(i).name);
+		settings.setValue("isSSL", connections.at(i).isSSL);
+		settings.setValue("ignoreSSLErrors", connections.at(i).ignoreSSLErrors);
+	}
+	settings.endArray();
+	*/
+	
+	QSslSocket::addDefaultCaCertificates(QString("%1/.nirc/ca.pem").arg(QDir::homePath()),QSsl::Pem);
+	QSslSocket::addDefaultCaCertificates(QString("%1/.nirc/ca.der").arg(QDir::homePath()),QSsl::Der);
+	
+	QSettings settings;
+	int size = settings.beginReadArray("connections");
+	for(int i = 0; i < size; i++)
+	{
+		settings.setArrayIndex(i);
+		ConnectionSettings connectionsetting;
+		connectionsetting.id = i;
+		connectionsetting.host = settings.value("host").toString();
+		connectionsetting.port = settings.value("port").toUInt();
+		connectionsetting.name = settings.value("name").toString();
+		connectionsetting.isSSL = settings.value("isSSL").toBool();
+		connectionsetting.ignoreSSLErrors = settings.value("ignoreSSLErrors").toBool();
+		connectionsettings.append(connectionsetting);
+	}
+	settings.endArray();
+}
+void ConnectionManager::openConnections()
+{
+	for(int i = 0; i < connectionsettings.size(); i++)
+	{
+		Connection *connection = new Connection(connectionsettings.at(i));
+		connect(connection, SIGNAL( dataReady(int) ), this, SLOT( dataReady(int) ));
+		connections.append(connection);
+	}
+}
+void ConnectionManager::sendLine(int cid, QString line)
+{
+	Q_ASSERT(connections.size() > cid);
+	connections.at(cid)->sendLine(line);
+}
+void ConnectionManager::dataReady(int cid)
+{
+	Connection *c = connections.at(cid);
+	while (c->hasLines())
+	{
+		emit nextLine(cid, c->nextLine());
+	}
+}

+ 34 - 0
ConnectionManager.h

@@ -0,0 +1,34 @@
+/*
+ *  ConnectionManager.h
+ *  nirc
+ *
+ *  Created by Niklas Bölter on 02.02.10.
+ *  Copyright 2010 Frubar Corporation. All rights reserved.
+ *
+ */
+
+#ifndef NIRC_CONNECTIONMANAGER_H
+#define NIRC_CONNECTIONMANAGER_H
+
+#include <QObject>
+#include <QSettings>
+#include <QDir>
+#include "Connection.h"
+
+class ConnectionManager : public QObject
+{
+	Q_OBJECT
+public:
+	ConnectionManager();
+	void openConnections();
+	void sendLine(int cid, QString line);
+private:
+	QList<ConnectionSettings> connectionsettings;
+	QList<Connection *> connections;
+private slots:
+	void dataReady(int cid);
+signals:
+	void nextLine(int cid, QString line);
+};
+
+#endif

+ 41 - 0
HistoryLineEdit.cpp

@@ -0,0 +1,41 @@
+/*
+ *  HistoryLineEdit.cpp
+ *  nirc
+ *
+ *  Created by Niklas Bölter on 03.02.10.
+ *  Copyright 2010 Frubar Corporation. All rights reserved.
+ *
+ */
+
+#include "HistoryLineEdit.h"
+
+HistoryLineEdit::HistoryLineEdit(QWidget *parent) : QLineEdit(parent) {}
+void HistoryLineEdit::keyPressEvent(QKeyEvent *event)
+{
+	switch (event->key()) {
+		case Qt::Key_Enter:
+		case Qt::Key_Return:
+			emit returnPressed();
+			event->accept();
+			break;
+		case Qt::Key_Up:
+			emit upPressed();
+			event->accept();
+			break;
+		case Qt::Key_Down:
+			emit downPressed();
+			event->accept();
+			break;
+		case Qt::Key_Tab:
+			emit tabPressed();
+			event->accept();
+			break;
+		default:
+			QLineEdit::keyPressEvent(event); 
+			break;
+	}
+}
+bool HistoryLineEdit::focusNextPrevChild(bool)
+{
+	return true; // Show that we have found the "nextprevchild" - we will keep focus!
+}

+ 31 - 0
HistoryLineEdit.h

@@ -0,0 +1,31 @@
+/*
+ *  HistoryLineEdit.h
+ *  nirc
+ *
+ *  Created by Niklas Bölter on 03.02.10.
+ *  Copyright 2010 Frubar Corporation. All rights reserved.
+ *
+ */
+
+#ifndef NIRC_HISTORYLINEDIT_H
+#define NIRC_HISTORYLINEDIT_H
+
+#include <QLineEdit>
+#include <QKeyEvent>
+
+class HistoryLineEdit : public QLineEdit
+{
+	Q_OBJECT
+public:
+	HistoryLineEdit(QWidget *parent = 0);
+protected:
+	void keyPressEvent(QKeyEvent *event);
+	bool focusNextPrevChild(bool next);
+signals:
+	void tabPressed();
+	void upPressed();
+	void downPressed();
+};
+
+
+#endif

+ 134 - 0
MainWindow.cpp

@@ -0,0 +1,134 @@
+/*
+ *  MainWindow.cpp
+ *  nirc
+ *
+ *  Created by Niklas Bölter on 02.02.10.
+ *  Copyright 2010 Frubar Corporation. All rights reserved.
+ *
+ */
+
+#include "MainWindow.h"
+#include <QStringListModel>
+
+MainWindow::MainWindow()
+{
+	setupUi(this);
+	input->setFocus();
+	
+	
+	
+	/* ONLY FOR TESTING */
+	
+//	content->setMaximumBlockCount(10);
+	
+	QFont networkNameFont("Times", 12, QFont::Bold);
+	QIcon channelIcon = QIcon(":/images/orb_green.xpm");
+	
+	QTreeWidgetItem *item = new QTreeWidgetItem(serverobjects);
+	item->setText(0, "XCHANNEL");
+	item->setFont(0, networkNameFont);
+	QTreeWidgetItem *channel;
+	channel = new QTreeWidgetItem(item);
+	channel->setText(0, "#xchannel");
+	channel->setIcon(0, channelIcon);
+	
+	channel = new QTreeWidgetItem(item);
+	channel->setText(0, "#xchannel");
+	channel = new QTreeWidgetItem(item);
+	channel->setText(0, "#xchannel");
+	channel = new QTreeWidgetItem(item);
+	channel->setText(0, "#xchannel");
+	channel = new QTreeWidgetItem(item);
+	channel->setText(0, "#xchannel");
+	
+	QTreeWidgetItem *item2 = new QTreeWidgetItem(serverobjects);
+	item2->setText(0, "FREENODE");
+	item2->setFont(0, networkNameFont);
+	QTreeWidgetItem *channel2 = new QTreeWidgetItem(item2);
+	channel2->setText(0, "#megworld");
+	
+	
+	/*
+	titlebar->setText("Geheimer FRUBAR Testchannel");
+	
+	QStringListModel *servermodel = new QStringListModel();
+	QStringList serverlist;
+	serverlist << "irc.example.org" << " #testfuck";
+	servermodel->setStringList(serverlist);
+	serverobjects->setModel(servermodel);
+	
+	QStringListModel *channelmodel = new QStringListModel();
+	QStringList channellist;
+	channellist << "niki" << "dasud" << "haskhk" << "lorem" << "ipsum" << "niki" << "dasud" << "haskhk" << "lorem" << "ipsum";
+	channelmodel->setStringList(channellist);
+	channelobject->setModel(channelmodel);
+	*/
+	
+	
+	/* HERE IS REAL CODE AGAIN */
+	
+	connect(input, SIGNAL( returnPressed() ), this, SLOT( handleInput() ));
+	connect(input, SIGNAL( upPressed() ), this, SLOT( handleUp() ));
+	connect(input, SIGNAL( downPressed() ), this, SLOT( handleDown() ));
+	connect(input, SIGNAL( tabPressed() ), this, SLOT( handleTab() ));
+	connect(content, SIGNAL ( anchorClicked(QUrl) ), this, SLOT( handleContentClick(QUrl) ));
+	
+	settings.inputHistoryAppendAlways = false;
+	settings.maxInputHistory = 20;
+
+}
+void MainWindow::handleInput()
+{
+	QString line = input->text();
+	input->clear();
+
+	historyLocation = -1;
+	if(settings.inputHistoryAppendAlways)
+	{
+		history.append(line);
+	}
+	else if (history.isEmpty() || line != history.last())
+	{
+		history.append(line);
+	}
+	if(history.size() > settings.maxInputHistory)
+	{
+		history.removeFirst();
+	}
+	emit sendLine(line);
+}
+void MainWindow::appendLine(QString line)
+{
+	content->append(line);
+}
+void MainWindow::handleUp()
+{
+	if(historyLocation == 0) return;
+	if(history.isEmpty()) return;
+	if(historyLocation == -1)
+	{
+		lastInput = input->text();
+		historyLocation = history.size();
+	}
+	historyLocation--;
+	input->setText(history.at(historyLocation));
+}
+void MainWindow::handleDown()
+{
+	if(historyLocation == -1) return;
+	if(historyLocation == (history.size() - 1))
+	{
+		input->setText(lastInput);
+		historyLocation = -1;
+		return;
+	}
+	historyLocation++;
+	input->setText(history.at(historyLocation));
+}
+void MainWindow::handleTab()
+{
+}
+void MainWindow::handleContentClick(QUrl url)
+{
+	qDebug() << url.toString();
+}

+ 44 - 0
MainWindow.h

@@ -0,0 +1,44 @@
+/*
+ *  MainWindow.h
+ *  nirc
+ *
+ *  Created by Niklas Bölter on 02.02.10.
+ *  Copyright 2010 Frubar Corporation. All rights reserved.
+ *
+ */
+
+#ifndef NIRC_MAINWINDOW_H
+#define NIRC_MAINWINDOW_H
+
+#include "ui_MainWindow.h"
+#include <QDebug>
+
+struct MainWindowSettings {
+	quint16 maxInputHistory;
+	bool inputHistoryAppendAlways;
+};
+
+class MainWindow : public QMainWindow, private Ui::MainWindow
+{
+	Q_OBJECT
+public:
+	MainWindow();
+private:
+	QList<QString> history;
+	MainWindowSettings settings;
+	qint16 historyLocation;
+	QString lastInput;
+	QList<QTextDocument *> tabs;
+protected slots:
+	void handleInput();
+	void handleContentClick(QUrl url);
+public slots:
+	void appendLine(QString line);
+	void handleTab();
+	void handleUp();
+	void handleDown();
+signals:
+	void sendLine(QString line);
+};
+
+#endif

+ 136 - 0
MainWindow.ui

@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>641</width>
+    <height>480</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QVBoxLayout" name="verticalLayout">
+    <property name="spacing">
+     <number>-1</number>
+    </property>
+    <property name="margin">
+     <number>0</number>
+    </property>
+    <item>
+     <widget class="HistoryLineEdit" name="titlebar"/>
+    </item>
+    <item>
+     <widget class="QSplitter" name="splitter">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <widget class="QTreeWidget" name="serverobjects">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>150</width>
+         <height>200</height>
+        </size>
+       </property>
+       <property name="indentation">
+        <number>5</number>
+       </property>
+       <property name="animated">
+        <bool>true</bool>
+       </property>
+       <attribute name="headerVisible">
+        <bool>false</bool>
+       </attribute>
+       <attribute name="headerVisible">
+        <bool>false</bool>
+       </attribute>
+       <column>
+        <property name="text">
+         <string notr="true">1</string>
+        </property>
+       </column>
+      </widget>
+      <widget class="QTextBrowser" name="content">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>300</width>
+         <height>200</height>
+        </size>
+       </property>
+      </widget>
+      <widget class="QTreeWidget" name="channelobjects">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>150</width>
+         <height>200</height>
+        </size>
+       </property>
+       <attribute name="headerVisible">
+        <bool>false</bool>
+       </attribute>
+       <attribute name="headerVisible">
+        <bool>false</bool>
+       </attribute>
+       <column>
+        <property name="text">
+         <string notr="true">1</string>
+        </property>
+       </column>
+      </widget>
+     </widget>
+    </item>
+    <item>
+     <widget class="HistoryLineEdit" name="input"/>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>641</width>
+     <height>22</height>
+    </rect>
+   </property>
+  </widget>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>HistoryLineEdit</class>
+   <extends>QLineEdit</extends>
+   <header>HistoryLineEdit.h</header>
+  </customwidget>
+ </customwidgets>
+ <tabstops>
+  <tabstop>input</tabstop>
+  <tabstop>titlebar</tabstop>
+  <tabstop>content</tabstop>
+  <tabstop>channelobjects</tabstop>
+  <tabstop>serverobjects</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>

+ 215 - 0
Numerics.h

@@ -0,0 +1,215 @@
+/*
+ *  Numerics.h
+ *  nirc
+ *
+ *  Created by Niklas Bölter on 05.02.10.
+ *  Copyright 2010 Frubar Corporation. All rights reserved.
+ *
+ */
+
+#ifndef NIRC_NUMERICS_H
+#define NIRC_NUMERICS_H
+
+// RFC 1459 - Internet Relay Chat Protocol
+
+
+/* REPLIES */
+
+#define RPL_TRACELINK			200 // "Link <version & debug level> <destination> <next server>"
+#define RPL_TRACECONNECTING		201 // "Try. <class> <server>"
+#define RPL_TRACEHANDSHAKE		202 // "H.S. <class> <server>"
+#define RPL_TRACEUNKNOWN		203 // "???? <class> [<client IP address in dot form>]"
+#define RPL_TRACEOPERATOR		204 // "Oper <class> <nick>"
+#define RPL_TRACEUSER			205 // "User <class> <nick>"
+#define RPL_TRACESERVER			206 // "Serv <class> <int>S <int>C <server> <nick!user|*!*>@<host|server>"
+#define RPL_TRACENEWTYPE		208 // "<newtype> 0 <client name>"
+#define RPL_TRACECLASS			209 // reserved
+#define RPL_STATSLINKINFO		211 // "<linkname> <sendq> <sent messages> <sent bytes> <received messages> <received bytes> <time open>"
+#define RPL_STATSCOMMANDS		212 // "<command> <count>"
+#define RPL_STATSCLINE			213 // "C <host> * <name> <port> <class>"
+#define RPL_STATSNLINE			214 // "N <host> * <name> <port> <class>"
+#define RPL_STATSILINE			215 // "I <host> * <host> <port> <class>"
+#define RPL_STATSKLINE			216 // "K <host> * <username> <port> <class>"
+#define RPL_STATSQLINE			217 // reserved
+#define RPL_STATSYLINE			218 // "Y <class> <ping frequency> <connect frequency> <max sendq>"
+#define RPL_ENDOFSTATS			219 // "<stats letter> :End of /STATS report"
+#define RPL_UMODEIS				221 // "<user mode string>"
+#define RPL_SERVICEINFO			231 // reserved
+#define RPL_ENDOFSERVICES		232 // reserved
+#define RPL_SERVICE				233 // reserved
+#define RPL_SERVLIST			234 // reserved
+#define RPL_SERVLISTEND			235 // reserved
+#define RPL_STATSLLINE			241 // "L <hostmask> * <servername> <maxdepth>"
+#define RPL_STATSUPTIME			242 // ":Server Up %d days %d:%02d:%02d"
+#define RPL_STATSOLINE			243 // "O <hostmask> * <name>"
+#define RPL_STATSHLINE			244 // "H <hostmask> * <servername>"
+#define RPL_LUSERCLIENT			251 // ":There are <integer> users and <integer> invisible on <integer> servers"
+#define RPL_LUSEROP				252 // "<integer> :operator(s) online"
+#define RPL_LUSERUNKNOWN		253 // "<integer> :unknown connection(s)"
+#define RPL_LUSERCHANNELS		254 // "<integer> :channels formed"
+#define RPL_LUSERME				255 // ":I have <integer> clients and <integer> servers"
+#define RPL_ADMINME				256 // "<server> :Administrative info"
+#define RPL_ADMINLOC1			257 // ":<admin info>"
+#define RPL_ADMINLOC2			258 // ":<admin info>"
+#define RPL_ADMINEMAIL			259 // ":<admin info>"
+#define RPL_TRACELOG			261 // "File <logfile> <debug level>"
+#define RPL_NONE				300 // Dummy reply number. Not used.
+#define RPL_AWAY				301 // "<nick> :<away message>"
+#define RPL_USERHOST			302 // ":[<reply>{<space><reply>}]"
+#define RPL_ISON				303 // ":[<nick> {<space><nick>}]"
+#define RPL_UNAWAY				305 // ":You are no longer marked as being away"
+#define RPL_NOWAWAY				306 // ":You have been marked as being away"
+#define RPL_WHOISUSER			311 // "<nick> <user> <host> * :<real name>"
+#define RPL_WHOISSERVER			312 // "<nick> <server> :<server info>"
+#define RPL_WHOISOPERATOR		313 // "<nick> :is an IRC operator"
+#define RPL_WHOWASUSER			314 // "<nick> <user> <host> * :<real name>"
+#define RPL_ENDOFWHO			315 // "<name> :End of /WHO list"
+#define RPL_WHOISCHANOP			316 // reserved
+#define RPL_WHOISIDLE			317 // "<nick> <integer> :seconds idle"
+#define RPL_ENDOFWHOIS			318 // "<nick> :End of /WHOIS list"
+#define RPL_WHOISCHANNELS		319 // "<nick> :{[@|+]<channel><space>}"
+#define RPL_LISTSTART			321 // "Channel :Users  Name"
+#define RPL_LIST				322 // "<channel> <# visible> :<topic>"
+#define RPL_LISTEND				323 // ":End of /LIST"
+#define RPL_CHANNELMODEIS		324 // "<channel> <mode> <mode params>"
+#define RPL_NOTOPIC				331 // "<channel> :No topic is set"
+#define RPL_TOPIC				332 // "<channel> :<topic>"
+#define RPL_INVITING			341 // "<channel> <nick>"
+#define RPL_SUMMONING			342 // "<user> :Summoning user to IRC"
+#define RPL_VERSION				351 // "<version>.<debuglevel> <server> :<comments>"
+#define RPL_WHOREPLY			352 // "<channel> <user> <host> <server> <nick> <H|G>[*][@|+] :<hopcount> <real name>"
+#define RPL_NAMREPLY			353 // "<channel> :[[@|+]<nick> [[@|+]<nick> [...]]]"
+#define RPL_KILLDONE			361 // reserved
+#define RPL_CLOSING				362 // reserved
+#define RPL_CLOSEEND			363 // reserved
+#define RPL_LINKS				364 // "<mask> <server> :<hopcount> <server info>"
+#define RPL_ENDOFLINKS			365 // "<mask> :End of /LINKS list"
+#define RPL_ENDOFNAMES			366 // "<channel> :End of /NAMES list"
+#define RPL_BANLIST				367 // "<channel> <banid>"
+#define RPL_ENDOFBANLIST		368 // "<channel> :End of channel ban list"
+#define RPL_ENDOFWHOWAS			369 // "<nick> :End of WHOWAS"
+#define RPL_INFO				371 // ":<string>"
+#define RPL_MOTD				372 // ":- <text>"
+#define RPL_INFOSTART			373 // reserved
+#define RPL_ENDOFINFO			374 // ":End of /INFO list"
+#define RPL_MOTDSTART			375 // ":- <server> Message of the day - "
+#define RPL_ENDOFMOTD			376 // ":End of /MOTD command"
+#define RPL_YOUREOPER			381 // ":You are now an IRC operator"
+#define RPL_REHASHING			382 // "<config file> :Rehashing"
+#define RPL_MYPORTIS			384 // reserved
+#define RPL_TIME				391 // "<server> :<string showing server's local time>"
+#define RPL_USERSSTART			392 // ":UserID   Terminal  Host"
+#define RPL_USERS				393 // ":%-8s %-9s %-8s" (username, ttyline, hostname)
+#define RPL_ENDOFUSERS			394 // ":End of users"
+#define RPL_NOUSERS				395 // ":Nobody logged in"
+
+/* ERRORS */
+
+#define ERR_NOSUCHNICK			401 // "<nickname> :No such nick/channel"
+#define ERR_NOSUCHSERVER		402 // "<server name> :No such server"
+#define ERR_NOSUCHCHANNEL		403 // "<channel name> :No such channel"
+#define ERR_CANNOTSENDTOCHAN	404 // "<channel name> :Cannot send to channel"
+#define ERR_TOOMANYCHANNELS		405 // "<channel name> :You have joined too many channels"
+#define ERR_WASNOSUCHNICK		406 // "<nickname> :There was no such nickname"
+#define ERR_TOOMANYTARGETS		407 // "<target> :Duplicate recipients. No message delivered"
+#define ERR_NOORIGIN			409 // ":No origin specified"
+#define ERR_NORECIPIENT			411 // ":No recipient given (<command>)"
+#define ERR_NOTEXTTOSEND		412 // ":No text to send"
+#define ERR_NOTOPLEVEL			413 // "<mask> :No toplevel domain specified"
+#define ERR_WILDTOPLEVEL		414 // "<mask> :Wildcard in toplevel domain"
+#define ERR_UNKNOWNCOMMAND		421 // "<command> :Unknown command"
+#define ERR_NOMOTD				422 // ":MOTD File is missing"
+#define ERR_NOADMININFO			423 // "<server> :No administrative info available"
+#define ERR_FILEERROR			424 // ":File error doing <file op> on <file>"
+#define ERR_NONICKNAMEGIVEN		431 // ":No nickname given"
+#define ERR_ERRONEUSNICKNAME	432 // "<nick> :Erroneus nickname"
+#define ERR_NICKNAMEINUSE		433 // "<nick> :Nickname is already in use"
+#define ERR_NICKCOLLISION		436 // "<nick> :Nickname collision KILL"
+#define ERR_USERNOTINCHANNEL	441 // "<nick> <channel> :They aren't on that channel"
+#define ERR_NOTONCHANNEL		442 // "<channel> :You're not on that channel"
+#define ERR_USERONCHANNEL		443 // "<user> <channel> :is already on channel"
+#define ERR_NOLOGIN				444 // "<user> :User not logged in"
+#define ERR_SUMMONDISABLED		445 // ":SUMMON has been disabled"
+#define ERR_USERSDISABLED		446 // ":USERS has been disabled"
+#define ERR_NOTREGISTERED		451 // ":You have not registered"
+#define ERR_NEEDMOREPARAMS		461 // "<command> :Not enough parameters"
+#define ERR_ALREADYREGISTRED	462 // ":You may not reregister"
+#define ERR_NOPERMFORHOST		463 // ":Your host isn't among the privileged"
+#define ERR_PASSWDMISMATCH		464 // ":Password incorrect"
+#define ERR_YOUREBANNEDCREEP	465 // ":You are banned from this server"
+#define ERR_YOUWILLBEBANNED		466 // reserved
+#define ERR_KEYSET				467 // "<channel> :Channel key already set"
+#define ERR_CHANNELISFULL		471 // "<channel> :Cannot join channel (+l)"
+#define ERR_UNKNOWNMODE			472 // "<char> :is unknown mode char to me"
+#define ERR_INVITEONLYCHAN		473 // "<channel> :Cannot join channel (+i)"
+#define ERR_BANNEDFROMCHAN		474 // "<channel> :Cannot join channel (+b)"
+#define ERR_BADCHANNELKEY		475 // "<channel> :Cannot join channel (+k)"
+#define ERR_BADCHANMASK			476 // reserved
+#define ERR_NOPRIVILEGES		481 // ":Permission Denied- You're not an IRC operator"
+#define ERR_CHANOPRIVSNEEDED	482 // "<channel> :You're not channel operator"
+#define ERR_CANTKILLSERVER		483 // ":You cant kill a server!"
+#define ERR_NOOPERHOST			491 // ":No O-lines for your host"
+#define ERR_NOSERVICEHOST		492 // reserved
+#define ERR_UMODEUNKNOWNFLAG	501 // ":Unknown MODE flag"
+#define ERR_USERSDONTMATCH		502 // ":Cant change mode for other users"
+
+
+// RFC 2812 - Internet Relay Chat: Client Protocol
+
+/* Changes from 1459 
+ *
+ * RPL_LISTSTART		is now obsolete
+ * RPL_NAMREPLY			now has "=","*" or "@" prefixes before the channel
+ *						name, indicating public/private/secret channels respectively
+ * RPL_TRACELINK		Parameters added: V<protocol version> <link uptime in seconds> <backstream sendq> <upstream sendq>
+ * RPL_TRACESERVER		Parameter added: V<protocol version>
+ * RPL_TRACECLASS		Now "Class <class> <count>"
+ * RPL_STATSCOMMANDS	Parameters added: <byte count> <remote count>
+ * RPL_SERVLIST			Now "<name> <server> <mask> <type> <hopcount> <info>"
+ * RPL_SERVLISTEND		Now "<mask> <type> :End of service listing"
+ * ERR_TOOMANYTARGETS	I now used more often. "<target> :<error code> recipients. <abort message>"
+ * ERR_NICKCOLLISION	Now shows user and host information: "<nick> :Nickname collision KILL from <user>@<host>"
+ * ERR_YOUWILLBEBANNED	Still no parameters (?!) but no longer reserved.
+ * ERR_BADCHANMASK		Now: "<channel> :Bad Channel Mask"
+ */
+
+/* REPLIES */
+
+#define RPL_WELCOME				  1 // "Welcome to the Internet Relay Network <nick>!<user>@<host>"
+#define RPL_YOURHOST			  2 // "Your host is <servername>, running version <ver>"
+#define RPL_CREATED				  3 // "This server was created <date>"
+#define RPL_MYINFO				  4 // "<servername> <version> <available user modes> <available channel modes>"
+#define RPL_BOUNCE				  5 // "Try server <server name>, port <port number>"
+#define RPL_TRACESERVICE		207 // "Service <class> <name> <type> <active type>"
+#define RPL_TRACERECONNECT		210 // Unused.
+#define RPL_STATSVLINE			240 // reserved
+#define RPL_STATSSLINE			244 // reserved
+#define RPL_STATSPING			246 // reserved
+#define RPL_STATSBLINE			247 // reserved
+#define RPL_STATSDLINE			250 // reserved
+#define RPL_TRACEEND			262 // "<server name> <version & debug level> :End of TRACE"
+#define RPL_TRYAGAIN			263 // "<command> :Please wait a while and try again."
+#define RPL_UNIQOPIS			325 // "<channel> <nickname>"
+#define RPL_INVITELIST			346 // "<channel> <invitemask>"
+#define RPL_ENDOFINVITELIST		347	// "<channel> :End of channel invite list"
+#define RPL_EXCEPTLIST			348 // "<channel> <exceptionmask>"
+#define RPL_ENDOFEXCEPTLIST		349 // "<channel> :End of channel exception list"
+#define RPL_YOURESERVICE		383 // "You are service <servicename>"
+
+/* ERRORS */
+
+#define ERR_NOSUCHSERVICE		408	// "<service name> :No such service"
+#define ERR_BADMASK				415 // "<mask> :Bad Server/host mask"
+#define ERR_UNAVAILRESOURCE		437 // "<nick/channel> :Nick/channel is temporarily unavailable"
+#define ERR_NOCHANMODES			477 // "<channel> :Channel doesn't support modes"
+#define ERR_BANLISTFULL			478 // "<channel> <char> :Channel list is full"
+#define ERR_RESTRICTED			484 // ":Your connection is restricted!"
+#define ERR_UNIQOPPRIVSNEEDED	485 //  ":You're not the original channel operator"
+
+/* Not standardized Shit */
+
+#define RPL_ISUPPORT			  5 // Whoever made this the same as RPL_BOUNCE should be forced to use ipchain for the rest of his life
+
+
+
+#endif

+ 137 - 0
Parser.cpp

@@ -0,0 +1,137 @@
+/*
+ *  Parser.cpp
+ *  nirc
+ *
+ *  Created by Niklas Bölter on 03.02.10.
+ *  Copyright 2010 Frubar Corporation. All rights reserved.
+ *
+ */
+
+#include "Parser.h"
+
+Parser::Parser(MainWindow *mw, ConnectionManager *cm)
+{
+	this->mw = mw;
+	this->cm = cm;
+	connect(this, SIGNAL( appendLine(QString) ), this->mw, SLOT( appendLine(QString) ));
+	connect(this->mw, SIGNAL( sendLine(QString) ), this, SLOT( readInput(QString) ));
+	connect(this->cm, SIGNAL( nextLine(int, QString) ), this, SLOT( parse(int, QString) ));
+	
+}
+void Parser::setup()
+{
+	cm->openConnections();
+	mw->show();
+}
+void Parser::reply(QString line)
+{
+	cm->sendLine(cid, line);
+}
+void Parser::parse(int cid, QString line)
+{
+	this->cid = cid;
+	qDebug() << QString("(Connection %1) %2").arg(this->cid).arg(line);
+	QStringList params;
+	QString prefix;
+	QString command;
+	int lastParameterStart = line.indexOf(" :");
+	if(lastParameterStart == -1)
+	{
+		params = line.split(QRegExp(" +"));
+	}
+	else
+	{
+		params = line.left(lastParameterStart).split(QRegExp(" +"));
+		params.append(line.right(line.size() - (2 + lastParameterStart)));
+	}
+	if(params.isEmpty()) return;
+	if(params.at(0)[0] == ':')
+	{
+		prefix = params.takeFirst().mid(1);
+	}
+	else
+	{
+		prefix = "";
+	}
+	if(params.isEmpty()) return;
+	command = params.takeFirst();
+	if(isServer(prefix))
+	{
+		handleServerCommand(prefix, command, params);
+	}
+	else
+	{
+		//handleUserCommand(user, command, params);
+	}
+}
+bool Parser::isServer(QString prefix)
+{
+	if(prefix.size() == 0) // Missing prefix should be interpreted as originating from connection partner
+	{
+		return true;
+	}
+	if(prefix.contains(".") && !prefix.contains("!") && !prefix.contains("@"))
+	{
+		return true;
+	}
+	return false;
+}
+void Parser::handleServerCommand(QString prefix, QString command, QStringList params)
+{
+	bool ok;
+	int numeric;
+	numeric = command.toInt(&ok);
+	if(ok && numeric > 0) // Numeric Received
+	{
+		switch (numeric) {
+			case RPL_WELCOME:
+				break;
+			case RPL_YOURHOST:
+				break;
+			case RPL_CREATED:
+				break;
+			case RPL_MYINFO:
+				break;
+		}
+	}
+	else
+	{
+		command = command.toUpper();
+		if(command == "PING")
+		{
+			handlePing(params);
+		}
+		else
+		{
+			if(prefix.size() > 0)
+			{
+				emit appendLine(QString("%1: %2").arg(prefix).arg(params.join(" ")));
+			}
+			else
+			{
+				emit appendLine(params.join(" "));
+			}
+
+		}
+	}
+}
+void Parser::handlePing(QStringList params)
+{
+	if (params.isEmpty())
+	{
+		reply("PONG");
+	}
+	else
+	{
+		reply(QString("PONG :%1").arg(params.at(0)));
+	}
+
+}
+void Parser::readInput(QString line)
+{
+	line = line.trimmed();
+	int cid = line.left(1).toUInt();
+	QString cmd = line.right(line.size() - 1);
+	cmd = cmd.trimmed();
+	cm->sendLine(cid, cmd);
+}

+ 51 - 0
Parser.h

@@ -0,0 +1,51 @@
+/*
+ *  Parser.h
+ *  nirc
+ *
+ *  Created by Niklas Bölter on 03.02.10.
+ *  Copyright 2010 Frubar Corporation. All rights reserved.
+ *
+ */
+
+#ifndef NIRC_PARSER_H
+#define NIRC_PARSER_H
+
+#include <QObject>
+#include <QString>
+#include <QStringList>
+#include "MainWindow.h"
+#include "Connection.h"
+#include "ConnectionManager.h"
+#include "Numerics.h"
+
+struct ParserSettings
+{
+	quint16 maxChannelHistory;
+	quint16 maxPrivateHistory;
+};
+
+class Parser : public QObject
+{
+	Q_OBJECT
+public:
+	Parser(MainWindow *mw, ConnectionManager *cm);
+	void setup();
+private:
+	MainWindow *mw;
+	ConnectionManager *cm;
+	void reply(QString line);
+	bool isServer(QString prefix);
+	void handleServerCommand(QString prefix, QString command, QStringList params);
+	//void handleUserCommand(User *user, QString command, QStringList params);
+	void handlePing(QStringList params);
+	QHash<QString, int> tabs;
+	ParserSettings settings;
+	int cid;
+private slots:
+	void parse(int cid, QString line);
+	void readInput(QString line);
+signals:
+	void appendLine(QString line);
+};
+
+#endif

+ 6 - 0
README

@@ -0,0 +1,6 @@
+nirc
+
+SSL Certificates
+nirc will try to import all CA Certificates under ~/.nirc/ca.pem or ~/.nirc/ca.der in PEM or DER format respectively. If the server uses a self signed certificate, you can set "ignoreSSLErrors" for that connection to true;
+
+

+ 40 - 0
images/orb_green.xpm

@@ -0,0 +1,40 @@
+/* XPM */
+static char *green_orb[] = {
+/* columns rows colors chars-per-pixel */
+"32 32 2 1",
+"  c #00FF00",
+". c None",
+/* pixels */
+"............        ............",
+".........              .........",
+".......                  .......",
+"......                    ......",
+".....                      .....",
+"....                        ....",
+"...                          ...",
+"..                            ..",
+"..                            ..",
+".                              .",
+".                              .",
+".                              .",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+".                              .",
+".                              .",
+".                              .",
+"..                            ..",
+"..                            ..",
+"...                          ...",
+"....                        ....",
+".....                      .....",
+"......                    ......",
+".......                  .......",
+".........              .........",
+"............        ............"
+};

+ 19 - 0
main.cpp

@@ -0,0 +1,19 @@
+#include <QApplication>
+#include <QSettings>
+#include "MainWindow.h"
+#include "ConnectionManager.h"
+#include "Parser.h"
+
+ int main(int argc, char *argv[])
+ {
+     QApplication app(argc, argv);
+	 QCoreApplication::setOrganizationName("Frubar");
+     QCoreApplication::setOrganizationDomain("frubar.net");
+     QCoreApplication::setApplicationName("nirc");
+	 
+	 MainWindow *mw = new MainWindow;
+	 ConnectionManager *cm = new ConnectionManager;
+	 Parser *p = new Parser(mw, cm);
+	 p->setup();
+     return app.exec();
+ }

+ 18 - 0
nirc.pro

@@ -0,0 +1,18 @@
+######################################################################
+# Automatically generated by qmake (2.01a) Di. Feb 2 18:59:38 2010
+######################################################################
+
+TEMPLATE = app
+TARGET = 
+DEPENDPATH += .
+INCLUDEPATH += .
+
+# Input
+HEADERS += Numerics.h HistoryLineEdit.h Parser.h Connection.h ConnectionManager.h MainWindow.h
+FORMS += MainWindow.ui
+SOURCES += HistoryLineEdit.cpp Parser.cpp Connection.cpp ConnectionManager.cpp main.cpp MainWindow.cpp
+RESOURCES += pixmaps.qrc
+
+QT += network
+#CONFIG += x86 x86_64
+CONFIG += x86_64

+ 6 - 0
pixmaps.qrc

@@ -0,0 +1,6 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+ <qresource>
+     <file>images/orb_green.xpm</file>
+ </qresource>
+</RCC>