return contact and account.getServer() as String

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/entities/Account.java                     |  10 
src/main/java/eu/siacs/conversations/entities/Bookmark.java                    |   5 
src/main/java/eu/siacs/conversations/entities/Contact.java                     |   4 
src/main/java/eu/siacs/conversations/entities/Conversation.java                |   4 
src/main/java/eu/siacs/conversations/generator/IqGenerator.java                |   4 
src/main/java/eu/siacs/conversations/services/AvatarService.java               |   2 
src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java |   2 
src/main/java/eu/siacs/conversations/services/NotificationService.java         |   4 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java       |  23 
src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java                 |   3 
src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java             |   3 
src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java                    |   7 
src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java         |   5 
src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java       |  18 
src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java         |   3 
src/main/java/eu/siacs/conversations/utils/GeoHelper.java                      |   2 
src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java                  | 240 
17 files changed, 170 insertions(+), 169 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/entities/Account.java 🔗

@@ -228,7 +228,7 @@ public class Account extends AbstractEntity {
 	protected Jid jid;
 	protected String password;
 	protected int options = 0;
-	protected String rosterVersion;
+	private String rosterVersion;
 	protected State status = State.OFFLINE;
 	protected final JSONObject keys;
 	protected String resource;
@@ -336,8 +336,8 @@ public class Account extends AbstractEntity {
 		return next != null && !next.equals(previousFull);
 	}
 
-	public Jid getServer() {
-		return Jid.ofDomain(jid.getDomain());
+	public String getServer() {
+		return jid.getDomain();
 	}
 
 	public String getPassword() {
@@ -357,8 +357,8 @@ public class Account extends AbstractEntity {
 	}
 
 	public boolean isOnion() {
-		final Jid server = getServer();
-		return server != null && server.toString().toLowerCase().endsWith(".onion");
+		final String server = getServer();
+		return server != null && server.endsWith(".onion");
 	}
 
 	public void setPort(int port) {

src/main/java/eu/siacs/conversations/entities/Bookmark.java 🔗

@@ -1,6 +1,7 @@
 package eu.siacs.conversations.entities;
 
 import android.content.Context;
+import android.support.annotation.NonNull;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -46,7 +47,7 @@ public class Bookmark extends Element implements ListItem {
 	}
 
 	@Override
-	public int compareTo(final ListItem another) {
+	public int compareTo(final @NonNull ListItem another) {
 		return this.getDisplayName().compareToIgnoreCase(
 				another.getDisplayName());
 	}
@@ -55,7 +56,7 @@ public class Bookmark extends Element implements ListItem {
 	public String getDisplayName() {
 		final Conversation c = getConversation();
 		if (c != null) {
-			return c.getName();
+			return c.getName().toString();
 		} else if (getBookmarkName() != null
 				&& !getBookmarkName().trim().isEmpty()) {
 			return getBookmarkName().trim();

src/main/java/eu/siacs/conversations/entities/Contact.java 🔗

@@ -394,8 +394,8 @@ public class Contact implements ListItem, Blockable {
 				another.getDisplayName());
 	}
 
-	public Jid getServer() {
-		return Jid.ofDomain(getJid().getDomain());
+	public String getServer() {
+		return getJid().getDomain();
 	}
 
 	public boolean setAvatar(Avatar avatar) {

src/main/java/eu/siacs/conversations/entities/Conversation.java 🔗

@@ -465,7 +465,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
 		}
 	}
 
-	public String getName() {
+	public CharSequence getName() {
 		if (getMode() == MODE_MULTI) {
 			final String subject = getMucOptions().getSubject();
 			Bookmark bookmark = getBookmark();
@@ -483,7 +483,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
 				}
 			}
 		} else if (isWithStranger()) {
-			return contactJid.asBareJid().toString();
+			return contactJid;
 		} else {
 			return this.getContact().getDisplayName();
 		}

src/main/java/eu/siacs/conversations/generator/IqGenerator.java 🔗

@@ -301,7 +301,7 @@ public class IqGenerator extends AbstractGenerator {
 
 	public IqPacket generateSetPassword(final Account account, final String newPassword) {
 		final IqPacket packet = new IqPacket(IqPacket.TYPE.SET);
-		packet.setTo(account.getServer());
+		packet.setTo(Jid.of(account.getServer()));
 		final Element query = packet.addChild("query", Namespace.REGISTER);
 		final Jid jid = account.getJid();
 		query.addChild("username").setContent(jid.getLocal());
@@ -368,7 +368,7 @@ public class IqGenerator extends AbstractGenerator {
 	public IqPacket generateCreateAccountWithCaptcha(Account account, String id, Data data) {
 		final IqPacket register = new IqPacket(IqPacket.TYPE.SET);
 		register.setFrom(account.getJid().asBareJid());
-		register.setTo(account.getServer());
+		register.setTo(Jid.of(account.getServer()));
 		register.setId(id);
 		Element query = register.query("jabber:iq:register");
 		if (data != null) {

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

@@ -216,7 +216,7 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
 		final List<MucOptions.User> users = mucOptions.getUsersRelevantForNameAndAvatar();
 		if (users.size() == 0) {
 			Conversation c = mucOptions.getConversation();
-			bitmap = getImpl(c.getName(),c.getJid().asBareJid().toString(),size);
+			bitmap = getImpl(c.getName().toString(),c.getJid().asBareJid().toString(),size);
 		} else {
 			bitmap = getImpl(users,size);
 		}

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

@@ -46,7 +46,7 @@ public class ContactChooserTargetService extends ChooserTargetService implements
 			final int pixel = (int) (48 * getResources().getDisplayMetrics().density);
 			for(int i = 0; i < Math.min(conversations.size(),MAX_TARGETS); ++i) {
 				final Conversation conversation = conversations.get(i);
-				final String name = conversation.getName();
+				final String name = conversation.getName().toString();
 				final Icon icon = Icon.createWithBitmap(mXmppConnectionService.getAvatarService().get(conversation, pixel));
 				final float score = 1 - (1.0f / MAX_TARGETS) * i;
 				final Bundle extras = new Bundle();

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

@@ -340,7 +340,7 @@ public class NotificationService {
 		for (final ArrayList<Message> messages : notifications.values()) {
 			if (messages.size() > 0) {
 				conversation = messages.get(0).getConversation();
-				final String name = conversation.getName();
+				final String name = conversation.getName().toString();
 				SpannableString styledString;
 				if (Config.HIDE_MESSAGE_TEXT_IN_NOTIFICATION) {
 					int count = messages.size();
@@ -379,7 +379,7 @@ public class NotificationService {
 		final Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService);
 		if (messages.size() >= 1) {
 			final Conversation conversation = messages.get(0).getConversation();
-			final UnreadConversation.Builder mUnreadBuilder = new UnreadConversation.Builder(conversation.getName());
+			final UnreadConversation.Builder mUnreadBuilder = new UnreadConversation.Builder(conversation.getName().toString());
 			mBuilder.setLargeIcon(mXmppConnectionService.getAvatarService()
 					.get(conversation, getPixel(64)));
 			mBuilder.setContentTitle(conversation.getName());

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

@@ -55,6 +55,7 @@ import java.util.List;
 import java.util.ListIterator;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -3392,42 +3393,40 @@ public class XmppConnectionService extends Service {
 
 	}
 
-	public List<String> getKnownHosts() {
-		final List<String> hosts = new ArrayList<>();
+	public Collection<String> getKnownHosts() {
+		final Set<String> hosts = new HashSet<>();
 		for (final Account account : getAccounts()) {
-			if (!hosts.contains(account.getServer().toString())) {
-				hosts.add(account.getServer().toString());
-			}
+			hosts.add(account.getServer());
 			for (final Contact contact : account.getRoster().getContacts()) {
 				if (contact.showInRoster()) {
-					final String server = contact.getServer().toString();
+					final String server = contact.getServer();
 					if (server != null && !hosts.contains(server)) {
 						hosts.add(server);
 					}
 				}
 			}
 		}
-		if (Config.DOMAIN_LOCK != null && !hosts.contains(Config.DOMAIN_LOCK)) {
+		if (Config.DOMAIN_LOCK != null) {
 			hosts.add(Config.DOMAIN_LOCK);
 		}
-		if (Config.MAGIC_CREATE_DOMAIN != null && !hosts.contains(Config.MAGIC_CREATE_DOMAIN)) {
+		if (Config.MAGIC_CREATE_DOMAIN != null) {
 			hosts.add(Config.MAGIC_CREATE_DOMAIN);
 		}
 		return hosts;
 	}
 
-	public List<String> getKnownConferenceHosts() {
-		final ArrayList<String> mucServers = new ArrayList<>();
+	public Collection<String> getKnownConferenceHosts() {
+		final Set<String> mucServers = new HashSet<>();
 		for (final Account account : accounts) {
 			if (account.getXmppConnection() != null) {
 				final String server = account.getXmppConnection().getMucServer();
-				if (server != null && !mucServers.contains(server)) {
+				if (server != null) {
 					mucServers.add(server);
 				}
 				for (Bookmark bookmark : account.getBookmarks()) {
 					final Jid jid = bookmark.getJid();
 					final String s = jid == null ? null : jid.getDomain();
-					if (s != null && !mucServers.contains(s)) {
+					if (s != null) {
 						mucServers.add(s);
 					}
 				}

src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java 🔗

@@ -9,6 +9,7 @@ import android.widget.AdapterView;
 import android.widget.Toast;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 
@@ -19,7 +20,7 @@ import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
 import rocks.xmpp.addr.Jid;
 
 public class BlocklistActivity extends AbstractSearchableListItemActivity implements OnUpdateBlocklist {
-	private List<String> mKnownHosts = new ArrayList<>();
+	private Collection<String> mKnownHosts = new ArrayList<>();
 
 	private Account account = null;
 

src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java 🔗

@@ -17,6 +17,7 @@ import android.widget.AbsListView.MultiChoiceModeListener;
 import android.widget.ListView;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -37,7 +38,7 @@ import rocks.xmpp.addr.Jid;
 public class ChooseContactActivity extends AbstractSearchableListItemActivity {
 	public static final String EXTRA_TITLE_RES_ID = "extra_title_res_id";
 	private List<String> mActivatedAccounts = new ArrayList<>();
-	private List<String> mKnownHosts;
+	private Collection<String> mKnownHosts;
 	private Set<Contact> selected;
 	private Set<String> filterContacts;
 

src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java 🔗

@@ -10,6 +10,7 @@ import android.widget.AutoCompleteTextView;
 import android.widget.Spinner;
 import android.widget.TextView;
 
+import java.util.Collection;
 import java.util.List;
 
 import eu.siacs.conversations.Config;
@@ -40,9 +41,9 @@ public class EnterJidDialog {
 	protected OnEnterJidDialogPositiveListener listener = null;
 
 	public EnterJidDialog(
-		final Context context, List<String> knownHosts, final List<String> activatedAccounts,
-		final String title, final String positiveButton,
-		final String prefilledJid, final String account, boolean allowEditJid
+			final Context context, Collection<String> knownHosts, final List<String> activatedAccounts,
+			final String title, final String positiveButton,
+			final String prefilledJid, final String account, boolean allowEditJid
 	) {
 		AlertDialog.Builder builder = new AlertDialog.Builder(context);
 		builder.setTitle(title);

src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java 🔗

@@ -59,6 +59,7 @@ import android.widget.Toast;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -94,8 +95,8 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 	private List<ListItem> conferences = new ArrayList<>();
 	private ListItemAdapter mConferenceAdapter;
 	private List<String> mActivatedAccounts = new ArrayList<>();
-	private List<String> mKnownHosts;
-	private List<String> mKnownConferenceHosts;
+	private Collection<String> mKnownHosts;
+	private Collection<String> mKnownConferenceHosts;
 	private Invite mPendingInvite = null;
 	private EditText mSearchEditText;
 	private AtomicBoolean mRequestedContactsPermission = new AtomicBoolean(false);

src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java 🔗

@@ -7,6 +7,7 @@ import android.graphics.Typeface;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
+import android.support.annotation.NonNull;
 import android.util.Log;
 import android.util.Pair;
 import android.view.LayoutInflater;
@@ -30,7 +31,9 @@ import eu.siacs.conversations.ui.XmppActivity;
 import eu.siacs.conversations.ui.util.Color;
 import eu.siacs.conversations.ui.widget.UnreadCountCustomView;
 import eu.siacs.conversations.utils.EmojiWrapper;
+import eu.siacs.conversations.utils.IrregularUnicodeDetector;
 import eu.siacs.conversations.utils.UIHelper;
+import rocks.xmpp.addr.Jid;
 
 public class ConversationAdapter extends ArrayAdapter<Conversation> {
 
@@ -43,7 +46,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
 	}
 
 	@Override
-	public View getView(int position, View view, ViewGroup parent) {
+	public View getView(int position, View view, @NonNull ViewGroup parent) {
 		if (view == null) {
 			LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 			view = inflater.inflate(R.layout.conversation_list_row,parent, false);
@@ -55,7 +58,12 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
 			viewHolder.swipeableItem.setBackgroundColor(c);
 		}
 		if (conversation.getMode() == Conversation.MODE_SINGLE || activity.useSubjectToIdentifyConference()) {
-			viewHolder.name.setText(EmojiWrapper.transform(conversation.getName()));
+			CharSequence name = conversation.getName();
+			if (name instanceof Jid) {
+				viewHolder.name.setText(IrregularUnicodeDetector.style(activity, (Jid) name));
+			} else {
+				viewHolder.name.setText(EmojiWrapper.transform(name));
+			}
 		} else {
 			viewHolder.name.setText(conversation.getJid().asBareJid().toString());
 		}
@@ -236,7 +244,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
 		}
 	}
 
-	public void loadAvatar(Conversation conversation, ImageView imageView) {
+	private void loadAvatar(Conversation conversation, ImageView imageView) {
 		if (cancelPotentialWork(conversation, imageView)) {
 			final Bitmap bm = activity.avatarService().get(conversation, activity.getPixel(56), true);
 			if (bm != null) {
@@ -244,7 +252,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
 				imageView.setImageBitmap(bm);
 				imageView.setBackgroundColor(0x00000000);
 			} else {
-				imageView.setBackgroundColor(UIHelper.getColorForName(conversation.getName()));
+				imageView.setBackgroundColor(UIHelper.getColorForName(conversation.getName().toString()));
 				imageView.setImageDrawable(null);
 				final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
 				final AsyncDrawable asyncDrawable = new AsyncDrawable(activity.getResources(), null, task);
@@ -257,7 +265,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
 		}
 	}
 
-	public static boolean cancelPotentialWork(Conversation conversation, ImageView imageView) {
+	private static boolean cancelPotentialWork(Conversation conversation, ImageView imageView) {
 		final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
 
 		if (bitmapWorkerTask != null) {

src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java 🔗

@@ -6,6 +6,7 @@ import android.widget.ArrayAdapter;
 import android.widget.Filter;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Locale;
 
@@ -58,7 +59,7 @@ public class KnownHostsAdapter extends ArrayAdapter<String> {
 		}
 	};
 
-	public KnownHostsAdapter(Context context, int viewResourceId, List<String> mKnownHosts) {
+	public KnownHostsAdapter(Context context, int viewResourceId, Collection<String> mKnownHosts) {
 		super(context, viewResourceId, new ArrayList<>());
 		domains = new ArrayList<>(mKnownHosts);
 	}

src/main/java/eu/siacs/conversations/utils/GeoHelper.java 🔗

@@ -42,7 +42,7 @@ public class GeoHelper {
 		String label;
 		if (conversation.getMode() == Conversation.MODE_SINGLE && message.getStatus() == Message.STATUS_RECEIVED) {
 			try {
-				label = "(" + URLEncoder.encode(message.getConversation().getName(), "UTF-8") + ")";
+				label = "(" + URLEncoder.encode(message.getConversation().getName().toString(), "UTF-8") + ")";
 			} catch (UnsupportedEncodingException e) {
 				label = "";
 			}

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

@@ -289,10 +289,10 @@ public class XmppConnection implements Runnable {
 				} catch (Exception e) {
 					throw new IOException(e.getMessage());
 				}
-			} else if (IP.matches(account.getServer().toString())) {
+			} else if (IP.matches(account.getServer())) {
 				localSocket = new Socket();
 				try {
-					localSocket.connect(new InetSocketAddress(account.getServer().toString(), 5222), Config.SOCKET_TIMEOUT * 1000);
+					localSocket.connect(new InetSocketAddress(account.getServer(), 5222), Config.SOCKET_TIMEOUT * 1000);
 				} catch (IOException e) {
 					throw new UnknownHostException();
 				}
@@ -352,12 +352,12 @@ public class XmppConnection implements Runnable {
 							}
 
 							SSLSocketHelper.setSecurity((SSLSocket) localSocket);
-							SSLSocketHelper.setSNIHost(tlsFactoryVerifier.factory, (SSLSocket) localSocket, account.getServer().getDomain());
+							SSLSocketHelper.setSNIHost(tlsFactoryVerifier.factory, (SSLSocket) localSocket, account.getServer());
 							SSLSocketHelper.setAlpnProtocol(tlsFactoryVerifier.factory, (SSLSocket) localSocket, "xmpp-client");
 
 							localSocket.connect(addr, Config.SOCKET_TIMEOUT * 1000);
 
-							if (!tlsFactoryVerifier.verifier.verify(account.getServer().getDomain(), verifiedHostname, ((SSLSocket) localSocket).getSession())) {
+							if (!tlsFactoryVerifier.verifier.verify(account.getServer(), verifiedHostname, ((SSLSocket) localSocket).getSession())) {
 								Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": TLS certificate verification failed");
 								if (!iterator.hasNext()) {
 									throw new StateChangingException(Account.State.TLS_ERROR);
@@ -794,7 +794,7 @@ public class XmppConnection implements Runnable {
 
 			SSLSocketHelper.setSecurity(sslSocket);
 
-			if (!tlsFactoryVerifier.verifier.verify(account.getServer().getDomain(), this.verifiedHostname, sslSocket.getSession())) {
+			if (!tlsFactoryVerifier.verifier.verify(account.getServer(), this.verifiedHostname, sslSocket.getSession())) {
 				Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": TLS certificate verification failed");
 				throw new StateChangingException(Account.State.TLS_ERROR);
 			}
@@ -898,74 +898,70 @@ public class XmppConnection implements Runnable {
 	private void sendRegistryRequest() {
 		final IqPacket register = new IqPacket(IqPacket.TYPE.GET);
 		register.query("jabber:iq:register");
-		register.setTo(account.getServer());
-		sendUnmodifiedIqPacket(register, new OnIqPacketReceived() {
-
-			@Override
-			public void onIqPacketReceived(final Account account, final IqPacket packet) {
-				if (packet.getType() == IqPacket.TYPE.TIMEOUT) {
-					return;
-				}
-				if (packet.getType() == IqPacket.TYPE.ERROR) {
-					throw new StateChangingError(Account.State.REGISTRATION_FAILED);
-				}
-				final Element query = packet.query("jabber:iq:register");
-				if (query.hasChild("username") && (query.hasChild("password"))) {
-					final IqPacket register = new IqPacket(IqPacket.TYPE.SET);
-					final Element username = new Element("username").setContent(account.getUsername());
-					final Element password = new Element("password").setContent(account.getPassword());
-					register.query("jabber:iq:register").addChild(username);
-					register.query().addChild(password);
-					register.setFrom(account.getJid().asBareJid());
-					sendUnmodifiedIqPacket(register, registrationResponseListener, true);
-				} else if (query.hasChild("x", Namespace.DATA)) {
-					final Data data = Data.parse(query.findChild("x", Namespace.DATA));
-					final Element blob = query.findChild("data", "urn:xmpp:bob");
-					final String id = packet.getId();
-					InputStream is;
-					if (blob != null) {
-						try {
-							final String base64Blob = blob.getContent();
-							final byte[] strBlob = Base64.decode(base64Blob, Base64.DEFAULT);
-							is = new ByteArrayInputStream(strBlob);
-						} catch (Exception e) {
-							is = null;
-						}
-					} else {
-						try {
-							Field field = data.getFieldByName("url");
-							URL url = field != null && field.getValue() != null ? new URL(field.getValue()) : null;
-							is = url != null ? url.openStream() : null;
-						} catch (IOException e) {
-							is = null;
-						}
+		register.setTo(Jid.of(account.getServer()));
+		sendUnmodifiedIqPacket(register, (account, packet) -> {
+			if (packet.getType() == IqPacket.TYPE.TIMEOUT) {
+				return;
+			}
+			if (packet.getType() == IqPacket.TYPE.ERROR) {
+				throw new StateChangingError(Account.State.REGISTRATION_FAILED);
+			}
+			final Element query = packet.query("jabber:iq:register");
+			if (query.hasChild("username") && (query.hasChild("password"))) {
+				final IqPacket register1 = new IqPacket(IqPacket.TYPE.SET);
+				final Element username = new Element("username").setContent(account.getUsername());
+				final Element password = new Element("password").setContent(account.getPassword());
+				register1.query("jabber:iq:register").addChild(username);
+				register1.query().addChild(password);
+				register1.setFrom(account.getJid().asBareJid());
+				sendUnmodifiedIqPacket(register1, registrationResponseListener, true);
+			} else if (query.hasChild("x", Namespace.DATA)) {
+				final Data data = Data.parse(query.findChild("x", Namespace.DATA));
+				final Element blob = query.findChild("data", "urn:xmpp:bob");
+				final String id = packet.getId();
+				InputStream is;
+				if (blob != null) {
+					try {
+						final String base64Blob = blob.getContent();
+						final byte[] strBlob = Base64.decode(base64Blob, Base64.DEFAULT);
+						is = new ByteArrayInputStream(strBlob);
+					} catch (Exception e) {
+						is = null;
+					}
+				} else {
+					try {
+						Field field = data.getFieldByName("url");
+						URL url = field != null && field.getValue() != null ? new URL(field.getValue()) : null;
+						is = url != null ? url.openStream() : null;
+					} catch (IOException e) {
+						is = null;
 					}
+				}
 
-					if (is != null) {
-						Bitmap captcha = BitmapFactory.decodeStream(is);
-						try {
-							if (mXmppConnectionService.displayCaptchaRequest(account, id, data, captcha)) {
-								return;
-							}
-						} catch (Exception e) {
-							throw new StateChangingError(Account.State.REGISTRATION_FAILED);
+				if (is != null) {
+					Bitmap captcha = BitmapFactory.decodeStream(is);
+					try {
+						if (mXmppConnectionService.displayCaptchaRequest(account, id, data, captcha)) {
+							return;
 						}
+					} catch (Exception e) {
+						throw new StateChangingError(Account.State.REGISTRATION_FAILED);
 					}
-					throw new StateChangingError(Account.State.REGISTRATION_FAILED);
-				} else if (query.hasChild("instructions") || query.hasChild("x",Namespace.OOB)) {
-					final String instructions = query.findChildContent("instructions");
-					final Element oob = query.findChild("x", Namespace.OOB);
-					final String url = oob == null ? null : oob.findChildContent("url");
-					if (url != null) {
-						setAccountCreationFailed(url);
-					} else if (instructions != null) {
-						Matcher matcher = Patterns.AUTOLINK_WEB_URL.matcher(instructions);
-						if (matcher.find()) {
-							setAccountCreationFailed(instructions.substring(matcher.start(), matcher.end()));
-						}
+				}
+				throw new StateChangingError(Account.State.REGISTRATION_FAILED);
+			} else if (query.hasChild("instructions") || query.hasChild("x",Namespace.OOB)) {
+				final String instructions = query.findChildContent("instructions");
+				final Element oob = query.findChild("x", Namespace.OOB);
+				final String url = oob == null ? null : oob.findChildContent("url");
+				if (url != null) {
+					setAccountCreationFailed(url);
+				} else if (instructions != null) {
+					Matcher matcher = Patterns.AUTOLINK_WEB_URL.matcher(instructions);
+					if (matcher.find()) {
+						setAccountCreationFailed(instructions.substring(matcher.start(), matcher.end()));
 					}
-					throw new StateChangingError(Account.State.REGISTRATION_FAILED);
 				}
+				throw new StateChangingError(Account.State.REGISTRATION_FAILED);
 			}
 		},true);
 	}
@@ -1142,17 +1138,17 @@ public class XmppConnection implements Runnable {
 		}
 		final boolean requestDiscoItemsFirst = !account.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY);
 		if (requestDiscoItemsFirst) {
-			sendServiceDiscoveryItems(account.getServer());
+			sendServiceDiscoveryItems(Jid.of(account.getServer()));
 		}
 		if (discoveryResult == null) {
-			sendServiceDiscoveryInfo(account.getServer());
+			sendServiceDiscoveryInfo(Jid.of(account.getServer()));
 		} else {
 			Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": server caps came from cache");
-			disco.put(account.getServer(), discoveryResult);
+			disco.put(Jid.of(account.getServer()), discoveryResult);
 		}
 		sendServiceDiscoveryInfo(account.getJid().asBareJid());
 		if (!requestDiscoItemsFirst) {
-			sendServiceDiscoveryItems(account.getServer());
+			sendServiceDiscoveryItems(Jid.of(account.getServer()));
 		}
 
 		if (!mWaitForDisco.get()) {
@@ -1166,32 +1162,28 @@ public class XmppConnection implements Runnable {
 		final IqPacket iq = new IqPacket(IqPacket.TYPE.GET);
 		iq.setTo(jid);
 		iq.query("http://jabber.org/protocol/disco#info");
-		this.sendIqPacket(iq, new OnIqPacketReceived() {
-
-			@Override
-			public void onIqPacketReceived(final Account account, final IqPacket packet) {
-				if (packet.getType() == IqPacket.TYPE.RESULT) {
-					boolean advancedStreamFeaturesLoaded;
-					synchronized (XmppConnection.this.disco) {
-						ServiceDiscoveryResult result = new ServiceDiscoveryResult(packet);
-						if (jid.equals(account.getServer())) {
-							mXmppConnectionService.databaseBackend.insertDiscoveryResult(result);
-						}
-						disco.put(jid, result);
-						advancedStreamFeaturesLoaded = disco.containsKey(account.getServer())
-								&& disco.containsKey(account.getJid().asBareJid());
-					}
-					if (advancedStreamFeaturesLoaded && (jid.equals(account.getServer()) || jid.equals(account.getJid().asBareJid()))) {
-						enableAdvancedStreamFeatures();
+		this.sendIqPacket(iq, (account, packet) -> {
+			if (packet.getType() == IqPacket.TYPE.RESULT) {
+				boolean advancedStreamFeaturesLoaded;
+				synchronized (XmppConnection.this.disco) {
+					ServiceDiscoveryResult result = new ServiceDiscoveryResult(packet);
+					if (jid.equals(Jid.of(account.getServer()))) {
+						mXmppConnectionService.databaseBackend.insertDiscoveryResult(result);
 					}
-				} else {
-					Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": could not query disco info for " + jid.toString());
+					disco.put(jid, result);
+					advancedStreamFeaturesLoaded = disco.containsKey(Jid.of(account.getServer()))
+							&& disco.containsKey(account.getJid().asBareJid());
 				}
-				if (packet.getType() != IqPacket.TYPE.TIMEOUT) {
-					if (mPendingServiceDiscoveries.decrementAndGet() == 0
-							&& mWaitForDisco.compareAndSet(true, false)) {
-						finalizeBind();
-					}
+				if (advancedStreamFeaturesLoaded && (jid.equals(Jid.of(account.getServer())) || jid.equals(account.getJid().asBareJid()))) {
+					enableAdvancedStreamFeatures();
+				}
+			} else {
+				Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": could not query disco info for " + jid.toString());
+			}
+			if (packet.getType() != IqPacket.TYPE.TIMEOUT) {
+				if (mPendingServiceDiscoveries.decrementAndGet() == 0
+						&& mWaitForDisco.compareAndSet(true, false)) {
+					finalizeBind();
 				}
 			}
 		});
@@ -1223,32 +1215,28 @@ public class XmppConnection implements Runnable {
 		final IqPacket iq = new IqPacket(IqPacket.TYPE.GET);
 		iq.setTo(Jid.ofDomain(server.getDomain()));
 		iq.query("http://jabber.org/protocol/disco#items");
-		this.sendIqPacket(iq, new OnIqPacketReceived() {
-
-			@Override
-			public void onIqPacketReceived(final Account account, final IqPacket packet) {
-				if (packet.getType() == IqPacket.TYPE.RESULT) {
-					HashSet<Jid> items = new HashSet<Jid>();
-					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())) {
-								items.add(jid);
-							}
+		this.sendIqPacket(iq, (account, packet) -> {
+			if (packet.getType() == IqPacket.TYPE.RESULT) {
+				HashSet<Jid> items = new HashSet<Jid>();
+				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(Jid.of(account.getServer()))) {
+							items.add(jid);
 						}
 					}
-					for (Jid jid : items) {
-						sendServiceDiscoveryInfo(jid);
-					}
-				} else {
-					Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": could not query disco items of " + server);
 				}
-				if (packet.getType() != IqPacket.TYPE.TIMEOUT) {
-					if (mPendingServiceDiscoveries.decrementAndGet() == 0
-							&& mWaitForDisco.compareAndSet(true, false)) {
-						finalizeBind();
-					}
+				for (Jid jid : items) {
+					sendServiceDiscoveryInfo(jid);
+				}
+			} else {
+				Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": could not query disco items of " + server);
+			}
+			if (packet.getType() != IqPacket.TYPE.TIMEOUT) {
+				if (mPendingServiceDiscoveries.decrementAndGet() == 0
+						&& mWaitForDisco.compareAndSet(true, false)) {
+					finalizeBind();
 				}
 			}
 		});
@@ -1479,7 +1467,7 @@ public class XmppConnection implements Runnable {
 		}
 	}
 
-	public void resetStreamId() {
+	private void resetStreamId() {
 		this.streamId = null;
 	}
 
@@ -1619,7 +1607,7 @@ public class XmppConnection implements Runnable {
 		private final SSLSocketFactory factory;
 		private final DomainHostnameVerifier verifier;
 
-		public TlsFactoryVerifier(final SSLSocketFactory factory, final DomainHostnameVerifier verifier) throws IOException {
+		TlsFactoryVerifier(final SSLSocketFactory factory, final DomainHostnameVerifier verifier) throws IOException {
 			this.factory = factory;
 			this.verifier = verifier;
 			if (factory == null || verifier == null) {
@@ -1705,23 +1693,23 @@ public class XmppConnection implements Runnable {
 		}
 
 		public boolean carbons() {
-			return hasDiscoFeature(account.getServer(), "urn:xmpp:carbons:2");
+			return hasDiscoFeature(Jid.of(account.getServer()), "urn:xmpp:carbons:2");
 		}
 
 		public boolean blocking() {
-			return hasDiscoFeature(account.getServer(), Namespace.BLOCKING);
+			return hasDiscoFeature(Jid.of(account.getServer()), Namespace.BLOCKING);
 		}
 
 		public boolean spamReporting() {
-			return hasDiscoFeature(account.getServer(), "urn:xmpp:reporting:reason:spam:0");
+			return hasDiscoFeature(Jid.of(account.getServer()), "urn:xmpp:reporting:reason:spam:0");
 		}
 
 		public boolean flexibleOfflineMessageRetrieval() {
-			return hasDiscoFeature(account.getServer(), Namespace.FLEXIBLE_OFFLINE_MESSAGE_RETRIEVAL);
+			return hasDiscoFeature(Jid.of(account.getServer()), Namespace.FLEXIBLE_OFFLINE_MESSAGE_RETRIEVAL);
 		}
 
 		public boolean register() {
-			return hasDiscoFeature(account.getServer(), Namespace.REGISTER);
+			return hasDiscoFeature(Jid.of(account.getServer()), Namespace.REGISTER);
 		}
 
 		public boolean sm() {
@@ -1767,7 +1755,7 @@ public class XmppConnection implements Runnable {
 
 		public boolean push() {
 			return hasDiscoFeature(account.getJid().asBareJid(), "urn:xmpp:push:0")
-					|| hasDiscoFeature(account.getServer(), "urn:xmpp:push:0");
+					|| hasDiscoFeature(Jid.of(account.getServer()), "urn:xmpp:push:0");
 		}
 
 		public boolean rosterVersioning() {