diff --git a/README.md b/README.md
index 2181aa961..66213e46c 100644
--- a/README.md
+++ b/README.md
@@ -50,9 +50,11 @@ run your own XMPP server for you and your friends. These XEP's are:
 * XEP-0313: Message Archive Management synchronize message history with the
   server. Catch up with messages that were sent while Conversations was
   offline.
-* XEP-0352: Client State Indication let the server know whether or not
+* XEP-0352: Client State Indication lets the server know whether or not
   Conversations is in the background. Allows the server to save bandwidth by
   withholding unimportant packages.
+* XEP-0191: Blocking command lets you blacklist spammers or block contacts
+  without removing them from your roster.
 
 ## Team
 
diff --git a/docs/XEPs.md b/docs/XEPs.md
index 980c1c658..35c7de455 100644
--- a/docs/XEPs.md
+++ b/docs/XEPs.md
@@ -16,3 +16,4 @@
 * XEP-0313: Message Archive Management
 * XEP-0333: Chat Markers
 * XEP-0352: Client State Indication
+* XEP-0191: Blocking command
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 8fdfa85b4..5662e626b 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -76,6 +76,9 @@
         <activity
             android:name=".ui.ChooseContactActivity"
             android:label="@string/title_activity_choose_contact" />
+        <activity
+            android:name=".ui.BlocklistActivity"
+            android:label="@string/title_activity_block_list" />
         <activity
             android:name=".ui.ManageAccountActivity"
             android:configChanges="orientation|screenSize"
diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java
index d90010174..d42974c68 100644
--- a/src/main/java/eu/siacs/conversations/entities/Account.java
+++ b/src/main/java/eu/siacs/conversations/entities/Account.java
@@ -11,8 +11,10 @@ import org.json.JSONException;
 import org.json.JSONObject;
 
 import java.security.interfaces.DSAPublicKey;
+import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
 
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
@@ -56,7 +58,7 @@ public class Account extends AbstractEntity {
 		SECURITY_ERROR(true),
 		INCOMPATIBLE_SERVER(true);
 
-		private boolean isError;
+		private final boolean isError;
 
 		public boolean isError() {
 			return this.isError;
@@ -120,6 +122,7 @@ public class Account extends AbstractEntity {
 	private String otrFingerprint;
 	private final Roster roster = new Roster(this);
 	private List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
+	private final Collection<Jid> blocklist = new CopyOnWriteArraySet<>();
 
 	public Account() {
 		this.uuid = "0";
@@ -279,7 +282,7 @@ public class Account extends AbstractEntity {
 		return values;
 	}
 
-	public void initOtrEngine(XmppConnectionService context) {
+	public void initOtrEngine(final XmppConnectionService context) {
 		this.otrEngine = new OtrEngine(context, this);
 	}
 
@@ -291,7 +294,7 @@ public class Account extends AbstractEntity {
 		return this.xmppConnection;
 	}
 
-	public void setXmppConnection(XmppConnection connection) {
+	public void setXmppConnection(final XmppConnection connection) {
 		this.xmppConnection = connection;
 	}
 
@@ -323,7 +326,7 @@ public class Account extends AbstractEntity {
 		}
 	}
 
-	public void setRosterVersion(String version) {
+	public void setRosterVersion(final String version) {
 		this.rosterVersion = version;
 	}
 
@@ -351,7 +354,7 @@ public class Account extends AbstractEntity {
 		return this.bookmarks;
 	}
 
-	public void setBookmarks(List<Bookmark> bookmarks) {
+	public void setBookmarks(final List<Bookmark> bookmarks) {
 		this.bookmarks = bookmarks;
 	}
 
@@ -399,4 +402,21 @@ public class Account extends AbstractEntity {
 			return "xmpp:" + this.getJid().toBareJid().toString();
 		}
 	}
+
+	public boolean isBlocked(final ListItem contact) {
+		final Jid jid = contact.getJid();
+		return jid != null && (blocklist.contains(jid.toBareJid()) || blocklist.contains(jid.toDomainJid()));
+	}
+
+	public boolean isBlocked(final Jid jid) {
+		return jid != null && blocklist.contains(jid.toBareJid());
+	}
+
+	public Collection<Jid> getBlocklist() {
+		return this.blocklist;
+	}
+
+	public void clearBlocklist() {
+		getBlocklist().clear();
+	}
 }
diff --git a/src/main/java/eu/siacs/conversations/entities/Blockable.java b/src/main/java/eu/siacs/conversations/entities/Blockable.java
new file mode 100644
index 000000000..dbcd55c43
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/entities/Blockable.java
@@ -0,0 +1,11 @@
+package eu.siacs.conversations.entities;
+
+import eu.siacs.conversations.xmpp.jid.Jid;
+
+public interface Blockable {
+	public boolean isBlocked();
+	public boolean isDomainBlocked();
+	public Jid getBlockedJid();
+	public Jid getJid();
+	public Account getAccount();
+}
diff --git a/src/main/java/eu/siacs/conversations/entities/Bookmark.java b/src/main/java/eu/siacs/conversations/entities/Bookmark.java
index 209056485..f81f1a876 100644
--- a/src/main/java/eu/siacs/conversations/entities/Bookmark.java
+++ b/src/main/java/eu/siacs/conversations/entities/Bookmark.java
@@ -6,7 +6,6 @@ import java.util.Locale;
 
 import eu.siacs.conversations.utils.UIHelper;
 import eu.siacs.conversations.xml.Element;
-import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 import eu.siacs.conversations.xmpp.jid.Jid;
 
 public class Bookmark extends Element implements ListItem {
diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java
index 0820504fc..af26981ee 100644
--- a/src/main/java/eu/siacs/conversations/entities/Contact.java
+++ b/src/main/java/eu/siacs/conversations/entities/Contact.java
@@ -16,7 +16,7 @@ import eu.siacs.conversations.xml.Element;
 import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 import eu.siacs.conversations.xmpp.jid.Jid;
 
-public class Contact implements ListItem {
+public class Contact implements ListItem, Blockable {
 	public static final String TABLENAME = "contacts";
 
 	public static final String SYSTEMNAME = "systemname";
@@ -47,8 +47,8 @@ public class Contact implements ListItem {
 	protected Account account;
 
 	public Contact(final String account, final String systemName, final String serverName,
-				   final Jid jid, final int subscription, final String photoUri,
-				   final String systemAccount, final String keys, final String avatar, final Lastseen lastseen, final String groups) {
+			final Jid jid, final int subscription, final String photoUri,
+			final String systemAccount, final String keys, final String avatar, final Lastseen lastseen, final String groups) {
 		this.accountUuid = account;
 		this.systemName = systemName;
 		this.serverName = serverName;
@@ -122,11 +122,10 @@ public class Contact implements ListItem {
 
 	@Override
 	public List<Tag> getTags() {
-		ArrayList<Tag> tags = new ArrayList<Tag>();
-		for (String group : getGroups()) {
+		final ArrayList<Tag> tags = new ArrayList<>();
+		for (final String group : getGroups()) {
 			tags.add(new Tag(group, UIHelper.getColorForName(group)));
 		}
-		int status = getMostAvailableStatus();
 		switch (getMostAvailableStatus()) {
 			case Presences.CHAT:
 			case Presences.ONLINE:
@@ -142,6 +141,9 @@ public class Contact implements ListItem {
 				tags.add(new Tag("dnd", 0xffe51c23));
 				break;
 		}
+		if (isBlocked()) {
+			tags.add(new Tag("blocked", 0xff2e2f3b));
+		}
 		return tags;
 	}
 
@@ -176,7 +178,7 @@ public class Contact implements ListItem {
 	}
 
 	public ContentValues getContentValues() {
-		ContentValues values = new ContentValues();
+		final ContentValues values = new ContentValues();
 		values.put(ACCOUNT, accountUuid);
 		values.put(SYSTEMNAME, systemName);
 		values.put(SERVERNAME, serverName);
@@ -213,11 +215,11 @@ public class Contact implements ListItem {
 		this.presences = pres;
 	}
 
-	public void updatePresence(String resource, int status) {
+	public void updatePresence(final String resource, final int status) {
 		this.presences.updatePresence(resource, status);
 	}
 
-	public void removePresence(String resource) {
+	public void removePresence(final String resource) {
 		this.presences.removePresence(resource);
 	}
 
@@ -337,8 +339,8 @@ public class Contact implements ListItem {
 
 	public boolean showInRoster() {
 		return (this.getOption(Contact.Options.IN_ROSTER) && (!this
-				.getOption(Contact.Options.DIRTY_DELETE)))
-				|| (this.getOption(Contact.Options.DIRTY_PUSH));
+					.getOption(Contact.Options.DIRTY_DELETE)))
+			|| (this.getOption(Contact.Options.DIRTY_PUSH));
 	}
 
 	public void parseSubscriptionFromElement(Element item) {
@@ -428,7 +430,7 @@ public class Contact implements ListItem {
 			if (this.keys.has("otr_fingerprints")) {
 				JSONArray newPrints = new JSONArray();
 				JSONArray oldPrints = this.keys
-						.getJSONArray("otr_fingerprints");
+					.getJSONArray("otr_fingerprints");
 				for (int i = 0; i < oldPrints.length(); ++i) {
 					if (!oldPrints.getString(i).equals(fingerprint)) {
 						newPrints.put(oldPrints.getString(i));
@@ -457,22 +459,40 @@ public class Contact implements ListItem {
 		}
 	}
 
+	@Override
+	public boolean isBlocked() {
+		return getAccount().isBlocked(this);
+	}
+
+	@Override
+	public boolean isDomainBlocked() {
+		return getAccount().isBlocked(this.getJid().toDomainJid());
+	}
+
+	@Override
+	public Jid getBlockedJid() {
+		if (isDomainBlocked()) {
+			return getJid().toDomainJid();
+		} else {
+			return getJid();
+		}
+	}
+
 	public static class Lastseen {
 		public long time;
 		public String presence;
 
 		public Lastseen() {
-			time = 0;
-			presence = null;
+			this(null, 0);
 		}
 
 		public Lastseen(final String presence, final long time) {
-			this.time = time;
 			this.presence = presence;
+			this.time = time;
 		}
 	}
 
-	public class Options {
+	public final class Options {
 		public static final int TO = 0;
 		public static final int FROM = 1;
 		public static final int ASKING = 2;
diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java
index e8482a962..22ddd307a 100644
--- a/src/main/java/eu/siacs/conversations/entities/Conversation.java
+++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java
@@ -3,7 +3,6 @@ package eu.siacs.conversations.entities;
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.os.SystemClock;
-import android.util.Log;
 
 import net.java.otr4j.OtrException;
 import net.java.otr4j.crypto.OtrCryptoEngineImpl;
@@ -25,7 +24,7 @@ import eu.siacs.conversations.Config;
 import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 import eu.siacs.conversations.xmpp.jid.Jid;
 
-public class Conversation extends AbstractEntity {
+public class Conversation extends AbstractEntity implements Blockable {
 	public static final String TABLENAME = "conversations";
 
 	public static final int STATUS_AVAILABLE = 0;
@@ -105,7 +104,7 @@ public class Conversation extends AbstractEntity {
 				if ((message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE)
 						&& message.getEncryption() != Message.ENCRYPTION_PGP) {
 					onMessageFound.onMessageFound(message);
-				}
+						}
 			}
 		}
 	}
@@ -117,7 +116,7 @@ public class Conversation extends AbstractEntity {
 						&& message.getEncryption() != Message.ENCRYPTION_PGP
 						&& message.getUuid().equals(uuid)) {
 					return message;
-				}
+						}
 			}
 		}
 		return null;
@@ -145,7 +144,7 @@ public class Conversation extends AbstractEntity {
 				if ((message.getStatus() == Message.STATUS_UNSEND || message.getStatus() == Message.STATUS_WAITING)
 						&& (message.getEncryption() == Message.ENCRYPTION_OTR)) {
 					onMessageFound.onMessageFound(message);
-				}
+						}
 			}
 		}
 	}
@@ -156,7 +155,7 @@ public class Conversation extends AbstractEntity {
 				if (message.getType() != Message.TYPE_IMAGE
 						&& message.getStatus() == Message.STATUS_UNSEND) {
 					onMessageFound.onMessageFound(message);
-				}
+						}
 			}
 		}
 	}
@@ -166,21 +165,37 @@ public class Conversation extends AbstractEntity {
 			for (Message message : this.messages) {
 				if (uuid.equals(message.getUuid())
 						|| (message.getStatus() >= Message.STATUS_SEND && uuid
-						.equals(message.getRemoteMsgId()))) {
+							.equals(message.getRemoteMsgId()))) {
 					return message;
-				}
+							}
 			}
 		}
 		return null;
 	}
 
-	public void populateWithMessages(List<Message> messages) {
+	public void populateWithMessages(final List<Message> messages) {
 		synchronized (this.messages) {
 			messages.clear();
 			messages.addAll(this.messages);
 		}
 	}
 
+	@Override
+	public boolean isBlocked() {
+		return getContact().isBlocked();
+	}
+
+	@Override
+	public boolean isDomainBlocked() {
+		return getContact().isDomainBlocked();
+	}
+
+	@Override
+	public Jid getBlockedJid() {
+		return getContact().getBlockedJid();
+	}
+
+
 	public interface OnMessageFound {
 		public void onMessageFound(final Message message);
 	}
@@ -212,8 +227,8 @@ public class Conversation extends AbstractEntity {
 	}
 
 	public boolean isRead() {
-        return (this.messages == null) || (this.messages.size() == 0) || this.messages.get(this.messages.size() - 1).isRead();
-    }
+		return (this.messages == null) || (this.messages.size() == 0) || this.messages.get(this.messages.size() - 1).isRead();
+	}
 
 	public void markRead() {
 		if (this.messages == null) {
@@ -239,7 +254,7 @@ public class Conversation extends AbstractEntity {
 				} else {
 					return this.messages.get(i);
 				}
-			}
+					}
 		}
 		return null;
 	}
@@ -267,7 +282,7 @@ public class Conversation extends AbstractEntity {
 				if (generatedName != null) {
 					return generatedName;
 				} else {
-					return getContactJid().getLocalpart();
+					return getJid().getLocalpart();
 				}
 			}
 		} else {
@@ -287,11 +302,12 @@ public class Conversation extends AbstractEntity {
 		return this.account.getRoster().getContact(this.contactJid);
 	}
 
-	public void setAccount(Account account) {
+	public void setAccount(final Account account) {
 		this.account = account;
 	}
 
-	public Jid getContactJid() {
+	@Override
+	public Jid getJid() {
 		return this.contactJid;
 	}
 
@@ -318,14 +334,14 @@ public class Conversation extends AbstractEntity {
 	}
 
 	public static Conversation fromCursor(Cursor cursor) {
-        Jid jid;
-        try {
-            jid = Jid.fromString(cursor.getString(cursor.getColumnIndex(CONTACTJID)));
-        } catch (final InvalidJidException e) {
-            // Borked DB..
-            jid = null;
-        }
-        return new Conversation(cursor.getString(cursor.getColumnIndex(UUID)),
+		Jid jid;
+		try {
+			jid = Jid.fromString(cursor.getString(cursor.getColumnIndex(CONTACTJID)));
+		} catch (final InvalidJidException e) {
+			// Borked DB..
+			jid = null;
+		}
+		return new Conversation(cursor.getString(cursor.getColumnIndex(UUID)),
 				cursor.getString(cursor.getColumnIndex(NAME)),
 				cursor.getString(cursor.getColumnIndex(CONTACT)),
 				cursor.getString(cursor.getColumnIndex(ACCOUNT)),
@@ -352,9 +368,9 @@ public class Conversation extends AbstractEntity {
 		if (this.otrSession != null) {
 			return this.otrSession;
 		} else {
-            final SessionID sessionId = new SessionID(this.getContactJid().toBareJid().toString(),
-                    presence,
-                    "xmpp");
+			final SessionID sessionId = new SessionID(this.getJid().toBareJid().toString(),
+					presence,
+					"xmpp");
 			this.otrSession = new SessionImpl(sessionId, getAccount().getOtrEngine());
 			try {
 				if (sendStart) {
@@ -393,7 +409,7 @@ public class Conversation extends AbstractEntity {
 			} catch (OtrException e) {
 				this.resetOtrSession();
 			}
-		}
+				}
 	}
 
 	public boolean endOtrIfNeeded() {
@@ -427,7 +443,7 @@ public class Conversation extends AbstractEntity {
 					return "";
 				}
 				DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession()
-						.getRemotePublicKey();
+					.getRemotePublicKey();
 				StringBuilder builder = new StringBuilder(
 						new OtrCryptoEngineImpl().getFingerprint(remotePubKey));
 				builder.insert(8, " ");
diff --git a/src/main/java/eu/siacs/conversations/entities/ListItem.java b/src/main/java/eu/siacs/conversations/entities/ListItem.java
index db9fbc374..efc1c2b93 100644
--- a/src/main/java/eu/siacs/conversations/entities/ListItem.java
+++ b/src/main/java/eu/siacs/conversations/entities/ListItem.java
@@ -12,10 +12,10 @@ public interface ListItem extends Comparable<ListItem> {
 	public List<Tag> getTags();
 
 	public final class Tag {
-		private String name;
-		private int color;
+		private final String name;
+		private final int color;
 
-		public Tag(String name, int color) {
+		public Tag(final String name, final int color) {
 			this.name = name;
 			this.color = color;
 		}
@@ -28,4 +28,6 @@ public interface ListItem extends Comparable<ListItem> {
 			return this.name;
 		}
 	}
+
+	public boolean match(final String needle);
 }
diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java
index 5b9371386..38e88fa4a 100644
--- a/src/main/java/eu/siacs/conversations/entities/Message.java
+++ b/src/main/java/eu/siacs/conversations/entities/Message.java
@@ -77,7 +77,7 @@ public class Message extends AbstractEntity {
 	public Message(Conversation conversation, String body, int encryption, int status) {
 		this(java.util.UUID.randomUUID().toString(),
 				conversation.getUuid(),
-				conversation.getContactJid() == null ? null : conversation.getContactJid().toBareJid(),
+				conversation.getJid() == null ? null : conversation.getJid().toBareJid(),
 				null,
 				body,
 				System.currentTimeMillis(),
@@ -91,9 +91,9 @@ public class Message extends AbstractEntity {
 	}
 
 	private Message(final String uuid, final String conversationUUid, final Jid counterpart,
-				   final Jid trueCounterpart, final String body, final long timeSent,
-				   final int encryption, final int status, final int type, final String remoteMsgId,
-				   final String relativeFilePath, final String serverMsgId) {
+			final Jid trueCounterpart, final String body, final long timeSent,
+			final int encryption, final int status, final int type, final String remoteMsgId,
+			final String relativeFilePath, final String serverMsgId) {
 		this.uuid = uuid;
 		this.conversationUuid = conversationUUid;
 		this.counterpart = counterpart;
@@ -206,7 +206,7 @@ public class Message extends AbstractEntity {
 				return null;
 			} else {
 				return this.conversation.getAccount().getRoster()
-						.getContactFromRoster(this.trueCounterpart);
+					.getContactFromRoster(this.trueCounterpart);
 			}
 		}
 	}
@@ -312,10 +312,10 @@ public class Message extends AbstractEntity {
 			return this.serverMsgId.equals(message.getServerMsgId());
 		} else {
 			return this.body != null
-					&& this.counterpart != null
-					&& ((this.remoteMsgId != null && this.remoteMsgId.equals(message.getRemoteMsgId()))
-					|| this.uuid.equals(message.getRemoteMsgId())) && this.body.equals(message.getBody())
-					&& this.counterpart.equals(message.getCounterpart());
+				&& this.counterpart != null
+				&& ((this.remoteMsgId != null && this.remoteMsgId.equals(message.getRemoteMsgId()))
+						|| this.uuid.equals(message.getRemoteMsgId())) && this.body.equals(message.getBody())
+				&& this.counterpart.equals(message.getCounterpart());
 		}
 	}
 
@@ -388,7 +388,7 @@ public class Message extends AbstractEntity {
 			if (!url.getProtocol().equalsIgnoreCase("http")
 					&& !url.getProtocol().equalsIgnoreCase("https")) {
 				return false;
-			}
+					}
 			if (url.getPath() == null) {
 				return false;
 			}
@@ -402,14 +402,14 @@ public class Message extends AbstractEntity {
 			String[] extensionParts = filename.split("\\.");
 			if (extensionParts.length == 2
 					&& Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains(
-					extensionParts[extensionParts.length - 1])) {
+						extensionParts[extensionParts.length - 1])) {
 				return true;
 			} else if (extensionParts.length == 3
 					&& Arrays
 					.asList(Downloadable.VALID_CRYPTO_EXTENSIONS)
 					.contains(extensionParts[extensionParts.length - 1])
 					&& Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains(
-					extensionParts[extensionParts.length - 2])) {
+						extensionParts[extensionParts.length - 2])) {
 				return true;
 			} else {
 				return false;
diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
index c8706fc95..97a63532f 100644
--- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java
+++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
@@ -80,20 +80,20 @@ public class MucOptions {
 
 		public void setRole(String role) {
 			role = role.toLowerCase();
-            switch (role) {
-                case "moderator":
-                    this.role = ROLE_MODERATOR;
-                    break;
-                case "participant":
-                    this.role = ROLE_PARTICIPANT;
-                    break;
-                case "visitor":
-                    this.role = ROLE_VISITOR;
-                    break;
-                default:
-                    this.role = ROLE_NONE;
-                    break;
-            }
+			switch (role) {
+				case "moderator":
+					this.role = ROLE_MODERATOR;
+					break;
+				case "participant":
+					this.role = ROLE_PARTICIPANT;
+					break;
+				case "visitor":
+					this.role = ROLE_VISITOR;
+					break;
+				default:
+					this.role = ROLE_NONE;
+					break;
+			}
 		}
 
 		public int getAffiliation() {
@@ -164,7 +164,7 @@ public class MucOptions {
 	}
 
 	public void processPacket(PresencePacket packet, PgpEngine pgp) {
-        final Jid from = packet.getFrom();
+		final Jid from = packet.getFrom();
 		if (!from.isBareJid()) {
 			final String name = from.getResourcepart();
 			final String type = packet.getAttribute("type");
@@ -179,7 +179,7 @@ public class MucOptions {
 						user.setAffiliation(item.getAttribute("affiliation"));
 						user.setRole(item.getAttribute("role"));
 						user.setJid(item.getAttributeAsJid("jid"));
-						if (codes.contains(STATUS_CODE_SELF_PRESENCE) || packet.getFrom().equals(this.conversation.getContactJid())) {
+						if (codes.contains(STATUS_CODE_SELF_PRESENCE) || packet.getFrom().equals(this.conversation.getJid())) {
 							this.isOnline = true;
 							this.error = ERROR_NO_ERROR;
 							self = user;
@@ -204,14 +204,14 @@ public class MucOptions {
 									msg = "";
 								}
 								user.setPgpKeyId(pgp.fetchKeyId(account, msg,
-										signed.getContent()));
+											signed.getContent()));
 							}
 						}
 					}
 				}
 			} else if (type.equals("unavailable")) {
 				if (codes.contains(STATUS_CODE_SELF_PRESENCE) ||
-						packet.getFrom().equals(this.conversation.getContactJid())) {
+						packet.getFrom().equals(this.conversation.getJid())) {
 					if (codes.contains(STATUS_CODE_CHANGED_NICK)) {
 						this.mNickChangingInProgress = true;
 					} else if (codes.contains(STATUS_CODE_KICKED)) {
@@ -282,8 +282,8 @@ public class MucOptions {
 				&& conversation.getBookmark().getNick() != null
 				&& !conversation.getBookmark().getNick().isEmpty()) {
 			return conversation.getBookmark().getNick();
-		} else if (!conversation.getContactJid().isBareJid()) {
-			return conversation.getContactJid().getResourcepart();
+		} else if (!conversation.getJid().isBareJid()) {
+			return conversation.getJid().getResourcepart();
 		} else {
 			return account.getUsername();
 		}
@@ -334,14 +334,14 @@ public class MucOptions {
 	public String createNameFromParticipants() {
 		if (users.size() >= 2) {
 			List<String> names = new ArrayList<String>();
-				for (User user : users) {
-					Contact contact = user.getContact();
-					if (contact != null && !contact.getDisplayName().isEmpty()) {
-						names.add(contact.getDisplayName().split("\\s+")[0]);
-					} else {
-						names.add(user.getName());
-					}
+			for (User user : users) {
+				Contact contact = user.getContact();
+				if (contact != null && !contact.getDisplayName().isEmpty()) {
+					names.add(contact.getDisplayName().split("\\s+")[0]);
+				} else {
+					names.add(user.getName());
 				}
+			}
 			StringBuilder builder = new StringBuilder();
 			for (int i = 0; i < names.size(); ++i) {
 				builder.append(names.get(i));
@@ -388,12 +388,12 @@ public class MucOptions {
 	}
 
 	public Jid createJoinJid(String nick) {
-        try {
-            return Jid.fromString(this.conversation.getContactJid().toBareJid().toString() + "/"+nick);
-        } catch (final InvalidJidException e) {
-            return null;
-        }
-    }
+		try {
+			return Jid.fromString(this.conversation.getJid().toBareJid().toString() + "/"+nick);
+		} catch (final InvalidJidException e) {
+			return null;
+		}
+	}
 
 	public Jid getTrueCounterpart(String counterpart) {
 		for (User user : this.getUsers()) {
diff --git a/src/main/java/eu/siacs/conversations/entities/Roster.java b/src/main/java/eu/siacs/conversations/entities/Roster.java
index 12a89cec2..1a81a419e 100644
--- a/src/main/java/eu/siacs/conversations/entities/Roster.java
+++ b/src/main/java/eu/siacs/conversations/entities/Roster.java
@@ -7,7 +7,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import eu.siacs.conversations.xmpp.jid.Jid;
 
 public class Roster {
-	Account account;
+	final Account account;
 	final ConcurrentHashMap<String, Contact> contacts = new ConcurrentHashMap<>();
 	private String version = null;
 
@@ -19,7 +19,7 @@ public class Roster {
 		if (jid == null) {
 			return null;
 		}
-		Contact contact = contacts.get(jid.toBareJid().toString());
+		final Contact contact = contacts.get(jid.toBareJid().toString());
 		if (contact != null && contact.showInRoster()) {
 			return contact;
 		} else {
@@ -32,7 +32,7 @@ public class Roster {
 		if (contacts.containsKey(bareJid.toString())) {
 			return contacts.get(bareJid.toString());
 		} else {
-			Contact contact = new Contact(bareJid);
+			final Contact contact = new Contact(bareJid);
 			contact.setAccount(account);
 			contacts.put(bareJid.toString(), contact);
 			return contact;
@@ -46,13 +46,13 @@ public class Roster {
 	}
 
 	public void markAllAsNotInRoster() {
-		for (Contact contact : getContacts()) {
+		for (final Contact contact : getContacts()) {
 			contact.resetOption(Contact.Options.IN_ROSTER);
 		}
 	}
 
 	public void clearSystemAccounts() {
-		for (Contact contact : getContacts()) {
+		for (final Contact contact : getContacts()) {
 			contact.setPhotoUri(null);
 			contact.setSystemName(null);
 			contact.setSystemAccount(null);
diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
index 4819f96eb..4b28e484a 100644
--- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
@@ -1,14 +1,12 @@
 package eu.siacs.conversations.generator;
 
-import android.util.Log;
-
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
-import eu.siacs.conversations.Config;
 import eu.siacs.conversations.services.MessageArchiveService;
 import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.utils.Xmlns;
 import eu.siacs.conversations.xml.Element;
 import eu.siacs.conversations.xmpp.forms.Data;
 import eu.siacs.conversations.xmpp.jid.Jid;
@@ -17,44 +15,44 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket;
 
 public class IqGenerator extends AbstractGenerator {
 
-	public IqGenerator(XmppConnectionService service) {
+	public IqGenerator(final XmppConnectionService service) {
 		super(service);
 	}
 
-	public IqPacket discoResponse(IqPacket request) {
-		IqPacket packet = new IqPacket(IqPacket.TYPE_RESULT);
+	public IqPacket discoResponse(final IqPacket request) {
+		final IqPacket packet = new IqPacket(IqPacket.TYPE_RESULT);
 		packet.setId(request.getId());
-        packet.setTo(request.getFrom());
-		Element query = packet.addChild("query",
+		packet.setTo(request.getFrom());
+		final Element query = packet.addChild("query",
 				"http://jabber.org/protocol/disco#info");
 		query.setAttribute("node", request.query().getAttribute("node"));
-		Element identity = query.addChild("identity");
+		final Element identity = query.addChild("identity");
 		identity.setAttribute("category", "client");
 		identity.setAttribute("type", this.IDENTITY_TYPE);
 		identity.setAttribute("name", IDENTITY_NAME);
-		List<String> features = Arrays.asList(FEATURES);
+		final List<String> features = Arrays.asList(FEATURES);
 		Collections.sort(features);
-		for (String feature : features) {
+		for (final String feature : features) {
 			query.addChild("feature").setAttribute("var", feature);
 		}
 		return packet;
 	}
 
-	protected IqPacket publish(String node, Element item) {
-		IqPacket packet = new IqPacket(IqPacket.TYPE_SET);
-		Element pubsub = packet.addChild("pubsub",
+	protected IqPacket publish(final String node, final Element item) {
+		final IqPacket packet = new IqPacket(IqPacket.TYPE_SET);
+		final Element pubsub = packet.addChild("pubsub",
 				"http://jabber.org/protocol/pubsub");
-		Element publish = pubsub.addChild("publish");
+		final Element publish = pubsub.addChild("publish");
 		publish.setAttribute("node", node);
 		publish.addChild(item);
 		return packet;
 	}
 
 	protected IqPacket retrieve(String node, Element item) {
-		IqPacket packet = new IqPacket(IqPacket.TYPE_GET);
-		Element pubsub = packet.addChild("pubsub",
+		final IqPacket packet = new IqPacket(IqPacket.TYPE_GET);
+		final Element pubsub = packet.addChild("pubsub",
 				"http://jabber.org/protocol/pubsub");
-		Element items = pubsub.addChild("items");
+		final Element items = pubsub.addChild("items");
 		items.setAttribute("node", node);
 		if (item != null) {
 			items.addChild(item);
@@ -63,19 +61,19 @@ public class IqGenerator extends AbstractGenerator {
 	}
 
 	public IqPacket publishAvatar(Avatar avatar) {
-		Element item = new Element("item");
+		final Element item = new Element("item");
 		item.setAttribute("id", avatar.sha1sum);
-		Element data = item.addChild("data", "urn:xmpp:avatar:data");
+		final Element data = item.addChild("data", "urn:xmpp:avatar:data");
 		data.setContent(avatar.image);
 		return publish("urn:xmpp:avatar:data", item);
 	}
 
-	public IqPacket publishAvatarMetadata(Avatar avatar) {
-		Element item = new Element("item");
+	public IqPacket publishAvatarMetadata(final Avatar avatar) {
+		final Element item = new Element("item");
 		item.setAttribute("id", avatar.sha1sum);
-		Element metadata = item
-				.addChild("metadata", "urn:xmpp:avatar:metadata");
-		Element info = metadata.addChild("info");
+		final Element metadata = item
+			.addChild("metadata", "urn:xmpp:avatar:metadata");
+		final Element info = metadata.addChild("info");
 		info.setAttribute("bytes", avatar.size);
 		info.setAttribute("id", avatar.sha1sum);
 		info.setAttribute("height", avatar.height);
@@ -84,10 +82,10 @@ public class IqGenerator extends AbstractGenerator {
 		return publish("urn:xmpp:avatar:metadata", item);
 	}
 
-	public IqPacket retrieveAvatar(Avatar avatar) {
-		Element item = new Element("item");
+	public IqPacket retrieveAvatar(final Avatar avatar) {
+		final Element item = new Element("item");
 		item.setAttribute("id", avatar.sha1sum);
-		IqPacket packet = retrieve("urn:xmpp:avatar:data", item);
+		final IqPacket packet = retrieve("urn:xmpp:avatar:data", item);
 		packet.setTo(avatar.owner);
 		return packet;
 	}
@@ -100,11 +98,11 @@ public class IqGenerator extends AbstractGenerator {
 		return packet;
 	}
 
-	public IqPacket queryMessageArchiveManagement(MessageArchiveService.Query mam) {
+	public IqPacket queryMessageArchiveManagement(final MessageArchiveService.Query mam) {
 		final IqPacket packet = new IqPacket(IqPacket.TYPE_SET);
-		Element query = packet.query("urn:xmpp:mam:0");
+		final Element query = packet.query("urn:xmpp:mam:0");
 		query.setAttribute("queryid",mam.getQueryId());
-		Data data = new Data();
+		final Data data = new Data();
 		data.setFormType("urn:xmpp:mam:0");
 		if (mam.getWith()!=null) {
 			data.put("with", mam.getWith().toString());
@@ -119,4 +117,25 @@ public class IqGenerator extends AbstractGenerator {
 		}
 		return packet;
 	}
+
+	public IqPacket generateGetBlockList() {
+		final IqPacket iq = new IqPacket(IqPacket.TYPE_GET);
+		iq.addChild("blocklist", Xmlns.BLOCKING);
+
+		return iq;
+	}
+
+	public IqPacket generateSetBlockRequest(final Jid jid) {
+		final IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
+		final Element block = iq.addChild("block", Xmlns.BLOCKING);
+		block.addChild("item").setAttribute("jid", jid.toBareJid().toString());
+		return iq;
+	}
+
+	public IqPacket generateSetUnblockRequest(final Jid jid) {
+		final IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
+		final Element block = iq.addChild("unblock", Xmlns.BLOCKING);
+		block.addChild("item").setAttribute("jid", jid.toBareJid().toString());
+		return iq;
+	}
 }
diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java
index ca5417e03..8e99888b5 100644
--- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java
@@ -114,7 +114,7 @@ public class MessageGenerator extends AbstractGenerator {
 	private MessagePacket generateError(MessagePacket origin) {
 		MessagePacket packet = new MessagePacket();
 		packet.setId(origin.getId());
-        packet.setTo(origin.getFrom());
+		packet.setTo(origin.getFrom());
 		packet.setBody(origin.getBody());
 		packet.setType(MessagePacket.TYPE_ERROR);
 		return packet;
@@ -135,7 +135,7 @@ public class MessageGenerator extends AbstractGenerator {
 			String subject) {
 		MessagePacket packet = new MessagePacket();
 		packet.setType(MessagePacket.TYPE_GROUPCHAT);
-		packet.setTo(conversation.getContactJid().toBareJid());
+		packet.setTo(conversation.getJid().toBareJid());
 		Element subjectChild = new Element("subject");
 		subjectChild.setContent(subject);
 		packet.addChild(subjectChild);
@@ -149,13 +149,13 @@ public class MessageGenerator extends AbstractGenerator {
 		packet.setTo(contact);
 		packet.setFrom(conversation.getAccount().getJid());
 		Element x = packet.addChild("x", "jabber:x:conference");
-		x.setAttribute("jid", conversation.getContactJid().toBareJid().toString());
+		x.setAttribute("jid", conversation.getJid().toBareJid().toString());
 		return packet;
 	}
 
 	public MessagePacket invite(Conversation conversation, Jid contact) {
 		MessagePacket packet = new MessagePacket();
-		packet.setTo(conversation.getContactJid().toBareJid());
+		packet.setTo(conversation.getJid().toBareJid());
 		packet.setFrom(conversation.getAccount().getJid());
 		Element x = new Element("x");
 		x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user");
@@ -170,7 +170,7 @@ public class MessageGenerator extends AbstractGenerator {
 			MessagePacket originalMessage, String namespace) {
 		MessagePacket receivedPacket = new MessagePacket();
 		receivedPacket.setType(MessagePacket.TYPE_NORMAL);
-        receivedPacket.setTo(originalMessage.getFrom());
+		receivedPacket.setTo(originalMessage.getFrom());
 		receivedPacket.setFrom(account.getJid());
 		Element received = receivedPacket.addChild("received", namespace);
 		received.setAttribute("id", originalMessage.getId());
diff --git a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java
index 39cbff4f1..8afc2ae0b 100644
--- a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java
@@ -53,10 +53,10 @@ public abstract class AbstractParser {
 
 	protected void updateLastseen(final Element packet, final Account account,
 			final boolean presenceOverwrite) {
-        Jid from = packet.getAttributeAsJid("from");
-        String presence = from == null || from.isBareJid() ? "" : from.getResourcepart();
-		Contact contact = account.getRoster().getContact(from);
-		long timestamp = getTimestamp(packet);
+		final Jid from = packet.getAttributeAsJid("from");
+		final String presence = from == null || from.isBareJid() ? "" : from.getResourcepart();
+		final Contact contact = account.getRoster().getContact(from);
+		final long timestamp = getTimestamp(packet);
 		if (timestamp >= contact.lastseen.time) {
 			contact.lastseen.time = timestamp;
 			if (!presence.isEmpty() && presenceOverwrite) {
diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java
index b583a1a14..b77d460d7 100644
--- a/src/main/java/eu/siacs/conversations/parser/IqParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java
@@ -2,36 +2,40 @@ package eu.siacs.conversations.parser;
 
 import android.util.Log;
 
+import java.util.ArrayList;
+import java.util.Collection;
+
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.utils.Xmlns;
 import eu.siacs.conversations.xml.Element;
 import eu.siacs.conversations.xmpp.OnIqPacketReceived;
-import eu.siacs.conversations.xmpp.jid.InvalidJidException;
+import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
 import eu.siacs.conversations.xmpp.jid.Jid;
 import eu.siacs.conversations.xmpp.stanzas.IqPacket;
 
 public class IqParser extends AbstractParser implements OnIqPacketReceived {
 
-	public IqParser(XmppConnectionService service) {
+	public IqParser(final XmppConnectionService service) {
 		super(service);
 	}
 
-	public void rosterItems(Account account, Element query) {
-		String version = query.getAttribute("ver");
+	public void rosterItems(final Account account, final Element query) {
+		final String version = query.getAttribute("ver");
 		if (version != null) {
 			account.getRoster().setVersion(version);
 		}
-		for (Element item : query.getChildren()) {
+		for (final Element item : query.getChildren()) {
 			if (item.getName().equals("item")) {
 				final Jid jid = item.getAttributeAsJid("jid");
 				if (jid == null) {
 					continue;
 				}
-				String name = item.getAttribute("name");
-				String subscription = item.getAttribute("subscription");
-				Contact contact = account.getRoster().getContact(jid);
+				final String name = item.getAttribute("name");
+				final String subscription = item.getAttribute("subscription");
+				final Contact contact = account.getRoster().getContact(jid);
 				if (!contact.getOption(Contact.Options.DIRTY_PUSH)) {
 					contact.setServerName(name);
 					contact.parseGroupsFromElement(item);
@@ -54,13 +58,13 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
 		mXmppConnectionService.updateRosterUi();
 	}
 
-	public String avatarData(IqPacket packet) {
-		Element pubsub = packet.findChild("pubsub",
+	public String avatarData(final IqPacket packet) {
+		final Element pubsub = packet.findChild("pubsub",
 				"http://jabber.org/protocol/pubsub");
 		if (pubsub == null) {
 			return null;
 		}
-		Element items = pubsub.findChild("items");
+		final Element items = pubsub.findChild("items");
 		if (items == null) {
 			return null;
 		}
@@ -68,13 +72,76 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
 	}
 
 	@Override
-	public void onIqPacketReceived(Account account, IqPacket packet) {
+	public void onIqPacketReceived(final Account account, final IqPacket packet) {
 		if (packet.hasChild("query", "jabber:iq:roster")) {
 			final Jid from = packet.getFrom();
 			if ((from == null) || (from.equals(account.getJid().toBareJid()))) {
-				Element query = packet.findChild("query");
+				final Element query = packet.findChild("query");
 				this.rosterItems(account, query);
 			}
+		}  else if (packet.hasChild("block", Xmlns.BLOCKING) || packet.hasChild("blocklist", Xmlns.BLOCKING)) {
+			// Only accept block list changes from the server.
+			// The server should probably prevent other people from faking a blocklist push,
+			// but just in case let's prevent it client side as well.
+			final Jid from = packet.getFrom();
+			if (from == null || from.equals(account.getServer()) || from.equals(account.getJid().toBareJid())) {
+				Log.d(Config.LOGTAG, "Received blocklist update from server");
+				final Element blocklist = packet.findChild("blocklist", Xmlns.BLOCKING);
+				final Element block = packet.findChild("block", Xmlns.BLOCKING);
+				final Collection<Element> items = blocklist != null ? blocklist.getChildren() :
+					(block != null ? block.getChildren() : null);
+				// If this is a response to a blocklist query, clear the block list and replace with the new one.
+				// Otherwise, just update the existing blocklist.
+				if (packet.getType() == IqPacket.TYPE_RESULT) {
+					account.clearBlocklist();
+				}
+				if (items != null) {
+					final Collection<Jid> jids = new ArrayList<>(items.size());
+					// Create a collection of Jids from the packet
+					for (final Element item : items) {
+						if (item.getName().equals("item")) {
+							final Jid jid = item.getAttributeAsJid("jid");
+							if (jid != null) {
+								jids.add(jid);
+							}
+						}
+					}
+					account.getBlocklist().addAll(jids);
+				}
+				// Update the UI
+				mXmppConnectionService.updateBlocklistUi(OnUpdateBlocklist.Status.BLOCKED);
+			} else {
+				Log.d(Config.LOGTAG, "Received blocklist update from invalid jid: " + from.toString());
+			}
+		} else if (packet.hasChild("unblock", Xmlns.BLOCKING)) {
+			final Jid from = packet.getFrom();
+			if ((from == null || from.equals(account.getServer()) || from.equals(account.getJid().toBareJid())) &&
+					packet.getType() == IqPacket.TYPE_SET) {
+				Log.d(Config.LOGTAG, "Received unblock update from server");
+				final Collection<Element> items = packet.getChildren().get(0).getChildren();
+				if (items.size() == 0) {
+					// No children to unblock == unblock all
+					account.getBlocklist().clear();
+				} else {
+					final Collection<Jid> jids = new ArrayList<>(items.size());
+					for (final Element item : items) {
+						if (item.getName().equals("item")) {
+							final Jid jid = item.getAttributeAsJid("jid");
+							if (jid != null) {
+								jids.add(jid);
+							}
+						}
+					}
+					account.getBlocklist().removeAll(jids);
+					mXmppConnectionService.updateBlocklistUi(OnUpdateBlocklist.Status.UNBLOCKED);
+				}
+			} else {
+				if (packet.getType() == IqPacket.TYPE_SET) {
+					Log.d(Config.LOGTAG, "Received unblock update from invalid jid " + from.toString());
+				} else {
+					Log.d(Config.LOGTAG, "Received unblock update with invalid type " + packet.getType());
+				}
+			}
 		} else {
 			if (packet.getFrom() == null) {
 				Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": received iq with invalid from "+packet.toString());
@@ -82,24 +149,24 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
 			} else if (packet.hasChild("open", "http://jabber.org/protocol/ibb")
 					|| packet.hasChild("data", "http://jabber.org/protocol/ibb")) {
 				mXmppConnectionService.getJingleConnectionManager()
-						.deliverIbbPacket(account, packet);
+					.deliverIbbPacket(account, packet);
 			} else if (packet.hasChild("query", "http://jabber.org/protocol/disco#info")) {
-				IqPacket response = mXmppConnectionService.getIqGenerator()
-						.discoResponse(packet);
+				final IqPacket response = mXmppConnectionService.getIqGenerator()
+					.discoResponse(packet);
 				account.getXmppConnection().sendIqPacket(response, null);
 			} else if (packet.hasChild("ping", "urn:xmpp:ping")) {
-				IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT);
+				final IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT);
 				mXmppConnectionService.sendIqPacket(account, response, null);
 			} else {
 				if ((packet.getType() == IqPacket.TYPE_GET)
 						|| (packet.getType() == IqPacket.TYPE_SET)) {
-					IqPacket response = packet.generateRespone(IqPacket.TYPE_ERROR);
-					Element error = response.addChild("error");
+					final IqPacket response = packet.generateRespone(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");
 					account.getXmppConnection().sendIqPacket(response, null);
-				}
+						}
 			}
 		}
 	}
diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
index aa07d9c03..7d29314bc 100644
--- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
+++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
@@ -228,9 +228,9 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 		return conversation;
 	}
 
-	public void updateConversation(Conversation conversation) {
-		SQLiteDatabase db = this.getWritableDatabase();
-		String[] args = { conversation.getUuid() };
+	public void updateConversation(final Conversation conversation) {
+		final SQLiteDatabase db = this.getWritableDatabase();
+		final String[] args = { conversation.getUuid() };
 		db.update(Conversation.TABLENAME, conversation.getContentValues(),
 				Conversation.UUID + "=?", args);
 	}
diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java
index 1a161c565..3fef5703c 100644
--- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java
+++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java
@@ -236,7 +236,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
 		public Query(Conversation conversation, long start, long end) {
 			this(conversation.getAccount(), start, end);
 			this.conversation = conversation;
-			this.with = conversation.getContactJid().toBareJid();
+			this.with = conversation.getJid().toBareJid();
 		}
 
 		public Query(Conversation conversation, long start, long end, PagingOrder order) {
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index dc3b3200f..65c631a1d 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -35,11 +35,13 @@ import org.openintents.openpgp.util.OpenPgpServiceConnection;
 import java.math.BigInteger;
 import java.security.SecureRandom;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import de.duenndns.ssl.MemorizingTrustManager;
@@ -47,11 +49,11 @@ import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.crypto.PgpEngine;
 import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Blockable;
 import eu.siacs.conversations.entities.Bookmark;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.Downloadable;
-import eu.siacs.conversations.entities.DownloadableFile;
 import eu.siacs.conversations.entities.DownloadablePlaceholder;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.entities.MucOptions;
@@ -77,7 +79,11 @@ import eu.siacs.conversations.xmpp.OnBindListener;
 import eu.siacs.conversations.xmpp.OnContactStatusChanged;
 import eu.siacs.conversations.xmpp.OnIqPacketReceived;
 import eu.siacs.conversations.xmpp.OnMessageAcknowledged;
+import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
+import eu.siacs.conversations.xmpp.OnPresencePacketReceived;
 import eu.siacs.conversations.xmpp.OnStatusChanged;
+import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
+import eu.siacs.conversations.xmpp.PacketReceived;
 import eu.siacs.conversations.xmpp.XmppConnection;
 import eu.siacs.conversations.xmpp.forms.Data;
 import eu.siacs.conversations.xmpp.forms.Field;
@@ -93,9 +99,10 @@ import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
 
 public class XmppConnectionService extends Service implements OnPhoneContactsLoadedListener {
 
-	public static String ACTION_CLEAR_NOTIFICATION = "clear_notification";
-	private static String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
-	public static String ACTION_DISABLE_FOREGROUND = "disable_foreground";
+	public static final String ACTION_CLEAR_NOTIFICATION = "clear_notification";
+	private static final String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
+	public static final String ACTION_DISABLE_FOREGROUND = "disable_foreground";
+
 	private ContentObserver contactObserver = new ContentObserver(null) {
 		@Override
 		public void onChange(boolean selfChange) {
@@ -129,13 +136,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 	private MemorizingTrustManager mMemorizingTrustManager;
 	private NotificationService mNotificationService = new NotificationService(
 			this);
-	private MessageParser mMessageParser = new MessageParser(this);
-	private PresenceParser mPresenceParser = new PresenceParser(this);
+	private OnMessagePacketReceived mMessageParser = new MessageParser(this);
+	private OnPresencePacketReceived mPresenceParser = new PresenceParser(this);
 	private IqParser mIqParser = new IqParser(this);
 	private MessageGenerator mMessageGenerator = new MessageGenerator(this);
 	private PresenceGenerator mPresenceGenerator = new PresenceGenerator(this);
 	private List<Account> accounts;
-	private final CopyOnWriteArrayList<Conversation> conversations = new CopyOnWriteArrayList<Conversation>();
+	private final List<Conversation> conversations = new CopyOnWriteArrayList<>();
 	private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(
 			this);
 	private HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager(
@@ -208,6 +215,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 
 	private int accountChangedListenerCount = 0;
 	private OnRosterUpdate mOnRosterUpdate = null;
+	private OnUpdateBlocklist mOnUpdateBlocklist = null;
+	private int updateBlocklistListenerCount = 0;
 	private int rosterChangedListenerCount = 0;
 	private OnMucRosterUpdate mOnMucRosterUpdate = null;
 	private int mucRosterChangedListenerCount = 0;
@@ -354,13 +363,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 			@Override
 			public void run() {
 				try {
-					DownloadableFile file = getFileBackend().copyImageToPrivateStorage(message, uri);
+					getFileBackend().copyImageToPrivateStorage(message, uri);
 					if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) {
 						getPgpEngine().encrypt(message, callback);
 					} else {
 						callback.success(message);
 					}
-				} catch (FileBackend.FileCopyException e) {
+				} catch (final FileBackend.FileCopyException e) {
 					callback.error(e.getResId(), message);
 				}
 			}
@@ -573,11 +582,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 
 	}
 
-	public XmppConnection createConnection(Account account) {
-		SharedPreferences sharedPref = getPreferences();
+	public XmppConnection createConnection(final Account account) {
+		final SharedPreferences sharedPref = getPreferences();
 		account.setResource(sharedPref.getString("resource", "mobile")
 				.toLowerCase(Locale.getDefault()));
-		XmppConnection connection = new XmppConnection(account, this);
+		final XmppConnection connection = new XmppConnection(account, this);
 		connection.setOnMessagePacketReceivedListener(this.mMessageParser);
 		connection.setOnStatusChangedListener(this.statusListener);
 		connection.setOnPresencePacketReceivedListener(this.mPresenceParser);
@@ -589,10 +598,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		return connection;
 	}
 
-	public void sendMessage(Message message) {
-		Account account = message.getConversation().getAccount();
+	public void sendMessage(final Message message) {
+		final Account account = message.getConversation().getAccount();
 		account.deactivateGracePeriod();
-		Conversation conv = message.getConversation();
+		final Conversation conv = message.getConversation();
 		MessagePacket packet = null;
 		boolean saveInDb = true;
 		boolean send = false;
@@ -694,7 +703,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		updateConversationUi();
 	}
 
-	private void sendUnsentMessages(Conversation conversation) {
+	private void sendUnsentMessages(final Conversation conversation) {
 		conversation.findWaitingMessages(new Conversation.OnMessageFound() {
 
 			@Override
@@ -704,7 +713,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		});
 	}
 
-	private void resendMessage(Message message) {
+	private void resendMessage(final Message message) {
 		Account account = message.getConversation().getAccount();
 		MessagePacket packet = null;
 		if (message.getEncryption() == Message.ENCRYPTION_OTR) {
@@ -731,7 +740,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 						} else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) {
 							mJingleConnectionManager.createNewConnection(message);
 						}
-					} catch (InvalidJidException e) {
+					} catch (final InvalidJidException ignored) {
 
 					}
 						}
@@ -774,8 +783,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		}
 	}
 
-	public void fetchRosterFromServer(Account account) {
-		IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
+	public void fetchRosterFromServer(final Account account) {
+		final IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
 		if (!"".equals(account.getRosterVersion())) {
 			Log.d(Config.LOGTAG, account.getJid().toBareJid()
 					+ ": fetching roster version " + account.getRosterVersion());
@@ -789,8 +798,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 
 					@Override
 					public void onIqPacketReceived(final Account account,
-												   IqPacket packet) {
-						Element query = packet.findChild("query");
+							final IqPacket packet) {
+						final Element query = packet.findChild("query");
 						if (query != null) {
 							account.getRoster().markAllAsNotInRoster();
 							mIqParser.rosterItems(account, query);
@@ -799,22 +808,22 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 				});
 	}
 
-	public void fetchBookmarks(Account account) {
-		IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
-		Element query = iqPacket.query("jabber:iq:private");
+	public void fetchBookmarks(final Account account) {
+		final IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
+		final Element query = iqPacket.query("jabber:iq:private");
 		query.addChild("storage", "storage:bookmarks");
-		OnIqPacketReceived callback = new OnIqPacketReceived() {
+		final PacketReceived callback = new OnIqPacketReceived() {
 
 			@Override
-			public void onIqPacketReceived(Account account, IqPacket packet) {
-				Element query = packet.query();
-				List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
-				Element storage = query.findChild("storage",
+			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 (Element item : storage.getChildren()) {
+					for (final Element item : storage.getChildren()) {
 						if (item.getName().equals("conference")) {
-							Bookmark bookmark = Bookmark.parse(item, account);
+							final Bookmark bookmark = Bookmark.parse(item, account);
 							bookmarks.add(bookmark);
 							Conversation conversation = find(bookmark);
 							if (conversation != null) {
@@ -832,7 +841,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 			}
 		};
 		sendIqPacket(account, iqPacket, callback);
-
 	}
 
 	public void pushBookmarks(Account account) {
@@ -868,8 +876,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 						}
 						final Contact contact = account.getRoster().getContact(jid);
 						String systemAccount = phoneContact.getInt("phoneid")
-								+ "#"
-								+ phoneContact.getString("lookup");
+							+ "#"
+							+ phoneContact.getString("lookup");
 						contact.setSystemAccount(systemAccount);
 						contact.setPhotoUri(phoneContact.getString("photouri"));
 						getAvatarService().clear(contact);
@@ -885,7 +893,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 
 	private void initConversations() {
 		synchronized (this.conversations) {
-			Hashtable<String, Account> accountLookupTable = new Hashtable<>();
+			final Map<String, Account> accountLookupTable = new Hashtable<>();
 			for (Account account : this.accounts) {
 				accountLookupTable.put(account.getUuid(), account);
 			}
@@ -992,8 +1000,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		return this.accounts;
 	}
 
-	public Conversation find(List<Conversation> haystack, Contact contact) {
-		for (Conversation conversation : haystack) {
+	public Conversation find(final Iterable<Conversation> haystack, final Contact contact) {
+		for (final Conversation conversation : haystack) {
 			if (conversation.getContact() == contact) {
 				return conversation;
 			}
@@ -1001,15 +1009,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		return null;
 	}
 
-	public Conversation find(final List<Conversation> haystack,
-			final Account account,
-			final Jid jid) {
+	public Conversation find(final Iterable<Conversation> haystack, final Account account, final Jid jid) {
 		if (jid == null ) {
 			return null;
 		}
-		for (Conversation conversation : haystack) {
+		for (final Conversation conversation : haystack) {
 			if ((account == null || conversation.getAccount() == account)
-					&& (conversation.getContactJid().toBareJid().equals(jid.toBareJid()))) {
+					&& (conversation.getJid().toBareJid().equals(jid.toBareJid()))) {
 				return conversation;
 					}
 		}
@@ -1177,7 +1183,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		}
 	}
 
-	public void setOnRosterUpdateListener(OnRosterUpdate listener) {
+	public void setOnRosterUpdateListener(final OnRosterUpdate listener) {
 		synchronized (this) {
 			if (checkListeners()) {
 				switchToForeground();
@@ -1202,6 +1208,31 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		}
 	}
 
+	public void setOnUpdateBlocklistListener(final OnUpdateBlocklist listener) {
+		synchronized (this) {
+			if (checkListeners()) {
+				switchToForeground();
+			}
+			this.mOnUpdateBlocklist = listener;
+			if (this.updateBlocklistListenerCount < 2) {
+				this.updateBlocklistListenerCount++;
+			}
+		}
+	}
+
+	public void removeOnUpdateBlocklistListener() {
+		synchronized (this) {
+			this.updateBlocklistListenerCount--;
+			if (this.updateBlocklistListenerCount <= 0) {
+				this.updateBlocklistListenerCount = 0;
+				this.mOnUpdateBlocklist = null;
+				if (checkListeners()) {
+					switchToBackground();
+				}
+			}
+		}
+	}
+
 	public void setOnMucRosterUpdateListener(OnMucRosterUpdate listener) {
 		synchronized (this) {
 			if (checkListeners()) {
@@ -1264,7 +1295,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 					&& (conversation.getAccount() == account)) {
 				conversation.resetMucOptions();
 				joinMuc(conversation);
-			}
+					}
 		}
 	}
 
@@ -1293,7 +1324,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 				packet.addChild("x", "jabber:x:signed").setContent(sig);
 			}
 			sendPresencePacket(account, packet);
-			if (!joinJid.equals(conversation.getContactJid())) {
+			if (!joinJid.equals(conversation.getJid())) {
 				conversation.setContactJid(joinJid);
 				databaseBackend.updateConversation(conversation);
 			}
@@ -1369,14 +1400,14 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		account.pendingConferenceLeaves.remove(conversation);
 		if (account.getStatus() == Account.State.ONLINE) {
 			PresencePacket packet = new PresencePacket();
-			packet.setTo(conversation.getContactJid());
+			packet.setTo(conversation.getJid());
 			packet.setFrom(conversation.getAccount().getJid());
 			packet.setAttribute("type", "unavailable");
 			sendPresencePacket(conversation.getAccount(), packet);
 			conversation.getMucOptions().setOffline();
 			conversation.deregisterWithBookmark();
 			Log.d(Config.LOGTAG, conversation.getAccount().getJid().toBareJid()
-					+ ": leaving muc " + conversation.getContactJid());
+					+ ": leaving muc " + conversation.getJid());
 		} else {
 			account.pendingConferenceLeaves.add(conversation);
 		}
@@ -1401,7 +1432,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		return null;
 	}
 
-	public void createAdhocConference(final Account account, final List<Jid> jids, final UiCallback<Conversation> callback) {
+	public void createAdhocConference(final Account account, final Iterable<Jid> jids, final UiCallback<Conversation> callback) {
 		Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": creating adhoc conference with "+ jids.toString());
 		if (account.getStatus() == Account.State.ONLINE) {
 			try {
@@ -1454,7 +1485,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 
 	public void pushConferenceConfiguration(final Conversation conversation,final Bundle options, final OnConferenceOptionsPushed callback) {
 		IqPacket request = new IqPacket(IqPacket.TYPE_GET);
-		request.setTo(conversation.getContactJid().toBareJid());
+		request.setTo(conversation.getJid().toBareJid());
 		request.query("http://jabber.org/protocol/muc#owner");
 		sendIqPacket(conversation.getAccount(),request,new OnIqPacketReceived() {
 			@Override
@@ -1468,7 +1499,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 					}
 					data.submit();
 					IqPacket set = new IqPacket(IqPacket.TYPE_SET);
-					set.setTo(conversation.getContactJid().toBareJid());
+					set.setTo(conversation.getJid().toBareJid());
 					set.query("http://jabber.org/protocol/muc#owner").addChild(data);
 					sendIqPacket(account, set, new OnIqPacketReceived() {
 						@Override
@@ -1506,7 +1537,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 							if (conversation.endOtrIfNeeded()) {
 								Log.d(Config.LOGTAG, account.getJid().toBareJid()
 										+ ": ended otr session with "
-										+ conversation.getContactJid());
+										+ conversation.getJid());
 							}
 						}
 					}
@@ -1552,8 +1583,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		final Session otrSession = conversation.getOtrSession();
 		Log.d(Config.LOGTAG,
 				account.getJid().toBareJid() + " otr session established with "
-						+ conversation.getContactJid() + "/"
-						+ otrSession.getSessionID().getUserID());
+				+ conversation.getJid() + "/"
+				+ otrSession.getSessionID().getUserID());
 		conversation.findUnsentMessagesWithOtrEncryption(new Conversation.OnMessageFound() {
 
 			@Override
@@ -1698,7 +1729,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 			@Override
 			public void onIqPacketReceived(Account account, IqPacket result) {
 				final String ERROR = account.getJid().toBareJid()
-						+ ": fetching avatar for " + avatar.owner + " failed ";
+					+ ": fetching avatar for " + avatar.owner + " failed ";
 				if (result.getType() == IqPacket.TYPE_RESULT) {
 					avatar.image = mIqParser.avatarData(result);
 					if (avatar.image != null) {
@@ -1712,7 +1743,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 								updateAccountUi();
 							} else {
 								Contact contact = account.getRoster()
-										.getContact(avatar.owner);
+									.getContact(avatar.owner);
 								contact.setAvatar(avatar.getFilename());
 								getAvatarService().clear(contact);
 								updateConversationUi();
@@ -1848,7 +1879,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 			return false;
 		} else {
 			for (Conversation conversation : getConversations()) {
-				if (conversation.getContactJid().equals(recipient)
+				if (conversation.getJid().equals(recipient)
 						&& conversation.getAccount().equals(account)) {
 					return markMessage(conversation, uuid, status);
 						}
@@ -1922,6 +1953,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		}
 	}
 
+	public void updateBlocklistUi(final OnUpdateBlocklist.Status status) {
+		if (mOnUpdateBlocklist != null) {
+			mOnUpdateBlocklist.OnUpdateBlocklist(status);
+		}
+	}
+
 	public void updateMucRosterUi() {
 		if (mOnMucRosterUpdate != null) {
 			mOnMucRosterUpdate.onMucRosterUpdate();
@@ -2034,9 +2071,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		}
 	}
 
-	public void sendIqPacket(Account account, IqPacket packet,
-			OnIqPacketReceived callback) {
-		XmppConnection connection = account.getXmppConnection();
+	public void sendIqPacket(final Account account, final IqPacket packet, final PacketReceived callback) {
+		final XmppConnection connection = account.getXmppConnection();
 		if (connection != null) {
 			connection.sendIqPacket(packet, callback);
 		}
@@ -2054,6 +2090,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		return this.mIqGenerator;
 	}
 
+	public IqParser getIqParser() { return this.mIqParser; }
+
 	public JingleConnectionManager getJingleConnectionManager() {
 		return this.mJingleConnectionManager;
 	}
@@ -2083,8 +2121,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		return this.mHttpConnectionManager;
 	}
 
-	public void resendFailedMessages(Message message) {
-		List<Message> messages = new ArrayList<>();
+	public void resendFailedMessages(final Message message) {
+		final Collection<Message> messages = new ArrayList<>();
 		Message current = message;
 		while (current.getStatus() == Message.STATUS_SEND_FAILED) {
 			messages.add(current);
@@ -2094,7 +2132,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 				break;
 			}
 		}
-		for (Message msg : messages) {
+		for (final Message msg : messages) {
 			markMessage(msg, Message.STATUS_WAITING);
 			this.resendMessage(msg);
 		}
@@ -2136,4 +2174,35 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 			return XmppConnectionService.this;
 		}
 	}
+
+	public void sendBlockRequest(final Blockable blockable) {
+		if (blockable != null && blockable.getBlockedJid() != null) {
+			final Jid jid = blockable.getBlockedJid();
+			this.sendIqPacket(blockable.getAccount(), getIqGenerator().generateSetBlockRequest(jid), new OnIqPacketReceived() {
+
+				@Override
+				public void onIqPacketReceived(final Account account, final IqPacket packet) {
+					if (packet.getType() == IqPacket.TYPE_RESULT) {
+						account.getBlocklist().add(jid);
+						updateBlocklistUi(OnUpdateBlocklist.Status.BLOCKED);
+					}
+				}
+			});
+		}
+	}
+
+	public void sendUnblockRequest(final Blockable blockable) {
+		if (blockable != null && blockable.getJid() != null) {
+			final Jid jid = blockable.getBlockedJid();
+			this.sendIqPacket(blockable.getAccount(), getIqGenerator().generateSetUnblockRequest(jid), new OnIqPacketReceived() {
+				@Override
+				public void onIqPacketReceived(final Account account, final IqPacket packet) {
+					if (packet.getType() == IqPacket.TYPE_RESULT) {
+						account.getBlocklist().remove(jid);
+						updateBlocklistUi(OnUpdateBlocklist.Status.UNBLOCKED);
+					}
+				}
+			});
+		}
+	}
 }
diff --git a/src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java b/src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java
new file mode 100644
index 000000000..1a9fc95c2
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java
@@ -0,0 +1,124 @@
+package eu.siacs.conversations.ui;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.ListView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.ListItem;
+import eu.siacs.conversations.ui.adapter.ListItemAdapter;
+
+public abstract class AbstractSearchableListItemActivity extends XmppActivity {
+	private ListView mListView;
+	private final List<ListItem> listItems = new ArrayList<>();
+	private ArrayAdapter<ListItem> mListItemsAdapter;
+
+	private EditText mSearchEditText;
+
+	private final MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
+
+		@Override
+		public boolean onMenuItemActionExpand(final MenuItem item) {
+			mSearchEditText.post(new Runnable() {
+
+				@Override
+				public void run() {
+					mSearchEditText.requestFocus();
+					final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+					imm.showSoftInput(mSearchEditText,
+							InputMethodManager.SHOW_IMPLICIT);
+				}
+			});
+
+			return true;
+		}
+
+		@Override
+		public boolean onMenuItemActionCollapse(final MenuItem item) {
+			final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+			imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
+					InputMethodManager.HIDE_IMPLICIT_ONLY);
+			mSearchEditText.setText("");
+			filterContacts();
+			return true;
+		}
+	};
+
+	private final TextWatcher mSearchTextWatcher = new TextWatcher() {
+
+		@Override
+		public void afterTextChanged(final Editable editable) {
+			filterContacts(editable.toString());
+		}
+
+		@Override
+		public void beforeTextChanged(final CharSequence s, final int start, final int count,
+				final int after) {
+		}
+
+		@Override
+		public void onTextChanged(final CharSequence s, final int start, final int before,
+				final int count) {
+		}
+	};
+
+	public ListView getListView() {
+		return mListView;
+	}
+
+	public List<ListItem> getListItems() {
+		return listItems;
+	}
+
+	public EditText getSearchEditText() {
+		return mSearchEditText;
+	}
+
+	public ArrayAdapter<ListItem> getListItemAdapter() {
+		return mListItemsAdapter;
+	}
+
+	@Override
+	public void onCreate(final Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.activity_choose_contact);
+		mListView = (ListView) findViewById(R.id.choose_contact_list);
+		mListView.setFastScrollEnabled(true);
+		mListItemsAdapter = new ListItemAdapter(this, listItems);
+		mListView.setAdapter(mListItemsAdapter);
+	}
+
+	@Override
+	public boolean onCreateOptionsMenu(final Menu menu) {
+		getMenuInflater().inflate(R.menu.choose_contact, menu);
+		final MenuItem menuSearchView = menu.findItem(R.id.action_search);
+		final View mSearchView = menuSearchView.getActionView();
+		mSearchEditText = (EditText) mSearchView
+			.findViewById(R.id.search_field);
+		mSearchEditText.addTextChangedListener(mSearchTextWatcher);
+		menuSearchView.setOnActionExpandListener(mOnActionExpandListener);
+		return true;
+	}
+
+	protected void filterContacts() {
+		filterContacts(null);
+	}
+
+	protected abstract void filterContacts(final String needle);
+
+	@Override
+	void onBackendConnected() {
+		filterContacts();
+	}
+}
diff --git a/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java b/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java
new file mode 100644
index 000000000..9cf7e9f85
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java
@@ -0,0 +1,41 @@
+package eu.siacs.conversations.ui;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Blockable;
+import eu.siacs.conversations.services.XmppConnectionService;
+
+public final class BlockContactDialog {
+	public static void show(final Context context,
+			final XmppConnectionService xmppConnectionService,
+			final Blockable blockable) {
+		final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+		final boolean isBlocked = blockable.isBlocked();
+		builder.setNegativeButton(R.string.cancel, null);
+
+		if (blockable.getJid().isDomainJid() || blockable.getAccount().isBlocked(blockable.getJid().toDomainJid())) {
+			builder.setTitle(isBlocked ? R.string.action_unblock_domain : R.string.action_block_domain);
+			builder.setMessage(context.getResources().getString(isBlocked ? R.string.unblock_domain_text : R.string.block_domain_text,
+						blockable.getJid().toDomainJid()));
+		} else {
+			builder.setTitle(isBlocked ? R.string.action_unblock_contact : R.string.action_block_contact);
+			builder.setMessage(context.getResources().getString(isBlocked ? R.string.unblock_contact_text : R.string.block_contact_text,
+						blockable.getJid().toBareJid()));
+		}
+		builder.setPositiveButton(isBlocked ? R.string.unblock : R.string.block, new DialogInterface.OnClickListener() {
+
+			@Override
+			public void onClick(final DialogInterface dialog, final int which) {
+				if (isBlocked) {
+					xmppConnectionService.sendUnblockRequest(blockable);
+				} else {
+					xmppConnectionService.sendBlockRequest(blockable);
+				}
+			}
+		});
+		builder.create().show();
+	}
+}
diff --git a/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java b/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java
new file mode 100644
index 000000000..13d7f4fc8
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java
@@ -0,0 +1,75 @@
+package eu.siacs.conversations.ui;
+
+import android.os.Bundle;
+import android.text.Editable;
+import android.view.View;
+import android.widget.AdapterView;
+
+import java.util.Collections;
+
+import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Contact;
+import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
+import eu.siacs.conversations.xmpp.jid.Jid;
+
+public class BlocklistActivity extends AbstractSearchableListItemActivity implements OnUpdateBlocklist {
+
+	private Account account = null;
+
+	@Override
+	public void onCreate(final Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
+
+			@Override
+			public boolean onItemLongClick(final AdapterView<?> parent,
+					final View view,
+					final int position,
+					final long id) {
+				BlockContactDialog.show(parent.getContext(), xmppConnectionService,(Contact) getListItems().get(position));
+				return true;
+			}
+		});
+	}
+
+	@Override
+	public void onBackendConnected() {
+		for (final Account account : xmppConnectionService.getAccounts()) {
+			if (account.getJid().toString().equals(getIntent().getStringExtra("account"))) {
+				this.account = account;
+				break;
+			}
+		}
+		filterContacts();
+	}
+
+	@Override
+	protected void filterContacts(final String needle) {
+		getListItems().clear();
+		if (account != null) {
+			for (final Jid jid : account.getBlocklist()) {
+				final Contact contact = account.getRoster().getContact(jid);
+				if (contact.match(needle) && contact.isBlocked()) {
+					getListItems().add(contact);
+				}
+			}
+			Collections.sort(getListItems());
+		}
+		runOnUiThread(new Runnable() {
+			@Override
+			public void run() {
+				getListItemAdapter().notifyDataSetChanged();
+			}
+		});
+	}
+
+	@Override
+	public void OnUpdateBlocklist(final OnUpdateBlocklist.Status status) {
+		final Editable editable = getSearchEditText().getText();
+		if (editable != null) {
+			filterContacts(editable.toString());
+		} else {
+			filterContacts();
+		}
+	}
+}
diff --git a/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java b/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java
index e7254933e..70b353c6b 100644
--- a/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java
@@ -1,101 +1,33 @@
 package eu.siacs.conversations.ui;
 
-import java.util.ArrayList;
-import java.util.Collections;
-
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.view.Menu;
-import android.view.MenuItem;
 import android.view.View;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.EditText;
-import android.widget.ListView;
-import eu.siacs.conversations.R;
+
+import java.util.Collections;
+
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.ListItem;
-import eu.siacs.conversations.ui.adapter.ListItemAdapter;
-
-public class ChooseContactActivity extends XmppActivity {
-
-	private ListView mListView;
-	private ArrayList<ListItem> contacts = new ArrayList<>();
-	private ArrayAdapter<ListItem> mContactsAdapter;
-
-	private EditText mSearchEditText;
-
-	private TextWatcher mSearchTextWatcher = new TextWatcher() {
-
-		@Override
-		public void afterTextChanged(Editable editable) {
-			filterContacts(editable.toString());
-		}
-
-		@Override
-		public void beforeTextChanged(CharSequence s, int start, int count,
-				int after) {
-		}
-
-		@Override
-		public void onTextChanged(CharSequence s, int start, int before,
-				int count) {
-		}
-	};
-
-	private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
-
-		@Override
-		public boolean onMenuItemActionExpand(MenuItem item) {
-			mSearchEditText.post(new Runnable() {
-
-				@Override
-				public void run() {
-					mSearchEditText.requestFocus();
-					InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
-					imm.showSoftInput(mSearchEditText,
-							InputMethodManager.SHOW_IMPLICIT);
-				}
-			});
-
-			return true;
-		}
-
-		@Override
-		public boolean onMenuItemActionCollapse(MenuItem item) {
-			InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
-			imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
-					InputMethodManager.HIDE_IMPLICIT_ONLY);
-			mSearchEditText.setText("");
-			filterContacts(null);
-			return true;
-		}
-	};
 
+public class ChooseContactActivity extends AbstractSearchableListItemActivity {
 	@Override
-	public void onCreate(Bundle savedInstanceState) {
+	public void onCreate(final Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
-		setContentView(R.layout.activity_choose_contact);
-		mListView = (ListView) findViewById(R.id.choose_contact_list);
-		mListView.setFastScrollEnabled(true);
-		mContactsAdapter = new ListItemAdapter(this, contacts);
-		mListView.setAdapter(mContactsAdapter);
-		mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+		getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
 
 			@Override
-			public void onItemClick(AdapterView<?> arg0, View arg1,
-					int position, long arg3) {
-				InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
-				imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
+			public void onItemClick(final AdapterView<?> parent, final View view,
+					final int position, final long id) {
+				final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+				imm.hideSoftInputFromWindow(getSearchEditText().getWindowToken(),
 						InputMethodManager.HIDE_IMPLICIT_ONLY);
-				Intent request = getIntent();
-				Intent data = new Intent();
-				ListItem mListItem = contacts.get(position);
+				final Intent request = getIntent();
+				final Intent data = new Intent();
+				final ListItem mListItem = getListItems().get(position);
 				data.putExtra("contact", mListItem.getJid().toString());
 				String account = request.getStringExtra("account");
 				if (account == null && mListItem instanceof Contact) {
@@ -108,38 +40,21 @@ public class ChooseContactActivity extends XmppActivity {
 				finish();
 			}
 		});
+
 	}
 
-	@Override
-	public boolean onCreateOptionsMenu(Menu menu) {
-		getMenuInflater().inflate(R.menu.choose_contact, menu);
-		MenuItem menuSearchView = menu.findItem(R.id.action_search);
-		View mSearchView = menuSearchView.getActionView();
-		mSearchEditText = (EditText) mSearchView
-				.findViewById(R.id.search_field);
-		mSearchEditText.addTextChangedListener(mSearchTextWatcher);
-		menuSearchView.setOnActionExpandListener(mOnActionExpandListener);
-		return true;
-	}
-
-	@Override
-	void onBackendConnected() {
-		filterContacts(null);
-	}
-
-	protected void filterContacts(String needle) {
-		this.contacts.clear();
-		for (Account account : xmppConnectionService.getAccounts()) {
+	protected void filterContacts(final String needle) {
+		getListItems().clear();
+		for (final Account account : xmppConnectionService.getAccounts()) {
 			if (account.getStatus() != Account.State.DISABLED) {
-				for (Contact contact : account.getRoster().getContacts()) {
+				for (final Contact contact : account.getRoster().getContacts()) {
 					if (contact.showInRoster() && contact.match(needle)) {
-						this.contacts.add(contact);
+						getListItems().add(contact);
 					}
 				}
 			}
 		}
-		Collections.sort(this.contacts);
-		mContactsAdapter.notifyDataSetChanged();
+		Collections.sort(getListItems());
+		getListItemAdapter().notifyDataSetChanged();
 	}
-
 }
diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
index 2e36c5450..eeb015f33 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
@@ -157,8 +157,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
 						@Override
 						public void onValueEdited(String value) {
 							MessagePacket packet = xmppConnectionService
-									.getMessageGenerator().conferenceSubject(
-											mConversation, value);
+								.getMessageGenerator().conferenceSubject(
+										mConversation, value);
 							xmppConnectionService.sendMessagePacket(
 									mConversation.getAccount(), packet);
 						}
@@ -191,7 +191,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
 	@Override
 	protected String getShareableUri() {
 		if (mConversation != null) {
-			return "xmpp:" + mConversation.getContactJid().toBareJid().toString() + "?join";
+			return "xmpp:" + mConversation.getJid().toBareJid().toString() + "?join";
 		} else {
 			return "";
 		}
@@ -202,7 +202,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
 		MenuItem menuItemSaveBookmark = menu.findItem(R.id.action_save_as_bookmark);
 		MenuItem menuItemDeleteBookmark = menu.findItem(R.id.action_delete_bookmark);
 		Account account = mConversation.getAccount();
-		if (account.hasBookmarkFor(mConversation.getContactJid().toBareJid())) {
+		if (account.hasBookmarkFor(mConversation.getJid().toBareJid())) {
 			menuItemSaveBookmark.setVisible(false);
 			menuItemDeleteBookmark.setVisible(true);
 		} else {
@@ -263,9 +263,9 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
 
 	protected void saveAsBookmark() {
 		Account account = mConversation.getAccount();
-		Bookmark bookmark = new Bookmark(account, mConversation.getContactJid().toBareJid());
-		if (!mConversation.getContactJid().isBareJid()) {
-			bookmark.setNick(mConversation.getContactJid().getResourcepart());
+		Bookmark bookmark = new Bookmark(account, mConversation.getJid().toBareJid());
+		if (!mConversation.getJid().isBareJid()) {
+			bookmark.setNick(mConversation.getJid().getResourcepart());
 		}
 		bookmark.setAutojoin(true);
 		account.getBookmarks().add(bookmark);
@@ -288,7 +288,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
 		}
 		if (uuid != null) {
 			this.mConversation = xmppConnectionService
-					.findConversationByUuid(uuid);
+				.findConversationByUuid(uuid);
 			if (this.mConversation != null) {
 				populateView();
 			}
@@ -297,11 +297,11 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
 
 	private void populateView() {
 		mAccountJid.setText(getString(R.string.using_account, mConversation
-				.getAccount().getJid().toBareJid()));
+					.getAccount().getJid().toBareJid()));
 		mYourPhoto.setImageBitmap(avatarService().get(
-				mConversation.getAccount(), getPixel(48)));
+					mConversation.getAccount(), getPixel(48)));
 		setTitle(mConversation.getName());
-		mFullJid.setText(mConversation.getContactJid().toBareJid().toString());
+		mFullJid.setText(mConversation.getJid().toBareJid().toString());
 		mYourNick.setText(mConversation.getMucOptions().getActualNick());
 		mRoleAffiliaton = (TextView) findViewById(R.id.muc_role);
 		if (mConversation.getMucOptions().online()) {
@@ -338,7 +338,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
 			registerForContextMenu(view);
 			view.setTag(user);
 			TextView name = (TextView) view
-					.findViewById(R.id.contact_display_name);
+				.findViewById(R.id.contact_display_name);
 			TextView key = (TextView) view.findViewById(R.id.key);
 			TextView role = (TextView) view.findViewById(R.id.contact_jid);
 			if (user.getPgpKeyId() != 0) {
diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
index 4259371ac..b195f2f10 100644
--- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
@@ -38,10 +38,11 @@ import eu.siacs.conversations.entities.ListItem;
 import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
 import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
 import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
 import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 import eu.siacs.conversations.xmpp.jid.Jid;
 
-public class ContactDetailsActivity extends XmppActivity implements OnAccountUpdate, OnRosterUpdate {
+public class ContactDetailsActivity extends XmppActivity implements OnAccountUpdate, OnRosterUpdate, OnUpdateBlocklist {
 	public static final String ACTION_VIEW_CONTACT = "view_contact";
 
 	private Contact contact;
@@ -50,7 +51,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 		@Override
 		public void onClick(DialogInterface dialog, int which) {
 			ContactDetailsActivity.this.xmppConnectionService
-					.deleteContactOnServer(contact);
+				.deleteContactOnServer(contact);
 			ContactDetailsActivity.this.finish();
 		}
 	};
@@ -58,14 +59,14 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 
 		@Override
 		public void onCheckedChanged(CompoundButton buttonView,
-									 boolean isChecked) {
+				boolean isChecked) {
 			if (isChecked) {
 				if (contact
 						.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
 					xmppConnectionService.sendPresencePacket(contact
-									.getAccount(),
+							.getAccount(),
 							xmppConnectionService.getPresenceGenerator()
-									.sendPresenceUpdatesTo(contact));
+							.sendPresenceUpdatesTo(contact));
 				} else {
 					contact.setOption(Contact.Options.PREEMPTIVE_GRANT);
 				}
@@ -73,7 +74,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 				contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
 				xmppConnectionService.sendPresencePacket(contact.getAccount(),
 						xmppConnectionService.getPresenceGenerator()
-								.stopPresenceUpdatesTo(contact));
+						.stopPresenceUpdatesTo(contact));
 			}
 		}
 	};
@@ -81,15 +82,15 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 
 		@Override
 		public void onCheckedChanged(CompoundButton buttonView,
-									 boolean isChecked) {
+				boolean isChecked) {
 			if (isChecked) {
 				xmppConnectionService.sendPresencePacket(contact.getAccount(),
 						xmppConnectionService.getPresenceGenerator()
-								.requestPresenceUpdatesFrom(contact));
+						.requestPresenceUpdatesFrom(contact));
 			} else {
 				xmppConnectionService.sendPresencePacket(contact.getAccount(),
 						xmppConnectionService.getPresenceGenerator()
-								.stopPresenceUpdatesFrom(contact));
+						.stopPresenceUpdatesFrom(contact));
 			}
 		}
 	};
@@ -127,7 +128,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 					ContactDetailsActivity.this);
 			builder.setTitle(getString(R.string.action_add_phone_book));
 			builder.setMessage(getString(R.string.add_phone_book_text,
-					contact.getJid()));
+						contact.getJid()));
 			builder.setNegativeButton(getString(R.string.cancel), null);
 			builder.setPositiveButton(getString(R.string.add), addToPhonebook);
 			builder.create().show();
@@ -166,7 +167,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 	}
 
 	@Override
-	protected void onCreate(Bundle savedInstanceState) {
+	protected void onCreate(final Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
 		if (getIntent().getAction().equals(ACTION_VIEW_CONTACT)) {
 			try {
@@ -188,15 +189,17 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 		badge = (QuickContactBadge) findViewById(R.id.details_contact_badge);
 		keys = (LinearLayout) findViewById(R.id.details_contact_keys);
 		tags = (LinearLayout) findViewById(R.id.tags);
-		getActionBar().setHomeButtonEnabled(true);
-		getActionBar().setDisplayHomeAsUpEnabled(true);
+		if (getActionBar() != null) {
+			getActionBar().setHomeButtonEnabled(true);
+			getActionBar().setDisplayHomeAsUpEnabled(true);
+		}
 
-		SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
+		final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
 		this.showDynamicTags = preferences.getBoolean("show_dynamic_tags",false);
 	}
 
 	@Override
-	public boolean onOptionsItemSelected(MenuItem menuItem) {
+	public boolean onOptionsItemSelected(final MenuItem menuItem) {
 		AlertDialog.Builder builder = new AlertDialog.Builder(this);
 		builder.setNegativeButton(getString(R.string.cancel), null);
 		switch (menuItem.getItemId()) {
@@ -205,11 +208,11 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 				break;
 			case R.id.action_delete_contact:
 				builder.setTitle(getString(R.string.action_delete_contact))
-						.setMessage(
-								getString(R.string.remove_contact_text,
-										contact.getJid()))
-						.setPositiveButton(getString(R.string.delete),
-								removeFromRoster).create().show();
+					.setMessage(
+							getString(R.string.remove_contact_text,
+								contact.getJid()))
+					.setPositiveButton(getString(R.string.delete),
+							removeFromRoster).create().show();
 				break;
 			case R.id.action_edit_contact:
 				if (contact.getSystemAccount() == null) {
@@ -219,7 +222,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 						public void onValueEdited(String value) {
 							contact.setServerName(value);
 							ContactDetailsActivity.this.xmppConnectionService
-									.pushContactToServer(contact);
+								.pushContactToServer(contact);
 							populateView();
 						}
 					});
@@ -285,7 +288,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 		receive.setOnCheckedChangeListener(this.mOnReceiveCheckedChange);
 
 		lastseen.setText(UIHelper.lastseen(getApplicationContext(),
-				contact.lastseen.time));
+					contact.lastseen.time));
 
 		if (contact.getPresences().size() > 1) {
 			contactJidTv.setText(contact.getJid() + " ("
@@ -294,7 +297,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 			contactJidTv.setText(contact.getJid().toString());
 		}
 		accountJidTv.setText(getString(R.string.using_account, contact
-				.getAccount().getJid().toBareJid()));
+					.getAccount().getJid().toBareJid()));
 		prepareContactBadge(badge, contact);
 		if (contact.getSystemAccount() == null) {
 			badge.setOnClickListener(onBadgeClick);
@@ -309,7 +312,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 			TextView key = (TextView) view.findViewById(R.id.key);
 			TextView keyType = (TextView) view.findViewById(R.id.key_type);
 			ImageButton remove = (ImageButton) view
-					.findViewById(R.id.button_remove);
+				.findViewById(R.id.button_remove);
 			remove.setVisibility(View.VISIBLE);
 			keyType.setText("OTR Fingerprint");
 			key.setText(otrFingerprint);
@@ -334,7 +337,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 				@Override
 				public void onClick(View v) {
 					PgpEngine pgp = ContactDetailsActivity.this.xmppConnectionService
-							.getPgpEngine();
+						.getPgpEngine();
 					if (pgp != null) {
 						PendingIntent intent = pgp.getIntentForKey(contact);
 						if (intent != null) {
@@ -363,8 +366,8 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 		} else {
 			tags.setVisibility(View.VISIBLE);
 			tags.removeAllViewsInLayout();
-			for(ListItem.Tag tag : tagList) {
-				TextView tv = (TextView) inflater.inflate(R.layout.list_item_tag,tags,false);
+			for(final ListItem.Tag tag : tagList) {
+				final TextView tv = (TextView) inflater.inflate(R.layout.list_item_tag,tags,false);
 				tv.setText(tag.getName());
 				tv.setBackgroundColor(tag.getColor());
 				tags.addView(tv);
@@ -406,7 +409,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 	public void onBackendConnected() {
 		if ((accountJid != null) && (contactJid != null)) {
 			Account account = xmppConnectionService
-					.findAccountByJid(accountJid);
+				.findAccountByJid(accountJid);
 			if (account == null) {
 				return;
 			}
@@ -414,4 +417,15 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 			populateView();
 		}
 	}
+
+	@Override
+	public void OnUpdateBlocklist(final Status status) {
+		runOnUiThread(new Runnable() {
+
+			@Override
+			public void run() {
+				populateView();
+			}
+		});
+	}
 }
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
index 6656de2b3..3a3f0778d 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
@@ -15,7 +15,6 @@ import android.os.SystemClock;
 import android.provider.MediaStore;
 import android.support.v4.widget.SlidingPaneLayout;
 import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener;
-import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
@@ -32,6 +31,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Blockable;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.Message;
@@ -40,9 +40,10 @@ import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdat
 import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
 import eu.siacs.conversations.ui.adapter.ConversationAdapter;
 import eu.siacs.conversations.utils.ExceptionHelper;
+import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
 
-public class ConversationActivity extends XmppActivity implements
-		OnAccountUpdate, OnConversationUpdate, OnRosterUpdate {
+public class ConversationActivity extends XmppActivity
+	implements OnAccountUpdate, OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist {
 
 	public static final String VIEW_CONVERSATION = "viewConversation";
 	public static final String CONVERSATION = "conversationUuid";
@@ -144,12 +145,12 @@ public class ConversationActivity extends XmppActivity implements
 	protected void onCreate(Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
 		if (savedInstanceState != null) {mOpenConverstaion = savedInstanceState.getString(
-					STATE_OPEN_CONVERSATION, null);
-			mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true);
-			String pending = savedInstanceState.getString(STATE_PENDING_URI, null);
-			if (pending != null) {
-				mPendingImageUri = Uri.parse(pending);
-			}
+				STATE_OPEN_CONVERSATION, null);
+		mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true);
+		String pending = savedInstanceState.getString(STATE_PENDING_URI, null);
+		if (pending != null) {
+			mPendingImageUri = Uri.parse(pending);
+		}
 		}
 
 		setContentView(R.layout.fragment_conversations_overview);
@@ -172,7 +173,7 @@ public class ConversationActivity extends XmppActivity implements
 
 			@Override
 			public void onItemClick(AdapterView<?> arg0, View clickedView,
-									int position, long arg3) {
+					int position, long arg3) {
 				if (getSelectedConversation() != conversationList.get(position)) {
 					setSelectedConversation(conversationList.get(position));
 					ConversationActivity.this.mConversationFragment.reInit(getSelectedConversation());
@@ -188,7 +189,7 @@ public class ConversationActivity extends XmppActivity implements
 			SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
 			mSlidingPaneLayout.setParallaxDistance(150);
 			mSlidingPaneLayout
-					.setShadowResource(R.drawable.es_slidingpane_shadow);
+				.setShadowResource(R.drawable.es_slidingpane_shadow);
 			mSlidingPaneLayout.setSliderFadeColor(0);
 			mSlidingPaneLayout.setPanelSlideListener(new PanelSlideListener() {
 
@@ -199,7 +200,7 @@ public class ConversationActivity extends XmppActivity implements
 					hideKeyboard();
 					if (xmppConnectionServiceBound) {
 						xmppConnectionService.getNotificationService()
-								.setOpenConversation(null);
+							.setOpenConversation(null);
 					}
 					closeContextMenu();
 				}
@@ -244,7 +245,7 @@ public class ConversationActivity extends XmppActivity implements
 				if (conversation.getMode() == Conversation.MODE_SINGLE || useSubjectToIdentifyConference()) {
 					ab.setTitle(conversation.getName());
 				} else {
-					ab.setTitle(conversation.getContactJid().toBareJid().toString());
+					ab.setTitle(conversation.getJid().toBareJid().toString());
 				}
 			} else {
 				ab.setDisplayHomeAsUpEnabled(false);
@@ -269,17 +270,18 @@ public class ConversationActivity extends XmppActivity implements
 	@Override
 	public boolean onCreateOptionsMenu(Menu menu) {
 		getMenuInflater().inflate(R.menu.conversations, menu);
-		MenuItem menuSecure = menu.findItem(R.id.action_security);
-		MenuItem menuArchive = menu.findItem(R.id.action_archive);
-		MenuItem menuMucDetails = menu.findItem(R.id.action_muc_details);
-		MenuItem menuContactDetails = menu
-				.findItem(R.id.action_contact_details);
-		MenuItem menuAttach = menu.findItem(R.id.action_attach_file);
-		MenuItem menuClearHistory = menu.findItem(R.id.action_clear_history);
-		MenuItem menuAdd = menu.findItem(R.id.action_add);
-		MenuItem menuInviteContact = menu.findItem(R.id.action_invite);
-		MenuItem menuMute = menu.findItem(R.id.action_mute);
-		MenuItem menuUnmute = menu.findItem(R.id.action_unmute);
+		final MenuItem menuSecure = menu.findItem(R.id.action_security);
+		final MenuItem menuArchive = menu.findItem(R.id.action_archive);
+		final MenuItem menuMucDetails = menu.findItem(R.id.action_muc_details);
+		final MenuItem menuContactDetails = menu.findItem(R.id.action_contact_details);
+		final MenuItem menuAttach = menu.findItem(R.id.action_attach_file);
+		final MenuItem menuClearHistory = menu.findItem(R.id.action_clear_history);
+		final MenuItem menuAdd = menu.findItem(R.id.action_add);
+		final MenuItem menuInviteContact = menu.findItem(R.id.action_invite);
+		final MenuItem menuMute = menu.findItem(R.id.action_mute);
+		final MenuItem menuUnmute = menu.findItem(R.id.action_unmute);
+		final MenuItem menuBlock = menu.findItem(R.id.action_block);
+		final MenuItem menuUnblock = menu.findItem(R.id.action_unblock);
 
 		if (isConversationsOverviewVisable()
 				&& isConversationsOverviewHideable()) {
@@ -292,19 +294,32 @@ public class ConversationActivity extends XmppActivity implements
 			menuClearHistory.setVisible(false);
 			menuMute.setVisible(false);
 			menuUnmute.setVisible(false);
+			menuBlock.setVisible(false);
+			menuUnblock.setVisible(false);
 		} else {
 			menuAdd.setVisible(!isConversationsOverviewHideable());
 			if (this.getSelectedConversation() != null) {
 				if (this.getSelectedConversation().getLatestMessage()
 						.getEncryption() != Message.ENCRYPTION_NONE) {
 					menuSecure.setIcon(R.drawable.ic_action_secure);
-				}
+						}
 				if (this.getSelectedConversation().getMode() == Conversation.MODE_MULTI) {
 					menuContactDetails.setVisible(false);
 					menuAttach.setVisible(false);
+					menuBlock.setVisible(false);
+					menuUnblock.setVisible(false);
 				} else {
 					menuMucDetails.setVisible(false);
 					menuInviteContact.setTitle(R.string.conference_with);
+					if (this.getSelectedConversation().isBlocked()) {
+						menuBlock.setVisible(false);
+					} else {
+						menuUnblock.setVisible(false);
+					}
+					if (!this.getSelectedConversation().getAccount().getXmppConnection().getFeatures().blocking()) {
+						menuBlock.setVisible(false);
+						menuUnblock.setVisible(false);
+					}
 				}
 				if (this.getSelectedConversation().isMuted()) {
 					menuMute.setVisible(false);
@@ -323,7 +338,7 @@ public class ConversationActivity extends XmppActivity implements
 			public void onPresenceSelected() {
 				if (attachmentChoice == ATTACHMENT_CHOICE_TAKE_PHOTO) {
 					mPendingImageUri = xmppConnectionService.getFileBackend()
-							.getTakePhotoUri();
+						.getTakePhotoUri();
 					Intent takePictureIntent = new Intent(
 							MediaStore.ACTION_IMAGE_CAPTURE);
 					takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
@@ -364,7 +379,7 @@ public class ConversationActivity extends XmppActivity implements
 
 								@Override
 								public void userInputRequried(PendingIntent pi,
-															  Contact contact) {
+										Contact contact) {
 									ConversationActivity.this.runIntent(pi,
 											attachmentChoice);
 								}
@@ -381,18 +396,18 @@ public class ConversationActivity extends XmppActivity implements
 							});
 				} else {
 					final ConversationFragment fragment = (ConversationFragment) getFragmentManager()
-							.findFragmentByTag("conversation");
+						.findFragmentByTag("conversation");
 					if (fragment != null) {
 						fragment.showNoPGPKeyDialog(false,
 								new OnClickListener() {
 
 									@Override
 									public void onClick(DialogInterface dialog,
-														int which) {
+											int which) {
 										conversation
-												.setNextEncryption(Message.ENCRYPTION_NONE);
+											.setNextEncryption(Message.ENCRYPTION_NONE);
 										xmppConnectionService.databaseBackend
-												.updateConversation(conversation);
+											.updateConversation(conversation);
 										selectPresenceToAttachFile(attachmentChoice);
 									}
 								});
@@ -402,7 +417,7 @@ public class ConversationActivity extends XmppActivity implements
 				showInstallPgpDialog();
 			}
 		} else if (getSelectedConversation().getNextEncryption(
-				forceEncryption()) == Message.ENCRYPTION_NONE) {
+					forceEncryption()) == Message.ENCRYPTION_NONE) {
 			selectPresenceToAttachFile(attachmentChoice);
 		} else {
 			selectPresenceToAttachFile(attachmentChoice);
@@ -410,7 +425,7 @@ public class ConversationActivity extends XmppActivity implements
 	}
 
 	@Override
-	public boolean onOptionsItemSelected(MenuItem item) {
+	public boolean onOptionsItemSelected(final MenuItem item) {
 		if (item.getItemId() == android.R.id.home) {
 			showConversationsOverview();
 			return true;
@@ -455,6 +470,12 @@ public class ConversationActivity extends XmppActivity implements
 				case R.id.action_unmute:
 					unmuteConversation(getSelectedConversation());
 					break;
+				case R.id.action_block:
+					BlockContactDialog.show(this, xmppConnectionService, getSelectedConversation());
+					break;
+				case R.id.action_unblock:
+					BlockContactDialog.show(this, xmppConnectionService, getSelectedConversation());
+					break;
 				default:
 					break;
 			}
@@ -483,7 +504,7 @@ public class ConversationActivity extends XmppActivity implements
 		View dialogView = getLayoutInflater().inflate(
 				R.layout.dialog_clear_history, null);
 		final CheckBox endConversationCheckBox = (CheckBox) dialogView
-				.findViewById(R.id.end_conversation_checkbox);
+			.findViewById(R.id.end_conversation_checkbox);
 		builder.setView(dialogView);
 		builder.setNegativeButton(getString(R.string.cancel), null);
 		builder.setPositiveButton(getString(R.string.delete_messages),
@@ -511,24 +532,24 @@ public class ConversationActivity extends XmppActivity implements
 		PopupMenu attachFilePopup = new PopupMenu(this, menuAttachFile);
 		attachFilePopup.inflate(R.menu.attachment_choices);
 		attachFilePopup
-				.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+			.setOnMenuItemClickListener(new OnMenuItemClickListener() {
 
-					@Override
-					public boolean onMenuItemClick(MenuItem item) {
-						switch (item.getItemId()) {
-							case R.id.attach_choose_picture:
-								attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE);
-								break;
-							case R.id.attach_take_picture:
-								attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO);
-								break;
-							case R.id.attach_record_voice:
-								attachFile(ATTACHMENT_CHOICE_CHOOSE_FILE);
-								break;
-						}
-						return false;
+				@Override
+				public boolean onMenuItemClick(MenuItem item) {
+					switch (item.getItemId()) {
+						case R.id.attach_choose_picture:
+							attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE);
+							break;
+						case R.id.attach_take_picture:
+							attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO);
+							break;
+						case R.id.attach_record_voice:
+							attachFile(ATTACHMENT_CHOICE_CHOOSE_FILE);
+							break;
 					}
-				});
+					return false;
+				}
+			});
 		attachFilePopup.show();
 	}
 
@@ -539,7 +560,7 @@ public class ConversationActivity extends XmppActivity implements
 		}
 		PopupMenu popup = new PopupMenu(this, menuItemView);
 		final ConversationFragment fragment = (ConversationFragment) getFragmentManager()
-				.findFragmentByTag("conversation");
+			.findFragmentByTag("conversation");
 		if (fragment != null) {
 			popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
 
@@ -559,7 +580,7 @@ public class ConversationActivity extends XmppActivity implements
 								if (conversation.getAccount().getKeys()
 										.has("pgp_signature")) {
 									conversation
-											.setNextEncryption(Message.ENCRYPTION_PGP);
+										.setNextEncryption(Message.ENCRYPTION_PGP);
 									item.setChecked(true);
 								} else {
 									announcePgp(conversation.getAccount(),
@@ -574,7 +595,7 @@ public class ConversationActivity extends XmppActivity implements
 							break;
 					}
 					xmppConnectionService.databaseBackend
-							.updateConversation(conversation);
+						.updateConversation(conversation);
 					fragment.updateChatMsgHint();
 					return true;
 				}
@@ -599,11 +620,11 @@ public class ConversationActivity extends XmppActivity implements
 					break;
 				case Message.ENCRYPTION_PGP:
 					popup.getMenu().findItem(R.id.encryption_choice_pgp)
-							.setChecked(true);
+						.setChecked(true);
 					break;
 				default:
 					popup.getMenu().findItem(R.id.encryption_choice_none)
-							.setChecked(true);
+						.setChecked(true);
 					break;
 			}
 			popup.show();
@@ -619,17 +640,17 @@ public class ConversationActivity extends XmppActivity implements
 				new OnClickListener() {
 
 					@Override
-					public void onClick(DialogInterface dialog, int which) {
-						long till;
+					public void onClick(final DialogInterface dialog, final int which) {
+						final long till;
 						if (durations[which] == -1) {
 							till = Long.MAX_VALUE;
 						} else {
 							till = SystemClock.elapsedRealtime()
-									+ (durations[which] * 1000);
+								+ (durations[which] * 1000);
 						}
 						conversation.setMutedTill(till);
 						ConversationActivity.this.xmppConnectionService.databaseBackend
-								.updateConversation(conversation);
+							.updateConversation(conversation);
 						updateConversationList();
 						ConversationActivity.this.mConversationFragment.updateMessages();
 						invalidateOptionsMenu();
@@ -763,11 +784,11 @@ public class ConversationActivity extends XmppActivity implements
 	}
 
 	private void selectConversationByUuid(String uuid) {
-        for (Conversation aConversationList : conversationList) {
-            if (aConversationList.getUuid().equals(uuid)) {
-                setSelectedConversation(aConversationList);
-            }
-        }
+		for (Conversation aConversationList : conversationList) {
+			if (aConversationList.getUuid().equals(uuid)) {
+				setSelectedConversation(aConversationList);
+			}
+		}
 	}
 
 	@Override
@@ -778,7 +799,7 @@ public class ConversationActivity extends XmppActivity implements
 
 	@Override
 	protected void onActivityResult(int requestCode, int resultCode,
-									final Intent data) {
+			final Intent data) {
 		super.onActivityResult(requestCode, resultCode, data);
 		if (resultCode == RESULT_OK) {
 			if (requestCode == REQUEST_DECRYPT_PGP) {
@@ -859,7 +880,7 @@ public class ConversationActivity extends XmppActivity implements
 
 					@Override
 					public void userInputRequried(PendingIntent pi,
-												  Message object) {
+							Message object) {
 						hidePrepareFileToast();
 						ConversationActivity.this.runIntent(pi,
 								ConversationActivity.REQUEST_SEND_PGP_IMAGE);
@@ -892,7 +913,7 @@ public class ConversationActivity extends XmppActivity implements
 
 	public void updateConversationList() {
 		xmppConnectionService
-				.populateWithOrderedConversations(conversationList);
+			.populateWithOrderedConversations(conversationList);
 		listAdapter.notifyDataSetChanged();
 	}
 
@@ -910,7 +931,7 @@ public class ConversationActivity extends XmppActivity implements
 
 					@Override
 					public void userInputRequried(PendingIntent pi,
-												  Message message) {
+							Message message) {
 						ConversationActivity.this.runIntent(pi,
 								ConversationActivity.REQUEST_SEND_MESSAGE);
 					}
@@ -962,7 +983,7 @@ public class ConversationActivity extends XmppActivity implements
 				updateConversationList();
 				if (conversationList.size() == 0) {
 					startActivity(new Intent(getApplicationContext(),
-							StartConversationActivity.class));
+								StartConversationActivity.class));
 					finish();
 				}
 				ConversationActivity.this.mConversationFragment.updateMessages();
@@ -975,12 +996,31 @@ public class ConversationActivity extends XmppActivity implements
 	public void onRosterUpdate() {
 		runOnUiThread(new Runnable() {
 
-				@Override
-				public void run() {
-					updateConversationList();
-					ConversationActivity.this.mConversationFragment.updateMessages();
-					updateActionBarTitle();
-				}
-			});
+			@Override
+			public void run() {
+				updateConversationList();
+				ConversationActivity.this.mConversationFragment.updateMessages();
+				updateActionBarTitle();
+			}
+		});
+	}
+
+	@Override
+	public void OnUpdateBlocklist(Status status) {
+		invalidateOptionsMenu();
+		runOnUiThread(new Runnable() {
+			@Override
+			public void run() {
+				ConversationActivity.this.mConversationFragment.updateMessages();
+			}
+		});
+	}
+
+	public void unblockConversation(final Blockable conversation) {
+		xmppConnectionService.sendUnblockRequest(conversation);
+	}
+
+	public void blockConversation(final Blockable conversation) {
+		xmppConnectionService.sendBlockRequest(conversation);
 	}
 }
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
index e4c3fa9e9..d356c73c5 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
@@ -9,7 +9,6 @@ import android.content.Intent;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
 import android.os.Bundle;
-import android.util.Log;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.Gravity;
@@ -39,7 +38,6 @@ import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
-import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.crypto.PgpEngine;
 import eu.siacs.conversations.entities.Account;
@@ -118,7 +116,7 @@ public class ConversationFragment extends Fragment {
 
 		@Override
 		public void onScroll(AbsListView view, int firstVisibleItem,
-							 int visibleItemCount, int totalItemCount) {
+				int visibleItemCount, int totalItemCount) {
 			synchronized (ConversationFragment.this.messageList) {
 				if (firstVisibleItem < 5 && messagesLoaded && messageList.size() > 0) {
 					long timestamp = ConversationFragment.this.messageList.get(0).getTimeSent();
@@ -223,7 +221,7 @@ public class ConversationFragment extends Fragment {
 		public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
 			if (actionId == EditorInfo.IME_ACTION_SEND) {
 				InputMethodManager imm = (InputMethodManager) v.getContext()
-						.getSystemService(Context.INPUT_METHOD_SERVICE);
+					.getSystemService(Context.INPUT_METHOD_SERVICE);
 				imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
 				sendMessage();
 				return true;
@@ -266,7 +264,7 @@ public class ConversationFragment extends Fragment {
 		}
 		Message message = new Message(conversation, mEditMessage.getText()
 				.toString(), conversation.getNextEncryption(activity
-				.forceEncryption()));
+					.forceEncryption()));
 		if (conversation.getMode() == Conversation.MODE_MULTI) {
 			if (conversation.getNextCounterpart() != null) {
 				message.setCounterpart(conversation.getNextCounterpart());
@@ -287,13 +285,13 @@ public class ConversationFragment extends Fragment {
 		if (conversation.getMode() == Conversation.MODE_MULTI
 				&& conversation.getNextCounterpart() != null) {
 			this.mEditMessage.setHint(getString(
-					R.string.send_private_message_to,
-					conversation.getNextCounterpart().getResourcepart()));
+						R.string.send_private_message_to,
+						conversation.getNextCounterpart().getResourcepart()));
 		} else {
 			switch (conversation.getNextEncryption(activity.forceEncryption())) {
 				case Message.ENCRYPTION_NONE:
 					mEditMessage
-							.setHint(getString(R.string.send_plain_text_message));
+						.setHint(getString(R.string.send_plain_text_message));
 					break;
 				case Message.ENCRYPTION_OTR:
 					mEditMessage.setHint(getString(R.string.send_otr_message));
@@ -309,7 +307,7 @@ public class ConversationFragment extends Fragment {
 
 	@Override
 	public View onCreateView(final LayoutInflater inflater,
-							 ViewGroup container, Bundle savedInstanceState) {
+			ViewGroup container, Bundle savedInstanceState) {
 		final View view = inflater.inflate(R.layout.fragment_conversation,
 				container, false);
 		mEditMessage = (EditMessage) view.findViewById(R.id.textinput);
@@ -342,49 +340,49 @@ public class ConversationFragment extends Fragment {
 		messageListAdapter = new MessageAdapter((ConversationActivity) getActivity(), this.messageList);
 		messageListAdapter.setOnContactPictureClicked(new OnContactPictureClicked() {
 
-					@Override
-					public void onContactPictureClicked(Message message) {
-						if (message.getStatus() <= Message.STATUS_RECEIVED) {
-							if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
-								if (message.getCounterpart() != null) {
-									if (!message.getCounterpart().isBareJid()) {
-										highlightInConference(message.getCounterpart().getResourcepart());
-									} else {
-										highlightInConference(message.getCounterpart().toString());
-									}
-								}
+			@Override
+			public void onContactPictureClicked(Message message) {
+				if (message.getStatus() <= Message.STATUS_RECEIVED) {
+					if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
+						if (message.getCounterpart() != null) {
+							if (!message.getCounterpart().isBareJid()) {
+								highlightInConference(message.getCounterpart().getResourcepart());
 							} else {
-								Contact contact = message.getConversation()
-										.getContact();
-								if (contact.showInRoster()) {
-									activity.switchToContactDetails(contact);
-								} else {
-									activity.showAddToRosterDialog(message
-											.getConversation());
-								}
+								highlightInConference(message.getCounterpart().toString());
 							}
+						}
+					} else {
+						Contact contact = message.getConversation()
+							.getContact();
+						if (contact.showInRoster()) {
+							activity.switchToContactDetails(contact);
 						} else {
-							Account account = message.getConversation().getAccount();
-							Intent intent = new Intent(activity, EditAccountActivity.class);
-							intent.putExtra("jid", account.getJid().toBareJid().toString());
-							startActivity(intent);
+							activity.showAddToRosterDialog(message
+									.getConversation());
 						}
 					}
-				});
+				} else {
+					Account account = message.getConversation().getAccount();
+					Intent intent = new Intent(activity, EditAccountActivity.class);
+					intent.putExtra("jid", account.getJid().toBareJid().toString());
+					startActivity(intent);
+				}
+			}
+		});
 		messageListAdapter
-				.setOnContactPictureLongClicked(new OnContactPictureLongClicked() {
+			.setOnContactPictureLongClicked(new OnContactPictureLongClicked() {
 
-					@Override
-					public void onContactPictureLongClicked(Message message) {
-						if (message.getStatus() <= Message.STATUS_RECEIVED) {
-							if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
-								if (message.getCounterpart() != null) {
-									privateMessageWith(message.getCounterpart());
-								}
+				@Override
+				public void onContactPictureLongClicked(Message message) {
+					if (message.getStatus() <= Message.STATUS_RECEIVED) {
+						if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
+							if (message.getCounterpart() != null) {
+								privateMessageWith(message.getCounterpart());
 							}
 						}
 					}
-				});
+				}
+			});
 		messagesView.setAdapter(messageListAdapter);
 
 		registerForContextMenu(messagesView);
@@ -394,7 +392,7 @@ public class ConversationFragment extends Fragment {
 
 	@Override
 	public void onCreateContextMenu(ContextMenu menu, View v,
-									ContextMenuInfo menuInfo) {
+			ContextMenuInfo menuInfo) {
 		synchronized (this.messageList) {
 			super.onCreateContextMenu(menu, v, menuInfo);
 			AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
@@ -416,28 +414,28 @@ public class ConversationFragment extends Fragment {
 			if (this.selectedMessage.getType() != Message.TYPE_TEXT
 					|| this.selectedMessage.getDownloadable() != null) {
 				copyText.setVisible(false);
-			}
+					}
 			if (this.selectedMessage.getType() != Message.TYPE_IMAGE
 					|| this.selectedMessage.getDownloadable() != null) {
 				shareImage.setVisible(false);
-			}
+					}
 			if (this.selectedMessage.getStatus() != Message.STATUS_SEND_FAILED) {
 				sendAgain.setVisible(false);
 			}
 			if ((this.selectedMessage.getType() != Message.TYPE_IMAGE && this.selectedMessage
-					.getDownloadable() == null)
+						.getDownloadable() == null)
 					|| this.selectedMessage.getImageParams().url == null) {
 				copyUrl.setVisible(false);
-			}
+					}
 			if (this.selectedMessage.getType() != Message.TYPE_TEXT
 					|| this.selectedMessage.getDownloadable() != null
 					|| !this.selectedMessage.bodyContainsDownloadable()) {
 				downloadImage.setVisible(false);
-			}
+					}
 			if (this.selectedMessage.getDownloadable() == null
 					|| this.selectedMessage.getDownloadable() instanceof DownloadablePlaceholder) {
 				cancelTransmission.setVisible(false);
-			}
+					}
 		}
 	}
 
@@ -472,16 +470,16 @@ public class ConversationFragment extends Fragment {
 		shareIntent.setAction(Intent.ACTION_SEND);
 		shareIntent.putExtra(Intent.EXTRA_STREAM,
 				activity.xmppConnectionService.getFileBackend()
-						.getJingleFileUri(message));
+				.getJingleFileUri(message));
 		shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
 		shareIntent.setType("image/webp");
 		activity.startActivity(Intent.createChooser(shareIntent,
-				getText(R.string.share_with)));
+					getText(R.string.share_with)));
 	}
 
 	private void copyText(Message message) {
 		if (activity.copyTextToClipboard(message.getMergedBody(),
-				R.string.message_text)) {
+					R.string.message_text)) {
 			Toast.makeText(activity, R.string.message_copied_to_clipboard,
 					Toast.LENGTH_SHORT).show();
 		}
@@ -501,15 +499,15 @@ public class ConversationFragment extends Fragment {
 
 	private void copyUrl(Message message) {
 		if (activity.copyTextToClipboard(
-				message.getImageParams().url.toString(), R.string.image_url)) {
+					message.getImageParams().url.toString(), R.string.image_url)) {
 			Toast.makeText(activity, R.string.url_copied_to_clipboard,
 					Toast.LENGTH_SHORT).show();
-		}
+					}
 	}
 
 	private void downloadImage(Message message) {
 		activity.xmppConnectionService.getHttpConnectionManager()
-				.createNewConnection(message);
+			.createNewConnection(message);
 	}
 
 	private void cancelTransmission(Message message) {
@@ -531,9 +529,9 @@ public class ConversationFragment extends Fragment {
 			mEditMessage.getText().insert(0, nick + ": ");
 		} else {
 			if (mEditMessage.getText().charAt(
-					mEditMessage.getSelectionStart() - 1) != ' ') {
+						mEditMessage.getSelectionStart() - 1) != ' ') {
 				nick = " " + nick;
-			}
+						}
 			mEditMessage.getText().insert(mEditMessage.getSelectionStart(),
 					nick + " ");
 		}
@@ -583,12 +581,30 @@ public class ConversationFragment extends Fragment {
 			final ConversationActivity activity = (ConversationActivity) getActivity();
 			if (this.conversation != null) {
 				final Contact contact = this.conversation.getContact();
-				if (this.conversation.isMuted()) {
+				if (this.conversation.isBlocked()) {
+					showSnackbar(R.string.contact_blocked, R.string.unblock,
+							new OnClickListener() {
+								@Override
+								public void onClick(final View v) {
+									v.post(new Runnable() {
+										@Override
+										public void run() {
+											v.setVisibility(View.INVISIBLE);
+										}
+									});
+									if (conversation.isDomainBlocked()) {
+										BlockContactDialog.show(getActivity(), ((ConversationActivity) getActivity()).xmppConnectionService, conversation);
+									} else {
+										((ConversationActivity) getActivity()).unblockConversation(conversation);
+									}
+								}
+							});
+				} else if (this.conversation.isMuted()) {
 					showSnackbar(R.string.notifications_disabled, R.string.enable,
 							new OnClickListener() {
 
 								@Override
-								public void onClick(View v) {
+								public void onClick(final View v) {
 									activity.unmuteConversation(conversation);
 								}
 							});
@@ -601,7 +617,7 @@ public class ConversationFragment extends Fragment {
 								@Override
 								public void onClick(View v) {
 									activity.xmppConnectionService
-											.createContact(contact);
+										.createContact(contact);
 									activity.switchToContactDetails(contact);
 								}
 							});
@@ -638,17 +654,17 @@ public class ConversationFragment extends Fragment {
 						default:
 							break;
 					}
-				}
+						}
 				conversation.populateWithMessages(ConversationFragment.this.messageList);
 				for (Message message : this.messageList) {
 					if (message.getEncryption() == Message.ENCRYPTION_PGP
 							&& (message.getStatus() == Message.STATUS_RECEIVED || message
-							.getStatus() >= Message.STATUS_SEND)
+								.getStatus() >= Message.STATUS_SEND)
 							&& message.getDownloadable() == null) {
 						if (!mEncryptedMessages.contains(message)) {
 							mEncryptedMessages.add(message);
 						}
-					}
+							}
 				}
 				decryptNext();
 				updateStatusMessages();
@@ -720,44 +736,44 @@ public class ConversationFragment extends Fragment {
 				switch (c.getContact().getMostAvailableStatus()) {
 					case Presences.CHAT:
 						this.mSendButton
-								.setImageResource(R.drawable.ic_action_send_now_online);
+							.setImageResource(R.drawable.ic_action_send_now_online);
 						break;
 					case Presences.ONLINE:
 						this.mSendButton
-								.setImageResource(R.drawable.ic_action_send_now_online);
+							.setImageResource(R.drawable.ic_action_send_now_online);
 						break;
 					case Presences.AWAY:
 						this.mSendButton
-								.setImageResource(R.drawable.ic_action_send_now_away);
+							.setImageResource(R.drawable.ic_action_send_now_away);
 						break;
 					case Presences.XA:
 						this.mSendButton
-								.setImageResource(R.drawable.ic_action_send_now_away);
+							.setImageResource(R.drawable.ic_action_send_now_away);
 						break;
 					case Presences.DND:
 						this.mSendButton
-								.setImageResource(R.drawable.ic_action_send_now_dnd);
+							.setImageResource(R.drawable.ic_action_send_now_dnd);
 						break;
 					default:
 						this.mSendButton
-								.setImageResource(R.drawable.ic_action_send_now_offline);
+							.setImageResource(R.drawable.ic_action_send_now_offline);
 						break;
 				}
 			} else if (c.getMode() == Conversation.MODE_MULTI) {
 				if (c.getMucOptions().online()) {
 					this.mSendButton
-							.setImageResource(R.drawable.ic_action_send_now_online);
+						.setImageResource(R.drawable.ic_action_send_now_online);
 				} else {
 					this.mSendButton
-							.setImageResource(R.drawable.ic_action_send_now_offline);
+						.setImageResource(R.drawable.ic_action_send_now_offline);
 				}
 			} else {
 				this.mSendButton
-						.setImageResource(R.drawable.ic_action_send_now_offline);
+					.setImageResource(R.drawable.ic_action_send_now_offline);
 			}
 		} else {
 			this.mSendButton
-					.setImageResource(R.drawable.ic_action_send_now_offline);
+				.setImageResource(R.drawable.ic_action_send_now_offline);
 		}
 	}
 
@@ -784,15 +800,16 @@ public class ConversationFragment extends Fragment {
 		} else if (conversation.hasValidOtrSession() && (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED)
 				&& (!conversation.isOtrFingerprintVerified())) {
 			showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify, clickToVerify);
-		}
+				}
 	}
 
-	protected void showSnackbar(int message, int action,
-								OnClickListener clickListener) {
+	protected void showSnackbar(final int message, final int action,
+			final OnClickListener clickListener) {
 		snackbar.setVisibility(View.VISIBLE);
 		snackbar.setOnClickListener(null);
 		snackbarMessage.setText(message);
 		snackbarMessage.setOnClickListener(null);
+		snackbarAction.setVisibility(View.VISIBLE);
 		snackbarAction.setText(action);
 		snackbarAction.setOnClickListener(clickListener);
 	}
@@ -819,7 +836,7 @@ public class ConversationFragment extends Fragment {
 
 								@Override
 								public void userInputRequried(PendingIntent pi,
-															  Contact contact) {
+										Contact contact) {
 									activity.runIntent(
 											pi,
 											ConversationActivity.REQUEST_ENCRYPT_MESSAGE);
@@ -843,11 +860,11 @@ public class ConversationFragment extends Fragment {
 
 								@Override
 								public void onClick(DialogInterface dialog,
-													int which) {
+										int which) {
 									conversation
-											.setNextEncryption(Message.ENCRYPTION_NONE);
+										.setNextEncryption(Message.ENCRYPTION_NONE);
 									xmppService.databaseBackend
-											.updateConversation(conversation);
+										.updateConversation(conversation);
 									message.setEncryption(Message.ENCRYPTION_NONE);
 									xmppService.sendMessage(message);
 									messageSent();
@@ -858,9 +875,9 @@ public class ConversationFragment extends Fragment {
 				if (conversation.getMucOptions().pgpKeysInUse()) {
 					if (!conversation.getMucOptions().everybodyHasKeys()) {
 						Toast warning = Toast
-								.makeText(getActivity(),
-										R.string.missing_public_keys,
-										Toast.LENGTH_LONG);
+							.makeText(getActivity(),
+									R.string.missing_public_keys,
+									Toast.LENGTH_LONG);
 						warning.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
 						warning.show();
 					}
@@ -872,12 +889,12 @@ public class ConversationFragment extends Fragment {
 
 								@Override
 								public void onClick(DialogInterface dialog,
-													int which) {
+										int which) {
 									conversation
-											.setNextEncryption(Message.ENCRYPTION_NONE);
+										.setNextEncryption(Message.ENCRYPTION_NONE);
 									message.setEncryption(Message.ENCRYPTION_NONE);
 									xmppService.databaseBackend
-											.updateConversation(conversation);
+										.updateConversation(conversation);
 									xmppService.sendMessage(message);
 									messageSent();
 								}
@@ -890,7 +907,7 @@ public class ConversationFragment extends Fragment {
 	}
 
 	public void showNoPGPKeyDialog(boolean plural,
-								   DialogInterface.OnClickListener listener) {
+			DialogInterface.OnClickListener listener) {
 		AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
 		builder.setIconAttribute(android.R.attr.alertDialogIcon);
 		if (plural) {
diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
index 8fad66cf9..47fe5964e 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -67,7 +67,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 				mAccount.setOption(Account.OPTION_DISABLED, false);
 				xmppConnectionService.updateAccount(mAccount);
 				return;
-			}
+					}
 			if (!Validator.isValidJid(mAccountJid.getText().toString())) {
 				mAccountJid.setError(getString(R.string.invalid_jid));
 				mAccountJid.requestFocus();
@@ -87,32 +87,32 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 			if (registerNewAccount) {
 				if (!password.equals(passwordConfirm)) {
 					mPasswordConfirm
-							.setError(getString(R.string.passwords_do_not_match));
+						.setError(getString(R.string.passwords_do_not_match));
 					mPasswordConfirm.requestFocus();
 					return;
 				}
 			}
 			if (mAccount != null) {
 				mAccount.setPassword(password);
-                try {
-                    mAccount.setUsername(jid.hasLocalpart() ? jid.getLocalpart() : "");
-                    mAccount.setServer(jid.getDomainpart());
-                } catch (final InvalidJidException ignored) {
-                }
+				try {
+					mAccount.setUsername(jid.hasLocalpart() ? jid.getLocalpart() : "");
+					mAccount.setServer(jid.getDomainpart());
+				} catch (final InvalidJidException ignored) {
+				}
 				mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount);
 				xmppConnectionService.updateAccount(mAccount);
 			} else {
-                try {
-                    if (xmppConnectionService.findAccountByJid(Jid.fromString(mAccountJid.getText().toString())) != null) {
-                        mAccountJid
-                                .setError(getString(R.string.account_already_exists));
-                        mAccountJid.requestFocus();
-                        return;
-                    }
-                } catch (InvalidJidException e) {
-                    return;
-                }
-                mAccount = new Account(jid.toBareJid(), password);
+				try {
+					if (xmppConnectionService.findAccountByJid(Jid.fromString(mAccountJid.getText().toString())) != null) {
+						mAccountJid
+							.setError(getString(R.string.account_already_exists));
+						mAccountJid.requestFocus();
+						return;
+					}
+				} catch (InvalidJidException e) {
+					return;
+				}
+				mAccount = new Account(jid.toBareJid(), password);
 				mAccount.setOption(Account.OPTION_USETLS, true);
 				mAccount.setOption(Account.OPTION_USECOMPRESSION, true);
 				mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount);
@@ -134,34 +134,34 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 			finish();
 		}
 	};
-		@Override
-		public void onAccountUpdate() {
-			runOnUiThread(new Runnable() {
+	@Override
+	public void onAccountUpdate() {
+		runOnUiThread(new Runnable() {
 
-				@Override
-				public void run() {
-					if (mAccount != null
-							&& mAccount.getStatus() != Account.State.ONLINE
-							&& mFetchingAvatar) {
-						startActivity(new Intent(getApplicationContext(),
+			@Override
+			public void run() {
+				if (mAccount != null
+						&& mAccount.getStatus() != Account.State.ONLINE
+						&& mFetchingAvatar) {
+					startActivity(new Intent(getApplicationContext(),
 								ManageAccountActivity.class));
-						finish();
-					} else if (jidToEdit == null && mAccount != null
-							&& mAccount.getStatus() == Account.State.ONLINE) {
-						if (!mFetchingAvatar) {
-							mFetchingAvatar = true;
-							xmppConnectionService.checkForAvatar(mAccount,
-									mAvatarFetchCallback);
-						}
-					} else {
-						updateSaveButton();
-					}
-					if (mAccount != null) {
-						updateAccountInformation();
+					finish();
+				} else if (jidToEdit == null && mAccount != null
+						&& mAccount.getStatus() == Account.State.ONLINE) {
+					if (!mFetchingAvatar) {
+						mFetchingAvatar = true;
+						xmppConnectionService.checkForAvatar(mAccount,
+								mAvatarFetchCallback);
 					}
+				} else {
+					updateSaveButton();
 				}
-			});
-		}
+				if (mAccount != null) {
+					updateAccountInformation();
+				}
+			}
+		});
+	}
 	private UiCallback<Avatar> mAvatarFetchCallback = new UiCallback<Avatar>() {
 
 		@Override
@@ -179,17 +179,17 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 			finishInitialSetup(avatar);
 		}
 	};
-    private TextWatcher mTextWatcher = new TextWatcher() {
+	private TextWatcher mTextWatcher = new TextWatcher() {
 
 		@Override
 		public void onTextChanged(CharSequence s, int start, int before,
-								  int count) {
+				int count) {
 			updateSaveButton();
 		}
 
 		@Override
 		public void beforeTextChanged(CharSequence s, int start, int count,
-									  int after) {
+				int after) {
 
 		}
 
@@ -264,9 +264,9 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 
 	protected boolean accountInfoEdited() {
 		return (!this.mAccount.getJid().toBareJid().equals(
-				this.mAccountJid.getText().toString()))
-				|| (!this.mAccount.getPassword().equals(
-				this.mPassword.getText().toString()));
+					this.mAccountJid.getText().toString()))
+			|| (!this.mAccount.getPassword().equals(
+						this.mPassword.getText().toString()));
 	}
 
 	@Override
@@ -303,28 +303,32 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 		this.mSaveButton.setOnClickListener(this.mSaveButtonClickListener);
 		this.mCancelButton.setOnClickListener(this.mCancelButtonClickListener);
 		this.mRegisterNew
-				.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+			.setOnCheckedChangeListener(new OnCheckedChangeListener() {
 
-					@Override
-					public void onCheckedChanged(CompoundButton buttonView,
-												 boolean isChecked) {
-						if (isChecked) {
-							mPasswordConfirm.setVisibility(View.VISIBLE);
-						} else {
-							mPasswordConfirm.setVisibility(View.GONE);
-						}
-						updateSaveButton();
+				@Override
+				public void onCheckedChanged(CompoundButton buttonView,
+						boolean isChecked) {
+					if (isChecked) {
+						mPasswordConfirm.setVisibility(View.VISIBLE);
+					} else {
+						mPasswordConfirm.setVisibility(View.GONE);
 					}
-				});
+					updateSaveButton();
+				}
+			});
 	}
 
 	@Override
-	public boolean onCreateOptionsMenu(Menu menu) {
+	public boolean onCreateOptionsMenu(final Menu menu) {
 		super.onCreateOptionsMenu(menu);
 		getMenuInflater().inflate(R.menu.editaccount, menu);
-		MenuItem showQrCode = menu.findItem(R.id.action_show_qr_code);
+		final MenuItem showQrCode = menu.findItem(R.id.action_show_qr_code);
+		final MenuItem showBlocklist = menu.findItem(R.id.action_show_block_list);
 		if (mAccount == null) {
 			showQrCode.setVisible(false);
+			showBlocklist.setVisible(false);
+		} else if (!mAccount.getXmppConnection().getFeatures().blocking()) {
+			showBlocklist.setVisible(false);
 		}
 		return true;
 	}
@@ -333,32 +337,38 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 	protected void onStart() {
 		super.onStart();
 		if (getIntent() != null) {
-            try {
-                this.jidToEdit = Jid.fromString(getIntent().getStringExtra("jid"));
-            } catch (final InvalidJidException | NullPointerException ignored) {
-                this.jidToEdit = null;
-            }
-            if (this.jidToEdit != null) {
+			try {
+				this.jidToEdit = Jid.fromString(getIntent().getStringExtra("jid"));
+			} catch (final InvalidJidException | NullPointerException ignored) {
+				this.jidToEdit = null;
+			}
+			if (this.jidToEdit != null) {
 				this.mRegisterNew.setVisibility(View.GONE);
-				getActionBar().setTitle(getString(R.string.account_details));
+				if (getActionBar() != null) {
+					getActionBar().setTitle(getString(R.string.account_details));
+				}
 			} else {
 				this.mAvatar.setVisibility(View.GONE);
-				getActionBar().setTitle(R.string.action_add_account);
+				if (getActionBar() != null) {
+					getActionBar().setTitle(R.string.action_add_account);
+				}
 			}
 		}
 	}
 
 	@Override
 	protected void onBackendConnected() {
-        KnownHostsAdapter mKnownHostsAdapter = new KnownHostsAdapter(this,
-                android.R.layout.simple_list_item_1,
-                xmppConnectionService.getKnownHosts());
+		final KnownHostsAdapter mKnownHostsAdapter = new KnownHostsAdapter(this,
+				android.R.layout.simple_list_item_1,
+				xmppConnectionService.getKnownHosts());
 		if (this.jidToEdit != null) {
 			this.mAccount = xmppConnectionService.findAccountByJid(jidToEdit);
 			updateAccountInformation();
 		} else if (this.xmppConnectionService.getAccounts().size() == 0) {
-			getActionBar().setDisplayHomeAsUpEnabled(false);
-			getActionBar().setDisplayShowHomeEnabled(false);
+			if (getActionBar() != null) {
+				getActionBar().setDisplayHomeAsUpEnabled(false);
+				getActionBar().setDisplayShowHomeEnabled(false);
+			}
 			this.mCancelButton.setEnabled(false);
 			this.mCancelButton.setTextColor(getSecondaryTextColor());
 		}
@@ -366,6 +376,18 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 		updateSaveButton();
 	}
 
+	@Override
+	public boolean onOptionsItemSelected(final MenuItem item) {
+		switch (item.getItemId()) {
+			case R.id.action_show_block_list:
+				final Intent intent = new Intent(this, BlocklistActivity.class);
+				intent.putExtra("account", mAccount.getJid().toString());
+				startActivity(intent);
+				break;
+		}
+		return super.onOptionsItemSelected(item);
+	}
+
 	private void updateAccountInformation() {
 		this.mAccountJid.setText(this.mAccount.getJid().toBareJid().toString());
 		this.mPassword.setText(this.mAccount.getPassword());
@@ -385,14 +407,14 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 				&& !this.mFetchingAvatar) {
 			this.mStats.setVisibility(View.VISIBLE);
 			this.mSessionEst.setText(UIHelper.readableTimeDifferenceFull(
-					getApplicationContext(), this.mAccount.getXmppConnection()
-							.getLastSessionEstablished()));
-			Features features = this.mAccount.getXmppConnection().getFeatures();
+						getApplicationContext(), this.mAccount.getXmppConnection()
+						.getLastSessionEstablished()));
+			final Features features = this.mAccount.getXmppConnection().getFeatures();
 			if (features.carbons()) {
 				this.mServerInfoCarbons.setText(R.string.server_info_available);
 			} else {
 				this.mServerInfoCarbons
-						.setText(R.string.server_info_unavailable);
+					.setText(R.string.server_info_unavailable);
 			}
 			if (features.sm()) {
 				this.mServerInfoSm.setText(R.string.server_info_available);
@@ -409,21 +431,21 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 				this.mOtrFingerprintBox.setVisibility(View.VISIBLE);
 				this.mOtrFingerprint.setText(CryptoHelper.prettifyFingerprint(fingerprint));
 				this.mOtrFingerprintToClipboardButton
-						.setVisibility(View.VISIBLE);
+					.setVisibility(View.VISIBLE);
 				this.mOtrFingerprintToClipboardButton
-						.setOnClickListener(new View.OnClickListener() {
+					.setOnClickListener(new View.OnClickListener() {
 
-							@Override
-							public void onClick(View v) {
+						@Override
+						public void onClick(View v) {
 
-								if (copyTextToClipboard(fingerprint, R.string.otr_fingerprint)) {
-									Toast.makeText(
-											EditAccountActivity.this,
-											R.string.toast_message_otr_fingerprint,
-											Toast.LENGTH_SHORT).show();
-								}
+							if (copyTextToClipboard(fingerprint, R.string.otr_fingerprint)) {
+								Toast.makeText(
+										EditAccountActivity.this,
+										R.string.toast_message_otr_fingerprint,
+										Toast.LENGTH_SHORT).show();
 							}
-						});
+						}
+					});
 			} else {
 				this.mOtrFingerprintBox.setVisibility(View.GONE);
 			}
diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
index be5eee991..c80755148 100644
--- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
@@ -117,10 +117,10 @@ public class ShareWithActivity extends XmppActivity {
 	}
 
 	@Override
-	public boolean onOptionsItemSelected(MenuItem item) {
+	public boolean onOptionsItemSelected(final MenuItem item) {
 		switch (item.getItemId()) {
 		case R.id.action_add:
-			Intent intent = new Intent(getApplicationContext(),
+			final Intent intent = new Intent(getApplicationContext(),
 					ChooseContactActivity.class);
 			startActivityForResult(intent, REQUEST_START_NEW_CONVERSATION);
 			return true;
diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java
index 4fdcf79e3..630dc6efe 100644
--- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java
@@ -53,19 +53,21 @@ import java.util.List;
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Blockable;
 import eu.siacs.conversations.entities.Bookmark;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.ListItem;
-import eu.siacs.conversations.utils.XmppUri;
 import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
 import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
 import eu.siacs.conversations.ui.adapter.ListItemAdapter;
 import eu.siacs.conversations.utils.Validator;
+import eu.siacs.conversations.utils.XmppUri;
+import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
 import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 import eu.siacs.conversations.xmpp.jid.Jid;
 
-public class StartConversationActivity extends XmppActivity implements OnRosterUpdate {
+public class StartConversationActivity extends XmppActivity implements OnRosterUpdate, OnUpdateBlocklist {
 
 	public int conference_context_id;
 	public int contact_context_id;
@@ -133,7 +135,9 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 	private ViewPager.SimpleOnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
 		@Override
 		public void onPageSelected(int position) {
-			getActionBar().setSelectedNavigationItem(position);
+			if (getActionBar() != null) {
+				getActionBar().setSelectedNavigationItem(position);
+			}
 			onTabChanged();
 		}
 	};
@@ -146,12 +150,12 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 
 		@Override
 		public void beforeTextChanged(CharSequence s, int start, int count,
-									  int after) {
+				int after) {
 		}
 
 		@Override
 		public void onTextChanged(CharSequence s, int start, int before,
-								  int count) {
+				int count) {
 		}
 	};
 	private MenuItem mMenuSearchView;
@@ -179,9 +183,9 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 		actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
 
 		mContactsTab = actionBar.newTab().setText(R.string.contacts)
-				.setTabListener(mTabListener);
+			.setTabListener(mTabListener);
 		mConferencesTab = actionBar.newTab().setText(R.string.conferences)
-				.setTabListener(mTabListener);
+			.setTabListener(mTabListener);
 		actionBar.addTab(mContactsTab);
 		actionBar.addTab(mConferencesTab);
 
@@ -207,35 +211,35 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 		mConferenceListFragment.setListAdapter(mConferenceAdapter);
 		mConferenceListFragment.setContextMenu(R.menu.conference_context);
 		mConferenceListFragment
-				.setOnListItemClickListener(new OnItemClickListener() {
+			.setOnListItemClickListener(new OnItemClickListener() {
 
-					@Override
-					public void onItemClick(AdapterView<?> arg0, View arg1,
-											int position, long arg3) {
-						openConversationForBookmark(position);
-					}
-				});
+				@Override
+				public void onItemClick(AdapterView<?> arg0, View arg1,
+						int position, long arg3) {
+					openConversationForBookmark(position);
+				}
+			});
 
 		mContactsAdapter = new ListItemAdapter(this, contacts);
 		mContactsListFragment.setListAdapter(mContactsAdapter);
 		mContactsListFragment.setContextMenu(R.menu.contact_context);
 		mContactsListFragment
-				.setOnListItemClickListener(new OnItemClickListener() {
+			.setOnListItemClickListener(new OnItemClickListener() {
 
-					@Override
-					public void onItemClick(AdapterView<?> arg0, View arg1,
-											int position, long arg3) {
-						openConversationForContact(position);
-					}
-				});
+				@Override
+				public void onItemClick(AdapterView<?> arg0, View arg1,
+						int position, long arg3) {
+					openConversationForContact(position);
+				}
+			});
 
 	}
 
 	protected void openConversationForContact(int position) {
 		Contact contact = (Contact) contacts.get(position);
 		Conversation conversation = xmppConnectionService
-				.findOrCreateConversation(contact.getAccount(),
-						contact.getJid(), false);
+			.findOrCreateConversation(contact.getAccount(),
+					contact.getJid(), false);
 		switchToConversation(conversation);
 	}
 
@@ -251,8 +255,8 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 	protected void openConversationForBookmark(int position) {
 		Bookmark bookmark = (Bookmark) conferences.get(position);
 		Conversation conversation = xmppConnectionService
-				.findOrCreateConversation(bookmark.getAccount(),
-						bookmark.getJid(), true);
+			.findOrCreateConversation(bookmark.getAccount(),
+					bookmark.getJid(), true);
 		conversation.setBookmark(bookmark);
 		if (!conversation.getMucOptions().online()) {
 			xmppConnectionService.joinMuc(conversation);
@@ -270,14 +274,19 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 		switchToContactDetails(contact);
 	}
 
+	protected void toggleContactBlock() {
+		final int position = contact_context_id;
+		BlockContactDialog.show(this, xmppConnectionService, (Contact)contacts.get(position));
+	}
+
 	protected void deleteContact() {
-		int position = contact_context_id;
+		final int position = contact_context_id;
 		final Contact contact = (Contact) contacts.get(position);
-		AlertDialog.Builder builder = new AlertDialog.Builder(this);
+		final AlertDialog.Builder builder = new AlertDialog.Builder(this);
 		builder.setNegativeButton(R.string.cancel, null);
 		builder.setTitle(R.string.action_delete_contact);
 		builder.setMessage(getString(R.string.remove_contact_text,
-				contact.getJid()));
+					contact.getJid()));
 		builder.setPositiveButton(R.string.delete, new OnClickListener() {
 
 			@Override
@@ -287,7 +296,6 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 			}
 		});
 		builder.create().show();
-
 	}
 
 	protected void deleteConference() {
@@ -298,7 +306,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 		builder.setNegativeButton(R.string.cancel, null);
 		builder.setTitle(R.string.delete_bookmark);
 		builder.setMessage(getString(R.string.remove_bookmark_text,
-				bookmark.getJid()));
+					bookmark.getJid()));
 		builder.setPositiveButton(R.string.delete, new OnClickListener() {
 
 			@Override
@@ -360,7 +368,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 								return;
 							}
 							Account account = xmppConnectionService
-									.findAccountByJid(accountJid);
+								.findAccountByJid(accountJid);
 							if (account == null) {
 								dialog.dismiss();
 								return;
@@ -395,7 +403,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 		}
 		populateAccountSpinner(spinner);
 		final CheckBox bookmarkCheckBox = (CheckBox) dialogView
-				.findViewById(R.id.bookmark);
+			.findViewById(R.id.bookmark);
 		builder.setView(dialogView);
 		builder.setNegativeButton(R.string.cancel, null);
 		builder.setPositiveButton(R.string.join, null);
@@ -424,7 +432,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 								return;
 							}
 							Account account = xmppConnectionService
-									.findAccountByJid(accountJid);
+								.findAccountByJid(accountJid);
 							if (account == null) {
 								dialog.dismiss();
 								return;
@@ -438,22 +446,22 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 									bookmark.setAutojoin(true);
 									account.getBookmarks().add(bookmark);
 									xmppConnectionService
-											.pushBookmarks(account);
+										.pushBookmarks(account);
 									Conversation conversation = xmppConnectionService
-											.findOrCreateConversation(account,
-													conferenceJid, true);
+										.findOrCreateConversation(account,
+												conferenceJid, true);
 									conversation.setBookmark(bookmark);
 									if (!conversation.getMucOptions().online()) {
 										xmppConnectionService
-												.joinMuc(conversation);
+											.joinMuc(conversation);
 									}
 									dialog.dismiss();
 									switchToConversation(conversation);
 								}
 							} else {
 								Conversation conversation = xmppConnectionService
-										.findOrCreateConversation(account,
-												conferenceJid, true);
+									.findOrCreateConversation(account,
+											conferenceJid, true);
 								if (!conversation.getMucOptions().online()) {
 									xmppConnectionService.joinMuc(conversation);
 								}
@@ -469,8 +477,8 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 
 	protected void switchToConversation(Contact contact) {
 		Conversation conversation = xmppConnectionService
-				.findOrCreateConversation(contact.getAccount(),
-						contact.getJid(), false);
+			.findOrCreateConversation(contact.getAccount(),
+					contact.getJid(), false);
 		switchToConversation(conversation);
 	}
 
@@ -486,14 +494,14 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 		this.mOptionsMenu = menu;
 		getMenuInflater().inflate(R.menu.start_conversation, menu);
 		MenuItem menuCreateContact = menu
-				.findItem(R.id.action_create_contact);
+			.findItem(R.id.action_create_contact);
 		MenuItem menuCreateConference = menu
-				.findItem(R.id.action_join_conference);
+			.findItem(R.id.action_join_conference);
 		mMenuSearchView = menu.findItem(R.id.action_search);
 		mMenuSearchView.setOnActionExpandListener(mOnActionExpandListener);
 		View mSearchView = mMenuSearchView.getActionView();
 		mSearchEditText = (EditText) mSearchView
-				.findViewById(R.id.search_field);
+			.findViewById(R.id.search_field);
 		mSearchEditText.addTextChangedListener(mSearchTextWatcher);
 		if (getActionBar().getSelectedNavigationIndex() == 0) {
 			menuCreateConference.setVisible(false);
@@ -562,7 +570,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 		}
 		this.mKnownHosts = xmppConnectionService.getKnownHosts();
 		this.mKnownConferenceHosts = xmppConnectionService
-				.getKnownConferenceHosts();
+			.getKnownConferenceHosts();
 		if (this.mPendingInvite != null) {
 			mPendingInvite.invite();
 			this.mPendingInvite = null;
@@ -604,7 +612,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 											byte[] payload = record.getPayload();
 											if (payload[0] == 0) {
 												return new Invite(Uri.parse(new String(Arrays.copyOfRange(
-														payload, 1, payload.length)))).invite();
+																	payload, 1, payload.length)))).invite();
 											}
 										}
 									}
@@ -685,16 +693,29 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 		invalidateOptionsMenu();
 	}
 
+	@Override
+	public void OnUpdateBlocklist(final Status status) {
+		runOnUiThread(new Runnable() {
+
+			@Override
+			public void run() {
+				if (mSearchEditText != null) {
+					filter(mSearchEditText.getText().toString());
+				}
+			}
+		});
+	}
+
 	public static class MyListFragment extends ListFragment {
 		private AdapterView.OnItemClickListener mOnItemClickListener;
 		private int mResContextMenu;
 
-		public void setContextMenu(int res) {
+		public void setContextMenu(final int res) {
 			this.mResContextMenu = res;
 		}
 
 		@Override
-		public void onListItemClick(ListView l, View v, int position, long id) {
+		public void onListItemClick(final ListView l, final View v, final int position, final long id) {
 			if (mOnItemClickListener != null) {
 				mOnItemClickListener.onItemClick(l, v, position, id);
 			}
@@ -705,28 +726,38 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 		}
 
 		@Override
-		public void onViewCreated(View view, Bundle savedInstanceState) {
+		public void onViewCreated(final View view, final Bundle savedInstanceState) {
 			super.onViewCreated(view, savedInstanceState);
 			registerForContextMenu(getListView());
 			getListView().setFastScrollEnabled(true);
 		}
 
 		@Override
-		public void onCreateContextMenu(ContextMenu menu, View v,
-										ContextMenuInfo menuInfo) {
+		public void onCreateContextMenu(final ContextMenu menu, final View v,
+				final ContextMenuInfo menuInfo) {
 			super.onCreateContextMenu(menu, v, menuInfo);
-			StartConversationActivity activity = (StartConversationActivity) getActivity();
+			final StartConversationActivity activity = (StartConversationActivity) getActivity();
 			activity.getMenuInflater().inflate(mResContextMenu, menu);
-			AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
+			final AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
 			if (mResContextMenu == R.menu.conference_context) {
 				activity.conference_context_id = acmi.position;
 			} else {
 				activity.contact_context_id = acmi.position;
+				final Blockable contact = (Contact) activity.contacts.get(acmi.position);
+
+				final MenuItem blockUnblockItem = menu.findItem(R.id.context_contact_block_unblock);
+				if (blockUnblockItem != null) {
+					if (contact.isBlocked()) {
+						blockUnblockItem.setTitle(R.string.unblock_contact);
+					} else {
+						blockUnblockItem.setTitle(R.string.block_contact);
+					}
+				}
 			}
 		}
 
 		@Override
-		public boolean onContextItemSelected(MenuItem item) {
+		public boolean onContextItemSelected(final MenuItem item) {
 			StartConversationActivity activity = (StartConversationActivity) getActivity();
 			switch (item.getItemId()) {
 				case R.id.context_start_conversation:
@@ -735,6 +766,9 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 				case R.id.context_contact_details:
 					activity.openDetailsForContact();
 					break;
+				case R.id.context_contact_block_unblock:
+					activity.toggleContactBlock();
+					break;
 				case R.id.context_delete_contact:
 					activity.deleteContact();
 					break;
@@ -750,11 +784,11 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 
 	private class Invite extends XmppUri {
 
-		public Invite(Uri uri) {
+		public Invite(final Uri uri) {
 			super(uri);
 		}
 
-		public Invite(String uri) {
+		public Invite(final String uri) {
 			super(uri);
 		}
 
diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
index e6ae2a1cf..69dd47e71 100644
--- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
@@ -71,6 +71,7 @@ import eu.siacs.conversations.services.AvatarService;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder;
 import eu.siacs.conversations.utils.ExceptionHelper;
+import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
 import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 import eu.siacs.conversations.xmpp.jid.Jid;
 
@@ -199,7 +200,7 @@ public abstract class XmppActivity extends Activity {
 							xmppConnectionServiceBound = false;
 						}
 						stopService(new Intent(XmppActivity.this,
-								XmppConnectionService.class));
+									XmppConnectionService.class));
 						finish();
 					}
 				});
@@ -209,13 +210,13 @@ public abstract class XmppActivity extends Activity {
 					@Override
 					public void onClick(DialogInterface dialog, int which) {
 						Uri uri = Uri
-								.parse("market://details?id=org.sufficientlysecure.keychain");
+							.parse("market://details?id=org.sufficientlysecure.keychain");
 						Intent marketIntent = new Intent(Intent.ACTION_VIEW,
 								uri);
 						PackageManager manager = getApplicationContext()
-								.getPackageManager();
+							.getPackageManager();
 						List<ResolveInfo> infos = manager
-								.queryIntentActivities(marketIntent, 0);
+							.queryIntentActivities(marketIntent, 0);
 						if (infos.size() > 0) {
 							startActivity(marketIntent);
 						} else {
@@ -245,6 +246,9 @@ public abstract class XmppActivity extends Activity {
 		if (this instanceof XmppConnectionService.OnMucRosterUpdate) {
 			this.xmppConnectionService.setOnMucRosterUpdateListener((XmppConnectionService.OnMucRosterUpdate) this);
 		}
+		if (this instanceof OnUpdateBlocklist) {
+			this.xmppConnectionService.setOnUpdateBlocklistListener((OnUpdateBlocklist) this);
+		}
 	}
 
 	protected void unregisterListeners() {
@@ -260,9 +264,13 @@ public abstract class XmppActivity extends Activity {
 		if (this instanceof XmppConnectionService.OnMucRosterUpdate) {
 			this.xmppConnectionService.removeOnMucRosterUpdateListener();
 		}
+		if (this instanceof OnUpdateBlocklist) {
+			this.xmppConnectionService.removeOnUpdateBlocklistListener();
+		}
 	}
 
-	public boolean onOptionsItemSelected(MenuItem item) {
+	@Override
+	public boolean onOptionsItemSelected(final MenuItem item) {
 		switch (item.getItemId()) {
 			case R.id.action_settings:
 				startActivity(new Intent(this, SettingsActivity.class));
@@ -300,7 +308,7 @@ public abstract class XmppActivity extends Activity {
 
 	protected SharedPreferences getPreferences() {
 		return PreferenceManager
-				.getDefaultSharedPreferences(getApplicationContext());
+			.getDefaultSharedPreferences(getApplicationContext());
 	}
 
 	public boolean useSubjectToIdentifyConference() {
@@ -312,7 +320,7 @@ public abstract class XmppActivity extends Activity {
 	}
 
 	public void switchToConversation(Conversation conversation, String text,
-									 boolean newTask) {
+			boolean newTask) {
 		switchToConversation(conversation,text,null,newTask);
 	}
 
@@ -372,7 +380,7 @@ public abstract class XmppActivity extends Activity {
 
 					@Override
 					public void userInputRequried(PendingIntent pi,
-												  Account account) {
+							Account account) {
 						try {
 							startIntentSenderForResult(pi.getIntentSender(),
 									REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
@@ -383,15 +391,15 @@ public abstract class XmppActivity extends Activity {
 					@Override
 					public void success(Account account) {
 						xmppConnectionService.databaseBackend
-								.updateAccount(account);
+							.updateAccount(account);
 						xmppConnectionService.sendPresencePacket(account,
 								xmppConnectionService.getPresenceGenerator()
-										.sendPresence(account));
+								.sendPresence(account));
 						if (conversation != null) {
 							conversation
-									.setNextEncryption(Message.ENCRYPTION_PGP);
+								.setNextEncryption(Message.ENCRYPTION_PGP);
 							xmppConnectionService.databaseBackend
-									.updateConversation(conversation);
+								.updateConversation(conversation);
 						}
 					}
 
@@ -420,7 +428,7 @@ public abstract class XmppActivity extends Activity {
 	}
 
 	protected void showAddToRosterDialog(final Conversation conversation) {
-		final Jid jid = conversation.getContactJid();
+		final Jid jid = conversation.getJid();
 		AlertDialog.Builder builder = new AlertDialog.Builder(this);
 		builder.setTitle(jid.toString());
 		builder.setMessage(getString(R.string.not_in_roster));
@@ -430,7 +438,7 @@ public abstract class XmppActivity extends Activity {
 
 					@Override
 					public void onClick(DialogInterface dialog, int which) {
-						final Jid jid = conversation.getContactJid();
+						final Jid jid = conversation.getJid();
 						Account account = conversation.getAccount();
 						Contact contact = account.getRoster().getContact(jid);
 						xmppConnectionService.createContact(contact);
@@ -462,7 +470,7 @@ public abstract class XmppActivity extends Activity {
 	}
 
 	private void warnMutalPresenceSubscription(final Conversation conversation,
-											   final OnPresenceSelected listener) {
+			final OnPresenceSelected listener) {
 		AlertDialog.Builder builder = new AlertDialog.Builder(this);
 		builder.setTitle(conversation.getContact().getJid().toString());
 		builder.setMessage(R.string.without_mutual_presence_updates);
@@ -485,13 +493,13 @@ public abstract class XmppActivity extends Activity {
 	}
 
 	protected void quickPasswordEdit(String previousValue,
-									 OnValueEdited callback) {
+			OnValueEdited callback) {
 		quickEdit(previousValue, callback, true);
 	}
 
 	@SuppressLint("InflateParams")
 	private void quickEdit(final String previousValue,
-						   final OnValueEdited callback, boolean password) {
+			final OnValueEdited callback, boolean password) {
 		AlertDialog.Builder builder = new AlertDialog.Builder(this);
 		View view = getLayoutInflater().inflate(R.layout.quickedit, null);
 		final EditText editor = (EditText) view.findViewById(R.id.editor);
@@ -521,7 +529,7 @@ public abstract class XmppActivity extends Activity {
 	}
 
 	public void selectPresence(final Conversation conversation,
-							   final OnPresenceSelected listener) {
+			final OnPresenceSelected listener) {
 		final Contact contact = conversation.getContact();
 		if (conversation.hasValidOtrSession()) {
 			SessionID id = conversation.getOtrSession().getSessionID();
@@ -576,7 +584,7 @@ public abstract class XmppActivity extends Activity {
 
 							@Override
 							public void onClick(DialogInterface dialog,
-												int which) {
+									int which) {
 								presence.delete(0, presence.length());
 								presence.append(presencesArray[which]);
 							}
@@ -600,7 +608,7 @@ public abstract class XmppActivity extends Activity {
 	}
 
 	protected void onActivityResult(int requestCode, int resultCode,
-									final Intent data) {
+			final Intent data) {
 		super.onActivityResult(requestCode, resultCode, data);
 		if (requestCode == REQUEST_INVITE_TO_CONVERSATION
 				&& resultCode == RESULT_OK) {
@@ -608,19 +616,19 @@ public abstract class XmppActivity extends Activity {
 				Jid jid = Jid.fromString(data.getStringExtra("contact"));
 				String conversationUuid = data.getStringExtra("conversation");
 				Conversation conversation = xmppConnectionService
-						.findConversationByUuid(conversationUuid);
+					.findConversationByUuid(conversationUuid);
 				if (conversation.getMode() == Conversation.MODE_MULTI) {
 					xmppConnectionService.invite(conversation, jid);
 				} else {
 					List<Jid> jids = new ArrayList<Jid>();
-					jids.add(conversation.getContactJid().toBareJid());
+					jids.add(conversation.getJid().toBareJid());
 					jids.add(jid);
 					xmppConnectionService.createAdhocConference(conversation.getAccount(), jids, adhocCallback);
 				}
 			} catch (final InvalidJidException ignored) {
 
 			}
-		}
+				}
 	}
 
 	private UiCallback<Conversation> adhocCallback = new UiCallback<Conversation>() {
@@ -688,18 +696,18 @@ public abstract class XmppActivity extends Activity {
 	}
 
 	protected void registerNdefPushMessageCallback() {
-			NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
-			if (nfcAdapter != null && nfcAdapter.isEnabled()) {
-				nfcAdapter.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() {
-					@Override
-					public NdefMessage createNdefMessage(NfcEvent nfcEvent) {
-                        return new NdefMessage(new NdefRecord[]{
-                                NdefRecord.createUri(getShareableUri()),
-                                NdefRecord.createApplicationRecord("eu.siacs.conversations")
-                        });
-					}
-				}, this);
-			}
+		NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
+		if (nfcAdapter != null && nfcAdapter.isEnabled()) {
+			nfcAdapter.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() {
+				@Override
+				public NdefMessage createNdefMessage(NfcEvent nfcEvent) {
+					return new NdefMessage(new NdefRecord[]{
+						NdefRecord.createUri(getShareableUri()),
+							NdefRecord.createApplicationRecord("eu.siacs.conversations")
+					});
+				}
+			}, this);
+		}
 	}
 
 	protected void unregisterNdefPushMessageCallback() {
@@ -831,13 +839,13 @@ public abstract class XmppActivity extends Activity {
 				try {
 					task.execute(message);
 				} catch (final RejectedExecutionException ignored) {
-                }
+				}
 			}
 		}
 	}
 
 	public static boolean cancelPotentialWork(Message message,
-											  ImageView imageView) {
+			ImageView imageView) {
 		final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
 
 		if (bitmapWorkerTask != null) {
@@ -866,7 +874,7 @@ public abstract class XmppActivity extends Activity {
 		private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
 
 		public AsyncDrawable(Resources res, Bitmap bitmap,
-							 BitmapWorkerTask bitmapWorkerTask) {
+				BitmapWorkerTask bitmapWorkerTask) {
 			super(res, bitmap);
 			bitmapWorkerTaskReference = new WeakReference<>(
 					bitmapWorkerTask);
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
index f728e800f..2465380fd 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
@@ -34,7 +34,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
 	public View getView(int position, View view, ViewGroup parent) {
 		if (view == null) {
 			LayoutInflater inflater = (LayoutInflater) activity
-					.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 			view = inflater.inflate(R.layout.conversation_list_row,
 					parent, false);
 		}
@@ -53,19 +53,19 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
 			}
 		}
 		TextView convName = (TextView) view
-				.findViewById(R.id.conversation_name);
+			.findViewById(R.id.conversation_name);
 		if (conversation.getMode() == Conversation.MODE_SINGLE
 				|| activity.useSubjectToIdentifyConference()) {
 			convName.setText(conversation.getName());
 		} else {
-			convName.setText(conversation.getContactJid().toBareJid().toString());
+			convName.setText(conversation.getJid().toBareJid().toString());
 		}
 		TextView mLastMessage = (TextView) view
-				.findViewById(R.id.conversation_lastmsg);
+			.findViewById(R.id.conversation_lastmsg);
 		TextView mTimestamp = (TextView) view
-				.findViewById(R.id.conversation_lastupdate);
+			.findViewById(R.id.conversation_lastupdate);
 		ImageView imagePreview = (ImageView) view
-				.findViewById(R.id.conversation_lastimage);
+			.findViewById(R.id.conversation_lastimage);
 
 		Message message = conversation.getLatestMessage();
 
@@ -151,12 +151,12 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
 			imagePreview.setVisibility(View.GONE);
 		}
 		mTimestamp.setText(UIHelper.readableTimeDifference(getContext(),
-				conversation.getLatestMessage().getTimeSent()));
+					conversation.getLatestMessage().getTimeSent()));
 
 		ImageView profilePicture = (ImageView) view
-				.findViewById(R.id.conversation_image);
+			.findViewById(R.id.conversation_image);
 		profilePicture.setImageBitmap(activity.avatarService().get(
-				conversation, activity.getPixel(56)));
+					conversation, activity.getPixel(56)));
 
 		return view;
 	}
diff --git a/src/main/java/eu/siacs/conversations/utils/Xmlns.java b/src/main/java/eu/siacs/conversations/utils/Xmlns.java
new file mode 100644
index 000000000..932e48ae6
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/utils/Xmlns.java
@@ -0,0 +1,5 @@
+package eu.siacs.conversations.utils;
+
+public final class Xmlns {
+	public static final String BLOCKING = "urn:xmpp:blocking";
+}
diff --git a/src/main/java/eu/siacs/conversations/utils/XmppUri.java b/src/main/java/eu/siacs/conversations/utils/XmppUri.java
index a9b8d1c03..d7c3bce5d 100644
--- a/src/main/java/eu/siacs/conversations/utils/XmppUri.java
+++ b/src/main/java/eu/siacs/conversations/utils/XmppUri.java
@@ -5,7 +5,6 @@ import android.net.Uri;
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
 
-import eu.siacs.conversations.utils.CryptoHelper;
 import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 import eu.siacs.conversations.xmpp.jid.Jid;
 
diff --git a/src/main/java/eu/siacs/conversations/xml/Element.java b/src/main/java/eu/siacs/conversations/xml/Element.java
index 9455d9e8f..517087595 100644
--- a/src/main/java/eu/siacs/conversations/xml/Element.java
+++ b/src/main/java/eu/siacs/conversations/xml/Element.java
@@ -62,16 +62,16 @@ public class Element {
 			if (child.getName().equals(name)
 					&& (child.getAttribute("xmlns").equals(xmlns))) {
 				return child;
-			}
+					}
 		}
 		return null;
 	}
 
-	public boolean hasChild(String name) {
+	public boolean hasChild(final String name) {
 		return findChild(name) != null;
 	}
 
-	public boolean hasChild(String name, String xmlns) {
+	public boolean hasChild(final String name, final String xmlns) {
 		return findChild(name, xmlns) != null;
 	}
 
@@ -110,15 +110,15 @@ public class Element {
 
 	public Jid getAttributeAsJid(String name) {
 		final String jid = this.getAttribute(name);
-        if (jid != null && !jid.isEmpty()) {
-            try {
-                return Jid.fromString(jid);
-            } catch (final InvalidJidException e) {
+		if (jid != null && !jid.isEmpty()) {
+			try {
+				return Jid.fromString(jid);
+			} catch (final InvalidJidException e) {
 				Log.e(Config.LOGTAG, "could not parse jid " + jid);
-                return null;
-            }
-        }
-        return null;
+				return null;
+			}
+		}
+		return null;
 	}
 
 	public Hashtable<String, String> getAttributes() {
diff --git a/src/main/java/eu/siacs/conversations/xmpp/OnContactStatusChanged.java b/src/main/java/eu/siacs/conversations/xmpp/OnContactStatusChanged.java
index 849e8e764..20b17f021 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/OnContactStatusChanged.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/OnContactStatusChanged.java
@@ -3,5 +3,5 @@ package eu.siacs.conversations.xmpp;
 import eu.siacs.conversations.entities.Contact;
 
 public interface OnContactStatusChanged {
-	public void onContactStatusChanged(Contact contact, boolean online);
+	public void onContactStatusChanged(final Contact contact, final boolean online);
 }
diff --git a/src/main/java/eu/siacs/conversations/xmpp/OnUpdateBlocklist.java b/src/main/java/eu/siacs/conversations/xmpp/OnUpdateBlocklist.java
new file mode 100644
index 000000000..92e72cfa8
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/xmpp/OnUpdateBlocklist.java
@@ -0,0 +1,13 @@
+package eu.siacs.conversations.xmpp;
+
+public interface OnUpdateBlocklist {
+	// Use an enum instead of a boolean to make sure we don't run into the boolean trap
+	// (`onUpdateBlocklist(true)' doesn't read well, and could be confusing).
+	public static enum Status {
+		BLOCKED,
+		UNBLOCKED
+	}
+
+	@SuppressWarnings("MethodNameSameAsClassName")
+	public void OnUpdateBlocklist(final Status status);
+}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
index b090d651a..7fd0a4b6c 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -30,10 +30,12 @@ import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.Map.Entry;
 
 import javax.net.ssl.HostnameVerifier;
@@ -48,8 +50,10 @@ import eu.siacs.conversations.crypto.sasl.Plain;
 import eu.siacs.conversations.crypto.sasl.SaslMechanism;
 import eu.siacs.conversations.crypto.sasl.ScramSha1;
 import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.generator.IqGenerator;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.utils.DNSHelper;
+import eu.siacs.conversations.utils.Xmlns;
 import eu.siacs.conversations.xml.Element;
 import eu.siacs.conversations.xml.Tag;
 import eu.siacs.conversations.xml.TagWriter;
@@ -76,19 +80,19 @@ public class XmppConnection implements Runnable {
 	private static final int PACKET_PRESENCE = 2;
 	private final Context applicationContext;
 	protected Account account;
-	private WakeLock wakeLock;
+	private final WakeLock wakeLock;
 	private Socket socket;
 	private XmlReader tagReader;
 	private TagWriter tagWriter;
-	private Features features = new Features(this);
+	private final Features features = new Features(this);
 	private boolean shouldBind = true;
 	private boolean shouldAuthenticate = true;
 	private Element streamFeatures;
-	private HashMap<String, List<String>> disco = new HashMap<>();
+	private final HashMap<String, List<String>> disco = new HashMap<>();
 
 	private String streamId = null;
 	private int smVersion = 3;
-	private SparseArray<String> messageReceipts = new SparseArray<>();
+	private final SparseArray<String> messageReceipts = new SparseArray<>();
 
 	private boolean enabledEncryption = false;
 	private boolean enabledCarbons = false;
@@ -100,20 +104,20 @@ public class XmppConnection implements Runnable {
 	private long lastConnect = 0;
 	private long lastSessionStarted = 0;
 	private int attempt = 0;
-	private Hashtable<String, PacketReceived> packetCallbacks = new Hashtable<>();
+	private final Map<String, PacketReceived> packetCallbacks = new Hashtable<>();
 	private OnPresencePacketReceived presenceListener = null;
 	private OnJinglePacketReceived jingleListener = null;
 	private OnIqPacketReceived unregisteredIqListener = null;
 	private OnMessagePacketReceived messageListener = null;
 	private OnStatusChanged statusListener = null;
 	private OnBindListener bindListener = null;
-	private ArrayList<OnAdvancedStreamFeaturesLoaded> advancedStreamFeaturesLoadedListeners = new ArrayList<>();
+	private final ArrayList<OnAdvancedStreamFeaturesLoaded> advancedStreamFeaturesLoadedListeners = new ArrayList<>();
 	private OnMessageAcknowledged acknowledgedListener = null;
 	private XmppConnectionService mXmppConnectionService = null;
 
 	private SaslMechanism saslMechanism;
 
-	public XmppConnection(Account account, XmppConnectionService service) {
+	public XmppConnection(final Account account, final XmppConnectionService service) {
 		this.account = account;
 		this.wakeLock = service.getPowerManager().newWakeLock(
 				PowerManager.PARTIAL_WAKE_LOCK, account.getJid().toBareJid().toString());
@@ -129,7 +133,7 @@ public class XmppConnection implements Runnable {
 					&& (account.getStatus() != Account.State.ONLINE)
 					&& (account.getStatus() != Account.State.DISABLED)) {
 				return;
-			}
+					}
 			if (nextStatus == Account.State.ONLINE) {
 				this.attempt = 0;
 			}
@@ -153,15 +157,15 @@ public class XmppConnection implements Runnable {
 			tagWriter = new TagWriter();
 			packetCallbacks.clear();
 			this.changeStatus(Account.State.CONNECTING);
-			Bundle result = DNSHelper.getSRVRecord(account.getServer());
-			ArrayList<Parcelable> values = result.getParcelableArrayList("values");
+			final Bundle result = DNSHelper.getSRVRecord(account.getServer());
+			final ArrayList<Parcelable> values = result.getParcelableArrayList("values");
 			if ("timeout".equals(result.getString("error"))) {
 				throw new IOException("timeout in dns");
 			} else if (values != null) {
 				int i = 0;
 				boolean socketError = true;
 				while (socketError && values.size() > i) {
-					Bundle namePort = (Bundle) values.get(i);
+					final Bundle namePort = (Bundle) values.get(i);
 					try {
 						String srvRecordServer;
 						try {
@@ -170,9 +174,9 @@ public class XmppConnection implements Runnable {
 							// TODO: Handle me?`
 							srvRecordServer = "";
 						}
-						int srvRecordPort = namePort.getInt("port");
-						String srvIpServer = namePort.getString("ip");
-						InetSocketAddress addr;
+						final int srvRecordPort = namePort.getInt("port");
+						final String srvIpServer = namePort.getString("ip");
+						final InetSocketAddress addr;
 						if (srvIpServer != null) {
 							addr = new InetSocketAddress(srvIpServer, srvRecordPort);
 							Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
@@ -187,10 +191,10 @@ public class XmppConnection implements Runnable {
 						socket = new Socket();
 						socket.connect(addr, 20000);
 						socketError = false;
-					} catch (UnknownHostException e) {
+					} catch (final UnknownHostException e) {
 						Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage());
 						i++;
-					} catch (IOException e) {
+					} catch (final IOException e) {
 						Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage());
 						i++;
 					}
@@ -204,9 +208,9 @@ public class XmppConnection implements Runnable {
 			} else {
 				throw new IOException("timeout in dns");
 			}
-			OutputStream out = socket.getOutputStream();
+			final OutputStream out = socket.getOutputStream();
 			tagWriter.setOutputStream(out);
-			InputStream in = socket.getInputStream();
+			final InputStream in = socket.getInputStream();
 			tagReader.setInputStream(in);
 			tagWriter.beginDocument();
 			sendStartStream();
@@ -222,14 +226,9 @@ public class XmppConnection implements Runnable {
 			if (socket.isConnected()) {
 				socket.close();
 			}
-		} catch (UnknownHostException e) {
+		} catch (final UnknownHostException | ConnectException e) {
 			this.changeStatus(Account.State.SERVER_NOT_FOUND);
-		} catch (final ConnectException e) {
-			this.changeStatus(Account.State.SERVER_NOT_FOUND);
-		} catch (final IOException | XmlPullParserException e) {
-			Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage());
-			this.changeStatus(Account.State.OFFLINE);
-		} catch (NoSuchAlgorithmException e) {
+		} catch (final IOException | XmlPullParserException | NoSuchAlgorithmException e) {
 			Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage());
 			this.changeStatus(Account.State.OFFLINE);
 		} finally {
@@ -268,7 +267,7 @@ public class XmppConnection implements Runnable {
 								}
 								Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": logged in");
 								account.setKey(Account.PINNED_MECHANISM_KEY,
-                                        String.valueOf(saslMechanism.getPriority()));
+										String.valueOf(saslMechanism.getPriority()));
 								tagReader.reset();
 								sendStartStream();
 								processStream(tagReader.readTag());
@@ -289,7 +288,7 @@ public class XmppConnection implements Runnable {
 								}
 								tagWriter.writeElement(response);
 							} else if (nextTag.isStart("enabled")) {
-								Element enabled = tagReader.readElement(nextTag);
+								final Element enabled = tagReader.readElement(nextTag);
 								if ("true".equals(enabled.getAttribute("resume"))) {
 									this.streamId = enabled.getAttribute("id");
 									Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
@@ -301,14 +300,14 @@ public class XmppConnection implements Runnable {
 								}
 								this.lastSessionStarted = SystemClock.elapsedRealtime();
 								this.stanzasReceived = 0;
-								RequestPacket r = new RequestPacket(smVersion);
+								final RequestPacket r = new RequestPacket(smVersion);
 								tagWriter.writeStanzaAsync(r);
 							} else if (nextTag.isStart("resumed")) {
 								lastPaketReceived = SystemClock.elapsedRealtime();
-								Element resumed = tagReader.readElement(nextTag);
-								String h = resumed.getAttribute("h");
+								final Element resumed = tagReader.readElement(nextTag);
+								final String h = resumed.getAttribute("h");
 								try {
-									int serverCount = Integer.parseInt(h);
+									final int serverCount = Integer.parseInt(h);
 									if (serverCount != stanzasSent) {
 										Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
 												+ ": session resumed with lost packages");
@@ -327,20 +326,19 @@ public class XmppConnection implements Runnable {
 									}
 									messageReceipts.clear();
 								} catch (final NumberFormatException ignored) {
-
 								}
 								sendServiceDiscoveryInfo(account.getServer());
 								sendServiceDiscoveryItems(account.getServer());
 								sendInitialPing();
 							} else if (nextTag.isStart("r")) {
 								tagReader.readElement(nextTag);
-								AckPacket ack = new AckPacket(this.stanzasReceived, smVersion);
+								final AckPacket ack = new AckPacket(this.stanzasReceived, smVersion);
 								tagWriter.writeStanzaAsync(ack);
 							} else if (nextTag.isStart("a")) {
-								Element ack = tagReader.readElement(nextTag);
+								final Element ack = tagReader.readElement(nextTag);
 								lastPaketReceived = SystemClock.elapsedRealtime();
-								int serverSequence = Integer.parseInt(ack.getAttribute("h"));
-								String msgId = this.messageReceipts.get(serverSequence);
+								final int serverSequence = Integer.parseInt(ack.getAttribute("h"));
+								final String msgId = this.messageReceipts.get(serverSequence);
 								if (msgId != null) {
 									if (this.acknowledgedListener != null) {
 										this.acknowledgedListener.onMessageAcknowledged(
@@ -374,13 +372,12 @@ public class XmppConnection implements Runnable {
 
 	private void sendInitialPing() {
 		Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": sending intial ping");
-		IqPacket iq = new IqPacket(IqPacket.TYPE_GET);
+		final IqPacket iq = new IqPacket(IqPacket.TYPE_GET);
 		iq.setFrom(account.getJid());
 		iq.addChild("ping", "urn:xmpp:ping");
 		this.sendIqPacket(iq, new OnIqPacketReceived() {
-
 			@Override
-			public void onIqPacketReceived(Account account, IqPacket packet) {
+			public void onIqPacketReceived(final Account account, final IqPacket packet) {
 				Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
 						+ ": online with resource " + account.getResource());
 				changeStatus(Account.State.ONLINE);
@@ -388,7 +385,7 @@ public class XmppConnection implements Runnable {
 		});
 	}
 
-	private Element processPacket(Tag currentTag, int packetType)
+	private Element processPacket(final Tag currentTag, final int packetType)
 		throws XmlPullParserException, IOException {
 		Element element;
 		switch (packetType) {
@@ -411,8 +408,8 @@ public class XmppConnection implements Runnable {
 		}
 		while (!nextTag.isEnd(element.getName())) {
 			if (!nextTag.isNo()) {
-				Element child = tagReader.readElement(nextTag);
-				String type = currentTag.getAttribute("type");
+				final Element child = tagReader.readElement(nextTag);
+				final String type = currentTag.getAttribute("type");
 				if (packetType == PACKET_IQ
 						&& "jingle".equals(child.getName())
 						&& ("set".equalsIgnoreCase(type) || "get"
@@ -432,9 +429,9 @@ public class XmppConnection implements Runnable {
 		return element;
 	}
 
-	private void processIq(Tag currentTag) throws XmlPullParserException,
+	private void processIq(final Tag currentTag) throws XmlPullParserException,
 					IOException {
-						IqPacket packet = (IqPacket) processPacket(currentTag, PACKET_IQ);
+						final IqPacket packet = (IqPacket) processPacket(currentTag, PACKET_IQ);
 
 						if (packet.getId() == null) {
 							return; // an iq packet without id is definitely invalid
@@ -461,11 +458,11 @@ public class XmppConnection implements Runnable {
 						}
 	}
 
-	private void processMessage(Tag currentTag) throws XmlPullParserException,
+	private void processMessage(final Tag currentTag) throws XmlPullParserException,
 					IOException {
-						MessagePacket packet = (MessagePacket) processPacket(currentTag,
+						final MessagePacket packet = (MessagePacket) processPacket(currentTag,
 								PACKET_MESSAGE);
-						String id = packet.getAttribute("id");
+						final String id = packet.getAttribute("id");
 						if ((id != null) && (packetCallbacks.containsKey(id))) {
 							if (packetCallbacks.get(id) instanceof OnMessagePacketReceived) {
 								((OnMessagePacketReceived) packetCallbacks.get(id))
@@ -477,11 +474,11 @@ public class XmppConnection implements Runnable {
 						}
 	}
 
-	private void processPresence(Tag currentTag) throws XmlPullParserException,
+	private void processPresence(final Tag currentTag) throws XmlPullParserException,
 					IOException {
 						PresencePacket packet = (PresencePacket) processPacket(currentTag,
 								PACKET_PRESENCE);
-						String id = packet.getAttribute("id");
+						final String id = packet.getAttribute("id");
 						if ((id != null) && (packetCallbacks.containsKey(id))) {
 							if (packetCallbacks.get(id) instanceof OnPresencePacketReceived) {
 								((OnPresencePacketReceived) packetCallbacks.get(id))
@@ -494,7 +491,7 @@ public class XmppConnection implements Runnable {
 	}
 
 	private void sendStartTLS() throws IOException {
-		Tag startTLS = Tag.empty("starttls");
+		final Tag startTLS = Tag.empty("starttls");
 		startTLS.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-tls");
 		tagWriter.writeTag(startTLS);
 	}
@@ -512,11 +509,11 @@ public class XmppConnection implements Runnable {
 					IOException {
 						tagReader.readTag();
 						try {
-							SSLContext sc = SSLContext.getInstance("TLS");
+							final SSLContext sc = SSLContext.getInstance("TLS");
 							sc.init(null,
 									new X509TrustManager[]{this.mXmppConnectionService.getMemorizingTrustManager()},
 									mXmppConnectionService.getRNG());
-							SSLSocketFactory factory = sc.getSocketFactory();
+							final SSLSocketFactory factory = sc.getSocketFactory();
 
 							if (factory == null) {
 								throw new IOException("SSLSocketFactory was null");
@@ -541,7 +538,7 @@ public class XmppConnection implements Runnable {
 							if (enableLegacySSL()) {
 								supportProtocols = sslSocket.getSupportedProtocols();
 							} else {
-								final List<String> supportedProtocols = new LinkedList<>(
+								final Collection<String> supportedProtocols = new LinkedList<>(
 										Arrays.asList(sslSocket.getSupportedProtocols()));
 								supportedProtocols.remove("SSLv3");
 								supportProtocols = new String[supportedProtocols.size()];
@@ -549,13 +546,13 @@ public class XmppConnection implements Runnable {
 							}
 							sslSocket.setEnabledProtocols(supportProtocols);
 
-                            if (verifier != null
-                                    && !verifier.verify(account.getServer().getDomainpart(),
-                                    sslSocket.getSession())) {
+							if (verifier != null
+									&& !verifier.verify(account.getServer().getDomainpart(),
+										sslSocket.getSession())) {
 								Log.d(Config.LOGTAG,account.getJid().toBareJid()+": TLS certificate verification failed");
 								disconnect(true);
 								changeStatus(Account.State.SECURITY_ERROR);
-                            }
+									}
 							tagReader.setInputStream(sslSocket.getInputStream());
 							tagWriter.setOutputStream(sslSocket.getOutputStream());
 							sendStartStream();
@@ -569,7 +566,7 @@ public class XmppConnection implements Runnable {
 						}
 	}
 
-	private void processStreamFeatures(Tag currentTag)
+	private void processStreamFeatures(final Tag currentTag)
 		throws XmlPullParserException, IOException {
 		this.streamFeatures = tagReader.readElement(currentTag);
 		if (this.streamFeatures.hasChild("starttls") && !enabledEncryption) {
@@ -605,7 +602,7 @@ public class XmppConnection implements Runnable {
 							"). Possible downgrade attack?");
 					disconnect(true);
 					changeStatus(Account.State.SECURITY_ERROR);
-				}
+						}
 			} catch (final JSONException e) {
 				Log.d(Config.LOGTAG, "Parse error while checking pinned auth mechanism");
 			}
@@ -618,7 +615,7 @@ public class XmppConnection implements Runnable {
 		} else if (this.streamFeatures.hasChild("sm", "urn:xmpp:sm:"
 					+ smVersion)
 				&& streamId != null) {
-			ResumePacket resume = new ResumePacket(this.streamId,
+			final ResumePacket resume = new ResumePacket(this.streamId,
 					stanzasReceived, smVersion);
 			this.tagWriter.writeStanzaAsync(resume);
 		} else if (this.streamFeatures.hasChild("bind") && shouldBind) {
@@ -629,45 +626,44 @@ public class XmppConnection implements Runnable {
 		}
 	}
 
-	private List<String> extractMechanisms(Element stream) {
-		ArrayList<String> mechanisms = new ArrayList<>(stream
+	private List<String> extractMechanisms(final Element stream) {
+		final ArrayList<String> mechanisms = new ArrayList<>(stream
 				.getChildren().size());
-		for (Element child : stream.getChildren()) {
+		for (final Element child : stream.getChildren()) {
 			mechanisms.add(child.getContent());
 		}
 		return mechanisms;
 	}
 
 	private void sendRegistryRequest() {
-		IqPacket register = new IqPacket(IqPacket.TYPE_GET);
+		final IqPacket register = new IqPacket(IqPacket.TYPE_GET);
 		register.query("jabber:iq:register");
 		register.setTo(account.getServer());
 		sendIqPacket(register, new OnIqPacketReceived() {
 
 			@Override
-			public void onIqPacketReceived(Account account, IqPacket packet) {
-				Element instructions = packet.query().findChild("instructions");
+			public void onIqPacketReceived(final Account account, final IqPacket packet) {
+				final Element instructions = packet.query().findChild("instructions");
 				if (packet.query().hasChild("username")
 						&& (packet.query().hasChild("password"))) {
-					IqPacket register = new IqPacket(IqPacket.TYPE_SET);
-					Element username = new Element("username")
-							.setContent(account.getUsername());
-					Element password = new Element("password")
-							.setContent(account.getPassword());
+					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);
 					sendIqPacket(register, new OnIqPacketReceived() {
 
 						@Override
-						public void onIqPacketReceived(Account account,
-													   IqPacket packet) {
+						public void onIqPacketReceived(final Account account, final IqPacket packet) {
 							if (packet.getType() == IqPacket.TYPE_RESULT) {
 								account.setOption(Account.OPTION_REGISTER,
 										false);
 								changeStatus(Account.State.REGISTRATION_SUCCESSFUL);
 							} else if (packet.hasChild("error")
 									&& (packet.findChild("error")
-									.hasChild("conflict"))) {
+										.hasChild("conflict"))) {
 								changeStatus(Account.State.REGISTRATION_CONFLICT);
 							} else {
 								changeStatus(Account.State.REGISTRATION_FAILED);
@@ -687,14 +683,14 @@ public class XmppConnection implements Runnable {
 		});
 	}
 
-	private void sendBindRequest() throws IOException {
-		IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
+	private void sendBindRequest() {
+		final IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
 		iq.addChild("bind", "urn:ietf:params:xml:ns:xmpp-bind")
 			.addChild("resource").setContent(account.getResource());
 		this.sendUnboundIqPacket(iq, new OnIqPacketReceived() {
 			@Override
-			public void onIqPacketReceived(Account account, IqPacket packet) {
-				Element bind = packet.findChild("bind");
+			public void onIqPacketReceived(final Account account, final IqPacket packet) {
+				final Element bind = packet.findChild("bind");
 				if (bind != null) {
 					final Element jid = bind.findChild("jid");
 					if (jid != null && jid.getContent() != null) {
@@ -705,14 +701,14 @@ public class XmppConnection implements Runnable {
 						}
 						if (streamFeatures.hasChild("sm", "urn:xmpp:sm:3")) {
 							smVersion = 3;
-							EnablePacket enable = new EnablePacket(smVersion);
+							final EnablePacket enable = new EnablePacket(smVersion);
 							tagWriter.writeStanzaAsync(enable);
 							stanzasSent = 0;
 							messageReceipts.clear();
 						} else if (streamFeatures.hasChild("sm",
-								"urn:xmpp:sm:2")) {
+									"urn:xmpp:sm:2")) {
 							smVersion = 2;
-							EnablePacket enable = new EnablePacket(smVersion);
+							final EnablePacket enable = new EnablePacket(smVersion);
 							tagWriter.writeStanzaAsync(enable);
 							stanzasSent = 0;
 							messageReceipts.clear();
@@ -736,7 +732,7 @@ public class XmppConnection implements Runnable {
 		if (this.streamFeatures.hasChild("session")) {
 			Log.d(Config.LOGTAG, account.getJid().toBareJid()
 					+ ": sending deprecated session");
-			IqPacket startSession = new IqPacket(IqPacket.TYPE_SET);
+			final IqPacket startSession = new IqPacket(IqPacket.TYPE_SET);
 			startSession.addChild("session",
 					"urn:ietf:params:xml:ns:xmpp-session");
 			this.sendUnboundIqPacket(startSession, null);
@@ -755,10 +751,10 @@ public class XmppConnection implements Runnable {
 			this.sendIqPacket(iq, new OnIqPacketReceived() {
 
 				@Override
-				public void onIqPacketReceived(Account account, IqPacket packet) {
+				public void onIqPacketReceived(final Account account, final IqPacket packet) {
 					final List<Element> elements = packet.query().getChildren();
 					final List<String> features = new ArrayList<>();
-					for (Element element : elements) {
+					for (final Element element : elements) {
 						if (element.getName().equals("identity")) {
 							if ("irc".equals(element.getAttribute("type"))) {
 								//add fake feature to not confuse irc and real muc
@@ -772,7 +768,7 @@ public class XmppConnection implements Runnable {
 
 					if (account.getServer().equals(server.toDomainJid())) {
 						enableAdvancedStreamFeatures();
-						for(OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) {
+						for (final OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) {
 							listener.onAdvancedStreamFeaturesAvailable(account);
 						}
 					}
@@ -787,6 +783,10 @@ public class XmppConnection implements Runnable {
 				sendEnableCarbons();
 			}
 		}
+		if (getFeatures().blocking()) {
+			Log.d(Config.LOGTAG, "Requesting block list");
+			this.sendIqPacket(getIqGenerator().generateGetBlockList(), mXmppConnectionService.getIqParser());
+		}
 	}
 
 	private void sendServiceDiscoveryItems(final Jid server) {
@@ -796,9 +796,9 @@ public class XmppConnection implements Runnable {
 		this.sendIqPacket(iq, new OnIqPacketReceived() {
 
 			@Override
-			public void onIqPacketReceived(Account account, IqPacket packet) {
-				List<Element> elements = packet.query().getChildren();
-				for (Element element : elements) {
+			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())) {
@@ -811,12 +811,12 @@ public class XmppConnection implements Runnable {
 	}
 
 	private void sendEnableCarbons() {
-		IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
+		final IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
 		iq.addChild("enable", "urn:xmpp:carbons:2");
 		this.sendIqPacket(iq, new OnIqPacketReceived() {
 
 			@Override
-			public void onIqPacketReceived(Account account, IqPacket packet) {
+			public void onIqPacketReceived(final Account account, final IqPacket packet) {
 				if (!packet.hasChild("error")) {
 					Log.d(Config.LOGTAG, account.getJid().toBareJid()
 							+ ": successfully enabled carbons");
@@ -829,20 +829,20 @@ public class XmppConnection implements Runnable {
 		});
 	}
 
-	private void processStreamError(Tag currentTag)
+	private void processStreamError(final Tag currentTag)
 		throws XmlPullParserException, IOException {
-		Element streamError = tagReader.readElement(currentTag);
+		final Element streamError = tagReader.readElement(currentTag);
 		if (streamError != null && streamError.hasChild("conflict")) {
 			final String resource = account.getResource().split("\\.")[0];
 			account.setResource(resource + "." + nextRandomId());
 			Log.d(Config.LOGTAG,
 					account.getJid().toBareJid() + ": switching resource due to conflict ("
-							+ account.getResource() + ")");
+					+ account.getResource() + ")");
 		}
 	}
 
 	private void sendStartStream() throws IOException {
-		Tag stream = Tag.start("stream:stream");
+		final Tag stream = Tag.start("stream:stream");
 		stream.setAttribute("from", account.getJid().toBareJid().toString());
 		stream.setAttribute("to", account.getServer().toString());
 		stream.setAttribute("version", "1.0");
@@ -856,33 +856,32 @@ public class XmppConnection implements Runnable {
 		return new BigInteger(50, mXmppConnectionService.getRNG()).toString(32);
 	}
 
-	public void sendIqPacket(IqPacket packet, OnIqPacketReceived callback) {
+	public void sendIqPacket(final IqPacket packet, final PacketReceived callback) {
 		if (packet.getId() == null) {
-			String id = nextRandomId();
+			final String id = nextRandomId();
 			packet.setAttribute("id", id);
 		}
 		packet.setFrom(account.getJid());
 		this.sendPacket(packet, callback);
 	}
 
-	public void sendUnboundIqPacket(IqPacket packet, OnIqPacketReceived callback) {
+	public void sendUnboundIqPacket(final IqPacket packet, final PacketReceived callback) {
 		if (packet.getId() == null) {
-			String id = nextRandomId();
+			final String id = nextRandomId();
 			packet.setAttribute("id", id);
 		}
 		this.sendPacket(packet, callback);
 	}
 
-	public void sendMessagePacket(MessagePacket packet) {
+	public void sendMessagePacket(final MessagePacket packet) {
 		this.sendPacket(packet, null);
 	}
 
-	public void sendPresencePacket(PresencePacket packet) {
+	public void sendPresencePacket(final PresencePacket packet) {
 		this.sendPacket(packet, null);
 	}
 
-	private synchronized void sendPacket(final AbstractStanza packet,
-			PacketReceived callback) {
+	private synchronized void sendPacket(final AbstractStanza packet, final PacketReceived callback) {
 		if (packet.getName().equals("iq") || packet.getName().equals("message")
 				|| packet.getName().equals("presence")) {
 			++stanzasSent;
@@ -907,7 +906,7 @@ public class XmppConnection implements Runnable {
 		if (streamFeatures.hasChild("sm")) {
 			tagWriter.writeStanzaAsync(new RequestPacket(smVersion));
 		} else {
-			IqPacket iq = new IqPacket(IqPacket.TYPE_GET);
+			final IqPacket iq = new IqPacket(IqPacket.TYPE_GET);
 			iq.setFrom(account.getJid());
 			iq.addChild("ping", "urn:xmpp:ping");
 			this.sendIqPacket(iq, null);
@@ -916,44 +915,44 @@ public class XmppConnection implements Runnable {
 	}
 
 	public void setOnMessagePacketReceivedListener(
-			OnMessagePacketReceived listener) {
+			final OnMessagePacketReceived listener) {
 		this.messageListener = listener;
 			}
 
 	public void setOnUnregisteredIqPacketReceivedListener(
-			OnIqPacketReceived listener) {
+			final OnIqPacketReceived listener) {
 		this.unregisteredIqListener = listener;
 			}
 
 	public void setOnPresencePacketReceivedListener(
-			OnPresencePacketReceived listener) {
+			final OnPresencePacketReceived listener) {
 		this.presenceListener = listener;
 			}
 
 	public void setOnJinglePacketReceivedListener(
-			OnJinglePacketReceived listener) {
+			final OnJinglePacketReceived listener) {
 		this.jingleListener = listener;
 			}
 
-	public void setOnStatusChangedListener(OnStatusChanged listener) {
+	public void setOnStatusChangedListener(final OnStatusChanged listener) {
 		this.statusListener = listener;
 	}
 
-	public void setOnBindListener(OnBindListener listener) {
+	public void setOnBindListener(final OnBindListener listener) {
 		this.bindListener = listener;
 	}
 
-	public void setOnMessageAcknowledgeListener(OnMessageAcknowledged listener) {
+	public void setOnMessageAcknowledgeListener(final OnMessageAcknowledged listener) {
 		this.acknowledgedListener = listener;
 	}
 
-	public void addOnAdvancedStreamFeaturesAvailableListener(OnAdvancedStreamFeaturesLoaded listener) {
+	public void addOnAdvancedStreamFeaturesAvailableListener(final OnAdvancedStreamFeaturesLoaded listener) {
 		if (!this.advancedStreamFeaturesLoadedListeners.contains(listener)) {
 			this.advancedStreamFeaturesLoadedListeners.add(listener);
 		}
 	}
 
-	public void disconnect(boolean force) {
+	public void disconnect(final boolean force) {
 		Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting");
 		try {
 			if (force) {
@@ -973,23 +972,23 @@ public class XmppConnection implements Runnable {
 							}
 							tagWriter.writeTag(Tag.end("stream:stream"));
 							socket.close();
-						} catch (IOException e) {
+						} catch (final IOException e) {
 							Log.d(Config.LOGTAG,
 									"io exception during disconnect");
-						} catch (InterruptedException e) {
+						} catch (final InterruptedException e) {
 							Log.d(Config.LOGTAG, "interrupted");
 						}
 					}
 				}
 			}).start();
-		} catch (IOException e) {
+		} catch (final IOException e) {
 			Log.d(Config.LOGTAG, "io exception during disconnect");
 		}
 	}
 
-	public List<String> findDiscoItemsByFeature(String feature) {
+	public List<String> findDiscoItemsByFeature(final String feature) {
 		final List<String> items = new ArrayList<>();
-		for (Entry<String, List<String>> cursor : disco.entrySet()) {
+		for (final Entry<String, List<String>> cursor : disco.entrySet()) {
 			if (cursor.getValue().contains(feature)) {
 				items.add(cursor.getKey());
 			}
@@ -997,8 +996,8 @@ public class XmppConnection implements Runnable {
 		return items;
 	}
 
-	public String findDiscoItemByFeature(String feature) {
-		List<String> items = findDiscoItemsByFeature(feature);
+	public String findDiscoItemByFeature(final String feature) {
+		final List<String> items = findDiscoItemsByFeature(feature);
 		if (items.size() >= 1) {
 			return items.get(0);
 		}
@@ -1010,8 +1009,7 @@ public class XmppConnection implements Runnable {
 	}
 
 	public String getMucServer() {
-		final List<String> items = new ArrayList<>();
-		for (Entry<String, List<String>> cursor : disco.entrySet()) {
+		for (final Entry<String, List<String>> cursor : disco.entrySet()) {
 			final List<String> value = cursor.getValue();
 			if (value.contains("http://jabber.org/protocol/muc") && !value.contains("jabber:iq:gateway") && !value.contains("siacs:no:muc")) {
 				return cursor.getKey();
@@ -1021,8 +1019,8 @@ public class XmppConnection implements Runnable {
 	}
 
 	public int getTimeToNextAttempt() {
-		int interval = (int) (25 * Math.pow(1.5, attempt));
-		int secondsSinceLast = (int) ((SystemClock.elapsedRealtime() - this.lastConnect) / 1000);
+		final int interval = (int) (25 * Math.pow(1.5, attempt));
+		final int secondsSinceLast = (int) ((SystemClock.elapsedRealtime() - this.lastConnect) / 1000);
 		return interval - secondsSinceLast;
 	}
 
@@ -1035,7 +1033,7 @@ public class XmppConnection implements Runnable {
 	}
 
 	public long getLastSessionEstablished() {
-		long diff;
+		final long diff;
 		if (this.lastSessionStarted == 0) {
 			diff = SystemClock.elapsedRealtime() - this.lastConnect;
 		} else {
@@ -1067,7 +1065,7 @@ public class XmppConnection implements Runnable {
 	public class Features {
 		XmppConnection connection;
 
-		public Features(XmppConnection connection) {
+		public Features(final XmppConnection connection) {
 			this.connection = connection;
 		}
 
@@ -1080,6 +1078,10 @@ public class XmppConnection implements Runnable {
 			return hasDiscoFeature(account.getServer(), "urn:xmpp:carbons:2");
 		}
 
+		public boolean blocking() {
+			return hasDiscoFeature(account.getServer(), Xmlns.BLOCKING);
+		}
+
 		public boolean sm() {
 			return streamId != null;
 		}
@@ -1110,4 +1112,8 @@ public class XmppConnection implements Runnable {
 				.findDiscoItemByFeature("http://jabber.org/protocol/bytestreams") != null;
 		}
 	}
+
+	private IqGenerator getIqGenerator() {
+		return mXmppConnectionService.getIqGenerator();
+	}
 }
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java b/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java
index c40fa0b65..a35ea37cd 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java
@@ -32,7 +32,7 @@ public final class Jid {
 		return resourcepart;
 	}
 
-	public static Jid fromSessionID(SessionID id) throws InvalidJidException{
+	public static Jid fromSessionID(final SessionID id) throws InvalidJidException{
 		if (id.getUserID().isEmpty()) {
 			return Jid.fromString(id.getAccountID());
 		} else {
@@ -190,4 +190,8 @@ public final class Jid {
 	public boolean isBareJid() {
 		return this.resourcepart.isEmpty();
 	}
+
+	public boolean isDomainJid() {
+		return !this.hasLocalpart();
+	}
 }
diff --git a/src/main/java/eu/siacs/conversations/xmpp/stanzas/IqPacket.java b/src/main/java/eu/siacs/conversations/xmpp/stanzas/IqPacket.java
index 9df05e678..9eff4cbf3 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/stanzas/IqPacket.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/stanzas/IqPacket.java
@@ -9,27 +9,27 @@ public class IqPacket extends AbstractStanza {
 	public static final int TYPE_RESULT = 1;
 	public static final int TYPE_GET = 2;
 
-	private IqPacket(String name) {
+	private IqPacket(final String name) {
 		super(name);
 	}
 
-	public IqPacket(int type) {
+	public IqPacket(final int type) {
 		super("iq");
 		switch (type) {
-		case TYPE_SET:
-			this.setAttribute("type", "set");
-			break;
-		case TYPE_GET:
-			this.setAttribute("type", "get");
-			break;
-		case TYPE_RESULT:
-			this.setAttribute("type", "result");
-			break;
-		case TYPE_ERROR:
-			this.setAttribute("type", "error");
-			break;
-		default:
-			break;
+			case TYPE_SET:
+				this.setAttribute("type", "set");
+				break;
+			case TYPE_GET:
+				this.setAttribute("type", "get");
+				break;
+			case TYPE_RESULT:
+				this.setAttribute("type", "result");
+				break;
+			case TYPE_ERROR:
+				this.setAttribute("type", "error");
+				break;
+			default:
+				break;
 		}
 	}
 
@@ -45,29 +45,30 @@ public class IqPacket extends AbstractStanza {
 		return query;
 	}
 
-	public Element query(String xmlns) {
-		Element query = query();
+	public Element query(final String xmlns) {
+		final Element query = query();
 		query.setAttribute("xmlns", xmlns);
 		return query();
 	}
 
 	public int getType() {
-		String type = getAttribute("type");
-		if ("error".equals(type)) {
-			return TYPE_ERROR;
-		} else if ("result".equals(type)) {
-			return TYPE_RESULT;
-		} else if ("set".equals(type)) {
-			return TYPE_SET;
-		} else if ("get".equals(type)) {
-			return TYPE_GET;
-		} else {
-			return 1000;
+		final String type = getAttribute("type");
+		switch (type) {
+			case "error":
+				return TYPE_ERROR;
+			case "result":
+				return TYPE_RESULT;
+			case "set":
+				return TYPE_SET;
+			case "get":
+				return TYPE_GET;
+			default:
+				return 1000;
 		}
 	}
 
-	public IqPacket generateRespone(int type) {
-		IqPacket packet = new IqPacket(type);
+	public IqPacket generateRespone(final int type) {
+		final IqPacket packet = new IqPacket(type);
 		packet.setTo(this.getFrom());
 		packet.setId(this.getId());
 		return packet;
diff --git a/src/main/res/menu/contact_context.xml b/src/main/res/menu/contact_context.xml
index 11ac7d7c0..223c7ece0 100644
--- a/src/main/res/menu/contact_context.xml
+++ b/src/main/res/menu/contact_context.xml
@@ -7,6 +7,9 @@
     <item
         android:id="@+id/context_contact_details"
         android:title="@string/view_contact_details"/>
+    <item
+        android:id="@+id/context_contact_block_unblock"
+        android:title="@string/block_contact"/>
     <item
         android:id="@+id/context_delete_contact"
         android:title="@string/delete_contact"/>
diff --git a/src/main/res/menu/conversations.xml b/src/main/res/menu/conversations.xml
index d68c1436e..6c22ed185 100644
--- a/src/main/res/menu/conversations.xml
+++ b/src/main/res/menu/conversations.xml
@@ -56,6 +56,18 @@
         android:showAsAction="never"
         android:title="@string/enable_notifications"/>
 
+    <item
+        android:id="@+id/action_block"
+        android:orderInCategory="72"
+        android:showAsAction="never"
+        android:title="@string/action_block_contact"/>
+
+    <item
+        android:id="@+id/action_unblock"
+        android:orderInCategory="73"
+        android:showAsAction="never"
+        android:title="@string/action_unblock_contact"/>
+
     <item
         android:id="@+id/action_accounts"
         android:orderInCategory="90"
diff --git a/src/main/res/menu/editaccount.xml b/src/main/res/menu/editaccount.xml
index 2301caf0d..5d10901eb 100644
--- a/src/main/res/menu/editaccount.xml
+++ b/src/main/res/menu/editaccount.xml
@@ -4,5 +4,9 @@
         android:id="@+id/action_show_qr_code"
         android:title="@string/show_qr_code"
         android:showAsAction="never" />
+    <item
+        android:id="@+id/action_show_block_list"
+        android:title="@string/show_block_list"
+        android:showAsAction="never" />
 
 </menu>
\ No newline at end of file
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index ec761d6e9..ba3051b23 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -13,6 +13,10 @@
     <string name="action_edit_contact">Edit name</string>
     <string name="action_add_phone_book">Add to phone book</string>
     <string name="action_delete_contact">Delete from roster</string>
+    <string name="action_block_contact">Block contact</string>
+    <string name="action_unblock_contact">Unblock contact</string>
+    <string name="action_block_domain">Block domain</string>
+    <string name="action_unblock_domain">Unblock domain</string>
     <string name="title_activity_manage_accounts">Manage Accounts</string>
     <string name="title_activity_settings">Settings</string>
     <string name="title_activity_conference_details">Conference Details</string>
@@ -21,6 +25,7 @@
     <string name="title_activity_sharewith">Share with Conversation</string>
     <string name="title_activity_start_conversation">Start Conversation</string>
     <string name="title_activity_choose_contact">Choose contact</string>
+    <string name="title_activity_block_list">Block list</string>
     <string name="just_now">just now</string>
     <string name="minute_ago">1 min ago</string>
     <string name="minutes_ago">%d mins ago</string>
@@ -34,6 +39,11 @@
     <string name="participant">Participant</string>
     <string name="visitor">Visitor</string>
     <string name="remove_contact_text">Would you like to remove %s from your roster? The conversation associated with this contact will not be removed.</string>
+    <string name="block_contact_text">Would you like to block %s from sending you messages?</string>
+    <string name="unblock_contact_text">Would you like to unblock %s and allow them to send you messages?</string>
+    <string name="block_domain_text">Block all contacts from %s?</string>
+    <string name="unblock_domain_text">Unblock all contacts from %s?</string>
+    <string name="contact_blocked">Contact blocked</string>
     <string name="remove_bookmark_text">Would you like to remove %s as a bookmark? The conversation associated with this bookmark will not be removed.</string>
     <string name="register_account">Register new account on server</string>
     <string name="share_with">Share with</string>
@@ -45,6 +55,8 @@
     <string name="add">Add</string>
     <string name="edit">Edit</string>
     <string name="delete">Delete</string>
+    <string name="block">Block</string>
+    <string name="unblock">Unblock</string>
     <string name="save">Save</string>
     <string name="ok">OK</string>
     <string name="crash_report_title">Conversations has crashed</string>
@@ -202,6 +214,8 @@
     <string name="join_conference">Join Conference</string>
     <string name="delete_contact">Delete Contact</string>
     <string name="view_contact_details">View contact details</string>
+    <string name="block_contact">Block contact</string>
+    <string name="unblock_contact">Unblock contact</string>
     <string name="create">Create</string>
     <string name="contact_already_exists">The contact already exists</string>
     <string name="join">Join</string>
@@ -318,6 +332,7 @@
     <string name="image_transmission_failed">Image transmission failed</string>
     <string name="scan_qr_code">Scan QR code</string>
     <string name="show_qr_code">Show QR code</string>
+    <string name="show_block_list">Show block list</string>
     <string name="account_details">Account details</string>
     <string name="verify_otr">Verify OTR</string>
     <string name="remote_fingerprint">Remote Fingerprint</string>