Begin: replace irc library with girc

This commit is contained in:
kayos@tcp.direct 2021-10-01 02:10:02 -07:00
parent 922e41f095
commit 9b7f5296e7
13 changed files with 210 additions and 305 deletions

View File

@ -1,9 +0,0 @@
ARG GOLANG_VERSION=1.16
FROM golang:$GOLANG_VERSION-alpine
WORKDIR /bot
COPY . .
RUN go build
CMD ["./go-discord-irc", "--config", "config.yml"]

View File

@ -2,21 +2,15 @@ MIT License
Copyright (c) 2017 Qais Patankar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -5,34 +5,31 @@
[![Preview](https://i.imgur.com/YpCqzdn.gif)](https://i.imgur.com/YpCqzdn.webm)
**Is this being maintained?** Yes. But I want to merge all this functionality
into the much superior
**Is this being maintained?** Yes. But I want to merge all this functionality into the much superior
[matterbridge by 42wim](https://github.com/42wim/matterbridge).
This is IRC to Discord bridge was originally built for
[@compsoc-edinburgh](http://github.com/compsoc-edinburgh) and
[ImaginaryNet](http://imaginarynet.uk/), but now it looks like more people are
using it!
[ImaginaryNet](http://imaginarynet.uk/), but now it looks like more people are using it!
- The `IRC -> Discord` side of things work as you would expect it to: messages
on IRC send to Discord as the bot user, as per usual.
- The `Discord -> IRC` side of things is a little different. On connect, this
bot will join the server with the `~d`, and spawn additional connections for
each online person in the Discord.
- The `IRC -> Discord` side of things work as you would expect it to: messages on IRC send to Discord as the bot user,
as per usual.
- The `Discord -> IRC` side of things is a little different. On connect, this bot will join the server with the `~d`,
and spawn additional connections for each online person in the Discord.
- Supports bidirectional PMs. (Not user friendly, but it works.)
**Features**
(not a full list)
- Every Discord user in your server will join your channel. Messages come from those "puppets", not from a single chat bridge user.
- Every Discord user in your server will join your channel. Messages come from those "puppets", not from a single chat
bridge user.
- Saying the puppet username will @ that person on Discord.
- When a Discord user's presence is "offline" or "idle", their irc puppet will
have their AWAY status set.
- A Discord user offline for will disconnect from IRC after 24 hours (or
whatever `cooldown_duration` you set).
- When a Discord user's presence is "offline" or "idle", their irc puppet will have their AWAY status set.
- A Discord user offline for will disconnect from IRC after 24 hours (or whatever `cooldown_duration` you set).
- Join/Quit/Part/Kick messages are sent to Discord (configurable!)
- Replying to someone on Discord will prefix that someone's name, e.g. replying to Alex with "yes that's fine" will show up as `<you> Alex: yes, that's fine` on IRC.
- Replying to someone on Discord will prefix that someone's name, e.g. replying to Alex with "yes that's fine" will show
up as `<you> Alex: yes, that's fine` on IRC.
- IRC users can send (custom!) emoji to Discord, just do `:somename:`. Discord emoji shows up like that on IRC.
- Reacting to a Discord message will send a CTCP ACTION (`/me`) on IRC.
@ -40,18 +37,16 @@ using it!
Things to keep in mind in terms of functionality:
- This does not work with private Discord channels properly (all discord users
are added to the channel)
- This does not work with private Discord channels properly (all discord users are added to the channel)
- **DO NOT USE THE SAME DISCORD BOT (API KEY) ACROSS MULTIPLE GUILDS
(SERVERS).**
It's built with configuration in mind, but may need a little bit of tweaking for
it to work for you:
It's built with configuration in mind, but may need a little bit of tweaking for it to work for you:
- **Hardcoded**: Hostnames are hardcoded to follow the IPv6 IPs listed
[here](https://github.com/qaisjp/go-discord-irc/issues/2).
- **Defaults aren't usable**: You should set the `suffix` and `separator` config
options. The default options require custom modifications to the IRC server.
- **Defaults aren't usable**: You should set the `suffix` and `separator` config options. The default options require
custom modifications to the IRC server.
- **Server config**: This uses `WEBIRC` to give Discord users on IRC a distinct
hostname. [See here](https://kiwiirc.com/docs/webirc).
@ -59,13 +54,11 @@ it to work for you:
The binary takes three flags:
- `--config filename.yaml`: to pass along a configuration file containing things
like passwords and channel options
- `--simple`: to only spawn one connection (the listener will send across
messages from Discord) instead of a connection per online Discord user
- `--debug`: provide this flag to print extra debug info. Setting this flag to
false (or not providing this flag) will take the value from the config file
instead
- `--config filename.yaml`: to pass along a configuration file containing things like passwords and channel options
- `--simple`: to only spawn one connection (the listener will send across messages from Discord) instead of a connection
per online Discord user
- `--debug`: provide this flag to print extra debug info. Setting this flag to false (or not providing this flag) will
take the value from the config file instead
- `--insecure`: used to skip TLS verification (false = use value from settings)
- `--no-tls`: turns off TLS
@ -83,7 +76,8 @@ The config file is a yaml formatted file with the following fields:
| `guild_id` | No | | No | the Discord guild (server) id |
| `irc_pass` | Yes | | Yes | password for connecting to the IRC server |
| `suffix` | No | `~d` | Yes | appended to each Discord user's nickname when they are connected to IRC. If set to `_d2`, if the name will be `bob_d2` |
| `separator` | No | `_` | Yes | used in fallback situations. If set to `-`, the **fallback name** will be like `bob-7247_d2` (where `7247` is the discord user's discriminator, and `_d2` is the suffix) |
| `separator` | No | `_` | Yes | used in fallback situations. If set to `-`, the **
fallback name** will be like `bob-7247_d2` (where `7247` is the discord user's discriminator, and `_d2` is the suffix) |
| `irc_listener_name` | Yes | `~d` | The name of the irc listener | |
| `ignored_discord_ids` | Sometimes | | Yes | A list of Discord IDs to not relay to IRC |
| `allowed_discord_ids` | Sometimes | `null` | Yes | A list of Discord IDs to relay to IRC. `null` allows all Discord users to be relayed to IRC. Hot reload: IDs added to the list require a presence change to take effect. |
@ -100,13 +94,11 @@ The config file is a yaml formatted file with the following fields:
| `ignored_irc_hostmasks` | No | | Yes | A list of IRC users identified by hostmask to not relay to Discord, uses matching syntax as in [glob](https://github.com/gobwas/glob) |
| `connection_limit` | Yes | 0 | Yes | How many connections to IRC (including our listener) to spawn (limit of 0 or less means unlimited) |
**The filename.yaml file is continuously read from and many changes will
automatically update on the bridge. This means you can add or remove channels
without restarting the bot.**
**The filename.yaml file is continuously read from and many changes will automatically update on the bridge. This means
you can add or remove channels without restarting the bot.**
An example configuration file can be seen in [`config.yml`](./config.yml). Those
marked as `requires restart` definitely require restart, but others may not
currently be configured to automatically update.
An example configuration file can be seen in [`config.yml`](./config.yml). Those marked as `requires restart` definitely
require restart, but others may not currently be configured to automatically update.
This bot needs permissions to manage webhooks as it creates webhooks on the go.
@ -122,9 +114,8 @@ Make sure you also give the bot application these intents too:
## Docker
First edit `config.yml` file to your needs.
Then launch `docker build -t go-discord-irc .` in the repository root folder.
And then `docker run -d go-discord-irc` to run the bot in background.
First edit `config.yml` file to your needs. Then launch `docker build -t go-discord-irc .` in the repository root
folder. And then `docker run -d go-discord-irc` to run the bot in background.
## Development

View File

@ -1,18 +1,18 @@
package bridge
import (
"crypto/tls"
"fmt"
"regexp"
"strings"
"time"
irc "git.tcp.direct/kayos/girc-tcpd"
"github.com/gobwas/glob"
"github.com/matterbridge/discordgo"
"github.com/pkg/errors"
"github.com/qaisjp/go-discord-irc/irc/varys"
irc "github.com/qaisjp/go-ircevent"
log "github.com/sirupsen/logrus"
"github.com/qaisjp/go-discord-irc/irc/varys"
)
// Config to be passed to New
@ -34,7 +34,6 @@ type Config struct {
DiscordAllowed map[string]struct{} // Discord user IDs to only bridge
ConnectionLimit int // number of IRC connections we can spawn
IRCPuppetPrejoinCommands []string
IRCListenerPrejoinCommands []string
// filters
@ -212,13 +211,13 @@ func (b *Bridge) SetChannelMappings(inMappings map[string]string) error {
}
}
b.ircListener.SendRaw("PART " + strings.Join(rmChannels, ","))
b.ircListener.Client.Cmd.SendRaw("PART " + strings.Join(rmChannels, ","))
if err := b.ircManager.varys.SendRaw("", varys.InterpolationParams{}, "PART "+strings.Join(rmChannels, ",")); err != nil {
panic(err.Error())
}
// The bots needs to join the new mappings
b.ircListener.JoinChannels()
b.ircListener.JoinChannels(b.ircListener.Client, irc.Event{})
for _, conn := range b.ircManager.ircConnections {
conn.JoinChannels()
}
@ -265,7 +264,7 @@ func New(conf *Config) (*Bridge, error) {
// SetIRCListenerName changes the username of the listener bot.
func (b *Bridge) SetIRCListenerName(name string) {
b.Config.IRCListenerName = name
b.ircListener.Nick(name)
b.ircListener.Client.Cmd.Nick(name)
}
// SetDebugMode allows you to control debug logging.
@ -283,41 +282,14 @@ func (b *Bridge) Open() (err error) {
return errors.Wrap(err, "can't open discord")
}
err = b.ircListener.Connect(b.Config.IRCServer)
err = b.ircListener.Connect()
if err != nil {
return errors.Wrap(err, "can't open irc connection")
}
// run listener loop
go b.ircListener.Loop()
return
}
// SetupIRCConnection sets up an IRC connection with config settings like
// UseTLS, InsecureSkipVerify, and WebIRCPass.
func (b *Bridge) SetupIRCConnection(con *irc.Connection, hostname, ip string) {
if !b.Config.NoTLS {
con.UseTLS = true
con.TLSConfig = &tls.Config{
InsecureSkipVerify: b.Config.InsecureSkipVerify,
}
}
// On kick, rejoin the channel
con.AddCallback("KICK", func(e *irc.Event) {
if e.Arguments[1] == con.GetNick() {
con.Join(e.Arguments[0])
}
})
con.Password = b.Config.IRCServerPass
if b.Config.WebIRCPass != "" {
con.WebIRC = fmt.Sprintf("%s discord %s %s", b.Config.WebIRCPass, hostname, ip)
}
}
// GetJoinCommand produces a JOIN command based on the provided mappings
func (b *Bridge) GetJoinCommand(mappings []Mapping) string {
var channels, keyedChannels, keys []string
@ -481,7 +453,7 @@ func (b *Bridge) loop() {
// Done!
case <-b.done:
b.discord.Close()
b.ircListener.Quit()
b.ircListener.Client.Quit("yeet")
b.ircManager.Close()
close(b.done)

View File

@ -7,6 +7,7 @@ import (
"strings"
"github.com/42wim/matterbridge/bridge/discord/transmitter"
"github.com/qaisjp/go-discord-irc/dstate"
ircnick "github.com/qaisjp/go-discord-irc/irc/nick"

View File

@ -5,9 +5,10 @@ import (
"strings"
"time"
"github.com/qaisjp/go-discord-irc/irc/varys"
irc "github.com/qaisjp/go-ircevent"
irc "git.tcp.direct/kayos/girc-tcpd"
log "github.com/sirupsen/logrus"
"github.com/qaisjp/go-discord-irc/irc/varys"
)
// An ircConnection should only ever communicate with its manager
@ -47,9 +48,9 @@ func (i *ircConnection) Connected() bool {
return connected
}
func (i *ircConnection) OnWelcome(e *irc.Event) {
func (i *ircConnection) OnWelcome(c *irc.Client, e irc.Event) {
// execute puppet prejoin commands
err := i.manager.varys.SendRaw(i.discord.ID, varys.InterpolationParams{Nick: true}, i.manager.bridge.Config.IRCPuppetPrejoinCommands...)
err := i.manager.varys.SendRaw(i.discord.ID, varys.InterpolationParams{Nick: true})
if err != nil {
panic(err.Error())
}
@ -132,27 +133,27 @@ func (i *ircConnection) introducePM(nick string) {
}
}
func (i *ircConnection) OnPrivateMessage(e *irc.Event) {
func (i *ircConnection) OnPrivateMessage(c *irc.Client, e irc.Event) {
// Ignored hostmasks
if i.manager.isIgnoredHostmask(e.Source) {
if i.manager.isIgnoredHostmask(e.Source.String()) {
return
}
// Alert private messages
if string(e.Arguments[0][0]) != "#" {
if e.Message() == "help" {
i.Privmsg(e.Nick, "Commands: help, who")
} else if e.Message() == "who" {
i.Privmsg(e.Nick, fmt.Sprintf("I am: %s#%s with ID %s", i.discord.Nick, i.discord.Discriminator, i.discord.ID))
if string(e.Params[0][0]) != "#" {
if e.Last() == "help" {
i.Privmsg(e.Source.Name, "Commands: help, who")
} else if e.Last() == "who" {
i.Privmsg(e.Source.Name, fmt.Sprintf("I am: %s#%s with ID %s", i.discord.Nick, i.discord.Discriminator, i.discord.ID))
}
d := i.manager.bridge.discord
i.introducePM(e.Nick)
i.introducePM(e.Source.Name)
msg := fmt.Sprintf(
"%s,%s - %s@%s: %s", e.Connection.Server, e.Source,
e.Nick, i.manager.bridge.Config.Discriminator, e.Message())
"%s - %s@%s: %s", e.Source,
e.Source.Name, i.manager.bridge.Config.Discriminator, e.Last())
_, err := d.Session.ChannelMessageSend(i.pmDiscordChannel, msg)
if err != nil {
log.Warnln("Could not send PM", i.discord, err)

View File

@ -1,74 +1,81 @@
package bridge
import (
"crypto/tls"
"fmt"
"os"
"strings"
"time"
irc "git.tcp.direct/kayos/girc-tcpd"
log "github.com/sirupsen/logrus"
ircf "github.com/qaisjp/go-discord-irc/irc/format"
irc "github.com/qaisjp/go-ircevent"
log "github.com/sirupsen/logrus"
)
type ircListener struct {
*irc.Connection
*irc.Client
bridge *Bridge
listenerCallbackIDs map[string]int
}
func newIRCListener(dib *Bridge, webIRCPass string) *ircListener {
irccon := irc.IRC(dib.Config.IRCListenerName, "discord")
listener := &ircListener{irccon, dib, make(map[string]int)}
var ircConfig = irc.Config{
Server: dib.Config.IRCListenerName,
User: dib.Config.IRCListenerName,
Nick: dib.Config.IRCListenerName,
ServerPass: dib.Config.IRCServerPass,
Version: "tcp.direct",
}
dib.SetupIRCConnection(irccon, "discord.", "fd75:f5f5:226f::")
listener.SetDebugMode(dib.Config.Debug)
if dib.Config.Debug {
ircConfig.Debug = os.Stdout
}
// Nick tracker for nick tracking
irccon.SetupNickTrack()
if !dib.Config.NoTLS {
ircConfig.SSL = true
ircConfig.TLSConfig = &tls.Config{
InsecureSkipVerify: dib.Config.InsecureSkipVerify,
}
}
// Welcome event
irccon.AddCallback("001", listener.OnWelcome)
ircClient := irc.New(ircConfig)
// Called when received channel names... essentially OnJoinChannel
irccon.AddCallback("366", listener.OnJoinChannel)
irccon.AddCallback("PRIVMSG", listener.OnPrivateMessage)
irccon.AddCallback("NOTICE", listener.OnPrivateMessage)
irccon.AddCallback("CTCP_ACTION", listener.OnPrivateMessage)
irccon.AddCallback("900", func(e *irc.Event) {
// Try to rejoni channels after authenticated with NickServ
listener.JoinChannels()
// On kick, rejoin the channel
ircClient.Handlers.Add("KICK", func(c *irc.Client, e irc.Event) {
if e.Params[1] == c.GetNick() {
c.Cmd.Join(e.Params[0])
}
})
// we are assuming this will be posible to run independent of any
// future NICK callbacks added, otherwise do it like the STQUIT callback
listener.AddCallback("NICK", listener.nickTrackNick)
listener := &ircListener{ircClient, dib, make(map[string]int)}
// Note that this might override SetupNickTrack!
listener.OnJoinQuitSettingChange()
// Welcome event
ircClient.Handlers.Add(irc.CONNECTED, listener.JoinChannels)
// Called when received channel names... essentially OnJoinChannel
ircClient.Handlers.Add("366", listener.OnJoinChannel)
ircClient.Handlers.Add("PRIVMSG", listener.OnPrivateMessage)
ircClient.Handlers.Add("NOTICE", listener.OnPrivateMessage)
ircClient.Handlers.Add("CTCP_ACTION", listener.OnPrivateMessage)
// Try to rejoin channels after authenticated with NickServ
ircClient.Handlers.Add("900", listener.JoinChannels)
return listener
}
func (i *ircListener) nickTrackNick(event *irc.Event) {
oldNick := event.Nick
newNick := event.Message()
if con, ok := i.bridge.ircManager.puppetNicks[oldNick]; ok {
i.bridge.ircManager.puppetNicks[newNick] = con
delete(i.bridge.ircManager.puppetNicks, oldNick)
}
}
func (i *ircListener) OnNickRelayToDiscord(event *irc.Event) {
func (i *ircListener) OnNickRelayToDiscord(e irc.Event) {
// ignored hostmasks, or we're a puppet? no relay
if i.bridge.ircManager.isIgnoredHostmask(event.Source) ||
i.isPuppetNick(event.Nick) ||
i.isPuppetNick(event.Message()) {
if i.bridge.ircManager.isIgnoredHostmask(e.Source.String()) ||
i.isPuppetNick(e.Source.Name) ||
i.isPuppetNick(e.Last()) {
return
}
oldNick := event.Nick
newNick := event.Message()
oldNick := e.Source.Name
newNick := e.Last()
msg := IRCMessage{
Username: "",
@ -77,8 +84,9 @@ func (i *ircListener) OnNickRelayToDiscord(event *irc.Event) {
for _, m := range i.bridge.mappings {
channel := m.IRCChannel
if channelObj, ok := i.Connection.GetChannel(channel); ok {
if _, ok := channelObj.GetUser(newNick); ok {
if channelObj := i.Client.LookupChannel(channel); channelObj != nil {
if channelObj.UserIn(newNick) {
msg.IRCChannel = channel
i.bridge.discordMessagesChan <- msg
}
@ -86,79 +94,55 @@ func (i *ircListener) OnNickRelayToDiscord(event *irc.Event) {
}
}
func (i *ircListener) nickTrackPuppetQuit(e *irc.Event) {
func (i *ircListener) nickTrackPuppetQuit(e irc.Event) {
// Protect against HostServ changing nicks or ircd's with CHGHOST/CHGIDENT or similar
// sending us a QUIT for a puppet nick only for it to rejoin right after.
// The puppet nick won't see a true disconnection itself and thus will still see itself
// as connected.
if con, ok := i.bridge.ircManager.puppetNicks[e.Nick]; ok && !con.Connected() {
delete(i.bridge.ircManager.puppetNicks, e.Nick)
if con, ok := i.bridge.ircManager.puppetNicks[e.Source.Name]; ok && !con.Connected() {
delete(i.bridge.ircManager.puppetNicks, e.Source.Name)
}
}
func (i *ircListener) OnJoinQuitSettingChange() {
// always remove our listener callbacks
for ev, id := range i.listenerCallbackIDs {
i.RemoveCallback(ev, id)
delete(i.listenerCallbackIDs, ev)
}
// we're either going to track quits, or track and relay said, so swap out the callback
// based on which is in effect.
if i.bridge.Config.ShowJoinQuit {
i.listenerCallbackIDs["STNICK"] = i.AddCallback("STNICK", i.OnNickRelayToDiscord)
// KICK is not state tracked!
callbacks := []string{"STJOIN", "STPART", "STQUIT", "KICK"}
for _, cb := range callbacks {
id := i.AddCallback(cb, i.OnJoinQuitCallback)
i.listenerCallbackIDs[cb] = id
}
} else {
id := i.AddCallback("STQUIT", i.nickTrackPuppetQuit)
i.listenerCallbackIDs["STQUIT"] = id
}
}
func (i *ircListener) OnJoinQuitCallback(event *irc.Event) {
func (i *ircListener) OnJoinQuitCallback(e irc.Event) {
// This checks if the source of the event was from a puppet.
if (event.Code == "KICK" && i.isPuppetNick(event.Arguments[1])) || i.isPuppetNick(event.Nick) {
if (e.Command == "KICK" && i.isPuppetNick(e.Params[1])) || i.isPuppetNick(e.Source.Name) {
// since we replace the STQUIT callback we have to manage our puppet nicks when
// this call back is active!
if event.Code == "STQUIT" {
i.nickTrackPuppetQuit(event)
if e.Command == "STQUIT" {
i.nickTrackPuppetQuit(e)
}
return
}
// Ignored hostmasks
if i.bridge.ircManager.isIgnoredHostmask(event.Source) {
if i.bridge.ircManager.isIgnoredHostmask(e.Source.String()) {
return
}
who := event.Nick
message := event.Nick
id := " (" + event.User + "@" + event.Host + ") "
who := e.Source.Name
message := e.Source.Name
id := " (" + e.Source.Ident + "@" + e.Source.Host + ") "
switch event.Code {
switch e.Command {
case "STJOIN":
message += " joined" + id
case "STPART":
message += " left" + id
if len(event.Arguments) > 1 {
message += ": " + event.Arguments[1]
if len(e.Params) > 1 {
message += ": " + e.Params[1]
}
case "STQUIT":
message += " quit" + id
reason := event.Nick
if len(event.Arguments) == 1 {
reason = event.Arguments[0]
reason := e.Source.Name
if len(e.Params) == 1 {
reason = e.Params[0]
}
message += "Quit: " + reason
case "KICK":
who = event.Arguments[1]
message = event.Arguments[1] + " was kicked by " + event.Nick + ": " + event.Arguments[2]
who = e.Params[1]
message = e.Params[1] + " was kicked by " + e.Source.Name + ": " + e.Params[2]
}
msg := IRCMessage{
@ -167,38 +151,38 @@ func (i *ircListener) OnJoinQuitCallback(event *irc.Event) {
Message: message,
}
if event.Code == "STQUIT" {
if e.Command == "STQUIT" {
// Notify channels that the user is in
for _, m := range i.bridge.mappings {
channel := m.IRCChannel
channelObj, ok := i.Connection.GetChannel(channel)
if !ok {
channelObj := i.Client.LookupChannel(channel)
if channelObj == nil {
log.WithField("channel", channel).WithField("who", who).Warnln("Trying to process QUIT. Channel not found in irc listener cache.")
continue
}
if _, ok := channelObj.GetUser(who); !ok {
if channelObj.UserIn(who) {
continue
}
msg.IRCChannel = channel
i.bridge.discordMessagesChan <- msg
}
} else {
msg.IRCChannel = event.Arguments[0]
msg.IRCChannel = e.Params[0]
i.bridge.discordMessagesChan <- msg
}
}
// FIXME: the user might not be on any channel that we're in and that would
// lead to incorrect assumptions the user doesn't exist!
// Good way to check is to utilize ISON
func (i *ircListener) DoesUserExist(user string) bool {
ret := false
i.IterChannels(func(name string, ch *irc.Channel) {
if !ret {
_, ret = ch.GetUser(user)
func (i *ircListener) DoesUserExist(user string) (exists bool) {
exists = false
i.Client.Cmd.SendRawf("ISON %s", user)
i.Client.Handlers.AddTmp("303", 5*time.Second, func(c *irc.Client, e irc.Event) bool {
if e.Params[len(e.Params)] == user {
exists = true
}
return false
})
return ret
return
}
func (i *ircListener) SetDebugMode(debug bool) {
@ -206,22 +190,14 @@ func (i *ircListener) SetDebugMode(debug bool) {
// i.Debug = debug
}
func (i *ircListener) OnWelcome(e *irc.Event) {
// Execute prejoin commands
for _, com := range i.bridge.Config.IRCListenerPrejoinCommands {
i.SendRaw(strings.ReplaceAll(com, "${NICK}", i.GetNick()))
func (i *ircListener) JoinChannels(c *irc.Client, e irc.Event) {
for _, mapping := range i.bridge.mappings {
c.Cmd.Join(mapping.IRCChannel)
}
// Join all channels
i.JoinChannels()
}
func (i *ircListener) JoinChannels() {
i.SendRaw(i.bridge.GetJoinCommand(i.bridge.mappings))
}
func (i *ircListener) OnJoinChannel(e *irc.Event) {
log.Infof("Listener has joined IRC channel %s.", e.Arguments[1])
func (i *ircListener) OnJoinChannel(c *irc.Client, e irc.Event) {
log.Infof("Listener has joined IRC channel %s.", e.Params[1])
}
func (i *ircListener) isPuppetNick(nick string) bool {
@ -234,18 +210,18 @@ func (i *ircListener) isPuppetNick(nick string) bool {
return false
}
func (i *ircListener) OnPrivateMessage(e *irc.Event) {
func (i *ircListener) OnPrivateMessage(c *irc.Client, e irc.Event) {
// Ignore private messages
if string(e.Arguments[0][0]) != "#" {
if string(e.Params[0][0]) != "#" {
// If you decide to extend this to respond to PMs, make sure
// you do not respond to NOTICEs, see issue #50.
return
}
if strings.TrimSpace(e.Message()) == "" || // Discord doesn't accept an empty message
i.isPuppetNick(e.Nick) || // ignore msg's from our puppets
i.bridge.ircManager.isIgnoredHostmask(e.Source) || //ignored hostmasks
i.bridge.ircManager.isFilteredIRCMessage(e.Message()) { // filtered
if strings.TrimSpace(e.Last()) == "" || // Discord doesn't accept an empty message
i.isPuppetNick(e.Source.Name) || // ignore msg's from our puppets
i.bridge.ircManager.isIgnoredHostmask(e.Source.String()) || // ignored hostmasks
i.bridge.ircManager.isFilteredIRCMessage(e.Last()) { // filtered
return
}
@ -256,18 +232,18 @@ func (i *ircListener) OnPrivateMessage(e *irc.Event) {
msg := strings.NewReplacer(
replacements...,
).Replace(e.Message())
).Replace(e.Last())
if e.Code == "CTCP_ACTION" {
if e.Command == "CTCP_ACTION" {
msg = "_" + msg + "_"
}
msg = ircf.BlocksToMarkdown(ircf.Parse(msg))
go func(e *irc.Event) {
go func(e irc.Event) {
i.bridge.discordMessagesChan <- IRCMessage{
IRCChannel: e.Arguments[0],
Username: e.Nick,
IRCChannel: e.Params[0],
Username: e.Source.Name,
Message: msg,
}
}(e)

View File

@ -9,10 +9,11 @@ import (
"github.com/mozillazg/go-unidecode"
"github.com/pkg/errors"
irc "git.tcp.direct/kayos/girc-tcpd"
log "github.com/sirupsen/logrus"
ircnick "github.com/qaisjp/go-discord-irc/irc/nick"
"github.com/qaisjp/go-discord-irc/irc/varys"
irc "github.com/qaisjp/go-ircevent"
log "github.com/sirupsen/logrus"
)
// DevMode is a hack
@ -258,7 +259,7 @@ func (m *IRCManager) HandleUser(user DiscordUser) {
WebIRCSuffix: fmt.Sprintf("discord %s %s", hostname, ip),
Callbacks: map[string]func(*irc.Event){
Callbacks: map[string]func(c *irc.Client, e irc.Event){
"001": con.OnWelcome,
"PRIVMSG": con.OnPrivateMessage,
},
@ -394,7 +395,7 @@ func (m *IRCManager) SendMessage(channel string, msg *DiscordMessage) {
if !ok {
length := len(msg.Author.Username)
for _, line := range strings.Split(content, "\n") {
m.bridge.ircListener.Privmsg(channel, fmt.Sprintf(
m.bridge.ircListener.Client.Cmd.Message(channel, fmt.Sprintf(
"<%s#%s> %s",
msg.Author.Username[:1]+"\u200B"+msg.Author.Username[1:length],
msg.Author.Discriminator,

2
go.mod
View File

@ -3,13 +3,13 @@ module github.com/qaisjp/go-discord-irc
go 1.15
require (
git.tcp.direct/kayos/girc-tcpd v0.0.0-20210905150122-4e0aac9cba2f
github.com/42wim/matterbridge v1.22.0
github.com/fsnotify/fsnotify v1.4.9
github.com/gobwas/glob v0.2.3
github.com/matterbridge/discordgo v0.23.2-0.20210201201054-fb39a175b4f7
github.com/mozillazg/go-unidecode v0.1.1
github.com/pkg/errors v0.9.1
github.com/qaisjp/go-ircevent v0.0.0-20210224154625-07452bfb05b5
github.com/sirupsen/logrus v1.7.0
github.com/spf13/viper v1.7.1
github.com/stretchr/testify v1.7.0

27
go.sum
View File

@ -44,6 +44,8 @@ dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
git.tcp.direct/kayos/girc-tcpd v0.0.0-20210905150122-4e0aac9cba2f h1:TfFJ1hBo5Ma29mn5QXJISE33UEJmfU0gjIpasYbb1Zw=
git.tcp.direct/kayos/girc-tcpd v0.0.0-20210905150122-4e0aac9cba2f/go.mod h1:w6yijBG8Jw2AOrhYn2IlutzSB3gqv5ZKDcsJFeJZOVw=
github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557/go.mod h1:jL0YSXMs/txjtGJ4PWrmETOk6KUHMDPMshgQZlTeB3Y=
github.com/42wim/matterbridge v1.22.0 h1:2RGvCa5s+hlGVhESgWnvvtQEhAYi1VrVEJ4zAXQQbwg=
github.com/42wim/matterbridge v1.22.0/go.mod h1:FEkNlc5IhzSbAus9yzHprVoEvfvtEHODrGfCtKvP92k=
@ -51,7 +53,6 @@ github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOv
github.com/Azure/azure-sdk-for-go v26.5.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-autorest v11.5.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f/go.mod h1:4a58ifQTEe2uwwsaqbh3i2un5/CBPg+At/qHpt18Tmk=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
@ -231,7 +232,6 @@ github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVB
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/frankban/quicktest v1.4.0/go.mod h1:36zfPVQyHxymz4cH7wlDmVwDrJuljRB60qkgn7rorfQ=
github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@ -356,7 +356,6 @@ github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
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/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
@ -474,18 +473,15 @@ github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgo
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/kljensen/snowball v0.6.0/go.mod h1:27N7E8fVU5H68RlUmnWwZCfxgt4POBJfENGMvNRhldw=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
@ -504,7 +500,6 @@ github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0U
github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7/go.mod h1:liX5MxHPrwgHaKowoLkYGwbXfYABh1jbZ6FpElbGF1I=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@ -576,7 +571,6 @@ github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUb
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
@ -654,7 +648,6 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T
github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c/go.mod h1:YnNlZP7l4MhyGQ4CBRwv6ohZTPrUJJZtEv4ZgADkbs4=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
@ -667,7 +660,6 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi
github.com/pierrec/lz4/v3 v3.3.2/go.mod h1:280XNCGS8jAcG++AHdd6SeWnzyJ1w9oow2vbORyey8Q=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -709,8 +701,6 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/qaisjp/go-ircevent v0.0.0-20210224154625-07452bfb05b5 h1:elH75Fsz3q1CQT3/dt55EuehXGTBK/rslX7qnLvxADg=
github.com/qaisjp/go-ircevent v0.0.0-20210224154625-07452bfb05b5/go.mod h1:QVUXUOAPFwMwEh+GKC+Zh56c5p7tZpRqGbXZzqaWbZE=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/reflog/dateconstraints v0.2.1/go.mod h1:Ax8AxTBcJc3E/oVS2hd2j7RDM/5MDtuPwuR7lIHtPLo=
@ -765,7 +755,6 @@ github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYED
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/simplereach/timeutils v1.2.0/go.mod h1:VVbQDfN/FHRZa1LSqcwo4kNZ62OOyqLLGQKYB3pB0Q8=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
@ -783,28 +772,23 @@ github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJ
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.3.4 h1:8q6vk3hthlpb2SouZcnBVKboxWQWMDNF38bwholZrJc=
github.com/spf13/afero v1.3.4/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
@ -819,7 +803,6 @@ github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5J
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -927,7 +910,6 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -1064,7 +1046,6 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1111,12 +1092,10 @@ golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d h1:MiWWjyhUzZ+jvhZvloX6ZrUsd
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@ -1289,7 +1268,6 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -1315,7 +1293,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -28,7 +28,7 @@ const (
FCHAN_C
FNICK_C
// add )
// add )
)
// MAXLENGTH is the maximum length of a nickname

View File

@ -6,22 +6,21 @@ package varys
import (
"crypto/tls"
"fmt"
"strings"
irc "github.com/qaisjp/go-ircevent"
irc "git.tcp.direct/kayos/girc-tcpd"
)
type Varys struct {
connConfig SetupParams
uidToConns map[string]*irc.Connection
uidToConns map[string]*irc.Client
}
func NewVarys() *Varys {
return &Varys{uidToConns: make(map[string]*irc.Connection)}
return &Varys{uidToConns: make(map[string]*irc.Client)}
}
func (v *Varys) connCall(uid string, fn func(*irc.Connection)) {
func (v *Varys) connCall(uid string, fn func(*irc.Client)) {
if uid == "" {
for _, conn := range v.uidToConns {
fn(conn)
@ -83,46 +82,52 @@ type ConnectParams struct {
WebIRCSuffix string
// TODO(qaisjp): does not support net/rpc!!!!
Callbacks map[string]func(*irc.Event)
Callbacks map[string]func(c *irc.Client, e irc.Event)
}
func (v *Varys) Connect(params ConnectParams, _ *struct{}) error {
conn := irc.IRC(params.Nick, params.Username)
// conn.Debug = true
conn.RealName = params.RealName
conn := irc.Config{
Nick: params.Nick,
User: params.Username,
Name: params.RealName,
Version: "tcp.direct",
SSL: false,
}
// TLS things, and the server password
conn.Password = v.connConfig.ServerPassword
conn.UseTLS = v.connConfig.UseTLS
conn.ServerPass = v.connConfig.ServerPassword
if v.connConfig.UseTLS {
conn.SSL = true
}
if v.connConfig.InsecureSkipVerify {
conn.TLSConfig = &tls.Config{
InsecureSkipVerify: true,
}
}
// Set up WebIRC, if a suffix is provided
if params.WebIRCSuffix != "" {
conn.WebIRC = v.connConfig.WebIRCPassword + " " + params.WebIRCSuffix
}
client := irc.New(conn)
// On kick, rejoin the channel
conn.AddCallback("KICK", func(e *irc.Event) {
if e.Arguments[1] == conn.GetNick() {
conn.Join(e.Arguments[0])
client.Handlers.Add("KICK", func(c *irc.Client, e irc.Event) {
if e.Params[1] == client.GetNick() {
c.Cmd.Join(e.Params[0])
}
})
for eventcode, callback := range params.Callbacks {
conn.AddCallback(eventcode, callback)
client.Handlers.Add(eventcode, callback)
}
err := conn.Connect(v.connConfig.Server)
if err != nil {
return fmt.Errorf("error opening irc connection: %w", err)
}
go func() {
err := client.Connect()
if err != nil {
println("error opening irc connection: %w", err)
}
}()
v.uidToConns[params.UID] = conn
go conn.Loop()
v.uidToConns[params.UID] = client
return nil
}
@ -133,9 +138,8 @@ type QuitParams struct {
func (v *Varys) QuitIfConnected(params QuitParams, _ *struct{}) error {
if conn, ok := v.uidToConns[params.UID]; ok {
if conn.Connected() {
conn.QuitMessage = params.QuitMessage
conn.Quit()
if conn.IsConnected() {
conn.Quit(params.QuitMessage)
}
}
delete(v.uidToConns, params.UID)
@ -153,12 +157,12 @@ type SendRawParams struct {
}
func (v *Varys) SendRaw(params SendRawParams, _ *struct{}) error {
v.connCall(params.UID, func(c *irc.Connection) {
v.connCall(params.UID, func(c *irc.Client) {
for _, msg := range params.Messages {
if params.Interpolation.Nick {
msg = strings.ReplaceAll(msg, "${NICK}", c.GetNick())
}
c.SendRaw(msg)
c.Cmd.SendRaw(msg)
}
})
return nil
@ -173,7 +177,7 @@ func (v *Varys) GetNick(uid string, result *string) error {
func (v *Varys) Connected(uid string, result *bool) error {
if conn, ok := v.uidToConns[uid]; ok {
*result = conn.Connected()
*result = conn.IsConnected()
}
return nil
@ -186,7 +190,7 @@ type NickParams struct {
func (v *Varys) Nick(params NickParams, _ *struct{}) error {
if conn, ok := v.uidToConns[params.UID]; ok {
conn.Nick(params.Nick)
conn.Cmd.Nick(params.Nick)
}
return nil
}

View File

@ -13,10 +13,11 @@ import (
"github.com/fsnotify/fsnotify"
"github.com/gobwas/glob"
"github.com/pkg/errors"
"github.com/qaisjp/go-discord-irc/bridge"
ircnick "github.com/qaisjp/go-discord-irc/irc/nick"
log "github.com/sirupsen/logrus"
"github.com/spf13/viper"
"github.com/qaisjp/go-discord-irc/bridge"
ircnick "github.com/qaisjp/go-discord-irc/irc/nick"
)
func main() {
@ -97,9 +98,6 @@ func main() {
*insecure = viper.GetBool("insecure")
}
//
viper.SetDefault("irc_puppet_prejoin_commands", []string{"MODE ${NICK} +D"})
ircPuppetPrejoinCommands := viper.GetStringSlice("irc_puppet_prejoin_commands") // Commands for each connection to send before joining channels
//
viper.SetDefault("avatar_url", "https://robohash.org/${USERNAME}.png?set=set4")
avatarURL := viper.GetString("avatar_url")
//
@ -153,7 +151,6 @@ func main() {
IRCListenerName: ircUsername,
IRCServer: ircServer,
IRCServerPass: ircPassword,
IRCPuppetPrejoinCommands: ircPuppetPrejoinCommands,
IRCListenerPrejoinCommands: ircListenerPrejoinCommands,
ConnectionLimit: connectionLimit,
IRCIgnores: matchers,