Merge branch 'master' into development

Daniel Gultsch created

Change summary

CHANGELOG.md                                                             |   3 
build.gradle                                                             |   2 
src/main/AndroidManifest.xml                                             |   2 
src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java  | 247 
src/main/java/eu/siacs/conversations/parser/IqParser.java                |  12 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java |  43 
src/main/java/eu/siacs/conversations/xml/Element.java                    |   5 
src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java            |  82 
8 files changed, 218 insertions(+), 178 deletions(-)

Detailed changes

CHANGELOG.md 🔗

@@ -1,5 +1,8 @@
 ###Changelog
 
+####Version 1.6.1
+* fixed crashes
+
 ####Version 1.6.0
 * new multi-end-to-multi-end encryption method
 * redesigned chat bubbles

build.gradle 🔗

@@ -48,7 +48,7 @@ android {
 	defaultConfig {
 		minSdkVersion 14
 		targetSdkVersion 21
-		versionCode 84
+		versionCode 85
 		versionName "1.7.0-alpha"
 	}
 

src/main/AndroidManifest.xml 🔗

@@ -15,6 +15,8 @@
     <uses-permission android:name="android.permission.VIBRATE" />
     <uses-permission android:name="android.permission.NFC" />
 
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove" />
+
     <application
         android:allowBackup="true"
         android:icon="@drawable/ic_launcher"

src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java 🔗

@@ -307,21 +307,25 @@ public class AxolotlService {
 		mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
 			@Override
 			public void onIqPacketReceived(Account account, IqPacket packet) {
-				Element item = mXmppConnectionService.getIqParser().getItem(packet);
-				Set<Integer> deviceIds = mXmppConnectionService.getIqParser().deviceIds(item);
-				if (deviceIds == null) {
-					deviceIds = new HashSet<Integer>();
-				}
-				if (!deviceIds.contains(getOwnDeviceId())) {
-					deviceIds.add(getOwnDeviceId());
-					IqPacket publish = mXmppConnectionService.getIqGenerator().publishDeviceIds(deviceIds);
-					Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Own device " + getOwnDeviceId() + " not in PEP devicelist. Publishing: " + publish);
-					mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
-						@Override
-						public void onIqPacketReceived(Account account, IqPacket packet) {
-							// TODO: implement this!
-						}
-					});
+				if (packet.getType() == IqPacket.TYPE.RESULT) {
+					Element item = mXmppConnectionService.getIqParser().getItem(packet);
+					Set<Integer> deviceIds = mXmppConnectionService.getIqParser().deviceIds(item);
+					if (deviceIds == null) {
+						deviceIds = new HashSet<Integer>();
+					}
+					if (!deviceIds.contains(getOwnDeviceId())) {
+						deviceIds.add(getOwnDeviceId());
+						IqPacket publish = mXmppConnectionService.getIqGenerator().publishDeviceIds(deviceIds);
+						Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Own device " + getOwnDeviceId() + " not in PEP devicelist. Publishing: " + publish);
+						mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
+							@Override
+							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() {
 			@Override
 			public void onIqPacketReceived(Account account, IqPacket packet) {
-				PreKeyBundle bundle = mXmppConnectionService.getIqParser().bundle(packet);
-				Map<Integer, ECPublicKey> keys = mXmppConnectionService.getIqParser().preKeyPublics(packet);
-				boolean flush = false;
-				if (bundle == null) {
-					Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received invalid bundle:" + packet);
-					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);
-				}
-				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;
+				if (packet.getType() == IqPacket.TYPE.RESULT) {
+					PreKeyBundle bundle = mXmppConnectionService.getIqParser().bundle(packet);
+					Map<Integer, ECPublicKey> keys = mXmppConnectionService.getIqParser().preKeyPublics(packet);
+					boolean flush = false;
+					if (bundle == null) {
+						Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received invalid bundle:" + packet);
+						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);
 					}
-
-					// 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())) {
+						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 {
+							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.");
 							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.");
-						signedPreKeyRecord = KeyHelper.generateSignedPreKey(identityKeyPair, numSignedPreKeys + 1);
-						axolotlStore.storeSignedPreKey(signedPreKeyRecord.getId(), signedPreKeyRecord);
-						changed = true;
-					}
 
-					// Validate PreKeys
-					Set<PreKeyRecord> preKeyRecords = new HashSet<>();
-					if (keys != null) {
-						for (Integer id : keys.keySet()) {
-							try {
-								PreKeyRecord preKeyRecord = axolotlStore.loadPreKey(id);
-								if (preKeyRecord.getKeyPair().getPublicKey().equals(keys.get(id))) {
-									preKeyRecords.add(preKeyRecord);
+						// Validate PreKeys
+						Set<PreKeyRecord> preKeyRecords = new HashSet<>();
+						if (keys != null) {
+							for (Integer id : keys.keySet()) {
+								try {
+									PreKeyRecord preKeyRecord = axolotlStore.loadPreKey(id);
+									if (preKeyRecord.getKeyPair().getPublicKey().equals(keys.get(id))) {
+										preKeyRecords.add(preKeyRecord);
+									}
+								} catch (InvalidKeyIdException ignored) {
 								}
-							} catch (InvalidKeyIdException ignored) {
 							}
 						}
-					}
-					int newKeys = NUM_KEYS_TO_PUBLISH - preKeyRecords.size();
-					if (newKeys > 0) {
-						List<PreKeyRecord> newRecords = KeyHelper.generatePreKeys(
-								axolotlStore.getCurrentPreKeyId() + 1, newKeys);
-						preKeyRecords.addAll(newRecords);
-						for (PreKeyRecord record : newRecords) {
-							axolotlStore.storePreKey(record.getId(), record);
+						int newKeys = NUM_KEYS_TO_PUBLISH - preKeyRecords.size();
+						if (newKeys > 0) {
+							List<PreKeyRecord> newRecords = KeyHelper.generatePreKeys(
+									axolotlStore.getCurrentPreKeyId() + 1, newKeys);
+							preKeyRecords.addAll(newRecords);
+							for (PreKeyRecord record : newRecords) {
+								axolotlStore.storePreKey(record.getId(), record);
+							}
+							changed = true;
+							Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding " + newKeys + " new preKeys to PEP.");
 						}
-						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);
-							}
-						});
+						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) {
-					Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Failed to publish bundle " + getOwnDeviceId() + ", reason: " + e.getMessage());
-					return;
+				} else {
+					Log.d(Config.LOGTAG, getLogprefix(account) + "Error received while publishing Bundle:" + packet.findChild("error"));
 				}
 			}
 		});
@@ -453,45 +461,52 @@ public class AxolotlService {
 
 				@Override
 				public void onIqPacketReceived(Account account, IqPacket packet) {
-					Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "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.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "preKey IQ packet invalid: " + packet);
-						fetchStatusMap.put(address, FetchStatus.ERROR);
+					if (packet.getType() == IqPacket.TYPE.RESULT) {
+						Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "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.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();
-						return;
-					}
-					Random random = new Random();
-					final PreKeyBundle preKey = preKeyBundleList.get(random.nextInt(preKeyBundleList.size()));
-					if (preKey == null) {
-						//should never happen
+					} else {
 						fetchStatusMap.put(address, FetchStatus.ERROR);
+						Log.d(Config.LOGTAG, getLogprefix(account) + "Error received while building session:" + packet.findChild("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) {

src/main/java/eu/siacs/conversations/parser/IqParser.java 🔗

@@ -236,7 +236,9 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
 
 	@Override
 	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");
 			// If this is in response to a query for the whole roster:
 			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);
 			mXmppConnectionService.sendIqPacket(account, response, null);
 		} else {
-			if ((packet.getType() == IqPacket.TYPE.GET)
-					|| (packet.getType() == IqPacket.TYPE.SET)) {
+			if (packet.getType() == IqPacket.TYPE.GET || packet.getType() == IqPacket.TYPE.SET) {
 				final IqPacket response = packet.generateResponse(IqPacket.TYPE.ERROR);
 				final Element error = response.addChild("error");
 				error.setAttribute("type", "cancel");
-				error.addChild("feature-not-implemented",
-						"urn:ietf:params:xml:ns:xmpp-stanzas");
+				error.addChild("feature-not-implemented","urn:ietf:params:xml:ns:xmpp-stanzas");
 				account.getXmppConnection().sendIqPacket(response, null);
-					}
+			}
 		}
 	}
 

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -867,28 +867,31 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 
 			@Override
 			public void onIqPacketReceived(final Account account, final IqPacket packet) {
-				final Element query = packet.query();
-				final List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
-				final Element storage = query.findChild("storage",
-						"storage:bookmarks");
-				if (storage != null) {
-					for (final Element item : storage.getChildren()) {
-						if (item.getName().equals("conference")) {
-							final Bookmark bookmark = Bookmark.parse(item, account);
-							bookmarks.add(bookmark);
-							Conversation conversation = find(bookmark);
-							if (conversation != null) {
-								conversation.setBookmark(bookmark);
-							} else if (bookmark.autojoin() && bookmark.getJid() != null) {
-								conversation = findOrCreateConversation(
-										account, bookmark.getJid(), true);
-								conversation.setBookmark(bookmark);
-								joinMuc(conversation);
+				if (packet.getType() == IqPacket.TYPE.RESULT) {
+					final Element query = packet.query();
+					final List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
+					final Element storage = query.findChild("storage", "storage:bookmarks");
+					if (storage != null) {
+						for (final Element item : storage.getChildren()) {
+							if (item.getName().equals("conference")) {
+								final Bookmark bookmark = Bookmark.parse(item, account);
+								bookmarks.add(bookmark);
+								Conversation conversation = find(bookmark);
+								if (conversation != null) {
+									conversation.setBookmark(bookmark);
+								} else if (bookmark.autojoin() && bookmark.getJid() != null) {
+									conversation = findOrCreateConversation(
+											account, bookmark.getJid(), true);
+									conversation.setBookmark(bookmark);
+									joinMuc(conversation);
+								}
 							}
 						}
 					}
+					account.setBookmarks(bookmarks);
+				} else {
+					Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not fetch bookmarks");
 				}
-				account.setBookmarks(bookmarks);
 			}
 		};
 		sendIqPacket(account, iqPacket, callback);
@@ -1952,10 +1955,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 						final IqPacket packet = XmppConnectionService.this.mIqGenerator
 								.publishAvatarMetadata(avatar);
 						sendIqPacket(account, packet, new OnIqPacketReceived() {
-
 							@Override
-							public void onIqPacketReceived(Account account,
-														   IqPacket result) {
+							public void onIqPacketReceived(Account account, IqPacket result) {
 								if (result.getType() == IqPacket.TYPE.RESULT) {
 									if (account.setAvatar(avatar.getFilename())) {
 										getAvatarService().clear(account);

src/main/java/eu/siacs/conversations/xml/Element.java 🔗

@@ -69,10 +69,9 @@ public class Element {
 
 	public Element findChild(String name, String xmlns) {
 		for (Element child : this.children) {
-			if (child.getName().equals(name)
-					&& (child.getAttribute("xmlns").equals(xmlns))) {
+			if (name.equals(child.getName()) && xmlns.equals(child.getAttribute("xmlns"))) {
 				return child;
-					}
+			}
 		}
 		return null;
 	}

src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java 🔗

@@ -34,7 +34,6 @@ import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
 import java.util.Map.Entry;
 
 import javax.net.ssl.HostnameVerifier;
@@ -102,7 +101,7 @@ public class XmppConnection implements Runnable {
 	private long lastConnect = 0;
 	private long lastSessionStarted = 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 OnJinglePacketReceived jingleListener = null;
 	private OnIqPacketReceived unregisteredIqListener = null;
@@ -649,8 +648,8 @@ public class XmppConnection implements Runnable {
 
 			@Override
 			public void onIqPacketReceived(final Account account, final IqPacket packet) {
-				final Element instructions = packet.query().findChild("instructions");
-				if (packet.query().hasChild("username")
+				if (packet.getType() == IqPacket.TYPE.RESULT
+						&& packet.query().hasChild("username")
 						&& (packet.query().hasChild("password"))) {
 					final IqPacket register = new IqPacket(IqPacket.TYPE.SET);
 					final Element username = new Element("username").setContent(account.getUsername());
@@ -677,6 +676,7 @@ public class XmppConnection implements Runnable {
 						}
 					});
 				} else {
+					final Element instructions = packet.query().findChild("instructions");
 					changeStatus(Account.State.REGISTRATION_FAILED);
 					disconnect(true);
 					Log.d(Config.LOGTAG, account.getJid().toBareJid()
@@ -716,9 +716,11 @@ public class XmppConnection implements Runnable {
 							sendPostBindInitialization();
 						}
 					} else {
+						Log.d(Config.LOGTAG,account.getJid()+": disconnecting because of bind failure");
 						disconnect(true);
 					}
 				} else {
+					Log.d(Config.LOGTAG,account.getJid()+": disconnecting because of bind failure");
 					disconnect(true);
 				}
 			}
@@ -726,16 +728,24 @@ public class XmppConnection implements Runnable {
 	}
 
 	private void clearIqCallbacks() {
-		Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": clearing iq iq callbacks");
 		final IqPacket failurePacket = new IqPacket(IqPacket.TYPE.ERROR);
+		final ArrayList<OnIqPacketReceived> callbacks = new ArrayList<>();
 		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()) {
-				Entry<String, Pair<IqPacket, OnIqPacketReceived>> entry = iterator.next();
-				entry.getValue().second.onIqPacketReceived(account, failurePacket);
+				Pair<IqPacket, OnIqPacketReceived> entry = iterator.next();
+				callbacks.add(entry.second);
 				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() {
@@ -747,6 +757,7 @@ public class XmppConnection implements Runnable {
 				if (packet.getType() == IqPacket.TYPE.RESULT) {
 					sendPostBindInitialization();
 				} else {
+					Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not init sessions");
 					disconnect(true);
 				}
 			}
@@ -792,26 +803,29 @@ public class XmppConnection implements Runnable {
 
 				@Override
 				public void onIqPacketReceived(final Account account, final IqPacket packet) {
-					final List<Element> elements = packet.query().getChildren();
-					final Info info = new Info();
-					for (final Element element : elements) {
-						if (element.getName().equals("identity")) {
-							String type = element.getAttribute("type");
-							String category = element.getAttribute("category");
-							if (type != null && category != null) {
-								info.identities.add(new Pair<>(category,type));
+					if (packet.getType() == IqPacket.TYPE.RESULT) {
+						final List<Element> elements = packet.query().getChildren();
+						final Info info = new Info();
+						for (final Element element : elements) {
+							if (element.getName().equals("identity")) {
+								String type = element.getAttribute("type");
+								String category = element.getAttribute("category");
+								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);
-
-					if (account.getServer().equals(jid)) {
-						enableAdvancedStreamFeatures();
-						for (final OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) {
-							listener.onAdvancedStreamFeaturesAvailable(account);
+						disco.put(jid, info);
+						if (account.getServer().equals(jid)) {
+							enableAdvancedStreamFeatures();
+							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
 			public void onIqPacketReceived(final Account account, final IqPacket packet) {
-				final List<Element> elements = packet.query().getChildren();
-				for (final Element element : elements) {
-					if (element.getName().equals("item")) {
-						final Jid jid = element.getAttributeAsJid("jid");
-						if (jid != null && !jid.equals(account.getServer())) {
-							sendServiceDiscoveryInfo(jid);
+				if (packet.getType() == IqPacket.TYPE.RESULT) {
+					final List<Element> elements = packet.query().getChildren();
+					for (final Element element : elements) {
+						if (element.getName().equals("item")) {
+							final Jid jid = element.getAttributeAsJid("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,
 					account.getJid().toBareJid() + ": switching resource due to conflict ("
 					+ account.getResource() + ")");
+		} else if (streamError != null) {
+			Log.d(Config.LOGTAG,account.getJid().toBareJid()+": stream error "+streamError.toString());
 		}
 	}