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