diff --git a/Client/Client.cpp b/Client/Client.cpp index f939aab..2a3e0f7 100644 --- a/Client/Client.cpp +++ b/Client/Client.cpp @@ -105,3 +105,14 @@ void Client::onSendPrivateMessage(QString receiver, QString message, QString sen std::string package = packaging.createPivatePackage(receiver.toStdString(), message.toStdString(), sender.toStdString()); sendPackage(QString::fromStdString(package)); } + +void Client::onSendFile(QByteArray blob, int fileSize, QString receiver, QString sender) { + // send over the file_size package + std::string package = packaging.createFileSizePackage(fileSize); + sendPackage(QString::fromStdString(package)); + + tcpSocket->waitForBytesWritten(); + tcpSocket->flush(); + package = blob.toStdString(); + sendPackage(QString::fromStdString(package)); +} diff --git a/Client/Client.h b/Client/Client.h index c36496f..7b89e0b 100644 --- a/Client/Client.h +++ b/Client/Client.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "../util/Packaging.h" @@ -47,6 +48,7 @@ public slots: void onLogoutRequest(); void onGlobalPackage(QString message); void onSendPrivateMessage(QString receiver, QString message, QString sender); + void onSendFile(QByteArray blob, int fileSize, QString receiver, QString sender); }; #endif // CLIENT_H diff --git a/Client/LoginDialog.cpp b/Client/LoginDialog.cpp index b295897..3445507 100644 --- a/Client/LoginDialog.cpp +++ b/Client/LoginDialog.cpp @@ -1,5 +1,5 @@ #include "LoginDialog.h" -#include "ui_logindialog.h" +#include "ui_LoginDialog.h" #include diff --git a/Client/LoginDialog.ui b/Client/LoginDialog.ui index 738a64a..d09148a 100644 --- a/Client/LoginDialog.ui +++ b/Client/LoginDialog.ui @@ -9,8 +9,8 @@ 0 0 - 300 - 210 + 250 + 197 diff --git a/Client/MainWindow.cpp b/Client/MainWindow.cpp index 4e873d2..e02d149 100644 --- a/Client/MainWindow.cpp +++ b/Client/MainWindow.cpp @@ -1,5 +1,5 @@ #include "MainWindow.h" -#include "ui_mainwindow.h" +#include "ui_MainWindow.h" MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); @@ -26,6 +26,7 @@ void MainWindow::onSignIn(QString username, QString password, QString serverAddr this->password = password; this->serverAddr = serverAddr; this->port = port; + this->setWindowTitle(username); initClient(); } diff --git a/Client/PrivateMessageDialog.cpp b/Client/PrivateMessageDialog.cpp index 4211c63..23ce876 100644 --- a/Client/PrivateMessageDialog.cpp +++ b/Client/PrivateMessageDialog.cpp @@ -9,6 +9,9 @@ PrivateMessageDialog::PrivateMessageDialog(QWidget* parent, Client* client, QStr connect(client, &Client::receivedPrivateMessage, this, &PrivateMessageDialog::onReceivedPrivateMessage); connect(ui->btnSendMessage, &QPushButton::clicked, this, &PrivateMessageDialog::onSendMessageButtonClicked); connect(this, &PrivateMessageDialog::sendPrivateMessage, client, &Client::onSendPrivateMessage); + + connect(ui->btnSendFile, &QPushButton::clicked, this, &PrivateMessageDialog::onSendFile); + connect(this, &PrivateMessageDialog::sendFile, client, &Client::onSendFile); } PrivateMessageDialog::~PrivateMessageDialog() { @@ -30,3 +33,21 @@ void PrivateMessageDialog::onSendMessageButtonClicked() { QString output = sender + ": " + message; ui->editRecvMessage->append(output); } + +void PrivateMessageDialog::onSendFile() { + QString fileName = QFileDialog::getOpenFileName(this, tr("Open file"), "/home", + tr("All files (*)")); + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) { + QMessageBox::information(this, "File open error", + tr("There was a problem with opening the file!")); + return; + } + + QByteArray blob = file.readAll(); + int fileSize = blob.size(); + QString receiver = chatPartner; + QString sender = client->getUsername(); + + emit sendFile(blob, fileSize, receiver, sender); +} diff --git a/Client/PrivateMessageDialog.h b/Client/PrivateMessageDialog.h index c52aa24..cbe254c 100644 --- a/Client/PrivateMessageDialog.h +++ b/Client/PrivateMessageDialog.h @@ -2,6 +2,10 @@ #define PRIVATEMESSAGEDIALOG_HPP #include +#include +#include +#include +#include #include "Client.h" @@ -27,10 +31,12 @@ class PrivateMessageDialog : public QDialog { signals: void closeDialog(QString username); void sendPrivateMessage(QString receiver, QString message, QString sender); + void sendFile(QByteArray blob, int fileSize, QString receiver, QString sender); public slots: void onReceivedPrivateMessage(QString receiver, QString message, QString sender); void onSendMessageButtonClicked(); + void onSendFile(); }; #endif // PRIVATEMESSAGEDIALOG_HPP diff --git a/Client/PrivateMessageDialog.ui b/Client/PrivateMessageDialog.ui index 5d0f96b..ba672d5 100644 --- a/Client/PrivateMessageDialog.ui +++ b/Client/PrivateMessageDialog.ui @@ -6,8 +6,8 @@ 0 0 - 241 - 308 + 282 + 334 @@ -15,8 +15,8 @@ - - + + QFrame::Panel @@ -29,7 +29,7 @@ - + QFrame::Panel @@ -76,7 +76,7 @@ background-color: rgb(85, 255, 127); - + Qt::Horizontal @@ -89,6 +89,17 @@ background-color: rgb(85, 255, 127); + + + + +background-color: rgb(85, 255, 127); + + + Attach file + + + diff --git a/Server/ClientThread.cpp b/Server/ClientThread.cpp index 220a423..a9e578a 100644 --- a/Server/ClientThread.cpp +++ b/Server/ClientThread.cpp @@ -52,9 +52,12 @@ void* ClientThread::run() { } else if (request.compare("private_package") == 0) { std::cout << "request: " << "private_package" << "\n"; onPrivateMessageRequest(package); + } else if (request.compare("file_size_package") == 0) { + std::cout << "request: " << "file transfer" << "\n"; + onFileTransfer(package); } - std::this_thread::sleep_for(std::chrono::milliseconds(5000)); + //std::this_thread::sleep_for(std::chrono::milliseconds(5000)); } } @@ -145,6 +148,20 @@ void ClientThread::onPrivateMessageRequest(const std::string& package) { sendPackageToTarget(package, receiver); } +void ClientThread::onFileTransfer(const std::string& package) { + packaging.parsePackage(package); + int fileSize = stoi(packaging.getMessage()); + std::cout << "file size: " << fileSize << "\n"; + + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + std::string readPackage = readFilePackage(fileSize); + //std::cout << readPackage; + std::ofstream file; + file.open("../output.txt", std::ios::out); + file << readPackage; + file.close(); +} + void ClientThread::onLogoutRequest() { std::cout << "Disconnecting user..\n"; // TODO: remove the disconnected user from the online user's list @@ -157,13 +174,32 @@ void ClientThread::onLogoutRequest() { std::string ClientThread::readPackage() { int buffSize = sizeof(messageBuff); - char msgBuff[1024]; - int res = recv(acceptSocket, msgBuff, buffSize, 0); - if (res != 0) { + int res = recv(acceptSocket, messageBuff, buffSize, 0); + if (res > 0) { std::cout << " bytes: " << res << "\n"; } - if (res < 0) { + else if (res == 0) { + tcpserver->removeClient(user.getUsername()); + pthread_exit(NULL); + } + else { + errorMsg = "error when receiving the message from the client!\n"; + error(errorMsg.c_str()); + } + messageBuff[res] = '\0'; + return messageBuff; +} + +std::string ClientThread::readFilePackage(int fileSize) { + int buffSize = sizeof(messageBuff); + char msgBuff[fileSize]; + + int res = recv(acceptSocket, msgBuff, fileSize, 0); + if (res > 0) { + std::cout << "\n file bytes read: " << res << "\n"; + } + else { errorMsg = "error when receiving the message from the client!\n"; error(errorMsg.c_str()); } diff --git a/Server/ClientThread.h b/Server/ClientThread.h index f82889e..4f27593 100644 --- a/Server/ClientThread.h +++ b/Server/ClientThread.h @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include "../util/Packaging.h" #include "MyThread.h" @@ -46,6 +48,7 @@ class ClientThread : public MyThread { void onLogoutRequest(); void onGlobalMessageRequest(const std::string& package); void onPrivateMessageRequest(const std::string& package); + void onFileTransfer(const std::string& package); bool logoutRequest = false; @@ -57,13 +60,16 @@ class ClientThread : public MyThread { private: int acceptSocket; - char messageBuff[1024]; + char messageBuff[2048]; /** basic information about a user */ User user; void sendPackage(const std::string& package); /** reads the incoming package from the user */ std::string readPackage(); + /** reads a file package which comes right after the file's size package and saves into an output file */ + std::string readFilePackage(int fileSize); + /** sends the package to every online user*/ void sendPackageToAll(const std::string& package); void sendPackageToTarget(const std::string& package, const std::string& target); diff --git a/Server/TCPServer.cpp b/Server/TCPServer.cpp index ec6291d..439aabf 100644 --- a/Server/TCPServer.cpp +++ b/Server/TCPServer.cpp @@ -75,9 +75,19 @@ void TCPServer::startServer() { } } -void TCPServer::removeClient(ClientThread& clientThread) { - //std::unique_ptr clientPtr = static_cast>(&clientThread); - //usersPtr->remove(clientPtr); +// TODO: remove client +void TCPServer::removeClient(const std::string& username) { + /* std::cout << "nr of users: " << usersPtr->size() << "\n"; + auto list = usersPtr.get(); + std::list>::const_iterator iterator; + for (iterator = list->begin(); iterator != list->end(); ++iterator) { + std::string tmp = (**iterator).getUsername(); + if (tmp.compare(username) == 0) { + break; + } + } + usersPtr->erase(iterator); + std::cout << "nr of users after delete: " << usersPtr->size() << "\n"; */ } std::vector TCPServer::getOnlineUsers() { diff --git a/Server/TCPServer.h b/Server/TCPServer.h index dfcd457..a2f4ff7 100644 --- a/Server/TCPServer.h +++ b/Server/TCPServer.h @@ -28,7 +28,7 @@ class TCPServer { virtual ~TCPServer(); void startServer(); - void removeClient(ClientThread& clientThread); + void removeClient(const std::string& username); std::vector getOnlineUsers(); void lockMutex() { pthread_mutex_lock(&mutex); } diff --git a/util/Packaging.cpp b/util/Packaging.cpp index 463d083..3d23e52 100644 --- a/util/Packaging.cpp +++ b/util/Packaging.cpp @@ -66,16 +66,26 @@ std::string Packaging::createOnlineUsersPackage(const std::vector& // inserts the elements into the "joinedFields" stream, with the "," delimiter std::copy(onlineUsers.begin(), onlineUsers.end(), std::ostream_iterator(joinedFields, ",")); std::string usersList = joinedFields.str(); - // unnecessary delimiter on the end of the string - //usersList[usersList.length() - 1] = '\0'; - /*std::string usersList; - usersList.assign(tmpStr, 0, tmpStr.length() - 1);*/ this->receiver = "list_users"; this->message = usersList; this->sender = "server"; return constructPackage(); } +std::string Packaging::createFileSizePackage(int fileSize) { + this->receiver = "file_size"; + this->message = std::to_string(fileSize); + this->sender = sender; + return constructPackage(); +} + +std::string Packaging::createFilePackage(const std::string& blob, const std::string& receiver, const std::string& sender) { + this->receiver = receiver; + this->message = blob; + this->sender = sender; + return constructPackage(); +} + std::string Packaging::constructPackage() { std::string pckg = receiver + glue + glue + message + glue + sender + glue; size_t len = pckg.length(); @@ -127,6 +137,9 @@ std::string Packaging::identifyRequest(std::string package) { if (token.compare("list_users") == 0) { return "online_users_package"; } + if (token.compare("file_size") == 0) { + return "file_size_package"; + } // erase token + glue package.erase(0, pos + 1); } diff --git a/util/Packaging.h b/util/Packaging.h index 25206a2..919d55b 100644 --- a/util/Packaging.h +++ b/util/Packaging.h @@ -33,6 +33,7 @@ * - disconnect: message = "disconnect" * - global: receiver = "global" * - list_users: receiver = "list_users" + * - file_size: receiver = "file_size" */ class Packaging { public: @@ -53,6 +54,10 @@ class Packaging { std::string createPivatePackage(const std::string& receiver, const std::string& message, const std::string& sender); /** package used to send the online user's list to a user */ std::string createOnlineUsersPackage(const std::vector& onlineUsers); + /** package used to signal the incoming file's size */ + std::string createFileSizePackage(int fileSize); + /** package used to send a binary stream */ + std::string createFilePackage(const std::string& blob, const std::string& receiver, const std::string& sender); void parsePackage(std::string package);