| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- // Copyright (c) 2021 Tulir Asokan
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this
- // file, You can obtain one at http://mozilla.org/MPL/2.0/.
- package whatsmeow
- import (
- "context"
- "fmt"
- waBinary "git.bobomao.top/joey/testwh/binary"
- "git.bobomao.top/joey/testwh/types"
- "git.bobomao.top/joey/testwh/types/events"
- )
- func (cli *Client) handleChatState(ctx context.Context, node *waBinary.Node) {
- source, err := cli.parseMessageSource(node, true)
- if err != nil {
- cli.Log.Warnf("Failed to parse chat state update: %v", err)
- } else if len(node.GetChildren()) != 1 {
- cli.Log.Warnf("Failed to parse chat state update: unexpected number of children in element (%d)", len(node.GetChildren()))
- } else {
- child := node.GetChildren()[0]
- presence := types.ChatPresence(child.Tag)
- if presence != types.ChatPresenceComposing && presence != types.ChatPresencePaused {
- cli.Log.Warnf("Unrecognized chat presence state %s", child.Tag)
- }
- media := types.ChatPresenceMedia(child.AttrGetter().OptionalString("media"))
- cli.dispatchEvent(&events.ChatPresence{
- MessageSource: source,
- State: presence,
- Media: media,
- })
- }
- }
- func (cli *Client) handlePresence(ctx context.Context, node *waBinary.Node) {
- var evt events.Presence
- ag := node.AttrGetter()
- evt.From = ag.JID("from")
- presenceType := ag.OptionalString("type")
- if presenceType == "unavailable" {
- evt.Unavailable = true
- } else if presenceType != "" {
- cli.Log.Debugf("Unrecognized presence type '%s' in presence event from %s", presenceType, evt.From)
- }
- lastSeen := ag.OptionalString("last")
- if lastSeen != "" && lastSeen != "deny" {
- evt.LastSeen = ag.UnixTime("last")
- }
- if !ag.OK() {
- cli.Log.Warnf("Error parsing presence event: %+v", ag.Errors)
- } else {
- cli.dispatchEvent(&evt)
- }
- }
- // SendPresence updates the user's presence status on WhatsApp.
- //
- // You should call this at least once after connecting so that the server has your pushname.
- // Otherwise, other users will see "-" as the name.
- func (cli *Client) SendPresence(ctx context.Context, state types.Presence) error {
- if cli == nil {
- return ErrClientIsNil
- } else if len(cli.Store.PushName) == 0 && cli.MessengerConfig == nil {
- return ErrNoPushName
- }
- if state == types.PresenceAvailable {
- cli.sendActiveReceipts.CompareAndSwap(0, 1)
- } else {
- cli.sendActiveReceipts.CompareAndSwap(1, 0)
- }
- attrs := waBinary.Attrs{
- "type": string(state),
- }
- // PushName not set when using WhatsApp for Messenger E2EE
- if cli.MessengerConfig == nil {
- attrs["name"] = cli.Store.PushName
- }
- return cli.sendNode(ctx, waBinary.Node{
- Tag: "presence",
- Attrs: attrs,
- })
- }
- // SubscribePresence asks the WhatsApp servers to send presence updates of a specific user to this client.
- //
- // After subscribing to this event, you should start receiving *events.Presence for that user in normal event handlers.
- //
- // Also, it seems that the WhatsApp servers require you to be online to receive presence status from other users,
- // so you should mark yourself as online before trying to use this function:
- //
- // cli.SendPresence(types.PresenceAvailable)
- func (cli *Client) SubscribePresence(ctx context.Context, jid types.JID) error {
- if cli == nil {
- return ErrClientIsNil
- }
- privacyToken, err := cli.Store.PrivacyTokens.GetPrivacyToken(ctx, jid)
- if err != nil {
- return fmt.Errorf("failed to get privacy token: %w", err)
- } else if privacyToken == nil {
- if cli.ErrorOnSubscribePresenceWithoutToken {
- return fmt.Errorf("%w for %v", ErrNoPrivacyToken, jid.ToNonAD())
- } else {
- cli.Log.Debugf("Trying to subscribe to presence of %s without privacy token", jid)
- }
- }
- req := waBinary.Node{
- Tag: "presence",
- Attrs: waBinary.Attrs{
- "type": "subscribe",
- "to": jid,
- },
- }
- if privacyToken != nil {
- req.Content = []waBinary.Node{{
- Tag: "tctoken",
- Content: privacyToken.Token,
- }}
- }
- return cli.sendNode(ctx, req)
- }
- // SendChatPresence updates the user's typing status in a specific chat.
- //
- // The media parameter can be set to indicate the user is recording media (like a voice message) rather than typing a text message.
- func (cli *Client) SendChatPresence(ctx context.Context, jid types.JID, state types.ChatPresence, media types.ChatPresenceMedia) error {
- ownID := cli.getOwnID()
- if ownID.IsEmpty() {
- return ErrNotLoggedIn
- }
- content := []waBinary.Node{{Tag: string(state)}}
- if state == types.ChatPresenceComposing && len(media) > 0 {
- content[0].Attrs = waBinary.Attrs{
- "media": string(media),
- }
- }
- return cli.sendNode(ctx, waBinary.Node{
- Tag: "chatstate",
- Attrs: waBinary.Attrs{
- "from": ownID,
- "to": jid,
- },
- Content: content,
- })
- }
|