slidge-whatsapp 0.3.0__cp311-cp311-manylinux_2_36_aarch64.whl → 0.3.1__cp311-cp311-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 (131) hide show
  1. slidge_whatsapp/event.go +33 -9
  2. slidge_whatsapp/generated/_whatsapp.cpython-311-aarch64-linux-gnu.h +150 -150
  3. slidge_whatsapp/generated/_whatsapp.cpython-311-aarch64-linux-gnu.so +0 -0
  4. slidge_whatsapp/generated/build.py +130 -130
  5. slidge_whatsapp/generated/whatsapp.c +1478 -1478
  6. slidge_whatsapp/generated/whatsapp.go +1123 -1123
  7. slidge_whatsapp/generated/whatsapp.py +863 -863
  8. slidge_whatsapp/generated/whatsapp_go.h +150 -150
  9. slidge_whatsapp/go.mod +5 -5
  10. slidge_whatsapp/go.sum +14 -14
  11. slidge_whatsapp/session.go +3 -3
  12. slidge_whatsapp/vendor/github.com/ebitengine/purego/README.md +21 -5
  13. slidge_whatsapp/vendor/github.com/ebitengine/purego/abi_loong64.h +60 -0
  14. slidge_whatsapp/vendor/github.com/ebitengine/purego/cgo.go +1 -1
  15. slidge_whatsapp/vendor/github.com/ebitengine/purego/dlerror.go +1 -1
  16. slidge_whatsapp/vendor/github.com/ebitengine/purego/dlfcn.go +1 -1
  17. slidge_whatsapp/vendor/github.com/ebitengine/purego/dlfcn_netbsd.go +15 -0
  18. slidge_whatsapp/vendor/github.com/ebitengine/purego/dlfcn_nocgo_netbsd.go +9 -0
  19. slidge_whatsapp/vendor/github.com/ebitengine/purego/dlfcn_stubs.s +1 -1
  20. slidge_whatsapp/vendor/github.com/ebitengine/purego/func.go +113 -60
  21. slidge_whatsapp/vendor/github.com/ebitengine/purego/gen.go +6 -0
  22. slidge_whatsapp/vendor/github.com/ebitengine/purego/go_runtime.go +1 -1
  23. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/cgo/dlfcn_cgo_unix.go +2 -2
  24. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/cgo/syscall_cgo_unix.go +2 -2
  25. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/abi_loong64.h +60 -0
  26. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_loong64.s +40 -0
  27. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/callbacks.go +1 -1
  28. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/doc.go +1 -1
  29. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/go_libinit.go +1 -1
  30. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/go_linux_loong64.go +92 -0
  31. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/go_netbsd.go +106 -0
  32. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/go_setenv.go +1 -1
  33. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/go_util.go +1 -1
  34. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/iscgo.go +1 -1
  35. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo.go +1 -1
  36. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo_darwin.go +4 -0
  37. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo_freebsd.go +4 -0
  38. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo_linux.go +4 -0
  39. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo_netbsd.go +26 -0
  40. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/netbsd.go +23 -0
  41. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/setenv.go +1 -1
  42. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/symbols.go +11 -1
  43. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/symbols_darwin.go +1 -0
  44. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/symbols_freebsd.go +1 -0
  45. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/symbols_linux.go +1 -0
  46. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/symbols_netbsd.go +30 -0
  47. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_loong64.s +71 -0
  48. slidge_whatsapp/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_stubs.s +5 -1
  49. slidge_whatsapp/vendor/github.com/ebitengine/purego/nocgo.go +1 -1
  50. slidge_whatsapp/vendor/github.com/ebitengine/purego/struct_amd64.go +8 -4
  51. slidge_whatsapp/vendor/github.com/ebitengine/purego/struct_arm64.go +16 -6
  52. slidge_whatsapp/vendor/github.com/ebitengine/purego/struct_loong64.go +190 -0
  53. slidge_whatsapp/vendor/github.com/ebitengine/purego/struct_other.go +6 -2
  54. slidge_whatsapp/vendor/github.com/ebitengine/purego/sys_amd64.s +1 -1
  55. slidge_whatsapp/vendor/github.com/ebitengine/purego/sys_arm64.s +1 -1
  56. slidge_whatsapp/vendor/github.com/ebitengine/purego/sys_loong64.s +96 -0
  57. slidge_whatsapp/vendor/github.com/ebitengine/purego/sys_unix_arm64.s +1 -1
  58. slidge_whatsapp/vendor/github.com/ebitengine/purego/sys_unix_loong64.s +75 -0
  59. slidge_whatsapp/vendor/github.com/ebitengine/purego/syscall.go +6 -3
  60. slidge_whatsapp/vendor/github.com/ebitengine/purego/syscall_cgo_linux.go +3 -3
  61. slidge_whatsapp/vendor/github.com/ebitengine/purego/syscall_sysv.go +13 -10
  62. slidge_whatsapp/vendor/github.com/ebitengine/purego/syscall_windows.go +1 -1
  63. slidge_whatsapp/vendor/github.com/ebitengine/purego/zcallback_amd64.s +2002 -2002
  64. slidge_whatsapp/vendor/github.com/ebitengine/purego/zcallback_arm64.s +4002 -4002
  65. slidge_whatsapp/vendor/github.com/ebitengine/purego/zcallback_loong64.s +4014 -0
  66. slidge_whatsapp/vendor/go.mau.fi/util/dbutil/log.go +1 -0
  67. slidge_whatsapp/vendor/go.mau.fi/util/dbutil/module.go +118 -0
  68. slidge_whatsapp/vendor/go.mau.fi/util/dbutil/upgradetable.go +0 -34
  69. slidge_whatsapp/vendor/go.mau.fi/util/exbytes/string.go +20 -0
  70. slidge_whatsapp/vendor/go.mau.fi/util/exbytes/writer.go +78 -0
  71. slidge_whatsapp/vendor/go.mau.fi/util/exslices/cast.go +42 -0
  72. slidge_whatsapp/vendor/go.mau.fi/util/exslices/chunk.go +28 -0
  73. slidge_whatsapp/vendor/go.mau.fi/util/exslices/deduplicate.go +67 -0
  74. slidge_whatsapp/vendor/go.mau.fi/util/exslices/diff.go +63 -0
  75. slidge_whatsapp/vendor/go.mau.fi/util/exsync/event.go +15 -1
  76. slidge_whatsapp/vendor/go.mau.fi/util/random/string.go +47 -7
  77. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/appstate/decode.go +1 -0
  78. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/appstate/encode.go +34 -0
  79. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/appstate/hash.go +1 -0
  80. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/appstate.go +3 -0
  81. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/armadillomessage.go +1 -2
  82. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/call.go +6 -0
  83. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/errors.go +1 -0
  84. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/group.go +63 -42
  85. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/internals.go +14 -10
  86. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/message.go +45 -18
  87. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/msgsecret.go +23 -0
  88. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/notification.go +5 -1
  89. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/pair.go +3 -7
  90. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waAICommon/WAAICommon.pb.go +7747 -0
  91. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/{waBotMetadata/WABotMetadata.proto → waAICommon/WAAICommon.proto} +269 -9
  92. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waDeviceCapabilities/WAProtobufsDeviceCapabilities.pb.go +128 -14
  93. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waDeviceCapabilities/WAProtobufsDeviceCapabilities.proto +10 -0
  94. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waE2E/WAWebProtobufsE2E.pb.go +3236 -4732
  95. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waE2E/WAWebProtobufsE2E.proto +125 -273
  96. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waHistorySync/WAWebProtobufsHistorySync.pb.go +11 -2
  97. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waHistorySync/WAWebProtobufsHistorySync.proto +1 -0
  98. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waStatusAttributions/WAStatusAttributions.pb.go +220 -81
  99. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waStatusAttributions/WAStatusAttributions.proto +13 -0
  100. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waSyncAction/WASyncAction.pb.go +705 -449
  101. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waSyncAction/WASyncAction.proto +23 -0
  102. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waWa6/WAWebProtobufsWa6.pb.go +78 -24
  103. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waWa6/WAWebProtobufsWa6.proto +6 -0
  104. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waWeb/WAWebProtobufsWeb.pb.go +516 -267
  105. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waWeb/WAWebProtobufsWeb.proto +22 -0
  106. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/receipt.go +2 -0
  107. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/request.go +4 -0
  108. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/retry.go +2 -3
  109. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/send.go +110 -28
  110. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/store/clientpayload.go +1 -1
  111. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/store/noop.go +12 -0
  112. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/store/sqlstore/lidmap.go +82 -4
  113. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/store/sqlstore/store.go +112 -55
  114. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/store/sqlstore/upgrades/00-latest-schema.sql +8 -7
  115. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/store/sqlstore/upgrades/11-redacted-phone-contacts.sql +2 -0
  116. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/store/store.go +20 -0
  117. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/types/call.go +6 -5
  118. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/types/message.go +7 -1
  119. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/types/user.go +3 -0
  120. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/user.go +31 -2
  121. slidge_whatsapp/vendor/google.golang.org/protobuf/internal/filedesc/desc.go +35 -17
  122. slidge_whatsapp/vendor/google.golang.org/protobuf/internal/filedesc/desc_init.go +14 -0
  123. slidge_whatsapp/vendor/google.golang.org/protobuf/internal/filedesc/desc_lazy.go +20 -0
  124. slidge_whatsapp/vendor/google.golang.org/protobuf/internal/version/version.go +1 -1
  125. slidge_whatsapp/vendor/modules.txt +8 -6
  126. {slidge_whatsapp-0.3.0.dist-info → slidge_whatsapp-0.3.1.dist-info}/METADATA +1 -1
  127. {slidge_whatsapp-0.3.0.dist-info → slidge_whatsapp-0.3.1.dist-info}/RECORD +130 -106
  128. slidge_whatsapp/vendor/go.mau.fi/whatsmeow/proto/waBotMetadata/WABotMetadata.pb.go +0 -5156
  129. {slidge_whatsapp-0.3.0.dist-info → slidge_whatsapp-0.3.1.dist-info}/WHEEL +0 -0
  130. {slidge_whatsapp-0.3.0.dist-info → slidge_whatsapp-0.3.1.dist-info}/entry_points.txt +0 -0
  131. {slidge_whatsapp-0.3.0.dist-info → slidge_whatsapp-0.3.1.dist-info}/licenses/LICENSE +0 -0
@@ -19,6 +19,7 @@ import (
19
19
  "time"
20
20
 
21
21
  "go.mau.fi/util/dbutil"
22
+ "go.mau.fi/util/exslices"
22
23
  "go.mau.fi/util/exsync"
23
24
 
24
25
  "go.mau.fi/whatsmeow/store"
@@ -108,9 +109,11 @@ func (s *SQLStore) IsTrustedIdentity(ctx context.Context, address string, key [3
108
109
  }
109
110
 
110
111
  const (
111
- getSessionQuery = `SELECT session FROM whatsmeow_sessions WHERE our_jid=$1 AND their_id=$2`
112
- hasSessionQuery = `SELECT true FROM whatsmeow_sessions WHERE our_jid=$1 AND their_id=$2`
113
- putSessionQuery = `
112
+ getSessionQuery = `SELECT session FROM whatsmeow_sessions WHERE our_jid=$1 AND their_id=$2`
113
+ hasSessionQuery = `SELECT true FROM whatsmeow_sessions WHERE our_jid=$1 AND their_id=$2`
114
+ hasManySessionQueryPostgres = `SELECT their_id FROM whatsmeow_sessions WHERE our_jid=$1 AND their_id = ANY($2)`
115
+ hasManySessionQueryGeneric = `SELECT their_id FROM whatsmeow_sessions WHERE our_jid=$1 AND their_id IN (%s)`
116
+ putSessionQuery = `
114
117
  INSERT INTO whatsmeow_sessions (our_jid, their_id, session) VALUES ($1, $2, $3)
115
118
  ON CONFLICT (our_jid, their_id) DO UPDATE SET session=excluded.session
116
119
  `
@@ -158,6 +161,38 @@ func (s *SQLStore) HasSession(ctx context.Context, address string) (has bool, er
158
161
  return
159
162
  }
160
163
 
164
+ var stringScanner = dbutil.ConvertRowFn[string](dbutil.ScanSingleColumn[string])
165
+
166
+ func (s *SQLStore) HasManySessions(ctx context.Context, addresses []string) (map[string]bool, error) {
167
+ if len(addresses) == 0 {
168
+ return nil, nil
169
+ }
170
+
171
+ var rows dbutil.Rows
172
+ var err error
173
+ if s.db.Dialect == dbutil.Postgres && PostgresArrayWrapper != nil {
174
+ rows, err = s.db.Query(ctx, hasManySessionQueryPostgres, s.JID, PostgresArrayWrapper(addresses))
175
+ } else {
176
+ args := make([]any, len(addresses)+1)
177
+ placeholders := make([]string, len(addresses))
178
+ args[0] = s.JID
179
+ for i, addr := range addresses {
180
+ args[i+1] = addr
181
+ placeholders[i] = fmt.Sprintf("$%d", i+2)
182
+ }
183
+ rows, err = s.db.Query(ctx, fmt.Sprintf(hasManySessionQueryGeneric, strings.Join(placeholders, ",")), args...)
184
+ }
185
+ result := make(map[string]bool, len(addresses))
186
+ for _, addr := range addresses {
187
+ result[addr] = false
188
+ }
189
+ err = stringScanner.NewRowIter(rows, err).Iter(func(s string) (bool, error) {
190
+ result[s] = true
191
+ return true, nil
192
+ })
193
+ return result, err
194
+ }
195
+
161
196
  func (s *SQLStore) PutSession(ctx context.Context, address string, session []byte) error {
162
197
  _, err := s.db.Exec(ctx, putSessionQuery, s.JID, address, session)
163
198
  return err
@@ -522,10 +557,10 @@ const (
522
557
  INSERT INTO whatsmeow_contacts (our_jid, their_jid, first_name, full_name) VALUES ($1, $2, $3, $4)
523
558
  ON CONFLICT (our_jid, their_jid) DO UPDATE SET first_name=excluded.first_name, full_name=excluded.full_name
524
559
  `
525
- putManyContactNamesQuery = `
526
- INSERT INTO whatsmeow_contacts (our_jid, their_jid, first_name, full_name)
527
- VALUES %s
528
- ON CONFLICT (our_jid, their_jid) DO UPDATE SET first_name=excluded.first_name, full_name=excluded.full_name
560
+ putRedactedPhoneQuery = `
561
+ INSERT INTO whatsmeow_contacts (our_jid, their_jid, redacted_phone)
562
+ VALUES ($1, $2, $3)
563
+ ON CONFLICT (our_jid, their_jid) DO UPDATE SET redacted_phone=excluded.redacted_phone
529
564
  `
530
565
  putPushNameQuery = `
531
566
  INSERT INTO whatsmeow_contacts (our_jid, their_jid, push_name) VALUES ($1, $2, $3)
@@ -536,13 +571,21 @@ const (
536
571
  ON CONFLICT (our_jid, their_jid) DO UPDATE SET business_name=excluded.business_name
537
572
  `
538
573
  getContactQuery = `
539
- SELECT first_name, full_name, push_name, business_name FROM whatsmeow_contacts WHERE our_jid=$1 AND their_jid=$2
574
+ SELECT first_name, full_name, push_name, business_name, redacted_phone FROM whatsmeow_contacts WHERE our_jid=$1 AND their_jid=$2
540
575
  `
541
576
  getAllContactsQuery = `
542
- SELECT their_jid, first_name, full_name, push_name, business_name FROM whatsmeow_contacts WHERE our_jid=$1
577
+ SELECT their_jid, first_name, full_name, push_name, business_name, redacted_phone FROM whatsmeow_contacts WHERE our_jid=$1
543
578
  `
544
579
  )
545
580
 
581
+ var putContactNamesMassInsertBuilder = dbutil.NewMassInsertBuilder[store.ContactEntry, [1]any](
582
+ putContactNameQuery, "($1, $%d, $%d, $%d)",
583
+ )
584
+
585
+ var putRedactedPhonesMassInsertBuilder = dbutil.NewMassInsertBuilder[store.RedactedPhoneEntry, [1]any](
586
+ putRedactedPhoneQuery, "($1, $%d, $%d)",
587
+ )
588
+
546
589
  func (s *SQLStore) PutPushName(ctx context.Context, user types.JID, pushName string) (bool, string, error) {
547
590
  s.contactCacheLock.Lock()
548
591
  defer s.contactCacheLock.Unlock()
@@ -607,44 +650,21 @@ func (s *SQLStore) PutContactName(ctx context.Context, user types.JID, firstName
607
650
 
608
651
  const contactBatchSize = 300
609
652
 
610
- func (s *SQLStore) putContactNamesBatch(ctx context.Context, contacts []store.ContactEntry) error {
611
- values := make([]any, 1, 1+len(contacts)*3)
612
- queryParts := make([]string, 0, len(contacts))
613
- values[0] = s.JID
614
- placeholderSyntax := "($1, $%d, $%d, $%d)"
615
- if s.db.Dialect == dbutil.SQLite {
616
- placeholderSyntax = "(?1, ?%d, ?%d, ?%d)"
617
- }
618
- i := 0
619
- handledContacts := make(map[types.JID]struct{}, len(contacts))
620
- for _, contact := range contacts {
621
- if contact.JID.IsEmpty() {
622
- s.log.Warnf("Empty contact info in mass insert: %+v", contact)
623
- continue
624
- }
625
- // The whole query will break if there are duplicates, so make sure there aren't any duplicates
626
- _, alreadyHandled := handledContacts[contact.JID]
627
- if alreadyHandled {
628
- s.log.Warnf("Duplicate contact info for %s in mass insert", contact.JID)
629
- continue
630
- }
631
- handledContacts[contact.JID] = struct{}{}
632
- baseIndex := i*3 + 1
633
- values = append(values, contact.JID.String(), contact.FirstName, contact.FullName)
634
- queryParts = append(queryParts, fmt.Sprintf(placeholderSyntax, baseIndex+1, baseIndex+2, baseIndex+3))
635
- i++
636
- }
637
- _, err := s.db.Exec(ctx, fmt.Sprintf(putManyContactNamesQuery, strings.Join(queryParts, ",")), values...)
638
- return err
639
- }
640
-
641
653
  func (s *SQLStore) PutAllContactNames(ctx context.Context, contacts []store.ContactEntry) error {
642
654
  if len(contacts) == 0 {
643
655
  return nil
644
656
  }
657
+ origLen := len(contacts)
658
+ contacts = exslices.DeduplicateUnsortedOverwriteFunc(contacts, func(t store.ContactEntry) types.JID {
659
+ return t.JID
660
+ })
661
+ if origLen != len(contacts) {
662
+ s.log.Warnf("%d duplicate contacts found in PutAllContactNames", origLen-len(contacts))
663
+ }
645
664
  err := s.db.DoTxn(ctx, nil, func(ctx context.Context) error {
646
665
  for slice := range slices.Chunk(contacts, contactBatchSize) {
647
- err := s.putContactNamesBatch(ctx, slice)
666
+ query, vars := putContactNamesMassInsertBuilder.Build([1]any{s.JID}, slice)
667
+ _, err := s.db.Exec(ctx, query, vars...)
648
668
  if err != nil {
649
669
  return err
650
670
  }
@@ -661,23 +681,59 @@ func (s *SQLStore) PutAllContactNames(ctx context.Context, contacts []store.Cont
661
681
  return nil
662
682
  }
663
683
 
684
+ func (s *SQLStore) PutManyRedactedPhones(ctx context.Context, entries []store.RedactedPhoneEntry) error {
685
+ if len(entries) == 0 {
686
+ return nil
687
+ }
688
+ origLen := len(entries)
689
+ entries = exslices.DeduplicateUnsortedOverwriteFunc(entries, func(t store.RedactedPhoneEntry) types.JID {
690
+ return t.JID
691
+ })
692
+ if origLen != len(entries) {
693
+ s.log.Warnf("%d duplicate contacts found in PutManyRedactedPhones", origLen-len(entries))
694
+ }
695
+ err := s.db.DoTxn(ctx, nil, func(ctx context.Context) error {
696
+ for slice := range slices.Chunk(entries, contactBatchSize) {
697
+ query, vars := putRedactedPhonesMassInsertBuilder.Build([1]any{s.JID}, slice)
698
+ _, err := s.db.Exec(ctx, query, vars...)
699
+ if err != nil {
700
+ return err
701
+ }
702
+ }
703
+ return nil
704
+ })
705
+ if err != nil {
706
+ return err
707
+ }
708
+ s.contactCacheLock.Lock()
709
+ for _, entry := range entries {
710
+ if cached, ok := s.contactCache[entry.JID]; ok && cached.RedactedPhone == entry.RedactedPhone {
711
+ continue
712
+ }
713
+ delete(s.contactCache, entry.JID)
714
+ }
715
+ s.contactCacheLock.Unlock()
716
+ return nil
717
+ }
718
+
664
719
  func (s *SQLStore) getContact(ctx context.Context, user types.JID) (*types.ContactInfo, error) {
665
720
  cached, ok := s.contactCache[user]
666
721
  if ok {
667
722
  return cached, nil
668
723
  }
669
724
 
670
- var first, full, push, business sql.NullString
671
- err := s.db.QueryRow(ctx, getContactQuery, s.JID, user).Scan(&first, &full, &push, &business)
725
+ var first, full, push, business, redactedPhone sql.NullString
726
+ err := s.db.QueryRow(ctx, getContactQuery, s.JID, user).Scan(&first, &full, &push, &business, &redactedPhone)
672
727
  if err != nil && !errors.Is(err, sql.ErrNoRows) {
673
728
  return nil, err
674
729
  }
675
730
  info := &types.ContactInfo{
676
- Found: err == nil,
677
- FirstName: first.String,
678
- FullName: full.String,
679
- PushName: push.String,
680
- BusinessName: business.String,
731
+ Found: err == nil,
732
+ FirstName: first.String,
733
+ FullName: full.String,
734
+ PushName: push.String,
735
+ BusinessName: business.String,
736
+ RedactedPhone: redactedPhone.String,
681
737
  }
682
738
  s.contactCache[user] = info
683
739
  return info, nil
@@ -703,17 +759,18 @@ func (s *SQLStore) GetAllContacts(ctx context.Context) (map[types.JID]types.Cont
703
759
  output := make(map[types.JID]types.ContactInfo, len(s.contactCache))
704
760
  for rows.Next() {
705
761
  var jid types.JID
706
- var first, full, push, business sql.NullString
707
- err = rows.Scan(&jid, &first, &full, &push, &business)
762
+ var first, full, push, business, redactedPhone sql.NullString
763
+ err = rows.Scan(&jid, &first, &full, &push, &business, &redactedPhone)
708
764
  if err != nil {
709
765
  return nil, fmt.Errorf("error scanning row: %w", err)
710
766
  }
711
767
  info := types.ContactInfo{
712
- Found: true,
713
- FirstName: first.String,
714
- FullName: full.String,
715
- PushName: push.String,
716
- BusinessName: business.String,
768
+ Found: true,
769
+ FirstName: first.String,
770
+ FullName: full.String,
771
+ PushName: push.String,
772
+ BusinessName: business.String,
773
+ RedactedPhone: redactedPhone.String,
717
774
  }
718
775
  output[jid] = info
719
776
  s.contactCache[jid] = &info
@@ -1,4 +1,4 @@
1
- -- v0 -> v10 (compatible with v8+): Latest schema
1
+ -- v0 -> v11 (compatible with v8+): Latest schema
2
2
  CREATE TABLE whatsmeow_device (
3
3
  jid TEXT PRIMARY KEY,
4
4
  lid TEXT,
@@ -98,12 +98,13 @@ CREATE TABLE whatsmeow_app_state_mutation_macs (
98
98
  );
99
99
 
100
100
  CREATE TABLE whatsmeow_contacts (
101
- our_jid TEXT,
102
- their_jid TEXT,
103
- first_name TEXT,
104
- full_name TEXT,
105
- push_name TEXT,
106
- business_name TEXT,
101
+ our_jid TEXT,
102
+ their_jid TEXT,
103
+ first_name TEXT,
104
+ full_name TEXT,
105
+ push_name TEXT,
106
+ business_name TEXT,
107
+ redacted_phone TEXT,
107
108
 
108
109
  PRIMARY KEY (our_jid, their_jid),
109
110
  FOREIGN KEY (our_jid) REFERENCES whatsmeow_device(jid) ON DELETE CASCADE ON UPDATE CASCADE
@@ -0,0 +1,2 @@
1
+ -- v11 (compatible with v8+): Store redacted phone number for LID members in groups
2
+ ALTER TABLE whatsmeow_contacts ADD COLUMN redacted_phone TEXT;
@@ -29,6 +29,7 @@ type IdentityStore interface {
29
29
  type SessionStore interface {
30
30
  GetSession(ctx context.Context, address string) ([]byte, error)
31
31
  HasSession(ctx context.Context, address string) (bool, error)
32
+ HasManySessions(ctx context.Context, addresses []string) (map[string]bool, error)
32
33
  PutSession(ctx context.Context, address string, session []byte) error
33
34
  DeleteAllSessions(ctx context.Context, phone string) error
34
35
  DeleteSession(ctx context.Context, address string) error
@@ -82,11 +83,25 @@ type ContactEntry struct {
82
83
  FullName string
83
84
  }
84
85
 
86
+ func (ce ContactEntry) GetMassInsertValues() [3]any {
87
+ return [...]any{ce.JID.String(), ce.FirstName, ce.FullName}
88
+ }
89
+
90
+ type RedactedPhoneEntry struct {
91
+ JID types.JID
92
+ RedactedPhone string
93
+ }
94
+
95
+ func (rpe RedactedPhoneEntry) GetMassInsertValues() [2]any {
96
+ return [...]any{rpe.JID.String(), rpe.RedactedPhone}
97
+ }
98
+
85
99
  type ContactStore interface {
86
100
  PutPushName(ctx context.Context, user types.JID, pushName string) (bool, string, error)
87
101
  PutBusinessName(ctx context.Context, user types.JID, businessName string) (bool, string, error)
88
102
  PutContactName(ctx context.Context, user types.JID, fullName, firstName string) error
89
103
  PutAllContactNames(ctx context.Context, contacts []ContactEntry) error
104
+ PutManyRedactedPhones(ctx context.Context, entries []RedactedPhoneEntry) error
90
105
  GetContact(ctx context.Context, user types.JID) (types.ContactInfo, error)
91
106
  GetAllContacts(ctx context.Context) (map[types.JID]types.ContactInfo, error)
92
107
  }
@@ -148,11 +163,16 @@ type LIDMapping struct {
148
163
  PN types.JID
149
164
  }
150
165
 
166
+ func (lm LIDMapping) GetMassInsertValues() [2]any {
167
+ return [...]any{lm.LID.User, lm.PN.User}
168
+ }
169
+
151
170
  type LIDStore interface {
152
171
  PutManyLIDMappings(ctx context.Context, mappings []LIDMapping) error
153
172
  PutLIDMapping(ctx context.Context, lid, jid types.JID) error
154
173
  GetPNForLID(ctx context.Context, lid types.JID) (types.JID, error)
155
174
  GetLIDForPN(ctx context.Context, pn types.JID) (types.JID, error)
175
+ GetManyLIDsForPNs(ctx context.Context, pns []types.JID) (map[types.JID]types.JID, error)
156
176
  }
157
177
 
158
178
  type AllSessionSpecificStores interface {
@@ -9,11 +9,12 @@ package types
9
9
  import "time"
10
10
 
11
11
  type BasicCallMeta struct {
12
- From JID
13
- Timestamp time.Time
14
- CallCreator JID
15
- CallID string
16
- GroupJID JID
12
+ From JID
13
+ Timestamp time.Time
14
+ CallCreator JID
15
+ CallCreatorAlt JID
16
+ CallID string
17
+ GroupJID JID
17
18
  }
18
19
 
19
20
  type CallRemoteMeta struct {
@@ -18,6 +18,11 @@ const (
18
18
  AddressingModeLID AddressingMode = "lid"
19
19
  )
20
20
 
21
+ type BroadcastRecipient struct {
22
+ LID JID
23
+ PN JID
24
+ }
25
+
21
26
  // MessageSource contains basic sender and chat information about a message.
22
27
  type MessageSource struct {
23
28
  Chat JID // The chat where the message was sent.
@@ -31,7 +36,8 @@ type MessageSource struct {
31
36
 
32
37
  // When sending a read receipt to a broadcast list message, the Chat is the broadcast list
33
38
  // and Sender is you, so this field contains the recipient of the read receipt.
34
- BroadcastListOwner JID
39
+ BroadcastListOwner JID
40
+ BroadcastRecipients []BroadcastRecipient
35
41
  }
36
42
 
37
43
  // IsIncomingBroadcast returns true if the message was sent to a broadcast list instead of directly to the user.
@@ -24,6 +24,7 @@ type UserInfo struct {
24
24
  Status string
25
25
  PictureID string
26
26
  Devices []JID
27
+ LID JID
27
28
  }
28
29
 
29
30
  type BotListInfo struct {
@@ -68,6 +69,8 @@ type ContactInfo struct {
68
69
  FullName string
69
70
  PushName string
70
71
  BusinessName string
72
+ // Only for LID members encountered in groups, the phone number in the form "+1∙∙∙∙∙∙∙∙80"
73
+ RedactedPhone string
71
74
  }
72
75
 
73
76
  // LocalChatSettings contains the cached local settings for a chat.
@@ -19,6 +19,7 @@ import (
19
19
  waBinary "go.mau.fi/whatsmeow/binary"
20
20
  "go.mau.fi/whatsmeow/proto/waHistorySync"
21
21
  "go.mau.fi/whatsmeow/proto/waVnameCert"
22
+ "go.mau.fi/whatsmeow/store"
22
23
  "go.mau.fi/whatsmeow/types"
23
24
  "go.mau.fi/whatsmeow/types/events"
24
25
  )
@@ -205,11 +206,13 @@ func (cli *Client) GetUserInfo(jids []types.JID) (map[types.JID]types.UserInfo,
205
206
  {Tag: "status"},
206
207
  {Tag: "picture"},
207
208
  {Tag: "devices", Attrs: waBinary.Attrs{"version": "2"}},
209
+ {Tag: "lid"},
208
210
  })
209
211
  if err != nil {
210
212
  return nil, err
211
213
  }
212
214
  respData := make(map[types.JID]types.UserInfo, len(jids))
215
+ mappings := make([]store.LIDMapping, 0, len(jids))
213
216
  for _, child := range list.GetChildren() {
214
217
  jid, jidOK := child.Attrs["jid"].(types.JID)
215
218
  if child.Tag != "user" || !jidOK {
@@ -224,11 +227,26 @@ func (cli *Client) GetUserInfo(jids []types.JID) (map[types.JID]types.UserInfo,
224
227
  info.Status = string(status)
225
228
  info.PictureID, _ = child.GetChildByTag("picture").Attrs["id"].(string)
226
229
  info.Devices = parseDeviceList(jid, child.GetChildByTag("devices"))
230
+
231
+ lidTag := child.GetChildByTag("lid")
232
+ info.LID = lidTag.AttrGetter().OptionalJIDOrEmpty("val")
233
+
234
+ if !info.LID.IsEmpty() {
235
+ mappings = append(mappings, store.LIDMapping{PN: jid, LID: info.LID})
236
+ }
237
+
227
238
  if verifiedName != nil {
228
239
  cli.updateBusinessName(context.TODO(), jid, nil, verifiedName.Details.GetVerifiedName())
229
240
  }
230
241
  respData[jid] = info
231
242
  }
243
+
244
+ err = cli.Store.LIDs.PutManyLIDMappings(context.TODO(), mappings)
245
+ if err != nil {
246
+ // not worth returning on the error, instead just post a log
247
+ cli.Log.Errorf("Failed to place LID mappings from USync call")
248
+ }
249
+
232
250
  return respData, nil
233
251
  }
234
252
 
@@ -527,9 +545,18 @@ func (cli *Client) GetProfilePictureInfo(jid types.JID, params *GetProfilePictur
527
545
  } else {
528
546
  to = types.ServerJID
529
547
  target = jid
548
+ var pictureContent []waBinary.Node
549
+ if token, _ := cli.Store.PrivacyTokens.GetPrivacyToken(context.TODO(), jid); token != nil {
550
+ pictureContent = []waBinary.Node{{
551
+ Tag: "tctoken",
552
+ Content: token.Token,
553
+ }}
554
+ }
555
+
530
556
  content = []waBinary.Node{{
531
- Tag: "picture",
532
- Attrs: attrs,
557
+ Tag: "picture",
558
+ Attrs: attrs,
559
+ Content: pictureContent,
533
560
  }}
534
561
  }
535
562
  resp, err := cli.sendIQ(infoQuery{
@@ -778,6 +805,8 @@ func (cli *Client) usync(ctx context.Context, jids []types.JID, mode, context st
778
805
  Content: jid.String(),
779
806
  }}
780
807
  case types.DefaultUserServer, types.HiddenUserServer:
808
+ // NOTE: You can pass in an LID with a JID (<lid jid=...> user node)
809
+ // Not sure if you can just put the LID in the jid tag here (works for <devices> queries mainly)
781
810
  userList[i].Attrs = waBinary.Attrs{"jid": jid}
782
811
  if jid.IsBot() {
783
812
  var personaID string
@@ -72,9 +72,10 @@ type (
72
72
  EditionFeatures EditionFeatures
73
73
  }
74
74
  FileL2 struct {
75
- Options func() protoreflect.ProtoMessage
76
- Imports FileImports
77
- Locations SourceLocations
75
+ Options func() protoreflect.ProtoMessage
76
+ Imports FileImports
77
+ OptionImports func() protoreflect.FileImports
78
+ Locations SourceLocations
78
79
  }
79
80
 
80
81
  // EditionFeatures is a frequently-instantiated struct, so please take care
@@ -126,12 +127,9 @@ func (fd *File) ParentFile() protoreflect.FileDescriptor { return fd }
126
127
  func (fd *File) Parent() protoreflect.Descriptor { return nil }
127
128
  func (fd *File) Index() int { return 0 }
128
129
  func (fd *File) Syntax() protoreflect.Syntax { return fd.L1.Syntax }
129
-
130
- // Not exported and just used to reconstruct the original FileDescriptor proto
131
- func (fd *File) Edition() int32 { return int32(fd.L1.Edition) }
132
- func (fd *File) Name() protoreflect.Name { return fd.L1.Package.Name() }
133
- func (fd *File) FullName() protoreflect.FullName { return fd.L1.Package }
134
- func (fd *File) IsPlaceholder() bool { return false }
130
+ func (fd *File) Name() protoreflect.Name { return fd.L1.Package.Name() }
131
+ func (fd *File) FullName() protoreflect.FullName { return fd.L1.Package }
132
+ func (fd *File) IsPlaceholder() bool { return false }
135
133
  func (fd *File) Options() protoreflect.ProtoMessage {
136
134
  if f := fd.lazyInit().Options; f != nil {
137
135
  return f()
@@ -150,6 +148,16 @@ func (fd *File) Format(s fmt.State, r rune) { descfmt.FormatD
150
148
  func (fd *File) ProtoType(protoreflect.FileDescriptor) {}
151
149
  func (fd *File) ProtoInternal(pragma.DoNotImplement) {}
152
150
 
151
+ // The next two are not part of the FileDescriptor interface. They are just used to reconstruct
152
+ // the original FileDescriptor proto.
153
+ func (fd *File) Edition() int32 { return int32(fd.L1.Edition) }
154
+ func (fd *File) OptionImports() protoreflect.FileImports {
155
+ if f := fd.lazyInit().OptionImports; f != nil {
156
+ return f()
157
+ }
158
+ return emptyFiles
159
+ }
160
+
153
161
  func (fd *File) lazyInit() *FileL2 {
154
162
  if atomic.LoadUint32(&fd.once) == 0 {
155
163
  fd.lazyInitOnce()
@@ -182,9 +190,9 @@ type (
182
190
  L2 *EnumL2 // protected by fileDesc.once
183
191
  }
184
192
  EnumL1 struct {
185
- eagerValues bool // controls whether EnumL2.Values is already populated
186
-
187
193
  EditionFeatures EditionFeatures
194
+ Visibility int32
195
+ eagerValues bool // controls whether EnumL2.Values is already populated
188
196
  }
189
197
  EnumL2 struct {
190
198
  Options func() protoreflect.ProtoMessage
@@ -219,6 +227,11 @@ func (ed *Enum) ReservedNames() protoreflect.Names { return &ed.lazyInit()
219
227
  func (ed *Enum) ReservedRanges() protoreflect.EnumRanges { return &ed.lazyInit().ReservedRanges }
220
228
  func (ed *Enum) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, ed) }
221
229
  func (ed *Enum) ProtoType(protoreflect.EnumDescriptor) {}
230
+
231
+ // This is not part of the EnumDescriptor interface. It is just used to reconstruct
232
+ // the original FileDescriptor proto.
233
+ func (ed *Enum) Visibility() int32 { return ed.L1.Visibility }
234
+
222
235
  func (ed *Enum) lazyInit() *EnumL2 {
223
236
  ed.L0.ParentFile.lazyInit() // implicitly initializes L2
224
237
  return ed.L2
@@ -244,13 +257,13 @@ type (
244
257
  L2 *MessageL2 // protected by fileDesc.once
245
258
  }
246
259
  MessageL1 struct {
247
- Enums Enums
248
- Messages Messages
249
- Extensions Extensions
250
- IsMapEntry bool // promoted from google.protobuf.MessageOptions
251
- IsMessageSet bool // promoted from google.protobuf.MessageOptions
252
-
260
+ Enums Enums
261
+ Messages Messages
262
+ Extensions Extensions
253
263
  EditionFeatures EditionFeatures
264
+ Visibility int32
265
+ IsMapEntry bool // promoted from google.protobuf.MessageOptions
266
+ IsMessageSet bool // promoted from google.protobuf.MessageOptions
254
267
  }
255
268
  MessageL2 struct {
256
269
  Options func() protoreflect.ProtoMessage
@@ -319,6 +332,11 @@ func (md *Message) Messages() protoreflect.MessageDescriptors { return &md.L
319
332
  func (md *Message) Extensions() protoreflect.ExtensionDescriptors { return &md.L1.Extensions }
320
333
  func (md *Message) ProtoType(protoreflect.MessageDescriptor) {}
321
334
  func (md *Message) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, md) }
335
+
336
+ // This is not part of the MessageDescriptor interface. It is just used to reconstruct
337
+ // the original FileDescriptor proto.
338
+ func (md *Message) Visibility() int32 { return md.L1.Visibility }
339
+
322
340
  func (md *Message) lazyInit() *MessageL2 {
323
341
  md.L0.ParentFile.lazyInit() // implicitly initializes L2
324
342
  return md.L2
@@ -284,6 +284,13 @@ func (ed *Enum) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd protorefl
284
284
  case genid.EnumDescriptorProto_Value_field_number:
285
285
  numValues++
286
286
  }
287
+ case protowire.VarintType:
288
+ v, m := protowire.ConsumeVarint(b)
289
+ b = b[m:]
290
+ switch num {
291
+ case genid.EnumDescriptorProto_Visibility_field_number:
292
+ ed.L1.Visibility = int32(v)
293
+ }
287
294
  default:
288
295
  m := protowire.ConsumeFieldValue(num, typ, b)
289
296
  b = b[m:]
@@ -365,6 +372,13 @@ func (md *Message) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd protor
365
372
  md.unmarshalSeedOptions(v)
366
373
  }
367
374
  prevField = num
375
+ case protowire.VarintType:
376
+ v, m := protowire.ConsumeVarint(b)
377
+ b = b[m:]
378
+ switch num {
379
+ case genid.DescriptorProto_Visibility_field_number:
380
+ md.L1.Visibility = int32(v)
381
+ }
368
382
  default:
369
383
  m := protowire.ConsumeFieldValue(num, typ, b)
370
384
  b = b[m:]
@@ -134,6 +134,7 @@ func (fd *File) unmarshalFull(b []byte) {
134
134
 
135
135
  var enumIdx, messageIdx, extensionIdx, serviceIdx int
136
136
  var rawOptions []byte
137
+ var optionImports []string
137
138
  fd.L2 = new(FileL2)
138
139
  for len(b) > 0 {
139
140
  num, typ, n := protowire.ConsumeTag(b)
@@ -157,6 +158,8 @@ func (fd *File) unmarshalFull(b []byte) {
157
158
  imp = PlaceholderFile(path)
158
159
  }
159
160
  fd.L2.Imports = append(fd.L2.Imports, protoreflect.FileImport{FileDescriptor: imp})
161
+ case genid.FileDescriptorProto_OptionDependency_field_number:
162
+ optionImports = append(optionImports, sb.MakeString(v))
160
163
  case genid.FileDescriptorProto_EnumType_field_number:
161
164
  fd.L1.Enums.List[enumIdx].unmarshalFull(v, sb)
162
165
  enumIdx++
@@ -178,6 +181,23 @@ func (fd *File) unmarshalFull(b []byte) {
178
181
  }
179
182
  }
180
183
  fd.L2.Options = fd.builder.optionsUnmarshaler(&descopts.File, rawOptions)
184
+ if len(optionImports) > 0 {
185
+ var imps FileImports
186
+ var once sync.Once
187
+ fd.L2.OptionImports = func() protoreflect.FileImports {
188
+ once.Do(func() {
189
+ imps = make(FileImports, len(optionImports))
190
+ for i, path := range optionImports {
191
+ imp, _ := fd.builder.FileRegistry.FindFileByPath(path)
192
+ if imp == nil {
193
+ imp = PlaceholderFile(path)
194
+ }
195
+ imps[i] = protoreflect.FileImport{FileDescriptor: imp}
196
+ }
197
+ })
198
+ return &imps
199
+ }
200
+ }
181
201
  }
182
202
 
183
203
  func (ed *Enum) unmarshalFull(b []byte, sb *strs.Builder) {
@@ -52,7 +52,7 @@ import (
52
52
  const (
53
53
  Major = 1
54
54
  Minor = 36
55
- Patch = 9
55
+ Patch = 10
56
56
  PreRelease = ""
57
57
  )
58
58