commit
a94663aaa4
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
|
@ -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";
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -174,13 +173,29 @@ public class Conversation extends AbstractEntity {
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,7 +368,7 @@ 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());
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -211,7 +211,7 @@ public class MucOptions {
|
||||||
}
|
}
|
||||||
} 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();
|
||||||
}
|
}
|
||||||
|
@ -389,7 +389,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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());
|
||||||
|
@ -84,17 +151,17 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
|
||||||
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");
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
@ -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()) {
|
||||||
|
@ -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,7 +1583,7 @@ 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() {
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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() {
|
|
||||||
|
|
||||||
|
public class ChooseContactActivity extends AbstractSearchableListItemActivity {
|
||||||
@Override
|
@Override
|
||||||
public void afterTextChanged(Editable editable) {
|
public void onCreate(final Bundle savedInstanceState) {
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
@ -301,7 +301,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
|
||||||
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()) {
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
if (getActionBar() != null) {
|
||||||
getActionBar().setHomeButtonEnabled(true);
|
getActionBar().setHomeButtonEnabled(true);
|
||||||
getActionBar().setDisplayHomeAsUpEnabled(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()) {
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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";
|
||||||
|
@ -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,6 +294,8 @@ 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) {
|
||||||
|
@ -302,9 +306,20 @@ public class ConversationActivity extends XmppActivity implements
|
||||||
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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -619,8 +640,8 @@ 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 {
|
||||||
|
@ -983,4 +1004,23 @@ public class ConversationActivity extends XmppActivity implements
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -787,12 +803,13 @@ public class ConversationFragment extends Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -319,12 +319,16 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
@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;
|
||||||
}
|
}
|
||||||
|
@ -340,25 +344,31 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
||||||
}
|
}
|
||||||
if (this.jidToEdit != null) {
|
if (this.jidToEdit != null) {
|
||||||
this.mRegisterNew.setVisibility(View.GONE);
|
this.mRegisterNew.setVisibility(View.GONE);
|
||||||
|
if (getActionBar() != null) {
|
||||||
getActionBar().setTitle(getString(R.string.account_details));
|
getActionBar().setTitle(getString(R.string.account_details));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.mAvatar.setVisibility(View.GONE);
|
this.mAvatar.setVisibility(View.GONE);
|
||||||
|
if (getActionBar() != null) {
|
||||||
getActionBar().setTitle(R.string.action_add_account);
|
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) {
|
||||||
|
if (getActionBar() != null) {
|
||||||
getActionBar().setDisplayHomeAsUpEnabled(false);
|
getActionBar().setDisplayHomeAsUpEnabled(false);
|
||||||
getActionBar().setDisplayShowHomeEnabled(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());
|
||||||
|
@ -387,7 +409,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
||||||
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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
if (getActionBar() != null) {
|
||||||
getActionBar().setSelectedNavigationItem(position);
|
getActionBar().setSelectedNavigationItem(position);
|
||||||
|
}
|
||||||
onTabChanged();
|
onTabChanged();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -270,10 +274,15 @@ 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,
|
||||||
|
@ -287,7 +296,6 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
builder.create().show();
|
builder.create().show();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void deleteConference() {
|
protected void deleteConference() {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
@ -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);
|
||||||
|
@ -613,7 +621,7 @@ public abstract class XmppActivity extends Activity {
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
|
||||||
|| 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);
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package eu.siacs.conversations.utils;
|
||||||
|
|
||||||
|
public final class Xmlns {
|
||||||
|
public static final String BLOCKING = "urn:xmpp:blocking";
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -67,11 +67,11 @@ public class Element {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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());
|
||||||
|
@ -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 {
|
||||||
|
@ -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()];
|
||||||
|
@ -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) {
|
||||||
|
@ -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,38 +626,37 @@ 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);
|
||||||
|
@ -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,9 +829,9 @@ 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());
|
||||||
|
@ -842,7 +842,7 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,11 @@ 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:
|
||||||
|
@ -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) {
|
||||||
|
case "error":
|
||||||
return TYPE_ERROR;
|
return TYPE_ERROR;
|
||||||
} else if ("result".equals(type)) {
|
case "result":
|
||||||
return TYPE_RESULT;
|
return TYPE_RESULT;
|
||||||
} else if ("set".equals(type)) {
|
case "set":
|
||||||
return TYPE_SET;
|
return TYPE_SET;
|
||||||
} else if ("get".equals(type)) {
|
case "get":
|
||||||
return TYPE_GET;
|
return TYPE_GET;
|
||||||
} else {
|
default:
|
||||||
return 1000;
|
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;
|
||||||
|
|
|
@ -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"/>
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue