kinda
This commit is contained in:
		| @@ -22,8 +22,7 @@ import ( | ||||
| 	"strings" | ||||
| 	"text/template" | ||||
|  | ||||
| 	"github.com/Rhymen/go-whatsapp" | ||||
|  | ||||
| 	"github.com/karmanyaahm/groupme" | ||||
| 	"maunium.net/go/mautrix/event" | ||||
| 	"maunium.net/go/mautrix/id" | ||||
|  | ||||
| @@ -158,19 +157,19 @@ type UsernameTemplateArgs struct { | ||||
| 	UserID id.UserID | ||||
| } | ||||
|  | ||||
| func (bc BridgeConfig) FormatDisplayname(contact whatsapp.Contact) (string, int8) { | ||||
| func (bc BridgeConfig) FormatDisplayname(contact groupme.User) (string, int8) { | ||||
| 	var buf bytes.Buffer | ||||
| 	if index := strings.IndexRune(contact.Jid, '@'); index > 0 { | ||||
| 		contact.Jid = "+" + contact.Jid[:index] | ||||
| 	if index := strings.IndexRune(contact.ID.String(), '@'); index > 0 { | ||||
| 		contact.ID = groupme.ID("+" + contact.ID.String()[:index]) | ||||
| 	} | ||||
| 	bc.displaynameTemplate.Execute(&buf, contact) | ||||
| 	var quality int8 | ||||
| 	switch { | ||||
| 	case len(contact.Notify) > 0: | ||||
| 	case len(contact.Name) > 0: | ||||
| 		quality = 3 | ||||
| 	case len(contact.Name) > 0 || len(contact.Short) > 0: | ||||
| 	case len(contact.Name) > 0 || len(contact.Name) > 0: | ||||
| 		quality = 2 | ||||
| 	case len(contact.Jid) > 0: | ||||
| 	case len(contact.ID) > 0: | ||||
| 		quality = 1 | ||||
| 	default: | ||||
| 		quality = 0 | ||||
|   | ||||
| @@ -52,8 +52,9 @@ func New(dbType string, uri string, baseLog log.Logger) (*Database, error) { | ||||
| 	} else { | ||||
| 		conn = postgres.Open(uri) | ||||
| 	} | ||||
| 	print("no") | ||||
|  | ||||
| 	gdb, err := gorm.Open(conn, &gorm.Config{ | ||||
| 		//	Logger: logger.Default.LogMode(logger.Info), | ||||
| 		// Logger: baseLog, | ||||
| 		NamingStrategy: schema.NamingStrategy{ | ||||
| 			NameReplacer: strings.NewReplacer("JID", "Jid", "MXID", "Mxid"), | ||||
|   | ||||
| @@ -17,9 +17,9 @@ | ||||
| package database | ||||
|  | ||||
| import ( | ||||
| 	"github.com/karmanyaahm/groupme" | ||||
| 	log "maunium.net/go/maulogger/v2" | ||||
|  | ||||
| 	"maunium.net/go/mautrix-whatsapp/groupmeExt" | ||||
| 	"maunium.net/go/mautrix-whatsapp/types" | ||||
| 	"maunium.net/go/mautrix/id" | ||||
| ) | ||||
| @@ -76,12 +76,12 @@ type Message struct { | ||||
| 	db  *Database | ||||
| 	log log.Logger | ||||
|  | ||||
| 	Chat      PortalKey        `gorm:"primaryKey;embedded;embeddedPrefix:chat_"` | ||||
| 	JID       types.GroupMeID  `gorm:"primaryKey"` | ||||
| 	MXID      id.EventID       `gorm:"unique;notNull"` | ||||
| 	Sender    types.GroupMeID  `gorm:"notNull"` | ||||
| 	Timestamp uint64           `gorm:"notNull;default:0"` | ||||
| 	Content   *groupme.Message `gorm:"type:TEXT;notNull"` | ||||
| 	Chat      PortalKey           `gorm:"primaryKey;embedded;embeddedPrefix:chat_"` | ||||
| 	JID       types.GroupMeID     `gorm:"primaryKey"` | ||||
| 	MXID      id.EventID          `gorm:"unique;notNull"` | ||||
| 	Sender    types.GroupMeID     `gorm:"notNull"` | ||||
| 	Timestamp uint64              `gorm:"notNull;default:0"` | ||||
| 	Content   *groupmeExt.Message `gorm:"type:TEXT;notNull"` | ||||
|  | ||||
| 	//	Portal Portal `gorm:"foreignKey:JID;"` //`gorm:"foreignKey:Chat.Receiver,Chat.JID;references:jid,receiver;constraint:onDelete:CASCADE;"`TODO | ||||
| } | ||||
| @@ -124,13 +124,13 @@ type Message struct { | ||||
| func (msg *Message) Insert() { | ||||
| 	ans := msg.db.Create(&msg) | ||||
| 	if ans.Error != nil { | ||||
| 		//	msg.log.Warnfln("Failed to insert %s@%s: %v", msg.Chat, msg.JID, ans.Error) | ||||
| 		msg.log.Warnfln("Failed to insert %s@%s: %v", msg.Chat, msg.JID, ans.Error) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (msg *Message) Delete() { | ||||
| 	ans := msg.db.Delete(&msg) | ||||
| 	if ans.Error != nil { | ||||
| 		//	msg.log.Warnfln("Failed to delete %s@%s: %v", msg.Chat, msg.JID, ans.Error) | ||||
| 		msg.log.Warnfln("Failed to delete %s@%s: %v", msg.Chat, msg.JID, ans.Error) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -44,6 +44,10 @@ func (pq *PuppetQuery) GetAll() (puppets []*Puppet) { | ||||
| 	if ans.Error != nil || len(puppets) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	for _, puppet := range puppets { | ||||
| 		puppet.db = pq.db | ||||
| 		puppet.log = pq.log | ||||
| 	} | ||||
| 	// defer rows.Close() | ||||
| 	// for rows.Next() { | ||||
| 	// 	puppets = append(puppets, pq.New().Scan(rows)) | ||||
| @@ -57,6 +61,8 @@ func (pq *PuppetQuery) Get(jid types.GroupMeID) *Puppet { | ||||
| 	if ans.Error != nil || ans.RowsAffected == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	puppet.db = pq.db | ||||
| 	puppet.log = pq.log | ||||
| 	return &puppet | ||||
| } | ||||
|  | ||||
| @@ -66,6 +72,8 @@ func (pq *PuppetQuery) GetByCustomMXID(mxid id.UserID) *Puppet { | ||||
| 	if ans.Error != nil || ans.RowsAffected == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	puppet.db = pq.db | ||||
| 	puppet.log = pq.log | ||||
| 	return &puppet | ||||
| } | ||||
|  | ||||
| @@ -75,6 +83,10 @@ func (pq *PuppetQuery) GetAllWithCustomMXID() (puppets []*Puppet) { | ||||
| 	if ans.Error != nil || len(puppets) != 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	for _, puppet := range puppets { | ||||
| 		puppet.db = pq.db | ||||
| 		puppet.log = pq.log | ||||
| 	} | ||||
| 	// defer rows.Close() | ||||
| 	// for rows.Next() { | ||||
| 	// 	puppets = append(puppets, pq.New().Scan(rows)) | ||||
|   | ||||
| @@ -153,6 +153,8 @@ func (store *SQLStateStore) FindSharedRooms(userID id.UserID) (rooms []id.RoomID | ||||
| 	rows, err := store.db.Table("mx_user_profile").Select("room_id"). | ||||
| 		Joins("LEFT JOIN portal ON portal.mxid=mx_user_profile.room_id"). | ||||
| 		Where("user_id = ? AND portal.encrypted=true", userID).Rows() | ||||
| 	defer rows.Close() | ||||
|  | ||||
| 	if err != nil { | ||||
| 		store.log.Warnfln("Failed to query shared rooms with %s: %v", userID, err) | ||||
| 		return | ||||
| @@ -198,7 +200,7 @@ func (store *SQLStateStore) SetMembership(roomID id.RoomID, userID id.UserID, me | ||||
| 	print("weird thing 2 502650285") | ||||
| 	print(user.Membership) | ||||
|  | ||||
| 	ans := store.db.Debug().Clauses(clause.OnConflict{ | ||||
| 	ans := store.db.Clauses(clause.OnConflict{ | ||||
| 		Columns:   []clause.Column{{Name: "room_id"}, {Name: "user_id"}}, | ||||
| 		DoUpdates: clause.AssignmentColumns([]string{"membership"}), | ||||
| 	}).Create(&user) | ||||
|   | ||||
| @@ -154,8 +154,9 @@ func (user *User) UpdateLastConnection() { | ||||
| func (user *User) Update() { | ||||
| 	ans := user.db.Save(&user) | ||||
| 	if ans.Error != nil { | ||||
| 		user.log.Warnfln("Failed to update last connection ts: %v", ans.Error) | ||||
| 		user.log.Warnfln("Failed to update user: %v", ans.Error) | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| type PortalKeyWithMeta struct { | ||||
| @@ -197,6 +198,7 @@ func (user *User) SetPortalKeys(newKeys []PortalKeyWithMeta) error { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	println("portalkey transaction complete") | ||||
| 	return tx.Commit().Error | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										48
									
								
								portal.go
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								portal.go
									
									
									
									
									
								
							| @@ -288,29 +288,30 @@ func init() { | ||||
|  | ||||
| func (portal *Portal) markHandled(source *User, message *groupme.Message, mxid id.EventID) { | ||||
| 	print("handle message") | ||||
| 	// msg := portal.bridge.DB.Message.New() | ||||
| 	// msg.Chat = portal.Key | ||||
| 	// msg.JID = message.GetKey().GetId() | ||||
| 	// msg.MXID = mxid | ||||
| 	// msg.Timestamp = message.GetMessageTimestamp() | ||||
| 	// if message.GetKey().GetFromMe() { | ||||
| 	// 	msg.Sender = source.JID | ||||
| 	// } else if portal.IsPrivateChat() { | ||||
| 	// 	msg.Sender = portal.Key.JID | ||||
| 	// } else { | ||||
| 	// 	msg.Sender = message.GetKey().GetParticipant() | ||||
| 	// 	if len(msg.Sender) == 0 { | ||||
| 	// 		msg.Sender = message.GetParticipant() | ||||
| 	// 	} | ||||
| 	// } | ||||
| 	// msg.Content = message.Message | ||||
| 	// msg.Insert() | ||||
| 	msg := portal.bridge.DB.Message.New() | ||||
| 	msg.Chat = portal.Key | ||||
| 	msg.JID = message.ID.String() | ||||
| 	msg.MXID = mxid | ||||
| 	msg.Timestamp = uint64(message.CreatedAt.ToTime().Unix()) | ||||
| 	if message.UserID.String() == source.JID { | ||||
| 		msg.Sender = source.JID | ||||
| 	} else if portal.IsPrivateChat() { | ||||
| 		msg.Sender = portal.Key.JID | ||||
| 	} else { | ||||
| 		msg.Sender = message.ID.String() | ||||
| 		if len(msg.Sender) == 0 { | ||||
| 			println("AAAAAAAAAAAAAAAAAAAAAAAAAAIDK") | ||||
| 			msg.Sender = message.SenderID.String() | ||||
| 		} | ||||
| 	} | ||||
| 	msg.Content = &groupmeExt.Message{Message: *message} | ||||
| 	msg.Insert() | ||||
|  | ||||
| 	// portal.recentlyHandledLock.Lock() | ||||
| 	// index := portal.recentlyHandledIndex | ||||
| 	// portal.recentlyHandledIndex = (portal.recentlyHandledIndex + 1) % recentlyHandledLength | ||||
| 	// portal.recentlyHandledLock.Unlock() | ||||
| 	// portal.recentlyHandled[index] = msg.JID | ||||
| 	portal.recentlyHandledLock.Lock() | ||||
| 	index := portal.recentlyHandledIndex | ||||
| 	portal.recentlyHandledIndex = (portal.recentlyHandledIndex + 1) % recentlyHandledLength | ||||
| 	portal.recentlyHandledLock.Unlock() | ||||
| 	portal.recentlyHandled[index] = groupme.ID(msg.JID) | ||||
| } | ||||
|  | ||||
| func (portal *Portal) getMessageIntent(user *User, info *groupme.Message) *appservice.IntentAPI { | ||||
| @@ -703,10 +704,13 @@ func (portal *Portal) BackfillHistory(user *User, lastMessageTime uint64) error | ||||
| 	endBackfill := portal.beginBackfill() | ||||
| 	defer endBackfill() | ||||
|  | ||||
| 	println("hi") | ||||
| 	lastMessage := portal.bridge.DB.Message.GetLastInChat(portal.Key) | ||||
| 	fmt.Println(lastMessage) | ||||
| 	if lastMessage == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	println(lastMessage.Timestamp, lastMessageTime) | ||||
| 	if lastMessage.Timestamp >= lastMessageTime { | ||||
| 		portal.log.Debugln("Not backfilling: no new messages") | ||||
| 		return nil | ||||
|   | ||||
							
								
								
									
										33
									
								
								puppet.go
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								puppet.go
									
									
									
									
									
								
							| @@ -21,7 +21,7 @@ import ( | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/Rhymen/go-whatsapp" | ||||
| 	"github.com/karmanyaahm/groupme" | ||||
| 	log "maunium.net/go/maulogger/v2" | ||||
|  | ||||
| 	"maunium.net/go/mautrix/appservice" | ||||
| @@ -232,7 +232,7 @@ func (puppet *Puppet) UpdateAvatar(source *User, avatar *whatsappExt.ProfilePicI | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| func (puppet *Puppet) UpdateName(source *User, contact whatsapp.Contact) bool { | ||||
| func (puppet *Puppet) UpdateName(source *User, contact groupme.User) bool { | ||||
| 	newName, quality := puppet.bridge.Config.Bridge.FormatDisplayname(contact) | ||||
| 	if puppet.Displayname != newName && quality >= puppet.NameQuality { | ||||
| 		err := puppet.DefaultIntent().SetDisplayName(newName) | ||||
| @@ -284,20 +284,21 @@ func (puppet *Puppet) updatePortalName() { | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func (puppet *Puppet) Sync(source *User, contact whatsapp.Contact) { | ||||
| 	// err := puppet.DefaultIntent().EnsureRegistered() | ||||
| 	// if err != nil { | ||||
| 	// 	puppet.log.Errorln("Failed to ensure registered:", err) | ||||
| 	// } | ||||
| func (puppet *Puppet) Sync(source *User, contact groupme.User) { | ||||
| 	err := puppet.DefaultIntent().EnsureRegistered() | ||||
| 	if err != nil { | ||||
| 		puppet.log.Errorln("Failed to ensure registered:", err) | ||||
| 	} | ||||
|  | ||||
| 	// if contact.Jid == source.JID { | ||||
| 	// 	contact.Notify = source.Conn.Info.Pushname | ||||
| 	// } | ||||
| 	if contact.ID.String() == source.JID { | ||||
| 		//TODO What is this | ||||
| 		//		contact.Notify = source.Conn.Info.Pushname | ||||
| 	} | ||||
|  | ||||
| 	// update := false | ||||
| 	// update = puppet.UpdateName(source, contact) || update | ||||
| 	// update = puppet.UpdateAvatar(source, nil) || update | ||||
| 	// if update { | ||||
| 	// 	puppet.Update() | ||||
| 	// } | ||||
| 	update := false | ||||
| 	update = puppet.UpdateName(source, contact) || update | ||||
| 	update = puppet.UpdateAvatar(source, nil) || update | ||||
| 	if update { | ||||
| 		puppet.Update() | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										453
									
								
								user.go
									
									
									
									
									
								
							
							
						
						
									
										453
									
								
								user.go
									
									
									
									
									
								
							| @@ -18,20 +18,16 @@ package main | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	log "maunium.net/go/maulogger/v2" | ||||
|  | ||||
| 	"github.com/Rhymen/go-whatsapp" | ||||
| 	waBinary "github.com/Rhymen/go-whatsapp/binary" | ||||
| 	waProto "github.com/Rhymen/go-whatsapp/binary/proto" | ||||
|  | ||||
| 	"maunium.net/go/mautrix" | ||||
| 	"maunium.net/go/mautrix/event" | ||||
| @@ -154,10 +150,10 @@ func (bridge *Bridge) loadDBUser(dbUser *database.User, mxid *id.UserID) *User { | ||||
| } | ||||
|  | ||||
| func (user *User) GetPortals() []*Portal { | ||||
| 	user.bridge.portalsLock.Lock() | ||||
| 	keys := user.User.GetPortalKeys() | ||||
| 	portals := make([]*Portal, len(keys)) | ||||
|  | ||||
| 	user.bridge.portalsLock.Lock() | ||||
| 	for i, key := range keys { | ||||
| 		portal, ok := user.bridge.portalsByJID[key] | ||||
| 		if !ok { | ||||
| @@ -237,6 +233,7 @@ func (user *User) Connect() bool { | ||||
| 	} else if len(user.Token) == 0 { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	user.log.Debugln("Connecting to WhatsApp") | ||||
| 	timeout := time.Duration(user.bridge.Config.Bridge.ConnectionTimeout) | ||||
| 	if timeout == 0 { | ||||
| @@ -244,6 +241,7 @@ func (user *User) Connect() bool { | ||||
| 	} | ||||
| 	conn := groupme.NewPushSubscription(context.TODO()) | ||||
| 	user.Conn = &conn | ||||
| 	user.Conn.StartListening(context.TODO()) | ||||
| 	// if err != nil { | ||||
| 	// 	user.log.Errorln("Failed to connect to WhatsApp:", err) | ||||
| 	// 	user.sendMarkdownBridgeAlert("\u26a0 Failed to connect to WhatsApp server. " + | ||||
| @@ -253,7 +251,7 @@ func (user *User) Connect() bool { | ||||
| 	// user.Conn = whatsappExt.ExtendConn(conn) | ||||
| 	// _ = user.Conn.SetClientName(user.bridge.Config.WhatsApp.OSName, user.bridge.Config.WhatsApp.BrowserName, WAVersion) | ||||
| 	// user.log.Debugln("WhatsApp connection successful") | ||||
| 	// user.Conn.AddHandler(user) | ||||
| 	user.Conn.AddHandler(user) | ||||
|  | ||||
| 	//TODO: typing notification? | ||||
| 	return user.RestoreSession() | ||||
| @@ -280,7 +278,10 @@ func (user *User) RestoreSession() bool { | ||||
| 		// 	return false | ||||
| 		// } | ||||
|  | ||||
| 		user.Conn.SubscribeToUser(context.TODO(), groupme.ID(user.JID), user.Token) | ||||
| 		err := user.Conn.SubscribeToUser(context.TODO(), groupme.ID(user.JID), user.Token) | ||||
| 		if err != nil { | ||||
| 			fmt.Println(err) | ||||
| 		} | ||||
| 		//TODO: typing notifics | ||||
| 		user.ConnectionErrors = 0 | ||||
| 		//user.SetSession(&sess) | ||||
| @@ -469,12 +470,14 @@ func (user *User) intPostLogin() { | ||||
| 	defer user.syncWait.Done() | ||||
| 	user.lastReconnection = time.Now().Unix() | ||||
| 	user.Client = groupmeExt.NewClient(user.Token) | ||||
| 	myuser, err := user.Client.MyUser(context.TODO()) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) //TODO | ||||
| 	if len(user.JID) == 0 { | ||||
| 		myuser, err := user.Client.MyUser(context.TODO()) | ||||
| 		if err != nil { | ||||
| 			log.Fatal(err) //TODO | ||||
| 		} | ||||
| 		user.JID = myuser.ID.String() | ||||
| 		user.Update() | ||||
| 	} | ||||
| 	user.JID = myuser.ID.String() | ||||
| 	user.Update() | ||||
|  | ||||
| 	user.createCommunity() | ||||
| 	user.tryAutomaticDoublePuppeting() | ||||
| @@ -550,7 +553,7 @@ func (user *User) syncPortals(chatMap map[string]groupme.Group, createAll bool) | ||||
|  | ||||
| 		chats = append(chats, Chat{ | ||||
| 			Portal:          portal, | ||||
| 			LastMessageTime: uint64(time.Now().Unix()), | ||||
| 			LastMessageTime: uint64(chat.UpdatedAt.ToTime().Unix()), | ||||
| 			Group:           chat, | ||||
| 		}) | ||||
| 		var inCommunity, ok bool | ||||
| @@ -564,6 +567,7 @@ func (user *User) syncPortals(chatMap map[string]groupme.Group, createAll bool) | ||||
| 		portalKeys = append(portalKeys, database.PortalKeyWithMeta{PortalKey: portal.Key, InCommunity: inCommunity}) | ||||
| 	} | ||||
| 	user.log.Infoln("Read chat list, updating user-portal mapping") | ||||
|  | ||||
| 	err := user.SetPortalKeys(portalKeys) | ||||
| 	if err != nil { | ||||
| 		user.log.Warnln("Failed to update user-portal mapping:", err) | ||||
| @@ -793,6 +797,13 @@ func (user *User) handleMessageLoop() { | ||||
| 		select { | ||||
| 		case msg := <-user.messageOutput: | ||||
| 			user.bridge.Metrics.TrackBufferLength(user.MXID, len(user.messageOutput)) | ||||
| 			puppet := user.bridge.GetPuppetByJID(msg.data.UserID.String()) | ||||
| 			if puppet != nil { | ||||
| 				puppet.Sync(user, groupme.User{ | ||||
| 					ID:   msg.data.ID, | ||||
| 					Name: msg.data.Name, | ||||
| 				}) //TODO: add params or docs? | ||||
| 			} | ||||
| 			user.GetPortalByJID(msg.chat).messages <- msg | ||||
| 		case <-user.syncStart: | ||||
| 			user.log.Debugln("Processing of incoming messages is locked") | ||||
| @@ -804,33 +815,33 @@ func (user *User) handleMessageLoop() { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (user *User) HandleNewContact(contact whatsapp.Contact) { | ||||
| 	user.log.Debugfln("Contact message: %+v", contact) | ||||
| 	go func() { | ||||
| 		if strings.HasSuffix(contact.Jid, whatsappExt.OldUserSuffix) { | ||||
| 			contact.Jid = strings.Replace(contact.Jid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, -1) | ||||
| 		} | ||||
| 		puppet := user.bridge.GetPuppetByJID(contact.Jid) | ||||
| 		puppet.UpdateName(user, contact) | ||||
| 	}() | ||||
| } | ||||
| //func (user *User) HandleNewContact(contact whatsapp.Contact) { | ||||
| //	user.log.Debugfln("Contact message: %+v", contact) | ||||
| //	go func() { | ||||
| //		if strings.HasSuffix(contact.Jid, whatsappExt.OldUserSuffix) { | ||||
| //			contact.Jid = strings.Replace(contact.Jid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, -1) | ||||
| //		} | ||||
| //		puppet := user.bridge.GetPuppetByJID(contact.Jid) | ||||
| //		puppet.UpdateName(user, contact) | ||||
| //	}() | ||||
| //} | ||||
|  | ||||
| func (user *User) HandleBatteryMessage(battery whatsapp.BatteryMessage) { | ||||
| 	user.log.Debugfln("Battery message: %+v", battery) | ||||
| 	var notice string | ||||
| 	if !battery.Plugged && battery.Percentage < 15 && user.batteryWarningsSent < 1 { | ||||
| 		notice = fmt.Sprintf("Phone battery low (%d %% remaining)", battery.Percentage) | ||||
| 		user.batteryWarningsSent = 1 | ||||
| 	} else if !battery.Plugged && battery.Percentage < 5 && user.batteryWarningsSent < 2 { | ||||
| 		notice = fmt.Sprintf("Phone battery very low (%d %% remaining)", battery.Percentage) | ||||
| 		user.batteryWarningsSent = 2 | ||||
| 	} else if battery.Percentage > 15 || battery.Plugged { | ||||
| 		user.batteryWarningsSent = 0 | ||||
| 	} | ||||
| 	if notice != "" { | ||||
| 		go user.sendBridgeNotice("%s", notice) | ||||
| 	} | ||||
| } | ||||
| //func (user *User) HandleBatteryMessage(battery whatsapp.BatteryMessage) { | ||||
| //	user.log.Debugfln("Battery message: %+v", battery) | ||||
| //	var notice string | ||||
| //	if !battery.Plugged && battery.Percentage < 15 && user.batteryWarningsSent < 1 { | ||||
| //		notice = fmt.Sprintf("Phone battery low (%d %% remaining)", battery.Percentage) | ||||
| //		user.batteryWarningsSent = 1 | ||||
| //	} else if !battery.Plugged && battery.Percentage < 5 && user.batteryWarningsSent < 2 { | ||||
| //		notice = fmt.Sprintf("Phone battery very low (%d %% remaining)", battery.Percentage) | ||||
| //		user.batteryWarningsSent = 2 | ||||
| //	} else if battery.Percentage > 15 || battery.Plugged { | ||||
| //		user.batteryWarningsSent = 0 | ||||
| //	} | ||||
| //	if notice != "" { | ||||
| //		go user.sendBridgeNotice("%s", notice) | ||||
| //	} | ||||
| //} | ||||
|  | ||||
| func (user *User) HandleTextMessage(message groupme.Message) { | ||||
| 	user.messageInput <- PortalMessage{message.GroupID.String(), user, &message, uint64(message.CreatedAt.ToTime().Unix())} | ||||
| @@ -909,191 +920,191 @@ type FakeMessage struct { | ||||
| //	} | ||||
| //} | ||||
|  | ||||
| func (user *User) HandlePresence(info whatsappExt.Presence) { | ||||
| 	puppet := user.bridge.GetPuppetByJID(info.SenderJID) | ||||
| 	switch info.Status { | ||||
| 	case whatsapp.PresenceUnavailable: | ||||
| 		_ = puppet.DefaultIntent().SetPresence("offline") | ||||
| 	case whatsapp.PresenceAvailable: | ||||
| 		if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() { | ||||
| 			portal := user.bridge.GetPortalByMXID(puppet.typingIn) | ||||
| 			_, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0) | ||||
| 			puppet.typingIn = "" | ||||
| 			puppet.typingAt = 0 | ||||
| 		} else { | ||||
| 			_ = puppet.DefaultIntent().SetPresence("online") | ||||
| 		} | ||||
| 	case whatsapp.PresenceComposing: | ||||
| 		portal := user.GetPortalByJID(info.JID) | ||||
| 		if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() { | ||||
| 			if puppet.typingIn == portal.MXID { | ||||
| 				return | ||||
| 			} | ||||
| 			_, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0) | ||||
| 		} | ||||
| 		puppet.typingIn = portal.MXID | ||||
| 		puppet.typingAt = time.Now().Unix() | ||||
| 		_, _ = puppet.IntentFor(portal).UserTyping(portal.MXID, true, 15*1000) | ||||
| 	} | ||||
| } | ||||
| //func (user *User) HandlePresence(info whatsappExt.Presence) { | ||||
| //	puppet := user.bridge.GetPuppetByJID(info.SenderJID) | ||||
| //	switch info.Status { | ||||
| //	case whatsapp.PresenceUnavailable: | ||||
| //		_ = puppet.DefaultIntent().SetPresence("offline") | ||||
| //	case whatsapp.PresenceAvailable: | ||||
| //		if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() { | ||||
| //			portal := user.bridge.GetPortalByMXID(puppet.typingIn) | ||||
| //			_, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0) | ||||
| //			puppet.typingIn = "" | ||||
| //			puppet.typingAt = 0 | ||||
| //		} else { | ||||
| //			_ = puppet.DefaultIntent().SetPresence("online") | ||||
| //		} | ||||
| //	case whatsapp.PresenceComposing: | ||||
| //		portal := user.GetPortalByJID(info.JID) | ||||
| //		if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() { | ||||
| //			if puppet.typingIn == portal.MXID { | ||||
| //				return | ||||
| //			} | ||||
| //			_, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0) | ||||
| //		} | ||||
| //		puppet.typingIn = portal.MXID | ||||
| //		puppet.typingAt = time.Now().Unix() | ||||
| //		_, _ = puppet.IntentFor(portal).UserTyping(portal.MXID, true, 15*1000) | ||||
| //	} | ||||
| //} | ||||
| // | ||||
| //func (user *User) HandleMsgInfo(info whatsappExt.MsgInfo) { | ||||
| //	if (info.Command == whatsappExt.MsgInfoCommandAck || info.Command == whatsappExt.MsgInfoCommandAcks) && info.Acknowledgement == whatsappExt.AckMessageRead { | ||||
| //		portal := user.GetPortalByJID(info.ToJID) | ||||
| //		if len(portal.MXID) == 0 { | ||||
| //			return | ||||
| //		} | ||||
| // | ||||
| //		go func() { | ||||
| //			intent := user.bridge.GetPuppetByJID(info.SenderJID).IntentFor(portal) | ||||
| //			for _, msgID := range info.IDs { | ||||
| //				msg := user.bridge.DB.Message.GetByJID(portal.Key, msgID) | ||||
| //				if msg == nil { | ||||
| //					continue | ||||
| //				} | ||||
| // | ||||
| //				err := intent.MarkRead(portal.MXID, msg.MXID) | ||||
| //				if err != nil { | ||||
| //					user.log.Warnln("Failed to mark message %s as read by %s: %v", msg.MXID, info.SenderJID, err) | ||||
| //				} | ||||
| //			} | ||||
| //		}() | ||||
| //	} | ||||
| //} | ||||
|  | ||||
| func (user *User) HandleMsgInfo(info whatsappExt.MsgInfo) { | ||||
| 	if (info.Command == whatsappExt.MsgInfoCommandAck || info.Command == whatsappExt.MsgInfoCommandAcks) && info.Acknowledgement == whatsappExt.AckMessageRead { | ||||
| 		portal := user.GetPortalByJID(info.ToJID) | ||||
| 		if len(portal.MXID) == 0 { | ||||
| 			return | ||||
| 		} | ||||
| //func (user *User) HandleReceivedMessage(received whatsapp.ReceivedMessage) { | ||||
| //	if received.Type == "read" { | ||||
| //		user.markSelfRead(received.Jid, received.Index) | ||||
| //	} else { | ||||
| //		user.log.Debugfln("Unknown received message type: %+v", received) | ||||
| //	} | ||||
| //} | ||||
| // | ||||
| //func (user *User) HandleReadMessage(read whatsapp.ReadMessage) { | ||||
| //	user.log.Debugfln("Received chat read message: %+v", read) | ||||
| //	user.markSelfRead(read.Jid, "") | ||||
| //} | ||||
| // | ||||
| //func (user *User) markSelfRead(jid, messageID string) { | ||||
| //	if strings.HasSuffix(jid, whatsappExt.OldUserSuffix) { | ||||
| //		jid = strings.Replace(jid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, -1) | ||||
| //	} | ||||
| //	puppet := user.bridge.GetPuppetByJID(user.JID) | ||||
| //	if puppet == nil { | ||||
| //		return | ||||
| //	} | ||||
| //	intent := puppet.CustomIntent() | ||||
| //	if intent == nil { | ||||
| //		return | ||||
| //	} | ||||
| //	portal := user.GetPortalByJID(jid) | ||||
| //	if portal == nil { | ||||
| //		return | ||||
| //	} | ||||
| //	var message *database.Message | ||||
| //	if messageID == "" { | ||||
| //		message = user.bridge.DB.Message.GetLastInChat(portal.Key) | ||||
| //		if message == nil { | ||||
| //			return | ||||
| //		} | ||||
| //		user.log.Debugfln("User read chat %s/%s in WhatsApp mobile (last known event: %s/%s)", portal.Key.JID, portal.MXID, message.JID, message.MXID) | ||||
| //	} else { | ||||
| //		message = user.bridge.DB.Message.GetByJID(portal.Key, messageID) | ||||
| //		if message == nil { | ||||
| //			return | ||||
| //		} | ||||
| //		user.log.Debugfln("User read message %s/%s in %s/%s in WhatsApp mobile", message.JID, message.MXID, portal.Key.JID, portal.MXID) | ||||
| //	} | ||||
| //	err := intent.MarkRead(portal.MXID, message.MXID) | ||||
| //	if err != nil { | ||||
| //		user.log.Warnfln("Failed to bridge own read receipt in %s: %v", jid, err) | ||||
| //	} | ||||
| //} | ||||
| // | ||||
| //func (user *User) HandleCommand(cmd whatsappExt.Command) { | ||||
| //	switch cmd.Type { | ||||
| //	case whatsappExt.CommandPicture: | ||||
| //		if strings.HasSuffix(cmd.JID, whatsappExt.NewUserSuffix) { | ||||
| //			puppet := user.bridge.GetPuppetByJID(cmd.JID) | ||||
| //			go puppet.UpdateAvatar(user, cmd.ProfilePicInfo) | ||||
| //		} else { | ||||
| //			portal := user.GetPortalByJID(cmd.JID) | ||||
| //			go portal.UpdateAvatar(user, cmd.ProfilePicInfo, true) | ||||
| //		} | ||||
| //	case whatsappExt.CommandDisconnect: | ||||
| //		user.cleanDisconnection = true | ||||
| //		if cmd.Kind == "replaced" { | ||||
| //			go user.sendMarkdownBridgeAlert("\u26a0 Your WhatsApp connection was closed by the server because you opened another WhatsApp Web client.\n\n" + | ||||
| //				"Use the `reconnect` command to disconnect the other client and resume bridging.") | ||||
| //		} else { | ||||
| //			user.log.Warnln("Unknown kind of disconnect:", string(cmd.Raw)) | ||||
| //			go user.sendMarkdownBridgeAlert("\u26a0 Your WhatsApp connection was closed by the server (reason code: %s).\n\n"+ | ||||
| //				"Use the `reconnect` command to reconnect.", cmd.Kind) | ||||
| //		} | ||||
| //	} | ||||
| //} | ||||
| // | ||||
| //func (user *User) HandleChatUpdate(cmd whatsappExt.ChatUpdate) { | ||||
| //	if cmd.Command != whatsappExt.ChatUpdateCommandAction { | ||||
| //		return | ||||
| //	} | ||||
| // | ||||
| //	portal := user.GetPortalByJID(cmd.JID) | ||||
| //	if len(portal.MXID) == 0 { | ||||
| //		if cmd.Data.Action == whatsappExt.ChatActionIntroduce || cmd.Data.Action == whatsappExt.ChatActionCreate { | ||||
| //			go func() { | ||||
| //				err := portal.CreateMatrixRoom(user) | ||||
| //				if err != nil { | ||||
| //					user.log.Errorln("Failed to create portal room after receiving join event:", err) | ||||
| //				} | ||||
| //			}() | ||||
| //		} | ||||
| //		return | ||||
| //	} | ||||
| // | ||||
| //	switch cmd.Data.Action { | ||||
| //	case whatsappExt.ChatActionNameChange: | ||||
| //		go portal.UpdateName(cmd.Data.NameChange.Name, cmd.Data.SenderJID, true) | ||||
| //	case whatsappExt.ChatActionAddTopic: | ||||
| //		go portal.UpdateTopic(cmd.Data.AddTopic.Topic, cmd.Data.SenderJID, true) | ||||
| //	case whatsappExt.ChatActionRemoveTopic: | ||||
| //		go portal.UpdateTopic("", cmd.Data.SenderJID, true) | ||||
| //	case whatsappExt.ChatActionPromote: | ||||
| //		go portal.ChangeAdminStatus(cmd.Data.UserChange.JIDs, true) | ||||
| //	case whatsappExt.ChatActionDemote: | ||||
| //		go portal.ChangeAdminStatus(cmd.Data.UserChange.JIDs, false) | ||||
| //	case whatsappExt.ChatActionAnnounce: | ||||
| //		go portal.RestrictMessageSending(cmd.Data.Announce) | ||||
| //	case whatsappExt.ChatActionRestrict: | ||||
| //		go portal.RestrictMetadataChanges(cmd.Data.Restrict) | ||||
| //	case whatsappExt.ChatActionRemove: | ||||
| //		go portal.HandleWhatsAppKick(cmd.Data.SenderJID, cmd.Data.UserChange.JIDs) | ||||
| //	case whatsappExt.ChatActionAdd: | ||||
| //		go portal.HandleWhatsAppInvite(cmd.Data.SenderJID, cmd.Data.UserChange.JIDs) | ||||
| //		//case whatsappExt.ChatActionIntroduce: | ||||
| //		//	if cmd.Data.SenderJID != "unknown" { | ||||
| //		//		go portal.Sync(user, whatsapp.Contact{Jid: portal.Key.JID}) | ||||
| //		//	} | ||||
| //	} | ||||
| //} | ||||
|  | ||||
| 		go func() { | ||||
| 			intent := user.bridge.GetPuppetByJID(info.SenderJID).IntentFor(portal) | ||||
| 			for _, msgID := range info.IDs { | ||||
| 				msg := user.bridge.DB.Message.GetByJID(portal.Key, msgID) | ||||
| 				if msg == nil { | ||||
| 					continue | ||||
| 				} | ||||
| //func (user *User) HandleJsonMessage(message string) { | ||||
| //	var msg json.RawMessage | ||||
| //	err := json.Unmarshal([]byte(message), &msg) | ||||
| //	if err != nil { | ||||
| //		return | ||||
| //	} | ||||
| //	user.log.Debugln("JSON message:", message) | ||||
| //	user.updateLastConnectionIfNecessary() | ||||
| //} | ||||
|  | ||||
| 				err := intent.MarkRead(portal.MXID, msg.MXID) | ||||
| 				if err != nil { | ||||
| 					user.log.Warnln("Failed to mark message %s as read by %s: %v", msg.MXID, info.SenderJID, err) | ||||
| 				} | ||||
| 			} | ||||
| 		}() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (user *User) HandleReceivedMessage(received whatsapp.ReceivedMessage) { | ||||
| 	if received.Type == "read" { | ||||
| 		user.markSelfRead(received.Jid, received.Index) | ||||
| 	} else { | ||||
| 		user.log.Debugfln("Unknown received message type: %+v", received) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (user *User) HandleReadMessage(read whatsapp.ReadMessage) { | ||||
| 	user.log.Debugfln("Received chat read message: %+v", read) | ||||
| 	user.markSelfRead(read.Jid, "") | ||||
| } | ||||
|  | ||||
| func (user *User) markSelfRead(jid, messageID string) { | ||||
| 	if strings.HasSuffix(jid, whatsappExt.OldUserSuffix) { | ||||
| 		jid = strings.Replace(jid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, -1) | ||||
| 	} | ||||
| 	puppet := user.bridge.GetPuppetByJID(user.JID) | ||||
| 	if puppet == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	intent := puppet.CustomIntent() | ||||
| 	if intent == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	portal := user.GetPortalByJID(jid) | ||||
| 	if portal == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	var message *database.Message | ||||
| 	if messageID == "" { | ||||
| 		message = user.bridge.DB.Message.GetLastInChat(portal.Key) | ||||
| 		if message == nil { | ||||
| 			return | ||||
| 		} | ||||
| 		user.log.Debugfln("User read chat %s/%s in WhatsApp mobile (last known event: %s/%s)", portal.Key.JID, portal.MXID, message.JID, message.MXID) | ||||
| 	} else { | ||||
| 		message = user.bridge.DB.Message.GetByJID(portal.Key, messageID) | ||||
| 		if message == nil { | ||||
| 			return | ||||
| 		} | ||||
| 		user.log.Debugfln("User read message %s/%s in %s/%s in WhatsApp mobile", message.JID, message.MXID, portal.Key.JID, portal.MXID) | ||||
| 	} | ||||
| 	err := intent.MarkRead(portal.MXID, message.MXID) | ||||
| 	if err != nil { | ||||
| 		user.log.Warnfln("Failed to bridge own read receipt in %s: %v", jid, err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (user *User) HandleCommand(cmd whatsappExt.Command) { | ||||
| 	switch cmd.Type { | ||||
| 	case whatsappExt.CommandPicture: | ||||
| 		if strings.HasSuffix(cmd.JID, whatsappExt.NewUserSuffix) { | ||||
| 			puppet := user.bridge.GetPuppetByJID(cmd.JID) | ||||
| 			go puppet.UpdateAvatar(user, cmd.ProfilePicInfo) | ||||
| 		} else { | ||||
| 			portal := user.GetPortalByJID(cmd.JID) | ||||
| 			go portal.UpdateAvatar(user, cmd.ProfilePicInfo, true) | ||||
| 		} | ||||
| 	case whatsappExt.CommandDisconnect: | ||||
| 		user.cleanDisconnection = true | ||||
| 		if cmd.Kind == "replaced" { | ||||
| 			go user.sendMarkdownBridgeAlert("\u26a0 Your WhatsApp connection was closed by the server because you opened another WhatsApp Web client.\n\n" + | ||||
| 				"Use the `reconnect` command to disconnect the other client and resume bridging.") | ||||
| 		} else { | ||||
| 			user.log.Warnln("Unknown kind of disconnect:", string(cmd.Raw)) | ||||
| 			go user.sendMarkdownBridgeAlert("\u26a0 Your WhatsApp connection was closed by the server (reason code: %s).\n\n"+ | ||||
| 				"Use the `reconnect` command to reconnect.", cmd.Kind) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (user *User) HandleChatUpdate(cmd whatsappExt.ChatUpdate) { | ||||
| 	if cmd.Command != whatsappExt.ChatUpdateCommandAction { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	portal := user.GetPortalByJID(cmd.JID) | ||||
| 	if len(portal.MXID) == 0 { | ||||
| 		if cmd.Data.Action == whatsappExt.ChatActionIntroduce || cmd.Data.Action == whatsappExt.ChatActionCreate { | ||||
| 			go func() { | ||||
| 				err := portal.CreateMatrixRoom(user) | ||||
| 				if err != nil { | ||||
| 					user.log.Errorln("Failed to create portal room after receiving join event:", err) | ||||
| 				} | ||||
| 			}() | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	switch cmd.Data.Action { | ||||
| 	case whatsappExt.ChatActionNameChange: | ||||
| 		go portal.UpdateName(cmd.Data.NameChange.Name, cmd.Data.SenderJID, true) | ||||
| 	case whatsappExt.ChatActionAddTopic: | ||||
| 		go portal.UpdateTopic(cmd.Data.AddTopic.Topic, cmd.Data.SenderJID, true) | ||||
| 	case whatsappExt.ChatActionRemoveTopic: | ||||
| 		go portal.UpdateTopic("", cmd.Data.SenderJID, true) | ||||
| 	case whatsappExt.ChatActionPromote: | ||||
| 		go portal.ChangeAdminStatus(cmd.Data.UserChange.JIDs, true) | ||||
| 	case whatsappExt.ChatActionDemote: | ||||
| 		go portal.ChangeAdminStatus(cmd.Data.UserChange.JIDs, false) | ||||
| 	case whatsappExt.ChatActionAnnounce: | ||||
| 		go portal.RestrictMessageSending(cmd.Data.Announce) | ||||
| 	case whatsappExt.ChatActionRestrict: | ||||
| 		go portal.RestrictMetadataChanges(cmd.Data.Restrict) | ||||
| 	case whatsappExt.ChatActionRemove: | ||||
| 		go portal.HandleWhatsAppKick(cmd.Data.SenderJID, cmd.Data.UserChange.JIDs) | ||||
| 	case whatsappExt.ChatActionAdd: | ||||
| 		go portal.HandleWhatsAppInvite(cmd.Data.SenderJID, cmd.Data.UserChange.JIDs) | ||||
| 		//case whatsappExt.ChatActionIntroduce: | ||||
| 		//	if cmd.Data.SenderJID != "unknown" { | ||||
| 		//		go portal.Sync(user, whatsapp.Contact{Jid: portal.Key.JID}) | ||||
| 		//	} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (user *User) HandleJsonMessage(message string) { | ||||
| 	var msg json.RawMessage | ||||
| 	err := json.Unmarshal([]byte(message), &msg) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	user.log.Debugln("JSON message:", message) | ||||
| 	user.updateLastConnectionIfNecessary() | ||||
| } | ||||
|  | ||||
| func (user *User) HandleRawMessage(message *waProto.WebMessageInfo) { | ||||
| 	user.updateLastConnectionIfNecessary() | ||||
| } | ||||
|  | ||||
| func (user *User) HandleUnknownBinaryNode(node *waBinary.Node) { | ||||
| 	user.log.Debugfln("Unknown binary message: %+v", node) | ||||
| } | ||||
| //func (user *User) HandleRawMessage(message *waProto.WebMessageInfo) { | ||||
| //	user.updateLastConnectionIfNecessary() | ||||
| //} | ||||
| // | ||||
| //func (user *User) HandleUnknownBinaryNode(node *waBinary.Node) { | ||||
| //	user.log.Debugfln("Unknown binary message: %+v", node) | ||||
| //} | ||||
|  | ||||
| func (user *User) NeedsRelaybot(portal *Portal) bool { | ||||
| 	return !user.HasSession() || !user.IsInPortal(portal.Key) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user