diff --git a/commands.go b/commands.go index 213c4e1..7f53ce3 100644 --- a/commands.go +++ b/commands.go @@ -19,9 +19,12 @@ package main import ( "strings" + "github.com/Rhymen/go-whatsapp" "maunium.net/go/maulogger" "maunium.net/go/mautrix-appservice" + "maunium.net/go/mautrix-whatsapp/database" "maunium.net/go/mautrix-whatsapp/types" + "maunium.net/go/mautrix-whatsapp/whatsapp-ext" ) type CommandHandler struct { @@ -49,7 +52,7 @@ type CommandEvent struct { // Reply sends a reply to command as notice func (ce *CommandEvent) Reply(msg string) { - _, err := ce.Bot.SendNotice(string(ce.RoomID), msg) + _, err := ce.Bot.SendNotice(string(ce.User.ManagementRoom), msg) if err != nil { ce.Handler.log.Warnfln("Failed to reply to command from %s: %v", ce.User.MXID, err) } @@ -74,6 +77,8 @@ func (handler *CommandHandler) Handle(roomID types.MatrixRoomID, user *User, mes handler.CommandLogout(ce) case "help": handler.CommandHelp(ce) + case "import": + handler.CommandImport(ce) default: ce.Reply("Unknown Command") } @@ -116,10 +121,53 @@ const cmdHelpHelp = `help - Prints this help` // CommandHelp handles help command func (handler *CommandHandler) CommandHelp(ce *CommandEvent) { - cmdPrefix := handler.bridge.Config.Bridge.CommandPrefix + " " + cmdPrefix := "" + if ce.User.ManagementRoom != ce.RoomID { + cmdPrefix = handler.bridge.Config.Bridge.CommandPrefix + " " + } + ce.Reply(strings.Join([]string{ cmdPrefix + cmdHelpHelp, cmdPrefix + cmdLoginHelp, cmdPrefix + cmdLogoutHelp, + cmdPrefix + cmdImportHelp, }, "\n")) } + +const cmdImportHelp = `import JID|contacts - Open up a room for JID or for each WhatsApp contact` + +// CommandImport handles import command +func (handler *CommandHandler) CommandImport(ce *CommandEvent) { + // ensure all messages go to the management room + ce.RoomID = ce.User.ManagementRoom + + user := ce.User + + if ce.Args[0] == "contacts" { + handler.log.Debugln("Importing all contacts of", user) + _, err := user.Conn.Contacts() + if err != nil { + handler.log.Errorln("Error on update of contacts of user", user, ":", err) + return + } + + for jid, contact := range user.Conn.Store.Contacts { + if strings.HasSuffix(jid, whatsappExt.NewUserSuffix) { + puppet := user.bridge.GetPuppetByJID(contact.Jid) + puppet.Sync(user, contact) + } else { + portal := user.bridge.GetPortalByJID(database.GroupPortalKey(contact.Jid)) + portal.Sync(user, contact) + } + } + + ce.Reply("Importing all contacts done") + } else { + jid := ce.Args[0] + whatsappExt.NewUserSuffix + handler.log.Debugln("Importing", jid, "for", user) + puppet := user.bridge.GetPuppetByJID(jid) + + contact := whatsapp.Contact { Jid: jid } + puppet.Sync(user, contact) + } +} diff --git a/main.go b/main.go index 5594e2c..9965727 100644 --- a/main.go +++ b/main.go @@ -185,7 +185,7 @@ func (bridge *Bridge) UpdateBotProfile() { func (bridge *Bridge) StartUsers() { for _, user := range bridge.GetAllUsers() { - go user.Start() + go user.Connect(false) } } diff --git a/matrix.go b/matrix.go index cd12447..8cbeade 100644 --- a/matrix.go +++ b/matrix.go @@ -98,7 +98,7 @@ func (mx *MatrixHandler) HandleBotInvite(evt *gomatrix.Event) { if !hasPuppets { user := mx.bridge.GetUserByMXID(types.MatrixUserID(evt.Sender)) user.SetManagementRoom(types.MatrixRoomID(resp.RoomID)) - intent.SendNotice(string(user.ManagementRoom), "This room has been registered as your bridge management/status room.") + intent.SendNotice(string(user.ManagementRoom), "This room has been registered as your bridge management/status room. Send `help` to get a list of commands.") mx.log.Debugln(resp.RoomID, "registered as a management room with", evt.Sender) } } diff --git a/portal.go b/portal.go index a538e31..41e0be7 100644 --- a/portal.go +++ b/portal.go @@ -258,6 +258,12 @@ func (portal *Portal) UpdateAvatar(user *User, avatar *whatsappExt.ProfilePicInf } } + if avatar.Status != 0 { + // 401: ??? + // 404: ??? + return false + } + if portal.Avatar == avatar.Tag { return false } @@ -316,6 +322,16 @@ func (portal *Portal) UpdateMetadata(user *User) bool { portal.log.Errorln(err) return false } + if metadata.Status != 0 { + // 401: access denied + // 404: group does (no longer) exist + // 500: ??? happens with status@broadcast + + // TODO: update the room, e.g. change priority level + // to send messages to moderator + return false + } + portal.SyncParticipants(metadata) update := false update = portal.UpdateName(metadata.Name, metadata.NameSetBy) || update @@ -439,6 +455,11 @@ func (portal *Portal) CreateMatrixRoom(invite []string) error { return nil } + intent := portal.MainIntent() + if err := intent.EnsureRegistered(); err != nil { + return err + } + name := portal.Name topic := portal.Topic isPrivateChat := false @@ -448,7 +469,7 @@ func (portal *Portal) CreateMatrixRoom(invite []string) error { isPrivateChat = true } - resp, err := portal.MainIntent().CreateRoom(&gomatrix.ReqCreateRoom{ + resp, err := intent.CreateRoom(&gomatrix.ReqCreateRoom{ Visibility: "private", Name: name, Topic: topic, diff --git a/user.go b/user.go index 0c44f5a..6f9129f 100644 --- a/user.go +++ b/user.go @@ -132,12 +132,6 @@ func (user *User) SetSession(session *whatsapp.Session) { user.Update() } -func (user *User) Start() { - if user.Connect(false) { - user.Sync() - } -} - func (user *User) Connect(evenIfNoSession bool) bool { if user.Conn != nil { return true @@ -210,22 +204,7 @@ func (user *User) Login(roomID types.MatrixRoomID) { user.JID = strings.Replace(user.Conn.Info.Wid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, 1) user.Session = &session user.Update() - bot.SendNotice(roomID, "Successfully logged in. Synchronizing chats...") - go user.Sync() -} - -func (user *User) Sync() { - user.log.Debugln("Syncing...") - user.Conn.Contacts() - for jid, contact := range user.Conn.Store.Contacts { - if strings.HasSuffix(jid, whatsappExt.NewUserSuffix) { - puppet := user.bridge.GetPuppetByJID(contact.Jid) - puppet.Sync(user, contact) - } else { - portal := user.bridge.GetPortalByJID(database.GroupPortalKey(contact.Jid)) - portal.Sync(user, contact) - } - } + bot.SendNotice(roomID, "Successfully logged in. Now, you may ask for `import contacts`.") } func (user *User) HandleError(err error) { diff --git a/whatsapp-ext/jsonmessage.go b/whatsapp-ext/jsonmessage.go index 232f3fb..8a7fd44 100644 --- a/whatsapp-ext/jsonmessage.go +++ b/whatsapp-ext/jsonmessage.go @@ -68,6 +68,7 @@ func (ext *ExtendedConn) HandleJsonMessage(message string) { msg := JSONMessage{} err := json.Unmarshal([]byte(message), &msg) if err != nil || len(msg) < 2 { + ext.jsonParseError(err) return } diff --git a/whatsapp-ext/whatsapp.go b/whatsapp-ext/whatsapp.go index 740a299..9f38345 100644 --- a/whatsapp-ext/whatsapp.go +++ b/whatsapp-ext/whatsapp.go @@ -61,6 +61,8 @@ type GroupInfo struct { GroupCreated int64 `json:"creation"` + Status int16 `json:"status"` + Participants []struct { JID string `json:"id"` IsAdmin bool `json:"isAdmin"` @@ -93,6 +95,8 @@ func (ext *ExtendedConn) GetGroupMetaData(jid string) (*GroupInfo, error) { type ProfilePicInfo struct { URL string `json:"eurl"` Tag string `json:"tag"` + + Status int16 `json:"status"` } func (ppi *ProfilePicInfo) Download() (io.ReadCloser, error) {