|
|
@ -15,6 +15,7 @@ func bindIRCHandlers(srv *Server, events *event.Dispatcher) { |
|
|
|
events.Bind("irc.CONNECT", HandleIRCEvent(srv, onIRCConnect)) |
|
|
|
events.Bind("irc.DISCONNECT", HandleIRCEvent(srv, onIRCDisconnect)) |
|
|
|
events.Bind("irc.PRIVMSG", HandleIRCEvent(srv, onIRCPrivmsg)) |
|
|
|
events.Bind("irc.NOTICE", HandleIRCEvent(srv, onIRCNotice)) |
|
|
|
events.Bind("irc.CTCP_ACTION", HandleIRCEvent(srv, onIRCAction)) |
|
|
|
events.Bind("irc.JOIN", HandleIRCEvent(srv, onIRCJoin)) |
|
|
|
events.Bind("irc.PART", HandleIRCEvent(srv, onIRCPart)) |
|
|
@ -23,6 +24,7 @@ func bindIRCHandlers(srv *Server, events *event.Dispatcher) { |
|
|
|
events.Bind("irc.PART", HandleIRCEvent(srv, onIRCNames)) |
|
|
|
events.Bind("irc.KICK", HandleIRCEvent(srv, onIRCNames)) |
|
|
|
events.Bind("irc.NICK", HandleIRCEvent(srv, onIRCNick)) |
|
|
|
events.Bind("irc.433", HandleIRCEvent(srv, onIRC433)) |
|
|
|
events.Bind("irc.353", HandleIRCEvent(srv, onIRC353)) |
|
|
|
events.Bind("irc.366", HandleIRCEvent(srv, onIRC366)) |
|
|
|
events.Bind("irc.QUIT", HandleIRCEvent(srv, onIRCQuit)) |
|
|
@ -39,6 +41,14 @@ func bindIRCHandlers(srv *Server, events *event.Dispatcher) { |
|
|
|
for _, code := range whoisCodes { |
|
|
|
events.Bind(code, HandleIRCEvent(srv, onIRCWhois)) |
|
|
|
} |
|
|
|
miscCodes := []string{ |
|
|
|
"irc.001", "irc.002", "irc.003", "irc.250", "irc.251", |
|
|
|
"irc.252", "irc.253", "irc.254", "irc.255", "irc.265", |
|
|
|
"irc.266", "irc.375", "irc.372", "irc.376", |
|
|
|
} |
|
|
|
for _, code := range miscCodes { |
|
|
|
events.Bind(code, HandleIRCEvent(srv, onIRCMessage)) |
|
|
|
} |
|
|
|
events.Bind("debug.IRC", event.HandlerFunc(handleIRCDebugEvent)) |
|
|
|
} |
|
|
|
|
|
|
@ -76,20 +86,43 @@ func normalizeDebugEvent(ev *event.Event) *IRCEvent { |
|
|
|
} |
|
|
|
|
|
|
|
var debugIgnore = map[string]struct{}{ |
|
|
|
"PRIVMSG": {}, |
|
|
|
"CTCP_ACTION": {}, |
|
|
|
"TOPIC": {}, |
|
|
|
"MODE": {}, |
|
|
|
"KICK": {}, |
|
|
|
"NICK": {}, |
|
|
|
"QUIT": {}, |
|
|
|
"JOIN": {}, |
|
|
|
"PART": {}, |
|
|
|
"366": {}, |
|
|
|
"353": {}, |
|
|
|
"324": {}, |
|
|
|
"331": {}, |
|
|
|
"332": {}, |
|
|
|
"CTCP_ACTION": {}, |
|
|
|
"CTCP_TIME": {}, |
|
|
|
"CTCP_VERSION": {}, |
|
|
|
"CTCP_USERINFO": {}, |
|
|
|
"CTCP_CLIENTINFO": {}, |
|
|
|
"CTCP_PING": {}, |
|
|
|
|
|
|
|
"PRIVMSG": {}, |
|
|
|
"NOTICE": {}, |
|
|
|
"TOPIC": {}, |
|
|
|
"MODE": {}, |
|
|
|
"KICK": {}, |
|
|
|
"NICK": {}, |
|
|
|
"QUIT": {}, |
|
|
|
"JOIN": {}, |
|
|
|
"PART": {}, |
|
|
|
|
|
|
|
"366": {}, |
|
|
|
"353": {}, |
|
|
|
"324": {}, |
|
|
|
"331": {}, |
|
|
|
"332": {}, |
|
|
|
"001": {}, |
|
|
|
"002": {}, |
|
|
|
"003": {}, |
|
|
|
"251": {}, |
|
|
|
"252": {}, |
|
|
|
"253": {}, |
|
|
|
"254": {}, |
|
|
|
"255": {}, |
|
|
|
"250": {}, |
|
|
|
"265": {}, |
|
|
|
"266": {}, |
|
|
|
"375": {}, |
|
|
|
"372": {}, |
|
|
|
"376": {}, |
|
|
|
"433": {}, |
|
|
|
} |
|
|
|
|
|
|
|
func handleIRCDebugEvent(ev *event.Event) { |
|
|
@ -97,7 +130,7 @@ func handleIRCDebugEvent(ev *event.Event) { |
|
|
|
if _, ok := debugIgnore[nev.Code]; ok { |
|
|
|
return |
|
|
|
} |
|
|
|
logrus.Debugf("irc.%s - %s => %s", nev.Code, nev.Target, strings.Join(nev.Args[1:], " ")) |
|
|
|
logrus.Debugf("irc.%s - T(%s) N(%s) => %s", nev.Code, nev.Target, nev.Nick, strings.Join(nev.Args[1:], " ")) |
|
|
|
} |
|
|
|
|
|
|
|
func NormalizeIRCEvent(ev *event.Event) *IRCEvent { |
|
|
@ -128,7 +161,7 @@ func HandleIRCEvent(srv *Server, h IRCEventHandler) event.Handler { |
|
|
|
|
|
|
|
func onIRC324(srv *Server, ev *IRCEvent) { |
|
|
|
modes := strings.Join(ev.Args[2:], " ") |
|
|
|
win := srv.WindowManager.Named(ev.Args[1]) |
|
|
|
win := srv.wm.Named(ev.Args[1]) |
|
|
|
blankBefore := false |
|
|
|
if ch, ok := win.(*Channel); ok { |
|
|
|
ch.mu.Lock() |
|
|
@ -150,7 +183,7 @@ func onIRC324(srv *Server, ev *IRCEvent) { |
|
|
|
|
|
|
|
func onIRC331(srv *Server, ev *IRCEvent) { |
|
|
|
target := ev.Args[1] |
|
|
|
win := srv.WindowManager.Named(target) |
|
|
|
win := srv.wm.Named(target) |
|
|
|
if ch, ok := win.(*Channel); ok { |
|
|
|
ch.mu.Lock() |
|
|
|
ch.topic = "" |
|
|
@ -161,7 +194,7 @@ func onIRC331(srv *Server, ev *IRCEvent) { |
|
|
|
|
|
|
|
func onIRC332(srv *Server, ev *IRCEvent) { |
|
|
|
target := ev.Args[1] |
|
|
|
win := srv.WindowManager.Named(target) |
|
|
|
win := srv.wm.Named(target) |
|
|
|
if ch, ok := win.(*Channel); ok { |
|
|
|
topic := strings.Join(ev.Args[2:], " ") |
|
|
|
ch.mu.Lock() |
|
|
@ -173,9 +206,7 @@ func onIRC332(srv *Server, ev *IRCEvent) { |
|
|
|
|
|
|
|
func onIRCConnect(srv *Server, _ *IRCEvent) { |
|
|
|
srv.IRCDoAsync(func(conn *irc.Connection) error { |
|
|
|
srv.mu.Lock() |
|
|
|
defer srv.mu.Unlock() |
|
|
|
srv.currentNick = conn.GetNick() |
|
|
|
srv.setCurrentNick(conn.GetNick()) |
|
|
|
conn.AddCallback("*", func(ev *irc2.Event) { |
|
|
|
srv.events.Emit("debug.IRC", map[string]interface{}{ |
|
|
|
"source": ev, |
|
|
@ -187,25 +218,24 @@ func onIRCConnect(srv *Server, _ *IRCEvent) { |
|
|
|
|
|
|
|
func onIRCDisconnect(srv *Server, _ *IRCEvent) { |
|
|
|
logrus.Infoln("*** Disconnected") |
|
|
|
srv.mu.Lock() |
|
|
|
defer srv.mu.Unlock() |
|
|
|
srv.currentNick = "" |
|
|
|
srv.setCurrentNick("") |
|
|
|
} |
|
|
|
|
|
|
|
func onIRCMode(srv *Server, ev *IRCEvent) { |
|
|
|
target := ev.Target |
|
|
|
nick := SomeNick(ev.Nick) |
|
|
|
mode := strings.Join(ev.Args[1:], " ") |
|
|
|
srv.mu.RLock() |
|
|
|
if ev.Nick == srv.currentNick { |
|
|
|
currNick := srv.CurrentNick() |
|
|
|
if ev.Nick == currNick { |
|
|
|
nick.me = true |
|
|
|
} else if target == currNick { |
|
|
|
nick = MyNick(target) |
|
|
|
} |
|
|
|
srv.mu.RUnlock() |
|
|
|
win := srv.WindowManager.Named(target) |
|
|
|
win := srv.wm.Named(target) |
|
|
|
if win != nil { |
|
|
|
WriteMode(win, nick, mode) |
|
|
|
} else { |
|
|
|
WriteMode(srv.WindowManager.Index(0), nick, mode) |
|
|
|
WriteMode(srv.wm.Index(0), nick, mode) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -213,12 +243,10 @@ func onIRCTopic(srv *Server, ev *IRCEvent) { |
|
|
|
target := ev.Target |
|
|
|
nick := SomeNick(ev.Nick) |
|
|
|
topic := strings.Join(ev.Args[1:], " ") |
|
|
|
srv.mu.RLock() |
|
|
|
if ev.Nick == srv.currentNick { |
|
|
|
if ev.Nick == srv.CurrentNick() { |
|
|
|
nick.me = true |
|
|
|
} |
|
|
|
srv.mu.RUnlock() |
|
|
|
win := srv.WindowManager.Named(target) |
|
|
|
win := srv.wm.Named(target) |
|
|
|
if win != nil { |
|
|
|
WriteTopic(win, nick, topic) |
|
|
|
} else { |
|
|
@ -226,26 +254,30 @@ func onIRCTopic(srv *Server, ev *IRCEvent) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func onIRC433(srv *Server, _ *IRCEvent) { |
|
|
|
srv.IRCDoAsync(func(conn *irc.Connection) error { |
|
|
|
srv.setCurrentNick(conn.GetNick()) |
|
|
|
return nil |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
func onIRCNick(srv *Server, ev *IRCEvent) { |
|
|
|
nick := SomeNick(ev.Nick) |
|
|
|
newNick := ev.Message |
|
|
|
srv.mu.Lock() |
|
|
|
if ev.Nick == srv.currentNick { |
|
|
|
newNick := SomeNick(ev.Message) |
|
|
|
if ev.Nick == srv.CurrentNick() { |
|
|
|
nick.me = true |
|
|
|
srv.currentNick = newNick |
|
|
|
newNick.me = true |
|
|
|
srv.setCurrentNick(newNick.string) |
|
|
|
} |
|
|
|
srv.mu.Unlock() |
|
|
|
WriteNick(srv.WindowManager, nick, newNick) |
|
|
|
WriteNick(srv.wm, nick, newNick) |
|
|
|
} |
|
|
|
|
|
|
|
func onIRCKick(srv *Server, ev *IRCEvent) { |
|
|
|
channel := ev.Target |
|
|
|
kicked := SomeNick(ev.Args[1]) |
|
|
|
srv.mu.RLock() |
|
|
|
if kicked.string == srv.currentNick { |
|
|
|
if kicked.string == srv.CurrentNick() { |
|
|
|
kicked.me = true |
|
|
|
} |
|
|
|
srv.mu.RUnlock() |
|
|
|
if kicked.me { |
|
|
|
go func() { |
|
|
|
<-time.After(2 * time.Second) |
|
|
@ -257,7 +289,7 @@ func onIRCKick(srv *Server, ev *IRCEvent) { |
|
|
|
} |
|
|
|
}() |
|
|
|
} |
|
|
|
win := srv.WindowManager.Named(channel) |
|
|
|
win := srv.wm.Named(channel) |
|
|
|
if win == nil { |
|
|
|
logrus.Errorln("received kick with no Window:", channel, ev.Message, ev.Nick) |
|
|
|
return |
|
|
@ -277,7 +309,7 @@ func onIRC353(srv *Server, ev *IRCEvent) { |
|
|
|
// NAMES
|
|
|
|
chanName := ev.Args[2] |
|
|
|
nicks := strings.Split(ev.Args[3], " ") |
|
|
|
win := srv.WindowManager.Named(chanName) |
|
|
|
win := srv.wm.Named(chanName) |
|
|
|
if win == nil { |
|
|
|
logrus.Warnln("received NAMES for channel with no window:", chanName) |
|
|
|
return |
|
|
@ -290,7 +322,7 @@ func onIRC353(srv *Server, ev *IRCEvent) { |
|
|
|
func onIRC366(srv *Server, ev *IRCEvent) { |
|
|
|
// END NAMES
|
|
|
|
chanName := ev.Args[1] |
|
|
|
win := srv.WindowManager.Named(chanName) |
|
|
|
win := srv.wm.Named(chanName) |
|
|
|
if win == nil { |
|
|
|
logrus.Warnln("received END NAMES for channel with no window:", chanName) |
|
|
|
return |
|
|
@ -304,7 +336,7 @@ func onIRC366(srv *Server, ev *IRCEvent) { |
|
|
|
defer namesCache.Unlock() |
|
|
|
ch.SetUsers(namesCache.values[chanName]) |
|
|
|
delete(namesCache.values, chanName) |
|
|
|
srv.WindowManager.events.Emit("ui.DIRTY", nil) |
|
|
|
srv.wm.events.Emit("ui.DIRTY", nil) |
|
|
|
} |
|
|
|
|
|
|
|
func onIRCError(srv *Server, ev *IRCEvent) { |
|
|
@ -314,22 +346,25 @@ func onIRCError(srv *Server, ev *IRCEvent) { |
|
|
|
} else { |
|
|
|
kind = ev.Target |
|
|
|
} |
|
|
|
win := srv.WindowManager.Named(kind) |
|
|
|
win := srv.wm.Named(kind) |
|
|
|
WriteError(win, kind, ev.Message) |
|
|
|
} |
|
|
|
|
|
|
|
func onIRCWhois(srv *Server, ev *IRCEvent) { |
|
|
|
nick := ev.Args[1] |
|
|
|
data := ev.Args[2:] |
|
|
|
win := srv.WindowManager.Named(nick) |
|
|
|
win := srv.wm.Named(nick) |
|
|
|
WriteWhois(win, nick, data) |
|
|
|
} |
|
|
|
|
|
|
|
func onIRCMessage(srv *Server, ev *IRCEvent) { |
|
|
|
win := srv.wm.Index(0) |
|
|
|
WriteMessage(win, strings.Join(ev.Args[1:], " ")) |
|
|
|
} |
|
|
|
|
|
|
|
func onIRCNames(srv *Server, ev *IRCEvent) { |
|
|
|
if ev.Code == "PART" || ev.Code == "KICK" { |
|
|
|
srv.mu.RLock() |
|
|
|
myNick := srv.currentNick |
|
|
|
srv.mu.RUnlock() |
|
|
|
myNick := srv.CurrentNick() |
|
|
|
if ev.Nick == myNick { |
|
|
|
// dont bother trying to get names when we are the one leaving
|
|
|
|
return |
|
|
@ -346,23 +381,21 @@ func onIRCNames(srv *Server, ev *IRCEvent) { |
|
|
|
|
|
|
|
func onIRCJoin(srv *Server, ev *IRCEvent) { |
|
|
|
target := ev.Target |
|
|
|
win := srv.WindowManager.Named(target) |
|
|
|
win := srv.wm.Named(target) |
|
|
|
nick := SomeNick(ev.Nick) |
|
|
|
srv.mu.RLock() |
|
|
|
if ev.Nick == srv.currentNick { |
|
|
|
if ev.Nick == srv.CurrentNick() { |
|
|
|
nick.me = true |
|
|
|
} |
|
|
|
srv.mu.RUnlock() |
|
|
|
if win == nil { |
|
|
|
ch := &Channel{ |
|
|
|
bufferedWindow: newBufferedWindow(target, srv.events), |
|
|
|
users: []User{}, |
|
|
|
usersIndexed: make(map[string]int), |
|
|
|
} |
|
|
|
srv.WindowManager.Append(ch) |
|
|
|
srv.wm.Append(ch) |
|
|
|
win = ch |
|
|
|
if nick.me { |
|
|
|
srv.WindowManager.SelectIndex(srv.WindowManager.Len() - 1) |
|
|
|
srv.wm.SelectIndex(srv.wm.Len() - 1) |
|
|
|
modeChange(srv, []string{"mode"}) |
|
|
|
} |
|
|
|
} |
|
|
@ -375,12 +408,10 @@ func onIRCJoin(srv *Server, ev *IRCEvent) { |
|
|
|
func onIRCPart(srv *Server, ev *IRCEvent) { |
|
|
|
target := ev.Target |
|
|
|
nick := SomeNick(ev.Nick) |
|
|
|
win := srv.WindowManager.Named(target) |
|
|
|
srv.mu.RLock() |
|
|
|
if ev.Nick == srv.currentNick { |
|
|
|
win := srv.wm.Named(target) |
|
|
|
if ev.Nick == srv.CurrentNick() { |
|
|
|
nick.me = true |
|
|
|
} |
|
|
|
srv.mu.RUnlock() |
|
|
|
if win == nil { |
|
|
|
if !nick.me { |
|
|
|
// dont bother logging if we are the ones leaving
|
|
|
@ -398,22 +429,20 @@ func onIRCAction(srv *Server, ev *IRCEvent) { |
|
|
|
direct := false |
|
|
|
target := ev.Target |
|
|
|
nick := ev.Nick |
|
|
|
srv.mu.RLock() |
|
|
|
myNick := MyNick(srv.currentNick) |
|
|
|
srv.mu.RUnlock() |
|
|
|
myNick := MyNick(srv.CurrentNick()) |
|
|
|
if target == myNick.string { |
|
|
|
// its a direct message!
|
|
|
|
direct = true |
|
|
|
target = nick |
|
|
|
} |
|
|
|
win := srv.WindowManager.Named(target) |
|
|
|
win := srv.wm.Named(target) |
|
|
|
if win == nil { |
|
|
|
if !direct { |
|
|
|
logrus.Warnln("received action message with no Window:", target, ev.Message, nick) |
|
|
|
return |
|
|
|
} else { |
|
|
|
ch := &DirectMessage{bufferedWindow: newBufferedWindow(target, srv.events)} |
|
|
|
srv.WindowManager.Append(ch) |
|
|
|
srv.wm.Append(ch) |
|
|
|
win = ch |
|
|
|
} |
|
|
|
} |
|
|
@ -425,22 +454,20 @@ func onIRCPrivmsg(srv *Server, ev *IRCEvent) { |
|
|
|
direct := false |
|
|
|
target := ev.Target |
|
|
|
nick := ev.Nick |
|
|
|
srv.mu.RLock() |
|
|
|
myNick := MyNick(srv.currentNick) |
|
|
|
srv.mu.RUnlock() |
|
|
|
myNick := MyNick(srv.CurrentNick()) |
|
|
|
if target == myNick.string { |
|
|
|
// its a direct message!
|
|
|
|
direct = true |
|
|
|
target = nick |
|
|
|
} |
|
|
|
win := srv.WindowManager.Named(target) |
|
|
|
win := srv.wm.Named(target) |
|
|
|
if win == nil { |
|
|
|
if !direct { |
|
|
|
logrus.Warnln("received message with no Window:", target, ev.Message, nick) |
|
|
|
return |
|
|
|
} else { |
|
|
|
ch := &DirectMessage{bufferedWindow: newBufferedWindow(target, srv.events)} |
|
|
|
srv.WindowManager.Append(ch) |
|
|
|
srv.wm.Append(ch) |
|
|
|
win = ch |
|
|
|
} |
|
|
|
} |
|
|
@ -448,13 +475,33 @@ func onIRCPrivmsg(srv *Server, ev *IRCEvent) { |
|
|
|
WritePrivmsg(win, SomeNick(nick), msg) |
|
|
|
} |
|
|
|
|
|
|
|
func onIRCNotice(srv *Server, ev *IRCEvent) { |
|
|
|
me := srv.CurrentNick() |
|
|
|
target := SomeTarget(ev.Target, me) |
|
|
|
// "*" is used by at least Freenode when you don't yet have a nick.
|
|
|
|
if target.string == "*" { |
|
|
|
target.me = true |
|
|
|
} |
|
|
|
if target.me { |
|
|
|
target = SomeTarget(ev.Nick, me) |
|
|
|
} |
|
|
|
win := srv.wm.Named(target.string) |
|
|
|
if win == nil { |
|
|
|
win = srv.wm.Index(0) |
|
|
|
} |
|
|
|
|
|
|
|
if strings.Contains(ev.Message, "\x01") { |
|
|
|
WriteCTCP(win, target, false, ev.Message) |
|
|
|
return |
|
|
|
} |
|
|
|
WriteNotice(win, target, false, ev.Message) |
|
|
|
} |
|
|
|
|
|
|
|
func onIRCQuit(srv *Server, ev *IRCEvent) { |
|
|
|
nick := SomeNick(ev.Nick) |
|
|
|
message := ev.Message |
|
|
|
srv.mu.RLock() |
|
|
|
if ev.Nick == srv.currentNick { |
|
|
|
nick = MyNick(srv.currentNick) |
|
|
|
if ev.Nick == srv.CurrentNick() { |
|
|
|
nick.me = true |
|
|
|
} |
|
|
|
srv.mu.RUnlock() |
|
|
|
WriteQuit(srv.WindowManager, nick, message) |
|
|
|
WriteQuit(srv.wm, nick, message) |
|
|
|
} |