aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/eu/siacs/conversations/Config.java1
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java6
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/sasl/Tokenizer.java4
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Account.java5
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Bookmark.java3
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Conversation.java12
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Message.java17
-rw-r--r--src/main/java/eu/siacs/conversations/entities/MucOptions.java13
-rw-r--r--src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java2
-rw-r--r--src/main/java/eu/siacs/conversations/parser/IqParser.java13
-rw-r--r--src/main/java/eu/siacs/conversations/parser/MessageParser.java24
-rw-r--r--src/main/java/eu/siacs/conversations/parser/PresenceParser.java2
-rw-r--r--src/main/java/eu/siacs/conversations/services/AvatarService.java28
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java160
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java68
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationActivity.java19
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationFragment.java37
-rw-r--r--src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java17
-rw-r--r--src/main/java/eu/siacs/conversations/ui/SettingsFragment.java52
-rw-r--r--src/main/java/eu/siacs/conversations/ui/XmppActivity.java6
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java6
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java7
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java16
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java80
-rw-r--r--src/main/java/eu/siacs/conversations/utils/PhoneHelper.java2
-rw-r--r--src/main/java/eu/siacs/conversations/utils/UIHelper.java45
-rw-r--r--src/main/java/eu/siacs/conversations/utils/zlib/ZLibInputStream.java54
-rw-r--r--src/main/java/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java95
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java64
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java328
30 files changed, 535 insertions, 651 deletions
diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java
index 7af29451..d777e5cc 100644
--- a/src/main/java/eu/siacs/conversations/Config.java
+++ b/src/main/java/eu/siacs/conversations/Config.java
@@ -18,7 +18,6 @@ public final class Config {
public static final int MESSAGE_MERGE_WINDOW = 20;
- public static final boolean PARSE_EMOTICONS = false;
public static final int PROGRESS_UI_UPDATE_INTERVAL = 750;
public static final boolean NO_PROXY_LOOKUP = false; //useful to debug ibb
diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java b/src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java
index 850cacc2..8b16215b 100644
--- a/src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java
+++ b/src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java
@@ -39,7 +39,7 @@ public class DigestMd5 extends SaslMechanism {
final Tokenizer tokenizer = new Tokenizer(Base64.decode(challenge, Base64.DEFAULT));
String nonce = "";
for (final String token : tokenizer) {
- final String[] parts = token.split("=");
+ final String[] parts = token.split("=", 2);
if (parts[0].equals("nonce")) {
nonce = parts[1].replace("\"", "");
} else if (parts[0].equals("rspauth")) {
@@ -79,6 +79,10 @@ public class DigestMd5 extends SaslMechanism {
case RESPONSE_SENT:
state = State.VALID_SERVER_RESPONSE;
break;
+ case VALID_SERVER_RESPONSE:
+ if (challenge==null) {
+ return null; //everything is fine
+ }
default:
throw new InvalidStateException(state);
}
diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/Tokenizer.java b/src/main/java/eu/siacs/conversations/crypto/sasl/Tokenizer.java
index 39be0224..e37e0fa7 100644
--- a/src/main/java/eu/siacs/conversations/crypto/sasl/Tokenizer.java
+++ b/src/main/java/eu/siacs/conversations/crypto/sasl/Tokenizer.java
@@ -16,6 +16,10 @@ public final class Tokenizer implements Iterator<String>, Iterable<String> {
public Tokenizer(final byte[] challenge) {
final String challengeString = new String(challenge);
parts = new ArrayList<>(Arrays.asList(challengeString.split(",")));
+ // Trim parts.
+ for (int i = 0; i < parts.size(); i++) {
+ parts.set(i, parts.get(i).trim());
+ }
index = 0;
}
diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java
index 1d0a025f..538d0ec2 100644
--- a/src/main/java/eu/siacs/conversations/entities/Account.java
+++ b/src/main/java/eu/siacs/conversations/entities/Account.java
@@ -372,8 +372,9 @@ public class Account extends AbstractEntity {
}
public boolean hasBookmarkFor(final Jid conferenceJid) {
- for (Bookmark bmark : this.bookmarks) {
- if (bmark.getJid().equals(conferenceJid.toBareJid())) {
+ for (Bookmark bookmark : this.bookmarks) {
+ final Jid jid = bookmark.getJid();
+ if (jid != null && jid.equals(conferenceJid.toBareJid())) {
return true;
}
}
diff --git a/src/main/java/eu/siacs/conversations/entities/Bookmark.java b/src/main/java/eu/siacs/conversations/entities/Bookmark.java
index 91dc25be..559e2f2d 100644
--- a/src/main/java/eu/siacs/conversations/entities/Bookmark.java
+++ b/src/main/java/eu/siacs/conversations/entities/Bookmark.java
@@ -128,7 +128,8 @@ public class Bookmark extends Element implements ListItem {
return true;
}
needle = needle.toLowerCase(Locale.US);
- return getJid().toString().contains(needle) ||
+ final Jid jid = getJid();
+ return (jid != null && jid.toString().contains(needle)) ||
getDisplayName().toLowerCase(Locale.US).contains(needle) ||
matchInTag(needle);
}
diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java
index ed42ac77..a7da0bc2 100644
--- a/src/main/java/eu/siacs/conversations/entities/Conversation.java
+++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java
@@ -458,6 +458,18 @@ public class Conversation extends AbstractEntity {
return false;
}
+ public Message findSentMessageWithBody(String body) {
+ synchronized (this.messages) {
+ for (int i = this.getMessages().size() - 1; i >= 0; --i) {
+ Message message = this.messages.get(i);
+ if ((message.getStatus() == Message.STATUS_UNSEND || message.getStatus() == Message.STATUS_SEND) && message.getBody() != null && message.getBody().equals(body)) {
+ return message;
+ }
+ }
+ return null;
+ }
+ }
+
public void setMutedTill(long value) {
this.setAttribute(ATTRIBUTE_MUTED_TILL, String.valueOf(value));
}
diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java
index 16635f7c..47861d06 100644
--- a/src/main/java/eu/siacs/conversations/entities/Message.java
+++ b/src/main/java/eu/siacs/conversations/entities/Message.java
@@ -73,14 +73,21 @@ public class Message extends AbstractEntity {
}
public Message(Conversation conversation, String body, int encryption, int status) {
- this(java.util.UUID.randomUUID().toString(), conversation.getUuid(),
- conversation.getContactJid().toBareJid(), null, body, System
- .currentTimeMillis(), encryption,
- status, TYPE_TEXT, null, null);
+ this(java.util.UUID.randomUUID().toString(),
+ conversation.getUuid(),
+ conversation.getContactJid() == null ? null : conversation.getContactJid().toBareJid(),
+ null,
+ body,
+ System.currentTimeMillis(),
+ encryption,
+ status,
+ TYPE_TEXT,
+ null,
+ null);
this.conversation = conversation;
}
- public Message(final String uuid, final String conversationUUid, final Jid counterpart,
+ private Message(final String uuid, final String conversationUUid, final Jid counterpart,
final Jid trueCounterpart, final String body, final long timeSent,
final int encryption, final int status, final int type, final String remoteMsgId, final String relativeFilePath) {
this.uuid = uuid;
diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
index 065b6ee4..c8706fc9 100644
--- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java
+++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
@@ -179,7 +179,7 @@ public class MucOptions {
user.setAffiliation(item.getAttribute("affiliation"));
user.setRole(item.getAttribute("role"));
user.setJid(item.getAttributeAsJid("jid"));
- if (codes.contains(STATUS_CODE_SELF_PRESENCE)) {
+ if (codes.contains(STATUS_CODE_SELF_PRESENCE) || packet.getFrom().equals(this.conversation.getContactJid())) {
this.isOnline = true;
this.error = ERROR_NO_ERROR;
self = user;
@@ -279,14 +279,13 @@ public class MucOptions {
public String getProposedNick() {
if (conversation.getBookmark() != null
- && conversation.getBookmark().getNick() != null) {
+ && conversation.getBookmark().getNick() != null
+ && !conversation.getBookmark().getNick().isEmpty()) {
return conversation.getBookmark().getNick();
+ } else if (!conversation.getContactJid().isBareJid()) {
+ return conversation.getContactJid().getResourcepart();
} else {
- if (!conversation.getContactJid().isBareJid()) {
- return conversation.getContactJid().getResourcepart();
- } else {
- return account.getUsername();
- }
+ return account.getUsername();
}
}
diff --git a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
index 419964ea..f46e7ba4 100644
--- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
@@ -20,7 +20,7 @@ public abstract class AbstractGenerator {
"http://jabber.org/protocol/disco#info",
"urn:xmpp:avatar:metadata+notify",
"urn:xmpp:ping"};
- public final String IDENTITY_NAME = "Conversations 0.9-alpha";
+ public final String IDENTITY_NAME = "Conversations 0.9.3";
public final String IDENTITY_TYPE = "phone";
protected XmppConnectionService mXmppConnectionService;
diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java
index b38cdc72..aeec56d0 100644
--- a/src/main/java/eu/siacs/conversations/parser/IqParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java
@@ -25,14 +25,11 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
}
for (Element item : query.getChildren()) {
if (item.getName().equals("item")) {
- Jid jid;
- try {
- jid = Jid.fromString(item.getAttribute("jid"));
- } catch (final InvalidJidException e) {
- // TODO: Handle this?
- jid = null;
- }
- String name = item.getAttribute("name");
+ final Jid jid = item.getAttributeAsJid("jid");
+ if (jid == null) {
+ break;
+ }
+ String name = item.getAttribute("name");
String subscription = item.getAttribute("subscription");
Contact contact = account.getRoster().getContact(jid);
if (!contact.getOption(Contact.Options.DIRTY_PUSH)) {
diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
index ce2103dc..782675da 100644
--- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
@@ -27,8 +27,10 @@ public class MessageParser extends AbstractParser implements
private Message parseChat(MessagePacket packet, Account account) {
final Jid jid = packet.getFrom();
- Conversation conversation = mXmppConnectionService
- .findOrCreateConversation(account, jid.toBareJid(), false);
+ if (jid == null) {
+ return null;
+ }
+ Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, jid.toBareJid(), false);
updateLastseen(packet, account, true);
String pgpBody = getPgpBody(packet);
Message finishedMessage;
@@ -61,6 +63,9 @@ public class MessageParser extends AbstractParser implements
boolean properlyAddressed = (!packet.getTo().isBareJid())
|| (account.countPresences() == 1);
final Jid from = packet.getFrom();
+ if (from == null) {
+ return null;
+ }
Conversation conversation = mXmppConnectionService
.findOrCreateConversation(account, from.toBareJid(), false);
String presence;
@@ -153,6 +158,14 @@ public class MessageParser extends AbstractParser implements
if (mXmppConnectionService.markMessage(conversation,
packet.getId(), Message.STATUS_SEND)) {
return null;
+ } else if (packet.getId() == null) {
+ Message message = conversation.findSentMessageWithBody(packet.getBody());
+ if (message != null) {
+ mXmppConnectionService.markMessage(message,Message.STATUS_SEND_RECEIVED);
+ return null;
+ } else {
+ status = Message.STATUS_SEND;
+ }
} else {
status = Message.STATUS_SEND;
}
@@ -319,12 +332,7 @@ public class MessageParser extends AbstractParser implements
}
} else if (packet.hasChild("x", "jabber:x:conference")) {
Element x = packet.findChild("x", "jabber:x:conference");
- Jid jid;
- try {
- jid = Jid.fromString(x.getAttribute("jid"));
- } catch (InvalidJidException e) {
- jid = null;
- }
+ Jid jid = x.getAttributeAsJid("jid");
String password = x.getAttribute("password");
if (jid != null) {
Conversation conversation = mXmppConnectionService
diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java
index 12167a1e..43c8fa8d 100644
--- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java
@@ -31,6 +31,8 @@ public class PresenceParser extends AbstractParser implements
mXmppConnectionService.getAvatarService().clear(conversation);
if (before != mucOptions.online() || (mucOptions.online() && count != mucOptions.getUsers().size())) {
mXmppConnectionService.updateConversationUi();
+ } else if (mucOptions.online()) {
+ mXmppConnectionService.updateMucRosterUi();
}
}
}
diff --git a/src/main/java/eu/siacs/conversations/services/AvatarService.java b/src/main/java/eu/siacs/conversations/services/AvatarService.java
index 1125859c..3ac4462d 100644
--- a/src/main/java/eu/siacs/conversations/services/AvatarService.java
+++ b/src/main/java/eu/siacs/conversations/services/AvatarService.java
@@ -113,7 +113,7 @@ public class AvatarService {
if (bitmap != null) {
return bitmap;
}
- List<MucOptions.User> users = mucOptions.getUsers();
+ final List<MucOptions.User> users = new ArrayList<>(mucOptions.getUsers());
int count = users.size();
bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
@@ -121,8 +121,8 @@ public class AvatarService {
if (count == 0) {
String name = mucOptions.getConversation().getName();
- String letter = name.substring(0, 1);
- int color = UIHelper.getColorForName(name);
+ final String letter = name.isEmpty() ? "X" : name.substring(0,1);
+ final int color = UIHelper.getColorForName(name);
drawTile(canvas, letter, color, 0, 0, size, size);
} else if (count == 1) {
drawTile(canvas, users.get(0), 0, 0, size, size);
@@ -212,15 +212,8 @@ public class AvatarService {
}
bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
- String letter;
- int color;
- if (name.length() > 0) {
- letter = name.substring(0, 1);
- color = UIHelper.getColorForName(name);
- } else {
- letter = "X";
- color = PLACEHOLDER_COLOR;
- }
+ final String letter = name.isEmpty() ? "X" : name.substring(0,1);
+ final int color = UIHelper.getColorForName(name);
drawTile(canvas, letter, color, 0, 0, size, size);
mXmppConnectionService.getBitmapCache().put(KEY, bitmap);
return bitmap;
@@ -275,15 +268,8 @@ public class AvatarService {
}
}
String name = contact != null ? contact.getDisplayName() : user.getName();
- String letter;
- int color;
- if (name.length() > 0) {
- letter = name.substring(0, 1);
- color = UIHelper.getColorForName(name);
- } else {
- letter = "X";
- color = PLACEHOLDER_COLOR;
- }
+ final String letter = name.isEmpty() ? "X" : name.substring(0,1);
+ final int color = UIHelper.getColorForName(name);
drawTile(canvas, letter, color, left, top, right, bottom);
}
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index 6958a062..41a40224 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -209,9 +209,11 @@ public class XmppConnectionService extends Service {
getNotificationService().updateErrorNotification();
}
};
- private Integer accountChangedListenerCount = 0;
+ private int accountChangedListenerCount = 0;
private OnRosterUpdate mOnRosterUpdate = null;
- private Integer rosterChangedListenerCount = 0;
+ private int rosterChangedListenerCount = 0;
+ private OnMucRosterUpdate mOnMucRosterUpdate = null;
+ private int mucRosterChangedListenerCount = 0;
private SecureRandom mRandom;
private FileObserver fileObserver = new FileObserver(
FileBackend.getConversationsImageDirectory()) {
@@ -781,7 +783,7 @@ public class XmppConnectionService extends Service {
@Override
public void onIqPacketReceived(final Account account,
- IqPacket packet) {
+ IqPacket packet) {
Element query = packet.findChild("query");
if (query != null) {
account.getRoster().markAllAsNotInRoster();
@@ -811,13 +813,11 @@ public class XmppConnectionService extends Service {
Conversation conversation = find(bookmark);
if (conversation != null) {
conversation.setBookmark(bookmark);
- } else {
- if (bookmark.autojoin()) {
- conversation = findOrCreateConversation(
- account, bookmark.getJid(), true);
- conversation.setBookmark(bookmark);
- joinMuc(conversation);
- }
+ } else if (bookmark.autojoin() && bookmark.getJid() != null) {
+ conversation = findOrCreateConversation(
+ account, bookmark.getJid(), true);
+ conversation.setBookmark(bookmark);
+ joinMuc(conversation);
}
}
}
@@ -978,6 +978,9 @@ public class XmppConnectionService extends Service {
public Conversation find(final List<Conversation> haystack,
final Account account,
final Jid jid) {
+ if (jid == null ) {
+ return null;
+ }
for (Conversation conversation : haystack) {
if ((account == null || conversation.getAccount() == account)
&& (conversation.getContactJid().toBareJid().equals(jid.toBareJid()))) {
@@ -1092,65 +1095,21 @@ public class XmppConnectionService extends Service {
}
}
- private void removeStaleListeners() {
- boolean removedListener = false;
- synchronized (this.convChangedListenerCount) {
- if (this.mOnConversationUpdate != null) {
- this.mOnConversationUpdate = null;
- this.convChangedListenerCount = 0;
- this.mNotificationService.setIsInForeground(false);
- removedListener = true;
- }
- }
- synchronized (this.accountChangedListenerCount) {
- if (this.mOnAccountUpdate != null) {
- this.mOnAccountUpdate = null;
- this.accountChangedListenerCount = 0;
- removedListener = true;
- }
- }
- synchronized (this.rosterChangedListenerCount) {
- if (this.mOnRosterUpdate != null) {
- this.mOnRosterUpdate = null;
- this.rosterChangedListenerCount = 0;
- removedListener = true;
- }
- }
- if (removedListener) {
- final String msg = "removed stale listeners";
- Log.d(Config.LOGTAG, msg);
- checkListeners();
- try {
- OutputStream os = openFileOutput("stacktrace.txt", MODE_PRIVATE);
- os.write(msg.getBytes());
- os.flush();
- os.close();
- } catch (final FileNotFoundException ignored) {
-
- } catch (final IOException ignored) {
- }
- }
- }
-
- public void setOnConversationListChangedListener(
- OnConversationUpdate listener) {
- /*if (!isScreenOn()) {
- Log.d(Config.LOGTAG,
- "ignoring setOnConversationListChangedListener");
- return;
- }*/
- synchronized (this.convChangedListenerCount) {
+ public void setOnConversationListChangedListener(OnConversationUpdate listener) {
+ synchronized (this) {
if (checkListeners()) {
switchToForeground();
}
this.mOnConversationUpdate = listener;
this.mNotificationService.setIsInForeground(true);
- this.convChangedListenerCount++;
- }
+ if (this.convChangedListenerCount < 2) {
+ this.convChangedListenerCount++;
}
+ }
+ }
public void removeOnConversationListChangedListener() {
- synchronized (this.convChangedListenerCount) {
+ synchronized (this) {
this.convChangedListenerCount--;
if (this.convChangedListenerCount <= 0) {
this.convChangedListenerCount = 0;
@@ -1164,21 +1123,19 @@ public class XmppConnectionService extends Service {
}
public void setOnAccountListChangedListener(OnAccountUpdate listener) {
- /*if (!isScreenOn()) {
- Log.d(Config.LOGTAG, "ignoring setOnAccountListChangedListener");
- return;
- }*/
- synchronized (this.accountChangedListenerCount) {
+ synchronized (this) {
if (checkListeners()) {
switchToForeground();
}
this.mOnAccountUpdate = listener;
- this.accountChangedListenerCount++;
+ if (this.accountChangedListenerCount < 2) {
+ this.accountChangedListenerCount++;
+ }
}
}
public void removeOnAccountListChangedListener() {
- synchronized (this.accountChangedListenerCount) {
+ synchronized (this) {
this.accountChangedListenerCount--;
if (this.accountChangedListenerCount <= 0) {
this.mOnAccountUpdate = null;
@@ -1191,21 +1148,19 @@ public class XmppConnectionService extends Service {
}
public void setOnRosterUpdateListener(OnRosterUpdate listener) {
- /*if (!isScreenOn()) {
- Log.d(Config.LOGTAG, "ignoring setOnRosterUpdateListener");
- return;
- }*/
- synchronized (this.rosterChangedListenerCount) {
+ synchronized (this) {
if (checkListeners()) {
switchToForeground();
}
this.mOnRosterUpdate = listener;
- this.rosterChangedListenerCount++;
+ if (this.rosterChangedListenerCount < 2) {
+ this.rosterChangedListenerCount++;
+ }
}
}
public void removeOnRosterUpdateListener() {
- synchronized (this.rosterChangedListenerCount) {
+ synchronized (this) {
this.rosterChangedListenerCount--;
if (this.rosterChangedListenerCount <= 0) {
this.rosterChangedListenerCount = 0;
@@ -1217,6 +1172,31 @@ public class XmppConnectionService extends Service {
}
}
+ public void setOnMucRosterUpdateListener(OnMucRosterUpdate listener) {
+ synchronized (this) {
+ if (checkListeners()) {
+ switchToForeground();
+ }
+ this.mOnMucRosterUpdate = listener;
+ if (this.mucRosterChangedListenerCount < 2) {
+ this.mucRosterChangedListenerCount++;
+ }
+ }
+ }
+
+ public void removeOnMucRosterUpdateListener() {
+ synchronized (this) {
+ this.mucRosterChangedListenerCount--;
+ if (this.mucRosterChangedListenerCount <= 0) {
+ this.mucRosterChangedListenerCount = 0;
+ this.mOnMucRosterUpdate = null;
+ if (checkListeners()) {
+ switchToBackground();
+ }
+ }
+ }
+ }
+
private boolean checkListeners() {
return (this.mOnAccountUpdate == null
&& this.mOnConversationUpdate == null && this.mOnRosterUpdate == null);
@@ -1247,12 +1227,6 @@ public class XmppConnectionService extends Service {
Log.d(Config.LOGTAG, "app switched into background");
}
- private boolean isScreenOn() {
- PowerManager pm = (PowerManager) this
- .getSystemService(Context.POWER_SERVICE);
- return pm.isScreenOn();
- }
-
public void connectMultiModeConversations(Account account) {
List<Conversation> conversations = getConversations();
for (Conversation conversation : conversations) {
@@ -1268,10 +1242,12 @@ public class XmppConnectionService extends Service {
account.pendingConferenceJoins.remove(conversation);
account.pendingConferenceLeaves.remove(conversation);
if (account.getStatus() == Account.State.ONLINE) {
- Log.d(Config.LOGTAG,
- "joining conversation " + conversation.getContactJid());
- String nick = conversation.getMucOptions().getProposedNick();
- Jid joinJid = conversation.getMucOptions().createJoinJid(nick);
+ final String nick = conversation.getMucOptions().getProposedNick();
+ final Jid joinJid = conversation.getMucOptions().createJoinJid(nick);
+ if (joinJid == null) {
+ return; //safety net
+ }
+ Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": joining conversation " + joinJid.toString());
PresencePacket packet = new PresencePacket();
packet.setFrom(conversation.getAccount().getJid());
packet.setTo(joinJid);
@@ -1703,7 +1679,7 @@ public class XmppConnectionService extends Service {
@Override
public void onIqPacketReceived(Account account, IqPacket result) {
final String ERROR = account.getJid().toBareJid()
- + ": fetching avatar for " + avatar.owner + " failed ";
+ + ": fetching avatar for " + avatar.owner + " failed ";
if (result.getType() == IqPacket.TYPE_RESULT) {
avatar.image = mIqParser.avatarData(result);
if (avatar.image != null) {
@@ -1717,7 +1693,7 @@ public class XmppConnectionService extends Service {
updateAccountUi();
} else {
Contact contact = account.getRoster()
- .getContact(avatar.owner);
+ .getContact(avatar.owner);
contact.setAvatar(avatar.getFilename());
getAvatarService().clear(contact);
updateConversationUi();
@@ -1928,6 +1904,12 @@ public class XmppConnectionService extends Service {
}
}
+ public void updateMucRosterUi() {
+ if (mOnMucRosterUpdate != null) {
+ mOnMucRosterUpdate.onMucRosterUpdate();
+ }
+ }
+
public Account findAccountByJid(final Jid accountJid) {
for (Account account : this.accounts) {
if (account.getJid().toBareJid().equals(accountJid.toBareJid())) {
@@ -2125,6 +2107,10 @@ public class XmppConnectionService extends Service {
public void onRosterUpdate();
}
+ public interface OnMucRosterUpdate {
+ public void onMucRosterUpdate();
+ }
+
private interface OnConferenceOptionsPushed {
public void onPushSucceeded();
public void onPushFailed();
diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
index 290842fb..2e36c545 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
@@ -27,13 +27,16 @@ import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
+import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.MucOptions.User;
+import eu.siacs.conversations.services.XmppConnectionService.OnMucRosterUpdate;
import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
-public class ConferenceDetailsActivity extends XmppActivity implements OnConversationUpdate {
+public class ConferenceDetailsActivity extends XmppActivity implements OnConversationUpdate, OnMucRosterUpdate {
public static final String ACTION_VIEW_MUC = "view_muc";
private Conversation mConversation;
private OnClickListener inviteListener = new OnClickListener() {
@@ -97,6 +100,17 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
}
@Override
+ public void onMucRosterUpdate() {
+ runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ populateView();
+ }
+ });
+ }
+
+ @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_muc_details);
@@ -110,8 +124,10 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
mMoreDetails.setVisibility(View.GONE);
mInviteButton = (Button) findViewById(R.id.invite);
mInviteButton.setOnClickListener(inviteListener);
- getActionBar().setHomeButtonEnabled(true);
- getActionBar().setDisplayHomeAsUpEnabled(true);
+ if (getActionBar() != null) {
+ getActionBar().setHomeButtonEnabled(true);
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+ }
mEditNickButton.setOnClickListener(new OnClickListener() {
@Override
@@ -149,6 +165,12 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
});
}
break;
+ case R.id.action_save_as_bookmark:
+ saveAsBookmark();
+ break;
+ case R.id.action_delete_bookmark:
+ deleteBookmark();
+ break;
}
return super.onOptionsItemSelected(menuItem);
}
@@ -176,6 +198,21 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
}
@Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuItem menuItemSaveBookmark = menu.findItem(R.id.action_save_as_bookmark);
+ MenuItem menuItemDeleteBookmark = menu.findItem(R.id.action_delete_bookmark);
+ Account account = mConversation.getAccount();
+ if (account.hasBookmarkFor(mConversation.getContactJid().toBareJid())) {
+ menuItemSaveBookmark.setVisible(false);
+ menuItemDeleteBookmark.setVisible(true);
+ } else {
+ menuItemDeleteBookmark.setVisible(false);
+ menuItemSaveBookmark.setVisible(true);
+ }
+ return true;
+ }
+
+ @Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.muc_details, menu);
return true;
@@ -219,11 +256,31 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
protected void startConversation(User user) {
if (user.getJid() != null) {
- Conversation conversation = xmppConnectionService.findOrCreateConversation(this.mConversation.getAccount(),user.getJid(),false);
+ Conversation conversation = xmppConnectionService.findOrCreateConversation(this.mConversation.getAccount(),user.getJid().toBareJid(),false);
switchToConversation(conversation);
}
}
+ protected void saveAsBookmark() {
+ Account account = mConversation.getAccount();
+ Bookmark bookmark = new Bookmark(account, mConversation.getContactJid().toBareJid());
+ if (!mConversation.getContactJid().isBareJid()) {
+ bookmark.setNick(mConversation.getContactJid().getResourcepart());
+ }
+ bookmark.setAutojoin(true);
+ account.getBookmarks().add(bookmark);
+ xmppConnectionService.pushBookmarks(account);
+ mConversation.setBookmark(bookmark);
+ }
+
+ protected void deleteBookmark() {
+ Account account = mConversation.getAccount();
+ Bookmark bookmark = mConversation.getBookmark();
+ bookmark.unregisterConversation();
+ account.getBookmarks().remove(bookmark);
+ xmppConnectionService.pushBookmarks(account);
+ }
+
@Override
void onBackendConnected() {
if (getIntent().getAction().equals(ACTION_VIEW_MUC)) {
@@ -313,6 +370,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
}
}
+ @SuppressWarnings("deprecation")
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void setListItemBackgroundOnView(View view) {
int sdk = android.os.Build.VERSION.SDK_INT;
@@ -332,7 +390,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
try {
startIntentSenderForResult(intent.getIntentSender(), 0,
null, 0, 0, 0);
- } catch (SendIntentException e) {
+ } catch (SendIntentException ignored) {
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
index 0277f155..5b0fa562 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
@@ -235,15 +235,16 @@ public class ConversationActivity extends XmppActivity implements
}
private void updateActionBarTitle(boolean titleShouldBeName) {
- ActionBar ab = getActionBar();
+ final ActionBar ab = getActionBar();
+ final Conversation conversation = getSelectedConversation();
if (ab != null) {
- if (titleShouldBeName) {
+ if (titleShouldBeName && conversation != null) {
ab.setDisplayHomeAsUpEnabled(true);
ab.setHomeButtonEnabled(true);
- if (getSelectedConversation().getMode() == Conversation.MODE_SINGLE || useSubjectToIdentifyConference()) {
- ab.setTitle(getSelectedConversation().getName());
+ if (conversation.getMode() == Conversation.MODE_SINGLE || useSubjectToIdentifyConference()) {
+ ab.setTitle(conversation.getName());
} else {
- ab.setTitle(getSelectedConversation().getContactJid().toBareJid().toString());
+ ab.setTitle(conversation.getContactJid().toBareJid().toString());
}
} else {
ab.setDisplayHomeAsUpEnabled(false);
@@ -770,12 +771,8 @@ public class ConversationActivity extends XmppActivity implements
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == REQUEST_DECRYPT_PGP) {
- ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager()
- .findFragmentByTag("conversation");
- if (selectedFragment != null) {
- selectedFragment.hideSnackbar();
- selectedFragment.updateMessages();
- }
+ mConversationFragment.hideSnackbar();
+ mConversationFragment.updateMessages();
} else if (requestCode == REQUEST_ATTACH_IMAGE_DIALOG) {
mPendingImageUri = data.getData();
if (xmppConnectionServiceBound) {
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
index 287d1636..0edc6b6f 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
@@ -35,6 +35,7 @@ import net.java.otr4j.session.SessionStatus;
import java.util.ArrayList;
import java.util.List;
+import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentLinkedQueue;
import eu.siacs.conversations.R;
@@ -503,6 +504,8 @@ public class ConversationFragment extends Fragment {
}
this.activity = (ConversationActivity) getActivity();
this.conversation = conversation;
+ this.mDecryptJobRunning = false;
+ this.mEncryptedMessages.clear();
if (this.conversation.getMode() == Conversation.MODE_MULTI) {
this.conversation.setNextCounterpart(null);
}
@@ -577,23 +580,23 @@ public class ConversationFragment extends Fragment {
break;
}
}
- for (Message message : this.conversation.getMessages()) {
- if (message.getEncryption() == Message.ENCRYPTION_PGP
- && (message.getStatus() == Message.STATUS_RECEIVED || message
- .getStatus() >= Message.STATUS_SEND)
- && message.getDownloadable() == null) {
- if (!mEncryptedMessages.contains(message)) {
- mEncryptedMessages.add(message);
- }
- }
- }
- decryptNext();
this.messageList.clear();
if (this.conversation.getMessages().size() == 0) {
messagesLoaded = false;
} else {
this.messageList.addAll(this.conversation.getMessages());
messagesLoaded = true;
+ for (Message message : this.messageList) {
+ if (message.getEncryption() == Message.ENCRYPTION_PGP
+ && (message.getStatus() == Message.STATUS_RECEIVED || message
+ .getStatus() >= Message.STATUS_SEND)
+ && message.getDownloadable() == null) {
+ if (!mEncryptedMessages.contains(message)) {
+ mEncryptedMessages.add(message);
+ }
+ }
+ }
+ decryptNext();
updateStatusMessages();
}
this.messageListAdapter.notifyDataSetChanged();
@@ -626,7 +629,11 @@ public class ConversationFragment extends Fragment {
@Override
public void success(Message message) {
mDecryptJobRunning = false;
- mEncryptedMessages.remove();
+ try {
+ mEncryptedMessages.remove();
+ } catch (final NoSuchElementException ignored) {
+
+ }
activity.xmppConnectionService.updateMessage(message);
}
@@ -634,7 +641,11 @@ public class ConversationFragment extends Fragment {
public void error(int error, Message message) {
message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
mDecryptJobRunning = false;
- mEncryptedMessages.remove();
+ try {
+ mEncryptedMessages.remove();
+ } catch (final NoSuchElementException ignored) {
+
+ }
activity.xmppConnectionService.updateConversationUi();
}
});
diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
index 22507483..8fad66cf 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -74,14 +74,15 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
return;
}
boolean registerNewAccount = mRegisterNew.isChecked();
- final Jid jid;
- try {
- jid = Jid.fromString(mAccountJid.getText().toString());
- } catch (final InvalidJidException e) {
- // TODO: Handle this error?
- return;
- }
- String password = mPassword.getText().toString();
+ final Jid jid;
+ try {
+ jid = Jid.fromString(mAccountJid.getText().toString());
+ } catch (final InvalidJidException e) {
+ mAccountJid.setError(getString(R.string.invalid_jid));
+ mAccountJid.requestFocus();
+ return;
+ }
+ String password = mPassword.getText().toString();
String passwordConfirm = mPasswordConfirm.getText().toString();
if (registerNewAccount) {
if (!password.equals(passwordConfirm)) {
diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/SettingsFragment.java
index 7e1c3698..e4185abc 100644
--- a/src/main/java/eu/siacs/conversations/ui/SettingsFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/SettingsFragment.java
@@ -1,10 +1,51 @@
package eu.siacs.conversations.ui;
-import eu.siacs.conversations.R;
+import android.app.Dialog;
import android.os.Bundle;
+import android.preference.Preference;
import android.preference.PreferenceFragment;
+import android.preference.PreferenceScreen;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+import eu.siacs.conversations.R;
public class SettingsFragment extends PreferenceFragment {
+
+ //http://stackoverflow.com/questions/16374820/action-bar-home-button-not-functional-with-nested-preferencescreen/16800527#16800527
+ private void initializeActionBar(PreferenceScreen preferenceScreen) {
+ final Dialog dialog = preferenceScreen.getDialog();
+
+ if (dialog != null) {
+ View homeBtn = dialog.findViewById(android.R.id.home);
+
+ if (homeBtn != null) {
+ View.OnClickListener dismissDialogClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ dialog.dismiss();
+ }
+ };
+
+ ViewParent homeBtnContainer = homeBtn.getParent();
+
+ if (homeBtnContainer instanceof FrameLayout) {
+ ViewGroup containerParent = (ViewGroup) homeBtnContainer.getParent();
+ if (containerParent instanceof LinearLayout) {
+ ((LinearLayout) containerParent).setOnClickListener(dismissDialogClickListener);
+ } else {
+ ((FrameLayout) homeBtnContainer).setOnClickListener(dismissDialogClickListener);
+ }
+ } else {
+ homeBtn.setOnClickListener(dismissDialogClickListener);
+ }
+ }
+ }
+ }
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -12,4 +53,13 @@ public class SettingsFragment extends PreferenceFragment {
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
}
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ super.onPreferenceTreeClick(preferenceScreen, preference);
+ if (preference instanceof PreferenceScreen) {
+ initializeActionBar((PreferenceScreen) preference);
+ }
+ return false;
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
index ddc57c2e..5fba1664 100644
--- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
@@ -241,6 +241,9 @@ public abstract class XmppActivity extends Activity {
if (this instanceof XmppConnectionService.OnRosterUpdate) {
this.xmppConnectionService.setOnRosterUpdateListener((XmppConnectionService.OnRosterUpdate) this);
}
+ if (this instanceof XmppConnectionService.OnMucRosterUpdate) {
+ this.xmppConnectionService.setOnMucRosterUpdateListener((XmppConnectionService.OnMucRosterUpdate) this);
+ }
}
protected void unregisterListeners() {
@@ -253,6 +256,9 @@ public abstract class XmppActivity extends Activity {
if (this instanceof XmppConnectionService.OnRosterUpdate) {
this.xmppConnectionService.removeOnRosterUpdateListener();
}
+ if (this instanceof XmppConnectionService.OnMucRosterUpdate) {
+ this.xmppConnectionService.removeOnMucRosterUpdateListener();
+ }
}
public boolean onOptionsItemSelected(MenuItem item) {
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
index b81544e6..f728e800 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
@@ -2,7 +2,6 @@ package eu.siacs.conversations.ui.adapter;
import java.util.List;
-import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Downloadable;
@@ -139,10 +138,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
} else {
if ((message.getEncryption() != Message.ENCRYPTION_PGP)
&& (message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED)) {
- String body = Config.PARSE_EMOTICONS ? UIHelper
- .transformAsciiEmoticons(message.getBody()) : message
- .getBody();
- mLastMessage.setText(body);
+ mLastMessage.setText(message.getBody());
} else {
mLastMessage.setText(R.string.encrypted_message_received);
}
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java
index 143dfda1..0993735f 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java
@@ -60,11 +60,8 @@ public class KnownHostsAdapter extends ArrayAdapter<String> {
public KnownHostsAdapter(Context context, int viewResourceId,
List<String> mKnownHosts) {
- super(context, viewResourceId, mKnownHosts);
- domains = new ArrayList<String>(mKnownHosts.size());
- for (String domain : mKnownHosts) {
- domains.add(new String(domain));
- }
+ super(context, viewResourceId, new ArrayList<String>());
+ domains = new ArrayList<String>(mKnownHosts);
}
@Override
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
index 250a69c3..0865d1aa 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
@@ -5,6 +5,8 @@ import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.ListItem;
import eu.siacs.conversations.ui.XmppActivity;
+import eu.siacs.conversations.xmpp.jid.Jid;
+
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
@@ -36,8 +38,8 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
if (view == null) {
view = inflater.inflate(R.layout.contact, parent, false);
}
- TextView name = (TextView) view.findViewById(R.id.contact_display_name);
- TextView jid = (TextView) view.findViewById(R.id.contact_jid);
+ TextView tvName = (TextView) view.findViewById(R.id.contact_display_name);
+ TextView tvJid = (TextView) view.findViewById(R.id.contact_jid);
ImageView picture = (ImageView) view.findViewById(R.id.contact_photo);
LinearLayout tagLayout = (LinearLayout) view.findViewById(R.id.tags);
@@ -54,9 +56,13 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
tagLayout.addView(tv);
}
}
-
- jid.setText(item.getJid().toString());
- name.setText(item.getDisplayName());
+ final Jid jid = item.getJid();
+ if (jid != null) {
+ tvJid.setText(jid.toString());
+ } else {
+ tvJid.setText("");
+ }
+ tvName.setText(item.getDisplayName());
picture.setImageBitmap(activity.avatarService().get(item,
activity.getPixel(48)));
return view;
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
index e14af11f..32062699 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
@@ -23,8 +23,8 @@ import android.widget.Toast;
import java.util.List;
-import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Downloadable;
@@ -224,10 +224,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder.messageBody.setVisibility(View.VISIBLE);
if (message.getBody() != null) {
if (message.getType() != Message.TYPE_PRIVATE) {
- String body = Config.PARSE_EMOTICONS ? UIHelper
- .transformAsciiEmoticons(message.getMergedBody())
- : message.getMergedBody();
- viewHolder.messageBody.setText(body);
+ viewHolder.messageBody.setText(message.getMergedBody());
} else {
String privateMarker;
if (message.getStatus() <= Message.STATUS_RECEIVED) {
@@ -339,8 +336,10 @@ public class MessageAdapter extends ArrayAdapter<Message> {
@Override
public View getView(int position, View view, ViewGroup parent) {
- final Message item = getItem(position);
- int type = getItemViewType(position);
+ final Message message = getItem(position);
+ final Conversation conversation = message.getConversation();
+ final Account account = conversation.getAccount();
+ final int type = getItemViewType(position);
ViewHolder viewHolder;
if (view == null) {
viewHolder = new ViewHolder();
@@ -368,7 +367,6 @@ public class MessageAdapter extends ArrayAdapter<Message> {
.findViewById(R.id.message_time);
viewHolder.indicatorReceived = (ImageView) view
.findViewById(R.id.indicator_received);
- view.setTag(viewHolder);
break;
case RECEIVED:
view = activity.getLayoutInflater().inflate(
@@ -389,28 +387,29 @@ public class MessageAdapter extends ArrayAdapter<Message> {
.findViewById(R.id.message_time);
viewHolder.indicatorReceived = (ImageView) view
.findViewById(R.id.indicator_received);
- view.setTag(viewHolder);
break;
case STATUS:
view = activity.getLayoutInflater().inflate(
R.layout.message_status, parent, false);
viewHolder.contact_picture = (ImageView) view
.findViewById(R.id.message_photo);
- view.setTag(viewHolder);
break;
default:
viewHolder = null;
break;
}
+ view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
+ if (viewHolder == null) {
+ return view;
+ }
}
if (type == STATUS) {
- if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
+ if (conversation.getMode() == Conversation.MODE_SINGLE) {
viewHolder.contact_picture.setImageBitmap(activity
- .avatarService().get(
- item.getConversation().getContact(),
+ .avatarService().get(conversation.getContact(),
activity.getPixel(32)));
viewHolder.contact_picture.setAlpha(0.5f);
viewHolder.contact_picture
@@ -418,8 +417,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
@Override
public void onClick(View v) {
- String name = item.getConversation()
- .getName();
+ String name = conversation.getName();
String read = getContext()
.getString(
R.string.contact_has_read_up_to_this_point,
@@ -441,15 +439,15 @@ public class MessageAdapter extends ArrayAdapter<Message> {
view.setLayoutParams(view.getLayoutParams());
return view;
} else if (type == RECEIVED) {
- Contact contact = item.getContact();
+ Contact contact = message.getContact();
if (contact != null) {
viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(contact, activity.getPixel(48)));
- } else if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
- viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(getDisplayedMucCounterpart(item.getCounterpart()),
+ } else if (conversation.getMode() == Conversation.MODE_MULTI) {
+ viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(getDisplayedMucCounterpart(message.getCounterpart()),
activity.getPixel(48)));
}
- } else if (type == SENT) {
- viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(item.getConversation().getAccount(), activity.getPixel(48)));
+ } else if (type == SENT && viewHolder.contact_picture != null) {
+ viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(account, activity.getPixel(48)));
}
if (viewHolder != null && viewHolder.contact_picture != null) {
@@ -460,7 +458,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
public void onClick(View v) {
if (MessageAdapter.this.mOnContactPictureClickedListener != null) {
MessageAdapter.this.mOnContactPictureClickedListener
- .onContactPictureClicked(item);
+ .onContactPictureClicked(message);
}
}
@@ -472,7 +470,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
public boolean onLongClick(View v) {
if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) {
MessageAdapter.this.mOnContactPictureLongClickedListener
- .onContactPictureLongClicked(item);
+ .onContactPictureLongClicked(message);
return true;
} else {
return false;
@@ -481,10 +479,10 @@ public class MessageAdapter extends ArrayAdapter<Message> {
});
}
- if (item.getDownloadable() != null && item.getDownloadable().getStatus() != Downloadable.STATUS_UPLOADING) {
- Downloadable d = item.getDownloadable();
+ if (message.getDownloadable() != null && message.getDownloadable().getStatus() != Downloadable.STATUS_UPLOADING) {
+ Downloadable d = message.getDownloadable();
if (d.getStatus() == Downloadable.STATUS_DOWNLOADING) {
- if (item.getType() == Message.TYPE_FILE) {
+ if (message.getType() == Message.TYPE_FILE) {
displayInfoMessage(viewHolder,activity.getString(R.string.receiving_file,d.getMimeType(),d.getProgress()));
} else {
displayInfoMessage(viewHolder,activity.getString(R.string.receiving_image,d.getProgress()));
@@ -492,35 +490,35 @@ public class MessageAdapter extends ArrayAdapter<Message> {
} else if (d.getStatus() == Downloadable.STATUS_CHECKING) {
displayInfoMessage(viewHolder,activity.getString(R.string.checking_image));
} else if (d.getStatus() == Downloadable.STATUS_DELETED) {
- if (item.getType() == Message.TYPE_FILE) {
+ if (message.getType() == Message.TYPE_FILE) {
displayInfoMessage(viewHolder, activity.getString(R.string.file_deleted));
} else {
displayInfoMessage(viewHolder, activity.getString(R.string.image_file_deleted));
}
} else if (d.getStatus() == Downloadable.STATUS_OFFER) {
- if (item.getType() == Message.TYPE_FILE) {
- displayDownloadableMessage(viewHolder,item,activity.getString(R.string.download_file,d.getMimeType()));
+ if (message.getType() == Message.TYPE_FILE) {
+ displayDownloadableMessage(viewHolder,message,activity.getString(R.string.download_file,d.getMimeType()));
} else {
- displayDownloadableMessage(viewHolder, item,activity.getString(R.string.download_image));
+ displayDownloadableMessage(viewHolder, message,activity.getString(R.string.download_image));
}
} else if (d.getStatus() == Downloadable.STATUS_OFFER_CHECK_FILESIZE) {
- displayDownloadableMessage(viewHolder, item,activity.getString(R.string.check_image_filesize));
+ displayDownloadableMessage(viewHolder, message,activity.getString(R.string.check_image_filesize));
} else if (d.getStatus() == Downloadable.STATUS_FAILED) {
- if (item.getType() == Message.TYPE_FILE) {
+ if (message.getType() == Message.TYPE_FILE) {
displayInfoMessage(viewHolder, activity.getString(R.string.file_transmission_failed));
} else {
displayInfoMessage(viewHolder, activity.getString(R.string.image_transmission_failed));
}
}
- } else if (item.getType() == Message.TYPE_IMAGE && item.getEncryption() != Message.ENCRYPTION_PGP && item.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) {
- displayImageMessage(viewHolder, item);
- } else if (item.getType() == Message.TYPE_FILE && item.getEncryption() != Message.ENCRYPTION_PGP && item.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) {
- if (item.getImageParams().width > 0) {
- displayImageMessage(viewHolder,item);
+ } else if (message.getType() == Message.TYPE_IMAGE && message.getEncryption() != Message.ENCRYPTION_PGP && message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) {
+ displayImageMessage(viewHolder, message);
+ } else if (message.getType() == Message.TYPE_FILE && message.getEncryption() != Message.ENCRYPTION_PGP && message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) {
+ if (message.getImageParams().width > 0) {
+ displayImageMessage(viewHolder,message);
} else {
- displayOpenableMessage(viewHolder, item);
+ displayOpenableMessage(viewHolder, message);
}
- } else if (item.getEncryption() == Message.ENCRYPTION_PGP) {
+ } else if (message.getEncryption() == Message.ENCRYPTION_PGP) {
if (activity.hasPgp()) {
displayInfoMessage(viewHolder,activity.getString(R.string.encrypted_message));
} else {
@@ -537,13 +535,13 @@ public class MessageAdapter extends ArrayAdapter<Message> {
});
}
}
- } else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
+ } else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
displayDecryptionFailed(viewHolder);
} else {
- displayTextMessage(viewHolder, item);
+ displayTextMessage(viewHolder, message);
}
- displayStatus(viewHolder, item);
+ displayStatus(viewHolder, message);
return view;
}
diff --git a/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java b/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java
index 5becc7e7..87973159 100644
--- a/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java
@@ -64,6 +64,7 @@ public class PhoneHelper {
if (listener != null) {
listener.onPhoneContactsLoaded(phoneContacts);
}
+ cursor.close();
}
});
try {
@@ -85,6 +86,7 @@ public class PhoneHelper {
} else {
mProfileCursor.moveToFirst();
String uri = mProfileCursor.getString(1);
+ mProfileCursor.close();
if (uri == null) {
return null;
} else {
diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java
index 341b3d77..2f1383b8 100644
--- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java
@@ -2,7 +2,6 @@ package eu.siacs.conversations.utils;
import java.util.Calendar;
import java.util.Date;
-import java.util.regex.Pattern;
import eu.siacs.conversations.R;
import android.content.Context;
@@ -86,48 +85,10 @@ public class UIHelper {
}
}
- private final static class EmoticonPattern {
- Pattern pattern;
- String replacement;
-
- EmoticonPattern(String ascii, int unicode) {
- this.pattern = Pattern.compile("(?<=(^|\\s))" + ascii
- + "(?=(\\s|$))");
- this.replacement = new String(new int[] { unicode, }, 0, 1);
- }
-
- String replaceAll(String body) {
- return pattern.matcher(body).replaceAll(replacement);
- }
- }
-
- private static final EmoticonPattern[] patterns = new EmoticonPattern[] {
- new EmoticonPattern(":-?D", 0x1f600),
- new EmoticonPattern("\\^\\^", 0x1f601),
- new EmoticonPattern(":'D", 0x1f602),
- new EmoticonPattern("\\]-?D", 0x1f608),
- new EmoticonPattern(";-?\\)", 0x1f609),
- new EmoticonPattern(":-?\\)", 0x1f60a),
- new EmoticonPattern("[B8]-?\\)", 0x1f60e),
- new EmoticonPattern(":-?\\|", 0x1f610),
- new EmoticonPattern(":-?[/\\\\]", 0x1f615),
- new EmoticonPattern(":-?\\*", 0x1f617),
- new EmoticonPattern(":-?[Ppb]", 0x1f61b),
- new EmoticonPattern(":-?\\(", 0x1f61e),
- new EmoticonPattern(":-?[0Oo]", 0x1f62e),
- new EmoticonPattern("\\\\o/", 0x1F631), };
-
- public static String transformAsciiEmoticons(String body) {
- if (body != null) {
- for (EmoticonPattern p : patterns) {
- body = p.replaceAll(body);
- }
- body = body.trim();
- }
- return body;
- }
-
public static int getColorForName(String name) {
+ if (name.isEmpty()) {
+ return 0xFF202020;
+ }
int colors[] = {0xFFe91e63, 0xFF9c27b0, 0xFF673ab7, 0xFF3f51b5,
0xFF5677fc, 0xFF03a9f4, 0xFF00bcd4, 0xFF009688, 0xFFff5722,
0xFF795548, 0xFF607d8b};
diff --git a/src/main/java/eu/siacs/conversations/utils/zlib/ZLibInputStream.java b/src/main/java/eu/siacs/conversations/utils/zlib/ZLibInputStream.java
deleted file mode 100644
index b777c10c..00000000
--- a/src/main/java/eu/siacs/conversations/utils/zlib/ZLibInputStream.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package eu.siacs.conversations.utils.zlib;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.zip.Inflater;
-import java.util.zip.InflaterInputStream;
-
-/**
- * ZLibInputStream is a zlib and input stream compatible version of an
- * InflaterInputStream. This class solves the incompatibility between
- * {@link InputStream#available()} and {@link InflaterInputStream#available()}.
- */
-public class ZLibInputStream extends InflaterInputStream {
-
- /**
- * Construct a ZLibInputStream, reading data from the underlying stream.
- *
- * @param is
- * The {@code InputStream} to read data from.
- * @throws IOException
- * If an {@code IOException} occurs.
- */
- public ZLibInputStream(InputStream is) throws IOException {
- super(is, new Inflater(), 512);
- }
-
- /**
- * Provide a more InputStream compatible version of available. A return
- * value of 1 means that it is likly to read one byte without blocking, 0
- * means that the system is known to block for more input.
- *
- * @return 0 if no data is available, 1 otherwise
- * @throws IOException
- */
- @Override
- public int available() throws IOException {
- /*
- * This is one of the funny code blocks. InflaterInputStream.available
- * violates the contract of InputStream.available, which breaks kXML2.
- *
- * I'm not sure who's to blame, oracle/sun for a broken api or the
- * google guys for mixing a sun bug with a xml reader that can't handle
- * it....
- *
- * Anyway, this simple if breaks suns distorted reality, but helps to
- * use the api as intended.
- */
- if (inf.needsInput()) {
- return 0;
- }
- return super.available();
- }
-
-}
diff --git a/src/main/java/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java b/src/main/java/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java
deleted file mode 100644
index 8b3f5e68..00000000
--- a/src/main/java/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package eu.siacs.conversations.utils.zlib;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.security.NoSuchAlgorithmException;
-import java.util.zip.Deflater;
-import java.util.zip.DeflaterOutputStream;
-
-/**
- * <p>
- * Android 2.2 includes Java7 FLUSH_SYNC option, which will be used by this
- * Implementation, preferable via reflection. The @hide was remove in API level
- * 19. This class might thus go away in the future.
- * </p>
- * <p>
- * Please use {@link ZLibOutputStream#SUPPORTED} to check for flush
- * compatibility.
- * </p>
- */
-public class ZLibOutputStream extends DeflaterOutputStream {
-
- /**
- * The reflection based flush method.
- */
-
- private final static Method method;
- /**
- * SUPPORTED is true if a flush compatible method exists.
- */
- public final static boolean SUPPORTED;
-
- /**
- * Static block to initialize {@link #SUPPORTED} and {@link #method}.
- */
- static {
- Method m = null;
- try {
- m = Deflater.class.getMethod("deflate", byte[].class, int.class,
- int.class, int.class);
- } catch (SecurityException e) {
- } catch (NoSuchMethodException e) {
- }
- method = m;
- SUPPORTED = (method != null);
- }
-
- /**
- * Create a new ZLib compatible output stream wrapping the given low level
- * stream. ZLib compatiblity means we will send a zlib header.
- *
- * @param os
- * OutputStream The underlying stream.
- * @throws IOException
- * In case of a lowlevel transfer problem.
- * @throws NoSuchAlgorithmException
- * In case of a {@link Deflater} error.
- */
- public ZLibOutputStream(OutputStream os) throws IOException,
- NoSuchAlgorithmException {
- super(os, new Deflater(Deflater.BEST_COMPRESSION));
- }
-
- /**
- * Flush the given stream, preferring Java7 FLUSH_SYNC if available.
- *
- * @throws IOException
- * In case of a lowlevel exception.
- */
- @Override
- public void flush() throws IOException {
- if (!SUPPORTED) {
- super.flush();
- return;
- }
- try {
- int count = 0;
- do {
- count = (Integer) method.invoke(def, buf, 0, buf.length, 3);
- if (count > 0) {
- out.write(buf, 0, count);
- }
- } while (count > 0);
- } catch (IllegalArgumentException e) {
- throw new IOException("Can't flush");
- } catch (IllegalAccessException e) {
- throw new IOException("Can't flush");
- } catch (InvocationTargetException e) {
- throw new IOException("Can't flush");
- }
- super.flush();
- }
-
-}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
index 2f5994c4..adb96fa2 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -50,8 +50,6 @@ import eu.siacs.conversations.crypto.sasl.ScramSha1;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.DNSHelper;
-import eu.siacs.conversations.utils.zlib.ZLibInputStream;
-import eu.siacs.conversations.utils.zlib.ZLibOutputStream;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Tag;
import eu.siacs.conversations.xml.TagWriter;
@@ -92,7 +90,6 @@ public class XmppConnection implements Runnable {
private int smVersion = 3;
private SparseArray<String> messageReceipts = new SparseArray<>();
- private boolean enabledCompression = false;
private boolean enabledEncryption = false;
private boolean enabledCarbons = false;
@@ -144,7 +141,6 @@ public class XmppConnection implements Runnable {
protected void connect() {
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": connecting");
- enabledCompression = false;
enabledEncryption = false;
lastConnect = SystemClock.elapsedRealtime();
lastPingSent = SystemClock.elapsedRealtime();
@@ -261,8 +257,6 @@ public class XmppConnection implements Runnable {
processStreamFeatures(nextTag);
} else if (nextTag.isStart("proceed")) {
switchOverToTls(nextTag);
- } else if (nextTag.isStart("compressed")) {
- switchOverToZLib(nextTag);
} else if (nextTag.isStart("success")) {
final String challenge = tagReader.readElement(nextTag).getContent();
try {
@@ -498,28 +492,6 @@ public class XmppConnection implements Runnable {
}
}
- private void sendCompressionZlib() throws IOException {
- Element compress = new Element("compress");
- compress.setAttribute("xmlns", "http://jabber.org/protocol/compress");
- compress.addChild("method").setContent("zlib");
- tagWriter.writeElement(compress);
- }
-
- private void switchOverToZLib(final Tag currentTag)
- throws XmlPullParserException, IOException,
- NoSuchAlgorithmException {
- tagReader.readTag(); // read tag close
- tagWriter.setOutputStream(new ZLibOutputStream(tagWriter
- .getOutputStream()));
- tagReader
- .setInputStream(new ZLibInputStream(tagReader.getInputStream()));
-
- sendStartStream();
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": compression enabled");
- enabledCompression = true;
- processStream(tagReader.readTag());
- }
-
private void sendStartTLS() throws IOException {
Tag startTLS = Tag.empty("starttls");
startTLS.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-tls");
@@ -601,8 +573,6 @@ public class XmppConnection implements Runnable {
this.streamFeatures = tagReader.readElement(currentTag);
if (this.streamFeatures.hasChild("starttls") && !enabledEncryption) {
sendStartTLS();
- } else if (compressionAvailable()) {
- sendCompressionZlib();
} else if (this.streamFeatures.hasChild("register")
&& account.isOptionSet(Account.OPTION_REGISTER)
&& enabledEncryption) {
@@ -658,28 +628,6 @@ public class XmppConnection implements Runnable {
}
}
- private boolean compressionAvailable() {
- if (!this.streamFeatures.hasChild("compression",
- "http://jabber.org/features/compress"))
- return false;
- if (!ZLibOutputStream.SUPPORTED)
- return false;
- if (!account.isOptionSet(Account.OPTION_USECOMPRESSION))
- return false;
-
- Element compression = this.streamFeatures.findChild("compression",
- "http://jabber.org/features/compress");
- for (Element child : compression.getChildren()) {
- if (!"method".equals(child.getName()))
- continue;
-
- if ("zlib".equalsIgnoreCase(child.getContent())) {
- return true;
- }
- }
- return false;
- }
-
private List<String> extractMechanisms(Element stream) {
ArrayList<String> mechanisms = new ArrayList<>(stream
.getChildren().size());
@@ -848,11 +796,9 @@ public class XmppConnection implements Runnable {
List<Element> elements = packet.query().getChildren();
for (Element element : elements) {
if (element.getName().equals("item")) {
- final String jid = element.getAttribute("jid");
- try {
- sendServiceDiscoveryInfo(Jid.fromString(jid).toDomainJid());
- } catch (final InvalidJidException ignored) {
- // TODO: Handle the case where an external JID is technically invalid?
+ final Jid jid = element.getAttributeAsJid("jid");
+ if (jid != null && !jid.equals(account.getServer())) {
+ sendServiceDiscoveryInfo(jid);
}
}
}
@@ -1149,9 +1095,5 @@ public class XmppConnection implements Runnable {
return connection
.findDiscoItemByFeature("http://jabber.org/protocol/bytestreams") != null;
}
-
- public boolean compression() {
- return connection.enabledCompression;
- }
}
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java b/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java
index ebf8a6ed..c40fa0b6 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java
@@ -12,25 +12,25 @@ import gnu.inet.encoding.StringprepException;
*/
public final class Jid {
- private final String localpart;
- private final String domainpart;
- private final String resourcepart;
+ private final String localpart;
+ private final String domainpart;
+ private final String resourcepart;
- // It's much more efficient to store the ful JID as well as the parts instead of figuring them
- // all out every time (since some characters are displayed but aren't used for comparisons).
- private final String displayjid;
+ // It's much more efficient to store the ful JID as well as the parts instead of figuring them
+ // all out every time (since some characters are displayed but aren't used for comparisons).
+ private final String displayjid;
- public String getLocalpart() {
- return localpart;
- }
+ public String getLocalpart() {
+ return localpart;
+ }
- public String getDomainpart() {
- return IDN.toUnicode(domainpart);
- }
+ public String getDomainpart() {
+ return IDN.toUnicode(domainpart);
+ }
- public String getResourcepart() {
- return resourcepart;
- }
+ public String getResourcepart() {
+ return resourcepart;
+ }
public static Jid fromSessionID(SessionID id) throws InvalidJidException{
if (id.getUserID().isEmpty()) {
@@ -40,152 +40,154 @@ public final class Jid {
}
}
- public static Jid fromString(final String jid) throws InvalidJidException {
- return new Jid(jid);
- }
-
- public static Jid fromParts(final String localpart,
- final String domainpart,
- final String resourcepart) throws InvalidJidException {
- String out;
- if (localpart == null || localpart.isEmpty()) {
- out = domainpart;
- } else {
- out = localpart + "@" + domainpart;
- }
- if (resourcepart != null && !resourcepart.isEmpty()) {
- out = out + "/" + resourcepart;
- }
- return new Jid(out);
- }
-
- private Jid(final String jid) throws InvalidJidException {
- // Hackish Android way to count the number of chars in a string... should work everywhere.
- final int atCount = jid.length() - jid.replace("@", "").length();
- final int slashCount = jid.length() - jid.replace("/", "").length();
-
- // Throw an error if there's anything obvious wrong with the JID...
- if (jid.isEmpty() || jid.length() > 3071) {
- throw new InvalidJidException(InvalidJidException.INVALID_LENGTH);
- }
- if (atCount > 1 || slashCount > 1 ||
- jid.startsWith("@") || jid.endsWith("@") ||
- jid.startsWith("/") || jid.endsWith("/")) {
- throw new InvalidJidException(InvalidJidException.INVALID_CHARACTER);
- }
-
- String finaljid;
-
- final int domainpartStart;
- if (atCount == 1) {
- final int atLoc = jid.indexOf("@");
- final String lp = jid.substring(0, atLoc);
- try {
- localpart = Stringprep.nodeprep(lp);
- } catch (final StringprepException e) {
- throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e);
- }
- if (localpart.isEmpty() || localpart.length() > 1023) {
- throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH);
- }
- domainpartStart = atLoc + 1;
- finaljid = lp + "@";
- } else {
- localpart = "";
- finaljid = "";
- domainpartStart = 0;
- }
-
- final String dp;
- if (slashCount == 1) {
- final int slashLoc = jid.indexOf("/");
- final String rp = jid.substring(slashLoc + 1, jid.length());
- try {
- resourcepart = Stringprep.resourceprep(rp);
- } catch (final StringprepException e) {
- throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e);
- }
- if (resourcepart.isEmpty() || resourcepart.length() > 1023) {
- throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH);
- }
- dp = IDN.toUnicode(jid.substring(domainpartStart, slashLoc), IDN.USE_STD3_ASCII_RULES);
- finaljid = finaljid + dp + "/" + rp;
- } else {
- resourcepart = "";
- dp = IDN.toUnicode(jid.substring(domainpartStart, jid.length()),
- IDN.USE_STD3_ASCII_RULES);
- finaljid = finaljid + dp;
- }
-
- // Remove trailing "." before storing the domain part.
- if (dp.endsWith(".")) {
- try {
- domainpart = IDN.toASCII(dp.substring(0, dp.length() - 1), IDN.USE_STD3_ASCII_RULES);
- } catch (final IllegalArgumentException e) {
- throw new InvalidJidException(e);
- }
- } else {
- try {
- domainpart = IDN.toASCII(dp, IDN.USE_STD3_ASCII_RULES);
- } catch (final IllegalArgumentException e) {
- throw new InvalidJidException(e);
- }
- }
-
- // TODO: Find a proper domain validation library; validate individual parts, separators, etc.
- if (domainpart.isEmpty() || domainpart.length() > 1023) {
- throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH);
- }
-
- this.displayjid = finaljid;
- }
-
- public Jid toBareJid() {
- try {
- return resourcepart.isEmpty() ? this : fromParts(localpart, domainpart, "");
- } catch (final InvalidJidException e) {
- // This should never happen.
- return null;
- }
- }
-
- public Jid toDomainJid() {
- try {
- return resourcepart.isEmpty() && localpart.isEmpty() ? this : fromString(getDomainpart());
- } catch (final InvalidJidException e) {
- // This should never happen.
- return null;
- }
- }
-
- @Override
- public String toString() {
- return displayjid;
- }
-
- @Override
- public boolean equals(final Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- final Jid jid = (Jid) o;
-
- return jid.hashCode() == this.hashCode();
- }
-
- @Override
- public int hashCode() {
- int result = localpart.hashCode();
- result = 31 * result + domainpart.hashCode();
- result = 31 * result + resourcepart.hashCode();
- return result;
- }
-
- public boolean hasLocalpart() {
- return !localpart.isEmpty();
- }
-
- public boolean isBareJid() {
- return this.resourcepart.isEmpty();
- }
+ public static Jid fromString(final String jid) throws InvalidJidException {
+ return new Jid(jid);
+ }
+
+ public static Jid fromParts(final String localpart,
+ final String domainpart,
+ final String resourcepart) throws InvalidJidException {
+ String out;
+ if (localpart == null || localpart.isEmpty()) {
+ out = domainpart;
+ } else {
+ out = localpart + "@" + domainpart;
+ }
+ if (resourcepart != null && !resourcepart.isEmpty()) {
+ out = out + "/" + resourcepart;
+ }
+ return new Jid(out);
+ }
+
+ private Jid(final String jid) throws InvalidJidException {
+ // Hackish Android way to count the number of chars in a string... should work everywhere.
+ final int atCount = jid.length() - jid.replace("@", "").length();
+ final int slashCount = jid.length() - jid.replace("/", "").length();
+
+ // Throw an error if there's anything obvious wrong with the JID...
+ if (jid.isEmpty() || jid.length() > 3071) {
+ throw new InvalidJidException(InvalidJidException.INVALID_LENGTH);
+ }
+
+ // Go ahead and check if the localpart or resourcepart is empty.
+ if (jid.startsWith("@") || (jid.endsWith("@") && slashCount == 0) || jid.startsWith("/") || (jid.endsWith("/") && slashCount < 2)) {
+ throw new InvalidJidException(InvalidJidException.INVALID_CHARACTER);
+ }
+
+ String finaljid;
+
+ final int domainpartStart;
+ final int atLoc = jid.indexOf("@");
+ final int slashLoc = jid.indexOf("/");
+ // If there is no "@" in the JID (eg. "example.net" or "example.net/resource")
+ // or there are one or more "@" signs but they're all in the resourcepart (eg. "example.net/@/rp@"):
+ if (atCount == 0 || (atCount > 0 && slashLoc != -1 && atLoc > slashLoc)) {
+ localpart = "";
+ finaljid = "";
+ domainpartStart = 0;
+ } else {
+ final String lp = jid.substring(0, atLoc);
+ try {
+ localpart = Stringprep.nodeprep(lp);
+ } catch (final StringprepException e) {
+ throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e);
+ }
+ if (localpart.isEmpty() || localpart.length() > 1023) {
+ throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH);
+ }
+ domainpartStart = atLoc + 1;
+ finaljid = lp + "@";
+ }
+
+ final String dp;
+ if (slashCount > 0) {
+ final String rp = jid.substring(slashLoc + 1, jid.length());
+ try {
+ resourcepart = Stringprep.resourceprep(rp);
+ } catch (final StringprepException e) {
+ throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e);
+ }
+ if (resourcepart.isEmpty() || resourcepart.length() > 1023) {
+ throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH);
+ }
+ dp = IDN.toUnicode(jid.substring(domainpartStart, slashLoc), IDN.USE_STD3_ASCII_RULES);
+ finaljid = finaljid + dp + "/" + rp;
+ } else {
+ resourcepart = "";
+ dp = IDN.toUnicode(jid.substring(domainpartStart, jid.length()),
+ IDN.USE_STD3_ASCII_RULES);
+ finaljid = finaljid + dp;
+ }
+
+ // Remove trailing "." before storing the domain part.
+ if (dp.endsWith(".")) {
+ try {
+ domainpart = IDN.toASCII(dp.substring(0, dp.length() - 1), IDN.USE_STD3_ASCII_RULES);
+ } catch (final IllegalArgumentException e) {
+ throw new InvalidJidException(e);
+ }
+ } else {
+ try {
+ domainpart = IDN.toASCII(dp, IDN.USE_STD3_ASCII_RULES);
+ } catch (final IllegalArgumentException e) {
+ throw new InvalidJidException(e);
+ }
+ }
+
+ // TODO: Find a proper domain validation library; validate individual parts, separators, etc.
+ if (domainpart.isEmpty() || domainpart.length() > 1023) {
+ throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH);
+ }
+
+ this.displayjid = finaljid;
+ }
+
+ public Jid toBareJid() {
+ try {
+ return resourcepart.isEmpty() ? this : fromParts(localpart, domainpart, "");
+ } catch (final InvalidJidException e) {
+ // This should never happen.
+ return null;
+ }
+ }
+
+ public Jid toDomainJid() {
+ try {
+ return resourcepart.isEmpty() && localpart.isEmpty() ? this : fromString(getDomainpart());
+ } catch (final InvalidJidException e) {
+ // This should never happen.
+ return null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return displayjid;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ final Jid jid = (Jid) o;
+
+ return jid.hashCode() == this.hashCode();
+ }
+
+ @Override
+ public int hashCode() {
+ int result = localpart.hashCode();
+ result = 31 * result + domainpart.hashCode();
+ result = 31 * result + resourcepart.hashCode();
+ return result;
+ }
+
+ public boolean hasLocalpart() {
+ return !localpart.isEmpty();
+ }
+
+ public boolean isBareJid() {
+ return this.resourcepart.isEmpty();
+ }
}