Compare commits

...

200 Commits

Author SHA1 Message Date
Wim
39f4fb3446 Release v1.18.1 (#1207) 2020-08-24 00:25:30 +02:00
Wim
56159b9bce Sleep when ratelimited on joins (matrix). Fixes #1201 (#1206) 2020-08-24 00:12:30 +02:00
Ben Wiederhake
b2af76e7dc Support Telegram animated stickers (tgs) format (#1173)
This is half a fix for #874

This patch introduces a new config flag:
- MediaConvertTgs

These need to be treated independently from the existing
MediaConvertWebPToPNG flag because Tgs→WebP results in an
*animated* WebP, and the WebP→PNG converter can't handle
animated WebP files yet.

Furthermore, some platforms (like discord) don't even support
animated WebP files, so the user may want to fall back to
static PNGs (not APNGs).

The final reason why this is only half a fix is that this
introduces an external dependency, namely lottie, to be
installed like this:

$ pip3 install lottie cairosvg

This patch works by writing the tgs to a temporary file in /tmp,
calling lottie to convert it (this conversion may take several seconds!),
and then deleting the temporary file.
The temporary file is absolutely necessary, as lottie refuses to
work on non-seekable files.
If anyone comes up with a reasonable use case where /tmp is
unavailable, I can add yet another config option for that, if desired.

Telegram will bail out if the option is configured but lottie isn't found.
2020-08-23 22:34:28 +02:00
Wim
491fe35397 Update workflow builds to go 1.15 2020-08-21 00:29:59 +02:00
Wim
b451285af7 Sync with upstream gozulipbot fixes (#1202) 2020-08-21 00:14:33 +02:00
Dellle
63a1847cdc Remove HTML formatting for push messages (#1188) (#1189)
When there is a valid HTML formatting then remove this in the cleartext
field of the matrix client. This leads to nicer push messages on
smartphone apps.

Fix #1188
2020-08-20 22:41:53 +02:00
Wim
4e50fd8649 Use mattermost v5 module (#1192) 2020-08-10 00:29:54 +02:00
Wim
dfdffa0027 Add EnableAllEvents
Add option to have all events send to the messagechan
2020-08-09 21:46:45 +02:00
Wim
ebd2073144 Handle panic in whatsapp. Fixes #1180 (#1184) 2020-07-30 23:55:31 +02:00
Wim
1e94b716fb Fix typo in documentation (#1183) 2020-07-30 23:46:03 +02:00
Wim
2a41abb3d1 Update linter config 2020-07-26 15:05:52 +02:00
Gary Kim
2d2bebe976 Fix Nextcloud Talk connection failure (#1179)
Fix #1177

Signed-off-by: Gary Kim <gary@garykim.dev>
2020-07-26 14:51:07 +02:00
Wim
e1629994bd Bump version 2020-07-24 21:31:28 +02:00
Wim
e3d8fe4fd8 Release v1.18.0 (#1176) 2020-07-24 21:00:57 +02:00
Wim
23d8742f0d Update dependencies for 1.18.0 release (#1175) 2020-07-18 17:27:41 +02:00
Wim
3b6a8be07b Update README.md 2020-07-18 17:26:19 +02:00
Gary Kim
71a5b72aff Add Nextcloud Talk support (#1167)
Signed-off-by: Gary Kim <gary@garykim.dev>
2020-07-18 16:08:25 +02:00
z3bra
213bf349c3 Add an option to log into a file rather than stdout (#1168)
Use Logfile option in the `[general]` section
2020-07-18 15:46:19 +02:00
Andrey Groshev
a94fe55886 Fix MarkdownV2 support in Telegram (#1169) 2020-07-12 22:40:22 +02:00
haykam821
9b22f16497 Add websocket to API (#970)
Co-authored-by: Qais Patankar <qaisjp@gmail.com>
2020-07-12 21:13:28 +02:00
Wim
2977a5957e Update README 2020-06-28 19:02:28 +02:00
Wim
f70d1c897a Set fetch-depth to 0 to fetch all tags 2020-06-28 18:30:18 +02:00
Wim
a4a3525265 Set fetch-depth correct and use vendor when building in workflow 2020-06-28 18:23:46 +02:00
Wim
a6dd8446e4 Increase fetch depth in workflow 2020-06-28 18:17:26 +02:00
Wim
7bf9e1cfb3 Fix space in workflow 2020-06-28 18:13:50 +02:00
Wim
f291832a77 Upload artifacts on commit 2020-06-28 18:11:02 +02:00
Nathanaël
1fee323247 Reload user information when a new contact is detected (whatsapp) (#1160)
Before returning an empty string, we refresh the WhatsApp contacts and if we found the one we wanted, we can return a real name. Fixes #796
2020-06-25 00:35:49 +02:00
Qais Patankar
a41accd033 Add sane RemoteNickFormat default for API (#1157) 2020-06-25 00:25:10 +02:00
James Lu
37f7caf7f3 Skip gIRC built-in rate limiting (irc) (#1164)
By default, gIRC rate limits all outgoing messages. 
Since matterbridge already implements message throttling, this is extra layer of throttling is not necessary.
2020-06-24 23:57:37 +02:00
TheHolyRoger
5847f7758c Only colour IRC nicks if there is one. (#1161) 2020-06-24 23:48:54 +02:00
Wim
bce736993e Remove travis as it isn't working anymore 2020-06-24 23:45:45 +02:00
Wim
5636992446 Increase fetch-depth in workflow 2020-06-24 23:37:02 +02:00
Wim
f996a2b7ae More linting fixes 2020-06-24 23:28:41 +02:00
Wim
587de96ab3 Update golangci-lint config 2020-06-24 23:21:15 +02:00
Wim
80eb1cd202 Fix duplicate name in workflow 2020-06-24 22:37:46 +02:00
Wim
bbf594c815 Use github workflows 2020-06-24 22:36:47 +02:00
Sandro
2f0f2ee40d Combine runs to one layer (#1151) 2020-05-28 00:31:32 +02:00
Wim
96022d3aaf Bump version 2020-05-24 22:44:10 +02:00
Wim
8eb5e3cbf8 Release v1.17.5 (#1150) 2020-05-24 22:35:56 +02:00
xnaas
ddc2625934 Update Dockerfile so inotify works (#1148)
This change would be required for the Docker image to actually read `RELOADABLE` config options from the `matterbridge.toml`.

This edit would require https://github.com/42wim/matterbridge/wiki/Deploy:-Docker to be updated as well to mention that mounting would have to change to mounting a ***directory*** not a file. inotify inside Docker cannot read directly mounted files, only directories, for whatever reason.

This will preserve setups that were configured to run the old way without breaking them and new configs can be setup "correctly" without issue.
2020-05-24 22:01:52 +02:00
Wim
7f7ca697a0 Ignore non-user messages (msteams). Fixes #1141 (#1149)
Ignore these messages for now, also add a extra
debug option for msteams so we can dump the whole
message.
2020-05-24 15:49:24 +02:00
Alexander
900375679b Prevent re-requesting avatar data (xmpp) (#1117)
Prevent asking the server again and again for a
user's avatar if the server does not respond to
our initial request.
2020-05-24 14:07:36 +02:00
Wim
9440b9e313 Increase debug logging with function,file and linenumber (#1147)
Show the function name,file and linenumber like this
[0000]  INFO main:         [setupLogger:matterbridge.go:100] Enabling debug logging.
[0000]  INFO main:         [main:matterbridge.go:46] Running version 1.17.5-dev

Only enable this for debug as this adds some overhead.
2020-05-24 13:58:15 +02:00
Wim
393f9e998b Update dependencies / vendor (#1146) 2020-05-24 00:06:21 +02:00
Wim
ba0bfe70a8 Add StripMarkdown option (irc). (#1145)
Enable `StripMarkdown` to strip markdown for irc.
2020-05-23 21:46:15 +02:00
Wim
3c4a3e3f75 Implement xep-0245 (xmpp). Closes #1137 (#1144) 2020-05-23 20:51:04 +02:00
Wim
274fb09ed4 Fix forward from hidden users (telegram). Closes #1131 (#1143)
Use ForwardDate to check if a message is forwarded.
If we have a nil ForwardedFrom then make this an unknown user.
2020-05-23 19:15:26 +02:00
Wim
d44598a900 Add an option to disable sending HTML to matrix. Fixes #1022 (#1135) 2020-05-14 00:37:41 +02:00
Wim
c9cfa59f54 Do not use webhooks when token is configured (slack) (fixes #1123) (#1134) 2020-05-14 00:27:34 +02:00
Tiago Epifânio
7062234331 Avoid creating invalid url when the user doesn't have an avatar (matrix) (#1130) 2020-05-11 00:21:56 +02:00
Qais Patankar
9754569525 Fix webhook EventUserAction messages being skipped (discord) (#1133)
Fixes #1132
2020-05-11 00:20:35 +02:00
Qais Patankar
52a071e34d Fix #1049: missing space before embeds (discord) (#1124) 2020-05-07 00:19:48 +02:00
Qais Patankar
2d8f749e36 Fix #1120: replaceAction "_" crash (discord) (#1121) 2020-04-25 14:22:22 +02:00
Wim
a18cb74f03 Bump version 2020-04-22 00:00:08 +02:00
Wim
6c442e239d Release v1.17.4 (#1112) 2020-04-21 23:53:51 +02:00
Wim
eaf92fca4d Add an ID cache (discord). Fixes #1106 (#1111)
When a webhook "edits" a message, it does this by deleting the message
and creating a new one with the new content.

On creation of this new message, we'll get another ID then already is
know by the gateway in its id cache. So we add it in our own cache and
replace it whenever we want to edit/delete it again.
2020-04-21 23:35:46 +02:00
Wim
06b7bad714 Lowercase account names. Fixes #1108 (#1110) 2020-04-21 20:42:11 +02:00
Wim
19eec2ed03 Update Rhymen/go-whatsapp. Fixes #1107 (#1109) 2020-04-21 19:55:47 +02:00
Wim
d99c54343a Remove panics and retry polling on failure (msteams). Fixes #1104 (#1105) 2020-04-21 19:29:24 +02:00
Wim
308a110000 Bump version 2020-04-19 17:23:17 +02:00
Wim
4f406b2ce6 Release v1.17.3 (#1103) 2020-04-19 17:13:58 +02:00
Wim
e564c555d7 Clip too long messages on 3000 length (slack). Fixes #1081 (#1102) 2020-04-19 17:00:11 +02:00
Wim
f7ec9af9e8 Add extra space before colon in attachments (irc). Fixes #1089 (#1101) 2020-04-19 16:45:53 +02:00
Wim
4d93a774ce Ignore non-critical errors (whatsapp). Fixes #1094 (#1100) 2020-04-19 13:45:35 +02:00
Wim
2595dd30bf Update matterbridge/go-xmpp. Fixes #1097 (#1099) 2020-04-19 01:06:44 +02:00
Wim
9190365289 Add JoinDelay option (irc). Fixes #1084 (#1098) 2020-04-19 00:46:35 +02:00
Wim
57794b3b9f Prevent image/message looping (slack). Fixes #1088 (#1096)
Also check for our matterbridge ID in Blocks set in SubMessages.
2020-04-18 22:30:49 +02:00
ldruschk
3c36f651be Fix the behavior of ShowTopicChange and SyncTopic (#1086)
Currently, the "topic_change" events are ignored if both, 
ShowTopicChange and SyncTopic are set, and forwarded otherwise. 

This pull requests changes the behavior such that the events are 
only forwarded if one of those two config options is set to true 
and ignored otherwise.
2020-04-18 22:05:27 +02:00
ldruschk
8e6ddadba2 Relay Joins/Topic changes in RocketChat bridge (#1085)
This pull request properly sets the events EventJoinLeave and EventTopicChange for messages from the RocketChat bridge and drops messages which are neither one of those events nor plain messages.
2020-04-18 22:00:35 +02:00
Wim
8a87a71927 Update matterbridge/go-xmpp to add PEP-0030 support (#1095) 2020-04-18 20:58:55 +02:00
Qais Patankar
0047e6f523 Sort README bridge and library links (#1093) 2020-04-18 18:12:16 +02:00
Alexander
7183095a28 Implement User Avatar spoofing of XMPP users (#1090)
* Implement User Avatar spoofing of XMPP users
2020-04-16 22:16:25 +02:00
Wim
13c90893c7 Update matterbridge/Rocket.Chat.Go.SDK (#1087) 2020-04-16 21:48:53 +02:00
Wim
976fbcd07f Bump version 2020-04-09 23:03:45 +02:00
Wim
d97b077e85 Release v1.17.2 (#1080) 2020-04-09 22:54:51 +02:00
Wim
8950575bfb Update Rhymen/go-whatsapp vendor and whatsapp version (#1078) 2020-04-09 22:30:08 +02:00
Jerry Heiselman
11fc4c286f Clarify terminology used in mapping group chat IDs to channels in config (#1079)
* Clarify embedded docs for channel specification

Should help with #1072
2020-04-08 23:52:38 +02:00
Wim
8d08e348a9 Reset start timestamp on reconnect (whatsapp). Fixes #1059 (#1064) 2020-03-31 23:26:53 +02:00
Wim
a18807f19e Update matterbridge/go-xmpp to add xmpp avatar support (#1070) 2020-03-29 17:35:40 +02:00
Wim
29f658fd3c Use DebugWriter after upstream changes (xmpp) 2020-03-29 15:03:24 +02:00
Wim
a30bb8fed0 Sync matterbridge/go-xmpp with upstream 2020-03-29 15:03:24 +02:00
Wim
092ca1cd67 Update vendor slack-go/slack (#1068) 2020-03-28 23:50:47 +01:00
Wim
0df2539641 Use upstream yaegashi/msgraph.go/msauth (msteams) (#1067) 2020-03-28 23:44:49 +01:00
Wim
0f2d8a599c Update vendor d5/tengo (#1066) 2020-03-28 23:41:35 +01:00
Wim
54b3143a1d Bump version 2020-03-28 00:29:41 +01:00
Wim
148f7d2a91 Release v1.17.1 (#1063) 2020-03-28 00:18:29 +01:00
Wim
1aa662f763 Update client version whatsapp. Fixes #1061 (#1062)
See https://github.com/Rhymen/go-whatsapp/issues/305
2020-03-28 00:18:03 +01:00
Alex Wigen
0b86b88de7 Remove build dependencies from final docker image (multistage build) (#1057)
This multistage build takes the resulting image size down from 346MB to
90MB.
2020-03-22 22:55:29 +01:00
Qais Patankar
98033b1ba7 Don't transmit typing events from ourselves (slack/discord) (#1056) 2020-03-22 18:39:11 +01:00
Qais Patankar
2b7eab629d Add support for build tags (#1054)
By default all bridges are available.

You can turn off certain bridges by providing
e.g. "nodiscord" as a build tag.

    go build -tags nomsteams,noapi
2020-03-22 18:34:14 +01:00
Wim
0e4973e15c Exclude gateway/bridgemap from linting (#1055) 2020-03-22 14:35:48 +01:00
Qais Patankar
af0acf0dae Strip extra info from emotes (discord) (#1052) 2020-03-22 14:16:31 +01:00
Qais Patankar
76e5fe5a87 Update vendor yaegashi/msgraph.go to v0.1.2 (2) 2020-03-22 00:02:48 +01:00
Qais Patankar
802c80f40c Update vendor yaegashi/msgraph.go to v0.1.2 (1) 2020-03-22 00:02:48 +01:00
Wim
a51c5bd905 Add more msteams docs (#1051) 2020-03-21 23:30:22 +01:00
Wim
8c68556f52 Bump version 2020-03-21 22:51:22 +01:00
Wim
cca1ea2404 Release v1.17.0 (#1050) 2020-03-21 21:33:16 +01:00
Wim
281016a501 Fix duplicate separator on empty description/url (discord). Fixes #1008 (#1035)
Make this work for all possible cases.
Add tests
2020-03-21 21:27:17 +01:00
Qais Patankar
d4acdf2f89 Use blocks not attachments (slack) (#1048)
This removes the extra space below messages, as shown in
https://user-images.githubusercontent.com/923242/77235190-a3359980-6bab-11ea-8b7b-697d730ae5c1.png
2020-03-21 21:03:12 +01:00
Qais Patankar
0951e75c85 Fix #1039: messages sent to Slack being synced back (#1046)
This is a regression from https://github.com/42wim/matterbridge/pull/581#issuecomment-562937576

Behaves the same as 95190f11bf
2020-03-21 20:12:30 +01:00
Jakub
6b017b226a Support JSON and YAML config formats (#1045)
Signed-off-by: Jakub Sokołowski <jakub@status.im>
2020-03-18 23:20:29 +01:00
Qais Patankar
9e3bd7398c Fix #1027: warning when handling inbound webhooks (discord) (#1044) 2020-03-18 23:12:48 +01:00
Qais Patankar
79f764c7a8 Refactor webhook permission checks 2020-03-18 23:10:47 +01:00
Qais Patankar
b5dc4353fb Fix #1040: spotty webhook permission verification 2020-03-18 23:10:47 +01:00
Qais Patankar
2fbac73c29 Ignore ConnectingEvent (slack) (#1041) 2020-03-18 23:03:20 +01:00
burner1024
6616d105d1 Add markdownv2 mode for telegram documentation, see #1032 (#1037) 2020-03-18 22:43:11 +01:00
Wim
6b4b19194e Update vendor shazow/ssh-chat (#1029) 2020-03-08 23:55:09 +01:00
Wim
9785edd263 Remove replace directives and use own fork to make go get work again (#1028)
See https://github.com/golang/go/issues/30354
go get doesn't honor the go.mod replace options.
2020-03-08 17:08:18 +01:00
Qais Patankar
2a0bc11b68 Make some discord matterbridge.toml.sample lines less verbose 2020-03-08 14:30:54 +01:00
Qais Patankar
dd0325a88d Remove trailing newlines from matterbridge.toml.sample 2020-03-08 14:30:54 +01:00
Qais Patankar
20783c0978 Refactor matterbridge.toml.sample discord section 2020-03-08 14:30:54 +01:00
Wim
3f06a40bd5 Support code snippets from msteams 2020-03-01 22:19:33 +01:00
Wim
68f43985ad Add scopes again 2020-03-01 22:19:33 +01:00
Wim
915ca8f817 Make linter happy and cleanup (msteams) 2020-03-01 22:19:33 +01:00
Wim
a65a81610b Support threading from other bridges to msteams 2020-03-01 22:19:33 +01:00
Wim
8eb6ed5639 Support receiving attachments from msteams 2020-03-01 22:19:33 +01:00
Wim
795a8705c3 Add initial Microsoft Teams support
Documentation on https://github.com/42wim/matterbridge/wiki/MS-Teams-setup
2020-03-01 22:19:33 +01:00
Wim
3af0dc3b3a Vendor libraries needed for msteams support 2020-03-01 22:19:33 +01:00
Wim
9cf9b958a3 Do not lint gomnd (#1021) 2020-03-01 22:05:50 +01:00
Wim
3ac2ba8d5a Update to go1.14 and golangci-lint 1.23.7 (#1020) 2020-03-01 21:50:21 +01:00
Wim
d893421c7b Update vendor keybase/go-keybase-chat-bot (#1019) 2020-03-01 21:09:23 +01:00
Wim
250b3bb579 Use upstream slack-go/slack again (#1018) 2020-03-01 20:59:19 +01:00
Alexander Pushkov
e9edbfc051 Make Keybase link point to the team directly (#1013) 2020-02-19 21:02:44 +01:00
Wim
e343db6f72 Make avatars download work with mediaserverdownload (telegram). Fixes #920 (#1012) 2020-02-15 18:31:40 +01:00
Qais Patankar
4d57d66f85 Fix typo in feature_request.md (#1009) 2020-02-10 22:35:11 +01:00
Wim
54ed6320c2 Add support for avatars from matrix. #984 (#1007) 2020-02-10 00:06:54 +01:00
Wim
23083f3ae0 Rebase gomatrix vendor with upstream (#1006) 2020-02-09 23:49:17 +01:00
Wim
1985873494 Implement basic reconnect (whatsapp). Fixes #987 (#1003) 2020-02-09 22:11:46 +01:00
Qais Patankar
8ae5917659 Be less lossy when throttling IRC messages (#1004)
Note that msg.Text and chucking it through a chan is OK: https://play.golang.org/p/MTfT3YSsgPX
2020-02-09 22:10:18 +01:00
Qais Patankar
c91bfd08d8 Add ability to procure avatars from the destination bridge (#1000)
* remote_avatar: add UseLocalAvatar

* remote_avatar: make sure msg.Protocol is always set correctly

* remote_avatars: support msg.Account

* remote_avatar: add to matterbridge.toml.sample

* remote_avatar: clarify something
2020-02-09 22:07:26 +01:00
Qais Patankar
49110a5872 Assign automatically labels when creating issues (#1005)
* Update Bug_report.md

* Add 'label: enhancement' to feature_request.md
2020-02-09 22:03:53 +01:00
Wim
c01c8edeb8 Fix go-keybase-chat-bot api changes 2020-02-08 18:33:05 +01:00
Wim
ff8cf067b8 Update kekeybase/go-keybase-chat-bot vendor 2020-02-08 18:33:05 +01:00
Qais Patankar
1420f68050 Check only bridged channels for PermManageWebhooks (discord) (#1001)
* Check only bridged channels for PermManageWebhooks

* add note
2020-02-08 15:13:23 +01:00
Martijn Braam
c0be3e585a Enable intra-word emphasis supression in markdown (#999)
This fixes plain links sent to Matrix being broken if they contain
underscores. Fixes issue #997
2020-02-04 13:22:05 +01:00
Wim
3049ef9151 Bump version 2020-02-02 22:40:44 +01:00
Wim
4be00bbe6b Release v1.16.5 2020-02-02 22:36:07 +01:00
Wim
9382dde098 Release v1.16.4 2020-02-02 22:22:39 +01:00
Wim
1bf46b7711 Fix duplicated messages (sshchat). Fixes #950 (#996) 2020-02-02 22:08:37 +01:00
Wim
b85bae31d9 Show file comment in webhook if normal message is empty (discord). Fixes #962 (#995) 2020-02-02 21:14:54 +01:00
Patrizio Bekerle
0898829313 Add Docker Compose configuration (#990)
* Add Docker Compose configuration

* Add docker wiki link
2020-02-02 21:14:19 +01:00
Wim
f8ad877601 Add DisableWebPagePreview option (telegram). Closes #980 (#994) 2020-02-02 18:53:04 +01:00
Wim
585d1556c1 Disable smartypants in markdown parser. Fixes #989, #983 (#993) 2020-02-02 18:35:43 +01:00
Wim
7486555875 Fail with message instead of panic. #988 (#991) 2020-02-01 15:23:50 +01:00
Humorhenker
fc30b1bacc Add QuoteLengthLimit option (telegram) fixes #963 (#985)
* QuoteLengthLimit option added to limit max. quoted message length if QuoteLengthLimit = 0 the whole message will be quoted
2020-01-30 00:02:33 +01:00
c0ncord2
0dd19af6e8 Create outmessage-discordemoji.tengo (#979) 2020-01-30 00:00:57 +01:00
Wim
4c44515f9d Fix channel ID problem with multiple gateways (discord). Fixes #953 (#977) 2020-01-09 23:54:04 +01:00
Wim
9d84d6dd64 Update to tengo v2 (#976) 2020-01-09 21:52:19 +01:00
Wim
0f708daf2d Update dependencies (#975) 2020-01-09 21:02:56 +01:00
Wim
b9354de8fd Clean up go.mod and vendor 2020-01-09 18:21:10 +01:00
Guillaume Lazzara
c9d5f4c898 Add support for WhatsApp media (jpeg/png/gif) bridging (#974)
* Whatsapp image bridging

* Prevent double message in telegram when media with caption received

Co-authored-by: imShara <shara@protonmail.com>
2020-01-09 18:14:01 +01:00
c0ncord2
810c150781 move stripCustomoji logic to default Tengo script (#973)
*  move stripCustomoji logic to default Tengo script 

Removing the image ID from the message (without any possibility of recovering it later) is a loss of valuable data that prevents users from giving support to custom emoji via Tengo scripts.

* bugfix - do send colors to other irc bridges

"if we're not sending to an irc bridge we strip the IRC colors"

Co-authored-by: c0ncord <59654954+c0ncord@users.noreply.github.com>
2020-01-09 18:02:53 +01:00
Wim
31dd538c0b Add extra mimetypes to docker image. Fixes #969 2020-01-07 23:34:11 +01:00
Justin W. Flory
62e38e7c45 Add link to Ansible role for Matterbridge (#968)
This commit replaces the FOSSRIT/infrastructure link to the Matterbridge
role to a properly-defined Ansible role published in Ansible Galaxy. I
am the maintainer of the FOSSRIT/infrastructure repo and I decided to
split the Ansible role there into its own dedicated role. I figure this
might make it more accessible to others and also gives other folks a
chance to contribute. 😄

Signed-off-by: Justin W. Flory <git@jwf.io>
2020-01-01 21:38:26 +01:00
Wim
b9da28a29b Bump version 2019-12-16 00:01:00 +01:00
Wim
84bfa8a6b1 Release v1.16.3 2019-12-15 23:54:21 +01:00
Wim
1f830963f6 Return when we have only WebhookURL (mattermost). Fixes #954 (#960) 2019-12-15 23:49:17 +01:00
Wim
12d2c6fe89 Update slack vendor to fix regression (#959) 2019-12-08 21:05:02 +01:00
Wim
f43faf15f8 Update slack vendor to master (#958) 2019-12-07 22:54:36 +01:00
Wim
173a38a374 Bump version 2019-11-26 00:18:00 +01:00
Qais Patankar
1604ff15b5 Re-add binary to .gitignore (#951)
* Fix binary path and include windows
2019-11-26 00:16:40 +01:00
Wim
214fe502cd Release v1.16.2 2019-11-17 23:25:08 +01:00
Wim
aae45a8179 Upgrade linter and travis to go1.13 (#949) 2019-11-17 23:16:06 +01:00
Wim
075ca9ca47 Switch to new emoji library kyokomi/emoji (#948) 2019-11-17 23:01:03 +01:00
Wim
d4253d7a55 Update shazow/ssh-chat dependency (#947) 2019-11-17 21:42:41 +01:00
Benjamin
0917dc8766 Update markdown parsing library to github.com/gomarkdown/markdown (#944) 2019-11-17 21:18:01 +01:00
Wim
aba86855b5 Use own slack fork to fix #937 (#943) 2019-11-14 00:04:39 +01:00
Wim
ed5386c213 Add MatterAMXX link 2019-11-04 23:20:44 +01:00
Wim
455e75e92f Bump version 2019-11-01 22:32:39 +01:00
Gonçalo Ribeiro
c394de0c88 Add support for receiving attachments (keybase) (#923) 2019-11-01 22:29:52 +01:00
Wim
bad1990173 Release v1.16.1 2019-10-27 01:49:41 +02:00
Wim
0bc159341d Update vendor (#932)
* Update vendor

* Fix godiscord api change
2019-10-27 01:45:57 +02:00
Wim
45bf1fd63a Convert slack bold/strike to correct markdown (slack). Fixes #918 (#930) 2019-10-27 01:10:59 +02:00
Wim
ff0de85817 Remove obsolete file upload links (discord). Fixes #908 (#931)
Since v1.16.0 we now can upload files via webhook.
Old way of showing files with webhook only setup can be removed.
2019-10-27 01:10:43 +02:00
Wim
727fa9f929 Add support for uploading application/x and audio/x (matrix). Fixes #925 (#929) 2019-10-27 00:06:44 +02:00
Wim
0b9bc18236 Update vendor matterbridge/gomatrix fork (#928) 2019-10-26 23:31:44 +02:00
Wim
bad3b83d33 Update golang-commonmark/linkify vendor and use upstream again. Fixes #924 (#926) 2019-10-26 22:08:02 +02:00
Wim
00967a98ac Fix panic on WebhookURL only setting (mattermost). Closes #916 (#917) 2019-10-04 01:01:24 +02:00
Qais Patankar
1d708ab351 Suppress unhandled HelloEvent message (slack) (#913) 2019-10-04 00:19:50 +02:00
Qais Patankar
ba6759010b Add UserTypingSupport (discord) (#914)
* Add Discord to UserTypingSupport

* discord: start typing in a channel on EventUserTyping receive

* discord: emit EventUserTyping to gateway
2019-10-04 00:18:56 +02:00
Wim
da3868c104 Try to fix blackfriday go modules mess 2019-09-22 00:34:37 +02:00
Wim
0abf4d5d5d Specify correct GuildID on unknown user query (discord). Fixes #879 (#894) 2019-09-15 20:25:42 +02:00
Michal Suchánek
9b320cd43f Add token support (RocketChat) (#892)
Signed-off-by: Michal Suchanek <msuchanek@suse.de>
2019-09-13 23:41:02 +02:00
Wim
28783a4146 Do configuration validation on start-up. Fixes #888 (#889)
Fail if:
* we don't have any gateways configured
* we have gateways configured but with non-existing bridge configuration
* we have gateways configured without any configuration
2019-09-09 23:48:00 +02:00
Wim
f92927eae5 Fix deprecation in goreleaser 2019-09-07 23:37:49 +02:00
Wim
294139ce7a Bump version and fix changelog 2019-09-07 23:30:17 +02:00
Wim
45becd2573 Release v1.16.0 2019-09-07 23:17:55 +02:00
Wim
a3bee01e0a Update dependencies (#886) 2019-09-07 22:46:58 +02:00
David Buckley
1dc93ec4f0 Make getChannelIdTeam behave like GetChannelId for groups (mattermost) (#873)
GetChannelId will support names generated from query groups when a team is not set,
but not when a team is set since it falls through to getChannelIdTeam which has a different inner loop. i
This pull makes the two implementations do the same thing.
2019-09-07 21:39:44 +02:00
Wim
3562d4220c Bail if incorrect Jid (xmpp). Fixes #869 (#883) 2019-09-07 21:36:25 +02:00
Wim
1532f6e427 Update lrstanley/girc vendor (#884) 2019-09-07 21:35:45 +02:00
Wim
9327810bbf Add tengo example for nick color filter. See #881 2019-09-07 20:01:54 +02:00
Wim
f66d5f1e58 Add extra debug info (discord) 2019-09-05 22:39:43 +02:00
MOZGIII
cec086994e Add support for sending files via webhook (discord) (#872) 2019-08-29 00:13:10 +02:00
Wim
942d8f1ced Create .fixmie.yml 2019-08-26 23:49:06 +02:00
Wim
1552dcb143 Replace bwmarrin/discordgo with matterbridge/discordgo (#878)
Needed for #872
2019-08-26 23:47:50 +02:00
Wim
d525f1c9e4 Update Rhymen/go-whatsapp vendor (#876) 2019-08-26 23:22:34 +02:00
cori hudson
921f2dfcdf Add initial Keybase Chat support (#877)
* initial work on native keybase bridging

* Hopefully make a functional keybase bridge

* add keybase to bridgemap

* send to right channel, try to figure out received msgs

* add account and userid

* i am a Dam Fool

* Fix formatting for messages, handle /me

* update vendors, ran golint and goimports

* move handlers to handlers.go, clean up unused config options

* add sample config, fix inconsistent remote nick handling

* Update readme with keybase links

* Resolve fixmie errors

* Error -> Errorf

* fix linting errors in go.mod and go.sum

* explicitly join channels, ignore messages from non-specified channels

* check that team names match before bridging message
2019-08-26 21:00:31 +02:00
Wim
79a006c8de Fix regression (discord). Closes #864 (#866) 2019-07-29 23:37:38 +02:00
Wim
ff27746c0c Bump version 2019-07-15 23:23:32 +02:00
3260 changed files with 467825 additions and 215137 deletions

3
.fixmie.yml Normal file
View File

@@ -0,0 +1,3 @@
go:
comments:
disabled: true

View File

@@ -1,6 +1,7 @@
--- ---
name: Bug report name: Bug report
about: Create a report to help us improve. (Check the FAQ on the wiki first) about: Create a report to help us improve. (Check the FAQ on the wiki first)
labels: bug
--- ---

View File

@@ -1,6 +1,7 @@
--- ---
name: Feature request name: Feature request
about: Suggest an idea for this project about: Suggest an idea for this project
labels: enhancement
--- ---

57
.github/workflows/development.yml vendored Normal file
View File

@@ -0,0 +1,57 @@
name: Development
on: [push, pull_request]
jobs:
lint:
name: golangci-lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 20
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v2
with:
version: v1.29
args: "-v --new-from-rev HEAD~5"
test-build-upload:
strategy:
matrix:
go-version: [1.14.x, 1.15.x]
platform: [ubuntu-latest]
runs-on: ${{ matrix.platform }}
steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Test
run: go test ./... -mod=vendor
- name: Build
run: |
mkdir -p output/{win,lin,arm,mac}
VERSION=$(git describe --tags)
GOOS=linux GOARCH=amd64 go build -mod=vendor -ldflags "-s -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o output/lin/matterbridge-$VERSION-linux-amd64
GOOS=windows GOARCH=amd64 go build -mod=vendor -ldflags "-s -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o output/win/matterbridge-$VERSION-windows-amd64.exe
GOOS=darwin GOARCH=amd64 go build -mod=vendor -ldflags "-s -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o output/mac/matterbridge-$VERSION-darwin-amd64
- name: Upload linux 64-bit
if: startsWith(matrix.go-version,'1.15')
uses: actions/upload-artifact@v2
with:
name: matterbridge-linux-64bit
path: output/lin
- name: Upload windows 64-bit
if: startsWith(matrix.go-version,'1.15')
uses: actions/upload-artifact@v2
with:
name: matterbridge-windows-64bit
path: output/win
- name: Upload darwin 64-bit
if: startsWith(matrix.go-version,'1.15')
uses: actions/upload-artifact@v2
with:
name: matterbridge-darwin-64bit
path: output/mac

3
.gitignore vendored
View File

@@ -1,5 +1,6 @@
# Exclude matterbridge binary # Exclude matterbridge binary
matterbridge /matterbridge
/matterbridge.exe
# Exclude configuration file # Exclude configuration file
matterbridge.toml matterbridge.toml

View File

@@ -23,7 +23,7 @@ run:
# default value is empty list, but next dirs are always skipped independently # default value is empty list, but next dirs are always skipped independently
# from this option's value: # from this option's value:
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
skip-dirs: skip-dirs: gateway/bridgemap$
# which files to skip: they will be analyzed, but issues from them # which files to skip: they will be analyzed, but issues from them
# won't be reported. Default value is empty list, but there is # won't be reported. Default value is empty list, but there is
@@ -174,7 +174,15 @@ linters:
- lll - lll
- maligned - maligned
- prealloc - prealloc
- wsl
- gomnd
- godox
- goerr113
- testpackage
- godot
- interfacer
- goheader
- noctx
# rules to deal with reported isues # rules to deal with reported isues
issues: issues:

View File

@@ -21,7 +21,11 @@ builds:
ldflags: ldflags:
- -s -w -X main.githash={{.ShortCommit}} - -s -w -X main.githash={{.ShortCommit}}
archive: archives:
-
id: matterbridge
builds:
- matterbridge
name_template: "{{ .Binary }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" name_template: "{{ .Binary }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
format: binary format: binary
files: files:

View File

@@ -1,56 +0,0 @@
language: go
go_import_path: github.com/42wim/matterbridge
# We have everything vendored so this helps TravisCI not run `go get ...`.
install: true
git:
depth: 200
notifications:
email: false
branches:
only:
- master
- /.*/
jobs:
include:
- stage: lint
# Run linting in one Go environment only.
script: ./ci/lint.sh
go: 1.12.x
env:
- GO111MODULE=on
- GOLANGCI_VERSION="v1.17.1"
- stage: test
# Run tests in a combination of Go environments.
script: ./ci/test.sh
go: 1.11.x
env:
- GO111MODULE=off
- script: ./ci/test.sh
go: 1.11.x
env:
- GO111MODULE=on
- script: ./ci/test.sh
go: 1.12.x
env:
- GO111MODULE=on
- REPORT_COVERAGE=1
- BINDEPLOY=1
before_deploy: /bin/bash ci/bintray.sh
deploy:
on:
all_branches: true
condition: $BINDEPLOY = 1
provider: bintray
edge:
branch: v1.8.47
file: ci/deploy.json
user: 42wim
key:
secure: "CeXXe6JOmt7HYR81MdWLua0ltQHhDdkIeRGBFbgd7hkb1wi8eF9DgpAcQrTso8NIlHNZmSAP46uhFgsRvkuezzX0ygalZ7DCJyAyn3sAMEh+UQSHV1WGThRehTtidqRGjetzsIGSwdrJOWil+XTfbO1Z8DGzfakhSuAZka8CM4BAoe3YeP9rYK8h+84x0GHfczvsLtXZ3mWLvQuwe4pK6+ItBCUg0ae7O7ZUpWHy0xQQkkWztY/6RAzXfaG7DuGjIw+20fhx3WOXRNpHCtZ6Bc3qERCpk0s1HhlQWlrN9wDaFTBWYwlvSnNgvxxMbNXJ6RrRJ0l0bA7FUswYwyroxhzrGLdzWDg8dHaQkypocngdalfhpsnoO9j3ApJhomUFJ3UoEq5nOGRUrKn8MPi+dP0zE4kNQ3e4VNa1ufNrvfpWolMg3xh8OXuhQdD5wIM5zFAbRJLqWSCVAjPq4DDPecmvXBOlIial7oa312lN5qnBnUjvAcxszZ+FUyDHT1Grxzna4tMwxY9obPzZUzm7359AOCCwIQFVB8GLqD2nwIstcXS0zGRz+fhviPipHuBa02q5bGUZwmkvrSNab0s8Jo7pCrel2Rz3nWPKaiCfq2WjbW1CLheSMkOQrjsdUd1hhbqNWFPUjJPInTc77NAKCfm5runv5uyowRLh4NNd0sI="

View File

@@ -1,11 +1,16 @@
FROM alpine:edge FROM alpine:edge AS builder
ENTRYPOINT ["/bin/matterbridge"]
COPY . /go/src/github.com/42wim/matterbridge COPY . /go/src/github.com/42wim/matterbridge
RUN apk update && apk add go git gcc musl-dev ca-certificates \ RUN apk update && apk add go git gcc musl-dev \
&& cd /go/src/github.com/42wim/matterbridge \ && cd /go/src/github.com/42wim/matterbridge \
&& export GOPATH=/go \ && export GOPATH=/go \
&& go get \ && go get \
&& go build -x -ldflags "-X main.githash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge \ && go build -x -ldflags "-X main.githash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge
&& rm -rf /go \
&& apk del --purge git go gcc musl-dev FROM alpine:edge
RUN apk --no-cache add ca-certificates mailcap
COPY --from=builder /bin/matterbridge /bin/matterbridge
RUN mkdir /etc/matterbridge \
&& touch /etc/matterbridge/matterbridge.toml \
&& ln -sf /matterbridge.toml /etc/matterbridge/matterbridge.toml
ENTRYPOINT ["/bin/matterbridge", "-conf", "/etc/matterbridge/matterbridge.toml"]

328
README.md
View File

@@ -3,32 +3,35 @@
# matterbridge # matterbridge
![Matterbridge Logo](img/matterbridge-notext.gif)<br /> ![Matterbridge Logo](img/matterbridge-notext.gif)<br />
**A simple chat bridge**<br /> **A simple chat bridge**<br />
Letting people be where they want to be.<br /> Letting people be where they want to be.<br />
<sub>Bridges between a growing number of protocols. Click below to demo or join the development chat.</sub> <sub>Bridges between a growing number of protocols. Click below to demo or join the development chat.</sub>
<sup> <sup>
[Gitter][mb-gitter] | [Discord][mb-discord] |
[IRC][mb-irc] | [Gitter][mb-gitter] |
[Discord][mb-discord] | [IRC][mb-irc] |
[Matrix][mb-matrix] | [Keybase][mb-keybase] |
[Slack][mb-slack] | [Matrix][mb-matrix] |
[Mattermost][mb-mattermost] | [Mattermost][mb-mattermost] |
[Rocket.Chat][mb-rocketchat] | [MSTeams][mb-msteams] |
[XMPP][mb-xmpp] | [Rocket.Chat][mb-rocketchat] |
[Twitch][mb-twitch] | [Slack][mb-slack] |
[WhatsApp][mb-whatsapp] | [Telegram][mb-telegram] |
[Zulip][mb-zulip] | [Twitch][mb-twitch] |
[Telegram][mb-telegram] | [WhatsApp][mb-whatsapp] |
And more... [XMPP][mb-xmpp] |
</sup> [Zulip][mb-zulip] |
And more...
</sup>
---
----
[![Download stable](https://img.shields.io/github/release/42wim/matterbridge.svg?label=download%20stable)](https://github.com/42wim/matterbridge/releases/latest) [![Download stable](https://img.shields.io/github/release/42wim/matterbridge.svg?label=download%20stable)](https://github.com/42wim/matterbridge/releases/latest)
[![Download dev](https://img.shields.io/bintray/v/42wim/nightly/Matterbridge.svg?label=download%20dev&colorB=007ec6)](https://bintray.com/42wim/nightly/Matterbridge/_latestVersion) [![Maintainability](https://api.codeclimate.com/v1/badges/82dff70ef2ba85a6173a/maintainability)](https://codeclimate.com/github/42wim/matterbridge/maintainability)
[![Maintainability](https://api.codeclimate.com/v1/badges/82dff70ef2ba85a6173a/maintainability)](https://codeclimate.com/github/42wim/matterbridge/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/82dff70ef2ba85a6173a/test_coverage)](https://codeclimate.com/github/42wim/matterbridge/test_coverage)<br />
[![Test Coverage](https://api.codeclimate.com/v1/badges/82dff70ef2ba85a6173a/test_coverage)](https://codeclimate.com/github/42wim/matterbridge/test_coverage)<br />
<hr /> <hr />
</div> </div>
<div align="right"><sup> <div align="right"><sup>
@@ -41,134 +44,161 @@
</a> </a>
</p> </p>
### Table of Contents # Table of Contents
* [Features](https://github.com/42wim/matterbridge/wiki/Features)
* [Natively supported](#natively-supported) - [matterbridge](#matterbridge)
* [3rd party via matterbridge api](#3rd-party-via-matterbridge-api) - [Table of Contents](#table-of-contents)
* [API](#API) - [Features](#features)
* [Chat with us](#chat-with-us) - [Natively supported](#natively-supported)
* [Screenshots](https://github.com/42wim/matterbridge/wiki/) - [3rd party via matterbridge api](#3rd-party-via-matterbridge-api)
* [Installing/upgrading](#installing--upgrading) - [API](#api)
* [Binaries](#binaries) - [Chat with us](#chat-with-us)
* [Building](#building) - [Screenshots](#screenshots)
* [Configuration](#configuration) - [Installing / upgrading](#installing--upgrading)
* [Howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) - [Binaries](#binaries)
* [Settings](#settings) - [Packages](#packages)
* [Examples](#examples) - [Building](#building)
* [Running](#running) - [Configuration](#configuration)
* [Docker](#docker) - [Basic configuration](#basic-configuration)
* [Changelog](#changelog) - [Settings](#settings)
* [FAQ](#faq) - [Advanced configuration](#advanced-configuration)
* [Related projects](#related-projects) - [Examples](#examples)
* [Articles](#articles) - [Bridge mattermost (off-topic) - irc (#testing)](#bridge-mattermost-off-topic---irc-testing)
* [Thanks](#thanks) - [Bridge slack (#general) - discord (general)](#bridge-slack-general---discord-general)
- [Running](#running)
- [Docker](#docker)
- [Changelog](#changelog)
- [FAQ](#faq)
- [Related projects](#related-projects)
- [Articles](#articles)
- [Thanks](#thanks)
## Features ## Features
* [Support bridging between any protocols](https://github.com/42wim/matterbridge/wiki/Features#support-bridging-between-any-protocols)
* [Support multiple gateways(bridges) for your protocols](https://github.com/42wim/matterbridge/wiki/Features#support-multiple-gatewaysbridges-for-your-protocols) - [Support bridging between any protocols](https://github.com/42wim/matterbridge/wiki/Features#support-bridging-between-any-protocols)
* [Message edits and deletes](https://github.com/42wim/matterbridge/wiki/Features#message-edits-and-deletes) - [Support multiple gateways(bridges) for your protocols](https://github.com/42wim/matterbridge/wiki/Features#support-multiple-gatewaysbridges-for-your-protocols)
* Preserves threading when possible - [Message edits and deletes](https://github.com/42wim/matterbridge/wiki/Features#message-edits-and-deletes)
* [Attachment / files handling](https://github.com/42wim/matterbridge/wiki/Features#attachment--files-handling) - Preserves threading when possible
* [Username and avatar spoofing](https://github.com/42wim/matterbridge/wiki/Features#username-and-avatar-spoofing) - [Attachment / files handling](https://github.com/42wim/matterbridge/wiki/Features#attachment--files-handling)
* [Private groups](https://github.com/42wim/matterbridge/wiki/Features#private-groups) - [Username and avatar spoofing](https://github.com/42wim/matterbridge/wiki/Features#username-and-avatar-spoofing)
* [API](https://github.com/42wim/matterbridge/wiki/Features#api) - [Private groups](https://github.com/42wim/matterbridge/wiki/Features#private-groups)
- [API](https://github.com/42wim/matterbridge/wiki/Features#api)
### Natively supported ### Natively supported
* [Mattermost](https://github.com/mattermost/mattermost-server/) 4.x, 5.x - [Discord](https://discordapp.com)
* [IRC](http://www.mirc.com/servers.html) - [Gitter](https://gitter.im)
* [XMPP](https://xmpp.org) - [IRC](http://www.mirc.com/servers.html)
* [Gitter](https://gitter.im) - [Keybase](https://keybase.io)
* [Slack](https://slack.com) - [Matrix](https://matrix.org)
* [Discord](https://discordapp.com) - [Mattermost](https://github.com/mattermost/mattermost-server/) 4.x, 5.x
* [Telegram](https://telegram.org) - [Microsoft Teams](https://teams.microsoft.com)
* [Rocket.chat](https://rocket.chat) - [Nextcloud Talk](https://nextcloud.com/talk/)
* [Matrix](https://matrix.org) - [Rocket.chat](https://rocket.chat)
* [Steam](https://store.steampowered.com/) - [Slack](https://slack.com)
* [Twitch](https://twitch.tv) - [Ssh-chat](https://github.com/shazow/ssh-chat)
* [Ssh-chat](https://github.com/shazow/ssh-chat) - [Steam](https://store.steampowered.com/)
* [WhatsApp](https://www.whatsapp.com/) - [Telegram](https://telegram.org)
* [Zulip](https://zulipchat.com) - [Twitch](https://twitch.tv)
- [WhatsApp](https://www.whatsapp.com/)
- [XMPP](https://xmpp.org)
- [Zulip](https://zulipchat.com)
### 3rd party via matterbridge api ### 3rd party via matterbridge api
* [Minecraft](https://github.com/elytra/MatterLink)
* [Reddit](https://github.com/bonehurtingjuice/mattereddit) - [Discourse](https://github.com/DeclanHoare/matterbabble)
* [Facebook messenger](https://github.com/VictorNine/fbridge) - [Facebook messenger](https://github.com/VictorNine/fbridge)
* [Discourse](https://github.com/DeclanHoare/matterbabble) - [Minecraft](https://github.com/elytra/MatterLink)
- [Reddit](https://github.com/bonehurtingjuice/mattereddit)
- [Counter-Strike, half-life and more](https://forums.alliedmods.net/showthread.php?t=319430)
- [MatterAMXX](https://github.com/GabeIggy/MatterAMXX)
### API ### API
The API is basic at the moment. The API is basic at the moment.
More info and examples on the [wiki](https://github.com/42wim/matterbridge/wiki/Api). More info and examples on the [wiki](https://github.com/42wim/matterbridge/wiki/Api).
Used by the projects below. Feel free to make a PR to add your project to this list. Used by the projects below. Feel free to make a PR to add your project to this list.
* [MatterLink](https://github.com/elytra/MatterLink) (Matterbridge link for Minecraft Server chat) - [MatterLink](https://github.com/elytra/MatterLink) (Matterbridge link for Minecraft Server chat)
* [pyCord](https://github.com/NikkyAI/pyCord) (crossplatform chatbot) - [pyCord](https://github.com/NikkyAI/pyCord) (crossplatform chatbot)
* [Mattereddit](https://github.com/bonehurtingjuice/mattereddit) (Reddit chat support) - [Mattereddit](https://github.com/bonehurtingjuice/mattereddit) (Reddit chat support)
* [fbridge](https://github.com/VictorNine/fbridge) (Facebook messenger support) - [fbridge](https://github.com/VictorNine/fbridge) (Facebook messenger support)
* [matterbabble](https://github.com/DeclanHoare/matterbabble) (Discourse support) - [matterbabble](https://github.com/DeclanHoare/matterbabble) (Discourse support)
- [MatterAMXX](https://forums.alliedmods.net/showthread.php?t=319430) (Counter-Strike, half-life and more via AMXX mod)
## Chat with us ## Chat with us
Questions or want to test on your favorite platform? Join below: Questions or want to test on your favorite platform? Join below:
* [Gitter][mb-gitter] - [Discord][mb-discord]
* [IRC][mb-irc] - [Gitter][mb-gitter]
* [Discord][mb-discord] - [IRC][mb-irc]
* [Matrix][mb-matrix] - [Keybase][mb-keybase]
* [Slack][mb-slack] - [Matrix][mb-matrix]
* [Mattermost][mb-mattermost] - [Mattermost][mb-mattermost]
* [Rocket.Chat][mb-rocketchat] - [Rocket.Chat][mb-rocketchat]
* [XMPP][mb-xmpp] (matterbridge@conference.jabber.de) - [Slack][mb-slack]
* [Twitch][mb-twitch] - [Telegram][mb-telegram]
* [Zulip][mb-zulip] - [Twitch][mb-twitch]
* [Telegram][mb-telegram] - [XMPP][mb-xmpp] (matterbridge@conference.jabber.de)
- [Zulip][mb-zulip]
## Screenshots ## Screenshots
See https://github.com/42wim/matterbridge/wiki See https://github.com/42wim/matterbridge/wiki
## Installing / upgrading ## Installing / upgrading
### Binaries ### Binaries
* Latest stable release [v1.15.1](https://github.com/42wim/matterbridge/releases/latest)
* Development releases (follows master) can be downloaded [here](https://dl.bintray.com/42wim/nightly/) - Latest stable release [v1.18.1](https://github.com/42wim/matterbridge/releases/latest)
- Development releases (follows master) can be downloaded [here](https://github.com/42wim/matterbridge/actions) selecting the latest green build and then artifacts.
To install or upgrade just download the latest [binary](https://github.com/42wim/matterbridge/releases/latest) and follow the instructions on the [howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) for a step by step walkthrough for creating your configuration. To install or upgrade just download the latest [binary](https://github.com/42wim/matterbridge/releases/latest) and follow the instructions on the [howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) for a step by step walkthrough for creating your configuration.
### Packages ### Packages
* [Overview](https://repology.org/metapackage/matterbridge/versions)
- [Overview](https://repology.org/metapackage/matterbridge/versions)
- [snap](https://snapcraft.io/matterbridge)
## Building ## Building
Most people just want to use binaries, you can find those [here](https://github.com/42wim/matterbridge/releases/latest) Most people just want to use binaries, you can find those [here](https://github.com/42wim/matterbridge/releases/latest)
If you really want to build from source, follow these instructions: If you really want to build from source, follow these instructions:
Go 1.9+ is required. Make sure you have [Go](https://golang.org/doc/install) properly installed, including setting up your [GOPATH](https://golang.org/doc/code.html#GOPATH). Go 1.12+ is required. Make sure you have [Go](https://golang.org/doc/install) properly installed.
After Go is setup, download matterbridge to your $GOPATH directory.
``` ```
cd $GOPATH
go get github.com/42wim/matterbridge go get github.com/42wim/matterbridge
``` ```
You should now have matterbridge binary in the bin directory: You should now have matterbridge binary in the ~/go/bin directory:
``` ```
$ ls bin/ $ ls ~/go/bin/
matterbridge matterbridge
``` ```
## Configuration ## Configuration
### Basic configuration ### Basic configuration
See [howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) for a step by step walkthrough for creating your configuration. See [howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) for a step by step walkthrough for creating your configuration.
### Settings ### Settings
All possible [settings](https://github.com/42wim/matterbridge/wiki/Settings) for each bridge. All possible [settings](https://github.com/42wim/matterbridge/wiki/Settings) for each bridge.
### Advanced configuration ### Advanced configuration
* [matterbridge.toml.sample](https://github.com/42wim/matterbridge/blob/master/matterbridge.toml.sample) for documentation and an example.
- [matterbridge.toml.sample](https://github.com/42wim/matterbridge/blob/master/matterbridge.toml.sample) for documentation and an example.
### Examples ### Examples
#### Bridge mattermost (off-topic) - irc (#testing) #### Bridge mattermost (off-topic) - irc (#testing)
```toml ```toml
[irc] [irc]
[irc.freenode] [irc.freenode]
@@ -197,6 +227,7 @@ enable=true
``` ```
#### Bridge slack (#general) - discord (general) #### Bridge slack (#general) - discord (general)
```toml ```toml
[slack] [slack]
[slack.test] [slack.test]
@@ -241,12 +272,11 @@ Usage of ./matterbridge:
``` ```
### Docker ### Docker
Create your matterbridge.toml file locally eg in `/tmp/matterbridge.toml`
``` Please take a look at the [Docker Wiki page](https://github.com/42wim/matterbridge/wiki/Deploy:-Docker) for more information.
docker run -ti -v /tmp/matterbridge.toml:/matterbridge.toml 42wim/matterbridge
```
## Changelog ## Changelog
See [changelog.md](https://github.com/42wim/matterbridge/blob/master/changelog.md) See [changelog.md](https://github.com/42wim/matterbridge/blob/master/changelog.md)
## FAQ ## FAQ
@@ -254,28 +284,31 @@ See [changelog.md](https://github.com/42wim/matterbridge/blob/master/changelog.m
See [FAQ](https://github.com/42wim/matterbridge/wiki/FAQ) See [FAQ](https://github.com/42wim/matterbridge/wiki/FAQ)
## Related projects ## Related projects
* [FOSSRIT/infrastructure - roles/matterbridge](https://github.com/FOSSRIT/infrastructure/tree/master/roles/matterbridge) (Ansible role used to automate deployments of Matterbridge)
* [matterbridge autoconfig](https://github.com/patcon/matterbridge-autoconfig) - [jwflory/ansible-role-matterbridge](https://galaxy.ansible.com/jwflory/matterbridge) (Ansible role to simplify deploying Matterbridge)
* [matterbridge config viewer](https://github.com/patcon/matterbridge-heroku-viewer) - [matterbridge autoconfig](https://github.com/patcon/matterbridge-autoconfig)
* [matterbridge-heroku](https://github.com/cadecairos/matterbridge-heroku) - [matterbridge config viewer](https://github.com/patcon/matterbridge-heroku-viewer)
* [mattereddit](https://github.com/bonehurtingjuice/mattereddit) - [matterbridge-heroku](https://github.com/cadecairos/matterbridge-heroku)
* [matterlink](https://github.com/elytra/MatterLink) - [mattereddit](https://github.com/bonehurtingjuice/mattereddit)
* [mattermost-plugin](https://github.com/matterbridge/mattermost-plugin) - Run matterbridge as a plugin in mattermost - [matterlink](https://github.com/elytra/MatterLink)
* [pyCord](https://github.com/NikkyAI/pyCord) (crossplatform chatbot) - [mattermost-plugin](https://github.com/matterbridge/mattermost-plugin) - Run matterbridge as a plugin in mattermost
* [fbridge](https://github.com/VictorNine/fbridge) (Facebook messenger support) - [pyCord](https://github.com/NikkyAI/pyCord) (crossplatform chatbot)
* [isla](https://github.com/alphachung/isla) (Bot for Discord-Telegram groups used alongside matterbridge) - [fbridge](https://github.com/VictorNine/fbridge) (Facebook messenger support)
* [matterbabble](https://github.com/DeclanHoare/matterbabble) (Connect Discourse threads to Matterbridge) - [isla](https://github.com/alphachung/isla) (Bot for Discord-Telegram groups used alongside matterbridge)
- [matterbabble](https://github.com/DeclanHoare/matterbabble) (Connect Discourse threads to Matterbridge)
## Articles ## Articles
* [matterbridge on kubernetes](https://medium.freecodecamp.org/using-kubernetes-to-deploy-a-chat-gateway-or-when-technology-works-like-its-supposed-to-a169a8cd69a3)
* https://mattermost.com/blog/connect-irc-to-mattermost/ - [matterbridge on kubernetes](https://medium.freecodecamp.org/using-kubernetes-to-deploy-a-chat-gateway-or-when-technology-works-like-its-supposed-to-a169a8cd69a3)
* https://blog.valvin.fr/2016/09/17/mattermost-et-un-channel-irc-cest-possible/ - https://mattermost.com/blog/connect-irc-to-mattermost/
* https://blog.brightscout.com/top-10-mattermost-integrations/ - https://blog.valvin.fr/2016/09/17/mattermost-et-un-channel-irc-cest-possible/
* http://bencey.co.nz/2018/09/17/bridge/ - https://blog.brightscout.com/top-10-mattermost-integrations/
* https://www.algoo.fr/blog/2018/01/19/recouvrez-votre-liberte-en-quittant-slack-pour-un-mattermost-auto-heberge/ - http://bencey.co.nz/2018/09/17/bridge/
* https://kopano.com/blog/matterbridge-bridging-mattermost-chat/ - https://www.algoo.fr/blog/2018/01/19/recouvrez-votre-liberte-en-quittant-slack-pour-un-mattermost-auto-heberge/
* https://www.stitcher.com/s/?eid=52382713 - https://kopano.com/blog/matterbridge-bridging-mattermost-chat/
* https://daniele.tech/2019/02/how-to-use-matterbridge-to-connect-2-different-slack-workspaces/ - https://www.stitcher.com/s/?eid=52382713
- https://daniele.tech/2019/02/how-to-use-matterbridge-to-connect-2-different-slack-workspaces/
- https://userlinux.net/mattermost-and-matterbridge.html
## Thanks ## Thanks
@@ -287,34 +320,39 @@ See [FAQ](https://github.com/42wim/matterbridge/wiki/FAQ)
</p> </p>
Matterbridge wouldn't exist without these libraries: Matterbridge wouldn't exist without these libraries:
* discord - https://github.com/bwmarrin/discordgo
* echo - https://github.com/labstack/echo - discord - https://github.com/bwmarrin/discordgo
* gitter - https://github.com/sromku/go-gitter - echo - https://github.com/labstack/echo
* gops - https://github.com/google/gops - gitter - https://github.com/sromku/go-gitter
* gozulipbot - https://github.com/ifo/gozulipbot - gops - https://github.com/google/gops
* irc - https://github.com/lrstanley/girc - gozulipbot - https://github.com/ifo/gozulipbot
* mattermost - https://github.com/mattermost/mattermost-server - irc - https://github.com/lrstanley/girc
* matrix - https://github.com/matrix-org/gomatrix - keybase - https://github.com/keybase/go-keybase-chat-bot
* sshchat - https://github.com/shazow/ssh-chat - matrix - https://github.com/matrix-org/gomatrix
* slack - https://github.com/nlopes/slack - mattermost - https://github.com/mattermost/mattermost-server
* steam - https://github.com/Philipp15b/go-steam - msgraph.go - https://github.com/yaegashi/msgraph.go
* telegram - https://github.com/go-telegram-bot-api/telegram-bot-api - slack - https://github.com/nlopes/slack
* xmpp - https://github.com/mattn/go-xmpp - sshchat - https://github.com/shazow/ssh-chat
* whatsapp - https://github.com/Rhymen/go-whatsapp/ - steam - https://github.com/Philipp15b/go-steam
* zulip - https://github.com/ifo/gozulipbot - telegram - https://github.com/go-telegram-bot-api/telegram-bot-api
* tengo - https://github.com/d5/tengo - tengo - https://github.com/d5/tengo
- whatsapp - https://github.com/Rhymen/go-whatsapp/
- xmpp - https://github.com/mattn/go-xmpp
- zulip - https://github.com/ifo/gozulipbot
<!-- Links --> <!-- Links -->
[mb-gitter]: https://gitter.im/42wim/matterbridge [mb-discord]: https://discord.gg/AkKPtrQ
[mb-irc]: https://webchat.freenode.net/?channels=matterbridgechat [mb-gitter]: https://gitter.im/42wim/matterbridge
[mb-discord]: https://discord.gg/AkKPtrQ [mb-irc]: https://webchat.freenode.net/?channels=matterbridgechat
[mb-matrix]: https://riot.im/app/#/room/#matterbridge:matrix.org [mb-keybase]: https://keybase.io/team/matterbridge
[mb-slack]: https://join.slack.com/matterbridgechat/shared_invite/MjEwODMxNjU1NDMwLTE0OTk2MTU3NTMtMzZkZmRiNDZhOA [mb-matrix]: https://riot.im/app/#/room/#matterbridge:matrix.org
[mb-mattermost]: https://framateam.org/signup_user_complete/?id=tfqm33ggop8x3qgu4boeieta6e [mb-mattermost]: https://framateam.org/signup_user_complete/?id=tfqm33ggop8x3qgu4boeieta6e
[mb-rocketchat]: https://open.rocket.chat/channel/matterbridge [mb-msteams]: https://teams.microsoft.com/join/hj92x75gd3y7
[mb-xmpp]: https://inverse.chat/ [mb-rocketchat]: https://open.rocket.chat/channel/matterbridge
[mb-twitch]: https://www.twitch.tv/matterbridge [mb-slack]: https://join.slack.com/matterbridgechat/shared_invite/MjEwODMxNjU1NDMwLTE0OTk2MTU3NTMtMzZkZmRiNDZhOA
[mb-whatsapp]: https://www.whatsapp.com/ [mb-telegram]: https://t.me/Matterbridge
[mb-zulip]: https://matterbridge.zulipchat.com/register/ [mb-twitch]: https://www.twitch.tv/matterbridge
[mb-telegram]: https://t.me/Matterbridge [mb-whatsapp]: https://www.whatsapp.com/
[mb-xmpp]: https://inverse.chat/
[mb-zulip]: https://matterbridge.zulipchat.com/register/

View File

@@ -8,9 +8,10 @@ import (
"github.com/42wim/matterbridge/bridge" "github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/gorilla/websocket"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware" "github.com/labstack/echo/v4/middleware"
"github.com/zfjagann/golang-ring" ring "github.com/zfjagann/golang-ring"
) )
type API struct { type API struct {
@@ -41,9 +42,17 @@ func New(cfg *bridge.Config) bridge.Bridger {
return key == b.GetString("Token"), nil return key == b.GetString("Token"), nil
})) }))
} }
// Set RemoteNickFormat to a sane default
if !b.IsKeySet("RemoteNickFormat") {
b.Log.Debugln("RemoteNickFormat is unset, defaulting to \"{NICK}\"")
b.Config.Config.Viper().Set(b.GetConfigKey("RemoteNickFormat"), "{NICK}")
}
e.GET("/api/health", b.handleHealthcheck) e.GET("/api/health", b.handleHealthcheck)
e.GET("/api/messages", b.handleMessages) e.GET("/api/messages", b.handleMessages)
e.GET("/api/stream", b.handleStream) e.GET("/api/stream", b.handleStream)
e.GET("/api/websocket", b.handleWebsocket)
e.POST("/api/message", b.handlePostMessage) e.POST("/api/message", b.handlePostMessage)
go func() { go func() {
if b.GetString("BindAddress") == "" { if b.GetString("BindAddress") == "" {
@@ -106,13 +115,17 @@ func (b *API) handleMessages(c echo.Context) error {
return nil return nil
} }
func (b *API) handleStream(c echo.Context) error { func (b *API) getGreeting() config.Message {
c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSON) return config.Message{
c.Response().WriteHeader(http.StatusOK)
greet := config.Message{
Event: config.EventAPIConnected, Event: config.EventAPIConnected,
Timestamp: time.Now(), Timestamp: time.Now(),
} }
}
func (b *API) handleStream(c echo.Context) error {
c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
c.Response().WriteHeader(http.StatusOK)
greet := b.getGreeting()
if err := json.NewEncoder(c.Response()).Encode(greet); err != nil { if err := json.NewEncoder(c.Response()).Encode(greet); err != nil {
return err return err
} }
@@ -128,3 +141,52 @@ func (b *API) handleStream(c echo.Context) error {
time.Sleep(200 * time.Millisecond) time.Sleep(200 * time.Millisecond)
} }
} }
func (b *API) handleWebsocketMessage(message config.Message) {
message.Channel = "api"
message.Protocol = "api"
message.Account = b.Account
message.ID = ""
message.Timestamp = time.Now()
b.Log.Debugf("Sending websocket message from %s on %s to gateway", message.Username, "api")
b.Remote <- message
}
func (b *API) writePump(conn *websocket.Conn) {
for {
msg := b.Messages.Dequeue()
if msg != nil {
err := conn.WriteJSON(msg)
if err != nil {
break
}
}
}
}
func (b *API) readPump(conn *websocket.Conn) {
for {
message := config.Message{}
err := conn.ReadJSON(&message)
if err != nil {
break
}
b.handleWebsocketMessage(message)
}
}
func (b *API) handleWebsocket(c echo.Context) error {
conn, err := websocket.Upgrade(c.Response().Writer, c.Request(), nil, 1024, 1024)
if err != nil {
return err
}
greet := b.getGreeting()
_ = conn.WriteJSON(greet)
go b.writePump(conn)
go b.readPump(conn)
return nil
}

View File

@@ -1,8 +1,10 @@
package bridge package bridge
import ( import (
"log"
"strings" "strings"
"sync" "sync"
"time"
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@@ -41,6 +43,10 @@ type Factory func(*Config) Bridger
func New(bridge *config.Bridge) *Bridge { func New(bridge *config.Bridge) *Bridge {
accInfo := strings.Split(bridge.Account, ".") accInfo := strings.Split(bridge.Account, ".")
if len(accInfo) != 2 {
log.Fatalf("config failure, account incorrect: %s", bridge.Account)
}
protocol := accInfo[0] protocol := accInfo[0]
name := accInfo[1] name := accInfo[1]
@@ -69,6 +75,7 @@ func (b *Bridge) joinChannels(channels map[string]config.ChannelInfo, exists map
for ID, channel := range channels { for ID, channel := range channels {
if !exists[ID] { if !exists[ID] {
b.Log.Infof("%s: joining %s (ID: %s)", b.Account, channel.Name, ID) b.Log.Infof("%s: joining %s (ID: %s)", b.Account, channel.Name, ID)
time.Sleep(time.Duration(b.GetInt("JoinDelay")) * time.Millisecond)
err := b.JoinChannel(channel) err := b.JoinChannel(channel)
if err != nil { if err != nil {
return err return err
@@ -79,8 +86,16 @@ func (b *Bridge) joinChannels(channels map[string]config.ChannelInfo, exists map
return nil return nil
} }
func (b *Bridge) GetConfigKey(key string) string {
return b.Account + "." + key
}
func (b *Bridge) IsKeySet(key string) bool {
return b.Config.IsKeySet(b.GetConfigKey(key)) || b.Config.IsKeySet("general."+key)
}
func (b *Bridge) GetBool(key string) bool { func (b *Bridge) GetBool(key string) bool {
val, ok := b.Config.GetBool(b.Account + "." + key) val, ok := b.Config.GetBool(b.GetConfigKey(key))
if !ok { if !ok {
val, _ = b.Config.GetBool("general." + key) val, _ = b.Config.GetBool("general." + key)
} }
@@ -88,7 +103,7 @@ func (b *Bridge) GetBool(key string) bool {
} }
func (b *Bridge) GetInt(key string) int { func (b *Bridge) GetInt(key string) int {
val, ok := b.Config.GetInt(b.Account + "." + key) val, ok := b.Config.GetInt(b.GetConfigKey(key))
if !ok { if !ok {
val, _ = b.Config.GetInt("general." + key) val, _ = b.Config.GetInt("general." + key)
} }
@@ -96,7 +111,7 @@ func (b *Bridge) GetInt(key string) int {
} }
func (b *Bridge) GetString(key string) string { func (b *Bridge) GetString(key string) string {
val, ok := b.Config.GetString(b.Account + "." + key) val, ok := b.Config.GetString(b.GetConfigKey(key))
if !ok { if !ok {
val, _ = b.Config.GetString("general." + key) val, _ = b.Config.GetString("general." + key)
} }
@@ -104,7 +119,7 @@ func (b *Bridge) GetString(key string) string {
} }
func (b *Bridge) GetStringSlice(key string) []string { func (b *Bridge) GetStringSlice(key string) []string {
val, ok := b.Config.GetStringSlice(b.Account + "." + key) val, ok := b.Config.GetStringSlice(b.GetConfigKey(key))
if !ok { if !ok {
val, _ = b.Config.GetStringSlice("general." + key) val, _ = b.Config.GetStringSlice("general." + key)
} }
@@ -112,7 +127,7 @@ func (b *Bridge) GetStringSlice(key string) []string {
} }
func (b *Bridge) GetStringSlice2D(key string) [][]string { func (b *Bridge) GetStringSlice2D(key string) [][]string {
val, ok := b.Config.GetStringSlice2D(b.Account + "." + key) val, ok := b.Config.GetStringSlice2D(b.GetConfigKey(key))
if !ok { if !ok {
val, _ = b.Config.GetStringSlice2D("general." + key) val, _ = b.Config.GetStringSlice2D("general." + key)
} }

View File

@@ -3,6 +3,8 @@ package config
import ( import (
"bytes" "bytes"
"io/ioutil" "io/ioutil"
"os"
"path/filepath"
"strings" "strings"
"sync" "sync"
"time" "time"
@@ -76,23 +78,29 @@ type Protocol struct {
BindAddress string // mattermost, slack // DEPRECATED BindAddress string // mattermost, slack // DEPRECATED
Buffer int // api Buffer int // api
Charset string // irc Charset string // irc
ClientID string // msteams
ColorNicks bool // only irc for now ColorNicks bool // only irc for now
Debug bool // general Debug bool // general
DebugLevel int // only for irc now DebugLevel int // only for irc now
DisableWebPagePreview bool // telegram
EditSuffix string // mattermost, slack, discord, telegram, gitter EditSuffix string // mattermost, slack, discord, telegram, gitter
EditDisable bool // mattermost, slack, discord, telegram, gitter EditDisable bool // mattermost, slack, discord, telegram, gitter
HTMLDisable bool // matrix
IconURL string // mattermost, slack IconURL string // mattermost, slack
IgnoreFailureOnStart bool // general IgnoreFailureOnStart bool // general
IgnoreNicks string // all protocols IgnoreNicks string // all protocols
IgnoreMessages string // all protocols IgnoreMessages string // all protocols
Jid string // xmpp Jid string // xmpp
JoinDelay string // all protocols
Label string // all protocols Label string // all protocols
Login string // mattermost, matrix Login string // mattermost, matrix
LogFile string // general
MediaDownloadBlackList []string MediaDownloadBlackList []string
MediaDownloadPath string // Basically MediaServerUpload, but instead of uploading it, just write it to a file on the same server. MediaDownloadPath string // Basically MediaServerUpload, but instead of uploading it, just write it to a file on the same server.
MediaDownloadSize int // all protocols MediaDownloadSize int // all protocols
MediaServerDownload string MediaServerDownload string
MediaServerUpload string MediaServerUpload string
MediaConvertTgs string // telegram
MediaConvertWebPToPNG bool // telegram MediaConvertWebPToPNG bool // telegram
MessageDelay int // IRC, time in millisecond to wait between messages MessageDelay int // IRC, time in millisecond to wait between messages
MessageFormat string // telegram MessageFormat string // telegram
@@ -116,12 +124,14 @@ type Protocol struct {
Protocol string // all protocols Protocol string // all protocols
QuoteDisable bool // telegram QuoteDisable bool // telegram
QuoteFormat string // telegram QuoteFormat string // telegram
QuoteLengthLimit int // telegram
RejoinDelay int // IRC RejoinDelay int // IRC
ReplaceMessages [][]string // all protocols ReplaceMessages [][]string // all protocols
ReplaceNicks [][]string // all protocols ReplaceNicks [][]string // all protocols
RemoteNickFormat string // all protocols RemoteNickFormat string // all protocols
RunCommands []string // IRC RunCommands []string // IRC
Server string // IRC,mattermost,XMPP,discord Server string // IRC,mattermost,XMPP,discord
SessionFile string // msteams,whatsapp
ShowJoinPart bool // all protocols ShowJoinPart bool // all protocols
ShowTopicChange bool // slack ShowTopicChange bool // slack
ShowUserTyping bool // slack ShowUserTyping bool // slack
@@ -129,13 +139,17 @@ type Protocol struct {
SkipTLSVerify bool // IRC, mattermost SkipTLSVerify bool // IRC, mattermost
SkipVersionCheck bool // mattermost SkipVersionCheck bool // mattermost
StripNick bool // all protocols StripNick bool // all protocols
StripMarkdown bool // irc
SyncTopic bool // slack SyncTopic bool // slack
TengoModifyMessage string // general TengoModifyMessage string // general
Team string // mattermost Team string // mattermost, keybase
TeamID string // msteams
TenantID string // msteams
Token string // gitter, slack, discord, api Token string // gitter, slack, discord, api
Topic string // zulip Topic string // zulip
URL string // mattermost, slack // DEPRECATED URL string // mattermost, slack // DEPRECATED
UseAPI bool // mattermost, slack UseAPI bool // mattermost, slack
UseLocalAvatar []string // discord
UseSASL bool // IRC UseSASL bool // IRC
UseTLS bool // IRC UseTLS bool // IRC
UseDiscriminator bool // discord UseDiscriminator bool // discord
@@ -198,6 +212,7 @@ type BridgeValues struct {
SSHChat map[string]Protocol SSHChat map[string]Protocol
WhatsApp map[string]Protocol // TODO is this struct used? Search for "SlackLegacy" for example didn't return any results WhatsApp map[string]Protocol // TODO is this struct used? Search for "SlackLegacy" for example didn't return any results
Zulip map[string]Protocol Zulip map[string]Protocol
Keybase map[string]Protocol
General Protocol General Protocol
Tengo Tengo Tengo Tengo
Gateway []Gateway Gateway []Gateway
@@ -205,7 +220,9 @@ type BridgeValues struct {
} }
type Config interface { type Config interface {
Viper() *viper.Viper
BridgeValues() *BridgeValues BridgeValues() *BridgeValues
IsKeySet(key string) bool
GetBool(key string) (bool, bool) GetBool(key string) (bool, bool)
GetInt(key string) (int, bool) GetInt(key string) (int, bool)
GetString(key string) (string, bool) GetString(key string) (string, bool)
@@ -231,7 +248,17 @@ func NewConfig(rootLogger *logrus.Logger, cfgfile string) Config {
logger.Fatalf("Failed to read configuration file: %#v", err) logger.Fatalf("Failed to read configuration file: %#v", err)
} }
mycfg := newConfigFromString(logger, input) cfgtype := detectConfigType(cfgfile)
mycfg := newConfigFromString(logger, input, cfgtype)
if mycfg.cv.General.LogFile != "" {
logfile, err := os.OpenFile(mycfg.cv.General.LogFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err == nil {
logger.Info("Opening log file ", mycfg.cv.General.LogFile)
rootLogger.Out = logfile
} else {
logger.Warn("Failed to open ", mycfg.cv.General.LogFile)
}
}
if mycfg.cv.General.MediaDownloadSize == 0 { if mycfg.cv.General.MediaDownloadSize == 0 {
mycfg.cv.General.MediaDownloadSize = 1000000 mycfg.cv.General.MediaDownloadSize = 1000000
} }
@@ -242,14 +269,26 @@ func NewConfig(rootLogger *logrus.Logger, cfgfile string) Config {
return mycfg return mycfg
} }
// detectConfigType detects JSON and YAML formats, defaults to TOML.
func detectConfigType(cfgfile string) string {
fileExt := filepath.Ext(cfgfile)
switch fileExt {
case ".json":
return "json"
case ".yaml", ".yml":
return "yaml"
}
return "toml"
}
// NewConfigFromString instantiates a new configuration based on the specified string. // NewConfigFromString instantiates a new configuration based on the specified string.
func NewConfigFromString(rootLogger *logrus.Logger, input []byte) Config { func NewConfigFromString(rootLogger *logrus.Logger, input []byte) Config {
logger := rootLogger.WithFields(logrus.Fields{"prefix": "config"}) logger := rootLogger.WithFields(logrus.Fields{"prefix": "config"})
return newConfigFromString(logger, input) return newConfigFromString(logger, input, "toml")
} }
func newConfigFromString(logger *logrus.Entry, input []byte) *config { func newConfigFromString(logger *logrus.Entry, input []byte, cfgtype string) *config {
viper.SetConfigType("toml") viper.SetConfigType(cfgtype)
viper.SetEnvPrefix("matterbridge") viper.SetEnvPrefix("matterbridge")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_")) viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
viper.AutomaticEnv() viper.AutomaticEnv()
@@ -273,6 +312,16 @@ func (c *config) BridgeValues() *BridgeValues {
return c.cv return c.cv
} }
func (c *config) Viper() *viper.Viper {
return c.v
}
func (c *config) IsKeySet(key string) bool {
c.RLock()
defer c.RUnlock()
return c.v.IsSet(key)
}
func (c *config) GetBool(key string) (bool, bool) { func (c *config) GetBool(key string) (bool, bool) {
c.RLock() c.RLock()
defer c.RUnlock() defer c.RUnlock()
@@ -332,6 +381,11 @@ type TestConfig struct {
Overrides map[string]interface{} Overrides map[string]interface{}
} }
func (c *TestConfig) IsKeySet(key string) bool {
_, ok := c.Overrides[key]
return ok || c.Config.IsKeySet(key)
}
func (c *TestConfig) GetBool(key string) (bool, bool) { func (c *TestConfig) GetBool(key string) (bool, bool) {
val, ok := c.Overrides[key] val, ok := c.Overrides[key]
if ok { if ok {

View File

@@ -10,7 +10,7 @@ import (
"github.com/42wim/matterbridge/bridge" "github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper" "github.com/42wim/matterbridge/bridge/helper"
"github.com/bwmarrin/discordgo" "github.com/matterbridge/discordgo"
) )
const MessageLength = 1950 const MessageLength = 1950
@@ -21,7 +21,7 @@ type Bdiscord struct {
c *discordgo.Session c *discordgo.Session
nick string nick string
useChannelID bool userID string
guildID string guildID string
webhookID string webhookID string
webhookToken string webhookToken string
@@ -34,6 +34,8 @@ type Bdiscord struct {
membersMutex sync.RWMutex membersMutex sync.RWMutex
userMemberMap map[string]*discordgo.Member userMemberMap map[string]*discordgo.Member
nickMemberMap map[string]*discordgo.Member nickMemberMap map[string]*discordgo.Member
webhookCache map[string]string
webhookMutex sync.RWMutex
} }
func New(cfg *bridge.Config) bridge.Bridger { func New(cfg *bridge.Config) bridge.Bridger {
@@ -41,6 +43,7 @@ func New(cfg *bridge.Config) bridge.Bridger {
b.userMemberMap = make(map[string]*discordgo.Member) b.userMemberMap = make(map[string]*discordgo.Member)
b.nickMemberMap = make(map[string]*discordgo.Member) b.nickMemberMap = make(map[string]*discordgo.Member)
b.channelInfoMap = make(map[string]*config.ChannelInfo) b.channelInfoMap = make(map[string]*config.ChannelInfo)
b.webhookCache = make(map[string]string)
if b.GetString("WebhookURL") != "" { if b.GetString("WebhookURL") != "" {
b.Log.Debug("Configuring Discord Incoming Webhook") b.Log.Debug("Configuring Discord Incoming Webhook")
b.webhookID, b.webhookToken = b.splitURL(b.GetString("WebhookURL")) b.webhookID, b.webhookToken = b.splitURL(b.GetString("WebhookURL"))
@@ -72,6 +75,7 @@ func (b *Bdiscord) Connect() error {
} }
b.Log.Info("Connection succeeded") b.Log.Info("Connection succeeded")
b.c.AddHandler(b.messageCreate) b.c.AddHandler(b.messageCreate)
b.c.AddHandler(b.messageTyping)
b.c.AddHandler(b.memberUpdate) b.c.AddHandler(b.memberUpdate)
b.c.AddHandler(b.messageUpdate) b.c.AddHandler(b.messageUpdate)
b.c.AddHandler(b.messageDelete) b.c.AddHandler(b.messageDelete)
@@ -92,6 +96,7 @@ func (b *Bdiscord) Connect() error {
} }
serverName := strings.Replace(b.GetString("Server"), "ID:", "", -1) serverName := strings.Replace(b.GetString("Server"), "ID:", "", -1)
b.nick = userinfo.Username b.nick = userinfo.Username
b.userID = userinfo.ID
b.channelsMutex.Lock() b.channelsMutex.Lock()
for _, guild := range guilds { for _, guild := range guilds {
if guild.Name == serverName || guild.ID == serverName { if guild.Name == serverName || guild.ID == serverName {
@@ -114,30 +119,37 @@ func (b *Bdiscord) Connect() error {
b.Log.Infof("Server=\"%s\" # Server ID", guild.ID) b.Log.Infof("Server=\"%s\" # Server ID", guild.ID)
} }
} }
if err != nil { if err != nil {
return err return err
} }
b.channelsMutex.RLock() b.channelsMutex.RLock()
if b.GetString("WebhookURL") == "" { if b.GetString("WebhookURL") == "" {
for _, channel := range b.channels { for _, channel := range b.channels {
b.Log.Debugf("found channel %#v", channel) b.Log.Debugf("found channel %#v", channel)
} }
} else { } else {
b.canEditWebhooks = true
for _, channel := range b.channels {
b.Log.Debugf("found channel %#v; verifying PermissionManageWebhooks", channel)
perms, permsErr := b.c.State.UserChannelPermissions(userinfo.ID, channel.ID)
manageWebhooks := discordgo.PermissionManageWebhooks manageWebhooks := discordgo.PermissionManageWebhooks
if permsErr != nil || perms&manageWebhooks != manageWebhooks { var channelsDenied []string
b.Log.Warnf("Can't manage webhooks in channel \"%s\"", channel.Name) for _, info := range b.Channels {
b.canEditWebhooks = false id := b.getChannelID(info.Name) // note(qaisjp): this readlocks channelsMutex
b.Log.Debugf("Verifying PermissionManageWebhooks for %s with ID %s", info.ID, id)
perms, permsErr := b.c.UserChannelPermissions(userinfo.ID, id)
if permsErr != nil {
b.Log.Warnf("Failed to check PermissionManageWebhooks in channel \"%s\": %s", info.Name, permsErr.Error())
} else if perms&manageWebhooks == manageWebhooks {
continue
} }
channelsDenied = append(channelsDenied, fmt.Sprintf("%#v", info.Name))
} }
b.canEditWebhooks = len(channelsDenied) == 0
if b.canEditWebhooks { if b.canEditWebhooks {
b.Log.Info("Can manage webhooks; will edit channel for global webhook on send") b.Log.Info("Can manage webhooks; will edit channel for global webhook on send")
} else { } else {
b.Log.Warn("Can't manage webhooks; won't edit channel for global webhook on send") b.Log.Warn("Can't manage webhooks; won't edit channel for global webhook on send")
b.Log.Warn("Can't manage webhooks in channels: ", strings.Join(channelsDenied, ", "))
} }
} }
b.channelsMutex.RUnlock() b.channelsMutex.RUnlock()
@@ -173,21 +185,27 @@ func (b *Bdiscord) JoinChannel(channel config.ChannelInfo) error {
defer b.channelsMutex.Unlock() defer b.channelsMutex.Unlock()
b.channelInfoMap[channel.ID] = &channel b.channelInfoMap[channel.ID] = &channel
idcheck := strings.Split(channel.Name, "ID:")
if len(idcheck) > 1 {
b.useChannelID = true
}
return nil return nil
} }
func (b *Bdiscord) Send(msg config.Message) (string, error) { func (b *Bdiscord) Send(msg config.Message) (string, error) {
b.Log.Debugf("=> Receiving %#v", msg) b.Log.Debugf("=> Receiving %#v", msg)
origMsgID := msg.ID
channelID := b.getChannelID(msg.Channel) channelID := b.getChannelID(msg.Channel)
if channelID == "" { if channelID == "" {
return "", fmt.Errorf("Could not find channelID for %v", msg.Channel) return "", fmt.Errorf("Could not find channelID for %v", msg.Channel)
} }
if msg.Event == config.EventUserTyping {
if b.GetBool("ShowUserTyping") {
err := b.c.ChannelTyping(channelID)
return "", err
}
return "", nil
}
// Make a action /me of the message // Make a action /me of the message
if msg.Event == config.EventUserAction { if msg.Event == config.EventUserAction {
msg.Text = "_" + msg.Text + "_" msg.Text = "_" + msg.Text + "_"
@@ -211,12 +229,13 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
// Use webhook to send the message // Use webhook to send the message
if wID != "" && msg.Event != config.EventMsgDelete { if wID != "" && msg.Event != config.EventMsgDelete {
// skip events // skip events
if msg.Event != "" && msg.Event != config.EventJoinLeave && msg.Event != config.EventTopicChange { if msg.Event != "" && msg.Event != config.EventUserAction && msg.Event != config.EventJoinLeave && msg.Event != config.EventTopicChange {
return "", nil return "", nil
} }
// If we are editing a message, delete the old message // If we are editing a message, delete the old message
if msg.ID != "" { if msg.ID != "" {
msg.ID = b.getCacheID(msg.ID)
b.Log.Debugf("Deleting edited webhook message") b.Log.Debugf("Deleting edited webhook message")
err := b.c.ChannelMessageDelete(channelID, msg.ID) err := b.c.ChannelMessageDelete(channelID, msg.ID)
if err != nil { if err != nil {
@@ -225,20 +244,10 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
} }
b.Log.Debugf("Broadcasting using Webhook") b.Log.Debugf("Broadcasting using Webhook")
for _, f := range msg.Extra["file"] {
fi := f.(config.FileInfo)
if fi.Comment != "" {
msg.Text += fi.Comment + ": "
}
if fi.URL != "" {
msg.Text = fi.URL
if fi.Comment != "" {
msg.Text = fi.Comment + ": " + fi.URL
}
}
}
// skip empty messages // skip empty messages
if msg.Text == "" { if msg.Text == "" && (msg.Extra == nil || len(msg.Extra["file"]) == 0) {
b.Log.Debugf("Skipping empty message %#v", msg)
return "", nil return "", nil
} }
@@ -261,16 +270,18 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
return "", err return "", err
} }
} }
msg, err := b.webhookExecute( b.Log.Debugf("Processing webhook sending for message %#v", msg)
wID, msg, err := b.webhookSend(&msg, wID, wToken)
wToken, if err != nil {
true, b.Log.Errorf("Could not broadcast via webook for message %#v: %s", msg, err)
&discordgo.WebhookParams{ return "", err
Content: msg.Text, }
Username: msg.Username, if msg == nil {
AvatarURL: msg.Avatar, return "", nil
}) }
return msg.ID, err
b.updateCacheID(origMsgID, msg.ID)
return msg.ID, nil
} }
b.Log.Debugf("Broadcasting using token (API)") b.Log.Debugf("Broadcasting using token (API)")
@@ -280,6 +291,7 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
if msg.ID == "" { if msg.ID == "" {
return "", nil return "", nil
} }
msg.ID = b.getCacheID(msg.ID)
err := b.c.ChannelMessageDelete(channelID, msg.ID) err := b.c.ChannelMessageDelete(channelID, msg.ID)
return "", err return "", err
} }
@@ -312,7 +324,7 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
return res.ID, err return res.ID, nil
} }
// useWebhook returns true if we have a webhook defined somewhere // useWebhook returns true if we have a webhook defined somewhere
@@ -376,3 +388,83 @@ func (b *Bdiscord) handleUploadFile(msg *config.Message, channelID string) (stri
} }
return "", nil return "", nil
} }
// webhookSend send one or more message via webhook, taking care of file
// uploads (from slack, telegram or mattermost).
// Returns messageID and error.
func (b *Bdiscord) webhookSend(msg *config.Message, webhookID, token string) (*discordgo.Message, error) {
var (
res *discordgo.Message
err error
)
// If avatar is unset, check if UseLocalAvatar contains the message's
// account or protocol, and if so, try to find a local avatar
if msg.Avatar == "" {
for _, val := range b.GetStringSlice("UseLocalAvatar") {
if msg.Protocol == val || msg.Account == val {
if avatar := b.findAvatar(msg); avatar != "" {
msg.Avatar = avatar
}
break
}
}
}
// WebhookParams can have either `Content` or `File`.
// We can't send empty messages.
if msg.Text != "" {
res, err = b.c.WebhookExecute(
webhookID,
token,
true,
&discordgo.WebhookParams{
Content: msg.Text,
Username: msg.Username,
AvatarURL: msg.Avatar,
},
)
if err != nil {
b.Log.Errorf("Could not send text (%s) for message %#v: %s", msg.Text, msg, err)
}
}
if msg.Extra != nil {
for _, f := range msg.Extra["file"] {
fi := f.(config.FileInfo)
file := discordgo.File{
Name: fi.Name,
ContentType: "",
Reader: bytes.NewReader(*fi.Data),
}
content := ""
if msg.Text == "" {
content = fi.Comment
}
_, e2 := b.c.WebhookExecute(
webhookID,
token,
false,
&discordgo.WebhookParams{
Username: msg.Username,
AvatarURL: msg.Avatar,
File: &file,
Content: content,
},
)
if e2 != nil {
b.Log.Errorf("Could not send file %#v for message %#v: %s", file, msg, e2)
}
}
}
return res, err
}
func (b *Bdiscord) findAvatar(m *config.Message) string {
member, err := b.getGuildMemberByNick(m.Username)
if err != nil {
return ""
}
return member.User.AvatarURL("")
}

View File

@@ -2,15 +2,13 @@ package bdiscord
import ( import (
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/bwmarrin/discordgo" "github.com/matterbridge/discordgo"
) )
func (b *Bdiscord) messageDelete(s *discordgo.Session, m *discordgo.MessageDelete) { //nolint:unparam func (b *Bdiscord) messageDelete(s *discordgo.Session, m *discordgo.MessageDelete) { //nolint:unparam
rmsg := config.Message{Account: b.Account, ID: m.ID, Event: config.EventMsgDelete, Text: config.EventMsgDelete} rmsg := config.Message{Account: b.Account, ID: m.ID, Event: config.EventMsgDelete, Text: config.EventMsgDelete}
rmsg.Channel = b.getChannelName(m.ChannelID) rmsg.Channel = b.getChannelName(m.ChannelID)
if b.useChannelID {
rmsg.Channel = "ID:" + m.ChannelID
}
b.Log.Debugf("<= Sending message from %s to gateway", b.Account) b.Log.Debugf("<= Sending message from %s to gateway", b.Account)
b.Log.Debugf("<= Message is %#v", rmsg) b.Log.Debugf("<= Message is %#v", rmsg)
b.Remote <- rmsg b.Remote <- rmsg
@@ -24,11 +22,7 @@ func (b *Bdiscord) messageDeleteBulk(s *discordgo.Session, m *discordgo.MessageD
ID: msgID, ID: msgID,
Event: config.EventMsgDelete, Event: config.EventMsgDelete,
Text: config.EventMsgDelete, Text: config.EventMsgDelete,
Channel: "ID:" + m.ChannelID, Channel: b.getChannelName(m.ChannelID),
}
if !b.useChannelID {
rmsg.Channel = b.getChannelName(m.ChannelID)
} }
b.Log.Debugf("<= Sending message from %s to gateway", b.Account) b.Log.Debugf("<= Sending message from %s to gateway", b.Account)
@@ -37,6 +31,21 @@ func (b *Bdiscord) messageDeleteBulk(s *discordgo.Session, m *discordgo.MessageD
} }
} }
func (b *Bdiscord) messageTyping(s *discordgo.Session, m *discordgo.TypingStart) {
if !b.GetBool("ShowUserTyping") {
return
}
// Ignore our own typing messages
if m.UserID == b.userID {
return
}
rmsg := config.Message{Account: b.Account, Event: config.EventUserTyping}
rmsg.Channel = b.getChannelName(m.ChannelID)
b.Remote <- rmsg
}
func (b *Bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) { //nolint:unparam func (b *Bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) { //nolint:unparam
if b.GetBool("EditDisable") { if b.GetBool("EditDisable") {
return return
@@ -45,7 +54,10 @@ func (b *Bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdat
if m.Message.EditedTimestamp != "" { if m.Message.EditedTimestamp != "" {
b.Log.Debugf("Sending edit message") b.Log.Debugf("Sending edit message")
m.Content += b.GetString("EditSuffix") m.Content += b.GetString("EditSuffix")
b.messageCreate(s, (*discordgo.MessageCreate)(m)) msg := &discordgo.MessageCreate{
Message: m.Message,
}
b.messageCreate(s, msg)
} }
} }
@@ -72,7 +84,6 @@ func (b *Bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
if m.Content != "" { if m.Content != "" {
b.Log.Debugf("== Receiving event %#v", m.Message) b.Log.Debugf("== Receiving event %#v", m.Message)
m.Message.Content = b.stripCustomoji(m.Message.Content)
m.Message.Content = b.replaceChannelMentions(m.Message.Content) m.Message.Content = b.replaceChannelMentions(m.Message.Content)
rmsg.Text, err = m.ContentWithMoreMentionsReplaced(b.c) rmsg.Text, err = m.ContentWithMoreMentionsReplaced(b.c)
if err != nil { if err != nil {
@@ -83,16 +94,13 @@ func (b *Bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
// set channel name // set channel name
rmsg.Channel = b.getChannelName(m.ChannelID) rmsg.Channel = b.getChannelName(m.ChannelID)
if b.useChannelID {
rmsg.Channel = "ID:" + m.ChannelID
}
// set username fromWebhook := m.WebhookID != ""
if !b.GetBool("UseUserName") { if !fromWebhook && !b.GetBool("UseUserName") {
rmsg.Username = b.getNick(m.Author) rmsg.Username = b.getNick(m.Author, m.GuildID)
} else { } else {
rmsg.Username = m.Author.Username rmsg.Username = m.Author.Username
if b.GetBool("UseDiscriminator") { if !fromWebhook && b.GetBool("UseDiscriminator") {
rmsg.Username += "#" + m.Author.Discriminator rmsg.Username += "#" + m.Author.Discriminator
} }
} }
@@ -100,7 +108,7 @@ func (b *Bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
// if we have embedded content add it to text // if we have embedded content add it to text
if b.GetBool("ShowEmbeds") && m.Message.Embeds != nil { if b.GetBool("ShowEmbeds") && m.Message.Embeds != nil {
for _, embed := range m.Message.Embeds { for _, embed := range m.Message.Embeds {
rmsg.Text = rmsg.Text + "embed: " + embed.Title + " - " + embed.Description + " - " + embed.URL + "\n" rmsg.Text += handleEmbed(embed)
} }
} }
@@ -116,6 +124,9 @@ func (b *Bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
rmsg.Event = config.EventUserAction rmsg.Event = config.EventUserAction
} }
// Replace emotes
rmsg.Text = replaceEmotes(rmsg.Text)
b.Log.Debugf("<= Sending message from %s on %s to gateway", m.Author.Username, b.Account) b.Log.Debugf("<= Sending message from %s on %s to gateway", m.Author.Username, b.Account)
b.Log.Debugf("<= Message is %#v", rmsg) b.Log.Debugf("<= Message is %#v", rmsg)
b.Remote <- rmsg b.Remote <- rmsg
@@ -189,3 +200,33 @@ func (b *Bdiscord) memberRemove(s *discordgo.Session, m *discordgo.GuildMemberRe
b.Log.Debugf("<= Message is %#v", rmsg) b.Log.Debugf("<= Message is %#v", rmsg)
b.Remote <- rmsg b.Remote <- rmsg
} }
func handleEmbed(embed *discordgo.MessageEmbed) string {
var t []string
var result string
t = append(t, embed.Title)
t = append(t, embed.Description)
t = append(t, embed.URL)
i := 0
for _, e := range t {
if e == "" {
continue
}
i++
if i == 1 {
result += " embed: " + e
continue
}
result += " - " + e
}
if result != "" {
result += "\n"
}
return result
}

View File

@@ -0,0 +1,58 @@
package bdiscord
import (
"testing"
"github.com/matterbridge/discordgo"
"github.com/stretchr/testify/assert"
)
func TestHandleEmbed(t *testing.T) {
testcases := map[string]struct {
embed *discordgo.MessageEmbed
result string
}{
"allempty": {
embed: &discordgo.MessageEmbed{},
result: "",
},
"one": {
embed: &discordgo.MessageEmbed{
Title: "blah",
},
result: " embed: blah\n",
},
"two": {
embed: &discordgo.MessageEmbed{
Title: "blah",
Description: "blah2",
},
result: " embed: blah - blah2\n",
},
"three": {
embed: &discordgo.MessageEmbed{
Title: "blah",
Description: "blah2",
URL: "blah3",
},
result: " embed: blah - blah2 - blah3\n",
},
"twob": {
embed: &discordgo.MessageEmbed{
Description: "blah2",
URL: "blah3",
},
result: " embed: blah2 - blah3\n",
},
"oneb": {
embed: &discordgo.MessageEmbed{
URL: "blah3",
},
result: " embed: blah3\n",
},
}
for name, tc := range testcases {
assert.Equalf(t, tc.result, handleEmbed(tc.embed), "Testcases %s", name)
}
}

View File

@@ -1,16 +1,15 @@
package bdiscord package bdiscord
import ( import (
"encoding/json"
"errors" "errors"
"regexp" "regexp"
"strings" "strings"
"unicode" "unicode"
"github.com/bwmarrin/discordgo" "github.com/matterbridge/discordgo"
) )
func (b *Bdiscord) getNick(user *discordgo.User) string { func (b *Bdiscord) getNick(user *discordgo.User, guildID string) string {
b.membersMutex.RLock() b.membersMutex.RLock()
defer b.membersMutex.RUnlock() defer b.membersMutex.RUnlock()
@@ -24,9 +23,9 @@ func (b *Bdiscord) getNick(user *discordgo.User) string {
} }
// If we didn't find nick, search for it. // If we didn't find nick, search for it.
member, err := b.c.GuildMember(b.guildID, user.ID) member, err := b.c.GuildMember(guildID, user.ID)
if err != nil { if err != nil {
b.Log.Warnf("Failed to fetch information for member %#v: %s", user, err) b.Log.Warnf("Failed to fetch information for member %#v on guild %#v: %s", user, guildID, err)
return user.Username return user.Username
} else if member == nil { } else if member == nil {
b.Log.Warnf("Got no information for member %#v", user) b.Log.Warnf("Got no information for member %#v", user)
@@ -97,6 +96,13 @@ func (b *Bdiscord) getChannelName(id string) string {
b.channelsMutex.RLock() b.channelsMutex.RLock()
defer b.channelsMutex.RUnlock() defer b.channelsMutex.RUnlock()
for _, c := range b.channelInfoMap {
if c.Name == "ID:"+id {
// if we have ID: specified in our gateway configuration return this
return c.Name
}
}
for _, channel := range b.channels { for _, channel := range b.channels {
if channel.ID == id { if channel.ID == id {
return b.getCategoryChannelName(channel.Name, channel.ParentID) return b.getCategoryChannelName(channel.Name, channel.ParentID)
@@ -130,8 +136,8 @@ func (b *Bdiscord) getCategoryChannelName(name, parentID string) string {
var ( var (
// See https://discordapp.com/developers/docs/reference#message-formatting. // See https://discordapp.com/developers/docs/reference#message-formatting.
channelMentionRE = regexp.MustCompile("<#[0-9]+>") channelMentionRE = regexp.MustCompile("<#[0-9]+>")
emojiRE = regexp.MustCompile("<(:.*?:)[0-9]+>")
userMentionRE = regexp.MustCompile("@[^@\n]{1,32}") userMentionRE = regexp.MustCompile("@[^@\n]{1,32}")
emoteRE = regexp.MustCompile(`<a?(:\w+:)\d+>`)
) )
func (b *Bdiscord) replaceChannelMentions(text string) string { func (b *Bdiscord) replaceChannelMentions(text string) string {
@@ -177,13 +183,14 @@ func (b *Bdiscord) replaceUserMentions(text string) string {
return userMentionRE.ReplaceAllStringFunc(text, replaceUserMentionFunc) return userMentionRE.ReplaceAllStringFunc(text, replaceUserMentionFunc)
} }
func (b *Bdiscord) stripCustomoji(text string) string { func replaceEmotes(text string) string {
return emojiRE.ReplaceAllString(text, `$1`) return emoteRE.ReplaceAllString(text, "$1")
} }
func (b *Bdiscord) replaceAction(text string) (string, bool) { func (b *Bdiscord) replaceAction(text string) (string, bool) {
if strings.HasPrefix(text, "_") && strings.HasSuffix(text, "_") { length := len(text)
return text[1:], true if length > 1 && text[0] == '_' && text[length-1] == '_' {
return text[1 : length-1], true
} }
return text, false return text, false
} }
@@ -202,6 +209,40 @@ func (b *Bdiscord) splitURL(url string) (string, string) {
return webhookURLSplit[webhookIdxID], webhookURLSplit[webhookIdxToken] return webhookURLSplit[webhookIdxID], webhookURLSplit[webhookIdxToken]
} }
// getcacheID tries to find a corresponding msgID in the webhook cache.
// if not found returns the original request.
func (b *Bdiscord) getCacheID(msgID string) string {
b.webhookMutex.RLock()
defer b.webhookMutex.RUnlock()
for k, v := range b.webhookCache {
if msgID == k {
return v
}
}
return msgID
}
// updateCacheID updates the cache so that the newID takes the place of
// the original ID. This is used for edit/deletes in combination with webhooks
// as editing a message via webhook means deleting the message and creating a
// new message (with a new ID). This ID needs to be set instead of the original ID
func (b *Bdiscord) updateCacheID(origID, newID string) {
b.webhookMutex.Lock()
match := false
for k, v := range b.webhookCache {
if v == origID {
delete(b.webhookCache, k)
b.webhookCache[origID] = newID
match = true
continue
}
}
if !match && origID != "" {
b.webhookCache[origID] = newID
}
b.webhookMutex.Unlock()
}
func enumerateUsernames(s string) []string { func enumerateUsernames(s string) []string {
onlySpace := true onlySpace := true
for _, r := range s { for _, r := range s {
@@ -236,26 +277,3 @@ func enumerateUsernames(s string) []string {
} }
return usernames return usernames
} }
// webhookExecute executes a webhook.
// webhookID: The ID of a webhook.
// token : The auth token for the webhook
// wait : Waits for server confirmation of message send and ensures that the return struct is populated (it is nil otherwise)
func (b *Bdiscord) webhookExecute(webhookID, token string, wait bool, data *discordgo.WebhookParams) (st *discordgo.Message, err error) {
uri := discordgo.EndpointWebhookToken(webhookID, token)
if wait {
uri += "?wait=true"
}
response, err := b.c.RequestWithBucketID("POST", uri, data, discordgo.EndpointWebhookToken("", ""))
if !wait || err != nil {
return nil, err
}
err = json.Unmarshal(response, &st)
if err != nil {
return nil, discordgo.ErrJSONUnmarshal
}
return st, nil
}

View File

@@ -5,7 +5,10 @@ import (
"fmt" "fmt"
"image/png" "image/png"
"io" "io"
"io/ioutil"
"net/http" "net/http"
"os"
"os/exec"
"regexp" "regexp"
"strings" "strings"
"time" "time"
@@ -14,8 +17,10 @@ import (
"golang.org/x/image/webp" "golang.org/x/image/webp"
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/html"
"github.com/gomarkdown/markdown/parser"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"gitlab.com/golang-commonmark/markdown"
) )
// DownloadFile downloads the given non-authenticated URL. // DownloadFile downloads the given non-authenticated URL.
@@ -176,15 +181,21 @@ func ClipMessage(text string, length int) string {
return text return text
} }
// ParseMarkdown takes in an input string as markdown and parses it to html
func ParseMarkdown(input string) string { func ParseMarkdown(input string) string {
md := markdown.New(markdown.XHTMLOutput(true), markdown.Breaks(true)) extensions := parser.HardLineBreak | parser.NoIntraEmphasis
res := md.RenderToString([]byte(input)) markdownParser := parser.NewWithExtensions(extensions)
renderer := html.NewRenderer(html.RendererOptions{
Flags: 0,
})
parsedMarkdown := markdown.ToHTML([]byte(input), markdownParser, renderer)
res := string(parsedMarkdown)
res = strings.TrimPrefix(res, "<p>") res = strings.TrimPrefix(res, "<p>")
res = strings.TrimSuffix(res, "</p>\n") res = strings.TrimSuffix(res, "</p>\n")
return res return res
} }
// ConvertWebPToPNG convert input data (which should be WebP format to PNG format) // ConvertWebPToPNG converts input data (which should be WebP format) to PNG format
func ConvertWebPToPNG(data *[]byte) error { func ConvertWebPToPNG(data *[]byte) error {
r := bytes.NewReader(*data) r := bytes.NewReader(*data)
m, err := webp.Decode(r) m, err := webp.Decode(r)
@@ -199,3 +210,49 @@ func ConvertWebPToPNG(data *[]byte) error {
*data = w.Bytes() *data = w.Bytes()
return nil return nil
} }
// CanConvertTgsToX Checks whether the external command necessary for ConvertTgsToX works.
func CanConvertTgsToX() error {
// We depend on the fact that `lottie_convert.py --help` has exit status 0.
// Hyrum's Law predicted this, and Murphy's Law predicts that this will break eventually.
// However, there is no alternative like `lottie_convert.py --is-properly-installed`
cmd := exec.Command("lottie_convert.py", "--help")
return cmd.Run()
}
// ConvertTgsToWebP convert input data (which should be tgs format) to WebP format
// This relies on an external command, which is ugly, but works.
func ConvertTgsToX(data *[]byte, outputFormat string, logger *logrus.Entry) error {
// lottie can't handle input from a pipe, so write to a temporary file:
tmpFile, err := ioutil.TempFile(os.TempDir(), "matterbridge-lottie-*.tgs")
if err != nil {
return err
}
tmpFileName := tmpFile.Name()
defer func() {
if removeErr := os.Remove(tmpFileName); removeErr != nil {
logger.Errorf("Could not delete temporary file %s: %v", tmpFileName, removeErr)
}
}()
if _, writeErr := tmpFile.Write(*data); writeErr != nil {
return writeErr
}
// Must close before calling lottie to avoid data races:
if closeErr := tmpFile.Close(); closeErr != nil {
return closeErr
}
// Call lottie to transform:
cmd := exec.Command("lottie_convert.py", "--input-format", "lottie", "--output-format", outputFormat, tmpFileName, "/dev/stdout")
cmd.Stderr = nil
// NB: lottie writes progress into to stderr in all cases.
stdout, stderr := cmd.Output()
if stderr != nil {
// 'stderr' already contains some parts of Stderr, because it was set to 'nil'.
return stderr
}
*data = stdout
return nil
}

View File

@@ -10,8 +10,8 @@ import (
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper" "github.com/42wim/matterbridge/bridge/helper"
"github.com/dfordsoft/golib/ic"
"github.com/lrstanley/girc" "github.com/lrstanley/girc"
"github.com/missdeer/golib/ic"
"github.com/paulrosania/go-charset/charset" "github.com/paulrosania/go-charset/charset"
"github.com/saintfish/chardet" "github.com/saintfish/chardet"
@@ -54,12 +54,12 @@ func (b *Birc) handleFiles(msg *config.Message) bool {
for _, f := range msg.Extra["file"] { for _, f := range msg.Extra["file"] {
fi := f.(config.FileInfo) fi := f.(config.FileInfo)
if fi.Comment != "" { if fi.Comment != "" {
msg.Text += fi.Comment + ": " msg.Text += fi.Comment + " : "
} }
if fi.URL != "" { if fi.URL != "" {
msg.Text = fi.URL msg.Text = fi.URL
if fi.Comment != "" { if fi.Comment != "" {
msg.Text = fi.Comment + ": " + fi.URL msg.Text = fi.Comment + " : " + fi.URL
} }
} }
b.Local <- config.Message{Text: msg.Text, Username: msg.Username, Channel: msg.Channel, Event: msg.Event} b.Local <- config.Message{Text: msg.Text, Username: msg.Username, Channel: msg.Channel, Event: msg.Event}

View File

@@ -14,6 +14,7 @@ import (
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper" "github.com/42wim/matterbridge/bridge/helper"
"github.com/lrstanley/girc" "github.com/lrstanley/girc"
stripmd "github.com/writeas/go-strip-markdown"
// We need to import the 'data' package as an implicit dependency. // We need to import the 'data' package as an implicit dependency.
// See: https://godoc.org/github.com/paulrosania/go-charset/charset // See: https://godoc.org/github.com/paulrosania/go-charset/charset
@@ -156,6 +157,10 @@ func (b *Birc) Send(msg config.Message) (string, error) {
} }
var msgLines []string var msgLines []string
if b.GetBool("StripMarkdown") {
msg.Text = stripmd.Strip(msg.Text)
}
if b.GetBool("MessageSplit") { if b.GetBool("MessageSplit") {
msgLines = helper.GetSubLines(msg.Text, b.MessageLength) msgLines = helper.GetSubLines(msg.Text, b.MessageLength)
} else { } else {
@@ -167,12 +172,8 @@ func (b *Birc) Send(msg config.Message) (string, error) {
return "", nil return "", nil
} }
b.Local <- config.Message{ msg.Text = msgLines[i]
Text: msgLines[i], b.Local <- msg
Username: msg.Username,
Channel: msg.Channel,
Event: msg.Event,
}
} }
return "", nil return "", nil
} }
@@ -205,7 +206,7 @@ func (b *Birc) doSend() {
for msg := range b.Local { for msg := range b.Local {
<-throttle.C <-throttle.C
username := msg.Username username := msg.Username
if b.GetBool("Colornicks") { if b.GetBool("Colornicks") && len(username) > 1 {
checksum := crc32.ChecksumIEEE([]byte(msg.Username)) checksum := crc32.ChecksumIEEE([]byte(msg.Username))
colorCode := checksum%14 + 2 // quick fix - prevent white or black color codes colorCode := checksum%14 + 2 // quick fix - prevent white or black color codes
username = fmt.Sprintf("\x03%02d%s\x0F", colorCode, msg.Username) username = fmt.Sprintf("\x03%02d%s\x0F", colorCode, msg.Username)
@@ -249,6 +250,8 @@ func (b *Birc) getClient() (*girc.Client, error) {
SSL: b.GetBool("UseTLS"), SSL: b.GetBool("UseTLS"),
TLSConfig: &tls.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), ServerName: server}, //nolint:gosec TLSConfig: &tls.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), ServerName: server}, //nolint:gosec
PingDelay: time.Minute, PingDelay: time.Minute,
// skip gIRC internal rate limiting, since we have our own throttling
AllowFlood: true,
}) })
return i, nil return i, nil
} }

View File

@@ -0,0 +1,59 @@
package bkeybase
import (
"strconv"
"github.com/42wim/matterbridge/bridge/config"
"github.com/keybase/go-keybase-chat-bot/kbchat/types/chat1"
)
func (b *Bkeybase) handleKeybase() {
sub, err := b.kbc.ListenForNewTextMessages()
if err != nil {
b.Log.Errorf("Error listening: %s", err.Error())
}
go func() {
for {
msg, err := sub.Read()
if err != nil {
b.Log.Errorf("failed to read message: %s", err.Error())
}
if msg.Message.Content.TypeName != "text" {
continue
}
if msg.Message.Sender.Username == b.kbc.GetUsername() {
continue
}
b.handleMessage(msg.Message)
}
}()
}
func (b *Bkeybase) handleMessage(msg chat1.MsgSummary) {
b.Log.Debugf("== Receiving event: %#v", msg)
if msg.Channel.TopicName != b.channel || msg.Channel.Name != b.team {
return
}
if msg.Sender.Username != b.kbc.GetUsername() {
// TODO download avatar
// Create our message
rmsg := config.Message{Username: msg.Sender.Username, Text: msg.Content.Text.Body, UserID: string(msg.Sender.Uid), Channel: msg.Channel.TopicName, ID: strconv.Itoa(int(msg.Id)), Account: b.Account}
// Text must be a string
if msg.Content.TypeName != "text" {
b.Log.Errorf("message is not text")
return
}
b.Log.Debugf("<= Sending message from %s on %s to gateway", msg.Sender.Username, msg.Channel.Name)
b.Remote <- rmsg
}
}

106
bridge/keybase/keybase.go Normal file
View File

@@ -0,0 +1,106 @@
package bkeybase
import (
"io/ioutil"
"os"
"path/filepath"
"strconv"
"github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config"
"github.com/keybase/go-keybase-chat-bot/kbchat"
)
// Bkeybase bridge structure
type Bkeybase struct {
kbc *kbchat.API
user string
channel string
team string
*bridge.Config
}
// New initializes Bkeybase object and sets team
func New(cfg *bridge.Config) bridge.Bridger {
b := &Bkeybase{Config: cfg}
b.team = b.Config.GetString("Team")
return b
}
// Connect starts keybase API and listener loop
func (b *Bkeybase) Connect() error {
var err error
b.Log.Infof("Connecting %s", b.GetString("Team"))
// use default keybase location (`keybase`)
b.kbc, err = kbchat.Start(kbchat.RunOptions{})
if err != nil {
return err
}
b.user = b.kbc.GetUsername()
b.Log.Info("Connection succeeded")
go b.handleKeybase()
return nil
}
// Disconnect doesn't do anything for now
func (b *Bkeybase) Disconnect() error {
return nil
}
// JoinChannel sets channel name in struct
func (b *Bkeybase) JoinChannel(channel config.ChannelInfo) error {
if _, err := b.kbc.JoinChannel(b.team, channel.Name); err != nil {
return err
}
b.channel = channel.Name
return nil
}
// Send receives bridge messages and sends them to Keybase chat room
func (b *Bkeybase) Send(msg config.Message) (string, error) {
b.Log.Debugf("=> Receiving %#v", msg)
// Handle /me events
if msg.Event == config.EventUserAction {
msg.Text = "_" + msg.Text + "_"
}
// Delete message if we have an ID
// Delete message not supported by keybase go library yet
// Edit message if we have an ID
// kbchat lib does not support message editing yet
if len(msg.Extra["file"]) > 0 {
// Upload a file
dir, err := ioutil.TempDir("", "matterbridge")
if err != nil {
return "", err
}
defer os.RemoveAll(dir)
for _, f := range msg.Extra["file"] {
fname := f.(config.FileInfo).Name
fdata := *f.(config.FileInfo).Data
fcaption := f.(config.FileInfo).Comment
fpath := filepath.Join(dir, fname)
if err = ioutil.WriteFile(fpath, fdata, 0600); err != nil {
return "", err
}
_, _ = b.kbc.SendAttachmentByTeam(b.team, &b.channel, fpath, fcaption)
}
return "", nil
}
// Send regular message
text := msg.Username + msg.Text
resp, err := b.kbc.SendMessageByTeamName(b.team, &b.channel, text)
if err != nil {
return "", err
}
return strconv.Itoa(int(*resp.Result.MessageID)), err
}

View File

@@ -2,12 +2,14 @@ package bmatrix
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"html" "html"
"mime" "mime"
"regexp" "regexp"
"strings" "strings"
"sync" "sync"
"time"
"github.com/42wim/matterbridge/bridge" "github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
@@ -21,12 +23,20 @@ type Bmatrix struct {
RoomMap map[string]string RoomMap map[string]string
sync.RWMutex sync.RWMutex
htmlTag *regexp.Regexp htmlTag *regexp.Regexp
htmlReplacementTag *regexp.Regexp
*bridge.Config *bridge.Config
} }
type httpError struct {
Errcode string `json:"errcode"`
Err string `json:"error"`
RetryAfterMs int `json:"retry_after_ms"`
}
func New(cfg *bridge.Config) bridge.Bridger { func New(cfg *bridge.Config) bridge.Bridger {
b := &Bmatrix{Config: cfg} b := &Bmatrix{Config: cfg}
b.htmlTag = regexp.MustCompile("</.*?>") b.htmlTag = regexp.MustCompile("</.*?>")
b.htmlReplacementTag = regexp.MustCompile("<[^>]*>")
b.RoomMap = make(map[string]string) b.RoomMap = make(map[string]string)
return b return b
} }
@@ -58,14 +68,25 @@ func (b *Bmatrix) Disconnect() error {
} }
func (b *Bmatrix) JoinChannel(channel config.ChannelInfo) error { func (b *Bmatrix) JoinChannel(channel config.ChannelInfo) error {
retry:
resp, err := b.mc.JoinRoom(channel.Name, "", nil) resp, err := b.mc.JoinRoom(channel.Name, "", nil)
if err != nil { if err != nil {
httpErr := handleError(err)
if httpErr.Errcode == "M_LIMIT_EXCEEDED" {
b.Log.Infof("getting ratelimited by matrix, sleeping approx %d seconds before joining %s", httpErr.RetryAfterMs/1000, channel.Name)
time.Sleep((time.Duration(httpErr.RetryAfterMs) * time.Millisecond))
goto retry
}
return err return err
} }
b.Lock() b.Lock()
b.RoomMap[resp.RoomID] = channel.Name b.RoomMap[resp.RoomID] = channel.Name
b.Unlock() b.Unlock()
return err
return nil
} }
func (b *Bmatrix) Send(msg config.Message) (string, error) { func (b *Bmatrix) Send(msg config.Message) (string, error) {
@@ -124,13 +145,28 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) {
return resp.EventID, err return resp.EventID, err
} }
username := html.EscapeString(msg.Username) if b.GetBool("HTMLDisable") {
resp, err := b.mc.SendText(channel, msg.Username+msg.Text)
if err != nil {
return "", err
}
return resp.EventID, err
}
var username string
var plainUsername string
// check if we have a </tag>. if we have, we don't escape HTML. #696 // check if we have a </tag>. if we have, we don't escape HTML. #696
if b.htmlTag.MatchString(msg.Username) { if b.htmlTag.MatchString(msg.Username) {
username = msg.Username username = msg.Username
// remove the HTML formatting for beautiful push messages #1188
plainUsername = b.htmlReplacementTag.ReplaceAllString(msg.Username, "")
} else {
username = html.EscapeString(msg.Username)
plainUsername = msg.Username
} }
// Post normal message with HTML support (eg riot.im) // Post normal message with HTML support (eg riot.im)
resp, err := b.mc.SendHTML(channel, msg.Username+msg.Text, username+helper.ParseMarkdown(msg.Text)) resp, err := b.mc.SendHTML(channel, plainUsername+msg.Text, username+helper.ParseMarkdown(msg.Text))
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -172,10 +208,15 @@ func (b *Bmatrix) handleEvent(ev *matrix.Event) {
return return
} }
// TODO download avatar
// Create our message // Create our message
rmsg := config.Message{Username: ev.Sender[1:], Channel: channel, Account: b.Account, UserID: ev.Sender, ID: ev.ID} rmsg := config.Message{
Username: ev.Sender[1:],
Channel: channel,
Account: b.Account,
UserID: ev.Sender,
ID: ev.ID,
Avatar: b.getAvatarURL(ev.Sender),
}
// Text must be a string // Text must be a string
if rmsg.Text, ok = ev.Content["body"].(string); !ok { if rmsg.Text, ok = ev.Content["body"].(string); !ok {
@@ -291,7 +332,8 @@ func (b *Bmatrix) handleUploadFile(msg *config.Message, channel string, fi *conf
content := bytes.NewReader(*fi.Data) content := bytes.NewReader(*fi.Data)
sp := strings.Split(fi.Name, ".") sp := strings.Split(fi.Name, ".")
mtype := mime.TypeByExtension("." + sp[len(sp)-1]) mtype := mime.TypeByExtension("." + sp[len(sp)-1])
if !strings.Contains(mtype, "image") && !strings.Contains(mtype, "video") { if !(strings.Contains(mtype, "image") || strings.Contains(mtype, "video") ||
strings.Contains(mtype, "application") || strings.Contains(mtype, "audio")) {
return return
} }
if fi.Comment != "" { if fi.Comment != "" {
@@ -326,6 +368,18 @@ func (b *Bmatrix) handleUploadFile(msg *config.Message, channel string, fi *conf
if err != nil { if err != nil {
b.Log.Errorf("sendImage failed: %#v", err) b.Log.Errorf("sendImage failed: %#v", err)
} }
case strings.Contains(mtype, "application"):
b.Log.Debugf("sendFile %s", res.ContentURI)
_, err = b.mc.SendFile(channel, fi.Name, res.ContentURI, mtype, uint(len(*fi.Data)))
if err != nil {
b.Log.Errorf("sendFile failed: %#v", err)
}
case strings.Contains(mtype, "audio"):
b.Log.Debugf("sendAudio %s", res.ContentURI)
_, err = b.mc.SendAudio(channel, fi.Name, res.ContentURI, mtype, uint(len(*fi.Data)))
if err != nil {
b.Log.Errorf("sendAudio failed: %#v", err)
}
} }
b.Log.Debugf("result: %#v", res) b.Log.Debugf("result: %#v", res)
} }
@@ -345,3 +399,36 @@ func (b *Bmatrix) containsAttachment(content map[string]interface{}) bool {
} }
return true return true
} }
// getAvatarURL returns the avatar URL of the specified sender
func (b *Bmatrix) getAvatarURL(sender string) string {
mxcURL, err := b.mc.GetSenderAvatarURL(sender)
if err != nil {
b.Log.Errorf("getAvatarURL failed: %s", err)
return ""
}
url := strings.ReplaceAll(mxcURL, "mxc://", b.GetString("Server")+"/_matrix/media/r0/thumbnail/")
if url != "" {
url += "?width=37&height=37&method=crop"
}
return url
}
func handleError(err error) *httpError {
mErr, ok := err.(matrix.HTTPError)
if !ok {
return &httpError{
Err: "not a HTTPError",
}
}
var httpErr httpError
if err := json.Unmarshal(mErr.Contents, &httpErr); err != nil {
return &httpError{
Err: "unmarshal failed",
}
}
return &httpErr
}

View File

@@ -4,7 +4,7 @@ import (
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper" "github.com/42wim/matterbridge/bridge/helper"
"github.com/42wim/matterbridge/matterclient" "github.com/42wim/matterbridge/matterclient"
"github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/v5/model"
) )
// handleDownloadAvatar downloads the avatar of userid from channel // handleDownloadAvatar downloads the avatar of userid from channel
@@ -66,6 +66,10 @@ func (b *Bmattermost) handleMatter() {
} else { } else {
b.Log.Debugf("Choosing login/password based receiving") b.Log.Debugf("Choosing login/password based receiving")
} }
// if for some reason we only want to sent stuff to mattermost but not receive, return
if b.GetString("WebhookBindAddress") == "" && b.GetString("WebhookURL") != "" && b.GetString("Token") == "" && b.GetString("Login") == "" {
b.Log.Debugf("No WebhookBindAddress specified, only WebhookURL. You will not receive messages from mattermost, only sending is possible.")
}
go b.handleMatterClient(messages) go b.handleMatterClient(messages)
} }
var ok bool var ok bool

View File

@@ -7,7 +7,7 @@ import (
"github.com/42wim/matterbridge/bridge/helper" "github.com/42wim/matterbridge/bridge/helper"
"github.com/42wim/matterbridge/matterclient" "github.com/42wim/matterbridge/matterclient"
"github.com/42wim/matterbridge/matterhook" "github.com/42wim/matterbridge/matterhook"
"github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/v5/model"
) )
func (b *Bmattermost) doConnectWebhookBind() error { func (b *Bmattermost) doConnectWebhookBind() error {

101
bridge/msteams/handler.go Normal file
View File

@@ -0,0 +1,101 @@
package bmsteams
import (
"encoding/json"
"fmt"
"io/ioutil"
"strings"
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper"
msgraph "github.com/yaegashi/msgraph.go/beta"
)
func (b *Bmsteams) findFile(weburl string) (string, error) {
itemRB, err := b.gc.GetDriveItemByURL(b.ctx, weburl)
if err != nil {
return "", err
}
itemRB.Workbook().Worksheets()
b.gc.Workbooks()
item, err := itemRB.Request().Get(b.ctx)
if err != nil {
return "", err
}
if url, ok := item.GetAdditionalData("@microsoft.graph.downloadUrl"); ok {
return url.(string), nil
}
return "", nil
}
// handleDownloadFile handles file download
func (b *Bmsteams) handleDownloadFile(rmsg *config.Message, filename, weburl string) error {
realURL, err := b.findFile(weburl)
if err != nil {
return err
}
// Actually download the file.
data, err := helper.DownloadFile(realURL)
if err != nil {
return fmt.Errorf("download %s failed %#v", weburl, err)
}
// If a comment is attached to the file(s) it is in the 'Text' field of the teams messge event
// and should be added as comment to only one of the files. We reset the 'Text' field to ensure
// that the comment is not duplicated.
comment := rmsg.Text
rmsg.Text = ""
helper.HandleDownloadData(b.Log, rmsg, filename, comment, weburl, data, b.General)
return nil
}
func (b *Bmsteams) handleAttachments(rmsg *config.Message, msg msgraph.ChatMessage) {
for _, a := range msg.Attachments {
//remove the attachment tags from the text
rmsg.Text = attachRE.ReplaceAllString(rmsg.Text, "")
//handle a code snippet (code block)
if *a.ContentType == "application/vnd.microsoft.card.codesnippet" {
b.handleCodeSnippet(rmsg, a)
continue
}
//handle the download
err := b.handleDownloadFile(rmsg, *a.Name, *a.ContentURL)
if err != nil {
b.Log.Errorf("download of %s failed: %s", *a.Name, err)
}
}
}
type AttachContent struct {
Language string `json:"language"`
CodeSnippetURL string `json:"codeSnippetUrl"`
}
func (b *Bmsteams) handleCodeSnippet(rmsg *config.Message, attach msgraph.ChatMessageAttachment) {
var content AttachContent
err := json.Unmarshal([]byte(*attach.Content), &content)
if err != nil {
b.Log.Errorf("unmarshal codesnippet failed: %s", err)
return
}
s := strings.Split(content.CodeSnippetURL, "/")
if len(s) != 13 {
b.Log.Errorf("codesnippetUrl has unexpected size: %s", content.CodeSnippetURL)
return
}
resp, err := b.gc.Teams().Request().Client().Get(content.CodeSnippetURL)
if err != nil {
b.Log.Errorf("retrieving snippet content failed:%s", err)
return
}
defer resp.Body.Close()
res, err := ioutil.ReadAll(resp.Body)
if err != nil {
b.Log.Errorf("reading snippet data failed: %s", err)
return
}
rmsg.Text = rmsg.Text + "\n```" + content.Language + "\n" + string(res) + "\n```\n"
}

224
bridge/msteams/msteams.go Normal file
View File

@@ -0,0 +1,224 @@
package bmsteams
import (
"context"
"fmt"
"os"
"regexp"
"strings"
"time"
"github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config"
"github.com/davecgh/go-spew/spew"
"github.com/mattn/godown"
msgraph "github.com/yaegashi/msgraph.go/beta"
"github.com/yaegashi/msgraph.go/msauth"
"golang.org/x/oauth2"
)
var defaultScopes = []string{"openid", "profile", "offline_access", "Group.Read.All", "Group.ReadWrite.All"}
var attachRE = regexp.MustCompile(`<attachment id=.*?attachment>`)
type Bmsteams struct {
gc *msgraph.GraphServiceRequestBuilder
ctx context.Context
botID string
*bridge.Config
}
func New(cfg *bridge.Config) bridge.Bridger {
return &Bmsteams{Config: cfg}
}
func (b *Bmsteams) Connect() error {
tokenCachePath := b.GetString("sessionFile")
if tokenCachePath == "" {
tokenCachePath = "msteams_session.json"
}
ctx := context.Background()
m := msauth.NewManager()
m.LoadFile(tokenCachePath) //nolint:errcheck
ts, err := m.DeviceAuthorizationGrant(ctx, b.GetString("TenantID"), b.GetString("ClientID"), defaultScopes, nil)
if err != nil {
return err
}
err = m.SaveFile(tokenCachePath)
if err != nil {
b.Log.Errorf("Couldn't save sessionfile in %s: %s", tokenCachePath, err)
}
// make file readable only for matterbridge user
err = os.Chmod(tokenCachePath, 0600)
if err != nil {
b.Log.Errorf("Couldn't change permissions for %s: %s", tokenCachePath, err)
}
httpClient := oauth2.NewClient(ctx, ts)
graphClient := msgraph.NewClient(httpClient)
b.gc = graphClient
b.ctx = ctx
err = b.setBotID()
if err != nil {
return err
}
b.Log.Info("Connection succeeded")
return nil
}
func (b *Bmsteams) Disconnect() error {
return nil
}
func (b *Bmsteams) JoinChannel(channel config.ChannelInfo) error {
go func(name string) {
for {
err := b.poll(name)
if err != nil {
b.Log.Errorf("polling failed for %s: %s. retrying in 5 seconds", name, err)
}
time.Sleep(time.Second * 5)
}
}(channel.Name)
return nil
}
func (b *Bmsteams) Send(msg config.Message) (string, error) {
b.Log.Debugf("=> Receiving %#v", msg)
if msg.ParentID != "" && msg.ParentID != "msg-parent-not-found" {
return b.sendReply(msg)
}
if msg.ParentID == "msg-parent-not-found" {
msg.ParentID = ""
msg.Text = fmt.Sprintf("[thread]: %s", msg.Text)
}
ct := b.gc.Teams().ID(b.GetString("TeamID")).Channels().ID(msg.Channel).Messages().Request()
text := msg.Username + msg.Text
content := &msgraph.ItemBody{Content: &text}
rmsg := &msgraph.ChatMessage{Body: content}
res, err := ct.Add(b.ctx, rmsg)
if err != nil {
return "", err
}
return *res.ID, nil
}
func (b *Bmsteams) sendReply(msg config.Message) (string, error) {
ct := b.gc.Teams().ID(b.GetString("TeamID")).Channels().ID(msg.Channel).Messages().ID(msg.ParentID).Replies().Request()
// Handle prefix hint for unthreaded messages.
text := msg.Username + msg.Text
content := &msgraph.ItemBody{Content: &text}
rmsg := &msgraph.ChatMessage{Body: content}
res, err := ct.Add(b.ctx, rmsg)
if err != nil {
return "", err
}
return *res.ID, nil
}
func (b *Bmsteams) getMessages(channel string) ([]msgraph.ChatMessage, error) {
ct := b.gc.Teams().ID(b.GetString("TeamID")).Channels().ID(channel).Messages().Request()
rct, err := ct.Get(b.ctx)
if err != nil {
return nil, err
}
b.Log.Debugf("got %#v messages", len(rct))
return rct, nil
}
//nolint:gocognit
func (b *Bmsteams) poll(channelName string) error {
msgmap := make(map[string]time.Time)
b.Log.Debug("getting initial messages")
res, err := b.getMessages(channelName)
if err != nil {
return err
}
for _, msg := range res {
msgmap[*msg.ID] = *msg.CreatedDateTime
if msg.LastModifiedDateTime != nil {
msgmap[*msg.ID] = *msg.LastModifiedDateTime
}
}
time.Sleep(time.Second * 5)
b.Log.Debug("polling for messages")
for {
res, err := b.getMessages(channelName)
if err != nil {
return err
}
for i := len(res) - 1; i >= 0; i-- {
msg := res[i]
if mtime, ok := msgmap[*msg.ID]; ok {
if mtime == *msg.CreatedDateTime && msg.LastModifiedDateTime == nil {
continue
}
if msg.LastModifiedDateTime != nil && mtime == *msg.LastModifiedDateTime {
continue
}
}
if b.GetBool("debug") {
b.Log.Debug("Msg dump: ", spew.Sdump(msg))
}
// skip non-user message for now.
if msg.From.User == nil {
continue
}
if *msg.From.User.ID == b.botID {
b.Log.Debug("skipping own message")
msgmap[*msg.ID] = *msg.CreatedDateTime
continue
}
msgmap[*msg.ID] = *msg.CreatedDateTime
if msg.LastModifiedDateTime != nil {
msgmap[*msg.ID] = *msg.LastModifiedDateTime
}
b.Log.Debugf("<= Sending message from %s on %s to gateway", *msg.From.User.DisplayName, b.Account)
text := b.convertToMD(*msg.Body.Content)
rmsg := config.Message{
Username: *msg.From.User.DisplayName,
Text: text,
Channel: channelName,
Account: b.Account,
Avatar: "",
UserID: *msg.From.User.ID,
ID: *msg.ID,
Extra: make(map[string][]interface{}),
}
b.handleAttachments(&rmsg, msg)
b.Log.Debugf("<= Message is %#v", rmsg)
b.Remote <- rmsg
}
time.Sleep(time.Second * 5)
}
}
func (b *Bmsteams) setBotID() error {
req := b.gc.Me().Request()
r, err := req.Get(b.ctx)
if err != nil {
return err
}
b.botID = *r.ID
return nil
}
func (b *Bmsteams) convertToMD(text string) string {
if !strings.Contains(text, "<div>") {
return text
}
var sb strings.Builder
err := godown.Convert(&sb, strings.NewReader(text), nil)
if err != nil {
b.Log.Errorf("Couldn't convert message to markdown %s", text)
return text
}
return sb.String()
}

114
bridge/nctalk/nctalk.go Normal file
View File

@@ -0,0 +1,114 @@
package nctalk
import (
"context"
"strconv"
"github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config"
talk "gomod.garykim.dev/nc-talk"
"gomod.garykim.dev/nc-talk/ocs"
"gomod.garykim.dev/nc-talk/room"
"gomod.garykim.dev/nc-talk/user"
)
type Btalk struct {
user *user.TalkUser
rooms []Broom
*bridge.Config
}
func New(cfg *bridge.Config) bridge.Bridger {
return &Btalk{Config: cfg}
}
type Broom struct {
room *room.TalkRoom
ctx context.Context
ctxCancel context.CancelFunc
}
func (b *Btalk) Connect() error {
b.Log.Info("Connecting")
b.user = talk.NewUser(b.GetString("Server"), b.GetString("Login"), b.GetString("Password"))
_, err := b.user.Capabilities()
if err != nil {
b.Log.Error("Cannot Connect")
return err
}
b.Log.Info("Connected")
return nil
}
func (b *Btalk) Disconnect() error {
for _, r := range b.rooms {
r.ctxCancel()
}
return nil
}
func (b *Btalk) JoinChannel(channel config.ChannelInfo) error {
newRoom := Broom{
room: talk.NewRoom(b.user, channel.Name),
}
newRoom.ctx, newRoom.ctxCancel = context.WithCancel(context.Background())
c, err := newRoom.room.ReceiveMessages(newRoom.ctx)
if err != nil {
return err
}
b.rooms = append(b.rooms, newRoom)
go func() {
for msg := range c {
// ignore messages that are one of the following
// * not a message from a user
// * from ourselves
if msg.MessageType != ocs.MessageComment || msg.ActorID == b.user.User {
continue
}
remoteMessage := config.Message{
Text: msg.Message,
Channel: newRoom.room.Token,
Username: msg.ActorDisplayName,
UserID: msg.ActorID,
Account: b.Account,
}
// It is possible for the ID to not be set on older versions of Talk so we only set it if
// the ID is not blank
if msg.ID != 0 {
remoteMessage.ID = strconv.Itoa(msg.ID)
}
b.Log.Debugf("<= Message is %#v", remoteMessage)
b.Remote <- remoteMessage
}
}()
return nil
}
func (b *Btalk) Send(msg config.Message) (string, error) {
r := b.getRoom(msg.Channel)
if r == nil {
b.Log.Errorf("Could not find room for %v", msg.Channel)
return "", nil
}
// Talk currently only supports sending normal messages
if msg.Event != "" {
return "", nil
}
sentMessage, err := r.room.SendMessage(msg.Username + msg.Text)
if err != nil {
b.Log.Errorf("Could not send message to room %v from %v: %v", msg.Channel, msg.Username, err)
return "", nil
}
return strconv.Itoa(sentMessage.ID), nil
}
func (b *Btalk) getRoom(token string) *Broom {
for _, r := range b.rooms {
if r.room.Token == token {
return &r
}
}
return nil
}

View File

@@ -2,6 +2,7 @@ package brocketchat
import ( import (
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/matterbridge/Rocket.Chat.Go.SDK/models"
) )
func (b *Brocketchat) handleRocket() { func (b *Brocketchat) handleRocket() {
@@ -38,6 +39,23 @@ func (b *Brocketchat) handleRocketHook(messages chan *config.Message) {
} }
} }
func (b *Brocketchat) handleStatusEvent(ev models.Message, rmsg *config.Message) bool {
switch ev.Type {
case "":
// this is a normal message, no processing needed
// return true so the message is not dropped
return true
case sUserJoined, sUserLeft:
rmsg.Event = config.EventJoinLeave
return true
case sRoomChangedTopic:
rmsg.Event = config.EventTopicChange
return true
}
b.Log.Debugf("Dropping message with unknown type: %s", ev.Type)
return false
}
func (b *Brocketchat) handleRocketClient(messages chan *config.Message) { func (b *Brocketchat) handleRocketClient(messages chan *config.Message) {
for message := range b.messageChan { for message := range b.messageChan {
// skip messages with same ID, apparently messages get duplicated for an unknown reason // skip messages with same ID, apparently messages get duplicated for an unknown reason
@@ -59,8 +77,13 @@ func (b *Brocketchat) handleRocketClient(messages chan *config.Message) {
UserID: message.User.ID, UserID: message.User.ID,
ID: message.ID, ID: message.ID,
} }
// handleStatusEvent returns false if the message should be dropped
// in that case it is probably some modification to the channel we do not want to relay
if b.handleStatusEvent(m, rmsg) {
messages <- rmsg messages <- rmsg
} }
}
} }
func (b *Brocketchat) handleUploadFile(msg *config.Message) error { func (b *Brocketchat) handleUploadFile(msg *config.Message) error {

View File

@@ -58,6 +58,9 @@ func (b *Brocketchat) doConnectWebhookURL() error {
func (b *Brocketchat) apiLogin() error { func (b *Brocketchat) apiLogin() error {
b.Log.Debugf("handling apiLogin()") b.Log.Debugf("handling apiLogin()")
credentials := &models.UserCredentials{Email: b.GetString("login"), Password: b.GetString("password")} credentials := &models.UserCredentials{Email: b.GetString("login"), Password: b.GetString("password")}
if b.GetString("Token") != "" {
credentials = &models.UserCredentials{ID: b.GetString("Login"), Token: b.GetString("Token")}
}
myURL, err := url.Parse(b.GetString("server")) myURL, err := url.Parse(b.GetString("server"))
if err != nil { if err != nil {
return err return err

View File

@@ -29,6 +29,12 @@ type Brocketchat struct {
sync.RWMutex sync.RWMutex
} }
const (
sUserJoined = "uj"
sUserLeft = "ul"
sRoomChangedTopic = "room_changed_topic"
)
func New(cfg *bridge.Config) bridge.Bridger { func New(cfg *bridge.Config) bridge.Bridger {
newCache, err := lru.New(100) newCache, err := lru.New(100)
if err != nil { if err != nil {

View File

@@ -1,18 +1,22 @@
package bslack package bslack
import ( import (
"errors"
"fmt" "fmt"
"html" "html"
"time" "time"
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper" "github.com/42wim/matterbridge/bridge/helper"
"github.com/nlopes/slack" "github.com/slack-go/slack"
) )
// ErrEventIgnored is for events that should be ignored
var ErrEventIgnored = errors.New("this event message should ignored")
func (b *Bslack) handleSlack() { func (b *Bslack) handleSlack() {
messages := make(chan *config.Message) messages := make(chan *config.Message)
if b.GetString(incomingWebhookConfig) != "" { if b.GetString(incomingWebhookConfig) != "" && b.GetString(tokenConfig) == "" {
b.Log.Debugf("Choosing webhooks based receiving") b.Log.Debugf("Choosing webhooks based receiving")
go b.handleMatterHook(messages) go b.handleMatterHook(messages)
} else { } else {
@@ -30,6 +34,7 @@ func (b *Bslack) handleSlack() {
message.Text = b.replaceVariable(message.Text) message.Text = b.replaceVariable(message.Text)
message.Text = b.replaceChannel(message.Text) message.Text = b.replaceChannel(message.Text)
message.Text = b.replaceURL(message.Text) message.Text = b.replaceURL(message.Text)
message.Text = b.replaceb0rkedMarkDown(message.Text)
message.Text = html.UnescapeString(message.Text) message.Text = html.UnescapeString(message.Text)
// Add the avatar // Add the avatar
@@ -43,7 +48,7 @@ func (b *Bslack) handleSlack() {
func (b *Bslack) handleSlackClient(messages chan *config.Message) { func (b *Bslack) handleSlackClient(messages chan *config.Message) {
for msg := range b.rtm.IncomingEvents { for msg := range b.rtm.IncomingEvents {
if msg.Type != sUserTyping && msg.Type != sLatencyReport { if msg.Type != sUserTyping && msg.Type != sHello && msg.Type != sLatencyReport {
b.Log.Debugf("== Receiving event %#v", msg.Data) b.Log.Debugf("== Receiving event %#v", msg.Data)
} }
switch ev := msg.Data.(type) { switch ev := msg.Data.(type) {
@@ -52,7 +57,9 @@ func (b *Bslack) handleSlackClient(messages chan *config.Message) {
continue continue
} }
rmsg, err := b.handleTypingEvent(ev) rmsg, err := b.handleTypingEvent(ev)
if err != nil { if err == ErrEventIgnored {
continue
} else if err != nil {
b.Log.Errorf("%#v", err) b.Log.Errorf("%#v", err)
continue continue
} }
@@ -86,7 +93,7 @@ func (b *Bslack) handleSlackClient(messages chan *config.Message) {
b.Log.Errorf("Connection failed %#v %#v", ev.Error(), ev.ErrorObj) b.Log.Errorf("Connection failed %#v %#v", ev.Error(), ev.ErrorObj)
case *slack.MemberJoinedChannelEvent: case *slack.MemberJoinedChannelEvent:
b.users.populateUser(ev.User) b.users.populateUser(ev.User)
case *slack.LatencyReport: case *slack.HelloEvent, *slack.LatencyReport, *slack.ConnectingEvent:
continue continue
default: default:
b.Log.Debugf("Unhandled incoming event: %T", ev) b.Log.Debugf("Unhandled incoming event: %T", ev)
@@ -123,11 +130,11 @@ func (b *Bslack) skipMessageEvent(ev *slack.MessageEvent) bool {
} }
} }
// Skip any messages that we made ourselves or from 'slackbot' (see #527). // Check for our callback ID
if ev.Username == sSlackBotUser || hasOurCallbackID := false
(b.rtm != nil && ev.Username == b.si.User.Name) || if len(ev.Blocks.BlockSet) == 1 {
(len(ev.Attachments) > 0 && ev.Attachments[0].CallbackID == "matterbridge_"+b.uuid) { block, ok := ev.Blocks.BlockSet[0].(*slack.SectionBlock)
return true hasOurCallbackID = ok && block.BlockID == "matterbridge_"+b.uuid
} }
if ev.SubMessage != nil { if ev.SubMessage != nil {
@@ -142,6 +149,16 @@ func (b *Bslack) skipMessageEvent(ev *slack.MessageEvent) bool {
if ev.SubType == "message_replied" && ev.Hidden { if ev.SubType == "message_replied" && ev.Hidden {
return true return true
} }
if len(ev.SubMessage.Blocks.BlockSet) == 1 {
block, ok := ev.SubMessage.Blocks.BlockSet[0].(*slack.SectionBlock)
hasOurCallbackID = ok && block.BlockID == "matterbridge_"+b.uuid
}
}
// Skip any messages that we made ourselves or from 'slackbot' (see #527).
if ev.Username == sSlackBotUser ||
(b.rtm != nil && ev.Username == b.si.User.Name) || hasOurCallbackID {
return true
} }
if len(ev.Files) > 0 { if len(ev.Files) > 0 {
@@ -269,6 +286,9 @@ func (b *Bslack) handleAttachments(ev *slack.MessageEvent, rmsg *config.Message)
} }
func (b *Bslack) handleTypingEvent(ev *slack.UserTypingEvent) (*config.Message, error) { func (b *Bslack) handleTypingEvent(ev *slack.UserTypingEvent) (*config.Message, error) {
if ev.User == b.si.User.ID {
return nil, ErrEventIgnored
}
channelInfo, err := b.channels.getChannelByID(ev.Channel) channelInfo, err := b.channels.getChannelByID(ev.Channel)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -7,8 +7,8 @@ import (
"time" "time"
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/nlopes/slack"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/slack-go/slack"
) )
// populateReceivedMessage shapes the initial Matterbridge message that we will forward to the // populateReceivedMessage shapes the initial Matterbridge message that we will forward to the
@@ -188,6 +188,36 @@ func (b *Bslack) replaceURL(text string) string {
return text return text
} }
func (b *Bslack) replaceb0rkedMarkDown(text string) string {
// taken from https://github.com/mattermost/mattermost-server/blob/master/app/slackimport.go
//
regexReplaceAllString := []struct {
regex *regexp.Regexp
rpl string
}{
// bold
{
regexp.MustCompile(`(^|[\s.;,])\*(\S[^*\n]+)\*`),
"$1**$2**",
},
// strikethrough
{
regexp.MustCompile(`(^|[\s.;,])\~(\S[^~\n]+)\~`),
"$1~~$2~~",
},
// single paragraph blockquote
// Slack converts > character to &gt;
{
regexp.MustCompile(`(?sm)^&gt;`),
">",
},
}
for _, rule := range regexReplaceAllString {
text = rule.regex.ReplaceAllString(text, rule.rpl)
}
return text
}
func (b *Bslack) replaceCodeFence(text string) string { func (b *Bslack) replaceCodeFence(text string) string {
return codeFenceRE.ReplaceAllString(text, "```") return codeFenceRE.ReplaceAllString(text, "```")
} }

View File

@@ -5,7 +5,7 @@ import (
"github.com/42wim/matterbridge/bridge" "github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/matterhook" "github.com/42wim/matterbridge/matterhook"
"github.com/nlopes/slack" "github.com/slack-go/slack"
) )
type BLegacy struct { type BLegacy struct {

View File

@@ -12,9 +12,9 @@ import (
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper" "github.com/42wim/matterbridge/bridge/helper"
"github.com/42wim/matterbridge/matterhook" "github.com/42wim/matterbridge/matterhook"
"github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
"github.com/nlopes/slack"
"github.com/rs/xid" "github.com/rs/xid"
"github.com/slack-go/slack"
) )
type Bslack struct { type Bslack struct {
@@ -36,6 +36,7 @@ type Bslack struct {
} }
const ( const (
sHello = "hello"
sChannelJoin = "channel_join" sChannelJoin = "channel_join"
sChannelLeave = "channel_leave" sChannelLeave = "channel_leave"
sChannelJoined = "channel_joined" sChannelJoined = "channel_joined"
@@ -63,6 +64,7 @@ const (
editSuffixConfig = "EditSuffix" editSuffixConfig = "EditSuffix"
iconURLConfig = "iconurl" iconURLConfig = "iconurl"
noSendJoinConfig = "nosendjoinpart" noSendJoinConfig = "nosendjoinpart"
messageLength = 3000
) )
func New(cfg *bridge.Config) bridge.Bridger { func New(cfg *bridge.Config) bridge.Bridger {
@@ -193,6 +195,7 @@ func (b *Bslack) Send(msg config.Message) (string, error) {
b.Log.Debugf("=> Receiving %#v", msg) b.Log.Debugf("=> Receiving %#v", msg)
} }
msg.Text = helper.ClipMessage(msg.Text, messageLength)
msg.Text = b.replaceCodeFence(msg.Text) msg.Text = b.replaceCodeFence(msg.Text)
// Make a action /me of the message // Make a action /me of the message
@@ -201,7 +204,7 @@ func (b *Bslack) Send(msg config.Message) (string, error) {
} }
// Use webhook to send the message // Use webhook to send the message
if b.GetString(outgoingWebhookConfig) != "" { if b.GetString(outgoingWebhookConfig) != "" && b.GetString(tokenConfig) == "" {
return "", b.sendWebhook(msg) return "", b.sendWebhook(msg)
} }
return b.sendRTM(msg) return b.sendRTM(msg)
@@ -407,7 +410,6 @@ func (b *Bslack) editMessage(msg *config.Message, channelInfo *slack.Channel) (b
} }
messageOptions := b.prepareMessageOptions(msg) messageOptions := b.prepareMessageOptions(msg)
for { for {
messageOptions = append(messageOptions, slack.MsgOptionText(msg.Text, false))
_, _, _, err := b.rtm.UpdateMessage(channelInfo.ID, msg.ID, messageOptions...) _, _, _, err := b.rtm.UpdateMessage(channelInfo.ID, msg.ID, messageOptions...)
if err == nil { if err == nil {
return true, nil return true, nil
@@ -426,11 +428,6 @@ func (b *Bslack) postMessage(msg *config.Message, channelInfo *slack.Channel) (s
return "", nil return "", nil
} }
messageOptions := b.prepareMessageOptions(msg) messageOptions := b.prepareMessageOptions(msg)
messageOptions = append(
messageOptions,
slack.MsgOptionText(msg.Text, false),
slack.MsgOptionEnableLinkUnfurl(),
)
for { for {
_, id, err := b.rtm.PostMessage(channelInfo.ID, messageOptions...) _, id, err := b.rtm.PostMessage(channelInfo.ID, messageOptions...)
if err == nil { if err == nil {
@@ -496,8 +493,6 @@ func (b *Bslack) prepareMessageOptions(msg *config.Message) []slack.MsgOption {
} }
var attachments []slack.Attachment var attachments []slack.Attachment
// add a callback ID so we can see we created it
attachments = append(attachments, slack.Attachment{CallbackID: "matterbridge_" + b.uuid})
// add file attachments // add file attachments
attachments = append(attachments, b.createAttach(msg.Extra)...) attachments = append(attachments, b.createAttach(msg.Extra)...)
// add slack attachments (from another slack bridge) // add slack attachments (from another slack bridge)
@@ -508,6 +503,19 @@ func (b *Bslack) prepareMessageOptions(msg *config.Message) []slack.MsgOption {
} }
var opts []slack.MsgOption var opts []slack.MsgOption
opts = append(opts,
// provide regular text field (fallback used in Slack notifications, etc.)
slack.MsgOptionText(msg.Text, false),
// add a callback ID so we can see we created it
slack.MsgOptionBlocks(slack.NewSectionBlock(
slack.NewTextBlockObject(slack.MarkdownType, msg.Text, false, false),
nil, nil,
slack.SectionBlockOptionBlockID("matterbridge_"+b.uuid),
)),
slack.MsgOptionEnableLinkUnfurl(),
)
opts = append(opts, slack.MsgOptionAttachments(attachments...)) opts = append(opts, slack.MsgOptionAttachments(attachments...))
opts = append(opts, slack.MsgOptionPostMessageParameters(params)) opts = append(opts, slack.MsgOptionPostMessageParameters(params))
return opts return opts

View File

@@ -8,8 +8,8 @@ import (
"time" "time"
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/nlopes/slack"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/slack-go/slack"
) )
const minimumRefreshInterval = 10 * time.Second const minimumRefreshInterval = 10 * time.Second

View File

@@ -130,6 +130,10 @@ func (b *Bsshchat) handleSSHChat() error {
if strings.Contains(b.r.Text(), "Rate limiting is in effect") { if strings.Contains(b.r.Text(), "Rate limiting is in effect") {
continue continue
} }
// skip our own messages
if !strings.HasPrefix(b.r.Text(), "["+b.GetString("Nick")+"] \x1b") {
continue
}
res := strings.Split(stripPrompt(b.r.Text()), ":") res := strings.Split(stripPrompt(b.r.Text()), ":")
if res[0] == "-> Set theme" { if res[0] == "-> Set theme" {
wait = false wait = false

View File

@@ -85,7 +85,7 @@ func (b *Bsteam) handleEvents() {
func (b *Bsteam) handleLogOnFailed(e *steam.LogOnFailedEvent, myLoginInfo *steam.LogOnDetails) error { func (b *Bsteam) handleLogOnFailed(e *steam.LogOnFailedEvent, myLoginInfo *steam.LogOnDetails) error {
switch e.Result { switch e.Result {
case steamlang.EResult_AccountLogonDeniedNeedTwoFactorCode: case steamlang.EResult_AccountLoginDeniedNeedTwoFactor:
b.Log.Info("Steam guard isn't letting me in! Enter 2FA code:") b.Log.Info("Steam guard isn't letting me in! Enter 2FA code:")
var code string var code string
fmt.Scanf("%s", &code) fmt.Scanf("%s", &code)

View File

@@ -39,22 +39,32 @@ func (b *Btelegram) handleGroups(rmsg *config.Message, message *tgbotapi.Message
// handleForwarded handles forwarded messages // handleForwarded handles forwarded messages
func (b *Btelegram) handleForwarded(rmsg *config.Message, message *tgbotapi.Message) { func (b *Btelegram) handleForwarded(rmsg *config.Message, message *tgbotapi.Message) {
if message.ForwardFrom != nil { if message.ForwardDate == 0 {
return
}
if message.ForwardFrom == nil {
rmsg.Text = "Forwarded from " + unknownUser + ": " + rmsg.Text
return
}
usernameForward := "" usernameForward := ""
if b.GetBool("UseFirstName") { if b.GetBool("UseFirstName") {
usernameForward = message.ForwardFrom.FirstName usernameForward = message.ForwardFrom.FirstName
} }
if usernameForward == "" { if usernameForward == "" {
usernameForward = message.ForwardFrom.UserName usernameForward = message.ForwardFrom.UserName
if usernameForward == "" { if usernameForward == "" {
usernameForward = message.ForwardFrom.FirstName usernameForward = message.ForwardFrom.FirstName
} }
} }
if usernameForward == "" { if usernameForward == "" {
usernameForward = unknownUser usernameForward = unknownUser
} }
rmsg.Text = "Forwarded from " + usernameForward + ": " + rmsg.Text rmsg.Text = "Forwarded from " + usernameForward + ": " + rmsg.Text
}
} }
// handleQuoting handles quoting of previous messages // handleQuoting handles quoting of previous messages
@@ -95,7 +105,7 @@ func (b *Btelegram) handleUsername(rmsg *config.Message, message *tgbotapi.Messa
} }
} }
// only download avatars if we have a place to upload them (configured mediaserver) // only download avatars if we have a place to upload them (configured mediaserver)
if b.General.MediaServerUpload != "" { if b.General.MediaServerUpload != "" || (b.General.MediaServerDownload != "" && b.General.MediaDownloadPath != "") {
b.handleDownloadAvatar(message.From.ID, rmsg.Channel) b.handleDownloadAvatar(message.From.ID, rmsg.Channel)
} }
} }
@@ -207,6 +217,46 @@ func (b *Btelegram) handleDownloadAvatar(userid int, channel string) {
} }
} }
func (b *Btelegram) maybeConvertTgs(name *string, data *[]byte) {
var format string
switch b.GetString("MediaConvertTgs") {
case FormatWebp:
b.Log.Debugf("Tgs to WebP conversion enabled, converting %v", name)
format = FormatWebp
case FormatPng:
// The WebP to PNG converter can't handle animated webp files yet,
// and I'm not going to write a path for x/image/webp.
// The error message would be:
// conversion failed: webp: non-Alpha VP8X is not implemented
// So instead, we tell lottie to directly go to PNG.
b.Log.Debugf("Tgs to PNG conversion enabled, converting %v", name)
format = FormatPng
default:
// Otherwise, no conversion was requested. Trying to run the usual webp
// converter would fail, because '.tgs.webp' is actually a gzipped JSON
// file, and has nothing to do with WebP.
return
}
err := helper.ConvertTgsToX(data, format, b.Log)
if err != nil {
b.Log.Errorf("conversion failed: %v", err)
} else {
*name = strings.Replace(*name, "tgs.webp", format, 1)
}
}
func (b *Btelegram) maybeConvertWebp(name *string, data *[]byte) {
if b.GetBool("MediaConvertWebPToPNG") {
b.Log.Debugf("WebP to PNG conversion enabled, converting %v", name)
err := helper.ConvertWebPToPNG(data)
if err != nil {
b.Log.Errorf("conversion failed: %v", err)
} else {
*name = strings.Replace(*name, ".webp", ".png", 1)
}
}
}
// handleDownloadFile handles file download // handleDownloadFile handles file download
func (b *Btelegram) handleDownload(rmsg *config.Message, message *tgbotapi.Message) error { func (b *Btelegram) handleDownload(rmsg *config.Message, message *tgbotapi.Message) error {
size := 0 size := 0
@@ -254,15 +304,13 @@ func (b *Btelegram) handleDownload(rmsg *config.Message, message *tgbotapi.Messa
if err != nil { if err != nil {
return err return err
} }
if strings.HasSuffix(name, ".webp") && b.GetBool("MediaConvertWebPToPNG") {
b.Log.Debugf("WebP to PNG conversion enabled, converting %s", name) if strings.HasSuffix(name, ".tgs.webp") {
err := helper.ConvertWebPToPNG(data) b.maybeConvertTgs(&name, data)
if err != nil { } else if strings.HasSuffix(name, ".webp") {
b.Log.Errorf("conversion failed: %s", err) b.maybeConvertWebp(&name, data)
} else {
name = strings.Replace(name, ".webp", ".png", 1)
}
} }
helper.HandleDownloadData(b.Log, rmsg, name, message.Caption, "", data, b.General) helper.HandleDownloadData(b.Log, rmsg, name, message.Caption, "", data, b.General)
return nil return nil
} }
@@ -312,6 +360,9 @@ func (b *Btelegram) handleEdit(msg *config.Message, chatid int64) (string, error
case "Markdown": case "Markdown":
b.Log.Debug("Using mode markdown") b.Log.Debug("Using mode markdown")
m.ParseMode = tgbotapi.ModeMarkdown m.ParseMode = tgbotapi.ModeMarkdown
case MarkdownV2:
b.Log.Debug("Using mode MarkdownV2")
m.ParseMode = MarkdownV2
} }
if strings.ToLower(b.GetString("MessageFormat")) == HTMLNick { if strings.ToLower(b.GetString("MessageFormat")) == HTMLNick {
b.Log.Debug("Using mode HTML - nick only") b.Log.Debug("Using mode HTML - nick only")
@@ -357,6 +408,14 @@ func (b *Btelegram) handleQuote(message, quoteNick, quoteMessage string) string
if format == "" { if format == "" {
format = "{MESSAGE} (re @{QUOTENICK}: {QUOTEMESSAGE})" format = "{MESSAGE} (re @{QUOTENICK}: {QUOTEMESSAGE})"
} }
quoteMessagelength := len(quoteMessage)
if b.GetInt("QuoteLengthLimit") != 0 && quoteMessagelength >= b.GetInt("QuoteLengthLimit") {
runes := []rune(quoteMessage)
quoteMessage = string(runes[0:b.GetInt("QuoteLengthLimit")])
if quoteMessagelength > b.GetInt("QuoteLengthLimit") {
quoteMessage += "..."
}
}
format = strings.Replace(format, "{MESSAGE}", message, -1) format = strings.Replace(format, "{MESSAGE}", message, -1)
format = strings.Replace(format, "{QUOTENICK}", quoteNick, -1) format = strings.Replace(format, "{QUOTENICK}", quoteNick, -1)
format = strings.Replace(format, "{QUOTEMESSAGE}", quoteMessage, -1) format = strings.Replace(format, "{QUOTEMESSAGE}", quoteMessage, -1)

View File

@@ -2,19 +2,23 @@ package btelegram
import ( import (
"html" "html"
"log"
"strconv" "strconv"
"strings" "strings"
"github.com/42wim/matterbridge/bridge" "github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper" "github.com/42wim/matterbridge/bridge/helper"
"github.com/go-telegram-bot-api/telegram-bot-api" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
) )
const ( const (
unknownUser = "unknown" unknownUser = "unknown"
HTMLFormat = "HTML" HTMLFormat = "HTML"
HTMLNick = "htmlnick" HTMLNick = "htmlnick"
MarkdownV2 = "MarkdownV2"
FormatPng = "png"
FormatWebp = "webp"
) )
type Btelegram struct { type Btelegram struct {
@@ -24,6 +28,16 @@ type Btelegram struct {
} }
func New(cfg *bridge.Config) bridge.Bridger { func New(cfg *bridge.Config) bridge.Bridger {
tgsConvertFormat := cfg.GetString("MediaConvertTgs")
if tgsConvertFormat != "" {
err := helper.CanConvertTgsToX()
if err != nil {
log.Fatalf("Telegram bridge configured to convert .tgs files to '%s', but lottie does not appear to work:\n%#v", tgsConvertFormat, err)
}
if tgsConvertFormat != FormatPng && tgsConvertFormat != FormatWebp {
log.Fatalf("Telegram bridge configured to convert .tgs files to '%s', but only '%s' and '%s' are supported.", FormatPng, FormatWebp, tgsConvertFormat)
}
}
return &Btelegram{Config: cfg, avatarMap: make(map[string]string)} return &Btelegram{Config: cfg, avatarMap: make(map[string]string)}
} }
@@ -81,8 +95,8 @@ func (b *Btelegram) Send(msg config.Message) (string, error) {
// Upload a file if it exists // Upload a file if it exists
if msg.Extra != nil { if msg.Extra != nil {
for _, rmsg := range helper.HandleExtra(&msg, b.General) { for _, rmsg := range helper.HandleExtra(&msg, b.General) {
if _, err := b.sendMessage(chatid, rmsg.Username, rmsg.Text); err != nil { if _, msgErr := b.sendMessage(chatid, rmsg.Username, rmsg.Text); msgErr != nil {
b.Log.Errorf("sendMessage failed: %s", err) b.Log.Errorf("sendMessage failed: %s", msgErr)
} }
} }
// check if we have files to upload (from slack, telegram or mattermost) // check if we have files to upload (from slack, telegram or mattermost)
@@ -97,7 +111,14 @@ func (b *Btelegram) Send(msg config.Message) (string, error) {
} }
// Post normal message // Post normal message
// TODO: recheck it.
// Ignore empty text field needs for prevent double messages from whatsapp to telegram
// when sending media with text caption
if msg.Text != "" {
return b.sendMessage(chatid, msg.Username, msg.Text) return b.sendMessage(chatid, msg.Username, msg.Text)
}
return "", nil
} }
func (b *Btelegram) getFileDirectURL(id string) string { func (b *Btelegram) getFileDirectURL(id string) string {
@@ -119,11 +140,18 @@ func (b *Btelegram) sendMessage(chatid int64, username, text string) (string, er
b.Log.Debug("Using mode markdown") b.Log.Debug("Using mode markdown")
m.ParseMode = tgbotapi.ModeMarkdown m.ParseMode = tgbotapi.ModeMarkdown
} }
if b.GetString("MessageFormat") == MarkdownV2 {
b.Log.Debug("Using mode MarkdownV2")
m.ParseMode = MarkdownV2
}
if strings.ToLower(b.GetString("MessageFormat")) == HTMLNick { if strings.ToLower(b.GetString("MessageFormat")) == HTMLNick {
b.Log.Debug("Using mode HTML - nick only") b.Log.Debug("Using mode HTML - nick only")
m.Text = username + html.EscapeString(text) m.Text = username + html.EscapeString(text)
m.ParseMode = tgbotapi.ModeHTML m.ParseMode = tgbotapi.ModeHTML
} }
m.DisableWebPagePreview = b.GetBool("DisableWebPagePreview")
res, err := b.c.Send(m) res, err := b.c.Send(m)
if err != nil { if err != nil {
return "", err return "", err

View File

@@ -1,11 +1,15 @@
package bwhatsapp package bwhatsapp
import ( import (
"fmt"
"mime"
"strings" "strings"
"time" "time"
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper"
"github.com/Rhymen/go-whatsapp" "github.com/Rhymen/go-whatsapp"
"github.com/jpillora/backoff"
) )
/* /*
@@ -19,10 +23,43 @@ Check:
// HandleError received from WhatsApp // HandleError received from WhatsApp
func (b *Bwhatsapp) HandleError(err error) { func (b *Bwhatsapp) HandleError(err error) {
// ignore received invalid data errors. https://github.com/42wim/matterbridge/issues/843 // ignore received invalid data errors. https://github.com/42wim/matterbridge/issues/843
if strings.Contains(err.Error(), "error processing data: received invalid data") { // ignore tag 174 errors. https://github.com/42wim/matterbridge/issues/1094
if strings.Contains(err.Error(), "error processing data: received invalid data") || strings.Contains(err.Error(), "invalid string with tag 174") {
return return
} }
b.Log.Errorf("%v", err) // TODO implement proper handling? at least respond to different error types
switch err.(type) {
case *whatsapp.ErrConnectionClosed, *whatsapp.ErrConnectionFailed:
b.reconnect(err)
default:
switch err {
case whatsapp.ErrConnectionTimeout:
b.reconnect(err)
default:
b.Log.Errorf("%v", err)
}
}
}
func (b *Bwhatsapp) reconnect(err error) {
bf := &backoff.Backoff{
Min: time.Second,
Max: 5 * time.Minute,
Jitter: true,
}
for {
d := bf.Duration()
b.Log.Errorf("Connection failed, underlying error: %v", err)
b.Log.Infof("Waiting %s...", d)
time.Sleep(d)
b.Log.Info("Reconnecting...")
err := b.conn.Restore()
if err == nil {
bf.Reset()
b.startedAt = uint64(time.Now().Unix())
return
}
}
} }
// HandleTextMessage sent from WhatsApp, relay it to the brige // HandleTextMessage sent from WhatsApp, relay it to the brige
@@ -36,16 +73,18 @@ func (b *Bwhatsapp) HandleTextMessage(message whatsapp.TextMessage) {
} }
messageTime := time.Unix(int64(message.Info.Timestamp), 0) // TODO check how behaves between timezones messageTime := time.Unix(int64(message.Info.Timestamp), 0) // TODO check how behaves between timezones
groupJid := message.Info.RemoteJid groupJID := message.Info.RemoteJid
senderJid := message.Info.SenderJid senderJID := message.Info.SenderJid
if len(senderJid) == 0 { if len(senderJID) == 0 {
// TODO workaround till https://github.com/Rhymen/go-whatsapp/issues/86 resolved // TODO workaround till https://github.com/Rhymen/go-whatsapp/issues/86 resolved
senderJid = *message.Info.Source.Participant if message.Info.Source != nil {
senderJID = *message.Info.Source.Participant
}
} }
// translate sender's Jid to the nicest username we can get // translate sender's JID to the nicest username we can get
senderName := b.getSenderName(senderJid) senderName := b.getSenderName(senderJID)
if senderName == "" { if senderName == "" {
senderName = "Someone" // don't expose telephone number senderName = "Someone" // don't expose telephone number
} }
@@ -53,8 +92,8 @@ func (b *Bwhatsapp) HandleTextMessage(message whatsapp.TextMessage) {
extText := message.Info.Source.Message.ExtendedTextMessage extText := message.Info.Source.Message.ExtendedTextMessage
if extText != nil && extText.ContextInfo != nil && extText.ContextInfo.MentionedJid != nil { if extText != nil && extText.ContextInfo != nil && extText.ContextInfo.MentionedJid != nil {
// handle user mentions // handle user mentions
for _, mentionedJid := range extText.ContextInfo.MentionedJid { for _, mentionedJID := range extText.ContextInfo.MentionedJid {
numberAndSuffix := strings.SplitN(mentionedJid, "@", 2) numberAndSuffix := strings.SplitN(mentionedJID, "@", 2)
// mentions comes as telephone numbers and we don't want to expose it to other bridges // mentions comes as telephone numbers and we don't want to expose it to other bridges
// replace it with something more meaninful to others // replace it with something more meaninful to others
@@ -66,13 +105,13 @@ func (b *Bwhatsapp) HandleTextMessage(message whatsapp.TextMessage) {
} }
} }
b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJid, b.Account) b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
rmsg := config.Message{ rmsg := config.Message{
UserID: senderJid, UserID: senderJID,
Username: senderName, Username: senderName,
Text: message.Text, Text: message.Text,
Timestamp: messageTime, Timestamp: messageTime,
Channel: groupJid, Channel: groupJID,
Account: b.Account, Account: b.Account,
Protocol: b.Protocol, Protocol: b.Protocol,
Extra: make(map[string][]interface{}), Extra: make(map[string][]interface{}),
@@ -81,7 +120,7 @@ func (b *Bwhatsapp) HandleTextMessage(message whatsapp.TextMessage) {
// Gateway string // will be added during message processing // Gateway string // will be added during message processing
ID: message.Info.Id} ID: message.Info.Id}
if avatarURL, exists := b.userAvatars[senderJid]; exists { if avatarURL, exists := b.userAvatars[senderJID]; exists {
rmsg.Avatar = avatarURL rmsg.Avatar = avatarURL
} }
@@ -89,11 +128,75 @@ func (b *Bwhatsapp) HandleTextMessage(message whatsapp.TextMessage) {
b.Remote <- rmsg b.Remote <- rmsg
} }
// // HandleImageMessage sent from WhatsApp, relay it to the brige
//func (b *Bwhatsapp) HandleImageMessage(message whatsapp.ImageMessage) { func (b *Bwhatsapp) HandleImageMessage(message whatsapp.ImageMessage) {
// fmt.Println(message) // TODO implement if message.Info.FromMe { // || !strings.Contains(strings.ToLower(message.Text), "@echo") {
//} return
// }
// whatsapp sends last messages to show context , cut them
if message.Info.Timestamp < b.startedAt {
return
}
messageTime := time.Unix(int64(message.Info.Timestamp), 0) // TODO check how behaves between timezones
groupJID := message.Info.RemoteJid
senderJID := message.Info.SenderJid
// if len(senderJid) == 0 {
// // TODO workaround till https://github.com/Rhymen/go-whatsapp/issues/86 resolved
// senderJid = *message.Info.Source.Participant
// }
// translate sender's Jid to the nicest username we can get
senderName := b.getSenderName(senderJID)
if senderName == "" {
senderName = "Someone" // don't expose telephone number
}
b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
rmsg := config.Message{
UserID: senderJID,
Username: senderName,
Timestamp: messageTime,
Channel: groupJID,
Account: b.Account,
Protocol: b.Protocol,
Extra: make(map[string][]interface{}),
// ParentID: TODO, // TODO handle thread replies // map from Info.QuotedMessageID string
// Event string `json:"event"`
// Gateway string // will be added during message processing
ID: message.Info.Id}
if avatarURL, exists := b.userAvatars[senderJID]; exists {
rmsg.Avatar = avatarURL
}
// Download and unencrypt content
data, err := message.Download()
if err != nil {
b.Log.Errorf("%v", err)
return
}
// Get file extension by mimetype
fileExt, err := mime.ExtensionsByType(message.Type)
if err != nil {
b.Log.Errorf("%v", err)
return
}
filename := fmt.Sprintf("%v%v", message.Info.Id, fileExt[0])
b.Log.Debugf("<= Image downloaded and unencrypted")
// Move file to bridge storage
helper.HandleDownloadData(b.Log, &rmsg, filename, message.Caption, "", &data, b.General)
b.Log.Debugf("<= Image Message is %#v", rmsg)
b.Remote <- rmsg
}
//func (b *Bwhatsapp) HandleVideoMessage(message whatsapp.VideoMessage) { //func (b *Bwhatsapp) HandleVideoMessage(message whatsapp.VideoMessage) {
// fmt.Println(message) // TODO implement // fmt.Println(message) // TODO implement
//} //}

View File

@@ -80,8 +80,33 @@ func (b *Bwhatsapp) getSenderName(senderJid string) string {
// if user is not in phone contacts // if user is not in phone contacts
// it is the most obvious scenario unless you sync your phone contacts with some remote updated source // it is the most obvious scenario unless you sync your phone contacts with some remote updated source
// users can change it in their WhatsApp settings -> profile -> click on Avatar // users can change it in their WhatsApp settings -> profile -> click on Avatar
if sender.Notify != "" {
return sender.Notify return sender.Notify
} }
if sender.Short != "" {
return sender.Short
}
}
// try to reload this contact
_, err := b.conn.Contacts()
if err != nil {
b.Log.Errorf("error on update of contacts: %v", err)
}
if contact, exists := b.conn.Store.Contacts[senderJid]; exists {
// Add it to the user map
b.users[senderJid] = contact
if contact.Name != "" {
return contact.Name
}
// if user is not in phone contacts
// same as above
return contact.Notify
}
return "" return ""
} }

View File

@@ -1,11 +1,14 @@
package bwhatsapp package bwhatsapp
import ( import (
"bytes"
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"mime"
"os" "os"
"path/filepath"
"strings" "strings"
"time" "time"
@@ -64,6 +67,7 @@ func (b *Bwhatsapp) Connect() error {
// https://github.com/Rhymen/go-whatsapp#creating-a-connection // https://github.com/Rhymen/go-whatsapp#creating-a-connection
b.Log.Debugln("Connecting to WhatsApp..") b.Log.Debugln("Connecting to WhatsApp..")
conn, err := whatsapp.NewConn(20 * time.Second) conn, err := whatsapp.NewConn(20 * time.Second)
conn.SetClientVersion(0, 4, 2080)
if err != nil { if err != nil {
return errors.New("failed to connect to WhatsApp: " + err.Error()) return errors.New("failed to connect to WhatsApp: " + err.Error())
} }
@@ -230,6 +234,66 @@ func (b *Bwhatsapp) JoinChannel(channel config.ChannelInfo) error {
return nil return nil
} }
// Post a document message from the bridge to WhatsApp
func (b *Bwhatsapp) PostDocumentMessage(msg config.Message, filetype string) (string, error) {
fi := msg.Extra["file"][0].(config.FileInfo)
// Post document message
message := whatsapp.DocumentMessage{
Info: whatsapp.MessageInfo{
RemoteJid: msg.Channel,
},
Title: fi.Name,
FileName: fi.Name,
Type: filetype,
Content: bytes.NewReader(*fi.Data),
}
b.Log.Debugf("=> Sending %#v", msg)
// create message ID
// TODO follow and act if https://github.com/Rhymen/go-whatsapp/issues/101 implemented
idBytes := make([]byte, 10)
if _, err := rand.Read(idBytes); err != nil {
b.Log.Warn(err.Error())
}
message.Info.Id = strings.ToUpper(hex.EncodeToString(idBytes))
_, err := b.conn.Send(message)
return message.Info.Id, err
}
// Post an image message from the bridge to WhatsApp
// Handle, for sure image/jpeg, image/png and image/gif MIME types
func (b *Bwhatsapp) PostImageMessage(msg config.Message, filetype string) (string, error) {
fi := msg.Extra["file"][0].(config.FileInfo)
// Post image message
message := whatsapp.ImageMessage{
Info: whatsapp.MessageInfo{
RemoteJid: msg.Channel,
},
Type: filetype,
Caption: msg.Username + fi.Comment,
Content: bytes.NewReader(*fi.Data),
}
b.Log.Debugf("=> Sending %#v", msg)
// create message ID
// TODO follow and act if https://github.com/Rhymen/go-whatsapp/issues/101 implemented
idBytes := make([]byte, 10)
if _, err := rand.Read(idBytes); err != nil {
b.Log.Warn(err.Error())
}
message.Info.Id = strings.ToUpper(hex.EncodeToString(idBytes))
_, err := b.conn.Send(message)
return message.Info.Id, err
}
// Send a message from the bridge to WhatsApp // Send a message from the bridge to WhatsApp
// Required implementation of the Bridger interface // Required implementation of the Bridger interface
// https://github.com/42wim/matterbridge/blob/2cfd880cdb0df29771bf8f31df8d990ab897889d/bridge/bridge.go#L11-L16 // https://github.com/42wim/matterbridge/blob/2cfd880cdb0df29771bf8f31df8d990ab897889d/bridge/bridge.go#L11-L16
@@ -259,18 +323,25 @@ func (b *Bwhatsapp) Send(msg config.Message) (string, error) {
// TODO handle edit as a message reply with updated text // TODO handle edit as a message reply with updated text
} }
//// TODO Handle Upload a file // Handle Upload a file
//if msg.Extra != nil { if msg.Extra["file"] != nil {
// for _, rmsg := range helper.HandleExtra(&msg, b.General) { fi := msg.Extra["file"][0].(config.FileInfo)
// b.c.SendMessage(roomID, rmsg.Username+rmsg.Text) filetype := mime.TypeByExtension(filepath.Ext(fi.Name))
// }
// if len(msg.Extra["file"]) > 0 { b.Log.Debugf("Extra file is %#v", filetype)
// return b.handleUploadFile(&msg, roomID)
// } // TODO: add different types
//} // TODO: add webp conversion
switch filetype {
case "image/jpeg", "image/png", "image/gif":
return b.PostImageMessage(msg, filetype)
default:
return b.PostDocumentMessage(msg, filetype)
}
}
// Post text message // Post text message
text := whatsapp.TextMessage{ message := whatsapp.TextMessage{
Info: whatsapp.MessageInfo{ Info: whatsapp.MessageInfo{
RemoteJid: msg.Channel, // which equals to group id RemoteJid: msg.Channel, // which equals to group id
}, },
@@ -281,15 +352,14 @@ func (b *Bwhatsapp) Send(msg config.Message) (string, error) {
// create message ID // create message ID
// TODO follow and act if https://github.com/Rhymen/go-whatsapp/issues/101 implemented // TODO follow and act if https://github.com/Rhymen/go-whatsapp/issues/101 implemented
bytes := make([]byte, 10) idBytes := make([]byte, 10)
if _, err := rand.Read(bytes); err != nil { if _, err := rand.Read(idBytes); err != nil {
b.Log.Warn(err.Error()) b.Log.Warn(err.Error())
} }
text.Info.Id = strings.ToUpper(hex.EncodeToString(bytes)) message.Info.Id = strings.ToUpper(hex.EncodeToString(idBytes))
_, err := b.conn.Send(message)
_, err := b.conn.Send(text) return message.Info.Id, err
return text.Info.Id, err
} }
// TODO do we want that? to allow login with QR code from a bridged channel? https://github.com/tulir/mautrix-whatsapp/blob/513eb18e2d59bada0dd515ee1abaaf38a3bfe3d5/commands.go#L76 // TODO do we want that? to allow login with QR code from a bridged channel? https://github.com/tulir/mautrix-whatsapp/blob/513eb18e2d59bada0dd515ee1abaaf38a3bfe3d5/commands.go#L76

34
bridge/xmpp/handler.go Normal file
View File

@@ -0,0 +1,34 @@
package bxmpp
import (
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper"
"github.com/matterbridge/go-xmpp"
)
// handleDownloadAvatar downloads the avatar of userid from channel
// sends a EVENT_AVATAR_DOWNLOAD message to the gateway if successful.
// logs an error message if it fails
func (b *Bxmpp) handleDownloadAvatar(avatar xmpp.AvatarData) {
rmsg := config.Message{
Username: "system",
Text: "avatar",
Channel: b.parseChannel(avatar.From),
Account: b.Account,
UserID: avatar.From,
Event: config.EventAvatarDownload,
Extra: make(map[string][]interface{}),
}
if _, ok := b.avatarMap[avatar.From]; !ok {
b.Log.Debugf("Avatar.From: %s", avatar.From)
err := helper.HandleDownloadSize(b.Log, &rmsg, avatar.From+".png", int64(len(avatar.Data)), b.General)
if err != nil {
b.Log.Error(err)
return
}
helper.HandleDownloadData(b.Log, &rmsg, avatar.From+".png", rmsg.Text, "", &avatar.Data, b.General)
b.Log.Debugf("Avatar download complete")
b.Remote <- rmsg
}
}

30
bridge/xmpp/helpers.go Normal file
View File

@@ -0,0 +1,30 @@
package bxmpp
import (
"regexp"
"github.com/42wim/matterbridge/bridge/config"
)
var pathRegex = regexp.MustCompile("[^a-zA-Z0-9]+")
// GetAvatar constructs a URL for a given user-avatar if it is available in the cache.
func getAvatar(av map[string]string, userid string, general *config.Protocol) string {
if hash, ok := av[userid]; ok {
// NOTE: This does not happen in bridge/helper/helper.go but messes up XMPP
id := pathRegex.ReplaceAllString(userid, "_")
return general.MediaServerDownload + "/" + hash + "/" + id + ".png"
}
return ""
}
func (b *Bxmpp) cacheAvatar(msg *config.Message) string {
fi := msg.Extra["file"][0].(config.FileInfo)
/* if we have a sha we have successfully uploaded the file to the media server,
so we can now cache the sha */
if fi.SHA != "" {
b.Log.Debugf("Added %s to %s in avatarMap", fi.SHA, msg.UserID)
b.avatarMap[msg.UserID] = fi.SHA
}
return ""
}

View File

@@ -23,12 +23,17 @@ type Bxmpp struct {
xmppMap map[string]string xmppMap map[string]string
connected bool connected bool
sync.RWMutex sync.RWMutex
avatarAvailability map[string]bool
avatarMap map[string]string
} }
func New(cfg *bridge.Config) bridge.Bridger { func New(cfg *bridge.Config) bridge.Bridger {
return &Bxmpp{ return &Bxmpp{
Config: cfg, Config: cfg,
xmppMap: make(map[string]string), xmppMap: make(map[string]string),
avatarAvailability: make(map[string]bool),
avatarMap: make(map[string]string),
} }
} }
@@ -67,8 +72,19 @@ func (b *Bxmpp) Send(msg config.Message) (string, error) {
if msg.Event == config.EventMsgDelete { if msg.Event == config.EventMsgDelete {
return "", nil return "", nil
} }
b.Log.Debugf("=> Receiving %#v", msg) b.Log.Debugf("=> Receiving %#v", msg)
if msg.Event == config.EventAvatarDownload {
return b.cacheAvatar(&msg), nil
}
// Make a action /me of the message, prepend the username with it.
// https://xmpp.org/extensions/xep-0245.html
if msg.Event == config.EventUserAction {
msg.Username = "/me " + msg.Username
}
// Upload a file (in XMPP case send the upload URL because XMPP has no native upload support). // Upload a file (in XMPP case send the upload URL because XMPP has no native upload support).
if msg.Extra != nil { if msg.Extra != nil {
for _, rmsg := range helper.HandleExtra(&msg, b.General) { for _, rmsg := range helper.HandleExtra(&msg, b.General) {
@@ -107,10 +123,16 @@ func (b *Bxmpp) Send(msg config.Message) (string, error) {
} }
func (b *Bxmpp) createXMPP() error { func (b *Bxmpp) createXMPP() error {
if !strings.Contains(b.GetString("Jid"), "@") {
return fmt.Errorf("the Jid %s doesn't contain an @", b.GetString("Jid"))
}
tc := &tls.Config{ tc := &tls.Config{
ServerName: strings.Split(b.GetString("Jid"), "@")[1], ServerName: strings.Split(b.GetString("Jid"), "@")[1],
InsecureSkipVerify: b.GetBool("SkipTLSVerify"), // nolint: gosec InsecureSkipVerify: b.GetBool("SkipTLSVerify"), // nolint: gosec
} }
xmpp.DebugWriter = b.Log.Writer()
options := xmpp.Options{ options := xmpp.Options{
Host: b.GetString("Server"), Host: b.GetString("Server"),
User: b.GetString("Jid"), User: b.GetString("Jid"),
@@ -119,7 +141,6 @@ func (b *Bxmpp) createXMPP() error {
StartTLS: true, StartTLS: true,
TLSConfig: tc, TLSConfig: tc,
Debug: b.GetBool("debug"), Debug: b.GetBool("debug"),
Logger: b.Log.Writer(),
Session: true, Session: true,
Status: "", Status: "",
StatusMessage: "", StatusMessage: "",
@@ -225,6 +246,16 @@ func (b *Bxmpp) handleXMPP() error {
event = config.EventTopicChange event = config.EventTopicChange
} }
available, sok := b.avatarAvailability[v.Remote]
avatar := ""
if !sok {
b.Log.Debugf("Requesting avatar data")
b.avatarAvailability[v.Remote] = false
b.xc.AvatarRequestData(v.Remote)
} else if available {
avatar = getAvatar(b.avatarMap, v.Remote, b.General)
}
msgID := v.ID msgID := v.ID
if v.ReplaceID != "" { if v.ReplaceID != "" {
msgID = v.ReplaceID msgID = v.ReplaceID
@@ -234,6 +265,7 @@ func (b *Bxmpp) handleXMPP() error {
Text: v.Text, Text: v.Text,
Channel: b.parseChannel(v.Remote), Channel: b.parseChannel(v.Remote),
Account: b.Account, Account: b.Account,
Avatar: avatar,
UserID: v.Remote, UserID: v.Remote,
ID: msgID, ID: msgID,
Event: event, Event: event,
@@ -250,6 +282,10 @@ func (b *Bxmpp) handleXMPP() error {
b.Log.Debugf("<= Message is %#v", rmsg) b.Log.Debugf("<= Message is %#v", rmsg)
b.Remote <- rmsg b.Remote <- rmsg
} }
case xmpp.AvatarData:
b.handleDownloadAvatar(v)
b.avatarAvailability[v.From] = true
b.Log.Debugf("Avatar for %s is now available", v.From)
case xmpp.Presence: case xmpp.Presence:
// Do nothing. // Do nothing.
} }

View File

@@ -1,15 +1,289 @@
# dev # v1.18.1
## New features
- telegram: Support Telegram animated stickers (tgs) format (#1173). See https://github.com/42wim/matterbridge/wiki/Settings#mediaConverttgs for more info
## Enhancements
- matrix: Remove HTML formatting for push messages (#1188) (#1189)
- mattermost: Use mattermost v5 module (#1192)
## Bugfix
- whatsapp: Handle panic in whatsapp. Fixes #1180 (#1184)
- nctalk: Fix Nextcloud Talk connection failure (#1179)
- matrix: Sleep when ratelimited on joins (matrix). Fixes #1201 (#1206)
This release couldn't exist without the following contributors:
@42wim, @BenWiederhake, @Dellle, @gary-kim
# v1.18.0
## New features
- nctalk: new protocol added. Add Nextcloud Talk support #1167
- general: Add an option to log into a file rather than stdout (#1168)
- api: Add websocket to API (#970)
## Enhancements
- telegram: Fix MarkdownV2 support in Telegram (#1169)
- whatsapp: Reload user information when a new contact is detected (whatsapp) (#1160)
- api: Add sane RemoteNickFormat default for API (#1157)
- irc: Skip gIRC built-in rate limiting (irc) (#1164)
- irc: Only colour IRC nicks if there is one. (#1161)
- docker: Combine runs to one layer (#1151)
## Bugfix
- general: Update dependencies for 1.18.0 release (#1175)
Discord users are encouraged to upgrade, this release works with the move to the discord.com domain.
This release couldn't exist without the following contributors:
@42wim, @jlu5, @qaisjp, @TheHolyRoger, @SuperSandro2000, @gary-kim, @z3bra, @greenx, @haykam821, @nathanaelhoun
# v1.17.5
## Enhancements
- irc: Add StripMarkdown option (irc). (#1145)
- general: Increase debug logging with function,file and linenumber (#1147)
- general: Update Dockerfile so inotify works (#1148)
- matrix: Add an option to disable sending HTML to matrix. Fixes #1022 (#1135)
- xmpp: Implement xep-0245 (xmpp). Closes #1137 (#1144)
## Bugfix
- discord: Fix #1120: replaceAction "_" crash (discord) (#1121)
- discord: Fix #1049: missing space before embeds (discord) (#1124)
- discord: Fix webhook EventUserAction messages being skipped (discord) (#1133)
- matrix: Avoid creating invalid url when the user doesn't have an avatar (matrix) (#1130)
- msteams: Ignore non-user messages (msteams). Fixes #1141 (#1149)
- slack: Do not use webhooks when token is configured (slack) (fixes #1123) (#1134)
- telegram: Fix forward from hidden users (telegram). Closes #1131 (#1143)
- xmpp: Prevent re-requesting avatar data (xmpp) (#1117)
This release couldn't exist without the following contributors:
@qaisjp, @xnaas, @42wim, @Polynomdivision, @tfve
# v1.17.4
## Bugfix
- general: Lowercase account names. Fixes #1108 (#1110)
- msteams: Remove panics and retry polling on failure (msteams). Fixes #1104 (#1105
- whatsapp: Update Rhymen/go-whatsapp. Fixes #1107 (#1109) (make whatsapp working again)
- discord: Add an ID cache (discord). Fixes #1106 (#1111) (fix delete/edits with webhooks)
# v1.17.3
## Enhancements
- xmpp: Implement User Avatar spoofing of XMPP users #1090
- rocketchat: Relay Joins/Topic changes in RocketChat bridge (#1085)
- irc: Add JoinDelay option (irc). Fixes #1084 (#1098)
- slack: Clip too long messages on 3000 length (slack). Fixes #1081 (#1102)
## Bugfix
- general: Fix the behavior of ShowTopicChange and SyncTopic (#1086)
- slack: Prevent image/message looping (slack). Fixes #1088 (#1096)
- whatsapp: Ignore non-critical errors (whatsapp). Fixes #1094 (#1100)
- irc: Add extra space before colon in attachments (irc). Fixes #1089 (#1101)
This release couldn't exist without the following contributors:
@42wim, @ldruschk, @qaisjp, @Polynomdivision
# v1.17.2
## Enhancements
- slack: Update vendor slack-go/slack (#1068)
- general: Update vendor d5/tengo (#1066)
- general: Clarify terminology used in mapping group chat IDs to channels in config (#1079)
## Bugfix
- whatsapp: Update Rhymen/go-whatsapp vendor and whatsapp version (#1078). Fixes Media upload #1074
- whatsapp: Reset start timestamp on reconnect (whatsapp). Fixes #1059 (#1064)
This release couldn't exist without the following contributors:
@42wim, @jheiselman
# v1.17.1
## Enhancements
- docker: Remove build dependencies from final image (multistage build) #1057
## Bugfix
- general: Don't transmit typing events from ourselves #1056
- general: Add support for build tags #1054
- discord: Strip extra info from emotes (discord) #1052
- msteams: fix macos build: Update vendor yaegashi/msgraph.go to v0.1.2 #1036
- whatsapp: Update client version whatsapp. Fixes #1061 #1062
This release couldn't exist without the following contributors:
@awigen, @qaisjp, @42wim
# v1.17.0
## New features
- msteams: new protocol added. Add initial Microsoft Teams support #967
See https://github.com/42wim/matterbridge/wiki/MS-Teams-setup for a complete walkthrough
- discord: Add ability to procure avatars from the destination bridge #1000
- matrix: Add support for avatars from matrix. #1007
- general: support JSON and YAML config formats #1045
## Enhancements
- discord: Check only bridged channels for PermManageWebhooks #1001
- irc: Be less lossy when throttling IRC messages #1004
- keybase: updated library #1002, #1019
- matrix: Rebase gomatrix vendor with upstream #1006
- slack: Use upstream slack-go/slack again #1018
- slack: Ignore ConnectingEvent #1041
- slack: use blocks not attachments #1048
- sshchat: Update vendor shazow/ssh-chat #1029
- telegram: added markdownv2 mode for telegram #1037
- whatsapp: Implement basic reconnect (whatsapp). Fixes #987 #1003
## Bugfix
- discord: Fix webhook permission checks sometimes failing #1043
- discord: Fix #1027: warning when handling inbound webhooks #1044
- discord: Fix duplicate separator on empty description/url (discord) #1035
- matrix: Fix issue with underscores in links #999
- slack: Fix #1039: messages sent to Slack being synced back #1046
- telegram: Make avatars download work with mediaserverdownload (telegram). Fixes #920
This release couldn't exist without the following contributors:
@qaisjp, @jakubgs, @burner1024, @notpushkin, @MartijnBraam, @42wim
# v1.16.5
- Fix version bump
# v1.16.4
## New features
- whatsapp: Add support for WhatsApp media (jpeg/png/gif) bridging (#974)
- telegram: Add QuoteLengthLimit option (telegram) fixes #963 (#985)
- telegram: Add DisableWebPagePreview option (telegram). Closes #980 (#994)
## Enhancements
- general: update dependencies
- tengo: update to tengo v2
- general: Add Docker Compose configuration (#990)
## Bugfix
- general: Fail with message instead of panic. #988 (#991)
- telegram: Add extra mimetypes to docker image. Fixes #969
- discord: Fix channel ID problem with multiple gateways (discord). Fixes #953 (#977)
- discord: Show file comment in webhook if normal message is empty (discord). Fixes #962 (#995)
- matrix: Fix parsing issues - Disable smartypants in markdown parser. Fixes #989, #983 (#993)
- sshchat: Fix duplicated messages (sshchat). Fixes #950 (#996)
This release couldn't exist without the following contributors:
@jwflory, @42wim, @pbek, @Humorhenker, @c0ncord2, @glazzara
# v1.16.3
## Bugfix
- slack: Fix issues with ratelimiting #959
- mattermost: Fix bug when using webhookURL and login/token together #960
# v1.16.2
## New features
- keybase: Add support for receiving attachments (keybase) (#923)
## Enhancements
- general: Switch to new emoji library kyokomi/emoji (#948)
- general: Update markdown parsing library to github.com/gomarkdown/markdown (#944)
- ssh-chat: Update shazow/ssh-chat dependency (#947)
## Bugfix
- slack: Fix issues with the slack block kit API #937 (#943).
This release couldn't exist without the following contributors:
@42wim, @bmpickford, @goncalor
# v1.16.1
## New features
* rocketchat: add token support #892
* matrix: Add support for uploading application/x and audio/x (matrix). #929
## Enhancements
* general: Do configuration validation on start-up. Fixes #888
* general: updated vendored libraries (discord/whatsapp) #932
* discord: user typing messages #914
* slack: Convert slack bold/strike to correct markdown (slack). Fixes #918
## Bugfix
* discord: fix Failed to fetch information for members message. #894
* discord: remove obsolete file upload links (discord). #931
* slack: suppress unhandled HelloEvent message #913
* mattermost: Fix panic on WebhookURL only setting (mattermost). #917
* matrix: fix corrupted links between slack and matrix #924
This release couldn't exist without the following contributors:
@qaisjp, @hramrach, @42wim
# v1.16.0
## New features
* keybase: new protocol added. Add initial Keybase Chat support #877 Thanks to @hyperobject
* discord: Support webhook files in discord #872
## Enhancements
* general: update dependencies
## Bugfix
* discord: Underscores from Discord don't arrive correctly #864
* xmpp: Fix possible panic at startup of the XMPP bridge #869
* mattermost: Make getChannelIdTeam behave like GetChannelId for groups (mattermost) #873
This release couldn't exist without the following contributors:
@hyperobject, @42wim, @bucko909, @MOZGIII
# v1.15.1 # v1.15.1
## New features
* discord: Support webhook message deletions (discord) (#853)
## Enhancements ## Enhancements
* discord: Support bulk deletions #851 * discord: Support bulk deletions #851
* discord: Support channels in categories #863 (use category/channel. See matterbridge.toml.sample for more info) * discord: Support channels in categories #863 (use category/channel. See matterbridge.toml.sample for more info)
* mattermost: Add an option to skip the Mattermost server version check #849 * mattermost: Add an option to skip the Mattermost server version check #849
## Bugfix ## Bugfix
* xmpp: fix segfault when disconnected/reconnected #856 * xmpp: fix segfault when disconnected/reconnected #856
* telegram: fix panic in handleEntities #858 * telegram: fix panic in handleEntities #858
This release couldn't exist without the following contributors:
@42wim, @qaisjp, @joohoi
# v1.15.0 # v1.15.0
## New features ## New features
* Add scripting (tengo) support for every outgoing message (#806) * Add scripting (tengo) support for every outgoing message (#806)
@@ -17,21 +291,21 @@
https://github.com/42wim/matterbridge/wiki/Settings#outmessage for more information https://github.com/42wim/matterbridge/wiki/Settings#outmessage for more information
* Add tengo support to RemoteNickFormat (#793) * Add tengo support to RemoteNickFormat (#793)
See https://github.com/42wim/matterbridge/wiki/Settings#remotenickformat-2 See https://github.com/42wim/matterbridge/wiki/Settings#remotenickformat-2
* Deprecated `Message` under `[tengo]` to `InMessage` * Deprecated `Message` under `[tengo]` to `InMessage`
## Enhancements ## Enhancements
* general: Forward only user-typing messages if supported by protocol (#832) * general: Forward only user-typing messages if supported by protocol (#832)
* general: updated wiki with all possible settings: https://github.com/42wim/matterbridge/wiki/Settings * general: updated wiki with all possible settings: https://github.com/42wim/matterbridge/wiki/Settings
* tengo: Add msg event to tengo * tengo: Add msg event to tengo
* xmpp: Verify TLS against JID domain, not the host. (xmpp) (#834) * xmpp: Verify TLS against JID domain, not the host. (xmpp) (#834)
* xmpp: Allow messages with timestamp (xmpp). Fixes #835 (#847) * xmpp: Allow messages with timestamp (xmpp). Fixes #835 (#847)
* irc: Add verbose IRC joins/parts (ident@host) (#805) * irc: Add verbose IRC joins/parts (ident@host) (#805)
See https://github.com/42wim/matterbridge/wiki/Settings#verbosejoinpart See https://github.com/42wim/matterbridge/wiki/Settings#verbosejoinpart
* rocketchat: Add useraction support (rocketchat). Closes #772 (#794) * rocketchat: Add useraction support (rocketchat). Closes #772 (#794)
## Bugfix ## Bugfix
* slack: Fix regression in autojoining with legacy tokens (slack). Fixes #651 (#848) * slack: Fix regression in autojoining with legacy tokens (slack). Fixes #651 (#848)
* xmpp: Revert xmpp to orig behaviour. Closes #844 * xmpp: Revert xmpp to orig behaviour. Closes #844
* whatsapp: Update github.com/Rhymen/go-whatsapp vendor. Fixes #843 * whatsapp: Update github.com/Rhymen/go-whatsapp vendor. Fixes #843
* mattermost: Update channels of all teams (mattermost) * mattermost: Update channels of all teams (mattermost)

View File

@@ -1,30 +0,0 @@
#!/usr/bin/env bash
set -u -e -x -o pipefail
go version | grep go1.12 || exit
VERSION=$(git describe --tags)
mkdir ci/binaries
GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-windows-amd64.exe
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-linux-amd64
GOOS=linux GOARCH=arm go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-linux-arm
GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-darwin-amd64
cd ci
cat > deploy.json <<EOF
{
"package": {
"name": "Matterbridge",
"repo": "nightly",
"subject": "42wim"
},
"version": {
"name": "$VERSION"
},
"files":
[
{"includePattern": "ci/binaries/(.*)", "uploadPattern":"\$1"}
],
"publish": true
}
EOF

View File

@@ -1,17 +0,0 @@
#!/usr/bin/env bash
set -u -e -x -o pipefail
if [[ -n "${GOLANGCI_VERSION-}" ]]; then
# Retrieve the golangci-lint linter binary.
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b ${GOPATH}/bin ${GOLANGCI_VERSION}
fi
# Run the linter.
golangci-lint run
if [[ "${GO111MODULE-off}" == "on" ]]; then
# If Go modules are active then check that dependencies are correctly maintained.
go mod tidy
go mod vendor
git diff --exit-code --quiet || (echo "Please run 'go mod tidy' to clean up the 'go.mod' and 'go.sum' files."; false)
fi

View File

@@ -1,17 +0,0 @@
#!/usr/bin/env bash
set -u -e -x -o pipefail
if [[ -n "${REPORT_COVERAGE+cover}" ]]; then
# Retrieve and prepare CodeClimate's test coverage reporter.
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
chmod +x ./cc-test-reporter
./cc-test-reporter before-build
fi
# Run all the tests with the race detector and generate coverage.
go test -v -race -coverprofile c.out ./...
if [[ -n "${REPORT_COVERAGE+cover}" && "${TRAVIS_SECURE_ENV_VARS}" == "true" ]]; then
# Upload test coverage to CodeClimate.
./cc-test-reporter after-build
fi

View File

@@ -0,0 +1,10 @@
text := import("text")
// if we're not sending to a discord bridge,
// then convert custom emoji tags into url's
if (inProtocol == "discord" && outProtocol != "discord") {
rePNG := text.re_compile(`<:.*?:([0-9]+)>`)
msgText=rePNG.replace(msgText,"https://cdn.discordapp.com/emojis/$1.png")
reGIF := text.re_compile(`<a:.*?:([0-9]+)>`)
msgText=reGIF.replace(msgText,"https://cdn.discordapp.com/emojis/$1.gif")
}

View File

@@ -0,0 +1,14 @@
// See https://github.com/42wim/matterbridge/issues/881
// Generates a colored nick for each msgUsername, with example to filter specific codes
text := import("text")
fmt := import("fmt")
if outProtocol == "irc" {
// generate a color for a nick, make sure it isn't 0 or 15
colorCode := len(msgUsername)+bytes(msgUsername)[0]%14 + 2
// example if we want to use colorCode 3 when we have calculated colorcode 14
if colorCode == 14 {
colorCode = 3
}
msgUsername=fmt.sprintf("\x03%02d%s\x0F", colorCode, msgUsername)
}

11
gateway/bridgemap/api.go Normal file
View File

@@ -0,0 +1,11 @@
// +build !noapi
package bridgemap
import (
"github.com/42wim/matterbridge/bridge/api"
)
func init() {
FullMap["api"] = api.New
}

View File

@@ -0,0 +1,12 @@
// +build !nodiscord
package bridgemap
import (
bdiscord "github.com/42wim/matterbridge/bridge/discord"
)
func init() {
FullMap["discord"] = bdiscord.New
UserTypingSupport["discord"] = struct{}{}
}

View File

@@ -0,0 +1,11 @@
// +build !nogitter
package bridgemap
import (
bgitter "github.com/42wim/matterbridge/bridge/gitter"
)
func init() {
FullMap["gitter"] = bgitter.New
}

11
gateway/bridgemap/birc.go Normal file
View File

@@ -0,0 +1,11 @@
// +build !noirc
package bridgemap
import (
birc "github.com/42wim/matterbridge/bridge/irc"
)
func init() {
FullMap["irc"] = birc.New
}

View File

@@ -0,0 +1,11 @@
// +build !nokeybase
package bridgemap
import (
bkeybase "github.com/42wim/matterbridge/bridge/keybase"
)
func init() {
FullMap["keybase"] = bkeybase.New
}

View File

@@ -0,0 +1,11 @@
// +build !nomatrix
package bridgemap
import (
bmatrix "github.com/42wim/matterbridge/bridge/matrix"
)
func init() {
FullMap["matrix"] = bmatrix.New
}

View File

@@ -0,0 +1,11 @@
// +build !nomattermost
package bridgemap
import (
bmattermost "github.com/42wim/matterbridge/bridge/mattermost"
)
func init() {
FullMap["mattermost"] = bmattermost.New
}

View File

@@ -0,0 +1,11 @@
// +build !nomsteams
package bridgemap
import (
bmsteams "github.com/42wim/matterbridge/bridge/msteams"
)
func init() {
FullMap["msteams"] = bmsteams.New
}

View File

@@ -0,0 +1,11 @@
// +build !nonctalk
package bridgemap
import (
btalk "github.com/42wim/matterbridge/bridge/nctalk"
)
func init() {
FullMap["nctalk"] = btalk.New
}

View File

@@ -2,42 +2,9 @@ package bridgemap
import ( import (
"github.com/42wim/matterbridge/bridge" "github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/api"
bdiscord "github.com/42wim/matterbridge/bridge/discord"
bgitter "github.com/42wim/matterbridge/bridge/gitter"
birc "github.com/42wim/matterbridge/bridge/irc"
bmatrix "github.com/42wim/matterbridge/bridge/matrix"
bmattermost "github.com/42wim/matterbridge/bridge/mattermost"
brocketchat "github.com/42wim/matterbridge/bridge/rocketchat"
bslack "github.com/42wim/matterbridge/bridge/slack"
bsshchat "github.com/42wim/matterbridge/bridge/sshchat"
bsteam "github.com/42wim/matterbridge/bridge/steam"
btelegram "github.com/42wim/matterbridge/bridge/telegram"
bwhatsapp "github.com/42wim/matterbridge/bridge/whatsapp"
bxmpp "github.com/42wim/matterbridge/bridge/xmpp"
bzulip "github.com/42wim/matterbridge/bridge/zulip"
) )
var ( var (
FullMap = map[string]bridge.Factory{ FullMap = map[string]bridge.Factory{}
"api": api.New, UserTypingSupport = map[string]struct{}{}
"discord": bdiscord.New,
"gitter": bgitter.New,
"irc": birc.New,
"mattermost": bmattermost.New,
"matrix": bmatrix.New,
"rocketchat": brocketchat.New,
"slack-legacy": bslack.NewLegacy,
"slack": bslack.New,
"sshchat": bsshchat.New,
"steam": bsteam.New,
"telegram": btelegram.New,
"whatsapp": bwhatsapp.New,
"xmpp": bxmpp.New,
"zulip": bzulip.New,
}
UserTypingSupport = map[string]struct{}{
"slack": {},
}
) )

View File

@@ -0,0 +1,11 @@
// +build !norocketchat
package bridgemap
import (
brocketchat "github.com/42wim/matterbridge/bridge/rocketchat"
)
func init() {
FullMap["rocketchat"] = brocketchat.New
}

View File

@@ -0,0 +1,13 @@
// +build !noslack
package bridgemap
import (
bslack "github.com/42wim/matterbridge/bridge/slack"
)
func init() {
FullMap["slack-legacy"] = bslack.NewLegacy
FullMap["slack"] = bslack.New
UserTypingSupport["slack"] = struct{}{}
}

View File

@@ -0,0 +1,11 @@
// +build !nosshchat
package bridgemap
import (
bsshchat "github.com/42wim/matterbridge/bridge/sshchat"
)
func init() {
FullMap["sshchat"] = bsshchat.New
}

View File

@@ -0,0 +1,11 @@
// +build !nosteam
package bridgemap
import (
bsteam "github.com/42wim/matterbridge/bridge/steam"
)
func init() {
FullMap["steam"] = bsteam.New
}

View File

@@ -0,0 +1,11 @@
// +build !notelegram
package bridgemap
import (
btelegram "github.com/42wim/matterbridge/bridge/telegram"
)
func init() {
FullMap["telegram"] = btelegram.New
}

View File

@@ -0,0 +1,11 @@
// +build !nowhatsapp
package bridgemap
import (
bwhatsapp "github.com/42wim/matterbridge/bridge/whatsapp"
)
func init() {
FullMap["whatsapp"] = bwhatsapp.New
}

View File

@@ -0,0 +1,11 @@
// +build !noxmpp
package bridgemap
import (
bxmpp "github.com/42wim/matterbridge/bridge/xmpp"
)
func init() {
FullMap["xmpp"] = bxmpp.New
}

View File

@@ -0,0 +1,11 @@
// +build !nozulip
package bridgemap
import (
bzulip "github.com/42wim/matterbridge/bridge/zulip"
)
func init() {
FullMap["zulip"] = bzulip.New
}

View File

@@ -10,10 +10,10 @@ import (
"github.com/42wim/matterbridge/bridge" "github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/internal" "github.com/42wim/matterbridge/internal"
"github.com/d5/tengo/script" "github.com/d5/tengo/v2"
"github.com/d5/tengo/stdlib" "github.com/d5/tengo/v2/stdlib"
lru "github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
"github.com/peterhellberg/emojilib" "github.com/matterbridge/emoji"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@@ -85,6 +85,7 @@ func (gw *Gateway) FindCanonicalMsgID(protocol string, mID string) string {
func (gw *Gateway) AddBridge(cfg *config.Bridge) error { func (gw *Gateway) AddBridge(cfg *config.Bridge) error {
br := gw.Router.getBridge(cfg.Account) br := gw.Router.getBridge(cfg.Account)
if br == nil { if br == nil {
gw.checkConfig(cfg)
br = bridge.New(cfg) br = bridge.New(cfg)
br.Config = gw.Router.Config br.Config = gw.Router.Config
br.General = &gw.BridgeValues().General br.General = &gw.BridgeValues().General
@@ -104,6 +105,19 @@ func (gw *Gateway) AddBridge(cfg *config.Bridge) error {
return nil return nil
} }
func (gw *Gateway) checkConfig(cfg *config.Bridge) {
match := false
for _, key := range gw.Router.Config.Viper().AllKeys() {
if strings.HasPrefix(key, strings.ToLower(cfg.Account)) {
match = true
break
}
}
if !match {
gw.logger.Fatalf("Account %s defined in gateway %s but no configuration found, exiting.", cfg.Account, gw.Name)
}
}
// AddConfig associates a new configuration with the gateway object. // AddConfig associates a new configuration with the gateway object.
func (gw *Gateway) AddConfig(cfg *config.Gateway) error { func (gw *Gateway) AddConfig(cfg *config.Gateway) error {
gw.Name = cfg.Name gw.Name = cfg.Name
@@ -292,8 +306,6 @@ func (gw *Gateway) ignoreMessage(msg *config.Message) bool {
} }
func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) string { func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) string {
br := gw.Bridges[msg.Account]
msg.Protocol = br.Protocol
if dest.GetBool("StripNick") { if dest.GetBool("StripNick") {
re := regexp.MustCompile("[^a-zA-Z0-9]+") re := regexp.MustCompile("[^a-zA-Z0-9]+")
msg.Username = re.ReplaceAllString(msg.Username, "") msg.Username = re.ReplaceAllString(msg.Username, "")
@@ -301,6 +313,7 @@ func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) stri
nick := dest.GetString("RemoteNickFormat") nick := dest.GetString("RemoteNickFormat")
// loop to replace nicks // loop to replace nicks
br := gw.Bridges[msg.Account]
for _, outer := range br.GetStringSlice2D("ReplaceNicks") { for _, outer := range br.GetStringSlice2D("ReplaceNicks") {
search := outer[0] search := outer[0]
replace := outer[1] replace := outer[1]
@@ -358,7 +371,7 @@ func (gw *Gateway) modifyMessage(msg *config.Message) {
} }
// replace :emoji: to unicode // replace :emoji: to unicode
msg.Text = emojilib.Replace(msg.Text) msg.Text = emoji.Sprint(msg.Text)
br := gw.Bridges[msg.Account] br := gw.Bridges[msg.Account]
// loop to replace messages // loop to replace messages
@@ -500,7 +513,7 @@ func modifyMessageTengo(filename string, msg *config.Message) error {
if err != nil { if err != nil {
return err return err
} }
s := script.New(res) s := tengo.NewScript(res)
s.SetImports(stdlib.GetModuleMap(stdlib.AllModuleNames()...)) s.SetImports(stdlib.GetModuleMap(stdlib.AllModuleNames()...))
_ = s.Add("msgText", msg.Text) _ = s.Add("msgText", msg.Text)
_ = s.Add("msgUsername", msg.Username) _ = s.Add("msgUsername", msg.Username)
@@ -527,7 +540,7 @@ func (gw *Gateway) modifyUsernameTengo(msg *config.Message, br *bridge.Bridge) (
if err != nil { if err != nil {
return "", err return "", err
} }
s := script.New(res) s := tengo.NewScript(res)
s.SetImports(stdlib.GetModuleMap(stdlib.AllModuleNames()...)) s.SetImports(stdlib.GetModuleMap(stdlib.AllModuleNames()...))
_ = s.Add("result", "") _ = s.Add("result", "")
_ = s.Add("msgText", msg.Text) _ = s.Add("msgText", msg.Text)
@@ -566,7 +579,7 @@ func (gw *Gateway) modifySendMessageTengo(origmsg *config.Message, msg *config.M
return err return err
} }
} }
s := script.New(res) s := tengo.NewScript(res)
s.SetImports(stdlib.GetModuleMap(stdlib.AllModuleNames()...)) s.SetImports(stdlib.GetModuleMap(stdlib.AllModuleNames()...))
_ = s.Add("inAccount", origmsg.Account) _ = s.Add("inAccount", origmsg.Account)
_ = s.Add("inProtocol", origmsg.Protocol) _ = s.Add("inProtocol", origmsg.Protocol)

View File

@@ -15,10 +15,15 @@ import (
var testconfig = []byte(` var testconfig = []byte(`
[irc.freenode] [irc.freenode]
server=""
[mattermost.test] [mattermost.test]
server=""
[gitter.42wim] [gitter.42wim]
server=""
[discord.test] [discord.test]
server=""
[slack.test] [slack.test]
server=""
[[gateway]] [[gateway]]
name = "bridge1" name = "bridge1"
@@ -44,10 +49,15 @@ var testconfig = []byte(`
var testconfig2 = []byte(` var testconfig2 = []byte(`
[irc.freenode] [irc.freenode]
server=""
[mattermost.test] [mattermost.test]
server=""
[gitter.42wim] [gitter.42wim]
server=""
[discord.test] [discord.test]
server=""
[slack.test] [slack.test]
server=""
[[gateway]] [[gateway]]
name = "bridge1" name = "bridge1"
@@ -87,8 +97,11 @@ var testconfig2 = []byte(`
var testconfig3 = []byte(` var testconfig3 = []byte(`
[irc.zzz] [irc.zzz]
server=""
[telegram.zzz] [telegram.zzz]
server=""
[slack.zzz] [slack.zzz]
server=""
[[gateway]] [[gateway]]
name="bridge" name="bridge"
enable=true enable=true
@@ -176,7 +189,6 @@ func TestNewRouter(t *testing.T) {
assert.Equal(t, 1, len(r.Gateways)) assert.Equal(t, 1, len(r.Gateways))
assert.Equal(t, 4, len(r.Gateways["bridge1"].Bridges)) assert.Equal(t, 4, len(r.Gateways["bridge1"].Bridges))
assert.Equal(t, 4, len(r.Gateways["bridge1"].Channels)) assert.Equal(t, 4, len(r.Gateways["bridge1"].Channels))
r = maketestRouter(testconfig2) r = maketestRouter(testconfig2)
assert.Equal(t, 2, len(r.Gateways)) assert.Equal(t, 2, len(r.Gateways))
assert.Equal(t, 4, len(r.Gateways["bridge1"].Bridges)) assert.Equal(t, 4, len(r.Gateways["bridge1"].Bridges))

View File

@@ -169,7 +169,7 @@ func (gw *Gateway) ignoreEvent(event string, dest *bridge.Bridge) bool {
switch event { switch event {
case config.EventAvatarDownload: case config.EventAvatarDownload:
// Avatar downloads are only relevant for telegram and mattermost for now // Avatar downloads are only relevant for telegram and mattermost for now
if dest.Protocol != "mattermost" && dest.Protocol != "telegram" { if dest.Protocol != "mattermost" && dest.Protocol != "telegram" && dest.Protocol != "xmpp" {
return true return true
} }
case config.EventJoinLeave: case config.EventJoinLeave:
@@ -179,7 +179,7 @@ func (gw *Gateway) ignoreEvent(event string, dest *bridge.Bridge) bool {
} }
case config.EventTopicChange: case config.EventTopicChange:
// only relay topic change when used in some way on other side // only relay topic change when used in some way on other side
if dest.GetBool("ShowTopicChange") && dest.GetBool("SyncTopic") { if !dest.GetBool("ShowTopicChange") && !dest.GetBool("SyncTopic") {
return true return true
} }
} }

View File

@@ -59,8 +59,14 @@ func NewRouter(rootLogger *logrus.Logger, cfg config.Config, bridgeMap map[strin
// between them. // between them.
func (r *Router) Start() error { func (r *Router) Start() error {
m := make(map[string]*bridge.Bridge) m := make(map[string]*bridge.Bridge)
if len(r.Gateways) == 0 {
return fmt.Errorf("no [[gateway]] configured. See https://github.com/42wim/matterbridge/wiki/How-to-create-your-config for more info")
}
for _, gw := range r.Gateways { for _, gw := range r.Gateways {
r.logger.Infof("Parsing gateway %s", gw.Name) r.logger.Infof("Parsing gateway %s", gw.Name)
if len(gw.Bridges) == 0 {
return fmt.Errorf("no bridges configured for gateway %s. See https://github.com/42wim/matterbridge/wiki/How-to-create-your-config for more info", gw.Name)
}
for _, br := range gw.Bridges { for _, br := range gw.Bridges {
m[br.Account] = br m[br.Account] = br
} }
@@ -126,6 +132,9 @@ func (r *Router) handleReceive() {
r.handleEventFailure(&msg) r.handleEventFailure(&msg)
r.handleEventRejoinChannels(&msg) r.handleEventRejoinChannels(&msg)
// Set message protocol based on the account it came from
msg.Protocol = r.getBridge(msg.Account).Protocol
filesHandled := false filesHandled := false
for _, gw := range r.Gateways { for _, gw := range r.Gateways {
// record all the message ID's of the different bridges // record all the message ID's of the different bridges

83
go.mod
View File

@@ -4,63 +4,52 @@ require (
github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557 github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
github.com/Jeffail/gabs v1.1.1 // indirect github.com/Jeffail/gabs v1.1.1 // indirect
github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329 github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0
github.com/Rhymen/go-whatsapp v0.0.2 github.com/Rhymen/go-whatsapp v0.1.1-0.20200421062035-31e8111ac334
github.com/bwmarrin/discordgo v0.19.0 github.com/d5/tengo/v2 v2.6.0
github.com/d5/tengo v1.24.1 github.com/davecgh/go-spew v1.1.1
github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec github.com/fsnotify/fsnotify v1.4.9
github.com/fsnotify/fsnotify v1.4.7 github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20200524105306-7434b0456e81
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible github.com/gomarkdown/markdown v0.0.0-20200609195525-3f9352745725
github.com/google/gops v0.3.6 github.com/google/gops v0.3.10
github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 // indirect github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 // indirect
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f // indirect
github.com/gorilla/schema v1.1.0 github.com/gorilla/schema v1.1.0
github.com/gorilla/websocket v1.4.0 github.com/gorilla/websocket v1.4.2
github.com/hashicorp/golang-lru v0.5.1 github.com/hashicorp/golang-lru v0.5.4
github.com/hpcloud/tail v1.0.0 // indirect github.com/jpillora/backoff v1.0.0
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7 github.com/keybase/go-keybase-chat-bot v0.0.0-20200505163032-5cacf52379da
github.com/jtolds/gls v4.2.1+incompatible // indirect github.com/labstack/echo/v4 v4.1.16
github.com/labstack/echo/v4 v4.1.6 github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7
github.com/lrstanley/girc v0.0.0-20190210212025-51b8e096d398 github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20200411204219-d5c18ce75048
github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 // indirect github.com/matterbridge/discordgo v0.21.2-0.20200718144317-01fe5db6c78d
github.com/lusis/slack-test v0.0.0-20180109053238-3c758769bfa6 // indirect github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050
github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91 github.com/matterbridge/gomatrix v0.0.0-20200209224845-c2104d7936a6
github.com/matterbridge/gomatrix v0.0.0-20190102230110-6f9631ca6dea github.com/matterbridge/gozulipbot v0.0.0-20200820220548-be5824faa913
github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18 github.com/matterbridge/logrus-prefixed-formatter v0.5.3-0.20200523233437-d971309a77ba
github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61 github.com/mattermost/mattermost-server/v5 v5.25.2
github.com/mattermost/mattermost-server v5.5.0+incompatible github.com/mattn/godown v0.0.0-20200217152941-afc959f6a561
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/missdeer/golib v1.0.3
github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474 // indirect github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474 // indirect
github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff // indirect github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff // indirect
github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9 github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9
github.com/nicksnyder/go-i18n v1.4.0 // indirect
github.com/nlopes/slack v0.5.0
github.com/onsi/ginkgo v1.6.0 // indirect
github.com/onsi/gomega v1.4.1 // indirect
github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c
github.com/pborman/uuid v0.0.0-20160216163710-c55201b03606 // indirect
github.com/peterhellberg/emojilib v0.0.0-20190124112554-c18758d55320
github.com/rs/xid v1.2.1 github.com/rs/xid v1.2.1
github.com/russross/blackfriday v1.5.2 github.com/russross/blackfriday v1.5.2
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca
github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296 github.com/shazow/ssh-chat v1.8.3-0.20200308224626-80ddf1f43a98
github.com/sirupsen/logrus v1.4.2 github.com/sirupsen/logrus v1.6.0
github.com/smartystreets/assertions v0.0.0-20180803164922-886ec427f6b9 // indirect github.com/slack-go/slack v0.6.5
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect github.com/spf13/viper v1.7.0
github.com/spf13/viper v1.4.0 github.com/stretchr/testify v1.5.1
github.com/stretchr/testify v1.3.0 github.com/writeas/go-strip-markdown v2.0.1+incompatible
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect
github.com/yaegashi/msgraph.go v0.1.3
github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2 github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2
gitlab.com/golang-commonmark/html v0.0.0-20180917080848-cfaf75183c4a // indirect golang.org/x/image v0.0.0-20200618115811-c13761719519
gitlab.com/golang-commonmark/linkify v0.0.0-20180917065525-c22b7bdb1179 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
gitlab.com/golang-commonmark/markdown v0.0.0-20181102083822-772775880e1f gomod.garykim.dev/nc-talk v0.0.2
gitlab.com/golang-commonmark/mdurl v0.0.0-20180912090424-e5bce34c34f2 // indirect
gitlab.com/golang-commonmark/puny v0.0.0-20180912090636-2cd490539afe // indirect
gitlab.com/opennota/wd v0.0.0-20180912061657-c5d65f63c638 // indirect
golang.org/x/image v0.0.0-20190616094056-33659d3de4f5
gopkg.in/fsnotify.v1 v1.4.7 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
) )
go 1.13

855
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -12,8 +12,14 @@ text := import("text")
// start - strip irc colors // start - strip irc colors
// if we're not sending to an irc bridge we strip the IRC colors // if we're not sending to an irc bridge we strip the IRC colors
if inProtocol == "irc" { if inProtocol == "irc" && outProtocol != "irc" {
re := text.re_compile(`\x03(?:\d{1,2}(?:,\d{1,2})?)?|[[:cntrl:]]`) re := text.re_compile(`\x03(?:\d{1,2}(?:,\d{1,2})?)?|[[:cntrl:]]`)
msgText=re.replace(msgText,"") msgText=re.replace(msgText,"")
} }
// end - strip irc colors // end - strip irc colors
// strip custom emoji
if inProtocol == "discord" {
re := text.re_compile(`<a?(:.*?:)[0-9]+>`)
msgText=re.replace(msgText,"$1")
}

View File

@@ -4,6 +4,7 @@ import (
"flag" "flag"
"fmt" "fmt"
"os" "os"
"runtime"
"strings" "strings"
"github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/config"
@@ -15,7 +16,7 @@ import (
) )
var ( var (
version = "1.15.1" version = "1.18.1"
githash string githash string
flagConfig = flag.String("conf", "matterbridge.toml", "config file") flagConfig = flag.String("conf", "matterbridge.toml", "config file")
@@ -50,6 +51,15 @@ func main() {
cfg := config.NewConfig(rootLogger, *flagConfig) cfg := config.NewConfig(rootLogger, *flagConfig)
cfg.BridgeValues().General.Debug = *flagDebug cfg.BridgeValues().General.Debug = *flagDebug
// if logging to a file, ensure it is closed when the program terminates
// nolint:errcheck
defer func() {
if f, ok := rootLogger.Out.(*os.File); ok {
f.Sync()
f.Close()
}
}()
r, err := gateway.NewRouter(rootLogger, cfg, bridgemap.FullMap) r, err := gateway.NewRouter(rootLogger, cfg, bridgemap.FullMap)
if err != nil { if err != nil {
logger.Fatalf("Starting gateway failed: %s", err) logger.Fatalf("Starting gateway failed: %s", err)
@@ -67,17 +77,31 @@ func setupLogger() *logrus.Logger {
Formatter: &prefixed.TextFormatter{ Formatter: &prefixed.TextFormatter{
PrefixPadding: 13, PrefixPadding: 13,
DisableColors: true, DisableColors: true,
FullTimestamp: true,
}, },
Level: logrus.InfoLevel, Level: logrus.InfoLevel,
} }
if *flagDebug || os.Getenv("DEBUG") == "1" { if *flagDebug || os.Getenv("DEBUG") == "1" {
logger.SetReportCaller(true)
logger.Formatter = &prefixed.TextFormatter{ logger.Formatter = &prefixed.TextFormatter{
PrefixPadding: 13, PrefixPadding: 13,
DisableColors: true, DisableColors: true,
FullTimestamp: false, FullTimestamp: false,
ForceFormatting: true,
CallerFormatter: func(function, file string) string {
return fmt.Sprintf(" [%s:%s]", function, file)
},
CallerPrettyfier: func(f *runtime.Frame) (string, string) {
sp := strings.SplitAfter(f.File, "/matterbridge/")
filename := f.File
if len(sp) > 1 {
filename = sp[1]
} }
s := strings.Split(f.Function, ".")
funcName := s[len(s)-1]
return funcName, fmt.Sprintf("%s:%d", filename, f.Line)
},
}
logger.Level = logrus.DebugLevel logger.Level = logrus.DebugLevel
logger.WithFields(logrus.Fields{"prefix": "main"}).Info("Enabling debug logging.") logger.WithFields(logrus.Fields{"prefix": "main"}).Info("Enabling debug logging.")
} }

View File

@@ -103,6 +103,10 @@ ColorNicks=false
#OPTIONAL (default empty) #OPTIONAL (default empty)
RunCommands=["PRIVMSG user hello","PRIVMSG chanserv something"] RunCommands=["PRIVMSG user hello","PRIVMSG chanserv something"]
#StripMarkdown strips markdown from messages
#OPTIONAL (default false)
StripMarkdown=false
#Nicks you want to ignore. #Nicks you want to ignore.
#Regular expressions supported #Regular expressions supported
#Messages from those users will not be sent to other bridges. #Messages from those users will not be sent to other bridges.
@@ -177,6 +181,12 @@ StripNick=false
#OPTIONAL (default false) #OPTIONAL (default false)
ShowTopicChange=false ShowTopicChange=false
#Delay in milliseconds between channel joins
#Only useful when you have a LOT of channels to join
#See https://github.com/42wim/matterbridge/issues/1084
#OPTIONAL (default 0)
JoinDelay=0
################################################################### ###################################################################
#XMPP section #XMPP section
################################################################### ###################################################################
@@ -522,6 +532,119 @@ StripNick=false
#OPTIONAL (default false) #OPTIONAL (default false)
ShowTopicChange=false ShowTopicChange=false
###################################################################
#
# Keybase
# You should have a separate bridge account on Keybase
# (it also needs to be logged in on the system you're running the bridge on)
#
###################################################################
[keybase.myteam]
# RemoteNickFormat defines how remote users appear on this bridge
# See [general] config section for default options
RemoteNickFormat="{NICK} ({PROTOCOL}): "
# extra label that can be used in the RemoteNickFormat
# optional (default empty)
Label=""
# Your team on Keybase.
# The bot user MUST be a member of this team
# REQUIRED
Team="myteam"
###################################################################
# Microsoft teams section
# See https://github.com/42wim/matterbridge/wiki/MS-Teams-setup
###################################################################
[msteams.myteam]
# TenantID
# See https://github.com/42wim/matterbridge/wiki/MS-Teams-setup#get-necessary-ids-for-matterbridge
TenantID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
# ClientID
# See https://github.com/42wim/matterbridge/wiki/MS-Teams-setup#get-necessary-ids-for-matterbridge
ClientID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
# TeamID
# See https://github.com/42wim/matterbridge/wiki/MS-Teams-setup#get-necessary-ids-for-matterbridge
TeamID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
## RELOADABLE SETTINGS
## Settings below can be reloaded by editing the file
#Nicks you want to ignore.
#Regular expressions supported
#Messages from those users will not be sent to other bridges.
#OPTIONAL
IgnoreNicks="ircspammer1 ircspammer2"
#Messages you want to ignore.
#Messages matching these regexp will be ignored and not sent to other bridges
#See https://regex-golang.appspot.com/assets/html/index.html for more regex info
#OPTIONAL (example below ignores messages starting with ~~ or messages containing badword
IgnoreMessages="^~~ badword"
#messages you want to replace.
#it replaces outgoing messages from the bridge.
#so you need to place it by the sending bridge definition.
#regular expressions supported
#some examples:
#this replaces cat => dog and sleep => awake
#replacemessages=[ ["cat","dog"], ["sleep","awake"] ]
#this replaces every number with number. 123 => numbernumbernumber
#replacemessages=[ ["[0-9]","number"] ]
#optional (default empty)
ReplaceMessages=[ ["cat","dog"] ]
#nicks you want to replace.
#see replacemessages for syntaxa
#optional (default empty)
ReplaceNicks=[ ["user--","user"] ]
#Extractnicks is used to for example rewrite messages from other relaybots
#See https://github.com/42wim/matterbridge/issues/713 and https://github.com/42wim/matterbridge/issues/466
#some examples:
#this replaces a message like "Relaybot: <relayeduser> something interesting" to "relayeduser: something interesting"
#ExtractNicks=[ [ "Relaybot", "<(.*?)>\\s+" ] ]
#you can use multiple entries for multiplebots
#this also replaces a message like "otherbot: (relayeduser) something else" to "relayeduser: something else"
#ExtractNicks=[ [ "Relaybot", "<(.*?)>\\s+" ],[ "otherbot","\\((.*?)\\)\\s+" ]
#OPTIONAL (default empty)
ExtractNicks=[ ["otherbot","<(.*?)>\\s+" ] ]
#extra label that can be used in the RemoteNickFormat
#optional (default empty)
Label=""
#RemoteNickFormat defines how remote users appear on this bridge
#See [general] config section for default options
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
#Enable to show users joins/parts from other bridges
#Currently works for messages from the following bridges: irc, mattermost, slack, discord
#OPTIONAL (default false)
ShowJoinPart=false
#StripNick only allows alphanumerical nicks. See https://github.com/42wim/matterbridge/issues/285
#It will strip other characters from the nick
#OPTIONAL (default false)
StripNick=false
#Enable to show topic changes from other bridges
#Only works hiding/show topic changes from slack bridge for now
#OPTIONAL (default false)
ShowTopicChange=false
#Opportunistically preserve threaded replies between bridges
#that support threading
#OPTIONAL (default false)
PreserveThreading=false
################################################################### ###################################################################
#slack section #slack section
################################################################### ###################################################################
@@ -680,114 +803,125 @@ ShowUserTyping=false
################################################################### ###################################################################
[discord] [discord]
#You can configure multiple servers "[discord.name]" or "[discord.name2]" # You can configure multiple servers "[discord.name]" or "[discord.name2]"
#In this example we use [discord.game] # In this example we use [discord.game]
#REQUIRED #REQUIRED
[discord.game] [discord.game]
#Token to connect with Discord API # Token (REQUIRED) is the token to connect with Discord API
#You can get your token by following the instructions on # You can get your token by following the instructions on
#https://github.com/reactiflux/discord-irc/wiki/Creating-a-discord-bot-&-getting-a-token # https://github.com/reactiflux/discord-irc/wiki/Creating-a-discord-bot-&-getting-a-token
#If you want roles/groups mentions to be shown with names instead of ID, you'll need to give your bot the "Manage Roles" permission. # If you want roles/groups mentions to be shown with names instead of ID, you'll need to give your bot the "Manage Roles" permission.
#REQUIRED
Token="Yourtokenhere" Token="Yourtokenhere"
#REQUIRED # Server (REQUIRED) is the ID or name of the guild to connect to, selected from the guilds the bot has been invited to
Server="yourservername" Server="yourservername"
## RELOADABLE SETTINGS ## RELOADABLE SETTINGS
## Settings below can be reloaded by editing the file ## All settings below can be reloaded by editing the file.
## They are also all optional.
#Shows title, description and URL of embedded messages (sent by other bots) # ShowEmbeds shows the title, description and URL of embedded messages (sent by other bots)
#OPTIONAL (default false)
ShowEmbeds=false ShowEmbeds=false
#Shows the username instead of the server nickname # UseLocalAvatar specifies source bridges for which an avatar should be 'guessed' when an incoming message has no avatar.
#OPTIONAL (default false) # This works by comparing the username of the message to an existing Discord user, and using the avatar of the Discord user.
#
# This only works if WebhookURL is set (AND the message has no avatar).
# Example: ["irc"]
UseLocalAvatar=[]
# UseUserName shows the username instead of the server nickname
UseUserName=false UseUserName=false
#Show #xxxx discriminator with UseUserName # UseDiscriminator appends the `#xxxx` discriminator when used with UseUserName
#OPTIONAL (default false)
UseDiscriminator=false UseDiscriminator=false
#Specify WebhookURL. If given, will relay messages using the Webhook, which gives a better look to messages. # WebhookURL sends messages in the style of puppets.
#This only works if you have one discord channel, if you have multiple discord channels you'll have to specify it in the gateway config # This only works if you have one discord channel, if you have multiple discord channels you'll have to specify it in the gateway config
#OPTIONAL (default empty) # Example: "https://discordapp.com/api/webhooks/1234/abcd_xyzw"
WebhookURL="Yourwebhooktokenhere" WebhookURL=""
#Disable sending of edits to other bridges # EditDisable disables sending of edits to other bridges
#OPTIONAL (default false)
EditDisable=false EditDisable=false
#Message to be appended to every edited message # EditSuffix specifies the message to be appended to every edited message
#OPTIONAL (default empty) # Example: " (edited)"
EditSuffix=" (edited)" EditSuffix=""
#Nicks you want to ignore. # IgnoreNicks mutes outgoing messages from certain users.
#Regular expressions supported # Messages from these users will not be transmitted to other bridges.
#Messages from those users will not be sent to other bridges. # Regular expressions are also supported.
#OPTIONAL # Example: "ircspammer1 ircspammer2"
IgnoreNicks="ircspammer1 ircspammer2" IgnoreNicks=""
#Messages you want to ignore. # IgnoreMessages mutes outgoing messages of a certain format.
#Messages matching these regexp will be ignored and not sent to other bridges # Messages matching this regular expression will not be transmitted sent to other bridges
#See https://regex-golang.appspot.com/assets/html/index.html for more regex info # See https://regex-golang.appspot.com/assets/html/index.html for more regex info
#OPTIONAL (example below ignores messages starting with ~~ or messages containing badword #
IgnoreMessages="^~~ badword" # Example that ignores messages starting with ~~ or messages containing badword:
# IgnoreMessages="^~~ badword"
IgnoreMessages=""
#messages you want to replace. # ReplaceMessages replaces substrings of messages in outgoing messages.
#it replaces outgoing messages from the bridge. # Regular expressions are supported.
#so you need to place it by the sending bridge definition. #
#regular expressions supported # Example that replaces 'cat' => 'dog' and 'sleep' => 'awake':
#some examples: # ReplaceMessages=[ ["cat","dog"], ["sleep","awake"] ]
#this replaces cat => dog and sleep => awake # Example that replaces all digits with the letter 'X', so 'hello123' becomes 'helloXXX':
#replacemessages=[ ["cat","dog"], ["sleep","awake"] ] # ReplaceMessages=[ ["[0-9]","X"] ]
#this replaces every number with number. 123 => numbernumbernumber ReplaceMessages=[]
#replacemessages=[ ["[0-9]","number"] ]
#optional (default empty)
ReplaceMessages=[ ["cat","dog"] ]
#nicks you want to replace. # ReplaceNicks replaces substrings of usernames in outgoing messages.
#see replacemessages for syntaxa # See the ReplaceMessages setting for examples.
#optional (default empty) # Example: [ ["user--","user"] ]
ReplaceNicks=[ ["user--","user"] ] ReplaceNicks=[]
#Extractnicks is used to for example rewrite messages from other relaybots # ExtractNicks allows for interoperability with other bridge software by rewriting messages and extracting usernames.
#See https://github.com/42wim/matterbridge/issues/713 and https://github.com/42wim/matterbridge/issues/466 #
#some examples: # Recommended reading:
#this replaces a message like "Relaybot: <relayeduser> something interesting" to "relayeduser: something interesting" # - https://github.com/42wim/matterbridge/issues/466
#ExtractNicks=[ [ "Relaybot", "<(.*?)>\\s+" ] ] # - https://github.com/42wim/matterbridge/issues/713
#you can use multiple entries for multiplebots #
#this also replaces a message like "otherbot: (relayeduser) something else" to "relayeduser: something else" # This example translates the following message
#ExtractNicks=[ [ "Relaybot", "<(.*?)>\\s+" ],[ "otherbot","\\((.*?)\\)\\s+" ] # "Relaybot: <relayeduser> something interesting"
#OPTIONAL (default empty) # into this message
ExtractNicks=[ ["otherbot","<(.*?)>\\s+" ] ] # "relayeduser: something interesting"
# like so:
# ExtractNicks=[ [ "Relaybot", "<(.*?)>\\s+" ] ]
#
# This example translates the following message
# "otherbot: (relayeduser) something else"
# into this message
# "relayeduser: something else"
# like so:
# ExtractNicks=[ [ "otherbot","\\((.*?)\\)\\s+" ] ]
#
# This example combines both of the above examples into one:
# ExtractNicks=[ [ "Relaybot", "<(.*?)>\\s+" ],[ "otherbot","\\((.*?)\\)\\s+" ]
#
ExtractNicks=[]
#extra label that can be used in the RemoteNickFormat # Label is as an extra identifier for use in the RemoteNickFormat setting.
#optional (default empty)
Label="" Label=""
#RemoteNickFormat defines how remote users appear on this bridge # RemoteNickFormat formats how remote users appear on this bridge.
#See [general] config section for default options # See the [general] config section for default options
RemoteNickFormat="[{PROTOCOL}] <{NICK}> " RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
#Enable to show users joins/parts from other bridges # ShowJoinPart emits messages that show joins/parts from other bridges
#Currently works for messages from the following bridges: irc, mattermost, slack, discord # Supported from the following bridges: irc, mattermost, slack, discord
#OPTIONAL (default false)
ShowJoinPart=false ShowJoinPart=false
#StripNick only allows alphanumerical nicks. See https://github.com/42wim/matterbridge/issues/285 # StripNick strips non-alphanumeric characters from nicknames.
#It will strip other characters from the nick # Recommended reading: https://github.com/42wim/matterbridge/issues/285
#OPTIONAL (default false)
StripNick=false StripNick=false
#Enable to show topic/purpose changes from other bridges # ShowTopicChange emits messages that show topic/purpose updates from other bridges
#Only works hiding/show topic changes from slack bridge for now # Supported from the following bridges: slack
#OPTIONAL (default false)
ShowTopicChange=false ShowTopicChange=false
#Enable to sync topic/purpose changes from other bridges # SyncTopic synchronises topic/purpose updates from other bridges
#Only works syncing topic changes from slack bridge for now # Supported from the following bridges: slack
#OPTIONAL (default false)
SyncTopic=false SyncTopic=false
################################################################### ###################################################################
@@ -808,12 +942,17 @@ Token="Yourtokenhere"
## Settings below can be reloaded by editing the file ## Settings below can be reloaded by editing the file
#OPTIONAL (default empty) #OPTIONAL (default empty)
#Supported formats are "HTML", "Markdown" and "HTMLNick" #Supported formats are:
#See https://core.telegram.org/bots/api#html-style #"HTML" https://core.telegram.org/bots/api#html-style
#See https://core.telegram.org/bots/api#markdown-style #"Markdown" https://core.telegram.org/bots/api#markdown-style - deprecated, doesn't display links with underscores correctly
#HTMLNick only allows HTML for the nick, the message itself will be html-escaped #"MarkdownV2" https://core.telegram.org/bots/api#markdownv2-style
#"HTMLNick" - only allows HTML for the nick, the message itself will be html-escaped
MessageFormat="" MessageFormat=""
#OPTIONAL (default false)
#Disables link previews for links in messages
DisableWebPagePreview=false
#If enabled use the "First Name" as username. If this is empty use the Username #If enabled use the "First Name" as username. If this is empty use the Username
#If disabled use the "Username" as username. If this is empty use the First Name #If disabled use the "Username" as username. If this is empty use the First Name
#If all names are empty, username will be "unknown" #If all names are empty, username will be "unknown"
@@ -830,6 +969,10 @@ UseInsecureURL=false
#OPTIONAL (default false) #OPTIONAL (default false)
QuoteDisable=false QuoteDisable=false
#Set the max. quoted length if 0 the whole message will be quoted
#OPTIONAL (default 0)
QuoteLengthLimit=0
#Format quoted/reply messages #Format quoted/reply messages
#OPTIONAL (default "{MESSAGE} (re @{QUOTENICK}: {QUOTEMESSAGE})") #OPTIONAL (default "{MESSAGE} (re @{QUOTENICK}: {QUOTEMESSAGE})")
QuoteFormat="{MESSAGE} (re @{QUOTENICK}: {QUOTEMESSAGE})" QuoteFormat="{MESSAGE} (re @{QUOTENICK}: {QUOTEMESSAGE})"
@@ -933,6 +1076,11 @@ Server="https://yourrocketchatserver.domain.com:443"
#REQUIRED (when not using webhooks) #REQUIRED (when not using webhooks)
Login="yourlogin@domain.com" Login="yourlogin@domain.com"
Password="yourpass" Password="yourpass"
# When using access token set Login to the User ID associated with your token and Token to your token.
# When Token is set Password is ignored.
# Login="yOurUSerID"
# Token="YoUrUsER_toKEN"
#### Settings for webhook matterbridge. #### Settings for webhook matterbridge.
#USE DEDICATED BOT USER WHEN POSSIBLE! This allows you to use advanced features like message editing/deleting and uploads #USE DEDICATED BOT USER WHEN POSSIBLE! This allows you to use advanced features like message editing/deleting and uploads
@@ -1065,6 +1213,11 @@ Password="yourpass"
#OPTIONAL (default false) #OPTIONAL (default false)
NoHomeServerSuffix=false NoHomeServerSuffix=false
#Whether to disable sending of HTML content to matrix
#See https://github.com/42wim/matterbridge/issues/1022
#OPTIONAL (default false)
HTMLDisable=false
## RELOADABLE SETTINGS ## RELOADABLE SETTINGS
## Settings below can be reloaded by editing the file ## Settings below can be reloaded by editing the file
@@ -1230,7 +1383,22 @@ StripNick=false
#OPTIONAL (default false) #OPTIONAL (default false)
ShowTopicChange=false ShowTopicChange=false
###################################################################
#
# NCTalk (Nextcloud Talk)
#
###################################################################
[nctalk.bridge]
# Url of your Nextcloud server
Server = "https://cloud.youdomain.me"
# Username of the bot
Login = "talkuser"
# Password of the bot
Password = "talkuserpass"
################################################################### ###################################################################
# #
@@ -1451,6 +1619,14 @@ MediaDownloadBlacklist=[".html$",".htm$"]
#OPTIONAL (default false) #OPTIONAL (default false)
IgnoreFailureOnStart=false IgnoreFailureOnStart=false
#LogFile defines the location of a file to write logs into, rather
#than stdout.
#Logging will still happen on stdout if the file cannot be open for
#writing, or if the value is empty. Note that the log won't roll, so
#you might want to use logrotate(8) with this feature.
#OPTIONAL (default empty)
LogFile="/var/log/matterbridge.log"
################################################################### ###################################################################
#Tengo configuration #Tengo configuration
################################################################### ###################################################################
@@ -1541,32 +1717,46 @@ enable=true
# REQUIRED # REQUIRED
account="irc.freenode" account="irc.freenode"
# channel to connect on that account # The channel key in each gateway is mapped to a similar group chat ID on the chat platform
# How to specify them for the different bridges: # To find the group chat ID for different platforms, refer to the table below
# #
# irc - #channel (# is required) (this needs to be lowercase!) # Platform | Identifier name | Example | Description
# mattermost - channel (the channel name as seen in the URL, not the displayname) # -------------------------------------------------------------------------------------------------------------------------------------
# gitter - username/room # | channel | general | Do not include the # symbol
# xmpp - channel # discord | channel id | ID:123456789 | See https://github.com/42wim/matterbridge/issues/57
# slack - channel (without the #) # | category/channel | Media/gaming | Without # symbol. If you're using discord categories to group your channels
# - ID:C123456 (where C123456 is the channel ID) does not work with webhook # -------------------------------------------------------------------------------------------------------------------------------------
# discord - channel (without the #) # gitter | username/room | general | As seen in the gitter.im URL
# - ID:123456789 (where 123456789 is the channel ID) # -------------------------------------------------------------------------------------------------------------------------------------
# (https://github.com/42wim/matterbridge/issues/57) # hipchat | id_channel | example needed | See https://www.hipchat.com/account/xmpp for the correct channel
# - category/channel (without the #) if you're using discord categories to group your channels # -------------------------------------------------------------------------------------------------------------------------------------
# telegram - chatid (a large negative number, eg -123456789) # irc | channel | #general | The # symbol is required and should be lowercase!
# see (https://www.linkedin.com/pulse/telegram-bots-beginners-marco-frau) # -------------------------------------------------------------------------------------------------------------------------------------
# hipchat - id_channel (see https://www.hipchat.com/account/xmpp for the correct channel) # mattermost | channel | general | This is the channel name as seen in the URL, not the display name
# rocketchat - #channel (# is required (also needed for private channels!) # -------------------------------------------------------------------------------------------------------------------------------------
# matrix - #channel:server (eg #yourchannel:matrix.org) # matrix | #channel:server | #yourchannel:matrix.org | Encrypted rooms are not supported in matrix
# - encrypted rooms are not supported in matrix # -------------------------------------------------------------------------------------------------------------------------------------
# steam - chatid (a large number). # msteams | threadId | 19:82abcxx@thread.skype | You'll find the threadId in the URL
# The number in the URL when you click "enter chat room" in the browser # -------------------------------------------------------------------------------------------------------------------------------------
# whatsapp - 48111222333-123455678999@g.us A unique group JID; # rocketchat | channel | #channel | # is required for private channels too
# if you specify an empty string bridge will list all the possibilities # -------------------------------------------------------------------------------------------------------------------------------------
# - "Group Name" if you specify a group name the bridge will hint its JID to specify # slack | channel name | general | Do not include the # symbol
# as group names might change in time and contain weird emoticons # | channel id | ID:C123456 | The underlying ID of a channel. This doesn't work with
# zulip - stream/topic:topicname (without the #) # -------------------------------------------------------------------------------------------------------------------------------------
# steam | chatid | example needed | The number in the URL when you click "enter chat room" in the browser
# -------------------------------------------------------------------------------------------------------------------------------------
# nctalk | token | xs25tz5y | The token in the URL when you are in a chat. It will be the last part of the URL.
# -------------------------------------------------------------------------------------------------------------------------------------
# telegram | chatid | -123456789 | A large negative number. see https://www.linkedin.com/pulse/telegram-bots-beginners-marco-frau
# -------------------------------------------------------------------------------------------------------------------------------------
# whatsapp | group JID | 48111222333-123455678999@g.us | A unique group JID. If you specify an empty string, bridge will list all the possibilities
# | "Group Name" | "Family Chat" | if you specify a group name, the bridge will find hint the JID to specify. Names can change over time and are not stable.
# -------------------------------------------------------------------------------------------------------------------------------------
# xmpp | channel | general | The room name
# -------------------------------------------------------------------------------------------------------------------------------------
# zulip | stream/topic:topic | general/off-topic:food | Do not use the # when specifying a topic
# -------------------------------------------------------------------------------------------------------------------------------------
# #
# REQUIRED # REQUIRED
channel="#testing" channel="#testing"

View File

@@ -4,7 +4,7 @@ import (
"errors" "errors"
"strings" "strings"
"github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/v5/model"
) )
// GetChannels returns all channels we're members off // GetChannels returns all channels we're members off
@@ -36,6 +36,16 @@ func (m *MMClient) GetChannelHeader(channelId string) string { //nolint:golint
return "" return ""
} }
func getNormalisedName(channel *model.Channel) string {
if channel.Type == model.CHANNEL_GROUP {
// (deprecated in favor of ReplaceAll in go 1.12)
res := strings.Replace(channel.DisplayName, ", ", "-", -1) //nolint: gocritic
res = strings.Replace(res, " ", "_", -1) //nolint: gocritic
return res
}
return channel.Name
}
func (m *MMClient) GetChannelId(name string, teamId string) string { //nolint:golint func (m *MMClient) GetChannelId(name string, teamId string) string { //nolint:golint
m.RLock() m.RLock()
defer m.RUnlock() defer m.RUnlock()
@@ -45,13 +55,7 @@ func (m *MMClient) GetChannelId(name string, teamId string) string { //nolint:go
for _, t := range m.OtherTeams { for _, t := range m.OtherTeams {
for _, channel := range append(t.Channels, t.MoreChannels...) { for _, channel := range append(t.Channels, t.MoreChannels...) {
if channel.Type == model.CHANNEL_GROUP { if getNormalisedName(channel) == name {
res := strings.Replace(channel.DisplayName, ", ", "-", -1)
res = strings.Replace(res, " ", "_", -1)
if res == name {
return channel.Id
}
} else if channel.Name == name {
return channel.Id return channel.Id
} }
} }
@@ -63,7 +67,7 @@ func (m *MMClient) getChannelIdTeam(name string, teamId string) string { //nolin
for _, t := range m.OtherTeams { for _, t := range m.OtherTeams {
if t.Id == teamId { if t.Id == teamId {
for _, channel := range append(t.Channels, t.MoreChannels...) { for _, channel := range append(t.Channels, t.MoreChannels...) {
if channel.Name == name { if getNormalisedName(channel) == name {
return channel.Id return channel.Id
} }
} }
@@ -81,12 +85,7 @@ func (m *MMClient) GetChannelName(channelId string) string { //nolint:golint
} }
for _, channel := range append(t.Channels, t.MoreChannels...) { for _, channel := range append(t.Channels, t.MoreChannels...) {
if channel.Id == channelId { if channel.Id == channelId {
if channel.Type == model.CHANNEL_GROUP { return getNormalisedName(channel)
res := strings.Replace(channel.DisplayName, ", ", "-", -1)
res = strings.Replace(res, " ", "_", -1)
return res
}
return channel.Name
} }
} }
} }
@@ -168,7 +167,7 @@ func (m *MMClient) JoinChannel(channelId string) error { //nolint:golint
} }
func (m *MMClient) UpdateChannelsTeam(teamID string) error { func (m *MMClient) UpdateChannelsTeam(teamID string) error {
mmchannels, resp := m.Client.GetChannelsForTeamForUser(teamID, m.User.Id, "") mmchannels, resp := m.Client.GetChannelsForTeamForUser(teamID, m.User.Id, false, "")
if resp.Error != nil { if resp.Error != nil {
return errors.New(resp.Error.DetailedError) return errors.New(resp.Error.DetailedError)
} }

View File

@@ -13,7 +13,7 @@ import (
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/jpillora/backoff" "github.com/jpillora/backoff"
"github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/v5/model"
) )
func (m *MMClient) doLogin(firstConnection bool, b *backoff.Backoff) error { func (m *MMClient) doLogin(firstConnection bool, b *backoff.Backoff) error {
@@ -154,7 +154,7 @@ func (m *MMClient) initUser() error {
t := &Team{Team: team, Users: usermap, Id: team.Id} t := &Team{Team: team, Users: usermap, Id: team.Id}
mmchannels, resp := m.Client.GetChannelsForTeamForUser(team.Id, m.User.Id, "") mmchannels, resp := m.Client.GetChannelsForTeamForUser(team.Id, m.User.Id, false, "")
if resp.Error != nil { if resp.Error != nil {
return resp.Error return resp.Error
} }

View File

@@ -11,7 +11,7 @@ import (
lru "github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
"github.com/jpillora/backoff" "github.com/jpillora/backoff"
prefixed "github.com/matterbridge/logrus-prefixed-formatter" prefixed "github.com/matterbridge/logrus-prefixed-formatter"
"github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/v5/model"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@@ -69,6 +69,7 @@ type MMClient struct {
logger *logrus.Entry logger *logrus.Entry
rootLogger *logrus.Logger rootLogger *logrus.Logger
lruCache *lru.Cache lruCache *lru.Cache
allevents bool
} }
// New will instantiate a new Matterclient with the specified login details without connecting. // New will instantiate a new Matterclient with the specified login details without connecting.
@@ -119,6 +120,10 @@ func (m *MMClient) SetLogLevel(level string) {
} }
} }
func (m *MMClient) EnableAllEvents() {
m.allevents = true
}
// Login tries to connect the client with the loging details with which it was initialized. // Login tries to connect the client with the loging details with which it was initialized.
func (m *MMClient) Login() error { func (m *MMClient) Login() error {
// check if this is a first connect or a reconnection // check if this is a first connect or a reconnection
@@ -220,6 +225,10 @@ func (m *MMClient) WsReceiver() {
continue continue
} }
} }
if m.allevents {
m.MessageChan <- msg
continue
}
switch msg.Raw.Event { switch msg.Raw.Event {
case model.WEBSOCKET_EVENT_USER_ADDED, case model.WEBSOCKET_EVENT_USER_ADDED,
model.WEBSOCKET_EVENT_USER_REMOVED, model.WEBSOCKET_EVENT_USER_REMOVED,

View File

@@ -3,7 +3,7 @@ package matterclient
import ( import (
"strings" "strings"
"github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/v5/model"
) )
func (m *MMClient) parseActionPost(rmsg *Message) { func (m *MMClient) parseActionPost(rmsg *Message) {

View File

@@ -4,7 +4,7 @@ import (
"errors" "errors"
"time" "time"
"github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/v5/model"
) )
func (m *MMClient) GetNickName(userId string) string { //nolint:golint func (m *MMClient) GetNickName(userId string) string { //nolint:golint

View File

@@ -14,7 +14,7 @@ import (
"time" "time"
"github.com/gorilla/schema" "github.com/gorilla/schema"
"github.com/nlopes/slack" "github.com/slack-go/slack"
) )
// OMessage for mattermost incoming webhook. (send to mattermost) // OMessage for mattermost incoming webhook. (send to mattermost)

View File

@@ -45,19 +45,10 @@ Whether you want to develop your own Steam bot or directly work on go-steam itse
## Updating go-steam to a new SteamKit version ## Updating go-steam to a new SteamKit version
To update go-steam to a new version of SteamKit, do the following: Go source code is generated with code in the `generator` directory.
Look at `generator/README.md` for more information on how to use the generator.
go get github.com/golang/protobuf/protoc-gen-go/ Then, after generating new Go source files, update `go-steam` as necessary.
git submodule init && git submodule update
cd generator
go run generator.go clean proto steamlang
Make sure that `$GOPATH/bin` / `protoc-gen-go` is in your `$PATH`. You'll also need [`protoc`](https://developers.google.com/protocol-buffers/docs/downloads), the protocol buffer compiler. At the moment, we use Protocol Buffers 2.6.1 with `proco-gen-go`-[2402d76](https://github.com/golang/protobuf/tree/2402d76f3d41f928c7902a765dfc872356dd3aad).
To compile the Steam Language files, you also need the [.NET Framework](https://www.microsoft.com/net/downloads)
on Windows or [mono](http://www.go-mono.com/mono-downloads/download.html) on other operating systems.
Apply the protocol changes where necessary.
## License ## License

View File

@@ -94,9 +94,6 @@ func (a *Auth) HandlePacket(packet *Packet) {
a.handleUpdateMachineAuth(packet) a.handleUpdateMachineAuth(packet)
case EMsg_ClientAccountInfo: case EMsg_ClientAccountInfo:
a.handleAccountInfo(packet) a.handleAccountInfo(packet)
case EMsg_ClientWalletInfoUpdate:
case EMsg_ClientRequestWebAPIAuthenticateUserNonceResponse:
case EMsg_ClientMarketingMessageUpdate:
} }
} }

View File

@@ -133,11 +133,17 @@ func (c *Client) Connected() bool {
// If you want to connect to a specific server, use `ConnectTo`. // If you want to connect to a specific server, use `ConnectTo`.
func (c *Client) Connect() *netutil.PortAddr { func (c *Client) Connect() *netutil.PortAddr {
var server *netutil.PortAddr var server *netutil.PortAddr
// try to initialize the directory cache
if !steamDirectoryCache.IsInitialized() {
_ = steamDirectoryCache.Initialize()
}
if steamDirectoryCache.IsInitialized() { if steamDirectoryCache.IsInitialized() {
server = steamDirectoryCache.GetRandomCM() server = steamDirectoryCache.GetRandomCM()
} else { } else {
server = GetRandomCM() server = GetRandomCM()
} }
c.ConnectTo(server) c.ConnectTo(server)
return server return server
} }

View File

@@ -1,6 +1,7 @@
package protocol package protocol
import ( import (
"encoding/hex"
"io" "io"
"math" "math"
"strconv" "strconv"
@@ -42,6 +43,7 @@ const EClientPersonaStateFlag_DefaultInfoRequest = EClientPersonaStateFlag_Playe
const DefaultAvatar = "fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb" const DefaultAvatar = "fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb"
func ValidAvatar(avatar string) bool { func ValidAvatar(avatar []byte) bool {
return !(avatar == "0000000000000000000000000000000000000000" || len(avatar) != 40) str := hex.EncodeToString(avatar)
return !(str == "0000000000000000000000000000000000000000" || len(str) != 40)
} }

View File

@@ -1,31 +1,60 @@
// Code generated by protoc-gen-go. // Code generated by protoc-gen-go. DO NOT EDIT.
// source: encrypted_app_ticket.proto // source: encrypted_app_ticket.proto
// DO NOT EDIT!
package protobuf package protobuf
import proto "github.com/golang/protobuf/proto" import (
import fmt "fmt" fmt "fmt"
import math "math" proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal var _ = proto.Marshal
var _ = fmt.Errorf var _ = fmt.Errorf
var _ = math.Inf var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package protobuf is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package protobuf to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type EncryptedAppTicket struct { type EncryptedAppTicket struct {
TicketVersionNo *uint32 `protobuf:"varint,1,opt,name=ticket_version_no" json:"ticket_version_no,omitempty"` TicketVersionNo *uint32 `protobuf:"varint,1,opt,name=ticket_version_no" json:"ticket_version_no,omitempty"`
CrcEncryptedticket *uint32 `protobuf:"varint,2,opt,name=crc_encryptedticket" json:"crc_encryptedticket,omitempty"` CrcEncryptedticket *uint32 `protobuf:"varint,2,opt,name=crc_encryptedticket" json:"crc_encryptedticket,omitempty"`
CbEncrypteduserdata *uint32 `protobuf:"varint,3,opt,name=cb_encrypteduserdata" json:"cb_encrypteduserdata,omitempty"` CbEncrypteduserdata *uint32 `protobuf:"varint,3,opt,name=cb_encrypteduserdata" json:"cb_encrypteduserdata,omitempty"`
CbEncryptedAppownershipticket *uint32 `protobuf:"varint,4,opt,name=cb_encrypted_appownershipticket" json:"cb_encrypted_appownershipticket,omitempty"` CbEncryptedAppownershipticket *uint32 `protobuf:"varint,4,opt,name=cb_encrypted_appownershipticket" json:"cb_encrypted_appownershipticket,omitempty"`
EncryptedTicket []byte `protobuf:"bytes,5,opt,name=encrypted_ticket" json:"encrypted_ticket,omitempty"` EncryptedTicket []byte `protobuf:"bytes,5,opt,name=encrypted_ticket" json:"encrypted_ticket,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *EncryptedAppTicket) Reset() { *m = EncryptedAppTicket{} } func (m *EncryptedAppTicket) Reset() { *m = EncryptedAppTicket{} }
func (m *EncryptedAppTicket) String() string { return proto.CompactTextString(m) } func (m *EncryptedAppTicket) String() string { return proto.CompactTextString(m) }
func (*EncryptedAppTicket) ProtoMessage() {} func (*EncryptedAppTicket) ProtoMessage() {}
func (*EncryptedAppTicket) Descriptor() ([]byte, []int) { return app_ticket_fileDescriptor0, []int{0} } func (*EncryptedAppTicket) Descriptor() ([]byte, []int) {
return fileDescriptor_c6d69fd1cac4e8d5, []int{0}
}
func (m *EncryptedAppTicket) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_EncryptedAppTicket.Unmarshal(m, b)
}
func (m *EncryptedAppTicket) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_EncryptedAppTicket.Marshal(b, m, deterministic)
}
func (m *EncryptedAppTicket) XXX_Merge(src proto.Message) {
xxx_messageInfo_EncryptedAppTicket.Merge(m, src)
}
func (m *EncryptedAppTicket) XXX_Size() int {
return xxx_messageInfo_EncryptedAppTicket.Size(m)
}
func (m *EncryptedAppTicket) XXX_DiscardUnknown() {
xxx_messageInfo_EncryptedAppTicket.DiscardUnknown(m)
}
var xxx_messageInfo_EncryptedAppTicket proto.InternalMessageInfo
func (m *EncryptedAppTicket) GetTicketVersionNo() uint32 { func (m *EncryptedAppTicket) GetTicketVersionNo() uint32 {
if m != nil && m.TicketVersionNo != nil { if m != nil && m.TicketVersionNo != nil {
@@ -66,17 +95,19 @@ func init() {
proto.RegisterType((*EncryptedAppTicket)(nil), "EncryptedAppTicket") proto.RegisterType((*EncryptedAppTicket)(nil), "EncryptedAppTicket")
} }
var app_ticket_fileDescriptor0 = []byte{ func init() { proto.RegisterFile("encrypted_app_ticket.proto", fileDescriptor_c6d69fd1cac4e8d5) }
// 162 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x92, 0x4a, 0xcd, 0x4b, 0x2e, var fileDescriptor_c6d69fd1cac4e8d5 = []byte{
// 164 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4a, 0xcd, 0x4b, 0x2e,
0xaa, 0x2c, 0x28, 0x49, 0x4d, 0x89, 0x4f, 0x2c, 0x28, 0x88, 0x2f, 0xc9, 0x4c, 0xce, 0x4e, 0x2d, 0xaa, 0x2c, 0x28, 0x49, 0x4d, 0x89, 0x4f, 0x2c, 0x28, 0x88, 0x2f, 0xc9, 0x4c, 0xce, 0x4e, 0x2d,
0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x5a, 0xcb, 0xc8, 0x25, 0xe4, 0x0a, 0x93, 0x76, 0x2c, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x5a, 0xcb, 0xc8, 0x25, 0xe4, 0x0a, 0x93, 0x76, 0x2c,
0x28, 0x08, 0x01, 0x4b, 0x0a, 0x49, 0x72, 0x09, 0x42, 0x94, 0xc5, 0x97, 0xa5, 0x16, 0x15, 0x67, 0x28, 0x08, 0x01, 0x4b, 0x0a, 0x49, 0x72, 0x09, 0x42, 0x94, 0xc5, 0x97, 0xa5, 0x16, 0x15, 0x67,
0xe6, 0xe7, 0xc5, 0xe7, 0xe5, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0xf0, 0x0a, 0x49, 0x73, 0x09, 0x27, 0xe6, 0xe7, 0xc5, 0xe7, 0xe5, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0xf0, 0x0a, 0x49, 0x73, 0x09, 0x27,
0x17, 0x25, 0xc7, 0xc3, 0xcd, 0x84, 0xa8, 0x93, 0x60, 0x02, 0x4b, 0xca, 0x70, 0x89, 0x24, 0x27, 0x17, 0x25, 0xc7, 0xc3, 0xcd, 0x84, 0xa8, 0x93, 0x60, 0x02, 0x4b, 0xca, 0x70, 0x89, 0x24, 0x27,
0x21, 0xe4, 0x4a, 0x8b, 0x53, 0x8b, 0x52, 0x12, 0x4b, 0x12, 0x25, 0x98, 0xc1, 0xb2, 0xea, 0x5c, 0x21, 0xe4, 0x4a, 0x8b, 0x53, 0x8b, 0x52, 0x12, 0x4b, 0x12, 0x25, 0x98, 0xc1, 0xb2, 0xea, 0x5c,
0xf2, 0xc8, 0xb2, 0x20, 0xd7, 0xe4, 0x97, 0xe7, 0x01, 0x2d, 0xc8, 0xc8, 0x2c, 0x80, 0x1a, 0xc3, 0xf2, 0xc8, 0xb2, 0x20, 0xd7, 0xe4, 0x97, 0xe7, 0xa5, 0x16, 0x15, 0x67, 0x64, 0x16, 0x40, 0x8d,
0x02, 0x56, 0x28, 0xc1, 0x25, 0x80, 0x50, 0x05, 0x95, 0x61, 0x05, 0xca, 0xf0, 0x38, 0xb1, 0x7a, 0x61, 0x01, 0x2b, 0x94, 0xe0, 0x12, 0x40, 0xa8, 0x82, 0xca, 0xb0, 0x2a, 0x30, 0x6a, 0xf0, 0x38,
0x30, 0x36, 0x30, 0x32, 0x00, 0x02, 0x00, 0x00, 0xff, 0xff, 0x03, 0x8c, 0xdb, 0x92, 0xd3, 0x00, 0xb1, 0x7a, 0x30, 0x36, 0x30, 0x32, 0x00, 0x02, 0x00, 0x00, 0xff, 0xff, 0x03, 0x8c, 0xdb, 0x92,
0x00, 0x00, 0xd3, 0x00, 0x00, 0x00,
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,397 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: steammessages_sitelicenseclient.proto
package protobuf
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package protobuf is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package protobuf to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type CMsgClientSiteInfo struct {
SiteId *uint64 `protobuf:"varint,1,opt,name=site_id" json:"site_id,omitempty"`
SiteName *string `protobuf:"bytes,2,opt,name=site_name" json:"site_name,omitempty"`
AllowCachedCredentials *bool `protobuf:"varint,3,opt,name=allow_cached_credentials" json:"allow_cached_credentials,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CMsgClientSiteInfo) Reset() { *m = CMsgClientSiteInfo{} }
func (m *CMsgClientSiteInfo) String() string { return proto.CompactTextString(m) }
func (*CMsgClientSiteInfo) ProtoMessage() {}
func (*CMsgClientSiteInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_0a32817a56a37a6e, []int{0}
}
func (m *CMsgClientSiteInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CMsgClientSiteInfo.Unmarshal(m, b)
}
func (m *CMsgClientSiteInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CMsgClientSiteInfo.Marshal(b, m, deterministic)
}
func (m *CMsgClientSiteInfo) XXX_Merge(src proto.Message) {
xxx_messageInfo_CMsgClientSiteInfo.Merge(m, src)
}
func (m *CMsgClientSiteInfo) XXX_Size() int {
return xxx_messageInfo_CMsgClientSiteInfo.Size(m)
}
func (m *CMsgClientSiteInfo) XXX_DiscardUnknown() {
xxx_messageInfo_CMsgClientSiteInfo.DiscardUnknown(m)
}
var xxx_messageInfo_CMsgClientSiteInfo proto.InternalMessageInfo
func (m *CMsgClientSiteInfo) GetSiteId() uint64 {
if m != nil && m.SiteId != nil {
return *m.SiteId
}
return 0
}
func (m *CMsgClientSiteInfo) GetSiteName() string {
if m != nil && m.SiteName != nil {
return *m.SiteName
}
return ""
}
func (m *CMsgClientSiteInfo) GetAllowCachedCredentials() bool {
if m != nil && m.AllowCachedCredentials != nil {
return *m.AllowCachedCredentials
}
return false
}
type CMsgClientSiteLicenseCheckout struct {
Appid *uint32 `protobuf:"varint,1,opt,name=appid" json:"appid,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CMsgClientSiteLicenseCheckout) Reset() { *m = CMsgClientSiteLicenseCheckout{} }
func (m *CMsgClientSiteLicenseCheckout) String() string { return proto.CompactTextString(m) }
func (*CMsgClientSiteLicenseCheckout) ProtoMessage() {}
func (*CMsgClientSiteLicenseCheckout) Descriptor() ([]byte, []int) {
return fileDescriptor_0a32817a56a37a6e, []int{1}
}
func (m *CMsgClientSiteLicenseCheckout) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CMsgClientSiteLicenseCheckout.Unmarshal(m, b)
}
func (m *CMsgClientSiteLicenseCheckout) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CMsgClientSiteLicenseCheckout.Marshal(b, m, deterministic)
}
func (m *CMsgClientSiteLicenseCheckout) XXX_Merge(src proto.Message) {
xxx_messageInfo_CMsgClientSiteLicenseCheckout.Merge(m, src)
}
func (m *CMsgClientSiteLicenseCheckout) XXX_Size() int {
return xxx_messageInfo_CMsgClientSiteLicenseCheckout.Size(m)
}
func (m *CMsgClientSiteLicenseCheckout) XXX_DiscardUnknown() {
xxx_messageInfo_CMsgClientSiteLicenseCheckout.DiscardUnknown(m)
}
var xxx_messageInfo_CMsgClientSiteLicenseCheckout proto.InternalMessageInfo
func (m *CMsgClientSiteLicenseCheckout) GetAppid() uint32 {
if m != nil && m.Appid != nil {
return *m.Appid
}
return 0
}
type CMsgClientSiteLicenseCheckoutResponse struct {
Eresult *int32 `protobuf:"varint,1,opt,name=eresult,def=2" json:"eresult,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CMsgClientSiteLicenseCheckoutResponse) Reset() { *m = CMsgClientSiteLicenseCheckoutResponse{} }
func (m *CMsgClientSiteLicenseCheckoutResponse) String() string { return proto.CompactTextString(m) }
func (*CMsgClientSiteLicenseCheckoutResponse) ProtoMessage() {}
func (*CMsgClientSiteLicenseCheckoutResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_0a32817a56a37a6e, []int{2}
}
func (m *CMsgClientSiteLicenseCheckoutResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CMsgClientSiteLicenseCheckoutResponse.Unmarshal(m, b)
}
func (m *CMsgClientSiteLicenseCheckoutResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CMsgClientSiteLicenseCheckoutResponse.Marshal(b, m, deterministic)
}
func (m *CMsgClientSiteLicenseCheckoutResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_CMsgClientSiteLicenseCheckoutResponse.Merge(m, src)
}
func (m *CMsgClientSiteLicenseCheckoutResponse) XXX_Size() int {
return xxx_messageInfo_CMsgClientSiteLicenseCheckoutResponse.Size(m)
}
func (m *CMsgClientSiteLicenseCheckoutResponse) XXX_DiscardUnknown() {
xxx_messageInfo_CMsgClientSiteLicenseCheckoutResponse.DiscardUnknown(m)
}
var xxx_messageInfo_CMsgClientSiteLicenseCheckoutResponse proto.InternalMessageInfo
const Default_CMsgClientSiteLicenseCheckoutResponse_Eresult int32 = 2
func (m *CMsgClientSiteLicenseCheckoutResponse) GetEresult() int32 {
if m != nil && m.Eresult != nil {
return *m.Eresult
}
return Default_CMsgClientSiteLicenseCheckoutResponse_Eresult
}
type CMsgClientSiteLicenseGetAvailableSeats struct {
Appid *uint32 `protobuf:"varint,1,opt,name=appid" json:"appid,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CMsgClientSiteLicenseGetAvailableSeats) Reset() {
*m = CMsgClientSiteLicenseGetAvailableSeats{}
}
func (m *CMsgClientSiteLicenseGetAvailableSeats) String() string { return proto.CompactTextString(m) }
func (*CMsgClientSiteLicenseGetAvailableSeats) ProtoMessage() {}
func (*CMsgClientSiteLicenseGetAvailableSeats) Descriptor() ([]byte, []int) {
return fileDescriptor_0a32817a56a37a6e, []int{3}
}
func (m *CMsgClientSiteLicenseGetAvailableSeats) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeats.Unmarshal(m, b)
}
func (m *CMsgClientSiteLicenseGetAvailableSeats) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeats.Marshal(b, m, deterministic)
}
func (m *CMsgClientSiteLicenseGetAvailableSeats) XXX_Merge(src proto.Message) {
xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeats.Merge(m, src)
}
func (m *CMsgClientSiteLicenseGetAvailableSeats) XXX_Size() int {
return xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeats.Size(m)
}
func (m *CMsgClientSiteLicenseGetAvailableSeats) XXX_DiscardUnknown() {
xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeats.DiscardUnknown(m)
}
var xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeats proto.InternalMessageInfo
func (m *CMsgClientSiteLicenseGetAvailableSeats) GetAppid() uint32 {
if m != nil && m.Appid != nil {
return *m.Appid
}
return 0
}
type CMsgClientSiteLicenseGetAvailableSeatsResponse struct {
Eresult *int32 `protobuf:"varint,1,opt,name=eresult,def=2" json:"eresult,omitempty"`
Seats *uint32 `protobuf:"varint,2,opt,name=seats" json:"seats,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) Reset() {
*m = CMsgClientSiteLicenseGetAvailableSeatsResponse{}
}
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) String() string {
return proto.CompactTextString(m)
}
func (*CMsgClientSiteLicenseGetAvailableSeatsResponse) ProtoMessage() {}
func (*CMsgClientSiteLicenseGetAvailableSeatsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_0a32817a56a37a6e, []int{4}
}
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeatsResponse.Unmarshal(m, b)
}
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeatsResponse.Marshal(b, m, deterministic)
}
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeatsResponse.Merge(m, src)
}
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) XXX_Size() int {
return xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeatsResponse.Size(m)
}
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) XXX_DiscardUnknown() {
xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeatsResponse.DiscardUnknown(m)
}
var xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeatsResponse proto.InternalMessageInfo
const Default_CMsgClientSiteLicenseGetAvailableSeatsResponse_Eresult int32 = 2
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) GetEresult() int32 {
if m != nil && m.Eresult != nil {
return *m.Eresult
}
return Default_CMsgClientSiteLicenseGetAvailableSeatsResponse_Eresult
}
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) GetSeats() uint32 {
if m != nil && m.Seats != nil {
return *m.Seats
}
return 0
}
type CMsgClientSiteLicenseGetContentCacheInfo struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CMsgClientSiteLicenseGetContentCacheInfo) Reset() {
*m = CMsgClientSiteLicenseGetContentCacheInfo{}
}
func (m *CMsgClientSiteLicenseGetContentCacheInfo) String() string { return proto.CompactTextString(m) }
func (*CMsgClientSiteLicenseGetContentCacheInfo) ProtoMessage() {}
func (*CMsgClientSiteLicenseGetContentCacheInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_0a32817a56a37a6e, []int{5}
}
func (m *CMsgClientSiteLicenseGetContentCacheInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfo.Unmarshal(m, b)
}
func (m *CMsgClientSiteLicenseGetContentCacheInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfo.Marshal(b, m, deterministic)
}
func (m *CMsgClientSiteLicenseGetContentCacheInfo) XXX_Merge(src proto.Message) {
xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfo.Merge(m, src)
}
func (m *CMsgClientSiteLicenseGetContentCacheInfo) XXX_Size() int {
return xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfo.Size(m)
}
func (m *CMsgClientSiteLicenseGetContentCacheInfo) XXX_DiscardUnknown() {
xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfo.DiscardUnknown(m)
}
var xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfo proto.InternalMessageInfo
type CMsgClientSiteLicenseGetContentCacheInfoResponse struct {
UseCache *bool `protobuf:"varint,1,opt,name=use_cache" json:"use_cache,omitempty"`
Ipv4Address *uint32 `protobuf:"varint,2,opt,name=ipv4_address" json:"ipv4_address,omitempty"`
PortNumber *uint32 `protobuf:"varint,3,opt,name=port_number" json:"port_number,omitempty"`
P2PGroup *uint32 `protobuf:"varint,4,opt,name=p2p_group" json:"p2p_group,omitempty"`
IpAddress *string `protobuf:"bytes,5,opt,name=ip_address" json:"ip_address,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) Reset() {
*m = CMsgClientSiteLicenseGetContentCacheInfoResponse{}
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) String() string {
return proto.CompactTextString(m)
}
func (*CMsgClientSiteLicenseGetContentCacheInfoResponse) ProtoMessage() {}
func (*CMsgClientSiteLicenseGetContentCacheInfoResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_0a32817a56a37a6e, []int{6}
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfoResponse.Unmarshal(m, b)
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfoResponse.Marshal(b, m, deterministic)
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfoResponse.Merge(m, src)
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) XXX_Size() int {
return xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfoResponse.Size(m)
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) XXX_DiscardUnknown() {
xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfoResponse.DiscardUnknown(m)
}
var xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfoResponse proto.InternalMessageInfo
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) GetUseCache() bool {
if m != nil && m.UseCache != nil {
return *m.UseCache
}
return false
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) GetIpv4Address() uint32 {
if m != nil && m.Ipv4Address != nil {
return *m.Ipv4Address
}
return 0
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) GetPortNumber() uint32 {
if m != nil && m.PortNumber != nil {
return *m.PortNumber
}
return 0
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) GetP2PGroup() uint32 {
if m != nil && m.P2PGroup != nil {
return *m.P2PGroup
}
return 0
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) GetIpAddress() string {
if m != nil && m.IpAddress != nil {
return *m.IpAddress
}
return ""
}
func init() {
proto.RegisterType((*CMsgClientSiteInfo)(nil), "CMsgClientSiteInfo")
proto.RegisterType((*CMsgClientSiteLicenseCheckout)(nil), "CMsgClientSiteLicenseCheckout")
proto.RegisterType((*CMsgClientSiteLicenseCheckoutResponse)(nil), "CMsgClientSiteLicenseCheckoutResponse")
proto.RegisterType((*CMsgClientSiteLicenseGetAvailableSeats)(nil), "CMsgClientSiteLicenseGetAvailableSeats")
proto.RegisterType((*CMsgClientSiteLicenseGetAvailableSeatsResponse)(nil), "CMsgClientSiteLicenseGetAvailableSeatsResponse")
proto.RegisterType((*CMsgClientSiteLicenseGetContentCacheInfo)(nil), "CMsgClientSiteLicenseGetContentCacheInfo")
proto.RegisterType((*CMsgClientSiteLicenseGetContentCacheInfoResponse)(nil), "CMsgClientSiteLicenseGetContentCacheInfoResponse")
}
func init() {
proto.RegisterFile("steammessages_sitelicenseclient.proto", fileDescriptor_0a32817a56a37a6e)
}
var fileDescriptor_0a32817a56a37a6e = []byte{
// 335 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0x41, 0x4b, 0xfb, 0x40,
0x14, 0xc4, 0xff, 0xfb, 0xb7, 0xa1, 0xed, 0xd3, 0x20, 0x5d, 0x3d, 0x04, 0x41, 0x08, 0x81, 0x4a,
0xf0, 0x50, 0xa4, 0x08, 0x82, 0x9e, 0x34, 0x07, 0x15, 0xf4, 0x62, 0x6f, 0x5e, 0xc2, 0x36, 0x79,
0xb6, 0x8b, 0x9b, 0xdd, 0x25, 0x6f, 0x53, 0xaf, 0x7e, 0x0b, 0xbf, 0xae, 0x64, 0x5b, 0x0a, 0x15,
0x2d, 0xbd, 0xee, 0xce, 0x6f, 0x66, 0x98, 0x07, 0x43, 0x72, 0x28, 0xaa, 0x0a, 0x89, 0xc4, 0x0c,
0x29, 0x27, 0xe9, 0x50, 0xc9, 0x02, 0x35, 0x61, 0xa1, 0x24, 0x6a, 0x37, 0xb2, 0xb5, 0x71, 0xe6,
0x24, 0xda, 0x94, 0x4d, 0x05, 0xe1, 0xf2, 0x27, 0x79, 0x05, 0x9e, 0x3d, 0xd3, 0x2c, 0xf3, 0xea,
0x89, 0x74, 0xf8, 0xa8, 0xdf, 0x0c, 0x3f, 0x84, 0x6e, 0x6b, 0x95, 0xcb, 0x32, 0x62, 0x31, 0x4b,
0x3b, 0x7c, 0x00, 0x7d, 0xff, 0xa0, 0x45, 0x85, 0xd1, 0xff, 0x98, 0xa5, 0x7d, 0x1e, 0x43, 0x24,
0x94, 0x32, 0x1f, 0x79, 0x21, 0x8a, 0x39, 0x96, 0x79, 0x51, 0x63, 0x89, 0xda, 0x49, 0xa1, 0x28,
0xda, 0x8b, 0x59, 0xda, 0x4b, 0x46, 0x70, 0xba, 0xe9, 0xfd, 0xb4, 0xac, 0x96, 0xcd, 0xb1, 0x78,
0x37, 0x8d, 0xe3, 0x21, 0x04, 0xc2, 0xda, 0x55, 0x48, 0x98, 0xdc, 0xc0, 0x70, 0xab, 0xfe, 0x05,
0xc9, 0x1a, 0x4d, 0xc8, 0x39, 0x74, 0xb1, 0x46, 0x6a, 0x94, 0xf3, 0x64, 0x70, 0xcd, 0xc6, 0xc9,
0x15, 0x9c, 0xfd, 0x0a, 0xdf, 0xa3, 0xbb, 0x5d, 0x08, 0xa9, 0xc4, 0x54, 0xe1, 0x04, 0x85, 0xa3,
0x9f, 0xa9, 0x13, 0x18, 0xed, 0x06, 0x6e, 0x8b, 0x6f, 0x4d, 0xa9, 0x15, 0xf9, 0x71, 0xc2, 0xe4,
0x1c, 0xd2, 0xbf, 0x4c, 0x33, 0xa3, 0x1d, 0x6a, 0x97, 0xb5, 0xab, 0xb5, 0x63, 0x27, 0x5f, 0x0c,
0x2e, 0x76, 0x15, 0xaf, 0x3b, 0x0c, 0xa0, 0xdf, 0x10, 0x2e, 0xb7, 0xf7, 0x2d, 0x7a, 0xfc, 0x18,
0x0e, 0xa4, 0x5d, 0x5c, 0xe6, 0xa2, 0x2c, 0x6b, 0xa4, 0x55, 0x13, 0x7e, 0x04, 0xfb, 0xd6, 0xd4,
0x2e, 0xd7, 0x4d, 0x35, 0xc5, 0xda, 0x5f, 0x26, 0x6c, 0x69, 0x3b, 0xb6, 0xf9, 0xac, 0x36, 0x8d,
0x8d, 0x3a, 0xfe, 0x89, 0x03, 0x48, 0xbb, 0x66, 0x83, 0xf6, 0xc4, 0x77, 0xc1, 0x03, 0xfb, 0x64,
0xff, 0xbe, 0x03, 0x00, 0x00, 0xff, 0xff, 0x09, 0x2f, 0x9f, 0xe9, 0x65, 0x02, 0x00, 0x00,
}

View File

@@ -1,27 +1,56 @@
// Code generated by protoc-gen-go. // Code generated by protoc-gen-go. DO NOT EDIT.
// source: content_manifest.proto // source: content_manifest.proto
// DO NOT EDIT!
package protobuf package protobuf
import proto "github.com/golang/protobuf/proto" import (
import fmt "fmt" fmt "fmt"
import math "math" proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal var _ = proto.Marshal
var _ = fmt.Errorf var _ = fmt.Errorf
var _ = math.Inf var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package protobuf is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package protobuf to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type ContentManifestPayload struct { type ContentManifestPayload struct {
Mappings []*ContentManifestPayload_FileMapping `protobuf:"bytes,1,rep,name=mappings" json:"mappings,omitempty"` Mappings []*ContentManifestPayload_FileMapping `protobuf:"bytes,1,rep,name=mappings" json:"mappings,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *ContentManifestPayload) Reset() { *m = ContentManifestPayload{} } func (m *ContentManifestPayload) Reset() { *m = ContentManifestPayload{} }
func (m *ContentManifestPayload) String() string { return proto.CompactTextString(m) } func (m *ContentManifestPayload) String() string { return proto.CompactTextString(m) }
func (*ContentManifestPayload) ProtoMessage() {} func (*ContentManifestPayload) ProtoMessage() {}
func (*ContentManifestPayload) Descriptor() ([]byte, []int) { return content_manifest_fileDescriptor0, []int{0} } func (*ContentManifestPayload) Descriptor() ([]byte, []int) {
return fileDescriptor_e3cda137a29253ba, []int{0}
}
func (m *ContentManifestPayload) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContentManifestPayload.Unmarshal(m, b)
}
func (m *ContentManifestPayload) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContentManifestPayload.Marshal(b, m, deterministic)
}
func (m *ContentManifestPayload) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContentManifestPayload.Merge(m, src)
}
func (m *ContentManifestPayload) XXX_Size() int {
return xxx_messageInfo_ContentManifestPayload.Size(m)
}
func (m *ContentManifestPayload) XXX_DiscardUnknown() {
xxx_messageInfo_ContentManifestPayload.DiscardUnknown(m)
}
var xxx_messageInfo_ContentManifestPayload proto.InternalMessageInfo
func (m *ContentManifestPayload) GetMappings() []*ContentManifestPayload_FileMapping { func (m *ContentManifestPayload) GetMappings() []*ContentManifestPayload_FileMapping {
if m != nil { if m != nil {
@@ -38,16 +67,36 @@ type ContentManifestPayload_FileMapping struct {
ShaContent []byte `protobuf:"bytes,5,opt,name=sha_content" json:"sha_content,omitempty"` ShaContent []byte `protobuf:"bytes,5,opt,name=sha_content" json:"sha_content,omitempty"`
Chunks []*ContentManifestPayload_FileMapping_ChunkData `protobuf:"bytes,6,rep,name=chunks" json:"chunks,omitempty"` Chunks []*ContentManifestPayload_FileMapping_ChunkData `protobuf:"bytes,6,rep,name=chunks" json:"chunks,omitempty"`
Linktarget *string `protobuf:"bytes,7,opt,name=linktarget" json:"linktarget,omitempty"` Linktarget *string `protobuf:"bytes,7,opt,name=linktarget" json:"linktarget,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *ContentManifestPayload_FileMapping) Reset() { *m = ContentManifestPayload_FileMapping{} } func (m *ContentManifestPayload_FileMapping) Reset() { *m = ContentManifestPayload_FileMapping{} }
func (m *ContentManifestPayload_FileMapping) String() string { return proto.CompactTextString(m) } func (m *ContentManifestPayload_FileMapping) String() string { return proto.CompactTextString(m) }
func (*ContentManifestPayload_FileMapping) ProtoMessage() {} func (*ContentManifestPayload_FileMapping) ProtoMessage() {}
func (*ContentManifestPayload_FileMapping) Descriptor() ([]byte, []int) { func (*ContentManifestPayload_FileMapping) Descriptor() ([]byte, []int) {
return content_manifest_fileDescriptor0, []int{0, 0} return fileDescriptor_e3cda137a29253ba, []int{0, 0}
} }
func (m *ContentManifestPayload_FileMapping) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContentManifestPayload_FileMapping.Unmarshal(m, b)
}
func (m *ContentManifestPayload_FileMapping) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContentManifestPayload_FileMapping.Marshal(b, m, deterministic)
}
func (m *ContentManifestPayload_FileMapping) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContentManifestPayload_FileMapping.Merge(m, src)
}
func (m *ContentManifestPayload_FileMapping) XXX_Size() int {
return xxx_messageInfo_ContentManifestPayload_FileMapping.Size(m)
}
func (m *ContentManifestPayload_FileMapping) XXX_DiscardUnknown() {
xxx_messageInfo_ContentManifestPayload_FileMapping.DiscardUnknown(m)
}
var xxx_messageInfo_ContentManifestPayload_FileMapping proto.InternalMessageInfo
func (m *ContentManifestPayload_FileMapping) GetFilename() string { func (m *ContentManifestPayload_FileMapping) GetFilename() string {
if m != nil && m.Filename != nil { if m != nil && m.Filename != nil {
return *m.Filename return *m.Filename
@@ -103,7 +152,9 @@ type ContentManifestPayload_FileMapping_ChunkData struct {
Offset *uint64 `protobuf:"varint,3,opt,name=offset" json:"offset,omitempty"` Offset *uint64 `protobuf:"varint,3,opt,name=offset" json:"offset,omitempty"`
CbOriginal *uint32 `protobuf:"varint,4,opt,name=cb_original" json:"cb_original,omitempty"` CbOriginal *uint32 `protobuf:"varint,4,opt,name=cb_original" json:"cb_original,omitempty"`
CbCompressed *uint32 `protobuf:"varint,5,opt,name=cb_compressed" json:"cb_compressed,omitempty"` CbCompressed *uint32 `protobuf:"varint,5,opt,name=cb_compressed" json:"cb_compressed,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *ContentManifestPayload_FileMapping_ChunkData) Reset() { func (m *ContentManifestPayload_FileMapping_ChunkData) Reset() {
@@ -114,9 +165,27 @@ func (m *ContentManifestPayload_FileMapping_ChunkData) String() string {
} }
func (*ContentManifestPayload_FileMapping_ChunkData) ProtoMessage() {} func (*ContentManifestPayload_FileMapping_ChunkData) ProtoMessage() {}
func (*ContentManifestPayload_FileMapping_ChunkData) Descriptor() ([]byte, []int) { func (*ContentManifestPayload_FileMapping_ChunkData) Descriptor() ([]byte, []int) {
return content_manifest_fileDescriptor0, []int{0, 0, 0} return fileDescriptor_e3cda137a29253ba, []int{0, 0, 0}
} }
func (m *ContentManifestPayload_FileMapping_ChunkData) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContentManifestPayload_FileMapping_ChunkData.Unmarshal(m, b)
}
func (m *ContentManifestPayload_FileMapping_ChunkData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContentManifestPayload_FileMapping_ChunkData.Marshal(b, m, deterministic)
}
func (m *ContentManifestPayload_FileMapping_ChunkData) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContentManifestPayload_FileMapping_ChunkData.Merge(m, src)
}
func (m *ContentManifestPayload_FileMapping_ChunkData) XXX_Size() int {
return xxx_messageInfo_ContentManifestPayload_FileMapping_ChunkData.Size(m)
}
func (m *ContentManifestPayload_FileMapping_ChunkData) XXX_DiscardUnknown() {
xxx_messageInfo_ContentManifestPayload_FileMapping_ChunkData.DiscardUnknown(m)
}
var xxx_messageInfo_ContentManifestPayload_FileMapping_ChunkData proto.InternalMessageInfo
func (m *ContentManifestPayload_FileMapping_ChunkData) GetSha() []byte { func (m *ContentManifestPayload_FileMapping_ChunkData) GetSha() []byte {
if m != nil { if m != nil {
return m.Sha return m.Sha
@@ -162,13 +231,35 @@ type ContentManifestMetadata struct {
UniqueChunks *uint32 `protobuf:"varint,7,opt,name=unique_chunks" json:"unique_chunks,omitempty"` UniqueChunks *uint32 `protobuf:"varint,7,opt,name=unique_chunks" json:"unique_chunks,omitempty"`
CrcEncrypted *uint32 `protobuf:"varint,8,opt,name=crc_encrypted" json:"crc_encrypted,omitempty"` CrcEncrypted *uint32 `protobuf:"varint,8,opt,name=crc_encrypted" json:"crc_encrypted,omitempty"`
CrcClear *uint32 `protobuf:"varint,9,opt,name=crc_clear" json:"crc_clear,omitempty"` CrcClear *uint32 `protobuf:"varint,9,opt,name=crc_clear" json:"crc_clear,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *ContentManifestMetadata) Reset() { *m = ContentManifestMetadata{} } func (m *ContentManifestMetadata) Reset() { *m = ContentManifestMetadata{} }
func (m *ContentManifestMetadata) String() string { return proto.CompactTextString(m) } func (m *ContentManifestMetadata) String() string { return proto.CompactTextString(m) }
func (*ContentManifestMetadata) ProtoMessage() {} func (*ContentManifestMetadata) ProtoMessage() {}
func (*ContentManifestMetadata) Descriptor() ([]byte, []int) { return content_manifest_fileDescriptor0, []int{1} } func (*ContentManifestMetadata) Descriptor() ([]byte, []int) {
return fileDescriptor_e3cda137a29253ba, []int{1}
}
func (m *ContentManifestMetadata) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContentManifestMetadata.Unmarshal(m, b)
}
func (m *ContentManifestMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContentManifestMetadata.Marshal(b, m, deterministic)
}
func (m *ContentManifestMetadata) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContentManifestMetadata.Merge(m, src)
}
func (m *ContentManifestMetadata) XXX_Size() int {
return xxx_messageInfo_ContentManifestMetadata.Size(m)
}
func (m *ContentManifestMetadata) XXX_DiscardUnknown() {
xxx_messageInfo_ContentManifestMetadata.DiscardUnknown(m)
}
var xxx_messageInfo_ContentManifestMetadata proto.InternalMessageInfo
func (m *ContentManifestMetadata) GetDepotId() uint32 { func (m *ContentManifestMetadata) GetDepotId() uint32 {
if m != nil && m.DepotId != nil { if m != nil && m.DepotId != nil {
@@ -235,13 +326,35 @@ func (m *ContentManifestMetadata) GetCrcClear() uint32 {
type ContentManifestSignature struct { type ContentManifestSignature struct {
Signature []byte `protobuf:"bytes,1,opt,name=signature" json:"signature,omitempty"` Signature []byte `protobuf:"bytes,1,opt,name=signature" json:"signature,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *ContentManifestSignature) Reset() { *m = ContentManifestSignature{} } func (m *ContentManifestSignature) Reset() { *m = ContentManifestSignature{} }
func (m *ContentManifestSignature) String() string { return proto.CompactTextString(m) } func (m *ContentManifestSignature) String() string { return proto.CompactTextString(m) }
func (*ContentManifestSignature) ProtoMessage() {} func (*ContentManifestSignature) ProtoMessage() {}
func (*ContentManifestSignature) Descriptor() ([]byte, []int) { return content_manifest_fileDescriptor0, []int{2} } func (*ContentManifestSignature) Descriptor() ([]byte, []int) {
return fileDescriptor_e3cda137a29253ba, []int{2}
}
func (m *ContentManifestSignature) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContentManifestSignature.Unmarshal(m, b)
}
func (m *ContentManifestSignature) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContentManifestSignature.Marshal(b, m, deterministic)
}
func (m *ContentManifestSignature) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContentManifestSignature.Merge(m, src)
}
func (m *ContentManifestSignature) XXX_Size() int {
return xxx_messageInfo_ContentManifestSignature.Size(m)
}
func (m *ContentManifestSignature) XXX_DiscardUnknown() {
xxx_messageInfo_ContentManifestSignature.DiscardUnknown(m)
}
var xxx_messageInfo_ContentManifestSignature proto.InternalMessageInfo
func (m *ContentManifestSignature) GetSignature() []byte { func (m *ContentManifestSignature) GetSignature() []byte {
if m != nil { if m != nil {
@@ -250,40 +363,184 @@ func (m *ContentManifestSignature) GetSignature() []byte {
return nil return nil
} }
type ContentDeltaChunks struct {
DepotId *uint32 `protobuf:"varint,1,opt,name=depot_id" json:"depot_id,omitempty"`
ManifestIdSource *uint64 `protobuf:"varint,2,opt,name=manifest_id_source" json:"manifest_id_source,omitempty"`
ManifestIdTarget *uint64 `protobuf:"varint,3,opt,name=manifest_id_target" json:"manifest_id_target,omitempty"`
DeltaChunks []*ContentDeltaChunks_DeltaChunk `protobuf:"bytes,4,rep,name=deltaChunks" json:"deltaChunks,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ContentDeltaChunks) Reset() { *m = ContentDeltaChunks{} }
func (m *ContentDeltaChunks) String() string { return proto.CompactTextString(m) }
func (*ContentDeltaChunks) ProtoMessage() {}
func (*ContentDeltaChunks) Descriptor() ([]byte, []int) {
return fileDescriptor_e3cda137a29253ba, []int{3}
}
func (m *ContentDeltaChunks) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContentDeltaChunks.Unmarshal(m, b)
}
func (m *ContentDeltaChunks) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContentDeltaChunks.Marshal(b, m, deterministic)
}
func (m *ContentDeltaChunks) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContentDeltaChunks.Merge(m, src)
}
func (m *ContentDeltaChunks) XXX_Size() int {
return xxx_messageInfo_ContentDeltaChunks.Size(m)
}
func (m *ContentDeltaChunks) XXX_DiscardUnknown() {
xxx_messageInfo_ContentDeltaChunks.DiscardUnknown(m)
}
var xxx_messageInfo_ContentDeltaChunks proto.InternalMessageInfo
func (m *ContentDeltaChunks) GetDepotId() uint32 {
if m != nil && m.DepotId != nil {
return *m.DepotId
}
return 0
}
func (m *ContentDeltaChunks) GetManifestIdSource() uint64 {
if m != nil && m.ManifestIdSource != nil {
return *m.ManifestIdSource
}
return 0
}
func (m *ContentDeltaChunks) GetManifestIdTarget() uint64 {
if m != nil && m.ManifestIdTarget != nil {
return *m.ManifestIdTarget
}
return 0
}
func (m *ContentDeltaChunks) GetDeltaChunks() []*ContentDeltaChunks_DeltaChunk {
if m != nil {
return m.DeltaChunks
}
return nil
}
type ContentDeltaChunks_DeltaChunk struct {
ShaSource []byte `protobuf:"bytes,1,opt,name=sha_source" json:"sha_source,omitempty"`
ShaTarget []byte `protobuf:"bytes,2,opt,name=sha_target" json:"sha_target,omitempty"`
SizeOriginal *uint32 `protobuf:"varint,3,opt,name=size_original" json:"size_original,omitempty"`
PatchMethod *uint32 `protobuf:"varint,4,opt,name=patch_method" json:"patch_method,omitempty"`
Chunk []byte `protobuf:"bytes,5,opt,name=chunk" json:"chunk,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ContentDeltaChunks_DeltaChunk) Reset() { *m = ContentDeltaChunks_DeltaChunk{} }
func (m *ContentDeltaChunks_DeltaChunk) String() string { return proto.CompactTextString(m) }
func (*ContentDeltaChunks_DeltaChunk) ProtoMessage() {}
func (*ContentDeltaChunks_DeltaChunk) Descriptor() ([]byte, []int) {
return fileDescriptor_e3cda137a29253ba, []int{3, 0}
}
func (m *ContentDeltaChunks_DeltaChunk) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContentDeltaChunks_DeltaChunk.Unmarshal(m, b)
}
func (m *ContentDeltaChunks_DeltaChunk) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContentDeltaChunks_DeltaChunk.Marshal(b, m, deterministic)
}
func (m *ContentDeltaChunks_DeltaChunk) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContentDeltaChunks_DeltaChunk.Merge(m, src)
}
func (m *ContentDeltaChunks_DeltaChunk) XXX_Size() int {
return xxx_messageInfo_ContentDeltaChunks_DeltaChunk.Size(m)
}
func (m *ContentDeltaChunks_DeltaChunk) XXX_DiscardUnknown() {
xxx_messageInfo_ContentDeltaChunks_DeltaChunk.DiscardUnknown(m)
}
var xxx_messageInfo_ContentDeltaChunks_DeltaChunk proto.InternalMessageInfo
func (m *ContentDeltaChunks_DeltaChunk) GetShaSource() []byte {
if m != nil {
return m.ShaSource
}
return nil
}
func (m *ContentDeltaChunks_DeltaChunk) GetShaTarget() []byte {
if m != nil {
return m.ShaTarget
}
return nil
}
func (m *ContentDeltaChunks_DeltaChunk) GetSizeOriginal() uint32 {
if m != nil && m.SizeOriginal != nil {
return *m.SizeOriginal
}
return 0
}
func (m *ContentDeltaChunks_DeltaChunk) GetPatchMethod() uint32 {
if m != nil && m.PatchMethod != nil {
return *m.PatchMethod
}
return 0
}
func (m *ContentDeltaChunks_DeltaChunk) GetChunk() []byte {
if m != nil {
return m.Chunk
}
return nil
}
func init() { func init() {
proto.RegisterType((*ContentManifestPayload)(nil), "ContentManifestPayload") proto.RegisterType((*ContentManifestPayload)(nil), "ContentManifestPayload")
proto.RegisterType((*ContentManifestPayload_FileMapping)(nil), "ContentManifestPayload.FileMapping") proto.RegisterType((*ContentManifestPayload_FileMapping)(nil), "ContentManifestPayload.FileMapping")
proto.RegisterType((*ContentManifestPayload_FileMapping_ChunkData)(nil), "ContentManifestPayload.FileMapping.ChunkData") proto.RegisterType((*ContentManifestPayload_FileMapping_ChunkData)(nil), "ContentManifestPayload.FileMapping.ChunkData")
proto.RegisterType((*ContentManifestMetadata)(nil), "ContentManifestMetadata") proto.RegisterType((*ContentManifestMetadata)(nil), "ContentManifestMetadata")
proto.RegisterType((*ContentManifestSignature)(nil), "ContentManifestSignature") proto.RegisterType((*ContentManifestSignature)(nil), "ContentManifestSignature")
proto.RegisterType((*ContentDeltaChunks)(nil), "ContentDeltaChunks")
proto.RegisterType((*ContentDeltaChunks_DeltaChunk)(nil), "ContentDeltaChunks.DeltaChunk")
} }
var content_manifest_fileDescriptor0 = []byte{ func init() { proto.RegisterFile("content_manifest.proto", fileDescriptor_e3cda137a29253ba) }
// 409 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x91, 0xbd, 0x8e, 0xd4, 0x30, var fileDescriptor_e3cda137a29253ba = []byte{
0x14, 0x85, 0xc9, 0xfc, 0x26, 0x37, 0x09, 0x5a, 0xbc, 0xb0, 0x58, 0x43, 0x83, 0x96, 0x66, 0x9b, // 508 bytes of a gzipped FileDescriptorProto
0x4d, 0x81, 0x44, 0x49, 0xc3, 0x22, 0x44, 0x33, 0x12, 0x12, 0x0f, 0x10, 0x5d, 0x1c, 0x27, 0x6b, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xcd, 0x8e, 0xd3, 0x30,
0x4d, 0x62, 0x07, 0xdb, 0x29, 0x96, 0x8a, 0x17, 0xe1, 0x0d, 0x91, 0x78, 0x05, 0x6c, 0x27, 0x99, 0x10, 0xc7, 0x49, 0xbf, 0x3b, 0x6d, 0x50, 0xf1, 0xb2, 0x8b, 0x55, 0x24, 0x54, 0x95, 0x4b, 0x2f,
0x1d, 0x8d, 0x28, 0x28, 0xcf, 0xf1, 0xb5, 0xcf, 0x77, 0x8f, 0xe1, 0x8a, 0x29, 0x69, 0xb9, 0xb4, 0x9b, 0x03, 0x88, 0x23, 0x17, 0x76, 0x85, 0xb8, 0x54, 0x42, 0xe2, 0x01, 0x2c, 0xd7, 0x76, 0x53,
0x65, 0x87, 0x52, 0xd4, 0xdc, 0xd8, 0xa2, 0xd7, 0xca, 0xaa, 0xeb, 0x3f, 0x0b, 0xb8, 0xba, 0x1b, 0xab, 0x89, 0x1d, 0x6c, 0xe7, 0xb0, 0x9c, 0xb8, 0xf0, 0x18, 0xbc, 0x21, 0x12, 0xaf, 0x80, 0xec,
0x8f, 0xf6, 0xd3, 0xc9, 0x17, 0x7c, 0x68, 0x15, 0x56, 0xe4, 0x1d, 0xc4, 0x1d, 0xf6, 0xbd, 0x90, 0x38, 0x4d, 0x55, 0xf6, 0xb0, 0xb7, 0xcc, 0x47, 0x3c, 0xbf, 0xf9, 0xcf, 0x1f, 0x6e, 0x98, 0x56,
0x8d, 0xa1, 0xd1, 0xeb, 0xe5, 0x4d, 0xfa, 0xf6, 0x4d, 0xf1, 0xef, 0xd1, 0xe2, 0x93, 0x68, 0xf9, 0x4e, 0x28, 0x47, 0x4a, 0xaa, 0xe4, 0x5e, 0x58, 0x97, 0x55, 0x46, 0x3b, 0xbd, 0xfe, 0xdb, 0x83,
0x7e, 0x9c, 0xdd, 0xfd, 0x5a, 0x40, 0x7a, 0xa2, 0xc9, 0x05, 0xc4, 0xb5, 0x93, 0x12, 0x3b, 0xee, 0x9b, 0xbb, 0xa6, 0xb4, 0x8d, 0x95, 0xaf, 0xf4, 0xa1, 0xd0, 0x94, 0xa3, 0x0f, 0x30, 0x29, 0x69,
0x9e, 0x89, 0x6e, 0x12, 0x92, 0xc1, 0xca, 0x88, 0x1f, 0x9c, 0x2e, 0x9c, 0x5a, 0x91, 0x1c, 0xd6, 0x55, 0x49, 0x95, 0x5b, 0x9c, 0xac, 0xfa, 0x9b, 0xd9, 0xbb, 0xb7, 0xd9, 0xe3, 0xad, 0xd9, 0x67,
0x75, 0x8b, 0x2e, 0x63, 0xe9, 0x64, 0x4e, 0x9e, 0x43, 0x66, 0xee, 0xb1, 0x3c, 0x5e, 0x59, 0x39, 0x59, 0x88, 0x6d, 0xd3, 0xbb, 0xfc, 0xdd, 0x83, 0xd9, 0x59, 0x8c, 0x16, 0x30, 0xd9, 0xcb, 0x42,
0x37, 0x23, 0x97, 0x90, 0x7a, 0x77, 0x5a, 0x82, 0xae, 0x83, 0xf9, 0x1e, 0x36, 0xec, 0x7e, 0x90, 0x28, 0x5a, 0x0a, 0x9c, 0xac, 0x92, 0xcd, 0x14, 0xcd, 0x61, 0x60, 0xe5, 0x0f, 0x81, 0x7b, 0xab,
0x07, 0x43, 0x37, 0x01, 0xef, 0xf6, 0x3f, 0xf0, 0x8a, 0x3b, 0x7f, 0xe3, 0x23, 0x5a, 0x24, 0x04, 0x64, 0x33, 0x40, 0x29, 0x0c, 0xf7, 0x05, 0xcd, 0x2d, 0xee, 0xaf, 0x92, 0x4d, 0x8a, 0x5e, 0xc2,
0xa0, 0x15, 0xf2, 0x60, 0x51, 0x37, 0xdc, 0xd2, 0xad, 0x47, 0xdb, 0x21, 0x24, 0x8f, 0x03, 0x29, 0xdc, 0x1e, 0x28, 0x39, 0xfd, 0x32, 0x58, 0x25, 0x9b, 0x39, 0xba, 0x82, 0x99, 0xcf, 0xc6, 0x25,
0x2c, 0x5d, 0x68, 0x80, 0xce, 0xbc, 0x60, 0x9a, 0x05, 0xe6, 0x2d, 0x79, 0x0a, 0x1b, 0x55, 0xd7, 0xf0, 0x30, 0x24, 0x3f, 0xc2, 0x88, 0x1d, 0x6a, 0x75, 0xb4, 0x78, 0x14, 0xf0, 0x6e, 0x9f, 0x80,
0xc6, 0x5d, 0x5b, 0x86, 0x1d, 0x1c, 0x1e, 0xfb, 0x56, 0x2a, 0x2d, 0x1a, 0x21, 0xb1, 0x0d, 0xcc, 0x97, 0xdd, 0xf9, 0x3f, 0xee, 0xa9, 0xa3, 0x08, 0x01, 0x14, 0x52, 0x1d, 0x1d, 0x35, 0xb9, 0x70,
0x39, 0x79, 0x01, 0xb9, 0x33, 0x99, 0xea, 0x7a, 0xcd, 0x8d, 0xe1, 0x55, 0xa0, 0xce, 0xaf, 0x7f, 0x78, 0xec, 0xd1, 0x96, 0x14, 0xa6, 0x5d, 0xc3, 0x0c, 0xfa, 0xf6, 0x40, 0x03, 0xf4, 0xdc, 0x07,
0x47, 0xf0, 0xf2, 0x8c, 0x73, 0xcf, 0x2d, 0x56, 0x3e, 0xd1, 0x75, 0x55, 0xf1, 0x5e, 0xd9, 0x52, 0xcc, 0xb0, 0xc0, 0x3c, 0x46, 0xcf, 0x61, 0xa4, 0xf7, 0x7b, 0x2b, 0x5c, 0x80, 0x1e, 0x78, 0x3c,
0x54, 0x21, 0x36, 0xd4, 0xd1, 0x88, 0xea, 0xf8, 0x6b, 0x53, 0x67, 0xfe, 0x69, 0xcd, 0xd1, 0x0a, 0xb6, 0x23, 0xda, 0xc8, 0x5c, 0x2a, 0x5a, 0x04, 0xe6, 0x14, 0x5d, 0x43, 0xca, 0x76, 0x84, 0xe9,
0x25, 0x4b, 0x2b, 0x5c, 0x4b, 0x63, 0x77, 0xaf, 0xe0, 0x72, 0xee, 0xcd, 0x94, 0x5c, 0x32, 0xfd, 0xb2, 0x32, 0xc2, 0x5a, 0xc1, 0x03, 0x75, 0xba, 0xfe, 0x93, 0xc0, 0xab, 0x0b, 0xce, 0xad, 0x70,
0xd0, 0x5b, 0x97, 0xeb, 0x71, 0x62, 0x42, 0xe1, 0xc2, 0xe1, 0x54, 0xc2, 0x1c, 0x1e, 0x41, 0xd7, 0x94, 0xfb, 0x89, 0x0b, 0x98, 0x70, 0x51, 0x69, 0x47, 0x24, 0x0f, 0x63, 0x83, 0x1c, 0xb9, 0xe4,
0xe1, 0xb5, 0x1d, 0x90, 0xf9, 0xe4, 0x84, 0x76, 0x33, 0x27, 0x0d, 0x52, 0x7c, 0x1f, 0x78, 0x39, 0xa7, 0xab, 0x45, 0xcd, 0xfc, 0xd3, 0x46, 0x50, 0x27, 0xb5, 0x22, 0x4e, 0x96, 0x22, 0x6a, 0xf7,
0x55, 0xbd, 0x3d, 0xee, 0xa6, 0xd9, 0x49, 0x46, 0x1c, 0xec, 0x67, 0x90, 0x78, 0x9b, 0xb5, 0x1c, 0x1a, 0xae, 0x5a, 0xdd, 0x2c, 0x11, 0x8a, 0x99, 0x87, 0xca, 0x09, 0x1e, 0x70, 0x26, 0x08, 0xc3,
0x35, 0x4d, 0xc2, 0xba, 0xb7, 0x40, 0xcf, 0xb6, 0xfd, 0x2a, 0x1a, 0x89, 0x76, 0xd0, 0xdc, 0x8f, 0x82, 0xed, 0x08, 0x97, 0xf6, 0xd8, 0x81, 0x0e, 0xc3, 0x6b, 0x4b, 0x40, 0x6d, 0xe5, 0x8c, 0x76,
0x9b, 0x59, 0x8c, 0x35, 0x7f, 0x58, 0x7f, 0x8e, 0x7e, 0x46, 0x4f, 0xfe, 0x06, 0x00, 0x00, 0xff, 0xd4, 0x4e, 0xaa, 0x95, 0xfc, 0x5e, 0x0b, 0x12, 0xa5, 0x1e, 0x9f, 0x76, 0x33, 0xec, 0x6c, 0xc6,
0xff, 0xc6, 0x87, 0xdb, 0xe6, 0xaf, 0x02, 0x00, 0x00, 0x24, 0xa4, 0x5f, 0xc0, 0xd4, 0xa7, 0x59, 0x21, 0xa8, 0xc1, 0xd3, 0xb0, 0xee, 0x2d, 0xe0, 0x8b,
0x6d, 0xbf, 0xc9, 0x5c, 0x51, 0x57, 0x1b, 0xe1, 0xdb, 0x6d, 0x1b, 0x34, 0x32, 0xaf, 0x7f, 0xf5,
0x00, 0xc5, 0xfe, 0x7b, 0x51, 0x38, 0x1a, 0xae, 0x61, 0x1f, 0x11, 0x66, 0x09, 0xa8, 0x15, 0x85,
0x48, 0x4e, 0xac, 0xae, 0x0d, 0x6b, 0x2d, 0x75, 0x51, 0x8b, 0x17, 0x6e, 0x4e, 0xf5, 0x1e, 0x66,
0xbc, 0x7b, 0x18, 0x0f, 0x82, 0x73, 0xde, 0x64, 0xff, 0xcf, 0xcc, 0xba, 0xef, 0x65, 0x05, 0xd0,
0x45, 0xde, 0x38, 0xde, 0x8c, 0x71, 0x64, 0x63, 0x8f, 0x98, 0x8b, 0xa3, 0x7a, 0x21, 0x77, 0x0d,
0xa9, 0xf7, 0x79, 0x27, 0xf7, 0xc9, 0xe1, 0x15, 0x75, 0xec, 0x40, 0x4a, 0xe1, 0x0e, 0x9a, 0x47,
0xb7, 0xa4, 0x30, 0x0c, 0x0a, 0x37, 0xde, 0xfe, 0x34, 0xfc, 0x92, 0xfc, 0x4c, 0x9e, 0xfd, 0x0b,
0x00, 0x00, 0xff, 0xff, 0x00, 0x92, 0x22, 0xd7, 0xb7, 0x03, 0x00, 0x00,
} }

File diff suppressed because it is too large Load Diff

View File

@@ -723,7 +723,7 @@ func (d *MsgClientNewLoginKeyAccepted) Deserialize(r io.Reader) error {
const ( const (
MsgClientLogon_ObfuscationMask uint32 = 0xBAADF00D MsgClientLogon_ObfuscationMask uint32 = 0xBAADF00D
MsgClientLogon_CurrentProtocol uint32 = 65579 MsgClientLogon_CurrentProtocol uint32 = 65580
MsgClientLogon_ProtocolVerMajorMask uint32 = 0xFFFF0000 MsgClientLogon_ProtocolVerMajorMask uint32 = 0xFFFF0000
MsgClientLogon_ProtocolVerMinorMask uint32 = 0xFFFF MsgClientLogon_ProtocolVerMinorMask uint32 = 0xFFFF
MsgClientLogon_ProtocolVerMinorMinGameServers uint16 = 4 MsgClientLogon_ProtocolVerMinorMinGameServers uint16 = 4
@@ -744,7 +744,11 @@ const (
MsgClientLogon_ProtocolVerMinorMinForMachineAuth uint16 = 33 MsgClientLogon_ProtocolVerMinorMinForMachineAuth uint16 = 33
MsgClientLogon_ProtocolVerMinorMinForSessionIDLastAnon uint16 = 36 MsgClientLogon_ProtocolVerMinorMinForSessionIDLastAnon uint16 = 36
MsgClientLogon_ProtocolVerMinorMinForEnhancedAppList uint16 = 40 MsgClientLogon_ProtocolVerMinorMinForEnhancedAppList uint16 = 40
MsgClientLogon_ProtocolVerMinorMinForSteamGuardNotificationUI uint16 = 41
MsgClientLogon_ProtocolVerMinorMinForProtoBufServiceModuleCalls uint16 = 42
MsgClientLogon_ProtocolVerMinorMinForGzipMultiMessages uint16 = 43 MsgClientLogon_ProtocolVerMinorMinForGzipMultiMessages uint16 = 43
MsgClientLogon_ProtocolVerMinorMinForNewVoiceCallAuthorize uint16 = 44
MsgClientLogon_ProtocolVerMinorMinForClientInstanceIDs uint16 = 44
) )
type MsgClientLogon struct { type MsgClientLogon struct {
@@ -1976,64 +1980,6 @@ func (d *MsgClientChatRoomInfo) Deserialize(r io.Reader) error {
return err return err
} }
type MsgClientGetNumberOfCurrentPlayers struct {
GameID uint64
}
func NewMsgClientGetNumberOfCurrentPlayers() *MsgClientGetNumberOfCurrentPlayers {
return &MsgClientGetNumberOfCurrentPlayers{}
}
func (d *MsgClientGetNumberOfCurrentPlayers) GetEMsg() EMsg {
return EMsg_ClientGetNumberOfCurrentPlayers
}
func (d *MsgClientGetNumberOfCurrentPlayers) Serialize(w io.Writer) error {
var err error
err = binary.Write(w, binary.LittleEndian, d.GameID)
return err
}
func (d *MsgClientGetNumberOfCurrentPlayers) Deserialize(r io.Reader) error {
var err error
d.GameID, err = rwu.ReadUint64(r)
return err
}
type MsgClientGetNumberOfCurrentPlayersResponse struct {
Result EResult
NumPlayers uint32
}
func NewMsgClientGetNumberOfCurrentPlayersResponse() *MsgClientGetNumberOfCurrentPlayersResponse {
return &MsgClientGetNumberOfCurrentPlayersResponse{}
}
func (d *MsgClientGetNumberOfCurrentPlayersResponse) GetEMsg() EMsg {
return EMsg_ClientGetNumberOfCurrentPlayersResponse
}
func (d *MsgClientGetNumberOfCurrentPlayersResponse) Serialize(w io.Writer) error {
var err error
err = binary.Write(w, binary.LittleEndian, d.Result)
if err != nil {
return err
}
err = binary.Write(w, binary.LittleEndian, d.NumPlayers)
return err
}
func (d *MsgClientGetNumberOfCurrentPlayersResponse) Deserialize(r io.Reader) error {
var err error
t0, err := rwu.ReadInt32(r)
if err != nil {
return err
}
d.Result = EResult(t0)
d.NumPlayers, err = rwu.ReadUint32(r)
return err
}
type MsgClientSetIgnoreFriend struct { type MsgClientSetIgnoreFriend struct {
MySteamId steamid.SteamId MySteamId steamid.SteamId
SteamIdFriend steamid.SteamId SteamIdFriend steamid.SteamId
@@ -2079,7 +2025,7 @@ func (d *MsgClientSetIgnoreFriend) Deserialize(r io.Reader) error {
} }
type MsgClientSetIgnoreFriendResponse struct { type MsgClientSetIgnoreFriendResponse struct {
Unknown uint64 FriendId steamid.SteamId
Result EResult Result EResult
} }
@@ -2093,7 +2039,7 @@ func (d *MsgClientSetIgnoreFriendResponse) GetEMsg() EMsg {
func (d *MsgClientSetIgnoreFriendResponse) Serialize(w io.Writer) error { func (d *MsgClientSetIgnoreFriendResponse) Serialize(w io.Writer) error {
var err error var err error
err = binary.Write(w, binary.LittleEndian, d.Unknown) err = binary.Write(w, binary.LittleEndian, d.FriendId)
if err != nil { if err != nil {
return err return err
} }
@@ -2103,12 +2049,13 @@ func (d *MsgClientSetIgnoreFriendResponse) Serialize(w io.Writer) error {
func (d *MsgClientSetIgnoreFriendResponse) Deserialize(r io.Reader) error { func (d *MsgClientSetIgnoreFriendResponse) Deserialize(r io.Reader) error {
var err error var err error
d.Unknown, err = rwu.ReadUint64(r) t0, err := rwu.ReadUint64(r)
if err != nil { if err != nil {
return err return err
} }
t0, err := rwu.ReadInt32(r) d.FriendId = steamid.SteamId(t0)
d.Result = EResult(t0) t1, err := rwu.ReadInt32(r)
d.Result = EResult(t1)
return err return err
} }
@@ -2226,73 +2173,6 @@ func (d *MsgClientLogOnResponse) Deserialize(r io.Reader) error {
return err return err
} }
type MsgClientSendGuestPass struct {
GiftId uint64
GiftType uint8
AccountId uint32
}
func NewMsgClientSendGuestPass() *MsgClientSendGuestPass {
return &MsgClientSendGuestPass{}
}
func (d *MsgClientSendGuestPass) GetEMsg() EMsg {
return EMsg_ClientSendGuestPass
}
func (d *MsgClientSendGuestPass) Serialize(w io.Writer) error {
var err error
err = binary.Write(w, binary.LittleEndian, d.GiftId)
if err != nil {
return err
}
err = binary.Write(w, binary.LittleEndian, d.GiftType)
if err != nil {
return err
}
err = binary.Write(w, binary.LittleEndian, d.AccountId)
return err
}
func (d *MsgClientSendGuestPass) Deserialize(r io.Reader) error {
var err error
d.GiftId, err = rwu.ReadUint64(r)
if err != nil {
return err
}
d.GiftType, err = rwu.ReadUint8(r)
if err != nil {
return err
}
d.AccountId, err = rwu.ReadUint32(r)
return err
}
type MsgClientSendGuestPassResponse struct {
Result EResult
}
func NewMsgClientSendGuestPassResponse() *MsgClientSendGuestPassResponse {
return &MsgClientSendGuestPassResponse{}
}
func (d *MsgClientSendGuestPassResponse) GetEMsg() EMsg {
return EMsg_ClientSendGuestPassResponse
}
func (d *MsgClientSendGuestPassResponse) Serialize(w io.Writer) error {
var err error
err = binary.Write(w, binary.LittleEndian, d.Result)
return err
}
func (d *MsgClientSendGuestPassResponse) Deserialize(r io.Reader) error {
var err error
t0, err := rwu.ReadInt32(r)
d.Result = EResult(t0)
return err
}
type MsgClientServerUnavailable struct { type MsgClientServerUnavailable struct {
JobidSent uint64 JobidSent uint64
EMsgSent uint32 EMsgSent uint32

View File

@@ -8,135 +8,116 @@ import (
) )
// CMServers contains a list of worlwide servers // CMServers contains a list of worlwide servers
var CMServers = [][]string{ var CMServers = []string{
{ // North American Servers "155.133.248.52:27018",
// Chicago "162.254.197.40:27018",
"162.254.193.44:27018", "162.254.197.180:27019",
"162.254.193.44:27019", "155.133.248.50:27019",
"162.254.193.44:27020", "162.254.197.181:27017",
"162.254.193.44:27021", "162.254.197.42:27019",
"162.254.193.45:27017", "162.254.197.180:27017",
"162.254.193.45:27018", "162.254.197.181:27018",
"162.254.193.45:27019", "162.254.197.42:27018",
"162.254.193.45:27021", "155.133.248.50:27017",
"162.254.193.46:27017", "155.133.248.52:27019",
"162.254.193.46:27018", "155.133.248.51:27019",
"162.254.193.46:27019", "155.133.248.53:27019",
"162.254.193.46:27020", "155.133.248.51:27017",
"162.254.193.46:27021", "155.133.248.53:27017",
"162.254.193.47:27019", "155.133.248.52:27017",
"162.254.193.47:27020", "155.133.248.50:27018",
"162.254.197.180:27018",
// Ashburn "162.254.197.40:27017",
"208.78.164.9:27017", "162.254.197.40:27019",
"208.78.164.9:27018", "162.254.197.42:27017",
"208.78.164.9:27019", "162.254.197.181:27019",
"208.78.164.10:27017", "155.133.248.53:27018",
"208.78.164.10:27018", "155.133.248.51:27018",
"208.78.164.10:27019", "146.66.152.11:27017",
"208.78.164.11:27017", "146.66.152.10:27019",
"208.78.164.11:27018",
"208.78.164.11:27019",
"208.78.164.12:27017",
"208.78.164.12:27018",
"208.78.164.12:27019",
"208.78.164.13:27017",
"208.78.164.13:27018",
"208.78.164.13:27019",
"208.78.164.14:27017",
"208.78.164.14:27018",
"208.78.164.14:27019",
},
{ // Europe Servers
// Luxembourg
"146.66.152.10:27017", "146.66.152.10:27017",
"146.66.152.10:27018", "146.66.152.10:27018",
"146.66.152.10:27019",
"146.66.152.10:27020",
"146.66.152.11:27017",
"146.66.152.11:27018",
"146.66.152.11:27019", "146.66.152.11:27019",
"146.66.152.11:27020", "162.254.198.133:27017",
"162.254.198.133:27018",
// Poland "162.254.198.130:27019",
"155.133.242.8:27017", "162.254.198.130:27017",
"155.133.242.8:27018", "162.254.198.132:27018",
"155.133.242.8:27019", "162.254.198.130:27018",
"155.133.242.8:27020", "162.254.198.132:27017",
"155.133.242.9:27017", "162.254.198.132:27019",
"155.133.242.9:27018", "162.254.198.131:27019",
"155.133.242.9:27019", "162.254.198.131:27017",
"155.133.242.9:27020", "146.66.152.11:27018",
"162.254.198.131:27018",
// Vienna "162.254.198.133:27019",
"146.66.155.8:27017", "185.25.182.77:27017",
"146.66.155.8:27018", "185.25.182.76:27018",
"146.66.155.8:27019", "185.25.182.76:27019",
"146.66.155.8:27020", "185.25.182.77:27018",
"185.25.182.10:27017", "185.25.182.76:27017",
"185.25.182.10:27018", "185.25.182.77:27019",
"185.25.182.10:27019", "162.254.196.67:27019",
"185.25.182.10:27020", "162.254.196.67:27018",
"162.254.196.83:27018",
// London "162.254.196.84:27018",
"162.254.196.40:27017", "162.254.196.83:27017",
"162.254.196.40:27018", "162.254.196.84:27017",
"162.254.196.40:27019", "162.254.196.68:27019",
"162.254.196.40:27020", "162.254.196.68:27017",
"162.254.196.40:27021", "162.254.196.84:27019",
"162.254.196.41:27017", "162.254.196.67:27017",
"162.254.196.41:27018", "162.254.196.83:27019",
"162.254.196.41:27019", "162.254.196.68:27018",
"162.254.196.41:27020", "146.66.155.101:27017",
"162.254.196.41:27021", "146.66.155.101:27018",
"162.254.196.42:27017", "146.66.155.100:27017",
"162.254.196.42:27018", "146.66.155.100:27018",
"162.254.196.42:27019", "146.66.155.101:27019",
"162.254.196.42:27020", "146.66.155.100:27019",
"162.254.196.42:27021", "155.133.230.50:27017",
"162.254.196.43:27017", "155.133.230.34:27018",
"162.254.196.43:27018", "155.133.230.34:27017",
"162.254.196.43:27019", "155.133.230.50:27019",
"162.254.196.43:27020", "155.133.230.34:27019",
"162.254.196.43:27021", "155.133.230.50:27018",
"162.254.192.100:27017",
// Stockholm "162.254.192.108:27017",
"185.25.180.14:27017", "155.133.246.68:27017",
"185.25.180.14:27018", "155.133.246.68:27018",
"185.25.180.14:27019", "155.133.246.68:27019",
"185.25.180.14:27020", "155.133.246.69:27019",
"185.25.180.15:27017", "155.133.246.69:27017",
"185.25.180.15:27018", "155.133.246.69:27018",
"185.25.180.15:27019", "162.254.192.108:27018",
"185.25.180.15:27020", "162.254.192.101:27018",
}, "162.254.192.101:27019",
"162.254.192.109:27018",
"162.254.192.100:27018",
"162.254.192.109:27017",
"162.254.192.109:27019",
"162.254.192.108:27019",
"162.254.192.101:27017",
"162.254.192.100:27019",
"162.254.193.46:27019",
"162.254.193.6:27018",
"162.254.193.47:27018",
"162.254.193.6:27019",
"162.254.193.7:27018",
"162.254.193.7:27017",
"162.254.193.7:27019",
"162.254.193.47:27017",
"162.254.193.47:27019",
"162.254.193.46:27018",
} }
// GetRandomCM returns back a random server anywhere // GetRandomCM returns a random server from a built-in IP list.
//
// Prefer Client.Connect(), which uses IPs from the Steam Directory,
// which is always more up-to-date.
func GetRandomCM() *netutil.PortAddr { func GetRandomCM() *netutil.PortAddr {
rng := rand.New(rand.NewSource(time.Now().UnixNano())) rng := rand.New(rand.NewSource(time.Now().UnixNano()))
servers := append(CMServers[0], CMServers[1]...) addr := netutil.ParsePortAddr(CMServers[rng.Int31n(int32(len(CMServers)))])
addr := netutil.ParsePortAddr(servers[rng.Int31n(int32(len(servers)))])
if addr == nil {
panic("invalid address in CMServers slice")
}
return addr
}
// GetRandomNorthAmericaCM returns back a random server in north america
func GetRandomNorthAmericaCM() *netutil.PortAddr {
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
addr := netutil.ParsePortAddr(CMServers[0][rng.Int31n(int32(len(CMServers[0])))])
if addr == nil {
panic("invalid address in CMServers slice")
}
return addr
}
// GetRandomEuropeCM returns back a random server in europe
func GetRandomEuropeCM() *netutil.PortAddr {
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
addr := netutil.ParsePortAddr(CMServers[1][rng.Int31n(int32(len(CMServers[1])))])
if addr == nil { if addr == nil {
panic("invalid address in CMServers slice") panic("invalid address in CMServers slice")
} }

Some files were not shown because too many files have changed in this diff Show More