Initial commit of XnoIRCd codebase
This commit is contained in:
commit
033456e949
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*.o
|
||||||
|
xnoircd
|
28
Makefile
Normal file
28
Makefile
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
FLAGS = -pthread
|
||||||
|
|
||||||
|
xnoircd: user.o nameable.o channel.o connection.o ircserver.o irccommand.o userconnection.o main.o
|
||||||
|
g++ $(FLAGS) user.o nameable.o channel.o connection.o ircserver.o irccommand.o userconnection.o main.o -o $@
|
||||||
|
|
||||||
|
user.o: user.cpp user.h
|
||||||
|
g++ -g -c $*.cpp
|
||||||
|
|
||||||
|
connection.o: connection.cpp connection.h
|
||||||
|
g++ -g -c $*.cpp
|
||||||
|
|
||||||
|
ircserver.o: ircserver.cpp ircserver.h
|
||||||
|
g++ -g -c $*.cpp
|
||||||
|
|
||||||
|
irccommand.o: irccommand.cpp irccommand.h
|
||||||
|
g++ -g -c $*.cpp
|
||||||
|
|
||||||
|
userconnection.o: userconnection.cpp userconnection.h
|
||||||
|
g++ -g -c $*.cpp
|
||||||
|
|
||||||
|
nameable.o: nameable.cpp nameable.h
|
||||||
|
g++ -g -c $*.cpp
|
||||||
|
|
||||||
|
channel.o: channel.cpp channel.h
|
||||||
|
g++ -g -c $*.cpp
|
||||||
|
|
||||||
|
main.o: main.cpp
|
||||||
|
g++ -g -c $*.cpp
|
28
channel.cpp
Normal file
28
channel.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include "channel.h"
|
||||||
|
|
||||||
|
Channel::Channel(IRCServer* server, std::string channel_name): Nameable(server) {
|
||||||
|
this->channel_name = channel_name;
|
||||||
|
server->register_addressable_name(channel_name, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Channel::~Channel() {
|
||||||
|
remove_addressable_name(channel_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Channel::send_direct(std::string message) {
|
||||||
|
send_relay(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Channel::get_topic() {
|
||||||
|
return topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Channel::set_topic(std::string topic) {
|
||||||
|
this->topic = topic;
|
||||||
|
}
|
||||||
|
bool Channel::has_topic() {
|
||||||
|
return (this->topic!="");
|
||||||
|
}
|
||||||
|
NameableType Channel::what_are_you() {
|
||||||
|
return NT_Channel;
|
||||||
|
}
|
26
channel.h
Normal file
26
channel.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef CHANNEL_H
|
||||||
|
#define CHANNEL_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "nameable.h"
|
||||||
|
#include "ircserver.h"
|
||||||
|
|
||||||
|
class Channel: public Nameable {
|
||||||
|
private:
|
||||||
|
std::string channel_name;
|
||||||
|
std::string topic;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Channel(IRCServer* server, std::string channel_name);
|
||||||
|
~Channel();
|
||||||
|
|
||||||
|
void send_direct(std::string message);
|
||||||
|
|
||||||
|
std::string get_topic();
|
||||||
|
bool has_topic();
|
||||||
|
void set_topic(std::string topic);
|
||||||
|
|
||||||
|
NameableType what_are_you();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
42
connection.cpp
Normal file
42
connection.cpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#include "connection.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
Connection::Connection(int fd) {
|
||||||
|
this->fd = fd;
|
||||||
|
std::thread(&Connection::conn_hdlr, this).detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection::~Connection() {
|
||||||
|
close(this->fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Connection::conn_hdlr() {
|
||||||
|
buffer = new char[512];
|
||||||
|
while (alive) {
|
||||||
|
if (read(this->fd, buffer, 511) == 0) {
|
||||||
|
destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::string message(buffer);
|
||||||
|
int index;
|
||||||
|
if ((index = message.find_first_of("\r\n")) == std::string::npos)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
message = message.substr(0, index);
|
||||||
|
process_cmd(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Connection::process_cmd(std::string command) {}
|
||||||
|
void Connection::destroy() {}
|
||||||
|
|
||||||
|
void Connection::kill() {
|
||||||
|
this->alive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Connection::send(std::string to_write) {
|
||||||
|
to_write = to_write + "\r\n";
|
||||||
|
const char* buffer = to_write.c_str();
|
||||||
|
int len = strlen(buffer);
|
||||||
|
write(this->fd, buffer, len);
|
||||||
|
}
|
29
connection.h
Normal file
29
connection.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef CONNECTION_H
|
||||||
|
#define CONNECTION_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
class Connection {
|
||||||
|
private:
|
||||||
|
int fd;
|
||||||
|
int alive = true;
|
||||||
|
char* buffer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Connection(int fd);
|
||||||
|
~Connection();
|
||||||
|
|
||||||
|
void conn_hdlr();
|
||||||
|
|
||||||
|
virtual void process_cmd(std::string command);
|
||||||
|
virtual void destroy();
|
||||||
|
|
||||||
|
void kill();
|
||||||
|
|
||||||
|
void send(std::string to_write);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
94
irccommand.cpp
Normal file
94
irccommand.cpp
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#include "irccommand.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
IRCCommand::IRCCommand(std::string raw_command) {
|
||||||
|
if (raw_command[0] == '@') {
|
||||||
|
int index = raw_command.find_first_of(" ");
|
||||||
|
|
||||||
|
std::string tag_section = raw_command.substr(1, index);
|
||||||
|
raw_command = raw_command.substr(index+1);
|
||||||
|
|
||||||
|
// Todo: Further process tags down
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raw_command[0] != 0)
|
||||||
|
raw_command.substr(1);
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (raw_command[0] == ':') {
|
||||||
|
int index = raw_command.find_first_of(" ");
|
||||||
|
source = raw_command.substr(1, index);
|
||||||
|
raw_command = raw_command.substr(index+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raw_command[0] != 0)
|
||||||
|
raw_command.substr(1);
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
int index = raw_command.find_first_of(" ");
|
||||||
|
command = raw_command.substr(0, index);
|
||||||
|
raw_command = raw_command.substr(index+1);
|
||||||
|
|
||||||
|
if (raw_command[0] != 0)
|
||||||
|
raw_command.substr(1);
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::vector<std::string> payloads;
|
||||||
|
index = raw_command.find_first_of(" ");
|
||||||
|
|
||||||
|
while (index != std::string::npos && raw_command[0] != ':') {
|
||||||
|
payloads.push_back(raw_command.substr(0, index));
|
||||||
|
raw_command = raw_command.substr(index + 1);
|
||||||
|
index = raw_command.find_first_of(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raw_command[0] == ':')
|
||||||
|
payloads.push_back(raw_command.substr(1));
|
||||||
|
else
|
||||||
|
payloads.push_back(raw_command);
|
||||||
|
|
||||||
|
this->payload = payloads;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IRCCommand::has_source() {
|
||||||
|
return (source!="");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string IRCCommand::get_source() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IRCCommand::has_command() {
|
||||||
|
return (command!="");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string IRCCommand::get_command() {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IRCCommand::has_payload() {
|
||||||
|
return payload.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string IRCCommand::get_payload(int i) {
|
||||||
|
return payload.at(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IRCCommand::get_payload_count() {
|
||||||
|
return payload.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string IRCCommand::to_string() {
|
||||||
|
std::string myself;
|
||||||
|
if (has_source())
|
||||||
|
myself += "Source: " + get_source() + "\n";
|
||||||
|
if (has_command())
|
||||||
|
myself += "Command: " + get_command() + "\n";
|
||||||
|
for (std::string p : payload)
|
||||||
|
myself += "Parameters: " + p + "\n";
|
||||||
|
return myself;
|
||||||
|
}
|
33
irccommand.h
Normal file
33
irccommand.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#ifndef IRCCOMMAND_H
|
||||||
|
#define IRCCOMMAND_H
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class IRCCommand {
|
||||||
|
private:
|
||||||
|
std::unordered_map<std::string, std::string> tags;
|
||||||
|
std::string source, command = "";
|
||||||
|
std::vector<std::string> payload;
|
||||||
|
public:
|
||||||
|
IRCCommand(std::string raw_command);
|
||||||
|
|
||||||
|
bool has_source();
|
||||||
|
|
||||||
|
std::string get_source();
|
||||||
|
|
||||||
|
bool has_command();
|
||||||
|
|
||||||
|
std::string get_command();
|
||||||
|
|
||||||
|
bool has_payload();
|
||||||
|
|
||||||
|
std::string get_payload(int i);
|
||||||
|
|
||||||
|
int get_payload_count();
|
||||||
|
|
||||||
|
std::string to_string();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
30
ircserver.cpp
Normal file
30
ircserver.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include "ircserver.h"
|
||||||
|
|
||||||
|
IRCServer::IRCServer(std::string hostname) {
|
||||||
|
this->hostname = hostname;
|
||||||
|
this->nameable_map = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IRCServer::is_addressable_name_free(std::string name) {
|
||||||
|
return nameable_map.find(name) == nameable_map.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IRCServer::has_addressable_name(std::string name) {
|
||||||
|
return !is_addressable_name_free(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRCServer::remove_addressable_name(std::string name) {
|
||||||
|
nameable_map.erase(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRCServer::register_addressable_name(std::string name, Nameable* bind) {
|
||||||
|
nameable_map[name] = bind;
|
||||||
|
}
|
||||||
|
|
||||||
|
Nameable* IRCServer::resolve_addressable_name(std::string name) {
|
||||||
|
return nameable_map[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string IRCServer::get_hostname() {
|
||||||
|
return hostname;
|
||||||
|
}
|
24
ircserver.h
Normal file
24
ircserver.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef IRCSERVER_H
|
||||||
|
#define IRCSERVER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
class Nameable;
|
||||||
|
class IRCServer {
|
||||||
|
private:
|
||||||
|
std::unordered_map<std::string, Nameable*> nameable_map;
|
||||||
|
std::string hostname;
|
||||||
|
public:
|
||||||
|
|
||||||
|
IRCServer(std::string);
|
||||||
|
|
||||||
|
void register_addressable_name(std::string name, Nameable* bind);
|
||||||
|
bool is_addressable_name_free(std::string name);
|
||||||
|
bool has_addressable_name(std::string name);
|
||||||
|
void remove_addressable_name(std::string name);
|
||||||
|
Nameable* resolve_addressable_name(std::string name);
|
||||||
|
std::string get_hostname();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
42
main.cpp
Normal file
42
main.cpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "ircserver.h"
|
||||||
|
#include "userconnection.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int socketfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (socketfd == 0) {
|
||||||
|
std::cout << "Socket Create Failed!\n" << std::flush;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int opt = 1;
|
||||||
|
if (setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
|
||||||
|
std::cout << "Setting Socket Options Failed!\n" << std::flush;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
addr.sin_port = htons(6667);
|
||||||
|
|
||||||
|
unsigned int addrsize = sizeof(addr);
|
||||||
|
if (bind(socketfd, (struct sockaddr*)&addr, addrsize) < 0) {
|
||||||
|
std::cout << "Socket Bind Failed!\n" << std::flush;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(socketfd, 5) < 0) {
|
||||||
|
std::cout << "Socket Listen Failed!\n" << std::flush;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
IRCServer* server = new IRCServer("xnoircd");
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
int sockfd = accept(socketfd, (struct sockaddr*)&addr, &addrsize);
|
||||||
|
new UserConnection(sockfd, server);
|
||||||
|
}
|
||||||
|
}
|
71
nameable.cpp
Normal file
71
nameable.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include "nameable.h"
|
||||||
|
|
||||||
|
Nameable::Nameable(IRCServer* server) {
|
||||||
|
this->server = server;
|
||||||
|
}
|
||||||
|
Nameable::~Nameable() {
|
||||||
|
this->associates.clear();
|
||||||
|
this->associates.shrink_to_fit();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Nameable::get_addressable_name() {
|
||||||
|
return this->addressable_name;
|
||||||
|
}
|
||||||
|
bool Nameable::set_addressable_name(std::string name) {
|
||||||
|
if (this->server->is_addressable_name_free(name)) {
|
||||||
|
this->addressable_name = name;
|
||||||
|
server->register_addressable_name(name, this);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool Nameable::has_addressable_name() {
|
||||||
|
return (this->addressable_name!="");
|
||||||
|
}
|
||||||
|
void Nameable::remove_addressable_name(std::string name) {
|
||||||
|
server->remove_addressable_name(name);
|
||||||
|
}
|
||||||
|
bool Nameable::rename(std::string name) {
|
||||||
|
if (server->is_addressable_name_free(name)) {
|
||||||
|
server->remove_addressable_name(name);
|
||||||
|
server->register_addressable_name(name, this);
|
||||||
|
this->addressable_name = name;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Nameable*> Nameable::get_associates() {
|
||||||
|
return this->associates;
|
||||||
|
}
|
||||||
|
void Nameable::add_associate(Nameable* associate) {
|
||||||
|
std::cout << "Adding: " << associate->get_addressable_name() << "\n";
|
||||||
|
this->associates.push_back(associate);
|
||||||
|
}
|
||||||
|
bool Nameable::has_associate(Nameable* associate) {
|
||||||
|
return !(std::find(associates.begin(), associates.end(), associate) == associates.end());
|
||||||
|
}
|
||||||
|
void Nameable::remove_associate(Nameable* associate) {
|
||||||
|
auto index = std::find(this->associates.begin(), this->associates.end(), associate);
|
||||||
|
if (index != this->associates.end()) {
|
||||||
|
this->associates.erase(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::string Nameable::associates_as_string() {
|
||||||
|
std::string associate_list;
|
||||||
|
for (Nameable* associate : associates) {
|
||||||
|
associate_list += associate->get_addressable_name() + " ";
|
||||||
|
}
|
||||||
|
return associate_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Nameable::send_direct(std::string message) {}
|
||||||
|
void Nameable::send_relay(std::string message) {
|
||||||
|
for (Nameable* associate : this->associates) {
|
||||||
|
associate->send_direct(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NameableType Nameable::what_are_you() {}
|
44
nameable.h
Normal file
44
nameable.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#ifndef NAMEABLE_H
|
||||||
|
#define NAMEABLE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include "connection.h"
|
||||||
|
#include "ircserver.h"
|
||||||
|
|
||||||
|
enum NameableType {
|
||||||
|
NT_User,
|
||||||
|
NT_Channel
|
||||||
|
};
|
||||||
|
|
||||||
|
class Nameable {
|
||||||
|
private:
|
||||||
|
std::string addressable_name = "";
|
||||||
|
std::vector<Nameable*> associates;
|
||||||
|
|
||||||
|
public:
|
||||||
|
IRCServer* server;
|
||||||
|
Nameable(IRCServer* server);
|
||||||
|
~Nameable();
|
||||||
|
|
||||||
|
std::string get_addressable_name();
|
||||||
|
bool set_addressable_name(std::string name);
|
||||||
|
bool has_addressable_name();
|
||||||
|
void remove_addressable_name(std::string name);
|
||||||
|
bool rename(std::string to);
|
||||||
|
|
||||||
|
std::vector<Nameable*> get_associates();
|
||||||
|
void add_associate(Nameable* associate);
|
||||||
|
bool has_associate(Nameable* associate);
|
||||||
|
void remove_associate(Nameable* associate);
|
||||||
|
std::string associates_as_string();
|
||||||
|
|
||||||
|
virtual void send_direct(std::string message);
|
||||||
|
void send_relay(std::string message);
|
||||||
|
|
||||||
|
virtual NameableType what_are_you();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
233
user.cpp
Normal file
233
user.cpp
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
#include "user.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
std::vector<std::string> split_string(std::string str, std::string delim) {
|
||||||
|
std::vector<std::string> to_return;
|
||||||
|
int delim_len = delim.length();
|
||||||
|
int index = str.find_first_of(delim);
|
||||||
|
while (index != std::string::npos) {
|
||||||
|
to_return.push_back(str.substr(0, index));
|
||||||
|
str = str.substr(index+delim_len);
|
||||||
|
index = str.find_first_of(delim);
|
||||||
|
}
|
||||||
|
to_return.push_back(str);
|
||||||
|
return to_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::tuple<int, std::function<void(User*, IRCCommand*)>>> User::commands = {
|
||||||
|
{"NICK", {0, &User::nick_cmd}},
|
||||||
|
{"PING", {1, &User::ping_cmd}},
|
||||||
|
{"WHO", {1, &User::who_cmd}},
|
||||||
|
{"WHOIS", {1, &User::whois_cmd}},
|
||||||
|
{"JOIN", {1, &User::join_cmd}},
|
||||||
|
{"PART", {1, &User::part_cmd}},
|
||||||
|
{"QUIT", {0, &User::quit_cmd}},
|
||||||
|
{"PRIVMSG", {2, &User::privmsg_cmd}},
|
||||||
|
{"TOPIC", {2, &User::topic_cmd}},
|
||||||
|
{"NAMES", {1, &User::names_cmd}}
|
||||||
|
};
|
||||||
|
|
||||||
|
User::User(IRCServer* server, UserConnection* conn): Nameable(server) {
|
||||||
|
this->connection = conn;
|
||||||
|
}
|
||||||
|
User::~User() {
|
||||||
|
this->server->remove_addressable_name(this->get_nick());
|
||||||
|
this->send_relay(":" + this->get_nick() + " QUIT :Quit: ");
|
||||||
|
for (Nameable* associate : this->get_associates())
|
||||||
|
associate->remove_associate(this);
|
||||||
|
delete connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::nick_cmd(IRCCommand* cmd) {
|
||||||
|
set_nick(cmd->get_payload(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::ping_cmd(IRCCommand* cmd) {
|
||||||
|
send_direct(":" + server->get_hostname() + " PONG " + server->get_hostname() + " " + cmd->get_payload(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::join_cmd(IRCCommand* cmd) {
|
||||||
|
std::string channels_parameter = cmd->get_payload(0);
|
||||||
|
|
||||||
|
std::vector<std::string> named_channels = split_string(channels_parameter, ",");
|
||||||
|
std::cout << named_channels.size() << "\n";
|
||||||
|
|
||||||
|
for (std::string named_channel : named_channels) {
|
||||||
|
Nameable* channel;
|
||||||
|
if (server->has_addressable_name(named_channel)) {
|
||||||
|
channel = server->resolve_addressable_name(named_channel);
|
||||||
|
} else {
|
||||||
|
channel = new Channel(server, named_channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel->what_are_you() != NT_Channel)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Channel* chan = (Channel*)channel;
|
||||||
|
|
||||||
|
this->add_associate(chan);
|
||||||
|
chan->add_associate(this);
|
||||||
|
chan->send_direct(":" + this->get_nick() + " JOIN " + named_channel);
|
||||||
|
std::vector<Nameable*> channel_members = chan->get_associates();
|
||||||
|
|
||||||
|
this->send_direct(":" + server->get_hostname() + " 353 " + this->get_nick() + " " + named_channel + " :" + chan->associates_as_string());
|
||||||
|
if (chan->has_topic())
|
||||||
|
this->send_direct(":" + server->get_hostname() + " 332 " + this->get_nick() + " " + named_channel + " :" + chan->get_topic());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::part_cmd(IRCCommand* cmd) {
|
||||||
|
std::string channels_parameter = cmd->get_payload(0);
|
||||||
|
|
||||||
|
std::vector<std::string> named_channels = split_string(channels_parameter, ",");
|
||||||
|
|
||||||
|
for (std::string named_channel : named_channels) {
|
||||||
|
if (server->has_addressable_name(named_channel)) {
|
||||||
|
Nameable* channel = server->resolve_addressable_name(named_channel);
|
||||||
|
this->remove_associate(channel);
|
||||||
|
channel->remove_associate(this);
|
||||||
|
channel->send_direct(":" + this->get_nick() + " PART " + named_channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::privmsg_cmd(IRCCommand* cmd) {
|
||||||
|
std::string named_target = cmd->get_payload(0);
|
||||||
|
|
||||||
|
if (server->has_addressable_name(named_target)) {
|
||||||
|
Nameable* target = server->resolve_addressable_name(named_target);
|
||||||
|
for (Nameable* associate : target->get_associates()) {
|
||||||
|
if (associate->get_addressable_name() != this->get_nick())
|
||||||
|
associate->send_direct(":" + this->get_nick() + " PRIVMSG " + named_target + " :" + cmd->get_payload(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::quit_cmd(IRCCommand* cmd) {
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::who_cmd(IRCCommand* cmd) {
|
||||||
|
if (!server->has_addressable_name(cmd->get_payload(0)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Nameable* target = server->resolve_addressable_name(cmd->get_payload(0));
|
||||||
|
if (target->what_are_you() != NT_User)
|
||||||
|
return;
|
||||||
|
|
||||||
|
User* user = (User*)target;
|
||||||
|
|
||||||
|
send_direct(":" + server->get_hostname() + " 352 " + this->get_nick() + " * " + user->get_username() + " " /*+ user->get_hostname()*/ + " " + server->get_hostname() + " H :0 " + user->get_realname());
|
||||||
|
send_direct(":" + server->get_hostname() + " 315 " + this->get_nick() + " " + user->get_nick() + " :End of WHO listing.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::whois_cmd(IRCCommand* cmd) {
|
||||||
|
if (!server->has_addressable_name(cmd->get_payload(0)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Nameable* target = server->resolve_addressable_name(cmd->get_payload(0));
|
||||||
|
if (target->what_are_you() != NT_User)
|
||||||
|
return;
|
||||||
|
|
||||||
|
User* user = (User*)target;
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::topic_cmd(IRCCommand* cmd) {
|
||||||
|
if (!server->has_addressable_name(cmd->get_payload(0)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Nameable* target = server->resolve_addressable_name(cmd->get_payload(0));
|
||||||
|
if (target->what_are_you() != NT_Channel)
|
||||||
|
return;
|
||||||
|
|
||||||
|
((Channel*)target)->set_topic(cmd->get_payload(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::names_cmd(IRCCommand* cmd) {
|
||||||
|
std::string named_channel = cmd->get_payload(0);
|
||||||
|
if (!server->has_addressable_name(named_channel))
|
||||||
|
return;
|
||||||
|
Nameable* resolved = server->resolve_addressable_name(named_channel);
|
||||||
|
if (resolved->what_are_you() != NT_Channel)
|
||||||
|
return;
|
||||||
|
Channel* chan = (Channel*)resolved;
|
||||||
|
this->send_direct(":" + server->get_hostname() + " 353 " + this->get_nick() + " " + named_channel + " :" + chan->associates_as_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::process_cmd(IRCCommand* cmd) {
|
||||||
|
auto command = commands.find(cmd->get_command());
|
||||||
|
if (command == commands.end()) {
|
||||||
|
send_direct(":" + server->get_hostname() + " 421 " + get_nick() + " " + cmd->get_command() + " :Unknown Command.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd->get_payload_count() < std::get<0>(command->second)) {
|
||||||
|
send_direct(":" + server->get_hostname() + " 461 " + get_nick() + " " + cmd->get_command() + " :Too few parameters.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::get<1>(command->second)(this, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::set_nick(std::string nick) {
|
||||||
|
bool success;
|
||||||
|
std::string old_nick = this->get_nick();
|
||||||
|
if (this->has_nick())
|
||||||
|
success = this->rename(nick);
|
||||||
|
else
|
||||||
|
success = this->set_addressable_name(nick);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
if (old_nick != "")
|
||||||
|
send_direct(":" + old_nick + " NICK :" + this->get_nick());
|
||||||
|
} else {
|
||||||
|
send_direct(":" + server->get_hostname() + " 433 * " + nick + " Nickname is already in use!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::set_username(std::string username) {
|
||||||
|
this->username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::set_realname(std::string realname) {
|
||||||
|
this->realname = realname;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool User::has_nick() {
|
||||||
|
return has_addressable_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool User::has_username(){
|
||||||
|
return (username!="");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool User::has_realname(){
|
||||||
|
return (realname!="");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string User::get_nick(){
|
||||||
|
return get_addressable_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string User::get_username(){
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string User::get_realname(){
|
||||||
|
return realname;
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::send_direct(std::string message) {
|
||||||
|
std::cout << message << "\n";
|
||||||
|
this->connection->send(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
NameableType User::what_are_you() {
|
||||||
|
return NT_User;
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::destroy() {
|
||||||
|
Connection* conn = connection;
|
||||||
|
delete this;
|
||||||
|
conn->kill();
|
||||||
|
}
|
69
user.h
Normal file
69
user.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#ifndef USER_H
|
||||||
|
#define USER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <tuple>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "irccommand.h"
|
||||||
|
#include "ircserver.h"
|
||||||
|
#include "userconnection.h"
|
||||||
|
#include "nameable.h"
|
||||||
|
#include "channel.h"
|
||||||
|
|
||||||
|
class UserConnection;
|
||||||
|
class User: public Nameable {
|
||||||
|
private:
|
||||||
|
std::string username, realname = "";
|
||||||
|
Connection* connection;
|
||||||
|
|
||||||
|
void nick_cmd(IRCCommand* cmd);
|
||||||
|
void ping_cmd(IRCCommand* cmd);
|
||||||
|
void who_cmd(IRCCommand* cmd);
|
||||||
|
void whois_cmd(IRCCommand* cmd);
|
||||||
|
void join_cmd(IRCCommand* cmd);
|
||||||
|
void part_cmd(IRCCommand* cmd);
|
||||||
|
void quit_cmd(IRCCommand* cmd);
|
||||||
|
void privmsg_cmd(IRCCommand* cmd);
|
||||||
|
void topic_cmd(IRCCommand* cmd);
|
||||||
|
void names_cmd(IRCCommand* cmd);
|
||||||
|
|
||||||
|
static std::unordered_map<std::string, std::tuple<int, std::function<void(User*, IRCCommand*)>>> commands;
|
||||||
|
|
||||||
|
//std::string construct_string(int count, std::string source, std::string command, std::string parameters...);
|
||||||
|
template<typename... T>
|
||||||
|
std::string construct_string(std::string source, std::string command, T... parameters);
|
||||||
|
|
||||||
|
public:
|
||||||
|
User(IRCServer* server, UserConnection* conn);
|
||||||
|
~User();
|
||||||
|
|
||||||
|
void process_cmd(IRCCommand* cmd);
|
||||||
|
|
||||||
|
void set_nick(std::string nick);
|
||||||
|
|
||||||
|
void set_username(std::string username);
|
||||||
|
|
||||||
|
void set_realname(std::string realname);
|
||||||
|
|
||||||
|
bool has_nick();
|
||||||
|
|
||||||
|
bool has_username();
|
||||||
|
|
||||||
|
bool has_realname();
|
||||||
|
|
||||||
|
std::string get_nick();
|
||||||
|
|
||||||
|
std::string get_username();
|
||||||
|
|
||||||
|
std::string get_realname();
|
||||||
|
|
||||||
|
void send_direct(std::string message);
|
||||||
|
|
||||||
|
NameableType what_are_you();
|
||||||
|
|
||||||
|
void destroy();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
50
userconnection.cpp
Normal file
50
userconnection.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include "userconnection.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
UserConnection::UserConnection(int fd, IRCServer* server): Connection(fd) {
|
||||||
|
this->server = server;
|
||||||
|
this->user = new User(server, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserConnection::~UserConnection() {}
|
||||||
|
|
||||||
|
void UserConnection::process_cmd(std::string cmd_in) {
|
||||||
|
if (cmd_in == "")
|
||||||
|
return;
|
||||||
|
|
||||||
|
IRCCommand* cmd = new IRCCommand(cmd_in);
|
||||||
|
std::cout << cmd_in << std::endl;
|
||||||
|
|
||||||
|
if (state == Registered) {
|
||||||
|
user->process_cmd(cmd);
|
||||||
|
delete cmd;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string command = cmd->get_command();
|
||||||
|
|
||||||
|
if (command == "NICK" && cmd->has_payload()) {
|
||||||
|
user->set_nick(cmd->get_payload(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command == "USER" && cmd->has_payload()) {
|
||||||
|
user->set_username(cmd->get_payload(0));
|
||||||
|
user->set_realname(cmd->get_payload(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user->has_nick() && user->has_username()) {
|
||||||
|
state = Registered;
|
||||||
|
send(":xnoircd 001 " + user->get_nick() + " :Welcome");
|
||||||
|
send(":xnoircd 002 " + user->get_nick() + " :Welcome");
|
||||||
|
send(":xnoircd 003 " + user->get_nick() + " :Welcome");
|
||||||
|
send(":xnoircd 004 " + user->get_nick() + " xnoircd 0 ABCabc ABCabc");
|
||||||
|
send(":xnoircd 422 " + user->get_nick() + " :No MOTD");
|
||||||
|
}
|
||||||
|
|
||||||
|
delete cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserConnection::destroy() {
|
||||||
|
this->user->destroy();
|
||||||
|
}
|
29
userconnection.h
Normal file
29
userconnection.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef USERCONNECTION_H
|
||||||
|
#define USERCONNECTION_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "connection.h"
|
||||||
|
#include "ircserver.h"
|
||||||
|
#include "user.h"
|
||||||
|
|
||||||
|
enum UCState {
|
||||||
|
Initial,
|
||||||
|
Registered
|
||||||
|
};
|
||||||
|
|
||||||
|
class User;
|
||||||
|
class UserConnection: public Connection {
|
||||||
|
private:
|
||||||
|
User* user;
|
||||||
|
UCState state = Initial;
|
||||||
|
IRCServer* server;
|
||||||
|
public:
|
||||||
|
UserConnection(int fd, IRCServer* server);
|
||||||
|
~UserConnection();
|
||||||
|
|
||||||
|
void process_cmd(std::string cmd_in);
|
||||||
|
void destroy();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user