You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
776 lines
30 KiB
JavaScript
776 lines
30 KiB
JavaScript
/*
|
|
* Copyright 2020-2022 Netsyms Technologies.
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
/*
|
|
* Matrix really, really, really needs better SDK docs.
|
|
*/
|
|
|
|
console.log("Starting up...");
|
|
import * as sdk from 'matrix-js-sdk';
|
|
import matrixcs from 'matrix-js-sdk';
|
|
import fs from 'fs';
|
|
import log4js from 'log4js';
|
|
import https from 'https';
|
|
import { fileURLToPath } from 'url';
|
|
import { dirname } from 'path';
|
|
import request from 'request';
|
|
import FileType from 'file-type';
|
|
import express from 'express';
|
|
import bodyParser from 'body-parser';
|
|
import fetch from 'node-fetch';
|
|
|
|
// Save script start time for ignoring older messages
|
|
var boottimestamp = Date.now();
|
|
|
|
var client;
|
|
var __dirname;
|
|
var __filename;
|
|
var initialsynccomplete = false;
|
|
|
|
// Init logging
|
|
var logger = log4js.getLogger();
|
|
logger.level = "debug";
|
|
logger.info("Log initialized.");
|
|
var settings = {};
|
|
|
|
/**
|
|
* Load settings from config.json
|
|
*/
|
|
function loadSettingsFile() {
|
|
__filename = fileURLToPath(import.meta.url);
|
|
__dirname = dirname(__filename);
|
|
let rawdata = fs.readFileSync(__dirname + '/config.json');
|
|
settings = JSON.parse(rawdata);
|
|
console.log(__dirname + "/config.json loaded.");
|
|
logger.level = settings.loglevel;
|
|
}
|
|
|
|
loadSettingsFile();
|
|
|
|
// https://github.com/matrix-org/matrix-js-sdk/issues/2415#issuecomment-1188812401
|
|
matrixcs.request(request);
|
|
|
|
/**
|
|
* From https://github.com/stevekinney/node-phone-formatter
|
|
* @param {string} phoneNumber
|
|
* @param {string} formatString
|
|
* @returns {string}
|
|
*/
|
|
function formatPhoneNumber(phoneNumber, formatString) {
|
|
phoneNumber = phoneNumber.replace(
|
|
/^[\+\d{1,3}\-\s]*\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/,
|
|
"$1$2$3"
|
|
);
|
|
for (var i = 0, l = phoneNumber.length; i < l; i++) {
|
|
formatString = formatString.replace("N", phoneNumber[i]);
|
|
}
|
|
return formatString;
|
|
}
|
|
|
|
function checkSMS() {
|
|
logger.debug("Checking SMS");
|
|
const options = {
|
|
hostname: 'smsapi.voxtelesys.net',
|
|
port: 443,
|
|
path: '/api/v1/msgs/inbound?unread_only=true',
|
|
method: 'GET',
|
|
headers: {
|
|
"Authorization": "Bearer " + settings.smsapikey
|
|
}
|
|
};
|
|
const req = https.request(options, res => {
|
|
res.on('data', d => {
|
|
try {
|
|
var json = JSON.parse(d);
|
|
var messages = json.results;
|
|
if (messages.length == 0) {
|
|
logger.debug("No new SMS messages.");
|
|
}
|
|
|
|
for (var i = 0; i < messages.length; i++) {
|
|
let msg = messages[i];
|
|
if (settings.smsonlyto.length > 0 && settings.smsonlyto.indexOf(msg.to) != -1) {
|
|
logger.info("Received SMS from " + msg.from + " for " + msg.to + ": " + msg.body);
|
|
createOrJoinSMSRoom(msg.from, msg.to, function (roomid) {
|
|
sendMatrix(roomid, msg.body, msg.media);
|
|
});
|
|
} else {
|
|
logger.info("Received SMS from " + msg.from + " for " + msg.to + ", ignoring based on smsonlyto list.");
|
|
}
|
|
}
|
|
} catch (ex) {
|
|
logger.error(ex);
|
|
}
|
|
});
|
|
});
|
|
req.on('error', error => {
|
|
logger.warn(error);
|
|
});
|
|
req.end();
|
|
}
|
|
|
|
/**
|
|
* Connect to the server and get the room ID and stuff
|
|
* @param {type} alias
|
|
* @returns {undefined}
|
|
*/
|
|
async function getRoomIDFromAlias(alias) {
|
|
var info = await client.getRoomIdForAlias(alias);
|
|
if (typeof info.room_id != "undefined") {
|
|
return info;
|
|
}
|
|
|
|
var response = await fetch(settings.homeserver + "/_matrix/client/v3/directory/room/" + encodeURIComponent(alias));
|
|
if (response.status != 200) {
|
|
throw new Error("Fetch returned invalid status code " + response.status);
|
|
}
|
|
var json = await response.json();
|
|
return json;
|
|
}
|
|
|
|
|
|
/**
|
|
* Join or create+join a room with alias #SMS_{tel}. If already joined, do nothing.
|
|
* @param {string} tel
|
|
* @param {string} ournumber the phone number Matrix messages will be sent from for this room
|
|
* @param {function} callback function with the room ID as an argument.
|
|
* @returns {undefined}
|
|
*/
|
|
async function createOrJoinSMSRoom(tel, ournumber, callback) {
|
|
var roomName = "#SMS_" + tel + "_" + ournumber + ":" + settings.matrixdomain;
|
|
logger.debug("Checking if room " + roomName + " exists.");
|
|
try {
|
|
var res = await getRoomIDFromAlias(roomName);
|
|
logger.debug(JSON.stringify(res));
|
|
logger.debug("Room " + roomName + " exists!");
|
|
var inRoom = false;
|
|
if (!res.error) {
|
|
var rooms = (await client.getJoinedRooms()).joined_rooms;
|
|
for (var i = 0; i < rooms.length; i++) {
|
|
if (rooms[i] == res.room_id) {
|
|
inRoom = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (inRoom) {
|
|
// we're already in the room, do nothing
|
|
logger.debug("Room " + roomName + " already joined.");
|
|
client.setRoomTag(res.room_id, "u.matrix-bridge-voxtelesys-sms", {tel: tel, ournumber: ournumber, order: 0.5});
|
|
callback(res.room_id);
|
|
} else {
|
|
// not in the room, join it
|
|
client.joinRoom(res.room_id).then((room) => {
|
|
logger.debug("Room " + roomName + " joined.");
|
|
client.setRoomTag(room.room_id, "u.matrix-bridge-voxtelesys-sms", {tel: tel, ournumber: ournumber, order: 0.5});
|
|
callback(res.room_id);
|
|
});
|
|
}
|
|
return;
|
|
} catch (err) {
|
|
// room doesn't exist, create it
|
|
logger.debug(err);
|
|
logger.debug("Room " + roomName + " does not exist. Creating it now.");
|
|
var userPowerLevels = {};
|
|
for (var i = 0; i < settings.inviteusers.length; i++) {
|
|
userPowerLevels[settings.inviteusers[i]] = 50;
|
|
}
|
|
userPowerLevels[settings["matrixuser"]] = 100;
|
|
try {
|
|
var room = await client.createRoom({
|
|
room_alias_name: "SMS_" + tel + "_" + ournumber,
|
|
preset: "trusted_private_chat",
|
|
visibility: "private",
|
|
invite: settings.inviteusers,
|
|
power_level_content_override: {
|
|
"events": {
|
|
"m.room.name": 50,
|
|
"m.room.power_levels": 50,
|
|
"m.room.canonical_alias": 100
|
|
},
|
|
"events_default": 0,
|
|
"invite": 50,
|
|
"kick": 50,
|
|
"notifications": {
|
|
"room": 50
|
|
},
|
|
"redact": 50,
|
|
"state_default": 50,
|
|
"users": userPowerLevels,
|
|
"users_default": 50
|
|
},
|
|
is_direct: true,
|
|
name: formatPhoneNumber(tel, "(NNN) NNN-NNNN"),
|
|
topic: "SMS conversation with " + formatPhoneNumber(tel, "(NNN) NNN-NNNN") + " (using " + formatPhoneNumber(ournumber, "(NNN) NNN-NNNN") + ")"
|
|
});
|
|
logger.debug("Room" + roomName + " created with ID " + room.room_id);
|
|
// The first message or two we send doesn't go through unless we do this.
|
|
// It just spits out "Error sending event M_FORBIDDEN: Unknown room" instead.
|
|
createOrJoinSMSRoom(tel, ournumber, callback);
|
|
} catch (errr) {
|
|
logger.error("Could not create " + roomName + ".");
|
|
logger.error(errr);
|
|
}
|
|
}
|
|
}
|
|
|
|
function getAndUploadFile(url, callback) {
|
|
logger.info("Downloading MMS media " + url);
|
|
// download
|
|
request({url, encoding: null}, (err, resp, buffer) => {
|
|
FileType.fromBuffer(buffer).then(function (mimeobj) {
|
|
logger.debug(mimeobj);
|
|
if (typeof mimeobj == "undefined") {
|
|
logger.error("Undefined media mimetype, not uploading to Matrix.");
|
|
return;
|
|
}
|
|
// upload
|
|
logger.info("Uploading MMS media to Matrix " + url);
|
|
client.uploadContent(buffer, {
|
|
onlyContentUri: true,
|
|
rawResponse: false,
|
|
type: mimeobj.mime
|
|
}).then((res) => {
|
|
if (typeof callback == "function") {
|
|
callback(res, mimeobj.mime);
|
|
logger.info("Media URI: " + res);
|
|
}
|
|
}).catch((err) => {
|
|
if (typeof callback == "function") {
|
|
callback(false);
|
|
}
|
|
if (err.data.error == "Unknown room") {
|
|
return;
|
|
}
|
|
logger.error(err);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Send a message to a Matrix room.
|
|
* @param {string} room the room to post the message in.
|
|
* @param {string} body message content.
|
|
* @param {array} media Array of media URLs to download via HTTP(s) and send to Matrix.
|
|
* @returns {undefined}
|
|
*/
|
|
async function sendMatrix(room, body, media) {
|
|
var roomid = room;
|
|
if (room.startsWith("#")) {
|
|
try {
|
|
roomid = (await getRoomIDFromAlias()).room_id;
|
|
logger.info("Translated alias " + room + " to room ID " + roomid);
|
|
} catch (err) {
|
|
logger.error(err);
|
|
}
|
|
}
|
|
if (Array.isArray(media)) {
|
|
for (var i = 0; i < media.length; i++) {
|
|
getAndUploadFile(media[i], async function (uri, mimetype) {
|
|
if (mimetype == "image/jpg" || mimetype == "image/jpeg" || mimetype == "image/png" || mimetype == "image/gif") {
|
|
var content = {
|
|
body: "Image",
|
|
msgtype: "m.image",
|
|
url: uri,
|
|
info: {
|
|
mimetype: mimetype
|
|
}
|
|
};
|
|
} else {
|
|
var content = {
|
|
body: "File",
|
|
msgtype: "m.file",
|
|
url: uri,
|
|
info: {
|
|
mimetype: mimetype
|
|
}
|
|
};
|
|
}
|
|
|
|
try {
|
|
await client.sendEvent(roomid, "m.room.message", content, "");
|
|
return true;
|
|
} catch (err) {
|
|
if (err.data.error == "Unknown room") {
|
|
return;
|
|
}
|
|
logger.error(err);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
if (body != "") {
|
|
var content = {
|
|
body: body,
|
|
msgtype: "m.text"
|
|
};
|
|
try {
|
|
await client.sendEvent(roomid, "m.room.message", content, "");
|
|
return true;
|
|
} catch (err) {
|
|
if (err.data.error == "Unknown room") {
|
|
return false;
|
|
}
|
|
logger.error(err);
|
|
}
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
function sendMatrixNotice(roomid, body, callback) {
|
|
var content = {
|
|
body: body,
|
|
msgtype: "m.notice"
|
|
};
|
|
client.sendEvent(roomid, "m.room.message", content, "").then((res) => {
|
|
if (typeof callback == "function") {
|
|
callback(true);
|
|
}
|
|
}).catch((err) => {
|
|
if (typeof callback == "function") {
|
|
callback(false);
|
|
}
|
|
if (err.data.error == "Unknown room") {
|
|
return;
|
|
}
|
|
logger.error(err);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Send a SMS to a phone number.
|
|
* @param {string} number
|
|
* @param {string} body message content.
|
|
* @param {function|undefined} callback passes true when successful, false on failure.
|
|
* @returns {undefined}
|
|
*/
|
|
function sendSMS(number, from, body, callback) {
|
|
if (settings.googleverifiedsms) {
|
|
// Use Google Verified SMS to add business branding to SMS message
|
|
}
|
|
logger.info("Sending SMS to " + number + " from " + from);
|
|
var data = {
|
|
to: [number],
|
|
from: from,
|
|
body: body
|
|
};
|
|
const jsondata = JSON.stringify(data);
|
|
const options = {
|
|
hostname: 'smsapi.voxtelesys.net',
|
|
port: 443,
|
|
path: '/api/v1/sms',
|
|
method: 'POST',
|
|
headers: {
|
|
"Authorization": "Bearer " + settings.smsapikey,
|
|
"Content-Type": "application/json",
|
|
"Accept": "application/json"
|
|
}
|
|
}
|
|
|
|
const req = https.request(options, res => {
|
|
res.on('data', d => {
|
|
logger.debug(d.toString('utf8'));
|
|
});
|
|
});
|
|
req.on('error', error => {
|
|
logger.error(error);
|
|
callback(false);
|
|
});
|
|
req.write(jsondata);
|
|
req.end();
|
|
if (typeof callback == "function") {
|
|
callback(true);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send a SMS to a phone number.
|
|
* @param {string} number
|
|
* @param {string} body message content.
|
|
* @param {function|undefined} callback passes true when successful, false on failure.
|
|
* @returns {undefined}
|
|
*/
|
|
function sendMMS(number, from, mediauri, mimetype, callback) {
|
|
logger.info("Sending MMS to " + number + " from " + from);
|
|
var urichunks = mediauri.split("/"); // should result in something like [ "mxc:", "", "matrix.org", "mediaidhere90473473" ]
|
|
if (urichunks.length < 4) {
|
|
logger.error("Invalid media uri");
|
|
if (typeof callback == "function") {
|
|
callback(false);
|
|
}
|
|
return;
|
|
}
|
|
var httpmediaurl = settings.mediaurlpath;
|
|
|
|
httpmediaurl = httpmediaurl.replace("{{server-name}}", urichunks[2]);
|
|
httpmediaurl = httpmediaurl.replace("{{media-id}}", urichunks[3]);
|
|
|
|
var body = "";
|
|
var media = [httpmediaurl];
|
|
|
|
switch (mimetype) {
|
|
case "image/jpeg":
|
|
case "image/png":
|
|
case "image/gif":
|
|
case "image/bmp":
|
|
// These are likely to work, so don't include the URL
|
|
body = "";
|
|
break;
|
|
default:
|
|
// Send link to content too
|
|
body = httpmediaurl;
|
|
//media = [];
|
|
}
|
|
|
|
var data = {
|
|
to: [number],
|
|
from: from,
|
|
body: body,
|
|
media: media
|
|
};
|
|
const jsondata = JSON.stringify(data);
|
|
const options = {
|
|
hostname: 'smsapi.voxtelesys.net',
|
|
port: 443,
|
|
path: '/api/v1/sms',
|
|
method: 'POST',
|
|
headers: {
|
|
"Authorization": "Bearer " + settings.smsapikey,
|
|
"Content-Type": "application/json",
|
|
"Accept": "application/json"
|
|
}
|
|
}
|
|
|
|
const req = https.request(options, res => {
|
|
res.on('data', d => {
|
|
logger.debug(d.toString('utf8'));
|
|
});
|
|
});
|
|
req.on('error', error => {
|
|
logger.error(error);
|
|
if (typeof callback == "function") {
|
|
callback(false);
|
|
}
|
|
});
|
|
req.write(jsondata);
|
|
req.end();
|
|
if (typeof callback == "function") {
|
|
callback(true);
|
|
}
|
|
}
|
|
|
|
function handleHTTPRequest(req, res) {
|
|
try {
|
|
logger.info("Got HTTP request: " + req.url);
|
|
if (req.url == "/webhook") {
|
|
try {
|
|
var msg = req.body;
|
|
|
|
if (msg.type == "mo") {
|
|
if (settings.smsonlyto.length > 0 && settings.smsonlyto.indexOf(msg.to) != -1) {
|
|
logger.info("Received SMS from " + msg.from + " for " + msg.to + ": " + msg.body);
|
|
createOrJoinSMSRoom(msg.from, msg.to, function (roomid) {
|
|
logger.info("Sending to room " + roomid);
|
|
sendMatrix(roomid, msg.body, msg.media);
|
|
});
|
|
res.sendStatus(204);
|
|
res.end();
|
|
} else {
|
|
logger.info("Received SMS from " + msg.from + " for " + msg.to + ", ignoring based on smsonlyto list.");
|
|
res.sendStatus(403);
|
|
res.end();
|
|
}
|
|
} else {
|
|
res.sendStatus(403);
|
|
res.end();
|
|
}
|
|
} catch (ex) {
|
|
logger.error("Decoding webhook body: " + ex);
|
|
logger.error(req.body);
|
|
res.sendStatus(500);
|
|
res.end();
|
|
}
|
|
} else {
|
|
try {
|
|
res.sendStatus(404);
|
|
res.end();
|
|
} catch (err) {
|
|
logger.error(err);
|
|
}
|
|
}
|
|
} catch (exx) {
|
|
logger.error(exx);
|
|
}
|
|
}
|
|
|
|
// Access token empty
|
|
if (settings.matrixaccesstoken == false) {
|
|
logger.error("Matrix access token not set.");
|
|
if (settings.matrixuser == false || settings.matrixpass == false) {
|
|
logger.error("Config values for matrixuser and/or matrixpass are not valid.");
|
|
process.exit(1);
|
|
}
|
|
logger.error("Attempting to fetch access token for you...");
|
|
try {
|
|
request({
|
|
method: "POST",
|
|
uri: settings.homeserver + "/_matrix/client/v3/login",
|
|
json: {
|
|
type: "m.login.password",
|
|
user: settings.matrixuser,
|
|
password: settings.matrixpass
|
|
}
|
|
}, function (error, resp, body) {
|
|
if (!error && resp.statusCode == 200) {
|
|
if (body.access_token) {
|
|
logger.error("Got access token for you. Writing it to " + __dirname + "/config.json now.");
|
|
settings.matrixaccesstoken = body.access_token;
|
|
fs.writeFileSync(__dirname + '/config.json', JSON.stringify(settings, null, 4));
|
|
logger.error("Exiting. Please restart me to load new config file.");
|
|
process.exit();
|
|
}
|
|
} else {
|
|
logger.error("Couldn't get access token. Get it yourself: curl -XPOST -d '{\"type\":\"m.login.password\", \"user\":\"" + settings.matrixuser + "\", \"password\":\"password here\"}' \"https://matrix.netsyms.net/_matrix/client/v3/login\"");
|
|
}
|
|
});
|
|
} catch (ex) {
|
|
logger.error("Couldn't get access token. Get it yourself: curl -XPOST -d '{\"type\":\"m.login.password\", \"user\":\"" + settings.matrixuser + "\", \"password\":\"password here\"}' \"https://matrix.netsyms.net/_matrix/client/v3/login\"");
|
|
}
|
|
} else {
|
|
client = sdk.createClient({baseUrl: settings.homeserver, userId: settings.matrixuser, accessToken: settings.matrixaccesstoken});
|
|
var httpserver = express();
|
|
var jsonParser = bodyParser.json();
|
|
client.startClient({initialSyncLimit: 10});
|
|
logger.info("Plugged into the matrix.");
|
|
|
|
client.once("sync", function (state, prevState, res) {
|
|
logger.debug("Initial sync complete (" + state + ")");
|
|
initialsynccomplete = true;
|
|
httpserver.post("*", jsonParser, (req, res) => {
|
|
handleHTTPRequest(req, res);
|
|
});
|
|
httpserver.get("*", (req, res) => {
|
|
handleHTTPRequest(req, res);
|
|
});
|
|
httpserver.listen(settings.listenport, () => {
|
|
logger.info("HTTP server listening on port " + settings.listenport);
|
|
});
|
|
logger.info("Up and running.");
|
|
if (settings.smsinterval > 0) {
|
|
setInterval(checkSMS, settings.smsinterval * 1000);
|
|
checkSMS();
|
|
}
|
|
});
|
|
client.on("Room.timeline", function (event, room) {
|
|
try {
|
|
if (!initialsynccomplete) {
|
|
return; // ignore anything while we were offline
|
|
}
|
|
if (event.getType() !== "m.room.message") {
|
|
return; // only use messages
|
|
}
|
|
if (client.getUserId() == event.getSender()) {
|
|
return; // skip own messages to prevent loop
|
|
}
|
|
if (event.getTs() < (Date.now() - 1000 * 60 * 60 * 8)) {
|
|
// Ignore old events (8 hrs), they're probably duplicates or something.
|
|
logger.warn("Ignoring stale Matrix room event [" + event.getId() + "]: older than 8 hours");
|
|
return;
|
|
}
|
|
if (event.getTs() < boottimestamp) {
|
|
logger.warn("Ignoring stale Matrix room event [" + event.getId() + "]: event predates start of this program");
|
|
return;
|
|
}
|
|
if (event.getContent() == null || typeof event.getContent().body == "undefined" || event.getContent().body == null) {
|
|
// Apparently this can happen?
|
|
return;
|
|
}
|
|
logger.debug("Got room message (event ID " + event.getId() + ")");
|
|
|
|
if (event.getContent().body.toLowerCase().startsWith("!sms")) {
|
|
// capture command to start room for new number
|
|
const matches = event.getContent().body.match(/([1-9]?[0-9]{10})/g);
|
|
if (matches == null) {
|
|
return;
|
|
}
|
|
if (matches.length == 1 || matches.length == 2) {
|
|
var tel = matches[0];
|
|
var ournumber = settings.smsfrom;
|
|
if (tel.length == 10) {
|
|
// make it the full number
|
|
tel = "1" + tel;
|
|
}
|
|
if (matches.length == 2) {
|
|
ournumber = matches[1];
|
|
if (ournumber.length == 10) {
|
|
// make it the full number
|
|
ournumber = "1" + ournumber;
|
|
}
|
|
}
|
|
logger.info("Got request to start new SMS conversation with " + tel + " using " + ournumber + " from " + event.getSender() + ".");
|
|
sendMatrixNotice(event.getRoomId(), "Starting conversation with " + tel);
|
|
createOrJoinSMSRoom(tel, ournumber, function (roomid) {
|
|
//client.setRoomTag(roomid, "u.matrix-bridge-voxtelesys-sms", {tel: tel, ournumber: ournumber});
|
|
});
|
|
}
|
|
return;
|
|
} else if (event.getContent().body.toLowerCase().replace(/\s/g, "").startsWith("!sms")) {
|
|
sendMatrixNotice(event.getRoomId(), "Malformed command detected, ignoring.");
|
|
sendMatrixNotice(event.getRoomId(), "Hint: there aren't supposed to be any spaces before or in the \"!sms\" part.");
|
|
return;
|
|
}
|
|
|
|
if (event.getContent().body.toLowerCase().startsWith("!fixusers")) {
|
|
sendMatrixNotice(event.getRoomId(), "Inviting missing users across all SMS chats. You may need to run this command several times, there's a server limit to how many invites can be sent at once.");
|
|
|
|
client.getJoinedRooms().then(function (rooms) {
|
|
var roomlist = rooms.joined_rooms;
|
|
for (var i = 0; i < roomlist.length; i++) {
|
|
(function (roomid) {
|
|
client.getJoinedRoomMembers(roomid).then(function (joined) {
|
|
var members = Object.keys(joined.joined);
|
|
for (var j = 0; j < settings.inviteusers.length; j++) {
|
|
if (members.indexOf(settings.inviteusers[j]) == -1) {
|
|
logger.info("Inviting missing user " + settings.inviteusers[j] + " to room " + roomid);
|
|
client.invite(roomid, settings.inviteusers[j]);
|
|
}
|
|
}
|
|
});
|
|
})(roomlist[i]);
|
|
}
|
|
});
|
|
|
|
|
|
return;
|
|
} else if (event.getContent().body.toLowerCase().replace(/\s/g, "").startsWith("!fixusers")) {
|
|
sendMatrixNotice(event.getRoomId(), "Malformed command detected, ignoring.");
|
|
return;
|
|
}
|
|
|
|
if (event.getContent().body.toLowerCase().replace(/\s/g, "").startsWith("!")) {
|
|
sendMatrixNotice(event.getRoomId(), "I'm sorry, but my programming forbids me from sending text messages that start with `!`.");
|
|
return;
|
|
}
|
|
|
|
var matches = room.name.match(/SMS_([1-9][0-9]+)(?:_([1-9][0-9]+))?/g);
|
|
if (matches == null || (matches.length != 1 && matches.length != 2)) {
|
|
client.getRoomTags(event.getRoomId()).then((response) => {
|
|
console.log(response);
|
|
if (typeof response.tags["u.matrix-bridge-voxtelesys-sms"] != "undefined") {
|
|
var tel = response.tags["u.matrix-bridge-voxtelesys-sms"].tel;
|
|
var from = response.tags["u.matrix-bridge-voxtelesys-sms"].ournumber;
|
|
logger.info("Got message for " + tel + " from " + event.getSender() + ", relaying to " + from + ".");
|
|
switch (event.getContent().msgtype) {
|
|
case "m.image":
|
|
case "m.file":
|
|
case "m.video":
|
|
sendMMS(
|
|
tel,
|
|
from,
|
|
event.getContent().url,
|
|
event.getContent().info.mimetype,
|
|
function () {
|
|
client.sendReadReceipt(event, "m.read");
|
|
});
|
|
break;
|
|
case "m.text":
|
|
default:
|
|
sendSMS(
|
|
tel,
|
|
from,
|
|
event.getContent().body,
|
|
function () {
|
|
client.sendReadReceipt(event, "m.read");
|
|
});
|
|
break;
|
|
}
|
|
} else if (typeof response.tags["com.netsyms.matrix-bridge-voxtelesys.sms"] != "undefined") {
|
|
var tel = response.tags["com.netsyms.matrix-bridge-voxtelesys.sms"].tel;
|
|
var from = response.tags["com.netsyms.matrix-bridge-voxtelesys.sms"].ournumber;
|
|
client.setRoomTag(event.getRoomId(), "u.matrix-bridge-voxtelesys-sms", {tel: tel, ournumber: from, order: 0.5});
|
|
logger.info("Got message for " + tel + " from " + event.getSender() + ", relaying to " + from + ".");
|
|
switch (event.getContent().msgtype) {
|
|
case "m.image":
|
|
case "m.file":
|
|
case "m.video":
|
|
sendMMS(
|
|
tel,
|
|
from,
|
|
event.getContent().url,
|
|
event.getContent().info.mimetype,
|
|
function () {
|
|
client.sendReadReceipt(event, "m.read");
|
|
});
|
|
break;
|
|
case "m.text":
|
|
default:
|
|
sendSMS(
|
|
tel,
|
|
from,
|
|
event.getContent().body,
|
|
function () {
|
|
client.sendReadReceipt(event, "m.read");
|
|
});
|
|
break;
|
|
}
|
|
} else {
|
|
console.log(response.tags);
|
|
sendMatrixNotice(room.roomId, "Error: couldn't determine correct number to send SMS from.");
|
|
}
|
|
});
|
|
} else {
|
|
if (matches.length == 1) {
|
|
var tel = matches[0];
|
|
logger.info("Got message for " + tel + " from " + event.getSender() + ", relaying.");
|
|
switch (event.getContent().msgtype) {
|
|
case "m.image":
|
|
case "m.file":
|
|
case "m.video":
|
|
sendMMS(tel, settings.smsfrom, event.getContent().url,
|
|
event.getContent().info.mimetype,
|
|
function () {
|
|
client.sendReadReceipt(event, "m.read");
|
|
});
|
|
break;
|
|
case "m.text":
|
|
default:
|
|
sendSMS(tel, settings.smsfrom, event.getContent().body, function () {
|
|
client.sendReadReceipt(event, "m.read");
|
|
});
|
|
break;
|
|
}
|
|
} else if (matches.length == 2) {
|
|
var tel = matches[0];
|
|
var from = matches[1];
|
|
logger.info("Got message for " + tel + " from " + event.getSender() + ", relaying to " + from + ".");
|
|
switch (event.getContent().msgtype) {
|
|
case "m.image":
|
|
case "m.file":
|
|
case "m.video":
|
|
sendMMS(tel, from, event.getContent().url,
|
|
event.getContent().info.mimetype,
|
|
function () {
|
|
client.sendReadReceipt(event, "m.read");
|
|
});
|
|
break;
|
|
case "m.text":
|
|
default:
|
|
sendSMS(tel, settings.smsfrom, event.getContent().body, function () {
|
|
client.sendReadReceipt(event, "m.read");
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} catch (ex) {
|
|
logger.error("Error handling incoming event: " + ex);
|
|
}
|
|
});
|
|
} |