Welcome back to our series of blogs on the Google Summer of Code (GSoC) project. In this blog post, I'll be sharing the progress made in implementing Multi-User Chat (MUC) support in Moxxy, the frontend counterpart to my GSoC project.
As you may recall, Moxxy is a frontend application developed as an innovative XMPP client. To enhance its functionality, my GSoC project focuses on adding MUC support. Before diving into the Moxxy implementation, it was crucial to establish the necessary MUC support in Moxxmpp, which is highlighted in this blog.
Currently, the implementation progress is to allow users to join an MUC through Moxxy, and view incoming live messages in the chat.
Design Plan for MUC Support in Moxxy
To implement MUC support in Moxxy, we need to extend its functionality and introduce new components. Let's outline the design plan for the MUC feature:
This page will contain just 1 text field - for the nickname that the user wants to join with. It also has a button that allows us to join the MUC with said nickname. It is an additional route to the current StartChat page, if the user selects that they want to join a groupchat.
This command is sent to the data layer worker (separate thread) from the UI, when the user clicks on the join groupchat button on the new join groupchat page. It contains information about the JID and the nick that the user tried to join with. This will only be sent to the worker thread if the input validations are cleared.
This event is sent back as a result of the JoinGroupchatCommand. Based on whether the request succeeded or failed, it will return the new Conversation object that has just been created.
Add a new GrouchatDetails table to the database containing two data items - the jid and the nick. The main reason to have a separate table for the groupchat details, instead of to just have a new nick item in the Conversation table - was to maintain the single responsibility principle.
When the user fetches a conversation of type groupchat from the database, a separate call will be made that fetches the relevant groupchat details from this new table, and attaches it to the Conversation object.
Changed the external helpers for the ConversationType to an enhanced enum. This allows us to include the functions within the enum.
The MUCManager was added to the list of registered managers for Moxxy. Not only this, the OccupantIdManager was also registered which will allow for the unique occupant identification moving forward. This will be required for message reactions/retractions in an MUC.
Added a new GroupchatService that allows for the following functions:
- getRoomInformation: Sends a request to moxxmpp to receive disco info about the MUC.
- joinRoom: Sends a request to moxxmpp to join the MUC if it's not password protected.
- addGroupchatDetailsFromData: Adds a new GroupchatDetails object to the database table.
- getGroupchatDetailsByJid: Fetches the GroupchatDetails from the database based on the JID provided. This is required as a separate step while fetching an MUC conversation since the Conversations and GroupchatDetails table are decoupled.
To prevent avoidable errors, Moxxy performs frontend checks when joining a room. These checks include ensuring to validate the JID input field, and checking for empty nicknames.
Possible errors that users may encounter during the MUC workflow include invalid or already in use nicknames, disallowed registration, invalid stanza format, and invalid disco info response. Moxxy will handle these errors gracefully.
Challenges and Considerations
Here is an enumeration of the possible challenges that we could face in the future implementation, and the ones I faced in the current implementation as well:
Differentiating Messages from Oneself: Moxxy/Moxxmpp need to distinguish between messages from other users and self-echoed messages. To address this, Moxxy uses the origin ID of the message. If the origin ID of the response matches the sent origin ID, the message is ignored and not displayed in the UI.
Handling Impersonation in Anonymous MUCs: In anonymous MUCs, users can impersonate others by reusing their nicknames after leaving. To tackle this, Moxxmpp leverages the occupant ID, as described in XEP-0421. Each user joining the group receives a unique occupant ID, which helps track message origins accurately.
Managing Discussion History on Rejoining: When a user rejoins an MUC, the room history is resent, including errors, self-presence with status code, room history, room subject, and live message/presence updates. To prevent appending duplicate history to the UI, Moxxy/Moxxmpp will have to wait until it receives the room subject before listening for message stanzas.
Conclusion and Future Work
In this blog post, we explored the implementation plan for adding MUC support, specifically XEP-0045, to Moxxy. Moxxmpp serves as the backbone for Moxxy's XMPP functionality, handling communication between the client and XMPP server. We discussed the directory structure, and key routines required for MUC support in Moxxmpp. Additionally, we addressed various challenges and considerations related to MUC features.
The implementation process has already commenced, with a pull request (PR) underway. Once the PR is complete, Moxxy will support joining a groupchat and listening to live messages. In further PRs, sending messages and leaving the MUC will be supported as well. The addition of MUC support will empower Moxxy users to enjoy enhanced collaboration and communication within XMPP group chats.
Stay tuned for future updates on the progress of MUC support in Moxxy. Until then, happy chatting!