Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c442e239d | ||
|
|
eaf92fca4d | ||
|
|
06b7bad714 | ||
|
|
19eec2ed03 | ||
|
|
d99c54343a | ||
|
|
308a110000 | ||
|
|
4f406b2ce6 | ||
|
|
e564c555d7 | ||
|
|
f7ec9af9e8 | ||
|
|
4d93a774ce | ||
|
|
2595dd30bf | ||
|
|
9190365289 | ||
|
|
57794b3b9f | ||
|
|
3c36f651be | ||
|
|
8e6ddadba2 | ||
|
|
8a87a71927 | ||
|
|
0047e6f523 | ||
|
|
7183095a28 | ||
|
|
13c90893c7 | ||
|
|
976fbcd07f | ||
|
|
d97b077e85 | ||
|
|
8950575bfb | ||
|
|
11fc4c286f | ||
|
|
8d08e348a9 | ||
|
|
a18807f19e | ||
|
|
29f658fd3c | ||
|
|
a30bb8fed0 | ||
|
|
092ca1cd67 | ||
|
|
0df2539641 | ||
|
|
0f2d8a599c | ||
|
|
54b3143a1d |
84
README.md
84
README.md
@@ -9,20 +9,20 @@ Letting people be where they want to be.<br />
|
||||
|
||||
<sup>
|
||||
|
||||
[Discord][mb-discord] |
|
||||
[Gitter][mb-gitter] |
|
||||
[IRC][mb-irc] |
|
||||
[Discord][mb-discord] |
|
||||
[Keybase][mb-keybase] |
|
||||
[Matrix][mb-matrix] |
|
||||
[Slack][mb-slack] |
|
||||
[Mattermost][mb-mattermost] |
|
||||
[MSTeams][mb-msteams] |
|
||||
[Rocket.Chat][mb-rocketchat] |
|
||||
[XMPP][mb-xmpp] |
|
||||
[Slack][mb-slack] |
|
||||
[Telegram][mb-telegram] |
|
||||
[Twitch][mb-twitch] |
|
||||
[WhatsApp][mb-whatsapp] |
|
||||
[XMPP][mb-xmpp] |
|
||||
[Zulip][mb-zulip] |
|
||||
[Telegram][mb-telegram] |
|
||||
[Keybase][mb-keybase] |
|
||||
[MSTeams][mb-msteams] |
|
||||
And more...
|
||||
</sup>
|
||||
|
||||
@@ -87,29 +87,29 @@ And more...
|
||||
|
||||
### Natively supported
|
||||
|
||||
- [Mattermost](https://github.com/mattermost/mattermost-server/) 4.x, 5.x
|
||||
- [IRC](http://www.mirc.com/servers.html)
|
||||
- [XMPP](https://xmpp.org)
|
||||
- [Gitter](https://gitter.im)
|
||||
- [Slack](https://slack.com)
|
||||
- [Discord](https://discordapp.com)
|
||||
- [Telegram](https://telegram.org)
|
||||
- [Rocket.chat](https://rocket.chat)
|
||||
- [Matrix](https://matrix.org)
|
||||
- [Microsoft Teams](https://teams.microsoft.com)
|
||||
- [Steam](https://store.steampowered.com/)
|
||||
- [Twitch](https://twitch.tv)
|
||||
- [Ssh-chat](https://github.com/shazow/ssh-chat)
|
||||
- [WhatsApp](https://www.whatsapp.com/)
|
||||
- [Zulip](https://zulipchat.com)
|
||||
- [Gitter](https://gitter.im)
|
||||
- [IRC](http://www.mirc.com/servers.html)
|
||||
- [Keybase](https://keybase.io)
|
||||
- [Matrix](https://matrix.org)
|
||||
- [Mattermost](https://github.com/mattermost/mattermost-server/) 4.x, 5.x
|
||||
- [Microsoft Teams](https://teams.microsoft.com)
|
||||
- [Rocket.chat](https://rocket.chat)
|
||||
- [Slack](https://slack.com)
|
||||
- [Ssh-chat](https://github.com/shazow/ssh-chat)
|
||||
- [Steam](https://store.steampowered.com/)
|
||||
- [Telegram](https://telegram.org)
|
||||
- [Twitch](https://twitch.tv)
|
||||
- [WhatsApp](https://www.whatsapp.com/)
|
||||
- [XMPP](https://xmpp.org)
|
||||
- [Zulip](https://zulipchat.com)
|
||||
|
||||
### 3rd party via matterbridge api
|
||||
|
||||
- [Discourse](https://github.com/DeclanHoare/matterbabble)
|
||||
- [Facebook messenger](https://github.com/VictorNine/fbridge)
|
||||
- [Minecraft](https://github.com/elytra/MatterLink)
|
||||
- [Reddit](https://github.com/bonehurtingjuice/mattereddit)
|
||||
- [Facebook messenger](https://github.com/VictorNine/fbridge)
|
||||
- [Discourse](https://github.com/DeclanHoare/matterbabble)
|
||||
- [Counter-Strike, half-life and more](https://forums.alliedmods.net/showthread.php?t=319430)
|
||||
|
||||
### API
|
||||
@@ -130,18 +130,18 @@ Used by the projects below. Feel free to make a PR to add your project to this l
|
||||
|
||||
Questions or want to test on your favorite platform? Join below:
|
||||
|
||||
- [Discord][mb-discord]
|
||||
- [Gitter][mb-gitter]
|
||||
- [IRC][mb-irc]
|
||||
- [Discord][mb-discord]
|
||||
- [Keybase][mb-keybase]
|
||||
- [Matrix][mb-matrix]
|
||||
- [Slack][mb-slack]
|
||||
- [Mattermost][mb-mattermost]
|
||||
- [Rocket.Chat][mb-rocketchat]
|
||||
- [XMPP][mb-xmpp] (matterbridge@conference.jabber.de)
|
||||
- [Twitch][mb-twitch]
|
||||
- [Zulip][mb-zulip]
|
||||
- [Slack][mb-slack]
|
||||
- [Telegram][mb-telegram]
|
||||
- [Keybase][mb-keybase]
|
||||
- [Twitch][mb-twitch]
|
||||
- [XMPP][mb-xmpp] (matterbridge@conference.jabber.de)
|
||||
- [Zulip][mb-zulip]
|
||||
|
||||
## Screenshots
|
||||
|
||||
@@ -151,7 +151,7 @@ See https://github.com/42wim/matterbridge/wiki
|
||||
|
||||
### Binaries
|
||||
|
||||
- Latest stable release [v1.17.1](https://github.com/42wim/matterbridge/releases/latest)
|
||||
- Latest stable release [v1.17.4](https://github.com/42wim/matterbridge/releases/latest)
|
||||
- Development releases (follows master) can be downloaded [here](https://dl.bintray.com/42wim/nightly/)
|
||||
|
||||
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.
|
||||
@@ -324,32 +324,32 @@ Matterbridge wouldn't exist without these libraries:
|
||||
- gops - https://github.com/google/gops
|
||||
- gozulipbot - https://github.com/ifo/gozulipbot
|
||||
- irc - https://github.com/lrstanley/girc
|
||||
- mattermost - https://github.com/mattermost/mattermost-server
|
||||
- keybase - https://github.com/keybase/go-keybase-chat-bot
|
||||
- matrix - https://github.com/matrix-org/gomatrix
|
||||
- sshchat - https://github.com/shazow/ssh-chat
|
||||
- mattermost - https://github.com/mattermost/mattermost-server
|
||||
- msgraph.go - https://github.com/yaegashi/msgraph.go
|
||||
- slack - https://github.com/nlopes/slack
|
||||
- sshchat - https://github.com/shazow/ssh-chat
|
||||
- steam - https://github.com/Philipp15b/go-steam
|
||||
- telegram - https://github.com/go-telegram-bot-api/telegram-bot-api
|
||||
- xmpp - https://github.com/mattn/go-xmpp
|
||||
- whatsapp - https://github.com/Rhymen/go-whatsapp/
|
||||
- zulip - https://github.com/ifo/gozulipbot
|
||||
- tengo - https://github.com/d5/tengo
|
||||
- keybase - https://github.com/keybase/go-keybase-chat-bot
|
||||
- msgraph.go - https://github.com/yaegashi/msgraph.go
|
||||
- whatsapp - https://github.com/Rhymen/go-whatsapp/
|
||||
- xmpp - https://github.com/mattn/go-xmpp
|
||||
- zulip - https://github.com/ifo/gozulipbot
|
||||
|
||||
<!-- Links -->
|
||||
|
||||
[mb-discord]: https://discord.gg/AkKPtrQ
|
||||
[mb-gitter]: https://gitter.im/42wim/matterbridge
|
||||
[mb-irc]: https://webchat.freenode.net/?channels=matterbridgechat
|
||||
[mb-discord]: https://discord.gg/AkKPtrQ
|
||||
[mb-keybase]: https://keybase.io/team/matterbridge
|
||||
[mb-matrix]: https://riot.im/app/#/room/#matterbridge:matrix.org
|
||||
[mb-slack]: https://join.slack.com/matterbridgechat/shared_invite/MjEwODMxNjU1NDMwLTE0OTk2MTU3NTMtMzZkZmRiNDZhOA
|
||||
[mb-mattermost]: https://framateam.org/signup_user_complete/?id=tfqm33ggop8x3qgu4boeieta6e
|
||||
[mb-msteams]: https://teams.microsoft.com/join/hj92x75gd3y7
|
||||
[mb-rocketchat]: https://open.rocket.chat/channel/matterbridge
|
||||
[mb-xmpp]: https://inverse.chat/
|
||||
[mb-slack]: https://join.slack.com/matterbridgechat/shared_invite/MjEwODMxNjU1NDMwLTE0OTk2MTU3NTMtMzZkZmRiNDZhOA
|
||||
[mb-telegram]: https://t.me/Matterbridge
|
||||
[mb-twitch]: https://www.twitch.tv/matterbridge
|
||||
[mb-whatsapp]: https://www.whatsapp.com/
|
||||
[mb-keybase]: https://keybase.io/team/matterbridge
|
||||
[mb-xmpp]: https://inverse.chat/
|
||||
[mb-zulip]: https://matterbridge.zulipchat.com/register/
|
||||
[mb-telegram]: https://t.me/Matterbridge
|
||||
[mb-msteams]: https://teams.microsoft.com/join/hj92x75gd3y7
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"log"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/42wim/matterbridge/bridge/config"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -74,6 +75,7 @@ func (b *Bridge) joinChannels(channels map[string]config.ChannelInfo, exists map
|
||||
for ID, channel := range channels {
|
||||
if !exists[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)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -89,6 +89,7 @@ type Protocol struct {
|
||||
IgnoreNicks string // all protocols
|
||||
IgnoreMessages string // all protocols
|
||||
Jid string // xmpp
|
||||
JoinDelay string // all protocols
|
||||
Label string // all protocols
|
||||
Login string // mattermost, matrix
|
||||
MediaDownloadBlackList []string
|
||||
|
||||
@@ -34,6 +34,8 @@ type Bdiscord struct {
|
||||
membersMutex sync.RWMutex
|
||||
userMemberMap map[string]*discordgo.Member
|
||||
nickMemberMap map[string]*discordgo.Member
|
||||
webhookCache map[string]string
|
||||
webhookMutex sync.RWMutex
|
||||
}
|
||||
|
||||
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.nickMemberMap = make(map[string]*discordgo.Member)
|
||||
b.channelInfoMap = make(map[string]*config.ChannelInfo)
|
||||
b.webhookCache = make(map[string]string)
|
||||
if b.GetString("WebhookURL") != "" {
|
||||
b.Log.Debug("Configuring Discord Incoming Webhook")
|
||||
b.webhookID, b.webhookToken = b.splitURL(b.GetString("WebhookURL"))
|
||||
@@ -188,6 +191,8 @@ func (b *Bdiscord) JoinChannel(channel config.ChannelInfo) error {
|
||||
func (b *Bdiscord) Send(msg config.Message) (string, error) {
|
||||
b.Log.Debugf("=> Receiving %#v", msg)
|
||||
|
||||
origMsgID := msg.ID
|
||||
|
||||
channelID := b.getChannelID(msg.Channel)
|
||||
if channelID == "" {
|
||||
return "", fmt.Errorf("Could not find channelID for %v", msg.Channel)
|
||||
@@ -230,6 +235,7 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
|
||||
|
||||
// If we are editing a message, delete the old message
|
||||
if msg.ID != "" {
|
||||
msg.ID = b.getCacheID(msg.ID)
|
||||
b.Log.Debugf("Deleting edited webhook message")
|
||||
err := b.c.ChannelMessageDelete(channelID, msg.ID)
|
||||
if err != nil {
|
||||
@@ -273,6 +279,8 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
|
||||
if msg == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
b.updateCacheID(origMsgID, msg.ID)
|
||||
return msg.ID, nil
|
||||
}
|
||||
|
||||
@@ -283,6 +291,7 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
|
||||
if msg.ID == "" {
|
||||
return "", nil
|
||||
}
|
||||
msg.ID = b.getCacheID(msg.ID)
|
||||
err := b.c.ChannelMessageDelete(channelID, msg.ID)
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -208,6 +208,40 @@ func (b *Bdiscord) splitURL(url string) (string, string) {
|
||||
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 {
|
||||
onlySpace := true
|
||||
for _, r := range s {
|
||||
|
||||
@@ -54,12 +54,12 @@ func (b *Birc) handleFiles(msg *config.Message) bool {
|
||||
for _, f := range msg.Extra["file"] {
|
||||
fi := f.(config.FileInfo)
|
||||
if fi.Comment != "" {
|
||||
msg.Text += fi.Comment + ": "
|
||||
msg.Text += fi.Comment + " : "
|
||||
}
|
||||
if fi.URL != "" {
|
||||
msg.Text = fi.URL
|
||||
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}
|
||||
|
||||
@@ -11,10 +11,9 @@ import (
|
||||
"github.com/42wim/matterbridge/bridge"
|
||||
"github.com/42wim/matterbridge/bridge/config"
|
||||
|
||||
// "github.com/davecgh/go-spew/spew"
|
||||
"github.com/matterbridge/msgraph.go/msauth"
|
||||
"github.com/mattn/godown"
|
||||
msgraph "github.com/yaegashi/msgraph.go/beta"
|
||||
"github.com/yaegashi/msgraph.go/msauth"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
@@ -72,7 +71,15 @@ func (b *Bmsteams) Disconnect() error {
|
||||
}
|
||||
|
||||
func (b *Bmsteams) JoinChannel(channel config.ChannelInfo) error {
|
||||
go b.poll(channel.Name)
|
||||
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
|
||||
}
|
||||
|
||||
@@ -121,12 +128,12 @@ func (b *Bmsteams) getMessages(channel string) ([]msgraph.ChatMessage, error) {
|
||||
}
|
||||
|
||||
//nolint:gocognit
|
||||
func (b *Bmsteams) poll(channelName string) {
|
||||
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 {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
for _, msg := range res {
|
||||
msgmap[*msg.ID] = *msg.CreatedDateTime
|
||||
@@ -139,7 +146,7 @@ func (b *Bmsteams) poll(channelName string) {
|
||||
for {
|
||||
res, err := b.getMessages(channelName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
for i := len(res) - 1; i >= 0; i-- {
|
||||
msg := res[i]
|
||||
|
||||
@@ -2,6 +2,7 @@ package brocketchat
|
||||
|
||||
import (
|
||||
"github.com/42wim/matterbridge/bridge/config"
|
||||
"github.com/matterbridge/Rocket.Chat.Go.SDK/models"
|
||||
)
|
||||
|
||||
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) {
|
||||
for message := range b.messageChan {
|
||||
// skip messages with same ID, apparently messages get duplicated for an unknown reason
|
||||
@@ -59,7 +77,12 @@ func (b *Brocketchat) handleRocketClient(messages chan *config.Message) {
|
||||
UserID: message.User.ID,
|
||||
ID: message.ID,
|
||||
}
|
||||
messages <- rmsg
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,12 @@ type Brocketchat struct {
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
const (
|
||||
sUserJoined = "uj"
|
||||
sUserLeft = "ul"
|
||||
sRoomChangedTopic = "room_changed_topic"
|
||||
)
|
||||
|
||||
func New(cfg *bridge.Config) bridge.Bridger {
|
||||
newCache, err := lru.New(100)
|
||||
if err != nil {
|
||||
|
||||
@@ -137,12 +137,6 @@ func (b *Bslack) skipMessageEvent(ev *slack.MessageEvent) bool {
|
||||
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 ev.SubMessage != nil {
|
||||
// It seems ev.SubMessage.Edited == nil when slack unfurls.
|
||||
// Do not forward these messages. See Github issue #266.
|
||||
@@ -155,6 +149,16 @@ func (b *Bslack) skipMessageEvent(ev *slack.MessageEvent) bool {
|
||||
if ev.SubType == "message_replied" && ev.Hidden {
|
||||
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 {
|
||||
|
||||
@@ -64,6 +64,7 @@ const (
|
||||
editSuffixConfig = "EditSuffix"
|
||||
iconURLConfig = "iconurl"
|
||||
noSendJoinConfig = "nosendjoinpart"
|
||||
messageLength = 3000
|
||||
)
|
||||
|
||||
func New(cfg *bridge.Config) bridge.Bridger {
|
||||
@@ -194,6 +195,7 @@ func (b *Bslack) Send(msg config.Message) (string, error) {
|
||||
b.Log.Debugf("=> Receiving %#v", msg)
|
||||
}
|
||||
|
||||
msg.Text = helper.ClipMessage(msg.Text, messageLength)
|
||||
msg.Text = b.replaceCodeFence(msg.Text)
|
||||
|
||||
// Make a action /me of the message
|
||||
|
||||
@@ -23,7 +23,8 @@ Check:
|
||||
// HandleError received from WhatsApp
|
||||
func (b *Bwhatsapp) HandleError(err error) {
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -55,6 +56,7 @@ func (b *Bwhatsapp) reconnect(err error) {
|
||||
err := b.conn.Restore()
|
||||
if err == nil {
|
||||
bf.Reset()
|
||||
b.startedAt = uint64(time.Now().Unix())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ func (b *Bwhatsapp) Connect() error {
|
||||
// https://github.com/Rhymen/go-whatsapp#creating-a-connection
|
||||
b.Log.Debugln("Connecting to WhatsApp..")
|
||||
conn, err := whatsapp.NewConn(20 * time.Second)
|
||||
conn.SetClientVersion(0, 4, 1307)
|
||||
conn.SetClientVersion(0, 4, 2080)
|
||||
if err != nil {
|
||||
return errors.New("failed to connect to WhatsApp: " + err.Error())
|
||||
}
|
||||
|
||||
34
bridge/xmpp/handler.go
Normal file
34
bridge/xmpp/handler.go
Normal 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
30
bridge/xmpp/helpers.go
Normal 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 ""
|
||||
}
|
||||
@@ -23,12 +23,15 @@ type Bxmpp struct {
|
||||
xmppMap map[string]string
|
||||
connected bool
|
||||
sync.RWMutex
|
||||
|
||||
avatarMap map[string]string
|
||||
}
|
||||
|
||||
func New(cfg *bridge.Config) bridge.Bridger {
|
||||
return &Bxmpp{
|
||||
Config: cfg,
|
||||
xmppMap: make(map[string]string),
|
||||
Config: cfg,
|
||||
xmppMap: make(map[string]string),
|
||||
avatarMap: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +72,10 @@ func (b *Bxmpp) Send(msg config.Message) (string, error) {
|
||||
}
|
||||
b.Log.Debugf("=> Receiving %#v", msg)
|
||||
|
||||
if msg.Event == config.EventAvatarDownload {
|
||||
return b.cacheAvatar(&msg), nil
|
||||
}
|
||||
|
||||
// Upload a file (in XMPP case send the upload URL because XMPP has no native upload support).
|
||||
if msg.Extra != nil {
|
||||
for _, rmsg := range helper.HandleExtra(&msg, b.General) {
|
||||
@@ -114,6 +121,9 @@ func (b *Bxmpp) createXMPP() error {
|
||||
ServerName: strings.Split(b.GetString("Jid"), "@")[1],
|
||||
InsecureSkipVerify: b.GetBool("SkipTLSVerify"), // nolint: gosec
|
||||
}
|
||||
|
||||
xmpp.DebugWriter = b.Log.Writer()
|
||||
|
||||
options := xmpp.Options{
|
||||
Host: b.GetString("Server"),
|
||||
User: b.GetString("Jid"),
|
||||
@@ -122,7 +132,6 @@ func (b *Bxmpp) createXMPP() error {
|
||||
StartTLS: true,
|
||||
TLSConfig: tc,
|
||||
Debug: b.GetBool("debug"),
|
||||
Logger: b.Log.Writer(),
|
||||
Session: true,
|
||||
Status: "",
|
||||
StatusMessage: "",
|
||||
@@ -228,6 +237,12 @@ func (b *Bxmpp) handleXMPP() error {
|
||||
event = config.EventTopicChange
|
||||
}
|
||||
|
||||
avatar := getAvatar(b.avatarMap, v.Remote, b.General)
|
||||
if avatar == "" {
|
||||
b.Log.Debugf("Requesting avatar data")
|
||||
b.xc.AvatarRequestData(v.Remote)
|
||||
}
|
||||
|
||||
msgID := v.ID
|
||||
if v.ReplaceID != "" {
|
||||
msgID = v.ReplaceID
|
||||
@@ -237,6 +252,7 @@ func (b *Bxmpp) handleXMPP() error {
|
||||
Text: v.Text,
|
||||
Channel: b.parseChannel(v.Remote),
|
||||
Account: b.Account,
|
||||
Avatar: avatar,
|
||||
UserID: v.Remote,
|
||||
ID: msgID,
|
||||
Event: event,
|
||||
@@ -253,6 +269,8 @@ func (b *Bxmpp) handleXMPP() error {
|
||||
b.Log.Debugf("<= Message is %#v", rmsg)
|
||||
b.Remote <- rmsg
|
||||
}
|
||||
case xmpp.AvatarData:
|
||||
b.handleDownloadAvatar(v)
|
||||
case xmpp.Presence:
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
44
changelog.md
44
changelog.md
@@ -1,3 +1,47 @@
|
||||
# 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
|
||||
|
||||
@@ -108,7 +108,7 @@ func (gw *Gateway) AddBridge(cfg *config.Bridge) error {
|
||||
func (gw *Gateway) checkConfig(cfg *config.Bridge) {
|
||||
match := false
|
||||
for _, key := range gw.Router.Config.Viper().AllKeys() {
|
||||
if strings.HasPrefix(key, cfg.Account) {
|
||||
if strings.HasPrefix(key, strings.ToLower(cfg.Account)) {
|
||||
match = true
|
||||
break
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ func (gw *Gateway) ignoreEvent(event string, dest *bridge.Bridge) bool {
|
||||
switch event {
|
||||
case config.EventAvatarDownload:
|
||||
// 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
|
||||
}
|
||||
case config.EventJoinLeave:
|
||||
@@ -179,7 +179,7 @@ func (gw *Gateway) ignoreEvent(event string, dest *bridge.Bridge) bool {
|
||||
}
|
||||
case config.EventTopicChange:
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
11
go.mod
11
go.mod
@@ -5,8 +5,8 @@ require (
|
||||
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
|
||||
github.com/Jeffail/gabs v1.1.1 // indirect
|
||||
github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0
|
||||
github.com/Rhymen/go-whatsapp v0.1.0
|
||||
github.com/d5/tengo/v2 v2.0.2
|
||||
github.com/Rhymen/go-whatsapp v0.1.1-0.20200421062035-31e8111ac334
|
||||
github.com/d5/tengo/v2 v2.1.2
|
||||
github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible
|
||||
@@ -21,14 +21,13 @@ require (
|
||||
github.com/keybase/go-keybase-chat-bot v0.0.0-20200226211841-4e48f3eaef3e
|
||||
github.com/labstack/echo/v4 v4.1.13
|
||||
github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7
|
||||
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d
|
||||
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20200411204219-d5c18ce75048
|
||||
github.com/matterbridge/discordgo v0.18.1-0.20200308151012-aa40f01cbcc3
|
||||
github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible
|
||||
github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91
|
||||
github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050
|
||||
github.com/matterbridge/gomatrix v0.0.0-20200209224845-c2104d7936a6
|
||||
github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18
|
||||
github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61
|
||||
github.com/matterbridge/msgraph.go v0.0.0-20200308150230-9e043fe9dbaa
|
||||
github.com/mattermost/mattermost-server v5.5.0+incompatible
|
||||
github.com/mattn/go-runewidth v0.0.7 // indirect
|
||||
github.com/mattn/godown v0.0.0-20180312012330-2e9e17e0ea51
|
||||
@@ -46,7 +45,7 @@ require (
|
||||
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca
|
||||
github.com/shazow/ssh-chat v1.8.3-0.20200308224626-80ddf1f43a98
|
||||
github.com/sirupsen/logrus v1.4.2
|
||||
github.com/slack-go/slack v0.6.3-0.20200228121756-f56d616d5901
|
||||
github.com/slack-go/slack v0.6.3
|
||||
github.com/spf13/viper v1.6.1
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
||||
|
||||
26
go.sum
26
go.sum
@@ -12,8 +12,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
|
||||
github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0 h1:TO7d4rocnNFng6ZQrPe7U6WqHtK5eHEMrgrnnM/72IQ=
|
||||
github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0/go.mod h1:HuVM+sZFzumUdKPWiz+IlCMb4RdsKdT3T+nQBKL+sYg=
|
||||
github.com/Rhymen/go-whatsapp v0.0.0/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA=
|
||||
github.com/Rhymen/go-whatsapp v0.1.0 h1:XTXhFIQ/fx9jKObUnUX2Q+nh58EyeHNhX7DniE8xeuA=
|
||||
github.com/Rhymen/go-whatsapp v0.1.0/go.mod h1:xJSy+okeRjKkQEH/lEYrnekXB3PG33fqL0I6ncAkV50=
|
||||
github.com/Rhymen/go-whatsapp v0.1.1-0.20200421062035-31e8111ac334 h1:kb1zvD+xd+XbPUdQ0lMxnRaQ76N5C9vMAClLi8Dyw1Y=
|
||||
github.com/Rhymen/go-whatsapp v0.1.1-0.20200421062035-31e8111ac334/go.mod h1:o7jjkvKnigfu432dMbQ/w4PH0Yp5u4Y6ysCNjUlcYCk=
|
||||
github.com/Rhymen/go-whatsapp/examples/echo v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:zgCiQtBtZ4P4gFWvwl9aashsdwOcbb/EHOGRmSzM8ME=
|
||||
github.com/Rhymen/go-whatsapp/examples/restoreSession v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:5sCUSpG616ZoSJhlt9iBNI/KXBqrVLcNUJqg7J9+8pU=
|
||||
github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:RdiyhanVEGXTam+mZ3k6Y3VDCCvXYCwReOoxGozqhHw=
|
||||
@@ -33,8 +33,8 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/d5/tengo/v2 v2.0.2 h1:3APkPZPc1FExaJoWrN5YzvDqc6GNkQH6ehmCRDmN83I=
|
||||
github.com/d5/tengo/v2 v2.0.2/go.mod h1:XRGjEs5I9jYIKTxly6HCF8oiiilk5E/RYXOZ5b0DZC8=
|
||||
github.com/d5/tengo/v2 v2.1.2 h1:JR5O6qJW2GW9lpv/MfEqK16a/Wpp2y8I0JZZ5fqNOL0=
|
||||
github.com/d5/tengo/v2 v2.1.2/go.mod h1:XRGjEs5I9jYIKTxly6HCF8oiiilk5E/RYXOZ5b0DZC8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -124,22 +124,20 @@ github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7 h1:BS9tqL0OCiOGuy/C
|
||||
github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7/go.mod h1:liX5MxHPrwgHaKowoLkYGwbXfYABh1jbZ6FpElbGF1I=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d h1:F+Sr+C0ojSlYQ37BLylQtSFmyQULe3jbAygcyXQ9mVs=
|
||||
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A=
|
||||
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20200411204219-d5c18ce75048 h1:B9HaistmV+MD8/33BXmZe1zPIn+RImAFVXNNSOrwU2E=
|
||||
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20200411204219-d5c18ce75048/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A=
|
||||
github.com/matterbridge/discordgo v0.18.1-0.20200308151012-aa40f01cbcc3 h1:VP/DNRn2HtrVRN6+X3h4FDcQI2OOKT+88WUi21ZD1Kw=
|
||||
github.com/matterbridge/discordgo v0.18.1-0.20200308151012-aa40f01cbcc3/go.mod h1:5a1bHtG/38ofcx9cgwM5eTW/Pl4SpbQksNDnTRcGA2Y=
|
||||
github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible h1:oaOqwbg5HxHRxvAbd84ks0Okwoc1ISyUZ87EiVJFhGI=
|
||||
github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible/go.mod h1:igE6rUAn3jai2wCdsjFHfhUoekjrFthoEjFObKKwSb4=
|
||||
github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91 h1:KzDEcy8eDbTx881giW8a6llsAck3e2bJvMyKvh1IK+k=
|
||||
github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91/go.mod h1:ECDRehsR9TYTKCAsRS8/wLeOk6UUqDydw47ln7wG41Q=
|
||||
github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050 h1:kWkP1lXpkvtoNL08jkP3XQH/zvDOEXJpdCJd/DlIvMw=
|
||||
github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050/go.mod h1:ECDRehsR9TYTKCAsRS8/wLeOk6UUqDydw47ln7wG41Q=
|
||||
github.com/matterbridge/gomatrix v0.0.0-20200209224845-c2104d7936a6 h1:Kl65VJv38HjYFnnwH+MP6Z8hcJT5UHuSpHVU5vW1HH0=
|
||||
github.com/matterbridge/gomatrix v0.0.0-20200209224845-c2104d7936a6/go.mod h1:+jWeaaUtXQbBRdKYWfjW6JDDYiI2XXE+3NnTjW5kg8g=
|
||||
github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18 h1:fLhwXtWGtfTgZVxHG1lcKjv+re7dRwyyuYFNu69xdho=
|
||||
github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18/go.mod h1:yAjnZ34DuDyPHMPHHjOsTk/FefW4JJjoMMCGt/8uuQA=
|
||||
github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61 h1:R/MgM/eUyRBQx2FiH6JVmXck8PaAuKfe2M1tWIzW7nE=
|
||||
github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61/go.mod h1:iXGEotOvwI1R1SjLxRc+BF5rUORTMtE0iMZBT2lxqAU=
|
||||
github.com/matterbridge/msgraph.go v0.0.0-20200308150230-9e043fe9dbaa h1:ZP87nK5Mhgvt6Rpgbztdmq9+6cb3aZ6MgW/JWKbnMrI=
|
||||
github.com/matterbridge/msgraph.go v0.0.0-20200308150230-9e043fe9dbaa/go.mod h1:l0kx9L8Z+NbBCGrQ/y+ldKZ/fiwBZjPoXwDS55LTumI=
|
||||
github.com/mattermost/mattermost-server v5.5.0+incompatible h1:0wcLGgYtd+YImtLDPf2AOfpBHxbU4suATx+6XKw1XbU=
|
||||
github.com/mattermost/mattermost-server v5.5.0+incompatible/go.mod h1:5L6MjAec+XXQwMIt791Ganu45GKsSiM+I0tLR9wUj8Y=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
@@ -169,6 +167,8 @@ github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9 h1:mp6tU1r0xLostUGL
|
||||
github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9/go.mod h1:A5SRAcpTemjGgIuBq6Kic2yHcoeUFWUinOAlMP/i9xo=
|
||||
github.com/nicksnyder/go-i18n v1.4.0 h1:AgLl+Yq7kg5OYlzCgu9cKTZOyI4tD/NgukKqLqC8E+I=
|
||||
github.com/nicksnyder/go-i18n v1.4.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q=
|
||||
github.com/nlopes/slack v0.6.0 h1:jt0jxVQGhssx1Ib7naAOZEZcGdtIhTzkP0nopK0AsRA=
|
||||
github.com/nlopes/slack v0.6.0/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
@@ -216,8 +216,8 @@ github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9 h1:lpEzuenPuO1XNTeikEmvqYFcU37GVLl8SRNblzyvGBE=
|
||||
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo=
|
||||
github.com/slack-go/slack v0.6.3-0.20200228121756-f56d616d5901 h1:sXIMY2YPYEm5NoGMCrJC50N+8t9W6vbY9qr61zcLEAE=
|
||||
github.com/slack-go/slack v0.6.3-0.20200228121756-f56d616d5901/go.mod h1:ZUNi+O1Pwr2ch2UOp2AfF+s7QYQgwht2Cd1UTeIYw9A=
|
||||
github.com/slack-go/slack v0.6.3 h1:qU037g8gQ71EuH6S9zYKnvYrEUj0fLFH4HFekFqBoRU=
|
||||
github.com/slack-go/slack v0.6.3/go.mod h1:HE4RwNe7YpOg/F0vqo5PwXH3Hki31TplTvKRW9dGGaw=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
@@ -290,8 +290,6 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
version = "1.17.1"
|
||||
version = "1.17.4"
|
||||
githash string
|
||||
|
||||
flagConfig = flag.String("conf", "matterbridge.toml", "config file")
|
||||
|
||||
@@ -177,6 +177,12 @@ StripNick=false
|
||||
#OPTIONAL (default 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
|
||||
###################################################################
|
||||
@@ -1679,34 +1685,44 @@ enable=true
|
||||
# REQUIRED
|
||||
account="irc.freenode"
|
||||
|
||||
# channel to connect on that account
|
||||
# How to specify them for the different bridges:
|
||||
# The channel key in each gateway is mapped to a similar group chat ID on the chat platform
|
||||
# To find the group chat ID for different platforms, refer to the table below
|
||||
#
|
||||
# irc - #channel (# is required) (this needs to be lowercase!)
|
||||
# mattermost - channel (the channel name as seen in the URL, not the displayname)
|
||||
# gitter - username/room
|
||||
# xmpp - channel
|
||||
# slack - channel (without the #)
|
||||
# - ID:C123456 (where C123456 is the channel ID) does not work with webhook
|
||||
# discord - channel (without the #)
|
||||
# - ID:123456789 (where 123456789 is the channel ID)
|
||||
# (https://github.com/42wim/matterbridge/issues/57)
|
||||
# - category/channel (without the #) if you're using discord categories to group your channels
|
||||
# telegram - chatid (a large negative number, eg -123456789)
|
||||
# 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)
|
||||
# rocketchat - #channel (# is required (also needed for private channels!)
|
||||
# matrix - #channel:server (eg #yourchannel:matrix.org)
|
||||
# - encrypted rooms are not supported in matrix
|
||||
# msteams - 19:xxxxxxxxxxxxxxxxxxxxxxxxxx@thread.skype
|
||||
# - You'll find the channel ID in the URL in the threadId=19:82abcxxxxxxxxx@thread.skype
|
||||
# steam - chatid (a large number).
|
||||
# The number in the URL when you click "enter chat room" in the browser
|
||||
# whatsapp - 48111222333-123455678999@g.us A unique group JID;
|
||||
# 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
|
||||
# as group names might change in time and contain weird emoticons
|
||||
# zulip - stream/topic:topicname (without the #)
|
||||
# Platform | Identifier name | Example | Description
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
# | channel | general | Do not include the # symbol
|
||||
# discord | channel id | ID:123456789 | See https://github.com/42wim/matterbridge/issues/57
|
||||
# | category/channel | Media/gaming | Without # symbol. If you're using discord categories to group your channels
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
# gitter | username/room | general | As seen in the gitter.im URL
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
# hipchat | id_channel | example needed | See https://www.hipchat.com/account/xmpp for the correct channel
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
# irc | channel | #general | The # symbol is required and should be lowercase!
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
# mattermost | channel | general | This is the channel name as seen in the URL, not the display name
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
# matrix | #channel:server | #yourchannel:matrix.org | Encrypted rooms are not supported in matrix
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
# msteams | threadId | 19:82abcxx@thread.skype | You'll find the threadId in the URL
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
# rocketchat | channel | #channel | # is required for private channels too
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
# slack | channel name | general | Do not include the # symbol
|
||||
# | channel id | ID:C123456 | The underlying ID of a channel. This doesn't work with
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
# steam | chatid | example needed | The number in the URL when you click "enter chat room" in the browser
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
# 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
|
||||
channel="#testing"
|
||||
|
||||
1481
vendor/github.com/Rhymen/go-whatsapp/binary/proto/def.pb.go
generated
vendored
1481
vendor/github.com/Rhymen/go-whatsapp/binary/proto/def.pb.go
generated
vendored
File diff suppressed because it is too large
Load Diff
78
vendor/github.com/Rhymen/go-whatsapp/binary/proto/def.proto
generated
vendored
78
vendor/github.com/Rhymen/go-whatsapp/binary/proto/def.proto
generated
vendored
@@ -56,6 +56,8 @@ message Location {
|
||||
}
|
||||
|
||||
message Point {
|
||||
optional int32 xDeprecated = 1;
|
||||
optional int32 yDeprecated = 2;
|
||||
optional double x = 3;
|
||||
optional double y = 4;
|
||||
}
|
||||
@@ -93,6 +95,7 @@ message ContextInfo {
|
||||
optional AdReplyInfo quotedAd = 23;
|
||||
optional MessageKey placeholderKey = 24;
|
||||
optional uint32 expiration = 25;
|
||||
optional int64 ephemeralSettingTimestamp = 26;
|
||||
}
|
||||
|
||||
message SenderKeyDistributionMessage {
|
||||
@@ -136,6 +139,11 @@ message LocationMessage {
|
||||
optional string name = 3;
|
||||
optional string address = 4;
|
||||
optional string url = 5;
|
||||
optional bool isLive = 6;
|
||||
optional uint32 accuracyInMeters = 7;
|
||||
optional float speedInMps = 8;
|
||||
optional uint32 degreesClockwiseFromMagneticNorth = 9;
|
||||
optional string comment = 11;
|
||||
optional bytes jpegThumbnail = 16;
|
||||
optional ContextInfo contextInfo = 17;
|
||||
}
|
||||
@@ -238,9 +246,29 @@ message ProtocolMessage {
|
||||
enum PROTOCOL_MESSAGE_TYPE {
|
||||
REVOKE = 0;
|
||||
EPHEMERAL_SETTING = 3;
|
||||
EPHEMERAL_SYNC_RESPONSE = 4;
|
||||
HISTORY_SYNC_NOTIFICATION = 5;
|
||||
}
|
||||
optional PROTOCOL_MESSAGE_TYPE type = 2;
|
||||
optional uint32 ephemeralExpiration = 4;
|
||||
optional int64 ephemeralSettingTimestamp = 5;
|
||||
optional HistorySyncNotification historySyncNotification = 6;
|
||||
}
|
||||
|
||||
message HistorySyncNotification {
|
||||
optional bytes fileSha256 = 1;
|
||||
optional uint64 fileLength = 2;
|
||||
optional bytes mediaKey = 3;
|
||||
optional bytes fileEncSha256 = 4;
|
||||
optional string directPath = 5;
|
||||
enum HISTORY_SYNC_NOTIFICATION_HISTORYSYNCTYPE {
|
||||
INITIAL_BOOTSTRAP = 0;
|
||||
INITIAL_STATUS_V3 = 1;
|
||||
FULL = 2;
|
||||
RECENT = 3;
|
||||
}
|
||||
optional HISTORY_SYNC_NOTIFICATION_HISTORYSYNCTYPE syncType = 6;
|
||||
optional uint32 chunkOrder = 7;
|
||||
}
|
||||
|
||||
message ContactsArrayMessage {
|
||||
@@ -355,6 +383,8 @@ message StickerMessage {
|
||||
optional int64 mediaKeyTimestamp = 10;
|
||||
optional uint32 firstFrameLength = 11;
|
||||
optional bytes firstFrameSidecar = 12;
|
||||
optional bool isAnimated = 13;
|
||||
optional bytes pngThumbnail = 16;
|
||||
optional ContextInfo contextInfo = 17;
|
||||
}
|
||||
|
||||
@@ -401,6 +431,12 @@ message TemplateButtonReplyMessage {
|
||||
optional uint32 selectedIndex = 4;
|
||||
}
|
||||
|
||||
message CatalogSnapshot {
|
||||
optional ImageMessage catalogImage = 1;
|
||||
optional string title = 2;
|
||||
optional string description = 3;
|
||||
}
|
||||
|
||||
message ProductSnapshot {
|
||||
optional ImageMessage productImage = 1;
|
||||
optional string productId = 2;
|
||||
@@ -417,6 +453,7 @@ message ProductSnapshot {
|
||||
message ProductMessage {
|
||||
optional ProductSnapshot product = 1;
|
||||
optional string businessOwnerJid = 2;
|
||||
optional CatalogSnapshot catalog = 4;
|
||||
optional ContextInfo contextInfo = 17;
|
||||
}
|
||||
|
||||
@@ -513,6 +550,8 @@ message WebFeatures {
|
||||
optional WEB_FEATURES_FLAG templateMessage = 30;
|
||||
optional WEB_FEATURES_FLAG templateMessageInteractivity = 31;
|
||||
optional WEB_FEATURES_FLAG ephemeralMessages = 32;
|
||||
optional WEB_FEATURES_FLAG e2ENotificationSync = 33;
|
||||
optional WEB_FEATURES_FLAG recentStickersV2 = 34;
|
||||
}
|
||||
|
||||
message TabletNotificationsInfo {
|
||||
@@ -537,6 +576,11 @@ message WebNotificationsInfo {
|
||||
}
|
||||
|
||||
message PaymentInfo {
|
||||
enum PAYMENT_INFO_CURRENCY {
|
||||
UNKNOWN_CURRENCY = 0;
|
||||
INR = 1;
|
||||
}
|
||||
optional PAYMENT_INFO_CURRENCY currencyDeprecated = 1;
|
||||
optional uint64 amount1000 = 2;
|
||||
optional string receiverJid = 3;
|
||||
enum PAYMENT_INFO_STATUS {
|
||||
@@ -559,6 +603,37 @@ message PaymentInfo {
|
||||
optional uint64 expiryTimestamp = 7;
|
||||
optional bool futureproofed = 8;
|
||||
optional string currency = 9;
|
||||
enum PAYMENT_INFO_TXNSTATUS {
|
||||
UNKNOWN = 0;
|
||||
PENDING_SETUP = 1;
|
||||
PENDING_RECEIVER_SETUP = 2;
|
||||
INIT = 3;
|
||||
SUCCESS = 4;
|
||||
COMPLETED = 5;
|
||||
FAILED = 6;
|
||||
FAILED_RISK = 7;
|
||||
FAILED_PROCESSING = 8;
|
||||
FAILED_RECEIVER_PROCESSING = 9;
|
||||
FAILED_DA = 10;
|
||||
FAILED_DA_FINAL = 11;
|
||||
REFUNDED_TXN = 12;
|
||||
REFUND_FAILED = 13;
|
||||
REFUND_FAILED_PROCESSING = 14;
|
||||
REFUND_FAILED_DA = 15;
|
||||
EXPIRED_TXN = 16;
|
||||
AUTH_CANCELED = 17;
|
||||
AUTH_CANCEL_FAILED_PROCESSING = 18;
|
||||
AUTH_CANCEL_FAILED = 19;
|
||||
COLLECT_INIT = 20;
|
||||
COLLECT_SUCCESS = 21;
|
||||
COLLECT_FAILED = 22;
|
||||
COLLECT_FAILED_RISK = 23;
|
||||
COLLECT_REJECTED = 24;
|
||||
COLLECT_EXPIRED = 25;
|
||||
COLLECT_CANCELED = 26;
|
||||
COLLECT_CANCELLING = 27;
|
||||
}
|
||||
optional PAYMENT_INFO_TXNSTATUS txnStatus = 10;
|
||||
}
|
||||
|
||||
message WebMessageInfo {
|
||||
@@ -668,4 +743,5 @@ message WebMessageInfo {
|
||||
optional PaymentInfo quotedPaymentInfo = 31;
|
||||
optional uint64 ephemeralStartTimestamp = 32;
|
||||
optional uint32 ephemeralDuration = 33;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
3
vendor/github.com/Rhymen/go-whatsapp/conn.go
generated
vendored
3
vendor/github.com/Rhymen/go-whatsapp/conn.go
generated
vendored
@@ -90,6 +90,7 @@ type Conn struct {
|
||||
|
||||
longClientName string
|
||||
shortClientName string
|
||||
clientVersion string
|
||||
|
||||
loginSessionLock sync.RWMutex
|
||||
Proxy func(*http.Request) (*url.URL, error)
|
||||
@@ -121,6 +122,7 @@ func NewConn(timeout time.Duration) (*Conn, error) {
|
||||
|
||||
longClientName: "github.com/rhymen/go-whatsapp",
|
||||
shortClientName: "go-whatsapp",
|
||||
clientVersion: "0.1.0",
|
||||
}
|
||||
return wac, wac.connect()
|
||||
}
|
||||
@@ -135,6 +137,7 @@ func NewConnWithProxy(timeout time.Duration, proxy func(*http.Request) (*url.URL
|
||||
|
||||
longClientName: "github.com/rhymen/go-whatsapp",
|
||||
shortClientName: "go-whatsapp",
|
||||
clientVersion: "0.1.0",
|
||||
Proxy: proxy,
|
||||
}
|
||||
return wac, wac.connect()
|
||||
|
||||
2
vendor/github.com/Rhymen/go-whatsapp/go.mod
generated
vendored
2
vendor/github.com/Rhymen/go-whatsapp/go.mod
generated
vendored
@@ -6,7 +6,7 @@ require (
|
||||
github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d // indirect
|
||||
github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc2581bbf24d // indirect
|
||||
github.com/golang/protobuf v1.3.0
|
||||
github.com/gorilla/websocket v1.4.0
|
||||
github.com/gorilla/websocket v1.4.1
|
||||
github.com/pkg/errors v0.8.1
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
|
||||
)
|
||||
|
||||
3
vendor/github.com/Rhymen/go-whatsapp/go.sum
generated
vendored
3
vendor/github.com/Rhymen/go-whatsapp/go.sum
generated
vendored
@@ -12,8 +12,9 @@ github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk=
|
||||
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=
|
||||
|
||||
116
vendor/github.com/Rhymen/go-whatsapp/media.go
generated
vendored
116
vendor/github.com/Rhymen/go-whatsapp/media.go
generated
vendored
@@ -10,10 +10,8 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/Rhymen/go-whatsapp/crypto/cbc"
|
||||
@@ -95,7 +93,50 @@ func downloadMedia(url string) (file []byte, mac []byte, err error) {
|
||||
return data[:n-10], data[n-10 : n], nil
|
||||
}
|
||||
|
||||
func (wac *Conn) Upload(reader io.Reader, appInfo MediaType) (url string, mediaKey []byte, fileEncSha256 []byte, fileSha256 []byte, fileLength uint64, err error) {
|
||||
type MediaConn struct {
|
||||
Status int `json:"status"`
|
||||
MediaConn struct {
|
||||
Auth string `json:"auth"`
|
||||
TTL int `json:"ttl"`
|
||||
Hosts []struct {
|
||||
Hostname string `json:"hostname"`
|
||||
IPs []string `json:"ips"`
|
||||
} `json:"hosts"`
|
||||
} `json:"media_conn"`
|
||||
}
|
||||
|
||||
func (wac *Conn) queryMediaConn() (hostname, auth string, ttl int, err error) {
|
||||
queryReq := []interface{}{"query", "mediaConn"}
|
||||
ch, err := wac.writeJson(queryReq)
|
||||
if err != nil {
|
||||
return "", "", 0, err
|
||||
}
|
||||
|
||||
var resp MediaConn
|
||||
select {
|
||||
case r := <-ch:
|
||||
if err = json.Unmarshal([]byte(r), &resp); err != nil {
|
||||
return "", "", 0, fmt.Errorf("error decoding query media conn response: %v", err)
|
||||
}
|
||||
case <-time.After(wac.msgTimeout):
|
||||
return "", "", 0, fmt.Errorf("query media conn timed out")
|
||||
}
|
||||
|
||||
if resp.Status != 200 {
|
||||
return "", "", 0, fmt.Errorf("query media conn responded with %d", resp.Status)
|
||||
}
|
||||
|
||||
return resp.MediaConn.Hosts[0].Hostname, resp.MediaConn.Auth, resp.MediaConn.TTL, nil
|
||||
}
|
||||
|
||||
var mediaTypeMap = map[MediaType]string{
|
||||
MediaImage: "/mms/image",
|
||||
MediaVideo: "/mms/video",
|
||||
MediaDocument: "/mms/document",
|
||||
MediaAudio: "/mms/audio",
|
||||
}
|
||||
|
||||
func (wac *Conn) Upload(reader io.Reader, appInfo MediaType) (downloadURL string, mediaKey []byte, fileEncSha256 []byte, fileSha256 []byte, fileLength uint64, err error) {
|
||||
data, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
return "", nil, nil, nil, 0, err
|
||||
@@ -128,67 +169,30 @@ func (wac *Conn) Upload(reader io.Reader, appInfo MediaType) (url string, mediaK
|
||||
sha.Write(append(enc, mac...))
|
||||
fileEncSha256 = sha.Sum(nil)
|
||||
|
||||
var filetype string
|
||||
switch appInfo {
|
||||
case MediaImage:
|
||||
filetype = "image"
|
||||
case MediaAudio:
|
||||
filetype = "audio"
|
||||
case MediaDocument:
|
||||
filetype = "document"
|
||||
case MediaVideo:
|
||||
filetype = "video"
|
||||
hostname, auth, _, err := wac.queryMediaConn()
|
||||
token := base64.URLEncoding.EncodeToString(fileEncSha256)
|
||||
q := url.Values{
|
||||
"auth": []string{auth},
|
||||
"token": []string{token},
|
||||
}
|
||||
path := mediaTypeMap[appInfo]
|
||||
uploadURL := url.URL{
|
||||
Scheme: "https",
|
||||
Host: hostname,
|
||||
Path: fmt.Sprintf("%s/%s", path, token),
|
||||
RawQuery: q.Encode(),
|
||||
}
|
||||
|
||||
uploadReq := []interface{}{"action", "encr_upload", filetype, base64.StdEncoding.EncodeToString(fileEncSha256)}
|
||||
ch, err := wac.writeJson(uploadReq)
|
||||
body := bytes.NewReader(append(enc, mac...))
|
||||
|
||||
req, err := http.NewRequest("POST", uploadURL.String(), body)
|
||||
if err != nil {
|
||||
return "", nil, nil, nil, 0, err
|
||||
}
|
||||
|
||||
var resp map[string]interface{}
|
||||
select {
|
||||
case r := <-ch:
|
||||
if err = json.Unmarshal([]byte(r), &resp); err != nil {
|
||||
return "", nil, nil, nil, 0, fmt.Errorf("error decoding upload response: %v", err)
|
||||
}
|
||||
case <-time.After(wac.msgTimeout):
|
||||
return "", nil, nil, nil, 0, fmt.Errorf("restore session init timed out")
|
||||
}
|
||||
|
||||
if int(resp["status"].(float64)) != 200 {
|
||||
return "", nil, nil, nil, 0, fmt.Errorf("upload responsed with %d", resp["status"])
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
w := multipart.NewWriter(&b)
|
||||
hashWriter, err := w.CreateFormField("hash")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
}
|
||||
io.Copy(hashWriter, strings.NewReader(base64.StdEncoding.EncodeToString(fileEncSha256)))
|
||||
|
||||
fileWriter, err := w.CreateFormFile("file", "blob")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
}
|
||||
io.Copy(fileWriter, bytes.NewReader(append(enc, mac...)))
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", resp["url"].(string), &b)
|
||||
if err != nil {
|
||||
return "", nil, nil, nil, 0, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", w.FormDataContentType())
|
||||
req.Header.Set("Origin", "https://web.whatsapp.com")
|
||||
req.Header.Set("Referer", "https://web.whatsapp.com/")
|
||||
|
||||
req.URL.Query().Set("f", "j")
|
||||
|
||||
client := &http.Client{}
|
||||
// Submit the request
|
||||
res, err := client.Do(req)
|
||||
|
||||
6
vendor/github.com/Rhymen/go-whatsapp/read.go
generated
vendored
6
vendor/github.com/Rhymen/go-whatsapp/read.go
generated
vendored
@@ -15,7 +15,10 @@ import (
|
||||
)
|
||||
|
||||
func (wac *Conn) readPump() {
|
||||
defer wac.wg.Done()
|
||||
defer func() {
|
||||
wac.wg.Done()
|
||||
_, _ = wac.Disconnect()
|
||||
}()
|
||||
|
||||
var readErr error
|
||||
var msgType int
|
||||
@@ -31,7 +34,6 @@ func (wac *Conn) readPump() {
|
||||
case <-readerFound:
|
||||
if readErr != nil {
|
||||
wac.handle(&ErrConnectionFailed{Err: readErr})
|
||||
_, _ = wac.Disconnect()
|
||||
return
|
||||
}
|
||||
msg, err := ioutil.ReadAll(reader)
|
||||
|
||||
18
vendor/github.com/Rhymen/go-whatsapp/session.go
generated
vendored
18
vendor/github.com/Rhymen/go-whatsapp/session.go
generated
vendored
@@ -18,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
//represents the WhatsAppWeb client version
|
||||
var waVersion = []int{0, 3, 3324}
|
||||
var waVersion = []int{0, 4, 2080}
|
||||
|
||||
/*
|
||||
Session contains session individual information. To be able to resume the connection without scanning the qr code
|
||||
@@ -107,10 +107,10 @@ func CheckCurrentServerVersion() ([]int, error) {
|
||||
}
|
||||
|
||||
b64ClientId := base64.StdEncoding.EncodeToString(clientId)
|
||||
login := []interface{}{"admin", "init", waVersion, []string{wac.longClientName, wac.shortClientName}, b64ClientId, true}
|
||||
login := []interface{}{"admin", "init", waVersion, []string{wac.longClientName, wac.shortClientName, wac.clientVersion}, b64ClientId, true}
|
||||
loginChan, err := wac.writeJson(login)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error writing login", err)
|
||||
return nil, fmt.Errorf("error writing login: %s", err.Error())
|
||||
}
|
||||
|
||||
// Retrieve an answer from the websocket
|
||||
@@ -123,7 +123,7 @@ func CheckCurrentServerVersion() ([]int, error) {
|
||||
|
||||
var resp map[string]interface{}
|
||||
if err = json.Unmarshal([]byte(r), &resp); err != nil {
|
||||
return nil, fmt.Errorf("error decoding login", err)
|
||||
return nil, fmt.Errorf("error decoding login: %s", err.Error())
|
||||
}
|
||||
|
||||
// Take the curr property as X.Y.Z and split it into as int slice
|
||||
@@ -141,17 +141,17 @@ func CheckCurrentServerVersion() ([]int, error) {
|
||||
SetClientName sets the long and short client names that are sent to WhatsApp when logging in and displayed in the
|
||||
WhatsApp Web device list. As the values are only sent when logging in, changing them after logging in is not possible.
|
||||
*/
|
||||
func (wac *Conn) SetClientName(long, short string) error {
|
||||
func (wac *Conn) SetClientName(long, short, version string) error {
|
||||
if wac.session != nil && (wac.session.EncKey != nil || wac.session.MacKey != nil) {
|
||||
return fmt.Errorf("cannot change client name after logging in")
|
||||
}
|
||||
wac.longClientName, wac.shortClientName = long, short
|
||||
wac.longClientName, wac.shortClientName, wac.clientVersion = long, short, version
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
SetClientVersion sets WhatsApp client version
|
||||
Default value is 0.3.3324
|
||||
Default value is 0.4.2080
|
||||
*/
|
||||
func (wac *Conn) SetClientVersion(major int, minor int, patch int) {
|
||||
waVersion = []int{major, minor, patch}
|
||||
@@ -213,7 +213,7 @@ func (wac *Conn) Login(qrChan chan<- string) (Session, error) {
|
||||
}
|
||||
|
||||
session.ClientId = base64.StdEncoding.EncodeToString(clientId)
|
||||
login := []interface{}{"admin", "init", waVersion, []string{wac.longClientName, wac.shortClientName}, session.ClientId, true}
|
||||
login := []interface{}{"admin", "init", waVersion, []string{wac.longClientName, wac.shortClientName, wac.clientVersion}, session.ClientId, true}
|
||||
loginChan, err := wac.writeJson(login)
|
||||
if err != nil {
|
||||
return session, fmt.Errorf("error writing login: %v\n", err)
|
||||
@@ -369,7 +369,7 @@ func (wac *Conn) Restore() error {
|
||||
wac.listener.Unlock()
|
||||
|
||||
//admin init
|
||||
init := []interface{}{"admin", "init", waVersion, []string{wac.longClientName, wac.shortClientName}, wac.session.ClientId, true}
|
||||
init := []interface{}{"admin", "init", waVersion, []string{wac.longClientName, wac.shortClientName, wac.clientVersion}, wac.session.ClientId, true}
|
||||
initChan, err := wac.writeJson(init)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error writing admin init: %v\n", err)
|
||||
|
||||
7
vendor/github.com/d5/tengo/v2/.goreleaser.yml
generated
vendored
7
vendor/github.com/d5/tengo/v2/.goreleaser.yml
generated
vendored
@@ -11,9 +11,10 @@ builds:
|
||||
- darwin
|
||||
- linux
|
||||
- windows
|
||||
archive:
|
||||
files:
|
||||
- none*
|
||||
archives:
|
||||
-
|
||||
files:
|
||||
- none*
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
changelog:
|
||||
|
||||
5
vendor/github.com/d5/tengo/v2/README.md
generated
vendored
5
vendor/github.com/d5/tengo/v2/README.md
generated
vendored
@@ -7,7 +7,6 @@
|
||||
[](https://godoc.org/github.com/d5/tengo)
|
||||
[](https://goreportcard.com/report/github.com/d5/tengo)
|
||||
[](https://circleci.com/gh/d5/tengo)
|
||||
[](https://sourcegraph.com/github.com/d5/tengo?badge)
|
||||
|
||||
**Tengo is a small, dynamic, fast, secure script language for Go.**
|
||||
|
||||
@@ -75,6 +74,10 @@ _* See [here](https://github.com/d5/tengobench) for commands/codes used_
|
||||
|
||||
## Quick Start
|
||||
|
||||
```
|
||||
go get github.com/d5/tengo/v2
|
||||
```
|
||||
|
||||
A simple Go example code that compiles/runs Tengo script code with some input/output values:
|
||||
|
||||
```golang
|
||||
|
||||
109
vendor/github.com/d5/tengo/v2/builtins.go
generated
vendored
109
vendor/github.com/d5/tengo/v2/builtins.go
generated
vendored
@@ -13,6 +13,14 @@ var builtinFuncs = []*BuiltinFunction{
|
||||
Name: "append",
|
||||
Value: builtinAppend,
|
||||
},
|
||||
{
|
||||
Name: "delete",
|
||||
Value: builtinDelete,
|
||||
},
|
||||
{
|
||||
Name: "splice",
|
||||
Value: builtinSplice,
|
||||
},
|
||||
{
|
||||
Name: "string",
|
||||
Value: builtinString,
|
||||
@@ -500,3 +508,104 @@ func builtinAppend(args ...Object) (Object, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// builtinDelete deletes Map keys
|
||||
// usage: delete(map, "key")
|
||||
// key must be a string
|
||||
func builtinDelete(args ...Object) (Object, error) {
|
||||
argsLen := len(args)
|
||||
if argsLen != 2 {
|
||||
return nil, ErrWrongNumArguments
|
||||
}
|
||||
switch arg := args[0].(type) {
|
||||
case *Map:
|
||||
if key, ok := args[1].(*String); ok {
|
||||
delete(arg.Value, key.Value)
|
||||
return UndefinedValue, nil
|
||||
}
|
||||
return nil, ErrInvalidArgumentType{
|
||||
Name: "second",
|
||||
Expected: "string",
|
||||
Found: args[1].TypeName(),
|
||||
}
|
||||
default:
|
||||
return nil, ErrInvalidArgumentType{
|
||||
Name: "first",
|
||||
Expected: "map",
|
||||
Found: arg.TypeName(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// builtinSplice deletes and changes given Array, returns deleted items.
|
||||
// usage:
|
||||
// deleted_items := splice(array[,start[,delete_count[,item1[,item2[,...]]]])
|
||||
func builtinSplice(args ...Object) (Object, error) {
|
||||
argsLen := len(args)
|
||||
if argsLen == 0 {
|
||||
return nil, ErrWrongNumArguments
|
||||
}
|
||||
|
||||
array, ok := args[0].(*Array)
|
||||
if !ok {
|
||||
return nil, ErrInvalidArgumentType{
|
||||
Name: "first",
|
||||
Expected: "array",
|
||||
Found: args[0].TypeName(),
|
||||
}
|
||||
}
|
||||
arrayLen := len(array.Value)
|
||||
|
||||
var startIdx int
|
||||
if argsLen > 1 {
|
||||
arg1, ok := args[1].(*Int)
|
||||
if !ok {
|
||||
return nil, ErrInvalidArgumentType{
|
||||
Name: "second",
|
||||
Expected: "int",
|
||||
Found: args[1].TypeName(),
|
||||
}
|
||||
}
|
||||
startIdx = int(arg1.Value)
|
||||
if startIdx < 0 || startIdx > arrayLen {
|
||||
return nil, ErrIndexOutOfBounds
|
||||
}
|
||||
}
|
||||
|
||||
delCount := len(array.Value)
|
||||
if argsLen > 2 {
|
||||
arg2, ok := args[2].(*Int)
|
||||
if !ok {
|
||||
return nil, ErrInvalidArgumentType{
|
||||
Name: "third",
|
||||
Expected: "int",
|
||||
Found: args[2].TypeName(),
|
||||
}
|
||||
}
|
||||
delCount = int(arg2.Value)
|
||||
if delCount < 0 {
|
||||
return nil, ErrIndexOutOfBounds
|
||||
}
|
||||
}
|
||||
// if count of to be deleted items is bigger than expected, truncate it
|
||||
if startIdx+delCount > arrayLen {
|
||||
delCount = arrayLen - startIdx
|
||||
}
|
||||
// delete items
|
||||
endIdx := startIdx + delCount
|
||||
deleted := append([]Object{}, array.Value[startIdx:endIdx]...)
|
||||
|
||||
head := array.Value[:startIdx]
|
||||
var items []Object
|
||||
if argsLen > 3 {
|
||||
items = make([]Object, 0, argsLen-3)
|
||||
for i := 3; i < argsLen; i++ {
|
||||
items = append(items, args[i])
|
||||
}
|
||||
}
|
||||
items = append(items, array.Value[endIdx:]...)
|
||||
array.Value = append(head, items...)
|
||||
|
||||
// return deleted items
|
||||
return &Array{Value: deleted}, nil
|
||||
}
|
||||
|
||||
6
vendor/github.com/d5/tengo/v2/vm.go
generated
vendored
6
vendor/github.com/d5/tengo/v2/vm.go
generated
vendored
@@ -80,14 +80,14 @@ func (v *VM) Run() (err error) {
|
||||
if err != nil {
|
||||
filePos := v.fileSet.Position(
|
||||
v.curFrame.fn.SourcePos(v.ip - 1))
|
||||
err = fmt.Errorf("Runtime Error: %s\n\tat %s",
|
||||
err.Error(), filePos)
|
||||
err = fmt.Errorf("Runtime Error: %w\n\tat %s",
|
||||
err, filePos)
|
||||
for v.framesIndex > 1 {
|
||||
v.framesIndex--
|
||||
v.curFrame = &v.frames[v.framesIndex-1]
|
||||
filePos = v.fileSet.Position(
|
||||
v.curFrame.fn.SourcePos(v.curFrame.ip - 1))
|
||||
err = fmt.Errorf("%s\n\tat %s", err.Error(), filePos)
|
||||
err = fmt.Errorf("%w\n\tat %s", err, filePos)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
4
vendor/github.com/matterbridge/Rocket.Chat.Go.SDK/models/message.go
generated
vendored
4
vendor/github.com/matterbridge/Rocket.Chat.Go.SDK/models/message.go
generated
vendored
@@ -7,6 +7,7 @@ type Message struct {
|
||||
RoomID string `json:"rid"`
|
||||
Msg string `json:"msg"`
|
||||
EditedBy string `json:"editedBy,omitempty"`
|
||||
Type string `json:"t,omitempty"`
|
||||
|
||||
Groupable bool `json:"groupable,omitempty"`
|
||||
|
||||
@@ -16,6 +17,9 @@ type Message struct {
|
||||
|
||||
Mentions []User `json:"mentions,omitempty"`
|
||||
User *User `json:"u,omitempty"`
|
||||
|
||||
Attachments []Attachment `json:"attachments,omitempty"`
|
||||
|
||||
PostMessage
|
||||
|
||||
// Bot interface{} `json:"bot"`
|
||||
|
||||
22
vendor/github.com/matterbridge/Rocket.Chat.Go.SDK/realtime/messages.go
generated
vendored
22
vendor/github.com/matterbridge/Rocket.Chat.Go.SDK/realtime/messages.go
generated
vendored
@@ -191,6 +191,26 @@ func getMessageFromData(data interface{}) *models.Message {
|
||||
|
||||
func getMessageFromDocument(arg *gabs.Container) *models.Message {
|
||||
var ts *time.Time
|
||||
var attachments []models.Attachment
|
||||
|
||||
attachmentSrc, err := arg.Path("attachments").Children()
|
||||
if err != nil {
|
||||
attachments = make([]models.Attachment, 0)
|
||||
} else {
|
||||
attachments = make([]models.Attachment, len(attachmentSrc))
|
||||
for i, attachment := range attachmentSrc {
|
||||
attachments[i] = models.Attachment{
|
||||
Timestamp: stringOrZero(attachment.Path("ts").Data()),
|
||||
Title: stringOrZero(attachment.Path("title").Data()),
|
||||
TitleLink: stringOrZero(attachment.Path("title_link").Data()),
|
||||
TitleLinkDownload: stringOrZero(attachment.Path("title_link_download").Data()),
|
||||
ImageURL: stringOrZero(attachment.Path("image_url").Data()),
|
||||
|
||||
AuthorName: stringOrZero(arg.Path("u.name").Data()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
date := stringOrZero(arg.Path("ts.$date").Data())
|
||||
if len(date) > 0 {
|
||||
if ti, err := strconv.ParseFloat(date, 64); err == nil {
|
||||
@@ -202,11 +222,13 @@ func getMessageFromDocument(arg *gabs.Container) *models.Message {
|
||||
ID: stringOrZero(arg.Path("_id").Data()),
|
||||
RoomID: stringOrZero(arg.Path("rid").Data()),
|
||||
Msg: stringOrZero(arg.Path("msg").Data()),
|
||||
Type: stringOrZero(arg.Path("t").Data()),
|
||||
Timestamp: ts,
|
||||
User: &models.User{
|
||||
ID: stringOrZero(arg.Path("u._id").Data()),
|
||||
UserName: stringOrZero(arg.Path("u.username").Data()),
|
||||
},
|
||||
Attachments: attachments,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
271
vendor/github.com/matterbridge/go-xmpp/xmpp.go
generated
vendored
271
vendor/github.com/matterbridge/go-xmpp/xmpp.go
generated
vendored
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
@@ -45,6 +45,9 @@ const (
|
||||
// Default TLS configuration options
|
||||
var DefaultConfig tls.Config
|
||||
|
||||
// DebugWriter is the writer used to write debugging output to.
|
||||
var DebugWriter io.Writer = os.Stderr
|
||||
|
||||
// Cookie is a unique XMPP session identifier
|
||||
type Cookie uint64
|
||||
|
||||
@@ -191,21 +194,40 @@ type Options struct {
|
||||
|
||||
// Status message
|
||||
StatusMessage string
|
||||
|
||||
// Logger
|
||||
Logger io.Writer
|
||||
}
|
||||
|
||||
// NewClient establishes a new Client connection based on a set of Options.
|
||||
func (o Options) NewClient() (*Client, error) {
|
||||
host := o.Host
|
||||
if strings.TrimSpace(host) == "" {
|
||||
a := strings.SplitN(o.User, "@", 2)
|
||||
if len(a) == 2 {
|
||||
if _, addrs, err := net.LookupSRV("xmpp-client", "tcp", a[1]); err == nil {
|
||||
if len(addrs) > 0 {
|
||||
// default to first record
|
||||
host = fmt.Sprintf("%s:%d", addrs[0].Target, addrs[0].Port)
|
||||
defP := addrs[0].Priority
|
||||
for _, adr := range addrs {
|
||||
if adr.Priority < defP {
|
||||
host = fmt.Sprintf("%s:%d", adr.Target, adr.Port)
|
||||
defP = adr.Priority
|
||||
}
|
||||
}
|
||||
} else {
|
||||
host = a[1]
|
||||
}
|
||||
} else {
|
||||
host = a[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
c, err := connect(host, o.User, o.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if strings.LastIndex(o.Host, ":") > 0 {
|
||||
host = host[:strings.LastIndex(o.Host, ":")]
|
||||
if strings.LastIndex(host, ":") > 0 {
|
||||
host = host[:strings.LastIndex(host, ":")]
|
||||
}
|
||||
|
||||
client := new(Client)
|
||||
@@ -487,6 +509,8 @@ func (c *Client) startTLSIfRequired(f *streamFeatures, o *Options, domain string
|
||||
case f.StartTLS == nil:
|
||||
// the server does not support STARTTLS
|
||||
return f, nil
|
||||
case !o.StartTLS && f.StartTLS.Required == nil:
|
||||
return f, nil
|
||||
case f.StartTLS.Required != nil:
|
||||
// the server requires STARTTLS.
|
||||
case !o.StartTLS:
|
||||
@@ -527,7 +551,7 @@ func (c *Client) startTLSIfRequired(f *streamFeatures, o *Options, domain string
|
||||
// will be returned.
|
||||
func (c *Client) startStream(o *Options, domain string) (*streamFeatures, error) {
|
||||
if o.Debug {
|
||||
c.p = xml.NewDecoder(tee{c.conn, o.Logger})
|
||||
c.p = xml.NewDecoder(tee{c.conn, DebugWriter})
|
||||
} else {
|
||||
c.p = xml.NewDecoder(c.conn)
|
||||
}
|
||||
@@ -618,6 +642,24 @@ func (c *Client) Recv() (stanza interface{}, err error) {
|
||||
}
|
||||
switch v := val.(type) {
|
||||
case *clientMessage:
|
||||
if v.Event.XMLNS == XMPPNS_PUBSUB_EVENT {
|
||||
// Handle Pubsub notifications
|
||||
switch v.Event.Items.Node {
|
||||
case XMPPNS_AVATAR_PEP_METADATA:
|
||||
return handleAvatarMetadata(v.Event.Items.Items[0].Body,
|
||||
v.From)
|
||||
// I am not sure whether this can even happen.
|
||||
// XEP-0084 only specifies a subscription to
|
||||
// the metadata node.
|
||||
/*case XMPPNS_AVATAR_PEP_DATA:
|
||||
return handleAvatarData(v.Event.Items.Items[0].Body,
|
||||
v.From,
|
||||
v.Event.Items.Items[0].ID)*/
|
||||
default:
|
||||
return pubsubClientToReturn(v.Event), nil
|
||||
}
|
||||
}
|
||||
|
||||
stamp, _ := time.Parse(
|
||||
"2006-01-02T15:04:05Z",
|
||||
v.Delay.Stamp,
|
||||
@@ -644,25 +686,166 @@ func (c *Client) Recv() (stanza interface{}, err error) {
|
||||
case *clientPresence:
|
||||
return Presence{v.From, v.To, v.Type, v.Show, v.Status}, nil
|
||||
case *clientIQ:
|
||||
// TODO check more strictly
|
||||
if bytes.Equal(bytes.TrimSpace(v.Query), []byte(`<ping xmlns='urn:xmpp:ping'/>`)) || bytes.Equal(bytes.TrimSpace(v.Query), []byte(`<ping xmlns="urn:xmpp:ping"/>`)) {
|
||||
switch {
|
||||
case v.Query.XMLName.Space == "urn:xmpp:ping":
|
||||
// TODO check more strictly
|
||||
err := c.SendResultPing(v.ID, v.From)
|
||||
if err != nil {
|
||||
return Chat{}, err
|
||||
}
|
||||
fallthrough
|
||||
case v.Type == "error":
|
||||
switch v.ID {
|
||||
case "sub1":
|
||||
// Pubsub subscription failed
|
||||
var errs []clientPubsubError
|
||||
err := xml.Unmarshal([]byte(v.Error.InnerXML), &errs)
|
||||
if err != nil {
|
||||
return PubsubSubscription{}, err
|
||||
}
|
||||
|
||||
var errsStr []string
|
||||
for _, e := range errs {
|
||||
errsStr = append(errsStr, e.XMLName.Local)
|
||||
}
|
||||
|
||||
return PubsubSubscription{
|
||||
Errors: errsStr,
|
||||
}, nil
|
||||
}
|
||||
case v.Type == "result":
|
||||
switch v.ID {
|
||||
case "sub1":
|
||||
if v.Query.XMLName.Local == "pubsub" {
|
||||
// Subscription or unsubscription was successful
|
||||
var sub clientPubsubSubscription
|
||||
err := xml.Unmarshal([]byte(v.Query.InnerXML), &sub)
|
||||
if err != nil {
|
||||
return PubsubSubscription{}, err
|
||||
}
|
||||
|
||||
return PubsubSubscription{
|
||||
SubID: sub.SubID,
|
||||
JID: sub.JID,
|
||||
Node: sub.Node,
|
||||
Errors: nil,
|
||||
}, nil
|
||||
}
|
||||
case "unsub1":
|
||||
if v.Query.XMLName.Local == "pubsub" {
|
||||
var sub clientPubsubSubscription
|
||||
err := xml.Unmarshal([]byte(v.Query.InnerXML), &sub)
|
||||
if err != nil {
|
||||
return PubsubUnsubscription{}, err
|
||||
}
|
||||
|
||||
return PubsubUnsubscription{
|
||||
SubID: sub.SubID,
|
||||
JID: v.From,
|
||||
Node: sub.Node,
|
||||
Errors: nil,
|
||||
}, nil
|
||||
} else {
|
||||
// Unsubscribing MAY contain a pubsub element. But it does
|
||||
// not have to
|
||||
return PubsubUnsubscription{
|
||||
SubID: "",
|
||||
JID: v.From,
|
||||
Node: "",
|
||||
Errors: nil,
|
||||
}, nil
|
||||
}
|
||||
case "info1":
|
||||
if v.Query.XMLName.Space == XMPPNS_DISCO_ITEMS {
|
||||
var itemsQuery clientDiscoItemsQuery
|
||||
err := xml.Unmarshal(v.InnerXML, &itemsQuery)
|
||||
if err != nil {
|
||||
return []DiscoItem{}, err
|
||||
}
|
||||
|
||||
return DiscoItems{
|
||||
Jid: v.From,
|
||||
Items: clientDiscoItemsToReturn(itemsQuery.Items),
|
||||
}, nil
|
||||
}
|
||||
case "info3":
|
||||
if v.Query.XMLName.Space == XMPPNS_DISCO_INFO {
|
||||
var disco clientDiscoQuery
|
||||
err := xml.Unmarshal(v.InnerXML, &disco)
|
||||
if err != nil {
|
||||
return DiscoResult{}, err
|
||||
}
|
||||
|
||||
return DiscoResult{
|
||||
Features: clientFeaturesToReturn(disco.Features),
|
||||
Identities: clientIdentitiesToReturn(disco.Identities),
|
||||
}, nil
|
||||
}
|
||||
case "items1", "items3":
|
||||
if v.Query.XMLName.Local == "pubsub" {
|
||||
var p clientPubsubItems
|
||||
err := xml.Unmarshal([]byte(v.Query.InnerXML), &p)
|
||||
if err != nil {
|
||||
return PubsubItems{}, err
|
||||
}
|
||||
|
||||
switch p.Node {
|
||||
case XMPPNS_AVATAR_PEP_DATA:
|
||||
return handleAvatarData(p.Items[0].Body,
|
||||
v.From,
|
||||
p.Items[0].ID)
|
||||
case XMPPNS_AVATAR_PEP_METADATA:
|
||||
return handleAvatarMetadata(p.Items[0].Body,
|
||||
v.From)
|
||||
default:
|
||||
return PubsubItems{
|
||||
p.Node,
|
||||
pubsubItemsToReturn(p.Items),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
// Note: XEP-0084 states that metadata and data
|
||||
// should be fetched with an id of retrieve1.
|
||||
// Since we already have PubSub implemented, we
|
||||
// can just use items1 and items3 to do the same
|
||||
// as an Avatar node is just a PEP (PubSub) node.
|
||||
/*case "retrieve1":
|
||||
if v.Query.XMLName.Local == "pubsub" {
|
||||
var p clientPubsubItems
|
||||
err := xml.Unmarshal([]byte(v.Query.InnerXML), &p)
|
||||
if err != nil {
|
||||
return PubsubItems{}, err
|
||||
}
|
||||
|
||||
switch p.Node {
|
||||
case XMPPNS_AVATAR_PEP_DATA:
|
||||
return handleAvatarData(p.Items[0].Body,
|
||||
v.From,
|
||||
p.Items[0].ID)
|
||||
case XMPPNS_AVATAR_PEP_METADATA:
|
||||
return handleAvatarMetadata(p.Items[0].Body,
|
||||
v.From)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
case v.Query.XMLName.Local == "":
|
||||
return IQ{ID: v.ID, From: v.From, To: v.To, Type: v.Type}, nil
|
||||
default:
|
||||
res, err := xml.Marshal(v.Query)
|
||||
if err != nil {
|
||||
return Chat{}, err
|
||||
}
|
||||
|
||||
return IQ{ID: v.ID, From: v.From, To: v.To, Type: v.Type,
|
||||
Query: res}, nil
|
||||
}
|
||||
return IQ{ID: v.ID, From: v.From, To: v.To, Type: v.Type, Query: v.Query}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send sends the message wrapped inside an XMPP message stanza body.
|
||||
func (c *Client) Send(chat Chat) (n int, err error) {
|
||||
var subtext = ``
|
||||
var thdtext = ``
|
||||
var oobtext = ``
|
||||
var msgidtext = ``
|
||||
var msgcorrecttext = ``
|
||||
var subtext, thdtext, oobtext, msgidtext, msgcorrecttext string
|
||||
if chat.Subject != `` {
|
||||
subtext = `<subject>` + xmlEscape(chat.Subject) + `</subject>`
|
||||
}
|
||||
@@ -676,20 +859,25 @@ func (c *Client) Send(chat Chat) (n int, err error) {
|
||||
}
|
||||
oobtext += `</x>`
|
||||
}
|
||||
|
||||
if chat.ID != `` {
|
||||
msgidtext = `id='` + xmlEscape(chat.ID) + `'`
|
||||
} else {
|
||||
msgidtext = `id='` + cnonce() + `'`
|
||||
}
|
||||
|
||||
if chat.ReplaceID != `` {
|
||||
msgcorrecttext = `<replace id='` + xmlEscape(chat.ReplaceID) + `' xmlns='urn:xmpp:message-correct:0'/>`
|
||||
}
|
||||
return fmt.Fprintf(c.conn, "<message to='%s' type='%s' " + msgidtext + " xml:lang='en'>" + subtext + "<body>%s</body>" + msgcorrecttext + oobtext + thdtext + "</message>",
|
||||
xmlEscape(chat.Remote), xmlEscape(chat.Type), xmlEscape(chat.Text))
|
||||
|
||||
stanza := "<message to='%s' type='%s' " + msgidtext + " xml:lang='en'>" + subtext + "<body>%s</body>" + msgcorrecttext + oobtext + thdtext + "</message>"
|
||||
|
||||
return fmt.Fprintf(c.conn, stanza, xmlEscape(chat.Remote), xmlEscape(chat.Type), xmlEscape(chat.Text))
|
||||
}
|
||||
|
||||
// SendOOB sends OOB data wrapped inside an XMPP message stanza, without actual body.
|
||||
func (c *Client) SendOOB(chat Chat) (n int, err error) {
|
||||
var thdtext = ``
|
||||
var oobtext = ``
|
||||
var thdtext, oobtext string
|
||||
if chat.Thread != `` {
|
||||
thdtext = `<thread>` + xmlEscape(chat.Thread) + `</thread>`
|
||||
}
|
||||
@@ -700,8 +888,8 @@ func (c *Client) SendOOB(chat Chat) (n int, err error) {
|
||||
}
|
||||
oobtext += `</x>`
|
||||
}
|
||||
return fmt.Fprintf(c.conn, "<message to='%s' type='%s' xml:lang='en'>" + oobtext + thdtext + "</message>",
|
||||
xmlEscape(chat.Remote), xmlEscape(chat.Type))
|
||||
return fmt.Fprintf(c.conn, "<message to='%s' type='%s' id='%s' xml:lang='en'>"+oobtext+thdtext+"</message>",
|
||||
xmlEscape(chat.Remote), xmlEscape(chat.Type), cnonce())
|
||||
}
|
||||
|
||||
// SendOrg sends the original text without being wrapped in an XMPP message stanza.
|
||||
@@ -800,8 +988,8 @@ type bindBind struct {
|
||||
}
|
||||
|
||||
type clientMessageCorrect struct {
|
||||
XMLName xml.Name `xml:"urn:xmpp:message-correct:0 replace"`
|
||||
ID string `xml:"id,attr"`
|
||||
XMLName xml.Name `xml:"urn:xmpp:message-correct:0 replace"`
|
||||
ID string `xml:"id,attr"`
|
||||
}
|
||||
|
||||
// RFC 3921 B.1 jabber:client
|
||||
@@ -813,11 +1001,14 @@ type clientMessage struct {
|
||||
Type string `xml:"type,attr"` // chat, error, groupchat, headline, or normal
|
||||
|
||||
// These should technically be []clientText, but string is much more convenient.
|
||||
Subject string `xml:"subject"`
|
||||
Body string `xml:"body"`
|
||||
Thread string `xml:"thread"`
|
||||
Subject string `xml:"subject"`
|
||||
Body string `xml:"body"`
|
||||
Thread string `xml:"thread"`
|
||||
ReplaceID clientMessageCorrect
|
||||
|
||||
// Pubsub
|
||||
Event clientPubsubEvent `xml:"event"`
|
||||
|
||||
// Any hasn't matched element
|
||||
Other []XMLElement `xml:",any"`
|
||||
|
||||
@@ -882,23 +1073,27 @@ type clientPresence struct {
|
||||
Error *clientError
|
||||
}
|
||||
|
||||
type clientIQ struct { // info/query
|
||||
XMLName xml.Name `xml:"jabber:client iq"`
|
||||
From string `xml:"from,attr"`
|
||||
ID string `xml:"id,attr"`
|
||||
To string `xml:"to,attr"`
|
||||
Type string `xml:"type,attr"` // error, get, result, set
|
||||
Query []byte `xml:",innerxml"`
|
||||
type clientIQ struct {
|
||||
// info/query
|
||||
XMLName xml.Name `xml:"jabber:client iq"`
|
||||
From string `xml:"from,attr"`
|
||||
ID string `xml:"id,attr"`
|
||||
To string `xml:"to,attr"`
|
||||
Type string `xml:"type,attr"` // error, get, result, set
|
||||
Query XMLElement `xml:",any"`
|
||||
Error clientError
|
||||
Bind bindBind
|
||||
|
||||
InnerXML []byte `xml:",innerxml"`
|
||||
}
|
||||
|
||||
type clientError struct {
|
||||
XMLName xml.Name `xml:"jabber:client error"`
|
||||
Code string `xml:",attr"`
|
||||
Type string `xml:",attr"`
|
||||
Any xml.Name
|
||||
Text string
|
||||
XMLName xml.Name `xml:"jabber:client error"`
|
||||
Code string `xml:",attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
Any xml.Name
|
||||
InnerXML []byte `xml:",innerxml"`
|
||||
Text string
|
||||
}
|
||||
|
||||
type clientQuery struct {
|
||||
|
||||
125
vendor/github.com/matterbridge/go-xmpp/xmpp_avatar.go
generated
vendored
Normal file
125
vendor/github.com/matterbridge/go-xmpp/xmpp_avatar.go
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
package xmpp
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
XMPPNS_AVATAR_PEP_DATA = "urn:xmpp:avatar:data"
|
||||
XMPPNS_AVATAR_PEP_METADATA = "urn:xmpp:avatar:metadata"
|
||||
)
|
||||
|
||||
type clientAvatarData struct {
|
||||
XMLName xml.Name `xml:"data"`
|
||||
Data []byte `xml:",innerxml"`
|
||||
}
|
||||
|
||||
type clientAvatarInfo struct {
|
||||
XMLName xml.Name `xml:"info"`
|
||||
Bytes string `xml:"bytes,attr"`
|
||||
Width string `xml:"width,attr"`
|
||||
Height string `xml:"height,attr"`
|
||||
ID string `xml:"id,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
URL string `xml:"url,attr"`
|
||||
}
|
||||
|
||||
type clientAvatarMetadata struct {
|
||||
XMLName xml.Name `xml:"metadata"`
|
||||
XMLNS string `xml:"xmlns,attr"`
|
||||
Info clientAvatarInfo `xml:"info"`
|
||||
}
|
||||
|
||||
type AvatarData struct {
|
||||
Data []byte
|
||||
From string
|
||||
}
|
||||
|
||||
type AvatarMetadata struct {
|
||||
From string
|
||||
Bytes int
|
||||
Width int
|
||||
Height int
|
||||
ID string
|
||||
Type string
|
||||
URL string
|
||||
}
|
||||
|
||||
func handleAvatarData(itemsBody []byte, from, id string) (AvatarData, error) {
|
||||
var data clientAvatarData
|
||||
err := xml.Unmarshal(itemsBody, &data)
|
||||
if err != nil {
|
||||
return AvatarData{}, err
|
||||
}
|
||||
|
||||
// Base64-decode the avatar data to check its SHA1 hash
|
||||
dataRaw, err := base64.StdEncoding.DecodeString(
|
||||
string(data.Data))
|
||||
if err != nil {
|
||||
return AvatarData{}, err
|
||||
}
|
||||
|
||||
hash := sha1.Sum(dataRaw)
|
||||
hashStr := hex.EncodeToString(hash[:])
|
||||
if hashStr != id {
|
||||
return AvatarData{}, errors.New("SHA1 hashes do not match")
|
||||
}
|
||||
|
||||
return AvatarData{
|
||||
Data: dataRaw,
|
||||
From: from,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func handleAvatarMetadata(body []byte, from string) (AvatarMetadata, error) {
|
||||
var meta clientAvatarMetadata
|
||||
err := xml.Unmarshal(body, &meta)
|
||||
if err != nil {
|
||||
return AvatarMetadata{}, err
|
||||
}
|
||||
|
||||
return AvatarMetadata{
|
||||
From: from,
|
||||
Bytes: atoiw(meta.Info.Bytes),
|
||||
Width: atoiw(meta.Info.Width),
|
||||
Height: atoiw(meta.Info.Height),
|
||||
ID: meta.Info.ID,
|
||||
Type: meta.Info.Type,
|
||||
URL: meta.Info.URL,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// A wrapper for atoi which just returns -1 if an error occurs
|
||||
func atoiw(str string) int {
|
||||
i, err := strconv.Atoi(str)
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
func (c *Client) AvatarSubscribeMetadata(jid string) {
|
||||
c.PubsubSubscribeNode(XMPPNS_AVATAR_PEP_METADATA, jid)
|
||||
}
|
||||
|
||||
func (c *Client) AvatarUnsubscribeMetadata(jid string) {
|
||||
c.PubsubUnsubscribeNode(XMPPNS_AVATAR_PEP_METADATA, jid)
|
||||
}
|
||||
|
||||
func (c *Client) AvatarRequestData(jid string) {
|
||||
c.PubsubRequestLastItems(XMPPNS_AVATAR_PEP_DATA, jid)
|
||||
}
|
||||
|
||||
func (c *Client) AvatarRequestDataByID(jid, id string) {
|
||||
c.PubsubRequestItem(XMPPNS_AVATAR_PEP_DATA, jid, id)
|
||||
}
|
||||
|
||||
func (c *Client) AvatarRequestMetadata(jid string) {
|
||||
c.PubsubRequestLastItems(XMPPNS_AVATAR_PEP_METADATA, jid)
|
||||
}
|
||||
99
vendor/github.com/matterbridge/go-xmpp/xmpp_disco.go
generated
vendored
Normal file
99
vendor/github.com/matterbridge/go-xmpp/xmpp_disco.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
package xmpp
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
)
|
||||
|
||||
const (
|
||||
XMPPNS_DISCO_ITEMS = "http://jabber.org/protocol/disco#items"
|
||||
XMPPNS_DISCO_INFO = "http://jabber.org/protocol/disco#info"
|
||||
)
|
||||
|
||||
type clientDiscoFeature struct {
|
||||
XMLName xml.Name `xml:"feature"`
|
||||
Var string `xml:"var,attr"`
|
||||
}
|
||||
|
||||
type clientDiscoIdentity struct {
|
||||
XMLName xml.Name `xml:"identity"`
|
||||
Category string `xml:"category,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
Name string `xml:"name,attr"`
|
||||
}
|
||||
|
||||
type clientDiscoQuery struct {
|
||||
XMLName xml.Name `xml:"query"`
|
||||
Features []clientDiscoFeature `xml:"feature"`
|
||||
Identities []clientDiscoIdentity `xml:"identity"`
|
||||
}
|
||||
|
||||
type clientDiscoItem struct {
|
||||
XMLName xml.Name `xml:"item"`
|
||||
Jid string `xml:"jid,attr"`
|
||||
Node string `xml:"node,attr"`
|
||||
Name string `xml:"name,attr"`
|
||||
}
|
||||
|
||||
type clientDiscoItemsQuery struct {
|
||||
XMLName xml.Name `xml:"query"`
|
||||
Items []clientDiscoItem `xml:"item"`
|
||||
}
|
||||
|
||||
type DiscoIdentity struct {
|
||||
Category string
|
||||
Type string
|
||||
Name string
|
||||
}
|
||||
|
||||
type DiscoItem struct {
|
||||
Jid string
|
||||
Name string
|
||||
Node string
|
||||
}
|
||||
|
||||
type DiscoResult struct {
|
||||
Features []string
|
||||
Identities []DiscoIdentity
|
||||
}
|
||||
|
||||
type DiscoItems struct {
|
||||
Jid string
|
||||
Items []DiscoItem
|
||||
}
|
||||
|
||||
func clientFeaturesToReturn(features []clientDiscoFeature) []string {
|
||||
var ret []string
|
||||
|
||||
for _, feature := range features {
|
||||
ret = append(ret, feature.Var)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func clientIdentitiesToReturn(identities []clientDiscoIdentity) []DiscoIdentity {
|
||||
var ret []DiscoIdentity
|
||||
|
||||
for _, id := range identities {
|
||||
ret = append(ret, DiscoIdentity{
|
||||
Category: id.Category,
|
||||
Type: id.Type,
|
||||
Name: id.Name,
|
||||
})
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func clientDiscoItemsToReturn(items []clientDiscoItem) []DiscoItem {
|
||||
var ret []DiscoItem
|
||||
for _, item := range items {
|
||||
ret = append(ret, DiscoItem{
|
||||
Jid: item.Jid,
|
||||
Name: item.Name,
|
||||
Node: item.Node,
|
||||
})
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
20
vendor/github.com/matterbridge/go-xmpp/xmpp_information_query.go
generated
vendored
20
vendor/github.com/matterbridge/go-xmpp/xmpp_information_query.go
generated
vendored
@@ -10,10 +10,26 @@ const IQTypeSet = "set"
|
||||
const IQTypeResult = "result"
|
||||
|
||||
func (c *Client) Discovery() (string, error) {
|
||||
const namespace = "http://jabber.org/protocol/disco#items"
|
||||
// use getCookie for a pseudo random id.
|
||||
reqID := strconv.FormatUint(uint64(getCookie()), 10)
|
||||
return c.RawInformationQuery(c.jid, c.domain, reqID, IQTypeGet, namespace, "")
|
||||
return c.RawInformationQuery(c.jid, c.domain, reqID, IQTypeGet, XMPPNS_DISCO_ITEMS, "")
|
||||
}
|
||||
|
||||
// Discover information about a node
|
||||
func (c *Client) DiscoverNodeInfo(node string) (string, error) {
|
||||
query := fmt.Sprintf("<query xmlns='%s' node='%s'/>", XMPPNS_DISCO_INFO, node)
|
||||
return c.RawInformation(c.jid, c.domain, "info3", IQTypeGet, query)
|
||||
}
|
||||
|
||||
// Discover items that the server exposes
|
||||
func (c *Client) DiscoverServerItems() (string, error) {
|
||||
return c.DiscoverEntityItems(c.domain)
|
||||
}
|
||||
|
||||
// Discover items that an entity exposes
|
||||
func (c *Client) DiscoverEntityItems(jid string) (string, error) {
|
||||
query := fmt.Sprintf("<query xmlns='%s'/>", XMPPNS_DISCO_ITEMS)
|
||||
return c.RawInformation(c.jid, jid, "info1", IQTypeGet, query)
|
||||
}
|
||||
|
||||
// RawInformationQuery sends an information query request to the server.
|
||||
|
||||
82
vendor/github.com/matterbridge/go-xmpp/xmpp_muc.go
generated
vendored
82
vendor/github.com/matterbridge/go-xmpp/xmpp_muc.go
generated
vendored
@@ -8,19 +8,19 @@
|
||||
package xmpp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
nsMUC = "http://jabber.org/protocol/muc"
|
||||
nsMUCUser = "http://jabber.org/protocol/muc#user"
|
||||
NoHistory = 0
|
||||
CharHistory = 1
|
||||
StanzaHistory = 2
|
||||
nsMUC = "http://jabber.org/protocol/muc"
|
||||
nsMUCUser = "http://jabber.org/protocol/muc#user"
|
||||
NoHistory = 0
|
||||
CharHistory = 1
|
||||
StanzaHistory = 2
|
||||
SecondsHistory = 3
|
||||
SinceHistory = 4
|
||||
SinceHistory = 4
|
||||
)
|
||||
|
||||
// Send sends room topic wrapped inside an XMPP message stanza body.
|
||||
@@ -47,35 +47,35 @@ func (c *Client) JoinMUC(jid, nick string, history_type, history int, history_da
|
||||
}
|
||||
switch history_type {
|
||||
case NoHistory:
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
|
||||
"<x xmlns='%s' />\n" +
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n"+
|
||||
"<x xmlns='%s' />\n"+
|
||||
"</presence>",
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC)
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC)
|
||||
case CharHistory:
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
|
||||
"<x xmlns='%s'>\n" +
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n"+
|
||||
"<x xmlns='%s'>\n"+
|
||||
"<history maxchars='%d'/></x>\n"+
|
||||
"</presence>",
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, history)
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, history)
|
||||
case StanzaHistory:
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
|
||||
"<x xmlns='%s'>\n" +
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n"+
|
||||
"<x xmlns='%s'>\n"+
|
||||
"<history maxstanzas='%d'/></x>\n"+
|
||||
"</presence>",
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, history)
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, history)
|
||||
case SecondsHistory:
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
|
||||
"<x xmlns='%s'>\n" +
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n"+
|
||||
"<x xmlns='%s'>\n"+
|
||||
"<history seconds='%d'/></x>\n"+
|
||||
"</presence>",
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, history)
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, history)
|
||||
case SinceHistory:
|
||||
if history_date != nil {
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
|
||||
"<x xmlns='%s'>\n" +
|
||||
"<history since='%s'/></x>\n" +
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n"+
|
||||
"<x xmlns='%s'>\n"+
|
||||
"<history since='%s'/></x>\n"+
|
||||
"</presence>",
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, history_date.Format(time.RFC3339))
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, history_date.Format(time.RFC3339))
|
||||
}
|
||||
}
|
||||
return 0, errors.New("Unknown history option")
|
||||
@@ -88,41 +88,41 @@ func (c *Client) JoinProtectedMUC(jid, nick string, password string, history_typ
|
||||
}
|
||||
switch history_type {
|
||||
case NoHistory:
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
|
||||
"<x xmlns='%s'>\n" +
|
||||
"<password>%s</password>" +
|
||||
"</x>\n" +
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n"+
|
||||
"<x xmlns='%s'>\n"+
|
||||
"<password>%s</password>"+
|
||||
"</x>\n"+
|
||||
"</presence>",
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password))
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password))
|
||||
case CharHistory:
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
|
||||
"<x xmlns='%s'>\n" +
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n"+
|
||||
"<x xmlns='%s'>\n"+
|
||||
"<password>%s</password>\n"+
|
||||
"<history maxchars='%d'/></x>\n"+
|
||||
"</presence>",
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history)
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history)
|
||||
case StanzaHistory:
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
|
||||
"<x xmlns='%s'>\n" +
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n"+
|
||||
"<x xmlns='%s'>\n"+
|
||||
"<password>%s</password>\n"+
|
||||
"<history maxstanzas='%d'/></x>\n"+
|
||||
"</presence>",
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history)
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history)
|
||||
case SecondsHistory:
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
|
||||
"<x xmlns='%s'>\n" +
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n"+
|
||||
"<x xmlns='%s'>\n"+
|
||||
"<password>%s</password>\n"+
|
||||
"<history seconds='%d'/></x>\n"+
|
||||
"</presence>",
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history)
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history)
|
||||
case SinceHistory:
|
||||
if history_date != nil {
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
|
||||
"<x xmlns='%s'>\n" +
|
||||
return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n"+
|
||||
"<x xmlns='%s'>\n"+
|
||||
"<password>%s</password>\n"+
|
||||
"<history since='%s'/></x>\n" +
|
||||
"<history since='%s'/></x>\n"+
|
||||
"</presence>",
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history_date.Format(time.RFC3339))
|
||||
xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history_date.Format(time.RFC3339))
|
||||
}
|
||||
}
|
||||
return 0, errors.New("Unknown history option")
|
||||
|
||||
133
vendor/github.com/matterbridge/go-xmpp/xmpp_pubsub.go
generated
vendored
Normal file
133
vendor/github.com/matterbridge/go-xmpp/xmpp_pubsub.go
generated
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
package xmpp
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
XMPPNS_PUBSUB = "http://jabber.org/protocol/pubsub"
|
||||
XMPPNS_PUBSUB_EVENT = "http://jabber.org/protocol/pubsub#event"
|
||||
)
|
||||
|
||||
type clientPubsubItem struct {
|
||||
XMLName xml.Name `xml:"item"`
|
||||
ID string `xml:"id,attr"`
|
||||
Body []byte `xml:",innerxml"`
|
||||
}
|
||||
|
||||
type clientPubsubItems struct {
|
||||
XMLName xml.Name `xml:"items"`
|
||||
Node string `xml:"node,attr"`
|
||||
Items []clientPubsubItem `xml:"item"`
|
||||
}
|
||||
|
||||
type clientPubsub struct {
|
||||
XMLName xml.Name `xml:"pubsub"`
|
||||
Items clientPubsubItems `xml:"items"`
|
||||
}
|
||||
|
||||
type clientPubsubEvent struct {
|
||||
XMLName xml.Name `xml:"event"`
|
||||
XMLNS string `xml:"xmlns,attr"`
|
||||
Items clientPubsubItems `xml:"items"`
|
||||
}
|
||||
|
||||
type clientPubsubError struct {
|
||||
XMLName xml.Name
|
||||
}
|
||||
|
||||
type clientPubsubSubscription struct {
|
||||
XMLName xml.Name `xml:"subscription"`
|
||||
Node string `xml:"node,attr"`
|
||||
JID string `xml:"jid,attr"`
|
||||
SubID string `xml:"subid,attr"`
|
||||
}
|
||||
|
||||
type PubsubEvent struct {
|
||||
Node string
|
||||
Items []PubsubItem
|
||||
}
|
||||
|
||||
type PubsubSubscription struct {
|
||||
SubID string
|
||||
JID string
|
||||
Node string
|
||||
Errors []string
|
||||
}
|
||||
type PubsubUnsubscription PubsubSubscription
|
||||
|
||||
type PubsubItem struct {
|
||||
ID string
|
||||
InnerXML []byte
|
||||
}
|
||||
|
||||
type PubsubItems struct {
|
||||
Node string
|
||||
Items []PubsubItem
|
||||
}
|
||||
|
||||
// Converts []clientPubsubItem to []PubsubItem
|
||||
func pubsubItemsToReturn(items []clientPubsubItem) []PubsubItem {
|
||||
var tmp []PubsubItem
|
||||
for _, i := range items {
|
||||
tmp = append(tmp, PubsubItem{
|
||||
ID: i.ID,
|
||||
InnerXML: i.Body,
|
||||
})
|
||||
}
|
||||
|
||||
return tmp
|
||||
}
|
||||
|
||||
func pubsubClientToReturn(event clientPubsubEvent) PubsubEvent {
|
||||
return PubsubEvent{
|
||||
Node: event.Items.Node,
|
||||
Items: pubsubItemsToReturn(event.Items.Items),
|
||||
}
|
||||
}
|
||||
|
||||
func pubsubStanza(body string) string {
|
||||
return fmt.Sprintf("<pubsub xmlns='%s'>%s</pubsub>",
|
||||
XMPPNS_PUBSUB, body)
|
||||
}
|
||||
|
||||
func pubsubSubscriptionStanza(node, jid string) string {
|
||||
body := fmt.Sprintf("<subscribe node='%s' jid='%s'/>",
|
||||
xmlEscape(node),
|
||||
xmlEscape(jid))
|
||||
return pubsubStanza(body)
|
||||
}
|
||||
|
||||
func pubsubUnsubscriptionStanza(node, jid string) string {
|
||||
body := fmt.Sprintf("<unsubscribe node='%s' jid='%s'/>",
|
||||
xmlEscape(node),
|
||||
xmlEscape(jid))
|
||||
return pubsubStanza(body)
|
||||
}
|
||||
|
||||
func (c *Client) PubsubSubscribeNode(node, jid string) {
|
||||
c.RawInformation(c.jid,
|
||||
jid,
|
||||
"sub1",
|
||||
"set",
|
||||
pubsubSubscriptionStanza(node, c.jid))
|
||||
}
|
||||
|
||||
func (c *Client) PubsubUnsubscribeNode(node, jid string) {
|
||||
c.RawInformation(c.jid,
|
||||
jid,
|
||||
"unsub1",
|
||||
"set",
|
||||
pubsubUnsubscriptionStanza(node, c.jid))
|
||||
}
|
||||
|
||||
func (c *Client) PubsubRequestLastItems(node, jid string) {
|
||||
body := fmt.Sprintf("<items node='%s'/>", node)
|
||||
c.RawInformation(c.jid, jid, "items1", "get", pubsubStanza(body))
|
||||
}
|
||||
|
||||
func (c *Client) PubsubRequestItem(node, jid, id string) {
|
||||
body := fmt.Sprintf("<items node='%s'><item id='%s'/></items>", node, id)
|
||||
c.RawInformation(c.jid, jid, "items3", "get", pubsubStanza(body))
|
||||
}
|
||||
201
vendor/github.com/matterbridge/msgraph.go/LICENSE
generated
vendored
201
vendor/github.com/matterbridge/msgraph.go/LICENSE
generated
vendored
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
6
vendor/github.com/slack-go/slack/Makefile
generated
vendored
6
vendor/github.com/slack-go/slack/Makefile
generated
vendored
@@ -25,12 +25,12 @@ lint:
|
||||
@go vet .
|
||||
|
||||
test:
|
||||
@go test -count=1 -timeout 300s -short .
|
||||
@go test -v -count=1 -timeout 300s -short ./...
|
||||
|
||||
test-race:
|
||||
@go test -count=1 -timeout 300s -short -race .
|
||||
@go test -v -count=1 -timeout 300s -short -race ./...
|
||||
|
||||
test-integration:
|
||||
@go test -count=1 -timeout 600s .
|
||||
@go test -v -count=1 -timeout 600s ./...
|
||||
|
||||
pr-prep: fmt lint test-race test-integration
|
||||
|
||||
2
vendor/github.com/slack-go/slack/auth.go
generated
vendored
2
vendor/github.com/slack-go/slack/auth.go
generated
vendored
@@ -27,7 +27,7 @@ func (api *Client) SendAuthRevoke(token string) (*AuthRevokeResponse, error) {
|
||||
return api.SendAuthRevokeContext(context.Background(), token)
|
||||
}
|
||||
|
||||
// SendAuthRevokeContext will retrieve the satus from api.test
|
||||
// SendAuthRevokeContext will send a revocation request for our token to api.revoke with context
|
||||
func (api *Client) SendAuthRevokeContext(ctx context.Context, token string) (*AuthRevokeResponse, error) {
|
||||
if token == "" {
|
||||
token = api.token
|
||||
|
||||
1
vendor/github.com/slack-go/slack/block.go
generated
vendored
1
vendor/github.com/slack-go/slack/block.go
generated
vendored
@@ -14,6 +14,7 @@ const (
|
||||
MBTImage MessageBlockType = "image"
|
||||
MBTAction MessageBlockType = "actions"
|
||||
MBTContext MessageBlockType = "context"
|
||||
MBTFile MessageBlockType = "file"
|
||||
MBTInput MessageBlockType = "input"
|
||||
)
|
||||
|
||||
|
||||
45
vendor/github.com/slack-go/slack/block_conv.go
generated
vendored
45
vendor/github.com/slack-go/slack/block_conv.go
generated
vendored
@@ -56,20 +56,16 @@ func (b *Blocks) UnmarshalJSON(data []byte) error {
|
||||
block = &ContextBlock{}
|
||||
case "divider":
|
||||
block = &DividerBlock{}
|
||||
case "file":
|
||||
block = &FileBlock{}
|
||||
case "image":
|
||||
block = &ImageBlock{}
|
||||
case "input":
|
||||
block = &InputBlock{}
|
||||
case "section":
|
||||
block = &SectionBlock{}
|
||||
case "rich_text":
|
||||
// for now ignore the (complex) content of rich_text blocks until we can fully support it
|
||||
continue
|
||||
case "file":
|
||||
// for now ignore the file blocks until we can fully support it
|
||||
continue
|
||||
default:
|
||||
return errors.New("unsupported block type")
|
||||
block = &UnknownBlock{}
|
||||
}
|
||||
|
||||
err = json.Unmarshal(r, block)
|
||||
@@ -253,12 +249,36 @@ func (a *Accessory) UnmarshalJSON(data []byte) error {
|
||||
return err
|
||||
}
|
||||
a.DatePickerElement = element.(*DatePickerBlockElement)
|
||||
case "static_select":
|
||||
case "plain_text_input":
|
||||
element, err := unmarshalBlockElement(r, &PlainTextInputBlockElement{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.PlainTextInputElement = element.(*PlainTextInputBlockElement)
|
||||
case "radio_buttons":
|
||||
element, err := unmarshalBlockElement(r, &RadioButtonsBlockElement{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.RadioButtonsElement = element.(*RadioButtonsBlockElement)
|
||||
case "static_select", "external_select", "users_select", "conversations_select", "channels_select":
|
||||
element, err := unmarshalBlockElement(r, &SelectBlockElement{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.SelectElement = element.(*SelectBlockElement)
|
||||
case "multi_static_select", "multi_external_select", "multi_users_select", "multi_conversations_select", "multi_channels_select":
|
||||
element, err := unmarshalBlockElement(r, &MultiSelectBlockElement{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.MultiSelectElement = element.(*MultiSelectBlockElement)
|
||||
default:
|
||||
element, err := unmarshalBlockElement(r, &UnknownBlockElement{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.UnknownElement = element.(*UnknownBlockElement)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -285,9 +305,18 @@ func toBlockElement(element *Accessory) BlockElement {
|
||||
if element.DatePickerElement != nil {
|
||||
return element.DatePickerElement
|
||||
}
|
||||
if element.PlainTextInputElement != nil {
|
||||
return element.PlainTextInputElement
|
||||
}
|
||||
if element.RadioButtonsElement != nil {
|
||||
return element.RadioButtonsElement
|
||||
}
|
||||
if element.SelectElement != nil {
|
||||
return element.SelectElement
|
||||
}
|
||||
if element.MultiSelectElement != nil {
|
||||
return element.MultiSelectElement
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
145
vendor/github.com/slack-go/slack/block_element.go
generated
vendored
145
vendor/github.com/slack-go/slack/block_element.go
generated
vendored
@@ -8,6 +8,7 @@ const (
|
||||
METOverflow MessageElementType = "overflow"
|
||||
METDatepicker MessageElementType = "datepicker"
|
||||
METPlainTextInput MessageElementType = "plain_text_input"
|
||||
METRadioButtons MessageElementType = "radio_buttons"
|
||||
|
||||
MixedElementImage MixedElementType = "mixed_image"
|
||||
MixedElementText MixedElementType = "mixed_text"
|
||||
@@ -17,6 +18,12 @@ const (
|
||||
OptTypeUser string = "users_select"
|
||||
OptTypeConversations string = "conversations_select"
|
||||
OptTypeChannels string = "channels_select"
|
||||
|
||||
MultiOptTypeStatic string = "multi_static_select"
|
||||
MultiOptTypeExternal string = "multi_external_select"
|
||||
MultiOptTypeUser string = "multi_users_select"
|
||||
MultiOptTypeConversations string = "multi_conversations_select"
|
||||
MultiOptTypeChannels string = "multi_channels_select"
|
||||
)
|
||||
|
||||
type MessageElementType string
|
||||
@@ -32,11 +39,15 @@ type MixedElement interface {
|
||||
}
|
||||
|
||||
type Accessory struct {
|
||||
ImageElement *ImageBlockElement
|
||||
ButtonElement *ButtonBlockElement
|
||||
OverflowElement *OverflowBlockElement
|
||||
DatePickerElement *DatePickerBlockElement
|
||||
SelectElement *SelectBlockElement
|
||||
ImageElement *ImageBlockElement
|
||||
ButtonElement *ButtonBlockElement
|
||||
OverflowElement *OverflowBlockElement
|
||||
DatePickerElement *DatePickerBlockElement
|
||||
PlainTextInputElement *PlainTextInputBlockElement
|
||||
RadioButtonsElement *RadioButtonsBlockElement
|
||||
SelectElement *SelectBlockElement
|
||||
MultiSelectElement *MultiSelectBlockElement
|
||||
UnknownElement *UnknownBlockElement
|
||||
}
|
||||
|
||||
// NewAccessory returns a new Accessory for a given block element
|
||||
@@ -50,11 +61,17 @@ func NewAccessory(element BlockElement) *Accessory {
|
||||
return &Accessory{OverflowElement: element.(*OverflowBlockElement)}
|
||||
case *DatePickerBlockElement:
|
||||
return &Accessory{DatePickerElement: element.(*DatePickerBlockElement)}
|
||||
case *PlainTextInputBlockElement:
|
||||
return &Accessory{PlainTextInputElement: element.(*PlainTextInputBlockElement)}
|
||||
case *RadioButtonsBlockElement:
|
||||
return &Accessory{RadioButtonsElement: element.(*RadioButtonsBlockElement)}
|
||||
case *SelectBlockElement:
|
||||
return &Accessory{SelectElement: element.(*SelectBlockElement)}
|
||||
case *MultiSelectBlockElement:
|
||||
return &Accessory{MultiSelectElement: element.(*MultiSelectBlockElement)}
|
||||
default:
|
||||
return &Accessory{UnknownElement: element.(*UnknownBlockElement)}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BlockElements is a convenience struct defined to allow dynamic unmarshalling of
|
||||
@@ -63,6 +80,20 @@ type BlockElements struct {
|
||||
ElementSet []BlockElement `json:"elements,omitempty"`
|
||||
}
|
||||
|
||||
// UnknownBlockElement any block element that this library does not directly support.
|
||||
// See the "Rich Elements" section at the following URL:
|
||||
// https://api.slack.com/changelog/2019-09-what-they-see-is-what-you-get-and-more-and-less
|
||||
// New block element types may be introduced by Slack at any time; this is a catch-all for any such block elements.
|
||||
type UnknownBlockElement struct {
|
||||
Type MessageElementType `json:"type"`
|
||||
Elements BlockElements
|
||||
}
|
||||
|
||||
// ElementType returns the type of the Element
|
||||
func (s UnknownBlockElement) ElementType() MessageElementType {
|
||||
return s.Type
|
||||
}
|
||||
|
||||
// ImageBlockElement An element to insert an image - this element can be used
|
||||
// in section and context blocks only. If you want a block with only an image
|
||||
// in it, you're looking for the image block.
|
||||
@@ -135,6 +166,20 @@ func NewButtonBlockElement(actionID, value string, text *TextBlockObject) *Butto
|
||||
}
|
||||
}
|
||||
|
||||
// OptionsResponse defines the response used for select block typahead.
|
||||
//
|
||||
// More Information: https://api.slack.com/reference/block-kit/block-elements#external_multi_select
|
||||
type OptionsResponse struct {
|
||||
Options []*OptionBlockObject `json:"options,omitempty"`
|
||||
}
|
||||
|
||||
// OptionGroupsResponse defines the response used for select block typahead.
|
||||
//
|
||||
// More Information: https://api.slack.com/reference/block-kit/block-elements#external_multi_select
|
||||
type OptionGroupsResponse struct {
|
||||
OptionGroups []*OptionGroupBlockObject `json:"option_groups,omitempty"`
|
||||
}
|
||||
|
||||
// SelectBlockElement defines the simplest form of select menu, with a static list
|
||||
// of options passed in when defining the element.
|
||||
//
|
||||
@@ -149,7 +194,7 @@ type SelectBlockElement struct {
|
||||
InitialUser string `json:"initial_user,omitempty"`
|
||||
InitialConversation string `json:"initial_conversation,omitempty"`
|
||||
InitialChannel string `json:"initial_channel,omitempty"`
|
||||
MinQueryLength int `json:"min_query_length,omitempty"`
|
||||
MinQueryLength *int `json:"min_query_length,omitempty"`
|
||||
Confirm *ConfirmationBlockObject `json:"confirm,omitempty"`
|
||||
}
|
||||
|
||||
@@ -185,6 +230,56 @@ func NewOptionsGroupSelectBlockElement(
|
||||
}
|
||||
}
|
||||
|
||||
// MultiSelectBlockElement defines a multiselect menu, with a static list
|
||||
// of options passed in when defining the element.
|
||||
//
|
||||
// More Information: https://api.slack.com/reference/messaging/block-elements#multi_select
|
||||
type MultiSelectBlockElement struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Placeholder *TextBlockObject `json:"placeholder,omitempty"`
|
||||
ActionID string `json:"action_id,omitempty"`
|
||||
Options []*OptionBlockObject `json:"options,omitempty"`
|
||||
OptionGroups []*OptionGroupBlockObject `json:"option_groups,omitempty"`
|
||||
InitialOptions []*OptionBlockObject `json:"initial_options,omitempty"`
|
||||
InitialUsers []string `json:"initial_users,omitempty"`
|
||||
InitialConversations []string `json:"initial_conversations,omitempty"`
|
||||
InitialChannels []string `json:"initial_channels,omitempty"`
|
||||
MinQueryLength *int `json:"min_query_length,omitempty"`
|
||||
Confirm *ConfirmationBlockObject `json:"confirm,omitempty"`
|
||||
}
|
||||
|
||||
// ElementType returns the type of the Element
|
||||
func (s MultiSelectBlockElement) ElementType() MessageElementType {
|
||||
return MessageElementType(s.Type)
|
||||
}
|
||||
|
||||
// NewOptionsMultiSelectBlockElement returns a new instance of SelectBlockElement for use with
|
||||
// the Options object only.
|
||||
func NewOptionsMultiSelectBlockElement(optType string, placeholder *TextBlockObject, actionID string, options ...*OptionBlockObject) *MultiSelectBlockElement {
|
||||
return &MultiSelectBlockElement{
|
||||
Type: optType,
|
||||
Placeholder: placeholder,
|
||||
ActionID: actionID,
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
||||
// NewOptionsGroupMultiSelectBlockElement returns a new instance of MultiSelectBlockElement for use with
|
||||
// the Options object only.
|
||||
func NewOptionsGroupMultiSelectBlockElement(
|
||||
optType string,
|
||||
placeholder *TextBlockObject,
|
||||
actionID string,
|
||||
optGroups ...*OptionGroupBlockObject,
|
||||
) *MultiSelectBlockElement {
|
||||
return &MultiSelectBlockElement{
|
||||
Type: optType,
|
||||
Placeholder: placeholder,
|
||||
ActionID: actionID,
|
||||
OptionGroups: optGroups,
|
||||
}
|
||||
}
|
||||
|
||||
// OverflowBlockElement defines the fields needed to use an overflow element.
|
||||
// And Overflow Element is like a cross between a button and a select menu -
|
||||
// when a user clicks on this overflow button, they will be presented with a
|
||||
@@ -238,10 +333,11 @@ func NewDatePickerBlockElement(actionID string) *DatePickerBlockElement {
|
||||
}
|
||||
}
|
||||
|
||||
// PlainTextInputBlockElement creates a field where a user can enter freeform data.
|
||||
// PlainTextInputBlockElement creates a field where a user can enter freeform
|
||||
// data.
|
||||
// Plain-text input elements are currently only available in modals.
|
||||
//
|
||||
// More Information: https://api.slack.com/reference/messaging/block-elements#input
|
||||
// More Information: https://api.slack.com/reference/block-kit/block-elements#input
|
||||
type PlainTextInputBlockElement struct {
|
||||
Type MessageElementType `json:"type"`
|
||||
ActionID string `json:"action_id"`
|
||||
@@ -257,7 +353,8 @@ func (s PlainTextInputBlockElement) ElementType() MessageElementType {
|
||||
return s.Type
|
||||
}
|
||||
|
||||
// NewPlainTextInputBlockElement returns an instance of a plain-text input element
|
||||
// NewPlainTextInputBlockElement returns an instance of a plain-text input
|
||||
// element
|
||||
func NewPlainTextInputBlockElement(placeholder *TextBlockObject, actionID string) *PlainTextInputBlockElement {
|
||||
return &PlainTextInputBlockElement{
|
||||
Type: METPlainTextInput,
|
||||
@@ -265,3 +362,29 @@ func NewPlainTextInputBlockElement(placeholder *TextBlockObject, actionID string
|
||||
Placeholder: placeholder,
|
||||
}
|
||||
}
|
||||
|
||||
// RadioButtonsBlockElement defines an element which lets users choose one item
|
||||
// from a list of possible options.
|
||||
//
|
||||
// More Information: https://api.slack.com/reference/block-kit/block-elements#radio
|
||||
type RadioButtonsBlockElement struct {
|
||||
Type MessageElementType `json:"type"`
|
||||
ActionID string `json:"action_id"`
|
||||
Options []*OptionBlockObject `json:"options"`
|
||||
InitialOption *OptionBlockObject `json:"initial_option,omitempty"`
|
||||
Confirm *ConfirmationBlockObject `json:"confirm,omitempty"`
|
||||
}
|
||||
|
||||
// ElementType returns the type of the Element
|
||||
func (s RadioButtonsBlockElement) ElementType() MessageElementType {
|
||||
return s.Type
|
||||
}
|
||||
|
||||
// NewRadioButtonsBlockElement returns an instance of a radio buttons element.
|
||||
func NewRadioButtonsBlockElement(actionID string, options ...*OptionBlockObject) *RadioButtonsBlockElement {
|
||||
return &RadioButtonsBlockElement{
|
||||
Type: METRadioButtons,
|
||||
ActionID: actionID,
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
||||
26
vendor/github.com/slack-go/slack/block_file.go
generated
vendored
Normal file
26
vendor/github.com/slack-go/slack/block_file.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package slack
|
||||
|
||||
// FileBlock defines data that is used to display a remote file.
|
||||
//
|
||||
// More Information: https://api.slack.com/reference/block-kit/blocks#file
|
||||
type FileBlock struct {
|
||||
Type MessageBlockType `json:"type"`
|
||||
BlockID string `json:"block_id,omitempty"`
|
||||
ExternalID string `json:"external_id"`
|
||||
Source string `json:"source"`
|
||||
}
|
||||
|
||||
// BlockType returns the type of the block
|
||||
func (s FileBlock) BlockType() MessageBlockType {
|
||||
return s.Type
|
||||
}
|
||||
|
||||
// NewFileBlock returns a new instance of a file block
|
||||
func NewFileBlock(blockID string, externalID string, source string) *FileBlock {
|
||||
return &FileBlock{
|
||||
Type: MBTFile,
|
||||
BlockID: blockID,
|
||||
ExternalID: externalID,
|
||||
Source: source,
|
||||
}
|
||||
}
|
||||
8
vendor/github.com/slack-go/slack/block_input.go
generated
vendored
8
vendor/github.com/slack-go/slack/block_input.go
generated
vendored
@@ -1,10 +1,8 @@
|
||||
package slack
|
||||
|
||||
// InputBlock defines data that is used to collect information from users -
|
||||
// it can hold a plain-text input element, a select menu element,
|
||||
// a multi-select menu element, or a datepicker.
|
||||
// InputBlock defines data that is used to display user input fields.
|
||||
//
|
||||
// More Information: https://api.slack.com/reference/messaging/blocks#input
|
||||
// More Information: https://api.slack.com/reference/block-kit/blocks#input
|
||||
type InputBlock struct {
|
||||
Type MessageBlockType `json:"type"`
|
||||
BlockID string `json:"block_id,omitempty"`
|
||||
@@ -19,7 +17,7 @@ func (s InputBlock) BlockType() MessageBlockType {
|
||||
return s.Type
|
||||
}
|
||||
|
||||
// NewInputBlock returns a new instance of an Input Block
|
||||
// NewInputBlock returns a new instance of an input block
|
||||
func NewInputBlock(blockID string, label *TextBlockObject, element BlockElement) *InputBlock {
|
||||
return &InputBlock{
|
||||
Type: MBTInput,
|
||||
|
||||
8
vendor/github.com/slack-go/slack/block_object.go
generated
vendored
8
vendor/github.com/slack-go/slack/block_object.go
generated
vendored
@@ -145,6 +145,14 @@ func NewTextBlockObject(elementType, text string, emoji, verbatim bool) *TextBlo
|
||||
}
|
||||
}
|
||||
|
||||
// BlockType returns the type of the block
|
||||
func (t TextBlockObject) BlockType() MessageBlockType {
|
||||
if t.Type == "mrkdown" {
|
||||
return MarkdownType
|
||||
}
|
||||
return PlainTextType
|
||||
}
|
||||
|
||||
// ConfirmationBlockObject defines a dialog that provides a confirmation step to
|
||||
// any interactive element. This dialog will ask the user to confirm their action by
|
||||
// offering a confirm and deny buttons.
|
||||
|
||||
13
vendor/github.com/slack-go/slack/block_unknown.go
generated
vendored
Normal file
13
vendor/github.com/slack-go/slack/block_unknown.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package slack
|
||||
|
||||
// UnknownBlock represents a block type that is not yet known. This block type exists to prevent Slack from introducing
|
||||
// new and unknown block types that break this library.
|
||||
type UnknownBlock struct {
|
||||
Type MessageBlockType `json:"type"`
|
||||
BlockID string `json:"block_id,omitempty"`
|
||||
}
|
||||
|
||||
// BlockType returns the type of the block
|
||||
func (b UnknownBlock) BlockType() MessageBlockType {
|
||||
return b.Type
|
||||
}
|
||||
117
vendor/github.com/slack-go/slack/channels.go
generated
vendored
117
vendor/github.com/slack-go/slack/channels.go
generated
vendored
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type channelResponseFull struct {
|
||||
@@ -14,6 +15,7 @@ type channelResponseFull struct {
|
||||
NotInChannel bool `json:"not_in_channel"`
|
||||
History
|
||||
SlackResponse
|
||||
Metadata ResponseMetadata `json:"response_metadata"`
|
||||
}
|
||||
|
||||
// Channel contains information about the channel
|
||||
@@ -35,25 +37,21 @@ func (api *Client) channelRequest(ctx context.Context, path string, values url.V
|
||||
return response, response.Err()
|
||||
}
|
||||
|
||||
type channelsConfig struct {
|
||||
values url.Values
|
||||
}
|
||||
|
||||
// GetChannelsOption option provided when getting channels.
|
||||
type GetChannelsOption func(*channelsConfig) error
|
||||
type GetChannelsOption func(*ChannelPagination) error
|
||||
|
||||
// GetChannelsOptionExcludeMembers excludes the members collection from each channel.
|
||||
func GetChannelsOptionExcludeMembers() GetChannelsOption {
|
||||
return func(config *channelsConfig) error {
|
||||
config.values.Add("exclude_members", "true")
|
||||
return func(p *ChannelPagination) error {
|
||||
p.excludeMembers = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetChannelsOptionExcludeArchived excludes archived channels from results.
|
||||
func GetChannelsOptionExcludeArchived() GetChannelsOption {
|
||||
return func(config *channelsConfig) error {
|
||||
config.values.Add("exclude_archived", "true")
|
||||
return func(p *ChannelPagination) error {
|
||||
p.excludeArchived = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -266,6 +264,78 @@ func (api *Client) KickUserFromChannelContext(ctx context.Context, channelID, us
|
||||
return err
|
||||
}
|
||||
|
||||
func newChannelPagination(c *Client, options ...GetChannelsOption) (cp ChannelPagination) {
|
||||
cp = ChannelPagination{
|
||||
c: c,
|
||||
limit: 200, // per slack api documentation.
|
||||
}
|
||||
|
||||
for _, opt := range options {
|
||||
opt(&cp)
|
||||
}
|
||||
|
||||
return cp
|
||||
}
|
||||
|
||||
// ChannelPagination allows for paginating over the channels
|
||||
type ChannelPagination struct {
|
||||
Channels []Channel
|
||||
limit int
|
||||
excludeArchived bool
|
||||
excludeMembers bool
|
||||
previousResp *ResponseMetadata
|
||||
c *Client
|
||||
}
|
||||
|
||||
// Done checks if the pagination has completed
|
||||
func (ChannelPagination) Done(err error) bool {
|
||||
return err == errPaginationComplete
|
||||
}
|
||||
|
||||
// Failure checks if pagination failed.
|
||||
func (t ChannelPagination) Failure(err error) error {
|
||||
if t.Done(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (t ChannelPagination) Next(ctx context.Context) (_ ChannelPagination, err error) {
|
||||
var (
|
||||
resp *channelResponseFull
|
||||
)
|
||||
|
||||
if t.c == nil || (t.previousResp != nil && t.previousResp.Cursor == "") {
|
||||
return t, errPaginationComplete
|
||||
}
|
||||
|
||||
t.previousResp = t.previousResp.initialize()
|
||||
|
||||
values := url.Values{
|
||||
"limit": {strconv.Itoa(t.limit)},
|
||||
"exclude_archived": {strconv.FormatBool(t.excludeArchived)},
|
||||
"exclude_members": {strconv.FormatBool(t.excludeMembers)},
|
||||
"token": {t.c.token},
|
||||
"cursor": {t.previousResp.Cursor},
|
||||
}
|
||||
|
||||
if resp, err = t.c.channelRequest(ctx, "channels.list", values); err != nil {
|
||||
return t, err
|
||||
}
|
||||
|
||||
t.c.Debugf("GetChannelsContext: got %d channels; metadata %v", len(resp.Channels), resp.Metadata)
|
||||
t.Channels = resp.Channels
|
||||
t.previousResp = &resp.Metadata
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// GetChannelsPaginated fetches channels in a paginated fashion, see GetChannelsContext for usage.
|
||||
func (api *Client) GetChannelsPaginated(options ...GetChannelsOption) ChannelPagination {
|
||||
return newChannelPagination(api, options...)
|
||||
}
|
||||
|
||||
// GetChannels retrieves all the channels
|
||||
// see https://api.slack.com/methods/channels.list
|
||||
func (api *Client) GetChannels(excludeArchived bool, options ...GetChannelsOption) ([]Channel, error) {
|
||||
@@ -274,28 +344,27 @@ func (api *Client) GetChannels(excludeArchived bool, options ...GetChannelsOptio
|
||||
|
||||
// GetChannelsContext retrieves all the channels with a custom context
|
||||
// see https://api.slack.com/methods/channels.list
|
||||
func (api *Client) GetChannelsContext(ctx context.Context, excludeArchived bool, options ...GetChannelsOption) ([]Channel, error) {
|
||||
config := channelsConfig{
|
||||
values: url.Values{
|
||||
"token": {api.token},
|
||||
},
|
||||
}
|
||||
|
||||
func (api *Client) GetChannelsContext(ctx context.Context, excludeArchived bool, options ...GetChannelsOption) (results []Channel, err error) {
|
||||
if excludeArchived {
|
||||
options = append(options, GetChannelsOptionExcludeArchived())
|
||||
}
|
||||
|
||||
for _, opt := range options {
|
||||
if err := opt(&config); err != nil {
|
||||
return nil, err
|
||||
p := api.GetChannelsPaginated(options...)
|
||||
for err == nil {
|
||||
p, err = p.Next(ctx)
|
||||
if err == nil {
|
||||
results = append(results, p.Channels...)
|
||||
} else if rateLimitedError, ok := err.(*RateLimitedError); ok {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
err = ctx.Err()
|
||||
case <-time.After(rateLimitedError.RetryAfter):
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response, err := api.channelRequest(ctx, "channels.list", config.values)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response.Channels, nil
|
||||
return results, p.Failure(err)
|
||||
}
|
||||
|
||||
// SetChannelReadMark sets the read mark of a given channel to a specific point
|
||||
|
||||
158
vendor/github.com/slack-go/slack/chat.go
generated
vendored
158
vendor/github.com/slack-go/slack/chat.go
generated
vendored
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/slack-go/slack/slackutilsx"
|
||||
)
|
||||
@@ -25,10 +26,11 @@ const (
|
||||
)
|
||||
|
||||
type chatResponseFull struct {
|
||||
Channel string `json:"channel"`
|
||||
Timestamp string `json:"ts"` //Regular message timestamp
|
||||
MessageTimeStamp string `json:"message_ts"` //Ephemeral message timestamp
|
||||
Text string `json:"text"`
|
||||
Channel string `json:"channel"`
|
||||
Timestamp string `json:"ts"` //Regular message timestamp
|
||||
MessageTimeStamp string `json:"message_ts"` //Ephemeral message timestamp
|
||||
ScheduledMessageID string `json:"scheduled_message_id,omitempty"` //Scheduled message id
|
||||
Text string `json:"text"`
|
||||
SlackResponse
|
||||
}
|
||||
|
||||
@@ -82,13 +84,34 @@ func NewPostMessageParameters() PostMessageParameters {
|
||||
|
||||
// DeleteMessage deletes a message in a channel
|
||||
func (api *Client) DeleteMessage(channel, messageTimestamp string) (string, string, error) {
|
||||
respChannel, respTimestamp, _, err := api.SendMessageContext(context.Background(), channel, MsgOptionDelete(messageTimestamp))
|
||||
respChannel, respTimestamp, _, err := api.SendMessageContext(
|
||||
context.Background(),
|
||||
channel,
|
||||
MsgOptionDelete(messageTimestamp),
|
||||
)
|
||||
return respChannel, respTimestamp, err
|
||||
}
|
||||
|
||||
// DeleteMessageContext deletes a message in a channel with a custom context
|
||||
func (api *Client) DeleteMessageContext(ctx context.Context, channel, messageTimestamp string) (string, string, error) {
|
||||
respChannel, respTimestamp, _, err := api.SendMessageContext(ctx, channel, MsgOptionDelete(messageTimestamp))
|
||||
respChannel, respTimestamp, _, err := api.SendMessageContext(
|
||||
ctx,
|
||||
channel,
|
||||
MsgOptionDelete(messageTimestamp),
|
||||
)
|
||||
return respChannel, respTimestamp, err
|
||||
}
|
||||
|
||||
// ScheduleMessage sends a message to a channel.
|
||||
// Message is escaped by default according to https://api.slack.com/docs/formatting
|
||||
// Use http://davestevens.github.io/slack-message-builder/ to help crafting your message.
|
||||
func (api *Client) ScheduleMessage(channelID, postAt string, options ...MsgOption) (string, string, error) {
|
||||
respChannel, respTimestamp, _, err := api.SendMessageContext(
|
||||
context.Background(),
|
||||
channelID,
|
||||
MsgOptionSchedule(postAt),
|
||||
MsgOptionCompose(options...),
|
||||
)
|
||||
return respChannel, respTimestamp, err
|
||||
}
|
||||
|
||||
@@ -132,18 +155,33 @@ func (api *Client) PostEphemeral(channelID, userID string, options ...MsgOption)
|
||||
// PostEphemeralContext sends an ephemeal message to a user in a channel with a custom context
|
||||
// For more details, see PostEphemeral documentation
|
||||
func (api *Client) PostEphemeralContext(ctx context.Context, channelID, userID string, options ...MsgOption) (timestamp string, err error) {
|
||||
_, timestamp, _, err = api.SendMessageContext(ctx, channelID, MsgOptionPostEphemeral(userID), MsgOptionCompose(options...))
|
||||
_, timestamp, _, err = api.SendMessageContext(
|
||||
ctx,
|
||||
channelID,
|
||||
MsgOptionPostEphemeral(userID),
|
||||
MsgOptionCompose(options...),
|
||||
)
|
||||
return timestamp, err
|
||||
}
|
||||
|
||||
// UpdateMessage updates a message in a channel
|
||||
func (api *Client) UpdateMessage(channelID, timestamp string, options ...MsgOption) (string, string, string, error) {
|
||||
return api.SendMessageContext(context.Background(), channelID, MsgOptionUpdate(timestamp), MsgOptionCompose(options...))
|
||||
return api.SendMessageContext(
|
||||
context.Background(),
|
||||
channelID,
|
||||
MsgOptionUpdate(timestamp),
|
||||
MsgOptionCompose(options...),
|
||||
)
|
||||
}
|
||||
|
||||
// UpdateMessageContext updates a message in a channel
|
||||
func (api *Client) UpdateMessageContext(ctx context.Context, channelID, timestamp string, options ...MsgOption) (string, string, string, error) {
|
||||
return api.SendMessageContext(ctx, channelID, MsgOptionUpdate(timestamp), MsgOptionCompose(options...))
|
||||
return api.SendMessageContext(
|
||||
ctx,
|
||||
channelID,
|
||||
MsgOptionUpdate(timestamp),
|
||||
MsgOptionCompose(options...),
|
||||
)
|
||||
}
|
||||
|
||||
// UnfurlMessage unfurls a message in a channel
|
||||
@@ -212,13 +250,14 @@ func buildSender(apiurl string, options ...MsgOption) sendConfig {
|
||||
type sendMode string
|
||||
|
||||
const (
|
||||
chatUpdate sendMode = "chat.update"
|
||||
chatPostMessage sendMode = "chat.postMessage"
|
||||
chatDelete sendMode = "chat.delete"
|
||||
chatPostEphemeral sendMode = "chat.postEphemeral"
|
||||
chatResponse sendMode = "chat.responseURL"
|
||||
chatMeMessage sendMode = "chat.meMessage"
|
||||
chatUnfurl sendMode = "chat.unfurl"
|
||||
chatUpdate sendMode = "chat.update"
|
||||
chatPostMessage sendMode = "chat.postMessage"
|
||||
chatScheduleMessage sendMode = "chat.scheduleMessage"
|
||||
chatDelete sendMode = "chat.delete"
|
||||
chatPostEphemeral sendMode = "chat.postEphemeral"
|
||||
chatResponse sendMode = "chat.responseURL"
|
||||
chatMeMessage sendMode = "chat.meMessage"
|
||||
chatUnfurl sendMode = "chat.unfurl"
|
||||
)
|
||||
|
||||
type sendConfig struct {
|
||||
@@ -287,6 +326,15 @@ func (t responseURLSender) BuildRequest() (*http.Request, func(*chatResponseFull
|
||||
// MsgOption option provided when sending a message.
|
||||
type MsgOption func(*sendConfig) error
|
||||
|
||||
// MsgOptionSchedule schedules a messages.
|
||||
func MsgOptionSchedule(postAt string) MsgOption {
|
||||
return func(config *sendConfig) error {
|
||||
config.endpoint = config.apiurl + string(chatScheduleMessage)
|
||||
config.values.Add("post_at", postAt)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MsgOptionPost posts a messages, this is the default.
|
||||
func MsgOptionPost() MsgOption {
|
||||
return func(config *sendConfig) error {
|
||||
@@ -625,3 +673,81 @@ func (api *Client) GetPermalinkContext(ctx context.Context, params *PermalinkPar
|
||||
}
|
||||
return response.Permalink, response.Err()
|
||||
}
|
||||
|
||||
type GetScheduledMessagesParameters struct {
|
||||
Channel string
|
||||
Cursor string
|
||||
Latest string
|
||||
Limit int
|
||||
Oldest string
|
||||
}
|
||||
|
||||
// GetScheduledMessages returns the list of scheduled messages based on params
|
||||
func (api *Client) GetScheduledMessages(params *GetScheduledMessagesParameters) (channels []Message, nextCursor string, err error) {
|
||||
return api.GetScheduledMessagesContext(context.Background(), params)
|
||||
}
|
||||
|
||||
// GetScheduledMessagesContext returns the list of scheduled messages in a Slack team with a custom context
|
||||
func (api *Client) GetScheduledMessagesContext(ctx context.Context, params *GetScheduledMessagesParameters) (channels []Message, nextCursor string, err error) {
|
||||
values := url.Values{
|
||||
"token": {api.token},
|
||||
}
|
||||
if params.Channel != "" {
|
||||
values.Add("channel", params.Channel)
|
||||
}
|
||||
if params.Cursor != "" {
|
||||
values.Add("cursor", params.Cursor)
|
||||
}
|
||||
if params.Limit != 0 {
|
||||
values.Add("limit", strconv.Itoa(params.Limit))
|
||||
}
|
||||
if params.Latest != "" {
|
||||
values.Add("latest", params.Latest)
|
||||
}
|
||||
if params.Oldest != "" {
|
||||
values.Add("oldest", params.Oldest)
|
||||
}
|
||||
response := struct {
|
||||
Messages []Message `json:"scheduled_messages"`
|
||||
ResponseMetaData responseMetaData `json:"response_metadata"`
|
||||
SlackResponse
|
||||
}{}
|
||||
|
||||
err = api.postMethod(ctx, "chat.scheduledMessages.list", values, &response)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
return response.Messages, response.ResponseMetaData.NextCursor, response.Err()
|
||||
}
|
||||
|
||||
type DeleteScheduledMessageParameters struct {
|
||||
Channel string
|
||||
ScheduledMessageID string
|
||||
AsUser bool
|
||||
}
|
||||
|
||||
// DeleteScheduledMessage returns the list of scheduled messages based on params
|
||||
func (api *Client) DeleteScheduledMessage(params *DeleteScheduledMessageParameters) (bool, error) {
|
||||
return api.DeleteScheduledMessageContext(context.Background(), params)
|
||||
}
|
||||
|
||||
// DeleteScheduledMessageContext returns the list of scheduled messages in a Slack team with a custom context
|
||||
func (api *Client) DeleteScheduledMessageContext(ctx context.Context, params *DeleteScheduledMessageParameters) (bool, error) {
|
||||
values := url.Values{
|
||||
"token": {api.token},
|
||||
"channel": {params.Channel},
|
||||
"scheduled_message_id": {params.ScheduledMessageID},
|
||||
"as_user": {strconv.FormatBool(params.AsUser)},
|
||||
}
|
||||
response := struct {
|
||||
SlackResponse
|
||||
}{}
|
||||
|
||||
err := api.postMethod(ctx, "chat.deleteScheduledMessage", values, &response)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return response.Ok, response.Err()
|
||||
}
|
||||
|
||||
7
vendor/github.com/slack-go/slack/go.mod
generated
vendored
7
vendor/github.com/slack-go/slack/go.mod
generated
vendored
@@ -1,12 +1,11 @@
|
||||
module github.com/slack-go/slack
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-test/deep v1.0.4
|
||||
github.com/gorilla/websocket v1.2.0
|
||||
github.com/nlopes/slack v0.6.0
|
||||
github.com/pkg/errors v0.8.0
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/stretchr/testify v1.2.2
|
||||
)
|
||||
|
||||
go 1.13
|
||||
|
||||
2
vendor/github.com/slack-go/slack/go.sum
generated
vendored
2
vendor/github.com/slack-go/slack/go.sum
generated
vendored
@@ -4,6 +4,8 @@ github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
|
||||
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ=
|
||||
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/nlopes/slack v0.6.0 h1:jt0jxVQGhssx1Ib7naAOZEZcGdtIhTzkP0nopK0AsRA=
|
||||
github.com/nlopes/slack v0.6.0/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk=
|
||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
|
||||
465
vendor/github.com/slack-go/slack/info.go
generated
vendored
465
vendor/github.com/slack-go/slack/info.go
generated
vendored
@@ -2,108 +2,381 @@ package slack
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// UserPrefs needs to be implemented
|
||||
type UserPrefsCarrier struct {
|
||||
SlackResponse
|
||||
UserPrefs *UserPrefs `json:"prefs"`
|
||||
}
|
||||
|
||||
// UserPrefs carries a bunch of user settings including some unknown types
|
||||
type UserPrefs struct {
|
||||
// "highlight_words":"",
|
||||
// "user_colors":"",
|
||||
// "color_names_in_list":true,
|
||||
// "growls_enabled":true,
|
||||
// "tz":"Europe\/London",
|
||||
// "push_dm_alert":true,
|
||||
// "push_mention_alert":true,
|
||||
// "push_everything":true,
|
||||
// "push_idle_wait":2,
|
||||
// "push_sound":"b2.mp3",
|
||||
// "push_loud_channels":"",
|
||||
// "push_mention_channels":"",
|
||||
// "push_loud_channels_set":"",
|
||||
// "email_alerts":"instant",
|
||||
// "email_alerts_sleep_until":0,
|
||||
// "email_misc":false,
|
||||
// "email_weekly":true,
|
||||
// "welcome_message_hidden":false,
|
||||
// "all_channels_loud":true,
|
||||
// "loud_channels":"",
|
||||
// "never_channels":"",
|
||||
// "loud_channels_set":"",
|
||||
// "show_member_presence":true,
|
||||
// "search_sort":"timestamp",
|
||||
// "expand_inline_imgs":true,
|
||||
// "expand_internal_inline_imgs":true,
|
||||
// "expand_snippets":false,
|
||||
// "posts_formatting_guide":true,
|
||||
// "seen_welcome_2":true,
|
||||
// "seen_ssb_prompt":false,
|
||||
// "search_only_my_channels":false,
|
||||
// "emoji_mode":"default",
|
||||
// "has_invited":true,
|
||||
// "has_uploaded":false,
|
||||
// "has_created_channel":true,
|
||||
// "search_exclude_channels":"",
|
||||
// "messages_theme":"default",
|
||||
// "webapp_spellcheck":true,
|
||||
// "no_joined_overlays":false,
|
||||
// "no_created_overlays":true,
|
||||
// "dropbox_enabled":false,
|
||||
// "seen_user_menu_tip_card":true,
|
||||
// "seen_team_menu_tip_card":true,
|
||||
// "seen_channel_menu_tip_card":true,
|
||||
// "seen_message_input_tip_card":true,
|
||||
// "seen_channels_tip_card":true,
|
||||
// "seen_domain_invite_reminder":false,
|
||||
// "seen_member_invite_reminder":false,
|
||||
// "seen_flexpane_tip_card":true,
|
||||
// "seen_search_input_tip_card":true,
|
||||
// "mute_sounds":false,
|
||||
// "arrow_history":false,
|
||||
// "tab_ui_return_selects":true,
|
||||
// "obey_inline_img_limit":true,
|
||||
// "new_msg_snd":"knock_brush.mp3",
|
||||
// "collapsible":false,
|
||||
// "collapsible_by_click":true,
|
||||
// "require_at":false,
|
||||
// "mac_ssb_bounce":"",
|
||||
// "mac_ssb_bullet":true,
|
||||
// "win_ssb_bullet":true,
|
||||
// "expand_non_media_attachments":true,
|
||||
// "show_typing":true,
|
||||
// "pagekeys_handled":true,
|
||||
// "last_snippet_type":"",
|
||||
// "display_real_names_override":0,
|
||||
// "time24":false,
|
||||
// "enter_is_special_in_tbt":false,
|
||||
// "graphic_emoticons":false,
|
||||
// "convert_emoticons":true,
|
||||
// "autoplay_chat_sounds":true,
|
||||
// "ss_emojis":true,
|
||||
// "sidebar_behavior":"",
|
||||
// "mark_msgs_read_immediately":true,
|
||||
// "start_scroll_at_oldest":true,
|
||||
// "snippet_editor_wrap_long_lines":false,
|
||||
// "ls_disabled":false,
|
||||
// "sidebar_theme":"default",
|
||||
// "sidebar_theme_custom_values":"",
|
||||
// "f_key_search":false,
|
||||
// "k_key_omnibox":true,
|
||||
// "speak_growls":false,
|
||||
// "mac_speak_voice":"com.apple.speech.synthesis.voice.Alex",
|
||||
// "mac_speak_speed":250,
|
||||
// "comma_key_prefs":false,
|
||||
// "at_channel_suppressed_channels":"",
|
||||
// "push_at_channel_suppressed_channels":"",
|
||||
// "prompted_for_email_disabling":false,
|
||||
// "full_text_extracts":false,
|
||||
// "no_text_in_notifications":false,
|
||||
// "muted_channels":"",
|
||||
// "no_macssb1_banner":false,
|
||||
// "privacy_policy_seen":true,
|
||||
// "search_exclude_bots":false,
|
||||
// "fuzzy_matching":false
|
||||
UserColors string `json:"user_colors,omitempty"`
|
||||
ColorNamesInList bool `json:"color_names_in_list,omitempty"`
|
||||
// Keyboard UnknownType `json:"keyboard"`
|
||||
EmailAlerts string `json:"email_alerts,omitempty"`
|
||||
EmailAlertsSleepUntil int `json:"email_alerts_sleep_until,omitempty"`
|
||||
EmailTips bool `json:"email_tips,omitempty"`
|
||||
EmailWeekly bool `json:"email_weekly,omitempty"`
|
||||
EmailOffers bool `json:"email_offers,omitempty"`
|
||||
EmailResearch bool `json:"email_research,omitempty"`
|
||||
EmailDeveloper bool `json:"email_developer,omitempty"`
|
||||
WelcomeMessageHidden bool `json:"welcome_message_hidden,omitempty"`
|
||||
SearchSort string `json:"search_sort,omitempty"`
|
||||
SearchFileSort string `json:"search_file_sort,omitempty"`
|
||||
SearchChannelSort string `json:"search_channel_sort,omitempty"`
|
||||
SearchPeopleSort string `json:"search_people_sort,omitempty"`
|
||||
ExpandInlineImages bool `json:"expand_inline_images,omitempty"`
|
||||
ExpandInternalInlineImages bool `json:"expand_internal_inline_images,omitempty"`
|
||||
ExpandSnippets bool `json:"expand_snippets,omitempty"`
|
||||
PostsFormattingGuide bool `json:"posts_formatting_guide,omitempty"`
|
||||
SeenWelcome2 bool `json:"seen_welcome_2,omitempty"`
|
||||
SeenSSBPrompt bool `json:"seen_ssb_prompt,omitempty"`
|
||||
SpacesNewXpBannerDismissed bool `json:"spaces_new_xp_banner_dismissed,omitempty"`
|
||||
SearchOnlyMyChannels bool `json:"search_only_my_channels,omitempty"`
|
||||
SearchOnlyCurrentTeam bool `json:"search_only_current_team,omitempty"`
|
||||
SearchHideMyChannels bool `json:"search_hide_my_channels,omitempty"`
|
||||
SearchOnlyShowOnline bool `json:"search_only_show_online,omitempty"`
|
||||
SearchHideDeactivatedUsers bool `json:"search_hide_deactivated_users,omitempty"`
|
||||
EmojiMode string `json:"emoji_mode,omitempty"`
|
||||
EmojiUse string `json:"emoji_use,omitempty"`
|
||||
HasInvited bool `json:"has_invited,omitempty"`
|
||||
HasUploaded bool `json:"has_uploaded,omitempty"`
|
||||
HasCreatedChannel bool `json:"has_created_channel,omitempty"`
|
||||
HasSearched bool `json:"has_searched,omitempty"`
|
||||
SearchExcludeChannels string `json:"search_exclude_channels,omitempty"`
|
||||
MessagesTheme string `json:"messages_theme,omitempty"`
|
||||
WebappSpellcheck bool `json:"webapp_spellcheck,omitempty"`
|
||||
NoJoinedOverlays bool `json:"no_joined_overlays,omitempty"`
|
||||
NoCreatedOverlays bool `json:"no_created_overlays,omitempty"`
|
||||
DropboxEnabled bool `json:"dropbox_enabled,omitempty"`
|
||||
SeenDomainInviteReminder bool `json:"seen_domain_invite_reminder,omitempty"`
|
||||
SeenMemberInviteReminder bool `json:"seen_member_invite_reminder,omitempty"`
|
||||
MuteSounds bool `json:"mute_sounds,omitempty"`
|
||||
ArrowHistory bool `json:"arrow_history,omitempty"`
|
||||
TabUIReturnSelects bool `json:"tab_ui_return_selects,omitempty"`
|
||||
ObeyInlineImgLimit bool `json:"obey_inline_img_limit,omitempty"`
|
||||
RequireAt bool `json:"require_at,omitempty"`
|
||||
SsbSpaceWindow string `json:"ssb_space_window,omitempty"`
|
||||
MacSsbBounce string `json:"mac_ssb_bounce,omitempty"`
|
||||
MacSsbBullet bool `json:"mac_ssb_bullet,omitempty"`
|
||||
ExpandNonMediaAttachments bool `json:"expand_non_media_attachments,omitempty"`
|
||||
ShowTyping bool `json:"show_typing,omitempty"`
|
||||
PagekeysHandled bool `json:"pagekeys_handled,omitempty"`
|
||||
LastSnippetType string `json:"last_snippet_type,omitempty"`
|
||||
DisplayRealNamesOverride int `json:"display_real_names_override,omitempty"`
|
||||
DisplayDisplayNames bool `json:"display_display_names,omitempty"`
|
||||
Time24 bool `json:"time24,omitempty"`
|
||||
EnterIsSpecialInTbt bool `json:"enter_is_special_in_tbt,omitempty"`
|
||||
MsgInputSendBtn bool `json:"msg_input_send_btn,omitempty"`
|
||||
MsgInputSendBtnAutoSet bool `json:"msg_input_send_btn_auto_set,omitempty"`
|
||||
MsgInputStickyComposer bool `json:"msg_input_sticky_composer,omitempty"`
|
||||
GraphicEmoticons bool `json:"graphic_emoticons,omitempty"`
|
||||
ConvertEmoticons bool `json:"convert_emoticons,omitempty"`
|
||||
SsEmojis bool `json:"ss_emojis,omitempty"`
|
||||
SeenOnboardingStart bool `json:"seen_onboarding_start,omitempty"`
|
||||
OnboardingCancelled bool `json:"onboarding_cancelled,omitempty"`
|
||||
SeenOnboardingSlackbotConversation bool `json:"seen_onboarding_slackbot_conversation,omitempty"`
|
||||
SeenOnboardingChannels bool `json:"seen_onboarding_channels,omitempty"`
|
||||
SeenOnboardingDirectMessages bool `json:"seen_onboarding_direct_messages,omitempty"`
|
||||
SeenOnboardingInvites bool `json:"seen_onboarding_invites,omitempty"`
|
||||
SeenOnboardingSearch bool `json:"seen_onboarding_search,omitempty"`
|
||||
SeenOnboardingRecentMentions bool `json:"seen_onboarding_recent_mentions,omitempty"`
|
||||
SeenOnboardingStarredItems bool `json:"seen_onboarding_starred_items,omitempty"`
|
||||
SeenOnboardingPrivateGroups bool `json:"seen_onboarding_private_groups,omitempty"`
|
||||
SeenOnboardingBanner bool `json:"seen_onboarding_banner,omitempty"`
|
||||
OnboardingSlackbotConversationStep int `json:"onboarding_slackbot_conversation_step,omitempty"`
|
||||
SetTzAutomatically bool `json:"set_tz_automatically,omitempty"`
|
||||
SuppressLinkWarning bool `json:"suppress_link_warning,omitempty"`
|
||||
DndEnabled bool `json:"dnd_enabled,omitempty"`
|
||||
DndStartHour string `json:"dnd_start_hour,omitempty"`
|
||||
DndEndHour string `json:"dnd_end_hour,omitempty"`
|
||||
DndBeforeMonday string `json:"dnd_before_monday,omitempty"`
|
||||
DndAfterMonday string `json:"dnd_after_monday,omitempty"`
|
||||
DndEnabledMonday string `json:"dnd_enabled_monday,omitempty"`
|
||||
DndBeforeTuesday string `json:"dnd_before_tuesday,omitempty"`
|
||||
DndAfterTuesday string `json:"dnd_after_tuesday,omitempty"`
|
||||
DndEnabledTuesday string `json:"dnd_enabled_tuesday,omitempty"`
|
||||
DndBeforeWednesday string `json:"dnd_before_wednesday,omitempty"`
|
||||
DndAfterWednesday string `json:"dnd_after_wednesday,omitempty"`
|
||||
DndEnabledWednesday string `json:"dnd_enabled_wednesday,omitempty"`
|
||||
DndBeforeThursday string `json:"dnd_before_thursday,omitempty"`
|
||||
DndAfterThursday string `json:"dnd_after_thursday,omitempty"`
|
||||
DndEnabledThursday string `json:"dnd_enabled_thursday,omitempty"`
|
||||
DndBeforeFriday string `json:"dnd_before_friday,omitempty"`
|
||||
DndAfterFriday string `json:"dnd_after_friday,omitempty"`
|
||||
DndEnabledFriday string `json:"dnd_enabled_friday,omitempty"`
|
||||
DndBeforeSaturday string `json:"dnd_before_saturday,omitempty"`
|
||||
DndAfterSaturday string `json:"dnd_after_saturday,omitempty"`
|
||||
DndEnabledSaturday string `json:"dnd_enabled_saturday,omitempty"`
|
||||
DndBeforeSunday string `json:"dnd_before_sunday,omitempty"`
|
||||
DndAfterSunday string `json:"dnd_after_sunday,omitempty"`
|
||||
DndEnabledSunday string `json:"dnd_enabled_sunday,omitempty"`
|
||||
DndDays string `json:"dnd_days,omitempty"`
|
||||
DndCustomNewBadgeSeen bool `json:"dnd_custom_new_badge_seen,omitempty"`
|
||||
DndNotificationScheduleNewBadgeSeen bool `json:"dnd_notification_schedule_new_badge_seen,omitempty"`
|
||||
// UnreadCollapsedChannels unknownType `json:"unread_collapsed_channels,omitempty"`
|
||||
SidebarBehavior string `json:"sidebar_behavior,omitempty"`
|
||||
ChannelSort string `json:"channel_sort,omitempty"`
|
||||
SeparatePrivateChannels bool `json:"separate_private_channels,omitempty"`
|
||||
SeparateSharedChannels bool `json:"separate_shared_channels,omitempty"`
|
||||
SidebarTheme string `json:"sidebar_theme,omitempty"`
|
||||
SidebarThemeCustomValues string `json:"sidebar_theme_custom_values,omitempty"`
|
||||
NoInvitesWidgetInSidebar bool `json:"no_invites_widget_in_sidebar,omitempty"`
|
||||
NoOmniboxInChannels bool `json:"no_omnibox_in_channels,omitempty"`
|
||||
|
||||
KKeyOmniboxAutoHideCount int `json:"k_key_omnibox_auto_hide_count,omitempty"`
|
||||
ShowSidebarQuickswitcherButton bool `json:"show_sidebar_quickswitcher_button,omitempty"`
|
||||
EntOrgWideChannelsSidebar bool `json:"ent_org_wide_channels_sidebar,omitempty"`
|
||||
MarkMsgsReadImmediately bool `json:"mark_msgs_read_immediately,omitempty"`
|
||||
StartScrollAtOldest bool `json:"start_scroll_at_oldest,omitempty"`
|
||||
SnippetEditorWrapLongLines bool `json:"snippet_editor_wrap_long_lines,omitempty"`
|
||||
LsDisabled bool `json:"ls_disabled,omitempty"`
|
||||
FKeySearch bool `json:"f_key_search,omitempty"`
|
||||
KKeyOmnibox bool `json:"k_key_omnibox,omitempty"`
|
||||
PromptedForEmailDisabling bool `json:"prompted_for_email_disabling,omitempty"`
|
||||
NoMacelectronBanner bool `json:"no_macelectron_banner,omitempty"`
|
||||
NoMacssb1Banner bool `json:"no_macssb1_banner,omitempty"`
|
||||
NoMacssb2Banner bool `json:"no_macssb2_banner,omitempty"`
|
||||
NoWinssb1Banner bool `json:"no_winssb1_banner,omitempty"`
|
||||
HideUserGroupInfoPane bool `json:"hide_user_group_info_pane,omitempty"`
|
||||
MentionsExcludeAtUserGroups bool `json:"mentions_exclude_at_user_groups,omitempty"`
|
||||
MentionsExcludeReactions bool `json:"mentions_exclude_reactions,omitempty"`
|
||||
PrivacyPolicySeen bool `json:"privacy_policy_seen,omitempty"`
|
||||
EnterpriseMigrationSeen bool `json:"enterprise_migration_seen,omitempty"`
|
||||
LastTosAcknowledged string `json:"last_tos_acknowledged,omitempty"`
|
||||
SearchExcludeBots bool `json:"search_exclude_bots,omitempty"`
|
||||
LoadLato2 bool `json:"load_lato_2,omitempty"`
|
||||
FullerTimestamps bool `json:"fuller_timestamps,omitempty"`
|
||||
LastSeenAtChannelWarning int `json:"last_seen_at_channel_warning,omitempty"`
|
||||
EmojiAutocompleteBig bool `json:"emoji_autocomplete_big,omitempty"`
|
||||
TwoFactorAuthEnabled bool `json:"two_factor_auth_enabled,omitempty"`
|
||||
// TwoFactorType unknownType `json:"two_factor_type,omitempty"`
|
||||
// TwoFactorBackupType unknownType `json:"two_factor_backup_type,omitempty"`
|
||||
HideHexSwatch bool `json:"hide_hex_swatch,omitempty"`
|
||||
ShowJumperScores bool `json:"show_jumper_scores,omitempty"`
|
||||
EnterpriseMdmCustomMsg string `json:"enterprise_mdm_custom_msg,omitempty"`
|
||||
// EnterpriseExcludedAppTeams unknownType `json:"enterprise_excluded_app_teams,omitempty"`
|
||||
ClientLogsPri string `json:"client_logs_pri,omitempty"`
|
||||
FlannelServerPool string `json:"flannel_server_pool,omitempty"`
|
||||
MentionsExcludeAtChannels bool `json:"mentions_exclude_at_channels,omitempty"`
|
||||
ConfirmClearAllUnreads bool `json:"confirm_clear_all_unreads,omitempty"`
|
||||
ConfirmUserMarkedAway bool `json:"confirm_user_marked_away,omitempty"`
|
||||
BoxEnabled bool `json:"box_enabled,omitempty"`
|
||||
SeenSingleEmojiMsg bool `json:"seen_single_emoji_msg,omitempty"`
|
||||
ConfirmShCallStart bool `json:"confirm_sh_call_start,omitempty"`
|
||||
PreferredSkinTone string `json:"preferred_skin_tone,omitempty"`
|
||||
ShowAllSkinTones bool `json:"show_all_skin_tones,omitempty"`
|
||||
WhatsNewRead int `json:"whats_new_read,omitempty"`
|
||||
// FrecencyJumper unknownType `json:"frecency_jumper,omitempty"`
|
||||
FrecencyEntJumper string `json:"frecency_ent_jumper,omitempty"`
|
||||
FrecencyEntJumperBackup string `json:"frecency_ent_jumper_backup,omitempty"`
|
||||
Jumbomoji bool `json:"jumbomoji,omitempty"`
|
||||
NewxpSeenLastMessage int `json:"newxp_seen_last_message,omitempty"`
|
||||
ShowMemoryInstrument bool `json:"show_memory_instrument,omitempty"`
|
||||
EnableUnreadView bool `json:"enable_unread_view,omitempty"`
|
||||
SeenUnreadViewCoachmark bool `json:"seen_unread_view_coachmark,omitempty"`
|
||||
EnableReactEmojiPicker bool `json:"enable_react_emoji_picker,omitempty"`
|
||||
SeenCustomStatusBadge bool `json:"seen_custom_status_badge,omitempty"`
|
||||
SeenCustomStatusCallout bool `json:"seen_custom_status_callout,omitempty"`
|
||||
SeenCustomStatusExpirationBadge bool `json:"seen_custom_status_expiration_badge,omitempty"`
|
||||
UsedCustomStatusKbShortcut bool `json:"used_custom_status_kb_shortcut,omitempty"`
|
||||
SeenGuestAdminSlackbotAnnouncement bool `json:"seen_guest_admin_slackbot_announcement,omitempty"`
|
||||
SeenThreadsNotificationBanner bool `json:"seen_threads_notification_banner,omitempty"`
|
||||
SeenNameTaggingCoachmark bool `json:"seen_name_tagging_coachmark,omitempty"`
|
||||
AllUnreadsSortOrder string `json:"all_unreads_sort_order,omitempty"`
|
||||
Locale string `json:"locale,omitempty"`
|
||||
SeenIntlChannelNamesCoachmark bool `json:"seen_intl_channel_names_coachmark,omitempty"`
|
||||
SeenP2LocaleChangeMessage int `json:"seen_p2_locale_change_message,omitempty"`
|
||||
SeenLocaleChangeMessage int `json:"seen_locale_change_message,omitempty"`
|
||||
SeenJapaneseLocaleChangeMessage bool `json:"seen_japanese_locale_change_message,omitempty"`
|
||||
SeenSharedChannelsCoachmark bool `json:"seen_shared_channels_coachmark,omitempty"`
|
||||
SeenSharedChannelsOptInChangeMessage bool `json:"seen_shared_channels_opt_in_change_message,omitempty"`
|
||||
HasRecentlySharedaChannel bool `json:"has_recently_shared_a_channel,omitempty"`
|
||||
SeenChannelBrowserAdminCoachmark bool `json:"seen_channel_browser_admin_coachmark,omitempty"`
|
||||
SeenAdministrationMenu bool `json:"seen_administration_menu,omitempty"`
|
||||
SeenDraftsSectionCoachmark bool `json:"seen_drafts_section_coachmark,omitempty"`
|
||||
SeenEmojiUpdateOverlayCoachmark bool `json:"seen_emoji_update_overlay_coachmark,omitempty"`
|
||||
SeenSonicDeluxeToast int `json:"seen_sonic_deluxe_toast,omitempty"`
|
||||
SeenWysiwygDeluxeToast bool `json:"seen_wysiwyg_deluxe_toast,omitempty"`
|
||||
SeenMarkdownPasteToast int `json:"seen_markdown_paste_toast,omitempty"`
|
||||
SeenMarkdownPasteShortcut int `json:"seen_markdown_paste_shortcut,omitempty"`
|
||||
SeenIaEducation bool `json:"seen_ia_education,omitempty"`
|
||||
PlainTextMode bool `json:"plain_text_mode,omitempty"`
|
||||
ShowSharedChannelsEducationBanner bool `json:"show_shared_channels_education_banner,omitempty"`
|
||||
AllowCallsToSetCurrentStatus bool `json:"allow_calls_to_set_current_status,omitempty"`
|
||||
InInteractiveMasMigrationFlow bool `json:"in_interactive_mas_migration_flow,omitempty"`
|
||||
SunsetInteractiveMessageViews int `json:"sunset_interactive_message_views,omitempty"`
|
||||
ShdepPromoCodeSubmitted bool `json:"shdep_promo_code_submitted,omitempty"`
|
||||
SeenShdepSlackbotMessage bool `json:"seen_shdep_slackbot_message,omitempty"`
|
||||
SeenCallsInteractiveCoachmark bool `json:"seen_calls_interactive_coachmark,omitempty"`
|
||||
AllowCmdTabIss bool `json:"allow_cmd_tab_iss,omitempty"`
|
||||
SeenWorkflowBuilderDeluxeToast bool `json:"seen_workflow_builder_deluxe_toast,omitempty"`
|
||||
WorkflowBuilderIntroModalClickedThrough bool `json:"workflow_builder_intro_modal_clicked_through,omitempty"`
|
||||
// WorkflowBuilderCoachmarks unknownType `json:"workflow_builder_coachmarks,omitempty"`
|
||||
SeenGdriveCoachmark bool `json:"seen_gdrive_coachmark,omitempty"`
|
||||
OverloadedMessageEnabled bool `json:"overloaded_message_enabled,omitempty"`
|
||||
SeenHighlightsCoachmark bool `json:"seen_highlights_coachmark,omitempty"`
|
||||
SeenHighlightsArrowsCoachmark bool `json:"seen_highlights_arrows_coachmark,omitempty"`
|
||||
SeenHighlightsWarmWelcome bool `json:"seen_highlights_warm_welcome,omitempty"`
|
||||
SeenNewSearchUi bool `json:"seen_new_search_ui,omitempty"`
|
||||
SeenChannelSearch bool `json:"seen_channel_search,omitempty"`
|
||||
SeenPeopleSearch bool `json:"seen_people_search,omitempty"`
|
||||
SeenPeopleSearchCount int `json:"seen_people_search_count,omitempty"`
|
||||
DismissedScrollSearchTooltipCount int `json:"dismissed_scroll_search_tooltip_count,omitempty"`
|
||||
LastDismissedScrollSearchTooltipTimestamp int `json:"last_dismissed_scroll_search_tooltip_timestamp,omitempty"`
|
||||
HasUsedQuickswitcherShortcut bool `json:"has_used_quickswitcher_shortcut,omitempty"`
|
||||
SeenQuickswitcherShortcutTipCount int `json:"seen_quickswitcher_shortcut_tip_count,omitempty"`
|
||||
BrowsersDismissedChannelsLowResultsEducation bool `json:"browsers_dismissed_channels_low_results_education,omitempty"`
|
||||
BrowsersSeenInitialChannelsEducation bool `json:"browsers_seen_initial_channels_education,omitempty"`
|
||||
BrowsersDismissedPeopleLowResultsEducation bool `json:"browsers_dismissed_people_low_results_education,omitempty"`
|
||||
BrowsersSeenInitialPeopleEducation bool `json:"browsers_seen_initial_people_education,omitempty"`
|
||||
BrowsersDismissedUserGroupsLowResultsEducation bool `json:"browsers_dismissed_user_groups_low_results_education,omitempty"`
|
||||
BrowsersSeenInitialUserGroupsEducation bool `json:"browsers_seen_initial_user_groups_education,omitempty"`
|
||||
BrowsersDismissedFilesLowResultsEducation bool `json:"browsers_dismissed_files_low_results_education,omitempty"`
|
||||
BrowsersSeenInitialFilesEducation bool `json:"browsers_seen_initial_files_education,omitempty"`
|
||||
A11yAnimations bool `json:"a11y_animations,omitempty"`
|
||||
SeenKeyboardShortcutsCoachmark bool `json:"seen_keyboard_shortcuts_coachmark,omitempty"`
|
||||
NeedsInitialPasswordSet bool `json:"needs_initial_password_set,omitempty"`
|
||||
LessonsEnabled bool `json:"lessons_enabled,omitempty"`
|
||||
TractorEnabled bool `json:"tractor_enabled,omitempty"`
|
||||
TractorExperimentGroup string `json:"tractor_experiment_group,omitempty"`
|
||||
OpenedSlackbotDm bool `json:"opened_slackbot_dm,omitempty"`
|
||||
NewxpSuggestedChannels string `json:"newxp_suggested_channels,omitempty"`
|
||||
OnboardingComplete bool `json:"onboarding_complete,omitempty"`
|
||||
WelcomePlaceState string `json:"welcome_place_state,omitempty"`
|
||||
// OnboardingRoleApps unknownType `json:"onboarding_role_apps,omitempty"`
|
||||
HasReceivedThreadedMessage bool `json:"has_received_threaded_message,omitempty"`
|
||||
SendYourFirstMessageBannerEnabled bool `json:"send_your_first_message_banner_enabled,omitempty"`
|
||||
WhocanseethisDmMpdmBadge bool `json:"whocanseethis_dm_mpdm_badge,omitempty"`
|
||||
HighlightWords string `json:"highlight_words,omitempty"`
|
||||
ThreadsEverything bool `json:"threads_everything,omitempty"`
|
||||
NoTextInNotifications bool `json:"no_text_in_notifications,omitempty"`
|
||||
PushShowPreview bool `json:"push_show_preview,omitempty"`
|
||||
GrowlsEnabled bool `json:"growls_enabled,omitempty"`
|
||||
AllChannelsLoud bool `json:"all_channels_loud,omitempty"`
|
||||
PushDmAlert bool `json:"push_dm_alert,omitempty"`
|
||||
PushMentionAlert bool `json:"push_mention_alert,omitempty"`
|
||||
PushEverything bool `json:"push_everything,omitempty"`
|
||||
PushIdleWait int `json:"push_idle_wait,omitempty"`
|
||||
PushSound string `json:"push_sound,omitempty"`
|
||||
NewMsgSnd string `json:"new_msg_snd,omitempty"`
|
||||
PushLoudChannels string `json:"push_loud_channels,omitempty"`
|
||||
PushMentionChannels string `json:"push_mention_channels,omitempty"`
|
||||
PushLoudChannelsSet string `json:"push_loud_channels_set,omitempty"`
|
||||
LoudChannels string `json:"loud_channels,omitempty"`
|
||||
NeverChannels string `json:"never_channels,omitempty"`
|
||||
LoudChannelsSet string `json:"loud_channels_set,omitempty"`
|
||||
AtChannelSuppressedChannels string `json:"at_channel_suppressed_channels,omitempty"`
|
||||
PushAtChannelSuppressedChannels string `json:"push_at_channel_suppressed_channels,omitempty"`
|
||||
MutedChannels string `json:"muted_channels,omitempty"`
|
||||
// AllNotificationsPrefs unknownType `json:"all_notifications_prefs,omitempty"`
|
||||
GrowthMsgLimitApproachingCtaCount int `json:"growth_msg_limit_approaching_cta_count,omitempty"`
|
||||
GrowthMsgLimitApproachingCtaTs int `json:"growth_msg_limit_approaching_cta_ts,omitempty"`
|
||||
GrowthMsgLimitReachedCtaCount int `json:"growth_msg_limit_reached_cta_count,omitempty"`
|
||||
GrowthMsgLimitReachedCtaLastTs int `json:"growth_msg_limit_reached_cta_last_ts,omitempty"`
|
||||
GrowthMsgLimitLongReachedCtaCount int `json:"growth_msg_limit_long_reached_cta_count,omitempty"`
|
||||
GrowthMsgLimitLongReachedCtaLastTs int `json:"growth_msg_limit_long_reached_cta_last_ts,omitempty"`
|
||||
GrowthMsgLimitSixtyDayBannerCtaCount int `json:"growth_msg_limit_sixty_day_banner_cta_count,omitempty"`
|
||||
GrowthMsgLimitSixtyDayBannerCtaLastTs int `json:"growth_msg_limit_sixty_day_banner_cta_last_ts,omitempty"`
|
||||
// GrowthAllBannersPrefs unknownType `json:"growth_all_banners_prefs,omitempty"`
|
||||
AnalyticsUpsellCoachmarkSeen bool `json:"analytics_upsell_coachmark_seen,omitempty"`
|
||||
SeenAppSpaceCoachmark bool `json:"seen_app_space_coachmark,omitempty"`
|
||||
SeenAppSpaceTutorial bool `json:"seen_app_space_tutorial,omitempty"`
|
||||
DismissedAppLauncherWelcome bool `json:"dismissed_app_launcher_welcome,omitempty"`
|
||||
DismissedAppLauncherLimit bool `json:"dismissed_app_launcher_limit,omitempty"`
|
||||
Purchaser bool `json:"purchaser,omitempty"`
|
||||
ShowEntOnboarding bool `json:"show_ent_onboarding,omitempty"`
|
||||
FoldersEnabled bool `json:"folders_enabled,omitempty"`
|
||||
// FolderData unknownType `json:"folder_data,omitempty"`
|
||||
SeenCorporateExportAlert bool `json:"seen_corporate_export_alert,omitempty"`
|
||||
ShowAutocompleteHelp int `json:"show_autocomplete_help,omitempty"`
|
||||
DeprecationToastLastSeen int `json:"deprecation_toast_last_seen,omitempty"`
|
||||
DeprecationModalLastSeen int `json:"deprecation_modal_last_seen,omitempty"`
|
||||
Iap1Lab int `json:"iap1_lab,omitempty"`
|
||||
IaTopNavTheme string `json:"ia_top_nav_theme,omitempty"`
|
||||
IaPlatformActionsLab int `json:"ia_platform_actions_lab,omitempty"`
|
||||
ActivityView string `json:"activity_view,omitempty"`
|
||||
FailoverProxyCheckCompleted int `json:"failover_proxy_check_completed,omitempty"`
|
||||
EdgeUploadProxyCheckCompleted int `json:"edge_upload_proxy_check_completed,omitempty"`
|
||||
AppSubdomainCheckCompleted int `json:"app_subdomain_check_completed,omitempty"`
|
||||
AddAppsPromptDismissed bool `json:"add_apps_prompt_dismissed,omitempty"`
|
||||
AddChannelPromptDismissed bool `json:"add_channel_prompt_dismissed,omitempty"`
|
||||
ChannelSidebarHideInvite bool `json:"channel_sidebar_hide_invite,omitempty"`
|
||||
InProdSurveysEnabled bool `json:"in_prod_surveys_enabled,omitempty"`
|
||||
DismissedInstalledAppDmSuggestions string `json:"dismissed_installed_app_dm_suggestions,omitempty"`
|
||||
SeenContextualMessageShortcutsModal bool `json:"seen_contextual_message_shortcuts_modal,omitempty"`
|
||||
SeenMessageNavigationEducationalToast bool `json:"seen_message_navigation_educational_toast,omitempty"`
|
||||
ContextualMessageShortcutsModalWasSeen bool `json:"contextual_message_shortcuts_modal_was_seen,omitempty"`
|
||||
MessageNavigationToastWasSeen bool `json:"message_navigation_toast_was_seen,omitempty"`
|
||||
UpToBrowseKbShortcut bool `json:"up_to_browse_kb_shortcut,omitempty"`
|
||||
ChannelSections string `json:"channel_sections,omitempty"`
|
||||
TZ string `json:"tz,omitempty"`
|
||||
}
|
||||
|
||||
func (api *Client) GetUserPrefs() (*UserPrefsCarrier, error) {
|
||||
values := url.Values{"token": {api.token}}
|
||||
response := UserPrefsCarrier{}
|
||||
|
||||
err := api.getMethod(context.Background(), "users.prefs.get", values, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &response, response.Err()
|
||||
}
|
||||
|
||||
func (api *Client) MuteChat(channelID string) (*UserPrefsCarrier, error) {
|
||||
prefs, err := api.GetUserPrefs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
chnls := strings.Split(prefs.UserPrefs.MutedChannels, ",")
|
||||
for _, chn := range chnls {
|
||||
if chn == channelID {
|
||||
return nil, nil // noop
|
||||
}
|
||||
}
|
||||
newChnls := prefs.UserPrefs.MutedChannels + "," + channelID
|
||||
values := url.Values{"token": {api.token}, "muted_channels": {newChnls}, "reason": {"update-muted-channels"}}
|
||||
response := UserPrefsCarrier{}
|
||||
|
||||
err = api.postMethod(context.Background(), "users.prefs.set", values, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &response, response.Err()
|
||||
}
|
||||
|
||||
func (api *Client) UnMuteChat(channelID string) (*UserPrefsCarrier, error) {
|
||||
prefs, err := api.GetUserPrefs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
chnls := strings.Split(prefs.UserPrefs.MutedChannels, ",")
|
||||
newChnls := make([]string, len(chnls)-1)
|
||||
for i, chn := range chnls {
|
||||
if chn == channelID {
|
||||
return nil, nil // noop
|
||||
}
|
||||
newChnls[i] = chn
|
||||
}
|
||||
values := url.Values{"token": {api.token}, "muted_channels": {strings.Join(newChnls, ",")}, "reason": {"update-muted-channels"}}
|
||||
response := UserPrefsCarrier{}
|
||||
|
||||
err = api.postMethod(context.Background(), "users.prefs.set", values, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &response, response.Err()
|
||||
}
|
||||
|
||||
// UserDetails contains user details coming in the initial response from StartRTM
|
||||
|
||||
14
vendor/github.com/slack-go/slack/interactions.go
generated
vendored
14
vendor/github.com/slack-go/slack/interactions.go
generated
vendored
@@ -24,6 +24,9 @@ const (
|
||||
InteractionTypeInteractionMessage = InteractionType("interactive_message")
|
||||
InteractionTypeMessageAction = InteractionType("message_action")
|
||||
InteractionTypeBlockActions = InteractionType("block_actions")
|
||||
InteractionTypeBlockSuggestion = InteractionType("block_suggestion")
|
||||
InteractionTypeViewSubmission = InteractionType("view_submission")
|
||||
InteractionTypeViewClosed = InteractionType("view_closed")
|
||||
)
|
||||
|
||||
// InteractionCallback is sent from slack when a user interactions with a button or dialog.
|
||||
@@ -44,8 +47,19 @@ type InteractionCallback struct {
|
||||
MessageTs string `json:"message_ts"`
|
||||
AttachmentID string `json:"attachment_id"`
|
||||
ActionCallback ActionCallbacks `json:"actions"`
|
||||
View View `json:"view"`
|
||||
ActionID string `json:"action_id"`
|
||||
APIAppID string `json:"api_app_id"`
|
||||
BlockID string `json:"block_id"`
|
||||
Container Container `json:"container"`
|
||||
DialogSubmissionCallback
|
||||
ViewSubmissionCallback
|
||||
ViewClosedCallback
|
||||
}
|
||||
|
||||
type Container struct {
|
||||
Type string `json:"type"`
|
||||
ViewID string `json:"view_id"`
|
||||
}
|
||||
|
||||
// ActionCallback is a convenience struct defined to allow dynamic unmarshalling of
|
||||
|
||||
54
vendor/github.com/slack-go/slack/oauth.go
generated
vendored
54
vendor/github.com/slack-go/slack/oauth.go
generated
vendored
@@ -31,6 +31,40 @@ type OAuthResponse struct {
|
||||
SlackResponse
|
||||
}
|
||||
|
||||
// OAuthV2Response ...
|
||||
type OAuthV2Response struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
Scope string `json:"scope"`
|
||||
BotUserID string `json:"bot_user_id"`
|
||||
AppID string `json:"app_id"`
|
||||
TeamID string `json:"team_id"`
|
||||
Team OAuthV2ResponseTeam `json:"team"`
|
||||
Enterprise OAuthV2ResponseEnterprise `json:"enterprise"`
|
||||
AuthedUser OAuthV2ResponseAuthedUser `json:"authed_user"`
|
||||
SlackResponse
|
||||
}
|
||||
|
||||
// OAuthV2ResponseTeam ...
|
||||
type OAuthV2ResponseTeam struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// OAuthV2ResponseEnterprise ...
|
||||
type OAuthV2ResponseEnterprise struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// OAuthV2ResponseAuthedUser ...
|
||||
type OAuthV2ResponseAuthedUser struct {
|
||||
ID string `json:"id"`
|
||||
Scope string `json:"scope"`
|
||||
AccessToken string `json:"access_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
}
|
||||
|
||||
// GetOAuthToken retrieves an AccessToken
|
||||
func GetOAuthToken(client httpClient, clientID, clientSecret, code, redirectURI string) (accessToken string, scope string, err error) {
|
||||
return GetOAuthTokenContext(context.Background(), client, clientID, clientSecret, code, redirectURI)
|
||||
@@ -62,3 +96,23 @@ func GetOAuthResponseContext(ctx context.Context, client httpClient, clientID, c
|
||||
}
|
||||
return response, response.Err()
|
||||
}
|
||||
|
||||
// GetOAuthV2Response gets a V2 OAuth access token response - https://api.slack.com/methods/oauth.v2.access
|
||||
func GetOAuthV2Response(client httpClient, clientID, clientSecret, code, redirectURI string) (resp *OAuthV2Response, err error) {
|
||||
return GetOAuthV2ResponseContext(context.Background(), client, clientID, clientSecret, code, redirectURI)
|
||||
}
|
||||
|
||||
// GetOAuthV2ResponseContext with a context, gets a V2 OAuth access token response
|
||||
func GetOAuthV2ResponseContext(ctx context.Context, client httpClient, clientID, clientSecret, code, redirectURI string) (resp *OAuthV2Response, err error) {
|
||||
values := url.Values{
|
||||
"client_id": {clientID},
|
||||
"client_secret": {clientSecret},
|
||||
"code": {code},
|
||||
"redirect_uri": {redirectURI},
|
||||
}
|
||||
response := &OAuthV2Response{}
|
||||
if err = postForm(ctx, client, APIURL+"oauth.v2.access", values, response, discard{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, response.Err()
|
||||
}
|
||||
|
||||
84
vendor/github.com/slack-go/slack/views.go
generated
vendored
84
vendor/github.com/slack-go/slack/views.go
generated
vendored
@@ -12,6 +12,10 @@ const (
|
||||
|
||||
type ViewType string
|
||||
|
||||
type ViewState struct {
|
||||
Values map[string]map[string]BlockAction `json:"values"`
|
||||
}
|
||||
|
||||
type View struct {
|
||||
SlackResponse
|
||||
ID string `json:"id"`
|
||||
@@ -23,7 +27,7 @@ type View struct {
|
||||
Blocks Blocks `json:"blocks"`
|
||||
PrivateMetadata string `json:"private_metadata"`
|
||||
CallbackID string `json:"callback_id"`
|
||||
State interface{} `json:"state"`
|
||||
State *ViewState `json:"state"`
|
||||
Hash string `json:"hash"`
|
||||
ClearOnClose bool `json:"clear_on_close"`
|
||||
NotifyOnClose bool `json:"notify_on_close"`
|
||||
@@ -34,17 +38,67 @@ type View struct {
|
||||
BotID string `json:"bot_id"`
|
||||
}
|
||||
|
||||
type ViewSubmissionCallback struct {
|
||||
Hash string `json:"hash"`
|
||||
}
|
||||
|
||||
type ViewClosedCallback struct {
|
||||
IsCleared bool `json:"is_cleared"`
|
||||
}
|
||||
|
||||
const (
|
||||
RAClear ViewResponseAction = "clear"
|
||||
RAUpdate ViewResponseAction = "update"
|
||||
RAPush ViewResponseAction = "push"
|
||||
RAErrors ViewResponseAction = "errors"
|
||||
)
|
||||
|
||||
type ViewResponseAction string
|
||||
|
||||
type ViewSubmissionResponse struct {
|
||||
ResponseAction ViewResponseAction `json:"response_action"`
|
||||
View *ModalViewRequest `json:"view,omitempty"`
|
||||
Errors map[string]string `json:"errors,omitempty"`
|
||||
}
|
||||
|
||||
func NewClearViewSubmissionResponse() *ViewSubmissionResponse {
|
||||
return &ViewSubmissionResponse{
|
||||
ResponseAction: RAClear,
|
||||
}
|
||||
}
|
||||
|
||||
func NewUpdateViewSubmissionResponse(view *ModalViewRequest) *ViewSubmissionResponse {
|
||||
return &ViewSubmissionResponse{
|
||||
ResponseAction: RAUpdate,
|
||||
View: view,
|
||||
}
|
||||
}
|
||||
|
||||
func NewPushViewSubmissionResponse(view *ModalViewRequest) *ViewSubmissionResponse {
|
||||
return &ViewSubmissionResponse{
|
||||
ResponseAction: RAPush,
|
||||
View: view,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorsViewSubmissionResponse(errors map[string]string) *ViewSubmissionResponse {
|
||||
return &ViewSubmissionResponse{
|
||||
ResponseAction: RAErrors,
|
||||
Errors: errors,
|
||||
}
|
||||
}
|
||||
|
||||
type ModalViewRequest struct {
|
||||
Type ViewType `json:"type"`
|
||||
Title *TextBlockObject `json:"title"`
|
||||
Blocks Blocks `json:"blocks"`
|
||||
Close *TextBlockObject `json:"close"`
|
||||
Submit *TextBlockObject `json:"submit"`
|
||||
PrivateMetadata string `json:"private_metadata"`
|
||||
CallbackID string `json:"callback_id"`
|
||||
ClearOnClose bool `json:"clear_on_close"`
|
||||
NotifyOnClose bool `json:"notify_on_close"`
|
||||
ExternalID string `json:"external_id"`
|
||||
Close *TextBlockObject `json:"close,omitempty"`
|
||||
Submit *TextBlockObject `json:"submit,omitempty"`
|
||||
PrivateMetadata string `json:"private_metadata,omitempty"`
|
||||
CallbackID string `json:"callback_id,omitempty"`
|
||||
ClearOnClose bool `json:"clear_on_close,omitempty"`
|
||||
NotifyOnClose bool `json:"notify_on_close,omitempty"`
|
||||
ExternalID string `json:"external_id,omitempty"`
|
||||
}
|
||||
|
||||
func (v *ModalViewRequest) ViewType() ViewType {
|
||||
@@ -54,9 +108,9 @@ func (v *ModalViewRequest) ViewType() ViewType {
|
||||
type HomeTabViewRequest struct {
|
||||
Type ViewType `json:"type"`
|
||||
Blocks Blocks `json:"blocks"`
|
||||
PrivateMetadata string `json:"private_metadata"`
|
||||
CallbackID string `json:"callback_id"`
|
||||
ExternalID string `json:"external_id"`
|
||||
PrivateMetadata string `json:"private_metadata,omitempty"`
|
||||
CallbackID string `json:"callback_id,omitempty"`
|
||||
ExternalID string `json:"external_id,omitempty"`
|
||||
}
|
||||
|
||||
func (v *HomeTabViewRequest) ViewType() ViewType {
|
||||
@@ -71,7 +125,7 @@ type openViewRequest struct {
|
||||
type publishViewRequest struct {
|
||||
UserID string `json:"user_id"`
|
||||
View HomeTabViewRequest `json:"view"`
|
||||
Hash string `json:"hash"`
|
||||
Hash string `json:"hash,omitempty"`
|
||||
}
|
||||
|
||||
type pushViewRequest struct {
|
||||
@@ -81,9 +135,9 @@ type pushViewRequest struct {
|
||||
|
||||
type updateViewRequest struct {
|
||||
View ModalViewRequest `json:"view"`
|
||||
ExternalID string `json:"external_id"`
|
||||
Hash string `json:"hash"`
|
||||
ViewID string `json:"view_id"`
|
||||
ExternalID string `json:"external_id,omitempty"`
|
||||
Hash string `json:"hash,omitempty"`
|
||||
ViewID string `json:"view_id,omitempty"`
|
||||
}
|
||||
|
||||
type ViewResponse struct {
|
||||
|
||||
2
vendor/github.com/slack-go/slack/websocket_channels.go
generated
vendored
2
vendor/github.com/slack-go/slack/websocket_channels.go
generated
vendored
@@ -45,7 +45,7 @@ type ChannelRenameEvent struct {
|
||||
type ChannelRenameInfo struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Created string `json:"created"`
|
||||
Created int `json:"created"`
|
||||
}
|
||||
|
||||
// ChannelHistoryChangedEvent represents the Channel history changed event
|
||||
|
||||
3
vendor/github.com/slack-go/slack/websocket_managed_conn.go
generated
vendored
3
vendor/github.com/slack-go/slack/websocket_managed_conn.go
generated
vendored
@@ -577,5 +577,6 @@ var EventMapping = map[string]interface{}{
|
||||
"subteam_self_removed": SubteamSelfRemovedEvent{},
|
||||
"subteam_updated": SubteamUpdatedEvent{},
|
||||
|
||||
"desktop_notification": DesktopNotificationEvent{},
|
||||
"desktop_notification": DesktopNotificationEvent{},
|
||||
"mobile_in_app_notification": MobileInAppNotificationEvent{},
|
||||
}
|
||||
|
||||
20
vendor/github.com/slack-go/slack/websocket_mobile_in_app_notification.go
generated
vendored
Normal file
20
vendor/github.com/slack-go/slack/websocket_mobile_in_app_notification.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package slack
|
||||
|
||||
// MobileInAppNotificationEvent represents the update event for Mobile App Notification.
|
||||
type MobileInAppNotificationEvent struct {
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title"`
|
||||
Subtitle string `json:"subtitle"`
|
||||
Timestamp string `json:"ts"`
|
||||
Channel string `json:"channel"`
|
||||
AvatarImage string `json:"avatarImage"`
|
||||
IsShared bool `json:"is_shared"`
|
||||
ChannelName string `json:"channel_name"`
|
||||
AuthorID string `json:"author_id"`
|
||||
AuthorDisplayName string `json:"author_display_name"`
|
||||
MessageText string `json:"msg_text"`
|
||||
PushID string `json:"push_id"`
|
||||
NotifcationID string `json:"notif_id"`
|
||||
MobileLaunchURI string `json:"mobileLaunchUri"`
|
||||
EventTimestamp string `json:"event_ts"`
|
||||
}
|
||||
13
vendor/modules.txt
vendored
13
vendor/modules.txt
vendored
@@ -15,7 +15,7 @@ github.com/Philipp15b/go-steam/protocol/steamlang
|
||||
github.com/Philipp15b/go-steam/rwu
|
||||
github.com/Philipp15b/go-steam/socialcache
|
||||
github.com/Philipp15b/go-steam/steamid
|
||||
# github.com/Rhymen/go-whatsapp v0.1.0
|
||||
# github.com/Rhymen/go-whatsapp v0.1.1-0.20200421062035-31e8111ac334
|
||||
github.com/Rhymen/go-whatsapp
|
||||
github.com/Rhymen/go-whatsapp/binary
|
||||
github.com/Rhymen/go-whatsapp/binary/proto
|
||||
@@ -23,7 +23,7 @@ github.com/Rhymen/go-whatsapp/binary/token
|
||||
github.com/Rhymen/go-whatsapp/crypto/cbc
|
||||
github.com/Rhymen/go-whatsapp/crypto/curve25519
|
||||
github.com/Rhymen/go-whatsapp/crypto/hkdf
|
||||
# github.com/d5/tengo/v2 v2.0.2
|
||||
# github.com/d5/tengo/v2 v2.1.2
|
||||
github.com/d5/tengo/v2
|
||||
github.com/d5/tengo/v2/parser
|
||||
github.com/d5/tengo/v2/stdlib
|
||||
@@ -95,7 +95,7 @@ github.com/labstack/gommon/random
|
||||
github.com/lrstanley/girc
|
||||
# github.com/magiconair/properties v1.8.1
|
||||
github.com/magiconair/properties
|
||||
# github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d
|
||||
# github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20200411204219-d5c18ce75048
|
||||
github.com/matterbridge/Rocket.Chat.Go.SDK/models
|
||||
github.com/matterbridge/Rocket.Chat.Go.SDK/realtime
|
||||
github.com/matterbridge/Rocket.Chat.Go.SDK/rest
|
||||
@@ -103,7 +103,7 @@ github.com/matterbridge/Rocket.Chat.Go.SDK/rest
|
||||
github.com/matterbridge/discordgo
|
||||
# github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible
|
||||
github.com/matterbridge/emoji
|
||||
# github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91
|
||||
# github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050
|
||||
github.com/matterbridge/go-xmpp
|
||||
# github.com/matterbridge/gomatrix v0.0.0-20200209224845-c2104d7936a6
|
||||
github.com/matterbridge/gomatrix
|
||||
@@ -111,8 +111,6 @@ github.com/matterbridge/gomatrix
|
||||
github.com/matterbridge/gozulipbot
|
||||
# github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61
|
||||
github.com/matterbridge/logrus-prefixed-formatter
|
||||
# github.com/matterbridge/msgraph.go v0.0.0-20200308150230-9e043fe9dbaa
|
||||
github.com/matterbridge/msgraph.go/msauth
|
||||
# github.com/mattermost/mattermost-server v5.5.0+incompatible
|
||||
github.com/mattermost/mattermost-server/mlog
|
||||
github.com/mattermost/mattermost-server/model
|
||||
@@ -174,7 +172,7 @@ github.com/sirupsen/logrus
|
||||
github.com/skip2/go-qrcode
|
||||
github.com/skip2/go-qrcode/bitset
|
||||
github.com/skip2/go-qrcode/reedsolomon
|
||||
# github.com/slack-go/slack v0.6.3-0.20200228121756-f56d616d5901
|
||||
# github.com/slack-go/slack v0.6.3
|
||||
github.com/slack-go/slack
|
||||
github.com/slack-go/slack/internal/errorsx
|
||||
github.com/slack-go/slack/internal/timex
|
||||
@@ -205,6 +203,7 @@ github.com/valyala/fasttemplate
|
||||
# github.com/yaegashi/msgraph.go v0.1.2
|
||||
github.com/yaegashi/msgraph.go/beta
|
||||
github.com/yaegashi/msgraph.go/jsonx
|
||||
github.com/yaegashi/msgraph.go/msauth
|
||||
# github.com/zfjagann/golang-ring v0.0.0-20190106091943-a88bb6aef447
|
||||
github.com/zfjagann/golang-ring
|
||||
# go.uber.org/atomic v1.4.0
|
||||
|
||||
Reference in New Issue
Block a user