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);