/* * asbots * Copyright (C) 2021 niansa * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef _INSTANCE_HPP #define _INSTANCE_HPP #include "config.hpp" #include "uid.hpp" #include "serviceBase.hpp" #include "utility.hpp" #include "incompletes.hpp" #include "exceptions.hpp" #include #include #include #include #include #include #include #include #include #include #include #include struct Event { // DON'T std::move() this class. EVER!!! AnyUID sender; std::string name, raw_args, text; std::vector args; std::string dump() const { return fmt::format(":{} {} {}{}\n", sender.str(), name, raw_args, (text.empty()?"":" :"+text)); } void parse(std::string_view str); void splitArgs() { args = Utility::strSplit(raw_args, ' '); } }; struct Command { std::string name, args, text; std::string dump() const { return fmt::format("{} {}{}\n", name, args, (text.empty()?"":" :"+text)); } void parse(std::string_view str); }; struct ModeSet { std::string str; std::vector> params; template void parse(std::string_view str, NetworkInfo& netInfo); }; struct Channel { SUID server; std::string name; ModeSet mode; std::string topic; std::vector members; void parse_sjoin(const Event &event, Cache& cache, NetworkInfo& netInfo); void removeMember(const u_User& member); Event get_sjoin(const UUID& initial_user) const { return { .sender = SUID(server), .name = "SJOIN", .raw_args = fmt::format("{} {} +{}", time(nullptr), name, mode.str), .text = fmt::format("@{}", initial_user.str()) }; } Event get_topic(std::string_view topic, const UUID& user) const { return { .sender = user, .name = "TOPIC", .raw_args = name, .text = std::string(topic) }; } }; struct User { SUID server; std::string nick; size_t hops = 1; ModeSet umode; std::string ident = "~"; std::optional vhost; std::optional ip; std::string realhost; UUID uid; std::string realname; std::vector channels; std::optional loginName; void parse_euid(const Event &event, NetworkInfo& netInfo); void removeChannel(const u_Channel &channel); Event get_euid() const { return { .sender = SUID(server), .name = "EUID", // nick // | hops // | | ts // | | | umode // | | | | ident // | | | | | vhost // | | | | | | ip // | | | | | | | uid // | | | | | | | | realhost // | | | | | | | | | account // | | | | | | | | | | realname .raw_args = fmt::format("{} 1 {} +{} {} {} {} {} {} {} :{}", nick, time(nullptr), umode.str, ident, vhost.value_or(realhost), ip.value_or("*"), uid.str(), realhost, loginName.value_or("*"), realname) }; } Event get_join(std::string_view channelName) const { return { .sender = uid, .name = "JOIN", .raw_args = fmt::format("{} {} +", time(nullptr), channelName) }; } Event get_part(std::string_view channelName, std::string_view message = "") const { return { .sender = uid, .name = "PART", .raw_args = std::string(channelName), .text = std::string(message) }; } Event get_quit(std::string_view message = "") const { return { .sender = uid, .name = "QUIT", .text = std::string(message) }; } Event get_encap_su(std::string_view login_name, const SUID& my_sid) { //: ENCAP * SU return { .sender = my_sid, .name = "ENCAP", .raw_args = fmt::format("* SU {} {}", uid.str(), login_name) }; } Event get_privmsg(std::string_view message, AnyUID target) const { return { .sender = uid, .name = "PRIVMSG", .raw_args = std::string(target.str()), .text = std::string(message) }; } Event get_notice(std::string_view message, AnyUID target) const { return { .sender = uid, .name = "NOTICE", .raw_args = std::string(target.str()), .text = std::string(message) }; } }; struct Cache { std::vector users; std::vector channels; std::vector::iterator find_user_by_nick(std::string_view nick); std::vector::iterator find_user_by_uid(const UUID& uid); std::vector::iterator find_channel_by_name(std::string_view name); }; struct NetworkInfo { async::oneshot_event ready_event; size_t fields_received = 0; bool ready = false; std::string name; struct { // list modes first, then modes that take a param when setting but not when unsetting (just +k), then modes that can only be set once and take args, then modes that can only be set once but take no args. std::string listModes, // Lists like mode b paramOnSetAndUnsetModes, // Properties like k paramOnSetOnlyModes, // Properties like f paramLessModes; // Properties like z std::unordered_map prefixMap; // Maps for example '@' to 'o' bool isListMode(char mode) { return listModes.find(mode) != std::string::npos; } bool takesNoParam(char mode) { return paramLessModes.find(mode) != paramLessModes.npos; } bool takesParamOnUnset(char mode) { return isListMode(mode) || paramOnSetAndUnsetModes.find(mode) != std::string::npos; } bool takesParamOnSet(char mode) { return paramOnSetOnlyModes.find(mode) != std::string::npos || takesParamOnUnset(mode); } } channelModes; async::result wait_ready() { if (!ready) { co_await ready_event.wait(); } } void mark_ready() { ready = true; ready_event.raise(); } }; class Instance { std::reference_wrapper s; uvpp::Addr addr; size_t lastUUID = 0; bool server_bursting = true, client_bursting = true; bool authed = false; public: std::unique_ptr socket; const Config config; Config::Server connected_server; NetworkInfo netInfo; Cache cache; std::vector> services; Instance(uvpp::loop_service &s, const Config& config) : s(s), config(config) { addr = uvpp::make_ipv4(config.connection.addr, config.connection.port); } async::result run(); async::result login(); async::result burst(); async::result process(const Command); async::result process(Event); async::result send_event(const Event&); async::result send_ping(); // utils.cpp UUID UUIDGen(); }; #endif