X-Git-Url: http://git.giacomolli.uk/onechat/blobdiff_plain/a6a82d96b4906e9e1f09f45f69f48124f11ae1bb..2e2524881dfe8f6c5cabfd9d342d5d3492953bd4:/whatsapp.go?ds=sidebyside diff --git a/whatsapp.go b/whatsapp.go index c5af946..5b07300 100644 --- a/whatsapp.go +++ b/whatsapp.go @@ -1,7 +1,6 @@ package main import ( - "cmp" "context" "crypto/sha256" "encoding/hex" @@ -15,7 +14,6 @@ import ( "strings" "sync" "time" - "unicode" "go.mau.fi/whatsmeow" "go.mau.fi/whatsmeow/proto/waE2E" @@ -24,9 +22,6 @@ import ( "go.mau.fi/whatsmeow/types" "go.mau.fi/whatsmeow/types/events" waLog "go.mau.fi/whatsmeow/util/log" - "golang.org/x/text/runes" - "golang.org/x/text/transform" - "golang.org/x/text/unicode/norm" // The session store of the library opens SQLite with this pure Go // driver. @@ -80,9 +75,6 @@ const ( // session database or of the groups from WhatsApp. whatsappLookupTime = 10 * time.Second - // whatsappFindMatches is the most matches of whatsapp_find. - whatsappFindMatches = 20 - // whatsappNotLinked is the answer of a WhatsApp tool without a link. whatsappNotLinked = "WhatsApp is not linked. Tell the user to run /whatsapp pair PHONE in the terminal or in Telegram." @@ -99,10 +91,6 @@ const ( whatsappSending = "sending" whatsappSent = "sent" whatsappFailed = "failed" - - // whatsappNamesNotReady is the answer of whatsapp_find before the names - // arrive from the phone. - whatsappNamesNotReady = "The names of the contacts and groups have not arrived from the phone yet. They come some minutes after the link. Try again later." ) // WhatsAppClient is the part of the WhatsApp client that the daemon uses. The @@ -363,6 +351,11 @@ func (w *WhatsApp) Close() error { return err } +// Find returns the answer of whatsapp_find for name, as whatsappFind says. +func (w *WhatsApp) Find(ctx context.Context, name string) (string, error) { + return whatsappFind(ctx, w.link(), w.groups, name) +} + func (w *WhatsApp) sessionPath() string { return filepath.Join(w.dir, whatsappSessionFileName) } @@ -522,80 +515,6 @@ func (w *WhatsApp) unlink(ctx context.Context, l *TurnLoop, answer func(text str return nil } -// Find returns the contacts and the groups whose name contains name, with no -// regard to case and accents, as lines "ID | name | contact" or "ID | name | -// group", sorted by name. It gives at most whatsappFindMatches lines and the -// number of the others. The contacts come from the session database, and the -// groups from WhatsApp, read again after whatsappGroupsAge. When the groups -// cannot be read and none are known, the answer says so. Before the names -// arrive from the phone, it says that they are not ready. -func (w *WhatsApp) Find(ctx context.Context, name string) (string, error) { - w.mutex.Lock() - linked := w.linked - device := w.device - own := slices.Clone(w.own) - w.mutex.Unlock() - - stale := w.groups.stale() - - if !linked { - return whatsappNotLinked, nil - } - - query := whatsappFold(name) - if query == "" { - return "", errors.New("name is empty: give a part of the name of the contact or the group") - } - - contacts, err := device.Contacts.GetAllContacts(ctx) - if err != nil { - return "", fmt.Errorf("read the contacts: %s", w.redact(err.Error())) - } - - read := !stale || w.groups.read(ctx, w.link()) - groups := w.groups.all() - - if len(contacts) == 0 && len(groups) == 0 { - if !read { - return "The names are not known yet, and WhatsApp is disconnected, so the groups cannot be read. Try again later.", nil - } - - return whatsappNamesNotReady, nil - } - - var matches []WhatsAppMatch - for jid, contact := range contacts { - names := []string{contact.FullName, contact.FirstName, contact.BusinessName, contact.PushName} - shown := slices.IndexFunc(names, func(name string) bool { - return name != "" - }) - - if slices.Contains(own, jid.User) || shown < 0 || !slices.ContainsFunc(names, func(name string) bool { - return strings.Contains(whatsappFold(name), query) - }) { - continue - } - - matches = append(matches, WhatsAppMatch{ - id: jid.ToNonAD().String(), - name: names[shown], - kind: "contact", - }) - } - - for id, group := range groups { - if strings.Contains(whatsappFold(group), query) { - matches = append(matches, WhatsAppMatch{ - id: id, - name: group, - kind: "group", - }) - } - } - - return whatsappFindAnswer(name, matches, read || len(groups) > 0), nil -} - // removeSession ends the connection, closes the session database, and deletes // its files. func (w *WhatsApp) removeSession() error { @@ -973,13 +892,6 @@ func (w *WhatsApp) Send(ctx context.Context, id, chat, text string) (string, err return record.Answer, nil } -// WhatsAppMatch is one contact or group of Find. -type WhatsAppMatch struct { - id string - name string - kind string -} - // WhatsAppLink is a copy of the link of the device at one time, for the parts // of WhatsApp that do not own it: the groups, the batches, find, and send. type WhatsAppLink struct { @@ -1055,44 +967,6 @@ func whatsappContactName(ctx context.Context, device *store.Device, jid types.JI } } -// whatsappFold returns text in lower case with no accents and no space at its -// ends, so that names match with no regard to case and accents. -func whatsappFold(text string) string { - folded, _, err := transform.String(transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC), text) - if err != nil { - folded = text - } - - return strings.ToLower(strings.TrimSpace(folded)) -} - -// whatsappFindAnswer returns the answer of Find for name with matches. Without -// groups, the answer says that it has no groups. -func whatsappFindAnswer(name string, matches []WhatsAppMatch, groups bool) string { - slices.SortFunc(matches, func(a, b WhatsAppMatch) int { - return cmp.Or(strings.Compare(whatsappFold(a.name), whatsappFold(b.name)), strings.Compare(a.id, b.id)) - }) - - var lines []string - for _, match := range matches[:min(len(matches), whatsappFindMatches)] { - lines = append(lines, match.id+" | "+match.name+" | "+match.kind) - } - - if len(matches) == 0 { - lines = append(lines, "No contact or group has a name with \""+name+"\".") - } - - if len(matches) > whatsappFindMatches { - lines = append(lines, fmt.Sprintf("%d more: give a longer part of the name.", len(matches)-whatsappFindMatches)) - } - - if !groups { - lines = append(lines, "The groups are not in this answer, because WhatsApp is disconnected.") - } - - return strings.Join(lines, "\n") -} - // whatsappSendCheck returns the JID of chat, and an error when id, chat, or // text cannot go to a send. The chat is a private chat or a group, and not the // chat of the user with itself.