SEND command
This commit is contained in:
parent
8557e32690
commit
8021d7c6cb
10
Makefile
10
Makefile
@ -1,7 +1,7 @@
|
|||||||
CC = g++
|
CC = g++
|
||||||
ASAN_FLAGS = -fsanitize=address -fno-omit-frame-pointer -Wno-format-security
|
ASAN_FLAGS = -fsanitize=address -fno-omit-frame-pointer -Wno-format-security
|
||||||
CFLAGS := -std=c++20 -Wall -lssl -lcrypto
|
CFLAGS := -g -std=c++20 -Wall -lssl -lcrypto
|
||||||
LDFLAGS += -lpthread
|
LDFLAGS += -fsanitize=address -lpthread
|
||||||
|
|
||||||
TARGET = client server
|
TARGET = client server
|
||||||
BUILD_DIR = build
|
BUILD_DIR = build
|
||||||
@ -9,7 +9,7 @@ BUILD_DIR = build
|
|||||||
SOURCES_CLIENT = client.cpp
|
SOURCES_CLIENT = client.cpp
|
||||||
OBJS_CLIENT = $(addprefix $(BUILD_DIR)/,$(SOURCES_CLIENT:.cpp=.o))
|
OBJS_CLIENT = $(addprefix $(BUILD_DIR)/,$(SOURCES_CLIENT:.cpp=.o))
|
||||||
|
|
||||||
SOURCES_SERVER = server.cpp user.cpp user_handler.cpp
|
SOURCES_SERVER = server.cpp user.cpp user_handler.cpp mail.cpp
|
||||||
OBJS_SERVER = $(addprefix $(BUILD_DIR)/,$(SOURCES_SERVER:.cpp=.o))
|
OBJS_SERVER = $(addprefix $(BUILD_DIR)/,$(SOURCES_SERVER:.cpp=.o))
|
||||||
|
|
||||||
all: $(BUILD_DIR) $(TARGET)
|
all: $(BUILD_DIR) $(TARGET)
|
||||||
@ -18,10 +18,10 @@ $(BUILD_DIR):
|
|||||||
mkdir -p $(BUILD_DIR)
|
mkdir -p $(BUILD_DIR)
|
||||||
|
|
||||||
client: $(OBJS_CLIENT)
|
client: $(OBJS_CLIENT)
|
||||||
$(CC) $(CFLAGS) $(ASAN_FLAGS) -o twmailer-client $^
|
$(CC) $(CFLAGS) $(ASAN_FLAGS) -o twmailer-client $^ $(LDFLAGS)
|
||||||
|
|
||||||
server: $(OBJS_SERVER)
|
server: $(OBJS_SERVER)
|
||||||
$(CC) $(CFLAGS) $(ASAN_FLAGS) -o twmailer-server $^
|
$(CC) $(CFLAGS) $(ASAN_FLAGS) -o twmailer-server $^ $(LDFLAGS)
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: %.cpp
|
$(BUILD_DIR)/%.o: %.cpp
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|||||||
24
mail.cpp
Normal file
24
mail.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include "mail.h"
|
||||||
|
|
||||||
|
mail::mail(std::string filename, int64_t timestamp, std::string subject) :
|
||||||
|
filename(filename),
|
||||||
|
timestamp(timestamp),
|
||||||
|
subject(subject)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fs::path mail::getPath() {
|
||||||
|
if (this->filename.empty())
|
||||||
|
return fs::path();
|
||||||
|
return fs::path(this->filename.insert(2, "/"));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void mail::remove()
|
||||||
|
{
|
||||||
|
if (this->filename.empty())
|
||||||
|
return;
|
||||||
|
std::remove((user_handler::getInstance()->getSpoolDir()/"objects"/fs::path(this->filename.insert(2, "/"))).c_str());
|
||||||
|
|
||||||
|
this->filename = "";
|
||||||
|
}
|
||||||
16
mail.h
16
mail.h
@ -19,6 +19,8 @@ struct mail {
|
|||||||
std::vector<std::string> recipients;
|
std::vector<std::string> recipients;
|
||||||
std::string subject;
|
std::string subject;
|
||||||
|
|
||||||
|
mail(std::string filename, int64_t timestamp, std::string subject);
|
||||||
|
|
||||||
bool operator()(const u_int& id) const {
|
bool operator()(const u_int& id) const {
|
||||||
return id == this->id;
|
return id == this->id;
|
||||||
}
|
}
|
||||||
@ -27,17 +29,7 @@ struct mail {
|
|||||||
return this->timestamp < left.timestamp;
|
return this->timestamp < left.timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path getPath() {
|
fs::path getPath() { return this->filename; };
|
||||||
if (this->filename.empty())
|
|
||||||
return fs::path();
|
|
||||||
return fs::path(this->filename.insert(2, "/"));
|
|
||||||
};
|
|
||||||
|
|
||||||
void remove() {
|
void remove();
|
||||||
if (this->filename.empty())
|
|
||||||
return;
|
|
||||||
std::remove((user_handler::getInstance()->getSpoolDir()/"objects"/fs::path(this->filename.insert(2, "/"))).c_str());
|
|
||||||
|
|
||||||
this->filename = "";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
123
server.cpp
123
server.cpp
@ -1,16 +1,19 @@
|
|||||||
#include "user.h"
|
#include "user.h"
|
||||||
#include "user_handler.h"
|
#include "user_handler.h"
|
||||||
|
|
||||||
#include "readline.h"
|
#include "mail.h"
|
||||||
|
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <ctime>
|
||||||
|
#include <exception>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <locale>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <boost/compute/detail/sha1.hpp>
|
#include <boost/compute/detail/sha1.hpp>
|
||||||
@ -41,11 +44,12 @@ int new_socket = -1;
|
|||||||
void printUsage();
|
void printUsage();
|
||||||
inline bool isInteger(const std::string & s);
|
inline bool isInteger(const std::string & s);
|
||||||
|
|
||||||
void saveToFile(fs::path object_dir, std::string message);
|
std::string saveToFile(fs::path object_dir, std::string message);
|
||||||
std::string get_sha1(const std::string& p_arg);
|
std::string get_sha1(const std::string& p_arg);
|
||||||
|
|
||||||
// from myserver.c
|
// from myserver.c
|
||||||
void *clientCommunication(void *data);
|
void *clientCommunication(void *data);
|
||||||
|
inline std::string recvToStr(int __fd, size_t __n, int __flags);
|
||||||
void signalHandler(int sig);
|
void signalHandler(int sig);
|
||||||
|
|
||||||
user_handler* user_handler::instancePtr = nullptr;
|
user_handler* user_handler::instancePtr = nullptr;
|
||||||
@ -185,56 +189,61 @@ void *clientCommunication(void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
size = recv(*current_socket, buffer, BUF - 1, 0);
|
std::string message;
|
||||||
if (size == -1) {
|
try {
|
||||||
if (abortRequested) {
|
message = recvToStr(*current_socket, BUF - 1, 0);
|
||||||
perror("recv error after aborted");
|
}
|
||||||
} else {
|
catch(...) {
|
||||||
perror("recv error");
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size == 0) {
|
std::stringstream ss(message.c_str());
|
||||||
printf("Client closed remote socket\n"); // ignore error
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove ugly debug message, because of the sent newline of client
|
|
||||||
if (buffer[size - 2] == '\r' && buffer[size - 1] == '\n') {
|
|
||||||
size -= 2;
|
|
||||||
} else if (buffer[size - 1] == '\n') {
|
|
||||||
--size;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer[size] = '\0';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* New code here for handling requests */
|
|
||||||
|
|
||||||
|
|
||||||
std::stringstream ss(buffer);
|
|
||||||
std::string line;
|
std::string line;
|
||||||
|
|
||||||
std::vector<std::string> message;
|
std::vector<std::string> lines;
|
||||||
|
|
||||||
while (std::getline(ss, line, '\n')) {
|
while (std::getline(ss, line, '\n')) {
|
||||||
message.push_back(line);
|
lines.push_back(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
enum commands cmd;
|
enum commands cmd;
|
||||||
|
|
||||||
// can't wait for reflections (maybe c++26?)
|
// can't wait for reflections (maybe c++26?)
|
||||||
if (boost::iequals(message.at(0), "SEND")) cmd = SEND;
|
if (boost::iequals(lines.at(0), "SEND")) cmd = SEND;
|
||||||
else if (boost::iequals(message.at(0), "LIST")) cmd = LIST;
|
else if (boost::iequals(lines.at(0), "LIST")) cmd = LIST;
|
||||||
else if (boost::iequals(message.at(0), "READ")) cmd = READ;
|
else if (boost::iequals(lines.at(0), "READ")) cmd = READ;
|
||||||
else if (boost::iequals(message.at(0), "DEL")) cmd = DEL;
|
else if (boost::iequals(lines.at(0), "DEL")) cmd = DEL;
|
||||||
else if (boost::iequals(message.at(0), "QUIT")) cmd = QUIT;
|
else if (boost::iequals(lines.at(0), "QUIT")) cmd = QUIT;
|
||||||
|
|
||||||
|
if (cmd == SEND && !boost::equals(lines.back(), ".\n")) {
|
||||||
|
try {
|
||||||
|
message.append(recvToStr(*current_socket, BUF - 1, 0));
|
||||||
|
std::stringstream ss(message.c_str()); // inefficient to repeat
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
lines.clear();
|
||||||
|
while (std::getline(ss, line, '\n')) {
|
||||||
|
lines.push_back(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(...) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SEND:
|
case SEND:
|
||||||
|
if (lines.at(3).length() > 80) {
|
||||||
|
// send error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
user_handler::getInstance()->getUser(lines.at(1))->sendMail(
|
||||||
|
new struct mail(saveToFile(user_handler::getInstance()->getSpoolDir()/"messages", lines.at(4)), std::time(0), lines.at(3)),
|
||||||
|
{lines.at(2)}
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
case LIST:
|
case LIST:
|
||||||
case READ:
|
case READ:
|
||||||
case DEL:
|
case DEL:
|
||||||
@ -246,6 +255,7 @@ void *clientCommunication(void *data)
|
|||||||
perror("send answer failed");
|
perror("send answer failed");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (strcmp(buffer, "quit") != 0 && !abortRequested);
|
} while (strcmp(buffer, "quit") != 0 && !abortRequested);
|
||||||
|
|
||||||
// closes/frees the descriptor if not already
|
// closes/frees the descriptor if not already
|
||||||
@ -262,6 +272,38 @@ void *clientCommunication(void *data)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::string recvToStr(int __fd, size_t __n, int __flags)
|
||||||
|
{
|
||||||
|
char buffer[BUF];
|
||||||
|
int size;
|
||||||
|
|
||||||
|
size = recv(__fd, buffer, __n, __flags);
|
||||||
|
if (size == -1) {
|
||||||
|
if (abortRequested) {
|
||||||
|
perror("recv error after aborted");
|
||||||
|
} else {
|
||||||
|
perror("recv error");
|
||||||
|
}
|
||||||
|
throw std::exception().what();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
printf("Client closed remote socket\n"); // ignore error
|
||||||
|
throw std::exception().what();
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove ugly debug message, because of the sent newline of client
|
||||||
|
if (buffer[size - 2] == '\r' && buffer[size - 1] == '\n') {
|
||||||
|
size -= 2;
|
||||||
|
} else if (buffer[size - 1] == '\n') {
|
||||||
|
--size;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[size] = '\0';
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
void signalHandler(int sig)
|
void signalHandler(int sig)
|
||||||
{
|
{
|
||||||
if (sig == SIGINT) {
|
if (sig == SIGINT) {
|
||||||
@ -294,11 +336,12 @@ void signalHandler(int sig)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveToFile(fs::path object_dir, std::string message)
|
std::string saveToFile(fs::path object_dir, std::string message)
|
||||||
{
|
{
|
||||||
std::string sha1 = get_sha1(message);
|
std::string sha1 = get_sha1(message);
|
||||||
std::ofstream ofs(object_dir/sha1); // possible issues with path length or file length limitations
|
std::ofstream ofs(object_dir/sha1); // possible issues with path length or file length limitations
|
||||||
ofs << message;
|
ofs << message;
|
||||||
|
return sha1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/28489153/how-to-portably-compute-a-sha1-hash-in-c
|
// https://stackoverflow.com/questions/28489153/how-to-portably-compute-a-sha1-hash-in-c
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#include "user_handler.h"
|
#include "user_handler.h"
|
||||||
|
#include "user.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
user_handler::user_handler()
|
user_handler::user_handler()
|
||||||
@ -9,4 +11,14 @@ user_handler::user_handler()
|
|||||||
this->users.insert(std::pair<std::string, user*>(fs::path(entry.path()).replace_extension(), new user(entry)));
|
this->users.insert(std::pair<std::string, user*>(fs::path(entry.path()).replace_extension(), new user(entry)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
user* user_handler::getUser(std::string name)
|
||||||
|
{
|
||||||
|
if (this->users.find(name) == this->users.end()) {
|
||||||
|
this->users[name] = fs::exists(this->spool_dir/"users"/(name+".json")) ?
|
||||||
|
new user(this->spool_dir/"users"/(name+".json")) :
|
||||||
|
new user(name, this->spool_dir/"users");
|
||||||
|
}
|
||||||
|
return this->users[name];
|
||||||
}
|
}
|
||||||
@ -26,7 +26,7 @@ public:
|
|||||||
|
|
||||||
void setSpoolDir(fs::path p) { this->spool_dir = p; };
|
void setSpoolDir(fs::path p) { this->spool_dir = p; };
|
||||||
fs::path getSpoolDir() { return this->spool_dir; };
|
fs::path getSpoolDir() { return this->spool_dir; };
|
||||||
user* getUser(std::string name) { return this->users[name]; };
|
user* getUser(std::string name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user