123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- package bridge
- import (
- "strings"
- "maunium.net/go/maulogger/v2"
- "maunium.net/go/mautrix"
- "maunium.net/go/mautrix/appservice"
- "maunium.net/go/mautrix/event"
- "maunium.net/go/mautrix/format"
- "maunium.net/go/mautrix/id"
- )
- type matrixHandler struct {
- as *appservice.AppService
- bridge *Bridge
- log maulogger.Logger
- cmd *commandHandler
- }
- func (b *Bridge) setupEvents() {
- b.eventProcessor = appservice.NewEventProcessor(b.as)
- b.matrixHandler = &matrixHandler{
- as: b.as,
- bridge: b,
- log: b.log.Sub("Matrix"),
- cmd: newCommandHandler(b),
- }
- b.eventProcessor.On(event.EventMessage, b.matrixHandler.handleMessage)
- b.eventProcessor.On(event.StateMember, b.matrixHandler.handleMembership)
- }
- func (mh *matrixHandler) join(evt *event.Event, intent *appservice.IntentAPI) *mautrix.RespJoinedMembers {
- resp, err := intent.JoinRoomByID(evt.RoomID)
- if err != nil {
- mh.log.Debugfln("Failed to join room %s as %s with invite from %s: %v", evt.RoomID, intent.UserID, evt.Sender, err)
- return nil
- }
- members, err := intent.JoinedMembers(resp.RoomID)
- if err != nil {
- intent.LeaveRoom(resp.RoomID)
- mh.log.Debugfln("Failed to get members in room %s after accepting invite from %s as %s: %v", resp.RoomID, evt.Sender, intent.UserID, err)
- return nil
- }
- if len(members.Joined) < 2 {
- intent.LeaveRoom(resp.RoomID)
- mh.log.Debugln("Leaving empty room", resp.RoomID, "after accepting invite from", evt.Sender, "as", intent.UserID)
- return nil
- }
- return members
- }
- func (mh *matrixHandler) ignoreEvent(evt *event.Event) bool {
- return false
- }
- func (mh *matrixHandler) handleMessage(evt *event.Event) {
- if mh.ignoreEvent(evt) {
- return
- }
- user := mh.bridge.GetUserByMXID(evt.Sender)
- if user == nil {
- return
- }
- content := evt.Content.AsMessage()
- content.RemoveReplyFallback()
- if content.MsgType == event.MsgText {
- prefix := mh.bridge.config.Bridge.CommandPrefix
- hasPrefix := strings.HasPrefix(content.Body, prefix)
- if hasPrefix {
- content.Body = strings.TrimLeft(content.Body[len(prefix):], " ")
- }
- if hasPrefix || evt.RoomID == user.ManagementRoom {
- mh.cmd.handle(evt.RoomID, user, content.Body, content.GetReplyTo())
- return
- }
- }
- }
- func (mh *matrixHandler) joinAndCheckMembers(evt *event.Event, intent *appservice.IntentAPI) *mautrix.RespJoinedMembers {
- resp, err := intent.JoinRoomByID(evt.RoomID)
- if err != nil {
- mh.log.Debugfln("Failed to join room %q as %q with invite from %q: %v", evt.RoomID, intent.UserID, evt.Sender, err)
- return nil
- }
- members, err := intent.JoinedMembers(resp.RoomID)
- if err != nil {
- mh.log.Debugfln("Failed to get members in room %q with invite from %q as %q: %v", resp.RoomID, evt.Sender, intent.UserID, err)
- return nil
- }
- if len(members.Joined) < 2 {
- mh.log.Debugfln("Leaving empty room %q with invite from %q as %q", resp.RoomID, evt.Sender, intent.UserID)
- intent.LeaveRoom(resp.RoomID)
- return nil
- }
- return members
- }
- func (mh *matrixHandler) sendNoticeWithmarkdown(roomID id.RoomID, message string) (*mautrix.RespSendEvent, error) {
- intent := mh.as.BotIntent()
- content := format.RenderMarkdown(message, true, false)
- content.MsgType = event.MsgNotice
- return intent.SendMessageEvent(roomID, event.EventMessage, content)
- }
- func (mh *matrixHandler) handleBotInvite(evt *event.Event) {
- intent := mh.as.BotIntent()
- user := mh.bridge.GetUserByMXID(evt.Sender)
- if user == nil {
- return
- }
- members := mh.joinAndCheckMembers(evt, intent)
- if members == nil {
- return
- }
- // If this is a DM and the user doesn't have a management room, make this
- // the management room.
- if len(members.Joined) == 2 && (user.ManagementRoom == "" || evt.Content.AsMember().IsDirect) {
- user.SetManagementRoom(evt.RoomID)
- intent.SendNotice(user.ManagementRoom, "This room has been registered as your bridge management/status room")
- mh.log.Debugfln("%q registered as management room with %q", evt.RoomID, evt.Sender)
- }
- // Wait to send the welcome message until we're sure we're not in an empty
- // room.
- mh.sendNoticeWithmarkdown(evt.RoomID, mh.bridge.config.Bridge.ManagementRoomText.Welcome)
- if evt.RoomID == user.ManagementRoom {
- if user.HasSession() {
- mh.sendNoticeWithmarkdown(evt.RoomID, mh.bridge.config.Bridge.ManagementRoomText.Connected)
- } else {
- mh.sendNoticeWithmarkdown(evt.RoomID, mh.bridge.config.Bridge.ManagementRoomText.NotConnected)
- }
- additionalHelp := mh.bridge.config.Bridge.ManagementRoomText.AdditionalHelp
- if additionalHelp != "" {
- mh.sendNoticeWithmarkdown(evt.RoomID, additionalHelp)
- }
- }
- }
- func (mh *matrixHandler) handlePuppetInvite(evt *event.Event, inviter *User, puppet *Puppet) {
- mh.log.Warnln("handling puppet invite!")
- }
- func (mh *matrixHandler) handleMembership(evt *event.Event) {
- // Return early if we're supposed to ignore the event.
- if mh.ignoreEvent(evt) {
- return
- }
- // Grab the content of the event.
- content := evt.Content.AsMember()
- // Check if this is a new conversation from a matrix user to the bot
- if content.Membership == event.MembershipInvite && id.UserID(evt.GetStateKey()) == mh.as.BotMXID() {
- mh.handleBotInvite(evt)
- return
- }
- // Load or create a new user.
- user := mh.bridge.GetUserByMXID(evt.Sender)
- if user == nil {
- return
- }
- // Load or create a new portal.
- portal := mh.bridge.GetPortalByMXID(evt.RoomID)
- if portal == nil {
- puppet := mh.bridge.GetPuppetByMXID(id.UserID(evt.GetStateKey()))
- if content.Membership == event.MembershipInvite && puppet != nil {
- mh.handlePuppetInvite(evt, user, puppet)
- }
- mh.log.Warnln("no existing portal for", evt.RoomID)
- return
- }
- isSelf := id.UserID(evt.GetStateKey()) == evt.Sender
- // Handle matrix invites.
- if content.Membership == event.MembershipInvite && !isSelf {
- portal.HandleMatrixInvite(user, evt)
- }
- }
|