Rework communication of room metadata, add room flags

In the API, a firm distinction between initially fetching a room's
metadata and receiving further changes has been made:
IM_ROOM_METADATA will be sent to Caya on request (IM_GET_ROOM_METADATA)
with the room's name, subject, etc. The other metadata-related messages
should only be sent to Caya after the room is initialized, not as a
means of initially setting its metadata.

Basic room flags were added, though they aren't yet used― they should
allow the protocol/add-on/user to configure some room features. Logging,
auto-joining, etc.
This commit is contained in:
Jaidyn Ann 2021-06-13 01:16:30 -05:00
parent 07350b3a0a
commit 7c9d1d9eaa
7 changed files with 181 additions and 26 deletions

View File

@ -1,6 +1,7 @@
/* /*
* Copyright 2009-2011, Andrea Anzani. All rights reserved. * Copyright 2009-2011, Andrea Anzani. All rights reserved.
* Copyright 2009-2011, Pier Luigi Fiorini. 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. * Distributed under the terms of the MIT License.
*/ */
#ifndef _CAYA_PROTOCOL_MESSAGES_H #ifndef _CAYA_PROTOCOL_MESSAGES_H
@ -100,7 +101,7 @@ enum im_what_code {
// Requires: String "user_id", Ref "ref" // Requires: String "user_id", Ref "ref"
IM_AVATAR_SET = 61, IM_AVATAR_SET = 61,
//! Get contact information →Caya //! Get contact information →Protocol
IM_GET_CONTACT_INFO = 62, IM_GET_CONTACT_INFO = 62,
//! Received contact information →Caya //! Received contact information →Caya
@ -194,8 +195,13 @@ enum im_what_code {
* Room membership * Room membership
*/ */
//! Create an individual chat //! Create an individual chat →Protocol
// Requires: String "user_id" →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, IM_CREATE_CHAT = 150,
//! Chat has been created →Caya //! Chat has been created →Caya
@ -206,6 +212,7 @@ enum im_what_code {
// Requires: String "chat_id" // Requires: String "chat_id"
IM_JOIN_ROOM = 152, IM_JOIN_ROOM = 152,
//! Confirm the room's been joined →Caya //! Confirm the room's been joined →Caya
// Requires: String "chat_id" // Requires: String "chat_id"
IM_ROOM_JOINED = 153, IM_ROOM_JOINED = 153,
@ -218,65 +225,83 @@ enum im_what_code {
// Requires: String "chat_id" // Requires: String "chat_id"
IM_ROOM_LEFT = 155, 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 //! Quietly add user(s) to the chat →Caya
// Shouldn't be sent automatically on joining a room.
// Requires: String "chat_id", StringList "user_id" // Requires: String "chat_id", StringList "user_id"
// Accepts: StringList "user_name" // Accepts: StringList "user_name"
IM_ROOM_PARTICIPANTS = 156, IM_ROOM_PARTICIPANTS = 157,
//! User has explicitly joined →Caya //! User has explicitly joined →Caya
// Requires: String "chat_id", String "user_id" // Requires: String "chat_id", String "user_id"
// Accepts: String "body" // Accepts: String "body"
IM_ROOM_PARTICIPANT_JOINED = 157, IM_ROOM_PARTICIPANT_JOINED = 158,
//! A user left the room →Caya //! A user left the room →Caya
// Requires: String "chat_id", String "user_id" // Requires: String "chat_id", String "user_id"
// Accepts: String "user_name", String "body" // Accepts: String "user_name", String "body"
IM_ROOM_PARTICIPANT_LEFT = 158, IM_ROOM_PARTICIPANT_LEFT = 159,
//! Invite a user to a room →Protocol //! 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" // Requires: String "chat_id", String "user_id"
// Accepts: String "body" // Accepts: String "body"
IM_ROOM_SEND_INVITE = 159, IM_ROOM_SEND_INVITE = 160,
//! Invitee explicitly refused →Caya //! Invitee explicitly refused →Caya
// Requires: String "chat_id", String "user_id" // Requires: String "chat_id", String "user_id"
// Accepts: String "user_name", String "body" // Accepts: String "user_name", String "body"
IM_ROOM_INVITE_REFUSED = 160, IM_ROOM_INVITE_REFUSED = 161,
//! User was invited to a room →Caya //! User was invited to a room →Caya
// Requires: String "chat_id" // Requires: String "chat_id"
// Accepts: String "user_id", String "chat_name", String "body" // Accepts: String "user_id", String "chat_name", String "body"
IM_ROOM_INVITE_RECEIVED = 161, IM_ROOM_INVITE_RECEIVED = 162,
//! User accepted an invite →Protocol //! User accepted an invite →Protocol
// Requires: String "chat_id" // Requires: String "chat_id"
IM_ROOM_INVITE_ACCEPT = 162, IM_ROOM_INVITE_ACCEPT = 163,
//! User denies an invite →Protocol //! User denies an invite →Protocol
// Requires: String "chat_id" // Requires: String "chat_id"
IM_ROOM_INVITE_REFUSE = 163, IM_ROOM_INVITE_REFUSE = 164,
/* /*
* Room metadata * 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 //! Set the room name →Protocol
// Requires: String "chat_id", String "chat_name" // 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" // Requires: String "chat_id", String "chat_name"
IM_ROOM_NAME_SET = 171, IM_ROOM_NAME_SET = 173,
//! Set the room subject →Caya //! Set the room subject →Caya
// Requires: String "chat_id", String "subject" // 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" // 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 //! A user was banned →Caya
// Requires: String "chat_id", String "user_id" // Requires: String "chat_id", String "user_id"
// Accepts: String "user_name", String "body" // Accepts: String "user_name", String "body"
IM_ROOM_PARTICIPANT_BANNED = 194, IM_ROOM_PARTICIPANT_BANNED = 194,
//! Unban user →Protocol //! Unban user →Protocol
IM_ROOM_UNBAN_PARTICIPANT = 195, IM_ROOM_UNBAN_PARTICIPANT = 195,
//! Mute user →Protocol //! Mute user →Protocol
// The result of this can be seen with IM_ROOM_ROLECHANGED.
// Requires: String "chat_id", String "user_id" // Requires: String "chat_id", String "user_id"
IM_ROOM_MUTE_PARTICIPANT = 196, IM_ROOM_MUTE_PARTICIPANT = 196,
//! Unmute user →Protocol //! Unmute user →Protocol
// The result of this can be seen with IM_ROOM_ROLECHANGED.
// Requires: String "chat_id", String "user_id" // Requires: String "chat_id", String "user_id"
IM_ROOM_UNMUTE_PARTICIPANT = 197, IM_ROOM_UNMUTE_PARTICIPANT = 197,
//! Deafen →Protocol //! Deafen →Protocol
// The result of this can be seen with IM_ROOM_ROLECHANGED.
// Requires: String "chat_id", String "user_id" // Requires: String "chat_id", String "user_id"
IM_ROOM_DEAFEN_PARTICIPANT = 198, IM_ROOM_DEAFEN_PARTICIPANT = 198,
//! Allow to read messages →Protocol //! Allow to read messages →Protocol
// The result of this can be seen with IM_ROOM_ROLECHANGED.
// Requires: String "chat_id", String "user_id" // Requires: String "chat_id", String "user_id"
IM_ROOM_UNDEAFEN_PARTICIPANT = 199, IM_ROOM_UNDEAFEN_PARTICIPANT = 199,
@ -339,4 +368,6 @@ enum im_what_code {
IM_PROTOCOL_READY = 1002 IM_PROTOCOL_READY = 1002
}; };
#endif // _CAYA_PROTOCOL_MESSAGES_H #endif // _CAYA_PROTOCOL_MESSAGES_H

View File

@ -31,7 +31,9 @@ Conversation::Conversation(BString id, BMessenger msgn)
fChatView(NULL), fChatView(NULL),
fLooper(NULL), fLooper(NULL),
fIcon(NULL), fIcon(NULL),
fDateFormatter() fDateFormatter(),
fRoomFlags(0),
fDisallowedFlags(0)
{ {
fConversationItem = new ConversationItem(fName.String(), this); fConversationItem = new ConversationItem(fName.String(), this);
RegisterObserver(fConversationItem); RegisterObserver(fConversationItem);
@ -83,6 +85,26 @@ Conversation::ImMessage(BMessage* msg)
fMessenger.SendMessage(msg); fMessenger.SendMessage(msg);
break; 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: case IM_ROOM_PARTICIPANT_JOINED:
{ {
BString user_id; BString user_id;

View File

@ -90,6 +90,9 @@ private:
BPath fCachePath; BPath fCachePath;
BDateTimeFormat fDateFormatter; BDateTimeFormat fDateFormatter;
int32 fRoomFlags;
int32 fDisallowedFlags;
UserMap fUsers; UserMap fUsers;
RoleMap fRoles; RoleMap fRoles;
}; };

24
application/RoomFlags.h Normal file
View File

@ -0,0 +1,24 @@
/*
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef ROOMFLAGS_H
#define ROOMFLAGS_H
#include <SupportDefs.h>
// 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

View File

@ -292,6 +292,13 @@ Server::ImMessage(BMessage* msg)
chat->ImMessage(msg); chat->ImMessage(msg);
break; break;
} }
case IM_ROOM_METADATA:
{
Conversation* chat = _EnsureConversation(msg);
if (chat != NULL)
chat->ImMessage(msg);
break;
}
case IM_ROOM_ROLECHANGED: case IM_ROOM_ROLECHANGED:
{ {
Conversation* chat = _EnsureConversation(msg); Conversation* chat = _EnsureConversation(msg);
@ -773,6 +780,17 @@ Server::_EnsureConversation(BMessage* message)
item->SetProtocolLooper(looper); item->SetProtocolLooper(looper);
item->AddUser(looper->ContactById(looper->GetOwnId())); item->AddUser(looper->ContactById(looper->GetOwnId()));
looper->AddConversation(item); 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; return item;

View File

@ -19,6 +19,7 @@
#include <CayaProtocolMessages.h> #include <CayaProtocolMessages.h>
#include <Role.h> #include <Role.h>
#include <RoomFlags.h>
#include <gloox/chatstatefilter.h> #include <gloox/chatstatefilter.h>
#include <gloox/messageeventfilter.h> #include <gloox/messageeventfilter.h>
@ -150,7 +151,6 @@ JabberHandler::Process(BMessage* msg)
BString chat_id; BString chat_id;
if (msg->FindString("chat_id", &chat_id) == B_OK) if (msg->FindString("chat_id", &chat_id) == B_OK)
_JoinRoom(chat_id.String()); _JoinRoom(chat_id.String());
break; break;
} }
@ -194,6 +194,37 @@ JabberHandler::Process(BMessage* msg)
break; 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_KICK_PARTICIPANT:
case IM_ROOM_BAN_PARTICIPANT: case IM_ROOM_BAN_PARTICIPANT:
case IM_ROOM_UNBAN_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 status_t
JabberHandler::_SetupAvatarCache() 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 = new gloox::MUCRoom(fClient, gloox::JID(join_id.String()), this, this);
room->join(); room->join();
room->getRoomItems();
fRooms.AddItem(BString(chat_id), room); fRooms.AddItem(BString(chat_id), room);
} }
@ -1273,6 +1310,8 @@ JabberHandler::handleMessage(const gloox::Message& m, gloox::MessageSession*)
if (m.body() == "") if (m.body() == "")
return; return;
_EnsureUserChat(m.from().bare().c_str());
// Notify that a chat message was received // Notify that a chat message was received
BMessage msg(IM_MESSAGE); BMessage msg(IM_MESSAGE);
msg.AddString("user_id", m.from().bare().c_str()); msg.AddString("user_id", m.from().bare().c_str());
@ -1299,6 +1338,8 @@ printf("------ %d\n", state);
if (state == gloox::ChatStateActive || state == gloox::ChatStateInvalid) if (state == gloox::ChatStateActive || state == gloox::ChatStateInvalid)
return; return;
_EnsureUserChat(from.bare().c_str());
BMessage msg(IM_MESSAGE); BMessage msg(IM_MESSAGE);
msg.AddString("user_id", from.bare().c_str()); msg.AddString("user_id", from.bare().c_str());
msg.AddString("chat_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, JabberHandler::handleMUCInfo(gloox::MUCRoom *room, int features,
const std::string &name, const gloox::DataForm *infoForm) 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);
} }

View File

@ -1,5 +1,6 @@
/* /*
* Copyright 2010, Pier Luigi Fiorini. All rights reserved. * Copyright 2010, Pier Luigi Fiorini. All rights reserved.
* Copyright 2021, Jaidyn Levesque. All rights reserved.
* Distributed under the terms of the GPL v2 License. * Distributed under the terms of the GPL v2 License.
*/ */
#ifndef _JABBER_HANDLER_H #ifndef _JABBER_HANDLER_H
@ -8,6 +9,7 @@
#include <Notification.h> #include <Notification.h>
#include <Path.h> #include <Path.h>
#include <String.h> #include <String.h>
#include <StringList.h>
#include <gloox/client.h> #include <gloox/client.h>
#include <gloox/chatstatehandler.h> #include <gloox/chatstatehandler.h>
@ -109,7 +111,9 @@ private:
gloox::JID fJid; gloox::JID fJid;
thread_id fRecvThread; thread_id fRecvThread;
RoomMap fRooms;
RoomMap fRooms; // Keylist of MUC rooms
BStringList fUserChats; // List of individual chats (non-gloox::MUCRooms)
BPath fCachePath; BPath fCachePath;
BPath fAvatarCachePath; BPath fAvatarCachePath;
@ -119,8 +123,8 @@ private:
void _SendMessage(BMessage* msg); void _SendMessage(BMessage* msg);
void _MessageSent(const char* id, const char* subject, void _MessageSent(const char* id, const char* subject,
const char* body); const char* body);
void _JoinRoom(const char* chat_id);
void _JoinRoom(const char* chat_id);
void _ChatCreatedMsg(const char* id); void _ChatCreatedMsg(const char* id);
void _RoleChangedMsg(BString chat_id, BString user_id, void _RoleChangedMsg(BString chat_id, BString user_id,
gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff); gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff);
@ -131,6 +135,8 @@ private:
void _Notify(notification_type type, const char* title, const char* message); void _Notify(notification_type type, const char* title, const char* message);
void _NotifyProgress(const char* title, const char* message, float progress); void _NotifyProgress(const char* title, const char* message, float progress);
void _EnsureUserChat(const char* chat_id);
status_t _SetupAvatarCache(); status_t _SetupAvatarCache();
status_t _SaveAvatarCache(); status_t _SaveAvatarCache();
void _CacheAvatar(const char* id, const char* binval, size_t length); void _CacheAvatar(const char* id, const char* binval, size_t length);
@ -202,7 +208,7 @@ private:
class InviteHandler : public gloox::MUCInvitationHandler { class InviteHandler : public gloox::MUCInvitationHandler {
public: public:
InviteHandler(gloox::ClientBase* parent, JabberHandler* handler); 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& reason, const std::string& body,
const std::string& password, bool cont, const std::string& password, bool cont,
const std::string& thread); const std::string& thread);