Add support for XEP-0191 (Blocking command)

Fixes #791

Squash of commits:
534f25d7dae3ce6852243e28fdd0a69ac01e9463
808fdf5147f27a912a60bee39aa4bf1ddd4f43b4
1eaf8a8330710ad35ba7c368e04f909af623ae4c
31585242c2359efdcd0eeddb9745077f54dbc9eb
2e69bd0bd0286ed1e98a42f4c3421ba4d8cf524b
e904fb5015bf3a1904ab941a1957edf3b1e7abd2
eebbadf3b3816bbf8fcccb763e419fed252d266f
7c5b87724ce494e5a6e8026557ed50a8fd9f23e8
b0eaaf446937794fe19cbdb4f8309c3ff83d4e42
8c652f9e8bb3512958d9ad8c6f1326505f2d98c8
ad0ea1ad948ff6f8fde7b0b10f5163dc8852032f
f5d49897e0dba691ef53a0eddb9ed34d129ad442
a08fa64c505bd895b7c626cfad182380373be20b
de67079113e08394a276048c31f6b21baa300829
9069f342173ba30c2b20c67529c7ff497a6a257d
0169fa79d161ee898c4b6762e207087682a952d8
8585a5bd75a5d56927fed8317729bd15fffe4dcc
0053528a078369e0b65dcf71bda251072a1299c7
e901a9c3554bd7cca193e92919b463991eadfea7
c5c78257434813c69ab9b7558bcc8f7cbe858433
e905af348d46d77bc46b5f7211527684acc02fab
13a0f9a10c7892b0f90f5fabd2f2615701b0fd66
2cfba1e24b0139839e4453b92be7e20634d150cf
58e074fb5bb44b05a8104250fccd7c024c808c1a
0d6cf98fc8eab212d798ac79b336f9b70a14f06d
e23620f56b85bcab9f3b5d9ce1c01524cd9674dc
d72cd2fcc8d54176c3ff53411a69b9bb4642eff3
195143dff8836623a37094a6b8fa6aa01ef31580
5f5f3caf3a1e480a99d27ee5c34ba516419c52e4
1dee3d5861c9f9c710da4cbda3688d94c622ca93
23949b8aa32c78b27bab49bb3c4f3ff588925ce1
9bf97f8ae522796e0dacb7f6fe7a7f90f86a93a1
This commit is contained in:
Sam Whited 2014-12-21 15:43:58 -05:00
parent 9656970051
commit af7a64491f
44 changed files with 1485 additions and 904 deletions

View File

@ -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 * XEP-0313: Message Archive Management synchronize message history with the
server. Catch up with messages that were sent while Conversations was server. Catch up with messages that were sent while Conversations was
offline. 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 Conversations is in the background. Allows the server to save bandwidth by
withholding unimportant packages. withholding unimportant packages.
* XEP-0191: Blocking command lets you blacklist spammers or block contacts
without removing them from your roster.
## Team ## Team

View File

@ -16,3 +16,4 @@
* XEP-0313: Message Archive Management * XEP-0313: Message Archive Management
* XEP-0333: Chat Markers * XEP-0333: Chat Markers
* XEP-0352: Client State Indication * XEP-0352: Client State Indication
* XEP-0191: Blocking command

View File

@ -76,6 +76,9 @@
<activity <activity
android:name=".ui.ChooseContactActivity" android:name=".ui.ChooseContactActivity"
android:label="@string/title_activity_choose_contact" /> android:label="@string/title_activity_choose_contact" />
<activity
android:name=".ui.BlocklistActivity"
android:label="@string/title_activity_block_list" />
<activity <activity
android:name=".ui.ManageAccountActivity" android:name=".ui.ManageAccountActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"

View File

@ -11,8 +11,10 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.security.interfaces.DSAPublicKey; import java.security.interfaces.DSAPublicKey;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
import eu.siacs.conversations.R; import eu.siacs.conversations.R;
@ -56,7 +58,7 @@ public class Account extends AbstractEntity {
SECURITY_ERROR(true), SECURITY_ERROR(true),
INCOMPATIBLE_SERVER(true); INCOMPATIBLE_SERVER(true);
private boolean isError; private final boolean isError;
public boolean isError() { public boolean isError() {
return this.isError; return this.isError;
@ -120,6 +122,7 @@ public class Account extends AbstractEntity {
private String otrFingerprint; private String otrFingerprint;
private final Roster roster = new Roster(this); private final Roster roster = new Roster(this);
private List<Bookmark> bookmarks = new CopyOnWriteArrayList<>(); private List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
private final Collection<Jid> blocklist = new CopyOnWriteArraySet<>();
public Account() { public Account() {
this.uuid = "0"; this.uuid = "0";
@ -279,7 +282,7 @@ public class Account extends AbstractEntity {
return values; return values;
} }
public void initOtrEngine(XmppConnectionService context) { public void initOtrEngine(final XmppConnectionService context) {
this.otrEngine = new OtrEngine(context, this); this.otrEngine = new OtrEngine(context, this);
} }
@ -291,7 +294,7 @@ public class Account extends AbstractEntity {
return this.xmppConnection; return this.xmppConnection;
} }
public void setXmppConnection(XmppConnection connection) { public void setXmppConnection(final XmppConnection connection) {
this.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; this.rosterVersion = version;
} }
@ -351,7 +354,7 @@ public class Account extends AbstractEntity {
return this.bookmarks; return this.bookmarks;
} }
public void setBookmarks(List<Bookmark> bookmarks) { public void setBookmarks(final List<Bookmark> bookmarks) {
this.bookmarks = bookmarks; this.bookmarks = bookmarks;
} }
@ -399,4 +402,21 @@ public class Account extends AbstractEntity {
return "xmpp:" + this.getJid().toBareJid().toString(); 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();
}
} }

View File

@ -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();
}

View File

@ -6,7 +6,6 @@ import java.util.Locale;
import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.jid.Jid;
public class Bookmark extends Element implements ListItem { public class Bookmark extends Element implements ListItem {

View File

@ -16,7 +16,7 @@ import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid; 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 TABLENAME = "contacts";
public static final String SYSTEMNAME = "systemname"; public static final String SYSTEMNAME = "systemname";
@ -47,8 +47,8 @@ public class Contact implements ListItem {
protected Account account; protected Account account;
public Contact(final String account, final String systemName, final String serverName, public Contact(final String account, final String systemName, final String serverName,
final Jid jid, final int subscription, final String photoUri, 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 String systemAccount, final String keys, final String avatar, final Lastseen lastseen, final String groups) {
this.accountUuid = account; this.accountUuid = account;
this.systemName = systemName; this.systemName = systemName;
this.serverName = serverName; this.serverName = serverName;
@ -122,11 +122,10 @@ public class Contact implements ListItem {
@Override @Override
public List<Tag> getTags() { public List<Tag> getTags() {
ArrayList<Tag> tags = new ArrayList<Tag>(); final ArrayList<Tag> tags = new ArrayList<>();
for (String group : getGroups()) { for (final String group : getGroups()) {
tags.add(new Tag(group, UIHelper.getColorForName(group))); tags.add(new Tag(group, UIHelper.getColorForName(group)));
} }
int status = getMostAvailableStatus();
switch (getMostAvailableStatus()) { switch (getMostAvailableStatus()) {
case Presences.CHAT: case Presences.CHAT:
case Presences.ONLINE: case Presences.ONLINE:
@ -142,6 +141,9 @@ public class Contact implements ListItem {
tags.add(new Tag("dnd", 0xffe51c23)); tags.add(new Tag("dnd", 0xffe51c23));
break; break;
} }
if (isBlocked()) {
tags.add(new Tag("blocked", 0xff2e2f3b));
}
return tags; return tags;
} }
@ -176,7 +178,7 @@ public class Contact implements ListItem {
} }
public ContentValues getContentValues() { public ContentValues getContentValues() {
ContentValues values = new ContentValues(); final ContentValues values = new ContentValues();
values.put(ACCOUNT, accountUuid); values.put(ACCOUNT, accountUuid);
values.put(SYSTEMNAME, systemName); values.put(SYSTEMNAME, systemName);
values.put(SERVERNAME, serverName); values.put(SERVERNAME, serverName);
@ -213,11 +215,11 @@ public class Contact implements ListItem {
this.presences = pres; this.presences = pres;
} }
public void updatePresence(String resource, int status) { public void updatePresence(final String resource, final int status) {
this.presences.updatePresence(resource, status); this.presences.updatePresence(resource, status);
} }
public void removePresence(String resource) { public void removePresence(final String resource) {
this.presences.removePresence(resource); this.presences.removePresence(resource);
} }
@ -337,8 +339,8 @@ public class Contact implements ListItem {
public boolean showInRoster() { public boolean showInRoster() {
return (this.getOption(Contact.Options.IN_ROSTER) && (!this return (this.getOption(Contact.Options.IN_ROSTER) && (!this
.getOption(Contact.Options.DIRTY_DELETE))) .getOption(Contact.Options.DIRTY_DELETE)))
|| (this.getOption(Contact.Options.DIRTY_PUSH)); || (this.getOption(Contact.Options.DIRTY_PUSH));
} }
public void parseSubscriptionFromElement(Element item) { public void parseSubscriptionFromElement(Element item) {
@ -428,7 +430,7 @@ public class Contact implements ListItem {
if (this.keys.has("otr_fingerprints")) { if (this.keys.has("otr_fingerprints")) {
JSONArray newPrints = new JSONArray(); JSONArray newPrints = new JSONArray();
JSONArray oldPrints = this.keys JSONArray oldPrints = this.keys
.getJSONArray("otr_fingerprints"); .getJSONArray("otr_fingerprints");
for (int i = 0; i < oldPrints.length(); ++i) { for (int i = 0; i < oldPrints.length(); ++i) {
if (!oldPrints.getString(i).equals(fingerprint)) { if (!oldPrints.getString(i).equals(fingerprint)) {
newPrints.put(oldPrints.getString(i)); 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 static class Lastseen {
public long time; public long time;
public String presence; public String presence;
public Lastseen() { public Lastseen() {
time = 0; this(null, 0);
presence = null;
} }
public Lastseen(final String presence, final long time) { public Lastseen(final String presence, final long time) {
this.time = time;
this.presence = presence; this.presence = presence;
this.time = time;
} }
} }
public class Options { public final class Options {
public static final int TO = 0; public static final int TO = 0;
public static final int FROM = 1; public static final int FROM = 1;
public static final int ASKING = 2; public static final int ASKING = 2;

View File

@ -3,7 +3,6 @@ package eu.siacs.conversations.entities;
import android.content.ContentValues; import android.content.ContentValues;
import android.database.Cursor; import android.database.Cursor;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.Log;
import net.java.otr4j.OtrException; import net.java.otr4j.OtrException;
import net.java.otr4j.crypto.OtrCryptoEngineImpl; 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.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid; 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 String TABLENAME = "conversations";
public static final int STATUS_AVAILABLE = 0; 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) if ((message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE)
&& message.getEncryption() != Message.ENCRYPTION_PGP) { && message.getEncryption() != Message.ENCRYPTION_PGP) {
onMessageFound.onMessageFound(message); onMessageFound.onMessageFound(message);
} }
} }
} }
} }
@ -117,7 +116,7 @@ public class Conversation extends AbstractEntity {
&& message.getEncryption() != Message.ENCRYPTION_PGP && message.getEncryption() != Message.ENCRYPTION_PGP
&& message.getUuid().equals(uuid)) { && message.getUuid().equals(uuid)) {
return message; return message;
} }
} }
} }
return null; return null;
@ -145,7 +144,7 @@ public class Conversation extends AbstractEntity {
if ((message.getStatus() == Message.STATUS_UNSEND || message.getStatus() == Message.STATUS_WAITING) if ((message.getStatus() == Message.STATUS_UNSEND || message.getStatus() == Message.STATUS_WAITING)
&& (message.getEncryption() == Message.ENCRYPTION_OTR)) { && (message.getEncryption() == Message.ENCRYPTION_OTR)) {
onMessageFound.onMessageFound(message); onMessageFound.onMessageFound(message);
} }
} }
} }
} }
@ -156,7 +155,7 @@ public class Conversation extends AbstractEntity {
if (message.getType() != Message.TYPE_IMAGE if (message.getType() != Message.TYPE_IMAGE
&& message.getStatus() == Message.STATUS_UNSEND) { && message.getStatus() == Message.STATUS_UNSEND) {
onMessageFound.onMessageFound(message); onMessageFound.onMessageFound(message);
} }
} }
} }
} }
@ -166,21 +165,37 @@ public class Conversation extends AbstractEntity {
for (Message message : this.messages) { for (Message message : this.messages) {
if (uuid.equals(message.getUuid()) if (uuid.equals(message.getUuid())
|| (message.getStatus() >= Message.STATUS_SEND && uuid || (message.getStatus() >= Message.STATUS_SEND && uuid
.equals(message.getRemoteMsgId()))) { .equals(message.getRemoteMsgId()))) {
return message; return message;
} }
} }
} }
return null; return null;
} }
public void populateWithMessages(List<Message> messages) { public void populateWithMessages(final List<Message> messages) {
synchronized (this.messages) { synchronized (this.messages) {
messages.clear(); messages.clear();
messages.addAll(this.messages); 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 interface OnMessageFound {
public void onMessageFound(final Message message); public void onMessageFound(final Message message);
} }
@ -212,8 +227,8 @@ public class Conversation extends AbstractEntity {
} }
public boolean isRead() { 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() { public void markRead() {
if (this.messages == null) { if (this.messages == null) {
@ -239,7 +254,7 @@ public class Conversation extends AbstractEntity {
} else { } else {
return this.messages.get(i); return this.messages.get(i);
} }
} }
} }
return null; return null;
} }
@ -267,7 +282,7 @@ public class Conversation extends AbstractEntity {
if (generatedName != null) { if (generatedName != null) {
return generatedName; return generatedName;
} else { } else {
return getContactJid().getLocalpart(); return getJid().getLocalpart();
} }
} }
} else { } else {
@ -287,11 +302,12 @@ public class Conversation extends AbstractEntity {
return this.account.getRoster().getContact(this.contactJid); return this.account.getRoster().getContact(this.contactJid);
} }
public void setAccount(Account account) { public void setAccount(final Account account) {
this.account = account; this.account = account;
} }
public Jid getContactJid() { @Override
public Jid getJid() {
return this.contactJid; return this.contactJid;
} }
@ -318,14 +334,14 @@ public class Conversation extends AbstractEntity {
} }
public static Conversation fromCursor(Cursor cursor) { public static Conversation fromCursor(Cursor cursor) {
Jid jid; Jid jid;
try { try {
jid = Jid.fromString(cursor.getString(cursor.getColumnIndex(CONTACTJID))); jid = Jid.fromString(cursor.getString(cursor.getColumnIndex(CONTACTJID)));
} catch (final InvalidJidException e) { } catch (final InvalidJidException e) {
// Borked DB.. // Borked DB..
jid = null; jid = null;
} }
return new Conversation(cursor.getString(cursor.getColumnIndex(UUID)), return new Conversation(cursor.getString(cursor.getColumnIndex(UUID)),
cursor.getString(cursor.getColumnIndex(NAME)), cursor.getString(cursor.getColumnIndex(NAME)),
cursor.getString(cursor.getColumnIndex(CONTACT)), cursor.getString(cursor.getColumnIndex(CONTACT)),
cursor.getString(cursor.getColumnIndex(ACCOUNT)), cursor.getString(cursor.getColumnIndex(ACCOUNT)),
@ -352,9 +368,9 @@ public class Conversation extends AbstractEntity {
if (this.otrSession != null) { if (this.otrSession != null) {
return this.otrSession; return this.otrSession;
} else { } else {
final SessionID sessionId = new SessionID(this.getContactJid().toBareJid().toString(), final SessionID sessionId = new SessionID(this.getJid().toBareJid().toString(),
presence, presence,
"xmpp"); "xmpp");
this.otrSession = new SessionImpl(sessionId, getAccount().getOtrEngine()); this.otrSession = new SessionImpl(sessionId, getAccount().getOtrEngine());
try { try {
if (sendStart) { if (sendStart) {
@ -393,7 +409,7 @@ public class Conversation extends AbstractEntity {
} catch (OtrException e) { } catch (OtrException e) {
this.resetOtrSession(); this.resetOtrSession();
} }
} }
} }
public boolean endOtrIfNeeded() { public boolean endOtrIfNeeded() {
@ -427,7 +443,7 @@ public class Conversation extends AbstractEntity {
return ""; return "";
} }
DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession() DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession()
.getRemotePublicKey(); .getRemotePublicKey();
StringBuilder builder = new StringBuilder( StringBuilder builder = new StringBuilder(
new OtrCryptoEngineImpl().getFingerprint(remotePubKey)); new OtrCryptoEngineImpl().getFingerprint(remotePubKey));
builder.insert(8, " "); builder.insert(8, " ");

View File

@ -12,10 +12,10 @@ public interface ListItem extends Comparable<ListItem> {
public List<Tag> getTags(); public List<Tag> getTags();
public final class Tag { public final class Tag {
private String name; private final String name;
private int color; private final int color;
public Tag(String name, int color) { public Tag(final String name, final int color) {
this.name = name; this.name = name;
this.color = color; this.color = color;
} }
@ -28,4 +28,6 @@ public interface ListItem extends Comparable<ListItem> {
return this.name; return this.name;
} }
} }
public boolean match(final String needle);
} }

View File

@ -77,7 +77,7 @@ public class Message extends AbstractEntity {
public Message(Conversation conversation, String body, int encryption, int status) { public Message(Conversation conversation, String body, int encryption, int status) {
this(java.util.UUID.randomUUID().toString(), this(java.util.UUID.randomUUID().toString(),
conversation.getUuid(), conversation.getUuid(),
conversation.getContactJid() == null ? null : conversation.getContactJid().toBareJid(), conversation.getJid() == null ? null : conversation.getJid().toBareJid(),
null, null,
body, body,
System.currentTimeMillis(), System.currentTimeMillis(),
@ -91,9 +91,9 @@ public class Message extends AbstractEntity {
} }
private Message(final String uuid, final String conversationUUid, final Jid counterpart, private Message(final String uuid, final String conversationUUid, final Jid counterpart,
final Jid trueCounterpart, final String body, final long timeSent, final Jid trueCounterpart, final String body, final long timeSent,
final int encryption, final int status, final int type, final String remoteMsgId, final int encryption, final int status, final int type, final String remoteMsgId,
final String relativeFilePath, final String serverMsgId) { final String relativeFilePath, final String serverMsgId) {
this.uuid = uuid; this.uuid = uuid;
this.conversationUuid = conversationUUid; this.conversationUuid = conversationUUid;
this.counterpart = counterpart; this.counterpart = counterpart;
@ -206,7 +206,7 @@ public class Message extends AbstractEntity {
return null; return null;
} else { } else {
return this.conversation.getAccount().getRoster() 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()); return this.serverMsgId.equals(message.getServerMsgId());
} else { } else {
return this.body != null return this.body != null
&& this.counterpart != null && this.counterpart != null
&& ((this.remoteMsgId != null && this.remoteMsgId.equals(message.getRemoteMsgId())) && ((this.remoteMsgId != null && this.remoteMsgId.equals(message.getRemoteMsgId()))
|| this.uuid.equals(message.getRemoteMsgId())) && this.body.equals(message.getBody()) || this.uuid.equals(message.getRemoteMsgId())) && this.body.equals(message.getBody())
&& this.counterpart.equals(message.getCounterpart()); && this.counterpart.equals(message.getCounterpart());
} }
} }
@ -388,7 +388,7 @@ public class Message extends AbstractEntity {
if (!url.getProtocol().equalsIgnoreCase("http") if (!url.getProtocol().equalsIgnoreCase("http")
&& !url.getProtocol().equalsIgnoreCase("https")) { && !url.getProtocol().equalsIgnoreCase("https")) {
return false; return false;
} }
if (url.getPath() == null) { if (url.getPath() == null) {
return false; return false;
} }
@ -402,14 +402,14 @@ public class Message extends AbstractEntity {
String[] extensionParts = filename.split("\\."); String[] extensionParts = filename.split("\\.");
if (extensionParts.length == 2 if (extensionParts.length == 2
&& Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains( && Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains(
extensionParts[extensionParts.length - 1])) { extensionParts[extensionParts.length - 1])) {
return true; return true;
} else if (extensionParts.length == 3 } else if (extensionParts.length == 3
&& Arrays && Arrays
.asList(Downloadable.VALID_CRYPTO_EXTENSIONS) .asList(Downloadable.VALID_CRYPTO_EXTENSIONS)
.contains(extensionParts[extensionParts.length - 1]) .contains(extensionParts[extensionParts.length - 1])
&& Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains( && Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains(
extensionParts[extensionParts.length - 2])) { extensionParts[extensionParts.length - 2])) {
return true; return true;
} else { } else {
return false; return false;

View File

@ -80,20 +80,20 @@ public class MucOptions {
public void setRole(String role) { public void setRole(String role) {
role = role.toLowerCase(); role = role.toLowerCase();
switch (role) { switch (role) {
case "moderator": case "moderator":
this.role = ROLE_MODERATOR; this.role = ROLE_MODERATOR;
break; break;
case "participant": case "participant":
this.role = ROLE_PARTICIPANT; this.role = ROLE_PARTICIPANT;
break; break;
case "visitor": case "visitor":
this.role = ROLE_VISITOR; this.role = ROLE_VISITOR;
break; break;
default: default:
this.role = ROLE_NONE; this.role = ROLE_NONE;
break; break;
} }
} }
public int getAffiliation() { public int getAffiliation() {
@ -164,7 +164,7 @@ public class MucOptions {
} }
public void processPacket(PresencePacket packet, PgpEngine pgp) { public void processPacket(PresencePacket packet, PgpEngine pgp) {
final Jid from = packet.getFrom(); final Jid from = packet.getFrom();
if (!from.isBareJid()) { if (!from.isBareJid()) {
final String name = from.getResourcepart(); final String name = from.getResourcepart();
final String type = packet.getAttribute("type"); final String type = packet.getAttribute("type");
@ -179,7 +179,7 @@ public class MucOptions {
user.setAffiliation(item.getAttribute("affiliation")); user.setAffiliation(item.getAttribute("affiliation"));
user.setRole(item.getAttribute("role")); user.setRole(item.getAttribute("role"));
user.setJid(item.getAttributeAsJid("jid")); 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.isOnline = true;
this.error = ERROR_NO_ERROR; this.error = ERROR_NO_ERROR;
self = user; self = user;
@ -204,14 +204,14 @@ public class MucOptions {
msg = ""; msg = "";
} }
user.setPgpKeyId(pgp.fetchKeyId(account, msg, user.setPgpKeyId(pgp.fetchKeyId(account, msg,
signed.getContent())); signed.getContent()));
} }
} }
} }
} }
} else if (type.equals("unavailable")) { } else if (type.equals("unavailable")) {
if (codes.contains(STATUS_CODE_SELF_PRESENCE) || 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)) { if (codes.contains(STATUS_CODE_CHANGED_NICK)) {
this.mNickChangingInProgress = true; this.mNickChangingInProgress = true;
} else if (codes.contains(STATUS_CODE_KICKED)) { } else if (codes.contains(STATUS_CODE_KICKED)) {
@ -282,8 +282,8 @@ public class MucOptions {
&& conversation.getBookmark().getNick() != null && conversation.getBookmark().getNick() != null
&& !conversation.getBookmark().getNick().isEmpty()) { && !conversation.getBookmark().getNick().isEmpty()) {
return conversation.getBookmark().getNick(); return conversation.getBookmark().getNick();
} else if (!conversation.getContactJid().isBareJid()) { } else if (!conversation.getJid().isBareJid()) {
return conversation.getContactJid().getResourcepart(); return conversation.getJid().getResourcepart();
} else { } else {
return account.getUsername(); return account.getUsername();
} }
@ -334,14 +334,14 @@ public class MucOptions {
public String createNameFromParticipants() { public String createNameFromParticipants() {
if (users.size() >= 2) { if (users.size() >= 2) {
List<String> names = new ArrayList<String>(); List<String> names = new ArrayList<String>();
for (User user : users) { for (User user : users) {
Contact contact = user.getContact(); Contact contact = user.getContact();
if (contact != null && !contact.getDisplayName().isEmpty()) { if (contact != null && !contact.getDisplayName().isEmpty()) {
names.add(contact.getDisplayName().split("\\s+")[0]); names.add(contact.getDisplayName().split("\\s+")[0]);
} else { } else {
names.add(user.getName()); names.add(user.getName());
}
} }
}
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
for (int i = 0; i < names.size(); ++i) { for (int i = 0; i < names.size(); ++i) {
builder.append(names.get(i)); builder.append(names.get(i));
@ -388,12 +388,12 @@ public class MucOptions {
} }
public Jid createJoinJid(String nick) { public Jid createJoinJid(String nick) {
try { try {
return Jid.fromString(this.conversation.getContactJid().toBareJid().toString() + "/"+nick); return Jid.fromString(this.conversation.getJid().toBareJid().toString() + "/"+nick);
} catch (final InvalidJidException e) { } catch (final InvalidJidException e) {
return null; return null;
} }
} }
public Jid getTrueCounterpart(String counterpart) { public Jid getTrueCounterpart(String counterpart) {
for (User user : this.getUsers()) { for (User user : this.getUsers()) {

View File

@ -7,7 +7,7 @@ import java.util.concurrent.ConcurrentHashMap;
import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.jid.Jid;
public class Roster { public class Roster {
Account account; final Account account;
final ConcurrentHashMap<String, Contact> contacts = new ConcurrentHashMap<>(); final ConcurrentHashMap<String, Contact> contacts = new ConcurrentHashMap<>();
private String version = null; private String version = null;
@ -19,7 +19,7 @@ public class Roster {
if (jid == null) { if (jid == null) {
return null; return null;
} }
Contact contact = contacts.get(jid.toBareJid().toString()); final Contact contact = contacts.get(jid.toBareJid().toString());
if (contact != null && contact.showInRoster()) { if (contact != null && contact.showInRoster()) {
return contact; return contact;
} else { } else {
@ -32,7 +32,7 @@ public class Roster {
if (contacts.containsKey(bareJid.toString())) { if (contacts.containsKey(bareJid.toString())) {
return contacts.get(bareJid.toString()); return contacts.get(bareJid.toString());
} else { } else {
Contact contact = new Contact(bareJid); final Contact contact = new Contact(bareJid);
contact.setAccount(account); contact.setAccount(account);
contacts.put(bareJid.toString(), contact); contacts.put(bareJid.toString(), contact);
return contact; return contact;
@ -46,13 +46,13 @@ public class Roster {
} }
public void markAllAsNotInRoster() { public void markAllAsNotInRoster() {
for (Contact contact : getContacts()) { for (final Contact contact : getContacts()) {
contact.resetOption(Contact.Options.IN_ROSTER); contact.resetOption(Contact.Options.IN_ROSTER);
} }
} }
public void clearSystemAccounts() { public void clearSystemAccounts() {
for (Contact contact : getContacts()) { for (final Contact contact : getContacts()) {
contact.setPhotoUri(null); contact.setPhotoUri(null);
contact.setSystemName(null); contact.setSystemName(null);
contact.setSystemAccount(null); contact.setSystemAccount(null);

View File

@ -1,14 +1,12 @@
package eu.siacs.conversations.generator; package eu.siacs.conversations.generator;
import android.util.Log;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.MessageArchiveService;
import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.Xmlns;
import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.forms.Data; import eu.siacs.conversations.xmpp.forms.Data;
import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.jid.Jid;
@ -17,44 +15,44 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket;
public class IqGenerator extends AbstractGenerator { public class IqGenerator extends AbstractGenerator {
public IqGenerator(XmppConnectionService service) { public IqGenerator(final XmppConnectionService service) {
super(service); super(service);
} }
public IqPacket discoResponse(IqPacket request) { public IqPacket discoResponse(final IqPacket request) {
IqPacket packet = new IqPacket(IqPacket.TYPE_RESULT); final IqPacket packet = new IqPacket(IqPacket.TYPE_RESULT);
packet.setId(request.getId()); packet.setId(request.getId());
packet.setTo(request.getFrom()); packet.setTo(request.getFrom());
Element query = packet.addChild("query", final Element query = packet.addChild("query",
"http://jabber.org/protocol/disco#info"); "http://jabber.org/protocol/disco#info");
query.setAttribute("node", request.query().getAttribute("node")); query.setAttribute("node", request.query().getAttribute("node"));
Element identity = query.addChild("identity"); final Element identity = query.addChild("identity");
identity.setAttribute("category", "client"); identity.setAttribute("category", "client");
identity.setAttribute("type", this.IDENTITY_TYPE); identity.setAttribute("type", this.IDENTITY_TYPE);
identity.setAttribute("name", IDENTITY_NAME); identity.setAttribute("name", IDENTITY_NAME);
List<String> features = Arrays.asList(FEATURES); final List<String> features = Arrays.asList(FEATURES);
Collections.sort(features); Collections.sort(features);
for (String feature : features) { for (final String feature : features) {
query.addChild("feature").setAttribute("var", feature); query.addChild("feature").setAttribute("var", feature);
} }
return packet; return packet;
} }
protected IqPacket publish(String node, Element item) { protected IqPacket publish(final String node, final Element item) {
IqPacket packet = new IqPacket(IqPacket.TYPE_SET); final IqPacket packet = new IqPacket(IqPacket.TYPE_SET);
Element pubsub = packet.addChild("pubsub", final Element pubsub = packet.addChild("pubsub",
"http://jabber.org/protocol/pubsub"); "http://jabber.org/protocol/pubsub");
Element publish = pubsub.addChild("publish"); final Element publish = pubsub.addChild("publish");
publish.setAttribute("node", node); publish.setAttribute("node", node);
publish.addChild(item); publish.addChild(item);
return packet; return packet;
} }
protected IqPacket retrieve(String node, Element item) { protected IqPacket retrieve(String node, Element item) {
IqPacket packet = new IqPacket(IqPacket.TYPE_GET); final IqPacket packet = new IqPacket(IqPacket.TYPE_GET);
Element pubsub = packet.addChild("pubsub", final Element pubsub = packet.addChild("pubsub",
"http://jabber.org/protocol/pubsub"); "http://jabber.org/protocol/pubsub");
Element items = pubsub.addChild("items"); final Element items = pubsub.addChild("items");
items.setAttribute("node", node); items.setAttribute("node", node);
if (item != null) { if (item != null) {
items.addChild(item); items.addChild(item);
@ -63,19 +61,19 @@ public class IqGenerator extends AbstractGenerator {
} }
public IqPacket publishAvatar(Avatar avatar) { public IqPacket publishAvatar(Avatar avatar) {
Element item = new Element("item"); final Element item = new Element("item");
item.setAttribute("id", avatar.sha1sum); 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); data.setContent(avatar.image);
return publish("urn:xmpp:avatar:data", item); return publish("urn:xmpp:avatar:data", item);
} }
public IqPacket publishAvatarMetadata(Avatar avatar) { public IqPacket publishAvatarMetadata(final Avatar avatar) {
Element item = new Element("item"); final Element item = new Element("item");
item.setAttribute("id", avatar.sha1sum); item.setAttribute("id", avatar.sha1sum);
Element metadata = item final Element metadata = item
.addChild("metadata", "urn:xmpp:avatar:metadata"); .addChild("metadata", "urn:xmpp:avatar:metadata");
Element info = metadata.addChild("info"); final Element info = metadata.addChild("info");
info.setAttribute("bytes", avatar.size); info.setAttribute("bytes", avatar.size);
info.setAttribute("id", avatar.sha1sum); info.setAttribute("id", avatar.sha1sum);
info.setAttribute("height", avatar.height); info.setAttribute("height", avatar.height);
@ -84,10 +82,10 @@ public class IqGenerator extends AbstractGenerator {
return publish("urn:xmpp:avatar:metadata", item); return publish("urn:xmpp:avatar:metadata", item);
} }
public IqPacket retrieveAvatar(Avatar avatar) { public IqPacket retrieveAvatar(final Avatar avatar) {
Element item = new Element("item"); final Element item = new Element("item");
item.setAttribute("id", avatar.sha1sum); 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); packet.setTo(avatar.owner);
return packet; return packet;
} }
@ -100,11 +98,11 @@ public class IqGenerator extends AbstractGenerator {
return packet; return packet;
} }
public IqPacket queryMessageArchiveManagement(MessageArchiveService.Query mam) { public IqPacket queryMessageArchiveManagement(final MessageArchiveService.Query mam) {
final IqPacket packet = new IqPacket(IqPacket.TYPE_SET); 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()); query.setAttribute("queryid",mam.getQueryId());
Data data = new Data(); final Data data = new Data();
data.setFormType("urn:xmpp:mam:0"); data.setFormType("urn:xmpp:mam:0");
if (mam.getWith()!=null) { if (mam.getWith()!=null) {
data.put("with", mam.getWith().toString()); data.put("with", mam.getWith().toString());
@ -119,4 +117,25 @@ public class IqGenerator extends AbstractGenerator {
} }
return packet; 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;
}
} }

View File

@ -114,7 +114,7 @@ public class MessageGenerator extends AbstractGenerator {
private MessagePacket generateError(MessagePacket origin) { private MessagePacket generateError(MessagePacket origin) {
MessagePacket packet = new MessagePacket(); MessagePacket packet = new MessagePacket();
packet.setId(origin.getId()); packet.setId(origin.getId());
packet.setTo(origin.getFrom()); packet.setTo(origin.getFrom());
packet.setBody(origin.getBody()); packet.setBody(origin.getBody());
packet.setType(MessagePacket.TYPE_ERROR); packet.setType(MessagePacket.TYPE_ERROR);
return packet; return packet;
@ -135,7 +135,7 @@ public class MessageGenerator extends AbstractGenerator {
String subject) { String subject) {
MessagePacket packet = new MessagePacket(); MessagePacket packet = new MessagePacket();
packet.setType(MessagePacket.TYPE_GROUPCHAT); packet.setType(MessagePacket.TYPE_GROUPCHAT);
packet.setTo(conversation.getContactJid().toBareJid()); packet.setTo(conversation.getJid().toBareJid());
Element subjectChild = new Element("subject"); Element subjectChild = new Element("subject");
subjectChild.setContent(subject); subjectChild.setContent(subject);
packet.addChild(subjectChild); packet.addChild(subjectChild);
@ -149,13 +149,13 @@ public class MessageGenerator extends AbstractGenerator {
packet.setTo(contact); packet.setTo(contact);
packet.setFrom(conversation.getAccount().getJid()); packet.setFrom(conversation.getAccount().getJid());
Element x = packet.addChild("x", "jabber:x:conference"); Element x = packet.addChild("x", "jabber:x:conference");
x.setAttribute("jid", conversation.getContactJid().toBareJid().toString()); x.setAttribute("jid", conversation.getJid().toBareJid().toString());
return packet; return packet;
} }
public MessagePacket invite(Conversation conversation, Jid contact) { public MessagePacket invite(Conversation conversation, Jid contact) {
MessagePacket packet = new MessagePacket(); MessagePacket packet = new MessagePacket();
packet.setTo(conversation.getContactJid().toBareJid()); packet.setTo(conversation.getJid().toBareJid());
packet.setFrom(conversation.getAccount().getJid()); packet.setFrom(conversation.getAccount().getJid());
Element x = new Element("x"); Element x = new Element("x");
x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user"); x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user");
@ -170,7 +170,7 @@ public class MessageGenerator extends AbstractGenerator {
MessagePacket originalMessage, String namespace) { MessagePacket originalMessage, String namespace) {
MessagePacket receivedPacket = new MessagePacket(); MessagePacket receivedPacket = new MessagePacket();
receivedPacket.setType(MessagePacket.TYPE_NORMAL); receivedPacket.setType(MessagePacket.TYPE_NORMAL);
receivedPacket.setTo(originalMessage.getFrom()); receivedPacket.setTo(originalMessage.getFrom());
receivedPacket.setFrom(account.getJid()); receivedPacket.setFrom(account.getJid());
Element received = receivedPacket.addChild("received", namespace); Element received = receivedPacket.addChild("received", namespace);
received.setAttribute("id", originalMessage.getId()); received.setAttribute("id", originalMessage.getId());

View File

@ -53,10 +53,10 @@ public abstract class AbstractParser {
protected void updateLastseen(final Element packet, final Account account, protected void updateLastseen(final Element packet, final Account account,
final boolean presenceOverwrite) { final boolean presenceOverwrite) {
Jid from = packet.getAttributeAsJid("from"); final Jid from = packet.getAttributeAsJid("from");
String presence = from == null || from.isBareJid() ? "" : from.getResourcepart(); final String presence = from == null || from.isBareJid() ? "" : from.getResourcepart();
Contact contact = account.getRoster().getContact(from); final Contact contact = account.getRoster().getContact(from);
long timestamp = getTimestamp(packet); final long timestamp = getTimestamp(packet);
if (timestamp >= contact.lastseen.time) { if (timestamp >= contact.lastseen.time) {
contact.lastseen.time = timestamp; contact.lastseen.time = timestamp;
if (!presence.isEmpty() && presenceOverwrite) { if (!presence.isEmpty() && presenceOverwrite) {

View File

@ -2,36 +2,40 @@ package eu.siacs.conversations.parser;
import android.util.Log; import android.util.Log;
import java.util.ArrayList;
import java.util.Collection;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.Xmlns;
import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.OnIqPacketReceived; 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.jid.Jid;
import eu.siacs.conversations.xmpp.stanzas.IqPacket; import eu.siacs.conversations.xmpp.stanzas.IqPacket;
public class IqParser extends AbstractParser implements OnIqPacketReceived { public class IqParser extends AbstractParser implements OnIqPacketReceived {
public IqParser(XmppConnectionService service) { public IqParser(final XmppConnectionService service) {
super(service); super(service);
} }
public void rosterItems(Account account, Element query) { public void rosterItems(final Account account, final Element query) {
String version = query.getAttribute("ver"); final String version = query.getAttribute("ver");
if (version != null) { if (version != null) {
account.getRoster().setVersion(version); account.getRoster().setVersion(version);
} }
for (Element item : query.getChildren()) { for (final Element item : query.getChildren()) {
if (item.getName().equals("item")) { if (item.getName().equals("item")) {
final Jid jid = item.getAttributeAsJid("jid"); final Jid jid = item.getAttributeAsJid("jid");
if (jid == null) { if (jid == null) {
continue; continue;
} }
String name = item.getAttribute("name"); final String name = item.getAttribute("name");
String subscription = item.getAttribute("subscription"); final String subscription = item.getAttribute("subscription");
Contact contact = account.getRoster().getContact(jid); final Contact contact = account.getRoster().getContact(jid);
if (!contact.getOption(Contact.Options.DIRTY_PUSH)) { if (!contact.getOption(Contact.Options.DIRTY_PUSH)) {
contact.setServerName(name); contact.setServerName(name);
contact.parseGroupsFromElement(item); contact.parseGroupsFromElement(item);
@ -54,13 +58,13 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
mXmppConnectionService.updateRosterUi(); mXmppConnectionService.updateRosterUi();
} }
public String avatarData(IqPacket packet) { public String avatarData(final IqPacket packet) {
Element pubsub = packet.findChild("pubsub", final Element pubsub = packet.findChild("pubsub",
"http://jabber.org/protocol/pubsub"); "http://jabber.org/protocol/pubsub");
if (pubsub == null) { if (pubsub == null) {
return null; return null;
} }
Element items = pubsub.findChild("items"); final Element items = pubsub.findChild("items");
if (items == null) { if (items == null) {
return null; return null;
} }
@ -68,13 +72,76 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
} }
@Override @Override
public void onIqPacketReceived(Account account, IqPacket packet) { public void onIqPacketReceived(final Account account, final IqPacket packet) {
if (packet.hasChild("query", "jabber:iq:roster")) { if (packet.hasChild("query", "jabber:iq:roster")) {
final Jid from = packet.getFrom(); final Jid from = packet.getFrom();
if ((from == null) || (from.equals(account.getJid().toBareJid()))) { if ((from == null) || (from.equals(account.getJid().toBareJid()))) {
Element query = packet.findChild("query"); final Element query = packet.findChild("query");
this.rosterItems(account, 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 { } else {
if (packet.getFrom() == null) { if (packet.getFrom() == null) {
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": received iq with invalid from "+packet.toString()); 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") } else if (packet.hasChild("open", "http://jabber.org/protocol/ibb")
|| packet.hasChild("data", "http://jabber.org/protocol/ibb")) { || packet.hasChild("data", "http://jabber.org/protocol/ibb")) {
mXmppConnectionService.getJingleConnectionManager() mXmppConnectionService.getJingleConnectionManager()
.deliverIbbPacket(account, packet); .deliverIbbPacket(account, packet);
} else if (packet.hasChild("query", "http://jabber.org/protocol/disco#info")) { } else if (packet.hasChild("query", "http://jabber.org/protocol/disco#info")) {
IqPacket response = mXmppConnectionService.getIqGenerator() final IqPacket response = mXmppConnectionService.getIqGenerator()
.discoResponse(packet); .discoResponse(packet);
account.getXmppConnection().sendIqPacket(response, null); account.getXmppConnection().sendIqPacket(response, null);
} else if (packet.hasChild("ping", "urn:xmpp:ping")) { } 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); mXmppConnectionService.sendIqPacket(account, response, null);
} else { } else {
if ((packet.getType() == IqPacket.TYPE_GET) if ((packet.getType() == IqPacket.TYPE_GET)
|| (packet.getType() == IqPacket.TYPE_SET)) { || (packet.getType() == IqPacket.TYPE_SET)) {
IqPacket response = packet.generateRespone(IqPacket.TYPE_ERROR); final IqPacket response = packet.generateRespone(IqPacket.TYPE_ERROR);
Element error = response.addChild("error"); final Element error = response.addChild("error");
error.setAttribute("type", "cancel"); error.setAttribute("type", "cancel");
error.addChild("feature-not-implemented", error.addChild("feature-not-implemented",
"urn:ietf:params:xml:ns:xmpp-stanzas"); "urn:ietf:params:xml:ns:xmpp-stanzas");
account.getXmppConnection().sendIqPacket(response, null); account.getXmppConnection().sendIqPacket(response, null);
} }
} }
} }
} }

View File

@ -228,9 +228,9 @@ public class DatabaseBackend extends SQLiteOpenHelper {
return conversation; return conversation;
} }
public void updateConversation(Conversation conversation) { public void updateConversation(final Conversation conversation) {
SQLiteDatabase db = this.getWritableDatabase(); final SQLiteDatabase db = this.getWritableDatabase();
String[] args = { conversation.getUuid() }; final String[] args = { conversation.getUuid() };
db.update(Conversation.TABLENAME, conversation.getContentValues(), db.update(Conversation.TABLENAME, conversation.getContentValues(),
Conversation.UUID + "=?", args); Conversation.UUID + "=?", args);
} }

View File

@ -236,7 +236,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
public Query(Conversation conversation, long start, long end) { public Query(Conversation conversation, long start, long end) {
this(conversation.getAccount(), start, end); this(conversation.getAccount(), start, end);
this.conversation = conversation; this.conversation = conversation;
this.with = conversation.getContactJid().toBareJid(); this.with = conversation.getJid().toBareJid();
} }
public Query(Conversation conversation, long start, long end, PagingOrder order) { public Query(Conversation conversation, long start, long end, PagingOrder order) {

View File

@ -35,11 +35,13 @@ import org.openintents.openpgp.util.OpenPgpServiceConnection;
import java.math.BigInteger; import java.math.BigInteger;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import de.duenndns.ssl.MemorizingTrustManager; import de.duenndns.ssl.MemorizingTrustManager;
@ -47,11 +49,11 @@ import eu.siacs.conversations.Config;
import eu.siacs.conversations.R; import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine; import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Blockable;
import eu.siacs.conversations.entities.Bookmark; import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Downloadable; import eu.siacs.conversations.entities.Downloadable;
import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.DownloadablePlaceholder; import eu.siacs.conversations.entities.DownloadablePlaceholder;
import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions; 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.OnContactStatusChanged;
import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.OnIqPacketReceived;
import eu.siacs.conversations.xmpp.OnMessageAcknowledged; 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.OnStatusChanged;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
import eu.siacs.conversations.xmpp.PacketReceived;
import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.forms.Data; import eu.siacs.conversations.xmpp.forms.Data;
import eu.siacs.conversations.xmpp.forms.Field; 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 class XmppConnectionService extends Service implements OnPhoneContactsLoadedListener {
public static String ACTION_CLEAR_NOTIFICATION = "clear_notification"; public static final String ACTION_CLEAR_NOTIFICATION = "clear_notification";
private static String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts"; private static final String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
public static String ACTION_DISABLE_FOREGROUND = "disable_foreground"; public static final String ACTION_DISABLE_FOREGROUND = "disable_foreground";
private ContentObserver contactObserver = new ContentObserver(null) { private ContentObserver contactObserver = new ContentObserver(null) {
@Override @Override
public void onChange(boolean selfChange) { public void onChange(boolean selfChange) {
@ -129,13 +136,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
private MemorizingTrustManager mMemorizingTrustManager; private MemorizingTrustManager mMemorizingTrustManager;
private NotificationService mNotificationService = new NotificationService( private NotificationService mNotificationService = new NotificationService(
this); this);
private MessageParser mMessageParser = new MessageParser(this); private OnMessagePacketReceived mMessageParser = new MessageParser(this);
private PresenceParser mPresenceParser = new PresenceParser(this); private OnPresencePacketReceived mPresenceParser = new PresenceParser(this);
private IqParser mIqParser = new IqParser(this); private IqParser mIqParser = new IqParser(this);
private MessageGenerator mMessageGenerator = new MessageGenerator(this); private MessageGenerator mMessageGenerator = new MessageGenerator(this);
private PresenceGenerator mPresenceGenerator = new PresenceGenerator(this); private PresenceGenerator mPresenceGenerator = new PresenceGenerator(this);
private List<Account> accounts; private List<Account> accounts;
private final CopyOnWriteArrayList<Conversation> conversations = new CopyOnWriteArrayList<Conversation>(); private final List<Conversation> conversations = new CopyOnWriteArrayList<>();
private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager( private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(
this); this);
private HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager( private HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager(
@ -208,6 +215,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
private int accountChangedListenerCount = 0; private int accountChangedListenerCount = 0;
private OnRosterUpdate mOnRosterUpdate = null; private OnRosterUpdate mOnRosterUpdate = null;
private OnUpdateBlocklist mOnUpdateBlocklist = null;
private int updateBlocklistListenerCount = 0;
private int rosterChangedListenerCount = 0; private int rosterChangedListenerCount = 0;
private OnMucRosterUpdate mOnMucRosterUpdate = null; private OnMucRosterUpdate mOnMucRosterUpdate = null;
private int mucRosterChangedListenerCount = 0; private int mucRosterChangedListenerCount = 0;
@ -354,13 +363,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
@Override @Override
public void run() { public void run() {
try { try {
DownloadableFile file = getFileBackend().copyImageToPrivateStorage(message, uri); getFileBackend().copyImageToPrivateStorage(message, uri);
if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) { if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) {
getPgpEngine().encrypt(message, callback); getPgpEngine().encrypt(message, callback);
} else { } else {
callback.success(message); callback.success(message);
} }
} catch (FileBackend.FileCopyException e) { } catch (final FileBackend.FileCopyException e) {
callback.error(e.getResId(), message); callback.error(e.getResId(), message);
} }
} }
@ -573,11 +582,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
} }
public XmppConnection createConnection(Account account) { public XmppConnection createConnection(final Account account) {
SharedPreferences sharedPref = getPreferences(); final SharedPreferences sharedPref = getPreferences();
account.setResource(sharedPref.getString("resource", "mobile") account.setResource(sharedPref.getString("resource", "mobile")
.toLowerCase(Locale.getDefault())); .toLowerCase(Locale.getDefault()));
XmppConnection connection = new XmppConnection(account, this); final XmppConnection connection = new XmppConnection(account, this);
connection.setOnMessagePacketReceivedListener(this.mMessageParser); connection.setOnMessagePacketReceivedListener(this.mMessageParser);
connection.setOnStatusChangedListener(this.statusListener); connection.setOnStatusChangedListener(this.statusListener);
connection.setOnPresencePacketReceivedListener(this.mPresenceParser); connection.setOnPresencePacketReceivedListener(this.mPresenceParser);
@ -589,10 +598,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
return connection; return connection;
} }
public void sendMessage(Message message) { public void sendMessage(final Message message) {
Account account = message.getConversation().getAccount(); final Account account = message.getConversation().getAccount();
account.deactivateGracePeriod(); account.deactivateGracePeriod();
Conversation conv = message.getConversation(); final Conversation conv = message.getConversation();
MessagePacket packet = null; MessagePacket packet = null;
boolean saveInDb = true; boolean saveInDb = true;
boolean send = false; boolean send = false;
@ -694,7 +703,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
updateConversationUi(); updateConversationUi();
} }
private void sendUnsentMessages(Conversation conversation) { private void sendUnsentMessages(final Conversation conversation) {
conversation.findWaitingMessages(new Conversation.OnMessageFound() { conversation.findWaitingMessages(new Conversation.OnMessageFound() {
@Override @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(); Account account = message.getConversation().getAccount();
MessagePacket packet = null; MessagePacket packet = null;
if (message.getEncryption() == Message.ENCRYPTION_OTR) { 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) { } else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) {
mJingleConnectionManager.createNewConnection(message); 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) { public void fetchRosterFromServer(final Account account) {
IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET); final IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
if (!"".equals(account.getRosterVersion())) { if (!"".equals(account.getRosterVersion())) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() Log.d(Config.LOGTAG, account.getJid().toBareJid()
+ ": fetching roster version " + account.getRosterVersion()); + ": fetching roster version " + account.getRosterVersion());
@ -789,8 +798,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
@Override @Override
public void onIqPacketReceived(final Account account, public void onIqPacketReceived(final Account account,
IqPacket packet) { final IqPacket packet) {
Element query = packet.findChild("query"); final Element query = packet.findChild("query");
if (query != null) { if (query != null) {
account.getRoster().markAllAsNotInRoster(); account.getRoster().markAllAsNotInRoster();
mIqParser.rosterItems(account, query); mIqParser.rosterItems(account, query);
@ -799,22 +808,22 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}); });
} }
public void fetchBookmarks(Account account) { public void fetchBookmarks(final Account account) {
IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET); final IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
Element query = iqPacket.query("jabber:iq:private"); final Element query = iqPacket.query("jabber:iq:private");
query.addChild("storage", "storage:bookmarks"); query.addChild("storage", "storage:bookmarks");
OnIqPacketReceived callback = new OnIqPacketReceived() { final PacketReceived callback = new OnIqPacketReceived() {
@Override @Override
public void onIqPacketReceived(Account account, IqPacket packet) { public void onIqPacketReceived(final Account account, final IqPacket packet) {
Element query = packet.query(); final Element query = packet.query();
List<Bookmark> bookmarks = new CopyOnWriteArrayList<>(); final List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
Element storage = query.findChild("storage", final Element storage = query.findChild("storage",
"storage:bookmarks"); "storage:bookmarks");
if (storage != null) { if (storage != null) {
for (Element item : storage.getChildren()) { for (final Element item : storage.getChildren()) {
if (item.getName().equals("conference")) { if (item.getName().equals("conference")) {
Bookmark bookmark = Bookmark.parse(item, account); final Bookmark bookmark = Bookmark.parse(item, account);
bookmarks.add(bookmark); bookmarks.add(bookmark);
Conversation conversation = find(bookmark); Conversation conversation = find(bookmark);
if (conversation != null) { if (conversation != null) {
@ -832,7 +841,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
} }
}; };
sendIqPacket(account, iqPacket, callback); sendIqPacket(account, iqPacket, callback);
} }
public void pushBookmarks(Account account) { public void pushBookmarks(Account account) {
@ -868,8 +876,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
} }
final Contact contact = account.getRoster().getContact(jid); final Contact contact = account.getRoster().getContact(jid);
String systemAccount = phoneContact.getInt("phoneid") String systemAccount = phoneContact.getInt("phoneid")
+ "#" + "#"
+ phoneContact.getString("lookup"); + phoneContact.getString("lookup");
contact.setSystemAccount(systemAccount); contact.setSystemAccount(systemAccount);
contact.setPhotoUri(phoneContact.getString("photouri")); contact.setPhotoUri(phoneContact.getString("photouri"));
getAvatarService().clear(contact); getAvatarService().clear(contact);
@ -885,7 +893,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
private void initConversations() { private void initConversations() {
synchronized (this.conversations) { synchronized (this.conversations) {
Hashtable<String, Account> accountLookupTable = new Hashtable<>(); final Map<String, Account> accountLookupTable = new Hashtable<>();
for (Account account : this.accounts) { for (Account account : this.accounts) {
accountLookupTable.put(account.getUuid(), account); accountLookupTable.put(account.getUuid(), account);
} }
@ -992,8 +1000,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
return this.accounts; return this.accounts;
} }
public Conversation find(List<Conversation> haystack, Contact contact) { public Conversation find(final Iterable<Conversation> haystack, final Contact contact) {
for (Conversation conversation : haystack) { for (final Conversation conversation : haystack) {
if (conversation.getContact() == contact) { if (conversation.getContact() == contact) {
return conversation; return conversation;
} }
@ -1001,15 +1009,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
return null; return null;
} }
public Conversation find(final List<Conversation> haystack, public Conversation find(final Iterable<Conversation> haystack, final Account account, final Jid jid) {
final Account account,
final Jid jid) {
if (jid == null ) { if (jid == null ) {
return null; return null;
} }
for (Conversation conversation : haystack) { for (final Conversation conversation : haystack) {
if ((account == null || conversation.getAccount() == account) if ((account == null || conversation.getAccount() == account)
&& (conversation.getContactJid().toBareJid().equals(jid.toBareJid()))) { && (conversation.getJid().toBareJid().equals(jid.toBareJid()))) {
return conversation; 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) { synchronized (this) {
if (checkListeners()) { if (checkListeners()) {
switchToForeground(); 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) { public void setOnMucRosterUpdateListener(OnMucRosterUpdate listener) {
synchronized (this) { synchronized (this) {
if (checkListeners()) { if (checkListeners()) {
@ -1264,7 +1295,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
&& (conversation.getAccount() == account)) { && (conversation.getAccount() == account)) {
conversation.resetMucOptions(); conversation.resetMucOptions();
joinMuc(conversation); joinMuc(conversation);
} }
} }
} }
@ -1293,7 +1324,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
packet.addChild("x", "jabber:x:signed").setContent(sig); packet.addChild("x", "jabber:x:signed").setContent(sig);
} }
sendPresencePacket(account, packet); sendPresencePacket(account, packet);
if (!joinJid.equals(conversation.getContactJid())) { if (!joinJid.equals(conversation.getJid())) {
conversation.setContactJid(joinJid); conversation.setContactJid(joinJid);
databaseBackend.updateConversation(conversation); databaseBackend.updateConversation(conversation);
} }
@ -1369,14 +1400,14 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
account.pendingConferenceLeaves.remove(conversation); account.pendingConferenceLeaves.remove(conversation);
if (account.getStatus() == Account.State.ONLINE) { if (account.getStatus() == Account.State.ONLINE) {
PresencePacket packet = new PresencePacket(); PresencePacket packet = new PresencePacket();
packet.setTo(conversation.getContactJid()); packet.setTo(conversation.getJid());
packet.setFrom(conversation.getAccount().getJid()); packet.setFrom(conversation.getAccount().getJid());
packet.setAttribute("type", "unavailable"); packet.setAttribute("type", "unavailable");
sendPresencePacket(conversation.getAccount(), packet); sendPresencePacket(conversation.getAccount(), packet);
conversation.getMucOptions().setOffline(); conversation.getMucOptions().setOffline();
conversation.deregisterWithBookmark(); conversation.deregisterWithBookmark();
Log.d(Config.LOGTAG, conversation.getAccount().getJid().toBareJid() Log.d(Config.LOGTAG, conversation.getAccount().getJid().toBareJid()
+ ": leaving muc " + conversation.getContactJid()); + ": leaving muc " + conversation.getJid());
} else { } else {
account.pendingConferenceLeaves.add(conversation); account.pendingConferenceLeaves.add(conversation);
} }
@ -1401,7 +1432,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
return null; 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()); Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": creating adhoc conference with "+ jids.toString());
if (account.getStatus() == Account.State.ONLINE) { if (account.getStatus() == Account.State.ONLINE) {
try { try {
@ -1454,7 +1485,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void pushConferenceConfiguration(final Conversation conversation,final Bundle options, final OnConferenceOptionsPushed callback) { public void pushConferenceConfiguration(final Conversation conversation,final Bundle options, final OnConferenceOptionsPushed callback) {
IqPacket request = new IqPacket(IqPacket.TYPE_GET); 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"); request.query("http://jabber.org/protocol/muc#owner");
sendIqPacket(conversation.getAccount(),request,new OnIqPacketReceived() { sendIqPacket(conversation.getAccount(),request,new OnIqPacketReceived() {
@Override @Override
@ -1468,7 +1499,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
} }
data.submit(); data.submit();
IqPacket set = new IqPacket(IqPacket.TYPE_SET); 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); set.query("http://jabber.org/protocol/muc#owner").addChild(data);
sendIqPacket(account, set, new OnIqPacketReceived() { sendIqPacket(account, set, new OnIqPacketReceived() {
@Override @Override
@ -1506,7 +1537,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
if (conversation.endOtrIfNeeded()) { if (conversation.endOtrIfNeeded()) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() Log.d(Config.LOGTAG, account.getJid().toBareJid()
+ ": ended otr session with " + ": ended otr session with "
+ conversation.getContactJid()); + conversation.getJid());
} }
} }
} }
@ -1552,8 +1583,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
final Session otrSession = conversation.getOtrSession(); final Session otrSession = conversation.getOtrSession();
Log.d(Config.LOGTAG, Log.d(Config.LOGTAG,
account.getJid().toBareJid() + " otr session established with " account.getJid().toBareJid() + " otr session established with "
+ conversation.getContactJid() + "/" + conversation.getJid() + "/"
+ otrSession.getSessionID().getUserID()); + otrSession.getSessionID().getUserID());
conversation.findUnsentMessagesWithOtrEncryption(new Conversation.OnMessageFound() { conversation.findUnsentMessagesWithOtrEncryption(new Conversation.OnMessageFound() {
@Override @Override
@ -1698,7 +1729,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
@Override @Override
public void onIqPacketReceived(Account account, IqPacket result) { public void onIqPacketReceived(Account account, IqPacket result) {
final String ERROR = account.getJid().toBareJid() final String ERROR = account.getJid().toBareJid()
+ ": fetching avatar for " + avatar.owner + " failed "; + ": fetching avatar for " + avatar.owner + " failed ";
if (result.getType() == IqPacket.TYPE_RESULT) { if (result.getType() == IqPacket.TYPE_RESULT) {
avatar.image = mIqParser.avatarData(result); avatar.image = mIqParser.avatarData(result);
if (avatar.image != null) { if (avatar.image != null) {
@ -1712,7 +1743,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
updateAccountUi(); updateAccountUi();
} else { } else {
Contact contact = account.getRoster() Contact contact = account.getRoster()
.getContact(avatar.owner); .getContact(avatar.owner);
contact.setAvatar(avatar.getFilename()); contact.setAvatar(avatar.getFilename());
getAvatarService().clear(contact); getAvatarService().clear(contact);
updateConversationUi(); updateConversationUi();
@ -1848,7 +1879,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
return false; return false;
} else { } else {
for (Conversation conversation : getConversations()) { for (Conversation conversation : getConversations()) {
if (conversation.getContactJid().equals(recipient) if (conversation.getJid().equals(recipient)
&& conversation.getAccount().equals(account)) { && conversation.getAccount().equals(account)) {
return markMessage(conversation, uuid, status); 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() { public void updateMucRosterUi() {
if (mOnMucRosterUpdate != null) { if (mOnMucRosterUpdate != null) {
mOnMucRosterUpdate.onMucRosterUpdate(); mOnMucRosterUpdate.onMucRosterUpdate();
@ -2034,9 +2071,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
} }
} }
public void sendIqPacket(Account account, IqPacket packet, public void sendIqPacket(final Account account, final IqPacket packet, final PacketReceived callback) {
OnIqPacketReceived callback) { final XmppConnection connection = account.getXmppConnection();
XmppConnection connection = account.getXmppConnection();
if (connection != null) { if (connection != null) {
connection.sendIqPacket(packet, callback); connection.sendIqPacket(packet, callback);
} }
@ -2054,6 +2090,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
return this.mIqGenerator; return this.mIqGenerator;
} }
public IqParser getIqParser() { return this.mIqParser; }
public JingleConnectionManager getJingleConnectionManager() { public JingleConnectionManager getJingleConnectionManager() {
return this.mJingleConnectionManager; return this.mJingleConnectionManager;
} }
@ -2083,8 +2121,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
return this.mHttpConnectionManager; return this.mHttpConnectionManager;
} }
public void resendFailedMessages(Message message) { public void resendFailedMessages(final Message message) {
List<Message> messages = new ArrayList<>(); final Collection<Message> messages = new ArrayList<>();
Message current = message; Message current = message;
while (current.getStatus() == Message.STATUS_SEND_FAILED) { while (current.getStatus() == Message.STATUS_SEND_FAILED) {
messages.add(current); messages.add(current);
@ -2094,7 +2132,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
break; break;
} }
} }
for (Message msg : messages) { for (final Message msg : messages) {
markMessage(msg, Message.STATUS_WAITING); markMessage(msg, Message.STATUS_WAITING);
this.resendMessage(msg); this.resendMessage(msg);
} }
@ -2136,4 +2174,35 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
return XmppConnectionService.this; 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);
}
}
});
}
}
} }

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}
}

View File

@ -1,101 +1,33 @@
package eu.siacs.conversations.ui; package eu.siacs.conversations.ui;
import java.util.ArrayList;
import java.util.Collections;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; 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.View;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText; import java.util.Collections;
import android.widget.ListView;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.ListItem; 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 @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_choose_contact); getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
mListView = (ListView) findViewById(R.id.choose_contact_list);
mListView.setFastScrollEnabled(true);
mContactsAdapter = new ListItemAdapter(this, contacts);
mListView.setAdapter(mContactsAdapter);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> arg0, View arg1, public void onItemClick(final AdapterView<?> parent, final View view,
int position, long arg3) { final int position, final long id) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(), imm.hideSoftInputFromWindow(getSearchEditText().getWindowToken(),
InputMethodManager.HIDE_IMPLICIT_ONLY); InputMethodManager.HIDE_IMPLICIT_ONLY);
Intent request = getIntent(); final Intent request = getIntent();
Intent data = new Intent(); final Intent data = new Intent();
ListItem mListItem = contacts.get(position); final ListItem mListItem = getListItems().get(position);
data.putExtra("contact", mListItem.getJid().toString()); data.putExtra("contact", mListItem.getJid().toString());
String account = request.getStringExtra("account"); String account = request.getStringExtra("account");
if (account == null && mListItem instanceof Contact) { if (account == null && mListItem instanceof Contact) {
@ -108,38 +40,21 @@ public class ChooseContactActivity extends XmppActivity {
finish(); finish();
} }
}); });
} }
@Override protected void filterContacts(final String needle) {
public boolean onCreateOptionsMenu(Menu menu) { getListItems().clear();
getMenuInflater().inflate(R.menu.choose_contact, menu); for (final Account account : xmppConnectionService.getAccounts()) {
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()) {
if (account.getStatus() != Account.State.DISABLED) { 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)) { if (contact.showInRoster() && contact.match(needle)) {
this.contacts.add(contact); getListItems().add(contact);
} }
} }
} }
} }
Collections.sort(this.contacts); Collections.sort(getListItems());
mContactsAdapter.notifyDataSetChanged(); getListItemAdapter().notifyDataSetChanged();
} }
} }

View File

@ -157,8 +157,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
@Override @Override
public void onValueEdited(String value) { public void onValueEdited(String value) {
MessagePacket packet = xmppConnectionService MessagePacket packet = xmppConnectionService
.getMessageGenerator().conferenceSubject( .getMessageGenerator().conferenceSubject(
mConversation, value); mConversation, value);
xmppConnectionService.sendMessagePacket( xmppConnectionService.sendMessagePacket(
mConversation.getAccount(), packet); mConversation.getAccount(), packet);
} }
@ -191,7 +191,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
@Override @Override
protected String getShareableUri() { protected String getShareableUri() {
if (mConversation != null) { if (mConversation != null) {
return "xmpp:" + mConversation.getContactJid().toBareJid().toString() + "?join"; return "xmpp:" + mConversation.getJid().toBareJid().toString() + "?join";
} else { } else {
return ""; return "";
} }
@ -202,7 +202,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
MenuItem menuItemSaveBookmark = menu.findItem(R.id.action_save_as_bookmark); MenuItem menuItemSaveBookmark = menu.findItem(R.id.action_save_as_bookmark);
MenuItem menuItemDeleteBookmark = menu.findItem(R.id.action_delete_bookmark); MenuItem menuItemDeleteBookmark = menu.findItem(R.id.action_delete_bookmark);
Account account = mConversation.getAccount(); Account account = mConversation.getAccount();
if (account.hasBookmarkFor(mConversation.getContactJid().toBareJid())) { if (account.hasBookmarkFor(mConversation.getJid().toBareJid())) {
menuItemSaveBookmark.setVisible(false); menuItemSaveBookmark.setVisible(false);
menuItemDeleteBookmark.setVisible(true); menuItemDeleteBookmark.setVisible(true);
} else { } else {
@ -263,9 +263,9 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
protected void saveAsBookmark() { protected void saveAsBookmark() {
Account account = mConversation.getAccount(); Account account = mConversation.getAccount();
Bookmark bookmark = new Bookmark(account, mConversation.getContactJid().toBareJid()); Bookmark bookmark = new Bookmark(account, mConversation.getJid().toBareJid());
if (!mConversation.getContactJid().isBareJid()) { if (!mConversation.getJid().isBareJid()) {
bookmark.setNick(mConversation.getContactJid().getResourcepart()); bookmark.setNick(mConversation.getJid().getResourcepart());
} }
bookmark.setAutojoin(true); bookmark.setAutojoin(true);
account.getBookmarks().add(bookmark); account.getBookmarks().add(bookmark);
@ -288,7 +288,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
} }
if (uuid != null) { if (uuid != null) {
this.mConversation = xmppConnectionService this.mConversation = xmppConnectionService
.findConversationByUuid(uuid); .findConversationByUuid(uuid);
if (this.mConversation != null) { if (this.mConversation != null) {
populateView(); populateView();
} }
@ -297,11 +297,11 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
private void populateView() { private void populateView() {
mAccountJid.setText(getString(R.string.using_account, mConversation mAccountJid.setText(getString(R.string.using_account, mConversation
.getAccount().getJid().toBareJid())); .getAccount().getJid().toBareJid()));
mYourPhoto.setImageBitmap(avatarService().get( mYourPhoto.setImageBitmap(avatarService().get(
mConversation.getAccount(), getPixel(48))); mConversation.getAccount(), getPixel(48)));
setTitle(mConversation.getName()); setTitle(mConversation.getName());
mFullJid.setText(mConversation.getContactJid().toBareJid().toString()); mFullJid.setText(mConversation.getJid().toBareJid().toString());
mYourNick.setText(mConversation.getMucOptions().getActualNick()); mYourNick.setText(mConversation.getMucOptions().getActualNick());
mRoleAffiliaton = (TextView) findViewById(R.id.muc_role); mRoleAffiliaton = (TextView) findViewById(R.id.muc_role);
if (mConversation.getMucOptions().online()) { if (mConversation.getMucOptions().online()) {
@ -338,7 +338,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
registerForContextMenu(view); registerForContextMenu(view);
view.setTag(user); view.setTag(user);
TextView name = (TextView) view 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 key = (TextView) view.findViewById(R.id.key);
TextView role = (TextView) view.findViewById(R.id.contact_jid); TextView role = (TextView) view.findViewById(R.id.contact_jid);
if (user.getPgpKeyId() != 0) { if (user.getPgpKeyId() != 0) {

View File

@ -38,10 +38,11 @@ import eu.siacs.conversations.entities.ListItem;
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
import eu.siacs.conversations.utils.UIHelper; 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.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid; 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"; public static final String ACTION_VIEW_CONTACT = "view_contact";
private Contact contact; private Contact contact;
@ -50,7 +51,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
ContactDetailsActivity.this.xmppConnectionService ContactDetailsActivity.this.xmppConnectionService
.deleteContactOnServer(contact); .deleteContactOnServer(contact);
ContactDetailsActivity.this.finish(); ContactDetailsActivity.this.finish();
} }
}; };
@ -58,14 +59,14 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
@Override @Override
public void onCheckedChanged(CompoundButton buttonView, public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) { boolean isChecked) {
if (isChecked) { if (isChecked) {
if (contact if (contact
.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) { .getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
xmppConnectionService.sendPresencePacket(contact xmppConnectionService.sendPresencePacket(contact
.getAccount(), .getAccount(),
xmppConnectionService.getPresenceGenerator() xmppConnectionService.getPresenceGenerator()
.sendPresenceUpdatesTo(contact)); .sendPresenceUpdatesTo(contact));
} else { } else {
contact.setOption(Contact.Options.PREEMPTIVE_GRANT); contact.setOption(Contact.Options.PREEMPTIVE_GRANT);
} }
@ -73,7 +74,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
contact.resetOption(Contact.Options.PREEMPTIVE_GRANT); contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
xmppConnectionService.sendPresencePacket(contact.getAccount(), xmppConnectionService.sendPresencePacket(contact.getAccount(),
xmppConnectionService.getPresenceGenerator() xmppConnectionService.getPresenceGenerator()
.stopPresenceUpdatesTo(contact)); .stopPresenceUpdatesTo(contact));
} }
} }
}; };
@ -81,15 +82,15 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
@Override @Override
public void onCheckedChanged(CompoundButton buttonView, public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) { boolean isChecked) {
if (isChecked) { if (isChecked) {
xmppConnectionService.sendPresencePacket(contact.getAccount(), xmppConnectionService.sendPresencePacket(contact.getAccount(),
xmppConnectionService.getPresenceGenerator() xmppConnectionService.getPresenceGenerator()
.requestPresenceUpdatesFrom(contact)); .requestPresenceUpdatesFrom(contact));
} else { } else {
xmppConnectionService.sendPresencePacket(contact.getAccount(), xmppConnectionService.sendPresencePacket(contact.getAccount(),
xmppConnectionService.getPresenceGenerator() xmppConnectionService.getPresenceGenerator()
.stopPresenceUpdatesFrom(contact)); .stopPresenceUpdatesFrom(contact));
} }
} }
}; };
@ -127,7 +128,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
ContactDetailsActivity.this); ContactDetailsActivity.this);
builder.setTitle(getString(R.string.action_add_phone_book)); builder.setTitle(getString(R.string.action_add_phone_book));
builder.setMessage(getString(R.string.add_phone_book_text, builder.setMessage(getString(R.string.add_phone_book_text,
contact.getJid())); contact.getJid()));
builder.setNegativeButton(getString(R.string.cancel), null); builder.setNegativeButton(getString(R.string.cancel), null);
builder.setPositiveButton(getString(R.string.add), addToPhonebook); builder.setPositiveButton(getString(R.string.add), addToPhonebook);
builder.create().show(); builder.create().show();
@ -166,7 +167,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
} }
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (getIntent().getAction().equals(ACTION_VIEW_CONTACT)) { if (getIntent().getAction().equals(ACTION_VIEW_CONTACT)) {
try { try {
@ -188,15 +189,17 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
badge = (QuickContactBadge) findViewById(R.id.details_contact_badge); badge = (QuickContactBadge) findViewById(R.id.details_contact_badge);
keys = (LinearLayout) findViewById(R.id.details_contact_keys); keys = (LinearLayout) findViewById(R.id.details_contact_keys);
tags = (LinearLayout) findViewById(R.id.tags); tags = (LinearLayout) findViewById(R.id.tags);
getActionBar().setHomeButtonEnabled(true); if (getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(true); 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); this.showDynamicTags = preferences.getBoolean("show_dynamic_tags",false);
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem menuItem) { public boolean onOptionsItemSelected(final MenuItem menuItem) {
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setNegativeButton(getString(R.string.cancel), null); builder.setNegativeButton(getString(R.string.cancel), null);
switch (menuItem.getItemId()) { switch (menuItem.getItemId()) {
@ -205,11 +208,11 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
break; break;
case R.id.action_delete_contact: case R.id.action_delete_contact:
builder.setTitle(getString(R.string.action_delete_contact)) builder.setTitle(getString(R.string.action_delete_contact))
.setMessage( .setMessage(
getString(R.string.remove_contact_text, getString(R.string.remove_contact_text,
contact.getJid())) contact.getJid()))
.setPositiveButton(getString(R.string.delete), .setPositiveButton(getString(R.string.delete),
removeFromRoster).create().show(); removeFromRoster).create().show();
break; break;
case R.id.action_edit_contact: case R.id.action_edit_contact:
if (contact.getSystemAccount() == null) { if (contact.getSystemAccount() == null) {
@ -219,7 +222,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
public void onValueEdited(String value) { public void onValueEdited(String value) {
contact.setServerName(value); contact.setServerName(value);
ContactDetailsActivity.this.xmppConnectionService ContactDetailsActivity.this.xmppConnectionService
.pushContactToServer(contact); .pushContactToServer(contact);
populateView(); populateView();
} }
}); });
@ -285,7 +288,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
receive.setOnCheckedChangeListener(this.mOnReceiveCheckedChange); receive.setOnCheckedChangeListener(this.mOnReceiveCheckedChange);
lastseen.setText(UIHelper.lastseen(getApplicationContext(), lastseen.setText(UIHelper.lastseen(getApplicationContext(),
contact.lastseen.time)); contact.lastseen.time));
if (contact.getPresences().size() > 1) { if (contact.getPresences().size() > 1) {
contactJidTv.setText(contact.getJid() + " (" contactJidTv.setText(contact.getJid() + " ("
@ -294,7 +297,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
contactJidTv.setText(contact.getJid().toString()); contactJidTv.setText(contact.getJid().toString());
} }
accountJidTv.setText(getString(R.string.using_account, contact accountJidTv.setText(getString(R.string.using_account, contact
.getAccount().getJid().toBareJid())); .getAccount().getJid().toBareJid()));
prepareContactBadge(badge, contact); prepareContactBadge(badge, contact);
if (contact.getSystemAccount() == null) { if (contact.getSystemAccount() == null) {
badge.setOnClickListener(onBadgeClick); badge.setOnClickListener(onBadgeClick);
@ -309,7 +312,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
TextView key = (TextView) view.findViewById(R.id.key); TextView key = (TextView) view.findViewById(R.id.key);
TextView keyType = (TextView) view.findViewById(R.id.key_type); TextView keyType = (TextView) view.findViewById(R.id.key_type);
ImageButton remove = (ImageButton) view ImageButton remove = (ImageButton) view
.findViewById(R.id.button_remove); .findViewById(R.id.button_remove);
remove.setVisibility(View.VISIBLE); remove.setVisibility(View.VISIBLE);
keyType.setText("OTR Fingerprint"); keyType.setText("OTR Fingerprint");
key.setText(otrFingerprint); key.setText(otrFingerprint);
@ -334,7 +337,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
@Override @Override
public void onClick(View v) { public void onClick(View v) {
PgpEngine pgp = ContactDetailsActivity.this.xmppConnectionService PgpEngine pgp = ContactDetailsActivity.this.xmppConnectionService
.getPgpEngine(); .getPgpEngine();
if (pgp != null) { if (pgp != null) {
PendingIntent intent = pgp.getIntentForKey(contact); PendingIntent intent = pgp.getIntentForKey(contact);
if (intent != null) { if (intent != null) {
@ -363,8 +366,8 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
} else { } else {
tags.setVisibility(View.VISIBLE); tags.setVisibility(View.VISIBLE);
tags.removeAllViewsInLayout(); tags.removeAllViewsInLayout();
for(ListItem.Tag tag : tagList) { for(final ListItem.Tag tag : tagList) {
TextView tv = (TextView) inflater.inflate(R.layout.list_item_tag,tags,false); final TextView tv = (TextView) inflater.inflate(R.layout.list_item_tag,tags,false);
tv.setText(tag.getName()); tv.setText(tag.getName());
tv.setBackgroundColor(tag.getColor()); tv.setBackgroundColor(tag.getColor());
tags.addView(tv); tags.addView(tv);
@ -406,7 +409,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
public void onBackendConnected() { public void onBackendConnected() {
if ((accountJid != null) && (contactJid != null)) { if ((accountJid != null) && (contactJid != null)) {
Account account = xmppConnectionService Account account = xmppConnectionService
.findAccountByJid(accountJid); .findAccountByJid(accountJid);
if (account == null) { if (account == null) {
return; return;
} }
@ -414,4 +417,15 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
populateView(); populateView();
} }
} }
@Override
public void OnUpdateBlocklist(final Status status) {
runOnUiThread(new Runnable() {
@Override
public void run() {
populateView();
}
});
}
} }

View File

@ -15,7 +15,6 @@ import android.os.SystemClock;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.support.v4.widget.SlidingPaneLayout; import android.support.v4.widget.SlidingPaneLayout;
import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener; import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener;
import android.view.KeyEvent;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
@ -32,6 +31,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import eu.siacs.conversations.R; import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Blockable;
import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message; 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.services.XmppConnectionService.OnRosterUpdate;
import eu.siacs.conversations.ui.adapter.ConversationAdapter; import eu.siacs.conversations.ui.adapter.ConversationAdapter;
import eu.siacs.conversations.utils.ExceptionHelper; import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
public class ConversationActivity extends XmppActivity implements public class ConversationActivity extends XmppActivity
OnAccountUpdate, OnConversationUpdate, OnRosterUpdate { implements OnAccountUpdate, OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist {
public static final String VIEW_CONVERSATION = "viewConversation"; public static final String VIEW_CONVERSATION = "viewConversation";
public static final String CONVERSATION = "conversationUuid"; public static final String CONVERSATION = "conversationUuid";
@ -144,12 +145,12 @@ public class ConversationActivity extends XmppActivity implements
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (savedInstanceState != null) {mOpenConverstaion = savedInstanceState.getString( if (savedInstanceState != null) {mOpenConverstaion = savedInstanceState.getString(
STATE_OPEN_CONVERSATION, null); STATE_OPEN_CONVERSATION, null);
mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true); mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true);
String pending = savedInstanceState.getString(STATE_PENDING_URI, null); String pending = savedInstanceState.getString(STATE_PENDING_URI, null);
if (pending != null) { if (pending != null) {
mPendingImageUri = Uri.parse(pending); mPendingImageUri = Uri.parse(pending);
} }
} }
setContentView(R.layout.fragment_conversations_overview); setContentView(R.layout.fragment_conversations_overview);
@ -172,7 +173,7 @@ public class ConversationActivity extends XmppActivity implements
@Override @Override
public void onItemClick(AdapterView<?> arg0, View clickedView, public void onItemClick(AdapterView<?> arg0, View clickedView,
int position, long arg3) { int position, long arg3) {
if (getSelectedConversation() != conversationList.get(position)) { if (getSelectedConversation() != conversationList.get(position)) {
setSelectedConversation(conversationList.get(position)); setSelectedConversation(conversationList.get(position));
ConversationActivity.this.mConversationFragment.reInit(getSelectedConversation()); ConversationActivity.this.mConversationFragment.reInit(getSelectedConversation());
@ -188,7 +189,7 @@ public class ConversationActivity extends XmppActivity implements
SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
mSlidingPaneLayout.setParallaxDistance(150); mSlidingPaneLayout.setParallaxDistance(150);
mSlidingPaneLayout mSlidingPaneLayout
.setShadowResource(R.drawable.es_slidingpane_shadow); .setShadowResource(R.drawable.es_slidingpane_shadow);
mSlidingPaneLayout.setSliderFadeColor(0); mSlidingPaneLayout.setSliderFadeColor(0);
mSlidingPaneLayout.setPanelSlideListener(new PanelSlideListener() { mSlidingPaneLayout.setPanelSlideListener(new PanelSlideListener() {
@ -199,7 +200,7 @@ public class ConversationActivity extends XmppActivity implements
hideKeyboard(); hideKeyboard();
if (xmppConnectionServiceBound) { if (xmppConnectionServiceBound) {
xmppConnectionService.getNotificationService() xmppConnectionService.getNotificationService()
.setOpenConversation(null); .setOpenConversation(null);
} }
closeContextMenu(); closeContextMenu();
} }
@ -244,7 +245,7 @@ public class ConversationActivity extends XmppActivity implements
if (conversation.getMode() == Conversation.MODE_SINGLE || useSubjectToIdentifyConference()) { if (conversation.getMode() == Conversation.MODE_SINGLE || useSubjectToIdentifyConference()) {
ab.setTitle(conversation.getName()); ab.setTitle(conversation.getName());
} else { } else {
ab.setTitle(conversation.getContactJid().toBareJid().toString()); ab.setTitle(conversation.getJid().toBareJid().toString());
} }
} else { } else {
ab.setDisplayHomeAsUpEnabled(false); ab.setDisplayHomeAsUpEnabled(false);
@ -269,17 +270,18 @@ public class ConversationActivity extends XmppActivity implements
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.conversations, menu); getMenuInflater().inflate(R.menu.conversations, menu);
MenuItem menuSecure = menu.findItem(R.id.action_security); final MenuItem menuSecure = menu.findItem(R.id.action_security);
MenuItem menuArchive = menu.findItem(R.id.action_archive); final MenuItem menuArchive = menu.findItem(R.id.action_archive);
MenuItem menuMucDetails = menu.findItem(R.id.action_muc_details); final MenuItem menuMucDetails = menu.findItem(R.id.action_muc_details);
MenuItem menuContactDetails = menu final MenuItem menuContactDetails = menu.findItem(R.id.action_contact_details);
.findItem(R.id.action_contact_details); final MenuItem menuAttach = menu.findItem(R.id.action_attach_file);
MenuItem menuAttach = menu.findItem(R.id.action_attach_file); final MenuItem menuClearHistory = menu.findItem(R.id.action_clear_history);
MenuItem menuClearHistory = menu.findItem(R.id.action_clear_history); final MenuItem menuAdd = menu.findItem(R.id.action_add);
MenuItem menuAdd = menu.findItem(R.id.action_add); final MenuItem menuInviteContact = menu.findItem(R.id.action_invite);
MenuItem menuInviteContact = menu.findItem(R.id.action_invite); final MenuItem menuMute = menu.findItem(R.id.action_mute);
MenuItem menuMute = menu.findItem(R.id.action_mute); final MenuItem menuUnmute = menu.findItem(R.id.action_unmute);
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() if (isConversationsOverviewVisable()
&& isConversationsOverviewHideable()) { && isConversationsOverviewHideable()) {
@ -292,19 +294,32 @@ public class ConversationActivity extends XmppActivity implements
menuClearHistory.setVisible(false); menuClearHistory.setVisible(false);
menuMute.setVisible(false); menuMute.setVisible(false);
menuUnmute.setVisible(false); menuUnmute.setVisible(false);
menuBlock.setVisible(false);
menuUnblock.setVisible(false);
} else { } else {
menuAdd.setVisible(!isConversationsOverviewHideable()); menuAdd.setVisible(!isConversationsOverviewHideable());
if (this.getSelectedConversation() != null) { if (this.getSelectedConversation() != null) {
if (this.getSelectedConversation().getLatestMessage() if (this.getSelectedConversation().getLatestMessage()
.getEncryption() != Message.ENCRYPTION_NONE) { .getEncryption() != Message.ENCRYPTION_NONE) {
menuSecure.setIcon(R.drawable.ic_action_secure); menuSecure.setIcon(R.drawable.ic_action_secure);
} }
if (this.getSelectedConversation().getMode() == Conversation.MODE_MULTI) { if (this.getSelectedConversation().getMode() == Conversation.MODE_MULTI) {
menuContactDetails.setVisible(false); menuContactDetails.setVisible(false);
menuAttach.setVisible(false); menuAttach.setVisible(false);
menuBlock.setVisible(false);
menuUnblock.setVisible(false);
} else { } else {
menuMucDetails.setVisible(false); menuMucDetails.setVisible(false);
menuInviteContact.setTitle(R.string.conference_with); 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()) { if (this.getSelectedConversation().isMuted()) {
menuMute.setVisible(false); menuMute.setVisible(false);
@ -323,7 +338,7 @@ public class ConversationActivity extends XmppActivity implements
public void onPresenceSelected() { public void onPresenceSelected() {
if (attachmentChoice == ATTACHMENT_CHOICE_TAKE_PHOTO) { if (attachmentChoice == ATTACHMENT_CHOICE_TAKE_PHOTO) {
mPendingImageUri = xmppConnectionService.getFileBackend() mPendingImageUri = xmppConnectionService.getFileBackend()
.getTakePhotoUri(); .getTakePhotoUri();
Intent takePictureIntent = new Intent( Intent takePictureIntent = new Intent(
MediaStore.ACTION_IMAGE_CAPTURE); MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
@ -364,7 +379,7 @@ public class ConversationActivity extends XmppActivity implements
@Override @Override
public void userInputRequried(PendingIntent pi, public void userInputRequried(PendingIntent pi,
Contact contact) { Contact contact) {
ConversationActivity.this.runIntent(pi, ConversationActivity.this.runIntent(pi,
attachmentChoice); attachmentChoice);
} }
@ -381,18 +396,18 @@ public class ConversationActivity extends XmppActivity implements
}); });
} else { } else {
final ConversationFragment fragment = (ConversationFragment) getFragmentManager() final ConversationFragment fragment = (ConversationFragment) getFragmentManager()
.findFragmentByTag("conversation"); .findFragmentByTag("conversation");
if (fragment != null) { if (fragment != null) {
fragment.showNoPGPKeyDialog(false, fragment.showNoPGPKeyDialog(false,
new OnClickListener() { new OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, public void onClick(DialogInterface dialog,
int which) { int which) {
conversation conversation
.setNextEncryption(Message.ENCRYPTION_NONE); .setNextEncryption(Message.ENCRYPTION_NONE);
xmppConnectionService.databaseBackend xmppConnectionService.databaseBackend
.updateConversation(conversation); .updateConversation(conversation);
selectPresenceToAttachFile(attachmentChoice); selectPresenceToAttachFile(attachmentChoice);
} }
}); });
@ -402,7 +417,7 @@ public class ConversationActivity extends XmppActivity implements
showInstallPgpDialog(); showInstallPgpDialog();
} }
} else if (getSelectedConversation().getNextEncryption( } else if (getSelectedConversation().getNextEncryption(
forceEncryption()) == Message.ENCRYPTION_NONE) { forceEncryption()) == Message.ENCRYPTION_NONE) {
selectPresenceToAttachFile(attachmentChoice); selectPresenceToAttachFile(attachmentChoice);
} else { } else {
selectPresenceToAttachFile(attachmentChoice); selectPresenceToAttachFile(attachmentChoice);
@ -410,7 +425,7 @@ public class ConversationActivity extends XmppActivity implements
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(final MenuItem item) {
if (item.getItemId() == android.R.id.home) { if (item.getItemId() == android.R.id.home) {
showConversationsOverview(); showConversationsOverview();
return true; return true;
@ -455,6 +470,12 @@ public class ConversationActivity extends XmppActivity implements
case R.id.action_unmute: case R.id.action_unmute:
unmuteConversation(getSelectedConversation()); unmuteConversation(getSelectedConversation());
break; break;
case R.id.action_block:
BlockContactDialog.show(this, xmppConnectionService, getSelectedConversation());
break;
case R.id.action_unblock:
BlockContactDialog.show(this, xmppConnectionService, getSelectedConversation());
break;
default: default:
break; break;
} }
@ -483,7 +504,7 @@ public class ConversationActivity extends XmppActivity implements
View dialogView = getLayoutInflater().inflate( View dialogView = getLayoutInflater().inflate(
R.layout.dialog_clear_history, null); R.layout.dialog_clear_history, null);
final CheckBox endConversationCheckBox = (CheckBox) dialogView final CheckBox endConversationCheckBox = (CheckBox) dialogView
.findViewById(R.id.end_conversation_checkbox); .findViewById(R.id.end_conversation_checkbox);
builder.setView(dialogView); builder.setView(dialogView);
builder.setNegativeButton(getString(R.string.cancel), null); builder.setNegativeButton(getString(R.string.cancel), null);
builder.setPositiveButton(getString(R.string.delete_messages), builder.setPositiveButton(getString(R.string.delete_messages),
@ -511,24 +532,24 @@ public class ConversationActivity extends XmppActivity implements
PopupMenu attachFilePopup = new PopupMenu(this, menuAttachFile); PopupMenu attachFilePopup = new PopupMenu(this, menuAttachFile);
attachFilePopup.inflate(R.menu.attachment_choices); attachFilePopup.inflate(R.menu.attachment_choices);
attachFilePopup attachFilePopup
.setOnMenuItemClickListener(new OnMenuItemClickListener() { .setOnMenuItemClickListener(new OnMenuItemClickListener() {
@Override @Override
public boolean onMenuItemClick(MenuItem item) { public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.attach_choose_picture: case R.id.attach_choose_picture:
attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE); attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE);
break; break;
case R.id.attach_take_picture: case R.id.attach_take_picture:
attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO); attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO);
break; break;
case R.id.attach_record_voice: case R.id.attach_record_voice:
attachFile(ATTACHMENT_CHOICE_CHOOSE_FILE); attachFile(ATTACHMENT_CHOICE_CHOOSE_FILE);
break; break;
}
return false;
} }
}); return false;
}
});
attachFilePopup.show(); attachFilePopup.show();
} }
@ -539,7 +560,7 @@ public class ConversationActivity extends XmppActivity implements
} }
PopupMenu popup = new PopupMenu(this, menuItemView); PopupMenu popup = new PopupMenu(this, menuItemView);
final ConversationFragment fragment = (ConversationFragment) getFragmentManager() final ConversationFragment fragment = (ConversationFragment) getFragmentManager()
.findFragmentByTag("conversation"); .findFragmentByTag("conversation");
if (fragment != null) { if (fragment != null) {
popup.setOnMenuItemClickListener(new OnMenuItemClickListener() { popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@ -559,7 +580,7 @@ public class ConversationActivity extends XmppActivity implements
if (conversation.getAccount().getKeys() if (conversation.getAccount().getKeys()
.has("pgp_signature")) { .has("pgp_signature")) {
conversation conversation
.setNextEncryption(Message.ENCRYPTION_PGP); .setNextEncryption(Message.ENCRYPTION_PGP);
item.setChecked(true); item.setChecked(true);
} else { } else {
announcePgp(conversation.getAccount(), announcePgp(conversation.getAccount(),
@ -574,7 +595,7 @@ public class ConversationActivity extends XmppActivity implements
break; break;
} }
xmppConnectionService.databaseBackend xmppConnectionService.databaseBackend
.updateConversation(conversation); .updateConversation(conversation);
fragment.updateChatMsgHint(); fragment.updateChatMsgHint();
return true; return true;
} }
@ -599,11 +620,11 @@ public class ConversationActivity extends XmppActivity implements
break; break;
case Message.ENCRYPTION_PGP: case Message.ENCRYPTION_PGP:
popup.getMenu().findItem(R.id.encryption_choice_pgp) popup.getMenu().findItem(R.id.encryption_choice_pgp)
.setChecked(true); .setChecked(true);
break; break;
default: default:
popup.getMenu().findItem(R.id.encryption_choice_none) popup.getMenu().findItem(R.id.encryption_choice_none)
.setChecked(true); .setChecked(true);
break; break;
} }
popup.show(); popup.show();
@ -619,17 +640,17 @@ public class ConversationActivity extends XmppActivity implements
new OnClickListener() { new OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(final DialogInterface dialog, final int which) {
long till; final long till;
if (durations[which] == -1) { if (durations[which] == -1) {
till = Long.MAX_VALUE; till = Long.MAX_VALUE;
} else { } else {
till = SystemClock.elapsedRealtime() till = SystemClock.elapsedRealtime()
+ (durations[which] * 1000); + (durations[which] * 1000);
} }
conversation.setMutedTill(till); conversation.setMutedTill(till);
ConversationActivity.this.xmppConnectionService.databaseBackend ConversationActivity.this.xmppConnectionService.databaseBackend
.updateConversation(conversation); .updateConversation(conversation);
updateConversationList(); updateConversationList();
ConversationActivity.this.mConversationFragment.updateMessages(); ConversationActivity.this.mConversationFragment.updateMessages();
invalidateOptionsMenu(); invalidateOptionsMenu();
@ -763,11 +784,11 @@ public class ConversationActivity extends XmppActivity implements
} }
private void selectConversationByUuid(String uuid) { private void selectConversationByUuid(String uuid) {
for (Conversation aConversationList : conversationList) { for (Conversation aConversationList : conversationList) {
if (aConversationList.getUuid().equals(uuid)) { if (aConversationList.getUuid().equals(uuid)) {
setSelectedConversation(aConversationList); setSelectedConversation(aConversationList);
} }
} }
} }
@Override @Override
@ -778,7 +799,7 @@ public class ConversationActivity extends XmppActivity implements
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, protected void onActivityResult(int requestCode, int resultCode,
final Intent data) { final Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
if (requestCode == REQUEST_DECRYPT_PGP) { if (requestCode == REQUEST_DECRYPT_PGP) {
@ -859,7 +880,7 @@ public class ConversationActivity extends XmppActivity implements
@Override @Override
public void userInputRequried(PendingIntent pi, public void userInputRequried(PendingIntent pi,
Message object) { Message object) {
hidePrepareFileToast(); hidePrepareFileToast();
ConversationActivity.this.runIntent(pi, ConversationActivity.this.runIntent(pi,
ConversationActivity.REQUEST_SEND_PGP_IMAGE); ConversationActivity.REQUEST_SEND_PGP_IMAGE);
@ -892,7 +913,7 @@ public class ConversationActivity extends XmppActivity implements
public void updateConversationList() { public void updateConversationList() {
xmppConnectionService xmppConnectionService
.populateWithOrderedConversations(conversationList); .populateWithOrderedConversations(conversationList);
listAdapter.notifyDataSetChanged(); listAdapter.notifyDataSetChanged();
} }
@ -910,7 +931,7 @@ public class ConversationActivity extends XmppActivity implements
@Override @Override
public void userInputRequried(PendingIntent pi, public void userInputRequried(PendingIntent pi,
Message message) { Message message) {
ConversationActivity.this.runIntent(pi, ConversationActivity.this.runIntent(pi,
ConversationActivity.REQUEST_SEND_MESSAGE); ConversationActivity.REQUEST_SEND_MESSAGE);
} }
@ -962,7 +983,7 @@ public class ConversationActivity extends XmppActivity implements
updateConversationList(); updateConversationList();
if (conversationList.size() == 0) { if (conversationList.size() == 0) {
startActivity(new Intent(getApplicationContext(), startActivity(new Intent(getApplicationContext(),
StartConversationActivity.class)); StartConversationActivity.class));
finish(); finish();
} }
ConversationActivity.this.mConversationFragment.updateMessages(); ConversationActivity.this.mConversationFragment.updateMessages();
@ -975,12 +996,31 @@ public class ConversationActivity extends XmppActivity implements
public void onRosterUpdate() { public void onRosterUpdate() {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
updateConversationList(); updateConversationList();
ConversationActivity.this.mConversationFragment.updateMessages(); ConversationActivity.this.mConversationFragment.updateMessages();
updateActionBarTitle(); 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);
} }
} }

View File

@ -9,7 +9,6 @@ import android.content.Intent;
import android.content.IntentSender; import android.content.IntentSender;
import android.content.IntentSender.SendIntentException; import android.content.IntentSender.SendIntentException;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu; import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo; import android.view.ContextMenu.ContextMenuInfo;
import android.view.Gravity; import android.view.Gravity;
@ -39,7 +38,6 @@ import java.util.List;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R; import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine; import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Account;
@ -118,7 +116,7 @@ public class ConversationFragment extends Fragment {
@Override @Override
public void onScroll(AbsListView view, int firstVisibleItem, public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) { int visibleItemCount, int totalItemCount) {
synchronized (ConversationFragment.this.messageList) { synchronized (ConversationFragment.this.messageList) {
if (firstVisibleItem < 5 && messagesLoaded && messageList.size() > 0) { if (firstVisibleItem < 5 && messagesLoaded && messageList.size() > 0) {
long timestamp = ConversationFragment.this.messageList.get(0).getTimeSent(); 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) { public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEND) { if (actionId == EditorInfo.IME_ACTION_SEND) {
InputMethodManager imm = (InputMethodManager) v.getContext() InputMethodManager imm = (InputMethodManager) v.getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE); .getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0); imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
sendMessage(); sendMessage();
return true; return true;
@ -266,7 +264,7 @@ public class ConversationFragment extends Fragment {
} }
Message message = new Message(conversation, mEditMessage.getText() Message message = new Message(conversation, mEditMessage.getText()
.toString(), conversation.getNextEncryption(activity .toString(), conversation.getNextEncryption(activity
.forceEncryption())); .forceEncryption()));
if (conversation.getMode() == Conversation.MODE_MULTI) { if (conversation.getMode() == Conversation.MODE_MULTI) {
if (conversation.getNextCounterpart() != null) { if (conversation.getNextCounterpart() != null) {
message.setCounterpart(conversation.getNextCounterpart()); message.setCounterpart(conversation.getNextCounterpart());
@ -287,13 +285,13 @@ public class ConversationFragment extends Fragment {
if (conversation.getMode() == Conversation.MODE_MULTI if (conversation.getMode() == Conversation.MODE_MULTI
&& conversation.getNextCounterpart() != null) { && conversation.getNextCounterpart() != null) {
this.mEditMessage.setHint(getString( this.mEditMessage.setHint(getString(
R.string.send_private_message_to, R.string.send_private_message_to,
conversation.getNextCounterpart().getResourcepart())); conversation.getNextCounterpart().getResourcepart()));
} else { } else {
switch (conversation.getNextEncryption(activity.forceEncryption())) { switch (conversation.getNextEncryption(activity.forceEncryption())) {
case Message.ENCRYPTION_NONE: case Message.ENCRYPTION_NONE:
mEditMessage mEditMessage
.setHint(getString(R.string.send_plain_text_message)); .setHint(getString(R.string.send_plain_text_message));
break; break;
case Message.ENCRYPTION_OTR: case Message.ENCRYPTION_OTR:
mEditMessage.setHint(getString(R.string.send_otr_message)); mEditMessage.setHint(getString(R.string.send_otr_message));
@ -309,7 +307,7 @@ public class ConversationFragment extends Fragment {
@Override @Override
public View onCreateView(final LayoutInflater inflater, public View onCreateView(final LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) { ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_conversation, final View view = inflater.inflate(R.layout.fragment_conversation,
container, false); container, false);
mEditMessage = (EditMessage) view.findViewById(R.id.textinput); mEditMessage = (EditMessage) view.findViewById(R.id.textinput);
@ -342,49 +340,49 @@ public class ConversationFragment extends Fragment {
messageListAdapter = new MessageAdapter((ConversationActivity) getActivity(), this.messageList); messageListAdapter = new MessageAdapter((ConversationActivity) getActivity(), this.messageList);
messageListAdapter.setOnContactPictureClicked(new OnContactPictureClicked() { messageListAdapter.setOnContactPictureClicked(new OnContactPictureClicked() {
@Override @Override
public void onContactPictureClicked(Message message) { public void onContactPictureClicked(Message message) {
if (message.getStatus() <= Message.STATUS_RECEIVED) { if (message.getStatus() <= Message.STATUS_RECEIVED) {
if (message.getConversation().getMode() == Conversation.MODE_MULTI) { if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
if (message.getCounterpart() != null) { if (message.getCounterpart() != null) {
if (!message.getCounterpart().isBareJid()) { if (!message.getCounterpart().isBareJid()) {
highlightInConference(message.getCounterpart().getResourcepart()); highlightInConference(message.getCounterpart().getResourcepart());
} else {
highlightInConference(message.getCounterpart().toString());
}
}
} else { } else {
Contact contact = message.getConversation() highlightInConference(message.getCounterpart().toString());
.getContact();
if (contact.showInRoster()) {
activity.switchToContactDetails(contact);
} else {
activity.showAddToRosterDialog(message
.getConversation());
}
} }
}
} else {
Contact contact = message.getConversation()
.getContact();
if (contact.showInRoster()) {
activity.switchToContactDetails(contact);
} else { } else {
Account account = message.getConversation().getAccount(); activity.showAddToRosterDialog(message
Intent intent = new Intent(activity, EditAccountActivity.class); .getConversation());
intent.putExtra("jid", account.getJid().toBareJid().toString());
startActivity(intent);
} }
} }
}); } else {
Account account = message.getConversation().getAccount();
Intent intent = new Intent(activity, EditAccountActivity.class);
intent.putExtra("jid", account.getJid().toBareJid().toString());
startActivity(intent);
}
}
});
messageListAdapter messageListAdapter
.setOnContactPictureLongClicked(new OnContactPictureLongClicked() { .setOnContactPictureLongClicked(new OnContactPictureLongClicked() {
@Override @Override
public void onContactPictureLongClicked(Message message) { public void onContactPictureLongClicked(Message message) {
if (message.getStatus() <= Message.STATUS_RECEIVED) { if (message.getStatus() <= Message.STATUS_RECEIVED) {
if (message.getConversation().getMode() == Conversation.MODE_MULTI) { if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
if (message.getCounterpart() != null) { if (message.getCounterpart() != null) {
privateMessageWith(message.getCounterpart()); privateMessageWith(message.getCounterpart());
}
} }
} }
} }
}); }
});
messagesView.setAdapter(messageListAdapter); messagesView.setAdapter(messageListAdapter);
registerForContextMenu(messagesView); registerForContextMenu(messagesView);
@ -394,7 +392,7 @@ public class ConversationFragment extends Fragment {
@Override @Override
public void onCreateContextMenu(ContextMenu menu, View v, public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) { ContextMenuInfo menuInfo) {
synchronized (this.messageList) { synchronized (this.messageList) {
super.onCreateContextMenu(menu, v, menuInfo); super.onCreateContextMenu(menu, v, menuInfo);
AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo; AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
@ -416,28 +414,28 @@ public class ConversationFragment extends Fragment {
if (this.selectedMessage.getType() != Message.TYPE_TEXT if (this.selectedMessage.getType() != Message.TYPE_TEXT
|| this.selectedMessage.getDownloadable() != null) { || this.selectedMessage.getDownloadable() != null) {
copyText.setVisible(false); copyText.setVisible(false);
} }
if (this.selectedMessage.getType() != Message.TYPE_IMAGE if (this.selectedMessage.getType() != Message.TYPE_IMAGE
|| this.selectedMessage.getDownloadable() != null) { || this.selectedMessage.getDownloadable() != null) {
shareImage.setVisible(false); shareImage.setVisible(false);
} }
if (this.selectedMessage.getStatus() != Message.STATUS_SEND_FAILED) { if (this.selectedMessage.getStatus() != Message.STATUS_SEND_FAILED) {
sendAgain.setVisible(false); sendAgain.setVisible(false);
} }
if ((this.selectedMessage.getType() != Message.TYPE_IMAGE && this.selectedMessage if ((this.selectedMessage.getType() != Message.TYPE_IMAGE && this.selectedMessage
.getDownloadable() == null) .getDownloadable() == null)
|| this.selectedMessage.getImageParams().url == null) { || this.selectedMessage.getImageParams().url == null) {
copyUrl.setVisible(false); copyUrl.setVisible(false);
} }
if (this.selectedMessage.getType() != Message.TYPE_TEXT if (this.selectedMessage.getType() != Message.TYPE_TEXT
|| this.selectedMessage.getDownloadable() != null || this.selectedMessage.getDownloadable() != null
|| !this.selectedMessage.bodyContainsDownloadable()) { || !this.selectedMessage.bodyContainsDownloadable()) {
downloadImage.setVisible(false); downloadImage.setVisible(false);
} }
if (this.selectedMessage.getDownloadable() == null if (this.selectedMessage.getDownloadable() == null
|| this.selectedMessage.getDownloadable() instanceof DownloadablePlaceholder) { || this.selectedMessage.getDownloadable() instanceof DownloadablePlaceholder) {
cancelTransmission.setVisible(false); cancelTransmission.setVisible(false);
} }
} }
} }
@ -472,16 +470,16 @@ public class ConversationFragment extends Fragment {
shareIntent.setAction(Intent.ACTION_SEND); shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, shareIntent.putExtra(Intent.EXTRA_STREAM,
activity.xmppConnectionService.getFileBackend() activity.xmppConnectionService.getFileBackend()
.getJingleFileUri(message)); .getJingleFileUri(message));
shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
shareIntent.setType("image/webp"); shareIntent.setType("image/webp");
activity.startActivity(Intent.createChooser(shareIntent, activity.startActivity(Intent.createChooser(shareIntent,
getText(R.string.share_with))); getText(R.string.share_with)));
} }
private void copyText(Message message) { private void copyText(Message message) {
if (activity.copyTextToClipboard(message.getMergedBody(), if (activity.copyTextToClipboard(message.getMergedBody(),
R.string.message_text)) { R.string.message_text)) {
Toast.makeText(activity, R.string.message_copied_to_clipboard, Toast.makeText(activity, R.string.message_copied_to_clipboard,
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
} }
@ -501,15 +499,15 @@ public class ConversationFragment extends Fragment {
private void copyUrl(Message message) { private void copyUrl(Message message) {
if (activity.copyTextToClipboard( 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.makeText(activity, R.string.url_copied_to_clipboard,
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
} }
} }
private void downloadImage(Message message) { private void downloadImage(Message message) {
activity.xmppConnectionService.getHttpConnectionManager() activity.xmppConnectionService.getHttpConnectionManager()
.createNewConnection(message); .createNewConnection(message);
} }
private void cancelTransmission(Message message) { private void cancelTransmission(Message message) {
@ -531,9 +529,9 @@ public class ConversationFragment extends Fragment {
mEditMessage.getText().insert(0, nick + ": "); mEditMessage.getText().insert(0, nick + ": ");
} else { } else {
if (mEditMessage.getText().charAt( if (mEditMessage.getText().charAt(
mEditMessage.getSelectionStart() - 1) != ' ') { mEditMessage.getSelectionStart() - 1) != ' ') {
nick = " " + nick; nick = " " + nick;
} }
mEditMessage.getText().insert(mEditMessage.getSelectionStart(), mEditMessage.getText().insert(mEditMessage.getSelectionStart(),
nick + " "); nick + " ");
} }
@ -583,12 +581,30 @@ public class ConversationFragment extends Fragment {
final ConversationActivity activity = (ConversationActivity) getActivity(); final ConversationActivity activity = (ConversationActivity) getActivity();
if (this.conversation != null) { if (this.conversation != null) {
final Contact contact = this.conversation.getContact(); 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, showSnackbar(R.string.notifications_disabled, R.string.enable,
new OnClickListener() { new OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(final View v) {
activity.unmuteConversation(conversation); activity.unmuteConversation(conversation);
} }
}); });
@ -601,7 +617,7 @@ public class ConversationFragment extends Fragment {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
activity.xmppConnectionService activity.xmppConnectionService
.createContact(contact); .createContact(contact);
activity.switchToContactDetails(contact); activity.switchToContactDetails(contact);
} }
}); });
@ -638,17 +654,17 @@ public class ConversationFragment extends Fragment {
default: default:
break; break;
} }
} }
conversation.populateWithMessages(ConversationFragment.this.messageList); conversation.populateWithMessages(ConversationFragment.this.messageList);
for (Message message : this.messageList) { for (Message message : this.messageList) {
if (message.getEncryption() == Message.ENCRYPTION_PGP if (message.getEncryption() == Message.ENCRYPTION_PGP
&& (message.getStatus() == Message.STATUS_RECEIVED || message && (message.getStatus() == Message.STATUS_RECEIVED || message
.getStatus() >= Message.STATUS_SEND) .getStatus() >= Message.STATUS_SEND)
&& message.getDownloadable() == null) { && message.getDownloadable() == null) {
if (!mEncryptedMessages.contains(message)) { if (!mEncryptedMessages.contains(message)) {
mEncryptedMessages.add(message); mEncryptedMessages.add(message);
} }
} }
} }
decryptNext(); decryptNext();
updateStatusMessages(); updateStatusMessages();
@ -720,44 +736,44 @@ public class ConversationFragment extends Fragment {
switch (c.getContact().getMostAvailableStatus()) { switch (c.getContact().getMostAvailableStatus()) {
case Presences.CHAT: case Presences.CHAT:
this.mSendButton this.mSendButton
.setImageResource(R.drawable.ic_action_send_now_online); .setImageResource(R.drawable.ic_action_send_now_online);
break; break;
case Presences.ONLINE: case Presences.ONLINE:
this.mSendButton this.mSendButton
.setImageResource(R.drawable.ic_action_send_now_online); .setImageResource(R.drawable.ic_action_send_now_online);
break; break;
case Presences.AWAY: case Presences.AWAY:
this.mSendButton this.mSendButton
.setImageResource(R.drawable.ic_action_send_now_away); .setImageResource(R.drawable.ic_action_send_now_away);
break; break;
case Presences.XA: case Presences.XA:
this.mSendButton this.mSendButton
.setImageResource(R.drawable.ic_action_send_now_away); .setImageResource(R.drawable.ic_action_send_now_away);
break; break;
case Presences.DND: case Presences.DND:
this.mSendButton this.mSendButton
.setImageResource(R.drawable.ic_action_send_now_dnd); .setImageResource(R.drawable.ic_action_send_now_dnd);
break; break;
default: default:
this.mSendButton this.mSendButton
.setImageResource(R.drawable.ic_action_send_now_offline); .setImageResource(R.drawable.ic_action_send_now_offline);
break; break;
} }
} else if (c.getMode() == Conversation.MODE_MULTI) { } else if (c.getMode() == Conversation.MODE_MULTI) {
if (c.getMucOptions().online()) { if (c.getMucOptions().online()) {
this.mSendButton this.mSendButton
.setImageResource(R.drawable.ic_action_send_now_online); .setImageResource(R.drawable.ic_action_send_now_online);
} else { } else {
this.mSendButton this.mSendButton
.setImageResource(R.drawable.ic_action_send_now_offline); .setImageResource(R.drawable.ic_action_send_now_offline);
} }
} else { } else {
this.mSendButton this.mSendButton
.setImageResource(R.drawable.ic_action_send_now_offline); .setImageResource(R.drawable.ic_action_send_now_offline);
} }
} else { } else {
this.mSendButton 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) } else if (conversation.hasValidOtrSession() && (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED)
&& (!conversation.isOtrFingerprintVerified())) { && (!conversation.isOtrFingerprintVerified())) {
showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify, clickToVerify); showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify, clickToVerify);
} }
} }
protected void showSnackbar(int message, int action, protected void showSnackbar(final int message, final int action,
OnClickListener clickListener) { final OnClickListener clickListener) {
snackbar.setVisibility(View.VISIBLE); snackbar.setVisibility(View.VISIBLE);
snackbar.setOnClickListener(null); snackbar.setOnClickListener(null);
snackbarMessage.setText(message); snackbarMessage.setText(message);
snackbarMessage.setOnClickListener(null); snackbarMessage.setOnClickListener(null);
snackbarAction.setVisibility(View.VISIBLE);
snackbarAction.setText(action); snackbarAction.setText(action);
snackbarAction.setOnClickListener(clickListener); snackbarAction.setOnClickListener(clickListener);
} }
@ -819,7 +836,7 @@ public class ConversationFragment extends Fragment {
@Override @Override
public void userInputRequried(PendingIntent pi, public void userInputRequried(PendingIntent pi,
Contact contact) { Contact contact) {
activity.runIntent( activity.runIntent(
pi, pi,
ConversationActivity.REQUEST_ENCRYPT_MESSAGE); ConversationActivity.REQUEST_ENCRYPT_MESSAGE);
@ -843,11 +860,11 @@ public class ConversationFragment extends Fragment {
@Override @Override
public void onClick(DialogInterface dialog, public void onClick(DialogInterface dialog,
int which) { int which) {
conversation conversation
.setNextEncryption(Message.ENCRYPTION_NONE); .setNextEncryption(Message.ENCRYPTION_NONE);
xmppService.databaseBackend xmppService.databaseBackend
.updateConversation(conversation); .updateConversation(conversation);
message.setEncryption(Message.ENCRYPTION_NONE); message.setEncryption(Message.ENCRYPTION_NONE);
xmppService.sendMessage(message); xmppService.sendMessage(message);
messageSent(); messageSent();
@ -858,9 +875,9 @@ public class ConversationFragment extends Fragment {
if (conversation.getMucOptions().pgpKeysInUse()) { if (conversation.getMucOptions().pgpKeysInUse()) {
if (!conversation.getMucOptions().everybodyHasKeys()) { if (!conversation.getMucOptions().everybodyHasKeys()) {
Toast warning = Toast Toast warning = Toast
.makeText(getActivity(), .makeText(getActivity(),
R.string.missing_public_keys, R.string.missing_public_keys,
Toast.LENGTH_LONG); Toast.LENGTH_LONG);
warning.setGravity(Gravity.CENTER_VERTICAL, 0, 0); warning.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
warning.show(); warning.show();
} }
@ -872,12 +889,12 @@ public class ConversationFragment extends Fragment {
@Override @Override
public void onClick(DialogInterface dialog, public void onClick(DialogInterface dialog,
int which) { int which) {
conversation conversation
.setNextEncryption(Message.ENCRYPTION_NONE); .setNextEncryption(Message.ENCRYPTION_NONE);
message.setEncryption(Message.ENCRYPTION_NONE); message.setEncryption(Message.ENCRYPTION_NONE);
xmppService.databaseBackend xmppService.databaseBackend
.updateConversation(conversation); .updateConversation(conversation);
xmppService.sendMessage(message); xmppService.sendMessage(message);
messageSent(); messageSent();
} }
@ -890,7 +907,7 @@ public class ConversationFragment extends Fragment {
} }
public void showNoPGPKeyDialog(boolean plural, public void showNoPGPKeyDialog(boolean plural,
DialogInterface.OnClickListener listener) { DialogInterface.OnClickListener listener) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setIconAttribute(android.R.attr.alertDialogIcon); builder.setIconAttribute(android.R.attr.alertDialogIcon);
if (plural) { if (plural) {

View File

@ -67,7 +67,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
mAccount.setOption(Account.OPTION_DISABLED, false); mAccount.setOption(Account.OPTION_DISABLED, false);
xmppConnectionService.updateAccount(mAccount); xmppConnectionService.updateAccount(mAccount);
return; return;
} }
if (!Validator.isValidJid(mAccountJid.getText().toString())) { if (!Validator.isValidJid(mAccountJid.getText().toString())) {
mAccountJid.setError(getString(R.string.invalid_jid)); mAccountJid.setError(getString(R.string.invalid_jid));
mAccountJid.requestFocus(); mAccountJid.requestFocus();
@ -87,32 +87,32 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
if (registerNewAccount) { if (registerNewAccount) {
if (!password.equals(passwordConfirm)) { if (!password.equals(passwordConfirm)) {
mPasswordConfirm mPasswordConfirm
.setError(getString(R.string.passwords_do_not_match)); .setError(getString(R.string.passwords_do_not_match));
mPasswordConfirm.requestFocus(); mPasswordConfirm.requestFocus();
return; return;
} }
} }
if (mAccount != null) { if (mAccount != null) {
mAccount.setPassword(password); mAccount.setPassword(password);
try { try {
mAccount.setUsername(jid.hasLocalpart() ? jid.getLocalpart() : ""); mAccount.setUsername(jid.hasLocalpart() ? jid.getLocalpart() : "");
mAccount.setServer(jid.getDomainpart()); mAccount.setServer(jid.getDomainpart());
} catch (final InvalidJidException ignored) { } catch (final InvalidJidException ignored) {
} }
mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount); mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount);
xmppConnectionService.updateAccount(mAccount); xmppConnectionService.updateAccount(mAccount);
} else { } else {
try { try {
if (xmppConnectionService.findAccountByJid(Jid.fromString(mAccountJid.getText().toString())) != null) { if (xmppConnectionService.findAccountByJid(Jid.fromString(mAccountJid.getText().toString())) != null) {
mAccountJid mAccountJid
.setError(getString(R.string.account_already_exists)); .setError(getString(R.string.account_already_exists));
mAccountJid.requestFocus(); mAccountJid.requestFocus();
return; return;
} }
} catch (InvalidJidException e) { } catch (InvalidJidException e) {
return; return;
} }
mAccount = new Account(jid.toBareJid(), password); mAccount = new Account(jid.toBareJid(), password);
mAccount.setOption(Account.OPTION_USETLS, true); mAccount.setOption(Account.OPTION_USETLS, true);
mAccount.setOption(Account.OPTION_USECOMPRESSION, true); mAccount.setOption(Account.OPTION_USECOMPRESSION, true);
mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount); mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount);
@ -134,34 +134,34 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
finish(); finish();
} }
}; };
@Override @Override
public void onAccountUpdate() { public void onAccountUpdate() {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
if (mAccount != null if (mAccount != null
&& mAccount.getStatus() != Account.State.ONLINE && mAccount.getStatus() != Account.State.ONLINE
&& mFetchingAvatar) { && mFetchingAvatar) {
startActivity(new Intent(getApplicationContext(), startActivity(new Intent(getApplicationContext(),
ManageAccountActivity.class)); ManageAccountActivity.class));
finish(); finish();
} else if (jidToEdit == null && mAccount != null } else if (jidToEdit == null && mAccount != null
&& mAccount.getStatus() == Account.State.ONLINE) { && mAccount.getStatus() == Account.State.ONLINE) {
if (!mFetchingAvatar) { if (!mFetchingAvatar) {
mFetchingAvatar = true; mFetchingAvatar = true;
xmppConnectionService.checkForAvatar(mAccount, xmppConnectionService.checkForAvatar(mAccount,
mAvatarFetchCallback); mAvatarFetchCallback);
}
} else {
updateSaveButton();
}
if (mAccount != null) {
updateAccountInformation();
} }
} else {
updateSaveButton();
} }
}); if (mAccount != null) {
} updateAccountInformation();
}
}
});
}
private UiCallback<Avatar> mAvatarFetchCallback = new UiCallback<Avatar>() { private UiCallback<Avatar> mAvatarFetchCallback = new UiCallback<Avatar>() {
@Override @Override
@ -179,17 +179,17 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
finishInitialSetup(avatar); finishInitialSetup(avatar);
} }
}; };
private TextWatcher mTextWatcher = new TextWatcher() { private TextWatcher mTextWatcher = new TextWatcher() {
@Override @Override
public void onTextChanged(CharSequence s, int start, int before, public void onTextChanged(CharSequence s, int start, int before,
int count) { int count) {
updateSaveButton(); updateSaveButton();
} }
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, 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() { protected boolean accountInfoEdited() {
return (!this.mAccount.getJid().toBareJid().equals( return (!this.mAccount.getJid().toBareJid().equals(
this.mAccountJid.getText().toString())) this.mAccountJid.getText().toString()))
|| (!this.mAccount.getPassword().equals( || (!this.mAccount.getPassword().equals(
this.mPassword.getText().toString())); this.mPassword.getText().toString()));
} }
@Override @Override
@ -303,28 +303,32 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
this.mSaveButton.setOnClickListener(this.mSaveButtonClickListener); this.mSaveButton.setOnClickListener(this.mSaveButtonClickListener);
this.mCancelButton.setOnClickListener(this.mCancelButtonClickListener); this.mCancelButton.setOnClickListener(this.mCancelButtonClickListener);
this.mRegisterNew this.mRegisterNew
.setOnCheckedChangeListener(new OnCheckedChangeListener() { .setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton buttonView, public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) { boolean isChecked) {
if (isChecked) { if (isChecked) {
mPasswordConfirm.setVisibility(View.VISIBLE); mPasswordConfirm.setVisibility(View.VISIBLE);
} else { } else {
mPasswordConfirm.setVisibility(View.GONE); mPasswordConfirm.setVisibility(View.GONE);
}
updateSaveButton();
} }
}); updateSaveButton();
}
});
} }
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(final Menu menu) {
super.onCreateOptionsMenu(menu); super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.editaccount, 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) { if (mAccount == null) {
showQrCode.setVisible(false); showQrCode.setVisible(false);
showBlocklist.setVisible(false);
} else if (!mAccount.getXmppConnection().getFeatures().blocking()) {
showBlocklist.setVisible(false);
} }
return true; return true;
} }
@ -333,32 +337,38 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
protected void onStart() { protected void onStart() {
super.onStart(); super.onStart();
if (getIntent() != null) { if (getIntent() != null) {
try { try {
this.jidToEdit = Jid.fromString(getIntent().getStringExtra("jid")); this.jidToEdit = Jid.fromString(getIntent().getStringExtra("jid"));
} catch (final InvalidJidException | NullPointerException ignored) { } catch (final InvalidJidException | NullPointerException ignored) {
this.jidToEdit = null; this.jidToEdit = null;
} }
if (this.jidToEdit != null) { if (this.jidToEdit != null) {
this.mRegisterNew.setVisibility(View.GONE); this.mRegisterNew.setVisibility(View.GONE);
getActionBar().setTitle(getString(R.string.account_details)); if (getActionBar() != null) {
getActionBar().setTitle(getString(R.string.account_details));
}
} else { } else {
this.mAvatar.setVisibility(View.GONE); this.mAvatar.setVisibility(View.GONE);
getActionBar().setTitle(R.string.action_add_account); if (getActionBar() != null) {
getActionBar().setTitle(R.string.action_add_account);
}
} }
} }
} }
@Override @Override
protected void onBackendConnected() { protected void onBackendConnected() {
KnownHostsAdapter mKnownHostsAdapter = new KnownHostsAdapter(this, final KnownHostsAdapter mKnownHostsAdapter = new KnownHostsAdapter(this,
android.R.layout.simple_list_item_1, android.R.layout.simple_list_item_1,
xmppConnectionService.getKnownHosts()); xmppConnectionService.getKnownHosts());
if (this.jidToEdit != null) { if (this.jidToEdit != null) {
this.mAccount = xmppConnectionService.findAccountByJid(jidToEdit); this.mAccount = xmppConnectionService.findAccountByJid(jidToEdit);
updateAccountInformation(); updateAccountInformation();
} else if (this.xmppConnectionService.getAccounts().size() == 0) { } else if (this.xmppConnectionService.getAccounts().size() == 0) {
getActionBar().setDisplayHomeAsUpEnabled(false); if (getActionBar() != null) {
getActionBar().setDisplayShowHomeEnabled(false); getActionBar().setDisplayHomeAsUpEnabled(false);
getActionBar().setDisplayShowHomeEnabled(false);
}
this.mCancelButton.setEnabled(false); this.mCancelButton.setEnabled(false);
this.mCancelButton.setTextColor(getSecondaryTextColor()); this.mCancelButton.setTextColor(getSecondaryTextColor());
} }
@ -366,6 +376,18 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
updateSaveButton(); 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() { private void updateAccountInformation() {
this.mAccountJid.setText(this.mAccount.getJid().toBareJid().toString()); this.mAccountJid.setText(this.mAccount.getJid().toBareJid().toString());
this.mPassword.setText(this.mAccount.getPassword()); this.mPassword.setText(this.mAccount.getPassword());
@ -385,14 +407,14 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
&& !this.mFetchingAvatar) { && !this.mFetchingAvatar) {
this.mStats.setVisibility(View.VISIBLE); this.mStats.setVisibility(View.VISIBLE);
this.mSessionEst.setText(UIHelper.readableTimeDifferenceFull( this.mSessionEst.setText(UIHelper.readableTimeDifferenceFull(
getApplicationContext(), this.mAccount.getXmppConnection() getApplicationContext(), this.mAccount.getXmppConnection()
.getLastSessionEstablished())); .getLastSessionEstablished()));
Features features = this.mAccount.getXmppConnection().getFeatures(); final Features features = this.mAccount.getXmppConnection().getFeatures();
if (features.carbons()) { if (features.carbons()) {
this.mServerInfoCarbons.setText(R.string.server_info_available); this.mServerInfoCarbons.setText(R.string.server_info_available);
} else { } else {
this.mServerInfoCarbons this.mServerInfoCarbons
.setText(R.string.server_info_unavailable); .setText(R.string.server_info_unavailable);
} }
if (features.sm()) { if (features.sm()) {
this.mServerInfoSm.setText(R.string.server_info_available); 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.mOtrFingerprintBox.setVisibility(View.VISIBLE);
this.mOtrFingerprint.setText(CryptoHelper.prettifyFingerprint(fingerprint)); this.mOtrFingerprint.setText(CryptoHelper.prettifyFingerprint(fingerprint));
this.mOtrFingerprintToClipboardButton this.mOtrFingerprintToClipboardButton
.setVisibility(View.VISIBLE); .setVisibility(View.VISIBLE);
this.mOtrFingerprintToClipboardButton this.mOtrFingerprintToClipboardButton
.setOnClickListener(new View.OnClickListener() { .setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (copyTextToClipboard(fingerprint, R.string.otr_fingerprint)) { if (copyTextToClipboard(fingerprint, R.string.otr_fingerprint)) {
Toast.makeText( Toast.makeText(
EditAccountActivity.this, EditAccountActivity.this,
R.string.toast_message_otr_fingerprint, R.string.toast_message_otr_fingerprint,
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
}
} }
}); }
});
} else { } else {
this.mOtrFingerprintBox.setVisibility(View.GONE); this.mOtrFingerprintBox.setVisibility(View.GONE);
} }

View File

@ -117,10 +117,10 @@ public class ShareWithActivity extends XmppActivity {
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_add: case R.id.action_add:
Intent intent = new Intent(getApplicationContext(), final Intent intent = new Intent(getApplicationContext(),
ChooseContactActivity.class); ChooseContactActivity.class);
startActivityForResult(intent, REQUEST_START_NEW_CONVERSATION); startActivityForResult(intent, REQUEST_START_NEW_CONVERSATION);
return true; return true;

View File

@ -53,19 +53,21 @@ import java.util.List;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
import eu.siacs.conversations.R; import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Blockable;
import eu.siacs.conversations.entities.Bookmark; import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.ListItem; import eu.siacs.conversations.entities.ListItem;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
import eu.siacs.conversations.ui.adapter.KnownHostsAdapter; import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
import eu.siacs.conversations.ui.adapter.ListItemAdapter; import eu.siacs.conversations.ui.adapter.ListItemAdapter;
import eu.siacs.conversations.utils.Validator; 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.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid; 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 conference_context_id;
public int contact_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() { private ViewPager.SimpleOnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
@Override @Override
public void onPageSelected(int position) { public void onPageSelected(int position) {
getActionBar().setSelectedNavigationItem(position); if (getActionBar() != null) {
getActionBar().setSelectedNavigationItem(position);
}
onTabChanged(); onTabChanged();
} }
}; };
@ -146,12 +150,12 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, public void beforeTextChanged(CharSequence s, int start, int count,
int after) { int after) {
} }
@Override @Override
public void onTextChanged(CharSequence s, int start, int before, public void onTextChanged(CharSequence s, int start, int before,
int count) { int count) {
} }
}; };
private MenuItem mMenuSearchView; private MenuItem mMenuSearchView;
@ -179,9 +183,9 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
mContactsTab = actionBar.newTab().setText(R.string.contacts) mContactsTab = actionBar.newTab().setText(R.string.contacts)
.setTabListener(mTabListener); .setTabListener(mTabListener);
mConferencesTab = actionBar.newTab().setText(R.string.conferences) mConferencesTab = actionBar.newTab().setText(R.string.conferences)
.setTabListener(mTabListener); .setTabListener(mTabListener);
actionBar.addTab(mContactsTab); actionBar.addTab(mContactsTab);
actionBar.addTab(mConferencesTab); actionBar.addTab(mConferencesTab);
@ -207,35 +211,35 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
mConferenceListFragment.setListAdapter(mConferenceAdapter); mConferenceListFragment.setListAdapter(mConferenceAdapter);
mConferenceListFragment.setContextMenu(R.menu.conference_context); mConferenceListFragment.setContextMenu(R.menu.conference_context);
mConferenceListFragment mConferenceListFragment
.setOnListItemClickListener(new OnItemClickListener() { .setOnListItemClickListener(new OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> arg0, View arg1, public void onItemClick(AdapterView<?> arg0, View arg1,
int position, long arg3) { int position, long arg3) {
openConversationForBookmark(position); openConversationForBookmark(position);
} }
}); });
mContactsAdapter = new ListItemAdapter(this, contacts); mContactsAdapter = new ListItemAdapter(this, contacts);
mContactsListFragment.setListAdapter(mContactsAdapter); mContactsListFragment.setListAdapter(mContactsAdapter);
mContactsListFragment.setContextMenu(R.menu.contact_context); mContactsListFragment.setContextMenu(R.menu.contact_context);
mContactsListFragment mContactsListFragment
.setOnListItemClickListener(new OnItemClickListener() { .setOnListItemClickListener(new OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> arg0, View arg1, public void onItemClick(AdapterView<?> arg0, View arg1,
int position, long arg3) { int position, long arg3) {
openConversationForContact(position); openConversationForContact(position);
} }
}); });
} }
protected void openConversationForContact(int position) { protected void openConversationForContact(int position) {
Contact contact = (Contact) contacts.get(position); Contact contact = (Contact) contacts.get(position);
Conversation conversation = xmppConnectionService Conversation conversation = xmppConnectionService
.findOrCreateConversation(contact.getAccount(), .findOrCreateConversation(contact.getAccount(),
contact.getJid(), false); contact.getJid(), false);
switchToConversation(conversation); switchToConversation(conversation);
} }
@ -251,8 +255,8 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
protected void openConversationForBookmark(int position) { protected void openConversationForBookmark(int position) {
Bookmark bookmark = (Bookmark) conferences.get(position); Bookmark bookmark = (Bookmark) conferences.get(position);
Conversation conversation = xmppConnectionService Conversation conversation = xmppConnectionService
.findOrCreateConversation(bookmark.getAccount(), .findOrCreateConversation(bookmark.getAccount(),
bookmark.getJid(), true); bookmark.getJid(), true);
conversation.setBookmark(bookmark); conversation.setBookmark(bookmark);
if (!conversation.getMucOptions().online()) { if (!conversation.getMucOptions().online()) {
xmppConnectionService.joinMuc(conversation); xmppConnectionService.joinMuc(conversation);
@ -270,14 +274,19 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
switchToContactDetails(contact); switchToContactDetails(contact);
} }
protected void toggleContactBlock() {
final int position = contact_context_id;
BlockContactDialog.show(this, xmppConnectionService, (Contact)contacts.get(position));
}
protected void deleteContact() { protected void deleteContact() {
int position = contact_context_id; final int position = contact_context_id;
final Contact contact = (Contact) contacts.get(position); 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.setNegativeButton(R.string.cancel, null);
builder.setTitle(R.string.action_delete_contact); builder.setTitle(R.string.action_delete_contact);
builder.setMessage(getString(R.string.remove_contact_text, builder.setMessage(getString(R.string.remove_contact_text,
contact.getJid())); contact.getJid()));
builder.setPositiveButton(R.string.delete, new OnClickListener() { builder.setPositiveButton(R.string.delete, new OnClickListener() {
@Override @Override
@ -287,7 +296,6 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
} }
}); });
builder.create().show(); builder.create().show();
} }
protected void deleteConference() { protected void deleteConference() {
@ -298,7 +306,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
builder.setNegativeButton(R.string.cancel, null); builder.setNegativeButton(R.string.cancel, null);
builder.setTitle(R.string.delete_bookmark); builder.setTitle(R.string.delete_bookmark);
builder.setMessage(getString(R.string.remove_bookmark_text, builder.setMessage(getString(R.string.remove_bookmark_text,
bookmark.getJid())); bookmark.getJid()));
builder.setPositiveButton(R.string.delete, new OnClickListener() { builder.setPositiveButton(R.string.delete, new OnClickListener() {
@Override @Override
@ -360,7 +368,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
return; return;
} }
Account account = xmppConnectionService Account account = xmppConnectionService
.findAccountByJid(accountJid); .findAccountByJid(accountJid);
if (account == null) { if (account == null) {
dialog.dismiss(); dialog.dismiss();
return; return;
@ -395,7 +403,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
} }
populateAccountSpinner(spinner); populateAccountSpinner(spinner);
final CheckBox bookmarkCheckBox = (CheckBox) dialogView final CheckBox bookmarkCheckBox = (CheckBox) dialogView
.findViewById(R.id.bookmark); .findViewById(R.id.bookmark);
builder.setView(dialogView); builder.setView(dialogView);
builder.setNegativeButton(R.string.cancel, null); builder.setNegativeButton(R.string.cancel, null);
builder.setPositiveButton(R.string.join, null); builder.setPositiveButton(R.string.join, null);
@ -424,7 +432,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
return; return;
} }
Account account = xmppConnectionService Account account = xmppConnectionService
.findAccountByJid(accountJid); .findAccountByJid(accountJid);
if (account == null) { if (account == null) {
dialog.dismiss(); dialog.dismiss();
return; return;
@ -438,22 +446,22 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
bookmark.setAutojoin(true); bookmark.setAutojoin(true);
account.getBookmarks().add(bookmark); account.getBookmarks().add(bookmark);
xmppConnectionService xmppConnectionService
.pushBookmarks(account); .pushBookmarks(account);
Conversation conversation = xmppConnectionService Conversation conversation = xmppConnectionService
.findOrCreateConversation(account, .findOrCreateConversation(account,
conferenceJid, true); conferenceJid, true);
conversation.setBookmark(bookmark); conversation.setBookmark(bookmark);
if (!conversation.getMucOptions().online()) { if (!conversation.getMucOptions().online()) {
xmppConnectionService xmppConnectionService
.joinMuc(conversation); .joinMuc(conversation);
} }
dialog.dismiss(); dialog.dismiss();
switchToConversation(conversation); switchToConversation(conversation);
} }
} else { } else {
Conversation conversation = xmppConnectionService Conversation conversation = xmppConnectionService
.findOrCreateConversation(account, .findOrCreateConversation(account,
conferenceJid, true); conferenceJid, true);
if (!conversation.getMucOptions().online()) { if (!conversation.getMucOptions().online()) {
xmppConnectionService.joinMuc(conversation); xmppConnectionService.joinMuc(conversation);
} }
@ -469,8 +477,8 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
protected void switchToConversation(Contact contact) { protected void switchToConversation(Contact contact) {
Conversation conversation = xmppConnectionService Conversation conversation = xmppConnectionService
.findOrCreateConversation(contact.getAccount(), .findOrCreateConversation(contact.getAccount(),
contact.getJid(), false); contact.getJid(), false);
switchToConversation(conversation); switchToConversation(conversation);
} }
@ -486,14 +494,14 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
this.mOptionsMenu = menu; this.mOptionsMenu = menu;
getMenuInflater().inflate(R.menu.start_conversation, menu); getMenuInflater().inflate(R.menu.start_conversation, menu);
MenuItem menuCreateContact = menu MenuItem menuCreateContact = menu
.findItem(R.id.action_create_contact); .findItem(R.id.action_create_contact);
MenuItem menuCreateConference = menu MenuItem menuCreateConference = menu
.findItem(R.id.action_join_conference); .findItem(R.id.action_join_conference);
mMenuSearchView = menu.findItem(R.id.action_search); mMenuSearchView = menu.findItem(R.id.action_search);
mMenuSearchView.setOnActionExpandListener(mOnActionExpandListener); mMenuSearchView.setOnActionExpandListener(mOnActionExpandListener);
View mSearchView = mMenuSearchView.getActionView(); View mSearchView = mMenuSearchView.getActionView();
mSearchEditText = (EditText) mSearchView mSearchEditText = (EditText) mSearchView
.findViewById(R.id.search_field); .findViewById(R.id.search_field);
mSearchEditText.addTextChangedListener(mSearchTextWatcher); mSearchEditText.addTextChangedListener(mSearchTextWatcher);
if (getActionBar().getSelectedNavigationIndex() == 0) { if (getActionBar().getSelectedNavigationIndex() == 0) {
menuCreateConference.setVisible(false); menuCreateConference.setVisible(false);
@ -562,7 +570,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
} }
this.mKnownHosts = xmppConnectionService.getKnownHosts(); this.mKnownHosts = xmppConnectionService.getKnownHosts();
this.mKnownConferenceHosts = xmppConnectionService this.mKnownConferenceHosts = xmppConnectionService
.getKnownConferenceHosts(); .getKnownConferenceHosts();
if (this.mPendingInvite != null) { if (this.mPendingInvite != null) {
mPendingInvite.invite(); mPendingInvite.invite();
this.mPendingInvite = null; this.mPendingInvite = null;
@ -604,7 +612,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
byte[] payload = record.getPayload(); byte[] payload = record.getPayload();
if (payload[0] == 0) { if (payload[0] == 0) {
return new Invite(Uri.parse(new String(Arrays.copyOfRange( 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(); 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 { public static class MyListFragment extends ListFragment {
private AdapterView.OnItemClickListener mOnItemClickListener; private AdapterView.OnItemClickListener mOnItemClickListener;
private int mResContextMenu; private int mResContextMenu;
public void setContextMenu(int res) { public void setContextMenu(final int res) {
this.mResContextMenu = res; this.mResContextMenu = res;
} }
@Override @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) { if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(l, v, position, id); mOnItemClickListener.onItemClick(l, v, position, id);
} }
@ -705,28 +726,38 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
} }
@Override @Override
public void onViewCreated(View view, Bundle savedInstanceState) { public void onViewCreated(final View view, final Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
registerForContextMenu(getListView()); registerForContextMenu(getListView());
getListView().setFastScrollEnabled(true); getListView().setFastScrollEnabled(true);
} }
@Override @Override
public void onCreateContextMenu(ContextMenu menu, View v, public void onCreateContextMenu(final ContextMenu menu, final View v,
ContextMenuInfo menuInfo) { final ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo); super.onCreateContextMenu(menu, v, menuInfo);
StartConversationActivity activity = (StartConversationActivity) getActivity(); final StartConversationActivity activity = (StartConversationActivity) getActivity();
activity.getMenuInflater().inflate(mResContextMenu, menu); activity.getMenuInflater().inflate(mResContextMenu, menu);
AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo; final AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
if (mResContextMenu == R.menu.conference_context) { if (mResContextMenu == R.menu.conference_context) {
activity.conference_context_id = acmi.position; activity.conference_context_id = acmi.position;
} else { } else {
activity.contact_context_id = acmi.position; 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 @Override
public boolean onContextItemSelected(MenuItem item) { public boolean onContextItemSelected(final MenuItem item) {
StartConversationActivity activity = (StartConversationActivity) getActivity(); StartConversationActivity activity = (StartConversationActivity) getActivity();
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.context_start_conversation: case R.id.context_start_conversation:
@ -735,6 +766,9 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
case R.id.context_contact_details: case R.id.context_contact_details:
activity.openDetailsForContact(); activity.openDetailsForContact();
break; break;
case R.id.context_contact_block_unblock:
activity.toggleContactBlock();
break;
case R.id.context_delete_contact: case R.id.context_delete_contact:
activity.deleteContact(); activity.deleteContact();
break; break;
@ -750,11 +784,11 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
private class Invite extends XmppUri { private class Invite extends XmppUri {
public Invite(Uri uri) { public Invite(final Uri uri) {
super(uri); super(uri);
} }
public Invite(String uri) { public Invite(final String uri) {
super(uri); super(uri);
} }

View File

@ -71,6 +71,7 @@ import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder; import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder;
import eu.siacs.conversations.utils.ExceptionHelper; 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.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.jid.Jid;
@ -199,7 +200,7 @@ public abstract class XmppActivity extends Activity {
xmppConnectionServiceBound = false; xmppConnectionServiceBound = false;
} }
stopService(new Intent(XmppActivity.this, stopService(new Intent(XmppActivity.this,
XmppConnectionService.class)); XmppConnectionService.class));
finish(); finish();
} }
}); });
@ -209,13 +210,13 @@ public abstract class XmppActivity extends Activity {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
Uri uri = Uri Uri uri = Uri
.parse("market://details?id=org.sufficientlysecure.keychain"); .parse("market://details?id=org.sufficientlysecure.keychain");
Intent marketIntent = new Intent(Intent.ACTION_VIEW, Intent marketIntent = new Intent(Intent.ACTION_VIEW,
uri); uri);
PackageManager manager = getApplicationContext() PackageManager manager = getApplicationContext()
.getPackageManager(); .getPackageManager();
List<ResolveInfo> infos = manager List<ResolveInfo> infos = manager
.queryIntentActivities(marketIntent, 0); .queryIntentActivities(marketIntent, 0);
if (infos.size() > 0) { if (infos.size() > 0) {
startActivity(marketIntent); startActivity(marketIntent);
} else { } else {
@ -245,6 +246,9 @@ public abstract class XmppActivity extends Activity {
if (this instanceof XmppConnectionService.OnMucRosterUpdate) { if (this instanceof XmppConnectionService.OnMucRosterUpdate) {
this.xmppConnectionService.setOnMucRosterUpdateListener((XmppConnectionService.OnMucRosterUpdate) this); this.xmppConnectionService.setOnMucRosterUpdateListener((XmppConnectionService.OnMucRosterUpdate) this);
} }
if (this instanceof OnUpdateBlocklist) {
this.xmppConnectionService.setOnUpdateBlocklistListener((OnUpdateBlocklist) this);
}
} }
protected void unregisterListeners() { protected void unregisterListeners() {
@ -260,9 +264,13 @@ public abstract class XmppActivity extends Activity {
if (this instanceof XmppConnectionService.OnMucRosterUpdate) { if (this instanceof XmppConnectionService.OnMucRosterUpdate) {
this.xmppConnectionService.removeOnMucRosterUpdateListener(); 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()) { switch (item.getItemId()) {
case R.id.action_settings: case R.id.action_settings:
startActivity(new Intent(this, SettingsActivity.class)); startActivity(new Intent(this, SettingsActivity.class));
@ -300,7 +308,7 @@ public abstract class XmppActivity extends Activity {
protected SharedPreferences getPreferences() { protected SharedPreferences getPreferences() {
return PreferenceManager return PreferenceManager
.getDefaultSharedPreferences(getApplicationContext()); .getDefaultSharedPreferences(getApplicationContext());
} }
public boolean useSubjectToIdentifyConference() { public boolean useSubjectToIdentifyConference() {
@ -312,7 +320,7 @@ public abstract class XmppActivity extends Activity {
} }
public void switchToConversation(Conversation conversation, String text, public void switchToConversation(Conversation conversation, String text,
boolean newTask) { boolean newTask) {
switchToConversation(conversation,text,null,newTask); switchToConversation(conversation,text,null,newTask);
} }
@ -372,7 +380,7 @@ public abstract class XmppActivity extends Activity {
@Override @Override
public void userInputRequried(PendingIntent pi, public void userInputRequried(PendingIntent pi,
Account account) { Account account) {
try { try {
startIntentSenderForResult(pi.getIntentSender(), startIntentSenderForResult(pi.getIntentSender(),
REQUEST_ANNOUNCE_PGP, null, 0, 0, 0); REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
@ -383,15 +391,15 @@ public abstract class XmppActivity extends Activity {
@Override @Override
public void success(Account account) { public void success(Account account) {
xmppConnectionService.databaseBackend xmppConnectionService.databaseBackend
.updateAccount(account); .updateAccount(account);
xmppConnectionService.sendPresencePacket(account, xmppConnectionService.sendPresencePacket(account,
xmppConnectionService.getPresenceGenerator() xmppConnectionService.getPresenceGenerator()
.sendPresence(account)); .sendPresence(account));
if (conversation != null) { if (conversation != null) {
conversation conversation
.setNextEncryption(Message.ENCRYPTION_PGP); .setNextEncryption(Message.ENCRYPTION_PGP);
xmppConnectionService.databaseBackend xmppConnectionService.databaseBackend
.updateConversation(conversation); .updateConversation(conversation);
} }
} }
@ -420,7 +428,7 @@ public abstract class XmppActivity extends Activity {
} }
protected void showAddToRosterDialog(final Conversation conversation) { protected void showAddToRosterDialog(final Conversation conversation) {
final Jid jid = conversation.getContactJid(); final Jid jid = conversation.getJid();
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(jid.toString()); builder.setTitle(jid.toString());
builder.setMessage(getString(R.string.not_in_roster)); builder.setMessage(getString(R.string.not_in_roster));
@ -430,7 +438,7 @@ public abstract class XmppActivity extends Activity {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
final Jid jid = conversation.getContactJid(); final Jid jid = conversation.getJid();
Account account = conversation.getAccount(); Account account = conversation.getAccount();
Contact contact = account.getRoster().getContact(jid); Contact contact = account.getRoster().getContact(jid);
xmppConnectionService.createContact(contact); xmppConnectionService.createContact(contact);
@ -462,7 +470,7 @@ public abstract class XmppActivity extends Activity {
} }
private void warnMutalPresenceSubscription(final Conversation conversation, private void warnMutalPresenceSubscription(final Conversation conversation,
final OnPresenceSelected listener) { final OnPresenceSelected listener) {
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(conversation.getContact().getJid().toString()); builder.setTitle(conversation.getContact().getJid().toString());
builder.setMessage(R.string.without_mutual_presence_updates); builder.setMessage(R.string.without_mutual_presence_updates);
@ -485,13 +493,13 @@ public abstract class XmppActivity extends Activity {
} }
protected void quickPasswordEdit(String previousValue, protected void quickPasswordEdit(String previousValue,
OnValueEdited callback) { OnValueEdited callback) {
quickEdit(previousValue, callback, true); quickEdit(previousValue, callback, true);
} }
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
private void quickEdit(final String previousValue, private void quickEdit(final String previousValue,
final OnValueEdited callback, boolean password) { final OnValueEdited callback, boolean password) {
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);
View view = getLayoutInflater().inflate(R.layout.quickedit, null); View view = getLayoutInflater().inflate(R.layout.quickedit, null);
final EditText editor = (EditText) view.findViewById(R.id.editor); 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, public void selectPresence(final Conversation conversation,
final OnPresenceSelected listener) { final OnPresenceSelected listener) {
final Contact contact = conversation.getContact(); final Contact contact = conversation.getContact();
if (conversation.hasValidOtrSession()) { if (conversation.hasValidOtrSession()) {
SessionID id = conversation.getOtrSession().getSessionID(); SessionID id = conversation.getOtrSession().getSessionID();
@ -576,7 +584,7 @@ public abstract class XmppActivity extends Activity {
@Override @Override
public void onClick(DialogInterface dialog, public void onClick(DialogInterface dialog,
int which) { int which) {
presence.delete(0, presence.length()); presence.delete(0, presence.length());
presence.append(presencesArray[which]); presence.append(presencesArray[which]);
} }
@ -600,7 +608,7 @@ public abstract class XmppActivity extends Activity {
} }
protected void onActivityResult(int requestCode, int resultCode, protected void onActivityResult(int requestCode, int resultCode,
final Intent data) { final Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_INVITE_TO_CONVERSATION if (requestCode == REQUEST_INVITE_TO_CONVERSATION
&& resultCode == RESULT_OK) { && resultCode == RESULT_OK) {
@ -608,19 +616,19 @@ public abstract class XmppActivity extends Activity {
Jid jid = Jid.fromString(data.getStringExtra("contact")); Jid jid = Jid.fromString(data.getStringExtra("contact"));
String conversationUuid = data.getStringExtra("conversation"); String conversationUuid = data.getStringExtra("conversation");
Conversation conversation = xmppConnectionService Conversation conversation = xmppConnectionService
.findConversationByUuid(conversationUuid); .findConversationByUuid(conversationUuid);
if (conversation.getMode() == Conversation.MODE_MULTI) { if (conversation.getMode() == Conversation.MODE_MULTI) {
xmppConnectionService.invite(conversation, jid); xmppConnectionService.invite(conversation, jid);
} else { } else {
List<Jid> jids = new ArrayList<Jid>(); List<Jid> jids = new ArrayList<Jid>();
jids.add(conversation.getContactJid().toBareJid()); jids.add(conversation.getJid().toBareJid());
jids.add(jid); jids.add(jid);
xmppConnectionService.createAdhocConference(conversation.getAccount(), jids, adhocCallback); xmppConnectionService.createAdhocConference(conversation.getAccount(), jids, adhocCallback);
} }
} catch (final InvalidJidException ignored) { } catch (final InvalidJidException ignored) {
} }
} }
} }
private UiCallback<Conversation> adhocCallback = new UiCallback<Conversation>() { private UiCallback<Conversation> adhocCallback = new UiCallback<Conversation>() {
@ -688,18 +696,18 @@ public abstract class XmppActivity extends Activity {
} }
protected void registerNdefPushMessageCallback() { protected void registerNdefPushMessageCallback() {
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (nfcAdapter != null && nfcAdapter.isEnabled()) { if (nfcAdapter != null && nfcAdapter.isEnabled()) {
nfcAdapter.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() { nfcAdapter.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() {
@Override @Override
public NdefMessage createNdefMessage(NfcEvent nfcEvent) { public NdefMessage createNdefMessage(NfcEvent nfcEvent) {
return new NdefMessage(new NdefRecord[]{ return new NdefMessage(new NdefRecord[]{
NdefRecord.createUri(getShareableUri()), NdefRecord.createUri(getShareableUri()),
NdefRecord.createApplicationRecord("eu.siacs.conversations") NdefRecord.createApplicationRecord("eu.siacs.conversations")
}); });
} }
}, this); }, this);
} }
} }
protected void unregisterNdefPushMessageCallback() { protected void unregisterNdefPushMessageCallback() {
@ -831,13 +839,13 @@ public abstract class XmppActivity extends Activity {
try { try {
task.execute(message); task.execute(message);
} catch (final RejectedExecutionException ignored) { } catch (final RejectedExecutionException ignored) {
} }
} }
} }
} }
public static boolean cancelPotentialWork(Message message, public static boolean cancelPotentialWork(Message message,
ImageView imageView) { ImageView imageView) {
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if (bitmapWorkerTask != null) { if (bitmapWorkerTask != null) {
@ -866,7 +874,7 @@ public abstract class XmppActivity extends Activity {
private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
public AsyncDrawable(Resources res, Bitmap bitmap, public AsyncDrawable(Resources res, Bitmap bitmap,
BitmapWorkerTask bitmapWorkerTask) { BitmapWorkerTask bitmapWorkerTask) {
super(res, bitmap); super(res, bitmap);
bitmapWorkerTaskReference = new WeakReference<>( bitmapWorkerTaskReference = new WeakReference<>(
bitmapWorkerTask); bitmapWorkerTask);

View File

@ -34,7 +34,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
public View getView(int position, View view, ViewGroup parent) { public View getView(int position, View view, ViewGroup parent) {
if (view == null) { if (view == null) {
LayoutInflater inflater = (LayoutInflater) activity LayoutInflater inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE); .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.conversation_list_row, view = inflater.inflate(R.layout.conversation_list_row,
parent, false); parent, false);
} }
@ -53,19 +53,19 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
} }
} }
TextView convName = (TextView) view TextView convName = (TextView) view
.findViewById(R.id.conversation_name); .findViewById(R.id.conversation_name);
if (conversation.getMode() == Conversation.MODE_SINGLE if (conversation.getMode() == Conversation.MODE_SINGLE
|| activity.useSubjectToIdentifyConference()) { || activity.useSubjectToIdentifyConference()) {
convName.setText(conversation.getName()); convName.setText(conversation.getName());
} else { } else {
convName.setText(conversation.getContactJid().toBareJid().toString()); convName.setText(conversation.getJid().toBareJid().toString());
} }
TextView mLastMessage = (TextView) view TextView mLastMessage = (TextView) view
.findViewById(R.id.conversation_lastmsg); .findViewById(R.id.conversation_lastmsg);
TextView mTimestamp = (TextView) view TextView mTimestamp = (TextView) view
.findViewById(R.id.conversation_lastupdate); .findViewById(R.id.conversation_lastupdate);
ImageView imagePreview = (ImageView) view ImageView imagePreview = (ImageView) view
.findViewById(R.id.conversation_lastimage); .findViewById(R.id.conversation_lastimage);
Message message = conversation.getLatestMessage(); Message message = conversation.getLatestMessage();
@ -151,12 +151,12 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
imagePreview.setVisibility(View.GONE); imagePreview.setVisibility(View.GONE);
} }
mTimestamp.setText(UIHelper.readableTimeDifference(getContext(), mTimestamp.setText(UIHelper.readableTimeDifference(getContext(),
conversation.getLatestMessage().getTimeSent())); conversation.getLatestMessage().getTimeSent()));
ImageView profilePicture = (ImageView) view ImageView profilePicture = (ImageView) view
.findViewById(R.id.conversation_image); .findViewById(R.id.conversation_image);
profilePicture.setImageBitmap(activity.avatarService().get( profilePicture.setImageBitmap(activity.avatarService().get(
conversation, activity.getPixel(56))); conversation, activity.getPixel(56)));
return view; return view;
} }

View File

@ -0,0 +1,5 @@
package eu.siacs.conversations.utils;
public final class Xmlns {
public static final String BLOCKING = "urn:xmpp:blocking";
}

View File

@ -5,7 +5,6 @@ import android.net.Uri;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder; import java.net.URLDecoder;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.jid.Jid;

View File

@ -62,16 +62,16 @@ public class Element {
if (child.getName().equals(name) if (child.getName().equals(name)
&& (child.getAttribute("xmlns").equals(xmlns))) { && (child.getAttribute("xmlns").equals(xmlns))) {
return child; return child;
} }
} }
return null; return null;
} }
public boolean hasChild(String name) { public boolean hasChild(final String name) {
return findChild(name) != null; 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; return findChild(name, xmlns) != null;
} }
@ -110,15 +110,15 @@ public class Element {
public Jid getAttributeAsJid(String name) { public Jid getAttributeAsJid(String name) {
final String jid = this.getAttribute(name); final String jid = this.getAttribute(name);
if (jid != null && !jid.isEmpty()) { if (jid != null && !jid.isEmpty()) {
try { try {
return Jid.fromString(jid); return Jid.fromString(jid);
} catch (final InvalidJidException e) { } catch (final InvalidJidException e) {
Log.e(Config.LOGTAG, "could not parse jid " + jid); Log.e(Config.LOGTAG, "could not parse jid " + jid);
return null; return null;
} }
} }
return null; return null;
} }
public Hashtable<String, String> getAttributes() { public Hashtable<String, String> getAttributes() {

View File

@ -3,5 +3,5 @@ package eu.siacs.conversations.xmpp;
import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Contact;
public interface OnContactStatusChanged { public interface OnContactStatusChanged {
public void onContactStatusChanged(Contact contact, boolean online); public void onContactStatusChanged(final Contact contact, final boolean online);
} }

View File

@ -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);
}

View File

@ -30,10 +30,12 @@ import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HostnameVerifier;
@ -48,8 +50,10 @@ import eu.siacs.conversations.crypto.sasl.Plain;
import eu.siacs.conversations.crypto.sasl.SaslMechanism; import eu.siacs.conversations.crypto.sasl.SaslMechanism;
import eu.siacs.conversations.crypto.sasl.ScramSha1; import eu.siacs.conversations.crypto.sasl.ScramSha1;
import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.generator.IqGenerator;
import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.DNSHelper; import eu.siacs.conversations.utils.DNSHelper;
import eu.siacs.conversations.utils.Xmlns;
import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Tag; import eu.siacs.conversations.xml.Tag;
import eu.siacs.conversations.xml.TagWriter; import eu.siacs.conversations.xml.TagWriter;
@ -76,19 +80,19 @@ public class XmppConnection implements Runnable {
private static final int PACKET_PRESENCE = 2; private static final int PACKET_PRESENCE = 2;
private final Context applicationContext; private final Context applicationContext;
protected Account account; protected Account account;
private WakeLock wakeLock; private final WakeLock wakeLock;
private Socket socket; private Socket socket;
private XmlReader tagReader; private XmlReader tagReader;
private TagWriter tagWriter; private TagWriter tagWriter;
private Features features = new Features(this); private final Features features = new Features(this);
private boolean shouldBind = true; private boolean shouldBind = true;
private boolean shouldAuthenticate = true; private boolean shouldAuthenticate = true;
private Element streamFeatures; 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 String streamId = null;
private int smVersion = 3; private int smVersion = 3;
private SparseArray<String> messageReceipts = new SparseArray<>(); private final SparseArray<String> messageReceipts = new SparseArray<>();
private boolean enabledEncryption = false; private boolean enabledEncryption = false;
private boolean enabledCarbons = false; private boolean enabledCarbons = false;
@ -100,20 +104,20 @@ public class XmppConnection implements Runnable {
private long lastConnect = 0; private long lastConnect = 0;
private long lastSessionStarted = 0; private long lastSessionStarted = 0;
private int attempt = 0; private int attempt = 0;
private Hashtable<String, PacketReceived> packetCallbacks = new Hashtable<>(); private final Map<String, PacketReceived> packetCallbacks = new Hashtable<>();
private OnPresencePacketReceived presenceListener = null; private OnPresencePacketReceived presenceListener = null;
private OnJinglePacketReceived jingleListener = null; private OnJinglePacketReceived jingleListener = null;
private OnIqPacketReceived unregisteredIqListener = null; private OnIqPacketReceived unregisteredIqListener = null;
private OnMessagePacketReceived messageListener = null; private OnMessagePacketReceived messageListener = null;
private OnStatusChanged statusListener = null; private OnStatusChanged statusListener = null;
private OnBindListener bindListener = null; private OnBindListener bindListener = null;
private ArrayList<OnAdvancedStreamFeaturesLoaded> advancedStreamFeaturesLoadedListeners = new ArrayList<>(); private final ArrayList<OnAdvancedStreamFeaturesLoaded> advancedStreamFeaturesLoadedListeners = new ArrayList<>();
private OnMessageAcknowledged acknowledgedListener = null; private OnMessageAcknowledged acknowledgedListener = null;
private XmppConnectionService mXmppConnectionService = null; private XmppConnectionService mXmppConnectionService = null;
private SaslMechanism saslMechanism; private SaslMechanism saslMechanism;
public XmppConnection(Account account, XmppConnectionService service) { public XmppConnection(final Account account, final XmppConnectionService service) {
this.account = account; this.account = account;
this.wakeLock = service.getPowerManager().newWakeLock( this.wakeLock = service.getPowerManager().newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, account.getJid().toBareJid().toString()); 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.ONLINE)
&& (account.getStatus() != Account.State.DISABLED)) { && (account.getStatus() != Account.State.DISABLED)) {
return; return;
} }
if (nextStatus == Account.State.ONLINE) { if (nextStatus == Account.State.ONLINE) {
this.attempt = 0; this.attempt = 0;
} }
@ -153,15 +157,15 @@ public class XmppConnection implements Runnable {
tagWriter = new TagWriter(); tagWriter = new TagWriter();
packetCallbacks.clear(); packetCallbacks.clear();
this.changeStatus(Account.State.CONNECTING); this.changeStatus(Account.State.CONNECTING);
Bundle result = DNSHelper.getSRVRecord(account.getServer()); final Bundle result = DNSHelper.getSRVRecord(account.getServer());
ArrayList<Parcelable> values = result.getParcelableArrayList("values"); final ArrayList<Parcelable> values = result.getParcelableArrayList("values");
if ("timeout".equals(result.getString("error"))) { if ("timeout".equals(result.getString("error"))) {
throw new IOException("timeout in dns"); throw new IOException("timeout in dns");
} else if (values != null) { } else if (values != null) {
int i = 0; int i = 0;
boolean socketError = true; boolean socketError = true;
while (socketError && values.size() > i) { while (socketError && values.size() > i) {
Bundle namePort = (Bundle) values.get(i); final Bundle namePort = (Bundle) values.get(i);
try { try {
String srvRecordServer; String srvRecordServer;
try { try {
@ -170,9 +174,9 @@ public class XmppConnection implements Runnable {
// TODO: Handle me?` // TODO: Handle me?`
srvRecordServer = ""; srvRecordServer = "";
} }
int srvRecordPort = namePort.getInt("port"); final int srvRecordPort = namePort.getInt("port");
String srvIpServer = namePort.getString("ip"); final String srvIpServer = namePort.getString("ip");
InetSocketAddress addr; final InetSocketAddress addr;
if (srvIpServer != null) { if (srvIpServer != null) {
addr = new InetSocketAddress(srvIpServer, srvRecordPort); addr = new InetSocketAddress(srvIpServer, srvRecordPort);
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
@ -187,10 +191,10 @@ public class XmppConnection implements Runnable {
socket = new Socket(); socket = new Socket();
socket.connect(addr, 20000); socket.connect(addr, 20000);
socketError = false; socketError = false;
} catch (UnknownHostException e) { } catch (final UnknownHostException e) {
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage()); Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage());
i++; i++;
} catch (IOException e) { } catch (final IOException e) {
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage()); Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage());
i++; i++;
} }
@ -204,9 +208,9 @@ public class XmppConnection implements Runnable {
} else { } else {
throw new IOException("timeout in dns"); throw new IOException("timeout in dns");
} }
OutputStream out = socket.getOutputStream(); final OutputStream out = socket.getOutputStream();
tagWriter.setOutputStream(out); tagWriter.setOutputStream(out);
InputStream in = socket.getInputStream(); final InputStream in = socket.getInputStream();
tagReader.setInputStream(in); tagReader.setInputStream(in);
tagWriter.beginDocument(); tagWriter.beginDocument();
sendStartStream(); sendStartStream();
@ -222,14 +226,9 @@ public class XmppConnection implements Runnable {
if (socket.isConnected()) { if (socket.isConnected()) {
socket.close(); socket.close();
} }
} catch (UnknownHostException e) { } catch (final UnknownHostException | ConnectException e) {
this.changeStatus(Account.State.SERVER_NOT_FOUND); this.changeStatus(Account.State.SERVER_NOT_FOUND);
} catch (final ConnectException e) { } catch (final IOException | XmlPullParserException | NoSuchAlgorithmException 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) {
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage()); Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage());
this.changeStatus(Account.State.OFFLINE); this.changeStatus(Account.State.OFFLINE);
} finally { } finally {
@ -268,7 +267,7 @@ public class XmppConnection implements Runnable {
} }
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": logged in"); Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": logged in");
account.setKey(Account.PINNED_MECHANISM_KEY, account.setKey(Account.PINNED_MECHANISM_KEY,
String.valueOf(saslMechanism.getPriority())); String.valueOf(saslMechanism.getPriority()));
tagReader.reset(); tagReader.reset();
sendStartStream(); sendStartStream();
processStream(tagReader.readTag()); processStream(tagReader.readTag());
@ -289,7 +288,7 @@ public class XmppConnection implements Runnable {
} }
tagWriter.writeElement(response); tagWriter.writeElement(response);
} else if (nextTag.isStart("enabled")) { } else if (nextTag.isStart("enabled")) {
Element enabled = tagReader.readElement(nextTag); final Element enabled = tagReader.readElement(nextTag);
if ("true".equals(enabled.getAttribute("resume"))) { if ("true".equals(enabled.getAttribute("resume"))) {
this.streamId = enabled.getAttribute("id"); this.streamId = enabled.getAttribute("id");
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
@ -301,14 +300,14 @@ public class XmppConnection implements Runnable {
} }
this.lastSessionStarted = SystemClock.elapsedRealtime(); this.lastSessionStarted = SystemClock.elapsedRealtime();
this.stanzasReceived = 0; this.stanzasReceived = 0;
RequestPacket r = new RequestPacket(smVersion); final RequestPacket r = new RequestPacket(smVersion);
tagWriter.writeStanzaAsync(r); tagWriter.writeStanzaAsync(r);
} else if (nextTag.isStart("resumed")) { } else if (nextTag.isStart("resumed")) {
lastPaketReceived = SystemClock.elapsedRealtime(); lastPaketReceived = SystemClock.elapsedRealtime();
Element resumed = tagReader.readElement(nextTag); final Element resumed = tagReader.readElement(nextTag);
String h = resumed.getAttribute("h"); final String h = resumed.getAttribute("h");
try { try {
int serverCount = Integer.parseInt(h); final int serverCount = Integer.parseInt(h);
if (serverCount != stanzasSent) { if (serverCount != stanzasSent) {
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
+ ": session resumed with lost packages"); + ": session resumed with lost packages");
@ -327,20 +326,19 @@ public class XmppConnection implements Runnable {
} }
messageReceipts.clear(); messageReceipts.clear();
} catch (final NumberFormatException ignored) { } catch (final NumberFormatException ignored) {
} }
sendServiceDiscoveryInfo(account.getServer()); sendServiceDiscoveryInfo(account.getServer());
sendServiceDiscoveryItems(account.getServer()); sendServiceDiscoveryItems(account.getServer());
sendInitialPing(); sendInitialPing();
} else if (nextTag.isStart("r")) { } else if (nextTag.isStart("r")) {
tagReader.readElement(nextTag); tagReader.readElement(nextTag);
AckPacket ack = new AckPacket(this.stanzasReceived, smVersion); final AckPacket ack = new AckPacket(this.stanzasReceived, smVersion);
tagWriter.writeStanzaAsync(ack); tagWriter.writeStanzaAsync(ack);
} else if (nextTag.isStart("a")) { } else if (nextTag.isStart("a")) {
Element ack = tagReader.readElement(nextTag); final Element ack = tagReader.readElement(nextTag);
lastPaketReceived = SystemClock.elapsedRealtime(); lastPaketReceived = SystemClock.elapsedRealtime();
int serverSequence = Integer.parseInt(ack.getAttribute("h")); final int serverSequence = Integer.parseInt(ack.getAttribute("h"));
String msgId = this.messageReceipts.get(serverSequence); final String msgId = this.messageReceipts.get(serverSequence);
if (msgId != null) { if (msgId != null) {
if (this.acknowledgedListener != null) { if (this.acknowledgedListener != null) {
this.acknowledgedListener.onMessageAcknowledged( this.acknowledgedListener.onMessageAcknowledged(
@ -374,13 +372,12 @@ public class XmppConnection implements Runnable {
private void sendInitialPing() { private void sendInitialPing() {
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": sending intial ping"); 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.setFrom(account.getJid());
iq.addChild("ping", "urn:xmpp:ping"); iq.addChild("ping", "urn:xmpp:ping");
this.sendIqPacket(iq, new OnIqPacketReceived() { this.sendIqPacket(iq, new OnIqPacketReceived() {
@Override @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() Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
+ ": online with resource " + account.getResource()); + ": online with resource " + account.getResource());
changeStatus(Account.State.ONLINE); 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 { throws XmlPullParserException, IOException {
Element element; Element element;
switch (packetType) { switch (packetType) {
@ -411,8 +408,8 @@ public class XmppConnection implements Runnable {
} }
while (!nextTag.isEnd(element.getName())) { while (!nextTag.isEnd(element.getName())) {
if (!nextTag.isNo()) { if (!nextTag.isNo()) {
Element child = tagReader.readElement(nextTag); final Element child = tagReader.readElement(nextTag);
String type = currentTag.getAttribute("type"); final String type = currentTag.getAttribute("type");
if (packetType == PACKET_IQ if (packetType == PACKET_IQ
&& "jingle".equals(child.getName()) && "jingle".equals(child.getName())
&& ("set".equalsIgnoreCase(type) || "get" && ("set".equalsIgnoreCase(type) || "get"
@ -432,9 +429,9 @@ public class XmppConnection implements Runnable {
return element; return element;
} }
private void processIq(Tag currentTag) throws XmlPullParserException, private void processIq(final Tag currentTag) throws XmlPullParserException,
IOException { IOException {
IqPacket packet = (IqPacket) processPacket(currentTag, PACKET_IQ); final IqPacket packet = (IqPacket) processPacket(currentTag, PACKET_IQ);
if (packet.getId() == null) { if (packet.getId() == null) {
return; // an iq packet without id is definitely invalid 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 { IOException {
MessagePacket packet = (MessagePacket) processPacket(currentTag, final MessagePacket packet = (MessagePacket) processPacket(currentTag,
PACKET_MESSAGE); PACKET_MESSAGE);
String id = packet.getAttribute("id"); final String id = packet.getAttribute("id");
if ((id != null) && (packetCallbacks.containsKey(id))) { if ((id != null) && (packetCallbacks.containsKey(id))) {
if (packetCallbacks.get(id) instanceof OnMessagePacketReceived) { if (packetCallbacks.get(id) instanceof OnMessagePacketReceived) {
((OnMessagePacketReceived) packetCallbacks.get(id)) ((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 { IOException {
PresencePacket packet = (PresencePacket) processPacket(currentTag, PresencePacket packet = (PresencePacket) processPacket(currentTag,
PACKET_PRESENCE); PACKET_PRESENCE);
String id = packet.getAttribute("id"); final String id = packet.getAttribute("id");
if ((id != null) && (packetCallbacks.containsKey(id))) { if ((id != null) && (packetCallbacks.containsKey(id))) {
if (packetCallbacks.get(id) instanceof OnPresencePacketReceived) { if (packetCallbacks.get(id) instanceof OnPresencePacketReceived) {
((OnPresencePacketReceived) packetCallbacks.get(id)) ((OnPresencePacketReceived) packetCallbacks.get(id))
@ -494,7 +491,7 @@ public class XmppConnection implements Runnable {
} }
private void sendStartTLS() throws IOException { 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"); startTLS.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-tls");
tagWriter.writeTag(startTLS); tagWriter.writeTag(startTLS);
} }
@ -512,11 +509,11 @@ public class XmppConnection implements Runnable {
IOException { IOException {
tagReader.readTag(); tagReader.readTag();
try { try {
SSLContext sc = SSLContext.getInstance("TLS"); final SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, sc.init(null,
new X509TrustManager[]{this.mXmppConnectionService.getMemorizingTrustManager()}, new X509TrustManager[]{this.mXmppConnectionService.getMemorizingTrustManager()},
mXmppConnectionService.getRNG()); mXmppConnectionService.getRNG());
SSLSocketFactory factory = sc.getSocketFactory(); final SSLSocketFactory factory = sc.getSocketFactory();
if (factory == null) { if (factory == null) {
throw new IOException("SSLSocketFactory was null"); throw new IOException("SSLSocketFactory was null");
@ -541,7 +538,7 @@ public class XmppConnection implements Runnable {
if (enableLegacySSL()) { if (enableLegacySSL()) {
supportProtocols = sslSocket.getSupportedProtocols(); supportProtocols = sslSocket.getSupportedProtocols();
} else { } else {
final List<String> supportedProtocols = new LinkedList<>( final Collection<String> supportedProtocols = new LinkedList<>(
Arrays.asList(sslSocket.getSupportedProtocols())); Arrays.asList(sslSocket.getSupportedProtocols()));
supportedProtocols.remove("SSLv3"); supportedProtocols.remove("SSLv3");
supportProtocols = new String[supportedProtocols.size()]; supportProtocols = new String[supportedProtocols.size()];
@ -549,13 +546,13 @@ public class XmppConnection implements Runnable {
} }
sslSocket.setEnabledProtocols(supportProtocols); sslSocket.setEnabledProtocols(supportProtocols);
if (verifier != null if (verifier != null
&& !verifier.verify(account.getServer().getDomainpart(), && !verifier.verify(account.getServer().getDomainpart(),
sslSocket.getSession())) { sslSocket.getSession())) {
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": TLS certificate verification failed"); Log.d(Config.LOGTAG,account.getJid().toBareJid()+": TLS certificate verification failed");
disconnect(true); disconnect(true);
changeStatus(Account.State.SECURITY_ERROR); changeStatus(Account.State.SECURITY_ERROR);
} }
tagReader.setInputStream(sslSocket.getInputStream()); tagReader.setInputStream(sslSocket.getInputStream());
tagWriter.setOutputStream(sslSocket.getOutputStream()); tagWriter.setOutputStream(sslSocket.getOutputStream());
sendStartStream(); sendStartStream();
@ -569,7 +566,7 @@ public class XmppConnection implements Runnable {
} }
} }
private void processStreamFeatures(Tag currentTag) private void processStreamFeatures(final Tag currentTag)
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
this.streamFeatures = tagReader.readElement(currentTag); this.streamFeatures = tagReader.readElement(currentTag);
if (this.streamFeatures.hasChild("starttls") && !enabledEncryption) { if (this.streamFeatures.hasChild("starttls") && !enabledEncryption) {
@ -605,7 +602,7 @@ public class XmppConnection implements Runnable {
"). Possible downgrade attack?"); "). Possible downgrade attack?");
disconnect(true); disconnect(true);
changeStatus(Account.State.SECURITY_ERROR); changeStatus(Account.State.SECURITY_ERROR);
} }
} catch (final JSONException e) { } catch (final JSONException e) {
Log.d(Config.LOGTAG, "Parse error while checking pinned auth mechanism"); 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:" } else if (this.streamFeatures.hasChild("sm", "urn:xmpp:sm:"
+ smVersion) + smVersion)
&& streamId != null) { && streamId != null) {
ResumePacket resume = new ResumePacket(this.streamId, final ResumePacket resume = new ResumePacket(this.streamId,
stanzasReceived, smVersion); stanzasReceived, smVersion);
this.tagWriter.writeStanzaAsync(resume); this.tagWriter.writeStanzaAsync(resume);
} else if (this.streamFeatures.hasChild("bind") && shouldBind) { } else if (this.streamFeatures.hasChild("bind") && shouldBind) {
@ -629,45 +626,44 @@ public class XmppConnection implements Runnable {
} }
} }
private List<String> extractMechanisms(Element stream) { private List<String> extractMechanisms(final Element stream) {
ArrayList<String> mechanisms = new ArrayList<>(stream final ArrayList<String> mechanisms = new ArrayList<>(stream
.getChildren().size()); .getChildren().size());
for (Element child : stream.getChildren()) { for (final Element child : stream.getChildren()) {
mechanisms.add(child.getContent()); mechanisms.add(child.getContent());
} }
return mechanisms; return mechanisms;
} }
private void sendRegistryRequest() { private void sendRegistryRequest() {
IqPacket register = new IqPacket(IqPacket.TYPE_GET); final IqPacket register = new IqPacket(IqPacket.TYPE_GET);
register.query("jabber:iq:register"); register.query("jabber:iq:register");
register.setTo(account.getServer()); register.setTo(account.getServer());
sendIqPacket(register, new OnIqPacketReceived() { sendIqPacket(register, new OnIqPacketReceived() {
@Override @Override
public void onIqPacketReceived(Account account, IqPacket packet) { public void onIqPacketReceived(final Account account, final IqPacket packet) {
Element instructions = packet.query().findChild("instructions"); final Element instructions = packet.query().findChild("instructions");
if (packet.query().hasChild("username") if (packet.query().hasChild("username")
&& (packet.query().hasChild("password"))) { && (packet.query().hasChild("password"))) {
IqPacket register = new IqPacket(IqPacket.TYPE_SET); final IqPacket register = new IqPacket(IqPacket.TYPE_SET);
Element username = new Element("username") final Element username = new Element("username")
.setContent(account.getUsername()); .setContent(account.getUsername());
Element password = new Element("password") final Element password = new Element("password")
.setContent(account.getPassword()); .setContent(account.getPassword());
register.query("jabber:iq:register").addChild(username); register.query("jabber:iq:register").addChild(username);
register.query().addChild(password); register.query().addChild(password);
sendIqPacket(register, new OnIqPacketReceived() { sendIqPacket(register, new OnIqPacketReceived() {
@Override @Override
public void onIqPacketReceived(Account account, public void onIqPacketReceived(final Account account, final IqPacket packet) {
IqPacket packet) {
if (packet.getType() == IqPacket.TYPE_RESULT) { if (packet.getType() == IqPacket.TYPE_RESULT) {
account.setOption(Account.OPTION_REGISTER, account.setOption(Account.OPTION_REGISTER,
false); false);
changeStatus(Account.State.REGISTRATION_SUCCESSFUL); changeStatus(Account.State.REGISTRATION_SUCCESSFUL);
} else if (packet.hasChild("error") } else if (packet.hasChild("error")
&& (packet.findChild("error") && (packet.findChild("error")
.hasChild("conflict"))) { .hasChild("conflict"))) {
changeStatus(Account.State.REGISTRATION_CONFLICT); changeStatus(Account.State.REGISTRATION_CONFLICT);
} else { } else {
changeStatus(Account.State.REGISTRATION_FAILED); changeStatus(Account.State.REGISTRATION_FAILED);
@ -687,14 +683,14 @@ public class XmppConnection implements Runnable {
}); });
} }
private void sendBindRequest() throws IOException { private void sendBindRequest() {
IqPacket iq = new IqPacket(IqPacket.TYPE_SET); final IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
iq.addChild("bind", "urn:ietf:params:xml:ns:xmpp-bind") iq.addChild("bind", "urn:ietf:params:xml:ns:xmpp-bind")
.addChild("resource").setContent(account.getResource()); .addChild("resource").setContent(account.getResource());
this.sendUnboundIqPacket(iq, new OnIqPacketReceived() { this.sendUnboundIqPacket(iq, new OnIqPacketReceived() {
@Override @Override
public void onIqPacketReceived(Account account, IqPacket packet) { public void onIqPacketReceived(final Account account, final IqPacket packet) {
Element bind = packet.findChild("bind"); final Element bind = packet.findChild("bind");
if (bind != null) { if (bind != null) {
final Element jid = bind.findChild("jid"); final Element jid = bind.findChild("jid");
if (jid != null && jid.getContent() != null) { if (jid != null && jid.getContent() != null) {
@ -705,14 +701,14 @@ public class XmppConnection implements Runnable {
} }
if (streamFeatures.hasChild("sm", "urn:xmpp:sm:3")) { if (streamFeatures.hasChild("sm", "urn:xmpp:sm:3")) {
smVersion = 3; smVersion = 3;
EnablePacket enable = new EnablePacket(smVersion); final EnablePacket enable = new EnablePacket(smVersion);
tagWriter.writeStanzaAsync(enable); tagWriter.writeStanzaAsync(enable);
stanzasSent = 0; stanzasSent = 0;
messageReceipts.clear(); messageReceipts.clear();
} else if (streamFeatures.hasChild("sm", } else if (streamFeatures.hasChild("sm",
"urn:xmpp:sm:2")) { "urn:xmpp:sm:2")) {
smVersion = 2; smVersion = 2;
EnablePacket enable = new EnablePacket(smVersion); final EnablePacket enable = new EnablePacket(smVersion);
tagWriter.writeStanzaAsync(enable); tagWriter.writeStanzaAsync(enable);
stanzasSent = 0; stanzasSent = 0;
messageReceipts.clear(); messageReceipts.clear();
@ -736,7 +732,7 @@ public class XmppConnection implements Runnable {
if (this.streamFeatures.hasChild("session")) { if (this.streamFeatures.hasChild("session")) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() Log.d(Config.LOGTAG, account.getJid().toBareJid()
+ ": sending deprecated session"); + ": sending deprecated session");
IqPacket startSession = new IqPacket(IqPacket.TYPE_SET); final IqPacket startSession = new IqPacket(IqPacket.TYPE_SET);
startSession.addChild("session", startSession.addChild("session",
"urn:ietf:params:xml:ns:xmpp-session"); "urn:ietf:params:xml:ns:xmpp-session");
this.sendUnboundIqPacket(startSession, null); this.sendUnboundIqPacket(startSession, null);
@ -755,10 +751,10 @@ public class XmppConnection implements Runnable {
this.sendIqPacket(iq, new OnIqPacketReceived() { this.sendIqPacket(iq, new OnIqPacketReceived() {
@Override @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<Element> elements = packet.query().getChildren();
final List<String> features = new ArrayList<>(); final List<String> features = new ArrayList<>();
for (Element element : elements) { for (final Element element : elements) {
if (element.getName().equals("identity")) { if (element.getName().equals("identity")) {
if ("irc".equals(element.getAttribute("type"))) { if ("irc".equals(element.getAttribute("type"))) {
//add fake feature to not confuse irc and real muc //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())) { if (account.getServer().equals(server.toDomainJid())) {
enableAdvancedStreamFeatures(); enableAdvancedStreamFeatures();
for(OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) { for (final OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) {
listener.onAdvancedStreamFeaturesAvailable(account); listener.onAdvancedStreamFeaturesAvailable(account);
} }
} }
@ -787,6 +783,10 @@ public class XmppConnection implements Runnable {
sendEnableCarbons(); sendEnableCarbons();
} }
} }
if (getFeatures().blocking()) {
Log.d(Config.LOGTAG, "Requesting block list");
this.sendIqPacket(getIqGenerator().generateGetBlockList(), mXmppConnectionService.getIqParser());
}
} }
private void sendServiceDiscoveryItems(final Jid server) { private void sendServiceDiscoveryItems(final Jid server) {
@ -796,9 +796,9 @@ public class XmppConnection implements Runnable {
this.sendIqPacket(iq, new OnIqPacketReceived() { this.sendIqPacket(iq, new OnIqPacketReceived() {
@Override @Override
public void onIqPacketReceived(Account account, IqPacket packet) { public void onIqPacketReceived(final Account account, final IqPacket packet) {
List<Element> elements = packet.query().getChildren(); final List<Element> elements = packet.query().getChildren();
for (Element element : elements) { for (final Element element : elements) {
if (element.getName().equals("item")) { if (element.getName().equals("item")) {
final Jid jid = element.getAttributeAsJid("jid"); final Jid jid = element.getAttributeAsJid("jid");
if (jid != null && !jid.equals(account.getServer())) { if (jid != null && !jid.equals(account.getServer())) {
@ -811,12 +811,12 @@ public class XmppConnection implements Runnable {
} }
private void sendEnableCarbons() { 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"); iq.addChild("enable", "urn:xmpp:carbons:2");
this.sendIqPacket(iq, new OnIqPacketReceived() { this.sendIqPacket(iq, new OnIqPacketReceived() {
@Override @Override
public void onIqPacketReceived(Account account, IqPacket packet) { public void onIqPacketReceived(final Account account, final IqPacket packet) {
if (!packet.hasChild("error")) { if (!packet.hasChild("error")) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() Log.d(Config.LOGTAG, account.getJid().toBareJid()
+ ": successfully enabled carbons"); + ": 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 { throws XmlPullParserException, IOException {
Element streamError = tagReader.readElement(currentTag); final Element streamError = tagReader.readElement(currentTag);
if (streamError != null && streamError.hasChild("conflict")) { if (streamError != null && streamError.hasChild("conflict")) {
final String resource = account.getResource().split("\\.")[0]; final String resource = account.getResource().split("\\.")[0];
account.setResource(resource + "." + nextRandomId()); account.setResource(resource + "." + nextRandomId());
Log.d(Config.LOGTAG, Log.d(Config.LOGTAG,
account.getJid().toBareJid() + ": switching resource due to conflict (" account.getJid().toBareJid() + ": switching resource due to conflict ("
+ account.getResource() + ")"); + account.getResource() + ")");
} }
} }
private void sendStartStream() throws IOException { 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("from", account.getJid().toBareJid().toString());
stream.setAttribute("to", account.getServer().toString()); stream.setAttribute("to", account.getServer().toString());
stream.setAttribute("version", "1.0"); stream.setAttribute("version", "1.0");
@ -856,33 +856,32 @@ public class XmppConnection implements Runnable {
return new BigInteger(50, mXmppConnectionService.getRNG()).toString(32); 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) { if (packet.getId() == null) {
String id = nextRandomId(); final String id = nextRandomId();
packet.setAttribute("id", id); packet.setAttribute("id", id);
} }
packet.setFrom(account.getJid()); packet.setFrom(account.getJid());
this.sendPacket(packet, callback); this.sendPacket(packet, callback);
} }
public void sendUnboundIqPacket(IqPacket packet, OnIqPacketReceived callback) { public void sendUnboundIqPacket(final IqPacket packet, final PacketReceived callback) {
if (packet.getId() == null) { if (packet.getId() == null) {
String id = nextRandomId(); final String id = nextRandomId();
packet.setAttribute("id", id); packet.setAttribute("id", id);
} }
this.sendPacket(packet, callback); this.sendPacket(packet, callback);
} }
public void sendMessagePacket(MessagePacket packet) { public void sendMessagePacket(final MessagePacket packet) {
this.sendPacket(packet, null); this.sendPacket(packet, null);
} }
public void sendPresencePacket(PresencePacket packet) { public void sendPresencePacket(final PresencePacket packet) {
this.sendPacket(packet, null); this.sendPacket(packet, null);
} }
private synchronized void sendPacket(final AbstractStanza packet, private synchronized void sendPacket(final AbstractStanza packet, final PacketReceived callback) {
PacketReceived callback) {
if (packet.getName().equals("iq") || packet.getName().equals("message") if (packet.getName().equals("iq") || packet.getName().equals("message")
|| packet.getName().equals("presence")) { || packet.getName().equals("presence")) {
++stanzasSent; ++stanzasSent;
@ -907,7 +906,7 @@ public class XmppConnection implements Runnable {
if (streamFeatures.hasChild("sm")) { if (streamFeatures.hasChild("sm")) {
tagWriter.writeStanzaAsync(new RequestPacket(smVersion)); tagWriter.writeStanzaAsync(new RequestPacket(smVersion));
} else { } else {
IqPacket iq = new IqPacket(IqPacket.TYPE_GET); final IqPacket iq = new IqPacket(IqPacket.TYPE_GET);
iq.setFrom(account.getJid()); iq.setFrom(account.getJid());
iq.addChild("ping", "urn:xmpp:ping"); iq.addChild("ping", "urn:xmpp:ping");
this.sendIqPacket(iq, null); this.sendIqPacket(iq, null);
@ -916,44 +915,44 @@ public class XmppConnection implements Runnable {
} }
public void setOnMessagePacketReceivedListener( public void setOnMessagePacketReceivedListener(
OnMessagePacketReceived listener) { final OnMessagePacketReceived listener) {
this.messageListener = listener; this.messageListener = listener;
} }
public void setOnUnregisteredIqPacketReceivedListener( public void setOnUnregisteredIqPacketReceivedListener(
OnIqPacketReceived listener) { final OnIqPacketReceived listener) {
this.unregisteredIqListener = listener; this.unregisteredIqListener = listener;
} }
public void setOnPresencePacketReceivedListener( public void setOnPresencePacketReceivedListener(
OnPresencePacketReceived listener) { final OnPresencePacketReceived listener) {
this.presenceListener = listener; this.presenceListener = listener;
} }
public void setOnJinglePacketReceivedListener( public void setOnJinglePacketReceivedListener(
OnJinglePacketReceived listener) { final OnJinglePacketReceived listener) {
this.jingleListener = listener; this.jingleListener = listener;
} }
public void setOnStatusChangedListener(OnStatusChanged listener) { public void setOnStatusChangedListener(final OnStatusChanged listener) {
this.statusListener = listener; this.statusListener = listener;
} }
public void setOnBindListener(OnBindListener listener) { public void setOnBindListener(final OnBindListener listener) {
this.bindListener = listener; this.bindListener = listener;
} }
public void setOnMessageAcknowledgeListener(OnMessageAcknowledged listener) { public void setOnMessageAcknowledgeListener(final OnMessageAcknowledged listener) {
this.acknowledgedListener = listener; this.acknowledgedListener = listener;
} }
public void addOnAdvancedStreamFeaturesAvailableListener(OnAdvancedStreamFeaturesLoaded listener) { public void addOnAdvancedStreamFeaturesAvailableListener(final OnAdvancedStreamFeaturesLoaded listener) {
if (!this.advancedStreamFeaturesLoadedListeners.contains(listener)) { if (!this.advancedStreamFeaturesLoadedListeners.contains(listener)) {
this.advancedStreamFeaturesLoadedListeners.add(listener); this.advancedStreamFeaturesLoadedListeners.add(listener);
} }
} }
public void disconnect(boolean force) { public void disconnect(final boolean force) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting"); Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting");
try { try {
if (force) { if (force) {
@ -973,23 +972,23 @@ public class XmppConnection implements Runnable {
} }
tagWriter.writeTag(Tag.end("stream:stream")); tagWriter.writeTag(Tag.end("stream:stream"));
socket.close(); socket.close();
} catch (IOException e) { } catch (final IOException e) {
Log.d(Config.LOGTAG, Log.d(Config.LOGTAG,
"io exception during disconnect"); "io exception during disconnect");
} catch (InterruptedException e) { } catch (final InterruptedException e) {
Log.d(Config.LOGTAG, "interrupted"); Log.d(Config.LOGTAG, "interrupted");
} }
} }
} }
}).start(); }).start();
} catch (IOException e) { } catch (final IOException e) {
Log.d(Config.LOGTAG, "io exception during disconnect"); 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<>(); 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)) { if (cursor.getValue().contains(feature)) {
items.add(cursor.getKey()); items.add(cursor.getKey());
} }
@ -997,8 +996,8 @@ public class XmppConnection implements Runnable {
return items; return items;
} }
public String findDiscoItemByFeature(String feature) { public String findDiscoItemByFeature(final String feature) {
List<String> items = findDiscoItemsByFeature(feature); final List<String> items = findDiscoItemsByFeature(feature);
if (items.size() >= 1) { if (items.size() >= 1) {
return items.get(0); return items.get(0);
} }
@ -1010,8 +1009,7 @@ public class XmppConnection implements Runnable {
} }
public String getMucServer() { public String getMucServer() {
final List<String> items = new ArrayList<>(); for (final Entry<String, List<String>> cursor : disco.entrySet()) {
for (Entry<String, List<String>> cursor : disco.entrySet()) {
final List<String> value = cursor.getValue(); final List<String> value = cursor.getValue();
if (value.contains("http://jabber.org/protocol/muc") && !value.contains("jabber:iq:gateway") && !value.contains("siacs:no:muc")) { if (value.contains("http://jabber.org/protocol/muc") && !value.contains("jabber:iq:gateway") && !value.contains("siacs:no:muc")) {
return cursor.getKey(); return cursor.getKey();
@ -1021,8 +1019,8 @@ public class XmppConnection implements Runnable {
} }
public int getTimeToNextAttempt() { public int getTimeToNextAttempt() {
int interval = (int) (25 * Math.pow(1.5, attempt)); final int interval = (int) (25 * Math.pow(1.5, attempt));
int secondsSinceLast = (int) ((SystemClock.elapsedRealtime() - this.lastConnect) / 1000); final int secondsSinceLast = (int) ((SystemClock.elapsedRealtime() - this.lastConnect) / 1000);
return interval - secondsSinceLast; return interval - secondsSinceLast;
} }
@ -1035,7 +1033,7 @@ public class XmppConnection implements Runnable {
} }
public long getLastSessionEstablished() { public long getLastSessionEstablished() {
long diff; final long diff;
if (this.lastSessionStarted == 0) { if (this.lastSessionStarted == 0) {
diff = SystemClock.elapsedRealtime() - this.lastConnect; diff = SystemClock.elapsedRealtime() - this.lastConnect;
} else { } else {
@ -1067,7 +1065,7 @@ public class XmppConnection implements Runnable {
public class Features { public class Features {
XmppConnection connection; XmppConnection connection;
public Features(XmppConnection connection) { public Features(final XmppConnection connection) {
this.connection = connection; this.connection = connection;
} }
@ -1080,6 +1078,10 @@ public class XmppConnection implements Runnable {
return hasDiscoFeature(account.getServer(), "urn:xmpp:carbons:2"); return hasDiscoFeature(account.getServer(), "urn:xmpp:carbons:2");
} }
public boolean blocking() {
return hasDiscoFeature(account.getServer(), Xmlns.BLOCKING);
}
public boolean sm() { public boolean sm() {
return streamId != null; return streamId != null;
} }
@ -1110,4 +1112,8 @@ public class XmppConnection implements Runnable {
.findDiscoItemByFeature("http://jabber.org/protocol/bytestreams") != null; .findDiscoItemByFeature("http://jabber.org/protocol/bytestreams") != null;
} }
} }
private IqGenerator getIqGenerator() {
return mXmppConnectionService.getIqGenerator();
}
} }

View File

@ -32,7 +32,7 @@ public final class Jid {
return resourcepart; return resourcepart;
} }
public static Jid fromSessionID(SessionID id) throws InvalidJidException{ public static Jid fromSessionID(final SessionID id) throws InvalidJidException{
if (id.getUserID().isEmpty()) { if (id.getUserID().isEmpty()) {
return Jid.fromString(id.getAccountID()); return Jid.fromString(id.getAccountID());
} else { } else {
@ -190,4 +190,8 @@ public final class Jid {
public boolean isBareJid() { public boolean isBareJid() {
return this.resourcepart.isEmpty(); return this.resourcepart.isEmpty();
} }
public boolean isDomainJid() {
return !this.hasLocalpart();
}
} }

View File

@ -9,27 +9,27 @@ public class IqPacket extends AbstractStanza {
public static final int TYPE_RESULT = 1; public static final int TYPE_RESULT = 1;
public static final int TYPE_GET = 2; public static final int TYPE_GET = 2;
private IqPacket(String name) { private IqPacket(final String name) {
super(name); super(name);
} }
public IqPacket(int type) { public IqPacket(final int type) {
super("iq"); super("iq");
switch (type) { switch (type) {
case TYPE_SET: case TYPE_SET:
this.setAttribute("type", "set"); this.setAttribute("type", "set");
break; break;
case TYPE_GET: case TYPE_GET:
this.setAttribute("type", "get"); this.setAttribute("type", "get");
break; break;
case TYPE_RESULT: case TYPE_RESULT:
this.setAttribute("type", "result"); this.setAttribute("type", "result");
break; break;
case TYPE_ERROR: case TYPE_ERROR:
this.setAttribute("type", "error"); this.setAttribute("type", "error");
break; break;
default: default:
break; break;
} }
} }
@ -45,29 +45,30 @@ public class IqPacket extends AbstractStanza {
return query; return query;
} }
public Element query(String xmlns) { public Element query(final String xmlns) {
Element query = query(); final Element query = query();
query.setAttribute("xmlns", xmlns); query.setAttribute("xmlns", xmlns);
return query(); return query();
} }
public int getType() { public int getType() {
String type = getAttribute("type"); final String type = getAttribute("type");
if ("error".equals(type)) { switch (type) {
return TYPE_ERROR; case "error":
} else if ("result".equals(type)) { return TYPE_ERROR;
return TYPE_RESULT; case "result":
} else if ("set".equals(type)) { return TYPE_RESULT;
return TYPE_SET; case "set":
} else if ("get".equals(type)) { return TYPE_SET;
return TYPE_GET; case "get":
} else { return TYPE_GET;
return 1000; default:
return 1000;
} }
} }
public IqPacket generateRespone(int type) { public IqPacket generateRespone(final int type) {
IqPacket packet = new IqPacket(type); final IqPacket packet = new IqPacket(type);
packet.setTo(this.getFrom()); packet.setTo(this.getFrom());
packet.setId(this.getId()); packet.setId(this.getId());
return packet; return packet;

View File

@ -7,6 +7,9 @@
<item <item
android:id="@+id/context_contact_details" android:id="@+id/context_contact_details"
android:title="@string/view_contact_details"/> android:title="@string/view_contact_details"/>
<item
android:id="@+id/context_contact_block_unblock"
android:title="@string/block_contact"/>
<item <item
android:id="@+id/context_delete_contact" android:id="@+id/context_delete_contact"
android:title="@string/delete_contact"/> android:title="@string/delete_contact"/>

View File

@ -56,6 +56,18 @@
android:showAsAction="never" android:showAsAction="never"
android:title="@string/enable_notifications"/> 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 <item
android:id="@+id/action_accounts" android:id="@+id/action_accounts"
android:orderInCategory="90" android:orderInCategory="90"

View File

@ -4,5 +4,9 @@
android:id="@+id/action_show_qr_code" android:id="@+id/action_show_qr_code"
android:title="@string/show_qr_code" android:title="@string/show_qr_code"
android:showAsAction="never" /> android:showAsAction="never" />
<item
android:id="@+id/action_show_block_list"
android:title="@string/show_block_list"
android:showAsAction="never" />
</menu> </menu>

View File

@ -13,6 +13,10 @@
<string name="action_edit_contact">Edit name</string> <string name="action_edit_contact">Edit name</string>
<string name="action_add_phone_book">Add to phone book</string> <string name="action_add_phone_book">Add to phone book</string>
<string name="action_delete_contact">Delete from roster</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_manage_accounts">Manage Accounts</string>
<string name="title_activity_settings">Settings</string> <string name="title_activity_settings">Settings</string>
<string name="title_activity_conference_details">Conference Details</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_sharewith">Share with Conversation</string>
<string name="title_activity_start_conversation">Start Conversation</string> <string name="title_activity_start_conversation">Start Conversation</string>
<string name="title_activity_choose_contact">Choose contact</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="just_now">just now</string>
<string name="minute_ago">1 min ago</string> <string name="minute_ago">1 min ago</string>
<string name="minutes_ago">%d mins ago</string> <string name="minutes_ago">%d mins ago</string>
@ -34,6 +39,11 @@
<string name="participant">Participant</string> <string name="participant">Participant</string>
<string name="visitor">Visitor</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="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="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="register_account">Register new account on server</string>
<string name="share_with">Share with</string> <string name="share_with">Share with</string>
@ -45,6 +55,8 @@
<string name="add">Add</string> <string name="add">Add</string>
<string name="edit">Edit</string> <string name="edit">Edit</string>
<string name="delete">Delete</string> <string name="delete">Delete</string>
<string name="block">Block</string>
<string name="unblock">Unblock</string>
<string name="save">Save</string> <string name="save">Save</string>
<string name="ok">OK</string> <string name="ok">OK</string>
<string name="crash_report_title">Conversations has crashed</string> <string name="crash_report_title">Conversations has crashed</string>
@ -202,6 +214,8 @@
<string name="join_conference">Join Conference</string> <string name="join_conference">Join Conference</string>
<string name="delete_contact">Delete Contact</string> <string name="delete_contact">Delete Contact</string>
<string name="view_contact_details">View contact details</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="create">Create</string>
<string name="contact_already_exists">The contact already exists</string> <string name="contact_already_exists">The contact already exists</string>
<string name="join">Join</string> <string name="join">Join</string>
@ -318,6 +332,7 @@
<string name="image_transmission_failed">Image transmission failed</string> <string name="image_transmission_failed">Image transmission failed</string>
<string name="scan_qr_code">Scan QR code</string> <string name="scan_qr_code">Scan QR code</string>
<string name="show_qr_code">Show 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="account_details">Account details</string>
<string name="verify_otr">Verify OTR</string> <string name="verify_otr">Verify OTR</string>
<string name="remote_fingerprint">Remote Fingerprint</string> <string name="remote_fingerprint">Remote Fingerprint</string>