package org.mercury_im.messenger.usecase; import org.jivesoftware.smack.AbstractXMPPConnection; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.sasl.SASLErrorException; import org.jxmpp.jid.BareJid; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.stringprep.XmppStringprepException; import org.mercury_im.messenger.Messenger; import org.mercury_im.messenger.data.repository.AccountRepository; import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.entity.IAccount; import org.mercury_im.messenger.exception.IllegalUsernameException; import org.mercury_im.messenger.xmpp.MercuryConnection; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import io.reactivex.Completable; import io.reactivex.Single; import io.reactivex.schedulers.Schedulers; public class AddAccount { private static final Logger LOGGER = Logger.getLogger(AddAccount.class.getName()); private String username; private String server; private BareJid address; private String password; private Account account; private final AccountRepository accountRepository; private final Messenger messenger; public AddAccount(AccountRepository accountRepository, Messenger messenger) { this.accountRepository = accountRepository; this.messenger = messenger; } public void setAddress(String address) { try { this.address = JidCreate.entityBareFrom(address); } catch (XmppStringprepException e) { this.address = null; throw new IllegalUsernameException(e); } } public boolean isAddressSet() { return address != null; } public void setPassword(String password) { this.password = password; } public boolean isPasswordSet() { return password != null; } public Single insertAccountIntoDatabase() { Account account = new IAccount(); account.setAddress(address.asUnescapedString()); account.setPassword(password); return accountRepository.insertAccount(account).doAfterSuccess(this::setAccount); } private void setAccount(Account account) { this.account = account; } public Single enableAccountAndLogin(Account account) { return enableAccount(account).andThen(login(account)); } private Completable enableAccount(Account account) { account.setEnabled(true); return accountRepository.upsertAccount(account) .doAfterSuccess(this::setAccount) .ignoreElement(); } private Single login(Account account) { return Single.fromCallable(() -> { MercuryConnection connection = getOrCreateConnection(account); return authenticateIfNecessary(connection); }).subscribeOn(Schedulers.io()); } private MercuryConnection getOrCreateConnection(Account account) { MercuryConnection connection = messenger.getConnection(account); if (connection == null) { connection = new MercuryConnection(account); messenger.addConnection(connection); } return connection; } private ConnectionResult authenticateIfNecessary(MercuryConnection connection) { try { doAuthenticateIfNecessary(connection); return ConnectionResult.success; } catch (SASLErrorException e) { LOGGER.log(Level.WARNING, "SASL Error while connecting to account " + account.getAddress(), e); return ConnectionResult.credential_error; } catch (SmackException.ConnectionException e) { LOGGER.log(Level.WARNING, "Connectivity error while connecting to account " + account.getAddress(), e); return ConnectionResult.server_error; } catch (IOException | XMPPException | SmackException | InterruptedException e) { LOGGER.log(Level.WARNING, "Error connecting to account " + account.getAddress(), e); return ConnectionResult.other_error; } } private void doAuthenticateIfNecessary(MercuryConnection connection) throws InterruptedException, XMPPException, SmackException, IOException { if (!connection.getConnection().isAuthenticated()) { ((AbstractXMPPConnection) connection.getConnection()).connect().login(); } } public enum ConnectionResult { success, credential_error, server_error, other_error } }