Merge branch 'master' into development
This commit is contained in:
commit
b0710cdf04
|
@ -1,5 +1,8 @@
|
||||||
###Changelog
|
###Changelog
|
||||||
|
|
||||||
|
####Version 1.6.1
|
||||||
|
* fixed crashes
|
||||||
|
|
||||||
####Version 1.6.0
|
####Version 1.6.0
|
||||||
* new multi-end-to-multi-end encryption method
|
* new multi-end-to-multi-end encryption method
|
||||||
* redesigned chat bubbles
|
* redesigned chat bubbles
|
||||||
|
|
|
@ -48,7 +48,7 @@ android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 21
|
targetSdkVersion 21
|
||||||
versionCode 84
|
versionCode 85
|
||||||
versionName "1.7.0-alpha"
|
versionName "1.7.0-alpha"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="android.permission.NFC" />
|
<uses-permission android:name="android.permission.NFC" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@drawable/ic_launcher"
|
||||||
|
|
|
@ -307,21 +307,25 @@ public class AxolotlService {
|
||||||
mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
|
mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
|
||||||
@Override
|
@Override
|
||||||
public void onIqPacketReceived(Account account, IqPacket packet) {
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||||
Element item = mXmppConnectionService.getIqParser().getItem(packet);
|
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
||||||
Set<Integer> deviceIds = mXmppConnectionService.getIqParser().deviceIds(item);
|
Element item = mXmppConnectionService.getIqParser().getItem(packet);
|
||||||
if (deviceIds == null) {
|
Set<Integer> deviceIds = mXmppConnectionService.getIqParser().deviceIds(item);
|
||||||
deviceIds = new HashSet<Integer>();
|
if (deviceIds == null) {
|
||||||
}
|
deviceIds = new HashSet<Integer>();
|
||||||
if (!deviceIds.contains(getOwnDeviceId())) {
|
}
|
||||||
deviceIds.add(getOwnDeviceId());
|
if (!deviceIds.contains(getOwnDeviceId())) {
|
||||||
IqPacket publish = mXmppConnectionService.getIqGenerator().publishDeviceIds(deviceIds);
|
deviceIds.add(getOwnDeviceId());
|
||||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Own device " + getOwnDeviceId() + " not in PEP devicelist. Publishing: " + publish);
|
IqPacket publish = mXmppConnectionService.getIqGenerator().publishDeviceIds(deviceIds);
|
||||||
mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
|
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Own device " + getOwnDeviceId() + " not in PEP devicelist. Publishing: " + publish);
|
||||||
@Override
|
mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
|
||||||
public void onIqPacketReceived(Account account, IqPacket packet) {
|
@Override
|
||||||
// TODO: implement this!
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||||
}
|
// TODO: implement this!
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG, getLogprefix(account) + "Error received while publishing device ID:" + packet.findChild("error"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -332,88 +336,92 @@ public class AxolotlService {
|
||||||
mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
|
mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
|
||||||
@Override
|
@Override
|
||||||
public void onIqPacketReceived(Account account, IqPacket packet) {
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||||
PreKeyBundle bundle = mXmppConnectionService.getIqParser().bundle(packet);
|
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
||||||
Map<Integer, ECPublicKey> keys = mXmppConnectionService.getIqParser().preKeyPublics(packet);
|
PreKeyBundle bundle = mXmppConnectionService.getIqParser().bundle(packet);
|
||||||
boolean flush = false;
|
Map<Integer, ECPublicKey> keys = mXmppConnectionService.getIqParser().preKeyPublics(packet);
|
||||||
if (bundle == null) {
|
boolean flush = false;
|
||||||
Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received invalid bundle:" + packet);
|
if (bundle == null) {
|
||||||
bundle = new PreKeyBundle(-1, -1, -1, null, -1, null, null, null);
|
Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received invalid bundle:" + packet);
|
||||||
flush = true;
|
bundle = new PreKeyBundle(-1, -1, -1, null, -1, null, null, null);
|
||||||
}
|
flush = true;
|
||||||
if (keys == null) {
|
}
|
||||||
Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received invalid prekeys:" + packet);
|
if (keys == null) {
|
||||||
}
|
Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received invalid prekeys:" + packet);
|
||||||
try {
|
|
||||||
boolean changed = false;
|
|
||||||
// Validate IdentityKey
|
|
||||||
IdentityKeyPair identityKeyPair = axolotlStore.getIdentityKeyPair();
|
|
||||||
if (flush || !identityKeyPair.getPublicKey().equals(bundle.getIdentityKey())) {
|
|
||||||
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding own IdentityKey " + identityKeyPair.getPublicKey() + " to PEP.");
|
|
||||||
changed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate signedPreKeyRecord + ID
|
|
||||||
SignedPreKeyRecord signedPreKeyRecord;
|
|
||||||
int numSignedPreKeys = axolotlStore.loadSignedPreKeys().size();
|
|
||||||
try {
|
try {
|
||||||
signedPreKeyRecord = axolotlStore.loadSignedPreKey(bundle.getSignedPreKeyId());
|
boolean changed = false;
|
||||||
if (flush
|
// Validate IdentityKey
|
||||||
|| !bundle.getSignedPreKey().equals(signedPreKeyRecord.getKeyPair().getPublicKey())
|
IdentityKeyPair identityKeyPair = axolotlStore.getIdentityKeyPair();
|
||||||
|| !Arrays.equals(bundle.getSignedPreKeySignature(), signedPreKeyRecord.getSignature())) {
|
if (flush || !identityKeyPair.getPublicKey().equals(bundle.getIdentityKey())) {
|
||||||
|
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding own IdentityKey " + identityKeyPair.getPublicKey() + " to PEP.");
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate signedPreKeyRecord + ID
|
||||||
|
SignedPreKeyRecord signedPreKeyRecord;
|
||||||
|
int numSignedPreKeys = axolotlStore.loadSignedPreKeys().size();
|
||||||
|
try {
|
||||||
|
signedPreKeyRecord = axolotlStore.loadSignedPreKey(bundle.getSignedPreKeyId());
|
||||||
|
if (flush
|
||||||
|
|| !bundle.getSignedPreKey().equals(signedPreKeyRecord.getKeyPair().getPublicKey())
|
||||||
|
|| !Arrays.equals(bundle.getSignedPreKeySignature(), signedPreKeyRecord.getSignature())) {
|
||||||
|
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding new signedPreKey with ID " + (numSignedPreKeys + 1) + " to PEP.");
|
||||||
|
signedPreKeyRecord = KeyHelper.generateSignedPreKey(identityKeyPair, numSignedPreKeys + 1);
|
||||||
|
axolotlStore.storeSignedPreKey(signedPreKeyRecord.getId(), signedPreKeyRecord);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
} catch (InvalidKeyIdException e) {
|
||||||
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding new signedPreKey with ID " + (numSignedPreKeys + 1) + " to PEP.");
|
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding new signedPreKey with ID " + (numSignedPreKeys + 1) + " to PEP.");
|
||||||
signedPreKeyRecord = KeyHelper.generateSignedPreKey(identityKeyPair, numSignedPreKeys + 1);
|
signedPreKeyRecord = KeyHelper.generateSignedPreKey(identityKeyPair, numSignedPreKeys + 1);
|
||||||
axolotlStore.storeSignedPreKey(signedPreKeyRecord.getId(), signedPreKeyRecord);
|
axolotlStore.storeSignedPreKey(signedPreKeyRecord.getId(), signedPreKeyRecord);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
} catch (InvalidKeyIdException e) {
|
|
||||||
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding new signedPreKey with ID " + (numSignedPreKeys + 1) + " to PEP.");
|
|
||||||
signedPreKeyRecord = KeyHelper.generateSignedPreKey(identityKeyPair, numSignedPreKeys + 1);
|
|
||||||
axolotlStore.storeSignedPreKey(signedPreKeyRecord.getId(), signedPreKeyRecord);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate PreKeys
|
// Validate PreKeys
|
||||||
Set<PreKeyRecord> preKeyRecords = new HashSet<>();
|
Set<PreKeyRecord> preKeyRecords = new HashSet<>();
|
||||||
if (keys != null) {
|
if (keys != null) {
|
||||||
for (Integer id : keys.keySet()) {
|
for (Integer id : keys.keySet()) {
|
||||||
try {
|
try {
|
||||||
PreKeyRecord preKeyRecord = axolotlStore.loadPreKey(id);
|
PreKeyRecord preKeyRecord = axolotlStore.loadPreKey(id);
|
||||||
if (preKeyRecord.getKeyPair().getPublicKey().equals(keys.get(id))) {
|
if (preKeyRecord.getKeyPair().getPublicKey().equals(keys.get(id))) {
|
||||||
preKeyRecords.add(preKeyRecord);
|
preKeyRecords.add(preKeyRecord);
|
||||||
|
}
|
||||||
|
} catch (InvalidKeyIdException ignored) {
|
||||||
}
|
}
|
||||||
} catch (InvalidKeyIdException ignored) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
int newKeys = NUM_KEYS_TO_PUBLISH - preKeyRecords.size();
|
||||||
int newKeys = NUM_KEYS_TO_PUBLISH - preKeyRecords.size();
|
if (newKeys > 0) {
|
||||||
if (newKeys > 0) {
|
List<PreKeyRecord> newRecords = KeyHelper.generatePreKeys(
|
||||||
List<PreKeyRecord> newRecords = KeyHelper.generatePreKeys(
|
axolotlStore.getCurrentPreKeyId() + 1, newKeys);
|
||||||
axolotlStore.getCurrentPreKeyId() + 1, newKeys);
|
preKeyRecords.addAll(newRecords);
|
||||||
preKeyRecords.addAll(newRecords);
|
for (PreKeyRecord record : newRecords) {
|
||||||
for (PreKeyRecord record : newRecords) {
|
axolotlStore.storePreKey(record.getId(), record);
|
||||||
axolotlStore.storePreKey(record.getId(), record);
|
|
||||||
}
|
|
||||||
changed = true;
|
|
||||||
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding " + newKeys + " new preKeys to PEP.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (changed) {
|
|
||||||
IqPacket publish = mXmppConnectionService.getIqGenerator().publishBundles(
|
|
||||||
signedPreKeyRecord, axolotlStore.getIdentityKeyPair().getPublicKey(),
|
|
||||||
preKeyRecords, getOwnDeviceId());
|
|
||||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + ": Bundle " + getOwnDeviceId() + " in PEP not current. Publishing: " + publish);
|
|
||||||
mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
|
|
||||||
@Override
|
|
||||||
public void onIqPacketReceived(Account account, IqPacket packet) {
|
|
||||||
// TODO: implement this!
|
|
||||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Published bundle, got: " + packet);
|
|
||||||
}
|
}
|
||||||
});
|
changed = true;
|
||||||
|
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding " + newKeys + " new preKeys to PEP.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
IqPacket publish = mXmppConnectionService.getIqGenerator().publishBundles(
|
||||||
|
signedPreKeyRecord, axolotlStore.getIdentityKeyPair().getPublicKey(),
|
||||||
|
preKeyRecords, getOwnDeviceId());
|
||||||
|
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + ": Bundle " + getOwnDeviceId() + " in PEP not current. Publishing: " + publish);
|
||||||
|
mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
|
||||||
|
@Override
|
||||||
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||||
|
// TODO: implement this!
|
||||||
|
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Published bundle, got: " + packet);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Failed to publish bundle " + getOwnDeviceId() + ", reason: " + e.getMessage());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} catch (InvalidKeyException e) {
|
} else {
|
||||||
Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Failed to publish bundle " + getOwnDeviceId() + ", reason: " + e.getMessage());
|
Log.d(Config.LOGTAG, getLogprefix(account) + "Error received while publishing Bundle:" + packet.findChild("error"));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -453,45 +461,52 @@ public class AxolotlService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onIqPacketReceived(Account account, IqPacket packet) {
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received preKey IQ packet, processing...");
|
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
||||||
final IqParser parser = mXmppConnectionService.getIqParser();
|
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received preKey IQ packet, processing...");
|
||||||
final List<PreKeyBundle> preKeyBundleList = parser.preKeys(packet);
|
final IqParser parser = mXmppConnectionService.getIqParser();
|
||||||
final PreKeyBundle bundle = parser.bundle(packet);
|
final List<PreKeyBundle> preKeyBundleList = parser.preKeys(packet);
|
||||||
if (preKeyBundleList.isEmpty() || bundle == null) {
|
final PreKeyBundle bundle = parser.bundle(packet);
|
||||||
Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "preKey IQ packet invalid: " + packet);
|
if (preKeyBundleList.isEmpty() || bundle == null) {
|
||||||
|
Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "preKey IQ packet invalid: " + packet);
|
||||||
|
fetchStatusMap.put(address, FetchStatus.ERROR);
|
||||||
|
finish();
|
||||||
|
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);
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
try {
|
||||||
|
SessionBuilder builder = new SessionBuilder(axolotlStore, address);
|
||||||
|
builder.process(preKeyBundle);
|
||||||
|
XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address, bundle.getIdentityKey().getFingerprint().replaceAll("\\s", ""));
|
||||||
|
sessions.put(address, session);
|
||||||
|
fetchStatusMap.put(address, FetchStatus.SUCCESS);
|
||||||
|
} catch (UntrustedIdentityException | InvalidKeyException e) {
|
||||||
|
Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Error building session for " + address + ": "
|
||||||
|
+ e.getClass().getName() + ", " + e.getMessage());
|
||||||
|
fetchStatusMap.put(address, FetchStatus.ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
finish();
|
||||||
|
} else {
|
||||||
fetchStatusMap.put(address, FetchStatus.ERROR);
|
fetchStatusMap.put(address, FetchStatus.ERROR);
|
||||||
|
Log.d(Config.LOGTAG, getLogprefix(account) + "Error received while building session:" + packet.findChild("error"));
|
||||||
finish();
|
finish();
|
||||||
return;
|
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);
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
|
|
||||||
try {
|
|
||||||
SessionBuilder builder = new SessionBuilder(axolotlStore, address);
|
|
||||||
builder.process(preKeyBundle);
|
|
||||||
XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address, bundle.getIdentityKey().getFingerprint().replaceAll("\\s", ""));
|
|
||||||
sessions.put(address, session);
|
|
||||||
fetchStatusMap.put(address, FetchStatus.SUCCESS);
|
|
||||||
} catch (UntrustedIdentityException | InvalidKeyException e) {
|
|
||||||
Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Error building session for " + address + ": "
|
|
||||||
+ e.getClass().getName() + ", " + e.getMessage());
|
|
||||||
fetchStatusMap.put(address, FetchStatus.ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
finish();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (InvalidJidException e) {
|
} catch (InvalidJidException e) {
|
||||||
|
|
|
@ -236,7 +236,9 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onIqPacketReceived(final Account account, final IqPacket packet) {
|
public void onIqPacketReceived(final Account account, final IqPacket packet) {
|
||||||
if (packet.hasChild("query", Xmlns.ROSTER) && packet.fromServer(account)) {
|
if (packet.getType() == IqPacket.TYPE.ERROR) {
|
||||||
|
return;
|
||||||
|
} else if (packet.hasChild("query", Xmlns.ROSTER) && packet.fromServer(account)) {
|
||||||
final Element query = packet.findChild("query");
|
final Element query = packet.findChild("query");
|
||||||
// If this is in response to a query for the whole roster:
|
// If this is in response to a query for the whole roster:
|
||||||
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
||||||
|
@ -306,15 +308,13 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
|
||||||
final IqPacket response = packet.generateResponse(IqPacket.TYPE.RESULT);
|
final IqPacket response = packet.generateResponse(IqPacket.TYPE.RESULT);
|
||||||
mXmppConnectionService.sendIqPacket(account, response, null);
|
mXmppConnectionService.sendIqPacket(account, response, null);
|
||||||
} else {
|
} else {
|
||||||
if ((packet.getType() == IqPacket.TYPE.GET)
|
if (packet.getType() == IqPacket.TYPE.GET || packet.getType() == IqPacket.TYPE.SET) {
|
||||||
|| (packet.getType() == IqPacket.TYPE.SET)) {
|
|
||||||
final IqPacket response = packet.generateResponse(IqPacket.TYPE.ERROR);
|
final IqPacket response = packet.generateResponse(IqPacket.TYPE.ERROR);
|
||||||
final Element error = response.addChild("error");
|
final Element error = response.addChild("error");
|
||||||
error.setAttribute("type", "cancel");
|
error.setAttribute("type", "cancel");
|
||||||
error.addChild("feature-not-implemented",
|
error.addChild("feature-not-implemented","urn:ietf:params:xml:ns:xmpp-stanzas");
|
||||||
"urn:ietf:params:xml:ns:xmpp-stanzas");
|
|
||||||
account.getXmppConnection().sendIqPacket(response, null);
|
account.getXmppConnection().sendIqPacket(response, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -867,28 +867,31 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onIqPacketReceived(final Account account, final IqPacket packet) {
|
public void onIqPacketReceived(final Account account, final IqPacket packet) {
|
||||||
final Element query = packet.query();
|
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
||||||
final List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
|
final Element query = packet.query();
|
||||||
final Element storage = query.findChild("storage",
|
final List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
|
||||||
"storage:bookmarks");
|
final Element storage = query.findChild("storage", "storage:bookmarks");
|
||||||
if (storage != null) {
|
if (storage != null) {
|
||||||
for (final Element item : storage.getChildren()) {
|
for (final Element item : storage.getChildren()) {
|
||||||
if (item.getName().equals("conference")) {
|
if (item.getName().equals("conference")) {
|
||||||
final Bookmark bookmark = Bookmark.parse(item, account);
|
final Bookmark bookmark = Bookmark.parse(item, account);
|
||||||
bookmarks.add(bookmark);
|
bookmarks.add(bookmark);
|
||||||
Conversation conversation = find(bookmark);
|
Conversation conversation = find(bookmark);
|
||||||
if (conversation != null) {
|
if (conversation != null) {
|
||||||
conversation.setBookmark(bookmark);
|
conversation.setBookmark(bookmark);
|
||||||
} else if (bookmark.autojoin() && bookmark.getJid() != null) {
|
} else if (bookmark.autojoin() && bookmark.getJid() != null) {
|
||||||
conversation = findOrCreateConversation(
|
conversation = findOrCreateConversation(
|
||||||
account, bookmark.getJid(), true);
|
account, bookmark.getJid(), true);
|
||||||
conversation.setBookmark(bookmark);
|
conversation.setBookmark(bookmark);
|
||||||
joinMuc(conversation);
|
joinMuc(conversation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
account.setBookmarks(bookmarks);
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not fetch bookmarks");
|
||||||
}
|
}
|
||||||
account.setBookmarks(bookmarks);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
sendIqPacket(account, iqPacket, callback);
|
sendIqPacket(account, iqPacket, callback);
|
||||||
|
@ -1952,10 +1955,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
final IqPacket packet = XmppConnectionService.this.mIqGenerator
|
final IqPacket packet = XmppConnectionService.this.mIqGenerator
|
||||||
.publishAvatarMetadata(avatar);
|
.publishAvatarMetadata(avatar);
|
||||||
sendIqPacket(account, packet, new OnIqPacketReceived() {
|
sendIqPacket(account, packet, new OnIqPacketReceived() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onIqPacketReceived(Account account,
|
public void onIqPacketReceived(Account account, IqPacket result) {
|
||||||
IqPacket result) {
|
|
||||||
if (result.getType() == IqPacket.TYPE.RESULT) {
|
if (result.getType() == IqPacket.TYPE.RESULT) {
|
||||||
if (account.setAvatar(avatar.getFilename())) {
|
if (account.setAvatar(avatar.getFilename())) {
|
||||||
getAvatarService().clear(account);
|
getAvatarService().clear(account);
|
||||||
|
|
|
@ -69,10 +69,9 @@ public class Element {
|
||||||
|
|
||||||
public Element findChild(String name, String xmlns) {
|
public Element findChild(String name, String xmlns) {
|
||||||
for (Element child : this.children) {
|
for (Element child : this.children) {
|
||||||
if (child.getName().equals(name)
|
if (name.equals(child.getName()) && xmlns.equals(child.getAttribute("xmlns"))) {
|
||||||
&& (child.getAttribute("xmlns").equals(xmlns))) {
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,6 @@ import java.util.Hashtable;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import javax.net.ssl.HostnameVerifier;
|
import javax.net.ssl.HostnameVerifier;
|
||||||
|
@ -102,7 +101,7 @@ public class XmppConnection implements Runnable {
|
||||||
private long lastConnect = 0;
|
private long lastConnect = 0;
|
||||||
private long lastSessionStarted = 0;
|
private long lastSessionStarted = 0;
|
||||||
private int attempt = 0;
|
private int attempt = 0;
|
||||||
private final Map<String, Pair<IqPacket, OnIqPacketReceived>> packetCallbacks = new Hashtable<>();
|
private final Hashtable<String, Pair<IqPacket, OnIqPacketReceived>> packetCallbacks = new Hashtable<>();
|
||||||
private OnPresencePacketReceived presenceListener = null;
|
private OnPresencePacketReceived presenceListener = null;
|
||||||
private OnJinglePacketReceived jingleListener = null;
|
private OnJinglePacketReceived jingleListener = null;
|
||||||
private OnIqPacketReceived unregisteredIqListener = null;
|
private OnIqPacketReceived unregisteredIqListener = null;
|
||||||
|
@ -649,8 +648,8 @@ public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onIqPacketReceived(final Account account, final IqPacket packet) {
|
public void onIqPacketReceived(final Account account, final IqPacket packet) {
|
||||||
final Element instructions = packet.query().findChild("instructions");
|
if (packet.getType() == IqPacket.TYPE.RESULT
|
||||||
if (packet.query().hasChild("username")
|
&& packet.query().hasChild("username")
|
||||||
&& (packet.query().hasChild("password"))) {
|
&& (packet.query().hasChild("password"))) {
|
||||||
final IqPacket register = new IqPacket(IqPacket.TYPE.SET);
|
final IqPacket register = new IqPacket(IqPacket.TYPE.SET);
|
||||||
final Element username = new Element("username").setContent(account.getUsername());
|
final Element username = new Element("username").setContent(account.getUsername());
|
||||||
|
@ -677,6 +676,7 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
final Element instructions = packet.query().findChild("instructions");
|
||||||
changeStatus(Account.State.REGISTRATION_FAILED);
|
changeStatus(Account.State.REGISTRATION_FAILED);
|
||||||
disconnect(true);
|
disconnect(true);
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid()
|
Log.d(Config.LOGTAG, account.getJid().toBareJid()
|
||||||
|
@ -716,9 +716,11 @@ public class XmppConnection implements Runnable {
|
||||||
sendPostBindInitialization();
|
sendPostBindInitialization();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Log.d(Config.LOGTAG,account.getJid()+": disconnecting because of bind failure");
|
||||||
disconnect(true);
|
disconnect(true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Log.d(Config.LOGTAG,account.getJid()+": disconnecting because of bind failure");
|
||||||
disconnect(true);
|
disconnect(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -726,16 +728,24 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearIqCallbacks() {
|
private void clearIqCallbacks() {
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": clearing iq iq callbacks");
|
|
||||||
final IqPacket failurePacket = new IqPacket(IqPacket.TYPE.ERROR);
|
final IqPacket failurePacket = new IqPacket(IqPacket.TYPE.ERROR);
|
||||||
|
final ArrayList<OnIqPacketReceived> callbacks = new ArrayList<>();
|
||||||
synchronized (this.packetCallbacks) {
|
synchronized (this.packetCallbacks) {
|
||||||
Iterator<Entry<String, Pair<IqPacket, OnIqPacketReceived>>> iterator = this.packetCallbacks.entrySet().iterator();
|
if (this.packetCallbacks.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": clearing "+this.packetCallbacks.size()+" iq callbacks");
|
||||||
|
final Iterator<Pair<IqPacket, OnIqPacketReceived>> iterator = this.packetCallbacks.values().iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
Entry<String, Pair<IqPacket, OnIqPacketReceived>> entry = iterator.next();
|
Pair<IqPacket, OnIqPacketReceived> entry = iterator.next();
|
||||||
entry.getValue().second.onIqPacketReceived(account, failurePacket);
|
callbacks.add(entry.second);
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for(OnIqPacketReceived callback : callbacks) {
|
||||||
|
callback.onIqPacketReceived(account,failurePacket);
|
||||||
|
}
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": done clearing iq callbacks. "+this.packetCallbacks.size()+" left");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendStartSession() {
|
private void sendStartSession() {
|
||||||
|
@ -747,6 +757,7 @@ public class XmppConnection implements Runnable {
|
||||||
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
||||||
sendPostBindInitialization();
|
sendPostBindInitialization();
|
||||||
} else {
|
} else {
|
||||||
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not init sessions");
|
||||||
disconnect(true);
|
disconnect(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -792,26 +803,29 @@ public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onIqPacketReceived(final Account account, final IqPacket packet) {
|
public void onIqPacketReceived(final Account account, final IqPacket packet) {
|
||||||
final List<Element> elements = packet.query().getChildren();
|
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
||||||
final Info info = new Info();
|
final List<Element> elements = packet.query().getChildren();
|
||||||
for (final Element element : elements) {
|
final Info info = new Info();
|
||||||
if (element.getName().equals("identity")) {
|
for (final Element element : elements) {
|
||||||
String type = element.getAttribute("type");
|
if (element.getName().equals("identity")) {
|
||||||
String category = element.getAttribute("category");
|
String type = element.getAttribute("type");
|
||||||
if (type != null && category != null) {
|
String category = element.getAttribute("category");
|
||||||
info.identities.add(new Pair<>(category,type));
|
if (type != null && category != null) {
|
||||||
|
info.identities.add(new Pair<>(category, type));
|
||||||
|
}
|
||||||
|
} else if (element.getName().equals("feature")) {
|
||||||
|
info.features.add(element.getAttribute("var"));
|
||||||
}
|
}
|
||||||
} else if (element.getName().equals("feature")) {
|
|
||||||
info.features.add(element.getAttribute("var"));
|
|
||||||
}
|
}
|
||||||
}
|
disco.put(jid, info);
|
||||||
disco.put(jid, info);
|
if (account.getServer().equals(jid)) {
|
||||||
|
enableAdvancedStreamFeatures();
|
||||||
if (account.getServer().equals(jid)) {
|
for (final OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) {
|
||||||
enableAdvancedStreamFeatures();
|
listener.onAdvancedStreamFeaturesAvailable(account);
|
||||||
for (final OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) {
|
}
|
||||||
listener.onAdvancedStreamFeaturesAvailable(account);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not query disco info for "+jid.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -836,14 +850,18 @@ public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onIqPacketReceived(final Account account, final IqPacket packet) {
|
public void onIqPacketReceived(final Account account, final IqPacket packet) {
|
||||||
final List<Element> elements = packet.query().getChildren();
|
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
||||||
for (final Element element : elements) {
|
final List<Element> elements = packet.query().getChildren();
|
||||||
if (element.getName().equals("item")) {
|
for (final Element element : elements) {
|
||||||
final Jid jid = element.getAttributeAsJid("jid");
|
if (element.getName().equals("item")) {
|
||||||
if (jid != null && !jid.equals(account.getServer())) {
|
final Jid jid = element.getAttributeAsJid("jid");
|
||||||
sendServiceDiscoveryInfo(jid);
|
if (jid != null && !jid.equals(account.getServer())) {
|
||||||
|
sendServiceDiscoveryInfo(jid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not query disco items of "+server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -877,6 +895,8 @@ public class XmppConnection implements Runnable {
|
||||||
Log.d(Config.LOGTAG,
|
Log.d(Config.LOGTAG,
|
||||||
account.getJid().toBareJid() + ": switching resource due to conflict ("
|
account.getJid().toBareJid() + ": switching resource due to conflict ("
|
||||||
+ account.getResource() + ")");
|
+ account.getResource() + ")");
|
||||||
|
} else if (streamError != null) {
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": stream error "+streamError.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue