diff --git a/channel.cpp b/channel.cpp index f373983..6a9a5f4 100644 --- a/channel.cpp +++ b/channel.cpp @@ -9,8 +9,8 @@ Channel::~Channel() { remove_addressable_name(channel_name); } -void Channel::send_direct(std::string message) { - send_relay(message); +void Channel::send_direct(std::vector messages) { + send_relay(messages); } std::string Channel::get_topic() { diff --git a/channel.h b/channel.h index 7e8a092..3a3d3e0 100644 --- a/channel.h +++ b/channel.h @@ -14,13 +14,13 @@ public: Channel(IRCServer* server, std::string channel_name); ~Channel(); - void send_direct(std::string message); + void send_direct(std::vector messages); std::string get_topic(); bool has_topic(); void set_topic(std::string topic); - NameableType what_are_you(); + NameableType what_are_you() override; }; #endif \ No newline at end of file diff --git a/connection.cpp b/connection.cpp index 80f7a65..505a509 100644 --- a/connection.cpp +++ b/connection.cpp @@ -35,6 +35,8 @@ void Connection::kill() { } void Connection::send(std::string to_write) { + if (to_write == "") + return; to_write = to_write + "\r\n"; const char* buffer = to_write.c_str(); int len = strlen(buffer); diff --git a/irccommand.cpp b/irccommand.cpp index 130765b..f0b0dd3 100644 --- a/irccommand.cpp +++ b/irccommand.cpp @@ -2,6 +2,7 @@ #include +IRCCommand::IRCCommand() {} IRCCommand::IRCCommand(std::string raw_command) { if (raw_command[0] == '@') { int index = raw_command.find_first_of(" "); @@ -30,28 +31,43 @@ IRCCommand::IRCCommand(std::string raw_command) { int index = raw_command.find_first_of(" "); command = raw_command.substr(0, index); + if (index == std::string::npos) + return; raw_command = raw_command.substr(index+1); if (raw_command[0] != 0) raw_command.substr(1); else return; - - std::vector payloads; index = raw_command.find_first_of(" "); while (index != std::string::npos && raw_command[0] != ':') { - payloads.push_back(raw_command.substr(0, index)); + this->parameters.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)); + this->parameters.push_back(raw_command.substr(1)); else - payloads.push_back(raw_command); - - this->payload = payloads; + this->parameters.push_back(raw_command); +} +IRCCommand::IRCCommand(std::string source, std::string command) { + this->source = source; + this->command = command; +} +/* +template +IRCCommand::IRCCommand(std::string source, std::string command, T... params) { + this->source = source; + this->command = command; + this->parameters = {params...}; +} +*/ + +IRCCommand::~IRCCommand() { + this->parameters.clear(); + this->parameters.shrink_to_fit(); } bool IRCCommand::has_source() { @@ -70,25 +86,27 @@ std::string IRCCommand::get_command() { return command; } -bool IRCCommand::has_payload() { - return payload.size() > 0; +bool IRCCommand::has_parameter() { + return parameters.size() > 0; } -std::string IRCCommand::get_payload(int i) { - return payload.at(i); +std::string IRCCommand::get_parameter(int i) { + return parameters.at(i); } -int IRCCommand::get_payload_count() { - return payload.size(); +int IRCCommand::get_parameter_count() { + return parameters.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"; + myself += ":" + get_source() + " "; + + myself += get_command(); + + for (auto i=parameters.begin(); i != parameters.end(); i++) + myself += ((i==parameters.end()-1)&&(i->find(" ")!=std::string::npos)?" :":" ") + *i; + return myself; } \ No newline at end of file diff --git a/irccommand.h b/irccommand.h index 7b98d8b..2358bc5 100644 --- a/irccommand.h +++ b/irccommand.h @@ -9,9 +9,19 @@ class IRCCommand { private: std::unordered_map tags; std::string source, command = ""; - std::vector payload; + std::vector parameters; public: + IRCCommand(); IRCCommand(std::string raw_command); + IRCCommand(std::string source, std::string command); + template + IRCCommand(std::string source, std::string command, T... params) { + this->source = source; + this->command = command; + this->parameters = {params...}; + } + + ~IRCCommand(); bool has_source(); @@ -21,11 +31,11 @@ public: std::string get_command(); - bool has_payload(); + bool has_parameter(); - std::string get_payload(int i); + std::string get_parameter(int i); - int get_payload_count(); + int get_parameter_count(); std::string to_string(); }; diff --git a/nameable.cpp b/nameable.cpp index 84692ae..5930ce2 100644 --- a/nameable.cpp +++ b/nameable.cpp @@ -61,11 +61,11 @@ std::string Nameable::associates_as_string() { return associate_list; } -void Nameable::send_direct(std::string message) {} -void Nameable::send_relay(std::string message) { +void Nameable::send_direct(std::vector messages) {} +void Nameable::send_relay(std::vector messages) { for (Nameable* associate : this->associates) { - associate->send_direct(message); + associate->send_direct(messages); } } -NameableType Nameable::what_are_you() {} \ No newline at end of file +NameableType Nameable::what_are_you() {return NT_None;} \ No newline at end of file diff --git a/nameable.h b/nameable.h index d01240b..3c7107e 100644 --- a/nameable.h +++ b/nameable.h @@ -7,10 +7,12 @@ #include #include "connection.h" #include "ircserver.h" +#include "irccommand.h" enum NameableType { - NT_User, - NT_Channel + NT_None = 1, + NT_User = 2, + NT_Channel = 3 }; class Nameable { @@ -35,8 +37,8 @@ public: void remove_associate(Nameable* associate); std::string associates_as_string(); - virtual void send_direct(std::string message); - void send_relay(std::string message); + virtual void send_direct(std::vector messages); + void send_relay(std::vector messages); virtual NameableType what_are_you(); }; diff --git a/user.cpp b/user.cpp index 173ab5c..b5879ce 100644 --- a/user.cpp +++ b/user.cpp @@ -14,17 +14,19 @@ std::vector split_string(std::string str, std::string delim) { return to_return; } -std::unordered_map>> 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}} +std::unordered_map(User*, IRCCommand)>, bool>> User::commands = { + {"NICK", {1, &User::nick_cmd, false}}, + {"USER", {4, &User::user_cmd, false}}, + {"PING", {1, &User::ping_cmd, false}}, + {"WHO", {1, &User::who_cmd, true}}, + {"WHOIS", {1, &User::whois_cmd, true}}, + {"JOIN", {1, &User::join_cmd, true}}, + {"PART", {1, &User::part_cmd, true}}, + {"QUIT", {0, &User::quit_cmd, true}}, + {"PRIVMSG", {2, &User::privmsg_cmd, true}}, + {"TOPIC", {2, &User::topic_cmd, true}}, + {"NAMES", {1, &User::names_cmd, true}}, + {"MOTD", {0, &User::motd_cmd, true}} }; User::User(IRCServer* server, UserConnection* conn): Nameable(server) { @@ -32,26 +34,45 @@ User::User(IRCServer* server, UserConnection* conn): Nameable(server) { } User::~User() { this->server->remove_addressable_name(this->get_nick()); - this->send_relay(":" + this->get_nick() + " QUIT :Quit: "); + this->send_relay({IRCCommand(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)); +std::vector User::nick_cmd(IRCCommand cmd) { + return {set_nick(cmd.get_parameter(0))}; } -void User::ping_cmd(IRCCommand* cmd) { - send_direct(":" + server->get_hostname() + " PONG " + server->get_hostname() + " " + cmd->get_payload(0)); +std::vector User::user_cmd(IRCCommand cmd) { + this->username = cmd.get_parameter(0); + this->realname = cmd.get_parameter(3); + + if (this->has_nick()) { + this->state = Registered; + } + + return { + IRCCommand(server->get_hostname(), "001", this->get_nick(), "Welcome to the Polyglottal Network, " + this->get_nick()), + IRCCommand(server->get_hostname(), "002", this->get_nick(), "Your host is " + server->get_hostname()), + IRCCommand(server->get_hostname(), "003", this->get_nick(), "This server was never created."), + IRCCommand(server->get_hostname(), "004", this->get_nick(), server->get_hostname(), "0", "ABCabc", "ABCabc"), + motd_cmd(IRCCommand())[0] + }; } -void User::join_cmd(IRCCommand* cmd) { - std::string channels_parameter = cmd->get_payload(0); +std::vector User::ping_cmd(IRCCommand cmd) { + return {IRCCommand(server->get_hostname(), "PONG", server->get_hostname(), cmd.get_parameter(0))}; +} + +std::vector User::join_cmd(IRCCommand cmd) { + std::string channels_parameter = cmd.get_parameter(0); std::vector named_channels = split_string(channels_parameter, ","); std::cout << named_channels.size() << "\n"; + std::vector to_return; + for (std::string named_channel : named_channels) { Nameable* channel; if (server->has_addressable_name(named_channel)) { @@ -59,7 +80,7 @@ void User::join_cmd(IRCCommand* cmd) { } else { channel = new Channel(server, named_channel); } - + if (channel->what_are_you() != NT_Channel) continue; @@ -67,17 +88,19 @@ void User::join_cmd(IRCCommand* cmd) { this->add_associate(chan); chan->add_associate(this); - chan->send_direct(":" + this->get_nick() + " JOIN " + named_channel); + chan->send_direct({IRCCommand(this->get_nick(), "JOIN", named_channel)}); std::vector channel_members = chan->get_associates(); - this->send_direct(":" + server->get_hostname() + " 353 " + this->get_nick() + " " + named_channel + " :" + chan->associates_as_string()); + to_return.push_back(IRCCommand(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()); + to_return.push_back(IRCCommand(server->get_hostname(), "332", this->get_nick(), named_channel, chan->get_topic())); } + + return to_return; } -void User::part_cmd(IRCCommand* cmd) { - std::string channels_parameter = cmd->get_payload(0); +std::vector User::part_cmd(IRCCommand cmd) { + std::string channels_parameter = cmd.get_parameter(0); std::vector named_channels = split_string(channels_parameter, ","); @@ -86,90 +109,105 @@ void User::part_cmd(IRCCommand* cmd) { 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); + channel->send_direct({IRCCommand(this->get_nick(), "PART", named_channel)}); } } + + return {}; } -void User::privmsg_cmd(IRCCommand* cmd) { - std::string named_target = cmd->get_payload(0); +std::vector User::privmsg_cmd(IRCCommand cmd) { + std::string named_target = cmd.get_parameter(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)); + associate->send_direct({IRCCommand(this->get_nick(), "PRIVMSG", named_target, cmd.get_parameter(1))}); } } + + return {}; } -void User::quit_cmd(IRCCommand* cmd) { +std::vector User::quit_cmd(IRCCommand cmd) { destroy(); + return {}; } -void User::who_cmd(IRCCommand* cmd) { - if (!server->has_addressable_name(cmd->get_payload(0))) - return; +std::vector User::who_cmd(IRCCommand cmd) { + if (!server->has_addressable_name(cmd.get_parameter(0))) + return {}; - Nameable* target = server->resolve_addressable_name(cmd->get_payload(0)); + Nameable* target = server->resolve_addressable_name(cmd.get_parameter(0)); if (target->what_are_you() != NT_User) - return; + 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."); + return { + IRCCommand(server->get_hostname(), "352", this->get_nick(), "*", user->get_username(), " ", server->get_hostname(), "H", "0 " + user->get_realname()), + IRCCommand(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; +std::vector User::whois_cmd(IRCCommand cmd) { + if (!server->has_addressable_name(cmd.get_parameter(0))) + return {}; - Nameable* target = server->resolve_addressable_name(cmd->get_payload(0)); + Nameable* target = server->resolve_addressable_name(cmd.get_parameter(0)); if (target->what_are_you() != NT_User) - return; + return {}; User* user = (User*)target; + return {}; } -void User::topic_cmd(IRCCommand* cmd) { - if (!server->has_addressable_name(cmd->get_payload(0))) - return; +std::vector User::topic_cmd(IRCCommand cmd) { + if (!server->has_addressable_name(cmd.get_parameter(0))) + return {}; - Nameable* target = server->resolve_addressable_name(cmd->get_payload(0)); + Nameable* target = server->resolve_addressable_name(cmd.get_parameter(0)); if (target->what_are_you() != NT_Channel) - return; + return {}; - ((Channel*)target)->set_topic(cmd->get_payload(1)); + ((Channel*)target)->set_topic(cmd.get_parameter(1)); + return {}; } -void User::names_cmd(IRCCommand* cmd) { - std::string named_channel = cmd->get_payload(0); +std::vector User::names_cmd(IRCCommand cmd) { + std::string named_channel = cmd.get_parameter(0); if (!server->has_addressable_name(named_channel)) - return; + return {}; Nameable* resolved = server->resolve_addressable_name(named_channel); if (resolved->what_are_you() != NT_Channel) - return; + return {}; Channel* chan = (Channel*)resolved; - this->send_direct(":" + server->get_hostname() + " 353 " + this->get_nick() + " " + named_channel + " :" + chan->associates_as_string()); + return {IRCCommand(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()); +std::vector User::motd_cmd(IRCCommand cmd) { + return {IRCCommand(server->get_hostname(), "422", this->get_nick(), "MOTD is not defined.")}; +} + +std::vector User::process_cmd(IRCCommand cmd) { + auto command = commands.find(cmd.get_command()); + //return {}; if (command == commands.end()) { - send_direct(":" + server->get_hostname() + " 421 " + get_nick() + " " + cmd->get_command() + " :Unknown Command."); - return; + return {IRCCommand(server->get_hostname(), "421", get_nick(), cmd.get_command(), "Unknown Command.")}; } - 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; + if (cmd.get_parameter_count() < std::get<0>(command->second)) { + return {IRCCommand(server->get_hostname(), "461", get_nick(), cmd.get_command(), "Too few parameters.")}; } + + if (this->state == Initial && std::get<2>(command->second)) + return {}; - std::get<1>(command->second)(this, cmd); + return std::get<1>(command->second)(this, cmd); } -void User::set_nick(std::string nick) { +IRCCommand User::set_nick(std::string nick) { bool success; std::string old_nick = this->get_nick(); if (this->has_nick()) @@ -178,10 +216,12 @@ void User::set_nick(std::string nick) { success = this->set_addressable_name(nick); if (success) { - if (old_nick != "") - send_direct(":" + old_nick + " NICK :" + this->get_nick()); + if (old_nick != "") { + return IRCCommand(old_nick, "NICK", this->get_nick()); + } + return {}; } else { - send_direct(":" + server->get_hostname() + " 433 * " + nick + " Nickname is already in use!"); + return IRCCommand(server->get_hostname(), "433", "*", nick, "Nickname is already in use!"); } } @@ -217,9 +257,11 @@ std::string User::get_realname(){ return realname; } -void User::send_direct(std::string message) { - std::cout << message << "\n"; - this->connection->send(message); +void User::send_direct(std::vector messages) { + for (IRCCommand m : messages) { + std::cout << m.to_string() << "\n"; + this->connection->send(m.to_string()); + } } NameableType User::what_are_you() { diff --git a/user.h b/user.h index 1372cda..5128fe6 100644 --- a/user.h +++ b/user.h @@ -12,24 +12,32 @@ #include "nameable.h" #include "channel.h" +enum UCState { + Initial, + Registered +}; + class UserConnection; class User: public Nameable { private: std::string username, realname = ""; Connection* connection; + UCState state; - 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); + std::vector nick_cmd(IRCCommand cmd); + std::vector user_cmd(IRCCommand cmd); + std::vector ping_cmd(IRCCommand cmd); + std::vector who_cmd(IRCCommand cmd); + std::vector whois_cmd(IRCCommand cmd); + std::vector join_cmd(IRCCommand cmd); + std::vector part_cmd(IRCCommand cmd); + std::vector quit_cmd(IRCCommand cmd); + std::vector privmsg_cmd(IRCCommand cmd); + std::vector topic_cmd(IRCCommand cmd); + std::vector names_cmd(IRCCommand cmd); + std::vector motd_cmd(IRCCommand cmd); - static std::unordered_map>> commands; + static std::unordered_map(User*, IRCCommand)>, bool>> commands; //std::string construct_string(int count, std::string source, std::string command, std::string parameters...); template @@ -39,9 +47,9 @@ public: User(IRCServer* server, UserConnection* conn); ~User(); - void process_cmd(IRCCommand* cmd); + std::vector process_cmd(IRCCommand cmd); - void set_nick(std::string nick); + IRCCommand set_nick(std::string nick); void set_username(std::string username); @@ -59,9 +67,9 @@ public: std::string get_realname(); - void send_direct(std::string message); + void send_direct(std::vector messages); - NameableType what_are_you(); + NameableType what_are_you() override; void destroy(); }; diff --git a/userconnection.cpp b/userconnection.cpp index 32bb3c6..ff15ff2 100644 --- a/userconnection.cpp +++ b/userconnection.cpp @@ -13,24 +13,24 @@ void UserConnection::process_cmd(std::string cmd_in) { if (cmd_in == "") return; - IRCCommand* cmd = new IRCCommand(cmd_in); - std::cout << cmd_in << std::endl; + IRCCommand cmd = IRCCommand(cmd_in); + std::cout << cmd.to_string() << std::endl; - if (state == Registered) { +/* if (state == Registered) { user->process_cmd(cmd); delete cmd; return; } - std::string command = cmd->get_command(); + std::string command = cmd.get_command(); - if (command == "NICK" && cmd->has_payload()) { - user->set_nick(cmd->get_payload(0)); + if (command == "NICK" && cmd.has_parameter()) { + user->set_nick(cmd.get_parameter(0)); } - if (command == "USER" && cmd->has_payload()) { - user->set_username(cmd->get_payload(0)); - user->set_realname(cmd->get_payload(3)); + if (command == "USER" && cmd.has_parameter()) { + user->set_username(cmd.get_parameter(0)); + user->set_realname(cmd.get_parameter(3)); } if (user->has_nick() && user->has_username()) { @@ -41,8 +41,10 @@ void UserConnection::process_cmd(std::string cmd_in) { send(":xnoircd 004 " + user->get_nick() + " xnoircd 0 ABCabc ABCabc"); send(":xnoircd 422 " + user->get_nick() + " :No MOTD"); } +*/ - delete cmd; + for (IRCCommand c : user->process_cmd(cmd)) + send(c.to_string()); } void UserConnection::destroy() { diff --git a/userconnection.h b/userconnection.h index 6b670c9..483fcaa 100644 --- a/userconnection.h +++ b/userconnection.h @@ -7,16 +7,10 @@ #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);