2022-01-30 15:27:37 -08:00
// 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 (
2022-08-13 07:14:26 -07:00
ErrNoSession = errors . New ( "can't encrypt message for device: no signal session established" )
ErrIQTimedOut = errors . New ( "info query timed out" )
ErrNotConnected = errors . New ( "websocket not connected" )
ErrNotLoggedIn = errors . New ( "the store doesn't contain a device JID" )
ErrMessageTimedOut = errors . New ( "timed out waiting for message send response" )
2022-01-30 15:27:37 -08:00
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" )
2022-08-13 07:14:26 -07:00
// ErrProfilePictureNotSet is returned by GetProfilePictureInfo when the given user or group doesn't have a profile
// picture (status code 404).
ErrProfilePictureNotSet = errors . New ( "that user or group does not have a profile picture" )
2022-01-30 15:27:37 -08:00
// 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" )
2022-03-12 14:02:04 -08:00
// 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" )
2022-05-09 14:00:23 -07:00
// ErrMediaNotAvailableOnPhone is returned by DecryptMediaRetryNotification if the given event contains error code 2.
ErrMediaNotAvailableOnPhone = errors . New ( "media no longer available on phone" )
// ErrUnknownMediaRetryError is returned by DecryptMediaRetryNotification if the given event contains an unknown error code.
ErrUnknownMediaRetryError = errors . New ( "unknown media retry error" )
2022-06-11 14:07:42 -07:00
// ErrInvalidDisappearingTimer is returned by SetDisappearingTimer if the given timer is not one of the allowed values.
ErrInvalidDisappearingTimer = errors . New ( "invalid disappearing timer provided" )
2022-01-30 15:27:37 -08:00
)
// Some errors that Client.SendMessage can return
var (
2022-06-11 14:07:42 -07:00
ErrBroadcastListUnsupported = errors . New ( "sending to non-status broadcast lists is not yet supported" )
2022-01-30 15:27:37 -08:00
ErrUnknownServer = errors . New ( "can't send message to unknown server" )
ErrRecipientADJID = errors . New ( "message recipient must be normal (non-AD) JID" )
)
// 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 (
2022-06-11 14:07:42 -07:00
ErrIQBadRequest error = & IQError { Code : 400 , Text : "bad-request" }
2022-01-30 15:27:37 -08:00
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 )
}
2022-05-09 14:00:23 -07:00
var ErrIQDisconnected = & DisconnectedError { Action : "info query" }
// DisconnectedError is returned if the websocket disconnects before an info query or other request gets a response.
type DisconnectedError struct {
Action string
Node * waBinary . Node
}
func ( err * DisconnectedError ) Error ( ) string {
return fmt . Sprintf ( "websocket disconnected before %s returned response" , err . Action )
}
func ( err * DisconnectedError ) Is ( other error ) bool {
otherDisc , ok := other . ( * DisconnectedError )
if ! ok {
return false
}
return otherDisc . Action == err . Action
}