summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2009-05-02 01:21:51 -0400
committerJason A. Donenfeld <Jason@zx2c4.com>2009-05-02 01:21:51 -0400
commitfb8677daa2658e52511317511d497dfc456e4dc8 (patch)
tree5cbeb07a8dbea9674d19ce1edb3d040ef175ea03
downloadMessagePopper-fb8677daa2658e52511317511d497dfc456e4dc8.tar.xz
MessagePopper-fb8677daa2658e52511317511d497dfc456e4dc8.zip
Initial commit.
-rw-r--r--MessageForm.cpp117
-rw-r--r--MessageForm.h40
-rw-r--r--MessageListener.cpp119
-rw-r--r--MessageListener.h47
-rw-r--r--MessagePopper.pro8
-rw-r--r--main.cpp15
6 files changed, 346 insertions, 0 deletions
diff --git a/MessageForm.cpp b/MessageForm.cpp
new file mode 100644
index 0000000..9156b35
--- /dev/null
+++ b/MessageForm.cpp
@@ -0,0 +1,117 @@
+#include <QMainWindow>
+#include <QLineEdit>
+#include <QTextBrowser>
+#include <QStatusBar>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QTextBrowser>
+#include <QPushButton>
+#include <QLabel>
+#include <QGroupBox>
+#include "MessageListener.h"
+#include "MessageForm.h"
+
+MessageForm::MessageForm(QWidget *parent)
+ : QMainWindow(parent)
+{
+ listener = new MessageListener(this);
+ connect(listener, SIGNAL(receivedMessage(QString)), this, SLOT(receivedMessage(QString)));
+ connect(listener, SIGNAL(connected()), this, SLOT(connected()));
+ connect(listener, SIGNAL(disconnected()), this, SLOT(disconnected()));
+ connect(listener, SIGNAL(connectionFailed()), this, SLOT(connectionFailed()));
+
+ messageInput = new QLineEdit;
+ messageDisplay = new QTextBrowser;
+ statusInfo = new QLabel;
+ statusBar()->addWidget(statusInfo, 1);
+ connectServer = new QLineEdit;
+ QPushButton *connectButton = new QPushButton("&Connect");
+ QPushButton *sendButton = new QPushButton("&Send");
+ QLabel *connectLabel = new QLabel("Server");
+ connectLabel->setBuddy(connectServer);
+
+ connect(connectServer, SIGNAL(returnPressed()), connectButton, SIGNAL(clicked()));
+ connect(messageInput, SIGNAL(returnPressed()), sendButton, SIGNAL(clicked()));
+ connect(connectButton, SIGNAL(clicked()), this, SLOT(connectToServer()));
+ connect(sendButton, SIGNAL(clicked()), this, SLOT(sendMessage()));
+
+
+ QHBoxLayout *connectLayout = new QHBoxLayout;
+ connectLayout->addWidget(connectLabel);
+ connectLayout->addWidget(connectServer);
+ connectLayout->addWidget(connectButton);
+ QVBoxLayout *messageLayout = new QVBoxLayout;
+ QHBoxLayout *sendLayout = new QHBoxLayout;
+ sendLayout->addWidget(messageInput);
+ sendLayout->addWidget(sendButton);
+ messageLayout->addWidget(messageDisplay);
+ messageLayout->addLayout(sendLayout);
+
+ connectGroup = new QGroupBox("Connect to Server");
+ connectGroup->setLayout(connectLayout);
+ messageGroup = new QGroupBox("Network Chat");
+ messageGroup->setLayout(messageLayout);
+
+ QVBoxLayout *allLayout = new QVBoxLayout;
+ allLayout->addWidget(connectGroup);
+ allLayout->addWidget(messageGroup);
+ QWidget *centralWidget = new QWidget;
+ centralWidget->setLayout(allLayout);
+ setCentralWidget(centralWidget);
+ setWindowTitle("ZX2C4 Message Popper");
+
+ listenForConnection();
+}
+void MessageForm::appendMessage(QString sender, const QString &message)
+{
+ static bool firstMessage = true;
+ messageDisplay->moveCursor(QTextCursor::End);
+ messageDisplay->insertHtml((firstMessage ? QString("") : "<br>") + "<b>" + sender + ": </b>" + message);
+ messageDisplay->moveCursor(QTextCursor::End);
+ firstMessage = false;
+}
+void MessageForm::receivedMessage(const QString text)
+{
+ appendMessage(QString("Stranger"), text);
+}
+void MessageForm::connected()
+{
+ messageGroup->setVisible(true);
+ connectGroup->setVisible(false);
+ statusInfo->setText(QString("Connected to %1.").arg(listener->remoteHost()));
+ statusBar()->clearMessage();
+}
+void MessageForm::disconnected()
+{
+ statusBar()->showMessage("Disconnected!", 2000);
+ listenForConnection();
+}
+void MessageForm::connectionFailed()
+{
+ statusBar()->showMessage("Connection failed!", 2000);
+ connectGroup->setEnabled(true);
+}
+void MessageForm::sendMessage()
+{
+ QString text = messageInput->text();
+ messageInput->clear();
+ listener->writeMessage(text);
+ appendMessage(QString("Me"), text);
+}
+void MessageForm::connectToServer()
+{
+ connectGroup->setEnabled(false);
+ listener->connectToHost(connectServer->text());
+ statusBar()->showMessage("Connecting...");
+}
+void MessageForm::listenForConnection()
+{
+ messageGroup->setVisible(false);
+ connectGroup->setVisible(true);
+ connectGroup->setEnabled(true);
+ if(listener->startListener())
+ statusInfo->setText("Listening for connection...");
+ else
+ statusInfo->setText("Listener failed to start.");
+ statusBar()->clearMessage();
+}
diff --git a/MessageForm.h b/MessageForm.h
new file mode 100644
index 0000000..9a3ce72
--- /dev/null
+++ b/MessageForm.h
@@ -0,0 +1,40 @@
+#ifndef MESSAGEFORM_H
+#define MESSAGEFORM_H
+
+#include <QMainWindow>
+
+class QLineEdit;
+class QTextBrowser;
+class QLabel;
+class QGroupBox;
+class QTextBrowser;
+class MessageListener;
+
+class MessageForm : public QMainWindow
+{
+ Q_OBJECT;
+
+public:
+ MessageForm(QWidget *parent = 0);
+
+private slots:
+ void receivedMessage(const QString text);
+ void connected();
+ void disconnected();
+ void connectionFailed();
+ void sendMessage();
+ void connectToServer();
+
+private:
+ MessageListener *listener;
+ QLineEdit *messageInput;
+ QTextBrowser *messageDisplay;
+ QLabel *statusInfo;
+ QLineEdit *connectServer;
+ QGroupBox *connectGroup;
+ QGroupBox *messageGroup;
+ inline void listenForConnection();
+ void appendMessage(QString sender, const QString &message);
+};
+
+#endif
diff --git a/MessageListener.cpp b/MessageListener.cpp
new file mode 100644
index 0000000..ecb3bda
--- /dev/null
+++ b/MessageListener.cpp
@@ -0,0 +1,119 @@
+#include <QtCore>
+#include <QtNetwork>
+#include "MessageListener.h"
+
+MessageListener::MessageListener(QObject *parent)
+ : QObject(parent)
+{
+ listener = new QTcpServer(this);
+ connection = 0;
+ connect(listener, SIGNAL(newConnection()), this, SLOT(receivedConnection()));
+}
+MessageListener::~MessageListener()
+{
+ stopListener();
+ if(connection) {
+ closeConnection();
+ delete connection;
+ }
+ delete listener;
+}
+bool MessageListener::startListener(quint16 port)
+{
+ if(listener->isListening())
+ return false;
+
+ return listener->listen(QHostAddress::Any, port);
+}
+void MessageListener::stopListener()
+{
+ listener->close();
+}
+void MessageListener::closeConnection()
+{
+ if(connection) {
+ connection->disconnectFromHost();
+ emit disconnected();
+ }
+}
+void MessageListener::receivedConnection()
+{
+ connection = listener->nextPendingConnection();
+ if(connection) {
+ stopListener();
+ setupConnections();
+ emit connected();
+ }
+}
+void MessageListener::setupConnections()
+{
+ connect(connection, SIGNAL(readyRead()), this, SLOT(receivedData()));
+ connect(connection, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(handleError(QAbstractSocket::SocketError)));
+}
+bool MessageListener::writeMessage(const QString &message)
+{
+ if(!connection || connection->state() != QAbstractSocket::ConnectedState)
+ return false;
+
+ QByteArray block;
+ QDataStream out(&block, QIODevice::WriteOnly);
+ out << (quint16)0;
+ out << message;
+ out.device()->seek(0);
+ out << (quint16)(block.size() - sizeof(quint16));
+ return connection->write(block) == block.size();
+
+}
+void MessageListener::connectToHost(const QString &address, quint16 port)
+{
+ if(connection && connection->state() == QAbstractSocket::ConnectedState)
+ closeConnection();
+
+ if(!connection) {
+ connection = new QTcpSocket(this);
+ connect(connection, SIGNAL(connected()), this, SLOT(stopListener()));
+ connect(connection, SIGNAL(connected()), this, SIGNAL(connected()));
+ setupConnections();
+ }
+ connection->connectToHost(address, port);
+}
+void MessageListener::receivedData()
+{
+ static quint16 blockSize = 0;
+ QDataStream in(connection);
+ if(blockSize == 0) {
+ if(connection->bytesAvailable() < (int)sizeof(quint16))
+ return;
+ in >> blockSize;
+ }
+
+ if(connection->bytesAvailable() < blockSize)
+ return;
+
+ QString message;
+ in >> message;
+ blockSize = 0;
+ emit receivedMessage(message);
+}
+void MessageListener::handleError(QAbstractSocket::SocketError error)
+{
+ switch(error)
+ {
+ case QAbstractSocket::RemoteHostClosedError:
+ emit disconnected();
+ break;
+ case QAbstractSocket::NetworkError:
+ case QAbstractSocket::UnknownSocketError:
+ closeConnection();
+ break;
+ default:
+ emit connectionFailed();
+ }
+}
+QString MessageListener::remoteHost() const
+{
+ if(connection)
+ return connection->peerAddress().toString();
+ else
+ return QString();
+}
diff --git a/MessageListener.h b/MessageListener.h
new file mode 100644
index 0000000..b6fb143
--- /dev/null
+++ b/MessageListener.h
@@ -0,0 +1,47 @@
+#ifndef MESSAGELISTENER_H
+#define MESSAGELISTENER_H
+
+#include <QObject>
+#include <QAbstractSocket>
+
+#define DEFAULT_PORT 3112
+
+class QTcpServer;
+class QTcpSocket;
+class QString;
+class QHostAddress;
+
+class MessageListener : public QObject
+{
+ Q_OBJECT
+
+public:
+ MessageListener(QObject *parent = 0);
+ ~MessageListener();
+ QString remoteHost() const;
+
+public slots:
+ bool startListener(quint16 port = DEFAULT_PORT);
+ void stopListener();
+ void closeConnection();
+ bool writeMessage(const QString &text);
+ void connectToHost(const QString &address, quint16 port = DEFAULT_PORT);
+
+signals:
+ void receivedMessage(const QString text);
+ void connected();
+ void disconnected();
+ void connectionFailed();
+
+private:
+ QTcpServer *listener;
+ QTcpSocket *connection;
+ inline void setupConnections();
+
+private slots:
+ void receivedConnection();
+ void receivedData();
+ void handleError(QAbstractSocket::SocketError error);
+};
+
+#endif
diff --git a/MessagePopper.pro b/MessagePopper.pro
new file mode 100644
index 0000000..a780c73
--- /dev/null
+++ b/MessagePopper.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+QT += network gui core
+HEADERS += MessageForm.h MessageListener.h
+SOURCES += main.cpp MessageForm.cpp MessageListener.cpp
+CONFIG += debug warn_on
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..4167e14
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,15 @@
+#include <QApplication>
+#include <QHostAddress>
+
+#include "MessageForm.h"
+#include "MessageListener.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+
+ MessageForm a;
+ a.show();
+
+ return app.exec();
+}