forked from tulir/whatsmeow
-
Notifications
You must be signed in to change notification settings - Fork 0
/
events.go
360 lines (302 loc) · 13.8 KB
/
events.go
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
// 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 events contains all the events that whatsmeow.Client emits to functions registered with AddEventHandler.
package events
import (
"fmt"
"time"
waBinary "github.com/lucklrj/whatsmeow/binary"
waProto "github.com/lucklrj/whatsmeow/binary/proto"
"github.com/lucklrj/whatsmeow/types"
)
// QR is emitted after connecting when there's no session data in the device store.
//
// The QR codes are available in the Codes slice. You should render the strings as QR codes one by
// one, switching to the next one whenever enough time has passed. WhatsApp web seems to show the
// first code for 60 seconds and all other codes for 20 seconds.
//
// When the QR code has been scanned and pairing is complete, PairSuccess will be emitted. If you
// run out of codes before scanning, the server will close the websocket, and you will have to
// reconnect to get more codes.
type QR struct {
Codes []string
}
// PairSuccess is emitted after the QR code has been scanned with the phone and the handshake has
// been completed. Note that this is generally followed by a websocket reconnection, so you should
// wait for the Connected before trying to send anything.
type PairSuccess struct {
ID types.JID
BusinessName string
Platform string
}
// PairError is emitted when a pair-success event is received from the server, but finishing the pairing locally fails.
type PairError struct {
ID types.JID
BusinessName string
Platform string
Error error
}
// QRScannedWithoutMultidevice is emitted when the pairing QR code is scanned, but the phone didn't have multidevice enabled.
// The same QR code can still be scanned after this event, which means the user can just be told to enable multidevice and re-scan the code.
type QRScannedWithoutMultidevice struct{}
// Connected is emitted when the client has successfully connected to the WhatsApp servers
// and is authenticated. The user who the client is authenticated as will be in the device store
// at this point, which is why this event doesn't contain any data.
type Connected struct{}
// LoggedOut is emitted when the client has been unpaired from the phone.
//
// This can happen while connected (stream:error messages) or right after connecting (connect failure messages).
type LoggedOut struct {
// OnConnect is true if the event was triggered by a connect failure message.
// If it's false, the event was triggered by a stream:error message.
OnConnect bool
// If OnConnect is true, then this field contains the reason code.
Reason ConnectFailureReason
}
// StreamReplaced is emitted when the client is disconnected by another client connecting with the same keys.
//
// This can happen if you accidentally start another process with the same session
// or otherwise try to connect twice with the same session.
type StreamReplaced struct{}
// TempBanReason is an error code included in temp ban error events.
type TempBanReason int
const (
TempBanBlockedByUsers TempBanReason = 101
TempBanSentToTooManyPeople TempBanReason = 102
TempBanCreatedTooManyGroups TempBanReason = 103
TempBanSentTooManySameMessage TempBanReason = 104
TempBanBroadcastList TempBanReason = 106
)
var tempBanReasonMessage = map[TempBanReason]string{
TempBanBlockedByUsers: "too many people blocked you",
TempBanSentToTooManyPeople: "you sent too many messages to people who don't have you in their address books",
TempBanCreatedTooManyGroups: "you created too many groups with people who don't have you in their address books",
TempBanSentTooManySameMessage: "you sent the same message to too many people",
TempBanBroadcastList: "you sent too many messages to a broadcast list",
}
// String returns the reason code and a human-readable description of the ban reason.
func (tbr TempBanReason) String() string {
msg, ok := tempBanReasonMessage[tbr]
if !ok {
msg = "you may have violated the terms of service (unknown error)"
}
return fmt.Sprintf("%d: %s", int(tbr), msg)
}
// TemporaryBan is emitted when there's a connection failure with the ConnectFailureTempBanned reason code.
type TemporaryBan struct {
Code TempBanReason
Expire time.Time
}
func (tb *TemporaryBan) String() string {
if tb.Expire.IsZero() {
return fmt.Sprintf("You've been temporarily banned: %v", tb.Code)
}
return fmt.Sprintf("You've been temporarily banned: %v. The ban expires at %v", tb.Code, tb.Expire)
}
// ConnectFailureReason is an error code included in connection failure events.
type ConnectFailureReason int
const (
ConnectFailureLoggedOut ConnectFailureReason = 401
ConnectFailureTempBanned ConnectFailureReason = 402
ConnectFailureBanned ConnectFailureReason = 403
ConnectFailureUnknownLogout ConnectFailureReason = 406
ConnectFailureClientOutdated ConnectFailureReason = 405
ConnectFailureBadUserAgent ConnectFailureReason = 409
// 400, 500 and 501 are also existing codes, but the meaning is unknown
)
var connectFailureReasonMessage = map[ConnectFailureReason]string{
ConnectFailureLoggedOut: "logged out from another device",
ConnectFailureTempBanned: "account temporarily banned",
ConnectFailureBanned: "account banned from WhatsApp",
ConnectFailureUnknownLogout: "logged out for unknown reason",
ConnectFailureClientOutdated: "client is out of date",
ConnectFailureBadUserAgent: "client user agent was rejected",
}
// IsLoggedOut returns true if the client should delete session data due to this connect failure.
func (cfr ConnectFailureReason) IsLoggedOut() bool {
return cfr == ConnectFailureLoggedOut || cfr == ConnectFailureBanned || cfr == ConnectFailureUnknownLogout
}
// String returns the reason code and a short human-readable description of the error.
func (cfr ConnectFailureReason) String() string {
msg, ok := connectFailureReasonMessage[cfr]
if !ok {
msg = "unknown error"
}
return fmt.Sprintf("%d: %s", int(cfr), msg)
}
// ConnectFailure is emitted when the WhatsApp server sends a <failure> node with an unknown reason.
//
// Known reasons are handled internally and emitted as different events (e.g. LoggedOut and TemporaryBan).
type ConnectFailure struct {
Reason ConnectFailureReason
Raw *waBinary.Node
}
// ClientOutdated is emitted when the WhatsApp server rejects the connection with the ConnectFailureClientOutdated code.
type ClientOutdated struct{}
// StreamError is emitted when the WhatsApp server sends a <stream:error> node with an unknown code.
//
// Known codes are handled internally and emitted as different events (e.g. LoggedOut).
type StreamError struct {
Code string
Raw *waBinary.Node
}
// Disconnected is emitted when the websocket is closed by the server.
type Disconnected struct{}
// HistorySync is emitted when the phone has sent a blob of historical messages.
type HistorySync struct {
Data *waProto.HistorySync
}
// UndecryptableMessage is emitted when receiving a new message that failed to decrypt.
//
// The library will automatically ask the sender to retry. If the sender resends the message,
// and it's decryptable, then it will be emitted as a normal Message event.
//
// The UndecryptableMessage event may also be repeated if the resent message is also undecryptable.
type UndecryptableMessage struct {
Info types.MessageInfo
// IsUnavailable is true if the recipient device didn't send a ciphertext to this device at all
// (as opposed to sending a ciphertext, but the ciphertext not being decryptable).
IsUnavailable bool
}
// Message is emitted when receiving a new message.
type Message struct {
Info types.MessageInfo // Information about the message like the chat and sender IDs
Message *waProto.Message // The actual message struct
IsEphemeral bool // True if the message was unwrapped from an EphemeralMessage
IsViewOnce bool // True if the message was unwrapped from a ViewOnceMessage
// The raw message struct. This is the raw unmodified data, which means the actual message might
// be wrapped in DeviceSentMessage, EphemeralMessage or ViewOnceMessage.
RawMessage *waProto.Message
}
// ReceiptType represents the type of a Receipt event.
type ReceiptType string
const (
// ReceiptTypeDelivered means the message was delivered to the device (but the user might not have noticed).
ReceiptTypeDelivered ReceiptType = ""
// ReceiptTypeRetry means the message was delivered to the device, but decrypting the message failed.
ReceiptTypeRetry ReceiptType = "retry"
// ReceiptTypeRead means the user opened the chat and saw the message.
ReceiptTypeRead ReceiptType = "read"
// ReceiptTypeReadSelf means the current user read a message from a different device, and has read receipts disabled in privacy settings.
ReceiptTypeReadSelf ReceiptType = "read-self"
)
// GoString returns the name of the Go constant for the ReceiptType value.
func (rt ReceiptType) GoString() string {
switch rt {
case ReceiptTypeRead:
return "events.ReceiptTypeRead"
case ReceiptTypeReadSelf:
return "events.ReceiptTypeReadSelf"
case ReceiptTypeDelivered:
return "events.ReceiptTypeDelivered"
default:
return fmt.Sprintf("events.ReceiptType(%#v)", string(rt))
}
}
// Receipt is emitted when an outgoing message is delivered to or read by another user, or when another device reads an incoming message.
//
// N.B. WhatsApp on Android sends message IDs from newest message to oldest, but WhatsApp on iOS sends them in the opposite order (oldest first).
type Receipt struct {
types.MessageSource
MessageIDs []types.MessageID
Timestamp time.Time
Type ReceiptType
}
// ChatPresence is emitted when a chat state update (also known as typing notification) is received.
//
// Note that WhatsApp won't send you these updates unless you mark yourself as online:
// client.SendPresence(types.PresenceAvailable)
type ChatPresence struct {
types.MessageSource
State types.ChatPresence
}
// Presence is emitted when a presence update is received.
//
// Note that WhatsApp only sends you presence updates for individual users after you subscribe to them:
// client.SubscribePresence(user JID)
type Presence struct {
// The user whose presence event this is
From types.JID
// True if the user is now offline
Unavailable bool
// The time when the user was last online. This may be the zero value if the user has hid their last seen time.
LastSeen time.Time
}
// JoinedGroup is emitted when you join or are added to a group.
type JoinedGroup struct {
Reason string // If the event was triggered by you using an invite link, this will be "invite"
types.GroupInfo
}
// GroupInfo is emitted when the metadata of a group changes.
type GroupInfo struct {
JID types.JID // The group ID in question
Notify string // Seems like a top-level type for the invite
Sender *types.JID // The user who made the change. Doesn't seem to be present when notify=invite
Timestamp time.Time // The time when the change occurred
Name *types.GroupName // Group name change
Topic *types.GroupTopic // Group topic (description) change
Locked *types.GroupLocked // Group locked status change (can only admins edit group info?)
Announce *types.GroupAnnounce // Group announce status change (can only admins send messages?)
Ephemeral *types.GroupEphemeral // Disappearing messages change
NewInviteLink *string // Group invite link change
PrevParticipantVersionID string
ParticipantVersionID string
JoinReason string // This will be "invite" if the user joined via invite link
Join []types.JID // Users who joined or were added the group
Leave []types.JID // Users who left or were removed from the group
Promote []types.JID // Users who were promoted to admins
Demote []types.JID // Users who were demoted to normal users
UnknownChanges []*waBinary.Node
}
// Picture is emitted when a user's profile picture or group's photo is changed.
//
// You can use Client.GetProfilePictureInfo to get the actual image URL after this event.
type Picture struct {
JID types.JID // The user or group ID where the picture was changed.
Author types.JID // The user who changed the picture.
Timestamp time.Time // The timestamp when the picture was changed.
Remove bool // True if the picture was removed.
PictureID string // The new picture ID if it was not removed.
}
// IdentityChange is emitted when another user changes their primary device.
type IdentityChange struct {
JID types.JID
Timestamp time.Time
// Implicit will be set to true if the event was triggered by an untrusted identity error,
// rather than an identity change notification from the server.
Implicit bool
}
// PrivacySettings is emitted when the user changes their privacy settings.
type PrivacySettings struct {
NewSettings types.PrivacySettings
GroupAddChanged bool
LastSeenChanged bool
StatusChanged bool
ProfileChanged bool
ReadReceiptsChanged bool
}
// OfflineSyncPreview is emitted right after connecting if the server is going to send events that the client missed during downtime.
type OfflineSyncPreview struct {
Total int
AppDataChanges int
Messages int
Notifications int
Receipts int
}
// OfflineSyncCompleted is emitted after the server has finished sending missed events.
type OfflineSyncCompleted struct {
Count int
}
// MediaRetry is emitted when the phone sends a response to a media retry request.
type MediaRetry struct {
Ciphertext []byte
IV []byte
Timestamp time.Time // The time of the response.
MessageID types.MessageID // The ID of the message.
ChatID types.JID // The chat ID where the message was sent.
SenderID types.JID // The user who sent the message. Only present in groups.
FromMe bool // Whether the message was sent by the current user or someone else.
}