mirror of
https://github.com/Ladebeze66/ft_irc.git
synced 2026-11-09 13:17:13 +01:00
Initial commit
This commit is contained in:
18
ft_irc3/.vscode/c_cpp_properties.json
vendored
Normal file
18
ft_irc3/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "linux-gcc-x64",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"compilerPath": "/usr/bin/gcc",
|
||||
"cStandard": "${default}",
|
||||
"cppStandard": "${default}",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"compilerArgs": [
|
||||
""
|
||||
]
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
24
ft_irc3/.vscode/launch.json
vendored
Normal file
24
ft_irc3/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "C/C++ Runner: Debug Session",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": false,
|
||||
"cwd": "/home/fgras-ca/Bureau/ft_irc3/src",
|
||||
"program": "/home/fgras-ca/Bureau/ft_irc3/src/build/Debug/outDebug",
|
||||
"MIMode": "gdb",
|
||||
"miDebuggerPath": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
120
ft_irc3/.vscode/settings.json
vendored
Normal file
120
ft_irc3/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"cctype": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"map": "cpp",
|
||||
"string": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"random": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"fstream": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"new": "cpp",
|
||||
"numbers": "cpp",
|
||||
"ostream": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"list": "cpp",
|
||||
"chrono": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"ctime": "cpp",
|
||||
"set": "cpp",
|
||||
"ratio": "cpp",
|
||||
"mutex": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"thread": "cpp",
|
||||
"cinttypes": "cpp"
|
||||
},
|
||||
"C_Cpp_Runner.cCompilerPath": "gcc",
|
||||
"C_Cpp_Runner.cppCompilerPath": "g++",
|
||||
"C_Cpp_Runner.debuggerPath": "gdb",
|
||||
"C_Cpp_Runner.cStandard": "",
|
||||
"C_Cpp_Runner.cppStandard": "",
|
||||
"C_Cpp_Runner.msvcBatchPath": "",
|
||||
"C_Cpp_Runner.useMsvc": false,
|
||||
"C_Cpp_Runner.warnings": [
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Wpedantic",
|
||||
"-Wshadow",
|
||||
"-Wformat=2",
|
||||
"-Wcast-align",
|
||||
"-Wconversion",
|
||||
"-Wsign-conversion",
|
||||
"-Wnull-dereference"
|
||||
],
|
||||
"C_Cpp_Runner.msvcWarnings": [
|
||||
"/W4",
|
||||
"/permissive-",
|
||||
"/w14242",
|
||||
"/w14287",
|
||||
"/w14296",
|
||||
"/w14311",
|
||||
"/w14826",
|
||||
"/w44062",
|
||||
"/w44242",
|
||||
"/w14905",
|
||||
"/w14906",
|
||||
"/w14263",
|
||||
"/w44265",
|
||||
"/w14928"
|
||||
],
|
||||
"C_Cpp_Runner.enableWarnings": true,
|
||||
"C_Cpp_Runner.warningsAsError": false,
|
||||
"C_Cpp_Runner.compilerArgs": [],
|
||||
"C_Cpp_Runner.linkerArgs": [],
|
||||
"C_Cpp_Runner.includePaths": [],
|
||||
"C_Cpp_Runner.includeSearch": [
|
||||
"*",
|
||||
"**/*"
|
||||
],
|
||||
"C_Cpp_Runner.excludeSearch": [
|
||||
"**/build",
|
||||
"**/build/**",
|
||||
"**/.*",
|
||||
"**/.*/**",
|
||||
"**/.vscode",
|
||||
"**/.vscode/**"
|
||||
],
|
||||
"C_Cpp_Runner.useAddressSanitizer": false,
|
||||
"C_Cpp_Runner.useUndefinedSanitizer": false,
|
||||
"C_Cpp_Runner.useLeakSanitizer": false,
|
||||
"C_Cpp_Runner.showCompilationTime": false,
|
||||
"C_Cpp_Runner.useLinkTimeOptimization": false,
|
||||
"C_Cpp_Runner.msvcSecureNoWarnings": false
|
||||
}
|
||||
46
ft_irc3/Makefile
Normal file
46
ft_irc3/Makefile
Normal file
@@ -0,0 +1,46 @@
|
||||
# **************************************************************************** #
|
||||
# #
|
||||
# ::: :::::::: #
|
||||
# Makefile :+: :+: :+: #
|
||||
# +:+ +:+ +:+ #
|
||||
# By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ #
|
||||
# +#+#+#+#+#+ +#+ #
|
||||
# Created: 2024/05/15 12:13:50 by fgras-ca #+# #+# #
|
||||
# Updated: 2024/05/15 12:47:49 by fgras-ca ### ########.fr #
|
||||
# #
|
||||
# **************************************************************************** #
|
||||
|
||||
CXX = g++
|
||||
CXXFLAGS = -Wall -Wextra -Werror -std=c++98
|
||||
LDFLAGS = -pthread
|
||||
|
||||
SRC_DIR = src
|
||||
INC_DIR = includes
|
||||
OBJ_DIR = obj
|
||||
LOG_DIR = logs
|
||||
|
||||
SRCS = $(wildcard $(SRC_DIR)/*.cpp)
|
||||
OBJS = $(SRCS:$(SRC_DIR)/%.cpp=$(OBJ_DIR)/%.o)
|
||||
|
||||
NAME = ircserv
|
||||
|
||||
all: $(NAME)
|
||||
|
||||
$(NAME): $(OBJS)
|
||||
$(CXX) $(CXXFLAGS) -I$(INC_DIR) -o $@ $^ $(LDFLAGS)
|
||||
mkdir -p $(LOG_DIR)
|
||||
touch $(LOG_DIR)/irc_server.log
|
||||
|
||||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
|
||||
mkdir -p $(OBJ_DIR)
|
||||
$(CXX) $(CXXFLAGS) -I$(INC_DIR) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJ_DIR) $(NAME)
|
||||
|
||||
fclean: clean
|
||||
rm -rf $(LOG_DIR)
|
||||
|
||||
re: fclean all
|
||||
|
||||
.PHONY: all clean fclean re
|
||||
50
ft_irc3/badwords.txt
Normal file
50
ft_irc3/badwords.txt
Normal file
@@ -0,0 +1,50 @@
|
||||
fuck
|
||||
Fuck
|
||||
fucking
|
||||
fucking
|
||||
Shit
|
||||
shit
|
||||
Shitty
|
||||
shitty
|
||||
Bullshit
|
||||
bullshit
|
||||
shithead
|
||||
Shithead
|
||||
Scumbag
|
||||
scumbag
|
||||
asshole
|
||||
Asshole
|
||||
Cocksucker
|
||||
cocksucker
|
||||
Dickhead
|
||||
dickhead
|
||||
Suck my dick
|
||||
suck my dick!
|
||||
Ass
|
||||
ass
|
||||
Bastard
|
||||
Bastard
|
||||
connard
|
||||
Connard
|
||||
Va te faire foutre
|
||||
va te faire foutre
|
||||
ferme ta gueule
|
||||
Ferme ta gueule
|
||||
Pute
|
||||
pute
|
||||
Salope
|
||||
salope
|
||||
trou du cul
|
||||
Trou du cul
|
||||
sac à merde
|
||||
Sac à merde
|
||||
casse-couilles
|
||||
Casse-couilles
|
||||
tête de bite
|
||||
Tête de bite
|
||||
bite
|
||||
bite
|
||||
pétasse
|
||||
Pétasse
|
||||
Fini à la pisse
|
||||
fini à la pisse
|
||||
0
ft_irc3/cmd
Normal file
0
ft_irc3/cmd
Normal file
48
ft_irc3/includes/AdditionalCommands.hpp
Normal file
48
ft_irc3/includes/AdditionalCommands.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* AdditionalCommands.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/21 18:09:05 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/01 18:48:32 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef ADDITIONALCOMMANDS_HPP
|
||||
#define ADDITIONALCOMMANDS_HPP
|
||||
|
||||
#include "Client.hpp"
|
||||
#include "Server.hpp"
|
||||
#include "Channel.hpp"
|
||||
#include "CommandHandler.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "RPL.hpp"
|
||||
#include "Who.hpp"
|
||||
#include "InviteHandler.hpp"
|
||||
#include "TopicHandler.hpp"
|
||||
#include "KickHandler.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
class Server;
|
||||
class Client;
|
||||
class Channel;
|
||||
class AdditionalCommands
|
||||
{
|
||||
private:
|
||||
Server *_server;
|
||||
|
||||
public:
|
||||
AdditionalCommands(Server *server);
|
||||
void processCommand(Client *client, const std::string &command);
|
||||
void broadcastChannelList(Client *client, Server *server);
|
||||
void handlePartCommand(Server *server, Client *client, const std::string &command);
|
||||
void handleNickCommand(Server *server, Client *client, const std::string &command);
|
||||
void handlePrivmsgCommand(Server *server, Client *client, const std::string &command);
|
||||
};
|
||||
|
||||
#endif
|
||||
45
ft_irc3/includes/BotFilter.hpp
Normal file
45
ft_irc3/includes/BotFilter.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* BotFilter.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/06/06 11:44:44 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/06 13:41:41 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef BOTFILTER_HPP
|
||||
#define BOTFILTER_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
#include "Server.hpp"
|
||||
#include "Client.hpp"
|
||||
#include "Channel.hpp"
|
||||
|
||||
class BotFilter
|
||||
{
|
||||
public:
|
||||
BotFilter(Server *server);
|
||||
void loadBadWords(const std::string &fileName);
|
||||
bool checkMessage(Client *client, Channel *channel, const std::string &message);
|
||||
|
||||
private:
|
||||
Server *_server;
|
||||
std::vector<std::string> _badWords;
|
||||
std::map<int, int> _warnings;
|
||||
|
||||
bool containsBadWords(const std::string &message);
|
||||
void warnClient(Client *client, Channel *channel);
|
||||
void kickClient(Client *client, Channel *channel);
|
||||
};
|
||||
|
||||
#endif
|
||||
81
ft_irc3/includes/Channel.hpp
Normal file
81
ft_irc3/includes/Channel.hpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* Channel.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/15 12:41:35 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/04 16:12:23 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef CHANNEL_HPP
|
||||
#define CHANNEL_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <ctime>
|
||||
|
||||
#include "RPL.hpp"
|
||||
#include "Client.hpp"
|
||||
#include "Server.hpp"
|
||||
|
||||
class Server;
|
||||
class Client;
|
||||
|
||||
class Channel
|
||||
{
|
||||
public:
|
||||
Channel(const std::string &name);
|
||||
~Channel();
|
||||
|
||||
const std::string &getName() const;
|
||||
void addClient(Client *client);
|
||||
void removeClient(Client *client);
|
||||
bool isEmpty() const;
|
||||
const std::vector<Client *> &getClients() const;
|
||||
void addOperator(Client *client);
|
||||
bool isOperator(Client *client) const;
|
||||
void removeOperator(Client *client); // Ajouté
|
||||
bool hasClient(Client *client) const;
|
||||
void broadcast(const std::string &message, Client *_client, Server *_server);
|
||||
bool isBanned(Client *client) const;
|
||||
bool isFull() const;
|
||||
bool isInviteOnly() const;
|
||||
bool isInvited(Client *client) const;
|
||||
bool checkKey(const std::string &key) const;
|
||||
const std::string &getTopic() const;
|
||||
const std::string &getTopicSetter() const;
|
||||
time_t getTopicTime() const;
|
||||
void setTopic(const std::string &topic, const std::string &setter);
|
||||
std::string getKey();
|
||||
|
||||
void setClientLimit(size_t limit);
|
||||
size_t getClientLimit() const;
|
||||
void setInviteOnly(bool inviteOnly);
|
||||
void setKey(const std::string &key);
|
||||
void setTopicProtection(bool protection);
|
||||
std::string getModes() const;
|
||||
bool getTopicProtection() const;
|
||||
void addInvitedClient(Client* client);
|
||||
|
||||
private:
|
||||
std::string _name;
|
||||
std::vector<Client *> _clients;
|
||||
std::vector<Client *> _operators;
|
||||
std::set<Client *> _bannedClients;
|
||||
std::set<Client *> _invitedClients;
|
||||
std::string _key;
|
||||
std::string _topic;
|
||||
std::string _topicSetter;
|
||||
time_t _topicTime;
|
||||
size_t _clientLimit;
|
||||
bool _inviteOnly;
|
||||
bool _topicProtection;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
68
ft_irc3/includes/Client.hpp
Normal file
68
ft_irc3/includes/Client.hpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* Client.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/15 12:15:42 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/06 13:23:23 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef CLIENT_HPP
|
||||
#define CLIENT_HPP
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
class Client
|
||||
{
|
||||
public:
|
||||
Client(int fd, const std::string &nickname, const std::string &user, const std::string &host, const std::string &password, const std::string &realname);
|
||||
|
||||
int getFd() const;
|
||||
const std::string &getNickname() const;
|
||||
void setNickname(const std::string &nickname);
|
||||
const std::string &getUser() const;
|
||||
void setUser(const std::string &user);
|
||||
const std::string &getHost() const;
|
||||
void setHost(const std::string &host);
|
||||
const std::string &getPassword() const;
|
||||
void setPassword(const std::string &password);
|
||||
const std::string &getRealName() const;
|
||||
void setRealName(const std::string &realname);
|
||||
bool isAuthenticated() const;
|
||||
void authenticate();
|
||||
bool isOperator() const;
|
||||
void setOperator(bool isOperator);
|
||||
|
||||
// Ajout des méthodes pour la gestion du statut "away"
|
||||
bool isAway() const;
|
||||
const std::string &getAwayMessage() const;
|
||||
void setAwayMessage(const std::string &message);
|
||||
void setAway(bool away);
|
||||
std::string getKey() const;
|
||||
void setkey(const std::string &key);
|
||||
char buffer[1024];
|
||||
char buffer2[1024];
|
||||
void joinChannel(const std::string &channel);
|
||||
void leaveChannel(const std::string &channel);
|
||||
const std::set<std::string> &getChannels() const;
|
||||
|
||||
private:
|
||||
int _fd;
|
||||
std::string _nickname;
|
||||
std::string _user;
|
||||
std::string _host;
|
||||
std::string _password;
|
||||
std::string _realname;
|
||||
bool _authenticated;
|
||||
bool _operator;
|
||||
bool _away;
|
||||
std::string _awayMessage;
|
||||
std::string _key;
|
||||
std::set<std::string> _channels;
|
||||
};
|
||||
|
||||
#endif
|
||||
56
ft_irc3/includes/ClientManager.hpp
Normal file
56
ft_irc3/includes/ClientManager.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* ClientManager.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/15 18:30:07 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/06 13:01:05 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef CLIENTMANAGER_HPP
|
||||
#define CLIENTMANAGER_HPP
|
||||
|
||||
#include "Client.hpp"
|
||||
#include "Channel.hpp"
|
||||
#include "Server.hpp"
|
||||
#include "CommandHandler.hpp"
|
||||
#include "RPL.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "BotFilter.hpp"
|
||||
|
||||
#include <poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
class Server;
|
||||
class Client;
|
||||
class BotFilter;
|
||||
|
||||
class ClientManager
|
||||
{
|
||||
public:
|
||||
ClientManager(Server *server);
|
||||
void acceptClient();
|
||||
void handleClientNext(int client_fd, char * buffer, int bytes_received);
|
||||
void handleClient(int client_fd);
|
||||
void removeClient(int client_fd);
|
||||
|
||||
private:
|
||||
Server *_server;
|
||||
BotFilter *_botFilter;
|
||||
};
|
||||
|
||||
#endif
|
||||
62
ft_irc3/includes/CommandHandler.hpp
Normal file
62
ft_irc3/includes/CommandHandler.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* CommandHandler.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/15 18:14:12 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/01 18:47:51 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef COMMANDHANDLER_HPP
|
||||
#define COMMANDHANDLER_HPP
|
||||
|
||||
#include "Utils.hpp"
|
||||
#include "Server.hpp"
|
||||
#include "Client.hpp"
|
||||
#include "Channel.hpp"
|
||||
#include "Who.hpp"
|
||||
#include "AdditionalCommands.hpp"
|
||||
#include "RPL.hpp"
|
||||
#include "Join.hpp"
|
||||
#include "Welcome.hpp"
|
||||
#include "ModeHandler.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
class Server;
|
||||
class Client;
|
||||
class Channel;
|
||||
class WhoHandler;
|
||||
class AdditionalCommands;
|
||||
class ModeHandler;
|
||||
|
||||
class CommandHandler
|
||||
{
|
||||
private:
|
||||
Server *_server;
|
||||
AdditionalCommands *_additionalCommands;
|
||||
ModeHandler *_modeHandler;
|
||||
|
||||
|
||||
public:
|
||||
CommandHandler(Server *server);
|
||||
bool isValidNickname(const std::string& nickname);
|
||||
bool isNicknameInUse(const std::string& nickname);
|
||||
void handleNick(Client* client, const std::vector<std::string>& tokens);
|
||||
|
||||
void handleUser(Client* client, const std::vector<std::string>& tokens);
|
||||
void handlePingCommand(Client* client, const std::vector<std::string>& tokens);
|
||||
void handleCommand(Client *client, const std::string &command);
|
||||
void handleCapCommand(Client* client, const std::vector<std::string>& tokens);
|
||||
void handlePassCommand(Client* client, const std::vector<std::string>& tokens);
|
||||
void handleQuitCommand(Client* client, const std::vector<std::string>& tokens);
|
||||
void handleErrorCommand(Client* client, const std::string &message);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
40
ft_irc3/includes/InviteHandler.hpp
Normal file
40
ft_irc3/includes/InviteHandler.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* InviteHandler.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/30 13:01:50 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/01 18:51:00 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef INVITEHANDLER_HPP
|
||||
#define INVITEHANDLER_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
#include "Server.hpp"
|
||||
#include "Client.hpp"
|
||||
#include "Channel.hpp"
|
||||
#include "RPL.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
class Server;
|
||||
class Client;
|
||||
class Channel;
|
||||
|
||||
class InviteHandler
|
||||
{
|
||||
public:
|
||||
InviteHandler(Server* server);
|
||||
void handleInviteCommand(Client* client, const std::string& command);
|
||||
|
||||
private:
|
||||
Server* _server;
|
||||
};
|
||||
|
||||
#endif
|
||||
40
ft_irc3/includes/Join.hpp
Normal file
40
ft_irc3/includes/Join.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* Join.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/21 19:51:08 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/01 18:51:10 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef JOIN_HPP
|
||||
#define JOIN_HPP
|
||||
|
||||
#include <string>
|
||||
#include "Client.hpp"
|
||||
#include "Server.hpp"
|
||||
#include "Channel.hpp"
|
||||
#include "RPL.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "Server.hpp"
|
||||
#include "Channel.hpp"
|
||||
#include "Client.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
class JoinHandler
|
||||
{
|
||||
public:
|
||||
void handleJoinCommand(Client *client, const std::string &channelName, Server *server);
|
||||
void sendJoinSuccess(Client *client, Channel *channel, Server *server);
|
||||
std::string getUsersList(Channel *channel);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
35
ft_irc3/includes/KickHandler.hpp
Normal file
35
ft_irc3/includes/KickHandler.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* KickHandler.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/06/01 16:59:42 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/01 18:51:26 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef KICKHANDLER_HPP
|
||||
#define KICKHANDLER_HPP
|
||||
|
||||
#include "Server.hpp"
|
||||
#include "Client.hpp"
|
||||
#include "Channel.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
class KickHandler
|
||||
{
|
||||
public:
|
||||
KickHandler(Server* server);
|
||||
void handleKickCommand(Client* client, const std::string& command);
|
||||
|
||||
private:
|
||||
Server* _server;
|
||||
};
|
||||
|
||||
#endif
|
||||
52
ft_irc3/includes/ModeHandler.hpp
Normal file
52
ft_irc3/includes/ModeHandler.hpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* ModeHandler.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/30 11:12:57 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/04 14:00:47 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef MODEHANDLER_HPP
|
||||
#define MODEHANDLER_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "Client.hpp"
|
||||
#include "Channel.hpp"
|
||||
#include "Server.hpp"
|
||||
#include "RPL.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
class Server;
|
||||
class Client;
|
||||
class Channel;
|
||||
|
||||
class ModeHandler
|
||||
{
|
||||
public:
|
||||
ModeHandler(Server* server);
|
||||
void handleModeCommand(Client* client, const std::string& command);
|
||||
|
||||
private:
|
||||
Server* _server;
|
||||
|
||||
void handleUserMode(Client* client, const std::vector<std::string>& tokens);
|
||||
void handleChannelMode(Client* client, const std::vector<std::string>& tokens);
|
||||
|
||||
void setChannelMode(Client *client, Channel* channel, const std::string& mode, bool adding, const std::string& argument);
|
||||
void applyModeL(Client *client, Channel* channel, bool adding, const std::string& argument);
|
||||
void applyModeI(Client *client, Channel* channel, bool adding);
|
||||
void applyModeK(Client *client, Channel* channel, bool adding, const std::string& argument);
|
||||
void applyModeT(Channel* channel, bool adding);
|
||||
void applyModeO(Client *client, Channel* channel, bool adding, const std::string& argument);
|
||||
};
|
||||
|
||||
#endif
|
||||
552
ft_irc3/includes/RPL.hpp
Normal file
552
ft_irc3/includes/RPL.hpp
Normal file
@@ -0,0 +1,552 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* RPL.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/19 15:12:47 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/06 12:28:50 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef RPL_HPP
|
||||
#define RPL_HPP
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "Client.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "Channel.hpp"
|
||||
|
||||
#define SERVER_NAME "IRC_Server"
|
||||
#define SERVER_VERSION "1.0"
|
||||
#define USER_MODES "None"
|
||||
#define CHANNEL_MODES "l"
|
||||
#define CHANNEL_MODES_WITH_PARAMS "l"
|
||||
|
||||
|
||||
#define CLIENT_FD(client) (client->getFd())
|
||||
#define CLIENT_NICK(client) ((client)->getNickname())
|
||||
#define CLIENT_USER(client) ((client)->getUser())
|
||||
#define CLIENT_HOST(client) ((client)->getHost())
|
||||
#define CLIENT_REALNAME(client) ((client)->getRealName())
|
||||
|
||||
inline std::string RPL_WELCOME(Client* client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 001 " << CLIENT_NICK(client)
|
||||
<< " :Welcome to the Internet Relay Network " << CLIENT_NICK(client)
|
||||
<< "!" << CLIENT_USER(client) << "@" << CLIENT_HOST(client) << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_YOURHOST(Client* client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 002 " << CLIENT_NICK(client)
|
||||
<< " :Your host is " << SERVER_NAME << ", running version " << SERVER_VERSION << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_CREATED(Client* client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 003 " << CLIENT_NICK(client)
|
||||
<< " :This server was created " << __DATE__ << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_MYINFO(Client* client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 004 " << CLIENT_NICK(client) << " "
|
||||
<< SERVER_NAME << " " << SERVER_VERSION << " "
|
||||
<< USER_MODES << " " << CHANNEL_MODES << " "
|
||||
<< CHANNEL_MODES_WITH_PARAMS << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_ISUPPORT(Client* client, const std::string& tokens)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 005 " << CLIENT_NICK(client)
|
||||
<< " " << tokens << " :are supported by this server\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_UMODEIS(Client* client, const std::string& modes)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 221 " << CLIENT_NICK(client) << " :" << modes << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_AWAY(Client *client, const std::string& target, const std::string& message)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 301 " << CLIENT_NICK(client) << " " << target << " :" << message << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_WHOISUSER(Client *client, Client* target)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 311 " << CLIENT_NICK(client) << " " << CLIENT_NICK(target) << " "
|
||||
<< CLIENT_USER(target) << " " << CLIENT_HOST(target) << " * :" << CLIENT_REALNAME(target) << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_WHOISSERVER(Client *client, const std::string& targetNick, const std::string& serverInfo)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 312 " << CLIENT_NICK(client) << " " << targetNick << " " << SERVER_NAME
|
||||
<< " :" << serverInfo << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_ENDOFWHO(Client *client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 315 " << CLIENT_NICK(client) << " " << channel << " :End of /WHO list.\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_ENDOFWHOIS(Client *client, const std::string& targetNick)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 318 " << CLIENT_NICK(client) << " " << targetNick << " :End of /WHOIS list.\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_LIST(Client *client, const std::string& channel, int numVisible, const std::string& topic)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 322 " << CLIENT_NICK(client) << " " << channel << " " << numVisible << " :" << topic << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_LISTEND(Client *client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 323 " << CLIENT_NICK(client) << " :End of /LIST\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_CHANNELMODEIS(int clientFd, const std::string& channel, const std::string& mode)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 324 " << clientFd << " " << channel << " " << mode << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_CREATIONTIME(Client *client, const std::string& channel, time_t creationTime)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 329 " << CLIENT_NICK(client) << " " << channel << " " << creationTime << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_NOTOPIC(Client* client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 331 " << CLIENT_NICK(client) << " " << channel << " :No topic is set\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_TOPIC(Client* client, const std::string& channel, const std::string& topic)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 332 " << CLIENT_NICK(client) << " " << channel << " :" << topic << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_TOPICWHOTIME(Client* client, const std::string& channel, const std::string& setter, time_t setTime)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 333 " << CLIENT_NICK(client) << " " << channel << " " << setter << " " << setTime << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_INVITELIST(Client *client, const std::string& channel, const std::string& inviteMask)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 336 " << CLIENT_NICK(client) << " " << channel << " " << inviteMask << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_ENDOFINVITELIST(Client *client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 337 " << CLIENT_NICK(client) << " " << channel << " :End of channel invite list\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_INVITING(Client* client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 341 " << CLIENT_NICK(client) << " " << CLIENT_NICK(client) << " " << channel << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_EXCEPTLIST(Client *client, const std::string& channel, const std::string& exceptionMask)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 348 " << CLIENT_NICK(client) << " " << channel << " " << exceptionMask << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_ENDOFEXCEPTLIST(Client *client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 349 " << CLIENT_NICK(client) << " " << channel << " :End of channel exception list\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_NAMREPLY(Client* client, const std::string& channel, const std::string& users)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 353 " << CLIENT_NICK(client) << " = " << channel << " :" << users << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_WHOREPLY(const std::string& channel, Client* target)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 352 " << CLIENT_NICK(target) << " " << channel << " "
|
||||
<< CLIENT_USER(target) << " " << CLIENT_HOST(target) << " " << SERVER_NAME << " "
|
||||
<< CLIENT_NICK(target) << " H :0 " << CLIENT_REALNAME(target) << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_ENDOFNAMES(Client* client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 366 " << CLIENT_NICK(client) << " " << channel << " :End of /NAMES list\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_BANLIST(Client *client, const std::string& channel, const std::string& banMask)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 367 " << CLIENT_NICK(client) << " " << channel << " " << banMask << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_ENDOFBANLIST(Client *client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 368 " << CLIENT_NICK(client) << " " << channel << " :End of channel ban list\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_MOTD(Client* client, const std::string& line)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 372 " << CLIENT_NICK(client)
|
||||
<< " :- " << line << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_MOTDSTART(Client* client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 375 " << CLIENT_NICK(client)
|
||||
<< " :- " << SERVER_NAME << " Message of the day - \r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_ENDOFMOTD(Client* client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 376 " << CLIENT_NICK(client)
|
||||
<< " :End of /MOTD command.\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_NOSUCHNICK(Client *client, const std::string& nick)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 401 " << CLIENT_NICK(client) << " " << nick << " :No such nick/channel\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_NOSUCHCHANNEL(Client *client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 403 " << CLIENT_NICK(client) << " " << channel << " :No such channel\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_CANNOTSENDTOCHAN(Client *client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 404 " << CLIENT_NICK(client) << " " << channel << " :Cannot send to channel\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_TOOMANYCHANNELS(Client* client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 405 " << CLIENT_NICK(client) << " " << channel << " :You have joined too many channels\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// RPL Error Messages
|
||||
inline std::string ERR_NOORIGIN(Client* client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 409 " << CLIENT_NICK(client) << " :No origin specified\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_NORECIPIENT(Client *client, const std::string& command)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 411 " << CLIENT_NICK(client) << " :No recipient given (" << command << ")\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_NOTEXTTOSEND(Client *client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 412 " << CLIENT_NICK(client) << " :No text to send\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_UNKNOWNCOMMAND(Client* client, const std::string& command)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 421 " << CLIENT_NICK(client) << " " << command << " :Unknown command\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_NOMOTD(Client* client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 422 " << CLIENT_NICK(client)
|
||||
<< " :MOTD File is missing\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_NONICKNAMEGIVEN(Client* client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 431 " << CLIENT_NICK(client) << " :No nickname given\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_ERRONEUSNICKNAME(Client* client, const std::string& nickname)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 432 " << CLIENT_NICK(client) << " " << nickname << " :Erroneous nickname\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_NICKNAMEINUSE(Client* client, const std::string& nickname)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 433 " << CLIENT_NICK(client) << " " << nickname << " :Nickname is already in use\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_USERNOTINCHANNEL(Client *client, const std::string& nick, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 441 " << CLIENT_NICK(client) << " " << nick << " " << channel
|
||||
<< " :They aren't on that channel\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_NOTONCHANNEL(Client *client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 442 " << CLIENT_NICK(client) << " " << channel << " :You're not on that channel\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// Ajoutez cette fonction pour ERR_USERONCHANNEL
|
||||
inline std::string ERR_USERONCHANNEL(Client* client, const std::string& nick, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 443 " << CLIENT_NICK(client) << " " << nick << " " << channel
|
||||
<< " :is already on channel\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_NOTREGISTERED(Client* client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 451 " << CLIENT_NICK(client) << " :You have not registered\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
//RPL Password
|
||||
// RPL Error Messages
|
||||
inline std::string ERR_NEEDMOREPARAMS(Client* client, const std::string& command)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 461 " << CLIENT_NICK(client) << " " << command << " :Not enough parameters\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_ALREADYREGISTERED(Client* client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 462 " << CLIENT_NICK(client) << " :You may not reregister\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_PASSWDMISMATCH(Client* client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 464 " << CLIENT_NICK(client) << " :Password incorrect\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_INVALIDKEY(Client* client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 467 " << CLIENT_NICK(client) << " " << channel << " :Invalid key\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_KEYSET(Client* client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 467 " << CLIENT_NICK(client) << " " << channel
|
||||
<< " :Channel key already set\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_LINKSET(Client* client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 469 " << CLIENT_NICK(client) << " " << channel
|
||||
<< " :No key set\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_CHANNELISFULL(Client* client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 471 " << CLIENT_NICK(client) << " " << channel << " :Cannot join channel (channel is full)\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_UNKNOWNMODE(Client* client, char mode, const std::string& channelName)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 472 " << CLIENT_NICK(client) << " " << mode << " :is unknown mode char to me for " << channelName << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_INVITEONLYCHAN(Client* client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 473 " << CLIENT_NICK(client) << " " << channel << " :Cannot join channel (invite only)\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_BANNEDFROMCHAN(Client* client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 474 " << CLIENT_NICK(client) << " " << channel << " :Cannot join channel (banned)\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_BADCHANNELKEY(Client* client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 475 " << CLIENT_NICK(client) << " " << channel << " :Cannot join channel (incorrect key)\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_BADCHANMASK(Client* client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 476 " << CLIENT_NICK(client) << " " << channel << " :Bad channel mask\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_NOCHANMODES(Client *client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 477 " << CLIENT_NICK(client) << " " << channel << " :Channel doesn't support modes\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_CHANOPRIVSNEEDED(Client *client, const std::string& channel)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 482 " << CLIENT_NICK(client) << " " << channel << " :You're not channel operator\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_UMODEUNKNOWNFLAG(Client *client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 501 " << CLIENT_NICK(client) << " :Unknown MODE flag\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_USERSDONTMATCH(Client *client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 502 " << CLIENT_NICK(client) << " :Cannot change mode for other users\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string ERR_INVALIDMODEPARAM(Client* client, const std::string& param)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " 696 " << CLIENT_NICK(client) << " " << param << " :Invalid mode parameter\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_PONG(const std::string& token)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " PONG " << SERVER_NAME << " " << token << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_CAP(Client *client, const std::string& subcommand, const std::string& capabilities)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " CAP " << CLIENT_NICK(client) << " " << subcommand << " :" << capabilities << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_PASSACCEPTED(Client* client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " NOTICE " << CLIENT_NICK(client)
|
||||
<< " :Password accepted!\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string RPL_CAPEND(Client *client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << SERVER_NAME << " CAP " << CLIENT_NICK(client) << " END\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string MODEACCEPTMESSAGE(Client *client, std::string channel, const std::string& mode)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << client->getNickname() << " MODE " << channel << " " << mode << " :" << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
|
||||
inline std::string BOTMESSAGE(Client *client, std::string channel, const std::string& message)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << ":" << client->getNickname() << " WARNING " << channel << " " << message << " :" << "\r\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
#endif
|
||||
91
ft_irc3/includes/Server.hpp
Normal file
91
ft_irc3/includes/Server.hpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* Server.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/15 12:15:13 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/06 12:04:58 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef SERVER_HPP
|
||||
#define SERVER_HPP
|
||||
|
||||
#include "Utils.hpp"
|
||||
#include "Client.hpp"
|
||||
#include "Channel.hpp"
|
||||
#include "ClientManager.hpp"
|
||||
#include "CommandHandler.hpp"
|
||||
#include "AdditionalCommands.hpp"
|
||||
#include "RPL.hpp"
|
||||
#include "ModeHandler.hpp"
|
||||
#include "TopicHandler.hpp"
|
||||
#include "BotFilter.hpp"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <poll.h>
|
||||
|
||||
class Client;
|
||||
class Channel;
|
||||
class ClientManager;
|
||||
class CommandHandler;
|
||||
class AdditionalCommands;
|
||||
class ModeHandler;
|
||||
class TopicHandler;
|
||||
class BotFilter;
|
||||
|
||||
class Server
|
||||
{
|
||||
public:
|
||||
Server(int port, const std::string &password);
|
||||
~Server();
|
||||
void run();
|
||||
void log(const std::string &message, const std::string &color = "\033[0m");
|
||||
void sendToClient(int client_fd, const std::string &message);
|
||||
|
||||
std::map<std::string, Channel *> &getChannels();
|
||||
std::map<int, Client *> &getClients();
|
||||
const std::string &getPassword() const;
|
||||
void broadcast(const std::string &message);
|
||||
Client* getClientByName(const std::string &name);
|
||||
Channel* getChannelByName(const std::string &name);
|
||||
void disconnectClient(int clientFd);
|
||||
bool MatchFd(const pollfd& pfd, int clientFd);
|
||||
void removePollFd(int clientFd);
|
||||
|
||||
protected:
|
||||
int _server_fd;
|
||||
int _port;
|
||||
std::string _password;
|
||||
std::map<int, Client *> _clients;
|
||||
std::map<std::string, Channel *> _channels;
|
||||
std::vector<struct pollfd> _poll_fds;
|
||||
ClientManager *_clientManager;
|
||||
CommandHandler *_commandHandler;
|
||||
ModeHandler *_modeHandler;
|
||||
TopicHandler *_topicHandler;
|
||||
BotFilter *_botFilter;
|
||||
|
||||
friend class ClientManager;
|
||||
friend class CommandHandler;
|
||||
friend class ModeHandler;
|
||||
friend class TopicHandler;
|
||||
|
||||
private:
|
||||
void initServer();
|
||||
void handleServerCommands();
|
||||
};
|
||||
|
||||
#endif
|
||||
38
ft_irc3/includes/TopicHandler.hpp
Normal file
38
ft_irc3/includes/TopicHandler.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* TopicHandler.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/30 17:04:33 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/01 19:02:10 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef TOPIC_HANDLER_HPP
|
||||
#define TOPIC_HANDLER_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include "Server.hpp"
|
||||
#include "Client.hpp"
|
||||
#include "Channel.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
|
||||
class TopicHandler
|
||||
{
|
||||
public:
|
||||
TopicHandler(Server* server);
|
||||
void handleTopicCommand(Client* client, const std::string& command);
|
||||
|
||||
private:
|
||||
void viewTopic(Client* client, Channel* channel);
|
||||
void changeTopic(Client* client, Channel* channel, const std::string& topic);
|
||||
|
||||
Server* _server;
|
||||
};
|
||||
|
||||
#endif
|
||||
30
ft_irc3/includes/Utils.hpp
Normal file
30
ft_irc3/includes/Utils.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* Utils.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/15 12:16:02 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/01 15:13:40 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef UTILS_HPP
|
||||
#define UTILS_HPP
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#define RESET "\033[0m"
|
||||
#define RED "\033[1;31m"
|
||||
#define GREEN "\033[1;32m"
|
||||
#define YELLOW "\033[1;33m"
|
||||
#define BLUE "\033[1;34m"
|
||||
#define MAGENTA "\033[1;35m"
|
||||
#define CYAN "\033[1;36m"
|
||||
|
||||
std::vector<std::string> split(const std::string &input, const std::string &delimiters);
|
||||
|
||||
#endif
|
||||
29
ft_irc3/includes/Welcome.hpp
Normal file
29
ft_irc3/includes/Welcome.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* Welcome.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/21 19:53:17 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/01 19:02:40 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef WELCOME_HPP
|
||||
#define WELCOME_HPP
|
||||
|
||||
#include "Client.hpp"
|
||||
#include "Server.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
class WelcomeHandler
|
||||
{
|
||||
public:
|
||||
void sendWelcomeMessages(Client *client, Server *server);
|
||||
void sendMotd(Client *client, Server *server);
|
||||
};
|
||||
|
||||
#endif
|
||||
38
ft_irc3/includes/Who.hpp
Normal file
38
ft_irc3/includes/Who.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* Who.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/17 16:08:48 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/01 19:03:06 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef WHO_HPP
|
||||
#define WHO_HPP
|
||||
|
||||
#include "Server.hpp"
|
||||
#include "Client.hpp"
|
||||
#include "Channel.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "RPL.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
class Server;
|
||||
class WhoHandler
|
||||
{
|
||||
public:
|
||||
WhoHandler(Server *server);
|
||||
void handleWhoCommand(Client *client, const std::string &command);
|
||||
void handleWhoisCommand(Client *client, const std::string &command);
|
||||
|
||||
private:
|
||||
Server *_server;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
9
ft_irc3/motd.txt
Normal file
9
ft_irc3/motd.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
░▒▓████████▓▒░▒▓████████▓▒░▒▓█▓▒░▒▓███████▓▒░ ░▒▓██████▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓███████▓▒░
|
||||
░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░
|
||||
░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░
|
||||
░▒▓██████▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓███████▓▒░░▒▓█▓▒░ ░▒▓████████▓▒░░▒▓██████▓▒░
|
||||
░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░
|
||||
░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░
|
||||
░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓██████▓▒░ ░▒▓█▓▒░▒▓████████▓▒░
|
||||
|
||||
188
ft_irc3/src/AdditionalCommands.cpp
Normal file
188
ft_irc3/src/AdditionalCommands.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* AdditionalCommands.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/16 15:27:29 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/04 13:55:09 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "AdditionalCommands.hpp"
|
||||
|
||||
AdditionalCommands::AdditionalCommands(Server *server) : _server(server) {}
|
||||
|
||||
void AdditionalCommands::processCommand(Client *client, const std::string &command)
|
||||
{
|
||||
if (command.find("PART") == 0)
|
||||
{
|
||||
handlePartCommand(_server, client, command);
|
||||
}
|
||||
else if (command.find("PRIVMSG") == 0)
|
||||
{
|
||||
handlePrivmsgCommand(_server, client, command);
|
||||
}
|
||||
else if (command.find("WHO") == 0)
|
||||
{
|
||||
WhoHandler whoHandler(_server);
|
||||
whoHandler.handleWhoCommand(client, command);
|
||||
}
|
||||
else if (command.find("WHOIS") == 0)
|
||||
{
|
||||
WhoHandler whoHandler(_server);
|
||||
whoHandler.handleWhoisCommand(client, command);
|
||||
}
|
||||
else if (command.find("INVITE") == 0)
|
||||
{
|
||||
InviteHandler inviteHandler(_server);
|
||||
inviteHandler.handleInviteCommand(client, command);
|
||||
}
|
||||
else if (command.find("TOPIC") == 0)
|
||||
{
|
||||
TopicHandler topichandler(_server);
|
||||
topichandler.handleTopicCommand(client, command);
|
||||
}
|
||||
else if (command.find("LIST") == 0)
|
||||
{
|
||||
broadcastChannelList(client, _server);
|
||||
}
|
||||
else if (command.find("KICK") == 0)
|
||||
{
|
||||
KickHandler kickHandler(_server);
|
||||
kickHandler.handleKickCommand(client, command);
|
||||
}
|
||||
else
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_UNKNOWNCOMMAND(client, command));
|
||||
_server->log("Message from client " + client->getNickname() + ": " + command, MAGENTA);
|
||||
}
|
||||
}
|
||||
|
||||
void AdditionalCommands::broadcastChannelList(Client *client, Server *server)
|
||||
{
|
||||
std::map<std::string, Channel *> &channels = server->getChannels();
|
||||
for (std::map<std::string, Channel *>::iterator it = channels.begin(); it != channels.end(); ++it)
|
||||
{
|
||||
server->sendToClient(client->getFd(), RPL_LIST(client, it->first, it->second->getClients().size(), it->second->getTopic()));
|
||||
}
|
||||
server->sendToClient(client->getFd(), RPL_LISTEND(client));
|
||||
}
|
||||
|
||||
// Fonction pour gérer la commande PART
|
||||
void AdditionalCommands::handlePartCommand(Server *server, Client *client, const std::string &command)
|
||||
{
|
||||
std::istringstream iss(command);
|
||||
std::string cmd, channelNames;
|
||||
iss >> cmd >> channelNames;
|
||||
|
||||
if (channelNames.empty())
|
||||
{
|
||||
server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client, "PART"));
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> channels = split(channelNames, ",");
|
||||
std::map<std::string, Channel *> &channelMap = server->getChannels();
|
||||
|
||||
for (size_t i = 0; i < channels.size(); ++i)
|
||||
{
|
||||
std::string &channelName = channels[i];
|
||||
if (channelMap.find(channelName) == channelMap.end())
|
||||
{
|
||||
server->sendToClient(client->getFd(), ERR_NOSUCHCHANNEL(client, channelName));
|
||||
continue;
|
||||
}
|
||||
|
||||
Channel *channel = channelMap[channelName];
|
||||
if (!channel->hasClient(client)) {
|
||||
server->sendToClient(client->getFd(), ERR_NOTONCHANNEL(client, channelName));
|
||||
continue;
|
||||
}
|
||||
|
||||
channel->removeClient(client);
|
||||
|
||||
std::ostringstream partMsg;
|
||||
partMsg << ":" << client->getNickname() << " PART " << channelName << "\r\n";
|
||||
server->sendToClient(client->getFd(), partMsg.str());
|
||||
|
||||
if (channel->isEmpty())
|
||||
{
|
||||
delete channel;
|
||||
channelMap.erase(channelName);
|
||||
}
|
||||
|
||||
server->log("Client " + client->getNickname() + " left channel " + channelName, MAGENTA);
|
||||
}
|
||||
}
|
||||
|
||||
void AdditionalCommands::handlePrivmsgCommand(Server *server, Client *client, const std::string &command)
|
||||
{
|
||||
std::istringstream iss(command);
|
||||
std::string cmd, target, message;
|
||||
iss >> cmd >> target;
|
||||
getline(iss, message);
|
||||
|
||||
// Enlever le ':' initial dans le message si présent
|
||||
if (!message.empty() && message[0] == ':')
|
||||
message = message.substr(1);
|
||||
|
||||
if (target.empty())
|
||||
{
|
||||
server->sendToClient(client->getFd(), ERR_NORECIPIENT(client, "PRIVMSG"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.empty())
|
||||
{
|
||||
server->sendToClient(client->getFd(), ERR_NOTEXTTOSEND(client));
|
||||
return;
|
||||
}
|
||||
|
||||
std::map<std::string, Channel *> &channels = server->getChannels();
|
||||
|
||||
if (channels.find(target) != channels.end())
|
||||
{
|
||||
Channel *channel = channels[target];
|
||||
|
||||
if (channel->isBanned(client))
|
||||
{
|
||||
server->sendToClient(client->getFd(), ERR_CANNOTSENDTOCHAN(client, target));
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Client *> channelClients = channel->getClients();
|
||||
|
||||
for (size_t i = 0; i < channelClients.size(); ++i)
|
||||
{
|
||||
if (channelClients[i] != client)
|
||||
{
|
||||
std::stringstream privMsg;
|
||||
privMsg << ":" << client->getNickname() << " PRIVMSG " << target << message << "\r\n";
|
||||
server->sendToClient(channelClients[i]->getFd(), privMsg.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Client *targetClient = server->getClientByName(target);
|
||||
|
||||
if (targetClient)
|
||||
{
|
||||
std::stringstream privMsg;
|
||||
privMsg << ":" << client->getNickname() << " PRIVMSG " << target << message << "\r\n";
|
||||
server->sendToClient(targetClient->getFd(), privMsg.str());
|
||||
|
||||
if (targetClient->isAway())
|
||||
{
|
||||
server->sendToClient(client->getFd(), RPL_AWAY(client, targetClient->getNickname(), targetClient->getAwayMessage()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Si la cible n'est ni un canal ni un utilisateur existant, envoyer un message d'erreur
|
||||
server->sendToClient(client->getFd(), ERR_NOSUCHNICK(client, target));
|
||||
}
|
||||
}
|
||||
}
|
||||
70
ft_irc3/src/BotFilter.cpp
Normal file
70
ft_irc3/src/BotFilter.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* BotFilter.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/06/06 11:45:43 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/06 13:37:24 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "BotFilter.hpp"
|
||||
|
||||
BotFilter::BotFilter(Server *server) : _server(server) {}
|
||||
|
||||
void BotFilter::loadBadWords(const std::string &fileName)
|
||||
{
|
||||
std::ifstream file(fileName.c_str());
|
||||
std::string line;
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
_badWords.push_back(line);
|
||||
}
|
||||
}
|
||||
|
||||
bool BotFilter::checkMessage(Client *client, Channel *channel, const std::string &message)
|
||||
{
|
||||
if (containsBadWords(message))
|
||||
{
|
||||
warnClient(client, channel);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BotFilter::containsBadWords(const std::string &message)
|
||||
{
|
||||
for (std::vector<std::string>::iterator it = _badWords.begin(); it != _badWords.end(); ++it)
|
||||
{
|
||||
if (message.find(*it) != std::string::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BotFilter::warnClient(Client* client, Channel *channel)
|
||||
{
|
||||
int fd = client->getFd();
|
||||
_warnings[fd] += 1;
|
||||
if (_warnings[fd] >= 3)
|
||||
{
|
||||
_server->sendToClient(fd, BOTMESSAGE(client, channel->getName(), "You have been kicked from the server for inappropriate language.\r\n"));
|
||||
_server->disconnectClient(fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Warning: Inappropriate language detected. You have " << (3 - _warnings[fd]) << " warnings left before you are kicked.\r\n";
|
||||
_server->sendToClient(fd, BOTMESSAGE(client, channel->getName(), oss.str()));
|
||||
}
|
||||
}
|
||||
|
||||
void BotFilter::kickClient(Client *client, Channel *channel)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), BOTMESSAGE(client, channel->getName(), "You have been kicked for inappropriate language.\r\n"));
|
||||
_server->disconnectClient(client->getFd());
|
||||
}
|
||||
172
ft_irc3/src/Channel.cpp
Normal file
172
ft_irc3/src/Channel.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* Channel.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/15 12:42:57 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/04 16:12:22 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "Channel.hpp"
|
||||
|
||||
Channel::Channel(const std::string &name)
|
||||
: _name(name), _clients(), _operators(), _bannedClients(), _invitedClients(), _key(""), _topic(""), _topicSetter(""), _topicTime(time(NULL)), _clientLimit(50), _inviteOnly(false), _topicProtection(false) {}
|
||||
|
||||
Channel::~Channel() {}
|
||||
|
||||
const std::string &Channel::getName() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
void Channel::addClient(Client *client)
|
||||
{
|
||||
_clients.push_back(client);
|
||||
}
|
||||
|
||||
void Channel::removeClient(Client *client)
|
||||
{
|
||||
_clients.erase(std::remove(_clients.begin(), _clients.end(), client), _clients.end());
|
||||
}
|
||||
|
||||
bool Channel::isEmpty() const
|
||||
{
|
||||
return _clients.empty();
|
||||
}
|
||||
|
||||
const std::vector<Client *> &Channel::getClients() const
|
||||
{
|
||||
return _clients;
|
||||
}
|
||||
|
||||
void Channel::addOperator(Client *client)
|
||||
{
|
||||
_operators.push_back(client);
|
||||
}
|
||||
|
||||
bool Channel::isOperator(Client *client) const
|
||||
{
|
||||
return std::find(_operators.begin(), _operators.end(), client) != _operators.end();
|
||||
}
|
||||
|
||||
void Channel::removeOperator(Client *client)
|
||||
{
|
||||
_operators.erase(std::remove(_operators.begin(), _operators.end(), client), _operators.end());
|
||||
}
|
||||
|
||||
bool Channel::hasClient(Client *client) const
|
||||
{
|
||||
return std::find(_clients.begin(), _clients.end(), client) != _clients.end();
|
||||
}
|
||||
|
||||
void Channel::broadcast(const std::string &message, Client *_client, Server *_server)
|
||||
{
|
||||
for (std::vector<Client *>::iterator it = _clients.begin(); it != _clients.end(); ++it)
|
||||
{
|
||||
if (*it != _client)
|
||||
{
|
||||
// Send message to each client except the sender
|
||||
_server->sendToClient((*it)->getFd(), message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Channel::isBanned(Client *client) const
|
||||
{
|
||||
return _bannedClients.find(client) != _bannedClients.end();
|
||||
}
|
||||
|
||||
bool Channel::isFull() const
|
||||
{
|
||||
return _clients.size() >= _clientLimit;
|
||||
}
|
||||
|
||||
bool Channel::isInviteOnly() const
|
||||
{
|
||||
return _inviteOnly;
|
||||
}
|
||||
|
||||
bool Channel::isInvited(Client *client) const
|
||||
{
|
||||
return _invitedClients.find(client) != _invitedClients.end();
|
||||
}
|
||||
|
||||
bool Channel::checkKey(const std::string &key) const
|
||||
{
|
||||
return _key.empty() || _key == key;
|
||||
}
|
||||
|
||||
const std::string &Channel::getTopic() const
|
||||
{
|
||||
return _topic;
|
||||
}
|
||||
|
||||
const std::string &Channel::getTopicSetter() const
|
||||
{
|
||||
return _topicSetter;
|
||||
}
|
||||
|
||||
time_t Channel::getTopicTime() const
|
||||
{
|
||||
return _topicTime;
|
||||
}
|
||||
|
||||
void Channel::setTopic(const std::string &topic, const std::string &setter)
|
||||
{
|
||||
_topic = topic;
|
||||
_topicSetter = setter;
|
||||
_topicTime = std::time(NULL);
|
||||
}
|
||||
|
||||
void Channel::setClientLimit(size_t limit)
|
||||
{
|
||||
_clientLimit = limit;
|
||||
}
|
||||
|
||||
size_t Channel::getClientLimit() const
|
||||
{
|
||||
return _clientLimit;
|
||||
}
|
||||
|
||||
void Channel::setInviteOnly(bool inviteOnly)
|
||||
{
|
||||
_inviteOnly = inviteOnly;
|
||||
}
|
||||
|
||||
void Channel::setKey(const std::string &key)
|
||||
{
|
||||
_key = key;
|
||||
}
|
||||
|
||||
std::string Channel::getKey()
|
||||
{
|
||||
return _key;
|
||||
}
|
||||
|
||||
void Channel::setTopicProtection(bool protection)
|
||||
{
|
||||
_topicProtection = protection;
|
||||
}
|
||||
|
||||
void Channel::addInvitedClient(Client* client)
|
||||
{
|
||||
_invitedClients.insert(client);
|
||||
}
|
||||
|
||||
std::string Channel::getModes() const
|
||||
{
|
||||
std::string modes;
|
||||
if (_inviteOnly) modes += 'i';
|
||||
if (!_key.empty()) modes += 'k';
|
||||
if (_clientLimit > 0) modes += 'l';
|
||||
if (_topicProtection) modes += 't';
|
||||
return modes;
|
||||
}
|
||||
|
||||
bool Channel::getTopicProtection() const
|
||||
{
|
||||
return _topicProtection;
|
||||
}
|
||||
136
ft_irc3/src/Client.cpp
Normal file
136
ft_irc3/src/Client.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* Client.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/15 12:17:42 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/06 13:23:32 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "Client.hpp"
|
||||
|
||||
Client::Client(int fd, const std::string &nickname, const std::string &user, const std::string &host, const std::string &password, const std::string &realname)
|
||||
: _fd(fd), _nickname(nickname), _user(user), _host(host), _password(password), _realname(realname), _authenticated(false), _operator(false), _away(false) {}
|
||||
|
||||
int Client::getFd() const
|
||||
{
|
||||
return _fd;
|
||||
}
|
||||
|
||||
const std::string &Client::getNickname() const
|
||||
{
|
||||
return _nickname;
|
||||
}
|
||||
|
||||
void Client::setNickname(const std::string &nickname)
|
||||
{
|
||||
_nickname = nickname;
|
||||
}
|
||||
|
||||
const std::string &Client::getUser() const
|
||||
{
|
||||
return _user;
|
||||
}
|
||||
|
||||
void Client::setUser(const std::string &user)
|
||||
{
|
||||
_user = user;
|
||||
}
|
||||
|
||||
const std::string &Client::getHost() const
|
||||
{
|
||||
return _host;
|
||||
}
|
||||
|
||||
void Client::setHost(const std::string &host)
|
||||
{
|
||||
_host = host;
|
||||
}
|
||||
|
||||
const std::string &Client::getPassword() const
|
||||
{
|
||||
return _password;
|
||||
}
|
||||
|
||||
void Client::setPassword(const std::string &password)
|
||||
{
|
||||
_password = password;
|
||||
}
|
||||
|
||||
const std::string &Client::getRealName() const
|
||||
{
|
||||
return _realname;
|
||||
}
|
||||
|
||||
void Client::setRealName(const std::string &realname)
|
||||
{
|
||||
_realname = realname;
|
||||
}
|
||||
|
||||
bool Client::isAuthenticated() const
|
||||
{
|
||||
return _authenticated;
|
||||
}
|
||||
|
||||
void Client::authenticate()
|
||||
{
|
||||
_authenticated = true;
|
||||
}
|
||||
|
||||
bool Client::isOperator() const
|
||||
{
|
||||
return _operator;
|
||||
}
|
||||
|
||||
void Client::setOperator(bool isOperator)
|
||||
{
|
||||
_operator = isOperator;
|
||||
}
|
||||
|
||||
bool Client::isAway() const
|
||||
{
|
||||
return _away;
|
||||
}
|
||||
|
||||
const std::string &Client::getAwayMessage() const
|
||||
{
|
||||
return _awayMessage;
|
||||
}
|
||||
|
||||
void Client::setAwayMessage(const std::string &message)
|
||||
{
|
||||
_awayMessage = message;
|
||||
}
|
||||
|
||||
void Client::setAway(bool away)
|
||||
{
|
||||
_away = away;
|
||||
}
|
||||
|
||||
std::string Client::getKey() const
|
||||
{
|
||||
return _key;
|
||||
}
|
||||
|
||||
void Client::setkey(const std::string &key)
|
||||
{
|
||||
_key = key;
|
||||
}
|
||||
|
||||
void Client::joinChannel(const std::string &channel)
|
||||
{
|
||||
_channels.insert(channel);
|
||||
}
|
||||
|
||||
void Client::leaveChannel(const std::string &channel)
|
||||
{
|
||||
_channels.erase(channel);
|
||||
}
|
||||
|
||||
const std::set<std::string> &Client::getChannels() const
|
||||
{
|
||||
return _channels;
|
||||
}
|
||||
173
ft_irc3/src/ClientManager.cpp
Normal file
173
ft_irc3/src/ClientManager.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* ClientManager.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/15 18:32:23 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/06 14:09:52 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "ClientManager.hpp"
|
||||
|
||||
ClientManager::ClientManager(Server *server)
|
||||
: _server(server)
|
||||
{
|
||||
_botFilter = new BotFilter(server);
|
||||
_botFilter->loadBadWords("badwords.txt");
|
||||
}
|
||||
|
||||
void ClientManager::acceptClient()
|
||||
{
|
||||
int client_fd = accept(_server->_server_fd, NULL, NULL);
|
||||
if (client_fd < 0)
|
||||
{
|
||||
_server->log("Failed to accept client.", RED);
|
||||
return;
|
||||
}
|
||||
|
||||
Client *newClient = new Client(client_fd, "", "", "", "", "");
|
||||
_server->_clients[client_fd] = newClient;
|
||||
struct pollfd client_pollfd;
|
||||
client_pollfd.fd = client_fd;
|
||||
client_pollfd.events = POLLIN;
|
||||
_server->_poll_fds.push_back(client_pollfd);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "Client attempting connection: " << client_fd;
|
||||
_server->log(ss.str(), YELLOW);
|
||||
}
|
||||
|
||||
void ClientManager::handleClient(int client_fd)
|
||||
{
|
||||
Client* client = _server->getClients()[client_fd];
|
||||
std::memset(client->buffer, 0, sizeof(client->buffer));
|
||||
int bytes_received = recv(client_fd, client->buffer, sizeof(client->buffer), 0);
|
||||
|
||||
if (bytes_received <= 0)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Client disconnected: " << client_fd;
|
||||
_server->log(oss.str(), RED);
|
||||
removeClient(client_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "Received data (" << bytes_received << " bytes): " << client->buffer << std::endl;
|
||||
|
||||
if (std::string(client->buffer).find('\n') != std::string::npos)
|
||||
{
|
||||
strcat(client->buffer2, client->buffer);
|
||||
std::string fullMessage(client->buffer2);
|
||||
|
||||
// Log the combined message
|
||||
std::cout << "Complete message: " << fullMessage << std::endl;
|
||||
|
||||
bool messageAllowed = true;
|
||||
|
||||
if (!client->getChannels().empty())
|
||||
{
|
||||
for (std::set<std::string>::const_iterator it = client->getChannels().begin(); it != client->getChannels().end(); ++it)
|
||||
{
|
||||
const std::string& channelName = *it;
|
||||
Channel* channel = _server->getChannelByName(channelName);
|
||||
if (channel && !_botFilter->checkMessage(client, channel, fullMessage))
|
||||
{
|
||||
messageAllowed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (messageAllowed)
|
||||
{
|
||||
handleClientNext(client_fd, client->buffer2, fullMessage.size());
|
||||
}
|
||||
|
||||
std::memset(client->buffer2, 0, sizeof(client->buffer2));
|
||||
}
|
||||
else
|
||||
{
|
||||
strcat(client->buffer2, client->buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ClientManager::handleClientNext(int client_fd, char * buffer, int bytes_received)
|
||||
{
|
||||
std::string message(buffer, bytes_received);
|
||||
std::ostringstream oss;
|
||||
oss << "Received from client " << client_fd << ": " << message;
|
||||
_server->log(oss.str(), BLUE);
|
||||
|
||||
Client* client = _server->getClients()[client_fd];
|
||||
if (!client)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Client not found for fd: " << client_fd;
|
||||
_server->log(oss.str(), RED);
|
||||
return;
|
||||
}
|
||||
|
||||
std::istringstream message_stream(message);
|
||||
std::string line;
|
||||
|
||||
while (std::getline(message_stream, line))
|
||||
{
|
||||
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
|
||||
line.erase(std::remove(line.begin(), line.end(), '\n'), line.end());
|
||||
|
||||
if (!line.empty())
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Processing command from client " << client_fd << ": " << line;
|
||||
_server->log(oss.str(), BLUE);
|
||||
_server->_commandHandler->handleCommand(client, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientManager::removeClient(int clientFd)
|
||||
{
|
||||
Client* client = _server->_clients[clientFd];
|
||||
if (client)
|
||||
{
|
||||
_server->log("Removing client: " + client->getNickname(), YELLOW);
|
||||
|
||||
std::map<std::string, Channel*>::iterator it = _server->_channels.begin();
|
||||
while (it != _server->_channels.end())
|
||||
{
|
||||
it->second->removeClient(client);
|
||||
if (it->second->isEmpty())
|
||||
{
|
||||
delete it->second;
|
||||
std::map<std::string, Channel*>::iterator it_to_delete = it++;
|
||||
_server->_channels.erase(it_to_delete);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
delete client;
|
||||
_server->_clients.erase(clientFd);
|
||||
}
|
||||
|
||||
std::vector<struct pollfd>::iterator it_poll = _server->_poll_fds.begin();
|
||||
while (it_poll != _server->_poll_fds.end())
|
||||
{
|
||||
if (it_poll->fd == clientFd)
|
||||
{
|
||||
_server->_poll_fds.erase(it_poll);
|
||||
break;
|
||||
}
|
||||
++it_poll;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "Client disconnected: " << clientFd;
|
||||
_server->log(ss.str(), YELLOW);
|
||||
}
|
||||
305
ft_irc3/src/CommandHandler.cpp
Normal file
305
ft_irc3/src/CommandHandler.cpp
Normal file
@@ -0,0 +1,305 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* CommandHandler.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/15 18:26:34 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/05 09:57:55 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "CommandHandler.hpp"
|
||||
|
||||
CommandHandler::CommandHandler(Server *server)
|
||||
: _server(server), _additionalCommands(new AdditionalCommands(server)), _modeHandler(new ModeHandler(server))
|
||||
{
|
||||
// Ensure that _server is not null
|
||||
if (!_server)
|
||||
{
|
||||
std::cerr << "Server pointer is null in CommandHandler constructor." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void CommandHandler::handleCommand(Client* client, const std::string& command)
|
||||
{
|
||||
std::vector<std::string> tokens = split(command, " \n\r\t");
|
||||
|
||||
if (tokens.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::string commandType = tokens[0];
|
||||
if (commandType == "CAP")
|
||||
{
|
||||
handleCapCommand(client, tokens);
|
||||
}
|
||||
else if (commandType == "PASS")
|
||||
{
|
||||
handlePassCommand(client, tokens);
|
||||
}
|
||||
else if (commandType == "NICK")
|
||||
{
|
||||
handleNick(client, tokens);
|
||||
}
|
||||
else if (commandType == "USER")
|
||||
{
|
||||
handleUser(client, tokens);
|
||||
}
|
||||
else if (commandType == "QUIT")
|
||||
{
|
||||
handleQuitCommand(client, tokens);
|
||||
}
|
||||
else if (commandType == "PING")
|
||||
{
|
||||
handlePingCommand(client, tokens);
|
||||
}
|
||||
else if (commandType == "ERROR")
|
||||
{
|
||||
if (tokens.size() > 1)
|
||||
{
|
||||
handleErrorCommand(client, tokens[1]);
|
||||
}
|
||||
}
|
||||
else if (commandType == "MODE")
|
||||
{
|
||||
_modeHandler->handleModeCommand(client, command);
|
||||
}
|
||||
else if (commandType == "JOIN")
|
||||
{
|
||||
std::string joinParams = command.substr(command.find(" ") + 1);
|
||||
JoinHandler joinHandler;
|
||||
joinHandler.handleJoinCommand(client, joinParams, _server);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!client->isAuthenticated())
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NOTREGISTERED(client));
|
||||
_server->log("Client " + client->getNickname() + " attempted to send a command before registering.", RED);
|
||||
}
|
||||
else
|
||||
{
|
||||
_additionalCommands->processCommand(client, command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CommandHandler::handleCapCommand(Client* client, const std::vector<std::string>& tokens)
|
||||
{
|
||||
if (tokens.size() < 2)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client, "CAP"));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string subcommand = tokens[1];
|
||||
std::string capabilities = "multi-prefix extended-join account-notify batch invite-notify";
|
||||
|
||||
if (subcommand == "LS")
|
||||
{
|
||||
_server->sendToClient(client->getFd(), RPL_CAP(client, "LS", capabilities));
|
||||
}
|
||||
else if (subcommand == "LIST")
|
||||
{
|
||||
_server->sendToClient(client->getFd(), RPL_CAP(client, "LIST", capabilities));
|
||||
}
|
||||
else if (subcommand == "REQ")
|
||||
{
|
||||
if (tokens.size() < 3)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client, "CAP"));
|
||||
return;
|
||||
}
|
||||
std::string requestedCapabilities = tokens[2];
|
||||
_server->sendToClient(client->getFd(), RPL_CAP(client, "ACK", requestedCapabilities));
|
||||
}
|
||||
else if (subcommand == "END")
|
||||
{
|
||||
_server->sendToClient(client->getFd(), RPL_CAPEND(client));
|
||||
}
|
||||
else
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_UNKNOWNCOMMAND(client, "CAP"));
|
||||
}
|
||||
}
|
||||
|
||||
void CommandHandler::handlePassCommand(Client* client, const std::vector<std::string>& tokens)
|
||||
{
|
||||
if (tokens.size() < 2)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client, "PASS"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (client->isAuthenticated())
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_ALREADYREGISTERED(client));
|
||||
return;
|
||||
}
|
||||
|
||||
if (tokens[1] == _server->_password)
|
||||
{
|
||||
client->setPassword(tokens[1]);
|
||||
_server->sendToClient(client->getFd(), ":server NOTICE * :Password accepted\r\n");
|
||||
_server->log("Client " + client->getNickname() + " provided correct password.", GREEN);
|
||||
} else {
|
||||
_server->sendToClient(client->getFd(), ERR_PASSWDMISMATCH(client));
|
||||
_server->log("Client " + client->getNickname() + " failed authentication password.", RED);
|
||||
}
|
||||
}
|
||||
|
||||
bool CommandHandler::isValidNickname(const std::string& nickname)
|
||||
{
|
||||
if (nickname.empty() || nickname[0] == '#' || nickname[0] == ':' || nickname.find(' ') != std::string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandHandler::isNicknameInUse(const std::string& nickname)
|
||||
{
|
||||
for (std::map<int, Client*>::iterator it = _server->_clients.begin(); it != _server->_clients.end(); ++it)
|
||||
{
|
||||
if (it->second->getNickname() == nickname)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CommandHandler::handleNick(Client* client, const std::vector<std::string>& tokens)
|
||||
{
|
||||
if (tokens.size() < 2)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NONICKNAMEGIVEN(client));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string newNick = tokens[1];
|
||||
|
||||
if (!isValidNickname(newNick))
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_ERRONEUSNICKNAME(client, newNick));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNicknameInUse(newNick))
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NICKNAMEINUSE(client, newNick));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string oldNick = client->getNickname();
|
||||
client->setNickname(newNick);
|
||||
|
||||
std::string nickMessage = ":" + oldNick + " NICK " + newNick + "\r\n";
|
||||
for (std::map<int, Client*>::iterator it = _server->_clients.begin(); it != _server->_clients.end(); ++it)
|
||||
{
|
||||
if (it->second->isAuthenticated())
|
||||
_server->sendToClient(it->second->getFd(), nickMessage);
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "Client " << client->getFd() << " changed nickname from " << oldNick << " to " << newNick;
|
||||
_server->log(oss.str(), GREEN);
|
||||
}
|
||||
|
||||
|
||||
void CommandHandler::handleUser(Client* client, const std::vector<std::string>& tokens)
|
||||
{
|
||||
if (tokens.size() < 5)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client, "USER"));
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "Client " << client->getFd() << ": USER command failed - not enough parameters.";
|
||||
_server->log(oss.str(), RED);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (client->isAuthenticated())
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_ALREADYREGISTERED(client));
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "Client " << client->getFd() << ": USER command failed - already registered.";
|
||||
_server->log(oss.str(), RED);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::string username = tokens[1];
|
||||
std::string realname = tokens[4].substr(1);
|
||||
|
||||
client->setUser(username);
|
||||
client->setRealName(realname);
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "Client " << client->getFd() << ": USER command set username to " << username << " and real name to " << realname;
|
||||
_server->log(oss.str(), BLUE);
|
||||
|
||||
if (client->getPassword() == _server->_password && !client->getNickname().empty())
|
||||
{
|
||||
client->authenticate();
|
||||
WelcomeHandler welcomeHandler;
|
||||
welcomeHandler.sendWelcomeMessages(client, _server);
|
||||
_server->log("Client " + client->getNickname() + " authenticated.", GREEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Client " << client->getFd() << ": USER command failed - authentication conditions not met.";
|
||||
_server->log(oss.str(), RED);
|
||||
}
|
||||
}
|
||||
|
||||
void CommandHandler::handlePingCommand(Client* client, const std::vector<std::string>& tokens)
|
||||
{
|
||||
if (tokens.size() < 2)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client, "PING"));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string serverName = tokens[1];
|
||||
std::string pongMessage = ":" + serverName + " PONG " + serverName + "\r\n";
|
||||
_server->sendToClient(client->getFd(), pongMessage);
|
||||
}
|
||||
|
||||
|
||||
void CommandHandler::handleQuitCommand(Client* client, const std::vector<std::string>& tokens)
|
||||
{
|
||||
std::string reason = "Quit: ";
|
||||
if (tokens.size() > 1)
|
||||
{
|
||||
reason += tokens[1];
|
||||
}
|
||||
|
||||
std::string quitMessage = ":" + client->getNickname() + " QUIT :" + reason + "\r\n";
|
||||
|
||||
std::map<std::string, Channel*>::iterator it;
|
||||
for (it = _server->getChannels().begin(); it != _server->getChannels().end(); ++it)
|
||||
{
|
||||
if (it->second->hasClient(client))
|
||||
{
|
||||
it->second->broadcast(quitMessage, client, _server);
|
||||
it->second->removeClient(client);
|
||||
}
|
||||
}
|
||||
|
||||
_server->sendToClient(client->getFd(), "ERROR :" + reason + "\r\n");
|
||||
_server->disconnectClient(client->getFd());
|
||||
}
|
||||
|
||||
void CommandHandler::handleErrorCommand(Client* client, const std::string &message)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), "ERROR :" + message + "\r\n");
|
||||
_server->disconnectClient(client->getFd());
|
||||
}
|
||||
67
ft_irc3/src/InviteHandler.cpp
Normal file
67
ft_irc3/src/InviteHandler.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* InviteHandler.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/30 13:02:09 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/01 19:11:22 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "InviteHandler.hpp"
|
||||
|
||||
InviteHandler::InviteHandler(Server* server) : _server(server) {}
|
||||
|
||||
void InviteHandler::handleInviteCommand(Client* client, const std::string& command)
|
||||
{
|
||||
std::istringstream iss(command);
|
||||
std::string cmd, nickname, channelName;
|
||||
iss >> cmd >> nickname >> channelName;
|
||||
|
||||
if (nickname.empty() || channelName.empty())
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client, "INVITE"));
|
||||
return;
|
||||
}
|
||||
|
||||
Channel* channel = _server->getChannelByName(channelName);
|
||||
if (!channel)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NOSUCHCHANNEL(client, channelName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel->hasClient(client))
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NOTONCHANNEL(client, channelName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel->isOperator(client) && channel->isInviteOnly())
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_CHANOPRIVSNEEDED(client, channelName));
|
||||
return;
|
||||
}
|
||||
|
||||
Client* targetClient = _server->getClientByName(nickname);
|
||||
if (!targetClient)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NOSUCHNICK(client, nickname));
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel->hasClient(targetClient))
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_USERONCHANNEL(client, nickname, channelName));
|
||||
return;
|
||||
}
|
||||
|
||||
channel->addInvitedClient(targetClient);
|
||||
_server->sendToClient(client->getFd(), RPL_INVITING(client, channel->getName()));
|
||||
|
||||
std::ostringstream inviteMsg;
|
||||
inviteMsg << ":" << client->getNickname() << " INVITE " << nickname << " " << channelName << "\r\n";
|
||||
_server->sendToClient(targetClient->getFd(), inviteMsg.str());
|
||||
}
|
||||
167
ft_irc3/src/Join.cpp
Normal file
167
ft_irc3/src/Join.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* Join.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/21 19:51:31 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/05/21 20:13:30 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "Join.hpp"
|
||||
|
||||
void JoinHandler::handleJoinCommand(Client* client, const std::string& params, Server* server)
|
||||
{
|
||||
std::map<std::string, Channel*>& channels = server->getChannels();
|
||||
Channel* channel;
|
||||
|
||||
server->log("Received JOIN command with params: " + params, RED);
|
||||
|
||||
// Split params into channel names and keys
|
||||
std::vector<std::string> parts = split(params, " ");
|
||||
server->log("Split parts: ", RED);
|
||||
for (size_t i = 0; i < parts.size(); ++i)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Part " << i << ": " << parts[i];
|
||||
server->log(oss.str(), RED);
|
||||
}
|
||||
if (parts.empty())
|
||||
{
|
||||
server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client, "JOIN"));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string channelNames = parts[0];
|
||||
std::string keys = (parts.size() > 1) ? parts[1] : "";
|
||||
|
||||
server->log("Split params: channelNames = " + channelNames + ", keys = " + keys, RED);
|
||||
|
||||
std::vector<std::string> channelList = split(channelNames, ",");
|
||||
std::vector<std::string> keyList = split(keys, ",");
|
||||
|
||||
server->log("channelList: ", RED);
|
||||
for (size_t i = 0; i < channelList.size(); ++i)
|
||||
{
|
||||
server->log(channelList[i], RED);
|
||||
}
|
||||
|
||||
server->log("keyList: ", RED);
|
||||
for (size_t i = 0; i < keyList.size(); ++i)
|
||||
{
|
||||
server->log(keyList[i], RED);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < channelList.size(); ++i)
|
||||
{
|
||||
const std::string& channelName = channelList[i];
|
||||
server->log("Processing channel: " + channelName, RED);
|
||||
|
||||
if (channelName.empty())
|
||||
{
|
||||
server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client, "JOIN"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (channelName[0] == '0' && channelName.size() == 1)
|
||||
{
|
||||
// Leave all channels
|
||||
return;
|
||||
}
|
||||
|
||||
if (channelName[0] != '#' && channelName[0] != '&')
|
||||
{
|
||||
server->sendToClient(client->getFd(), ERR_NOSUCHCHANNEL(client, channelName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (channels.find(channelName) == channels.end())
|
||||
{
|
||||
channel = new Channel(channelName);
|
||||
channels[channelName] = channel;
|
||||
channel->addOperator(client); // Set client as operator for new channel
|
||||
}
|
||||
else
|
||||
{
|
||||
channel = channels[channelName];
|
||||
}
|
||||
|
||||
if (channel->isBanned(client))
|
||||
{
|
||||
server->sendToClient(client->getFd(), ERR_BANNEDFROMCHAN(client, channelName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel->isFull())
|
||||
{
|
||||
server->sendToClient(client->getFd(), ERR_CHANNELISFULL(client, channelName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel->isInviteOnly() && !channel->isInvited(client))
|
||||
{
|
||||
server->sendToClient(client->getFd(), ERR_INVITEONLYCHAN(client, channelName));
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract the key for this channel, if provided
|
||||
std::string key = (i < keyList.size()) ? keyList[i] : "";
|
||||
server->log("Using key: " + key + " for channel: " + channelName, RED);
|
||||
|
||||
if (!channel->checkKey(key))
|
||||
{
|
||||
server->sendToClient(client->getFd(), ERR_BADCHANNELKEY(client, channelName));
|
||||
return;
|
||||
}
|
||||
|
||||
channel->addClient(client);
|
||||
sendJoinSuccess(client, channel, server);
|
||||
}
|
||||
}
|
||||
|
||||
void JoinHandler::sendJoinSuccess(Client* client, Channel* channel, Server* server)
|
||||
{
|
||||
std::vector<Client*> clients = channel->getClients();
|
||||
for (std::vector<Client*>::iterator it = clients.begin(); it != clients.end(); ++it)
|
||||
{
|
||||
std::string joinMsg = ":" + client->getNickname() + " JOIN " + channel->getName() + "\r\n";
|
||||
server->sendToClient((*it)->getFd(), joinMsg);
|
||||
}
|
||||
|
||||
if (!channel->getTopic().empty())
|
||||
{
|
||||
server->sendToClient(client->getFd(), RPL_TOPIC(client, channel->getName(), channel->getTopic()));
|
||||
server->sendToClient(client->getFd(), RPL_TOPICWHOTIME(client, channel->getName(), channel->getTopicSetter(), channel->getTopicTime()));
|
||||
}
|
||||
else
|
||||
{
|
||||
server->sendToClient(client->getFd(), RPL_NOTOPIC(client, channel->getName()));
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << RPL_CHANNELMODEIS(client->getFd(), channel->getName(), channel->getModes());
|
||||
oss << RPL_CREATIONTIME(client, channel->getName(), channel->getTopicTime());
|
||||
server->sendToClient(client->getFd(), oss.str());
|
||||
|
||||
std::string usersList = getUsersList(channel);
|
||||
server->sendToClient(client->getFd(), usersList);
|
||||
}
|
||||
|
||||
std::string JoinHandler::getUsersList(Channel* channel)
|
||||
{
|
||||
std::vector<Client*> clients = channel->getClients();
|
||||
std::string users;
|
||||
for (std::vector<Client*>::iterator it = clients.begin(); it != clients.end(); ++it)
|
||||
{
|
||||
if (channel->isOperator((*it)))
|
||||
users += "@";
|
||||
users += (*it)->getNickname() + " ";
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << RPL_NAMREPLY(clients[0], channel->getName(), users);
|
||||
oss << RPL_ENDOFNAMES(clients[0], channel->getName());
|
||||
return oss.str();
|
||||
}
|
||||
68
ft_irc3/src/KickHandler.cpp
Normal file
68
ft_irc3/src/KickHandler.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* KickHandler.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/06/01 17:00:31 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/01 19:12:13 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "KickHandler.hpp"
|
||||
|
||||
|
||||
|
||||
KickHandler::KickHandler(Server* server) : _server(server) {}
|
||||
|
||||
void KickHandler::handleKickCommand(Client* client, const std::string& command)
|
||||
{
|
||||
std::vector<std::string> tokens = split(command, " ");
|
||||
if (tokens.size() < 3)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client, "KICK"));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string channelName = tokens[1];
|
||||
std::string targetNickname = tokens[2];
|
||||
std::string comment = (tokens.size() > 3) ? tokens[3] : "Kicked by operator";
|
||||
|
||||
Channel* channel = _server->getChannelByName(channelName);
|
||||
if (!channel)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NOSUCHCHANNEL(client, channelName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel->hasClient(client))
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NOTONCHANNEL(client, channelName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel->isOperator(client))
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_CHANOPRIVSNEEDED(client, channelName));
|
||||
return;
|
||||
}
|
||||
|
||||
Client* targetClient = _server->getClientByName(targetNickname);
|
||||
if (!targetClient)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NOSUCHNICK(client, targetNickname));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel->hasClient(targetClient))
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_USERNOTINCHANNEL(client, targetNickname, channelName));
|
||||
return;
|
||||
}
|
||||
|
||||
channel->removeClient(targetClient);
|
||||
std::string kickMessage = ":" + client->getNickname() + " KICK " + channelName + " " + targetNickname + " :" + comment + "\r\n";
|
||||
channel->broadcast(kickMessage, NULL, _server);
|
||||
_server->sendToClient(targetClient->getFd(), kickMessage);
|
||||
}
|
||||
277
ft_irc3/src/ModeHandler.cpp
Normal file
277
ft_irc3/src/ModeHandler.cpp
Normal file
@@ -0,0 +1,277 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* ModeHandler.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/30 11:13:08 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/04 16:12:50 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "ModeHandler.hpp"
|
||||
|
||||
ModeHandler::ModeHandler(Server* server) : _server(server) {}
|
||||
|
||||
void ModeHandler::handleModeCommand(Client* client, const std::string& command)
|
||||
{
|
||||
_server->log("Received MODE command: " + command, BLUE);
|
||||
std::vector<std::string> tokens = split(command, " \n\r\t");
|
||||
|
||||
if (tokens.size() < 2)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client, "MODE"));
|
||||
_server->log("MODE command error: Need more parameters", RED);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string target = tokens[1];
|
||||
if (target[0] == '#' || target[0] == '&')
|
||||
{
|
||||
_server->log("Handling channel mode for target: " + target, GREEN);
|
||||
handleChannelMode(client, tokens);
|
||||
}
|
||||
else
|
||||
{
|
||||
_server->log("Handling user mode for target: " + target, GREEN);
|
||||
handleUserMode(client, tokens);
|
||||
}
|
||||
}
|
||||
|
||||
void ModeHandler::handleUserMode(Client* client, const std::vector<std::string>& tokens)
|
||||
{
|
||||
_server->log("Entered handleUserMode", MAGENTA);
|
||||
std::string target = tokens[1];
|
||||
_server->log("User mode target: " + target, CYAN);
|
||||
if (target != client->getNickname())
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_USERSDONTMATCH(client));
|
||||
_server->log("User mode error: Users don't match", RED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tokens.size() == 2)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), RPL_UMODEIS(client, ""));
|
||||
_server->log("Sent user modes to client", GREEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string modeString = tokens[2];
|
||||
_server->log("Updating user modes: " + modeString, BLUE);
|
||||
}
|
||||
}
|
||||
|
||||
void ModeHandler::handleChannelMode(Client* client, const std::vector<std::string>& tokens)
|
||||
{
|
||||
_server->log("Entered handleChannelMode", MAGENTA);
|
||||
std::string channelName = tokens[1];
|
||||
_server->log("Channel mode target: " + channelName, CYAN);
|
||||
Channel* channel = _server->getChannelByName(channelName);
|
||||
if (!channel)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NOSUCHCHANNEL(client, channelName));
|
||||
_server->log("Channel mode error: No such channel " + channelName, RED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tokens.size() == 2)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << RPL_CHANNELMODEIS(client->getFd(), channel->getName(), channel->getModes());
|
||||
oss << RPL_CREATIONTIME(client, channel->getName(), channel->getTopicTime());
|
||||
_server->sendToClient(client->getFd(), oss.str());
|
||||
_server->log("Sent channel modes to client", GREEN);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel->isOperator(client))
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_CHANOPRIVSNEEDED(client, channelName));
|
||||
_server->log("Channel mode error: Channel operator privileges needed for " + channelName, RED);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string modeString = tokens[2];
|
||||
bool adding = true;
|
||||
size_t argIndex = 3;
|
||||
|
||||
for (size_t i = 0; i < modeString.length(); ++i)
|
||||
{
|
||||
char mode = modeString[i];
|
||||
if (mode == '+')
|
||||
{
|
||||
adding = true;
|
||||
_server->log("Adding mode: " + std::string(1, mode), GREEN);
|
||||
} else if (mode == '-')
|
||||
{
|
||||
adding = false;
|
||||
_server->log("Removing mode: " + std::string(1, mode), RED);
|
||||
} else if (mode == 'b' || mode == 'l' || mode == 'i' || mode == 'k' || mode == 't' || mode == 'o')
|
||||
{
|
||||
std::string argument;
|
||||
if (argIndex < tokens.size())
|
||||
{
|
||||
argument = tokens[argIndex++];
|
||||
}
|
||||
setChannelMode(client, channel, std::string(1, mode), adding, argument);
|
||||
}
|
||||
else
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_UNKNOWNMODE(client, mode, channelName));
|
||||
_server->log("Unknown mode: " + std::string(1, mode), RED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModeHandler::setChannelMode(Client *client, Channel* channel, const std::string& mode, bool adding, const std::string& argument)
|
||||
{
|
||||
_server->log("Setting channel mode: " + mode + " Adding: " + (adding ? "true" : "false") + " Argument: " + argument, GREEN);
|
||||
if (mode == "l")
|
||||
{
|
||||
applyModeL(client, channel, adding, argument);
|
||||
}
|
||||
else if (mode == "i")
|
||||
{
|
||||
applyModeI(client, channel, adding);
|
||||
}
|
||||
else if (mode == "k")
|
||||
{
|
||||
applyModeK(client, channel, adding, argument);
|
||||
}
|
||||
else if (mode == "t")
|
||||
{
|
||||
applyModeT(channel, adding);
|
||||
}
|
||||
else if (mode == "o")
|
||||
applyModeO(client, channel, adding, argument);
|
||||
}
|
||||
|
||||
void ModeHandler::applyModeL(Client *client, Channel* channel, bool adding, const std::string& argument)
|
||||
{
|
||||
if (adding)
|
||||
{
|
||||
int limit = std::atoi(argument.c_str());
|
||||
if (limit <= 0)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_INVALIDMODEPARAM(client, argument));
|
||||
_server->log("Invalid limit for mode +l: " + argument, RED);
|
||||
return;
|
||||
}
|
||||
std::ostringstream oss;
|
||||
oss << limit;
|
||||
_server->log("Applying mode L: Setting limit to " + oss.str(), GREEN);
|
||||
channel->setClientLimit(limit);
|
||||
}
|
||||
else
|
||||
{
|
||||
_server->log("Applying mode L: Removing limit", RED);
|
||||
channel->setClientLimit(0);
|
||||
}
|
||||
}
|
||||
|
||||
void ModeHandler::applyModeI(Client *client, Channel *channel, bool adding)
|
||||
{
|
||||
std::string modeChange;
|
||||
bool isAlreadySet;
|
||||
|
||||
modeChange = adding ? "+i" : "-i";
|
||||
isAlreadySet = channel->isInviteOnly() == adding;
|
||||
if (!isAlreadySet)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), MODEACCEPTMESSAGE(client, channel->getName(), modeChange));
|
||||
_server->log("Applying mode I: " + std::string(adding ? "Setting invite-only" : "Removing invite-only"), GREEN);
|
||||
channel->setInviteOnly(adding);
|
||||
}
|
||||
}
|
||||
|
||||
void ModeHandler::applyModeK(Client *client, Channel *channel, bool adding, const std::string &argument)
|
||||
{
|
||||
bool isAlreadyProtected;
|
||||
|
||||
isAlreadyProtected = !channel->getKey().empty();
|
||||
if (adding)
|
||||
{
|
||||
if (isAlreadyProtected)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_KEYSET(client, channel->getName()));
|
||||
_server->log("Mode +k error: Channel already has a key set", RED);
|
||||
return;
|
||||
}
|
||||
if (argument.empty())
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client, "MODE +k"));
|
||||
_server->log("Mode +k error: No key provided", RED);
|
||||
return;
|
||||
}
|
||||
if (argument.find(' ') != std::string::npos)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_INVALIDMODEPARAM(client, argument));
|
||||
_server->log("Invalid key for mode +k: contains spaces", RED);
|
||||
return;
|
||||
}
|
||||
_server->sendToClient(client->getFd(), MODEACCEPTMESSAGE(client, channel->getName(), "+k " + argument));
|
||||
_server->log("Applying mode K: Setting key to " + argument, GREEN);
|
||||
channel->setKey(argument);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isAlreadyProtected)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_LINKSET(client, channel->getName()));
|
||||
_server->log("Mode -k error: No key to remove", RED);
|
||||
return;
|
||||
}
|
||||
_server->sendToClient(client->getFd(), MODEACCEPTMESSAGE(client, channel->getName(), "-k"));
|
||||
_server->log("Applying mode K: Removing key", RED);
|
||||
channel->setKey("");
|
||||
}
|
||||
}
|
||||
|
||||
void ModeHandler::applyModeT(Channel* channel, bool adding)
|
||||
{
|
||||
std::string modeChange;
|
||||
bool isAlreadySet;
|
||||
|
||||
modeChange = adding ? "+t" : "-t";
|
||||
isAlreadySet = channel->isInviteOnly() == adding;
|
||||
if (!isAlreadySet)
|
||||
{
|
||||
_server->log("Applying mode T: " + std::string(adding ? "Setting topic protection" : "Removing topic protection"), GREEN);
|
||||
channel->setTopicProtection(adding);
|
||||
}
|
||||
}
|
||||
|
||||
void ModeHandler::applyModeO(Client* client, Channel* channel, bool adding, const std::string& argument)
|
||||
{
|
||||
Client* targetClient = _server->getClientByName(argument);
|
||||
if (!targetClient)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NOSUCHNICK(client, argument));
|
||||
_server->log("Mode o error: No such client " + argument, RED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel->hasClient(targetClient))
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_USERNOTINCHANNEL(client, argument, channel->getName()));
|
||||
_server->log("Mode o error: Client " + argument + " not in channel " + channel->getName(), RED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (adding)
|
||||
{
|
||||
_server->log("Applying mode o: Adding operator " + argument, GREEN);
|
||||
channel->addOperator(targetClient);
|
||||
std::string message = ":" + client->getNickname() + " MODE " + channel->getName() + " +o " + targetClient->getNickname() + "\r\n";
|
||||
channel->broadcast(message, NULL, _server);
|
||||
}
|
||||
else
|
||||
{
|
||||
_server->log("Applying mode o: Removing operator " + argument, RED);
|
||||
channel->removeOperator(targetClient);
|
||||
std::string message = ":" + client->getNickname() + " MODE " + channel->getName() + " -o " + targetClient->getNickname() + "\r\n";
|
||||
channel->broadcast(message, NULL, _server);
|
||||
}
|
||||
}
|
||||
252
ft_irc3/src/Server.cpp
Normal file
252
ft_irc3/src/Server.cpp
Normal file
@@ -0,0 +1,252 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* Server.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/15 12:17:12 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/06 13:00:25 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "Server.hpp"
|
||||
|
||||
Server::Server(int port, const std::string &password)
|
||||
: _port(port), _password(password), _clientManager(new ClientManager(this)), _commandHandler(new CommandHandler(this)), _modeHandler(new ModeHandler(this)), _topicHandler(new TopicHandler(this))
|
||||
{
|
||||
initServer();
|
||||
_botFilter = new BotFilter(this);
|
||||
_botFilter->loadBadWords("badwords.txt");
|
||||
}
|
||||
|
||||
Server::~Server()
|
||||
{
|
||||
delete _clientManager;
|
||||
delete _commandHandler;
|
||||
delete _topicHandler;
|
||||
delete _botFilter;
|
||||
|
||||
for (std::map<int, Client*>::iterator it = _clients.begin(); it != _clients.end(); ++it)
|
||||
{
|
||||
delete it->second;
|
||||
}
|
||||
for (std::map<std::string, Channel*>::iterator it = _channels.begin(); it != _channels.end(); ++it)
|
||||
{
|
||||
delete it->second;
|
||||
}
|
||||
close(_server_fd);
|
||||
}
|
||||
|
||||
void Server::initServer()
|
||||
{
|
||||
_server_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (_server_fd == -1)
|
||||
{
|
||||
log("Failed to create socket.", RED);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int opt = 1;
|
||||
if (setsockopt(_server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1)
|
||||
{
|
||||
log("Failed to set socket options.", RED);
|
||||
close(_server_fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
struct sockaddr_in server_addr;
|
||||
std::memset(&server_addr, 0, sizeof(server_addr));
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
server_addr.sin_port = htons(_port);
|
||||
|
||||
if (bind(_server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
|
||||
{
|
||||
log("Failed to bind socket.", RED);
|
||||
close(_server_fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (listen(_server_fd, SOMAXCONN) == -1)
|
||||
{
|
||||
log("Failed to listen on socket.", RED);
|
||||
close(_server_fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
log("Server initialized.", GREEN);
|
||||
}
|
||||
|
||||
void Server::run()
|
||||
{
|
||||
struct pollfd server_pollfd;
|
||||
server_pollfd.fd = _server_fd;
|
||||
server_pollfd.events = POLLIN;
|
||||
server_pollfd.revents = 0;
|
||||
_poll_fds.push_back(server_pollfd);
|
||||
|
||||
|
||||
struct pollfd stdin_pollfd;
|
||||
stdin_pollfd.fd = STDIN_FILENO;
|
||||
stdin_pollfd.events = POLLIN;
|
||||
stdin_pollfd.revents = 0;
|
||||
_poll_fds.push_back(stdin_pollfd);
|
||||
|
||||
while (true)
|
||||
{
|
||||
int poll_count = poll(&_poll_fds[0], _poll_fds.size(), -1);
|
||||
if (poll_count == -1)
|
||||
{
|
||||
log("Poll error.", RED);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _poll_fds.size(); ++i)
|
||||
{
|
||||
if (_poll_fds[i].revents & POLLIN)
|
||||
{
|
||||
if (_poll_fds[i].fd == _server_fd)
|
||||
{
|
||||
_clientManager->acceptClient();
|
||||
}
|
||||
else if (_poll_fds[i].fd == STDIN_FILENO)
|
||||
{
|
||||
handleServerCommands();
|
||||
}
|
||||
else
|
||||
{
|
||||
_clientManager->handleClient(_poll_fds[i].fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::map<std::string, Channel *> &Server::getChannels()
|
||||
{
|
||||
return _channels;
|
||||
}
|
||||
|
||||
const std::string &Server::getPassword() const
|
||||
{
|
||||
return _password;
|
||||
}
|
||||
|
||||
void Server::handleServerCommands()
|
||||
{
|
||||
std::string command;
|
||||
std::getline(std::cin, command);
|
||||
|
||||
if (command == "quit")
|
||||
{
|
||||
log("Server shutting down.", YELLOW);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
else if (command == "channels")
|
||||
{
|
||||
log("Listing all channels:", BLUE);
|
||||
for (std::map<std::string, Channel*>::iterator it = _channels.begin(); it != _channels.end(); ++it)
|
||||
{
|
||||
log(it->first, BLUE);
|
||||
}
|
||||
}
|
||||
else if (command == "clients")
|
||||
{
|
||||
log("Listing all clients:", BLUE);
|
||||
for (std::map<int, Client*>::iterator it = _clients.begin(); it != _clients.end(); ++it)
|
||||
{
|
||||
log(it->second->getNickname(), BLUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log("Unknown server command.", RED);
|
||||
}
|
||||
}
|
||||
|
||||
void Server::log(const std::string &message, const std::string &color)
|
||||
{
|
||||
std::cout << color << message << std::endl;
|
||||
}
|
||||
|
||||
void Server::sendToClient(int client_fd, const std::string &message)
|
||||
{
|
||||
int result = send(client_fd, message.c_str(), message.length(), 0);
|
||||
if (result < 0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Failed to send message to client " << client_fd;
|
||||
log(ss.str(), RED);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Sent message to client " << client_fd << ": " << message;
|
||||
log(ss.str(), YELLOW);
|
||||
}
|
||||
}
|
||||
std::map<int, Client *> &Server::getClients()
|
||||
{
|
||||
return _clients;
|
||||
}
|
||||
|
||||
void Server::broadcast(const std::string &message)
|
||||
{
|
||||
for (std::map<int, Client *>::iterator it = _clients.begin(); it != _clients.end(); ++it)
|
||||
{
|
||||
sendToClient(it->first, message);
|
||||
}
|
||||
}
|
||||
|
||||
Client* Server::getClientByName(const std::string &name)
|
||||
{
|
||||
for (std::map<int, Client *>::iterator it = _clients.begin(); it != _clients.end(); ++it)
|
||||
{
|
||||
if (it->second->getNickname() == name)
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Channel* Server::getChannelByName(const std::string &name)
|
||||
{
|
||||
std::map<std::string, Channel *>::iterator it = _channels.find(name);
|
||||
if (it != _channels.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool Server::MatchFd(const pollfd& pfd, int clientFd)
|
||||
{
|
||||
return pfd.fd == clientFd;
|
||||
}
|
||||
|
||||
void Server::removePollFd(int clientFd)
|
||||
{
|
||||
for (std::vector<struct pollfd>::iterator it = _poll_fds.begin(); it != _poll_fds.end(); ++it)
|
||||
{
|
||||
if (MatchFd(*it, clientFd))
|
||||
{
|
||||
_poll_fds.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Server::disconnectClient(int clientFd)
|
||||
{
|
||||
close(clientFd);
|
||||
|
||||
_clients.erase(clientFd);
|
||||
removePollFd(clientFd);
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "Client disconnected: " << clientFd;
|
||||
log(oss.str(), YELLOW);
|
||||
}
|
||||
96
ft_irc3/src/TopicHandler.cpp
Normal file
96
ft_irc3/src/TopicHandler.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* TopicHandler.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/30 17:04:58 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/06/01 19:17:25 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "TopicHandler.hpp"
|
||||
|
||||
TopicHandler::TopicHandler(Server* server) : _server(server) {}
|
||||
|
||||
void TopicHandler::handleTopicCommand(Client* client, const std::string& command)
|
||||
{
|
||||
_server->log("Received TOPIC command: " + command, "\033[1;34m");
|
||||
std::vector<std::string> tokens = split(command, " \n\r\t");
|
||||
|
||||
if (tokens.size() < 2)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client, "TOPIC"));
|
||||
_server->log("TOPIC command error: Need more parameters", RED);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string channelName = tokens[1];
|
||||
Channel* channel = _server->getChannelByName(channelName);
|
||||
if (!channel)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NOSUCHCHANNEL(client, channelName));
|
||||
_server->log("TOPIC command error: No such channel " + channelName, RED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel->hasClient(client))
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NOTONCHANNEL(client, channelName));
|
||||
_server->log("TOPIC command error: Client not on channel " + channelName, RED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tokens.size() == 2)
|
||||
{
|
||||
viewTopic(client, channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t topicStart = command.find(" :");
|
||||
std::string topic = (topicStart != std::string::npos) ? command.substr(topicStart + 2) : "";
|
||||
changeTopic(client, channel, topic);
|
||||
}
|
||||
}
|
||||
|
||||
void TopicHandler::viewTopic(Client* client, Channel* channel)
|
||||
{
|
||||
if (channel->getTopic().empty())
|
||||
{
|
||||
_server->sendToClient(client->getFd(), RPL_NOTOPIC(client, channel->getName()));
|
||||
_server->log("No topic set for channel " + channel->getName(), GREEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
_server->sendToClient(client->getFd(), RPL_TOPIC(client, channel->getName(), channel->getTopic()));
|
||||
_server->sendToClient(client->getFd(), RPL_TOPICWHOTIME(client, channel->getName(), channel->getTopicSetter(), channel->getTopicTime()));
|
||||
_server->log("Sent topic info for channel " + channel->getName(), GREEN);
|
||||
}
|
||||
}
|
||||
|
||||
void TopicHandler::changeTopic(Client* client, Channel* channel, const std::string& topic)
|
||||
{
|
||||
if (channel->getTopicProtection() && !channel->isOperator(client))
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_CHANOPRIVSNEEDED(client, channel->getName()));
|
||||
_server->log("TOPIC command error: Channel operator privileges needed for " + channel->getName(), RED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (topic == channel->getTopic())
|
||||
{
|
||||
_server->sendToClient(client->getFd(), RPL_TOPIC(client, channel->getName(), channel->getTopic()));
|
||||
_server->log("TOPIC unchanged for channel " + channel->getName(), GREEN);
|
||||
return;
|
||||
}
|
||||
|
||||
channel->setTopic(topic, client->getNickname());
|
||||
std::vector<Client*> clients = channel->getClients();
|
||||
for (std::vector<Client*>::iterator it = clients.begin(); it != clients.end(); ++it)
|
||||
{
|
||||
_server->sendToClient((*it)->getFd(), ":" + client->getNickname() + " TOPIC " + channel->getName() + " :" + topic + "\r\n");
|
||||
}
|
||||
|
||||
_server->log("Changed topic for channel " + channel->getName() + " to: " + topic, GREEN);
|
||||
}
|
||||
37
ft_irc3/src/Utils.cpp
Normal file
37
ft_irc3/src/Utils.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* Utils.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/15 12:17:59 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/05/16 18:17:21 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "Utils.hpp"
|
||||
|
||||
std::vector<std::string> split(const std::string &input, const std::string &delimiters)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
size_t startPos = 0;
|
||||
size_t foundPos = input.find_first_of(delimiters, startPos);
|
||||
|
||||
while (foundPos != std::string::npos)
|
||||
{
|
||||
if (foundPos != startPos)
|
||||
{
|
||||
result.push_back(input.substr(startPos, foundPos - startPos));
|
||||
}
|
||||
startPos = foundPos + 1;
|
||||
foundPos = input.find_first_of(delimiters, startPos);
|
||||
}
|
||||
|
||||
if (startPos < input.length())
|
||||
{
|
||||
result.push_back(input.substr(startPos));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
44
ft_irc3/src/Welcome.cpp
Normal file
44
ft_irc3/src/Welcome.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* Welcome.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/21 17:53:52 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/05/30 16:43:14 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "Welcome.hpp"
|
||||
|
||||
void WelcomeHandler::sendWelcomeMessages(Client *client, Server *server)
|
||||
{
|
||||
server->sendToClient(client->getFd(), RPL_WELCOME(client));
|
||||
server->sendToClient(client->getFd(), RPL_YOURHOST(client));
|
||||
server->sendToClient(client->getFd(), RPL_CREATED(client));
|
||||
server->sendToClient(client->getFd(), RPL_MYINFO(client));
|
||||
server->sendToClient(client->getFd(), RPL_ISUPPORT(client, "i/t/k/o/l"));
|
||||
|
||||
sendMotd(client, server);
|
||||
}
|
||||
|
||||
void WelcomeHandler::sendMotd(Client *client, Server *server)
|
||||
{
|
||||
std::ifstream motdFile("motd.txt");
|
||||
if (motdFile.is_open())
|
||||
{
|
||||
std::string line;
|
||||
server->sendToClient(client->getFd(), RPL_MOTDSTART(client));
|
||||
while (std::getline(motdFile, line))
|
||||
{
|
||||
server->sendToClient(client->getFd(), RPL_MOTD(client, line));
|
||||
}
|
||||
server->sendToClient(client->getFd(), RPL_ENDOFMOTD(client));
|
||||
motdFile.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
server->sendToClient(client->getFd(), ERR_NOMOTD(client));
|
||||
}
|
||||
}
|
||||
71
ft_irc3/src/Who.cpp
Normal file
71
ft_irc3/src/Who.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* Who.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/17 16:09:20 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/05/30 16:56:03 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "Who.hpp"
|
||||
|
||||
WhoHandler::WhoHandler(Server *server)
|
||||
: _server(server)
|
||||
{
|
||||
}
|
||||
|
||||
void WhoHandler::handleWhoCommand(Client *client, const std::string &command)
|
||||
{
|
||||
std::istringstream iss(command);
|
||||
std::string cmd, mask;
|
||||
iss >> cmd >> mask;
|
||||
|
||||
std::map<std::string, Channel *> &channels = _server->getChannels();
|
||||
if (channels.find(mask) != channels.end())
|
||||
{
|
||||
Channel *channel = channels[mask];
|
||||
std::vector<Client *> channelClients = channel->getClients();
|
||||
|
||||
for (size_t i = 0; i < channelClients.size(); ++i)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), RPL_WHOREPLY(mask, channelClients[i]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Client *targetClient = _server->getClientByName(mask);
|
||||
if (targetClient)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), RPL_WHOREPLY("*", targetClient));
|
||||
}
|
||||
}
|
||||
|
||||
_server->sendToClient(client->getFd(), RPL_ENDOFWHO(client, mask));
|
||||
}
|
||||
|
||||
void WhoHandler::handleWhoisCommand(Client *client, const std::string &command)
|
||||
{
|
||||
std::istringstream iss(command);
|
||||
std::string cmd, target;
|
||||
iss >> cmd >> target;
|
||||
|
||||
if (target.empty())
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NONICKNAMEGIVEN(client));
|
||||
return;
|
||||
}
|
||||
|
||||
Client *targetClient = _server->getClientByName(target);
|
||||
if (!targetClient)
|
||||
{
|
||||
_server->sendToClient(client->getFd(), ERR_NOSUCHNICK(client, target));
|
||||
return;
|
||||
}
|
||||
|
||||
_server->sendToClient(client->getFd(), RPL_WHOISUSER(client, targetClient));
|
||||
_server->sendToClient(client->getFd(), RPL_WHOISSERVER(client, target, "IRC server info"));
|
||||
_server->sendToClient(client->getFd(), RPL_ENDOFWHOIS(client, target));
|
||||
}
|
||||
33
ft_irc3/src/main.cpp
Normal file
33
ft_irc3/src/main.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* main.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/05/15 12:16:41 by fgras-ca #+# #+# */
|
||||
/* Updated: 2024/05/15 12:49:07 by fgras-ca ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "Server.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 3)
|
||||
{
|
||||
std::cerr << RED << "Usage: " << argv[0] << " <port> <password>" << RESET << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int port = std::atoi(argv[1]);
|
||||
std::string password = argv[2];
|
||||
|
||||
Server server(port, password);
|
||||
server.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
0
ft_irc3/target
Normal file
0
ft_irc3/target
Normal file
Reference in New Issue
Block a user