slidge-whatsapp 0.2.6__cp312-cp312-manylinux_2_36_aarch64.whl → 0.2.7__cp312-cp312-manylinux_2_36_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of slidge-whatsapp might be problematic. Click here for more details.

Files changed (87) hide show
  1. slidge_whatsapp/event.go +8 -2
  2. slidge_whatsapp/generated/_whatsapp.cpython-312-aarch64-linux-gnu.h +164 -164
  3. slidge_whatsapp/generated/_whatsapp.cpython-312-aarch64-linux-gnu.so +0 -0
  4. slidge_whatsapp/generated/build.py +130 -130
  5. slidge_whatsapp/generated/whatsapp.c +1504 -1504
  6. slidge_whatsapp/generated/whatsapp.go +1021 -1021
  7. slidge_whatsapp/generated/whatsapp.py +1209 -1209
  8. slidge_whatsapp/generated/whatsapp_go.h +164 -164
  9. slidge_whatsapp/go.mod +6 -6
  10. slidge_whatsapp/go.sum +12 -18
  11. slidge_whatsapp/media/media.go +5 -1
  12. slidge_whatsapp/vendor/go.mau.fi/util/exhttp/json.go +1 -6
  13. slidge_whatsapp/vendor/go.mau.fi/util/exstrings/stringutil.go +76 -0
  14. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/armadillomessage.go +38 -6
  15. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/binary/encoder.go +1 -1
  16. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/call.go +1 -1
  17. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/client.go +64 -27
  18. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/connectionevents.go +8 -6
  19. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/download-to-file.go +19 -12
  20. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/download.go +22 -6
  21. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/group.go +2 -2
  22. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/internals.go +33 -17
  23. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/keepalive.go +1 -0
  24. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/message.go +198 -48
  25. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/notification.go +12 -7
  26. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/extra.go +7 -0
  27. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloAddMessage/InstamadilloAddMessage.pb.go +983 -0
  28. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloAddMessage/InstamadilloAddMessage.proto +85 -0
  29. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloAddMessage/extra.go +3 -0
  30. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloCoreTypeActionLog/InstamadilloCoreTypeActionLog.pb.go +197 -0
  31. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloCoreTypeActionLog/InstamadilloCoreTypeActionLog.proto +13 -0
  32. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloCoreTypeAdminMessage/InstamadilloCoreTypeAdminMessage.pb.go +279 -0
  33. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloCoreTypeAdminMessage/InstamadilloCoreTypeAdminMessage.proto +21 -0
  34. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloCoreTypeCollection/InstamadilloCoreTypeCollection.pb.go +137 -0
  35. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloCoreTypeCollection/InstamadilloCoreTypeCollection.proto +10 -0
  36. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloCoreTypeLink/InstamadilloCoreTypeLink.pb.go +313 -0
  37. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloCoreTypeLink/InstamadilloCoreTypeLink.proto +27 -0
  38. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.pb.go +1299 -0
  39. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.proto +112 -0
  40. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloCoreTypeText/InstamadilloCoreTypeText.pb.go +514 -0
  41. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloCoreTypeText/InstamadilloCoreTypeText.proto +47 -0
  42. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloDeleteMessage/InstamadilloDeleteMessage.pb.go +123 -0
  43. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloDeleteMessage/InstamadilloDeleteMessage.proto +7 -0
  44. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloDeleteMessage/extra.go +3 -0
  45. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloSupplementMessage/InstamadilloSupplementMessage.pb.go +720 -0
  46. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloSupplementMessage/InstamadilloSupplementMessage.proto +59 -0
  47. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloSupplementMessage/extra.go +3 -0
  48. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloTransportPayload/InstamadilloTransportPayload.pb.go +365 -0
  49. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloTransportPayload/InstamadilloTransportPayload.proto +33 -0
  50. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloXmaContentRef/InstamadilloXmaContentRef.pb.go +1238 -0
  51. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/instamadilloXmaContentRef/InstamadilloXmaContentRef.proto +105 -0
  52. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waArmadilloXMA/WAArmadilloXMA.pb.go +16 -4
  53. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waArmadilloXMA/WAArmadilloXMA.proto +3 -0
  54. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waCompanionReg/WACompanionReg.pb.go +16 -7
  55. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waCompanionReg/WACompanionReg.proto +1 -0
  56. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waE2E/WAWebProtobufsE2E.pb.go +2436 -1676
  57. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waE2E/WAWebProtobufsE2E.proto +85 -7
  58. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waLidMigrationSyncPayload/WAWebProtobufLidMigrationSyncPayload.pb.go +198 -0
  59. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waLidMigrationSyncPayload/WAWebProtobufLidMigrationSyncPayload.proto +14 -0
  60. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waMsgTransport/extra.go +7 -6
  61. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waStatusAttributions/WAStatusAttributions.pb.go +800 -0
  62. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waStatusAttributions/WAStatusAttributions.proto +72 -0
  63. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waSyncAction/WASyncAction.pb.go +678 -441
  64. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waSyncAction/WASyncAction.proto +20 -0
  65. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waWeb/WAWebProtobufsWeb.pb.go +11 -3
  66. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waWeb/WAWebProtobufsWeb.proto +2 -0
  67. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/receipt.go +13 -7
  68. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/reportingfields.json +1 -0
  69. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/reportingtoken.go +176 -0
  70. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/retry.go +10 -2
  71. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/send.go +32 -17
  72. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/sendfb.go +1 -0
  73. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/store/clientpayload.go +1 -1
  74. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/store/sqlstore/container.go +9 -6
  75. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/store/sqlstore/upgrades/00-latest-schema.sql +4 -2
  76. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/store/sqlstore/upgrades/10-chat-db-lid-migration-ts.sql +2 -0
  77. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/store/store.go +2 -0
  78. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/types/events/events.go +5 -2
  79. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/types/message.go +1 -0
  80. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/user.go +2 -0
  81. slidge_whatsapp/vendor/golang.org/x/net/http2/frame.go +8 -8
  82. slidge_whatsapp/vendor/modules.txt +20 -6
  83. {slidge_whatsapp-0.2.6.dist-info → slidge_whatsapp-0.2.7.dist-info}/METADATA +1 -1
  84. {slidge_whatsapp-0.2.6.dist-info → slidge_whatsapp-0.2.7.dist-info}/RECORD +87 -54
  85. {slidge_whatsapp-0.2.6.dist-info → slidge_whatsapp-0.2.7.dist-info}/LICENSE +0 -0
  86. {slidge_whatsapp-0.2.6.dist-info → slidge_whatsapp-0.2.7.dist-info}/WHEEL +0 -0
  87. {slidge_whatsapp-0.2.6.dist-info → slidge_whatsapp-0.2.7.dist-info}/entry_points.txt +0 -0
@@ -13,7 +13,7 @@ import (
13
13
  )
14
14
 
15
15
  func (cli *Client) handleCallEvent(node *waBinary.Node) {
16
- defer cli.maybeDeferredAck(node)()
16
+ defer cli.maybeDeferredAck(cli.BackgroundEventCtx, node)()
17
17
 
18
18
  if len(node.GetChildren()) != 1 {
19
19
  cli.dispatchEvent(&events.UnknownCallEvent{Node: node})
@@ -21,6 +21,7 @@ import (
21
21
 
22
22
  "github.com/gorilla/websocket"
23
23
  "go.mau.fi/util/exhttp"
24
+ "go.mau.fi/util/exsync"
24
25
  "go.mau.fi/util/random"
25
26
  "golang.org/x/net/proxy"
26
27
 
@@ -39,12 +40,13 @@ import (
39
40
 
40
41
  // EventHandler is a function that can handle events from WhatsApp.
41
42
  type EventHandler func(evt any)
43
+ type EventHandlerWithSuccessStatus func(evt any) bool
42
44
  type nodeHandler func(node *waBinary.Node)
43
45
 
44
46
  var nextHandlerID uint32
45
47
 
46
48
  type wrappedEventHandler struct {
47
- fn EventHandler
49
+ fn EventHandlerWithSuccessStatus
48
50
  id uint32
49
51
  }
50
52
 
@@ -66,7 +68,7 @@ type Client struct {
66
68
  wsDialer *websocket.Dialer
67
69
 
68
70
  isLoggedIn atomic.Bool
69
- expectedDisconnect atomic.Bool
71
+ expectedDisconnect *exsync.Event
70
72
  EnableAutoReconnect bool
71
73
  InitialAutoReconnect bool
72
74
  LastSuccessfulConnect time.Time
@@ -96,6 +98,7 @@ type Client struct {
96
98
 
97
99
  historySyncNotifications chan *waE2E.HistorySyncNotification
98
100
  historySyncHandlerStarted atomic.Bool
101
+ ManualHistorySyncDownload bool
99
102
 
100
103
  uploadPreKeysLock sync.Mutex
101
104
  lastPreKeyUpload time.Time
@@ -159,6 +162,10 @@ type Client struct {
159
162
  // Should SubscribePresence return an error if no privacy token is stored for the user?
160
163
  ErrorOnSubscribePresenceWithoutToken bool
161
164
 
165
+ SendReportingTokens bool
166
+
167
+ BackgroundEventCtx context.Context
168
+
162
169
  phoneLinkingCache *phoneLinkingCache
163
170
 
164
171
  uniqueID string
@@ -175,7 +182,7 @@ type Client struct {
175
182
  // separate library for all the non-e2ee-related stuff like logging in.
176
183
  // The library is currently embedded in mautrix-meta (https://github.com/mautrix/meta), but may be separated later.
177
184
  MessengerConfig *MessengerConfig
178
- RefreshCAT func() error
185
+ RefreshCAT func(context.Context) error
179
186
  }
180
187
 
181
188
  type groupMetaCache struct {
@@ -219,18 +226,19 @@ func NewClient(deviceStore *store.Device, log waLog.Logger) *Client {
219
226
  http: &http.Client{
220
227
  Transport: (http.DefaultTransport.(*http.Transport)).Clone(),
221
228
  },
222
- proxy: http.ProxyFromEnvironment,
223
- Store: deviceStore,
224
- Log: log,
225
- recvLog: log.Sub("Recv"),
226
- sendLog: log.Sub("Send"),
227
- uniqueID: fmt.Sprintf("%d.%d-", uniqueIDPrefix[0], uniqueIDPrefix[1]),
228
- responseWaiters: make(map[string]chan<- *waBinary.Node),
229
- eventHandlers: make([]wrappedEventHandler, 0, 1),
230
- messageRetries: make(map[string]int),
231
- handlerQueue: make(chan *waBinary.Node, handlerQueueSize),
232
- appStateProc: appstate.NewProcessor(deviceStore, log.Sub("AppState")),
233
- socketWait: make(chan struct{}),
229
+ proxy: http.ProxyFromEnvironment,
230
+ Store: deviceStore,
231
+ Log: log,
232
+ recvLog: log.Sub("Recv"),
233
+ sendLog: log.Sub("Send"),
234
+ uniqueID: fmt.Sprintf("%d.%d-", uniqueIDPrefix[0], uniqueIDPrefix[1]),
235
+ responseWaiters: make(map[string]chan<- *waBinary.Node),
236
+ eventHandlers: make([]wrappedEventHandler, 0, 1),
237
+ messageRetries: make(map[string]int),
238
+ handlerQueue: make(chan *waBinary.Node, handlerQueueSize),
239
+ appStateProc: appstate.NewProcessor(deviceStore, log.Sub("AppState")),
240
+ socketWait: make(chan struct{}),
241
+ expectedDisconnect: exsync.NewEvent(),
234
242
 
235
243
  incomingRetryRequestCounter: make(map[incomingRetryKey]int),
236
244
 
@@ -248,6 +256,8 @@ func NewClient(deviceStore *store.Device, log waLog.Logger) *Client {
248
256
 
249
257
  EnableAutoReconnect: true,
250
258
  AutoTrustIdentity: true,
259
+
260
+ BackgroundEventCtx: context.Background(),
251
261
  }
252
262
  cli.nodeHandlers = map[string]nodeHandler{
253
263
  "message": cli.handleEncryptedMessage,
@@ -411,6 +421,8 @@ func (cli *Client) WaitForConnection(timeout time.Duration) bool {
411
421
  case <-ch:
412
422
  case <-timeoutChan:
413
423
  return false
424
+ case <-cli.expectedDisconnect.GetChan():
425
+ return false
414
426
  }
415
427
  cli.socketLock.RLock()
416
428
  }
@@ -425,9 +437,16 @@ func (cli *Client) SetWSDialer(dialer *websocket.Dialer) {
425
437
  // Connect connects the client to the WhatsApp web websocket. After connection, it will either
426
438
  // authenticate if there's data in the device store, or emit a QREvent to set up a new link.
427
439
  func (cli *Client) Connect() error {
428
- err := cli.connect()
440
+ if cli == nil {
441
+ return ErrClientIsNil
442
+ }
443
+
444
+ cli.socketLock.Lock()
445
+ defer cli.socketLock.Unlock()
446
+
447
+ err := cli.unlockedConnect()
429
448
  if exhttp.IsNetworkError(err) && cli.InitialAutoReconnect && cli.EnableAutoReconnect {
430
- cli.Log.Errorf("Initial connection failed but reconnecting in background")
449
+ cli.Log.Errorf("Initial connection failed but reconnecting in background (%v)", err)
431
450
  go cli.dispatchEvent(&events.Disconnected{})
432
451
  go cli.autoReconnect()
433
452
  return nil
@@ -436,11 +455,13 @@ func (cli *Client) Connect() error {
436
455
  }
437
456
 
438
457
  func (cli *Client) connect() error {
439
- if cli == nil {
440
- return ErrClientIsNil
441
- }
442
458
  cli.socketLock.Lock()
443
459
  defer cli.socketLock.Unlock()
460
+
461
+ return cli.unlockedConnect()
462
+ }
463
+
464
+ func (cli *Client) unlockedConnect() error {
444
465
  if cli.socket != nil {
445
466
  if !cli.socket.IsConnected() {
446
467
  cli.unlockedDisconnect()
@@ -514,15 +535,15 @@ func (cli *Client) onDisconnect(ns *socket.NoiseSocket, remote bool) {
514
535
  }
515
536
 
516
537
  func (cli *Client) expectDisconnect() {
517
- cli.expectedDisconnect.Store(true)
538
+ cli.expectedDisconnect.Set()
518
539
  }
519
540
 
520
541
  func (cli *Client) resetExpectedDisconnect() {
521
- cli.expectedDisconnect.Store(false)
542
+ cli.expectedDisconnect.Clear()
522
543
  }
523
544
 
524
545
  func (cli *Client) isExpectedDisconnect() bool {
525
- return cli.expectedDisconnect.Load()
546
+ return cli.expectedDisconnect.IsSet()
526
547
  }
527
548
 
528
549
  func (cli *Client) autoReconnect() {
@@ -533,12 +554,17 @@ func (cli *Client) autoReconnect() {
533
554
  autoReconnectDelay := time.Duration(cli.AutoReconnectErrors) * 2 * time.Second
534
555
  cli.Log.Debugf("Automatically reconnecting after %v", autoReconnectDelay)
535
556
  cli.AutoReconnectErrors++
536
- time.Sleep(autoReconnectDelay)
557
+ if cli.expectedDisconnect.WaitTimeout(autoReconnectDelay) {
558
+ return
559
+ }
537
560
  err := cli.connect()
538
561
  if errors.Is(err, ErrAlreadyConnected) {
539
562
  cli.Log.Debugf("Connect() said we're already connected after autoreconnect sleep")
540
563
  return
541
564
  } else if err != nil {
565
+ if cli.expectedDisconnect.IsSet() {
566
+ return
567
+ }
542
568
  cli.Log.Errorf("Error reconnecting after autoreconnect sleep: %v", err)
543
569
  if cli.AutoReconnectHook != nil && !cli.AutoReconnectHook(err) {
544
570
  cli.Log.Debugf("AutoReconnectHook returned false, not reconnecting")
@@ -567,10 +593,11 @@ func (cli *Client) IsConnected() bool {
567
593
  // This will not emit any events, the Disconnected event is only used when the
568
594
  // connection is closed by the server or a network error.
569
595
  func (cli *Client) Disconnect() {
570
- if cli == nil || cli.socket == nil {
596
+ if cli == nil {
571
597
  return
572
598
  }
573
599
  cli.socketLock.Lock()
600
+ cli.expectDisconnect()
574
601
  cli.unlockedDisconnect()
575
602
  cli.socketLock.Unlock()
576
603
  cli.clearDelayedMessageRequests()
@@ -657,6 +684,13 @@ func (cli *Client) Logout(ctx context.Context) error {
657
684
  // // Handle event and access mycli.WAClient
658
685
  // }
659
686
  func (cli *Client) AddEventHandler(handler EventHandler) uint32 {
687
+ return cli.AddEventHandlerWithSuccessStatus(func(evt any) bool {
688
+ handler(evt)
689
+ return true
690
+ })
691
+ }
692
+
693
+ func (cli *Client) AddEventHandlerWithSuccessStatus(handler EventHandlerWithSuccessStatus) uint32 {
660
694
  nextID := atomic.AddUint32(&nextHandlerID, 1)
661
695
  cli.eventHandlersLock.Lock()
662
696
  cli.eventHandlers = append(cli.eventHandlers, wrappedEventHandler{handler, nextID})
@@ -803,7 +837,7 @@ func (cli *Client) sendNode(node waBinary.Node) error {
803
837
  return err
804
838
  }
805
839
 
806
- func (cli *Client) dispatchEvent(evt any) {
840
+ func (cli *Client) dispatchEvent(evt any) (handlerFailed bool) {
807
841
  cli.eventHandlersLock.RLock()
808
842
  defer func() {
809
843
  cli.eventHandlersLock.RUnlock()
@@ -813,8 +847,11 @@ func (cli *Client) dispatchEvent(evt any) {
813
847
  }
814
848
  }()
815
849
  for _, handler := range cli.eventHandlers {
816
- handler.fn(evt)
850
+ if !handler.fn(evt) {
851
+ return true
852
+ }
817
853
  }
854
+ return false
818
855
  }
819
856
 
820
857
  // ParseWebMessage parses a WebMessageInfo object into *events.Message to match what real-time messages have.
@@ -17,7 +17,7 @@ import (
17
17
  )
18
18
 
19
19
  func (cli *Client) handleStreamError(node *waBinary.Node) {
20
- ctx := context.TODO()
20
+ ctx := cli.BackgroundEventCtx
21
21
  cli.isLoggedIn.Store(false)
22
22
  cli.clearResponseWaiters(node)
23
23
  code, _ := node.Attrs["code"].(string)
@@ -58,7 +58,7 @@ func (cli *Client) handleStreamError(node *waBinary.Node) {
58
58
  cli.Log.Infof("Got %s stream error, refreshing CAT before reconnecting...", code)
59
59
  cli.socketLock.RLock()
60
60
  defer cli.socketLock.RUnlock()
61
- err := cli.RefreshCAT()
61
+ err := cli.RefreshCAT(ctx)
62
62
  if err != nil {
63
63
  cli.Log.Errorf("Failed to refresh CAT: %v", err)
64
64
  cli.expectDisconnect()
@@ -94,7 +94,7 @@ func (cli *Client) handleIB(node *waBinary.Node) {
94
94
  }
95
95
 
96
96
  func (cli *Client) handleConnectFailure(node *waBinary.Node) {
97
- ctx := context.TODO()
97
+ ctx := cli.BackgroundEventCtx
98
98
  ag := node.AttrGetter()
99
99
  reason := events.ConnectFailureReason(ag.Int("reason"))
100
100
  message := ag.OptionalString("message")
@@ -136,7 +136,7 @@ func (cli *Client) handleConnectFailure(node *waBinary.Node) {
136
136
  go cli.dispatchEvent(&events.ClientOutdated{})
137
137
  } else if reason == events.ConnectFailureCATInvalid || reason == events.ConnectFailureCATExpired {
138
138
  cli.Log.Infof("Got %d/%s connect failure, refreshing CAT before reconnecting...", int(reason), message)
139
- err := cli.RefreshCAT()
139
+ err := cli.RefreshCAT(ctx)
140
140
  if err != nil {
141
141
  cli.Log.Errorf("Failed to refresh CAT: %v", err)
142
142
  cli.expectDisconnect()
@@ -151,7 +151,7 @@ func (cli *Client) handleConnectFailure(node *waBinary.Node) {
151
151
  }
152
152
 
153
153
  func (cli *Client) handleConnectSuccess(node *waBinary.Node) {
154
- ctx := context.TODO()
154
+ ctx := cli.BackgroundEventCtx
155
155
  cli.Log.Infof("Successfully authenticated")
156
156
  cli.LastSuccessfulConnect = time.Now()
157
157
  cli.AutoReconnectErrors = 0
@@ -165,8 +165,10 @@ func (cli *Client) handleConnectSuccess(node *waBinary.Node) {
165
165
  } else {
166
166
  cli.Log.Infof("Updated LID to %s", cli.Store.LID)
167
167
  }
168
- cli.StoreLIDPNMapping(ctx, cli.Store.GetLID(), cli.Store.GetJID())
169
168
  }
169
+ // Some users are missing their own LID-PN mapping even though it's already in the device table,
170
+ // so do this unconditionally for a few months to ensure everyone gets the row.
171
+ cli.StoreLIDPNMapping(ctx, cli.Store.GetLID(), cli.Store.GetJID())
170
172
  go func() {
171
173
  if dbCount, err := cli.Store.PreKeys.UploadedPreKeyCount(ctx); err != nil {
172
174
  cli.Log.Errorf("Failed to get number of prekeys in database: %v", err)
@@ -94,8 +94,13 @@ func (cli *Client) DownloadMediaWithPathToFile(
94
94
  // TODO omit hash for unencrypted media?
95
95
  mediaURL := fmt.Sprintf("https://%s%s&hash=%s&mms-type=%s&__wa-mms=", host.Hostname, directPath, base64.URLEncoding.EncodeToString(encFileHash), mmsType)
96
96
  err = cli.downloadAndDecryptToFile(ctx, mediaURL, mediaKey, mediaType, fileLength, encFileHash, fileHash, file)
97
- if err == nil || errors.Is(err, ErrFileLengthMismatch) || errors.Is(err, ErrInvalidMediaSHA256) ||
98
- errors.Is(err, ErrMediaDownloadFailedWith403) || errors.Is(err, ErrMediaDownloadFailedWith404) || errors.Is(err, ErrMediaDownloadFailedWith410) {
97
+ if err == nil ||
98
+ errors.Is(err, ErrFileLengthMismatch) ||
99
+ errors.Is(err, ErrInvalidMediaSHA256) ||
100
+ errors.Is(err, ErrMediaDownloadFailedWith403) ||
101
+ errors.Is(err, ErrMediaDownloadFailedWith404) ||
102
+ errors.Is(err, ErrMediaDownloadFailedWith410) ||
103
+ errors.Is(err, context.Canceled) {
99
104
  return err
100
105
  } else if i >= len(mediaConn.Hosts)-1 {
101
106
  return fmt.Errorf("failed to download media from last host: %w", err)
@@ -127,16 +132,18 @@ func (cli *Client) downloadAndDecryptToFile(
127
132
  return fmt.Errorf("failed to seek to start of file after validating mac: %w", err)
128
133
  } else if err = cbcutil.DecryptFile(cipherKey, iv, file); err != nil {
129
134
  return fmt.Errorf("failed to decrypt file: %w", err)
130
- } else if info, err := file.Stat(); err != nil {
131
- return fmt.Errorf("failed to stat file: %w", err)
132
- } else if fileLength >= 0 && info.Size() != int64(fileLength) {
133
- return fmt.Errorf("%w: expected %d, got %d", ErrFileLengthMismatch, fileLength, info.Size())
134
- } else if _, err = file.Seek(0, io.SeekStart); err != nil {
135
- return fmt.Errorf("failed to seek to start of file after decrypting: %w", err)
136
- } else if _, err = io.Copy(hasher, file); err != nil {
137
- return fmt.Errorf("failed to hash file: %w", err)
138
- } else if !hmac.Equal(fileSHA256, hasher.Sum(nil)) {
139
- return ErrInvalidMediaSHA256
135
+ } else if ReturnDownloadWarnings {
136
+ if info, err := file.Stat(); err != nil {
137
+ return fmt.Errorf("failed to stat file: %w", err)
138
+ } else if fileLength >= 0 && info.Size() != int64(fileLength) {
139
+ return fmt.Errorf("%w: expected %d, got %d", ErrFileLengthMismatch, fileLength, info.Size())
140
+ } else if _, err = file.Seek(0, io.SeekStart); err != nil {
141
+ return fmt.Errorf("failed to seek to start of file after decrypting: %w", err)
142
+ } else if _, err = io.Copy(hasher, file); err != nil {
143
+ return fmt.Errorf("failed to hash file: %w", err)
144
+ } else if !hmac.Equal(fileSHA256, hasher.Sum(nil)) {
145
+ return ErrInvalidMediaSHA256
146
+ }
140
147
  }
141
148
  return nil
142
149
  }
@@ -130,6 +130,8 @@ var mediaTypeToMMSType = map[MediaType]string{
130
130
  }
131
131
 
132
132
  // DownloadAny loops through the downloadable parts of the given message and downloads the first non-nil item.
133
+ //
134
+ // Deprecated: it's recommended to find the specific message type you want to download manually and use the Download method instead.
133
135
  func (cli *Client) DownloadAny(ctx context.Context, msg *waE2E.Message) (data []byte, err error) {
134
136
  if msg == nil {
135
137
  return nil, ErrNothingDownloadableFound
@@ -161,6 +163,10 @@ func getSize(msg DownloadableMessage) int {
161
163
  }
162
164
  }
163
165
 
166
+ // ReturnDownloadWarnings controls whether the Download function returns non-fatal validation warnings.
167
+ // Currently, these include [ErrFileLengthMismatch] and [ErrInvalidMediaSHA256].
168
+ var ReturnDownloadWarnings = true
169
+
164
170
  // DownloadThumbnail downloads a thumbnail from a message.
165
171
  //
166
172
  // This is primarily intended for downloading link preview thumbnails, which are in ExtendedTextMessage:
@@ -257,8 +263,13 @@ func (cli *Client) DownloadMediaWithPath(
257
263
  // TODO omit hash for unencrypted media?
258
264
  mediaURL := fmt.Sprintf("https://%s%s&hash=%s&mms-type=%s&__wa-mms=", host.Hostname, directPath, base64.URLEncoding.EncodeToString(encFileHash), mmsType)
259
265
  data, err = cli.downloadAndDecrypt(ctx, mediaURL, mediaKey, mediaType, fileLength, encFileHash, fileHash)
260
- if err == nil || errors.Is(err, ErrFileLengthMismatch) || errors.Is(err, ErrInvalidMediaSHA256) ||
261
- errors.Is(err, ErrMediaDownloadFailedWith403) || errors.Is(err, ErrMediaDownloadFailedWith404) || errors.Is(err, ErrMediaDownloadFailedWith410) {
266
+ if err == nil ||
267
+ errors.Is(err, ErrFileLengthMismatch) ||
268
+ errors.Is(err, ErrInvalidMediaSHA256) ||
269
+ errors.Is(err, ErrMediaDownloadFailedWith403) ||
270
+ errors.Is(err, ErrMediaDownloadFailedWith404) ||
271
+ errors.Is(err, ErrMediaDownloadFailedWith410) ||
272
+ errors.Is(err, context.Canceled) {
262
273
  return
263
274
  } else if i >= len(mediaConn.Hosts)-1 {
264
275
  return nil, fmt.Errorf("failed to download media from last host: %w", err)
@@ -288,10 +299,12 @@ func (cli *Client) downloadAndDecrypt(
288
299
 
289
300
  } else if data, err = cbcutil.Decrypt(cipherKey, iv, ciphertext); err != nil {
290
301
  err = fmt.Errorf("failed to decrypt file: %w", err)
291
- } else if fileLength >= 0 && len(data) != fileLength {
292
- err = fmt.Errorf("%w: expected %d, got %d", ErrFileLengthMismatch, fileLength, len(data))
293
- } else if len(fileSHA256) == 32 && sha256.Sum256(data) != *(*[32]byte)(fileSHA256) {
294
- err = ErrInvalidMediaSHA256
302
+ } else if ReturnDownloadWarnings {
303
+ if fileLength >= 0 && len(data) != fileLength {
304
+ err = fmt.Errorf("%w: expected %d, got %d", ErrFileLengthMismatch, fileLength, len(data))
305
+ } else if len(fileSHA256) == 32 && sha256.Sum256(data) != *(*[32]byte)(fileSHA256) {
306
+ err = ErrInvalidMediaSHA256
307
+ }
295
308
  }
296
309
  return
297
310
  }
@@ -302,6 +315,9 @@ func getMediaKeys(mediaKey []byte, appInfo MediaType) (iv, cipherKey, macKey, re
302
315
  }
303
316
 
304
317
  func shouldRetryMediaDownload(err error) bool {
318
+ if errors.Is(err, context.Canceled) {
319
+ return false
320
+ }
305
321
  var netErr net.Error
306
322
  var httpErr DownloadHTTPError
307
323
  return errors.As(err, &netErr) ||
@@ -752,8 +752,8 @@ func (cli *Client) parseGroupChange(node *waBinary.Node) (*events.GroupInfo, err
752
752
  for _, child := range node.GetChildren() {
753
753
  cag := child.AttrGetter()
754
754
  if child.Tag == "add" || child.Tag == "remove" || child.Tag == "promote" || child.Tag == "demote" {
755
- evt.PrevParticipantVersionID = cag.String("prev_v_id")
756
- evt.ParticipantVersionID = cag.String("v_id")
755
+ evt.PrevParticipantVersionID = cag.OptionalString("prev_v_id")
756
+ evt.ParticipantVersionID = cag.OptionalString("v_id")
757
757
  }
758
758
  switch child.Tag {
759
759
  case "add":
@@ -67,7 +67,7 @@ func (int *DangerousInternalClient) RequestAppStateKeys(ctx context.Context, raw
67
67
  int.c.requestAppStateKeys(ctx, rawKeyIDs)
68
68
  }
69
69
 
70
- func (int *DangerousInternalClient) HandleDecryptedArmadillo(ctx context.Context, info *types.MessageInfo, decrypted []byte, retryCount int) bool {
70
+ func (int *DangerousInternalClient) HandleDecryptedArmadillo(ctx context.Context, info *types.MessageInfo, decrypted []byte, retryCount int) (handled, handlerFailed bool) {
71
71
  return int.c.handleDecryptedArmadillo(ctx, info, decrypted, retryCount)
72
72
  }
73
73
 
@@ -99,6 +99,14 @@ func (int *DangerousInternalClient) GetOwnLID() types.JID {
99
99
  return int.c.getOwnLID()
100
100
  }
101
101
 
102
+ func (int *DangerousInternalClient) Connect() error {
103
+ return int.c.connect()
104
+ }
105
+
106
+ func (int *DangerousInternalClient) UnlockedConnect() error {
107
+ return int.c.unlockedConnect()
108
+ }
109
+
102
110
  func (int *DangerousInternalClient) OnDisconnect(ns *socket.NoiseSocket, remote bool) {
103
111
  int.c.onDisconnect(ns, remote)
104
112
  }
@@ -139,8 +147,8 @@ func (int *DangerousInternalClient) SendNode(node waBinary.Node) error {
139
147
  return int.c.sendNode(node)
140
148
  }
141
149
 
142
- func (int *DangerousInternalClient) DispatchEvent(evt any) {
143
- int.c.dispatchEvent(evt)
150
+ func (int *DangerousInternalClient) DispatchEvent(evt any) (handlerFailed bool) {
151
+ return int.c.dispatchEvent(evt)
144
152
  }
145
153
 
146
154
  func (int *DangerousInternalClient) HandleStreamError(node *waBinary.Node) {
@@ -271,16 +279,16 @@ func (int *DangerousInternalClient) ParseMessageInfo(node *waBinary.Node) (*type
271
279
  return int.c.parseMessageInfo(node)
272
280
  }
273
281
 
274
- func (int *DangerousInternalClient) HandlePlaintextMessage(ctx context.Context, info *types.MessageInfo, node *waBinary.Node) {
275
- int.c.handlePlaintextMessage(ctx, info, node)
282
+ func (int *DangerousInternalClient) HandlePlaintextMessage(ctx context.Context, info *types.MessageInfo, node *waBinary.Node) bool {
283
+ return int.c.handlePlaintextMessage(ctx, info, node)
276
284
  }
277
285
 
278
286
  func (int *DangerousInternalClient) MigrateSessionStore(ctx context.Context, pn, lid types.JID) {
279
287
  int.c.migrateSessionStore(ctx, pn, lid)
280
288
  }
281
289
 
282
- func (int *DangerousInternalClient) DecryptMessages(ctx context.Context, info *types.MessageInfo, node *waBinary.Node) {
283
- int.c.decryptMessages(ctx, info, node)
290
+ func (int *DangerousInternalClient) DecryptMessages(ctx context.Context, info *types.MessageInfo, node *waBinary.Node) (handlerFailed bool) {
291
+ return int.c.decryptMessages(ctx, info, node)
284
292
  }
285
293
 
286
294
  func (int *DangerousInternalClient) ClearUntrustedIdentity(ctx context.Context, target types.JID) error {
@@ -307,10 +315,6 @@ func (int *DangerousInternalClient) HandleHistorySyncNotificationLoop() {
307
315
  int.c.handleHistorySyncNotificationLoop()
308
316
  }
309
317
 
310
- func (int *DangerousInternalClient) HandleHistorySyncNotification(ctx context.Context, notif *waE2E.HistorySyncNotification) {
311
- int.c.handleHistorySyncNotification(ctx, notif)
312
- }
313
-
314
318
  func (int *DangerousInternalClient) HandleAppStateSyncKeyShare(ctx context.Context, keys *waE2E.AppStateSyncKeyShare) {
315
319
  int.c.handleAppStateSyncKeyShare(ctx, keys)
316
320
  }
@@ -335,8 +339,8 @@ func (int *DangerousInternalClient) StoreHistoricalMessageSecrets(ctx context.Co
335
339
  int.c.storeHistoricalMessageSecrets(ctx, conversations)
336
340
  }
337
341
 
338
- func (int *DangerousInternalClient) HandleDecryptedMessage(ctx context.Context, info *types.MessageInfo, msg *waE2E.Message, retryCount int) {
339
- int.c.handleDecryptedMessage(ctx, info, msg, retryCount)
342
+ func (int *DangerousInternalClient) HandleDecryptedMessage(ctx context.Context, info *types.MessageInfo, msg *waE2E.Message, retryCount int) bool {
343
+ return int.c.handleDecryptedMessage(ctx, info, msg, retryCount)
340
344
  }
341
345
 
342
346
  func (int *DangerousInternalClient) SendProtocolMessageReceipt(id types.MessageID, msgType types.ReceiptType) {
@@ -491,8 +495,8 @@ func (int *DangerousInternalClient) ParseReceipt(node *waBinary.Node) (*events.R
491
495
  return int.c.parseReceipt(node)
492
496
  }
493
497
 
494
- func (int *DangerousInternalClient) MaybeDeferredAck(node *waBinary.Node) func() {
495
- return int.c.maybeDeferredAck(node)
498
+ func (int *DangerousInternalClient) MaybeDeferredAck(ctx context.Context, node *waBinary.Node) func(...*bool) {
499
+ return int.c.maybeDeferredAck(ctx, node)
496
500
  }
497
501
 
498
502
  func (int *DangerousInternalClient) SendAck(node *waBinary.Node) {
@@ -567,6 +571,10 @@ func (int *DangerousInternalClient) DelayedRequestMessageFromPhone(info *types.M
567
571
  int.c.delayedRequestMessageFromPhone(info)
568
572
  }
569
573
 
574
+ func (int *DangerousInternalClient) ImmediateRequestMessageFromPhone(ctx context.Context, info *types.MessageInfo) {
575
+ int.c.immediateRequestMessageFromPhone(ctx, info)
576
+ }
577
+
570
578
  func (int *DangerousInternalClient) ClearDelayedMessageRequests() {
571
579
  int.c.clearDelayedMessageRequests()
572
580
  }
@@ -603,8 +611,8 @@ func (int *DangerousInternalClient) SendNewsletter(to types.JID, id types.Messag
603
611
  return int.c.sendNewsletter(to, id, message, mediaID, timings)
604
612
  }
605
613
 
606
- func (int *DangerousInternalClient) SendGroup(ctx context.Context, to types.JID, participants []types.JID, id types.MessageID, message *waE2E.Message, timings *MessageDebugTimings, extraParams nodeExtraParams) (string, []byte, error) {
607
- return int.c.sendGroup(ctx, to, participants, id, message, timings, extraParams)
614
+ func (int *DangerousInternalClient) SendGroup(ctx context.Context, ownID, to types.JID, participants []types.JID, id types.MessageID, message *waE2E.Message, timings *MessageDebugTimings, extraParams nodeExtraParams) (string, []byte, error) {
615
+ return int.c.sendGroup(ctx, ownID, to, participants, id, message, timings, extraParams)
608
616
  }
609
617
 
610
618
  func (int *DangerousInternalClient) SendPeerMessage(ctx context.Context, to types.JID, id types.MessageID, message *waE2E.Message, timings *MessageDebugTimings) ([]byte, error) {
@@ -678,3 +686,11 @@ func (int *DangerousInternalClient) Usync(ctx context.Context, jids []types.JID,
678
686
  func (int *DangerousInternalClient) ParseBlocklist(node *waBinary.Node) *types.Blocklist {
679
687
  return int.c.parseBlocklist(node)
680
688
  }
689
+
690
+ func (int *DangerousInternalClient) ShouldIncludeReportingToken(message *waE2E.Message) bool {
691
+ return int.c.shouldIncludeReportingToken(message)
692
+ }
693
+
694
+ func (int *DangerousInternalClient) GetMessageReportingToken(msgProtobuf []byte, msg *waE2E.Message, senderJID, remoteJID types.JID, messageID types.MessageID) waBinary.Node {
695
+ return int.c.getMessageReportingToken(msgProtobuf, msg, senderJID, remoteJID, messageID)
696
+ }
@@ -46,6 +46,7 @@ func (cli *Client) keepAliveLoop(ctx context.Context) {
46
46
  if cli.EnableAutoReconnect && time.Since(lastSuccess) > KeepAliveMaxFailTime {
47
47
  cli.Log.Debugf("Forcing reconnect due to keepalive failure")
48
48
  cli.Disconnect()
49
+ cli.resetExpectedDisconnect()
49
50
  go cli.autoReconnect()
50
51
  }
51
52
  } else {