aboutsummaryrefslogtreecommitdiff
path: root/account.go
diff options
context:
space:
mode:
Diffstat (limited to 'account.go')
-rw-r--r--account.go331
1 files changed, 331 insertions, 0 deletions
diff --git a/account.go b/account.go
new file mode 100644
index 0000000..8da6d44
--- /dev/null
+++ b/account.go
@@ -0,0 +1,331 @@
+package main
+
+import (
+ "fmt"
+ "strings"
+
+ log "github.com/sirupsen/logrus"
+
+ . "git.deuxfleurs.fr/Deuxfleurs/easybridge/connector"
+)
+
+type Account struct {
+ MatrixUser string
+ AccountName string
+ Protocol string
+ Conn Connector
+
+ JoinedRooms map[RoomID]bool
+}
+
+var registeredAccounts = map[string]map[string]*Account{}
+
+func AddAccount(a *Account) {
+ if _, ok := registeredAccounts[a.MatrixUser]; !ok {
+ registeredAccounts[a.MatrixUser] = make(map[string]*Account)
+ }
+ registeredAccounts[a.MatrixUser][a.AccountName] = a
+ ezbrSystemSendf(a.MatrixUser, "Connecting to account %s (%s)", a.AccountName, a.Protocol)
+}
+
+func FindAccount(mxUser string, name string) *Account {
+ if u, ok := registeredAccounts[mxUser]; ok {
+ if a, ok := u[name]; ok {
+ return a
+ }
+ }
+ return nil
+}
+
+func FindJoinedAccount(mxUser string, protocol string, room RoomID) *Account {
+ if u, ok := registeredAccounts[mxUser]; ok {
+ for _, acct := range u {
+ if acct.Protocol == protocol {
+ if j, ok := acct.JoinedRooms[room]; ok && j {
+ return acct
+ }
+ }
+ }
+ }
+ return nil
+}
+
+func RemoveAccount(mxUser string, name string) {
+ if u, ok := registeredAccounts[mxUser]; ok {
+ delete(u, name)
+ }
+}
+
+func (a *Account) ezbrMessagef(format string, args ...interface{}) {
+ msg := fmt.Sprintf(format, args...)
+ msg = fmt.Sprintf("%s: %s", a.Protocol, msg)
+ ezbrSystemSend(a.MatrixUser, msg)
+}
+
+// ---- Begin event handlers ----
+
+func (a *Account) Joined(roomId RoomID) {
+ err := a.joinedInternal(roomId)
+ if err != nil {
+ a.ezbrMessagef("Dropping Account.Joined %s: %s", roomId, err.Error())
+ }
+}
+
+func (a *Account) joinedInternal(roomId RoomID) error {
+ a.JoinedRooms[roomId] = true
+
+ mx_room_id, err := dbGetMxRoom(a.Protocol, roomId)
+ if err != nil {
+ return err
+ }
+
+ log.Debugf("Joined %s (%s)\n", roomId, a.MatrixUser)
+
+ err = mx.RoomInvite(mx_room_id, a.MatrixUser)
+ if err != nil && strings.Contains(err.Error(), "already in the room") {
+ err = nil
+ }
+ return err
+}
+
+// ----
+
+func (a *Account) Left(roomId RoomID) {
+ err := a.leftInternal(roomId)
+ if err != nil {
+ a.ezbrMessagef("Dropping Account.Left %s: %s", roomId, err.Error())
+ }
+}
+
+func (a *Account) leftInternal(roomId RoomID) error {
+ delete(a.JoinedRooms, roomId)
+
+ mx_room_id, err := dbGetMxRoom(a.Protocol, roomId)
+ if err != nil {
+ return err
+ }
+
+ log.Printf("Left %s (%s)\n", roomId, a.MatrixUser)
+
+ err = mx.RoomKick(mx_room_id, a.MatrixUser, fmt.Sprintf("got leave room event on %s", a.Protocol))
+ if err != nil && strings.Contains(err.Error(), "not in the room") {
+ err = nil
+ }
+ return err
+}
+
+// ----
+
+func (a *Account) UserInfoUpdated(user UserID, info *UserInfo) {
+ err := a.userInfoUpdatedInternal(user, info)
+ if err != nil {
+ a.ezbrMessagef("Dropping Account.UserInfoUpdated %s: %s", user, err.Error())
+ }
+}
+
+func (a *Account) userInfoUpdatedInternal(user UserID, info *UserInfo) error {
+ mx_user_id, err := dbGetMxUser(a.Protocol, user)
+ if err != nil {
+ return err
+ }
+
+ if info.DisplayName != "" {
+ err2 := mx.ProfileDisplayname(mx_user_id, fmt.Sprintf("%s (%s)", info.DisplayName, a.Protocol))
+ if err2 != nil {
+ err = err2
+ }
+ }
+
+ if info.Avatar != nil {
+ cache_key := fmt.Sprintf("%s/user_avatar/%s", a.Protocol, user)
+ cache_val := info.Avatar.Filename()
+ if cache_val == "" || dbCacheTestAndSet(cache_key, cache_val) {
+ err2 := mx.ProfileAvatar(mx_user_id, info.Avatar)
+ if err2 != nil {
+ err = err2
+ }
+ }
+ }
+
+ return err
+}
+
+// ----
+
+func (a *Account) RoomInfoUpdated(roomId RoomID, author UserID, info *RoomInfo) {
+ err := a.roomInfoUpdatedInternal(roomId, author, info)
+ if err != nil {
+ a.ezbrMessagef("Dropping Account.RoomInfoUpdated %s: %s", roomId, err.Error())
+ }
+}
+
+func (a *Account) roomInfoUpdatedInternal(roomId RoomID, author UserID, info *RoomInfo) error {
+ mx_room_id, err := dbGetMxRoom(a.Protocol, roomId)
+ if err != nil {
+ return err
+ }
+
+ as_mxid := ezbrMxId()
+ if len(author) > 0 {
+ mx_user_id, err2 := dbGetMxUser(a.Protocol, author)
+ if err2 == nil {
+ as_mxid = mx_user_id
+ }
+ }
+
+ if info.Topic != "" {
+ err2 := mx.RoomTopicAs(mx_room_id, info.Topic, as_mxid)
+ if err2 != nil {
+ err = err2
+ }
+ }
+
+ if info.Name != "" {
+ name := fmt.Sprintf("%s (%s)", info.Name, a.Protocol)
+ err2 := mx.RoomNameAs(mx_room_id, name, as_mxid)
+ if err2 != nil {
+ err = err2
+ }
+ }
+
+ if info.Picture != nil {
+ cache_key := fmt.Sprintf("%s/room_picture/%s", a.Protocol, roomId)
+ cache_val := info.Picture.Filename()
+ if cache_val == "" || dbCacheTestAndSet(cache_key, cache_val) {
+ err2 := mx.RoomAvatarAs(mx_room_id, info.Picture, as_mxid)
+ if err2 != nil {
+ err = err2
+ }
+ }
+ }
+
+ return err
+}
+
+// ----
+
+func (a *Account) Event(event *Event) {
+ err := a.eventInternal(event)
+ if err != nil {
+ a.ezbrMessagef("Dropping Account.Event %s %s %s: %s", event.Author, event.Recipient, event.Room, err.Error())
+ }
+}
+
+func (a *Account) eventInternal(event *Event) error {
+ // TODO: automatically ignore events that come from one of our bridged matrix users
+ // TODO: deduplicate events if we have several matrix users joined the same room (hard problem)
+
+ mx_user_id, err := dbGetMxUser(a.Protocol, event.Author)
+ if err != nil {
+ return err
+ }
+
+ if event.Type == EVENT_JOIN {
+ log.Printf("%s join %s %s", a.Protocol, event.Author, event.Room)
+ mx_room_id, err := dbGetMxRoom(a.Protocol, event.Room)
+ if err != nil {
+ return err
+ }
+
+ err = mx.RoomInvite(mx_room_id, mx_user_id)
+ if err != nil {
+ if strings.Contains(err.Error(), "already in the room") {
+ return nil
+ }
+ return err
+ }
+
+ return mx.RoomJoinAs(mx_room_id, mx_user_id)
+ } else if event.Type == EVENT_LEAVE {
+ log.Printf("%s join %s %s", a.Protocol, event.Author, event.Room)
+ mx_room_id, err := dbGetMxRoom(a.Protocol, event.Room)
+ if err != nil {
+ return err
+ }
+
+ return mx.RoomLeaveAs(mx_room_id, mx_user_id)
+ } else {
+ log.Printf("%s msg %s %s", a.Protocol, event.Author, event.Room)
+ mx_room_id := ""
+
+ if len(event.Room) > 0 {
+ mx_room_id, err = dbGetMxRoom(a.Protocol, event.Room)
+ if err != nil {
+ return err
+ }
+ } else {
+ mx_room_id, err = dbGetMxPmRoom(a.Protocol, event.Author, mx_user_id, a.MatrixUser, a.AccountName)
+ if err != nil {
+ return err
+ }
+ }
+
+ if event.Id != "" {
+ cache_key := fmt.Sprintf("%s/event_seen/%s/%s",
+ a.Protocol, mx_room_id, event.Id)
+ if !dbCacheTestAndSet(cache_key, "yes") {
+ // false: cache key was not modified, meaning we
+ // already saw the event
+ return nil
+ }
+ }
+
+ typ := "m.text"
+ if event.Type == EVENT_ACTION {
+ typ = "m.emote"
+ }
+
+ err = mx.SendMessageAs(mx_room_id, typ, event.Text, mx_user_id)
+ if err != nil {
+ return err
+ }
+
+ if event.Attachments != nil {
+ for _, file := range event.Attachments {
+ mxfile, err := mx.UploadMedia(file)
+ if err != nil {
+ return err
+ }
+ content := map[string]interface{}{
+ "body": mxfile.Filename(),
+ "filename": mxfile.Filename(),
+ "url": fmt.Sprintf("mxc://%s/%s", mxfile.MxcServer, mxfile.MxcMediaId),
+ }
+ if sz := mxfile.ImageSize(); sz != nil {
+ content["msgtype"] = "m.image"
+ content["info"] = map[string]interface{}{
+ "mimetype": mxfile.Mimetype(),
+ "size": mxfile.Size(),
+ "w": sz.Width,
+ "h": sz.Height,
+ }
+ } else {
+ content["msgtype"] = "m.file"
+ content["info"] = map[string]interface{}{
+ "mimetype": mxfile.Mimetype(),
+ "size": mxfile.Size(),
+ }
+ }
+ err = mx.SendAs(mx_room_id, "m.room.message", content, mx_user_id)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+ }
+}
+
+// ----
+
+func (a *Account) CacheGet(key string) string {
+ cache_key := fmt.Sprintf("%s/account/%s/%s/%s",
+ a.Protocol, a.MatrixUser, a.AccountName, key)
+ return dbCacheGet(cache_key)
+}
+
+func (a *Account) CachePut(key string, value string) {
+ cache_key := fmt.Sprintf("%s/account/%s/%s/%s",
+ a.Protocol, a.MatrixUser, a.AccountName, key)
+ dbCachePut(cache_key, value)
+}