package org.asamk.signal.manager; import com.google.i18n.phonenumbers.PhoneNumberUtil; import org.asamk.signal.manager.api.AlreadyReceivingException; import org.asamk.signal.manager.api.AttachmentInvalidException; import org.asamk.signal.manager.api.CaptchaRejectedException; import org.asamk.signal.manager.api.CaptchaRequiredException; import org.asamk.signal.manager.api.Configuration; import org.asamk.signal.manager.api.Device; import org.asamk.signal.manager.api.DeviceLimitExceededException; import org.asamk.signal.manager.api.DeviceLinkUrl; import org.asamk.signal.manager.api.Group; import org.asamk.signal.manager.api.GroupId; import org.asamk.signal.manager.api.GroupInviteLinkUrl; import org.asamk.signal.manager.api.GroupNotFoundException; import org.asamk.signal.manager.api.GroupSendingNotAllowedException; import org.asamk.signal.manager.api.Identity; import org.asamk.signal.manager.api.IdentityVerificationCode; import org.asamk.signal.manager.api.InactiveGroupLinkException; import org.asamk.signal.manager.api.IncorrectPinException; import org.asamk.signal.manager.api.InvalidDeviceLinkException; import org.asamk.signal.manager.api.InvalidStickerException; import org.asamk.signal.manager.api.InvalidUsernameException; import org.asamk.signal.manager.api.LastGroupAdminException; import org.asamk.signal.manager.api.Message; import org.asamk.signal.manager.api.MessageEnvelope; import org.asamk.signal.manager.api.NonNormalizedPhoneNumberException; import org.asamk.signal.manager.api.NotAGroupMemberException; import org.asamk.signal.manager.api.NotPrimaryDeviceException; import org.asamk.signal.manager.api.Pair; import org.asamk.signal.manager.api.PendingAdminApprovalException; import org.asamk.signal.manager.api.PinLockedException; import org.asamk.signal.manager.api.RateLimitException; import org.asamk.signal.manager.api.ReceiveConfig; import org.asamk.signal.manager.api.Recipient; import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.SendGroupMessageResults; import org.asamk.signal.manager.api.SendMessageResults; import org.asamk.signal.manager.api.StickerPack; import org.asamk.signal.manager.api.StickerPackId; import org.asamk.signal.manager.api.StickerPackInvalidException; import org.asamk.signal.manager.api.StickerPackUrl; import org.asamk.signal.manager.api.TypingAction; import org.asamk.signal.manager.api.UnregisteredRecipientException; import org.asamk.signal.manager.api.UpdateGroup; import org.asamk.signal.manager.api.UpdateProfile; import org.asamk.signal.manager.api.UserStatus; import org.asamk.signal.manager.api.UsernameLinkUrl; import org.asamk.signal.manager.api.UsernameStatus; import org.asamk.signal.manager.api.VerificationMethodNotAvailableException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Closeable; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.time.Duration; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; public interface Manager extends Closeable { static boolean isValidNumber(final String e164Number, final String countryCode) { return PhoneNumberUtil.getInstance().isPossibleNumber(e164Number, countryCode); } static boolean isSignalClientAvailable() { final Logger logger = LoggerFactory.getLogger(Manager.class); try { try { org.signal.libsignal.internal.Native.UuidCiphertext_CheckValidContents(new byte[0]); } catch (Exception e) { logger.trace("Expected exception when checking libsignal-client: {}", e.getMessage()); } return true; } catch (UnsatisfiedLinkError e) { logger.warn("Failed to call libsignal-client: {}", e.getMessage()); return false; } } String getSelfNumber(); /** * This is used for checking a set of phone numbers for registration on Signal * * @param numbers The set of phone number in question * @return A map of numbers to canonicalized number and uuid. If a number is not registered the uuid is null. * @throws IOException if it's unable to get the contacts to check if they're registered */ Map getUserStatus(Set numbers) throws IOException, RateLimitException; Map getUsernameStatus(Set usernames); void updateAccountAttributes( String deviceName, Boolean unrestrictedUnidentifiedSender, final Boolean discoverableByNumber, final Boolean numberSharing ) throws IOException; Configuration getConfiguration(); void updateConfiguration(Configuration configuration) throws NotPrimaryDeviceException; /** * Update the user's profile. * If a field is null, the previous value will be kept. */ void updateProfile(UpdateProfile updateProfile) throws IOException; String getUsername(); UsernameLinkUrl getUsernameLink(); /** * Set a username for the account. * If the username is null, it will be deleted. */ void setUsername(String username) throws IOException, InvalidUsernameException; /** * Set a username for the account. * If the username is null, it will be deleted. */ void deleteUsername() throws IOException; void startChangeNumber( String newNumber, boolean voiceVerification, String captcha ) throws RateLimitException, IOException, CaptchaRequiredException, NonNormalizedPhoneNumberException, NotPrimaryDeviceException, VerificationMethodNotAvailableException; void finishChangeNumber( String newNumber, String verificationCode, String pin ) throws IncorrectPinException, PinLockedException, IOException, NotPrimaryDeviceException; void unregister() throws IOException; void deleteAccount() throws IOException; void submitRateLimitRecaptchaChallenge( String challenge, String captcha ) throws IOException, CaptchaRejectedException; List getLinkedDevices() throws IOException; void removeLinkedDevices(int deviceId) throws IOException, NotPrimaryDeviceException; void addDeviceLink(DeviceLinkUrl linkUri) throws IOException, InvalidDeviceLinkException, NotPrimaryDeviceException, DeviceLimitExceededException; void setRegistrationLockPin(Optional pin) throws IOException, NotPrimaryDeviceException; List getGroups(); SendGroupMessageResults quitGroup( GroupId groupId, Set groupAdmins ) throws GroupNotFoundException, IOException, NotAGroupMemberException, LastGroupAdminException, UnregisteredRecipientException; void deleteGroup(GroupId groupId) throws IOException; Pair createGroup( String name, Set members, String avatarFile ) throws IOException, AttachmentInvalidException, UnregisteredRecipientException; SendGroupMessageResults updateGroup( final GroupId groupId, final UpdateGroup updateGroup ) throws IOException, GroupNotFoundException, AttachmentInvalidException, NotAGroupMemberException, GroupSendingNotAllowedException, UnregisteredRecipientException; Pair joinGroup( GroupInviteLinkUrl inviteLinkUrl ) throws IOException, InactiveGroupLinkException, PendingAdminApprovalException; SendMessageResults sendTypingMessage( TypingAction action, Set recipients ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException; SendMessageResults sendReadReceipt(RecipientIdentifier.Single sender, List messageIds); SendMessageResults sendViewedReceipt(RecipientIdentifier.Single sender, List messageIds); SendMessageResults sendMessage( Message message, Set recipients, boolean notifySelf ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException; SendMessageResults sendEditMessage( Message message, Set recipients, long editTargetTimestamp ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException; SendMessageResults sendRemoteDeleteMessage( long targetSentTimestamp, Set recipients ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException; SendMessageResults sendMessageReaction( String emoji, boolean remove, RecipientIdentifier.Single targetAuthor, long targetSentTimestamp, Set recipients, final boolean isStory ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException; SendMessageResults sendPaymentNotificationMessage( byte[] receipt, String note, RecipientIdentifier.Single recipient ) throws IOException; SendMessageResults sendEndSessionMessage(Set recipients) throws IOException; SendMessageResults sendMessageRequestResponse( MessageEnvelope.Sync.MessageRequestResponse.Type type, Set recipientIdentifiers ); void hideRecipient(RecipientIdentifier.Single recipient); void deleteRecipient(RecipientIdentifier.Single recipient); void deleteContact(RecipientIdentifier.Single recipient); void setContactName( final RecipientIdentifier.Single recipient, final String givenName, final String familyName, final String nickGivenName, final String nickFamilyName, final String note ) throws NotPrimaryDeviceException, UnregisteredRecipientException; void setContactsBlocked( Collection recipient, boolean blocked ) throws NotPrimaryDeviceException, IOException, UnregisteredRecipientException; void setGroupsBlocked( Collection groupId, boolean blocked ) throws GroupNotFoundException, IOException, NotPrimaryDeviceException; /** * Change the expiration timer for a contact */ void setExpirationTimer( RecipientIdentifier.Single recipient, int messageExpirationTimer ) throws IOException, UnregisteredRecipientException; /** * Upload the sticker pack from path. * * @param path Path can be a path to a manifest.json file or to a zip file that contains a manifest.json file * @return if successful, returns the URL to install the sticker pack in the signal app */ StickerPackUrl uploadStickerPack(File path) throws IOException, StickerPackInvalidException; void installStickerPack(StickerPackUrl url) throws IOException; List getStickerPacks(); void requestAllSyncData() throws IOException; /** * Add a handler to receive new messages. * Will start receiving messages from server, if not already started. */ default void addReceiveHandler(ReceiveMessageHandler handler) { addReceiveHandler(handler, false); } void addReceiveHandler(ReceiveMessageHandler handler, final boolean isWeakListener); /** * Remove a handler to receive new messages. * Will stop receiving messages from server, if this was the last registered receiver. */ void removeReceiveHandler(ReceiveMessageHandler handler); boolean isReceiving(); /** * Receive new messages from server, returns if no new message arrive in a timespan of timeout. */ void receiveMessages( Optional timeout, Optional maxMessages, ReceiveMessageHandler handler ) throws IOException, AlreadyReceivingException; void stopReceiveMessages(); void setReceiveConfig(ReceiveConfig receiveConfig); boolean isContactBlocked(RecipientIdentifier.Single recipient); void sendContacts() throws IOException; List getRecipients( boolean onlyContacts, Optional blocked, Collection address, Optional name ); String getContactOrProfileName(RecipientIdentifier.Single recipient); Group getGroup(GroupId groupId); List getIdentities(); List getIdentities(RecipientIdentifier.Single recipient); /** * Trust this the identity with this fingerprint/safetyNumber * * @param recipient account of the identity */ boolean trustIdentityVerified( RecipientIdentifier.Single recipient, IdentityVerificationCode verificationCode ) throws UnregisteredRecipientException; /** * Trust all keys of this identity without verification * * @param recipient account of the identity */ boolean trustIdentityAllKeys(RecipientIdentifier.Single recipient) throws UnregisteredRecipientException; void addAddressChangedListener(Runnable listener); void addClosedListener(Runnable listener); InputStream retrieveAttachment(final String id) throws IOException; InputStream retrieveContactAvatar(final RecipientIdentifier.Single recipient) throws IOException, UnregisteredRecipientException; InputStream retrieveProfileAvatar(final RecipientIdentifier.Single recipient) throws IOException, UnregisteredRecipientException; InputStream retrieveGroupAvatar(final GroupId groupId) throws IOException; InputStream retrieveSticker(final StickerPackId stickerPackId, final int stickerId) throws IOException; @Override void close(); interface ReceiveMessageHandler { ReceiveMessageHandler EMPTY = (envelope, e) -> { }; void handleMessage(MessageEnvelope envelope, Throwable e); } }