diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dd7adce..748f61d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -52,11 +52,11 @@ target_link_libraries(solanaceae_ircclient_messages PUBLIC ######################################## -add_executable(test2 EXCLUDE_FROM_ALL +add_executable(irc_test2 EXCLUDE_FROM_ALL test2.cpp ) -target_link_libraries(test2 PUBLIC +target_link_libraries(irc_test2 PUBLIC solanaceae_ircclient solanaceae_ircclient_contacts solanaceae_ircclient_messages diff --git a/src/solanaceae/ircclient/ircclient.hpp b/src/solanaceae/ircclient/ircclient.hpp index ec5e007..96fc20e 100644 --- a/src/solanaceae/ircclient/ircclient.hpp +++ b/src/solanaceae/ircclient/ircclient.hpp @@ -12,7 +12,7 @@ extern "C" void* irc_get_ctx(irc_session_t* session); namespace IRCClient::Events { - // TODO: proper param seperation + // TODO: proper param separation struct Numeric { unsigned int event; diff --git a/src/solanaceae/ircclient_contacts/ircclient_contact_model.cpp b/src/solanaceae/ircclient_contacts/ircclient_contact_model.cpp index f021e7f..9c96b9f 100644 --- a/src/solanaceae/ircclient_contacts/ircclient_contact_model.cpp +++ b/src/solanaceae/ircclient_contacts/ircclient_contact_model.cpp @@ -26,6 +26,7 @@ IRCClientContactModel::IRCClientContactModel( _ircc.subscribe(this, IRCClient_Event::JOIN); _ircc.subscribe(this, IRCClient_Event::PART); + _ircc.subscribe(this, IRCClient_Event::TOPIC); _ircc.subscribe(this, IRCClient_Event::QUIT); _ircc.subscribe(this, IRCClient_Event::CTCP_REQ); @@ -65,13 +66,21 @@ std::vector IRCClientContactModel::getHash(std::string_view value) { return hash; } +std::vector IRCClientContactModel::getHash(const std::vector& value) { + assert(!value.empty()); + + std::vector hash(crypto_hash_sha256_bytes(), 0x00); + crypto_hash_sha256(hash.data(), value.data(), value.size()); + return hash; +} + std::vector IRCClientContactModel::getIDHash(std::string_view name) { assert(!_server_hash.empty()); assert(!name.empty()); std::vector data = _server_hash; data.insert(data.end(), name.begin(), name.end()); - return getHash(std::string_view{reinterpret_cast(data.data()), data.size()}); + return getHash(data); } Contact3Handle IRCClientContactModel::getC(std::string_view channel) { @@ -148,6 +157,9 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Connect& e) { _cr.emplace_or_replace(_server, Contact::Components::ConnectionState::State::direct); _cr.emplace_or_replace(_server); + // the server connection is also the root contact (ircccm only handles 1 server 1 user) + _cr.emplace_or_replace(_server); + // TODO: should this be its own node instead? or should the server node be created on construction? } { // self @@ -159,16 +171,17 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Connect& e) { // check for empty contact by id for (const auto e : _cr.view()) { if (_cr.get(e).data == self_hash) { - _server = e; + _self = e; break; } } } - if (!_cr.valid(_server)) { + if (!_cr.valid(_self)) { _self = _cr.create(); } } _cr.emplace_or_replace(_self, this); + _cr.emplace_or_replace(_self, _server); _cr.emplace_or_replace(_self); _cr.emplace_or_replace(_self, std::string{_ircc.getServerName()}); // really? if (!e.params.empty()) { @@ -177,9 +190,18 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Connect& e) { // make id hash(hash(ServerName)+UserName) // or irc name format, but those might cause collisions _cr.emplace_or_replace(_self, getIDHash(e.params.front())); + +#if 0 + std::cout << "### created self with" + << " e:" << entt::to_integral(_self) + << " ircn:" << _cr.get(_self).name + << " ircsn:" << _cr.get(_self).name + << " id:" << bin2hex(_cr.get(_self).data) + << "\n"; +#endif } - _cr.emplace_or_replace(_self, Contact::Components::ConnectionState::State::cloud); + _cr.emplace_or_replace(_self, Contact::Components::ConnectionState::State::direct); // add self to server _cr.emplace_or_replace(_server, _self); @@ -211,15 +233,19 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Numeric& e) { return false; } - if (e.params.at(1) != "=") { - // error, unexpected + if ( + e.params.at(1) != "=" && // Public channel + e.params.at(1) != "@" && // Secret channel + e.params.at(1) != "*" // Private channel + ) { + std::cerr << "IRCCCM error: name list for unknown channel type\n"; return false; } const auto& channel_name = e.params.at(2); auto channel = getC(channel_name); if (!channel.valid()) { - std::cerr << "IRCCM error: name list for unknown channel\n"; + std::cerr << "IRCCCM error: name list for unknown channel\n"; return false; } @@ -231,7 +257,7 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Numeric& e) { auto user_str = user_list.substr(0, space_pos); { // handle user // rfc 2812 5.1 - // The '@' and '+' characters next to the channel name + // The '@' and '+' characters next to the user name // indicate whether a client is a channel operator or // has been granted permission to speak on a moderated // channel. @@ -317,6 +343,27 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Numeric& e) { } user_list = user_list.substr(next_non_space); } while (space_pos != std::string_view::npos); + } else if (e.event == LIBIRC_RFC_RPL_TOPIC) { + // origin is the server + // params.at(0) is the user (self) + // params.at(1) is the channel + // params.at(2) is the topic + if (e.params.size() != 3) { + // error + return false; + } + + // TODO: check user (self) + + const auto channel_name = e.params.at(1); + auto channel = getC(channel_name); + if (!channel.valid()) { + std::cerr << "IRCCCM error: topic for unknown channel\n"; + return false; + } + + const auto topic = e.params.at(2); + channel.emplace_or_replace(std::string{topic}).fillFirstLineLength(); } return false; } @@ -345,6 +392,8 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Join& e) { channel.emplace_or_replace(channel_hash); } channel.emplace_or_replace(this); + channel.emplace_or_replace(_server); + channel.emplace_or_replace(); // start empty channel.emplace_or_replace(std::string{_ircc.getServerName()}); channel.emplace_or_replace(std::string{joined_channel_name}); channel.emplace_or_replace(std::string{joined_channel_name}); @@ -354,6 +403,7 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Join& e) { channel.emplace_or_replace(Contact::Components::ConnectionState::State::cloud); channel.emplace_or_replace(); + channel.emplace_or_replace(); // add self to channel channel.emplace_or_replace(_self); @@ -372,14 +422,22 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Join& e) { if (!user.valid()) { user = {_cr, _cr.create()}; user.emplace_or_replace(user_hash); + std::cerr << "IRCCCM error: had to create joining user (self?)\n"; } user.emplace_or_replace(this); + user.emplace_or_replace(_server); user.emplace_or_replace(std::string{_ircc.getServerName()}); // channel list? // add to channel? user.emplace_or_replace(std::string{e.origin}); user.emplace_or_replace(std::string{e.origin}); + + std::cout << "### created self(?) with" + << " ircn:" << _cr.get(_self).name + << " ircsn:" << _cr.get(_self).name + << " id:" << bin2hex(_cr.get(_self).data) + << "\n"; } if (user.entity() != _self) { @@ -433,6 +491,29 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Part& e) { return false; } +bool IRCClientContactModel::onEvent(const IRCClient::Events::Topic& e) { + // sadly only fired on topic change + + // origin is user (setter) + // params.at(0) is channel + // params.at(1) is new topic + if (e.params.size() != 2) { + // error + return false; + } + + const auto channel_name = e.params.at(0); + auto channel = getC(channel_name); + if (!channel.valid()) { + std::cerr << "IRCCCM error: new topic for unknown channel\n"; + return false; + } + + const auto topic = e.params.at(1); + channel.emplace_or_replace(std::string{topic}).fillFirstLineLength(); + return false; +} + bool IRCClientContactModel::onEvent(const IRCClient::Events::Quit& e) { // e.origin // is the quitting user diff --git a/src/solanaceae/ircclient_contacts/ircclient_contact_model.hpp b/src/solanaceae/ircclient_contacts/ircclient_contact_model.hpp index 7333a4f..f5bcfb6 100644 --- a/src/solanaceae/ircclient_contacts/ircclient_contact_model.hpp +++ b/src/solanaceae/ircclient_contacts/ircclient_contact_model.hpp @@ -41,6 +41,7 @@ class IRCClientContactModel : public IRCClientEventI, public ContactModel3I { private: // just the hash algo std::vector getHash(std::string_view value); + std::vector getHash(const std::vector& value); public: // the actually ID is a chain containing the server+channel or server+name @@ -57,6 +58,7 @@ class IRCClientContactModel : public IRCClientEventI, public ContactModel3I { bool onEvent(const IRCClient::Events::Numeric& e) override; bool onEvent(const IRCClient::Events::Join& e) override; bool onEvent(const IRCClient::Events::Part& e) override; + bool onEvent(const IRCClient::Events::Topic& e) override; bool onEvent(const IRCClient::Events::Quit& e) override; bool onEvent(const IRCClient::Events::CTCP_Req&) override; }; diff --git a/src/solanaceae/ircclient_messages/ircclient_message_manager.cpp b/src/solanaceae/ircclient_messages/ircclient_message_manager.cpp index 277788b..9e21538 100644 --- a/src/solanaceae/ircclient_messages/ircclient_message_manager.cpp +++ b/src/solanaceae/ircclient_messages/ircclient_message_manager.cpp @@ -16,12 +16,6 @@ #include #include -//namespace Components { - //struct ServerName { - //std::string name; - //}; -//} // Components - IRCClientMessageManager::IRCClientMessageManager( RegistryMessageModel& rmm, Contact3Registry& cr, @@ -207,19 +201,21 @@ bool IRCClientMessageManager::onEvent(const IRCClient::Events::PrivMSG& e) { // e.origin is sender auto from = _ircccm.getU(e.origin); // assuming its always a user // aka ContactFrom if (!from.valid()) { - std::cerr << "IRCCMM error: channel event unknown sender\n"; + std::cerr << "IRCCMM error: privmsg event unknown sender\n"; return false; } // e.params.at(0) is receiver (us?) auto to = _ircccm.getU(e.params.at(0)); // aka ContactTo if (!to.valid()) { - std::cerr << "IRCCMM error: channel event unknown channel\n"; + std::cerr << "IRCCMM error: privmsg event unknown channel\n"; return false; } + // TODO: move this to contact // upgrade contact to big from.emplace_or_replace(); // could be like an invite? + from.emplace_or_replace(); return processMessage(from, to, e.params.at(1), false); }