package com.xabber.android.data.extension.carbons;
import com.xabber.android.data.Application;
import com.xabber.android.data.SettingsManager;
import com.xabber.android.data.SettingsManager.SecurityOtrMode;
import com.xabber.android.data.account.AccountManager;
import com.xabber.android.data.connection.ConnectionItem;
import com.xabber.android.data.entity.AccountJid;
import com.xabber.android.data.extension.otr.OTRManager;
import com.xabber.android.data.extension.otr.SecurityLevel;
import com.xabber.android.data.log.LogManager;
import com.xabber.android.data.message.AbstractChat;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.carbons.packet.CarbonExtension;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Packet extension for XEP-0280: Message Carbons. This class implements
* the manager for registering Carbon support, enabling and disabling
* message carbons.
* <p/>
* You should call enableCarbons() before sending your first undirected
* presence.
*
* @author Georg Lukas, Semyon Baranov
*/
public class CarbonManager {
private static CarbonManager instance;
@SuppressWarnings("WeakerAccess")
Map<AccountJid, CarbonCopyListener> carbonCopyListeners;
public static CarbonManager getInstance() {
if (instance == null) {
instance = new CarbonManager();
}
return instance;
}
private CarbonManager() {
carbonCopyListeners = new ConcurrentHashMap<>();
}
public void onAuthorized(final ConnectionItem connection) {
updateIsSupported(connection);
}
@SuppressWarnings("WeakerAccess")
void updateIsSupported(final ConnectionItem connectionItem) {
org.jivesoftware.smackx.carbons.CarbonManager carbonManager
= org.jivesoftware.smackx.carbons.CarbonManager
.getInstanceFor(connectionItem.getConnection());
try {
if (carbonManager.isSupportedByServer()) {
if (carbonManager.getCarbonsEnabled()) {
// Smack CarbonManager still thinks, that carbons enabled and does not sent IQ
// it drops flag to false when on authorized listener, but it happens after this listener
// so it is problem of unordered authorized listeners
carbonManager.setCarbonsEnabled(false);
}
carbonManager.setCarbonsEnabled(SettingsManager.connectionUseCarbons());
addListener(carbonManager, connectionItem.getAccount());
}
} catch (SmackException.NoResponseException | XMPPException.XMPPErrorException
| SmackException.NotConnectedException | InterruptedException e) {
LogManager.exception(this, e);
}
}
// we need to remove old listener not to cause memory leak
private void addListener(org.jivesoftware.smackx.carbons.CarbonManager carbonManager, AccountJid account) {
CarbonCopyListener carbonCopyListener = carbonCopyListeners.remove(account);
if (carbonCopyListener != null) {
carbonManager.removeCarbonCopyReceivedListener(carbonCopyListener);
}
carbonCopyListener = new CarbonCopyListener(account);
carbonCopyListeners.put(account, carbonCopyListener);
carbonManager.addCarbonCopyReceivedListener(carbonCopyListener);
}
private boolean isCarbonsEnabledForConnection(ConnectionItem connection) {
return org.jivesoftware.smackx.carbons.CarbonManager
.getInstanceFor(connection.getConnection())
.getCarbonsEnabled();
}
/**
* Sends the new state of message carbons to the server
* when this setting has been changed
*/
public void onUseCarbonsSettingsChanged() {
Application.getInstance().runInBackgroundUserRequest(new Runnable() {
@Override
public void run() {
Collection<AccountJid> accounts = AccountManager.getInstance().getEnabledAccounts();
for (AccountJid account : accounts) {
updateIsSupported(AccountManager.getInstance().getAccount(account));
}
}
});
}
/**
* Update outgoing message before sending.
* Marks the message as non-carbon-copied in the following cases:
* - Message Carbons is enabled and OTR mode is enabled.
* - Message Carbons is enabled and OTR security level != plain.
*
* @param abstractChat
* @param message the <tt>Message</tt> to be sent
*/
public void updateOutgoingMessage(AbstractChat abstractChat, Message message) {
if (!SettingsManager.connectionUseCarbons()) {
return;
}
if (SettingsManager.securityOtrMode() == SecurityOtrMode.disabled) {
return;
}
SecurityLevel securityLevel = OTRManager.getInstance().getSecurityLevel(abstractChat.getAccount(), abstractChat.getUser());
if (securityLevel == SecurityLevel.plain) {
return;
}
if (isCarbonsEnabledForConnection(AccountManager.getInstance().getAccount(abstractChat.getAccount()))) {
return;
}
CarbonExtension.Private.addTo(message);
}
}