2023-07-14 13:20:59 +02:00
|
|
|
/*
|
|
|
|
Copyright 2015, 2016 OpenMarket Ltd
|
|
|
|
Copyright 2018 New Vector Ltd
|
|
|
|
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
|
|
|
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
|
|
|
|
|
|
|
import { _td } from "../languageHandler";
|
|
|
|
import { reject, success } from "./utils";
|
|
|
|
import { isPermalinkHost, parsePermalink } from "../utils/permalinks/Permalinks";
|
|
|
|
import dis from "../dispatcher/dispatcher";
|
|
|
|
import { ViewRoomPayload } from "../dispatcher/payloads/ViewRoomPayload";
|
|
|
|
import { Action } from "../dispatcher/actions";
|
|
|
|
import { TimelineRenderingType } from "../contexts/RoomContext";
|
|
|
|
import { Command } from "./command";
|
|
|
|
import { CommandCategories, RunResult } from "./interface";
|
|
|
|
|
|
|
|
// A return of undefined here signals a usage error, where the command should return `reject(this.getUsage());`
|
|
|
|
function openRoom(cli: MatrixClient, args: string | undefined, autoJoin: boolean): RunResult | undefined {
|
|
|
|
if (!args) return;
|
|
|
|
const params = args.split(" ");
|
|
|
|
if (params.length < 1) return;
|
|
|
|
|
|
|
|
let isPermalink = false;
|
|
|
|
if (params[0].startsWith("http:") || params[0].startsWith("https:")) {
|
|
|
|
// It's at least a URL - try and pull out a hostname to check against the
|
|
|
|
// permalink handler
|
|
|
|
const parsedUrl = new URL(params[0]);
|
|
|
|
const hostname = parsedUrl.host || parsedUrl.hostname; // takes first non-falsey value
|
|
|
|
|
|
|
|
// if we're using a Element permalink handler, this will catch it before we get much further.
|
|
|
|
// see below where we make assumptions about parsing the URL.
|
|
|
|
if (isPermalinkHost(hostname)) {
|
|
|
|
isPermalink = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (params[0][0] === "#") {
|
|
|
|
let roomAlias = params[0];
|
|
|
|
if (!roomAlias.includes(":")) {
|
|
|
|
roomAlias += ":" + cli.getDomain();
|
|
|
|
}
|
|
|
|
|
|
|
|
dis.dispatch<ViewRoomPayload>({
|
|
|
|
action: Action.ViewRoom,
|
|
|
|
room_alias: roomAlias,
|
|
|
|
auto_join: autoJoin,
|
|
|
|
metricsTrigger: "SlashCommand",
|
|
|
|
metricsViaKeyboard: true,
|
|
|
|
});
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (params[0][0] === "!") {
|
|
|
|
const [roomId, ...viaServers] = params;
|
|
|
|
|
|
|
|
dis.dispatch<ViewRoomPayload>({
|
|
|
|
action: Action.ViewRoom,
|
|
|
|
room_id: roomId,
|
|
|
|
via_servers: viaServers, // for the rejoin button
|
|
|
|
auto_join: autoJoin,
|
|
|
|
metricsTrigger: "SlashCommand",
|
|
|
|
metricsViaKeyboard: true,
|
|
|
|
});
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isPermalink) {
|
|
|
|
const permalinkParts = parsePermalink(params[0]);
|
|
|
|
|
|
|
|
// This check technically isn't needed because we already did our
|
|
|
|
// safety checks up above. However, for good measure, let's be sure.
|
|
|
|
if (!permalinkParts) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If for some reason someone wanted to join a user, we should
|
|
|
|
// stop them now.
|
|
|
|
if (!permalinkParts.roomIdOrAlias) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const entity = permalinkParts.roomIdOrAlias;
|
|
|
|
const viaServers = permalinkParts.viaServers;
|
|
|
|
const eventId = permalinkParts.eventId;
|
|
|
|
|
|
|
|
const dispatch: ViewRoomPayload = {
|
|
|
|
action: Action.ViewRoom,
|
|
|
|
auto_join: autoJoin,
|
|
|
|
metricsTrigger: "SlashCommand",
|
|
|
|
metricsViaKeyboard: true,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (entity[0] === "!") dispatch["room_id"] = entity;
|
|
|
|
else dispatch["room_alias"] = entity;
|
|
|
|
|
|
|
|
if (eventId) {
|
|
|
|
dispatch["event_id"] = eventId;
|
|
|
|
dispatch["highlighted"] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (viaServers) {
|
|
|
|
// For the join, these are passed down to the js-sdk's /join call
|
|
|
|
dispatch["opts"] = { viaServers };
|
|
|
|
|
|
|
|
// For if the join fails (rejoin button)
|
|
|
|
dispatch["via_servers"] = viaServers;
|
|
|
|
}
|
|
|
|
|
|
|
|
dis.dispatch(dispatch);
|
|
|
|
return success();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, it's a usage error. Return `undefined`.
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note: we support 2 versions of this command. The first is
|
|
|
|
// the public-facing one for most users and the other is a
|
|
|
|
// power-user edition where someone may join via permalink or
|
|
|
|
// room ID with optional servers. Practically, this results
|
|
|
|
// in the following variations:
|
|
|
|
// /join #example:example.org
|
|
|
|
// /join !example:example.org
|
|
|
|
// /join !example:example.org altserver.com elsewhere.ca
|
|
|
|
// /join https://matrix.to/#/!example:example.org?via=altserver.com
|
|
|
|
// The command also supports event permalinks transparently:
|
|
|
|
// /join https://matrix.to/#/!example:example.org/$something:example.org
|
|
|
|
// /join https://matrix.to/#/!example:example.org/$something:example.org?via=altserver.com
|
|
|
|
export const join = new Command({
|
|
|
|
command: "join",
|
|
|
|
aliases: ["j"],
|
|
|
|
args: "<room-address>",
|
2023-09-19 08:17:31 +02:00
|
|
|
description: _td("slash_command|join"),
|
2023-07-14 13:20:59 +02:00
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
|
|
|
return openRoom(cli, args, true) ?? reject(this.getUsage());
|
|
|
|
},
|
|
|
|
category: CommandCategories.actions,
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
|
|
|
});
|
|
|
|
|
|
|
|
// Similar to join but doesn't auto join the room if you aren't already joined to it
|
|
|
|
export const goto = new Command({
|
|
|
|
command: "goto",
|
|
|
|
aliases: ["view"],
|
|
|
|
args: "<room-address>",
|
2023-09-19 08:17:31 +02:00
|
|
|
description: _td("slash_command|view"),
|
2023-07-14 13:20:59 +02:00
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
|
|
|
return openRoom(cli, args, false) ?? reject(this.getUsage());
|
|
|
|
},
|
|
|
|
category: CommandCategories.actions,
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
|
|
|
});
|