diff --git a/personal/q3k/lelegram/irc/conn.go b/personal/q3k/lelegram/irc/conn.go index 5ec3c62c..88467167 100644 --- a/personal/q3k/lelegram/irc/conn.go +++ b/personal/q3k/lelegram/irc/conn.go @@ -53,7 +53,7 @@ type ircconn struct { connected int64 } -var reIRCNick = regexp.MustCompile(`[^A-Za-z0-09]`) +var reIRCNick = regexp.MustCompile(`[^A-Za-z0-9]`) // Say is called by the Manager when a message should be sent out by the // connection. @@ -74,8 +74,23 @@ type IRCMessage struct { text string } -func NewConn(server, channel, user string, backup bool, h func(e *event)) (*ircconn, error) { - glog.Infof("Connecting to IRC/%s/%s/%s...", server, channel, user) +func NewConn(server, channel, userTelegram string, backup bool, h func(e *event)) (*ircconn, error) { + // Generate IRC nick from username. + nick := reIRCNick.ReplaceAllString(userTelegram, "") + username := nick + if len(username) > 9 { + username = username[:9] + } + nick = strings.ToLower(nick) + if len(nick) > 13 { + nick = nick[:13] + } + if len(nick) == 0 { + glog.Errorf("Could not create IRC nick for %q", userTelegram) + nick = "wtf" + } + nick += "[t]" + glog.Infof("Connecting to IRC/%s/%s/%s as %s from %s...", server, channel, userTelegram, nick, username) conn, err := net.Dial("tcp", server) if err != nil { return nil, fmt.Errorf("Dial(_, %q): %v", server, err) @@ -84,7 +99,7 @@ func NewConn(server, channel, user string, backup bool, h func(e *event)) (*ircc i := &ircconn{ server: server, channel: channel, - user: user, + user: userTelegram, eventHandler: h, @@ -102,22 +117,14 @@ func NewConn(server, channel, user string, backup bool, h func(e *event)) (*ircc connected: int64(0), } - // Generate IRC nick from username. - nick := reIRCNick.ReplaceAllString(user, "") - if len(nick) > 13 { - nick = nick[:13] - } - if len(nick) == 0 { - glog.Errorf("Could not create IRC nick for %q", user) - nick = "wtf" - } - nick += "[t]" + + // Configure IRC client to populate the IRC Queue. config := irc.ClientConfig{ Nick: nick, - User: user, - Name: user, + User: username, + Name: userTelegram, Handler: irc.HandlerFunc(func(c *irc.Client, m *irc.Message) { i.iq <- m }), @@ -221,6 +228,9 @@ func (i *ircconn) loop(ctx context.Context) { glog.V(1).Infof("IRC/%s/debug: %+v", i.user, m) } + glog.V(16).Infof("irc/debug16: Message: cmd(%s), channel(%s)", m.Command, m.Params[0]) + glog.V(16).Infof("irc/debug16: Current: channel(%s), command(%s)", i.channel, "PRIVMSG") + glog.V(16).Infof("irc/debug16: Current: channel-eq(%t), command-eq(%t)", i.channel == m.Params[0], "PRIVMSG" == m.Command) switch { case m.Command == "001": glog.Infof("IRC/%s/info: joining %s...", i.user, i.channel) @@ -250,8 +260,8 @@ func (i *ircconn) loop(ctx context.Context) { glog.Infof("IRC/%s/info: got kicked", i.user) die(nil) return - - case m.Command == "PRIVMSG" && m.Params[0] == i.channel: + case m.Command == "PRIVMSG" && strings.ToLower(m.Params[0]) == i.channel: + glog.V(8).Infof("IRC/%s/debug8: received message on %s", i.user, i.channel) go i.eventHandler(&event{ message: &eventMessage{i, m.Prefix.Name, m.Params[1]}, }) diff --git a/personal/q3k/lelegram/irc/manager.go b/personal/q3k/lelegram/irc/manager.go index 4e8365d9..da1d3e38 100644 --- a/personal/q3k/lelegram/irc/manager.go +++ b/personal/q3k/lelegram/irc/manager.go @@ -24,6 +24,8 @@ import ( type Manager struct { // maximum IRC sessions to maintain max int + // IRC bot's username + login string // IRC server address server string // IRC channel name @@ -45,9 +47,10 @@ type Manager struct { runctx context.Context } -func NewManager(max int, server, channel string) *Manager { +func NewManager(max int, server, channel string, login string) *Manager { return &Manager{ max: max, + login: login, server: server, channel: channel, ctrl: make(chan *control), @@ -142,7 +145,7 @@ func (m *Manager) ensureReceiver(ctx context.Context) { if len(m.conns) == 0 { // Noone said anything on telegram, make backup glog.Infof("No receiver found, making backup") - name := "lelegram" + name := m.login c, err := m.newconn(ctx, name, true) if err != nil { glog.Errorf("Could not make backup receiver: %v", err) diff --git a/personal/q3k/lelegram/irc/manager_conns.go b/personal/q3k/lelegram/irc/manager_conns.go index 6427ec6c..b578f0d5 100644 --- a/personal/q3k/lelegram/irc/manager_conns.go +++ b/personal/q3k/lelegram/irc/manager_conns.go @@ -14,13 +14,13 @@ var ( // getconn either gets a connection by username, or creates a new one (after // evicting the least recently used connection). -func (m *Manager) getconn(ctx context.Context, user string) (*ircconn, error) { +func (m *Manager) getconn(ctx context.Context, userTelegram string) (*ircconn, error) { // Is the user shitlisted? - if t, ok := m.shitlist[user]; ok && time.Now().Before(t) { + if t, ok := m.shitlist[userTelegram]; ok && time.Now().Before(t) { return nil, errBanned } // Do we already have a connection? - c, ok := m.conns[user] + c, ok := m.conns[userTelegram] if ok { // Bump and return. c.last = time.Now() @@ -46,17 +46,17 @@ func (m *Manager) getconn(ctx context.Context, user string) (*ircconn, error) { } // Allocate new connection - return m.newconn(ctx, user, false) + return m.newconn(ctx, userTelegram, false) } // newconn creates a new IRC connection as a given user, and saves it to the // conns map. -func (m *Manager) newconn(ctx context.Context, user string, backup bool) (*ircconn, error) { - c, err := NewConn(m.server, m.channel, user, backup, m.Event) +func (m *Manager) newconn(ctx context.Context, userTelegram string, backup bool) (*ircconn, error) { + c, err := NewConn(m.server, m.channel, userTelegram, backup, m.Event) if err != nil { return nil, err } - m.conns[user] = c + m.conns[userTelegram] = c go c.Run(m.runctx) diff --git a/personal/q3k/lelegram/irc/manager_event.go b/personal/q3k/lelegram/irc/manager_event.go index 399915ca..07d978c2 100644 --- a/personal/q3k/lelegram/irc/manager_event.go +++ b/personal/q3k/lelegram/irc/manager_event.go @@ -77,8 +77,10 @@ func (m *Manager) notifyAll(n *Notification) { // doevent handles incoming events. func (m *Manager) doevent(ctx context.Context, e *event) { + glog.V(16).Infof("event/debug16: New event handling") switch { case e.nick != nil: + glog.V(8).Infof("event/debug8: nick (%s)", e.nick.nick) // Nick update from connection // Ensure this connection is still used. diff --git a/personal/q3k/lelegram/main.go b/personal/q3k/lelegram/main.go index f4360a98..9e8f9774 100644 --- a/personal/q3k/lelegram/main.go +++ b/personal/q3k/lelegram/main.go @@ -27,6 +27,7 @@ var ( flagIRCMaxConnections int flagIRCServer string flagIRCChannel string + flagIRCLogin string ) // server is responsible for briding IRC and Telegram. @@ -76,6 +77,7 @@ func main() { flag.IntVar(&flagIRCMaxConnections, "irc_max_connections", 10, "How many simulataneous connections can there be to IRC before they get recycled") flag.StringVar(&flagIRCServer, "irc_server", "chat.freenode.net:6667", "The address (with port) of the IRC server to connect to") flag.StringVar(&flagIRCChannel, "irc_channel", "", "The channel name (including hash(es)) to bridge") + flag.StringVar(&flagIRCLogin, "irc_login", "lelegram[t]", "The login of irc user used by bot") flag.Parse() if flagTelegramToken == "" { @@ -85,7 +87,10 @@ func main() { if flagIRCChannel == "" { glog.Exitf("irc_channel must be set") } - + if flagIRCLogin == "" { + flagIRCLogin = "lelegram" + } + glog.Infof("dabug: Backup login in IRC: %s", flagIRCLogin) // Parse given group ID. // If not set, start server in 'lame' mode, ie. one that will not actually // perform any bridging, but will let you figure out the IDs of groups that @@ -107,8 +112,9 @@ func main() { glog.Exitf("Listen(): %v", err) } - mgr := irc.NewManager(flagIRCMaxConnections, flagIRCServer, flagIRCChannel) - + // https://tools.ietf.org/html/rfc2812#section-1.3 "Channel names are case insensitive" + mgr := irc.NewManager(flagIRCMaxConnections, flagIRCServer, strings.ToLower(flagIRCChannel), flagIRCLogin) + glog.V(4).Infof("telegram/debug4: Linking to group: %d", groupId) s, err := newServer(groupId, mgr) if err != nil { glog.Exitf("newServer(): %v", err) @@ -140,17 +146,17 @@ func main() { func (s *server) bridge(ctx context.Context) { nickmap := make(map[string]string) for { + glog.V(32).Info("bridge/debug32: New element in queue") select { case <-ctx.Done(): return - case m := <-s.telLog: // Event from Telegram (message). Translate Telegram names into IRC names. text := m.text for t, i := range nickmap { text = strings.ReplaceAll(text, "@"+t, i) } - glog.Infof("telegram/%s: %v", m.user, text) + glog.Infof("telegram/info/%s: %v", m.user, text) // Attempt to route message to IRC twice. // This blocks until success or failure, making sure the log stays @@ -166,6 +172,7 @@ func (s *server) bridge(ctx context.Context) { cancel() case n := <-s.ircLog: + glog.V(4).Infof("bridge/irc/debug4: Get message from irc: %s", n.Message) // Notification from IRC (message or new nickmap) switch { case n.Nickmap != nil: diff --git a/personal/q3k/lelegram/telegram.go b/personal/q3k/lelegram/telegram.go index e6b673c1..7d234ffd 100644 --- a/personal/q3k/lelegram/telegram.go +++ b/personal/q3k/lelegram/telegram.go @@ -21,29 +21,31 @@ func (s *server) telegramConnection(ctx context.Context) error { if err != nil { return fmt.Errorf("GetUpdatesChan(%+v): %v", u, err) } + glog.V(8).Infof("telegram/debug8: New update") for { select { case <-ctx.Done(): return ctx.Err() - case u, ok := <-updates: + case update, ok := <-updates: if !ok { return fmt.Errorf("Updates channel closed") } // Dispatch update. switch { - case u.Message != nil: - if u.Message.Chat.ID != s.groupId { - glog.Infof("[ignored group %d] <%s> %v", u.Message.Chat.ID, u.Message.From, u.Message.Text) + case update.Message != nil: + glog.V(4).Infof("telegram/debug4: New message: %d", update.Message.Chat.ID) + if update.Message.Chat.ID != s.groupId { + glog.Infof("[ignored group %d] <%s> %v", update.Message.Chat.ID, update.Message.From, update.Message.Text) continue } - date := time.Unix(int64(u.Message.Date), 0) + date := time.Unix(int64(update.Message.Date), 0) if time.Since(date) > 2*time.Minute { - glog.Infof("[old message] <%s> %v", u.Message.From, u.Message.Text) + glog.Infof("[old message] <%s> %v", update.Message.From, update.Message.Text) continue } - if msg := plainFromTelegram(s.tel.Self.ID, &u); msg != nil { + if msg := plainFromTelegram(s.tel.Self.ID, &update); msg != nil { s.telLog <- msg } } @@ -54,6 +56,7 @@ func (s *server) telegramConnection(ctx context.Context) error { // telegramLoop maintains a telegramConnection. func (s *server) telegramLoop(ctx context.Context) { for { + glog.V(4).Info("telegram/debug4: Starting telegram connection loop") err := s.telegramConnection(ctx) if err == ctx.Err() { glog.Infof("Telegram connection closing: %v", err)