slidge 0.1.0rc1__py3-none-any.whl → 0.1.2__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. slidge/__init__.py +54 -31
  2. slidge/__main__.py +51 -5
  3. slidge/command/__init__.py +28 -0
  4. slidge/command/adhoc.py +258 -0
  5. slidge/command/admin.py +193 -0
  6. slidge/command/base.py +441 -0
  7. slidge/command/categories.py +3 -0
  8. slidge/command/chat_command.py +288 -0
  9. slidge/command/register.py +179 -0
  10. slidge/command/user.py +250 -0
  11. slidge/contact/__init__.py +8 -0
  12. slidge/contact/contact.py +452 -0
  13. slidge/contact/roster.py +192 -0
  14. slidge/core/__init__.py +2 -0
  15. slidge/core/cache.py +121 -39
  16. slidge/core/config.py +116 -11
  17. slidge/core/gateway/__init__.py +3 -0
  18. slidge/core/gateway/base.py +895 -0
  19. slidge/core/gateway/caps.py +63 -0
  20. slidge/core/gateway/delivery_receipt.py +52 -0
  21. slidge/core/gateway/disco.py +80 -0
  22. slidge/core/gateway/mam.py +75 -0
  23. slidge/core/gateway/muc_admin.py +35 -0
  24. slidge/core/gateway/ping.py +66 -0
  25. slidge/core/gateway/presence.py +95 -0
  26. slidge/core/gateway/registration.py +53 -0
  27. slidge/core/gateway/search.py +102 -0
  28. slidge/core/gateway/session_dispatcher.py +795 -0
  29. slidge/core/gateway/vcard_temp.py +130 -0
  30. slidge/core/mixins/__init__.py +9 -1
  31. slidge/core/mixins/attachment.py +506 -0
  32. slidge/core/mixins/avatar.py +167 -0
  33. slidge/core/mixins/base.py +6 -19
  34. slidge/core/mixins/disco.py +66 -15
  35. slidge/core/mixins/lock.py +31 -0
  36. slidge/core/mixins/message.py +254 -252
  37. slidge/core/mixins/message_maker.py +154 -0
  38. slidge/core/mixins/presence.py +128 -31
  39. slidge/core/mixins/recipient.py +43 -0
  40. slidge/core/pubsub.py +275 -116
  41. slidge/core/session.py +586 -518
  42. slidge/group/__init__.py +10 -0
  43. slidge/group/archive.py +125 -0
  44. slidge/group/bookmarks.py +163 -0
  45. slidge/group/participant.py +458 -0
  46. slidge/group/room.py +1103 -0
  47. slidge/migration.py +18 -0
  48. slidge/slixfix/__init__.py +68 -0
  49. slidge/{util/xep_0050 → slixfix/link_preview}/__init__.py +4 -5
  50. slidge/slixfix/link_preview/link_preview.py +17 -0
  51. slidge/slixfix/link_preview/stanza.py +99 -0
  52. slidge/slixfix/roster.py +60 -0
  53. slidge/{util → slixfix}/xep_0077/register.py +1 -2
  54. slidge/slixfix/xep_0077/stanza.py +104 -0
  55. slidge/{util → slixfix}/xep_0100/gateway.py +17 -12
  56. slidge/slixfix/xep_0153/__init__.py +10 -0
  57. slidge/slixfix/xep_0153/stanza.py +25 -0
  58. slidge/slixfix/xep_0153/vcard_avatar.py +23 -0
  59. slidge/slixfix/xep_0264/__init__.py +5 -0
  60. slidge/slixfix/xep_0264/stanza.py +36 -0
  61. slidge/slixfix/xep_0264/thumbnail.py +23 -0
  62. slidge/slixfix/xep_0292/__init__.py +5 -0
  63. slidge/slixfix/xep_0292/vcard4.py +100 -0
  64. slidge/slixfix/xep_0313/__init__.py +12 -0
  65. slidge/slixfix/xep_0313/mam.py +262 -0
  66. slidge/slixfix/xep_0313/stanza.py +359 -0
  67. slidge/slixfix/xep_0317/__init__.py +5 -0
  68. slidge/slixfix/xep_0317/hats.py +17 -0
  69. slidge/slixfix/xep_0317/stanza.py +28 -0
  70. slidge/{util → slixfix}/xep_0356_old/privilege.py +9 -7
  71. slidge/slixfix/xep_0424/__init__.py +9 -0
  72. slidge/slixfix/xep_0424/retraction.py +77 -0
  73. slidge/slixfix/xep_0424/stanza.py +28 -0
  74. slidge/slixfix/xep_0490/__init__.py +8 -0
  75. slidge/slixfix/xep_0490/mds.py +47 -0
  76. slidge/slixfix/xep_0490/stanza.py +17 -0
  77. slidge/util/__init__.py +4 -6
  78. slidge/util/archive_msg.py +61 -0
  79. slidge/util/conf.py +25 -4
  80. slidge/util/db.py +23 -69
  81. slidge/util/schema.sql +126 -0
  82. slidge/util/sql.py +508 -0
  83. slidge/util/test.py +136 -86
  84. slidge/util/types.py +155 -14
  85. slidge/util/util.py +225 -51
  86. slidge-0.1.2.dist-info/METADATA +111 -0
  87. slidge-0.1.2.dist-info/RECORD +96 -0
  88. {slidge-0.1.0rc1.dist-info → slidge-0.1.2.dist-info}/WHEEL +1 -1
  89. slidge/core/adhoc.py +0 -492
  90. slidge/core/chat_command.py +0 -197
  91. slidge/core/contact.py +0 -441
  92. slidge/core/disco.py +0 -59
  93. slidge/core/gateway.py +0 -899
  94. slidge/core/muc/__init__.py +0 -3
  95. slidge/core/muc/bookmarks.py +0 -74
  96. slidge/core/muc/participant.py +0 -152
  97. slidge/core/muc/room.py +0 -348
  98. slidge/plugins/discord/__init__.py +0 -121
  99. slidge/plugins/discord/client.py +0 -121
  100. slidge/plugins/discord/session.py +0 -172
  101. slidge/plugins/dummy.py +0 -334
  102. slidge/plugins/facebook.py +0 -591
  103. slidge/plugins/hackernews.py +0 -209
  104. slidge/plugins/mattermost/__init__.py +0 -1
  105. slidge/plugins/mattermost/api.py +0 -288
  106. slidge/plugins/mattermost/gateway.py +0 -417
  107. slidge/plugins/mattermost/websocket.py +0 -248
  108. slidge/plugins/signal/__init__.py +0 -4
  109. slidge/plugins/signal/config.py +0 -4
  110. slidge/plugins/signal/contact.py +0 -104
  111. slidge/plugins/signal/gateway.py +0 -379
  112. slidge/plugins/signal/group.py +0 -76
  113. slidge/plugins/signal/session.py +0 -515
  114. slidge/plugins/signal/txt.py +0 -13
  115. slidge/plugins/signal/util.py +0 -32
  116. slidge/plugins/skype.py +0 -310
  117. slidge/plugins/steam.py +0 -400
  118. slidge/plugins/telegram/__init__.py +0 -6
  119. slidge/plugins/telegram/client.py +0 -325
  120. slidge/plugins/telegram/config.py +0 -21
  121. slidge/plugins/telegram/contact.py +0 -154
  122. slidge/plugins/telegram/gateway.py +0 -182
  123. slidge/plugins/telegram/group.py +0 -184
  124. slidge/plugins/telegram/session.py +0 -275
  125. slidge/plugins/telegram/util.py +0 -153
  126. slidge/plugins/whatsapp/__init__.py +0 -6
  127. slidge/plugins/whatsapp/config.py +0 -17
  128. slidge/plugins/whatsapp/contact.py +0 -33
  129. slidge/plugins/whatsapp/event.go +0 -455
  130. slidge/plugins/whatsapp/gateway.go +0 -156
  131. slidge/plugins/whatsapp/gateway.py +0 -69
  132. slidge/plugins/whatsapp/go.mod +0 -17
  133. slidge/plugins/whatsapp/go.sum +0 -22
  134. slidge/plugins/whatsapp/session.go +0 -371
  135. slidge/plugins/whatsapp/session.py +0 -370
  136. slidge/util/xep_0030/__init__.py +0 -13
  137. slidge/util/xep_0030/disco.py +0 -811
  138. slidge/util/xep_0030/stanza/__init__.py +0 -7
  139. slidge/util/xep_0030/stanza/info.py +0 -270
  140. slidge/util/xep_0030/stanza/items.py +0 -147
  141. slidge/util/xep_0030/static.py +0 -467
  142. slidge/util/xep_0050/adhoc.py +0 -631
  143. slidge/util/xep_0050/stanza.py +0 -180
  144. slidge/util/xep_0077/stanza.py +0 -71
  145. slidge/util/xep_0292/__init__.py +0 -1
  146. slidge/util/xep_0292/stanza.py +0 -167
  147. slidge/util/xep_0292/vcard4.py +0 -74
  148. slidge/util/xep_0356/__init__.py +0 -7
  149. slidge/util/xep_0356/permissions.py +0 -35
  150. slidge/util/xep_0356/privilege.py +0 -160
  151. slidge/util/xep_0356/stanza.py +0 -44
  152. slidge/util/xep_0461/__init__.py +0 -6
  153. slidge/util/xep_0461/reply.py +0 -48
  154. slidge/util/xep_0461/stanza.py +0 -80
  155. slidge-0.1.0rc1.dist-info/METADATA +0 -171
  156. slidge-0.1.0rc1.dist-info/RECORD +0 -99
  157. /slidge/{plugins/__init__.py → py.typed} +0 -0
  158. /slidge/{util → slixfix}/xep_0077/__init__.py +0 -0
  159. /slidge/{util → slixfix}/xep_0100/__init__.py +0 -0
  160. /slidge/{util → slixfix}/xep_0100/stanza.py +0 -0
  161. /slidge/{util → slixfix}/xep_0356_old/__init__.py +0 -0
  162. /slidge/{util → slixfix}/xep_0356_old/stanza.py +0 -0
  163. {slidge-0.1.0rc1.dist-info → slidge-0.1.2.dist-info}/LICENSE +0 -0
  164. {slidge-0.1.0rc1.dist-info → slidge-0.1.2.dist-info}/entry_points.txt +0 -0
@@ -1,22 +0,0 @@
1
- filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
2
- filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
3
- github.com/go-python/gopy v0.4.5 h1:cwnd24UKA91vFFZoRvavb/vzBSKV99Gp3+2d5+jTG0U=
4
- github.com/go-python/gopy v0.4.5/go.mod h1:tlA/KcD7rM8B+NQJR4SASwiinfKY0aiMFanHszR8BZA=
5
- github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
6
- github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
7
- github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
8
- github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
9
- github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
10
- github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
11
- github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
12
- go.mau.fi/libsignal v0.0.0-20221015105917-d970e7c3c9cf h1:mzPxXBgDPHKDHMVV1tIWh7lwCiRpzCsXC0gNRX+K07c=
13
- go.mau.fi/libsignal v0.0.0-20221015105917-d970e7c3c9cf/go.mod h1:XCjaU93vl71YNRPn059jMrK0xRDwVO5gKbxoPxow9mQ=
14
- go.mau.fi/whatsmeow v0.0.0-20221213225758-70ef67df3c68 h1:uieThnMYyFDdUNDrHxauuZOW5ip+igWhHwyWFNjA2Sw=
15
- go.mau.fi/whatsmeow v0.0.0-20221213225758-70ef67df3c68/go.mod h1:2yweL8nczvtlIxkrvCb0y8xiO13rveX9lJPambwYV/E=
16
- golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg=
17
- golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
18
- golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
19
- golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
20
- google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
21
- google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
22
- google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
@@ -1,371 +0,0 @@
1
- package whatsapp
2
-
3
- import (
4
- // Standard library.
5
- "context"
6
- "fmt"
7
- "io"
8
- "runtime"
9
- "time"
10
-
11
- // Third-party libraries.
12
- _ "github.com/mattn/go-sqlite3"
13
- "go.mau.fi/whatsmeow"
14
- "go.mau.fi/whatsmeow/appstate"
15
- "go.mau.fi/whatsmeow/binary/proto"
16
- "go.mau.fi/whatsmeow/store"
17
- "go.mau.fi/whatsmeow/types"
18
- "go.mau.fi/whatsmeow/types/events"
19
- )
20
-
21
- const (
22
- // The default host part for user JIDs on WhatsApp.
23
- DefaultUserServer = types.DefaultUserServer
24
- )
25
-
26
- // HandleEventFunc represents a handler for incoming events sent to the Python Session, accepting an
27
- // event type and payload. Note that this is distinct to the [Session.handleEvent] function, which
28
- // may emit events into the Python Session event handler but which otherwise does not process across
29
- // Python/Go boundaries.
30
- type HandleEventFunc func(EventKind, *EventPayload)
31
-
32
- // A Session represents a connection (active or not) between a linked device and WhatsApp. Active
33
- // sessions need to be established by logging in, after which incoming events will be forwarded to
34
- // the adapter event handler, and outgoing events will be forwarded to WhatsApp.
35
- type Session struct {
36
- device LinkedDevice // The linked device this session corresponds to.
37
- eventHandler HandleEventFunc // The event handler for the overarching Session.
38
- client *whatsmeow.Client // The concrete client connection to WhatsApp for this session.
39
- gateway *Gateway // The Gateway this Session is attached to.
40
- }
41
-
42
- // Login attempts to authenticate the given [Session], either by re-using the [LinkedDevice] attached
43
- // or by initiating a pairing session for a new linked device. Callers are expected to have set an
44
- // event handler in order to receive any incoming events from the underlying WhatsApp session.
45
- func (s *Session) Login() error {
46
- var err error
47
- var store *store.Device
48
-
49
- // Try to fetch existing device from given device JID.
50
- if s.device.ID != "" {
51
- store, err = s.gateway.container.GetDevice(s.device.JID())
52
- if err != nil {
53
- return err
54
- }
55
- }
56
-
57
- if store == nil {
58
- store = s.gateway.container.NewDevice()
59
- }
60
-
61
- s.client = whatsmeow.NewClient(store, s.gateway.logger)
62
- s.client.AddEventHandler(s.handleEvent)
63
-
64
- // Simply connect our client if already registered.
65
- if s.client.Store.ID != nil {
66
- return s.client.Connect()
67
- }
68
-
69
- // Attempt out-of-band registration of client via QR code.
70
- qrChan, _ := s.client.GetQRChannel(context.Background())
71
- if err = s.client.Connect(); err != nil {
72
- return err
73
- }
74
-
75
- go func() {
76
- for e := range qrChan {
77
- if !s.client.IsConnected() {
78
- return
79
- }
80
- switch e.Event {
81
- case "code":
82
- s.propagateEvent(EventQRCode, &EventPayload{QRCode: e.Code})
83
- }
84
- }
85
- }()
86
-
87
- return nil
88
- }
89
-
90
- // Logout disconnects and removes the current linked device locally and initiates a logout remotely.
91
- func (s *Session) Logout() error {
92
- if s.client == nil || s.client.Store.ID == nil {
93
- return nil
94
- }
95
-
96
- err := s.client.Logout()
97
- s.client = nil
98
-
99
- return err
100
- }
101
-
102
- // Disconnects detaches the current connection to WhatsApp without removing any linked device state.
103
- func (s *Session) Disconnect() error {
104
- if s.client != nil {
105
- s.client.Disconnect()
106
- s.client = nil
107
- }
108
-
109
- return nil
110
- }
111
-
112
- // SendMessage processes the given Message and sends a WhatsApp message for the kind and contact JID
113
- // specified within. In general, different message kinds require different fields to be set; see the
114
- // documentation for the [Message] type for more information.
115
- func (s *Session) SendMessage(message Message) error {
116
- if s.client == nil || s.client.Store.ID == nil {
117
- return fmt.Errorf("Cannot send message for unauthenticated session")
118
- }
119
-
120
- jid, err := types.ParseJID(message.JID)
121
- if err != nil {
122
- return fmt.Errorf("Could not parse sender JID for message: %s", err)
123
- }
124
-
125
- var payload *proto.Message
126
- var messageID string
127
-
128
- switch message.Kind {
129
- case MessageAttachment:
130
- // Handle message with attachment, if any.
131
- if len(message.Attachments) == 0 {
132
- return nil
133
- }
134
-
135
- // Attempt to download attachment data if URL is set.
136
- if url := message.Attachments[0].URL; url != "" {
137
- if resp, err := s.gateway.httpClient.Get(url); err != nil {
138
- return fmt.Errorf("Failed downloading attachment: %s", err)
139
- } else if buf, err := io.ReadAll(resp.Body); err != nil {
140
- return fmt.Errorf("Failed downloading attachment: %s", err)
141
- } else {
142
- resp.Body.Close()
143
- message.Attachments[0].Data = buf
144
- }
145
- }
146
-
147
- // Ignore attachments with no data set or downloaded.
148
- if len(message.Attachments[0].Data) == 0 {
149
- return nil
150
- }
151
-
152
- // Upload attachment into WhatsApp before sending message.
153
- if payload, err = uploadAttachment(s.client, message.Attachments[0]); err != nil {
154
- return fmt.Errorf("Failed uploading attachment: %s", err)
155
- }
156
- messageID = message.ID
157
- case MessageRevoke:
158
- // Don't send message, but revoke existing message by ID.
159
- payload = s.client.BuildRevoke(s.device.JID().ToNonAD(), types.EmptyJID, message.ID)
160
- case MessageReaction:
161
- // Send message as emoji reaction to a given message.
162
- payload = &proto.Message{
163
- ReactionMessage: &proto.ReactionMessage{
164
- Key: &proto.MessageKey{
165
- RemoteJid: &message.JID,
166
- FromMe: &message.IsCarbon,
167
- Id: &message.ID,
168
- },
169
- Text: &message.Body,
170
- SenderTimestampMs: ptrTo(time.Now().UnixMilli()),
171
- },
172
- }
173
- default:
174
- // Compose extended message when made as a reply to a different message, otherwise compose
175
- // plain-text message for body given for all other message kinds.
176
- if message.ReplyID != "" {
177
- payload = &proto.Message{
178
- ExtendedTextMessage: &proto.ExtendedTextMessage{
179
- Text: &message.Body,
180
- ContextInfo: &proto.ContextInfo{
181
- StanzaId: &message.ReplyID,
182
- QuotedMessage: &proto.Message{Conversation: ptrTo(message.ReplyBody)},
183
- },
184
- },
185
- }
186
- } else {
187
- payload = &proto.Message{Conversation: &message.Body}
188
- }
189
- messageID = message.ID
190
- }
191
-
192
- _, err = s.client.SendMessage(context.Background(), jid, messageID, payload)
193
- return err
194
- }
195
-
196
- // SendChatState sends the given chat state notification (e.g. composing message) to WhatsApp for the
197
- // contact specified within.
198
- func (s *Session) SendChatState(state ChatState) error {
199
- if s.client == nil || s.client.Store.ID == nil {
200
- return fmt.Errorf("Cannot send chat state for unauthenticated session")
201
- }
202
-
203
- jid, err := types.ParseJID(state.JID)
204
- if err != nil {
205
- return fmt.Errorf("Could not parse sender JID for chat state: %s", err)
206
- }
207
-
208
- var presence types.ChatPresence
209
- switch state.Kind {
210
- case ChatStateComposing:
211
- presence = types.ChatPresenceComposing
212
- case ChatStatePaused:
213
- presence = types.ChatPresencePaused
214
- }
215
-
216
- return s.client.SendChatPresence(jid, presence, "")
217
- }
218
-
219
- // SendReceipt sends a read receipt to WhatsApp for the message IDs specified within.
220
- func (s *Session) SendReceipt(receipt Receipt) error {
221
- if s.client == nil || s.client.Store.ID == nil {
222
- return fmt.Errorf("Cannot send receipt for unauthenticated session")
223
- }
224
-
225
- jid, err := types.ParseJID(receipt.JID)
226
- if err != nil {
227
- return fmt.Errorf("Could not parse sender JID for receipt: %s", err)
228
- }
229
-
230
- ids := append([]types.MessageID{}, receipt.MessageIDs...)
231
- return s.client.MarkRead(ids, time.Unix(receipt.Timestamp, 0), jid, types.EmptyJID)
232
- }
233
-
234
- // FetchRoster subscribes to the WhatsApp roster currently stored in the Session's internal state.
235
- // If `refresh` is `true`, FetchRoster will pull application state from the remote service and
236
- // synchronize any contacts found with the adapter.
237
- func (s *Session) FetchRoster(refresh bool) error {
238
- if s.client == nil || s.client.Store.ID == nil {
239
- return fmt.Errorf("Cannot fetch roster for unauthenticated session")
240
- }
241
-
242
- // Synchronize remote application state with local state if requested.
243
- if refresh {
244
- err := s.client.FetchAppState(appstate.WAPatchCriticalUnblockLow, false, false)
245
- if err != nil {
246
- s.gateway.logger.Warnf("Could not fetch app state from server: %s", err)
247
- }
248
- }
249
-
250
- // Synchronize local contact state with overarching gateway for all local contacts.
251
- contacts, err := s.client.Store.Contacts.GetAllContacts()
252
- if err != nil {
253
- return fmt.Errorf("Failed fetching local contacts for %s", s.device.ID)
254
- }
255
-
256
- for jid, info := range contacts {
257
- if err = s.client.SubscribePresence(jid); err != nil {
258
- s.gateway.logger.Warnf("Failed to subscribe to presence for %s", jid)
259
- }
260
-
261
- go s.propagateEvent(newContactSyncEvent(s.client, jid, info))
262
- }
263
-
264
- return nil
265
- }
266
-
267
- // SetEventHandler assigns the given handler function for propagating internal events into the Python
268
- // gateway. Note that the event handler function is not entirely safe to use directly, and all calls
269
- // should instead be made via the [propagateEvent] function.
270
- func (s *Session) SetEventHandler(h HandleEventFunc) {
271
- s.eventHandler = h
272
- }
273
-
274
- // PropagateEvent handles the given event kind and payload with the adapter event handler defined in
275
- // SetEventHandler. If no event handler is set, this function will return early with no error.
276
- func (s *Session) propagateEvent(kind EventKind, payload *EventPayload) {
277
- if s.eventHandler == nil {
278
- s.gateway.logger.Errorf("Event handler not set when propagating event %d with payload %v", kind, payload)
279
- return
280
- } else if kind == EventUnknown {
281
- return
282
- }
283
-
284
- // Send empty payload instead of a nil pointer, as Python has trouble handling the latter.
285
- if payload == nil {
286
- payload = &EventPayload{}
287
- }
288
-
289
- // Don't allow other Goroutines from using this thread, as this might lead to concurrent use of
290
- // the GIL, which can lead to crashes.
291
- runtime.LockOSThread()
292
- defer runtime.UnlockOSThread()
293
-
294
- s.eventHandler(kind, payload)
295
- }
296
-
297
- // HandleEvent processes the given incoming WhatsApp event, checking its concrete type and
298
- // propagating it to the adapter event handler. Unknown or unhandled events are ignored, and any
299
- // errors that occur during processing are logged.
300
- func (s *Session) handleEvent(evt interface{}) {
301
- s.gateway.logger.Debugf("Handling event: %#v", evt)
302
-
303
- switch evt := evt.(type) {
304
- case *events.AppStateSyncComplete:
305
- if len(s.client.Store.PushName) > 0 && evt.Name == appstate.WAPatchCriticalBlock {
306
- s.propagateEvent(EventConnected, nil)
307
- if err := s.client.SendPresence(types.PresenceAvailable); err != nil {
308
- s.gateway.logger.Warnf("Failed to send available presence: %s", err)
309
- }
310
- }
311
- case *events.Connected, *events.PushNameSetting:
312
- if len(s.client.Store.PushName) == 0 {
313
- return
314
- }
315
- s.propagateEvent(EventConnected, nil)
316
- if err := s.client.SendPresence(types.PresenceAvailable); err != nil {
317
- s.gateway.logger.Warnf("Failed to send available presence: %s", err)
318
- }
319
- case *events.HistorySync:
320
- switch evt.Data.GetSyncType() {
321
- case proto.HistorySync_PUSH_NAME:
322
- for _, n := range evt.Data.Pushnames {
323
- jid, err := types.ParseJID(n.GetId())
324
- if err != nil {
325
- continue
326
- }
327
- s.propagateEvent(newContactSyncEvent(s.client, jid, types.ContactInfo{FullName: n.GetPushname()}))
328
- if err = s.client.SubscribePresence(jid); err != nil {
329
- s.gateway.logger.Warnf("Failed to subscribe to presence for %s", jid)
330
- }
331
- }
332
- }
333
- case *events.Message:
334
- s.propagateEvent(newMessageEvent(s.client, evt))
335
- case *events.Receipt:
336
- s.propagateEvent(newReceiptEvent(evt))
337
- case *events.Presence:
338
- s.propagateEvent(newPresenceEvent(evt))
339
- case *events.PushName:
340
- s.propagateEvent(newContactSyncEvent(s.client, evt.JID, types.ContactInfo{FullName: evt.NewPushName}))
341
- case *events.ChatPresence:
342
- s.propagateEvent(newChatStateEvent(evt))
343
- case *events.CallTerminate:
344
- if evt.Reason == "timeout" {
345
- s.propagateEvent(newCallEvent(CallMissed, evt.BasicCallMeta))
346
- }
347
- case *events.LoggedOut:
348
- s.client.Disconnect()
349
- if err := s.client.Store.Delete(); err != nil {
350
- s.gateway.logger.Warnf("Unable to delete local device state on logout: %s", err)
351
- }
352
- s.client = nil
353
- s.propagateEvent(EventLoggedOut, nil)
354
- case *events.PairSuccess:
355
- if s.client.Store.ID == nil {
356
- s.gateway.logger.Errorf("Pairing succeeded, but device ID is missing")
357
- return
358
- }
359
- deviceID := s.client.Store.ID.String()
360
- s.propagateEvent(EventPairSuccess, &EventPayload{PairDeviceID: deviceID})
361
- if err := s.gateway.CleanupSession(LinkedDevice{ID: deviceID}); err != nil {
362
- s.gateway.logger.Warnf("Failed to clean up devices after pair: %s", err)
363
- }
364
- }
365
- }
366
-
367
- // PtrTo returns a pointer to the given value, and is used for convenience when converting between
368
- // concrete and pointer values without assigning to a variable.
369
- func ptrTo[T any](t T) *T {
370
- return &t
371
- }