diff --git a/doc/TODO b/doc/TODO index a627723..8898514 100644 --- a/doc/TODO +++ b/doc/TODO @@ -17,6 +17,7 @@ matrix: list room members change password ability to select specification revision + add event type to membership_info reddit: handle imgur albums diff --git a/include/matrix.hpp b/include/matrix.hpp index adf860b..e295fd9 100644 --- a/include/matrix.hpp +++ b/include/matrix.hpp @@ -118,21 +118,21 @@ namespace matrix{ } }; - struct msg_info + struct event_info { const raii::rjp_string& roomid; const raii::rjp_string& sender; - const msgtype type; - const raii::rjp_string& body; const raii::rjp_string& eventid; const int age; }; - struct invite_info + struct msg_info : public event_info { - const raii::rjp_string& roomid; - const raii::rjp_string& sender; - const raii::rjp_string& eventid; - const int age; + const msgtype type; + const raii::rjp_string& body; + }; + struct membership_info : public event_info + { + const raii::rjp_string& recipient; }; //main class @@ -208,7 +208,7 @@ namespace matrix{ raii::rjp_string m_next_batch; //string which tracks where we are in the server history std::function m_message_callback; - std::function m_invite_callback; + std::function m_membership_callback; public: bot(const auth_data& a, const raii::string_base& useragent); @@ -245,8 +245,8 @@ namespace matrix{ bool join_room(const raii::string_base& roomid)const; bool leave_room(const raii::string_base& roomid)const; - bool accept_invite(const invite_info& invite)const; - bool reject_invite(const invite_info& invite)const; + bool accept_invite(const membership_info& invite)const; + bool reject_invite(const membership_info& invite)const; //upload media file_info upload_file(const raii::string_base& filename)const; @@ -275,13 +275,15 @@ namespace matrix{ m_message_callback = std::forward(f); } template - void set_invite_callback(Func&& f){ - m_invite_callback = std::forward(f); + void set_membership_callback(Func&& f){ + m_membership_callback = std::forward(f); } raii::string sync(size_t timeout); void logout(void); protected: + void _handle_membership_events(RJP_value* rooms); + void _handle_other_membership(RJP_value* join); void _handle_invites(RJP_value* invites); void _handle_messages(RJP_value* messages); void _send_read_receipt(const raii::string_base& roomid, const raii::string_base& eventid)const; diff --git a/src/matrix.cpp b/src/matrix.cpp index 85e4a06..8e3fb43 100644 --- a/src/matrix.cpp +++ b/src/matrix.cpp @@ -44,8 +44,8 @@ namespace matrix{ auth_data parse_auth_data(RJP_value* root){ static const char* fields[] = {"username", "password", "homeserver", "access_token"}; - RJP_search_res details[5]; - rjp_search_members(root, 5, fields, details, 0); + RJP_search_res details[4]; + rjp_search_members(root, 4, fields, details, 0); return auth_data{details[0].value, details[1].value, details[2].value, @@ -135,10 +135,10 @@ namespace matrix{ bool bot::leave_room(const raii::string_base& roomid)const{ return _post_curl(raii::string(), m_urls.leave_room(m_homeserver, m_access_token, m_curl.encode(roomid)), raii::curl_llist()); } - bool bot::accept_invite(const invite_info& invite)const{ + bool bot::accept_invite(const membership_info& invite)const{ return join_room(invite.roomid); } - bool bot::reject_invite(const invite_info& invite)const{ + bool bot::reject_invite(const membership_info& invite)const{ return leave_room(invite.roomid); } file_info bot::upload_file(const raii::string_base& filename)const{ @@ -454,8 +454,8 @@ namespace matrix{ if(res.value){ if(m_message_callback != nullptr) _handle_messages(res.value); - if(m_invite_callback != nullptr) - _handle_invites(res.value); + if(m_membership_callback != nullptr) + _handle_membership_events(res.value); } return reply; } @@ -465,11 +465,43 @@ namespace matrix{ Internal functions ********************************/ + void bot::_handle_membership_events(RJP_value* rooms){ + RJP_search_res res = rjp_search_member(rooms, "invite", 0); + if(res.value) + _handle_invites(res.value); + res = rjp_search_member(rooms, "join", 0); + if(res.value) + _handle_other_membership(res.value); + } + void bot::_handle_other_membership(RJP_value* join){ + for(RJP_value* roomid = rjp_get_member(join);roomid;roomid = rjp_next_member(roomid)){ + RJP_search_res res = rjp_search_member(roomid, "timeline", 0); + if(!res.value) continue; + res = rjp_search_member(res.value, "events", 0); + if(!res.value) continue; + for(RJP_value* event = rjp_get_element(res.value);event;event = rjp_next_element(event)){ + static constexpr const char* search_terms[] = {"content", "event_id", "sender", "state_key", "unsigned"}; + static constexpr size_t num_searches = sizeof(search_terms)/sizeof(search_terms[0]); + RJP_search_res results[num_searches] = {}; + rjp_search_members(event, num_searches, search_terms, results, 0); + if(!results[0].value || !results[1].value || !results[2].value || !results[3].value || !results[4].value) continue; + RJP_search_res age = rjp_search_member(results[4].value, "age", 0); + if(!age.value) continue; + RJP_search_res type = rjp_search_member(results[0].value, "membership", 0); + if(!type.value) continue; + + raii::rjp_string event_str = results[1].value; + raii::rjp_string sender_str = results[2].value; + raii::rjp_string rec_str = results[3].value; + raii::rjp_string room_str = rjp_member_name(roomid); + + m_membership_callback(*this, membership_info{room_str, sender_str, event_str, rjp_value_integer(age.value), rec_str}); + } + } + } void bot::_handle_invites(RJP_value* invites){ - RJP_search_res res = rjp_search_member(invites, "invite", 0); - if(!res.value) return; - for(RJP_value* roomid = rjp_get_member(res.value);roomid;roomid = rjp_next_member(roomid)){ - res = rjp_search_member(roomid, "invite_state", 0); + for(RJP_value* roomid = rjp_get_member(invites);roomid;roomid = rjp_next_member(roomid)){ + RJP_search_res res = rjp_search_member(roomid, "invite_state", 0); if(!res.value) continue; res = rjp_search_member(res.value, "events", 0); if(!res.value) continue; @@ -479,9 +511,8 @@ namespace matrix{ RJP_search_res results[num_searches] = {}; rjp_search_members(event, num_searches, search_terms, results, 0); if(!results[0].value || !results[1].value || !results[2].value || !results[3].value) continue; - if(strcmp(rjp_value_string(results[2].value), m_userid)) continue; raii::rjp_string room_str = rjp_member_name(roomid); - m_invite_callback(*this, invite_info{room_str, raii::rjp_string(results[1].value), raii::rjp_string(results[0].value), rjp_value_integer(results[3].value)}); + m_membership_callback(*this, membership_info{room_str, raii::rjp_string(results[1].value), raii::rjp_string(results[0].value), rjp_value_integer(results[3].value), raii::rjp_string(results[2].value)}); } } } @@ -499,18 +530,18 @@ namespace matrix{ RJP_search_res results[num_searches] = {}; rjp_search_members(event, num_searches, searches, results, 0); if(!results[0].value || !results[1].value || !results[2].value || !results[3].value) continue; - raii::rjp_string sender_str = results[0].value; - if(sender_str == m_userid) continue; + if(!strcmp(rjp_value_string(results[0].value), m_userid)) continue; RJP_search_res msg = rjp_search_member(results[1].value, "msgtype", 0); if(!msg.value) continue; RJP_search_res body = rjp_search_member(results[1].value, "body", 0); if(!body.value) continue; RJP_search_res age = rjp_search_member(results[3].value, "age", 0); if(!age.value) continue; + raii::rjp_string sender_str = results[0].value; raii::rjp_string room_str = rjp_member_name(roomid); raii::rjp_string eventid_str = results[2].value; _send_read_receipt(room_str, eventid_str); - m_message_callback(*this, msg_info{room_str, sender_str, msg::from_str(rjp_value_string(msg.value)), raii::rjp_string(body.value), eventid_str, rjp_value_integer(age.value)}); + m_message_callback(*this, msg_info{room_str, sender_str, eventid_str, rjp_value_integer(age.value), msg::from_str(rjp_value_string(msg.value)), raii::rjp_string(body.value)}); } } } diff --git a/src/test.cpp b/src/test.cpp index 1a09ea5..7e74330 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -445,18 +445,19 @@ int main(){ bot.send_image(msg.roomid, {"mxc://matrix.org/SYkDDTUwcfscliYTuIfYFIrx"_ss, "nipple.jpg"_ss, "image/jpeg"_ss, 40202, 512, 402, {}, 512, 402, 40202}); } }; - auto invite_callback = [&](const matrix::bot& bot, const matrix::invite_info& invite)->bool{ - bot.accept_invite(invite); - return true; + auto invite_callback = [&](const matrix::bot& bot, const matrix::membership_info& invite)->void{ + printf("membership event:\nsender: %s\nrecipient: %s\n", invite.sender.get(), invite.recipient.get()); + if(!strcmp(invite.recipient, "@proghumorbot:matrix.org")) + bot.accept_invite(invite); }; matbot.set_message_callback(sync_callback); - matbot.set_invite_callback(invite_callback); + matbot.set_membership_callback(invite_callback); matbot.redact_event("!QeYfNDCRodtNohhnaI:matrix.org"_ss, "$1553965753281066lkKaO:matrix.org"_ss, "too gay"_ss); while(!should_quit){ sync_reply = matbot.sync(30000); - DEBUG_PRINT("syncing\n"); + //DEBUG_PRINT("syncing\n"); //DEBUG_PRINT("%s\n", sync_reply.get()); }