mirror of
https://github.com/plantroon/mx-puppet-xmpp.git
synced 2024-12-22 06:31:41 +00:00
Basic XMPP
This commit is contained in:
parent
282e4da983
commit
db76a70295
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,5 +1,8 @@
|
|||||||
node_modules
|
node_modules
|
||||||
config.yaml
|
config.yaml
|
||||||
build
|
build
|
||||||
skype-registration.yaml
|
registration.yaml
|
||||||
|
xmpp-registration.yaml
|
||||||
*.db
|
*.db
|
||||||
|
*-audit.json
|
||||||
|
*.log.*
|
24
Dockerfile
24
Dockerfile
@ -1,11 +1,11 @@
|
|||||||
FROM node:alpine AS builder
|
FROM node:alpine AS builder
|
||||||
|
|
||||||
WORKDIR /opt/mx-puppet-skype
|
WORKDIR /opt/mx-puppet-xmpp
|
||||||
|
|
||||||
# run build process as user in case of npm pre hooks
|
# run build process as user in case of npm pre hooks
|
||||||
# pre hooks are not executed while running as root
|
# pre hooks are not executed while running as root
|
||||||
RUN chown node:node /opt/mx-puppet-skype
|
RUN chown node:node /opt/mx-puppet-xmpp
|
||||||
RUN apk --no-cache add git python make g++ pkgconfig \
|
RUN apk update && apk --no-cache add git python3 make g++ pkgconfig \
|
||||||
build-base \
|
build-base \
|
||||||
cairo-dev \
|
cairo-dev \
|
||||||
jpeg-dev \
|
jpeg-dev \
|
||||||
@ -15,7 +15,8 @@ RUN apk --no-cache add git python make g++ pkgconfig \
|
|||||||
pixman-dev \
|
pixman-dev \
|
||||||
pangomm-dev \
|
pangomm-dev \
|
||||||
libjpeg-turbo-dev \
|
libjpeg-turbo-dev \
|
||||||
freetype-dev
|
freetype-dev \
|
||||||
|
&& rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
RUN wget -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub && \
|
RUN wget -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub && \
|
||||||
wget -O glibc-2.32-r0.apk https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.32-r0/glibc-2.32-r0.apk && \
|
wget -O glibc-2.32-r0.apk https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.32-r0/glibc-2.32-r0.apk && \
|
||||||
@ -38,10 +39,10 @@ FROM node:alpine
|
|||||||
VOLUME /data
|
VOLUME /data
|
||||||
|
|
||||||
ENV CONFIG_PATH=/data/config.yaml \
|
ENV CONFIG_PATH=/data/config.yaml \
|
||||||
REGISTRATION_PATH=/data/skype-registration.yaml
|
REGISTRATION_PATH=/data/xmpp-registration.yaml
|
||||||
|
|
||||||
# su-exec is used by docker-run.sh to drop privileges
|
# su-exec is used by docker-run.sh to drop privileges
|
||||||
RUN apk add --no-cache su-exec \
|
RUN apk update && apk add --no-cache su-exec \
|
||||||
cairo \
|
cairo \
|
||||||
jpeg \
|
jpeg \
|
||||||
pango \
|
pango \
|
||||||
@ -50,15 +51,16 @@ RUN apk add --no-cache su-exec \
|
|||||||
pixman \
|
pixman \
|
||||||
pangomm \
|
pangomm \
|
||||||
libjpeg-turbo \
|
libjpeg-turbo \
|
||||||
freetype
|
freetype \
|
||||||
|
&& rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
|
|
||||||
WORKDIR /opt/mx-puppet-skype
|
WORKDIR /opt/mx-puppet-xmpp
|
||||||
COPY docker-run.sh ./
|
COPY docker-run.sh ./
|
||||||
COPY --from=builder /opt/mx-puppet-skype/node_modules/ ./node_modules/
|
COPY --from=builder /opt/mx-puppet-xmpp/node_modules/ ./node_modules/
|
||||||
COPY --from=builder /opt/mx-puppet-skype/build/ ./build/
|
COPY --from=builder /opt/mx-puppet-xmpp/build/ ./build/
|
||||||
|
|
||||||
# change workdir to /data so relative paths in the config.yaml
|
# change workdir to /data so relative paths in the config.yaml
|
||||||
# point to the persisten volume
|
# point to the persisten volume
|
||||||
WORKDIR /data
|
WORKDIR /data
|
||||||
ENTRYPOINT ["/opt/mx-puppet-skype/docker-run.sh"]
|
ENTRYPOINT ["/opt/mx-puppet-xmpp/docker-run.sh"]
|
||||||
|
40
README.md
40
README.md
@ -1,11 +1,17 @@
|
|||||||
[![Support room on Matrix](https://img.shields.io/matrix/mx-puppet-bridge:sorunome.de.svg?label=%23mx-puppet-bridge%3Asorunome.de&logo=matrix&server_fqdn=sorunome.de)](https://matrix.to/#/#mx-puppet-bridge:sorunome.de)[![donate](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/Sorunome/donate)
|
[![donate](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/rkd/donate)
|
||||||
|
|
||||||
# mx-puppet-skype
|
# [WIP] mx-puppet-xmpp
|
||||||
This is a skype puppeting bridge for matrix. It is based on [mx-puppet-bridge](https://github.com/Sorunome/mx-puppet-bridge) and provide multi-user instances.
|
This is a xmpp puppeting bridge for matrix. It is based on [mx-puppet-bridge](https://github.com/Sorunome/mx-puppet-bridge) and provide multi-user instances.
|
||||||
|
|
||||||
|
##
|
||||||
|
|
||||||
## Quick start using Docker
|
## Quick start using Docker
|
||||||
|
|
||||||
Docker image can be found at https://hub.docker.com/r/sorunome/mx-puppet-skype
|
To build docker image:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker build -t mx-puppet-xmpp:latest .
|
||||||
|
```
|
||||||
|
|
||||||
For docker you probably want the following changes in `config.yaml`:
|
For docker you probably want the following changes in `config.yaml`:
|
||||||
|
|
||||||
@ -21,16 +27,16 @@ Also check the config for other values, like your homeserver domain.
|
|||||||
|
|
||||||
* Clone and install:
|
* Clone and install:
|
||||||
```
|
```
|
||||||
git clone https://github.com/Sorunome/mx-puppet-skype.git
|
git clone https://github.com/Sorunome/mx-puppet-xmpp.git
|
||||||
cd mx-puppet-skype
|
cd mx-puppet-xmpp
|
||||||
npm install
|
npm install
|
||||||
* Edit the configuration file and generate the registration file:
|
* Edit the configuration file and generate the registration file:
|
||||||
```
|
```
|
||||||
cp sample.config.yaml config.yaml
|
cp sample.config.yaml config.yaml
|
||||||
# fill info about your homeserver and skype app credentials to config.yaml manually
|
# fill info about your homeserver and xmpp app credentials to config.yaml manually
|
||||||
npm run start -- -r # generate registration file
|
npm run start -- -r # generate registration file
|
||||||
or
|
or
|
||||||
docker run -v </path/to/host>/data:/data -it sorunome/mx-puppet-skype -r
|
docker run -v </path/to/host>/data:/data -it mx-puppet-xmpp -r
|
||||||
```
|
```
|
||||||
* Copy the registration file to your synapse config directory.
|
* Copy the registration file to your synapse config directory.
|
||||||
* Add the registration file to the list under `app_service_config_files:` in your synapse config.
|
* Add the registration file to the list under `app_service_config_files:` in your synapse config.
|
||||||
@ -39,9 +45,9 @@ Also check the config for other values, like your homeserver domain.
|
|||||||
```
|
```
|
||||||
npm run start
|
npm run start
|
||||||
```
|
```
|
||||||
* Start a direct chat with the bot user (`@_skypepuppet_bot:domain.tld` unless you changed the config).
|
* Start a direct chat with the bot user (`@_xmpppuppet_bot:domain.tld` unless you changed the config).
|
||||||
(Give it some time after the invite, it'll join after a minute maybe.)
|
(Give it some time after the invite, it'll join after a minute maybe.)
|
||||||
* Get your Skype username and password as below, and tell the bot user to link your skype account:
|
* Get your Xmpp username and password as below, and tell the bot user to link your xmpp account:
|
||||||
```
|
```
|
||||||
link <username> <password>
|
link <username> <password>
|
||||||
```
|
```
|
||||||
@ -50,3 +56,17 @@ Also check the config for other values, like your homeserver domain.
|
|||||||
list
|
list
|
||||||
```
|
```
|
||||||
Clicking rooms in the list will result in you receiving an invite to the bridged room.
|
Clicking rooms in the list will result in you receiving an invite to the bridged room.
|
||||||
|
|
||||||
|
## Working
|
||||||
|
|
||||||
|
- link
|
||||||
|
- text messages (mx -> xmpp)
|
||||||
|
- text messages (xmpp -> mx)
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- replies
|
||||||
|
- edits
|
||||||
|
- deletes
|
||||||
|
- images
|
||||||
|
- files
|
@ -32,7 +32,7 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# $su_exec is used in case we have to drop the privileges
|
# $su_exec is used in case we have to drop the privileges
|
||||||
exec $su_exec /usr/local/bin/node '/opt/mx-puppet-skype/build/index.js' \
|
exec $su_exec /usr/local/bin/node '/opt/mx-puppet-xmpp/build/index.js' \
|
||||||
-c "$CONFIG_PATH" \
|
-c "$CONFIG_PATH" \
|
||||||
-f "$REGISTRATION_PATH" \
|
-f "$REGISTRATION_PATH" \
|
||||||
$args
|
$args
|
||||||
|
7629
package-lock.json
generated
7629
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "mx-puppet-skype",
|
"name": "mx-puppet-xmpp",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
@ -9,9 +9,9 @@
|
|||||||
"start": "npm run-script build && node ./build/index.js",
|
"start": "npm run-script build && node ./build/index.js",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"author": "Sorunome",
|
"author": "rkd",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sorunome/skype-http": "^1.5.2",
|
"@xmpp/client": "^0.13.0",
|
||||||
"cheerio": "^1.0.0-rc.3",
|
"cheerio": "^1.0.0-rc.3",
|
||||||
"command-line-args": "^5.1.1",
|
"command-line-args": "^5.1.1",
|
||||||
"command-line-usage": "^5.0.5",
|
"command-line-usage": "^5.0.5",
|
||||||
@ -20,7 +20,7 @@
|
|||||||
"events": "^3.0.0",
|
"events": "^3.0.0",
|
||||||
"expire-set": "^1.0.0",
|
"expire-set": "^1.0.0",
|
||||||
"js-yaml": "^3.13.1",
|
"js-yaml": "^3.13.1",
|
||||||
"mx-puppet-bridge": "0.1.4",
|
"mx-puppet-bridge": "0.1.6",
|
||||||
"node-emoji": "^1.10.0",
|
"node-emoji": "^1.10.0",
|
||||||
"node-html-parser": "^1.2.13",
|
"node-html-parser": "^1.2.13",
|
||||||
"tough-cookie": "^4.0.0",
|
"tough-cookie": "^4.0.0",
|
||||||
|
389
src/client.ts
389
src/client.ts
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2020 mx-puppet-skype
|
Copyright 2020 mx-puppet-xmpp
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
@ -11,185 +11,108 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Log, IRemoteRoom, Util } from "mx-puppet-bridge";
|
import { Log, IRemoteRoom } from "mx-puppet-bridge";
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
import * as skypeHttp from "@sorunome/skype-http";
|
import { client, xml } from "@xmpp/client";
|
||||||
import { Contact as SkypeContact } from "@sorunome/skype-http/dist/lib/types/contact";
|
import { Client as XmppClient } from "@xmpp/client-core";
|
||||||
import { NewMediaMessage as SkypeNewMediaMessage } from "@sorunome/skype-http/dist/lib/interfaces/api/api";
|
|
||||||
import { Context as SkypeContext } from "@sorunome/skype-http/dist/lib/interfaces/api/context";
|
|
||||||
import ExpireSet from "expire-set";
|
|
||||||
import * as toughCookie from "tough-cookie";
|
|
||||||
|
|
||||||
const log = new Log("SkypePuppet:client");
|
const log = new Log("XmppPuppet:client");
|
||||||
|
|
||||||
// tslint:disable no-magic-numbers
|
type Contact = {
|
||||||
const ID_TIMEOUT = 60000;
|
personId: string,
|
||||||
const CONTACTS_DELTA_INTERVAL = 5 * 60 * 1000;
|
workloads: any,
|
||||||
// tslint:enable no-magic-numbers
|
mri: string,
|
||||||
|
blocked: boolean,
|
||||||
|
authorized: boolean,
|
||||||
|
creationTime: Date,
|
||||||
|
displayName: string,
|
||||||
|
displayNameSource: any, // tslint:disable-line no-any
|
||||||
|
profile: {
|
||||||
|
roomId: string,
|
||||||
|
avatarUrl: string | undefined,
|
||||||
|
name: {
|
||||||
|
first: string | undefined,
|
||||||
|
surname: string | undefined,
|
||||||
|
nickname: string | undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
export class Client extends EventEmitter {
|
export class Client extends EventEmitter {
|
||||||
public contacts: Map<string, SkypeContact> = new Map();
|
public contacts: Map<string, Contact> = new Map();
|
||||||
public conversations: Map<string, skypeHttp.Conversation> = new Map();
|
public conversations: Map<string, any> = new Map();
|
||||||
private api: skypeHttp.Api;
|
private api: XmppClient;
|
||||||
private handledIds: ExpireSet<string>;
|
|
||||||
private contactsInterval: NodeJS.Timeout | null = null;
|
|
||||||
constructor(
|
constructor(
|
||||||
private loginUsername: string,
|
private loginUsername: string,
|
||||||
private password: string,
|
private password: string,
|
||||||
private state?: SkypeContext.Json,
|
) { super(); }
|
||||||
) {
|
|
||||||
super();
|
|
||||||
this.handledIds = new ExpireSet(ID_TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get username(): string {
|
public get username(): string {
|
||||||
return "8:" + this.api.context.username;
|
return this.loginUsername.split("@")[0].trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
public get getState(): SkypeContext.Json {
|
public get host(): string {
|
||||||
return this.api.getState();
|
return this.loginUsername.split("@")[1].trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get getState() {
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async connect() {
|
public async connect() {
|
||||||
let connectedWithAuth = false;
|
log.info("Connecting to ", this.host);
|
||||||
if (this.state) {
|
log.info(this.username);
|
||||||
try {
|
|
||||||
this.api = await skypeHttp.connect({ state: this.state, verbose: true });
|
|
||||||
connectedWithAuth = true;
|
|
||||||
} catch (err) {
|
|
||||||
this.api = await skypeHttp.connect({
|
|
||||||
credentials: {
|
|
||||||
username: this.loginUsername,
|
|
||||||
password: this.password,
|
|
||||||
},
|
|
||||||
verbose: true,
|
|
||||||
});
|
|
||||||
connectedWithAuth = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.api = await skypeHttp.connect({
|
|
||||||
credentials: {
|
|
||||||
username: this.loginUsername,
|
|
||||||
password: this.password,
|
|
||||||
},
|
|
||||||
verbose: true,
|
|
||||||
});
|
|
||||||
connectedWithAuth = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
this.api = client({
|
||||||
await this.startupApi();
|
service: "ws://"+this.host+":5280/xmpp-websocket",
|
||||||
} catch (err) {
|
domain: this.host,
|
||||||
if (!connectedWithAuth) {
|
resource: "mx_bridge",
|
||||||
throw err;
|
username: this.username,
|
||||||
}
|
password: this.password,
|
||||||
this.api = await skypeHttp.connect({
|
});
|
||||||
credentials: {
|
|
||||||
username: this.loginUsername,
|
|
||||||
password: this.password,
|
|
||||||
},
|
|
||||||
verbose: true,
|
|
||||||
});
|
|
||||||
connectedWithAuth = false;
|
|
||||||
await this.startupApi();
|
|
||||||
}
|
|
||||||
|
|
||||||
const registerErrorHandler = () => {
|
await this.startupApi();
|
||||||
this.api.on("error", (err: Error) => {
|
|
||||||
log.error("An error occured", err);
|
|
||||||
this.emit("error", err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (connectedWithAuth) {
|
this.api.on("error", (err: Error) => {
|
||||||
let resolved = false;
|
log.error("An error occured", err);
|
||||||
return new Promise(async (resolve, reject) => {
|
this.emit("error", err);
|
||||||
const TIMEOUT_SUCCESS = 5000;
|
});
|
||||||
setTimeout(() => {
|
this.api.start();
|
||||||
if (resolved) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolved = true;
|
|
||||||
registerErrorHandler();
|
|
||||||
resolve();
|
|
||||||
}, TIMEOUT_SUCCESS);
|
|
||||||
this.api.once("error", async () => {
|
|
||||||
if (resolved) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolved = true;
|
|
||||||
// alright, re-try as normal user
|
|
||||||
try {
|
|
||||||
await this.api.stopListening();
|
|
||||||
this.api = await skypeHttp.connect({
|
|
||||||
credentials: {
|
|
||||||
username: this.loginUsername,
|
|
||||||
password: this.password,
|
|
||||||
},
|
|
||||||
verbose: true,
|
|
||||||
});
|
|
||||||
await this.startupApi();
|
|
||||||
registerErrorHandler();
|
|
||||||
resolve();
|
|
||||||
} catch (err) {
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
await this.api.listen();
|
|
||||||
}).then(async () => {
|
|
||||||
await this.api.setStatus("Online");
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
registerErrorHandler();
|
|
||||||
await this.api.listen();
|
|
||||||
await this.api.setStatus("Online");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async disconnect() {
|
public async disconnect() {
|
||||||
if (this.api) {
|
if (this.api) {
|
||||||
await this.api.stopListening();
|
await this.api.stop();
|
||||||
}
|
|
||||||
if (this.contactsInterval) {
|
|
||||||
clearInterval(this.contactsInterval);
|
|
||||||
this.contactsInterval = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getContact(id: string): Promise<SkypeContact | null> {
|
public async getContact(username: string): Promise<any> {
|
||||||
log.debug(`Fetching contact ${id}`);
|
log.debug(`Fetching contact from: ` + username);
|
||||||
const hasStart = Boolean(id.match(/^\d+:/));
|
if (this.contacts.has(username)) {
|
||||||
const fullId = hasStart ? id : `8:${id}`;
|
const ret = this.contacts.get(username);
|
||||||
if (this.contacts.has(fullId)) {
|
|
||||||
log.debug("Returning cached result");
|
|
||||||
const ret = this.contacts.get(fullId) || null;
|
|
||||||
log.silly(ret);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
if (hasStart) {
|
|
||||||
id = id.substr(id.indexOf(":") + 1);
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
const rawContact = await this.api.getContact(id);
|
const contact = {
|
||||||
const contact: SkypeContact = {
|
personId: username,
|
||||||
personId: rawContact.id.raw,
|
|
||||||
workloads: null,
|
workloads: null,
|
||||||
mri: rawContact.id.raw,
|
mri: username,
|
||||||
blocked: false,
|
blocked: false,
|
||||||
authorized: true,
|
authorized: true,
|
||||||
creationTime: new Date(),
|
creationTime: new Date(),
|
||||||
displayName: (rawContact.name && rawContact.name.displayName) || rawContact.id.id,
|
displayName: username,
|
||||||
displayNameSource: "profile" as any, // tslint:disable-line no-any
|
displayNameSource: "profile" as any, // tslint:disable-line no-any
|
||||||
profile: {
|
profile: {
|
||||||
avatarUrl: rawContact.avatarUrl || undefined,
|
roomId: username,
|
||||||
|
avatarUrl: undefined,
|
||||||
name: {
|
name: {
|
||||||
first: (rawContact.name && rawContact.name).first || undefined,
|
first: undefined,
|
||||||
surname: (rawContact.name && rawContact.name).surname || undefined,
|
surname: undefined,
|
||||||
nickname: (rawContact.name && rawContact.name).nickname || undefined,
|
nickname: username,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
this.contacts.set(contact.mri, contact || null);
|
this.contacts.set(contact.mri, contact);
|
||||||
log.debug("Returning new result");
|
log.debug("Returning new result");
|
||||||
log.silly(contact);
|
log.silly(contact);
|
||||||
return contact || null;
|
return contact || null;
|
||||||
@ -201,181 +124,93 @@ export class Client extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getConversation(room: IRemoteRoom): Promise<skypeHttp.Conversation | null> {
|
public async getConversation(room: IRemoteRoom): Promise<any> {
|
||||||
log.debug(`Fetching conversation puppetId=${room.puppetId} roomId=${room.roomId}`);
|
log.info(`Fetching conversation`, room);
|
||||||
|
log.info(`Fetching conversation puppetId=${room.puppetId} roomId=${room.roomId}`);
|
||||||
let id = room.roomId;
|
let id = room.roomId;
|
||||||
const match = id.match(/^dm-\d+-/);
|
|
||||||
if (match) {
|
|
||||||
const [_, puppetId] = id.split("-");
|
|
||||||
if (Number(puppetId) !== room.puppetId) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
id = id.substr(match[0].length);
|
|
||||||
}
|
|
||||||
if (this.conversations.has(id)) {
|
if (this.conversations.has(id)) {
|
||||||
log.debug("Returning cached result");
|
log.info("Returning cached result");
|
||||||
const ret = this.conversations.get(id) || null;
|
const ret = this.conversations.get(id) || null;
|
||||||
log.silly(ret);
|
log.silly(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const conversation = await this.api.getConversation(id);
|
const conversation = {id: room.roomId, members: []};
|
||||||
this.conversations.set(conversation.id, conversation || null);
|
this.conversations.set(room.roomId, conversation || null);
|
||||||
log.debug("Returning new result");
|
log.info("Returning new result");
|
||||||
log.silly(conversation);
|
log.info(conversation);
|
||||||
return conversation || null;
|
return conversation || null;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// conversation not found
|
// conversation not found
|
||||||
log.debug("No such conversation found");
|
log.error("No such conversation found");
|
||||||
log.debug(err.body || err);
|
log.error(err.body || err);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async downloadFile(url: string, type: string = "imgpsh_fullsize_anim"): Promise<Buffer> {
|
public async downloadFile(url: string, type: string = "imgpsh_fullsize_anim") {
|
||||||
if (url.startsWith("https://api.asm.skype.com/") && !url.includes("/views/")) {
|
// TODO
|
||||||
url = `${url}/views/${type}`;
|
|
||||||
}
|
|
||||||
const cookieJar = new toughCookie.CookieJar(this.api.context.cookies);
|
|
||||||
return await Util.DownloadFile(url, {
|
|
||||||
responseType: "buffer",
|
|
||||||
headers: {
|
|
||||||
Authorization: "skypetoken=" + this.api.context.skypeToken.value,
|
|
||||||
RegistrationToken: this.api.context.registrationToken.raw,
|
|
||||||
},
|
|
||||||
cookieJar: {
|
|
||||||
setCookie: async (rawCookie: string, cookieUrl: string) =>
|
|
||||||
new Promise((resolve, reject) =>
|
|
||||||
cookieJar.setCookie(rawCookie, cookieUrl, (err, value) =>
|
|
||||||
err ? reject(err) : resolve(value),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
getCookieString: async (cookieUrl: string) =>
|
|
||||||
new Promise((resolve, reject) =>
|
|
||||||
cookieJar.getCookieString(cookieUrl, (err, value) => {
|
|
||||||
if (err) {
|
|
||||||
reject(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (url.startsWith("https://api.asm.skype.com/")) {
|
|
||||||
if (value) {
|
|
||||||
value += "; ";
|
|
||||||
}
|
|
||||||
value += "skypetoken_asm=" + encodeURIComponent(this.api.context.skypeToken.value);
|
|
||||||
}
|
|
||||||
resolve(value);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async sendMessage(conversationId: string, msg: string): Promise<skypeHttp.Api.SendMessageResult> {
|
public async sendMessage(conversationId: string, msg: string) {
|
||||||
return await this.api.sendMessage({
|
return await this.api.send(xml(
|
||||||
textContent: msg,
|
"message",
|
||||||
}, conversationId);
|
{ type: "chat", to: conversationId },
|
||||||
|
xml("body", {}, msg),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async sendEdit(conversationId: string, messageId: string, msg: string) {
|
public async sendEdit(conversationId: string, messageId: string, msg: string) {
|
||||||
return await this.api.sendEdit({
|
// TODO
|
||||||
textContent: msg,
|
// return await this.api.sendEdit({
|
||||||
}, conversationId, messageId);
|
// textContent: msg,
|
||||||
|
// }, conversationId, messageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async sendDelete(conversationId: string, messageId: string) {
|
public async sendDelete(conversationId: string, messageId: string) {
|
||||||
return await this.api.sendDelete(conversationId, messageId);
|
// TODO
|
||||||
|
// return await this.api.sendDelete(conversationId, messageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async sendAudio(
|
public async sendAudio(
|
||||||
conversationId: string,
|
conversationId: string,
|
||||||
opts: SkypeNewMediaMessage,
|
opts: any,
|
||||||
): Promise<skypeHttp.Api.SendMessageResult> {
|
) {
|
||||||
return await this.api.sendAudio(opts, conversationId);
|
// TODO
|
||||||
|
// return await this.api.sendAudio(opts, conversationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async sendDocument(
|
public async sendDocument(
|
||||||
conversationId: string,
|
conversationId: string,
|
||||||
opts: SkypeNewMediaMessage,
|
opts: any,
|
||||||
): Promise<skypeHttp.Api.SendMessageResult> {
|
) {
|
||||||
return await this.api.sendDocument(opts, conversationId);
|
// TODO
|
||||||
|
// return await this.api.sendDocument(opts, conversationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async sendImage(
|
public async sendImage(
|
||||||
conversationId: string,
|
conversationId: string,
|
||||||
opts: SkypeNewMediaMessage,
|
opts: any,
|
||||||
): Promise<skypeHttp.Api.SendMessageResult> {
|
) {
|
||||||
return await this.api.sendImage(opts, conversationId);
|
// TODO
|
||||||
|
// return await this.api.sendImage(opts, conversationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async startupApi() {
|
private async startupApi() {
|
||||||
this.api.on("event", (evt: skypeHttp.events.EventMessage) => {
|
this.api.on("stanza", async (stanza) => {
|
||||||
if (!evt || !evt.resource) {
|
if (stanza.is("message")) {
|
||||||
return;
|
this.emit("text", stanza);
|
||||||
}
|
|
||||||
const resource = evt.resource;
|
|
||||||
log.debug(`Got new event of type ${resource.type}`);
|
|
||||||
log.silly(evt);
|
|
||||||
const [type, subtype] = resource.type.split("/");
|
|
||||||
switch (type) {
|
|
||||||
case "RichText":
|
|
||||||
if (evt.resourceType === "NewMessage") {
|
|
||||||
if (resource.native.skypeeditedid || this.handledIds.has(resource.id)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.handledIds.add(resource.id);
|
|
||||||
if (subtype === "Location") {
|
|
||||||
this.emit("location", resource);
|
|
||||||
} else if (subtype) {
|
|
||||||
this.emit("file", resource);
|
|
||||||
} else {
|
|
||||||
this.emit("text", resource);
|
|
||||||
}
|
|
||||||
} else if (evt.resourceType === "MessageUpdate") {
|
|
||||||
this.emit("edit", resource);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "Control":
|
|
||||||
if (subtype === "Typing" || subtype === "ClearTyping") {
|
|
||||||
this.emit("typing", resource, subtype === "Typing");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "ThreadActivity":
|
|
||||||
if (subtype === "MemberConsumptionHorizonUpdate") {
|
|
||||||
this.emit("presence", resource);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const contacts = await this.api.getContacts();
|
this.api.on("online", async (address) => {
|
||||||
for (const contact of contacts) {
|
await this.api.send(xml("presence"));
|
||||||
this.contacts.set(contact.mri, contact);
|
});
|
||||||
}
|
|
||||||
const conversations = await this.api.getConversations();
|
|
||||||
for (const conversation of conversations) {
|
|
||||||
this.conversations.set(conversation.id, conversation);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.contactsInterval) {
|
// const contacts = await this.api.getContacts();
|
||||||
clearInterval(this.contactsInterval);
|
// for (const contact of contacts) {
|
||||||
this.contactsInterval = null;
|
// this.contacts.set(contact.mri, contact);
|
||||||
}
|
// }
|
||||||
this.contactsInterval = setInterval(this.updateContacts.bind(this), CONTACTS_DELTA_INTERVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async updateContacts() {
|
|
||||||
log.verbose("Getting contacts diff....");
|
|
||||||
try {
|
|
||||||
const contacts = await this.api.getContacts(true);
|
|
||||||
const MANY_CONTACTS = 5;
|
|
||||||
for (const contact of contacts) {
|
|
||||||
const oldContact = this.contacts.get(contact.mri) || null;
|
|
||||||
this.contacts.set(contact.mri, contact);
|
|
||||||
this.emit("updateContact", oldContact, contact);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
log.error("Failed to get contacts diff", err);
|
|
||||||
this.emit("error", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
68
src/index.ts
68
src/index.ts
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2020 mx-puppet-skype
|
Copyright 2020 mx-puppet-xmpp
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
@ -23,10 +23,10 @@ import * as commandLineArgs from "command-line-args";
|
|||||||
import * as commandLineUsage from "command-line-usage";
|
import * as commandLineUsage from "command-line-usage";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import * as yaml from "js-yaml";
|
import * as yaml from "js-yaml";
|
||||||
import { Skype } from "./skype";
|
import { Xmpp } from "./xmpp";
|
||||||
import { Client } from "./client";
|
import { Client } from "./client";
|
||||||
|
|
||||||
const log = new Log("SkypePuppet:index");
|
const log = new Log("XmppPuppet:index");
|
||||||
|
|
||||||
const commandOptions = [
|
const commandOptions = [
|
||||||
{ name: "register", alias: "r", type: Boolean },
|
{ name: "register", alias: "r", type: Boolean },
|
||||||
@ -36,7 +36,7 @@ const commandOptions = [
|
|||||||
];
|
];
|
||||||
const options = Object.assign({
|
const options = Object.assign({
|
||||||
"register": false,
|
"register": false,
|
||||||
"registration-file": "skype-registration.yaml",
|
"registration-file": "xmpp-registration.yaml",
|
||||||
"config": "config.yaml",
|
"config": "config.yaml",
|
||||||
"help": false,
|
"help": false,
|
||||||
}, commandLineArgs(commandOptions));
|
}, commandLineArgs(commandOptions));
|
||||||
@ -45,8 +45,8 @@ if (options.help) {
|
|||||||
// tslint:disable-next-line:no-console
|
// tslint:disable-next-line:no-console
|
||||||
console.log(commandLineUsage([
|
console.log(commandLineUsage([
|
||||||
{
|
{
|
||||||
header: "Matrix Skype Puppet Bridge",
|
header: "Matrix Xmpp Puppet Bridge",
|
||||||
content: "A matrix puppet bridge for Skype",
|
content: "A matrix puppet bridge for Xmpp",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: "Options",
|
header: "Options",
|
||||||
@ -58,16 +58,16 @@ if (options.help) {
|
|||||||
|
|
||||||
const protocol: IProtocolInformation = {
|
const protocol: IProtocolInformation = {
|
||||||
features: {
|
features: {
|
||||||
image: true,
|
image: false,
|
||||||
audio: true,
|
audio: false,
|
||||||
file: true,
|
file: false,
|
||||||
edit: true,
|
edit: false,
|
||||||
reply: true,
|
reply: false,
|
||||||
globalNamespace: true,
|
globalNamespace: true,
|
||||||
},
|
},
|
||||||
id: "skype",
|
id: "xmpp",
|
||||||
displayname: "Skype",
|
displayname: "Xmpp",
|
||||||
externalUrl: "https://skype.com/",
|
externalUrl: "https://xmpp.com/",
|
||||||
};
|
};
|
||||||
|
|
||||||
const puppet = new PuppetBridge(options["registration-file"], options.config, protocol);
|
const puppet = new PuppetBridge(options["registration-file"], options.config, protocol);
|
||||||
@ -77,8 +77,8 @@ if (options.register) {
|
|||||||
puppet.readConfig(false);
|
puppet.readConfig(false);
|
||||||
try {
|
try {
|
||||||
puppet.generateRegistration({
|
puppet.generateRegistration({
|
||||||
prefix: "_skypepuppet_",
|
prefix: "_xmpppuppet_",
|
||||||
id: "skype-puppet",
|
id: "xmpp-puppet",
|
||||||
url: `http://${puppet.Config.bridge.bindAddress}:${puppet.Config.bridge.port}`,
|
url: `http://${puppet.Config.bridge.bindAddress}:${puppet.Config.bridge.port}`,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -90,24 +90,24 @@ if (options.register) {
|
|||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
await puppet.init();
|
await puppet.init();
|
||||||
const skype = new Skype(puppet);
|
const xmpp = new Xmpp(puppet);
|
||||||
puppet.on("puppetNew", skype.newPuppet.bind(skype));
|
puppet.on("puppetNew", xmpp.newPuppet.bind(xmpp));
|
||||||
puppet.on("puppetDelete", skype.deletePuppet.bind(skype));
|
puppet.on("puppetDelete", xmpp.deletePuppet.bind(xmpp));
|
||||||
puppet.on("message", skype.handleMatrixMessage.bind(skype));
|
puppet.on("message", xmpp.handleMatrixMessage.bind(xmpp));
|
||||||
puppet.on("edit", skype.handleMatrixEdit.bind(skype));
|
puppet.on("edit", xmpp.handleMatrixEdit.bind(xmpp));
|
||||||
puppet.on("reply", skype.handleMatrixReply.bind(skype));
|
puppet.on("reply", xmpp.handleMatrixReply.bind(xmpp));
|
||||||
puppet.on("redact", skype.handleMatrixRedact.bind(skype));
|
puppet.on("redact", xmpp.handleMatrixRedact.bind(xmpp));
|
||||||
puppet.on("image", skype.handleMatrixImage.bind(skype));
|
puppet.on("image", xmpp.handleMatrixImage.bind(xmpp));
|
||||||
puppet.on("audio", skype.handleMatrixAudio.bind(skype));
|
puppet.on("audio", xmpp.handleMatrixAudio.bind(xmpp));
|
||||||
puppet.on("file", skype.handleMatrixFile.bind(skype));
|
puppet.on("file", xmpp.handleMatrixFile.bind(xmpp));
|
||||||
puppet.setCreateUserHook(skype.createUser.bind(skype));
|
puppet.setCreateUserHook(xmpp.createUser.bind(xmpp));
|
||||||
puppet.setCreateRoomHook(skype.createRoom.bind(skype));
|
puppet.setCreateRoomHook(xmpp.createRoom.bind(xmpp));
|
||||||
puppet.setGetDmRoomIdHook(skype.getDmRoom.bind(skype));
|
puppet.setGetDmRoomIdHook(xmpp.getDmRoom.bind(xmpp));
|
||||||
puppet.setListUsersHook(skype.listUsers.bind(skype));
|
puppet.setListUsersHook(xmpp.listUsers.bind(xmpp));
|
||||||
puppet.setListRoomsHook(skype.listRooms.bind(skype));
|
puppet.setListRoomsHook(xmpp.listRooms.bind(xmpp));
|
||||||
puppet.setGetUserIdsInRoomHook(skype.getUserIdsInRoom.bind(skype));
|
puppet.setGetUserIdsInRoomHook(xmpp.getUserIdsInRoom.bind(xmpp));
|
||||||
puppet.setGetDescHook(async (puppetId: number, data: any): Promise<string> => {
|
puppet.setGetDescHook(async (puppetId: number, data: any): Promise<string> => {
|
||||||
let s = "Skype";
|
let s = "Xmpp";
|
||||||
if (data.username) {
|
if (data.username) {
|
||||||
s += ` as \`${data.username}\``;
|
s += ` as \`${data.username}\``;
|
||||||
}
|
}
|
||||||
@ -139,7 +139,7 @@ async function run() {
|
|||||||
return retData;
|
return retData;
|
||||||
});
|
});
|
||||||
puppet.setBotHeaderMsgHook((): string => {
|
puppet.setBotHeaderMsgHook((): string => {
|
||||||
return "Skype Puppet Bridge";
|
return "Xmpp Puppet Bridge";
|
||||||
});
|
});
|
||||||
await puppet.start();
|
await puppet.start();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2020 mx-puppet-skype
|
Copyright 2020 mx-puppet-xmpp
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2020 mx-puppet-skype
|
Copyright 2020 mx-puppet-xmpp
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
@ -16,46 +16,46 @@ import {
|
|||||||
IRetList, IReplyEvent,
|
IRetList, IReplyEvent,
|
||||||
} from "mx-puppet-bridge";
|
} from "mx-puppet-bridge";
|
||||||
import { Client } from "./client";
|
import { Client } from "./client";
|
||||||
import * as skypeHttp from "@sorunome/skype-http";
|
|
||||||
import { Contact as SkypeContact } from "@sorunome/skype-http/dist/lib/types/contact";
|
|
||||||
import { NewMediaMessage as SkypeNewMediaMessage } from "@sorunome/skype-http/dist/lib/interfaces/api/api";
|
|
||||||
import { UnexpectedHttpStatusError } from "@sorunome/skype-http/dist/lib/errors";
|
|
||||||
import * as decodeHtml from "decode-html";
|
import * as decodeHtml from "decode-html";
|
||||||
import * as escapeHtml from "escape-html";
|
import * as escapeHtml from "escape-html";
|
||||||
import { MatrixMessageParser } from "./matrixmessageparser";
|
import { MatrixMessageParser } from "./matrixmessageparser";
|
||||||
import { SkypeMessageParser } from "./skypemessageparser";
|
import { XmppMessageParser } from "./xmppmessageparser";
|
||||||
import * as cheerio from "cheerio";
|
import * as cheerio from "cheerio";
|
||||||
import ExpireSet from "expire-set";
|
import ExpireSet from "expire-set";
|
||||||
|
|
||||||
const log = new Log("SkypePuppet:skype");
|
const log = new Log("XmppPuppet:xmpp");
|
||||||
|
|
||||||
const ROOM_TYPE_DM = 8;
|
interface IXmppPuppet {
|
||||||
|
|
||||||
interface ISkypePuppet {
|
|
||||||
client: Client;
|
client: Client;
|
||||||
data: any;
|
data: any;
|
||||||
deletedMessages: ExpireSet<string>;
|
deletedMessages: ExpireSet<string>;
|
||||||
restarting: boolean;
|
restarting: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ISkypePuppets {
|
interface IXmppPuppets {
|
||||||
[puppetId: number]: ISkypePuppet;
|
[puppetId: number]: IXmppPuppet;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Skype {
|
interface IStanza {
|
||||||
private puppets: ISkypePuppets = {};
|
attrs: {to: string, from:string, id: string};
|
||||||
|
|
||||||
|
getChild(path: string): {text: () => string}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Xmpp {
|
||||||
|
private puppets: IXmppPuppets = {};
|
||||||
private messageDeduplicator: MessageDeduplicator;
|
private messageDeduplicator: MessageDeduplicator;
|
||||||
private matrixMessageParser: MatrixMessageParser;
|
private matrixMessageParser: MatrixMessageParser;
|
||||||
private skypeMessageParser: SkypeMessageParser;
|
private xmppMessageParser: XmppMessageParser;
|
||||||
constructor(
|
constructor(
|
||||||
private puppet: PuppetBridge,
|
private puppet: PuppetBridge,
|
||||||
) {
|
) {
|
||||||
this.messageDeduplicator = new MessageDeduplicator();
|
this.messageDeduplicator = new MessageDeduplicator();
|
||||||
this.matrixMessageParser = new MatrixMessageParser();
|
this.matrixMessageParser = new MatrixMessageParser();
|
||||||
this.skypeMessageParser = new SkypeMessageParser();
|
this.xmppMessageParser = new XmppMessageParser();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getUserParams(puppetId: number, contact: SkypeContact): IRemoteUser {
|
public getUserParams(puppetId: number, contact: any): IRemoteUser {
|
||||||
return {
|
return {
|
||||||
puppetId,
|
puppetId,
|
||||||
userId: contact.mri,
|
userId: contact.mri,
|
||||||
@ -64,55 +64,38 @@ export class Skype {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public getRoomParams(puppetId: number, conversation: skypeHttp.Conversation): IRemoteRoom {
|
public getRoomParams(puppetId: number, conversation: any): IRemoteRoom {
|
||||||
const roomType = Number(conversation.id.split(":")[0]);
|
|
||||||
const isDirect = roomType === ROOM_TYPE_DM;
|
|
||||||
if (isDirect) {
|
|
||||||
return {
|
|
||||||
puppetId,
|
|
||||||
roomId: `dm-${puppetId}-${conversation.id}`,
|
|
||||||
isDirect: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
let avatarUrl: string | null = null;
|
let avatarUrl: string | null = null;
|
||||||
let name: string | null = null;
|
let name: string | null = null;
|
||||||
if (conversation.threadProperties) {
|
|
||||||
name = conversation.threadProperties.topic || null;
|
|
||||||
if (name) {
|
|
||||||
name = decodeHtml(name);
|
|
||||||
}
|
|
||||||
const picture = conversation.threadProperties.picture;
|
|
||||||
if (picture && picture.startsWith("URL@")) {
|
|
||||||
avatarUrl = picture.slice("URL@".length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const p = this.puppets[puppetId];
|
const p = this.puppets[puppetId];
|
||||||
return {
|
return {
|
||||||
puppetId,
|
puppetId,
|
||||||
roomId: conversation.id,
|
roomId: conversation.id,
|
||||||
name,
|
name,
|
||||||
avatarUrl,
|
avatarUrl,
|
||||||
downloadFile: async (url: string): Promise<Buffer> => {
|
downloadFile: async (url: string): Promise<any> => {
|
||||||
return await p.client.downloadFile(url, "swx_avatar");
|
return await p.client.downloadFile(url, "swx_avatar");
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getSendParams(puppetId: number, resource: skypeHttp.resources.Resource): Promise<IReceiveParams | null> {
|
public async getSendParams(puppetId: number, stanza: IStanza): Promise<IReceiveParams | null> {
|
||||||
const roomType = Number(resource.conversation.split(":")[0]);
|
|
||||||
const p = this.puppets[puppetId];
|
const p = this.puppets[puppetId];
|
||||||
const contact = await p.client.getContact(resource.from.raw);
|
const contact = await p.client.getContact(stanza.attrs.from);
|
||||||
|
log.info("stanza.attrs", stanza.attrs);
|
||||||
const conversation = await p.client.getConversation({
|
const conversation = await p.client.getConversation({
|
||||||
puppetId,
|
puppetId: puppetId,
|
||||||
roomId: resource.conversation,
|
roomId: stanza.attrs.from.split("/")[0],
|
||||||
});
|
});
|
||||||
|
log.info("Received contact", contact);
|
||||||
|
log.info("Received conversation", conversation);
|
||||||
if (!contact || !conversation) {
|
if (!contact || !conversation) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
user: this.getUserParams(puppetId, contact),
|
user: this.getUserParams(puppetId, contact),
|
||||||
room: this.getRoomParams(puppetId, conversation),
|
room: this.getRoomParams(puppetId, conversation),
|
||||||
eventId: resource.id, // tslint:disable-line no-any
|
eventId: stanza.attrs.id, // tslint:disable-line no-any
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,51 +113,58 @@ export class Skype {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await this.stopClient(puppetId);
|
await this.stopClient(puppetId);
|
||||||
p.client = new Client(p.data.username, p.data.password, p.data.state);
|
p.client = new Client(p.data.username, p.data.password);
|
||||||
const client = p.client;
|
const client = p.client;
|
||||||
client.on("text", async (resource: skypeHttp.resources.TextResource) => {
|
client.on("text", async (stanza: any) => {
|
||||||
try {
|
try {
|
||||||
await this.handleSkypeText(puppetId, resource);
|
await this.handleXmppText(puppetId, stanza);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error("Error while handling text event", err);
|
log.error("Error while handling text event", err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
client.on("edit", async (resource: skypeHttp.resources.RichTextResource) => {
|
client.on("edit", async (stanza: any) => {
|
||||||
try {
|
try {
|
||||||
await this.handleSkypeEdit(puppetId, resource);
|
await this.handleXmppEdit(puppetId, stanza);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error("Error while handling edit event", err);
|
log.error("Error while handling edit event", err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
client.on("location", async (resource: skypeHttp.resources.RichTextLocationResource) => {
|
client.on("location", async (stanza: any) => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error("Error while handling location event", err);
|
log.error("Error while handling location event", err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
client.on("file", async (resource: skypeHttp.resources.FileResource) => {
|
client.on("file", async (stanza: any) => {
|
||||||
try {
|
try {
|
||||||
await this.handleSkypeFile(puppetId, resource);
|
await this.handleXmppFile(puppetId, stanza);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error("Error while handling file event", err);
|
log.error("Error while handling file event", err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
client.on("typing", async (resource: skypeHttp.resources.Resource, typing: boolean) => {
|
client.on("typing", async (stanza: any, typing: boolean) => {
|
||||||
try {
|
try {
|
||||||
await this.handleSkypeTyping(puppetId, resource, typing);
|
await this.handleXmppTyping(puppetId, stanza, typing);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error("Error while handling typing event", err);
|
log.error("Error while handling typing event", err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
client.on("presence", async (resource: skypeHttp.resources.Resource) => {
|
client.on("presence", async (stanza: any) => {
|
||||||
try {
|
try {
|
||||||
await this.handleSkypePresence(puppetId, resource);
|
await this.handleXmppPresence(puppetId, stanza);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error("Error while handling presence event", err);
|
log.error("Error while handling presence event", err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
client.on("updateContact", async (oldContact: SkypeContact | null, newContact: SkypeContact) => {
|
client.on("receipt", async (stanza: any) => {
|
||||||
|
try {
|
||||||
|
await this.handleXmppPresence(puppetId, stanza);
|
||||||
|
} catch (err) {
|
||||||
|
log.error("Error while handling receipt event", err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
client.on("updateContact", async (oldContact: any | null, newContact: any) => {
|
||||||
try {
|
try {
|
||||||
let update = oldContact === null;
|
let update = oldContact === null;
|
||||||
const newUser = this.getUserParams(puppetId, newContact);
|
const newUser = this.getUserParams(puppetId, newContact);
|
||||||
@ -197,16 +187,7 @@ export class Skype {
|
|||||||
}
|
}
|
||||||
p.restarting = true;
|
p.restarting = true;
|
||||||
const causeName = (err as any).cause ? (err as any).cause.name : "";
|
const causeName = (err as any).cause ? (err as any).cause.name : "";
|
||||||
log.error("Error when polling");
|
log.error("Error when polling", err.message);
|
||||||
log.error("name: ", err.name);
|
|
||||||
const errr = err as any;
|
|
||||||
if (errr.cause) {
|
|
||||||
log.error("cause name: ", errr.cause.name);
|
|
||||||
}
|
|
||||||
log.error("code: ", errr.code);
|
|
||||||
log.error("body: ", errr.body);
|
|
||||||
log.error("cause: ", errr.cause);
|
|
||||||
log.error("data: ", errr.data);
|
|
||||||
log.error(err);
|
log.error(err);
|
||||||
if (causeName === "UnexpectedHttpStatus") {
|
if (causeName === "UnexpectedHttpStatus") {
|
||||||
await this.puppet.sendStatusMessage(puppetId, "Error: " + err);
|
await this.puppet.sendStatusMessage(puppetId, "Error: " + err);
|
||||||
@ -346,6 +327,7 @@ export class Skype {
|
|||||||
if (!p) {
|
if (!p) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
log.info("getUserIdsInRoom", room);
|
||||||
const conversation = await p.client.getConversation(room);
|
const conversation = await p.client.getConversation(room);
|
||||||
if (!conversation) {
|
if (!conversation) {
|
||||||
return null;
|
return null;
|
||||||
@ -356,10 +338,12 @@ export class Skype {
|
|||||||
users.add(member);
|
users.add(member);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.info("getUserIdsInRoom users", users);
|
||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleMatrixMessage(room: IRemoteRoom, data: IMessageEvent) {
|
public async handleMatrixMessage(room: IRemoteRoom, data: IMessageEvent) {
|
||||||
|
log.info("handleMatrixMessage");
|
||||||
const p = this.puppets[room.puppetId];
|
const p = this.puppets[room.puppetId];
|
||||||
if (!p) {
|
if (!p) {
|
||||||
return;
|
return;
|
||||||
@ -414,6 +398,7 @@ export class Skype {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async handleMatrixReply(room: IRemoteRoom, eventId: string, data: IReplyEvent) {
|
public async handleMatrixReply(room: IRemoteRoom, eventId: string, data: IReplyEvent) {
|
||||||
|
log.info("handleMatrixReply");
|
||||||
const p = this.puppets[room.puppetId];
|
const p = this.puppets[room.puppetId];
|
||||||
if (!p) {
|
if (!p) {
|
||||||
return;
|
return;
|
||||||
@ -481,230 +466,209 @@ export class Skype {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async handleMatrixImage(room: IRemoteRoom, data: IFileEvent) {
|
public async handleMatrixImage(room: IRemoteRoom, data: IFileEvent) {
|
||||||
await this.handleMatrixFile(room, data, "sendImage");
|
// TODO
|
||||||
|
// await this.handleMatrixFile(room, data, "sendImage");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleMatrixAudio(room: IRemoteRoom, data: IFileEvent) {
|
public async handleMatrixAudio(room: IRemoteRoom, data: IFileEvent) {
|
||||||
await this.handleMatrixFile(room, data, "sendAudio");
|
// TODO
|
||||||
|
// await this.handleMatrixFile(room, data, "sendAudio");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleMatrixFile(room: IRemoteRoom, data: IFileEvent, method?: string) {
|
public async handleMatrixFile(room: IRemoteRoom, data: IFileEvent, method?: string) {
|
||||||
if (!method) {
|
// TODO
|
||||||
method = "sendDocument";
|
// if (!method) {
|
||||||
}
|
// method = "sendDocument";
|
||||||
const p = this.puppets[room.puppetId];
|
// }
|
||||||
if (!p) {
|
// const p = this.puppets[room.puppetId];
|
||||||
return;
|
// if (!p) {
|
||||||
}
|
// return;
|
||||||
log.info("Received file from matrix");
|
// }
|
||||||
const conversation = await p.client.getConversation(room);
|
// log.info("Received file from matrix");
|
||||||
if (!conversation) {
|
// const conversation = await p.client.getConversation(room);
|
||||||
log.warn(`Room ${room.roomId} not found!`);
|
// if (!conversation) {
|
||||||
return;
|
// log.warn(`Room ${room.roomId} not found!`);
|
||||||
}
|
// return;
|
||||||
const buffer = await Util.DownloadFile(data.url);
|
// }
|
||||||
const opts: SkypeNewMediaMessage = {
|
// const buffer = await Util.DownloadFile(data.url);
|
||||||
file: buffer,
|
// const opts: XmppNewMediaMessage = {
|
||||||
name: data.filename,
|
// file: buffer,
|
||||||
};
|
// name: data.filename,
|
||||||
if (data.info) {
|
// };
|
||||||
if (data.info.w) {
|
// if (data.info) {
|
||||||
opts.width = data.info.w;
|
// if (data.info.w) {
|
||||||
}
|
// opts.width = data.info.w;
|
||||||
if (data.info.h) {
|
// }
|
||||||
opts.height = data.info.h;
|
// if (data.info.h) {
|
||||||
}
|
// opts.height = data.info.h;
|
||||||
}
|
// }
|
||||||
const dedupeKey = `${room.puppetId};${room.roomId}`;
|
// }
|
||||||
this.messageDeduplicator.lock(dedupeKey, p.client.username, `file:${data.filename}`);
|
// const dedupeKey = `${room.puppetId};${room.roomId}`;
|
||||||
const ret = await p.client[method](conversation.id, opts);
|
// this.messageDeduplicator.lock(dedupeKey, p.client.username, `file:${data.filename}`);
|
||||||
const eventId = ret && ret.MessageId;
|
// const ret = await p.client[method](conversation.id, opts);
|
||||||
this.messageDeduplicator.unlock(dedupeKey, p.client.username, eventId);
|
// const eventId = ret && ret.MessageId;
|
||||||
if (eventId) {
|
// this.messageDeduplicator.unlock(dedupeKey, p.client.username, eventId);
|
||||||
await this.puppet.eventSync.insert(room, data.eventId!, eventId);
|
// if (eventId) {
|
||||||
}
|
// await this.puppet.eventSync.insert(room, data.eventId!, eventId);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleSkypeText(
|
private async handleXmppText(
|
||||||
puppetId: number,
|
puppetId: number,
|
||||||
resource: skypeHttp.resources.TextResource | skypeHttp.resources.RichTextResource,
|
stanza: IStanza,
|
||||||
) {
|
) {
|
||||||
const p = this.puppets[puppetId];
|
const p = this.puppets[puppetId];
|
||||||
if (!p) {
|
if (!p) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const rich = resource.native.messagetype.startsWith("RichText");
|
log.info("Got new xmpp message");
|
||||||
log.info("Got new skype message");
|
log.silly(stanza);
|
||||||
log.silly(resource);
|
const params = await this.getSendParams(puppetId, stanza);
|
||||||
const params = await this.getSendParams(puppetId, resource);
|
|
||||||
if (!params) {
|
if (!params) {
|
||||||
log.warn("Couldn't generate params");
|
log.warn("Couldn't generate params");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let msg = resource.content;
|
let msg = stanza.getChild("body").text();
|
||||||
let emote = false;
|
let emote = false;
|
||||||
if (resource.native.skypeemoteoffset) {
|
|
||||||
emote = true;
|
|
||||||
msg = msg.substr(Number(resource.native.skypeemoteoffset));
|
|
||||||
}
|
|
||||||
const dedupeKey = `${puppetId};${params.room.roomId}`;
|
const dedupeKey = `${puppetId};${params.room.roomId}`;
|
||||||
if (rich && msg.trim().startsWith("<URIObject") && msg.trim().endsWith("</URIObject>")) {
|
|
||||||
// okay, we might have a sticker or something...
|
|
||||||
const $ = cheerio.load(msg);
|
|
||||||
const obj = $("URIObject");
|
|
||||||
let uri = obj.attr("uri");
|
|
||||||
const filename = $(obj.find("OriginalName")).attr("v");
|
|
||||||
if (uri) {
|
|
||||||
if (await this.messageDeduplicator.dedupe(dedupeKey, params.user.userId, params.eventId, `file:${filename}`)) {
|
|
||||||
log.silly("file message dedupe");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
uri += "/views/thumblarge";
|
|
||||||
uri = uri.replace("static.asm.skype.com", "static-asm.secure.skypeassets.com");
|
|
||||||
const buffer = await p.client.downloadFile(uri);
|
|
||||||
await this.puppet.sendFileDetect(params, buffer, filename);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (await this.messageDeduplicator.dedupe(dedupeKey, params.user.userId, params.eventId, msg)) {
|
if (await this.messageDeduplicator.dedupe(dedupeKey, params.user.userId, params.eventId, msg)) {
|
||||||
log.silly("normal message dedupe");
|
log.silly("normal message dedupe");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (rich && msg.trim().startsWith("<quote")) {
|
if (msg.trim().startsWith("<quote")) {
|
||||||
|
// TODO
|
||||||
// okay, we might have a reply...
|
// okay, we might have a reply...
|
||||||
const $ = cheerio.load(msg);
|
// const $ = cheerio.load(msg);
|
||||||
const quote = $("quote");
|
// const quote = $("quote");
|
||||||
const messageid = quote.attr("messageid");
|
// const messageid = quote.attr("messageid");
|
||||||
if (messageid) {
|
// if (messageid) {
|
||||||
const sendQuoteMsg = this.skypeMessageParser.parse(msg, { noQuotes: true });
|
// const sendQuoteMsg = this.xmppMessageParser.parse(msg, { noQuotes: true });
|
||||||
await this.puppet.sendReply(params, messageid, sendQuoteMsg);
|
// await this.puppet.sendReply(params, messageid, sendQuoteMsg);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
let sendMsg: IMessageEvent;
|
let sendMsg: IMessageEvent;
|
||||||
if (rich) {
|
sendMsg = {
|
||||||
sendMsg = this.skypeMessageParser.parse(msg);
|
body: msg,
|
||||||
} else {
|
};
|
||||||
sendMsg = {
|
|
||||||
body: msg,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (emote) {
|
|
||||||
sendMsg.emote = true;
|
|
||||||
}
|
|
||||||
await this.puppet.sendMessage(params, sendMsg);
|
await this.puppet.sendMessage(params, sendMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleSkypeEdit(
|
private async handleXmppEdit(
|
||||||
puppetId: number,
|
puppetId: number,
|
||||||
resource: skypeHttp.resources.TextResource | skypeHttp.resources.RichTextResource,
|
stanza: IStanza,
|
||||||
) {
|
) {
|
||||||
const p = this.puppets[puppetId];
|
// TODO
|
||||||
if (!p) {
|
// const p = this.puppets[puppetId];
|
||||||
return;
|
// if (!p) {
|
||||||
}
|
// return;
|
||||||
const rich = resource.native.messagetype.startsWith("RichText");
|
// }
|
||||||
log.info("Got new skype edit");
|
// const rich = resource.native.messagetype.startsWith("RichText");
|
||||||
log.silly(resource);
|
// log.info("Got new xmpp edit");
|
||||||
const params = await this.getSendParams(puppetId, resource);
|
// log.silly(resource);
|
||||||
if (!params) {
|
// const params = await this.getSendParams(puppetId, resource);
|
||||||
log.warn("Couldn't generate params");
|
// if (!params) {
|
||||||
return;
|
// log.warn("Couldn't generate params");
|
||||||
}
|
// return;
|
||||||
let msg = resource.content;
|
// }
|
||||||
let emote = false;
|
// let msg = resource.content;
|
||||||
if (resource.native.skypeemoteoffset) {
|
// let emote = false;
|
||||||
emote = true;
|
// if (resource.native.xmppemoteoffset) {
|
||||||
msg = msg.substr(Number(resource.native.skypeemoteoffset));
|
// emote = true;
|
||||||
}
|
// msg = msg.substr(Number(resource.native.xmppemoteoffset));
|
||||||
const dedupeKey = `${puppetId};${params.room.roomId}`;
|
// }
|
||||||
if (await this.messageDeduplicator.dedupe(dedupeKey, params.user.userId, params.eventId, msg)) {
|
// const dedupeKey = `${puppetId};${params.room.roomId}`;
|
||||||
log.silly("normal message dedupe");
|
// if (await this.messageDeduplicator.dedupe(dedupeKey, params.user.userId, params.eventId, msg)) {
|
||||||
return;
|
// log.silly("normal message dedupe");
|
||||||
}
|
// return;
|
||||||
let sendMsg: IMessageEvent;
|
// }
|
||||||
if (rich) {
|
// let sendMsg: IMessageEvent;
|
||||||
sendMsg = this.skypeMessageParser.parse(msg, { noQuotes: msg.trim().startsWith("<quote") });
|
// if (rich) {
|
||||||
} else {
|
// sendMsg = this.xmppMessageParser.parse(msg, { noQuotes: msg.trim().startsWith("<quote") });
|
||||||
sendMsg = {
|
// } else {
|
||||||
body: msg,
|
// sendMsg = {
|
||||||
};
|
// body: msg,
|
||||||
}
|
// };
|
||||||
if (emote) {
|
// }
|
||||||
sendMsg.emote = true;
|
// if (emote) {
|
||||||
}
|
// sendMsg.emote = true;
|
||||||
if (resource.content) {
|
// }
|
||||||
await this.puppet.sendEdit(params, resource.id, sendMsg);
|
// if (resource.content) {
|
||||||
} else if (p.deletedMessages.has(resource.id)) {
|
// await this.puppet.sendEdit(params, resource.id, sendMsg);
|
||||||
log.silly("normal message redact dedupe");
|
// } else if (p.deletedMessages.has(resource.id)) {
|
||||||
return;
|
// log.silly("normal message redact dedupe");
|
||||||
} else {
|
// return;
|
||||||
await this.puppet.sendRedact(params, resource.id);
|
// } else {
|
||||||
}
|
// await this.puppet.sendRedact(params, resource.id);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleSkypeFile(puppetId: number, resource: skypeHttp.resources.FileResource) {
|
private async handleXmppFile(puppetId: number, stanza: IStanza) {
|
||||||
const p = this.puppets[puppetId];
|
// TODO
|
||||||
if (!p) {
|
// const p = this.puppets[puppetId];
|
||||||
return;
|
// if (!p) {
|
||||||
}
|
// return;
|
||||||
log.info("Got new skype file");
|
// }
|
||||||
log.silly(resource);
|
// log.info("Got new xmpp file");
|
||||||
const params = await this.getSendParams(puppetId, resource);
|
// log.silly(resource);
|
||||||
if (!params) {
|
// const params = await this.getSendParams(puppetId, resource);
|
||||||
log.warn("Couldn't generate params");
|
// if (!params) {
|
||||||
return;
|
// log.warn("Couldn't generate params");
|
||||||
}
|
// return;
|
||||||
const filename = resource.original_file_name;
|
// }
|
||||||
const dedupeKey = `${puppetId};${params.room.roomId}`;
|
// const filename = resource.original_file_name;
|
||||||
if (await this.messageDeduplicator.dedupe(dedupeKey, params.user.userId, params.eventId, `file:${filename}`)) {
|
// const dedupeKey = `${puppetId};${params.room.roomId}`;
|
||||||
log.silly("file message dedupe");
|
// if (await this.messageDeduplicator.dedupe(dedupeKey, params.user.userId, params.eventId, `file:${filename}`)) {
|
||||||
return;
|
// log.silly("file message dedupe");
|
||||||
}
|
// return;
|
||||||
const buffer = await p.client.downloadFile(resource.uri);
|
// }
|
||||||
await this.puppet.sendFileDetect(params, buffer, filename);
|
// const buffer = await p.client.downloadFile(resource.uri);
|
||||||
|
// await this.puppet.sendFileDetect(params, buffer, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleSkypeTyping(puppetId: number, resource: skypeHttp.resources.Resource, typing: boolean) {
|
private async handleXmppTyping(puppetId: number, stanza: IStanza, typing: boolean) {
|
||||||
const p = this.puppets[puppetId];
|
// TODO
|
||||||
if (!p) {
|
// const p = this.puppets[puppetId];
|
||||||
return;
|
// if (!p) {
|
||||||
}
|
// return;
|
||||||
log.info("Got new skype typing event");
|
// }
|
||||||
log.silly(resource);
|
// log.info("Got new xmpp typing event");
|
||||||
const params = await this.getSendParams(puppetId, resource);
|
// log.silly(resource);
|
||||||
if (!params) {
|
// const params = await this.getSendParams(puppetId, resource);
|
||||||
log.warn("Couldn't generate params");
|
// if (!params) {
|
||||||
return;
|
// log.warn("Couldn't generate params");
|
||||||
}
|
// return;
|
||||||
await this.puppet.setUserTyping(params, typing);
|
// }
|
||||||
|
// await this.puppet.setUserTyping(params, typing);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleSkypePresence(puppetId: number, resource: skypeHttp.resources.Resource) {
|
private async handleXmppPresence(puppetId: number, stanza: IStanza) {
|
||||||
const p = this.puppets[puppetId];
|
// TODO
|
||||||
if (!p) {
|
// const p = this.puppets[puppetId];
|
||||||
return;
|
// if (!p) {
|
||||||
}
|
// return;
|
||||||
log.info("Got new skype presence event");
|
// }
|
||||||
log.silly(resource);
|
// log.info("Got new xmpp presence event");
|
||||||
const content = JSON.parse(resource.native.content);
|
// log.silly(resource);
|
||||||
const contact = await p.client.getContact(content.user);
|
// const content = JSON.parse(resource.native.content);
|
||||||
const conversation = await p.client.getConversation({
|
// const contact = await p.client.getContact(content.user);
|
||||||
puppetId,
|
// const conversation = await p.client.getConversation({
|
||||||
roomId: resource.conversation,
|
// puppetId,
|
||||||
});
|
// roomId: resource.conversation,
|
||||||
if (!contact || !conversation) {
|
// });
|
||||||
log.warn("Couldn't generate params");
|
// if (!contact || !conversation) {
|
||||||
return;
|
// log.warn("Couldn't generate params");
|
||||||
}
|
// return;
|
||||||
const params: IReceiveParams = {
|
// }
|
||||||
user: this.getUserParams(puppetId, contact),
|
// const params: IReceiveParams = {
|
||||||
room: this.getRoomParams(puppetId, conversation),
|
// user: this.getUserParams(puppetId, contact),
|
||||||
};
|
// room: this.getRoomParams(puppetId, conversation),
|
||||||
const [id, _, clientId] = content.consumptionhorizon.split(";");
|
// };
|
||||||
params.eventId = id;
|
// const [id, _, clientId] = content.consumptionhorizon.split(";");
|
||||||
await this.puppet.sendReadReceipt(params);
|
// params.eventId = id;
|
||||||
params.eventId = clientId;
|
// await this.puppet.sendReadReceipt(params);
|
||||||
await this.puppet.sendReadReceipt(params);
|
// params.eventId = clientId;
|
||||||
|
// await this.puppet.sendReadReceipt(params);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2020 mx-puppet-skype
|
Copyright 2020 mx-puppet-xmpp
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
@ -17,12 +17,12 @@ import * as escapeHtml from "escape-html";
|
|||||||
import { IMessageEvent } from "mx-puppet-bridge";
|
import { IMessageEvent } from "mx-puppet-bridge";
|
||||||
import * as emoji from "node-emoji";
|
import * as emoji from "node-emoji";
|
||||||
|
|
||||||
interface ISkypeMessageParserOpts {
|
interface IXmppMessageParserOpts {
|
||||||
noQuotes?: boolean;
|
noQuotes?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SkypeMessageParser {
|
export class XmppMessageParser {
|
||||||
public parse(msg: string, opts: ISkypeMessageParserOpts = {}): IMessageEvent {
|
public parse(msg: string, opts: IXmppMessageParserOpts = {}): IMessageEvent {
|
||||||
opts = Object.assign({
|
opts = Object.assign({
|
||||||
noQuotes: false,
|
noQuotes: false,
|
||||||
}, opts);
|
}, opts);
|
||||||
@ -33,7 +33,7 @@ export class SkypeMessageParser {
|
|||||||
return this.walkNode(nodes, opts);
|
return this.walkNode(nodes, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
private walkChildNodes(node: Parser.Node, opts: ISkypeMessageParserOpts): IMessageEvent {
|
private walkChildNodes(node: Parser.Node, opts: IXmppMessageParserOpts): IMessageEvent {
|
||||||
if (!node.childNodes.length) {
|
if (!node.childNodes.length) {
|
||||||
return {
|
return {
|
||||||
body: "",
|
body: "",
|
||||||
@ -55,7 +55,7 @@ export class SkypeMessageParser {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private walkNode(node: Parser.Node, opts: ISkypeMessageParserOpts): IMessageEvent {
|
private walkNode(node: Parser.Node, opts: IXmppMessageParserOpts): IMessageEvent {
|
||||||
if (node.nodeType === Parser.NodeType.TEXT_NODE) {
|
if (node.nodeType === Parser.NodeType.TEXT_NODE) {
|
||||||
return this.escape((node as Parser.TextNode).text);
|
return this.escape((node as Parser.TextNode).text);
|
||||||
} else if (node.nodeType === Parser.NodeType.ELEMENT_NODE) {
|
} else if (node.nodeType === Parser.NodeType.ELEMENT_NODE) {
|
||||||
@ -111,7 +111,7 @@ export class SkypeMessageParser {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "ss": {
|
case "ss": {
|
||||||
// skype emoji
|
// xmpp emoji
|
||||||
const type = nodeHtml.attributes.type;
|
const type = nodeHtml.attributes.type;
|
||||||
let emojiType = {
|
let emojiType = {
|
||||||
smile: "slightly_smiling_face",
|
smile: "slightly_smiling_face",
|
Loading…
Reference in New Issue
Block a user