diff --git a/package-lock.json b/package-lock.json
index f9293f3..23b84a5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -98,9 +98,9 @@
}
},
"@sorunome/skype-http": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/@sorunome/skype-http/-/skype-http-1.5.1.tgz",
- "integrity": "sha512-dJ0fMeTmtzTUWbXN3+SCth8C9XElhrEkzbp454xyo0vXYyoPMbIUYuWeEas1hyeYjaqI9PdgTOe5xI9y+qr9/g==",
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/@sorunome/skype-http/-/skype-http-1.5.2.tgz",
+ "integrity": "sha512-NAxvVVHIi7G/9v5RbB3vkNqbgy2CB+puE6ZvwX1ha4+PCP5MTy5KZRfrhOpIVyTLmTEXS50USl/ixAek5RwLlA==",
"requires": {
"async-file": "^2.0.2",
"big-integer": "^1.6.26",
diff --git a/package.json b/package.json
index c894493..c56f640 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
},
"author": "Sorunome",
"dependencies": {
- "@sorunome/skype-http": "^1.5.1",
+ "@sorunome/skype-http": "^1.5.2",
"cheerio": "^1.0.0-rc.3",
"command-line-args": "^5.1.1",
"command-line-usage": "^5.0.5",
diff --git a/src/index.ts b/src/index.ts
index 193b903..2c4b7a5 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -62,6 +62,7 @@ const protocol: IProtocolInformation = {
audio: true,
file: true,
edit: true,
+ reply: true,
globalNamespace: true,
},
id: "skype",
@@ -94,6 +95,7 @@ async function run() {
puppet.on("puppetDelete", skype.deletePuppet.bind(skype));
puppet.on("message", skype.handleMatrixMessage.bind(skype));
puppet.on("edit", skype.handleMatrixEdit.bind(skype));
+ puppet.on("reply", skype.handleMatrixReply.bind(skype));
puppet.on("redact", skype.handleMatrixRedact.bind(skype));
puppet.on("image", skype.handleMatrixImage.bind(skype));
puppet.on("audio", skype.handleMatrixAudio.bind(skype));
diff --git a/src/matrixmessageparser.ts b/src/matrixmessageparser.ts
index 5a1be43..07e57c8 100644
--- a/src/matrixmessageparser.ts
+++ b/src/matrixmessageparser.ts
@@ -52,8 +52,12 @@ export class MatrixMessageParser {
const inner = this.walkChildNodes(nodeHtml);
return `${inner}`;
}
+ case "blockquote":
+ return `${this.walkChildNodes(nodeHtml)}
`;
case "wrap":
return this.walkChildNodes(nodeHtml);
+ case "mx-reply": // disgard replies
+ return "";
default:
if (!nodeHtml.tagName) {
return this.walkChildNodes(nodeHtml);
diff --git a/src/skype.ts b/src/skype.ts
index 5e52a8b..73fb03c 100644
--- a/src/skype.ts
+++ b/src/skype.ts
@@ -409,6 +409,63 @@ export class Skype {
}
}
+ public async handleMatrixReply(room: IRemoteRoom, eventId: string, data: IMessageEvent) {
+ const p = this.puppets[room.puppetId];
+ if (!p) {
+ return;
+ }
+ log.info("Received reply from matrix");
+ const conversation = await p.client.getConversation(room);
+ if (!conversation) {
+ log.warn(`Room ${room.roomId} not found!`);
+ return;
+ }
+ let msg: string;
+ if (data.formattedBody) {
+ msg = this.matrixMessageParser.parse(data.formattedBody);
+ } else {
+ msg = escapeHtml(data.body);
+ }
+ // now prepend the reply
+ const author = escapeHtml(p.client.username.substr(p.client.username.indexOf(":") + 1));
+ const ownContact = await p.client.getContact(p.client.username);
+ const authorname = escapeHtml(ownContact ? ownContact.displayName : p.client.username);
+ const conversationId = escapeHtml(conversation.id);
+ const timestamp = Math.round(Number(eventId) / 1000).toString();
+ const origEventId = (await this.puppet.eventSync.getMatrix(room.puppetId, eventId))[0];
+ let contents = "blah";
+ if (origEventId) {
+ const [realOrigEventId, roomId] = origEventId.split(";");
+ try {
+ const client = (await this.puppet.roomSync.getRoomOp(roomId)) || this.puppet.botIntent.underlyingClient;
+ const evt = await client.getEvent(roomId, realOrigEventId);
+ if (evt && evt.content && typeof evt.content.body === "string") {
+ if (evt.content.formatted_body) {
+ contents = this.matrixMessageParser.parse(evt.content.formatted_body);
+ } else {
+ contents = escapeHtml(evt.content.body);
+ }
+ }
+ } catch (err) {
+ log.verbose("Event not found", err.body || err);
+ }
+ }
+ const quote = `` +
+ `[${timestamp}] ${authorname}: ${contents}
+
+<<<
`;
+ msg = quote + msg;
+ const dedupeKey = `${room.puppetId};${room.roomId}`;
+ this.messageDeduplicator.lock(dedupeKey, p.client.username, msg);
+ const ret = await p.client.sendMessage(conversation.id, msg);
+ const newEventId = ret && ret.MessageId;
+ this.messageDeduplicator.unlock(dedupeKey, p.client.username, newEventId);
+ if (newEventId) {
+ await this.puppet.eventSync.insert(room.puppetId, data.eventId!, newEventId);
+ }
+ }
+
public async handleMatrixRedact(room: IRemoteRoom, eventId: string) {
const p = this.puppets[room.puppetId];
if (!p) {
@@ -514,6 +571,17 @@ export class Skype {
log.silly("normal message dedupe");
return;
}
+ if (rich && msg.trim().startsWith("${msg}`, {
lowerCaseTagName: true,
pre: true,
});
- return this.walkNode(nodes);
+ return this.walkNode(nodes, opts);
}
- private walkChildNodes(node: Parser.Node): IMessageEvent {
+ private walkChildNodes(node: Parser.Node, opts: ISkypeMessageParserOpts): IMessageEvent {
if (!node.childNodes.length) {
return {
body: "",
formattedBody: "",
};
}
- return node.childNodes.map((n) => this.walkNode(n)).reduce((acc, curr) => {
+ return node.childNodes.map((n) => this.walkNode(n, opts)).reduce((acc, curr) => {
return {
body: acc.body + curr.body,
formattedBody: acc.formattedBody! + curr.formattedBody!,
@@ -48,35 +55,35 @@ export class SkypeMessageParser {
};
}
- private walkNode(node: Parser.Node): IMessageEvent {
+ private walkNode(node: Parser.Node, opts: ISkypeMessageParserOpts): IMessageEvent {
if (node.nodeType === Parser.NodeType.TEXT_NODE) {
return this.escape((node as Parser.TextNode).text);
} else if (node.nodeType === Parser.NodeType.ELEMENT_NODE) {
const nodeHtml = node as Parser.HTMLElement;
switch (nodeHtml.tagName) {
case "i": {
- const child = this.walkChildNodes(nodeHtml);
+ const child = this.walkChildNodes(nodeHtml, opts);
return {
body: `_${child.body}_`,
formattedBody: `${child.formattedBody}`,
};
}
case "b": {
- const child = this.walkChildNodes(nodeHtml);
+ const child = this.walkChildNodes(nodeHtml, opts);
return {
body: `*${child.body}*`,
formattedBody: `${child.formattedBody}`,
};
}
case "s": {
- const child = this.walkChildNodes(nodeHtml);
+ const child = this.walkChildNodes(nodeHtml, opts);
return {
body: `~${child.body}~`,
formattedBody: `${child.formattedBody}`,
};
}
case "pre": {
- const child = this.walkChildNodes(nodeHtml);
+ const child = this.walkChildNodes(nodeHtml, opts);
return {
body: `{code}${child.body}{code}`,
formattedBody: `${child.formattedBody}
`,
@@ -84,12 +91,25 @@ export class SkypeMessageParser {
}
case "a": {
const href = nodeHtml.attributes.href;
- const child = this.walkChildNodes(nodeHtml);
+ const child = this.walkChildNodes(nodeHtml, opts);
return {
body: child.body === href ? href : `[${child.body}](${href})`,
formattedBody: `${child.formattedBody}`,
};
}
+ case "quote": {
+ if (opts.noQuotes) {
+ return {
+ body: "",
+ formattedBody: "",
+ };
+ }
+ const child = this.walkChildNodes(nodeHtml, opts);
+ return {
+ body: `> ${child.body}\n`,
+ formattedBody: `${child.formattedBody}
- ${nodeHtml.attributes.authorname}
`,
+ };
+ }
case "ss": {
// skype emoji
const type = nodeHtml.attributes.type;
@@ -164,14 +184,14 @@ export class SkypeMessageParser {
formattedBody: `(${escapeHtml(type)})`,
};
}
- case "e_m":
- // empty edit tag
+ case "e_m": // empty edit tag
+ case "legacyquote": // empty legacy quote tag
return {
body: "",
formattedBody: "",
};
default:
- return this.walkChildNodes(nodeHtml);
+ return this.walkChildNodes(nodeHtml, opts);
}
}
return {