diff --git a/application/CayaProtocolMessages.h b/application/CayaProtocolMessages.h index 48a1ebb..764aa2b 100644 --- a/application/CayaProtocolMessages.h +++ b/application/CayaProtocolMessages.h @@ -1,6 +1,7 @@ /* * Copyright 2009-2011, Andrea Anzani. All rights reserved. * Copyright 2009-2011, Pier Luigi Fiorini. All rights reserved. + * Copyright 2021, Jaidyn Levesque. All rights reserved. * Distributed under the terms of the MIT License. */ #ifndef _CAYA_PROTOCOL_MESSAGES_H @@ -100,7 +101,7 @@ enum im_what_code { // Requires: String "user_id", Ref "ref" IM_AVATAR_SET = 61, - //! Get contact information →Caya + //! Get contact information →Protocol IM_GET_CONTACT_INFO = 62, //! Received contact information →Caya @@ -194,8 +195,13 @@ enum im_what_code { * Room membership */ - //! Create an individual chat - // Requires: String "user_id" →Protocol + //! Create an individual chat →Protocol + // Individual chats and rooms are really the same thing (at least according + // to Caya)― the only difference is in how they're created and joined. + // A "chat" should be uniquely tied to a single user, and its chat_id + // should be derivable from the user's ID (when sent back from + // CHAT_CREATED). It doesn't matter how you get this done, really. + // Requires: String "user_id" IM_CREATE_CHAT = 150, //! Chat has been created →Caya @@ -206,6 +212,7 @@ enum im_what_code { // Requires: String "chat_id" IM_JOIN_ROOM = 152, + //! Confirm the room's been joined →Caya // Requires: String "chat_id" IM_ROOM_JOINED = 153, @@ -218,65 +225,83 @@ enum im_what_code { // Requires: String "chat_id" IM_ROOM_LEFT = 155, + //! Request a room's userlist →Protocol + // Requires: String "chat_id" + IM_GET_ROOM_PARTICIPANTS = 156, + //! Quietly add user(s) to the chat →Caya + // Shouldn't be sent automatically on joining a room. // Requires: String "chat_id", StringList "user_id" // Accepts: StringList "user_name" - IM_ROOM_PARTICIPANTS = 156, + IM_ROOM_PARTICIPANTS = 157, //! User has explicitly joined →Caya // Requires: String "chat_id", String "user_id" // Accepts: String "body" - IM_ROOM_PARTICIPANT_JOINED = 157, + IM_ROOM_PARTICIPANT_JOINED = 158, //! A user left the room →Caya // Requires: String "chat_id", String "user_id" // Accepts: String "user_name", String "body" - IM_ROOM_PARTICIPANT_LEFT = 158, + IM_ROOM_PARTICIPANT_LEFT = 159, //! Invite a user to a room →Protocol - // You can tell it succeded with ROOM_PARTICIPANT_JOINED + // You can tell it succeded with IM_ROOM_PARTICIPANT_JOINED. // Requires: String "chat_id", String "user_id" // Accepts: String "body" - IM_ROOM_SEND_INVITE = 159, + IM_ROOM_SEND_INVITE = 160, //! Invitee explicitly refused →Caya // Requires: String "chat_id", String "user_id" // Accepts: String "user_name", String "body" - IM_ROOM_INVITE_REFUSED = 160, + IM_ROOM_INVITE_REFUSED = 161, //! User was invited to a room →Caya // Requires: String "chat_id" // Accepts: String "user_id", String "chat_name", String "body" - IM_ROOM_INVITE_RECEIVED = 161, + IM_ROOM_INVITE_RECEIVED = 162, //! User accepted an invite →Protocol // Requires: String "chat_id" - IM_ROOM_INVITE_ACCEPT = 162, + IM_ROOM_INVITE_ACCEPT = 163, //! User denies an invite →Protocol // Requires: String "chat_id" - IM_ROOM_INVITE_REFUSE = 163, + IM_ROOM_INVITE_REFUSE = 164, /* * Room metadata */ + //! Request a room's metadata →Protocol + // Requires: String "chat_id" + IM_GET_ROOM_METADATA = 170, + + //! Receive room metadata →Caya + // The idea is that all other metadata-related messages should only be + // called either from a request, or from a change. + // This shouldn't be sent automatically upon joining a room. + // Requires: String "chat_id" + // Allows: String "chat_name", String "subject", + // int32 "room_default_flags", int32 "room_disallowed_flags" + IM_ROOM_METADATA = 171, + //! Set the room name →Protocol // Requires: String "chat_id", String "chat_name" - IM_SET_ROOM_NAME = 170, + IM_SET_ROOM_NAME = 172, - //! Room name changed →Protocol + //! Room name has changed →Protocol // Requires: String "chat_id", String "chat_name" - IM_ROOM_NAME_SET = 171, + IM_ROOM_NAME_SET = 173, //! Set the room subject →Caya // Requires: String "chat_id", String "subject" - IM_SET_ROOM_SUBJECT = 172, + IM_SET_ROOM_SUBJECT = 174, - //! Subject has been set →Caya + //! Subject has been changed →Caya // Requires: String "chat_id", String "subject" - IM_ROOM_SUBJECT_SET = 173, + IM_ROOM_SUBJECT_SET = 175, /* @@ -302,25 +327,29 @@ enum im_what_code { //! A user was banned →Caya // Requires: String "chat_id", String "user_id" - // Accepts: String "user_name", String "body" + // Accepts: String "user_name", String "body" IM_ROOM_PARTICIPANT_BANNED = 194, //! Unban user →Protocol IM_ROOM_UNBAN_PARTICIPANT = 195, //! Mute user →Protocol + // The result of this can be seen with IM_ROOM_ROLECHANGED. // Requires: String "chat_id", String "user_id" IM_ROOM_MUTE_PARTICIPANT = 196, //! Unmute user →Protocol + // The result of this can be seen with IM_ROOM_ROLECHANGED. // Requires: String "chat_id", String "user_id" IM_ROOM_UNMUTE_PARTICIPANT = 197, //! Deafen →Protocol + // The result of this can be seen with IM_ROOM_ROLECHANGED. // Requires: String "chat_id", String "user_id" IM_ROOM_DEAFEN_PARTICIPANT = 198, //! Allow to read messages →Protocol + // The result of this can be seen with IM_ROOM_ROLECHANGED. // Requires: String "chat_id", String "user_id" IM_ROOM_UNDEAFEN_PARTICIPANT = 199, @@ -339,4 +368,6 @@ enum im_what_code { IM_PROTOCOL_READY = 1002 }; + #endif // _CAYA_PROTOCOL_MESSAGES_H + diff --git a/application/Conversation.cpp b/application/Conversation.cpp index 4dc5cf5..fbba3bc 100644 --- a/application/Conversation.cpp +++ b/application/Conversation.cpp @@ -31,7 +31,9 @@ Conversation::Conversation(BString id, BMessenger msgn) fChatView(NULL), fLooper(NULL), fIcon(NULL), - fDateFormatter() + fDateFormatter(), + fRoomFlags(0), + fDisallowedFlags(0) { fConversationItem = new ConversationItem(fName.String(), this); RegisterObserver(fConversationItem); @@ -83,6 +85,26 @@ Conversation::ImMessage(BMessage* msg) fMessenger.SendMessage(msg); break; } + case IM_ROOM_METADATA: + { + BString name; + if (msg->FindString("chat_name", &name) == B_OK) + SetNotifyName(name.String()); + + BString subject; + if (msg->FindString("subject", &subject) == B_OK) + SetNotifySubject(subject.String()); + + int32 defaultFlags; + if (msg->FindInt32("room_default_flags", &defaultFlags) == B_OK) + if (fRoomFlags == 0) + fRoomFlags = defaultFlags; + + int32 disabledFlags; + if (msg->FindInt32("room_disallowed_flags", &disabledFlags) == B_OK) + fDisallowedFlags = disabledFlags; + break; + } case IM_ROOM_PARTICIPANT_JOINED: { BString user_id; diff --git a/application/Conversation.h b/application/Conversation.h index 02d2c15..bf4c017 100644 --- a/application/Conversation.h +++ b/application/Conversation.h @@ -90,6 +90,9 @@ private: BPath fCachePath; BDateTimeFormat fDateFormatter; + int32 fRoomFlags; + int32 fDisallowedFlags; + UserMap fUsers; RoleMap fRoles; }; diff --git a/application/RoomFlags.h b/application/RoomFlags.h new file mode 100644 index 0000000..926d303 --- /dev/null +++ b/application/RoomFlags.h @@ -0,0 +1,24 @@ +/* + * Copyright 2021, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef ROOMFLAGS_H +#define ROOMFLAGS_H + +#include + +// AUTOJOIN, AUTOCREATE, LOG, POPULATE +// Auto-join on login, auto-create on login (non-persistent rooms), keep local +// logs, populate chat with local logs on join… + +// JCLP +// 0000 + +#define ROOM_AUTOJOIN 1 +#define ROOM_AUTOCREATE 2 +#define ROOM_LOG_LOCALLY 4 +#define ROOM_POPULATE_LOGS 8 + + +#endif // ROOMFLAGS_H + diff --git a/application/Server.cpp b/application/Server.cpp index 00f71fc..94b0392 100644 --- a/application/Server.cpp +++ b/application/Server.cpp @@ -292,6 +292,13 @@ Server::ImMessage(BMessage* msg) chat->ImMessage(msg); break; } + case IM_ROOM_METADATA: + { + Conversation* chat = _EnsureConversation(msg); + if (chat != NULL) + chat->ImMessage(msg); + break; + } case IM_ROOM_ROLECHANGED: { Conversation* chat = _EnsureConversation(msg); @@ -773,6 +780,17 @@ Server::_EnsureConversation(BMessage* message) item->SetProtocolLooper(looper); item->AddUser(looper->ContactById(looper->GetOwnId())); looper->AddConversation(item); + + BMessage meta(IM_MESSAGE); + meta.AddInt32("im_what", IM_GET_ROOM_METADATA); + meta.AddString("chat_id", chat_id); + + BMessage users(IM_MESSAGE); + users.AddInt32("im_what", IM_GET_ROOM_PARTICIPANTS); + users.AddString("chat_id", chat_id); + + looper->MessageReceived(&meta); + looper->MessageReceived(&users); } } return item; diff --git a/protocols/xmpp/JabberHandler.cpp b/protocols/xmpp/JabberHandler.cpp index 6e56b3f..8b91c32 100644 --- a/protocols/xmpp/JabberHandler.cpp +++ b/protocols/xmpp/JabberHandler.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -150,7 +151,6 @@ JabberHandler::Process(BMessage* msg) BString chat_id; if (msg->FindString("chat_id", &chat_id) == B_OK) _JoinRoom(chat_id.String()); - break; } @@ -194,6 +194,37 @@ JabberHandler::Process(BMessage* msg) break; } + case IM_GET_ROOM_PARTICIPANTS: { + BString chat_id = msg->FindString("chat_id"); + gloox::MUCRoom* room = fRooms.ValueFor(chat_id); + + if (room != NULL) + room->getRoomItems(); + else if (fUserChats.HasString(chat_id) == true) { + BMessage users(IM_MESSAGE); + users.AddInt32("im_what", IM_ROOM_PARTICIPANTS); + users.AddString("user_id", chat_id); + } + break; + } + + case IM_GET_ROOM_METADATA: { + BString chat_id = msg->FindString("chat_id"); + gloox::MUCRoom* room = fRooms.ValueFor(chat_id); + if (room != NULL) + room->getRoomInfo(); + else if (fUserChats.HasString(chat_id) == true) + { + BMessage metadata(IM_MESSAGE); + metadata.AddInt32("im_what", IM_ROOM_METADATA); + metadata.AddString("chat_id", chat_id); + metadata.AddInt32("room_default_flags", + 0 | ROOM_AUTOCREATE | ROOM_LOG_LOCALLY | ROOM_POPULATE_LOGS); + metadata.AddInt32("room_disallowed_flags", 0 | ROOM_AUTOJOIN); + } + break; + } + case IM_ROOM_KICK_PARTICIPANT: case IM_ROOM_BAN_PARTICIPANT: case IM_ROOM_UNBAN_PARTICIPANT: @@ -797,6 +828,14 @@ JabberHandler::_StatusSetMsg(const char* user_id, gloox::Presence::PresenceType } +void +JabberHandler::_EnsureUserChat(const char* chat_id) +{ + if (fUserChats.HasString(BString(chat_id)) == false) + fUserChats.Add(BString(chat_id)); +} + + status_t JabberHandler::_SetupAvatarCache() { @@ -996,8 +1035,6 @@ JabberHandler::_JoinRoom(const char* chat_id) room = new gloox::MUCRoom(fClient, gloox::JID(join_id.String()), this, this); room->join(); - room->getRoomItems(); - fRooms.AddItem(BString(chat_id), room); } @@ -1273,6 +1310,8 @@ JabberHandler::handleMessage(const gloox::Message& m, gloox::MessageSession*) if (m.body() == "") return; + _EnsureUserChat(m.from().bare().c_str()); + // Notify that a chat message was received BMessage msg(IM_MESSAGE); msg.AddString("user_id", m.from().bare().c_str()); @@ -1299,6 +1338,8 @@ printf("------ %d\n", state); if (state == gloox::ChatStateActive || state == gloox::ChatStateInvalid) return; + _EnsureUserChat(from.bare().c_str()); + BMessage msg(IM_MESSAGE); msg.AddString("user_id", from.bare().c_str()); msg.AddString("chat_id", from.bare().c_str()); @@ -1459,6 +1500,16 @@ void JabberHandler::handleMUCInfo(gloox::MUCRoom *room, int features, const std::string &name, const gloox::DataForm *infoForm) { + BString chat_id = _MUCChatId(room); + + BMessage metadata(IM_MESSAGE); + metadata.AddInt32("im_what", IM_ROOM_METADATA); + metadata.AddString("chat_id", chat_id); + metadata.AddString("chat_name", name.c_str()); + metadata.AddInt32("room_default_flags", + 0 | ROOM_AUTOJOIN | ROOM_LOG_LOCALLY | ROOM_POPULATE_LOGS); + metadata.AddInt32("room_disallowed_flags", 0 | ROOM_AUTOCREATE); + _SendMessage(&metadata); } diff --git a/protocols/xmpp/JabberHandler.h b/protocols/xmpp/JabberHandler.h index 91b939d..0b5a03a 100644 --- a/protocols/xmpp/JabberHandler.h +++ b/protocols/xmpp/JabberHandler.h @@ -1,5 +1,6 @@ /* * Copyright 2010, Pier Luigi Fiorini. All rights reserved. + * Copyright 2021, Jaidyn Levesque. All rights reserved. * Distributed under the terms of the GPL v2 License. */ #ifndef _JABBER_HANDLER_H @@ -8,6 +9,7 @@ #include #include #include +#include #include #include @@ -109,7 +111,9 @@ private: gloox::JID fJid; thread_id fRecvThread; - RoomMap fRooms; + + RoomMap fRooms; // Keylist of MUC rooms + BStringList fUserChats; // List of individual chats (non-gloox::MUCRooms) BPath fCachePath; BPath fAvatarCachePath; @@ -119,8 +123,8 @@ private: void _SendMessage(BMessage* msg); void _MessageSent(const char* id, const char* subject, const char* body); - void _JoinRoom(const char* chat_id); + void _JoinRoom(const char* chat_id); void _ChatCreatedMsg(const char* id); void _RoleChangedMsg(BString chat_id, BString user_id, gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff); @@ -131,6 +135,8 @@ private: void _Notify(notification_type type, const char* title, const char* message); void _NotifyProgress(const char* title, const char* message, float progress); + void _EnsureUserChat(const char* chat_id); + status_t _SetupAvatarCache(); status_t _SaveAvatarCache(); void _CacheAvatar(const char* id, const char* binval, size_t length); @@ -202,7 +208,7 @@ private: class InviteHandler : public gloox::MUCInvitationHandler { public: InviteHandler(gloox::ClientBase* parent, JabberHandler* handler); - void handleMUCInvitation(const gloox::JID& room, const gloox::JID& from, + void handleMUCInvitation(const gloox::JID& room, const gloox::JID& from, const std::string& reason, const std::string& body, const std::string& password, bool cont, const std::string& thread);