-// 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.
-func whatsappSendCheck(id, chat, text string, own []string) (types.JID, error) {
- jid, err := types.ParseJID(chat)
- switch {
- case strings.TrimSpace(id) == "" || len(id) > whatsappSendIDBytes:
- return types.EmptyJID, fmt.Errorf("the id must have 1 to %d bytes", whatsappSendIDBytes)
- case strings.TrimSpace(text) == "" || len(text) > whatsappSendBytes:
- return types.EmptyJID, fmt.Errorf("the text must have 1 to %d bytes", whatsappSendBytes)
- case err != nil || jid.User == "" || jid != jid.ToNonAD() || jid.String() != chat:
- return types.EmptyJID, fmt.Errorf("%q is not the ID of a WhatsApp chat: find the ID with whatsapp_find", chat)
- case jid.Server != types.DefaultUserServer && jid.Server != types.HiddenUserServer && jid.Server != types.GroupServer:
- return types.EmptyJID, fmt.Errorf("%q is not a private chat or a group", chat)
- case slices.Contains(own, jid.User):
- return types.EmptyJID, errors.New("this is the chat of the user with itself: send to another chat")
- }
-
- return jid, nil
-}
-
-// whatsappOwnIDs returns the own number and the own LID that are not empty.
-func whatsappOwnIDs(ids ...string) []string {
- var own []string
- for _, id := range ids {
- if id != "" {
- own = append(own, id)
- }
- }
-
- return own
-}
-
-// whatsappSessionAddress returns the SQLite address of the session database at
-// path, with foreign keys on, as the library needs, and a wait for a busy
-// database.
-func whatsappSessionAddress(path string) (string, error) {
- path, err := filepath.Abs(path)
- if err != nil {
- return "", fmt.Errorf("find WhatsApp session: %w", err)
- }
-
- address := url.URL{
- Scheme: "file",
- Path: path,
- RawQuery: "_pragma=foreign_keys(1)&_pragma=busy_timeout(5000)",
- }