diff --git a/CHANGELOG.md b/CHANGELOG.md index 176bd5f..bf88b6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## v0.2 +### Added +- `AWAY` and `away-notify` + ## v0.1.1 - 2022-02-09 - Fix `DELETEMSG` being sent to unsupporting clients - Fix missing parameter in `900` numeric. diff --git a/README.md b/README.md index 52a25f9..7015d96 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ On Libera I'm `emerson`, on Matrix I'm `@emersonveenstra:matrix.org`, feel free | Channel lists/searching | ❌ | ❌ | [#30](https://todo.sr.ht/~emerson/reflectionircd/30) | | Encrypted rooms | ❌ | ❌ | [#20](https://todo.sr.ht/~emerson/reflectionircd/20) | | Rich text | ❌ | ❌ | [#31](https://todo.sr.ht/~emerson/reflectionircd/31) | -| Presence | ❌ | ❌ | [#25](https://todo.sr.ht/~emerson/reflectionircd/25) Note that not all homeservers have presence enabled | +| Presence | ✅ | ✅ | Note that not all homeservers have presence enabled | | Channel renaming (IRCv3) | ✅ | ❌ | [#16](https://todo.sr.ht/~emerson/reflectionircd/16) | | Message replies (IRCv3) | ✅ | ✅ | Clients without support will still receive the reply message, but it won't be marked as a reply | | Message reactions (IRCv3) | ✅ | ✅ || diff --git a/src/Client.ts b/src/Client.ts index c1bc033..4317be4 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -112,6 +112,9 @@ export abstract class Client { case 'AUTHENTICATE': this.doAUTHENTICATE(message); break; + case 'AWAY': + this.doAWAY(message); + break; case 'BATCH': this.doBATCH(message); break; @@ -187,6 +190,34 @@ export abstract class Client { } } + doAWAY(message: IRCMessage) { + const data = { + presence: 'online', + status_msg: '' + } + if (message.params.length === 1) { + data.presence = 'unavailable'; + data.status_msg = message.params[0]; + } + this.apiCall.put(`/presence/${this.user.mxid}/status`, data).then(r => { + // Returning the IRC numerics here because most servers have presence disabled anyways + if (data.presence === 'online') { + this.sendMessage(this.server.name, "305", [this.user.nick, "You are no longer marked as being away"]); + } else { + this.sendMessage(this.server.name, "306", [this.user.nick, "You have been marked as being away"]); + } + }).catch(function (error) { + if (error.response) { + console.log(error.response.data); + } else if (error.request) { + console.log(error.request); + } else { + console.log('Error', error.message); + console.log(error.config); + } + }) + } + doBATCH(message: IRCMessage) { const referenceTag = message.params[0].substring(1); if (message.params[0].startsWith('+')) { diff --git a/src/Server.ts b/src/Server.ts index 09b36d6..52bf476 100644 --- a/src/Server.ts +++ b/src/Server.ts @@ -211,6 +211,9 @@ export class Server { routeMatrixEvent(nextEvent: any, targetChannel: Channel) { switch (nextEvent["type"]) { + case 'm.presence': + this.handleMatrixPresence(nextEvent); + break; case 'm.reaction': this.handleMatrixReaction(nextEvent, targetChannel); break; @@ -279,6 +282,31 @@ export class Server { } } + handleMatrixPresence(event: any) { + let matrixUser = this.matrixUsers.get(event["sender"]); + // Don't bother sending if the user isn't joined to any channels yet + if (!matrixUser) { + return; + } + if (matrixUser.mxid === this.ourMatrixUser.mxid) { + return; + } + const presence = event["content"]?.["presence"]; + if (!presence) { + return; + } + const status = event["content"]?.["status_msg"]; + if (status === undefined) { + return; + } + if (presence === 'online') { + this.sendToAllWithCap('away-notify', matrixUser.getMask(), 'AWAY', []); + } else { + const awayMessage = (status === '') ? "user is away" : status; + this.sendToAllWithCap('away-notify', matrixUser.getMask(), 'AWAY', [awayMessage]); + } + } + handleMatrixReaction(event: any, targetChannel: Channel) { const sourceUser = this.getOrCreateMatrixUser(event["sender"]); this.checkForLazyJoin(event, sourceUser, targetChannel);