forked from tulir/whatsmeow
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpresence.go
More file actions
148 lines (140 loc) · 4.63 KB
/
presence.go
File metadata and controls
148 lines (140 loc) · 4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// 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 "go.mau.fi/whatsmeow/binary"
"go.mau.fi/whatsmeow/types"
"go.mau.fi/whatsmeow/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,
})
}