aboutsummaryrefslogtreecommitdiffstats
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java252
-rw-r--r--src/main/java/eu/siacs/conversations/generator/IqGenerator.java29
-rw-r--r--src/main/java/eu/siacs/conversations/parser/IqParser.java20
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java3
4 files changed, 157 insertions, 147 deletions
diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
index 8879a0fe..22e959eb 100644
--- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
@@ -30,6 +30,7 @@ import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
import org.whispersystems.libaxolotl.util.KeyHelper;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -53,14 +54,16 @@ public class AxolotlService {
public static final String PEP_PREFIX = "eu.siacs.conversations.axolotl";
public static final String PEP_DEVICE_LIST = PEP_PREFIX + ".devicelist";
- public static final String PEP_PREKEYS = PEP_PREFIX + ".prekeys";
- public static final String PEP_BUNDLE = PEP_PREFIX + ".bundle";
+ public static final String PEP_BUNDLES = PEP_PREFIX + ".bundles";
+
+ public static final int NUM_KEYS_TO_PUBLISH = 10;
private final Account account;
private final XmppConnectionService mXmppConnectionService;
private final SQLiteAxolotlStore axolotlStore;
private final SessionMap sessions;
private final BundleMap bundleCache;
+ private final Map<Jid, Set<Integer>> deviceIds;
private int ownDeviceId;
public static class SQLiteAxolotlStore implements AxolotlStore {
@@ -565,6 +568,7 @@ public class AxolotlService {
this.mXmppConnectionService = connectionService;
this.account = account;
this.axolotlStore = new SQLiteAxolotlStore(this.account, this.mXmppConnectionService);
+ this.deviceIds = new HashMap<>();
this.sessions = new SessionMap(axolotlStore, account);
this.bundleCache = new BundleMap();
this.ownDeviceId = axolotlStore.getLocalRegistrationId();
@@ -607,80 +611,11 @@ public class AxolotlService {
return ownDeviceId;
}
- public void fetchBundleIfNeeded(final Contact contact, final Integer deviceId) {
- final AxolotlAddress address = new AxolotlAddress(contact.getJid().toString(), deviceId);
- if (sessions.get(address) != null) {
- return;
- }
-
- synchronized (bundleCache) {
- PreKeyBundle bundle = bundleCache.get(address);
- if (bundle == null) {
- bundle = new PreKeyBundle(0, deviceId, 0, null, 0, null, null, null);
- bundleCache.put(address, bundle);
- }
-
- if(bundle.getPreKey() == null) {
- Log.d(Config.LOGTAG, "No preKey in cache, fetching...");
- IqPacket prekeysPacket = mXmppConnectionService.getIqGenerator().retrievePreKeysForDevice(contact.getJid(), deviceId);
- mXmppConnectionService.sendIqPacket(account, prekeysPacket, new OnIqPacketReceived() {
- @Override
- public void onIqPacketReceived(Account account, IqPacket packet) {
- synchronized (bundleCache) {
- Log.d(Config.LOGTAG, "Received preKey IQ packet, processing...");
- final IqParser parser = mXmppConnectionService.getIqParser();
- final PreKeyBundle bundle = bundleCache.get(address);
- final List<PreKeyBundle> preKeyBundleList = parser.preKeys(packet);
- if (preKeyBundleList.isEmpty()) {
- Log.d(Config.LOGTAG, "preKey IQ packet invalid: " + packet);
- return;
- }
- Random random = new Random();
- final PreKeyBundle newBundle = preKeyBundleList.get(random.nextInt(preKeyBundleList.size()));
- if (bundle == null || newBundle == null) {
- //should never happen
- return;
- }
-
- final PreKeyBundle mergedBundle = new PreKeyBundle(bundle.getRegistrationId(),
- bundle.getDeviceId(), newBundle.getPreKeyId(), newBundle.getPreKey(),
- bundle.getSignedPreKeyId(), bundle.getSignedPreKey(),
- bundle.getSignedPreKeySignature(), bundle.getIdentityKey());
-
- bundleCache.put(address, mergedBundle);
- }
- }
- });
- }
- if(bundle.getIdentityKey() == null) {
- Log.d(Config.LOGTAG, "No bundle in cache, fetching...");
- IqPacket bundlePacket = mXmppConnectionService.getIqGenerator().retrieveBundleForDevice(contact.getJid(), deviceId);
- mXmppConnectionService.sendIqPacket(account, bundlePacket, new OnIqPacketReceived() {
- @Override
- public void onIqPacketReceived(Account account, IqPacket packet) {
- synchronized (bundleCache) {
- Log.d(Config.LOGTAG, "Received bundle IQ packet, processing...");
- final IqParser parser = mXmppConnectionService.getIqParser();
- final PreKeyBundle bundle = bundleCache.get(address);
- final PreKeyBundle newBundle = parser.bundle(packet);
- if( bundle == null || newBundle == null ) {
- Log.d(Config.LOGTAG, "bundle IQ packet invalid: " + packet);
- //should never happen
- return;
- }
-
- final PreKeyBundle mergedBundle = new PreKeyBundle(bundle.getRegistrationId(),
- bundle.getDeviceId(), bundle.getPreKeyId(), bundle.getPreKey(),
- newBundle.getSignedPreKeyId(), newBundle.getSignedPreKey(),
- newBundle.getSignedPreKeySignature(), newBundle.getIdentityKey());
-
- axolotlStore.saveIdentity(contact.getJid().toBareJid().toString(), newBundle.getIdentityKey());
- bundleCache.put(address, mergedBundle);
- }
- }
- });
- }
+ public void registerDevices(final Jid jid, final Set<Integer> deviceIds) {
+ for(Integer i:deviceIds) {
+ Log.d(Config.LOGTAG, "Adding Device ID:"+ jid + ":"+i);
}
+ this.deviceIds.put(jid, deviceIds);
}
public void publishOwnDeviceIdIfNeeded() {
@@ -689,14 +624,14 @@ public class AxolotlService {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
Element item = mXmppConnectionService.getIqParser().getItem(packet);
- List<Integer> deviceIds = mXmppConnectionService.getIqParser().deviceIds(item);
- if(deviceIds == null) {
- deviceIds = new ArrayList<>();
+ Set<Integer> deviceIds = mXmppConnectionService.getIqParser().deviceIds(item);
+ if (deviceIds == null) {
+ deviceIds = new HashSet<Integer>();
}
- if(!deviceIds.contains(getOwnDeviceId())) {
- Log.d(Config.LOGTAG, "Own device " + getOwnDeviceId() + " not in PEP devicelist. Publishing...");
+ if (!deviceIds.contains(getOwnDeviceId())) {
deviceIds.add(getOwnDeviceId());
IqPacket publish = mXmppConnectionService.getIqGenerator().publishDeviceIds(deviceIds);
+ Log.d(Config.LOGTAG, "Own device " + getOwnDeviceId() + " not in PEP devicelist. Publishing: " + publish);
mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
@@ -708,22 +643,68 @@ public class AxolotlService {
});
}
- public void publishBundleIfNeeded() {
- IqPacket packet = mXmppConnectionService.getIqGenerator().retrieveBundleForDevice(account.getJid().toBareJid(), ownDeviceId);
+ private boolean validateBundle(PreKeyBundle bundle) {
+ if (bundle == null || bundle.getIdentityKey() == null
+ || bundle.getSignedPreKey() == null || bundle.getSignedPreKeySignature() == null) {
+ return false;
+ }
+
+ try {
+ SignedPreKeyRecord signedPreKeyRecord = axolotlStore.loadSignedPreKey(bundle.getSignedPreKeyId());
+ IdentityKey identityKey = axolotlStore.getIdentityKeyPair().getPublicKey();
+ Log.d(Config.LOGTAG,"own identity key:"+identityKey.getFingerprint()+", foreign: "+bundle.getIdentityKey().getFingerprint());
+ Log.d(Config.LOGTAG,"bundle: "+Boolean.toString(bundle.getSignedPreKey().equals(signedPreKeyRecord.getKeyPair().getPublicKey()))
+ +" " + Boolean.toString(Arrays.equals(bundle.getSignedPreKeySignature(), signedPreKeyRecord.getSignature()))
+ +" " + Boolean.toString( bundle.getIdentityKey().equals(identityKey)));
+ return bundle.getSignedPreKey().equals(signedPreKeyRecord.getKeyPair().getPublicKey())
+ && Arrays.equals(bundle.getSignedPreKeySignature(), signedPreKeyRecord.getSignature())
+ && bundle.getIdentityKey().equals(identityKey);
+ } catch (InvalidKeyIdException ignored) {
+ return false;
+ }
+ }
+
+ private boolean validatePreKeys(Map<Integer, ECPublicKey> keys) {
+ if(keys == null) { return false; }
+ for(Integer id:keys.keySet()) {
+ try {
+ PreKeyRecord preKeyRecord = axolotlStore.loadPreKey(id);
+ if(!preKeyRecord.getKeyPair().getPublicKey().equals(keys.get(id))) {
+ return false;
+ }
+ } catch (InvalidKeyIdException ignored) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void publishBundlesIfNeeded() {
+ IqPacket packet = mXmppConnectionService.getIqGenerator().retrieveBundlesForDevice(account.getJid().toBareJid(), ownDeviceId);
mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
PreKeyBundle bundle = mXmppConnectionService.getIqParser().bundle(packet);
- if(bundle == null) {
- Log.d(Config.LOGTAG, "Bundle " + getOwnDeviceId() + " not in PEP. Publishing...");
+ Map<Integer, ECPublicKey> keys = mXmppConnectionService.getIqParser().preKeyPublics(packet);
+ SignedPreKeyRecord signedPreKeyRecord;
+ List<PreKeyRecord> preKeyRecords;
+ if (!validateBundle(bundle) || keys.isEmpty() || !validatePreKeys(keys)) {
int numSignedPreKeys = axolotlStore.loadSignedPreKeys().size();
try {
- SignedPreKeyRecord signedPreKeyRecord = KeyHelper.generateSignedPreKey(
+ signedPreKeyRecord = KeyHelper.generateSignedPreKey(
axolotlStore.getIdentityKeyPair(), numSignedPreKeys + 1);
axolotlStore.storeSignedPreKey(signedPreKeyRecord.getId(), signedPreKeyRecord);
- IqPacket publish = mXmppConnectionService.getIqGenerator().publishBundle(
+
+ preKeyRecords = KeyHelper.generatePreKeys(
+ axolotlStore.getCurrentPreKeyId(), NUM_KEYS_TO_PUBLISH);
+ for (PreKeyRecord record : preKeyRecords) {
+ axolotlStore.storePreKey(record.getId(), record);
+ }
+
+ IqPacket publish = mXmppConnectionService.getIqGenerator().publishBundles(
signedPreKeyRecord, axolotlStore.getIdentityKeyPair().getPublicKey(),
- ownDeviceId);
+ preKeyRecords, ownDeviceId);
+ Log.d(Config.LOGTAG, "Bundle " + getOwnDeviceId() + " not in PEP. Publishing: " + publish);
mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
@@ -733,48 +714,83 @@ public class AxolotlService {
});
} catch (InvalidKeyException e) {
Log.e(Config.LOGTAG, "Failed to publish bundle " + getOwnDeviceId() + ", reason: " + e.getMessage());
+ return;
}
}
}
});
}
- public void publishPreKeysIfNeeded() {
- IqPacket packet = mXmppConnectionService.getIqGenerator().retrievePreKeysForDevice(account.getJid().toBareJid(), ownDeviceId);
- mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
- @Override
- public void onIqPacketReceived(Account account, IqPacket packet) {
- Map<Integer, ECPublicKey> keys = mXmppConnectionService.getIqParser().preKeyPublics(packet);
- if(keys == null || keys.isEmpty()) {
- Log.d(Config.LOGTAG, "Prekeys " + getOwnDeviceId() + " not in PEP. Publishing...");
- List<PreKeyRecord> preKeyRecords = KeyHelper.generatePreKeys(
- axolotlStore.getCurrentPreKeyId(), 100);
- for(PreKeyRecord record : preKeyRecords) {
- axolotlStore.storePreKey(record.getId(), record);
- }
- IqPacket publish = mXmppConnectionService.getIqGenerator().publishPreKeys(
- preKeyRecords, ownDeviceId);
-
- mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
- @Override
- public void onIqPacketReceived(Account account, IqPacket packet) {
- Log.d(Config.LOGTAG, "Published prekeys, got: " + packet);
- // TODO: implement this!
- }
- });
- }
- }
- });
+ public boolean isContactAxolotlCapable(Contact contact) {
+ Jid jid = contact.getJid().toBareJid();
+ AxolotlAddress address = new AxolotlAddress(jid.toString(), 0);
+ return sessions.hasAny(address) ||
+ ( deviceIds.containsKey(jid) && !deviceIds.get(jid).isEmpty());
}
+ private void buildSessionFromPEP(final Conversation conversation, final AxolotlAddress address) {
+ Log.d(Config.LOGTAG, "Building new sesstion for " + address.getDeviceId());
+
+ try {
+ IqPacket bundlesPacket = mXmppConnectionService.getIqGenerator().retrieveBundlesForDevice(
+ Jid.fromString(address.getName()), address.getDeviceId());
+ Log.d(Config.LOGTAG, "Retrieving bundle: " + bundlesPacket);
+ mXmppConnectionService.sendIqPacket(account, bundlesPacket, new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ Log.d(Config.LOGTAG, "Received preKey IQ packet, processing...");
+ final IqParser parser = mXmppConnectionService.getIqParser();
+ final List<PreKeyBundle> preKeyBundleList = parser.preKeys(packet);
+ final PreKeyBundle bundle = parser.bundle(packet);
+ if (preKeyBundleList.isEmpty() || bundle == null) {
+ Log.d(Config.LOGTAG, "preKey IQ packet invalid: " + packet);
+ fetchStatusMap.put(address, FetchStatus.ERROR);
+ return;
+ }
+ Random random = new Random();
+ final PreKeyBundle preKey = preKeyBundleList.get(random.nextInt(preKeyBundleList.size()));
+ if (preKey == null) {
+ //should never happen
+ fetchStatusMap.put(address, FetchStatus.ERROR);
+ return;
+ }
- public boolean isContactAxolotlCapable(Contact contact) {
- AxolotlAddress address = new AxolotlAddress(contact.getJid().toBareJid().toString(), 0);
- return sessions.hasAny(address) || bundleCache.hasAny(address);
- }
+ final PreKeyBundle preKeyBundle = new PreKeyBundle(0, address.getDeviceId(),
+ preKey.getPreKeyId(), preKey.getPreKey(),
+ bundle.getSignedPreKeyId(), bundle.getSignedPreKey(),
+ bundle.getSignedPreKeySignature(), bundle.getIdentityKey());
+
+ axolotlStore.saveIdentity(address.getName(), bundle.getIdentityKey());
- public void initiateSynchronousSession(Contact contact) {
+ try {
+ SessionBuilder builder = new SessionBuilder(axolotlStore, address);
+ builder.process(preKeyBundle);
+ XmppAxolotlSession session = new XmppAxolotlSession(axolotlStore, address);
+ sessions.put(address, session);
+ fetchStatusMap.put(address, FetchStatus.SUCCESS);
+ } catch (UntrustedIdentityException|InvalidKeyException e) {
+ Log.d(Config.LOGTAG, "Error building session for " + address + ": "
+ + e.getClass().getName() + ", " + e.getMessage());
+ fetchStatusMap.put(address, FetchStatus.ERROR);
+ }
+ AxolotlAddress ownAddress = new AxolotlAddress(conversation.getAccount().getJid().toBareJid().toString(),0);
+ AxolotlAddress foreignAddress = new AxolotlAddress(conversation.getJid().toBareJid().toString(),0);
+ if (!fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING)
+ && !fetchStatusMap.getAll(foreignAddress).containsValue(FetchStatus.PENDING)) {
+ conversation.findUnsentMessagesWithEncryption(Message.ENCRYPTION_AXOLOTL,
+ new Conversation.OnMessageFound() {
+ @Override
+ public void onMessageFound(Message message) {
+ processSending(message);
+ }
+ });
+ }
+ }
+ });
+ } catch (InvalidJidException e) {
+ Log.e(Config.LOGTAG,"Got address with invalid jid: " + address.getName());
+ }
}
private void createSessionsIfNeeded(Contact contact) throws NoSessionsCreatedException {
diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
index 5b3bde6a..0bef8853 100644
--- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
@@ -10,6 +10,7 @@ import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.entities.Account;
@@ -131,23 +132,15 @@ public class IqGenerator extends AbstractGenerator {
return packet;
}
- public IqPacket retrieveBundleForDevice(final Jid to, final int deviceid) {
- final IqPacket packet = retrieve(AxolotlService.PEP_BUNDLE+":"+deviceid, null);
+ public IqPacket retrieveBundlesForDevice(final Jid to, final int deviceid) {
+ final IqPacket packet = retrieve(AxolotlService.PEP_BUNDLES+":"+deviceid, null);
if(to != null) {
packet.setTo(to);
}
return packet;
}
- public IqPacket retrievePreKeysForDevice(final Jid to, final int deviceId) {
- final IqPacket packet = retrieve(AxolotlService.PEP_PREKEYS+":"+deviceId, null);
- if(to != null) {
- packet.setTo(to);
- }
- return packet;
- }
-
- public IqPacket publishDeviceIds(final List<Integer> ids) {
+ public IqPacket publishDeviceIds(final Set<Integer> ids) {
final Element item = new Element("item");
final Element list = item.addChild("list", AxolotlService.PEP_PREFIX);
for(Integer id:ids) {
@@ -158,7 +151,8 @@ public class IqGenerator extends AbstractGenerator {
return publish(AxolotlService.PEP_DEVICE_LIST, item);
}
- public IqPacket publishBundle(final SignedPreKeyRecord signedPreKeyRecord, IdentityKey identityKey, final int deviceId) {
+ public IqPacket publishBundles(final SignedPreKeyRecord signedPreKeyRecord, final IdentityKey identityKey,
+ final List<PreKeyRecord> preKeyRecords, final int deviceId) {
final Element item = new Element("item");
final Element bundle = item.addChild("bundle", AxolotlService.PEP_PREFIX);
final Element signedPreKeyPublic = bundle.addChild("signedPreKeyPublic");
@@ -170,19 +164,14 @@ public class IqGenerator extends AbstractGenerator {
final Element identityKeyElement = bundle.addChild("identityKey");
identityKeyElement.setContent(Base64.encodeToString(identityKey.serialize(), Base64.DEFAULT));
- return publish(AxolotlService.PEP_BUNDLE+":"+deviceId, item);
- }
-
- public IqPacket publishPreKeys(final List<PreKeyRecord> prekeyList, final int deviceId) {
- final Element item = new Element("item");
- final Element prekeys = item.addChild("prekeys", AxolotlService.PEP_PREFIX);
- for(PreKeyRecord preKeyRecord:prekeyList) {
+ final Element prekeys = bundle.addChild("prekeys", AxolotlService.PEP_PREFIX);
+ for(PreKeyRecord preKeyRecord:preKeyRecords) {
final Element prekey = prekeys.addChild("preKeyPublic");
prekey.setAttribute("preKeyId", preKeyRecord.getId());
prekey.setContent(Base64.encodeToString(preKeyRecord.getKeyPair().getPublicKey().serialize(), Base64.DEFAULT));
}
- return publish(AxolotlService.PEP_PREKEYS+":"+deviceId, item);
+ return publish(AxolotlService.PEP_BUNDLES+":"+deviceId, item);
}
public IqPacket queryMessageArchiveManagement(final MessageArchiveService.Query mam) {
diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java
index df143a41..93551787 100644
--- a/src/main/java/eu/siacs/conversations/parser/IqParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java
@@ -12,8 +12,10 @@ import org.whispersystems.libaxolotl.state.PreKeyBundle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
@@ -94,8 +96,8 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
return items.findChild("item");
}
- public List<Integer> deviceIds(final Element item) {
- List<Integer> deviceIds = new ArrayList<>();
+ public Set<Integer> deviceIds(final Element item) {
+ Set<Integer> deviceIds = new HashSet<>();
if (item == null) {
return null;
}
@@ -165,14 +167,18 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
public Map<Integer, ECPublicKey> preKeyPublics(final IqPacket packet) {
Map<Integer, ECPublicKey> preKeyRecords = new HashMap<>();
- Element prekeysItem = getItem(packet);
- if (prekeysItem == null) {
- Log.d(Config.LOGTAG, "Couldn't find <item> in preKeyPublic IQ packet: " + packet);
+ Element item = getItem(packet);
+ if (item == null) {
+ Log.d(Config.LOGTAG, "Couldn't find <item> in bundle IQ packet: " + packet);
+ return null;
+ }
+ final Element bundleElement = item.findChild("bundle");
+ if(bundleElement == null) {
return null;
}
- final Element prekeysElement = prekeysItem.findChild("prekeys");
+ final Element prekeysElement = bundleElement.findChild("prekeys");
if(prekeysElement == null) {
- Log.d(Config.LOGTAG, "Couldn't find <prekeys> in preKeyPublic IQ packet: " + packet);
+ Log.d(Config.LOGTAG, "Couldn't find <prekeys> in bundle IQ packet: " + packet);
return null;
}
for(Element preKeyPublicElement : prekeysElement.getChildren()) {
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index 9a4cc276..f96e5d7e 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -275,8 +275,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
syncDirtyContacts(account);
account.getAxolotlService().publishOwnDeviceIdIfNeeded();
- account.getAxolotlService().publishBundleIfNeeded();
- account.getAxolotlService().publishPreKeysIfNeeded();
+ account.getAxolotlService().publishBundlesIfNeeded();
scheduleWakeUpCall(Config.PING_MAX_INTERVAL, account.getUuid().hashCode());
} else if (account.getStatus() == Account.State.OFFLINE) {