160 lines
6.3 KiB
Go
160 lines
6.3 KiB
Go
// Copyright (c) 2021 Tulir Asokan
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
package whatsmeow
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
waBinary "go.mau.fi/whatsmeow/binary"
|
|
)
|
|
|
|
// Miscellaneous errors
|
|
var (
|
|
ErrNoSession = errors.New("can't encrypt message for device: no signal session established")
|
|
ErrIQTimedOut = errors.New("info query timed out")
|
|
ErrIQDisconnected = errors.New("websocket disconnected before info query returned response")
|
|
ErrNotConnected = errors.New("websocket not connected")
|
|
ErrNotLoggedIn = errors.New("the store doesn't contain a device JID")
|
|
|
|
ErrAlreadyConnected = errors.New("websocket is already connected")
|
|
|
|
ErrQRAlreadyConnected = errors.New("GetQRChannel must be called before connecting")
|
|
ErrQRStoreContainsID = errors.New("GetQRChannel can only be called when there's no user ID in the client's Store")
|
|
|
|
ErrNoPushName = errors.New("can't send presence without PushName set")
|
|
)
|
|
|
|
var (
|
|
// ErrProfilePictureUnauthorized is returned by GetProfilePictureInfo when trying to get the profile picture of a user
|
|
// whose privacy settings prevent you from seeing their profile picture (status code 401).
|
|
ErrProfilePictureUnauthorized = errors.New("the user has hidden their profile picture from you")
|
|
// ErrGroupInviteLinkUnauthorized is returned by GetGroupInviteLink if you don't have the permission to get the link (status code 401).
|
|
ErrGroupInviteLinkUnauthorized = errors.New("you don't have the permission to get the group's invite link")
|
|
// ErrNotInGroup is returned by group info getting methods if you're not in the group (status code 403).
|
|
ErrNotInGroup = errors.New("you're not participating in that group")
|
|
// ErrGroupNotFound is returned by group info getting methods if the group doesn't exist (status code 404).
|
|
ErrGroupNotFound = errors.New("that group does not exist")
|
|
// ErrInviteLinkInvalid is returned by methods that use group invite links if the invite link is malformed.
|
|
ErrInviteLinkInvalid = errors.New("that group invite link is not valid")
|
|
// ErrInviteLinkRevoked is returned by methods that use group invite links if the invite link was valid, but has been revoked and can no longer be used.
|
|
ErrInviteLinkRevoked = errors.New("that group invite link has been revoked")
|
|
// ErrBusinessMessageLinkNotFound is returned by ResolveBusinessMessageLink if the link doesn't exist or has been revoked.
|
|
ErrBusinessMessageLinkNotFound = errors.New("that business message link does not exist or has been revoked")
|
|
// ErrInvalidImageFormat is returned by SetGroupPhoto if the given photo is not in the correct format.
|
|
ErrInvalidImageFormat = errors.New("the given data is not a valid image")
|
|
)
|
|
|
|
// Some errors that Client.SendMessage can return
|
|
var (
|
|
ErrBroadcastListUnsupported = errors.New("sending to broadcast lists is not yet supported")
|
|
ErrUnknownServer = errors.New("can't send message to unknown server")
|
|
ErrRecipientADJID = errors.New("message recipient must be normal (non-AD) JID")
|
|
ErrSendDisconnected = errors.New("websocket disconnected before message send returned response")
|
|
)
|
|
|
|
// Some errors that Client.Download can return
|
|
var (
|
|
ErrMediaDownloadFailedWith404 = errors.New("download failed with status code 404")
|
|
ErrMediaDownloadFailedWith410 = errors.New("download failed with status code 410")
|
|
ErrNoURLPresent = errors.New("no url present")
|
|
ErrFileLengthMismatch = errors.New("file length does not match")
|
|
ErrTooShortFile = errors.New("file too short")
|
|
ErrInvalidMediaHMAC = errors.New("invalid media hmac")
|
|
ErrInvalidMediaEncSHA256 = errors.New("hash of media ciphertext doesn't match")
|
|
ErrInvalidMediaSHA256 = errors.New("hash of media plaintext doesn't match")
|
|
ErrUnknownMediaType = errors.New("unknown media type")
|
|
ErrNothingDownloadableFound = errors.New("didn't find any attachments in message")
|
|
)
|
|
|
|
type wrappedIQError struct {
|
|
HumanError error
|
|
IQError error
|
|
}
|
|
|
|
func (err *wrappedIQError) Error() string {
|
|
return err.HumanError.Error()
|
|
}
|
|
|
|
func (err *wrappedIQError) Is(other error) bool {
|
|
return errors.Is(other, err.HumanError)
|
|
}
|
|
|
|
func (err *wrappedIQError) Unwrap() error {
|
|
return err.IQError
|
|
}
|
|
|
|
func wrapIQError(human, iq error) error {
|
|
return &wrappedIQError{human, iq}
|
|
}
|
|
|
|
// IQError is a generic error container for info queries
|
|
type IQError struct {
|
|
Code int
|
|
Text string
|
|
ErrorNode *waBinary.Node
|
|
RawNode *waBinary.Node
|
|
}
|
|
|
|
// Common errors returned by info queries for use with errors.Is
|
|
var (
|
|
ErrIQNotAuthorized error = &IQError{Code: 401, Text: "not-authorized"}
|
|
ErrIQForbidden error = &IQError{Code: 403, Text: "forbidden"}
|
|
ErrIQNotFound error = &IQError{Code: 404, Text: "item-not-found"}
|
|
ErrIQNotAcceptable error = &IQError{Code: 406, Text: "not-acceptable"}
|
|
ErrIQGone error = &IQError{Code: 410, Text: "gone"}
|
|
)
|
|
|
|
func parseIQError(node *waBinary.Node) error {
|
|
var err IQError
|
|
err.RawNode = node
|
|
val, ok := node.GetOptionalChildByTag("error")
|
|
if ok {
|
|
err.ErrorNode = &val
|
|
ag := val.AttrGetter()
|
|
err.Code = ag.OptionalInt("code")
|
|
err.Text = ag.OptionalString("text")
|
|
}
|
|
return &err
|
|
}
|
|
|
|
func (iqe *IQError) Error() string {
|
|
if iqe.Code == 0 {
|
|
if iqe.ErrorNode != nil {
|
|
return fmt.Sprintf("info query returned unknown error: %s", iqe.ErrorNode.XMLString())
|
|
} else if iqe.RawNode != nil {
|
|
return fmt.Sprintf("info query returned unexpected response: %s", iqe.RawNode.XMLString())
|
|
} else {
|
|
return "unknown info query error"
|
|
}
|
|
}
|
|
return fmt.Sprintf("info query returned status %d: %s", iqe.Code, iqe.Text)
|
|
}
|
|
|
|
func (iqe *IQError) Is(other error) bool {
|
|
otherIQE, ok := other.(*IQError)
|
|
if !ok {
|
|
return false
|
|
} else if iqe.Code != 0 && otherIQE.Code != 0 {
|
|
return otherIQE.Code == iqe.Code && otherIQE.Text == iqe.Text
|
|
} else if iqe.ErrorNode != nil && otherIQE.ErrorNode != nil {
|
|
return iqe.ErrorNode.XMLString() == otherIQE.ErrorNode.XMLString()
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
// ElementMissingError is returned by various functions that parse XML elements when a required element is missing.
|
|
type ElementMissingError struct {
|
|
Tag string
|
|
In string
|
|
}
|
|
|
|
func (eme *ElementMissingError) Error() string {
|
|
return fmt.Sprintf("missing <%s> element in %s", eme.Tag, eme.In)
|
|
}
|