Skip to content

Commit

Permalink
Fixed private messages when sent from multiple clients (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
insomniacslk authored May 19, 2018
1 parent 6ab982a commit e30286d
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 123 deletions.
41 changes: 40 additions & 1 deletion event_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,46 @@ func eventHandler(ctx *IrcContext, rtm *slack.RTM) {
}
} else if strings.HasPrefix(ev.Msg.Channel, "D") {
// Direct message to me
channame = ctx.Nick
users, err := usersInConversation(ctx, ev.Msg.Channel)
if err != nil {
// ERR_UNKNOWNERROR
SendIrcNumeric(ctx, 400, ctx.Nick, fmt.Sprintf("Cannot get conversation info for %s", ev.Msg.Channel))
return
}
// we expect only two members in a direct message. Raise an
// error if not.
if len(users) != 2 {
// ERR_UNKNOWNERROR
SendIrcNumeric(ctx, 400, ctx.Nick, fmt.Sprintf("Exactly two users expected in direct message, got %d (conversation ID: %s)", len(users), ev.Msg.Channel))
return

}
// of the two users, one is me. Otherwise fail
if ctx.UserID() == "" {
// ERR_UNKNOWNERROR
SendIrcNumeric(ctx, 400, ctx.UserID(), "Cannot get my own user ID")
return
}
if users[0] != ctx.UserID() && users[1] != ctx.UserID() {
// ERR_UNKNOWNERROR
SendIrcNumeric(ctx, 400, ctx.UserID(), fmt.Sprintf("Got a direct message where I am not part of the members list (members: %s)", strings.Join(users, ", ")))
return
}
var recipientID string
if users[0] == ctx.UserID() {
// then it's the other user
recipientID = users[1]
} else {
recipientID = users[0]
}
// now resolve the ID to the user's nickname
nickname := ctx.GetUserInfo(recipientID)
if nickname == nil {
// ERR_UNKNOWNERROR
SendIrcNumeric(ctx, 400, ctx.UserID(), fmt.Sprintf("Unknown destination user ID %s for direct message %s", recipientID, ev.Msg.Channel))
return
}
channame = nickname.Name
} else {
log.Printf("Unknown recipient ID: %s", ev.Msg.Channel)
return
Expand Down
9 changes: 9 additions & 0 deletions irc_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@ func (ic *IrcContext) GetUserInfoByName(username string) *slack.User {
return nil
}

// UserID returns the user's Slack ID
func (ic IrcContext) UserID() string {
user := ic.GetUserInfoByName(ic.Nick)
if user == nil {
return ""
}
return user.ID
}

// Mask returns the IRC mask for the current user
func (ic IrcContext) Mask() string {
var username string
Expand Down
140 changes: 18 additions & 122 deletions irc_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,33 +106,40 @@ func IrcSendChanInfoAfterJoin(ctx *IrcContext, name, topic string, members []str
ctx.ChanMutex.Unlock()
}

// join will join the channel with the given ID, name and topic, and send back a
// response to the IRC client
func join(ctx *IrcContext, id, name, topic string) {
func usersInConversation(ctx *IrcContext, conversation string) ([]string, error) {
var (
info string
members, m []string
nextCursor string
err error
)
for {
m, nextCursor, err = ctx.SlackClient.GetUsersInConversation(&slack.GetUsersInConversationParameters{ChannelID: id, Cursor: nextCursor})
m, nextCursor, err = ctx.SlackClient.GetUsersInConversation(&slack.GetUsersInConversationParameters{ChannelID: conversation, Cursor: nextCursor})
if err != nil {
log.Printf("Cannot get member list for channel %s: %v", name, err)
break
return nil, fmt.Errorf("Cannot get member list for conversation %s: %v", conversation, err)
}
members = append(members, m...)
log.Printf(" nextCursor=%v", nextCursor)
if nextCursor == "" {
break
}
}
info = "(joined) "
return members, nil
}

// join will join the channel with the given ID, name and topic, and send back a
// response to the IRC client
func join(ctx *IrcContext, id, name, topic string) error {
members, err := usersInConversation(ctx, id)
if err != nil {
return err
}
info := "(joined) "
info += fmt.Sprintf(" topic=%s members=%d", topic, len(members))
log.Printf(info)
// the channels are already joined, notify the IRC client of their
// existence
go IrcSendChanInfoAfterJoin(ctx, name, topic, members, false)
return nil
}

// joinChannels gets all the available Slack channels and sends an IRC JOIN message
Expand All @@ -156,7 +163,9 @@ func joinChannels(ctx *IrcContext) error {
}
for _, ch := range channels {
if ch.IsMember {
join(ctx, ch.ID, ch.Name, ch.Topic.Value)
if err := join(ctx, ch.ID, ch.Name, ch.Topic.Value); err != nil {
return err
}
}
}
return nil
Expand Down Expand Up @@ -184,119 +193,6 @@ func IrcAfterLoggingIn(ctx *IrcContext, rtm *slack.RTM) error {
}

go eventHandler(ctx, rtm)
/*
go func(rtm *slack.RTM) {
log.Print("Started Slack event listener")
for msg := range rtm.IncomingEvents {
switch ev := msg.Data.(type) {
case *slack.MessageEvent:
// get user
var name string
user := ctx.GetUserInfo(ev.Msg.User)
if user == nil {
log.Printf("Error getting user info for %v", ev.Msg.User)
name = ev.Msg.User
} else {
name = user.Name
}
// get channel or other recipient (e.g. recipient of a direct message)
var channame string
if strings.HasPrefix(ev.Msg.Channel, "C") {
// Channel message
// TODO cache channel info
channel, err := ctx.SlackClient.GetChannelInfo(ev.Msg.Channel)
if err != nil {
log.Printf("Error getting channel info for %v: %v", ev.Msg.Channel, err)
channame = "unknown"
} else {
channame = "#" + channel.Name
}
} else if strings.HasPrefix(ev.Msg.Channel, "D") {
// Direct message to me
channame = ctx.Nick
} else {
log.Printf("Unknown recipient ID: %s", ev.Msg.Channel)
return
}
log.Printf("SLACK msg from %v (%v) on %v: %v",
ev.Msg.User,
name,
ev.Msg.Channel,
ev.Msg.Text,
)
if ev.Msg.User == "" && ev.Msg.Text == "" {
log.Printf("WARNING: empty user and message: %+v", ev.Msg)
continue
}
// replace UIDs with user names
text := ev.Msg.Text
// replace UIDs with nicknames
text = rxSlackUser.ReplaceAllStringFunc(text, func(subs string) string {
uid := subs[2 : len(subs)-1]
user := ctx.GetUserInfo(uid)
if user == nil {
return subs
}
return fmt.Sprintf("@%s", user.Name)
})
// replace some HTML entities
text = ExpandText(text)
// FIXME if two instances are connected to the Slack API at the
// same time, this will hide the other instance's message
// believing it was sent from here. But since it's not, both
// local echo and remote message won't be shown
botID := msg.Data.(*slack.MessageEvent).BotID
if name == ctx.Nick && botID != user.Profile.BotID {
// don't print my own messages
continue
}
// handle multi-line messages
for _, line := range strings.Split(text, "\n") {
privmsg := fmt.Sprintf(":%v!%v@%v PRIVMSG %v :%v\r\n",
name, ev.Msg.User, ctx.ServerName,
channame, line,
)
log.Print(privmsg)
ctx.Conn.Write([]byte(privmsg))
}
msgEv := msg.Data.(*slack.MessageEvent)
// Check if the topic has changed
if msgEv.Topic != ctx.Channels[msgEv.Channel].Topic {
// Send out new topic
channel, err := ctx.SlackClient.GetChannelInfo(msgEv.Channel)
if err != nil {
log.Printf("Cannot get channel name for %v", msgEv.Channel)
} else {
newTopic := fmt.Sprintf(":%v TOPIC #%v :%v\r\n", ctx.Mask(), channel.Name, msgEv.Topic)
log.Printf("Got new topic: %v", newTopic)
ctx.Conn.Write([]byte(newTopic))
}
}
// check if new people joined the channel
added, removed := ctx.Channels[msgEv.Channel].MembersDiff(msgEv.Members)
if len(added) > 0 || len(removed) > 0 {
log.Printf("[*] People who joined: %v", added)
log.Printf("[*] People who left: %v", removed)
}
case *slack.ConnectedEvent:
log.Print("Connected to Slack")
ctx.SlackConnected = true
case *slack.DisconnectedEvent:
log.Printf("Disconnected from Slack (intentional: %v)", msg.Data.(*slack.DisconnectedEvent).Intentional)
ctx.SlackConnected = false
ctx.Conn.Close()
case *slack.MemberJoinedChannelEvent, *slack.MemberLeftChannelEvent:
// refresh the users list
// FIXME also send a JOIN / PART message to the IRC client
ctx.GetUsers(true)
default:
log.Printf("SLACK event: %v: %v", msg.Type, msg.Data)
}
}
}(rtm)
*/
return nil
}

Expand Down

0 comments on commit e30286d

Please sign in to comment.