diff --git a/application/CayaProtocolMessages.h b/application/CayaProtocolMessages.h index c0dadca..5c1c000 100644 --- a/application/CayaProtocolMessages.h +++ b/application/CayaProtocolMessages.h @@ -222,11 +222,14 @@ enum im_what_code { * Room moderation */ + //! A user's role has been changed + IM_ROOM_ROLECHANGE = 170, + //! Ban user - IM_ROOM_BAN_PARTICIPANT = 170, + IM_ROOM_BAN_PARTICIPANT = 171, //! Kick user - IM_ROOM_KICK_PARTICIPANT = 171, + IM_ROOM_KICK_PARTICIPANT = 172, /* diff --git a/application/Conversation.cpp b/application/Conversation.cpp index eca210d..65f7306 100644 --- a/application/Conversation.cpp +++ b/application/Conversation.cpp @@ -162,6 +162,42 @@ Conversation::GetName() const } +ConversationView* +Conversation::GetView() +{ + if (fChatView != NULL) + return fChatView; + + fChatView = new ConversationView(this); + + if (fLooper->Protocol()->SaveLogs() == false) + return fChatView; + + BStringList logs = _GetChatLogs(); + BMessage logMsg(IM_MESSAGE); + logMsg.AddInt32("im_what", IM_LOGS_RECEIVED); + logMsg.AddStrings("body", logs); + fChatView->MessageReceived(&logMsg); + + RegisterObserver(fChatView); + return fChatView; +} + + +void +Conversation::ShowView(bool typing, bool userAction) +{ + ((TheApp*)be_app)->GetMainWindow()->SetConversation(this); +} + + +ConversationItem* +Conversation::GetListItem() +{ + return fConversationItem; +} + + UserMap Conversation::Users() { @@ -196,39 +232,30 @@ Conversation::RemoveUser(User* user) } +BString +Conversation::OwnUserId() +{ + return _GetServer()->GetOwnContact(); +} + + void -Conversation::ShowView(bool typing, bool userAction) +Conversation::SetRole(BString id, Role* role) { - ((TheApp*)be_app)->GetMainWindow()->SetConversation(this); + Role* oldRole = fRoles.ValueFor(id); + if (oldRole != NULL) { + fRoles.RemoveItemFor(id); + delete oldRole; + } + + fRoles.AddItem(id, role); } -ConversationView* -Conversation::GetView() +Role* +Conversation::GetRole(BString id) { - if (fChatView != NULL) - return fChatView; - - fChatView = new ConversationView(this); - - if (fLooper->Protocol()->SaveLogs() == false) - return fChatView; - - BStringList logs = _GetChatLogs(); - BMessage logMsg(IM_MESSAGE); - logMsg.AddInt32("im_what", IM_LOGS_RECEIVED); - logMsg.AddStrings("body", logs); - fChatView->MessageReceived(&logMsg); - - RegisterObserver(fChatView); - return fChatView; -} - - -ConversationItem* -Conversation::GetListItem() -{ - return fConversationItem; + return fRoles.ValueFor(id); } diff --git a/application/Conversation.h b/application/Conversation.h index 832e0c5..324849c 100644 --- a/application/Conversation.h +++ b/application/Conversation.h @@ -12,6 +12,7 @@ #include #include "Observer.h" +#include "Role.h" #include "Server.h" #include "User.h" @@ -23,6 +24,7 @@ class Server; typedef KeyMap UserMap; +typedef KeyMap RoleMap; class Conversation : public Notifier, public Observer { @@ -48,20 +50,22 @@ public: BBitmap* ProtocolBitmap() const; BBitmap* IconBitmap() const; - - void ShowView(bool typing, bool userAction); + BString GetName() const; ConversationView* GetView(); + void ShowView(bool typing, bool userAction); ConversationItem* GetListItem(); - BString GetName() const; - UserMap Users(); User* UserById(BString id); + BString OwnUserId(); void AddUser(User* user); void RemoveUser(User* user); + void SetRole(BString id, Role* role); + Role* GetRole(BString id); + private: void _LogChatMessage(BMessage* msg); BStringList _GetChatLogs(); @@ -85,6 +89,7 @@ private: BDateTimeFormat fDateFormatter; UserMap fUsers; + RoleMap fRoles; }; diff --git a/application/Role.h b/application/Role.h new file mode 100644 index 0000000..dff8732 --- /dev/null +++ b/application/Role.h @@ -0,0 +1,54 @@ +/* + * Copyright 2021, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef PERMS_H +#define PERMS_H + +#include + +// NAME, SUBJECT, ROLECHANGE, BAN, KICK, DEAFEN, MUTE, NICK, READ, WRITE +// Set name of room, set subject, change user's "role" (permission presets +// defined by the protocol), etc… + +// NSRBKDMNRW +// 0000000000 + +#define PERM_WRITE 0x01 +#define PERM_READ 0x02 +#define PERM_NICK 0x04 +#define PERM_MUTE 0x08 +#define PERM_DEAFEN 0x016 +#define PERM_KICK 0x032 +#define PERM_BAN 0x064 +#define PERM_ROLECHANGE 0x0128 +#define PERM_ROOM_SUBJECT 0x0256 +#define PERM_ROOM_NAME 0x0512 +#define PERM_ALL 1023 + + +class Role { +public: + Role() + : fTitle("Default"), fPerms(0 | PERM_WRITE | PERM_READ), fPriority(0) + { + } + + Role(BString title, uint32 perms, uint32 priority) + : fTitle(title), fPerms(perms), fPriority(priority) + { + } + + BString fTitle; + uint32 fPerms; // Permissions afforded to role, as described above. + uint32 fPriority; // 'Rank' of role, with higher being greater priority. + // I.E., a user with a priority of 11 can't kick a user + // with a priority of 12, but can one with 10. + // This sort of hierarchy might not be universal in + // chat protocols, but I think it can be adequately + // simulated in add-ons. +}; + + +#endif // PERMS_H + diff --git a/application/Server.cpp b/application/Server.cpp index 708187e..85d64f3 100644 --- a/application/Server.cpp +++ b/application/Server.cpp @@ -286,6 +286,19 @@ Server::ImMessage(BMessage* msg) chat->RemoveUser(user); break; } + case IM_ROOM_ROLECHANGE: + { + Conversation* chat = _EnsureConversation(msg); + BString user_id; + Role* role = _GetRole(msg); + + if (chat == NULL || msg->FindString("user_id", &user_id) != B_OK + || role == NULL) + break; + + chat->SetRole(user_id, role); + break; + } case IM_ROOM_SUBJECT: { BString subject; @@ -633,3 +646,22 @@ Server::_EnsureConversation(BMessage* message) } +Role* +Server::_GetRole(BMessage* msg) +{ + if (!msg) + return NULL; + + BString title; + uint32 perms; + uint32 priority; + + if (msg->FindString("role_title", &title) != B_OK + || msg->FindUInt32("role_perms", &perms) != B_OK + || msg->FindUInt32("role_priority", &priority) != B_OK) + return NULL; + + return new Role(title, perms, priority); +} + + diff --git a/application/Server.h b/application/Server.h index 318b1c8..f3fb452 100644 --- a/application/Server.h +++ b/application/Server.h @@ -72,6 +72,8 @@ private: User* _EnsureUser(BString id, ProtocolLooper* protoLooper); Conversation* _EnsureConversation(BMessage* message); + Role* _GetRole(BMessage* msg); + void _ReplicantStatusNotify(CayaStatus status); RosterMap fRosterMap; diff --git a/application/User.h b/application/User.h index 84893a1..81f7b06 100644 --- a/application/User.h +++ b/application/User.h @@ -13,8 +13,8 @@ #include -#include "Notifier.h" #include "CayaConstants.h" +#include "Notifier.h" class BBitmap; diff --git a/protocols/xmpp/JabberHandler.cpp b/protocols/xmpp/JabberHandler.cpp index 7640977..c214025 100644 --- a/protocols/xmpp/JabberHandler.cpp +++ b/protocols/xmpp/JabberHandler.cpp @@ -13,10 +13,11 @@ #include #include -#include - #include +#include +#include + #include #include #include @@ -894,6 +895,58 @@ JabberHandler::_MUCUserId(BString chat_id, const char* nick, BString* id) } +const char* +JabberHandler::_RoleTitle(gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff) +{ + switch (role) + { + case gloox::RoleVisitor: + return "Visitor"; + case gloox::RoleParticipant: + return "Member"; + case gloox::RoleModerator: + if (aff == gloox::AffiliationOwner) + return "Owner"; + return "Moderator"; + } + return "Invalid"; +} + + +uint32 +JabberHandler::_RolePerms(gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff) +{ + switch (role) + { + case gloox::RoleVisitor: + return 0 | PERM_READ | PERM_NICK; + case gloox::RoleParticipant: + return 0 | PERM_READ | PERM_WRITE | PERM_ROOM_SUBJECT; + case gloox::RoleModerator: + if (aff == gloox::AffiliationOwner) + return PERM_ALL; + return PERM_ALL; + } + return 0; +} + + +uint32 +JabberHandler::_RolePriority(gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff) +{ + switch (role) + { + case gloox::RoleParticipant: + return 1; + case gloox::RoleModerator: + if (aff == gloox::AffiliationOwner) + return 3; + return 2; + } + return 0; +} + + BMessage JabberHandler::_SettingsTemplate(const char* username, bool serverOption) { @@ -1132,6 +1185,12 @@ JabberHandler::handleMUCParticipantPresence(gloox::MUCRoom *room, const gloox::MUCRoomParticipant participant, const gloox::Presence &presence) { + // participant.flags, particpiant.role + // 0-0 (left), 0-* (joined/rolechange) + + gloox::MUCRoomRole role = participant.role; + gloox::MUCRoomAffiliation aff = participant.affiliation; + const char* nick = participant.nick->resource().c_str(); BString user_id; @@ -1150,6 +1209,7 @@ JabberHandler::handleMUCParticipantPresence(gloox::MUCRoom *room, joinedMsg.AddInt32("im_what", im_what); joinedMsg.AddString("chat_id", chat_id); _SendMessage(&joinedMsg); + _RoleChanged(chat_id, user_id, role, aff); return; } @@ -1175,6 +1235,23 @@ JabberHandler::handleMUCParticipantPresence(gloox::MUCRoom *room, joinMsg.AddString("user_name", nick); joinMsg.AddString("chat_id", chat_id); _SendMessage(&joinMsg); + + _RoleChanged(chat_id, user_id, role, aff); +} + + +void +JabberHandler::_RoleChanged(BString chat_id, BString user_id, + gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff) +{ + BMessage roleMsg(IM_MESSAGE); + roleMsg.AddInt32("im_what", IM_ROOM_ROLECHANGE); + roleMsg.AddString("user_id", user_id); + roleMsg.AddString("chat_id", chat_id); + roleMsg.AddString("role_title", _RoleTitle(role, aff)); + roleMsg.AddUInt32("role_perms", _RolePerms(role, aff)); + roleMsg.AddUInt32("role_priority", _RolePriority(role, aff)); + _SendMessage(&roleMsg); } diff --git a/protocols/xmpp/JabberHandler.h b/protocols/xmpp/JabberHandler.h index e3ee2dd..d3cd131 100644 --- a/protocols/xmpp/JabberHandler.h +++ b/protocols/xmpp/JabberHandler.h @@ -118,7 +118,8 @@ private: const char* body); void _ChatCreated(const char* id); - + void _RoleChanged(BString chat_id, BString user_id, + gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff); void _Notify(notification_type type, const char* title, const char* message); void _NotifyProgress(const char* title, const char* message, float progress); @@ -133,6 +134,10 @@ private: BString _MUCChatId(gloox::MUCRoom* room); bool _MUCUserId(BString chat_id, const char* nick, BString* id); + const char* _RoleTitle(gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff); + uint32 _RolePerms(gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff); + uint32 _RolePriority(gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff); + virtual void onConnect(); virtual void onDisconnect(gloox::ConnectionError); virtual bool onTLSConnect(const gloox::CertInfo&);