aboutsummaryrefslogtreecommitdiffstats
path: root/src/eu
diff options
context:
space:
mode:
Diffstat (limited to 'src/eu')
-rw-r--r--src/eu/siacs/conversations/Config.java25
-rw-r--r--src/eu/siacs/conversations/crypto/OtrEngine.java83
-rw-r--r--src/eu/siacs/conversations/crypto/PgpEngine.java27
-rw-r--r--src/eu/siacs/conversations/entities/AbstractEntity.java11
-rw-r--r--src/eu/siacs/conversations/entities/Account.java17
-rw-r--r--src/eu/siacs/conversations/entities/Bookmark.java67
-rw-r--r--src/eu/siacs/conversations/entities/Contact.java40
-rw-r--r--src/eu/siacs/conversations/entities/Conversation.java74
-rw-r--r--src/eu/siacs/conversations/entities/Downloadable.java5
-rw-r--r--src/eu/siacs/conversations/entities/ListItem.java2
-rw-r--r--src/eu/siacs/conversations/entities/Message.java179
-rw-r--r--src/eu/siacs/conversations/entities/MucOptions.java40
-rw-r--r--src/eu/siacs/conversations/entities/Presences.java17
-rw-r--r--src/eu/siacs/conversations/entities/Roster.java20
-rw-r--r--src/eu/siacs/conversations/generator/IqGenerator.java50
-rw-r--r--src/eu/siacs/conversations/generator/MessageGenerator.java53
-rw-r--r--src/eu/siacs/conversations/generator/PresenceGenerator.java7
-rw-r--r--src/eu/siacs/conversations/parser/AbstractParser.java34
-rw-r--r--src/eu/siacs/conversations/parser/IqParser.java28
-rw-r--r--src/eu/siacs/conversations/parser/MessageParser.java84
-rw-r--r--src/eu/siacs/conversations/parser/PresenceParser.java12
-rw-r--r--src/eu/siacs/conversations/persistance/DatabaseBackend.java7
-rw-r--r--src/eu/siacs/conversations/persistance/FileBackend.java9
-rw-r--r--src/eu/siacs/conversations/services/Defaults.java11
-rw-r--r--src/eu/siacs/conversations/services/EventReceiver.java1
-rw-r--r--src/eu/siacs/conversations/services/ImageProvider.java29
-rw-r--r--src/eu/siacs/conversations/services/XmppConnectionService.java538
-rw-r--r--src/eu/siacs/conversations/ui/ChooseContactActivity.java34
-rw-r--r--src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java7
-rw-r--r--src/eu/siacs/conversations/ui/ContactDetailsActivity.java50
-rw-r--r--src/eu/siacs/conversations/ui/ConversationActivity.java249
-rw-r--r--src/eu/siacs/conversations/ui/ConversationFragment.java112
-rw-r--r--src/eu/siacs/conversations/ui/EditAccountActivity.java5
-rw-r--r--src/eu/siacs/conversations/ui/PublishProfilePictureActivity.java4
-rw-r--r--src/eu/siacs/conversations/ui/SettingsActivity.java45
-rw-r--r--src/eu/siacs/conversations/ui/ShareWithActivity.java207
-rw-r--r--src/eu/siacs/conversations/ui/StartConversationActivity.java8
-rw-r--r--src/eu/siacs/conversations/ui/UiCallback.java2
-rw-r--r--src/eu/siacs/conversations/ui/XmppActivity.java216
-rw-r--r--src/eu/siacs/conversations/ui/adapter/AccountAdapter.java6
-rw-r--r--src/eu/siacs/conversations/ui/adapter/ConversationAdapter.java35
-rw-r--r--src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java6
-rw-r--r--src/eu/siacs/conversations/ui/adapter/MessageAdapter.java101
-rw-r--r--src/eu/siacs/conversations/utils/CryptoHelper.java40
-rw-r--r--src/eu/siacs/conversations/utils/DNSHelper.java50
-rw-r--r--src/eu/siacs/conversations/utils/ExceptionHandler.java17
-rw-r--r--src/eu/siacs/conversations/utils/ExceptionHelper.java107
-rw-r--r--src/eu/siacs/conversations/utils/PRNGFixes.java539
-rw-r--r--src/eu/siacs/conversations/utils/PhoneHelper.java22
-rw-r--r--src/eu/siacs/conversations/utils/UIHelper.java68
-rw-r--r--src/eu/siacs/conversations/utils/Validator.java6
-rw-r--r--src/eu/siacs/conversations/utils/zlib/ZLibInputStream.java72
-rw-r--r--src/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java135
-rw-r--r--src/eu/siacs/conversations/xml/Element.java6
-rw-r--r--src/eu/siacs/conversations/xml/Tag.java51
-rw-r--r--src/eu/siacs/conversations/xml/TagWriter.java53
-rw-r--r--src/eu/siacs/conversations/xml/XmlReader.java82
-rw-r--r--src/eu/siacs/conversations/xmpp/OnMessageAcknowledged.java7
-rw-r--r--src/eu/siacs/conversations/xmpp/XmppConnection.java254
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java67
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java89
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java58
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleFile.java35
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java19
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java51
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleTransport.java51
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/OnFileTransmissionStatusChanged.java1
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/OnPrimaryCandidateFound.java3
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/OnTransportConnected.java1
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java64
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java28
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/stanzas/Reason.java2
-rw-r--r--src/eu/siacs/conversations/xmpp/pep/Avatar.java27
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java12
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/IqPacket.java15
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java16
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/PresencePacket.java3
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/csi/ActivePacket.java10
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/csi/InactivePacket.java10
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/streammgmt/AckPacket.java4
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/streammgmt/EnablePacket.java2
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/streammgmt/RequestPacket.java2
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/streammgmt/ResumePacket.java4
83 files changed, 2820 insertions, 1820 deletions
diff --git a/src/eu/siacs/conversations/Config.java b/src/eu/siacs/conversations/Config.java
new file mode 100644
index 00000000..1725eca6
--- /dev/null
+++ b/src/eu/siacs/conversations/Config.java
@@ -0,0 +1,25 @@
+package eu.siacs.conversations;
+
+import android.graphics.Bitmap;
+
+public final class Config {
+
+ public static final String LOGTAG = "conversations";
+
+ public static final int PING_MAX_INTERVAL = 300;
+ public static final int PING_MIN_INTERVAL = 30;
+ public static final int PING_TIMEOUT = 10;
+ public static final int CONNECT_TIMEOUT = 90;
+ public static final int CARBON_GRACE_PERIOD = 60;
+
+ public static final int AVATAR_SIZE = 192;
+ public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.WEBP;
+
+ public static final int MESSAGE_MERGE_WINDOW = 20;
+
+ public static final boolean PARSE_EMOTICONS = false;
+
+ private Config() {
+
+ }
+}
diff --git a/src/eu/siacs/conversations/crypto/OtrEngine.java b/src/eu/siacs/conversations/crypto/OtrEngine.java
index 7960aa2b..5dfd6fd6 100644
--- a/src/eu/siacs/conversations/crypto/OtrEngine.java
+++ b/src/eu/siacs/conversations/crypto/OtrEngine.java
@@ -14,11 +14,13 @@ import java.security.spec.InvalidKeySpecException;
import org.json.JSONException;
import org.json.JSONObject;
-import android.content.Context;
import android.util.Log;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
-import eu.siacs.conversations.persistance.DatabaseBackend;
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
import net.java.otr4j.OtrEngineHost;
@@ -27,35 +29,36 @@ import net.java.otr4j.OtrPolicy;
import net.java.otr4j.OtrPolicyImpl;
import net.java.otr4j.session.InstanceTag;
import net.java.otr4j.session.SessionID;
+import net.java.otr4j.session.SessionImpl;
+import net.java.otr4j.session.SessionStatus;
public class OtrEngine implements OtrEngineHost {
-
- private static final String LOGTAG = "xmppService";
-
+
private Account account;
private OtrPolicy otrPolicy;
private KeyPair keyPair;
- private Context context;
+ private XmppConnectionService mXmppConnectionService;
- public OtrEngine(Context context, Account account) {
+ public OtrEngine(XmppConnectionService service, Account account) {
this.account = account;
this.otrPolicy = new OtrPolicyImpl();
this.otrPolicy.setAllowV1(false);
this.otrPolicy.setAllowV2(true);
this.otrPolicy.setAllowV3(true);
this.keyPair = loadKey(account.getKeys());
+ this.mXmppConnectionService = service;
}
-
+
private KeyPair loadKey(JSONObject keys) {
if (keys == null) {
return null;
}
try {
- BigInteger x = new BigInteger(keys.getString("otr_x"),16);
- BigInteger y = new BigInteger(keys.getString("otr_y"),16);
- BigInteger p = new BigInteger(keys.getString("otr_p"),16);
- BigInteger q = new BigInteger(keys.getString("otr_q"),16);
- BigInteger g = new BigInteger(keys.getString("otr_g"),16);
+ BigInteger x = new BigInteger(keys.getString("otr_x"), 16);
+ BigInteger y = new BigInteger(keys.getString("otr_y"), 16);
+ BigInteger p = new BigInteger(keys.getString("otr_p"), 16);
+ BigInteger q = new BigInteger(keys.getString("otr_q"), 16);
+ BigInteger g = new BigInteger(keys.getString("otr_g"), 16);
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
DSAPublicKeySpec pubKeySpec = new DSAPublicKeySpec(y, p, q, g);
DSAPrivateKeySpec privateKeySpec = new DSAPrivateKeySpec(x, p, q, g);
@@ -70,26 +73,28 @@ public class OtrEngine implements OtrEngineHost {
return null;
}
}
-
+
private void saveKey() {
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
KeyFactory keyFactory;
try {
keyFactory = KeyFactory.getInstance("DSA");
- DSAPrivateKeySpec privateKeySpec = keyFactory.getKeySpec(privateKey, DSAPrivateKeySpec.class);
- DSAPublicKeySpec publicKeySpec = keyFactory.getKeySpec(publicKey, DSAPublicKeySpec.class);
- this.account.setKey("otr_x",privateKeySpec.getX().toString(16));
- this.account.setKey("otr_g",privateKeySpec.getG().toString(16));
- this.account.setKey("otr_p",privateKeySpec.getP().toString(16));
- this.account.setKey("otr_q",privateKeySpec.getQ().toString(16));
- this.account.setKey("otr_y",publicKeySpec.getY().toString(16));
+ DSAPrivateKeySpec privateKeySpec = keyFactory.getKeySpec(
+ privateKey, DSAPrivateKeySpec.class);
+ DSAPublicKeySpec publicKeySpec = keyFactory.getKeySpec(publicKey,
+ DSAPublicKeySpec.class);
+ this.account.setKey("otr_x", privateKeySpec.getX().toString(16));
+ this.account.setKey("otr_g", privateKeySpec.getG().toString(16));
+ this.account.setKey("otr_p", privateKeySpec.getP().toString(16));
+ this.account.setKey("otr_q", privateKeySpec.getQ().toString(16));
+ this.account.setKey("otr_y", publicKeySpec.getY().toString(16));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
-
+
}
@Override
@@ -101,14 +106,12 @@ public class OtrEngine implements OtrEngineHost {
@Override
public void finishedSessionMessage(SessionID arg0, String arg1)
throws OtrException {
- // TODO Auto-generated method stub
}
@Override
public String getFallbackMessage(SessionID arg0) {
- // TODO Auto-generated method stub
- return null;
+ return "I would like to start a private (OTR encrypted) conversation but your client doesn’t seem to support that";
}
@Override
@@ -123,18 +126,19 @@ public class OtrEngine implements OtrEngineHost {
}
return this.keyPair.getPublic();
}
-
+
@Override
public KeyPair getLocalKeyPair(SessionID arg0) throws OtrException {
- if (this.keyPair==null) {
+ if (this.keyPair == null) {
KeyPairGenerator kg;
try {
- kg = KeyPairGenerator.getInstance("DSA");
- this.keyPair = kg.genKeyPair();
- this.saveKey();
- DatabaseBackend.getInstance(context).updateAccount(account);
+ kg = KeyPairGenerator.getInstance("DSA");
+ this.keyPair = kg.genKeyPair();
+ this.saveKey();
+ mXmppConnectionService.databaseBackend.updateAccount(account);
} catch (NoSuchAlgorithmException e) {
- Log.d(LOGTAG,"error generating key pair "+e.getMessage());
+ Log.d(Config.LOGTAG,
+ "error generating key pair " + e.getMessage());
}
}
return this.keyPair;
@@ -152,25 +156,26 @@ public class OtrEngine implements OtrEngineHost {
}
@Override
- public void injectMessage(SessionID session, String body) throws OtrException {
+ public void injectMessage(SessionID session, String body)
+ throws OtrException {
MessagePacket packet = new MessagePacket();
packet.setFrom(account.getFullJid());
if (session.getUserID().isEmpty()) {
packet.setTo(session.getAccountID());
} else {
- packet.setTo(session.getAccountID()+"/"+session.getUserID());
+ packet.setTo(session.getAccountID() + "/" + session.getUserID());
}
packet.setBody(body);
- packet.addChild("private","urn:xmpp:carbons:2");
- packet.addChild("no-copy","urn:xmpp:hints");
+ packet.addChild("private", "urn:xmpp:carbons:2");
+ packet.addChild("no-copy", "urn:xmpp:hints");
packet.setType(MessagePacket.TYPE_CHAT);
account.getXmppConnection().sendMessagePacket(packet);
}
@Override
- public void messageFromAnotherInstanceReceived(SessionID arg0) {
- // TODO Auto-generated method stub
-
+ public void messageFromAnotherInstanceReceived(SessionID id) {
+ Log.d(Config.LOGTAG,
+ "unreadable message received from " + id.getAccountID());
}
@Override
diff --git a/src/eu/siacs/conversations/crypto/PgpEngine.java b/src/eu/siacs/conversations/crypto/PgpEngine.java
index d8222ac5..e7058a68 100644
--- a/src/eu/siacs/conversations/crypto/PgpEngine.java
+++ b/src/eu/siacs/conversations/crypto/PgpEngine.java
@@ -14,6 +14,7 @@ import org.openintents.openpgp.OpenPgpSignatureResult;
import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpApi.IOpenPgpCallback;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
@@ -38,7 +39,7 @@ public class PgpEngine {
public void decrypt(final Message message,
final UiCallback<Message> callback) {
- Log.d("xmppService", "decrypting message " + message.getUuid());
+ Log.d(Config.LOGTAG, "decrypting message " + message.getUuid());
Intent params = new Intent();
params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, message
@@ -65,7 +66,7 @@ public class PgpEngine {
callback.error(R.string.openpgp_error, message);
return;
}
-
+
return;
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
callback.userInputRequried((PendingIntent) result
@@ -73,8 +74,9 @@ public class PgpEngine {
message);
return;
case OpenPgpApi.RESULT_CODE_ERROR:
- OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERROR);
- Log.d("xmppService",error.getMessage());
+ OpenPgpError error = result
+ .getParcelableExtra(OpenPgpApi.RESULT_ERROR);
+ Log.d(Config.LOGTAG, error.getMessage());
callback.error(R.string.openpgp_error, message);
return;
default:
@@ -104,12 +106,13 @@ public class PgpEngine {
outputFile.getAbsolutePath(), options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
- message.setBody("" + outputFile.getSize() + ","
- + imageWidth + "," + imageHeight);
+ message.setBody(Long.toString(outputFile.getSize())
+ + ',' + imageWidth + ',' + imageHeight);
message.setEncryption(Message.ENCRYPTION_DECRYPTED);
PgpEngine.this.mXmppConnectionService
.updateMessage(message);
- PgpEngine.this.mXmppConnectionService.updateConversationUi();
+ PgpEngine.this.mXmppConnectionService
+ .updateConversationUi();
callback.success(message);
return;
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
@@ -179,7 +182,7 @@ public class PgpEngine {
} catch (IOException e) {
callback.error(R.string.openpgp_error, message);
}
-
+
break;
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
callback.userInputRequried((PendingIntent) result
@@ -223,9 +226,9 @@ public class PgpEngine {
}
});
} catch (FileNotFoundException e) {
- Log.d("xmppService", "file not found: " + e.getMessage());
+ Log.d(Config.LOGTAG, "file not found: " + e.getMessage());
} catch (IOException e) {
- Log.d("xmppService", "io exception during file encrypt");
+ Log.d(Config.LOGTAG, "io exception during file encrypt");
}
}
}
@@ -269,7 +272,7 @@ public class PgpEngine {
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
return 0;
case OpenPgpApi.RESULT_CODE_ERROR:
- Log.d("xmppService",
+ Log.d(Config.LOGTAG,
"openpgp error: "
+ ((OpenPgpError) result
.getParcelableExtra(OpenPgpApi.RESULT_ERROR))
@@ -298,7 +301,7 @@ public class PgpEngine {
os.flush();
String[] lines = os.toString().split("\n");
boolean sig = false;
- for(String line : lines) {
+ for (String line : lines) {
if (sig) {
if (line.contains("END PGP SIGNATURE")) {
sig = false;
diff --git a/src/eu/siacs/conversations/entities/AbstractEntity.java b/src/eu/siacs/conversations/entities/AbstractEntity.java
index 4891723e..92b8a729 100644
--- a/src/eu/siacs/conversations/entities/AbstractEntity.java
+++ b/src/eu/siacs/conversations/entities/AbstractEntity.java
@@ -4,19 +4,18 @@ import android.content.ContentValues;
public abstract class AbstractEntity {
-
public static final String UUID = "uuid";
-
+
protected String uuid;
-
+
public String getUuid() {
return this.uuid;
}
-
+
public abstract ContentValues getContentValues();
-
+
public boolean equals(AbstractEntity entity) {
return this.getUuid().equals(entity.getUuid());
}
-
+
}
diff --git a/src/eu/siacs/conversations/entities/Account.java b/src/eu/siacs/conversations/entities/Account.java
index d31d2324..eacd172c 100644
--- a/src/eu/siacs/conversations/entities/Account.java
+++ b/src/eu/siacs/conversations/entities/Account.java
@@ -14,6 +14,7 @@ import org.json.JSONObject;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.OtrEngine;
import eu.siacs.conversations.persistance.FileBackend;
+import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.XmppConnection;
import android.content.ContentValues;
@@ -82,11 +83,12 @@ public class Account extends AbstractEntity {
public Account(String username, String server, String password) {
this(java.util.UUID.randomUUID().toString(), username, server,
- password, 0, null, "",null);
+ password, 0, null, "", null);
}
public Account(String uuid, String username, String server,
- String password, int options, String rosterVersion, String keys, String avatar) {
+ String password, int options, String rosterVersion, String keys,
+ String avatar) {
this.uuid = uuid;
this.username = username;
this.server = server;
@@ -151,7 +153,10 @@ public class Account extends AbstractEntity {
public boolean errorStatus() {
int s = getStatus();
- return (s == STATUS_REGISTRATION_FAILED || s == STATUS_REGISTRATION_CONFLICT || s == STATUS_REGISTRATION_NOT_SUPPORTED || s == STATUS_SERVER_NOT_FOUND || s == STATUS_UNAUTHORIZED);
+ return (s == STATUS_REGISTRATION_FAILED
+ || s == STATUS_REGISTRATION_CONFLICT
+ || s == STATUS_REGISTRATION_NOT_SUPPORTED
+ || s == STATUS_SERVER_NOT_FOUND || s == STATUS_UNAUTHORIZED);
}
public boolean hasErrorStatus() {
@@ -226,7 +231,7 @@ public class Account extends AbstractEntity {
cursor.getString(cursor.getColumnIndex(AVATAR)));
}
- public OtrEngine getOtrEngine(Context context) {
+ public OtrEngine getOtrEngine(XmppConnectionService context) {
if (otrEngine == null) {
otrEngine = new OtrEngine(context, this);
}
@@ -279,8 +284,8 @@ public class Account extends AbstractEntity {
this.rosterVersion = version;
}
- public String getOtrFingerprint(Context applicationContext) {
- this.getOtrEngine(applicationContext);
+ public String getOtrFingerprint(XmppConnectionService service) {
+ this.getOtrEngine(service);
return this.getOtrFingerprint();
}
diff --git a/src/eu/siacs/conversations/entities/Bookmark.java b/src/eu/siacs/conversations/entities/Bookmark.java
index 38c03410..14f010e7 100644
--- a/src/eu/siacs/conversations/entities/Bookmark.java
+++ b/src/eu/siacs/conversations/entities/Bookmark.java
@@ -8,57 +8,75 @@ import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xml.Element;
public class Bookmark implements ListItem {
-
+
private Account account;
private String jid;
private String nick;
private String name;
+ private String password;
private boolean autojoin;
+ private boolean providePassword;
private Conversation mJoinedConversation;
-
+
public Bookmark(Account account, String jid) {
this.account = account;
this.jid = jid;
}
public static Bookmark parse(Element element, Account account) {
- Bookmark bookmark = new Bookmark(account,element.getAttribute("jid"));
+ Bookmark bookmark = new Bookmark(account, element.getAttribute("jid"));
bookmark.setName(element.getAttribute("name"));
String autojoin = element.getAttribute("autojoin");
- if (autojoin!=null && (autojoin.equals("true")||autojoin.equals("1"))) {
+ if (autojoin != null
+ && (autojoin.equals("true") || autojoin.equals("1"))) {
bookmark.setAutojoin(true);
} else {
bookmark.setAutojoin(false);
}
Element nick = element.findChild("nick");
- if (nick!=null) {
+ if (nick != null) {
bookmark.setNick(nick.getContent());
}
+ Element password = element.findChild("password");
+ if (password != null) {
+ bookmark.setPassword(password.getContent());
+ bookmark.setProvidePassword(true);
+ }
return bookmark;
}
public void setAutojoin(boolean autojoin) {
this.autojoin = autojoin;
}
-
+
public void setName(String name) {
this.name = name;
}
-
+
public void setNick(String nick) {
this.nick = nick;
}
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ private void setProvidePassword(boolean providePassword) {
+ this.providePassword = providePassword;
+ }
+
@Override
public int compareTo(ListItem another) {
- return this.getDisplayName().compareToIgnoreCase(another.getDisplayName());
+ return this.getDisplayName().compareToIgnoreCase(
+ another.getDisplayName());
}
@Override
public String getDisplayName() {
- if (this.mJoinedConversation!=null && (this.mJoinedConversation.getMucOptions().getSubject() != null)) {
+ if (this.mJoinedConversation != null
+ && (this.mJoinedConversation.getMucOptions().getSubject() != null)) {
return this.mJoinedConversation.getMucOptions().getSubject();
- } else if (name!=null) {
+ } else if (name != null) {
return name;
} else {
return this.jid.split("@")[0];
@@ -69,20 +87,28 @@ public class Bookmark implements ListItem {
public String getJid() {
return this.jid.toLowerCase(Locale.US);
}
-
+
public String getNick() {
return this.nick;
}
-
+
public boolean autojoin() {
return autojoin;
}
+ public String getPassword() {
+ return this.password;
+ }
+
+ public boolean isProvidePassword() {
+ return this.providePassword;
+ }
+
public boolean match(String needle) {
return needle == null
|| getJid().contains(needle.toLowerCase(Locale.US))
- || getDisplayName().toLowerCase(Locale.US)
- .contains(needle.toLowerCase(Locale.US));
+ || getDisplayName().toLowerCase(Locale.US).contains(
+ needle.toLowerCase(Locale.US));
}
public Account getAccount() {
@@ -91,10 +117,12 @@ public class Bookmark implements ListItem {
@Override
public Bitmap getImage(int dpSize, Context context) {
- if (this.mJoinedConversation==null) {
- return UIHelper.getContactPicture(getDisplayName(), dpSize, context, false);
+ if (this.mJoinedConversation == null) {
+ return UIHelper.getContactPicture(getDisplayName(), dpSize,
+ context, false);
} else {
- return UIHelper.getContactPicture(this.mJoinedConversation, dpSize, context, false);
+ return UIHelper.getContactPicture(this.mJoinedConversation, dpSize,
+ context, false);
}
}
@@ -105,7 +133,7 @@ public class Bookmark implements ListItem {
public String getName() {
return name;
}
-
+
public Element toElement() {
Element element = new Element("conference");
element.setAttribute("jid", this.getJid());
@@ -120,6 +148,9 @@ public class Bookmark implements ListItem {
if (this.nick != null) {
element.addChild("nick").setContent(this.nick);
}
+ if (this.password != null && isProvidePassword()) {
+ element.addChild("password").setContent(this.password);
+ }
return element;
}
diff --git a/src/eu/siacs/conversations/entities/Contact.java b/src/eu/siacs/conversations/entities/Contact.java
index ab05b9d1..dfd6c059 100644
--- a/src/eu/siacs/conversations/entities/Contact.java
+++ b/src/eu/siacs/conversations/entities/Contact.java
@@ -32,6 +32,7 @@ public class Contact implements ListItem {
protected String accountUuid;
protected String systemName;
protected String serverName;
+ protected String presenceName;
protected String jid;
protected int subscription = 0;
protected String systemAccount;
@@ -76,6 +77,8 @@ public class Contact implements ListItem {
return this.systemName;
} else if (this.serverName != null) {
return this.serverName;
+ } else if (this.presenceName != null) {
+ return this.presenceName;
} else {
return this.jid.split("@")[0];
}
@@ -106,7 +109,7 @@ public class Contact implements ListItem {
values.put(SYSTEMACCOUNT, systemAccount);
values.put(PHOTOURI, photoUri);
values.put(KEYS, keys.toString());
- values.put(AVATAR,avatar);
+ values.put(AVATAR, avatar);
return values;
}
@@ -138,7 +141,7 @@ public class Contact implements ListItem {
public Account getAccount() {
return this.account;
}
-
+
public Presences getPresences() {
return this.presences;
}
@@ -175,6 +178,10 @@ public class Contact implements ListItem {
this.systemName = systemName;
}
+ public void setPresenceName(String presenceName) {
+ this.presenceName = presenceName;
+ }
+
public String getSystemAccount() {
return systemAccount;
}
@@ -309,7 +316,8 @@ public class Contact implements ListItem {
@Override
public int compareTo(ListItem another) {
- return this.getDisplayName().compareToIgnoreCase(another.getDisplayName());
+ return this.getDisplayName().compareToIgnoreCase(
+ another.getDisplayName());
}
public String getServer() {
@@ -323,9 +331,9 @@ public class Contact implements ListItem {
@Override
public Bitmap getImage(int size, Context context) {
- if (this.avatar!=null) {
+ if (this.avatar != null) {
Bitmap bm = FileBackend.getAvatar(avatar, size, context);
- if (bm==null) {
+ if (bm == null) {
return UIHelper.getContactPicture(this, size, context, false);
} else {
return bm;
@@ -343,4 +351,26 @@ public class Contact implements ListItem {
return true;
}
}
+
+ public boolean deleteOtrFingerprint(String fingerprint) {
+ boolean success = false;
+ try {
+ if (this.keys.has("otr_fingerprints")) {
+ JSONArray newPrints = new JSONArray();
+ JSONArray oldPrints = this.keys
+ .getJSONArray("otr_fingerprints");
+ for (int i = 0; i < oldPrints.length(); ++i) {
+ if (!oldPrints.getString(i).equals(fingerprint)) {
+ newPrints.put(oldPrints.getString(i));
+ } else {
+ success = true;
+ }
+ }
+ this.keys.put("otr_fingerprints", newPrints);
+ }
+ return success;
+ } catch (JSONException e) {
+ return false;
+ }
+ }
}
diff --git a/src/eu/siacs/conversations/entities/Conversation.java b/src/eu/siacs/conversations/entities/Conversation.java
index 439f9f22..005b83db 100644
--- a/src/eu/siacs/conversations/entities/Conversation.java
+++ b/src/eu/siacs/conversations/entities/Conversation.java
@@ -4,6 +4,7 @@ import java.security.interfaces.DSAPublicKey;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
+import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.UIHelper;
import net.java.otr4j.OtrException;
@@ -16,6 +17,7 @@ import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
+import android.os.SystemClock;
public class Conversation extends AbstractEntity {
public static final String TABLENAME = "conversations";
@@ -43,6 +45,8 @@ public class Conversation extends AbstractEntity {
private long created;
private int mode;
+ private long mutedTill = 0;
+
private String nextPresence;
private transient CopyOnWriteArrayList<Message> messages = null;
@@ -88,7 +92,8 @@ public class Conversation extends AbstractEntity {
public List<Message> getMessages() {
if (messages == null) {
- this.messages = new CopyOnWriteArrayList<Message>(); // prevent null pointer
+ this.messages = new CopyOnWriteArrayList<Message>(); // prevent null
+ // pointer
}
// populate with Conversation (this)
@@ -140,9 +145,8 @@ public class Conversation extends AbstractEntity {
this.messages = msgs;
}
- public String getName(boolean useSubject) {
- if ((getMode() == MODE_MULTI) && (getMucOptions().getSubject() != null)
- && useSubject) {
+ public String getName() {
+ if (getMode() == MODE_MULTI && getMucOptions().getSubject() != null) {
return getMucOptions().getSubject();
} else if (getMode() == MODE_MULTI && bookmark != null
&& bookmark.getName() != null) {
@@ -220,15 +224,15 @@ public class Conversation extends AbstractEntity {
this.mode = mode;
}
- public SessionImpl startOtrSession(Context context, String presence,
- boolean sendStart) {
+ public SessionImpl startOtrSession(XmppConnectionService service,
+ String presence, boolean sendStart) {
if (this.otrSession != null) {
return this.otrSession;
} else {
- SessionID sessionId = new SessionID(this.getContactJid(), presence,
- "xmpp");
+ SessionID sessionId = new SessionID(
+ this.getContactJid().split("/")[0], presence, "xmpp");
this.otrSession = new SessionImpl(sessionId, getAccount()
- .getOtrEngine(context));
+ .getOtrEngine(service));
try {
if (sendStart) {
this.otrSession.startSession();
@@ -287,7 +291,7 @@ public class Conversation extends AbstractEntity {
public String getOtrFingerprint() {
if (this.otrFingerprint == null) {
try {
- if (getOtrSession()== null) {
+ if (getOtrSession() == null) {
return "";
}
DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession()
@@ -335,26 +339,36 @@ public class Conversation extends AbstractEntity {
if ((latestEncryption == Message.ENCRYPTION_DECRYPTED)
|| (latestEncryption == Message.ENCRYPTION_DECRYPTION_FAILED)) {
return Message.ENCRYPTION_PGP;
- } else if (latestEncryption == Message.ENCRYPTION_NONE) {
- if (getContact().getPresences().size() == 1) {
- if (getContact().getOtrFingerprints().size() >= 1) {
- return Message.ENCRYPTION_OTR;
- } else {
- return latestEncryption;
- }
- } else {
- return latestEncryption;
- }
} else {
return latestEncryption;
}
}
- public int getNextEncryption() {
+ public int getNextEncryption(boolean force) {
if (this.nextMessageEncryption == -1) {
- return this.getLatestEncryption();
+ int latest = this.getLatestEncryption();
+ if (latest == Message.ENCRYPTION_NONE) {
+ if (force && getMode() == MODE_SINGLE) {
+ return Message.ENCRYPTION_OTR;
+ } else if (getContact().getPresences().size() == 1) {
+ if (getContact().getOtrFingerprints().size() >= 1) {
+ return Message.ENCRYPTION_OTR;
+ } else {
+ return latest;
+ }
+ } else {
+ return latest;
+ }
+ } else {
+ return latest;
+ }
+ }
+ if (this.nextMessageEncryption == Message.ENCRYPTION_NONE && force
+ && getMode() == MODE_SINGLE) {
+ return Message.ENCRYPTION_OTR;
+ } else {
+ return this.nextMessageEncryption;
}
- return this.nextMessageEncryption;
}
public void setNextEncryption(int encryption) {
@@ -403,19 +417,27 @@ public class Conversation extends AbstractEntity {
}
public Bitmap getImage(Context context, int size) {
- if (mode==MODE_SINGLE) {
+ if (mode == MODE_SINGLE) {
return getContact().getImage(size, context);
} else {
return UIHelper.getContactPicture(this, size, context, false);
}
}
-
+
public boolean hasDuplicateMessage(Message message) {
- for(int i = this.getMessages().size() -1; i >= 0; --i) {
+ for (int i = this.getMessages().size() - 1; i >= 0; --i) {
if (this.messages.get(i).equals(message)) {
return true;
}
}
return false;
}
+
+ public void setMutedTill(long mutedTill) {
+ this.mutedTill = mutedTill;
+ }
+
+ public boolean isMuted() {
+ return SystemClock.elapsedRealtime() < this.mutedTill;
+ }
}
diff --git a/src/eu/siacs/conversations/entities/Downloadable.java b/src/eu/siacs/conversations/entities/Downloadable.java
new file mode 100644
index 00000000..8fb4977e
--- /dev/null
+++ b/src/eu/siacs/conversations/entities/Downloadable.java
@@ -0,0 +1,5 @@
+package eu.siacs.conversations.entities;
+
+public interface Downloadable {
+ public void start();
+}
diff --git a/src/eu/siacs/conversations/entities/ListItem.java b/src/eu/siacs/conversations/entities/ListItem.java
index c89c85d9..19089b28 100644
--- a/src/eu/siacs/conversations/entities/ListItem.java
+++ b/src/eu/siacs/conversations/entities/ListItem.java
@@ -5,6 +5,8 @@ import android.graphics.Bitmap;
public interface ListItem extends Comparable<ListItem> {
public String getDisplayName();
+
public String getJid();
+
public Bitmap getImage(int dpSize, Context context);
}
diff --git a/src/eu/siacs/conversations/entities/Message.java b/src/eu/siacs/conversations/entities/Message.java
index 9dea2f8a..ce496d27 100644
--- a/src/eu/siacs/conversations/entities/Message.java
+++ b/src/eu/siacs/conversations/entities/Message.java
@@ -1,13 +1,13 @@
package eu.siacs.conversations.entities;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
-import eu.siacs.conversations.xmpp.jingle.JingleConnection;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
public class Message extends AbstractEntity {
-
+
public static final String TABLENAME = "messages";
public static final int STATUS_RECEPTION_FAILED = -3;
@@ -28,7 +28,7 @@ public class Message extends AbstractEntity {
public static final int ENCRYPTION_OTR = 2;
public static final int ENCRYPTION_DECRYPTED = 3;
public static final int ENCRYPTION_DECRYPTION_FAILED = 4;
-
+
public static final int TYPE_TEXT = 0;
public static final int TYPE_IMAGE = 1;
public static final int TYPE_AUDIO = 2;
@@ -58,27 +58,32 @@ public class Message extends AbstractEntity {
protected String remoteMsgId = null;
protected transient Conversation conversation = null;
-
- protected transient JingleConnection jingleConnection = null;
-
+
+ protected transient Downloadable downloadable = null;
+
private Message() {
-
+
}
public Message(Conversation conversation, String body, int encryption) {
this(java.util.UUID.randomUUID().toString(), conversation.getUuid(),
- conversation.getContactJid(), null, body, System.currentTimeMillis(), encryption,
- Message.STATUS_UNSEND,TYPE_TEXT,null);
+ conversation.getContactJid(), null, body, System
+ .currentTimeMillis(), encryption,
+ Message.STATUS_UNSEND, TYPE_TEXT, null);
this.conversation = conversation;
}
-
- public Message(Conversation conversation, String counterpart, String body, int encryption, int status) {
- this(java.util.UUID.randomUUID().toString(), conversation.getUuid(),counterpart, null, body, System.currentTimeMillis(), encryption,status,TYPE_TEXT,null);
+
+ public Message(Conversation conversation, String counterpart, String body,
+ int encryption, int status) {
+ this(java.util.UUID.randomUUID().toString(), conversation.getUuid(),
+ counterpart, null, body, System.currentTimeMillis(),
+ encryption, status, TYPE_TEXT, null);
this.conversation = conversation;
}
-
- public Message(String uuid, String conversationUUid, String counterpart, String trueCounterpart,
- String body, long timeSent, int encryption, int status, int type, String remoteMsgId) {
+
+ public Message(String uuid, String conversationUUid, String counterpart,
+ String trueCounterpart, String body, long timeSent, int encryption,
+ int status, int type, String remoteMsgId) {
this.uuid = uuid;
this.conversationUuid = conversationUUid;
this.counterpart = counterpart;
@@ -97,20 +102,20 @@ public class Message extends AbstractEntity {
values.put(UUID, uuid);
values.put(CONVERSATION, conversationUuid);
values.put(COUNTERPART, counterpart);
- values.put(TRUE_COUNTERPART,trueCounterpart);
+ values.put(TRUE_COUNTERPART, trueCounterpart);
values.put(BODY, body);
values.put(TIME_SENT, timeSent);
values.put(ENCRYPTION, encryption);
values.put(STATUS, status);
values.put(TYPE, type);
- values.put(REMOTE_MSG_ID,remoteMsgId);
+ values.put(REMOTE_MSG_ID, remoteMsgId);
return values;
}
public String getConversationUuid() {
return conversationUuid;
}
-
+
public Conversation getConversation() {
return this.conversation;
}
@@ -118,7 +123,7 @@ public class Message extends AbstractEntity {
public String getCounterpart() {
return counterpart;
}
-
+
public Contact getContact() {
if (this.conversation.getMode() == Conversation.MODE_SINGLE) {
return this.conversation.getContact();
@@ -127,7 +132,8 @@ public class Message extends AbstractEntity {
return null;
} else {
Account account = this.conversation.getAccount();
- Contact contact = account.getRoster().getContact(this.trueCounterpart);
+ Contact contact = account.getRoster().getContact(
+ this.trueCounterpart);
if (contact.showInRoster()) {
return contact;
} else {
@@ -140,16 +146,18 @@ public class Message extends AbstractEntity {
public String getBody() {
return body;
}
-
+
public String getReadableBody(Context context) {
- if ((encryption == ENCRYPTION_PGP)&&(type == TYPE_TEXT)) {
- return ""+context.getText(R.string.encrypted_message_received);
- } else if ((encryption == ENCRYPTION_OTR)&&(type == TYPE_IMAGE)) {
- return ""+context.getText(R.string.encrypted_image_received);
+ if ((encryption == ENCRYPTION_PGP) && (type == TYPE_TEXT)) {
+ return context.getText(R.string.encrypted_message_received)
+ .toString();
+ } else if ((encryption == ENCRYPTION_OTR) && (type == TYPE_IMAGE)) {
+ return context.getText(R.string.encrypted_image_received)
+ .toString();
} else if (encryption == ENCRYPTION_DECRYPTION_FAILED) {
- return ""+context.getText(R.string.decryption_failed);
+ return context.getText(R.string.decryption_failed).toString();
} else if (type == TYPE_IMAGE) {
- return ""+context.getText(R.string.image_file);
+ return context.getText(R.string.image_file).toString();
} else {
return body.trim();
}
@@ -166,11 +174,11 @@ public class Message extends AbstractEntity {
public int getStatus() {
return status;
}
-
+
public String getRemoteMsgId() {
return this.remoteMsgId;
}
-
+
public void setRemoteMsgId(String id) {
this.remoteMsgId = id;
}
@@ -199,11 +207,11 @@ public class Message extends AbstractEntity {
public boolean isRead() {
return this.read;
}
-
+
public void markRead() {
this.read = true;
}
-
+
public void markUnread() {
this.read = false;
}
@@ -223,7 +231,7 @@ public class Message extends AbstractEntity {
public String getEncryptedBody() {
return this.encryptedBody;
}
-
+
public void setEncryptedBody(String body) {
this.encryptedBody = body;
}
@@ -231,40 +239,44 @@ public class Message extends AbstractEntity {
public void setType(int type) {
this.type = type;
}
-
+
public int getType() {
return this.type;
}
public void setPresence(String presence) {
- if (presence == null || presence.isEmpty()) {
+ if (presence == null) {
this.counterpart = this.counterpart.split("/")[0];
} else {
this.counterpart = this.counterpart.split("/")[0] + "/" + presence;
}
}
-
+
public void setTrueCounterpart(String trueCounterpart) {
this.trueCounterpart = trueCounterpart;
}
-
+
public String getPresence() {
String[] counterparts = this.counterpart.split("/");
if (counterparts.length == 2) {
return counterparts[1];
} else {
- return null;
+ if (this.counterpart.contains("/")) {
+ return "";
+ } else {
+ return null;
+ }
}
}
-
- public void setJingleConnection(JingleConnection connection) {
- this.jingleConnection = connection;
+
+ public void setDownloadable(Downloadable downloadable) {
+ this.downloadable = downloadable;
}
-
- public JingleConnection getJingleConnection() {
- return this.jingleConnection;
+
+ public Downloadable getDownloadable() {
+ return this.downloadable;
}
-
+
public static Message createStatusMessage(Conversation conversation) {
Message message = new Message();
message.setType(Message.TYPE_STATUS);
@@ -275,12 +287,85 @@ public class Message extends AbstractEntity {
public void setCounterpart(String counterpart) {
this.counterpart = counterpart;
}
-
+
public boolean equals(Message message) {
- if ((this.remoteMsgId!=null) && (this.body != null) && (this.counterpart != null)) {
- return this.remoteMsgId.equals(message.getRemoteMsgId()) && this.body.equals(message.getBody()) && this.counterpart.equals(message.getCounterpart());
+ if ((this.remoteMsgId != null) && (this.body != null)
+ && (this.counterpart != null)) {
+ return this.remoteMsgId.equals(message.getRemoteMsgId())
+ && this.body.equals(message.getBody())
+ && this.counterpart.equals(message.getCounterpart());
} else {
return false;
}
}
+
+ public Message next() {
+ int index = this.conversation.getMessages().indexOf(this);
+ if (index < 0 || index >= this.conversation.getMessages().size() - 1) {
+ return null;
+ } else {
+ return this.conversation.getMessages().get(index + 1);
+ }
+ }
+
+ public Message prev() {
+ int index = this.conversation.getMessages().indexOf(this);
+ if (index <= 0 || index > this.conversation.getMessages().size()) {
+ return null;
+ } else {
+ return this.conversation.getMessages().get(index - 1);
+ }
+ }
+
+ public boolean mergable(Message message) {
+ if (message == null) {
+ return false;
+ }
+ return (message.getType() == Message.TYPE_TEXT
+ && message.getEncryption() != Message.ENCRYPTION_PGP
+ && this.getType() == message.getType()
+ && this.getEncryption() == message.getEncryption()
+ && this.getCounterpart().equals(message.getCounterpart())
+ && (message.getTimeSent() - this.getTimeSent()) <= (Config.MESSAGE_MERGE_WINDOW * 1000) && ((this
+ .getStatus() == message.getStatus()) || ((this.getStatus() == Message.STATUS_SEND || this
+ .getStatus() == Message.STATUS_SEND_RECEIVED) && (message
+ .getStatus() == Message.STATUS_UNSEND
+ || message.getStatus() == Message.STATUS_SEND || message
+ .getStatus() == Message.STATUS_SEND_DISPLAYED))));
+ }
+
+ public String getMergedBody() {
+ Message next = this.next();
+ if (this.mergable(next)) {
+ return body.trim() + '\n' + next.getMergedBody();
+ }
+ return body.trim();
+ }
+
+ public int getMergedStatus() {
+ Message next = this.next();
+ if (this.mergable(next)) {
+ return next.getMergedStatus();
+ } else {
+ return getStatus();
+ }
+ }
+
+ public long getMergedTimeSent() {
+ Message next = this.next();
+ if (this.mergable(next)) {
+ return next.getMergedTimeSent();
+ } else {
+ return getTimeSent();
+ }
+ }
+
+ public boolean wasMergedIntoPrevious() {
+ Message prev = this.prev();
+ if (prev == null) {
+ return false;
+ } else {
+ return prev.mergable(this);
+ }
+ }
}
diff --git a/src/eu/siacs/conversations/entities/MucOptions.java b/src/eu/siacs/conversations/entities/MucOptions.java
index 61b2732d..e9ab6908 100644
--- a/src/eu/siacs/conversations/entities/MucOptions.java
+++ b/src/eu/siacs/conversations/entities/MucOptions.java
@@ -14,6 +14,7 @@ public class MucOptions {
public static final int ERROR_NO_ERROR = 0;
public static final int ERROR_NICK_IN_USE = 1;
public static final int ERROR_ROOM_NOT_FOUND = 2;
+ public static final int ERROR_PASSWORD_REQUIRED = 3;
public interface OnRenameListener {
public void onRename(boolean success);
@@ -106,6 +107,8 @@ public class MucOptions {
private User self = new User();
private String subject = null;
private String joinnick;
+ private String password = null;
+ private boolean passwordChanged = false;
public MucOptions(Account account) {
this.account = account;
@@ -155,6 +158,10 @@ public class MucOptions {
}
aboutToRename = false;
}
+ if (conversation.getBookmark() != null
+ && conversation.getBookmark().isProvidePassword()) {
+ this.passwordChanged = false;
+ }
} else {
addUser(user);
}
@@ -186,6 +193,12 @@ public class MucOptions {
} else {
this.error = ERROR_NICK_IN_USE;
}
+ } else if (error.hasChild("not-authorized")) {
+ if (conversation.getBookmark() != null
+ && conversation.getBookmark().isProvidePassword()) {
+ this.passwordChanged = true;
+ }
+ this.error = ERROR_PASSWORD_REQUIRED;
}
}
}
@@ -299,13 +312,36 @@ public class MucOptions {
return this.conversation.getContactJid().split("/")[0] + "/"
+ this.joinnick;
}
-
+
public String getTrueCounterpart(String counterpart) {
- for(User user : this.getUsers()) {
+ for (User user : this.getUsers()) {
if (user.getName().equals(counterpart)) {
return user.getJid();
}
}
return null;
}
+
+ public String getPassword() {
+ if (conversation.getBookmark() != null
+ && conversation.getBookmark().getPassword() != null) {
+ return conversation.getBookmark().getPassword();
+ } else {
+ return this.password;
+ }
+ }
+
+ public void setPassword(String password) {
+ if (conversation.getBookmark() != null
+ && conversation.getBookmark().isProvidePassword()) {
+ conversation.getBookmark().setPassword(password);
+ } else {
+ this.password = password;
+ }
+ }
+
+ public boolean isPasswordChanged() {
+ return this.passwordChanged;
+ }
+
} \ No newline at end of file
diff --git a/src/eu/siacs/conversations/entities/Presences.java b/src/eu/siacs/conversations/entities/Presences.java
index acd80735..b5899847 100644
--- a/src/eu/siacs/conversations/entities/Presences.java
+++ b/src/eu/siacs/conversations/entities/Presences.java
@@ -14,7 +14,7 @@ public class Presences {
public static final int XA = 2;
public static final int DND = 3;
public static final int OFFLINE = 4;
-
+
private Hashtable<String, Integer> presences = new Hashtable<String, Integer>();
public Hashtable<String, Integer> getPresences() {
@@ -28,23 +28,24 @@ public class Presences {
public void removePresence(String resource) {
this.presences.remove(resource);
}
-
+
public void clearPresences() {
this.presences.clear();
}
-
+
public int getMostAvailableStatus() {
int status = OFFLINE;
Iterator<Entry<String, Integer>> it = presences.entrySet().iterator();
while (it.hasNext()) {
Entry<String, Integer> entry = it.next();
- if (entry.getValue()<status) status = entry.getValue();
+ if (entry.getValue() < status)
+ status = entry.getValue();
}
return status;
}
public static int parseShow(Element show) {
- if ((show == null)||(show.getContent() == null)) {
+ if ((show == null) || (show.getContent() == null)) {
return Presences.ONLINE;
} else if (show.getContent().equals("away")) {
return Presences.AWAY;
@@ -53,16 +54,16 @@ public class Presences {
} else if (show.getContent().equals("chat")) {
return Presences.CHAT;
} else if (show.getContent().equals("dnd")) {
- return Presences.DND;
+ return Presences.DND;
} else {
return Presences.OFFLINE;
}
}
-
+
public int size() {
return presences.size();
}
-
+
public String[] asStringArray() {
final String[] presencesArray = new String[presences.size()];
presences.keySet().toArray(presencesArray);
diff --git a/src/eu/siacs/conversations/entities/Roster.java b/src/eu/siacs/conversations/entities/Roster.java
index aa328664..c6212f77 100644
--- a/src/eu/siacs/conversations/entities/Roster.java
+++ b/src/eu/siacs/conversations/entities/Roster.java
@@ -9,16 +9,16 @@ public class Roster {
Account account;
ConcurrentHashMap<String, Contact> contacts = new ConcurrentHashMap<String, Contact>();
private String version = null;
-
+
public Roster(Account account) {
this.account = account;
}
-
+
public boolean hasContact(String jid) {
String cleanJid = jid.split("/")[0];
return contacts.containsKey(cleanJid);
}
-
+
public Contact getContact(String jid) {
String cleanJid = jid.split("/")[0].toLowerCase(Locale.getDefault());
if (contacts.containsKey(cleanJid)) {
@@ -32,19 +32,19 @@ public class Roster {
}
public void clearPresences() {
- for(Contact contact : getContacts()) {
+ for (Contact contact : getContacts()) {
contact.clearPresences();
}
}
-
+
public void markAllAsNotInRoster() {
- for(Contact contact : getContacts()) {
+ for (Contact contact : getContacts()) {
contact.resetOption(Contact.Options.IN_ROSTER);
}
}
-
+
public void clearSystemAccounts() {
- for(Contact contact : getContacts()) {
+ for (Contact contact : getContacts()) {
contact.setPhotoUri(null);
contact.setSystemName(null);
contact.setSystemAccount(null);
@@ -58,13 +58,13 @@ public class Roster {
public void initContact(Contact contact) {
contact.setAccount(account);
contact.setOption(Contact.Options.IN_ROSTER);
- contacts.put(contact.getJid(),contact);
+ contacts.put(contact.getJid(), contact);
}
public void setVersion(String version) {
this.version = version;
}
-
+
public String getVersion() {
return this.version;
}
diff --git a/src/eu/siacs/conversations/generator/IqGenerator.java b/src/eu/siacs/conversations/generator/IqGenerator.java
index 259538c2..b5ecafb5 100644
--- a/src/eu/siacs/conversations/generator/IqGenerator.java
+++ b/src/eu/siacs/conversations/generator/IqGenerator.java
@@ -10,67 +10,69 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket;
public class IqGenerator extends AbstractGenerator {
-
-
public IqPacket discoResponse(IqPacket request) {
IqPacket packet = new IqPacket(IqPacket.TYPE_RESULT);
packet.setId(request.getId());
packet.setTo(request.getFrom());
- Element query = packet.addChild("query","http://jabber.org/protocol/disco#info");
+ Element query = packet.addChild("query",
+ "http://jabber.org/protocol/disco#info");
query.setAttribute("node", request.query().getAttribute("node"));
Element identity = query.addChild("identity");
- identity.setAttribute("category","client");
+ identity.setAttribute("category", "client");
identity.setAttribute("type", this.IDENTITY_TYPE);
identity.setAttribute("name", IDENTITY_NAME);
List<String> features = Arrays.asList(FEATURES);
Collections.sort(features);
- for(String feature : features) {
- query.addChild("feature").setAttribute("var",feature);
+ for (String feature : features) {
+ query.addChild("feature").setAttribute("var", feature);
}
return packet;
}
-
+
protected IqPacket publish(String node, Element item) {
IqPacket packet = new IqPacket(IqPacket.TYPE_SET);
- Element pubsub = packet.addChild("pubsub", "http://jabber.org/protocol/pubsub");
+ Element pubsub = packet.addChild("pubsub",
+ "http://jabber.org/protocol/pubsub");
Element publish = pubsub.addChild("publish");
publish.setAttribute("node", node);
publish.addChild(item);
return packet;
}
-
+
protected IqPacket retrieve(String node, Element item) {
IqPacket packet = new IqPacket(IqPacket.TYPE_GET);
- Element pubsub = packet.addChild("pubsub", "http://jabber.org/protocol/pubsub");
- Element items = pubsub.addChild("items");
- items.setAttribute("node", node);
- if (item!=null) {
+ Element pubsub = packet.addChild("pubsub",
+ "http://jabber.org/protocol/pubsub");
+ Element items = pubsub.addChild("items");
+ items.setAttribute("node", node);
+ if (item != null) {
items.addChild(item);
}
return packet;
}
-
+
public IqPacket publishAvatar(Avatar avatar) {
Element item = new Element("item");
item.setAttribute("id", avatar.sha1sum);
- Element data = item.addChild("data","urn:xmpp:avatar:data");
+ Element data = item.addChild("data", "urn:xmpp:avatar:data");
data.setContent(avatar.image);
return publish("urn:xmpp:avatar:data", item);
}
-
+
public IqPacket publishAvatarMetadata(Avatar avatar) {
Element item = new Element("item");
item.setAttribute("id", avatar.sha1sum);
- Element metadata = item.addChild("metadata","urn:xmpp:avatar:metadata");
+ Element metadata = item
+ .addChild("metadata", "urn:xmpp:avatar:metadata");
Element info = metadata.addChild("info");
- info.setAttribute("bytes",avatar.size);
- info.setAttribute("id",avatar.sha1sum);
- info.setAttribute("height",avatar.height);
- info.setAttribute("width",avatar.height);
+ info.setAttribute("bytes", avatar.size);
+ info.setAttribute("id", avatar.sha1sum);
+ info.setAttribute("height", avatar.height);
+ info.setAttribute("width", avatar.height);
info.setAttribute("type", avatar.type);
- return publish("urn:xmpp:avatar:metadata",item);
+ return publish("urn:xmpp:avatar:metadata", item);
}
-
+
public IqPacket retrieveAvatar(Avatar avatar) {
Element item = new Element("item");
item.setAttribute("id", avatar.sha1sum);
@@ -81,7 +83,7 @@ public class IqGenerator extends AbstractGenerator {
public IqPacket retrieveAvatarMetaData(String to) {
IqPacket packet = retrieve("urn:xmpp:avatar:metadata", null);
- if (to!=null) {
+ if (to != null) {
packet.setTo(to);
}
return packet;
diff --git a/src/eu/siacs/conversations/generator/MessageGenerator.java b/src/eu/siacs/conversations/generator/MessageGenerator.java
index 26182aad..ecfb4744 100644
--- a/src/eu/siacs/conversations/generator/MessageGenerator.java
+++ b/src/eu/siacs/conversations/generator/MessageGenerator.java
@@ -32,62 +32,63 @@ public class MessageGenerator {
packet.setFrom(account.getFullJid());
packet.setId(message.getUuid());
if (addDelay) {
- addDelay(packet,message.getTimeSent());
+ addDelay(packet, message.getTimeSent());
}
return packet;
}
-
+
private void addDelay(MessagePacket packet, long timestamp) {
- final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",Locale.US);
+ final SimpleDateFormat mDateFormat = new SimpleDateFormat(
+ "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
mDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Element delay = packet.addChild("delay", "urn:xmpp:delay");
Date date = new Date(timestamp);
delay.setAttribute("stamp", mDateFormat.format(date));
}
-
+
public MessagePacket generateOtrChat(Message message) {
return generateOtrChat(message, false);
}
-
+
public MessagePacket generateOtrChat(Message message, boolean addDelay) {
Session otrSession = message.getConversation().getOtrSession();
- if (otrSession==null) {
+ if (otrSession == null) {
return null;
}
- MessagePacket packet = preparePacket(message,addDelay);
+ MessagePacket packet = preparePacket(message, addDelay);
packet.addChild("private", "urn:xmpp:carbons:2");
packet.addChild("no-copy", "urn:xmpp:hints");
try {
- packet.setBody(otrSession.transformSending(message
- .getBody()));
+ packet.setBody(otrSession.transformSending(message.getBody()));
return packet;
} catch (OtrException e) {
return null;
}
}
-
+
public MessagePacket generateChat(Message message) {
return generateChat(message, false);
}
-
+
public MessagePacket generateChat(Message message, boolean addDelay) {
- MessagePacket packet = preparePacket(message,addDelay);
+ MessagePacket packet = preparePacket(message, addDelay);
packet.setBody(message.getBody());
return packet;
}
-
+
public MessagePacket generatePgpChat(Message message) {
return generatePgpChat(message, false);
}
-
+
public MessagePacket generatePgpChat(Message message, boolean addDelay) {
- MessagePacket packet = preparePacket(message,addDelay);
+ MessagePacket packet = preparePacket(message, addDelay);
packet.setBody("This is an XEP-0027 encryted message");
if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
packet.addChild("x", "jabber:x:encrypted").setContent(
message.getEncryptedBody());
} else if (message.getEncryption() == Message.ENCRYPTION_PGP) {
- packet.setBody(message.getBody());
+ packet.addChild("x", "jabber:x:encrypted").setContent(
+ message.getBody());
}
return packet;
}
@@ -100,7 +101,7 @@ public class MessageGenerator {
error.addChild("not-acceptable");
return packet;
}
-
+
private MessagePacket generateError(MessagePacket origin) {
MessagePacket packet = new MessagePacket();
packet.setId(origin.getId());
@@ -109,7 +110,7 @@ public class MessageGenerator {
packet.setType(MessagePacket.TYPE_ERROR);
return packet;
}
-
+
public MessagePacket confirm(Account account, String to, String id) {
MessagePacket packet = new MessagePacket();
packet.setType(MessagePacket.TYPE_NORMAL);
@@ -120,8 +121,9 @@ public class MessageGenerator {
received.setAttribute("id", id);
return packet;
}
-
- public MessagePacket conferenceSubject(Conversation conversation,String subject) {
+
+ public MessagePacket conferenceSubject(Conversation conversation,
+ String subject) {
MessagePacket packet = new MessagePacket();
packet.setType(MessagePacket.TYPE_GROUPCHAT);
packet.setTo(conversation.getContactJid().split("/")[0]);
@@ -131,7 +133,7 @@ public class MessageGenerator {
packet.setFrom(conversation.getAccount().getJid());
return packet;
}
-
+
public MessagePacket directInvite(Conversation conversation, String contact) {
MessagePacket packet = new MessagePacket();
packet.setType(MessagePacket.TYPE_NORMAL);
@@ -141,7 +143,7 @@ public class MessageGenerator {
x.setAttribute("jid", conversation.getContactJid().split("/")[0]);
return packet;
}
-
+
public MessagePacket invite(Conversation conversation, String contact) {
MessagePacket packet = new MessagePacket();
packet.setTo(conversation.getContactJid().split("/")[0]);
@@ -154,13 +156,14 @@ public class MessageGenerator {
packet.addChild(x);
return packet;
}
-
- public MessagePacket received(Account account, MessagePacket originalMessage, String namespace) {
+
+ public MessagePacket received(Account account,
+ MessagePacket originalMessage, String namespace) {
MessagePacket receivedPacket = new MessagePacket();
receivedPacket.setType(MessagePacket.TYPE_NORMAL);
receivedPacket.setTo(originalMessage.getFrom());
receivedPacket.setFrom(account.getFullJid());
- Element received = receivedPacket.addChild("received",namespace);
+ Element received = receivedPacket.addChild("received", namespace);
received.setAttribute("id", originalMessage.getId());
return receivedPacket;
}
diff --git a/src/eu/siacs/conversations/generator/PresenceGenerator.java b/src/eu/siacs/conversations/generator/PresenceGenerator.java
index b3431568..87e361f5 100644
--- a/src/eu/siacs/conversations/generator/PresenceGenerator.java
+++ b/src/eu/siacs/conversations/generator/PresenceGenerator.java
@@ -14,7 +14,7 @@ public class PresenceGenerator extends AbstractGenerator {
packet.setAttribute("from", contact.getAccount().getJid());
return packet;
}
-
+
public PresencePacket requestPresenceUpdatesFrom(Contact contact) {
return subscription("subscribe", contact);
}
@@ -41,9 +41,10 @@ public class PresenceGenerator extends AbstractGenerator {
}
String capHash = getCapHash();
if (capHash != null) {
- Element cap = packet.addChild("c","http://jabber.org/protocol/caps");
+ Element cap = packet.addChild("c",
+ "http://jabber.org/protocol/caps");
cap.setAttribute("hash", "sha-1");
- cap.setAttribute("node","http://conversions.siacs.eu");
+ cap.setAttribute("node", "http://conversions.siacs.eu");
cap.setAttribute("ver", capHash);
}
return packet;
diff --git a/src/eu/siacs/conversations/parser/AbstractParser.java b/src/eu/siacs/conversations/parser/AbstractParser.java
index 96d11508..25fcd921 100644
--- a/src/eu/siacs/conversations/parser/AbstractParser.java
+++ b/src/eu/siacs/conversations/parser/AbstractParser.java
@@ -13,17 +13,17 @@ import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xml.Element;
public abstract class AbstractParser {
-
+
protected XmppConnectionService mXmppConnectionService;
protected AbstractParser(XmppConnectionService service) {
this.mXmppConnectionService = service;
}
-
+
protected long getTimestamp(Element packet) {
long now = System.currentTimeMillis();
ArrayList<String> stamps = new ArrayList<String>();
- for(Element child : packet.getChildren()) {
+ for (Element child : packet.getChildren()) {
if (child.getName().equals("delay")) {
stamps.add(child.getAttribute("stamp").replace("Z", "+0000"));
}
@@ -33,17 +33,18 @@ public abstract class AbstractParser {
try {
String stamp = stamps.get(stamps.size() - 1);
if (stamp.contains(".")) {
- Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ",Locale.US)
- .parse(stamp);
- if (now<date.getTime()) {
+ Date date = new SimpleDateFormat(
+ "yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US)
+ .parse(stamp);
+ if (now < date.getTime()) {
return now;
} else {
return date.getTime();
}
} else {
- Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ",Locale.US)
- .parse(stamp);
- if (now<date.getTime()) {
+ Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ",
+ Locale.US).parse(stamp);
+ if (now < date.getTime()) {
return now;
} else {
return date.getTime();
@@ -56,8 +57,9 @@ public abstract class AbstractParser {
return now;
}
}
-
- protected void updateLastseen(Element packet, Account account, boolean presenceOverwrite) {
+
+ protected void updateLastseen(Element packet, Account account,
+ boolean presenceOverwrite) {
String[] fromParts = packet.getAttribute("from").split("/");
String from = fromParts[0];
String presence = null;
@@ -70,19 +72,19 @@ public abstract class AbstractParser {
long timestamp = getTimestamp(packet);
if (timestamp >= contact.lastseen.time) {
contact.lastseen.time = timestamp;
- if ((presence!=null)&&(presenceOverwrite)) {
+ if ((presence != null) && (presenceOverwrite)) {
contact.lastseen.presence = presence;
}
}
}
-
+
protected String avatarData(Element items) {
Element item = items.findChild("item");
- if (item==null) {
+ if (item == null) {
return null;
}
- Element data = item.findChild("data","urn:xmpp:avatar:data");
- if (data==null) {
+ Element data = item.findChild("data", "urn:xmpp:avatar:data");
+ if (data == null) {
return null;
}
return data.getContent();
diff --git a/src/eu/siacs/conversations/parser/IqParser.java b/src/eu/siacs/conversations/parser/IqParser.java
index a22ff6a5..592b77a4 100644
--- a/src/eu/siacs/conversations/parser/IqParser.java
+++ b/src/eu/siacs/conversations/parser/IqParser.java
@@ -12,7 +12,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
public IqParser(XmppConnectionService service) {
super(service);
}
-
+
public void rosterItems(Account account, Element query) {
String version = query.getAttribute("ver");
if (version != null) {
@@ -27,7 +27,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
if (!contact.getOption(Contact.Options.DIRTY_PUSH)) {
contact.setServerName(name);
}
- if (subscription!=null) {
+ if (subscription != null) {
if (subscription.equals("remove")) {
contact.resetOption(Contact.Options.IN_ROSTER);
contact.resetOption(Contact.Options.DIRTY_DELETE);
@@ -42,14 +42,15 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
}
mXmppConnectionService.updateRosterUi();
}
-
+
public String avatarData(IqPacket packet) {
- Element pubsub = packet.findChild("pubsub", "http://jabber.org/protocol/pubsub");
- if (pubsub==null) {
+ Element pubsub = packet.findChild("pubsub",
+ "http://jabber.org/protocol/pubsub");
+ if (pubsub == null) {
return null;
}
Element items = pubsub.findChild("items");
- if (items==null) {
+ if (items == null) {
return null;
}
return super.avatarData(items);
@@ -63,20 +64,19 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
Element query = packet.findChild("query");
this.rosterItems(account, query);
}
- } else if (packet
- .hasChild("open", "http://jabber.org/protocol/ibb")
- || packet
- .hasChild("data", "http://jabber.org/protocol/ibb")) {
- mXmppConnectionService.getJingleConnectionManager().deliverIbbPacket(account, packet);
+ } else if (packet.hasChild("open", "http://jabber.org/protocol/ibb")
+ || packet.hasChild("data", "http://jabber.org/protocol/ibb")) {
+ mXmppConnectionService.getJingleConnectionManager()
+ .deliverIbbPacket(account, packet);
} else if (packet.hasChild("query",
"http://jabber.org/protocol/disco#info")) {
- IqPacket response = mXmppConnectionService.getIqGenerator().discoResponse(packet);
+ IqPacket response = mXmppConnectionService.getIqGenerator()
+ .discoResponse(packet);
account.getXmppConnection().sendIqPacket(response, null);
} else {
if ((packet.getType() == IqPacket.TYPE_GET)
|| (packet.getType() == IqPacket.TYPE_SET)) {
- IqPacket response = packet
- .generateRespone(IqPacket.TYPE_ERROR);
+ IqPacket response = packet.generateRespone(IqPacket.TYPE_ERROR);
Element error = response.addChild("error");
error.setAttribute("type", "cancel");
error.addChild("feature-not-implemented",
diff --git a/src/eu/siacs/conversations/parser/MessageParser.java b/src/eu/siacs/conversations/parser/MessageParser.java
index 0d46074d..bd136a33 100644
--- a/src/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/eu/siacs/conversations/parser/MessageParser.java
@@ -1,9 +1,9 @@
package eu.siacs.conversations.parser;
import android.os.SystemClock;
-import android.util.Log;
import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionStatus;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
@@ -18,7 +18,7 @@ import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
public class MessageParser extends AbstractParser implements
OnMessagePacketReceived {
- private long lastCarbonMessageReceived = -XmppConnectionService.CARBON_GRACE_PERIOD;
+ private long lastCarbonMessageReceived = -(Config.CARBON_GRACE_PERIOD * 1000);
public MessageParser(XmppConnectionService service) {
super(service);
@@ -70,11 +70,13 @@ public class MessageParser extends AbstractParser implements
}
updateLastseen(packet, account, true);
String body = packet.getBody();
+ if (body.matches("^\\?OTRv\\d*\\?")) {
+ conversation.resetOtrSession();
+ }
if (!conversation.hasValidOtrSession()) {
if (properlyAddressed) {
- conversation.startOtrSession(
- mXmppConnectionService.getApplicationContext(),
- presence, false);
+ conversation.startOtrSession(mXmppConnectionService, presence,
+ false);
} else {
return null;
}
@@ -84,8 +86,7 @@ public class MessageParser extends AbstractParser implements
if (!foreignPresence.equals(presence)) {
conversation.endOtrIfNeeded();
if (properlyAddressed) {
- conversation.startOtrSession(
- mXmppConnectionService.getApplicationContext(),
+ conversation.startOtrSession(mXmppConnectionService,
presence, false);
} else {
return null;
@@ -124,7 +125,7 @@ public class MessageParser extends AbstractParser implements
if (receivedId != null) {
mXmppConnectionService.replyWithNotAcceptable(account, packet);
}
- conversation.endOtrIfNeeded();
+ conversation.resetOtrSession();
return null;
}
}
@@ -173,7 +174,8 @@ public class MessageParser extends AbstractParser implements
finishedMessage.setTrueCounterpart(conversation.getMucOptions()
.getTrueCounterpart(counterPart));
}
- if (packet.hasChild("delay") && conversation.hasDuplicateMessage(finishedMessage)) {
+ if (packet.hasChild("delay")
+ && conversation.hasDuplicateMessage(finishedMessage)) {
return null;
}
finishedMessage.setTime(getTimestamp(packet));
@@ -198,7 +200,8 @@ public class MessageParser extends AbstractParser implements
}
Element message = forwarded.findChild("message");
if ((message == null) || (!message.hasChild("body"))) {
- if (status == Message.STATUS_RECEIVED && message.getAttribute("from")!=null) {
+ if (status == Message.STATUS_RECEIVED
+ && message.getAttribute("from") != null) {
parseNormal(message, account);
}
return null;
@@ -220,7 +223,7 @@ public class MessageParser extends AbstractParser implements
Conversation conversation = mXmppConnectionService
.findOrCreateConversation(account, parts[0], false);
conversation.setLatestMarkableMessageId(getMarkableMessageId(packet));
-
+
String pgpBody = getPgpBody(message);
Message finishedMessage;
if (pgpBody != null) {
@@ -243,7 +246,7 @@ public class MessageParser extends AbstractParser implements
return null;
}
}
-
+
return finishedMessage;
}
@@ -282,6 +285,11 @@ public class MessageParser extends AbstractParser implements
.findOrCreateConversation(account,
packet.getAttribute("from"), true);
if (!conversation.getMucOptions().online()) {
+ if (x.hasChild("password")) {
+ Element password = x.findChild("password");
+ conversation.getMucOptions().setPassword(
+ password.getContent());
+ }
mXmppConnectionService.joinMuc(conversation);
mXmppConnectionService.updateConversationUi();
}
@@ -290,10 +298,14 @@ public class MessageParser extends AbstractParser implements
} else if (packet.hasChild("x", "jabber:x:conference")) {
Element x = packet.findChild("x", "jabber:x:conference");
String jid = x.getAttribute("jid");
+ String password = x.getAttribute("password");
if (jid != null) {
Conversation conversation = mXmppConnectionService
.findOrCreateConversation(account, jid, true);
if (!conversation.getMucOptions().online()) {
+ if (password != null) {
+ conversation.getMucOptions().setPassword(password);
+ }
mXmppConnectionService.joinMuc(conversation);
mXmppConnectionService.updateConversationUi();
}
@@ -307,28 +319,38 @@ public class MessageParser extends AbstractParser implements
if (node != null) {
if (node.equals("urn:xmpp:avatar:metadata")) {
Avatar avatar = Avatar.parseMetadata(items);
- if (avatar!=null) {
+ if (avatar != null) {
avatar.owner = from;
if (mXmppConnectionService.getFileBackend().isAvatarCached(
avatar)) {
if (account.getJid().equals(from)) {
if (account.setAvatar(avatar.getFilename())) {
- mXmppConnectionService.databaseBackend.updateAccount(account);
+ mXmppConnectionService.databaseBackend
+ .updateAccount(account);
}
} else {
- Contact contact = account.getRoster().getContact(from);
+ Contact contact = account.getRoster().getContact(
+ from);
contact.setAvatar(avatar.getFilename());
}
} else {
mXmppConnectionService.fetchAvatar(account, avatar);
}
}
- } else {
- Log.d("xmppService", account.getJid() + ": " + node + " from "
- + from);
+ } else if (node.equals("http://jabber.org/protocol/nick")) {
+ Element item = items.findChild("item");
+ if (item != null) {
+ Element nick = item.findChild("nick",
+ "http://jabber.org/protocol/nick");
+ if (nick != null) {
+ if (from != null) {
+ Contact contact = account.getRoster().getContact(
+ from);
+ contact.setPresenceName(nick.getContent());
+ }
+ }
+ }
}
- } else {
- Log.d("xmppService", event.toString());
}
}
@@ -355,9 +377,11 @@ public class MessageParser extends AbstractParser implements
boolean notify = true;
if (mXmppConnectionService.getPreferences().getBoolean(
"notification_grace_period_after_carbon_received", true)) {
- notify = (SystemClock.elapsedRealtime() - lastCarbonMessageReceived) > XmppConnectionService.CARBON_GRACE_PERIOD;
+ notify = (SystemClock.elapsedRealtime() - lastCarbonMessageReceived) > (Config.CARBON_GRACE_PERIOD * 1000);
}
+ this.parseNick(packet, account);
+
if ((packet.getType() == MessagePacket.TYPE_CHAT)) {
if ((packet.getBody() != null)
&& (packet.getBody().startsWith("?OTR"))) {
@@ -428,8 +452,12 @@ public class MessageParser extends AbstractParser implements
Conversation conversation = message.getConversation();
conversation.getMessages().add(message);
if (packet.getType() != MessagePacket.TYPE_ERROR) {
- mXmppConnectionService.databaseBackend.createMessage(message);
+ if (message.getEncryption() == Message.ENCRYPTION_NONE
+ || mXmppConnectionService.saveEncryptedMessages()) {
+ mXmppConnectionService.databaseBackend.createMessage(message);
+ }
}
+ notify = notify && !conversation.isMuted();
mXmppConnectionService.notifyUi(conversation, notify);
}
@@ -440,4 +468,16 @@ public class MessageParser extends AbstractParser implements
parseEvent(event, packet.getFrom(), account);
}
}
+
+ private void parseNick(MessagePacket packet, Account account) {
+ Element nick = packet.findChild("nick",
+ "http://jabber.org/protocol/nick");
+ if (nick != null) {
+ if (packet.getFrom() != null) {
+ Contact contact = account.getRoster().getContact(
+ packet.getFrom());
+ contact.setPresenceName(nick.getContent());
+ }
+ }
+ }
}
diff --git a/src/eu/siacs/conversations/parser/PresenceParser.java b/src/eu/siacs/conversations/parser/PresenceParser.java
index ea19df6f..05ffa67e 100644
--- a/src/eu/siacs/conversations/parser/PresenceParser.java
+++ b/src/eu/siacs/conversations/parser/PresenceParser.java
@@ -26,7 +26,7 @@ public class PresenceParser extends AbstractParser implements
if (muc != null) {
boolean before = muc.getMucOptions().online();
muc.getMucOptions().processPacket(packet, mPgpEngine);
- if (before!=muc.getMucOptions().online()) {
+ if (before != muc.getMucOptions().online()) {
mXmppConnectionService.updateConversationUi();
}
}
@@ -36,7 +36,7 @@ public class PresenceParser extends AbstractParser implements
if (muc != null) {
boolean before = muc.getMucOptions().online();
muc.getMucOptions().processPacket(packet, mPgpEngine);
- if (before!=muc.getMucOptions().online()) {
+ if (before != muc.getMucOptions().online()) {
mXmppConnectionService.updateConversationUi();
}
}
@@ -49,7 +49,7 @@ public class PresenceParser extends AbstractParser implements
if (packet.getFrom() == null) {
return;
}
- String[] fromParts = packet.getFrom().split("/");
+ String[] fromParts = packet.getFrom().split("/", 2);
String type = packet.getAttribute("type");
if (fromParts[0].equals(account.getJid())) {
if (fromParts.length == 2) {
@@ -60,7 +60,6 @@ public class PresenceParser extends AbstractParser implements
account.removePresence(fromParts[1]);
}
}
-
} else {
Contact contact = account.getRoster().getContact(packet.getFrom());
if (type == null) {
@@ -108,6 +107,11 @@ public class PresenceParser extends AbstractParser implements
contact.setOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST);
}
}
+ Element nick = packet.findChild("nick",
+ "http://jabber.org/protocol/nick");
+ if (nick != null) {
+ contact.setPresenceName(nick.getContent());
+ }
}
mXmppConnectionService.updateRosterUi();
}
diff --git a/src/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/eu/siacs/conversations/persistance/DatabaseBackend.java
index 62736ffa..cda2f356 100644
--- a/src/eu/siacs/conversations/persistance/DatabaseBackend.java
+++ b/src/eu/siacs/conversations/persistance/DatabaseBackend.java
@@ -13,7 +13,6 @@ import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
-import android.util.Log;
public class DatabaseBackend extends SQLiteOpenHelper {
@@ -138,7 +137,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
public CopyOnWriteArrayList<Conversation> getConversations(int status) {
CopyOnWriteArrayList<Conversation> list = new CopyOnWriteArrayList<Conversation>();
SQLiteDatabase db = this.getReadableDatabase();
- String[] selectionArgs = { "" + status };
+ String[] selectionArgs = { Integer.toString(status) };
Cursor cursor = db.rawQuery("select * from " + Conversation.TABLENAME
+ " where " + Conversation.STATUS + " = ? order by "
+ Conversation.CREATED + " desc", selectionArgs);
@@ -164,7 +163,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
+ "=?", selectionArgs, null, null, Message.TIME_SENT
+ " DESC", String.valueOf(limit));
} else {
- String[] selectionArgs = { conversation.getUuid(), "" + timestamp };
+ String[] selectionArgs = { conversation.getUuid(),
+ Long.toString(timestamp) };
cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION
+ "=? and " + Message.TIME_SENT + "<?", selectionArgs,
null, null, Message.TIME_SENT + " DESC",
@@ -203,7 +203,6 @@ public class DatabaseBackend extends SQLiteOpenHelper {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(Account.TABLENAME, null, null, null, null,
null, null);
- Log.d("gultsch", "found " + cursor.getCount() + " accounts");
while (cursor.moveToNext()) {
list.add(Account.fromCursor(cursor));
}
diff --git a/src/eu/siacs/conversations/persistance/FileBackend.java b/src/eu/siacs/conversations/persistance/FileBackend.java
index d8166040..2b2aa86e 100644
--- a/src/eu/siacs/conversations/persistance/FileBackend.java
+++ b/src/eu/siacs/conversations/persistance/FileBackend.java
@@ -29,6 +29,7 @@ import android.util.Base64;
import android.util.Base64OutputStream;
import android.util.Log;
import android.util.LruCache;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
@@ -154,7 +155,7 @@ public class FileBackend {
Bitmap originalBitmap;
BitmapFactory.Options options = new BitmapFactory.Options();
int inSampleSize = (int) Math.pow(2, sampleSize);
- Log.d("xmppService", "reading bitmap with sample size "
+ Log.d(Config.LOGTAG, "reading bitmap with sample size "
+ inSampleSize);
options.inSampleSize = inSampleSize;
originalBitmap = BitmapFactory.decodeStream(is, null, options);
@@ -179,7 +180,7 @@ public class FileBackend {
long size = file.getSize();
int width = scalledBitmap.getWidth();
int height = scalledBitmap.getHeight();
- message.setBody("" + size + "," + width + "," + height);
+ message.setBody(Long.toString(size) + ',' + width + ',' + height);
return file;
} catch (FileNotFoundException e) {
throw new ImageCopyException(R.string.error_file_not_found);
@@ -267,7 +268,7 @@ public class FileBackend {
try {
this.deleteFile(file);
} catch (IOException e) {
- Log.d("xmppService",
+ Log.d(Config.LOGTAG,
"error deleting file: " + file.getAbsolutePath());
}
}
@@ -351,7 +352,7 @@ public class FileBackend {
file.renameTo(new File(filename));
return true;
} else {
- Log.d("xmppService", "sha1sum mismatch for " + avatar.owner);
+ Log.d(Config.LOGTAG, "sha1sum mismatch for " + avatar.owner);
file.delete();
return false;
}
diff --git a/src/eu/siacs/conversations/services/Defaults.java b/src/eu/siacs/conversations/services/Defaults.java
deleted file mode 100644
index c942dd48..00000000
--- a/src/eu/siacs/conversations/services/Defaults.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package eu.siacs.conversations.services;
-
-import android.graphics.Bitmap;
-
-public final class Defaults {
- public static final int AVATAR_SIZE = 192;
- public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.WEBP;
- private Defaults() {
-
- }
-}
diff --git a/src/eu/siacs/conversations/services/EventReceiver.java b/src/eu/siacs/conversations/services/EventReceiver.java
index a13d51f2..c0bf67f3 100644
--- a/src/eu/siacs/conversations/services/EventReceiver.java
+++ b/src/eu/siacs/conversations/services/EventReceiver.java
@@ -3,6 +3,7 @@ package eu.siacs.conversations.services;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+
public class EventReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/src/eu/siacs/conversations/services/ImageProvider.java b/src/eu/siacs/conversations/services/ImageProvider.java
index 7ab57f5e..15b86802 100644
--- a/src/eu/siacs/conversations/services/ImageProvider.java
+++ b/src/eu/siacs/conversations/services/ImageProvider.java
@@ -2,8 +2,8 @@ package eu.siacs.conversations.services;
import java.io.File;
import java.io.FileNotFoundException;
-import java.io.IOException;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
@@ -27,7 +27,7 @@ public class ImageProvider extends ContentProvider {
DatabaseBackend databaseBackend = DatabaseBackend
.getInstance(getContext());
String uuids = uri.getPath();
- Log.d("xmppService", "uuids = " + uuids+" mode="+mode);
+ Log.d(Config.LOGTAG, "uuids = " + uuids + " mode=" + mode);
if (uuids == null) {
throw new FileNotFoundException();
}
@@ -37,21 +37,21 @@ public class ImageProvider extends ContentProvider {
}
String conversationUuid = uuidsSplited[1];
String messageUuid = uuidsSplited[2].split("\\.")[0];
-
- Log.d("xmppService","messageUuid="+messageUuid);
-
+
+ Log.d(Config.LOGTAG, "messageUuid=" + messageUuid);
+
Conversation conversation = databaseBackend
.findConversationByUuid(conversationUuid);
if (conversation == null) {
- throw new FileNotFoundException("conversation " + conversationUuid
- + " could not be found");
+ throw new FileNotFoundException("conversation "
+ + conversationUuid + " could not be found");
}
Message message = databaseBackend.findMessageByUuid(messageUuid);
if (message == null) {
throw new FileNotFoundException("message " + messageUuid
+ " could not be found");
}
-
+
Account account = databaseBackend.findAccountByUuid(conversation
.getAccountUuid());
if (account == null) {
@@ -60,7 +60,7 @@ public class ImageProvider extends ContentProvider {
}
message.setConversation(conversation);
conversation.setAccount(account);
-
+
File file = fileBackend.getJingleFileLegacy(message);
pfd = ParcelFileDescriptor.open(file,
ParcelFileDescriptor.MODE_READ_ONLY);
@@ -100,13 +100,10 @@ public class ImageProvider extends ContentProvider {
public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
return 0;
}
-
+
public static Uri getProviderUri(Message message) {
- return Uri
- .parse("content://eu.siacs.conversations.images/"
- + message.getConversationUuid()
- + "/"
- + message.getUuid()
- + ".webp");
+ return Uri.parse("content://eu.siacs.conversations.images/"
+ + message.getConversationUuid() + "/" + message.getUuid()
+ + ".webp");
}
} \ No newline at end of file
diff --git a/src/eu/siacs/conversations/services/XmppConnectionService.java b/src/eu/siacs/conversations/services/XmppConnectionService.java
index c535f1a3..5c5288de 100644
--- a/src/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/eu/siacs/conversations/services/XmppConnectionService.java
@@ -20,6 +20,7 @@ import de.duenndns.ssl.MemorizingTrustManager;
import net.java.otr4j.OtrException;
import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionStatus;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.entities.Account;
@@ -49,6 +50,7 @@ import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.OnBindListener;
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
+import eu.siacs.conversations.xmpp.OnMessageAcknowledged;
import eu.siacs.conversations.xmpp.OnStatusChanged;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager;
@@ -82,20 +84,13 @@ import android.util.Log;
public class XmppConnectionService extends Service {
- protected static final String LOGTAG = "xmppService";
public DatabaseBackend databaseBackend;
private FileBackend fileBackend;
public long startDate;
- private static final int PING_MAX_INTERVAL = 300;
- private static final int PING_MIN_INTERVAL = 30;
- private static final int PING_TIMEOUT = 10;
- private static final int CONNECT_TIMEOUT = 90;
- public static final long CARBON_GRACE_PERIOD = 60000L;
-
private static String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
-
+
private MemorizingTrustManager mMemorizingTrustManager;
private MessageParser mMessageParser = new MessageParser(this);
@@ -103,7 +98,7 @@ public class XmppConnectionService extends Service {
private IqParser mIqParser = new IqParser(this);
private MessageGenerator mMessageGenerator = new MessageGenerator();
private PresenceGenerator mPresenceGenerator = new PresenceGenerator();
-
+
private List<Account> accounts;
private CopyOnWriteArrayList<Conversation> conversations = null;
private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(
@@ -118,9 +113,9 @@ public class XmppConnectionService extends Service {
@Override
public void onContactStatusChanged(Contact contact, boolean online) {
- Conversation conversation = find(getConversations(),contact);
+ Conversation conversation = find(getConversations(), contact);
if (conversation != null) {
- conversation.endOtrIfNeeded();
+ conversation.resetOtrSession();
if (online && (contact.getPresences().size() == 1)) {
sendUnsendMessages(conversation);
}
@@ -146,14 +141,16 @@ public class XmppConnectionService extends Service {
@Override
public void onStatusChanged(Account account) {
+ XmppConnection connection = account.getXmppConnection();
if (mOnAccountUpdate != null) {
- mOnAccountUpdate.onAccountUpdate();;
+ mOnAccountUpdate.onAccountUpdate();
+ ;
}
if (account.getStatus() == Account.STATUS_ONLINE) {
- for(Conversation conversation : account.pendingConferenceLeaves) {
+ for (Conversation conversation : account.pendingConferenceLeaves) {
leaveMuc(conversation);
}
- for(Conversation conversation : account.pendingConferenceJoins) {
+ for (Conversation conversation : account.pendingConferenceJoins) {
joinMuc(conversation);
}
mJingleConnectionManager.cancelInTransmission();
@@ -164,27 +161,36 @@ public class XmppConnectionService extends Service {
sendUnsendMessages(conversations.get(i));
}
}
+ if (connection != null && connection.getFeatures().csi()) {
+ if (checkListeners()) {
+ Log.d(Config.LOGTAG, account.getJid()
+ + " sending csi//inactive");
+ connection.sendInactive();
+ } else {
+ Log.d(Config.LOGTAG, account.getJid()
+ + " sending csi//active");
+ connection.sendActive();
+ }
+ }
syncDirtyContacts(account);
- scheduleWakeupCall(PING_MAX_INTERVAL, true);
+ scheduleWakeupCall(Config.PING_MAX_INTERVAL, true);
} else if (account.getStatus() == Account.STATUS_OFFLINE) {
+ resetSendingToWaiting(account);
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
int timeToReconnect = mRandom.nextInt(50) + 10;
scheduleWakeupCall(timeToReconnect, false);
}
-
} else if (account.getStatus() == Account.STATUS_REGISTRATION_SUCCESSFULL) {
databaseBackend.updateAccount(account);
reconnectAccount(account, true);
} else if ((account.getStatus() != Account.STATUS_CONNECTING)
&& (account.getStatus() != Account.STATUS_NO_INTERNET)) {
- XmppConnection connection = account.getXmppConnection();
- if (connection!=null) {
+ if (connection != null) {
int next = connection.getTimeToNextAttempt();
- Log.d(LOGTAG, account.getJid()
- + ": error connecting account. try again in " + next
- + "s for the "
- + (connection.getAttempt() + 1)
- + " time");
+ Log.d(Config.LOGTAG, account.getJid()
+ + ": error connecting account. try again in "
+ + next + "s for the "
+ + (connection.getAttempt() + 1) + " time");
scheduleWakeupCall((int) (next * 1.2), false);
}
}
@@ -209,19 +215,39 @@ public class XmppConnectionService extends Service {
private PowerManager pm;
private OnBindListener mOnBindListener = new OnBindListener() {
- @Override
- public void onBind(final Account account) {
- account.getRoster().clearPresences();
- account.clearPresences(); // self presences
- account.pendingConferenceJoins.clear();
- account.pendingConferenceLeaves.clear();
- fetchRosterFromServer(account);
- fetchBookmarks(account);
- sendPresencePacket(account, mPresenceGenerator.sendPresence(account));
- connectMultiModeConversations(account);
- updateConversationUi();
+ @Override
+ public void onBind(final Account account) {
+ account.getRoster().clearPresences();
+ account.clearPresences(); // self presences
+ account.pendingConferenceJoins.clear();
+ account.pendingConferenceLeaves.clear();
+ fetchRosterFromServer(account);
+ fetchBookmarks(account);
+ sendPresencePacket(account,
+ mPresenceGenerator.sendPresence(account));
+ connectMultiModeConversations(account);
+ updateConversationUi();
+ }
+ };
+
+ private OnMessageAcknowledged mOnMessageAcknowledgedListener = new OnMessageAcknowledged() {
+
+ @Override
+ public void onMessageAcknowledged(Account account, String uuid) {
+ for (Conversation conversation : getConversations()) {
+ if (conversation.getAccount() == account) {
+ for (Message message : conversation.getMessages()) {
+ if ((message.getStatus() == Message.STATUS_UNSEND || message
+ .getStatus() == Message.STATUS_WAITING)
+ && message.getUuid().equals(uuid)) {
+ markMessage(message, Message.STATUS_SEND);
+ return;
+ }
+ }
+ }
}
- };
+ }
+ };
public PgpEngine getPgpEngine() {
if (pgpServiceConnection.isBound()) {
@@ -244,12 +270,12 @@ public class XmppConnectionService extends Service {
public Message attachImageToConversation(final Conversation conversation,
final Uri uri, final UiCallback<Message> callback) {
final Message message;
- if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) {
+ if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) {
message = new Message(conversation, "",
Message.ENCRYPTION_DECRYPTED);
} else {
message = new Message(conversation, "",
- conversation.getNextEncryption());
+ conversation.getNextEncryption(forceEncryption()));
}
message.setPresence(conversation.getNextPresence());
message.setType(Message.TYPE_IMAGE);
@@ -260,7 +286,7 @@ public class XmppConnectionService extends Service {
public void run() {
try {
getFileBackend().copyImageToPrivateStorage(message, uri);
- if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) {
+ if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) {
getPgpEngine().encrypt(message, callback);
} else {
callback.success(message);
@@ -274,11 +300,11 @@ public class XmppConnectionService extends Service {
}
public Conversation find(Bookmark bookmark) {
- return find(bookmark.getAccount(),bookmark.getJid());
+ return find(bookmark.getAccount(), bookmark.getJid());
}
-
+
public Conversation find(Account account, String jid) {
- return find(getConversations(),account,jid);
+ return find(getConversations(), account, jid);
}
public class XmppConnectionBinder extends Binder {
@@ -320,12 +346,15 @@ public class XmppConnectionService extends Service {
}
}
if (account.getStatus() == Account.STATUS_ONLINE) {
- long lastReceived = account.getXmppConnection().getLastPacketReceived();
- long lastSent = account.getXmppConnection().getLastPingSent();
- if (lastSent - lastReceived >= PING_TIMEOUT * 1000) {
- Log.d(LOGTAG, account.getJid() + ": ping timeout");
+ long lastReceived = account.getXmppConnection()
+ .getLastPacketReceived();
+ long lastSent = account.getXmppConnection()
+ .getLastPingSent();
+ if (lastSent - lastReceived >= Config.PING_TIMEOUT * 1000) {
+ Log.d(Config.LOGTAG, account.getJid()
+ + ": ping timeout");
this.reconnectAccount(account, true);
- } else if (SystemClock.elapsedRealtime() - lastReceived >= PING_MIN_INTERVAL * 1000) {
+ } else if (SystemClock.elapsedRealtime() - lastReceived >= Config.PING_MIN_INTERVAL * 1000) {
account.getXmppConnection().sendPing();
this.scheduleWakeupCall(2, false);
}
@@ -337,8 +366,8 @@ public class XmppConnectionService extends Service {
new Thread(account.getXmppConnection()).start();
} else if ((account.getStatus() == Account.STATUS_CONNECTING)
&& ((SystemClock.elapsedRealtime() - account
- .getXmppConnection().getLastConnect()) / 1000 >= CONNECT_TIMEOUT)) {
- Log.d(LOGTAG, account.getJid()
+ .getXmppConnection().getLastConnect()) / 1000 >= Config.CONNECT_TIMEOUT)) {
+ Log.d(Config.LOGTAG, account.getJid()
+ ": time out during connect reconnecting");
reconnectAccount(account, true);
} else {
@@ -347,7 +376,7 @@ public class XmppConnectionService extends Service {
}
}
// in any case. reschedule wakup call
- this.scheduleWakeupCall(PING_MAX_INTERVAL, true);
+ this.scheduleWakeupCall(Config.PING_MAX_INTERVAL, true);
}
if (mOnAccountUpdate != null) {
mOnAccountUpdate.onAccountUpdate();
@@ -369,7 +398,8 @@ public class XmppConnectionService extends Service {
ExceptionHelper.init(getApplicationContext());
PRNGFixes.apply();
this.mRandom = new SecureRandom();
- this.mMemorizingTrustManager = new MemorizingTrustManager(getApplicationContext());
+ this.mMemorizingTrustManager = new MemorizingTrustManager(
+ getApplicationContext());
this.databaseBackend = DatabaseBackend
.getInstance(getApplicationContext());
this.fileBackend = new FileBackend(getApplicationContext());
@@ -416,7 +446,7 @@ public class XmppConnectionService extends Service {
.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, EventReceiver.class);
alarmManager.cancel(PendingIntent.getBroadcast(context, 0, intent, 0));
- Log.d(LOGTAG, "good bye");
+ Log.d(Config.LOGTAG, "good bye");
stopSelf();
}
@@ -466,10 +496,11 @@ public class XmppConnectionService extends Service {
connection.setOnMessagePacketReceivedListener(this.mMessageParser);
connection.setOnStatusChangedListener(this.statusListener);
connection.setOnPresencePacketReceivedListener(this.mPresenceParser);
- connection
- .setOnUnregisteredIqPacketReceivedListener(this.mIqParser);
+ connection.setOnUnregisteredIqPacketReceivedListener(this.mIqParser);
connection.setOnJinglePacketReceivedListener(this.jingleListener);
connection.setOnBindListener(this.mOnBindListener);
+ connection
+ .setOnMessageAcknowledgeListener(this.mOnMessageAcknowledgedListener);
return connection;
}
@@ -485,8 +516,8 @@ public class XmppConnectionService extends Service {
if (message.getEncryption() == Message.ENCRYPTION_OTR) {
if (!conv.hasValidOtrSession()
&& (message.getPresence() != null)) {
- conv.startOtrSession(getApplicationContext(),
- message.getPresence(), true);
+ conv.startOtrSession(this, message.getPresence(),
+ true);
message.setStatus(Message.STATUS_WAITING);
} else if (conv.hasValidOtrSession()
&& conv.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) {
@@ -505,8 +536,7 @@ public class XmppConnectionService extends Service {
if (message.getEncryption() == Message.ENCRYPTION_OTR) {
if (!conv.hasValidOtrSession()
&& (message.getPresence() != null)) {
- conv.startOtrSession(getApplicationContext(),
- message.getPresence(), true);
+ conv.startOtrSession(this, message.getPresence(), true);
message.setStatus(Message.STATUS_WAITING);
} else if (conv.hasValidOtrSession()
&& conv.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) {
@@ -514,8 +544,7 @@ public class XmppConnectionService extends Service {
.getUserID());
packet = mMessageGenerator.generateOtrChat(message);
send = true;
- message.setStatus(Message.STATUS_SEND);
-
+
} else if (message.getPresence() == null) {
message.setStatus(Message.STATUS_WAITING);
}
@@ -523,14 +552,10 @@ public class XmppConnectionService extends Service {
message.getConversation().endOtrIfNeeded();
failWaitingOtrMessages(message.getConversation());
packet = mMessageGenerator.generatePgpChat(message);
- message.setStatus(Message.STATUS_SEND);
send = true;
} else {
message.getConversation().endOtrIfNeeded();
failWaitingOtrMessages(message.getConversation());
- if (message.getConversation().getMode() == Conversation.MODE_SINGLE || message.getType() == Message.TYPE_PRIVATE) {
- message.setStatus(Message.STATUS_SEND);
- }
packet = mMessageGenerator.generateChat(message);
send = true;
}
@@ -542,31 +567,38 @@ public class XmppConnectionService extends Service {
String pgpBody = message.getEncryptedBody();
String decryptedBody = message.getBody();
message.setBody(pgpBody);
+ message.setEncryption(Message.ENCRYPTION_PGP);
databaseBackend.createMessage(message);
saveInDb = false;
message.setBody(decryptedBody);
+ message.setEncryption(Message.ENCRYPTION_DECRYPTED);
} else if (message.getEncryption() == Message.ENCRYPTION_OTR) {
if (conv.hasValidOtrSession()) {
message.setPresence(conv.getOtrSession().getSessionID()
.getUserID());
} else if (!conv.hasValidOtrSession()
&& message.getPresence() != null) {
- conv.startOtrSession(getApplicationContext(),
- message.getPresence(), false);
+ conv.startOtrSession(this, message.getPresence(), false);
}
}
}
}
if (saveInDb) {
- databaseBackend.createMessage(message);
+ if (message.getEncryption() == Message.ENCRYPTION_NONE
+ || saveEncryptedMessages()) {
+ databaseBackend.createMessage(message);
+ }
}
conv.getMessages().add(message);
- updateConversationUi();
if ((send) && (packet != null)) {
+ if (!account.getXmppConnection().getFeatures().sm()
+ && conv.getMode() != Conversation.MODE_MULTI) {
+ message.setStatus(Message.STATUS_SEND);
+ }
sendMessagePacket(account, packet);
}
-
+ updateConversationUi();
}
private void sendUnsendMessages(Conversation conversation) {
@@ -587,14 +619,13 @@ public class XmppConnectionService extends Service {
if (!message.getConversation().hasValidOtrSession()) {
if ((message.getPresence() != null)
&& (presences.has(message.getPresence()))) {
- message.getConversation().startOtrSession(
- getApplicationContext(), message.getPresence(),
- true);
+ message.getConversation().startOtrSession(this,
+ message.getPresence(), true);
} else {
if (presences.size() == 1) {
String presence = presences.asStringArray()[0];
- message.getConversation().startOtrSession(
- getApplicationContext(), presence, true);
+ message.getConversation().startOtrSession(this,
+ presence, true);
}
}
} else {
@@ -632,7 +663,7 @@ public class XmppConnectionService extends Service {
}
}
if (packet != null) {
- sendMessagePacket(account,packet);
+ sendMessagePacket(account, packet);
markMessage(message, Message.STATUS_SEND);
}
}
@@ -640,10 +671,10 @@ public class XmppConnectionService extends Service {
public void fetchRosterFromServer(Account account) {
IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
if (!"".equals(account.getRosterVersion())) {
- Log.d(LOGTAG, account.getJid() + ": fetching roster version "
- + account.getRosterVersion());
+ Log.d(Config.LOGTAG, account.getJid()
+ + ": fetching roster version " + account.getRosterVersion());
} else {
- Log.d(LOGTAG, account.getJid() + ": fetching roster");
+ Log.d(Config.LOGTAG, account.getJid() + ": fetching roster");
}
iqPacket.query("jabber:iq:roster").setAttribute("ver",
account.getRosterVersion());
@@ -661,29 +692,31 @@ public class XmppConnectionService extends Service {
}
});
}
-
+
public void fetchBookmarks(Account account) {
IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
Element query = iqPacket.query("jabber:iq:private");
query.addChild("storage", "storage:bookmarks");
OnIqPacketReceived callback = new OnIqPacketReceived() {
-
+
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
Element query = packet.query();
List<Bookmark> bookmarks = new CopyOnWriteArrayList<Bookmark>();
- Element storage = query.findChild("storage", "storage:bookmarks");
- if (storage!=null) {
- for(Element item : storage.getChildren()) {
+ Element storage = query.findChild("storage",
+ "storage:bookmarks");
+ if (storage != null) {
+ for (Element item : storage.getChildren()) {
if (item.getName().equals("conference")) {
- Bookmark bookmark = Bookmark.parse(item,account);
+ Bookmark bookmark = Bookmark.parse(item, account);
bookmarks.add(bookmark);
Conversation conversation = find(bookmark);
- if (conversation!=null) {
+ if (conversation != null) {
conversation.setBookmark(bookmark);
} else {
if (bookmark.autojoin()) {
- conversation = findOrCreateConversation(account, bookmark.getJid(), true);
+ conversation = findOrCreateConversation(
+ account, bookmark.getJid(), true);
conversation.setBookmark(bookmark);
joinMuc(conversation);
}
@@ -695,17 +728,17 @@ public class XmppConnectionService extends Service {
}
};
sendIqPacket(account, iqPacket, callback);
-
+
}
-
+
public void pushBookmarks(Account account) {
IqPacket iqPacket = new IqPacket(IqPacket.TYPE_SET);
Element query = iqPacket.query("jabber:iq:private");
Element storage = query.addChild("storage", "storage:bookmarks");
- for(Bookmark bookmark : account.getBookmarks()) {
+ for (Bookmark bookmark : account.getBookmarks()) {
storage.addChild(bookmark.toElement());
}
- sendIqPacket(account, iqPacket,null);
+ sendIqPacket(account, iqPacket, null);
}
private void mergePhoneContactsWithRoster() {
@@ -750,13 +783,26 @@ public class XmppConnectionService extends Service {
conv.setMessages(databaseBackend.getMessages(conv, 50));
}
}
-
+
return this.conversations;
}
-
+
public void populateWithOrderedConversations(List<Conversation> list) {
+ populateWithOrderedConversations(list, true);
+ }
+
+ public void populateWithOrderedConversations(List<Conversation> list,
+ boolean includeConferences) {
list.clear();
- list.addAll(getConversations());
+ if (includeConferences) {
+ list.addAll(getConversations());
+ } else {
+ for (Conversation conversation : getConversations()) {
+ if (conversation.getMode() == Conversation.MODE_SINGLE) {
+ list.add(conversation);
+ }
+ }
+ }
Collections.sort(list, new Comparator<Conversation>() {
@Override
public int compare(Conversation lhs, Conversation rhs) {
@@ -796,7 +842,8 @@ public class XmppConnectionService extends Service {
return null;
}
- public Conversation find(List<Conversation> haystack, Account account, String jid) {
+ public Conversation find(List<Conversation> haystack, Account account,
+ String jid) {
for (Conversation conversation : haystack) {
if ((conversation.getAccount().equals(account))
&& (conversation.getContactJid().split("/")[0].equals(jid))) {
@@ -805,15 +852,14 @@ public class XmppConnectionService extends Service {
}
return null;
}
-
-
+
public Conversation findOrCreateConversation(Account account, String jid,
boolean muc) {
Conversation conversation = find(account, jid);
if (conversation != null) {
return conversation;
}
- conversation = databaseBackend.findConversation(account,jid);
+ conversation = databaseBackend.findConversation(account, jid);
if (conversation != null) {
conversation.setStatus(Conversation.STATUS_AVAILABLE);
conversation.setAccount(account);
@@ -850,7 +896,7 @@ public class XmppConnectionService extends Service {
public void archiveConversation(Conversation conversation) {
if (conversation.getMode() == Conversation.MODE_MULTI) {
Bookmark bookmark = conversation.getBookmark();
- if (bookmark!=null && bookmark.autojoin()) {
+ if (bookmark != null && bookmark.autojoin()) {
bookmark.setAutojoin(false);
pushBookmarks(bookmark.getAccount());
}
@@ -890,7 +936,7 @@ public class XmppConnectionService extends Service {
}
public void deleteAccount(Account account) {
- for(Conversation conversation : conversations) {
+ for (Conversation conversation : conversations) {
if (conversation.getAccount() == account) {
if (conversation.getMode() == Conversation.MODE_MULTI) {
leaveMuc(conversation);
@@ -911,6 +957,9 @@ public class XmppConnectionService extends Service {
public void setOnConversationListChangedListener(
OnConversationUpdate listener) {
+ if (checkListeners()) {
+ switchToForeground();
+ }
this.mOnConversationUpdate = listener;
this.convChangedListenerCount++;
}
@@ -919,10 +968,16 @@ public class XmppConnectionService extends Service {
this.convChangedListenerCount--;
if (this.convChangedListenerCount == 0) {
this.mOnConversationUpdate = null;
+ if (checkListeners()) {
+ switchToBackground();
+ }
}
}
public void setOnAccountListChangedListener(OnAccountUpdate listener) {
+ if (checkListeners()) {
+ switchToForeground();
+ }
this.mOnAccountUpdate = listener;
this.accountChangedListenerCount++;
}
@@ -931,15 +986,55 @@ public class XmppConnectionService extends Service {
this.accountChangedListenerCount--;
if (this.accountChangedListenerCount == 0) {
this.mOnAccountUpdate = null;
+ if (checkListeners()) {
+ switchToBackground();
+ }
}
}
-
+
public void setOnRosterUpdateListener(OnRosterUpdate listener) {
+ if (checkListeners()) {
+ switchToForeground();
+ }
this.mOnRosterUpdate = listener;
}
public void removeOnRosterUpdateListener() {
this.mOnRosterUpdate = null;
+ if (checkListeners()) {
+ switchToBackground();
+ }
+ }
+
+ private boolean checkListeners() {
+ return (this.mOnAccountUpdate == null
+ && this.mOnConversationUpdate == null && this.mOnRosterUpdate == null);
+ }
+
+ private void switchToForeground() {
+ for (Account account : getAccounts()) {
+ if (account.getStatus() == Account.STATUS_ONLINE) {
+ XmppConnection connection = account.getXmppConnection();
+ if (connection != null && connection.getFeatures().csi()) {
+ connection.sendActive();
+ Log.d(Config.LOGTAG, account.getJid()
+ + " sending csi//active");
+ }
+ }
+ }
+ }
+
+ private void switchToBackground() {
+ for (Account account : getAccounts()) {
+ if (account.getStatus() == Account.STATUS_ONLINE) {
+ XmppConnection connection = account.getXmppConnection();
+ if (connection != null && connection.getFeatures().csi()) {
+ connection.sendInactive();
+ Log.d(Config.LOGTAG, account.getJid()
+ + " sending csi//inactive");
+ }
+ }
+ }
}
public void connectMultiModeConversations(Account account) {
@@ -958,14 +1053,19 @@ public class XmppConnectionService extends Service {
account.pendingConferenceJoins.remove(conversation);
account.pendingConferenceLeaves.remove(conversation);
if (account.getStatus() == Account.STATUS_ONLINE) {
- Log.d(LOGTAG,"joining conversation "+conversation.getContactJid());
+ Log.d(Config.LOGTAG,
+ "joining conversation " + conversation.getContactJid());
String nick = conversation.getMucOptions().getProposedNick();
conversation.getMucOptions().setJoinNick(nick);
PresencePacket packet = new PresencePacket();
String joinJid = conversation.getMucOptions().getJoinJid();
- packet.setAttribute("to",conversation.getMucOptions().getJoinJid());
+ packet.setAttribute("to", conversation.getMucOptions().getJoinJid());
Element x = new Element("x");
x.setAttribute("xmlns", "http://jabber.org/protocol/muc");
+ if (conversation.getMucOptions().getPassword() != null) {
+ Element password = x.addChild("password");
+ password.setContent(conversation.getMucOptions().getPassword());
+ }
String sig = account.getPgpSignature();
if (sig != null) {
packet.addChild("status").setContent("online");
@@ -975,8 +1075,8 @@ public class XmppConnectionService extends Service {
final SimpleDateFormat mDateFormat = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
mDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- Date date = new Date(
- conversation.getLatestMessage().getTimeSent() + 1000);
+ Date date = new Date(conversation.getLatestMessage()
+ .getTimeSent() + 1000);
x.addChild("history").setAttribute("since",
mDateFormat.format(date));
}
@@ -998,6 +1098,20 @@ public class XmppConnectionService extends Service {
this.renameListener = listener;
}
+ public void providePasswordForMuc(Conversation conversation, String password) {
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ conversation.getMucOptions().setPassword(password);
+ if (conversation.getBookmark() != null
+ && conversation.getMucOptions().isPasswordChanged()) {
+ if (!conversation.getBookmark().autojoin()) {
+ conversation.getBookmark().setAutojoin(true);
+ }
+ pushBookmarks(conversation.getAccount());
+ }
+ joinMuc(conversation);
+ }
+ }
+
public void renameInMuc(final Conversation conversation, final String nick) {
final MucOptions options = conversation.getMucOptions();
options.setJoinNick(nick);
@@ -1011,10 +1125,11 @@ public class XmppConnectionService extends Service {
renameListener.onRename(success);
}
if (success) {
- conversation.setContactJid(conversation.getMucOptions().getJoinJid());
+ conversation.setContactJid(conversation.getMucOptions()
+ .getJoinJid());
databaseBackend.updateConversation(conversation);
Bookmark bookmark = conversation.getBookmark();
- if (bookmark!=null) {
+ if (bookmark != null) {
bookmark.setNick(nick);
pushBookmarks(bookmark.getAccount());
}
@@ -1023,7 +1138,7 @@ public class XmppConnectionService extends Service {
});
options.flagAboutToRename();
PresencePacket packet = new PresencePacket();
- packet.setAttribute("to",options.getJoinJid());
+ packet.setAttribute("to", options.getJoinJid());
packet.setAttribute("from", conversation.getAccount().getFullJid());
String sig = account.getPgpSignature();
@@ -1031,13 +1146,13 @@ public class XmppConnectionService extends Service {
packet.addChild("status").setContent("online");
packet.addChild("x", "jabber:x:signed").setContent(sig);
}
- sendPresencePacket(account,packet);
+ sendPresencePacket(account, packet);
} else {
conversation.setContactJid(options.getJoinJid());
databaseBackend.updateConversation(conversation);
if (conversation.getAccount().getStatus() == Account.STATUS_ONLINE) {
Bookmark bookmark = conversation.getBookmark();
- if (bookmark!=null) {
+ if (bookmark != null) {
bookmark.setNick(nick);
pushBookmarks(bookmark.getAccount());
}
@@ -1055,10 +1170,11 @@ public class XmppConnectionService extends Service {
packet.setAttribute("to", conversation.getMucOptions().getJoinJid());
packet.setAttribute("from", conversation.getAccount().getFullJid());
packet.setAttribute("type", "unavailable");
- sendPresencePacket(conversation.getAccount(),packet);
+ sendPresencePacket(conversation.getAccount(), packet);
conversation.getMucOptions().setOffline();
conversation.deregisterWithBookmark();
- Log.d(LOGTAG,conversation.getAccount().getJid()+" leaving muc "+conversation.getContactJid());
+ Log.d(Config.LOGTAG, conversation.getAccount().getJid()
+ + " leaving muc " + conversation.getContactJid());
} else {
account.pendingConferenceLeaves.add(conversation);
}
@@ -1099,7 +1215,6 @@ public class XmppConnectionService extends Service {
pushContactToServer(contact);
}
if (contact.getOption(Contact.Options.DIRTY_DELETE)) {
- Log.d(LOGTAG, "dirty delete");
deleteContactOnServer(contact);
}
}
@@ -1119,9 +1234,10 @@ public class XmppConnectionService extends Service {
Account account = conversation.getAccount();
List<Message> messages = conversation.getMessages();
Session otrSession = conversation.getOtrSession();
- Log.d(LOGTAG, account.getJid() + " otr session established with "
- + conversation.getContactJid() + "/"
- + otrSession.getSessionID().getUserID());
+ Log.d(Config.LOGTAG,
+ account.getJid() + " otr session established with "
+ + conversation.getContactJid() + "/"
+ + otrSession.getSessionID().getUserID());
for (int i = 0; i < messages.size(); ++i) {
Message msg = messages.get(i);
if ((msg.getStatus() == Message.STATUS_UNSEND || msg.getStatus() == Message.STATUS_WAITING)
@@ -1133,7 +1249,7 @@ public class XmppConnectionService extends Service {
if (outPacket != null) {
msg.setStatus(Message.STATUS_SEND);
databaseBackend.updateMessage(msg);
- sendMessagePacket(account,outPacket);
+ sendMessagePacket(account, outPacket);
}
} else if (msg.getType() == Message.TYPE_IMAGE) {
mJingleConnectionManager.createNewConnection(msg);
@@ -1160,7 +1276,7 @@ public class XmppConnectionService extends Service {
packet.setBody(otrSession
.transformSending(CryptoHelper.FILETRANSFER
+ CryptoHelper.bytesToHex(symmetricKey)));
- sendMessagePacket(account,packet);
+ sendMessagePacket(account, packet);
conversation.setSymmetricKey(symmetricKey);
return true;
} catch (OtrException e) {
@@ -1176,26 +1292,30 @@ public class XmppConnectionService extends Service {
Account account = contact.getAccount();
if (account.getStatus() == Account.STATUS_ONLINE) {
boolean ask = contact.getOption(Contact.Options.ASKING);
- boolean sendUpdates = contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)
+ boolean sendUpdates = contact
+ .getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)
&& contact.getOption(Contact.Options.PREEMPTIVE_GRANT);
IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
iq.query("jabber:iq:roster").addChild(contact.asElement());
account.getXmppConnection().sendIqPacket(iq, null);
if (sendUpdates) {
- sendPresencePacket(account, mPresenceGenerator.sendPresenceUpdatesTo(contact));
+ sendPresencePacket(account,
+ mPresenceGenerator.sendPresenceUpdatesTo(contact));
}
if (ask) {
- sendPresencePacket(account, mPresenceGenerator.requestPresenceUpdatesFrom(contact));
+ sendPresencePacket(account,
+ mPresenceGenerator.requestPresenceUpdatesFrom(contact));
}
}
}
-
- public void publishAvatar(Account account, Uri image, final UiCallback<Avatar> callback) {
- final Bitmap.CompressFormat format = Defaults.AVATAR_FORMAT;
- final int size = Defaults.AVATAR_SIZE;
- final Avatar avatar = getFileBackend().getPepAvatar(image, size, format);
- if (avatar!=null) {
+ public void publishAvatar(Account account, Uri image,
+ final UiCallback<Avatar> callback) {
+ final Bitmap.CompressFormat format = Config.AVATAR_FORMAT;
+ final int size = Config.AVATAR_SIZE;
+ final Avatar avatar = getFileBackend()
+ .getPepAvatar(image, size, format);
+ if (avatar != null) {
avatar.height = size;
avatar.width = size;
if (format.equals(Bitmap.CompressFormat.WEBP)) {
@@ -1211,27 +1331,33 @@ public class XmppConnectionService extends Service {
}
IqPacket packet = this.mIqGenerator.publishAvatar(avatar);
this.sendIqPacket(account, packet, new OnIqPacketReceived() {
-
+
@Override
public void onIqPacketReceived(Account account, IqPacket result) {
if (result.getType() == IqPacket.TYPE_RESULT) {
- IqPacket packet = XmppConnectionService.this.mIqGenerator.publishAvatarMetadata(avatar);
+ IqPacket packet = XmppConnectionService.this.mIqGenerator
+ .publishAvatarMetadata(avatar);
sendIqPacket(account, packet, new OnIqPacketReceived() {
-
+
@Override
- public void onIqPacketReceived(Account account, IqPacket result) {
+ public void onIqPacketReceived(Account account,
+ IqPacket result) {
if (result.getType() == IqPacket.TYPE_RESULT) {
if (account.setAvatar(avatar.getFilename())) {
databaseBackend.updateAccount(account);
}
callback.success(avatar);
} else {
- callback.error(R.string.error_publish_avatar_server_reject, avatar);
+ callback.error(
+ R.string.error_publish_avatar_server_reject,
+ avatar);
}
}
});
} else {
- callback.error(R.string.error_publish_avatar_server_reject, avatar);
+ callback.error(
+ R.string.error_publish_avatar_server_reject,
+ avatar);
}
}
});
@@ -1239,55 +1365,76 @@ public class XmppConnectionService extends Service {
callback.error(R.string.error_publish_avatar_converting, null);
}
}
-
+
public void fetchAvatar(Account account, Avatar avatar) {
fetchAvatar(account, avatar, null);
}
-
- public void fetchAvatar(Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
- Log.d(LOGTAG,account.getJid()+": retrieving avatar for "+avatar.owner);
+
+ public void fetchAvatar(Account account, final Avatar avatar,
+ final UiCallback<Avatar> callback) {
IqPacket packet = this.mIqGenerator.retrieveAvatar(avatar);
sendIqPacket(account, packet, new OnIqPacketReceived() {
-
+
@Override
public void onIqPacketReceived(Account account, IqPacket result) {
- avatar.image = mIqParser.avatarData(result);
- if (avatar.image!=null) {
- if (getFileBackend().save(avatar)) {
- if (account.getJid().equals(avatar.owner)) {
- if (account.setAvatar(avatar.getFilename())) {
- databaseBackend.updateAccount(account);
+ final String ERROR = account.getJid()
+ + ": fetching avatar for " + avatar.owner + " failed ";
+ if (result.getType() == IqPacket.TYPE_RESULT) {
+ avatar.image = mIqParser.avatarData(result);
+ if (avatar.image != null) {
+ if (getFileBackend().save(avatar)) {
+ if (account.getJid().equals(avatar.owner)) {
+ if (account.setAvatar(avatar.getFilename())) {
+ databaseBackend.updateAccount(account);
+ }
+ } else {
+ Contact contact = account.getRoster()
+ .getContact(avatar.owner);
+ contact.setAvatar(avatar.getFilename());
}
- } else {
- Contact contact = account.getRoster().getContact(avatar.owner);
- contact.setAvatar(avatar.getFilename());
- }
- if (callback!=null) {
- callback.success(avatar);
+ if (callback != null) {
+ callback.success(avatar);
+ }
+ Log.d(Config.LOGTAG, account.getJid()
+ + ": succesfully fetched avatar for "
+ + avatar.owner);
+ return;
}
- return;
+ } else {
+
+ Log.d(Config.LOGTAG, ERROR + "(parsing error)");
+ }
+ } else {
+ Element error = result.findChild("error");
+ if (error == null) {
+ Log.d(Config.LOGTAG, ERROR + "(server error)");
+ } else {
+ Log.d(Config.LOGTAG, ERROR + error.toString());
}
}
- if (callback!=null) {
+ if (callback != null) {
callback.error(0, null);
}
+
}
});
}
-
- public void checkForAvatar(Account account, final UiCallback<Avatar> callback) {
+
+ public void checkForAvatar(Account account,
+ final UiCallback<Avatar> callback) {
IqPacket packet = this.mIqGenerator.retrieveAvatarMetaData(null);
this.sendIqPacket(account, packet, new OnIqPacketReceived() {
-
+
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
if (packet.getType() == IqPacket.TYPE_RESULT) {
- Element pubsub = packet.findChild("pubsub", "http://jabber.org/protocol/pubsub");
- if (pubsub!=null) {
+ Element pubsub = packet.findChild("pubsub",
+ "http://jabber.org/protocol/pubsub");
+ if (pubsub != null) {
Element items = pubsub.findChild("items");
- if (items!=null) {
+ if (items != null) {
Avatar avatar = Avatar.parseMetadata(items);
- if (avatar!=null) {
+ if (avatar != null) {
avatar.owner = account.getJid();
if (fileBackend.isAvatarCached(avatar)) {
if (account.setAvatar(avatar.getFilename())) {
@@ -1295,7 +1442,7 @@ public class XmppConnectionService extends Service {
}
callback.success(avatar);
} else {
- fetchAvatar(account, avatar,callback);
+ fetchAvatar(account, avatar, callback);
}
return;
}
@@ -1306,7 +1453,7 @@ public class XmppConnectionService extends Service {
}
});
}
-
+
public void deleteContactOnServer(Contact contact) {
contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
contact.resetOption(Contact.Options.DIRTY_PUSH);
@@ -1339,7 +1486,8 @@ public class XmppConnectionService extends Service {
}
Thread thread = new Thread(account.getXmppConnection());
thread.start();
- scheduleWakeupCall((int) (CONNECT_TIMEOUT * 1.2), false);
+ scheduleWakeupCall((int) (Config.CONNECT_TIMEOUT * 1.2),
+ false);
}
}
}).start();
@@ -1347,7 +1495,20 @@ public class XmppConnectionService extends Service {
public void invite(Conversation conversation, String contact) {
MessagePacket packet = mMessageGenerator.invite(conversation, contact);
- sendMessagePacket(conversation.getAccount(),packet);
+ sendMessagePacket(conversation.getAccount(), packet);
+ }
+
+ public void resetSendingToWaiting(Account account) {
+ for (Conversation conversation : getConversations()) {
+ if (conversation.getAccount() == account) {
+ for (Message message : conversation.getMessages()) {
+ if (message.getType() != Message.TYPE_IMAGE
+ && message.getStatus() == Message.STATUS_UNSEND) {
+ markMessage(message, Message.STATUS_WAITING);
+ }
+ }
+ }
+ }
}
public boolean markMessage(Account account, String recipient, String uuid,
@@ -1373,6 +1534,11 @@ public class XmppConnectionService extends Service {
}
public void markMessage(Message message, int status) {
+ if (status == Message.STATUS_SEND_FAILED
+ && (message.getStatus() == Message.STATUS_SEND_RECEIVED || message
+ .getStatus() == Message.STATUS_SEND_DISPLAYED)) {
+ return;
+ }
message.setStatus(status);
databaseBackend.updateMessage(message);
updateConversationUi();
@@ -1383,10 +1549,18 @@ public class XmppConnectionService extends Service {
.getDefaultSharedPreferences(getApplicationContext());
}
+ public boolean forceEncryption() {
+ return getPreferences().getBoolean("force_encryption", false);
+ }
+
public boolean confirmMessages() {
return getPreferences().getBoolean("confirm_messages", true);
}
+ public boolean saveEncryptedMessages() {
+ return !getPreferences().getBoolean("dont_save_encrypted", false);
+ }
+
public void notifyUi(Conversation conversation, boolean notify) {
if (mOnConversationUpdate != null) {
mOnConversationUpdate.onConversationUpdate();
@@ -1395,19 +1569,19 @@ public class XmppConnectionService extends Service {
getConversations(), conversation, notify);
}
}
-
+
public void updateConversationUi() {
if (mOnConversationUpdate != null) {
mOnConversationUpdate.onConversationUpdate();
}
}
-
+
public void updateAccountUi() {
if (mOnAccountUpdate != null) {
mOnAccountUpdate.onAccountUpdate();
}
}
-
+
public void updateRosterUi() {
if (mOnRosterUpdate != null) {
mOnRosterUpdate.onRosterUpdate();
@@ -1422,7 +1596,7 @@ public class XmppConnectionService extends Service {
}
return null;
}
-
+
public Conversation findConversationByUuid(String uuid) {
for (Conversation conversation : getConversations()) {
if (conversation.getUuid().equals(uuid)) {
@@ -1438,10 +1612,11 @@ public class XmppConnectionService extends Service {
if (confirmMessages() && id != null) {
Account account = conversation.getAccount();
String to = conversation.getContactJid();
- this.sendMessagePacket(conversation.getAccount(), mMessageGenerator.confirm(account, to, id));
+ this.sendMessagePacket(conversation.getAccount(),
+ mMessageGenerator.confirm(account, to, id));
}
}
-
+
public void failWaitingOtrMessages(Conversation conversation) {
for (Message message : conversation.getMessages()) {
if (message.getEncryption() == Message.ENCRYPTION_OTR
@@ -1454,7 +1629,7 @@ public class XmppConnectionService extends Service {
public SecureRandom getRNG() {
return this.mRandom;
}
-
+
public MemorizingTrustManager getMemorizingTrustManager() {
return this.mMemorizingTrustManager;
}
@@ -1467,7 +1642,7 @@ public class XmppConnectionService extends Service {
if (account.getStatus() == Account.STATUS_ONLINE) {
MessagePacket error = this.mMessageGenerator
.generateNotAcceptable(packet);
- sendMessagePacket(account,error);
+ sendMessagePacket(account, error);
}
}
@@ -1512,43 +1687,44 @@ public class XmppConnectionService extends Service {
}
return mucServers;
}
-
+
public void sendMessagePacket(Account account, MessagePacket packet) {
account.getXmppConnection().sendMessagePacket(packet);
}
-
+
public void sendPresencePacket(Account account, PresencePacket packet) {
account.getXmppConnection().sendPresencePacket(packet);
}
-
- public void sendIqPacket(Account account, IqPacket packet, OnIqPacketReceived callback) {
+
+ public void sendIqPacket(Account account, IqPacket packet,
+ OnIqPacketReceived callback) {
account.getXmppConnection().sendIqPacket(packet, callback);
}
-
+
public MessageGenerator getMessageGenerator() {
return this.mMessageGenerator;
}
-
+
public PresenceGenerator getPresenceGenerator() {
return this.mPresenceGenerator;
}
-
+
public IqGenerator getIqGenerator() {
- return this.mIqGenerator ;
+ return this.mIqGenerator;
}
-
+
public JingleConnectionManager getJingleConnectionManager() {
return this.mJingleConnectionManager;
}
-
+
public interface OnConversationUpdate {
public void onConversationUpdate();
}
-
+
public interface OnAccountUpdate {
public void onAccountUpdate();
}
-
+
public interface OnRosterUpdate {
public void onRosterUpdate();
}
diff --git a/src/eu/siacs/conversations/ui/ChooseContactActivity.java b/src/eu/siacs/conversations/ui/ChooseContactActivity.java
index 4236ea70..277d21d6 100644
--- a/src/eu/siacs/conversations/ui/ChooseContactActivity.java
+++ b/src/eu/siacs/conversations/ui/ChooseContactActivity.java
@@ -23,13 +23,13 @@ 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<ListItem>();
private ArrayAdapter<ListItem> mContactsAdapter;
-
+
private EditText mSearchEditText;
-
+
private TextWatcher mSearchTextWatcher = new TextWatcher() {
@Override
@@ -47,7 +47,7 @@ public class ChooseContactActivity extends XmppActivity {
int count) {
}
};
-
+
private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
@Override
@@ -76,35 +76,39 @@ public class ChooseContactActivity extends XmppActivity {
return true;
}
};
-
-
-
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_choose_contact);
mListView = (ListView) findViewById(R.id.choose_contact_list);
- mContactsAdapter = new ListItemAdapter(getApplicationContext(), contacts);
+ mContactsAdapter = new ListItemAdapter(this, contacts);
mListView.setAdapter(mContactsAdapter);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
- public void onItemClick(AdapterView<?> arg0, View arg1, int position,
- long arg3) {
+ public void onItemClick(AdapterView<?> arg0, View arg1,
+ int position, long arg3) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
InputMethodManager.HIDE_IMPLICIT_ONLY);
Intent request = getIntent();
Intent data = new Intent();
- data.putExtra("contact",contacts.get(position).getJid());
- data.putExtra("account",request.getStringExtra("account"));
- data.putExtra("conversation",request.getStringExtra("conversation"));
+ ListItem mListItem = contacts.get(position);
+ data.putExtra("contact", mListItem.getJid());
+ String account = request.getStringExtra("account");
+ if (account == null && mListItem instanceof Contact) {
+ account = ((Contact) mListItem).getAccount().getJid();
+ }
+ data.putExtra("account", account);
+ data.putExtra("conversation",
+ request.getStringExtra("conversation"));
setResult(RESULT_OK, data);
finish();
}
});
}
-
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.choose_contact, menu);
@@ -121,7 +125,7 @@ public class ChooseContactActivity extends XmppActivity {
void onBackendConnected() {
filterContacts(null);
}
-
+
protected void filterContacts(String needle) {
this.contacts.clear();
for (Account account : xmppConnectionService.getAccounts()) {
diff --git a/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
index c33277f9..2cfa1635 100644
--- a/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
+++ b/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
@@ -109,7 +109,7 @@ public class ConferenceDetailsActivity extends XmppActivity {
break;
case R.id.action_edit_subject:
if (conversation != null) {
- quickEdit(conversation.getName(true), new OnValueEdited() {
+ quickEdit(conversation.getName(), new OnValueEdited() {
@Override
public void onValueEdited(String value) {
@@ -200,7 +200,7 @@ public class ConferenceDetailsActivity extends XmppActivity {
private void populateView() {
mYourPhoto.setImageBitmap(conversation.getAccount().getImage(this, 48));
- setTitle(conversation.getName(true));
+ setTitle(conversation.getName());
mFullJid.setText(conversation.getContactJid().split("/")[0]);
mYourNick.setText(conversation.getMucOptions().getActualNick());
mRoleAffiliaton = (TextView) findViewById(R.id.muc_role);
@@ -250,7 +250,8 @@ public class ConferenceDetailsActivity extends XmppActivity {
if (contact.showInRoster()) {
bm = contact.getImage(48, this);
name.setText(contact.getDisplayName());
- role.setText(user.getName() + " \u2022 " + getReadableRole(user.getRole()));
+ role.setText(user.getName() + " \u2022 "
+ + getReadableRole(user.getRole()));
} else {
bm = UIHelper.getContactPicture(user.getName(), 48, this,
false);
diff --git a/src/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/eu/siacs/conversations/ui/ContactDetailsActivity.java
index 7c13c518..8de2ce80 100644
--- a/src/eu/siacs/conversations/ui/ContactDetailsActivity.java
+++ b/src/eu/siacs/conversations/ui/ContactDetailsActivity.java
@@ -23,6 +23,7 @@ import android.view.View.OnClickListener;
import android.widget.CheckBox;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.CompoundButton;
+import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.QuickContactBadge;
import android.widget.TextView;
@@ -111,7 +112,8 @@ public class ContactDetailsActivity extends XmppActivity {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if (isChecked) {
- if (contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
+ if (contact
+ .getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
xmppConnectionService.sendPresencePacket(contact
.getAccount(),
xmppConnectionService.getPresenceGenerator()
@@ -146,7 +148,7 @@ public class ContactDetailsActivity extends XmppActivity {
};
private OnAccountUpdate accountUpdate = new OnAccountUpdate() {
-
+
@Override
public void onAccountUpdate() {
runOnUiThread(new Runnable() {
@@ -269,7 +271,7 @@ public class ContactDetailsActivity extends XmppActivity {
send.setOnCheckedChangeListener(this.mOnSendCheckedChange);
receive.setOnCheckedChangeListener(this.mOnReceiveCheckedChange);
-
+
lastseen.setText(UIHelper.lastseen(getApplicationContext(),
contact.lastseen.time));
@@ -322,16 +324,28 @@ public class ContactDetailsActivity extends XmppActivity {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for (Iterator<String> iterator = contact.getOtrFingerprints()
.iterator(); iterator.hasNext();) {
- String otrFingerprint = iterator.next();
- View view = (View) inflater.inflate(R.layout.contact_key, null);
+ final String otrFingerprint = iterator.next();
+ View view = (View) inflater.inflate(R.layout.contact_key, keys,
+ false);
TextView key = (TextView) view.findViewById(R.id.key);
TextView keyType = (TextView) view.findViewById(R.id.key_type);
+ ImageButton remove = (ImageButton) view
+ .findViewById(R.id.button_remove);
+ remove.setVisibility(View.VISIBLE);
keyType.setText("OTR Fingerprint");
key.setText(otrFingerprint);
keys.addView(view);
+ remove.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ confirmToDeleteFingerprint(otrFingerprint);
+ }
+ });
}
if (contact.getPgpKeyId() != 0) {
- View view = (View) inflater.inflate(R.layout.contact_key, null);
+ View view = (View) inflater.inflate(R.layout.contact_key, keys,
+ false);
TextView key = (TextView) view.findViewById(R.id.key);
TextView keyType = (TextView) view.findViewById(R.id.key_type);
keyType.setText("PGP Key ID");
@@ -360,10 +374,32 @@ public class ContactDetailsActivity extends XmppActivity {
}
}
+ protected void confirmToDeleteFingerprint(final String fingerprint) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.delete_fingerprint);
+ builder.setMessage(R.string.sure_delete_fingerprint);
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setPositiveButton(R.string.delete,
+ new android.content.DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (contact.deleteOtrFingerprint(fingerprint)) {
+ populateView();
+ xmppConnectionService.syncRosterToDisk(contact
+ .getAccount());
+ }
+ }
+
+ });
+ builder.create().show();
+ }
+
@Override
public void onBackendConnected() {
xmppConnectionService.setOnRosterUpdateListener(this.rosterUpdate);
- xmppConnectionService.setOnAccountListChangedListener(this.accountUpdate );
+ xmppConnectionService
+ .setOnAccountListChangedListener(this.accountUpdate);
if ((accountJid != null) && (contactJid != null)) {
Account account = xmppConnectionService
.findAccountByJid(accountJid);
diff --git a/src/eu/siacs/conversations/ui/ConversationActivity.java b/src/eu/siacs/conversations/ui/ConversationActivity.java
index c68063d2..5eedda1c 100644
--- a/src/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/eu/siacs/conversations/ui/ConversationActivity.java
@@ -1,10 +1,7 @@
package eu.siacs.conversations.ui;
-import java.io.FileNotFoundException;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.RejectedExecutionException;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Contact;
@@ -15,8 +12,8 @@ import eu.siacs.conversations.ui.adapter.ConversationAdapter;
import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.utils.UIHelper;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.app.ActionBar;
@@ -27,15 +24,8 @@ import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.IntentSender.SendIntentException;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
import android.support.v4.widget.SlidingPaneLayout;
import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener;
-import android.util.DisplayMetrics;
-import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
@@ -47,7 +37,6 @@ import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.PopupMenu.OnMenuItemClickListener;
-import android.widget.ImageView;
import android.widget.Toast;
public class ConversationActivity extends XmppActivity {
@@ -76,12 +65,10 @@ public class ConversationActivity extends XmppActivity {
private ListView listView;
private boolean paneShouldBeOpen = true;
- private boolean useSubject = true;
- private boolean showLastseen = false;
private ArrayAdapter<Conversation> listAdapter;
private OnConversationUpdate onConvChanged = new OnConversationUpdate() {
-
+
@Override
public void onConversationUpdate() {
runOnUiThread(new Runnable() {
@@ -109,9 +96,8 @@ public class ConversationActivity extends XmppActivity {
};
protected ConversationActivity activity = this;
- private DisplayMetrics metrics;
private Toast prepareImageToast;
-
+
private Uri pendingImageUri = null;
public List<Conversation> getConversationList() {
@@ -140,15 +126,12 @@ public class ConversationActivity extends XmppActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
-
- metrics = getResources().getDisplayMetrics();
-
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_conversations_overview);
listView = (ListView) findViewById(R.id.list);
-
+
getActionBar().setDisplayHomeAsUpEnabled(false);
getActionBar().setHomeButtonEnabled(false);
@@ -179,7 +162,7 @@ public class ConversationActivity extends XmppActivity {
public void onPanelOpened(View arg0) {
paneShouldBeOpen = true;
ActionBar ab = getActionBar();
- if (ab!=null) {
+ if (ab != null) {
ab.setDisplayHomeAsUpEnabled(false);
ab.setHomeButtonEnabled(false);
ab.setTitle(R.string.app_name);
@@ -194,11 +177,10 @@ public class ConversationActivity extends XmppActivity {
if ((conversationList.size() > 0)
&& (getSelectedConversation() != null)) {
ActionBar ab = getActionBar();
- if (ab!=null) {
+ if (ab != null) {
ab.setDisplayHomeAsUpEnabled(true);
ab.setHomeButtonEnabled(true);
- ab.setTitle(
- getSelectedConversation().getName(useSubject));
+ ab.setTitle(getSelectedConversation().getName());
}
invalidateOptionsMenu();
if (!getSelectedConversation().isRead()) {
@@ -232,7 +214,9 @@ public class ConversationActivity extends XmppActivity {
MenuItem menuClearHistory = (MenuItem) menu
.findItem(R.id.action_clear_history);
MenuItem menuAdd = (MenuItem) menu.findItem(R.id.action_add);
- MenuItem menuInviteContact = (MenuItem) menu.findItem(R.id.action_invite);
+ MenuItem menuInviteContact = (MenuItem) menu
+ .findItem(R.id.action_invite);
+ MenuItem menuMute = (MenuItem) menu.findItem(R.id.action_mute);
if ((spl.isOpen() && (spl.isSlideable()))) {
menuArchive.setVisible(false);
@@ -242,6 +226,7 @@ public class ConversationActivity extends XmppActivity {
menuInviteContact.setVisible(false);
menuAttach.setVisible(false);
menuClearHistory.setVisible(false);
+ menuMute.setVisible(false);
} else {
menuAdd.setVisible(!spl.isSlideable());
if (this.getSelectedConversation() != null) {
@@ -267,11 +252,12 @@ public class ConversationActivity extends XmppActivity {
@Override
public void onPresenceSelected() {
if (attachmentChoice == ATTACHMENT_CHOICE_TAKE_PHOTO) {
- pendingImageUri = xmppConnectionService.getFileBackend().getTakePhotoUri();
- Log.d("xmppService",pendingImageUri.toString());
+ pendingImageUri = xmppConnectionService.getFileBackend()
+ .getTakePhotoUri();
Intent takePictureIntent = new Intent(
MediaStore.ACTION_IMAGE_CAPTURE);
- takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,pendingImageUri);
+ takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
+ pendingImageUri);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent,
REQUEST_IMAGE_CAPTURE);
@@ -294,7 +280,7 @@ public class ConversationActivity extends XmppActivity {
private void attachFile(final int attachmentChoice) {
final Conversation conversation = getSelectedConversation();
- if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) {
+ if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) {
if (hasPgp()) {
if (conversation.getContact().getPgpKeyId() != 0) {
xmppConnectionService.getPgpEngine().hasKey(
@@ -338,7 +324,8 @@ public class ConversationActivity extends XmppActivity {
} else {
showInstallPgpDialog();
}
- } else if (getSelectedConversation().getNextEncryption() == Message.ENCRYPTION_NONE) {
+ } else if (getSelectedConversation().getNextEncryption(
+ forceEncryption()) == Message.ENCRYPTION_NONE) {
selectPresenceToAttachFile(attachmentChoice);
} else {
selectPresenceToAttachFile(attachmentChoice);
@@ -353,7 +340,7 @@ public class ConversationActivity extends XmppActivity {
return true;
case R.id.action_attach_file:
View menuAttachFile = findViewById(R.id.action_attach_file);
- if (menuAttachFile==null) {
+ if (menuAttachFile == null) {
break;
}
PopupMenu attachFilePopup = new PopupMenu(this, menuAttachFile);
@@ -405,7 +392,7 @@ public class ConversationActivity extends XmppActivity {
case R.id.action_security:
final Conversation conversation = getSelectedConversation();
View menuItemView = findViewById(R.id.action_security);
- if (menuItemView==null) {
+ if (menuItemView == null) {
break;
}
PopupMenu popup = new PopupMenu(this, menuItemView);
@@ -454,13 +441,18 @@ public class ConversationActivity extends XmppActivity {
popup.inflate(R.menu.encryption_choices);
MenuItem otr = popup.getMenu().findItem(
R.id.encryption_choice_otr);
+ MenuItem none = popup.getMenu().findItem(
+ R.id.encryption_choice_none);
if (conversation.getMode() == Conversation.MODE_MULTI) {
otr.setEnabled(false);
+ } else {
+ if (forceEncryption()) {
+ none.setVisible(false);
+ }
}
- switch (conversation.getNextEncryption()) {
+ switch (conversation.getNextEncryption(forceEncryption())) {
case Message.ENCRYPTION_NONE:
- popup.getMenu().findItem(R.id.encryption_choice_none)
- .setChecked(true);
+ none.setChecked(true);
break;
case Message.ENCRYPTION_OTR:
otr.setChecked(true);
@@ -481,6 +473,9 @@ public class ConversationActivity extends XmppActivity {
case R.id.action_clear_history:
clearHistoryDialog(getSelectedConversation());
break;
+ case R.id.action_mute:
+ muteConversationDialog(getSelectedConversation());
+ break;
default:
break;
}
@@ -523,15 +518,43 @@ public class ConversationActivity extends XmppActivity {
builder.create().show();
}
+ protected void muteConversationDialog(final Conversation conversation) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.disable_notifications_for_this_conversation);
+ final int[] durations = getResources().getIntArray(
+ R.array.mute_options_durations);
+ builder.setItems(R.array.mute_options_descriptions,
+ new OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ long till;
+ if (durations[which] == -1) {
+ till = Long.MAX_VALUE;
+ } else {
+ till = SystemClock.elapsedRealtime()
+ + (durations[which] * 1000);
+ }
+ conversation.setMutedTill(till);
+ ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager()
+ .findFragmentByTag("conversation");
+ if (selectedFragment != null) {
+ selectedFragment.updateMessages();
+ }
+ }
+ });
+ builder.create().show();
+ }
+
protected ConversationFragment swapConversationFragment() {
ConversationFragment selectedFragment = new ConversationFragment();
if (!isFinishing()) {
- FragmentTransaction transaction = getFragmentManager()
- .beginTransaction();
- transaction.replace(R.id.selected_conversation, selectedFragment,
- "conversation");
-
+ FragmentTransaction transaction = getFragmentManager()
+ .beginTransaction();
+ transaction.replace(R.id.selected_conversation, selectedFragment,
+ "conversation");
+
transaction.commitAllowingStateLoss();
}
return selectedFragment;
@@ -553,7 +576,8 @@ public class ConversationActivity extends XmppActivity {
if (xmppConnectionServiceBound) {
if ((Intent.ACTION_VIEW.equals(intent.getAction()) && (VIEW_CONVERSATION
.equals(intent.getType())))) {
- String convToView = (String) intent.getExtras().get(CONVERSATION);
+ String convToView = (String) intent.getExtras().get(
+ CONVERSATION);
updateConversationList();
for (int i = 0; i < conversationList.size(); ++i) {
if (conversationList.get(i).getUuid().equals(convToView)) {
@@ -574,10 +598,6 @@ public class ConversationActivity extends XmppActivity {
@Override
public void onStart() {
super.onStart();
- SharedPreferences preferences = PreferenceManager
- .getDefaultSharedPreferences(this);
- this.useSubject = preferences.getBoolean("use_subject_in_muc", true);
- this.showLastseen = preferences.getBoolean("show_last_seen", false);
if (this.xmppConnectionServiceBound) {
this.onBackendConnected();
}
@@ -600,9 +620,10 @@ public class ConversationActivity extends XmppActivity {
if (conversationList.size() == 0) {
updateConversationList();
}
-
- if (getSelectedConversation()!=null && pendingImageUri !=null) {
- attachImageToConversation(getSelectedConversation(), pendingImageUri);
+
+ if (getSelectedConversation() != null && pendingImageUri != null) {
+ attachImageToConversation(getSelectedConversation(),
+ pendingImageUri);
pendingImageUri = null;
} else {
pendingImageUri = null;
@@ -670,7 +691,8 @@ public class ConversationActivity extends XmppActivity {
} else if (requestCode == REQUEST_ATTACH_FILE_DIALOG) {
pendingImageUri = data.getData();
if (xmppConnectionServiceBound) {
- attachImageToConversation(getSelectedConversation(),pendingImageUri);
+ attachImageToConversation(getSelectedConversation(),
+ pendingImageUri);
pendingImageUri = null;
}
} else if (requestCode == REQUEST_SEND_PGP_IMAGE) {
@@ -686,10 +708,12 @@ public class ConversationActivity extends XmppActivity {
// encryptTextMessage();
} else if (requestCode == REQUEST_IMAGE_CAPTURE) {
if (xmppConnectionServiceBound) {
- attachImageToConversation(getSelectedConversation(), pendingImageUri);
+ attachImageToConversation(getSelectedConversation(),
+ pendingImageUri);
pendingImageUri = null;
}
- Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+ Intent intent = new Intent(
+ Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(pendingImageUri);
sendBroadcast(intent);
} else if (requestCode == REQUEST_RECORD_AUDIO) {
@@ -700,7 +724,7 @@ public class ConversationActivity extends XmppActivity {
}
private void attachAudioToConversation(Conversation conversation, Uri uri) {
-
+
}
private void attachImageToConversation(Conversation conversation, Uri uri) {
@@ -744,122 +768,16 @@ public class ConversationActivity extends XmppActivity {
}
public void updateConversationList() {
- xmppConnectionService.populateWithOrderedConversations(conversationList);
- listView.invalidateViews();
- }
-
- public boolean showLastseen() {
- if (getSelectedConversation() == null) {
- return false;
- } else {
- return this.showLastseen
- && getSelectedConversation().getMode() == Conversation.MODE_SINGLE;
- }
+ xmppConnectionService
+ .populateWithOrderedConversations(conversationList);
+ listAdapter.notifyDataSetChanged();
}
public void runIntent(PendingIntent pi, int requestCode) {
try {
this.startIntentSenderForResult(pi.getIntentSender(), requestCode,
null, 0, 0, 0);
- } catch (SendIntentException e1) {}
- }
-
- class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> {
- private final WeakReference<ImageView> imageViewReference;
- private Message message = null;
-
- public BitmapWorkerTask(ImageView imageView) {
- imageViewReference = new WeakReference<ImageView>(imageView);
- }
-
- @Override
- protected Bitmap doInBackground(Message... params) {
- message = params[0];
- try {
- return xmppConnectionService.getFileBackend().getThumbnail(
- message, (int) (metrics.density * 288), false);
- } catch (FileNotFoundException e) {
- return null;
- }
- }
-
- @Override
- protected void onPostExecute(Bitmap bitmap) {
- if (imageViewReference != null && bitmap != null) {
- final ImageView imageView = imageViewReference.get();
- if (imageView != null) {
- imageView.setImageBitmap(bitmap);
- imageView.setBackgroundColor(0x00000000);
- }
- }
- }
- }
-
- public void loadBitmap(Message message, ImageView imageView) {
- Bitmap bm;
- try {
- bm = xmppConnectionService.getFileBackend().getThumbnail(message,
- (int) (metrics.density * 288), true);
- } catch (FileNotFoundException e) {
- bm = null;
- }
- if (bm != null) {
- imageView.setImageBitmap(bm);
- imageView.setBackgroundColor(0x00000000);
- } else {
- if (cancelPotentialWork(message, imageView)) {
- imageView.setBackgroundColor(0xff333333);
- final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
- final AsyncDrawable asyncDrawable = new AsyncDrawable(
- getResources(), null, task);
- imageView.setImageDrawable(asyncDrawable);
- try {
- task.execute(message);
- } catch (RejectedExecutionException e) {
- return;
- }
- }
- }
- }
-
- public static boolean cancelPotentialWork(Message message,
- ImageView imageView) {
- final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
-
- if (bitmapWorkerTask != null) {
- final Message oldMessage = bitmapWorkerTask.message;
- if (oldMessage == null || message != oldMessage) {
- bitmapWorkerTask.cancel(true);
- } else {
- return false;
- }
- }
- return true;
- }
-
- private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
- if (imageView != null) {
- final Drawable drawable = imageView.getDrawable();
- if (drawable instanceof AsyncDrawable) {
- final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
- return asyncDrawable.getBitmapWorkerTask();
- }
- }
- return null;
- }
-
- static class AsyncDrawable extends BitmapDrawable {
- private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
-
- public AsyncDrawable(Resources res, Bitmap bitmap,
- BitmapWorkerTask bitmapWorkerTask) {
- super(res, bitmap);
- bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(
- bitmapWorkerTask);
- }
-
- public BitmapWorkerTask getBitmapWorkerTask() {
- return bitmapWorkerTaskReference.get();
+ } catch (SendIntentException e1) {
}
}
@@ -886,4 +804,9 @@ public class ConversationActivity extends XmppActivity {
}
});
}
+
+ public boolean forceEncryption() {
+ return PreferenceManager.getDefaultSharedPreferences(
+ getApplicationContext()).getBoolean("force_encryption", false);
+ }
}
diff --git a/src/eu/siacs/conversations/ui/ConversationFragment.java b/src/eu/siacs/conversations/ui/ConversationFragment.java
index 9309db9c..b73bcadb 100644
--- a/src/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/eu/siacs/conversations/ui/ConversationFragment.java
@@ -15,6 +15,7 @@ import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.EditMessage.OnEnterPressed;
import eu.siacs.conversations.ui.XmppActivity.OnPresenceSelected;
+import eu.siacs.conversations.ui.XmppActivity.OnValueEdited;
import eu.siacs.conversations.ui.adapter.MessageAdapter;
import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureClicked;
import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureLongClicked;
@@ -26,10 +27,8 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
-import android.content.SharedPreferences;
import android.content.IntentSender.SendIntentException;
import android.os.Bundle;
-import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.Selection;
import android.view.Gravity;
@@ -67,7 +66,6 @@ public class ConversationFragment extends Fragment {
private TextView snackbarMessage;
private TextView snackbarAction;
- private boolean useSubject = true;
private boolean messagesLoaded = false;
private IntentSender askForPassphraseIntent = null;
@@ -131,6 +129,26 @@ public class ConversationFragment extends Fragment {
}
};
+ private OnClickListener enterPassword = new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ MucOptions muc = conversation.getMucOptions();
+ String password = muc.getPassword();
+ if (password == null) {
+ password = "";
+ }
+ activity.quickPasswordEdit(password, new OnValueEdited() {
+
+ @Override
+ public void onValueEdited(String value) {
+ activity.xmppConnectionService.providePasswordForMuc(
+ conversation, value);
+ }
+ });
+ }
+ };
+
private OnScrollListener mOnScrollListener = new OnScrollListener() {
@Override
@@ -160,6 +178,9 @@ public class ConversationFragment extends Fragment {
private ConversationActivity activity;
private void sendMessage() {
+ if (this.conversation == null) {
+ return;
+ }
if (mEditMessage.getText().length() < 1) {
if (this.conversation.getMode() == Conversation.MODE_MULTI) {
conversation.setNextPresence(null);
@@ -168,7 +189,8 @@ public class ConversationFragment extends Fragment {
return;
}
Message message = new Message(conversation, mEditMessage.getText()
- .toString(), conversation.getNextEncryption());
+ .toString(), conversation.getNextEncryption(activity
+ .forceEncryption()));
if (conversation.getMode() == Conversation.MODE_MULTI) {
if (conversation.getNextPresence() != null) {
message.setPresence(conversation.getNextPresence());
@@ -176,9 +198,9 @@ public class ConversationFragment extends Fragment {
conversation.setNextPresence(null);
}
}
- if (conversation.getNextEncryption() == Message.ENCRYPTION_OTR) {
+ if (conversation.getNextEncryption(activity.forceEncryption()) == Message.ENCRYPTION_OTR) {
sendOtrMessage(message);
- } else if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) {
+ } else if (conversation.getNextEncryption(activity.forceEncryption()) == Message.ENCRYPTION_PGP) {
sendPgpMessage(message);
} else {
sendPlainTextMessage(message);
@@ -192,7 +214,7 @@ public class ConversationFragment extends Fragment {
R.string.send_private_message_to,
conversation.getNextPresence()));
} else {
- switch (conversation.getNextEncryption()) {
+ switch (conversation.getNextEncryption(activity.forceEncryption())) {
case Message.ENCRYPTION_NONE:
mEditMessage
.setHint(getString(R.string.send_plain_text_message));
@@ -287,23 +309,22 @@ public class ConversationFragment extends Fragment {
protected void highlightInConference(String nick) {
String oldString = mEditMessage.getText().toString().trim();
- if (oldString.isEmpty()) {
- mEditMessage.setText(nick + ": ");
+ if (oldString.isEmpty() || mEditMessage.getSelectionStart() == 0) {
+ mEditMessage.getText().insert(0, nick + ": ");
} else {
- mEditMessage.setText(oldString + " " + nick + " ");
+ if (mEditMessage.getText().charAt(
+ mEditMessage.getSelectionStart() - 1) != ' ') {
+ nick = " " + nick;
+ }
+ mEditMessage.getText().insert(mEditMessage.getSelectionStart(),
+ nick + " ");
}
- int position = mEditMessage.length();
- Editable etext = mEditMessage.getText();
- Selection.setSelection(etext, position);
}
@Override
public void onStart() {
super.onStart();
this.activity = (ConversationActivity) getActivity();
- SharedPreferences preferences = PreferenceManager
- .getDefaultSharedPreferences(activity);
- this.useSubject = preferences.getBoolean("use_subject_in_muc", true);
if (activity.xmppConnectionServiceBound) {
this.onBackendConnected();
}
@@ -343,8 +364,7 @@ public class ConversationFragment extends Fragment {
activity.getSlidingPaneLayout().closePane();
activity.getActionBar().setDisplayHomeAsUpEnabled(true);
activity.getActionBar().setHomeButtonEnabled(true);
- activity.getActionBar().setTitle(
- conversation.getName(useSubject));
+ activity.getActionBar().setTitle(conversation.getName());
activity.invalidateOptionsMenu();
}
}
@@ -390,7 +410,17 @@ public class ConversationFragment extends Fragment {
final ConversationActivity activity = (ConversationActivity) getActivity();
if (this.conversation != null) {
final Contact contact = this.conversation.getContact();
- if (!contact.showInRoster()
+ if (this.conversation.isMuted()) {
+ showSnackbar(R.string.notifications_disabled, R.string.enable,
+ new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ conversation.setMutedTill(0);
+ updateMessages();
+ }
+ });
+ } else if (!contact.showInRoster()
&& contact
.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
showSnackbar(R.string.contact_added_you, R.string.add_back,
@@ -412,15 +442,11 @@ public class ConversationFragment extends Fragment {
break;
}
}
+ this.messageList.clear();
if (this.conversation.getMessages().size() == 0) {
- this.messageList.clear();
messagesLoaded = false;
} else {
- for (Message message : this.conversation.getMessages()) {
- if (!this.messageList.contains(message)) {
- this.messageList.add(message);
- }
- }
+ this.messageList.addAll(this.conversation.getMessages());
messagesLoaded = true;
updateStatusMessages();
}
@@ -432,12 +458,22 @@ public class ConversationFragment extends Fragment {
} else {
if (!conversation.getMucOptions().online()
&& conversation.getAccount().getStatus() == Account.STATUS_ONLINE) {
- if (conversation.getMucOptions().getError() == MucOptions.ERROR_NICK_IN_USE) {
+ int error = conversation.getMucOptions().getError();
+ switch (error) {
+ case MucOptions.ERROR_NICK_IN_USE:
showSnackbar(R.string.nick_in_use, R.string.edit,
clickToMuc);
- } else if (conversation.getMucOptions().getError() == MucOptions.ERROR_ROOM_NOT_FOUND) {
+ break;
+ case MucOptions.ERROR_ROOM_NOT_FOUND:
showSnackbar(R.string.conference_not_found,
R.string.leave, leaveMuc);
+ break;
+ case MucOptions.ERROR_PASSWORD_REQUIRED:
+ showSnackbar(R.string.conference_requires_password,
+ R.string.enter_password, enterPassword);
+ break;
+ default:
+ break;
}
}
}
@@ -445,7 +481,6 @@ public class ConversationFragment extends Fragment {
updateChatMsgHint();
if (!activity.shouldPaneBeOpen()) {
activity.xmppConnectionService.markRead(conversation);
- // TODO update notifications
UIHelper.updateNotification(getActivity(),
activity.getConversationList(), null, false);
activity.updateConversationList();
@@ -463,23 +498,15 @@ public class ConversationFragment extends Fragment {
}
protected void updateStatusMessages() {
- boolean addedStatusMsg = false;
if (conversation.getMode() == Conversation.MODE_SINGLE) {
for (int i = this.messageList.size() - 1; i >= 0; --i) {
- if (addedStatusMsg) {
- if (this.messageList.get(i).getType() == Message.TYPE_STATUS) {
- this.messageList.remove(i);
- --i;
- }
+ if (this.messageList.get(i).getStatus() == Message.STATUS_RECEIVED) {
+ return;
} else {
- if (this.messageList.get(i).getStatus() == Message.STATUS_RECEIVED) {
- addedStatusMsg = true;
- } else {
- if (this.messageList.get(i).getStatus() == Message.STATUS_SEND_DISPLAYED) {
- this.messageList.add(i + 1,
- Message.createStatusMessage(conversation));
- addedStatusMsg = true;
- }
+ if (this.messageList.get(i).getStatus() == Message.STATUS_SEND_DISPLAYED) {
+ this.messageList.add(i + 1,
+ Message.createStatusMessage(conversation));
+ return;
}
}
}
@@ -491,6 +518,7 @@ public class ConversationFragment extends Fragment {
.getOtrFingerprints();
if ((latestEncryption == Message.ENCRYPTION_OTR)
&& (conversation.hasValidOtrSession()
+ && (!conversation.isMuted())
&& (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
.contains(conversation.getOtrFingerprint())))) {
showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify,
diff --git a/src/eu/siacs/conversations/ui/EditAccountActivity.java b/src/eu/siacs/conversations/ui/EditAccountActivity.java
index d98a0ca7..bc946115 100644
--- a/src/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -201,7 +201,8 @@ public class EditAccountActivity extends XmppActivity {
this.mSaveButton.setEnabled(true);
this.mSaveButton.setTextColor(getPrimaryTextColor());
if (jidToEdit != null) {
- if (mAccount!= null && mAccount.getStatus() == Account.STATUS_ONLINE) {
+ if (mAccount != null
+ && mAccount.getStatus() == Account.STATUS_ONLINE) {
this.mSaveButton.setText(R.string.save);
} else {
this.mSaveButton.setText(R.string.connect);
@@ -324,7 +325,7 @@ public class EditAccountActivity extends XmppActivity {
this.mServerInfoPep.setText(R.string.server_info_unavailable);
}
String fingerprint = this.mAccount
- .getOtrFingerprint(getApplicationContext());
+ .getOtrFingerprint(xmppConnectionService);
if (fingerprint != null) {
this.mOtrFingerprintHeadline.setVisibility(View.VISIBLE);
this.mOtrFingerprint.setVisibility(View.VISIBLE);
diff --git a/src/eu/siacs/conversations/ui/PublishProfilePictureActivity.java b/src/eu/siacs/conversations/ui/PublishProfilePictureActivity.java
index c979d137..f46d92f9 100644
--- a/src/eu/siacs/conversations/ui/PublishProfilePictureActivity.java
+++ b/src/eu/siacs/conversations/ui/PublishProfilePictureActivity.java
@@ -46,7 +46,7 @@ public class PublishProfilePictureActivity extends XmppActivity {
public void run() {
if (mInitialAccountSetup) {
startActivity(new Intent(getApplicationContext(),
- StartConversationActivity.class));
+ StartConversationActivity.class));
}
finish();
}
@@ -111,7 +111,7 @@ public class PublishProfilePictureActivity extends XmppActivity {
public void onClick(View v) {
if (mInitialAccountSetup) {
startActivity(new Intent(getApplicationContext(),
- StartConversationActivity.class));
+ StartConversationActivity.class));
}
finish();
}
diff --git a/src/eu/siacs/conversations/ui/SettingsActivity.java b/src/eu/siacs/conversations/ui/SettingsActivity.java
index f8fd9469..6b280719 100644
--- a/src/eu/siacs/conversations/ui/SettingsActivity.java
+++ b/src/eu/siacs/conversations/ui/SettingsActivity.java
@@ -1,20 +1,57 @@
package eu.siacs.conversations.ui;
+import java.util.Locale;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Account;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
+import android.preference.PreferenceManager;
-public class SettingsActivity extends XmppActivity {
+public class SettingsActivity extends XmppActivity implements
+ OnSharedPreferenceChangeListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
- // Display the fragment as the main content.
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new SettingsFragment()).commit();
}
@Override
void onBackendConnected() {
-
+
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ PreferenceManager.getDefaultSharedPreferences(this)
+ .registerOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ PreferenceManager.getDefaultSharedPreferences(this)
+ .unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences preferences,
+ String name) {
+ if (name.equals("resource")) {
+ String resource = preferences.getString("resource", "mobile")
+ .toLowerCase(Locale.US);
+ if (xmppConnectionServiceBound) {
+ for (Account account : xmppConnectionService.getAccounts()) {
+ account.setResource(resource);
+ if (!account.isOptionSet(Account.OPTION_DISABLED)) {
+ xmppConnectionService.reconnectAccount(account, false);
+ }
+ }
+ }
+ }
}
}
diff --git a/src/eu/siacs/conversations/ui/ShareWithActivity.java b/src/eu/siacs/conversations/ui/ShareWithActivity.java
index 57b4ba31..9fbc3db1 100644
--- a/src/eu/siacs/conversations/ui/ShareWithActivity.java
+++ b/src/eu/siacs/conversations/ui/ShareWithActivity.java
@@ -1,37 +1,41 @@
package eu.siacs.conversations.ui;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
+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.Message;
-import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.ui.adapter.ConversationAdapter;
import android.app.PendingIntent;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
-import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ListView;
import android.widget.Toast;
public class ShareWithActivity extends XmppActivity {
- private LinearLayout conversations;
- private LinearLayout contacts;
- private boolean isImage = false;
+ private class Share {
+ public Uri uri;
+ public String account;
+ public String contact;
+ public String text;
+ }
+
+ private Share share;
+
+ private static final int REQUEST_START_NEW_CONVERSATION = 0x0501;
+ private ListView mListView;
+ private List<Conversation> mConversations = new ArrayList<Conversation>();
private UiCallback<Message> attachImageCallback = new UiCallback<Message>() {
@@ -53,110 +57,110 @@ public class ShareWithActivity extends XmppActivity {
}
};
+ protected void onActivityResult(int requestCode, int resultCode,
+ final Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == REQUEST_START_NEW_CONVERSATION
+ && resultCode == RESULT_OK) {
+ share.contact = data.getStringExtra("contact");
+ share.account = data.getStringExtra("account");
+ Log.d(Config.LOGTAG, "contact: " + share.contact + " account:"
+ + share.account);
+ }
+ if (xmppConnectionServiceBound && share != null
+ && share.contact != null && share.account != null) {
+ share();
+ }
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ getActionBar().setDisplayHomeAsUpEnabled(false);
+ getActionBar().setHomeButtonEnabled(false);
+
setContentView(R.layout.share_with);
setTitle(getString(R.string.title_activity_sharewith));
- contacts = (LinearLayout) findViewById(R.id.contacts);
- conversations = (LinearLayout) findViewById(R.id.conversations);
+ mListView = (ListView) findViewById(R.id.choose_conversation_list);
+ ConversationAdapter mAdapter = new ConversationAdapter(this,
+ this.mConversations);
+ mListView.setAdapter(mAdapter);
+ mListView.setOnItemClickListener(new OnItemClickListener() {
+
+ @Override
+ public void onItemClick(AdapterView<?> arg0, View arg1,
+ int position, long arg3) {
+ Conversation conversation = mConversations.get(position);
+ if (conversation.getMode() == Conversation.MODE_SINGLE
+ || share.uri == null) {
+ share(mConversations.get(position));
+ }
+ }
+ });
+ this.share = new Share();
}
- public View createContactView(String name, String msgTxt, Bitmap bm) {
- View view = (View) getLayoutInflater().inflate(R.layout.contact, null);
- view.setBackgroundResource(R.drawable.greybackground);
- TextView contactName = (TextView) view
- .findViewById(R.id.contact_display_name);
- contactName.setText(name);
- TextView msg = (TextView) view.findViewById(R.id.contact_jid);
- msg.setText(msgTxt);
- ImageView imageView = (ImageView) view.findViewById(R.id.contact_photo);
- imageView.setImageBitmap(bm);
- return view;
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.share_with, menu);
+ return true;
}
@Override
- void onBackendConnected() {
- this.isImage = (getIntent().getType() != null && getIntent().getType()
- .startsWith("image/"));
- SharedPreferences preferences = PreferenceManager
- .getDefaultSharedPreferences(this);
- boolean useSubject = preferences.getBoolean("use_subject_in_muc", true);
-
- Set<Contact> displayedContacts = new HashSet<Contact>();
- conversations.removeAllViews();
- List<Conversation> convList = new ArrayList<Conversation>();
- xmppConnectionService.populateWithOrderedConversations(convList);
- Collections.sort(convList, new Comparator<Conversation>() {
- @Override
- public int compare(Conversation lhs, Conversation rhs) {
- return (int) (rhs.getLatestMessage().getTimeSent() - lhs
- .getLatestMessage().getTimeSent());
- }
- });
- for (final Conversation conversation : convList) {
- if (!isImage || conversation.getMode() == Conversation.MODE_SINGLE) {
- View view = createContactView(conversation.getName(useSubject),
- conversation.getLatestMessage().getBody().trim(),
- conversation.getImage(getApplicationContext(), 48));
- view.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- share(conversation);
- }
- });
- conversations.addView(view);
- displayedContacts.add(conversation.getContact());
- }
- }
- contacts.removeAllViews();
- List<Contact> contactsList = new ArrayList<Contact>();
- for (Account account : xmppConnectionService.getAccounts()) {
- for (Contact contact : account.getRoster().getContacts()) {
- if (!displayedContacts.contains(contact)
- && (contact.showInRoster())) {
- contactsList.add(contact);
- }
- }
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.action_add:
+ Intent intent = new Intent(getApplicationContext(),
+ ChooseContactActivity.class);
+ startActivityForResult(intent, REQUEST_START_NEW_CONVERSATION);
+ return true;
}
+ return super.onOptionsItemSelected(item);
+ }
- Collections.sort(contactsList, new Comparator<Contact>() {
- @Override
- public int compare(Contact lhs, Contact rhs) {
- return lhs.getDisplayName().compareToIgnoreCase(
- rhs.getDisplayName());
- }
- });
+ @Override
+ public void onStart() {
+ if (getIntent().getType() != null
+ && getIntent().getType().startsWith("image/")) {
+ this.share.uri = (Uri) getIntent().getParcelableExtra(
+ Intent.EXTRA_STREAM);
+ } else {
+ this.share.text = getIntent().getStringExtra(Intent.EXTRA_TEXT);
+ }
+ if (xmppConnectionServiceBound) {
+ xmppConnectionService.populateWithOrderedConversations(
+ mConversations, this.share.uri == null);
+ }
+ super.onStart();
+ }
- for (int i = 0; i < contactsList.size(); ++i) {
- final Contact contact = contactsList.get(i);
- View view = createContactView(contact.getDisplayName(),
- contact.getJid(),
- contact.getImage(48, getApplicationContext()));
- view.setOnClickListener(new OnClickListener() {
+ @Override
+ void onBackendConnected() {
+ if (xmppConnectionServiceBound && share != null
+ && share.contact != null && share.account != null) {
+ share();
+ return;
+ }
+ xmppConnectionService.populateWithOrderedConversations(mConversations,
+ this.share != null && this.share.uri == null);
+ }
- @Override
- public void onClick(View v) {
- Conversation conversation = xmppConnectionService
- .findOrCreateConversation(contact.getAccount(),
- contact.getJid(), false);
- share(conversation);
- }
- });
- contacts.addView(view);
+ private void share() {
+ Account account = xmppConnectionService.findAccountByJid(share.account);
+ if (account == null) {
+ return;
}
+ Conversation conversation = xmppConnectionService
+ .findOrCreateConversation(account, share.contact, false);
+ share(conversation);
}
private void share(final Conversation conversation) {
- String sharedText = null;
- if (isImage) {
- final Uri uri = (Uri) getIntent().getParcelableExtra(
- Intent.EXTRA_STREAM);
+ if (share.uri != null) {
selectPresence(conversation, new OnPresenceSelected() {
@Override
public void onPresenceSelected() {
@@ -164,7 +168,7 @@ public class ShareWithActivity extends XmppActivity {
getText(R.string.preparing_image),
Toast.LENGTH_LONG).show();
ShareWithActivity.this.xmppConnectionService
- .attachImageToConversation(conversation, uri,
+ .attachImageToConversation(conversation, share.uri,
attachImageCallback);
switchToConversation(conversation, null, true);
finish();
@@ -172,11 +176,10 @@ public class ShareWithActivity extends XmppActivity {
});
} else {
- sharedText = getIntent().getStringExtra(Intent.EXTRA_TEXT);
- switchToConversation(conversation, sharedText, true);
+ switchToConversation(conversation, this.share.text, true);
finish();
}
}
-}
+} \ No newline at end of file
diff --git a/src/eu/siacs/conversations/ui/StartConversationActivity.java b/src/eu/siacs/conversations/ui/StartConversationActivity.java
index bd66bd94..6287070c 100644
--- a/src/eu/siacs/conversations/ui/StartConversationActivity.java
+++ b/src/eu/siacs/conversations/ui/StartConversationActivity.java
@@ -191,8 +191,7 @@ public class StartConversationActivity extends XmppActivity {
}
});
- mConferenceAdapter = new ListItemAdapter(getApplicationContext(),
- conferences);
+ mConferenceAdapter = new ListItemAdapter(this, conferences);
mConferenceListFragment.setListAdapter(mConferenceAdapter);
mConferenceListFragment.setContextMenu(R.menu.conference_context);
mConferenceListFragment
@@ -205,8 +204,7 @@ public class StartConversationActivity extends XmppActivity {
}
});
- mContactsAdapter = new ListItemAdapter(getApplicationContext(),
- contacts);
+ mContactsAdapter = new ListItemAdapter(this, contacts);
mContactsListFragment.setListAdapter(mContactsAdapter);
mContactsListFragment.setContextMenu(R.menu.contact_context);
mContactsListFragment
@@ -340,7 +338,7 @@ public class StartConversationActivity extends XmppActivity {
String contactJid = jid.getText().toString();
Account account = xmppConnectionService
.findAccountByJid(accountJid);
- if (account==null) {
+ if (account == null) {
dialog.dismiss();
return;
}
diff --git a/src/eu/siacs/conversations/ui/UiCallback.java b/src/eu/siacs/conversations/ui/UiCallback.java
index 05a869f7..c80199e1 100644
--- a/src/eu/siacs/conversations/ui/UiCallback.java
+++ b/src/eu/siacs/conversations/ui/UiCallback.java
@@ -4,6 +4,8 @@ import android.app.PendingIntent;
public interface UiCallback<T> {
public void success(T object);
+
public void error(int errorCode, T object);
+
public void userInputRequried(PendingIntent pi, T object);
}
diff --git a/src/eu/siacs/conversations/ui/XmppActivity.java b/src/eu/siacs/conversations/ui/XmppActivity.java
index 44043a79..f13c112a 100644
--- a/src/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/eu/siacs/conversations/ui/XmppActivity.java
@@ -1,5 +1,10 @@
package eu.siacs.conversations.ui;
+import java.io.FileNotFoundException;
+import java.lang.ref.WeakReference;
+import java.util.concurrent.RejectedExecutionException;
+
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
@@ -16,26 +21,34 @@ import android.app.AlertDialog.Builder;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.SharedPreferences;
import android.content.DialogInterface.OnClickListener;
import android.content.IntentSender.SendIntentException;
+import android.content.res.Resources;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
+import android.preference.PreferenceManager;
+import android.text.InputType;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
+import android.widget.ImageView;
public abstract class XmppActivity extends Activity {
protected static final int REQUEST_ANNOUNCE_PGP = 0x0101;
protected static final int REQUEST_INVITE_TO_CONVERSATION = 0x0102;
- protected final static String LOGTAG = "xmppService";
-
public XmppConnectionService xmppConnectionService;
public boolean xmppConnectionServiceBound = false;
protected boolean handledViewIntent = false;
@@ -45,6 +58,8 @@ public abstract class XmppActivity extends Activity {
protected int mWarningTextColor;
protected int mPrimaryColor;
+ private DisplayMetrics metrics;
+
protected interface OnValueEdited {
public void onValueEdited(String value);
}
@@ -164,11 +179,20 @@ public abstract class XmppActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ metrics = getResources().getDisplayMetrics();
ExceptionHelper.init(getApplicationContext());
mPrimaryTextColor = getResources().getColor(R.color.primarytext);
mSecondaryTextColor = getResources().getColor(R.color.secondarytext);
mWarningTextColor = getResources().getColor(R.color.warningtext);
mPrimaryColor = getResources().getColor(R.color.primary);
+ if (getPreferences().getBoolean("use_larger_font", false)) {
+ setTheme(R.style.ConversationsTheme_LargerText);
+ }
+ }
+
+ protected SharedPreferences getPreferences() {
+ return PreferenceManager
+ .getDefaultSharedPreferences(getApplicationContext());
}
public void switchToConversation(Conversation conversation) {
@@ -284,16 +308,62 @@ public abstract class XmppActivity extends Activity {
builder.create().show();
}
- protected void quickEdit(final String previousValue,
- final OnValueEdited callback) {
+ private void showAskForPresenceDialog(final Contact contact) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(contact.getJid());
+ builder.setMessage(R.string.request_presence_updates);
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setPositiveButton(R.string.request_now,
+ new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (xmppConnectionServiceBound) {
+ xmppConnectionService.sendPresencePacket(contact
+ .getAccount(), xmppConnectionService
+ .getPresenceGenerator()
+ .requestPresenceUpdatesFrom(contact));
+ }
+ }
+ });
+ builder.create().show();
+ }
+
+ private void warnMutalPresenceSubscription(final Conversation conversation,
+ final OnPresenceSelected listener) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(conversation.getContact().getJid());
+ builder.setMessage(R.string.without_mutual_presence_updates);
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setPositiveButton(R.string.ignore, new OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ conversation.setNextPresence(null);
+ if (listener != null) {
+ listener.onPresenceSelected();
+ }
+ }
+ });
+ builder.create().show();
+ }
+
+ protected void quickEdit(String previousValue, OnValueEdited callback) {
+ quickEdit(previousValue, callback, false);
+ }
+
+ protected void quickPasswordEdit(String previousValue,
+ OnValueEdited callback) {
+ quickEdit(previousValue, callback, true);
+ }
+
+ private void quickEdit(final String previousValue,
+ final OnValueEdited callback, boolean password) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
View view = (View) getLayoutInflater()
.inflate(R.layout.quickedit, null);
final EditText editor = (EditText) view.findViewById(R.id.editor);
- editor.setText(previousValue);
- builder.setView(view);
- builder.setNegativeButton(R.string.cancel, null);
- builder.setPositiveButton(R.string.edit, new OnClickListener() {
+ OnClickListener mClickListener = new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
@@ -302,7 +372,19 @@ public abstract class XmppActivity extends Activity {
callback.onValueEdited(value);
}
}
- });
+ };
+ if (password) {
+ editor.setInputType(InputType.TYPE_CLASS_TEXT
+ | InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ editor.setHint(R.string.password);
+ builder.setPositiveButton(R.string.accept, mClickListener);
+ } else {
+ builder.setPositiveButton(R.string.edit, mClickListener);
+ }
+ editor.requestFocus();
+ editor.setText(previousValue);
+ builder.setView(view);
+ builder.setNegativeButton(R.string.cancel, null);
builder.create().show();
}
@@ -314,8 +396,17 @@ public abstract class XmppActivity extends Activity {
} else {
Presences presences = contact.getPresences();
if (presences.size() == 0) {
- conversation.setNextPresence(null);
- listener.onPresenceSelected();
+ if (!contact.getOption(Contact.Options.TO)
+ && !contact.getOption(Contact.Options.ASKING)
+ && contact.getAccount().getStatus() == Account.STATUS_ONLINE) {
+ showAskForPresenceDialog(contact);
+ } else if (!contact.getOption(Contact.Options.TO)
+ || !contact.getOption(Contact.Options.FROM)) {
+ warnMutalPresenceSubscription(conversation, listener);
+ } else {
+ conversation.setNextPresence(null);
+ listener.onPresenceSelected();
+ }
} else if (presences.size() == 1) {
String presence = (String) presences.asStringArray()[0];
conversation.setNextPresence(presence);
@@ -370,8 +461,8 @@ public abstract class XmppActivity extends Activity {
if (conversation.getMode() == Conversation.MODE_MULTI) {
xmppConnectionService.invite(conversation, contactJid);
}
- Log.d("xmppService", "inviting " + contactJid + " to "
- + conversation.getName(true));
+ Log.d(Config.LOGTAG, "inviting " + contactJid + " to "
+ + conversation.getName());
}
}
@@ -390,4 +481,103 @@ public abstract class XmppActivity extends Activity {
public int getPrimaryColor() {
return this.mPrimaryColor;
}
+
+ class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> {
+ private final WeakReference<ImageView> imageViewReference;
+ private Message message = null;
+
+ public BitmapWorkerTask(ImageView imageView) {
+ imageViewReference = new WeakReference<ImageView>(imageView);
+ }
+
+ @Override
+ protected Bitmap doInBackground(Message... params) {
+ message = params[0];
+ try {
+ return xmppConnectionService.getFileBackend().getThumbnail(
+ message, (int) (metrics.density * 288), false);
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap bitmap) {
+ if (imageViewReference != null && bitmap != null) {
+ final ImageView imageView = imageViewReference.get();
+ if (imageView != null) {
+ imageView.setImageBitmap(bitmap);
+ imageView.setBackgroundColor(0x00000000);
+ }
+ }
+ }
+ }
+
+ public void loadBitmap(Message message, ImageView imageView) {
+ Bitmap bm;
+ try {
+ bm = xmppConnectionService.getFileBackend().getThumbnail(message,
+ (int) (metrics.density * 288), true);
+ } catch (FileNotFoundException e) {
+ bm = null;
+ }
+ if (bm != null) {
+ imageView.setImageBitmap(bm);
+ imageView.setBackgroundColor(0x00000000);
+ } else {
+ if (cancelPotentialWork(message, imageView)) {
+ imageView.setBackgroundColor(0xff333333);
+ final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
+ final AsyncDrawable asyncDrawable = new AsyncDrawable(
+ getResources(), null, task);
+ imageView.setImageDrawable(asyncDrawable);
+ try {
+ task.execute(message);
+ } catch (RejectedExecutionException e) {
+ return;
+ }
+ }
+ }
+ }
+
+ public static boolean cancelPotentialWork(Message message,
+ ImageView imageView) {
+ final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
+
+ if (bitmapWorkerTask != null) {
+ final Message oldMessage = bitmapWorkerTask.message;
+ if (oldMessage == null || message != oldMessage) {
+ bitmapWorkerTask.cancel(true);
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
+ if (imageView != null) {
+ final Drawable drawable = imageView.getDrawable();
+ if (drawable instanceof AsyncDrawable) {
+ final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
+ return asyncDrawable.getBitmapWorkerTask();
+ }
+ }
+ return null;
+ }
+
+ static class AsyncDrawable extends BitmapDrawable {
+ private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
+
+ public AsyncDrawable(Resources res, Bitmap bitmap,
+ BitmapWorkerTask bitmapWorkerTask) {
+ super(res, bitmap);
+ bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(
+ bitmapWorkerTask);
+ }
+
+ public BitmapWorkerTask getBitmapWorkerTask() {
+ return bitmapWorkerTaskReference.get();
+ }
+ }
}
diff --git a/src/eu/siacs/conversations/ui/adapter/AccountAdapter.java b/src/eu/siacs/conversations/ui/adapter/AccountAdapter.java
index cd8b376f..5c25bf34 100644
--- a/src/eu/siacs/conversations/ui/adapter/AccountAdapter.java
+++ b/src/eu/siacs/conversations/ui/adapter/AccountAdapter.java
@@ -14,9 +14,9 @@ import android.widget.ImageView;
import android.widget.TextView;
public class AccountAdapter extends ArrayAdapter<Account> {
-
+
private XmppActivity activity;
-
+
public AccountAdapter(XmppActivity activity, List<Account> objects) {
super(activity, 0, objects);
this.activity = activity;
@@ -34,7 +34,7 @@ public class AccountAdapter extends ArrayAdapter<Account> {
jid.setText(account.getJid());
TextView statusView = (TextView) view.findViewById(R.id.account_status);
ImageView imageView = (ImageView) view.findViewById(R.id.account_image);
- imageView.setImageBitmap(account.getImage(activity,48));
+ imageView.setImageBitmap(account.getImage(activity, 48));
switch (account.getStatus()) {
case Account.STATUS_DISABLED:
statusView.setText(getContext().getString(
diff --git a/src/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
index fcc57601..bfcba135 100644
--- a/src/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
+++ b/src/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
@@ -2,10 +2,12 @@ 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.Message;
import eu.siacs.conversations.ui.ConversationActivity;
+import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.utils.UIHelper;
import android.content.Context;
import android.graphics.Color;
@@ -19,9 +21,9 @@ import android.widget.TextView;
public class ConversationAdapter extends ArrayAdapter<Conversation> {
- ConversationActivity activity;
+ private XmppActivity activity;
- public ConversationAdapter(ConversationActivity activity,
+ public ConversationAdapter(XmppActivity activity,
List<Conversation> conversations) {
super(activity, 0, conversations);
this.activity = activity;
@@ -36,18 +38,21 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
parent, false);
}
Conversation conv = getItem(position);
- if (!activity.getSlidingPaneLayout().isSlideable()) {
- if (conv == activity.getSelectedConversation()) {
- view.setBackgroundColor(0xffdddddd);
+ if (this.activity instanceof ConversationActivity) {
+ ConversationActivity activity = (ConversationActivity) this.activity;
+ if (!activity.getSlidingPaneLayout().isSlideable()) {
+ if (conv == activity.getSelectedConversation()) {
+ view.setBackgroundColor(0xffdddddd);
+ } else {
+ view.setBackgroundColor(Color.TRANSPARENT);
+ }
} else {
view.setBackgroundColor(Color.TRANSPARENT);
}
- } else {
- view.setBackgroundColor(Color.TRANSPARENT);
}
TextView convName = (TextView) view
.findViewById(R.id.conversation_name);
- convName.setText(conv.getName(true));
+ convName.setText(conv.getName());
TextView convLastMsg = (TextView) view
.findViewById(R.id.conversation_lastmsg);
ImageView imagePreview = (ImageView) view
@@ -59,10 +64,12 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
|| latestMessage.getType() == Message.TYPE_PRIVATE) {
if ((latestMessage.getEncryption() != Message.ENCRYPTION_PGP)
&& (latestMessage.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED)) {
- convLastMsg.setText(conv.getLatestMessage().getBody());
+ String body = Config.PARSE_EMOTICONS ? UIHelper
+ .transformAsciiEmoticons(latestMessage.getBody())
+ : latestMessage.getBody();
+ convLastMsg.setText(body);
} else {
- convLastMsg.setText(activity
- .getText(R.string.encrypted_message_received));
+ convLastMsg.setText(R.string.encrypted_message_received);
}
convLastMsg.setVisibility(View.VISIBLE);
imagePreview.setVisibility(View.GONE);
@@ -75,11 +82,9 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
convLastMsg.setVisibility(View.VISIBLE);
imagePreview.setVisibility(View.GONE);
if (latestMessage.getStatus() == Message.STATUS_RECEIVED_OFFER) {
- convLastMsg.setText(activity
- .getText(R.string.image_offered_for_download));
+ convLastMsg.setText(R.string.image_offered_for_download);
} else if (latestMessage.getStatus() == Message.STATUS_RECEIVING) {
- convLastMsg.setText(activity
- .getText(R.string.receiving_image));
+ convLastMsg.setText(R.string.receiving_image);
} else {
convLastMsg.setText("");
}
diff --git a/src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java b/src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java
index d286052c..0534bc25 100644
--- a/src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java
+++ b/src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java
@@ -19,7 +19,8 @@ public class KnownHostsAdapter extends ArrayAdapter<String> {
final String[] split = constraint.toString().split("@");
if (split.length == 1) {
for (String domain : domains) {
- suggestions.add(split[0].toLowerCase(Locale.getDefault()) + "@" + domain);
+ suggestions.add(split[0].toLowerCase(Locale
+ .getDefault()) + "@" + domain);
}
} else if (split.length == 2) {
for (String domain : domains) {
@@ -27,7 +28,8 @@ public class KnownHostsAdapter extends ArrayAdapter<String> {
suggestions.clear();
break;
} else if (domain.contains(split[1])) {
- suggestions.add(split[0].toLowerCase(Locale.getDefault()) + "@" + domain);
+ suggestions.add(split[0].toLowerCase(Locale
+ .getDefault()) + "@" + domain);
}
}
} else {
diff --git a/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java
index 2452a555..967042d8 100644
--- a/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java
+++ b/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java
@@ -3,9 +3,11 @@ package eu.siacs.conversations.ui.adapter;
import java.util.HashMap;
import java.util.List;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Downloadable;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.ui.ConversationActivity;
import eu.siacs.conversations.utils.UIHelper;
@@ -14,7 +16,6 @@ import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Typeface;
-import android.text.Html;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
@@ -34,8 +35,9 @@ import android.widget.Toast;
public class MessageAdapter extends ArrayAdapter<Message> {
private static final int SENT = 0;
- private static final int RECIEVED = 1;
+ private static final int RECEIVED = 1;
private static final int STATUS = 2;
+ private static final int NULL = 3;
private ConversationActivity activity;
@@ -67,22 +69,25 @@ public class MessageAdapter extends ArrayAdapter<Message> {
public void setOnContactPictureClicked(OnContactPictureClicked listener) {
this.mOnContactPictureClickedListener = listener;
}
-
- public void setOnContactPictureLongClicked(OnContactPictureLongClicked listener) {
+
+ public void setOnContactPictureLongClicked(
+ OnContactPictureLongClicked listener) {
this.mOnContactPictureLongClickedListener = listener;
}
@Override
public int getViewTypeCount() {
- return 3;
+ return 4;
}
@Override
public int getItemViewType(int position) {
- if (getItem(position).getType() == Message.TYPE_STATUS) {
+ if (getItem(position).wasMergedIntoPrevious()) {
+ return NULL;
+ } else if (getItem(position).getType() == Message.TYPE_STATUS) {
return STATUS;
} else if (getItem(position).getStatus() <= Message.STATUS_RECEIVED) {
- return RECIEVED;
+ return RECEIVED;
} else {
return SENT;
}
@@ -93,7 +98,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
String info = null;
boolean error = false;
boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI
- && message.getStatus() <= Message.STATUS_RECEIVED;
+ && message.getMergedStatus() <= Message.STATUS_RECEIVED;
if (message.getType() == Message.TYPE_IMAGE) {
String[] fileParams = message.getBody().split(",");
try {
@@ -103,7 +108,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
filesize = "0 KB";
}
}
- switch (message.getStatus()) {
+ switch (message.getMergedStatus()) {
case Message.STATUS_WAITING:
info = getContext().getString(R.string.waiting);
break;
@@ -151,7 +156,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
String formatedTime = UIHelper.readableTimeDifference(getContext(),
- message.getTimeSent());
+ message.getMergedTimeSent());
if (message.getStatus() <= Message.STATUS_RECEIVED) {
if ((filesize != null) && (info != null)) {
viewHolder.time.setText(filesize + " \u00B7 " + info);
@@ -212,11 +217,15 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder.messageBody.setVisibility(View.VISIBLE);
if (message.getBody() != null) {
if (message.getType() != Message.TYPE_PRIVATE) {
- viewHolder.messageBody.setText(message.getBody().trim());
+ String body = Config.PARSE_EMOTICONS ? UIHelper
+ .transformAsciiEmoticons(message.getMergedBody())
+ : message.getMergedBody();
+ viewHolder.messageBody.setText(body);
} else {
String privateMarker;
if (message.getStatus() <= Message.STATUS_RECEIVED) {
- privateMarker = activity.getString(R.string.private_message);
+ privateMarker = activity
+ .getString(R.string.private_message);
} else {
String to;
if (message.getPresence() != null) {
@@ -224,11 +233,18 @@ public class MessageAdapter extends ArrayAdapter<Message> {
} else {
to = message.getCounterpart();
}
- privateMarker = activity.getString(R.string.private_message_to, to);
+ privateMarker = activity.getString(
+ R.string.private_message_to, to);
}
- SpannableString span = new SpannableString(privateMarker+" "+message.getBody());
- span.setSpan(new ForegroundColorSpan(activity.getSecondaryTextColor()), 0, privateMarker.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- span.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, privateMarker.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ SpannableString span = new SpannableString(privateMarker + " "
+ + message.getBody());
+ span.setSpan(
+ new ForegroundColorSpan(activity
+ .getSecondaryTextColor()), 0, privateMarker
+ .length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ span.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0,
+ privateMarker.length(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
viewHolder.messageBody.setText(span);
}
} else {
@@ -301,6 +317,10 @@ public class MessageAdapter extends ArrayAdapter<Message> {
if (view == null) {
viewHolder = new ViewHolder();
switch (type) {
+ case NULL:
+ view = (View) activity.getLayoutInflater().inflate(
+ R.layout.message_null, parent, false);
+ break;
case SENT:
view = (View) activity.getLayoutInflater().inflate(
R.layout.message_sent, parent, false);
@@ -319,7 +339,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
.findViewById(R.id.message_time);
view.setTag(viewHolder);
break;
- case RECIEVED:
+ case RECEIVED:
view = (View) activity.getLayoutInflater().inflate(
R.layout.message_received, parent, false);
viewHolder.message_box = (LinearLayout) view
@@ -362,7 +382,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
@Override
public void onClick(View v) {
String name = item.getConversation()
- .getName(true);
+ .getName();
String read = getContext()
.getString(
R.string.contact_has_read_up_to_this_point,
@@ -382,11 +402,11 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder = (ViewHolder) view.getTag();
}
- if (type == STATUS) {
+ if (type == STATUS || type == NULL) {
return view;
}
- if (type == RECIEVED) {
+ if (type == RECEIVED) {
if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
Contact contact = item.getContact();
if (contact != null) {
@@ -394,10 +414,11 @@ public class MessageAdapter extends ArrayAdapter<Message> {
contact, getContext()));
} else {
String name = item.getPresence();
- if (name==null) {
+ if (name == null) {
name = item.getCounterpart();
}
- viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(name, getContext()));
+ viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(
+ name, getContext()));
}
viewHolder.contact_picture
.setOnClickListener(new OnClickListener() {
@@ -412,18 +433,20 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
});
- viewHolder.contact_picture.setOnLongClickListener(new OnLongClickListener() {
-
- @Override
- public boolean onLongClick(View v) {
- if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) {
- MessageAdapter.this.mOnContactPictureLongClickedListener.onContactPictureLongClicked(item);
- return true;
- } else {
- return false;
- }
- }
- });
+ viewHolder.contact_picture
+ .setOnLongClickListener(new OnLongClickListener() {
+
+ @Override
+ public boolean onLongClick(View v) {
+ if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) {
+ MessageAdapter.this.mOnContactPictureLongClickedListener
+ .onContactPictureLongClicked(item);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ });
}
}
@@ -439,10 +462,10 @@ public class MessageAdapter extends ArrayAdapter<Message> {
@Override
public void onClick(View v) {
- JingleConnection connection = item
- .getJingleConnection();
- if (connection != null) {
- connection.accept();
+ Downloadable downloadable = item
+ .getDownloadable();
+ if (downloadable != null) {
+ downloadable.start();
}
}
});
@@ -522,7 +545,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
public interface OnContactPictureClicked {
public void onContactPictureClicked(Message message);
}
-
+
public interface OnContactPictureLongClicked {
public void onContactPictureLongClicked(Message message);
}
diff --git a/src/eu/siacs/conversations/utils/CryptoHelper.java b/src/eu/siacs/conversations/utils/CryptoHelper.java
index a70b419e..a28b519e 100644
--- a/src/eu/siacs/conversations/utils/CryptoHelper.java
+++ b/src/eu/siacs/conversations/utils/CryptoHelper.java
@@ -11,7 +11,7 @@ import eu.siacs.conversations.entities.Account;
import android.util.Base64;
public class CryptoHelper {
- public static final String FILETRANSFER = "?FILETRANSFERv1:";
+ public static final String FILETRANSFER = "?FILETRANSFERv1:";
final protected static char[] hexArray = "0123456789abcdef".toCharArray();
final protected static char[] vowels = "aeiou".toCharArray();
final protected static char[] consonants = "bcdfghjklmnpqrstvwxyz"
@@ -26,7 +26,7 @@ public class CryptoHelper {
}
return new String(hexChars);
}
-
+
public static byte[] hexToBytes(String hexString) {
byte[] array = new BigInteger(hexString, 16).toByteArray();
if (array[0] == 0) {
@@ -42,13 +42,14 @@ public class CryptoHelper {
}
private static byte[] concatenateByteArrays(byte[] a, byte[] b) {
- byte[] result = new byte[a.length + b.length];
- System.arraycopy(a, 0, result, 0, a.length);
- System.arraycopy(b, 0, result, a.length, b.length);
- return result;
- }
-
- public static String saslDigestMd5(Account account, String challenge, SecureRandom random) {
+ byte[] result = new byte[a.length + b.length];
+ System.arraycopy(a, 0, result, 0, a.length);
+ System.arraycopy(b, 0, result, a.length, b.length);
+ return result;
+ }
+
+ public static String saslDigestMd5(Account account, String challenge,
+ SecureRandom random) {
try {
String[] challengeParts = new String(Base64.decode(challenge,
Base64.DEFAULT)).split(",");
@@ -61,28 +62,29 @@ public class CryptoHelper {
return null;
}
}
- String digestUri = "xmpp/"+account.getServer();
+ String digestUri = "xmpp/" + account.getServer();
String nonceCount = "00000001";
String x = account.getUsername() + ":" + account.getServer() + ":"
+ account.getPassword();
MessageDigest md = MessageDigest.getInstance("MD5");
- byte[] y = md
- .digest(x.getBytes(Charset.defaultCharset()));
+ byte[] y = md.digest(x.getBytes(Charset.defaultCharset()));
String cNonce = new BigInteger(100, random).toString(32);
- byte[] a1 = concatenateByteArrays(y,(":"+nonce+":"+cNonce).getBytes(Charset.defaultCharset()));
- String a2 = "AUTHENTICATE:"+digestUri;
+ byte[] a1 = concatenateByteArrays(y,
+ (":" + nonce + ":" + cNonce).getBytes(Charset
+ .defaultCharset()));
+ String a2 = "AUTHENTICATE:" + digestUri;
String ha1 = bytesToHex(md.digest(a1));
String ha2 = bytesToHex(md.digest(a2.getBytes(Charset
.defaultCharset())));
- String kd = ha1 + ":" + nonce + ":"+nonceCount+":" + cNonce + ":auth:"
- + ha2;
+ String kd = ha1 + ":" + nonce + ":" + nonceCount + ":" + cNonce
+ + ":auth:" + ha2;
String response = bytesToHex(md.digest(kd.getBytes(Charset
.defaultCharset())));
String saslString = "username=\"" + account.getUsername()
+ "\",realm=\"" + account.getServer() + "\",nonce=\""
- + nonce + "\",cnonce=\"" + cNonce
- + "\",nc="+nonceCount+",qop=auth,digest-uri=\""+digestUri+"\",response=" + response
- + ",charset=utf-8";
+ + nonce + "\",cnonce=\"" + cNonce + "\",nc=" + nonceCount
+ + ",qop=auth,digest-uri=\"" + digestUri + "\",response="
+ + response + ",charset=utf-8";
return Base64.encodeToString(
saslString.getBytes(Charset.defaultCharset()),
Base64.NO_WRAP);
diff --git a/src/eu/siacs/conversations/utils/DNSHelper.java b/src/eu/siacs/conversations/utils/DNSHelper.java
index 002e124f..fd3b1953 100644
--- a/src/eu/siacs/conversations/utils/DNSHelper.java
+++ b/src/eu/siacs/conversations/utils/DNSHelper.java
@@ -10,6 +10,7 @@ import de.measite.minidns.record.A;
import de.measite.minidns.record.AAAA;
import de.measite.minidns.record.Data;
import de.measite.minidns.util.NameUtil;
+import eu.siacs.conversations.Config;
import java.io.IOException;
import java.net.InetAddress;
@@ -47,14 +48,11 @@ public class DNSHelper {
Bundle namePort = new Bundle();
try {
String qname = "_xmpp-client._tcp." + host;
- Log.d("xmppService", "using dns server: " + dnsServer.getHostAddress()
- + " to look up " + host);
- DNSMessage message =
- client.query(
- qname,
- TYPE.SRV,
- CLASS.IN,
- dnsServer.getHostAddress());
+ Log.d(Config.LOGTAG,
+ "using dns server: " + dnsServer.getHostAddress()
+ + " to look up " + host);
+ DNSMessage message = client.query(qname, TYPE.SRV, CLASS.IN,
+ dnsServer.getHostAddress());
// How should we handle priorities and weight?
// Wikipedia has a nice article about priorities vs. weights:
@@ -64,21 +62,20 @@ public class DNSHelper {
// a random order respecting the weight, and dump that priority by
// priority
- TreeMap<Integer, ArrayList<SRV>> priorities =
- new TreeMap<Integer, ArrayList<SRV>>();
- TreeMap<String, ArrayList<String>> ips4 =
- new TreeMap<String, ArrayList<String>>();
- TreeMap<String, ArrayList<String>> ips6 =
- new TreeMap<String, ArrayList<String>>();
+ TreeMap<Integer, ArrayList<SRV>> priorities = new TreeMap<Integer, ArrayList<SRV>>();
+ TreeMap<String, ArrayList<String>> ips4 = new TreeMap<String, ArrayList<String>>();
+ TreeMap<String, ArrayList<String>> ips6 = new TreeMap<String, ArrayList<String>>();
- for (Record[] rrset : new Record[][]{ message.getAnswers(),
- message.getAdditionalResourceRecords()}) {
+ for (Record[] rrset : new Record[][] { message.getAnswers(),
+ message.getAdditionalResourceRecords() }) {
for (Record rr : rrset) {
Data d = rr.getPayload();
- if (d instanceof SRV && NameUtil.idnEquals(qname,rr.getName())) {
+ if (d instanceof SRV
+ && NameUtil.idnEquals(qname, rr.getName())) {
SRV srv = (SRV) d;
if (!priorities.containsKey(srv.getPriority())) {
- priorities.put(srv.getPriority(), new ArrayList<SRV>(2));
+ priorities.put(srv.getPriority(),
+ new ArrayList<SRV>(2));
}
priorities.get(srv.getPriority()).add(srv);
}
@@ -100,8 +97,9 @@ public class DNSHelper {
}
Random rnd = new Random();
- ArrayList<SRV> result = new ArrayList<SRV>(priorities.size() * 2 + 1);
- for (ArrayList<SRV> s: priorities.values()) {
+ ArrayList<SRV> result = new ArrayList<SRV>(
+ priorities.size() * 2 + 1);
+ for (ArrayList<SRV> s : priorities.values()) {
// trivial case
if (s.size() <= 1) {
@@ -110,18 +108,20 @@ public class DNSHelper {
}
long totalweight = 0l;
- for (SRV srv: s) {
+ for (SRV srv : s) {
totalweight += srv.getWeight();
}
while (totalweight > 0l && s.size() > 0) {
- long p = (rnd.nextLong() & 0x7fffffffffffffffl) % totalweight;
+ long p = (rnd.nextLong() & 0x7fffffffffffffffl)
+ % totalweight;
int i = 0;
while (p > 0) {
p -= s.get(i++).getPriority();
}
i--;
- // remove is expensive, but we have only a few entries anyway
+ // remove is expensive, but we have only a few entries
+ // anyway
SRV srv = s.remove(i);
totalweight -= srv.getWeight();
result.add(srv);
@@ -164,10 +164,10 @@ public class DNSHelper {
}
} catch (SocketTimeoutException e) {
- Log.d("xmppService", "timeout during dns");
+ Log.d(Config.LOGTAG, "timeout during dns");
namePort.putString("error", "timeout");
} catch (Exception e) {
- Log.d("xmppService","unhandled exception in sub project");
+ Log.d(Config.LOGTAG, "unhandled exception in sub project");
namePort.putString("error", "unhandled");
}
return namePort;
diff --git a/src/eu/siacs/conversations/utils/ExceptionHandler.java b/src/eu/siacs/conversations/utils/ExceptionHandler.java
index 01cfebbb..88fa18ff 100644
--- a/src/eu/siacs/conversations/utils/ExceptionHandler.java
+++ b/src/eu/siacs/conversations/utils/ExceptionHandler.java
@@ -11,22 +11,25 @@ import java.lang.Thread.UncaughtExceptionHandler;
import android.content.Context;
public class ExceptionHandler implements UncaughtExceptionHandler {
-
+
private UncaughtExceptionHandler defaultHandler;
private Context context;
+
public ExceptionHandler(Context context) {
this.context = context;
this.defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
}
+
@Override
public void uncaughtException(Thread thread, Throwable ex) {
Writer result = new StringWriter();
- PrintWriter printWriter = new PrintWriter(result);
- ex.printStackTrace(printWriter);
- String stacktrace = result.toString();
- printWriter.close();
- try {
- OutputStream os = context.openFileOutput("stacktrace.txt",Context.MODE_PRIVATE);
+ PrintWriter printWriter = new PrintWriter(result);
+ ex.printStackTrace(printWriter);
+ String stacktrace = result.toString();
+ printWriter.close();
+ try {
+ OutputStream os = context.openFileOutput("stacktrace.txt",
+ Context.MODE_PRIVATE);
os.write(stacktrace.getBytes());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
diff --git a/src/eu/siacs/conversations/utils/ExceptionHelper.java b/src/eu/siacs/conversations/utils/ExceptionHelper.java
index 373aadd3..b5fc88bd 100644
--- a/src/eu/siacs/conversations/utils/ExceptionHelper.java
+++ b/src/eu/siacs/conversations/utils/ExceptionHelper.java
@@ -7,6 +7,7 @@ import java.io.IOException;
import java.io.InputStreamReader;
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.Conversation;
@@ -26,77 +27,91 @@ import android.util.Log;
public class ExceptionHelper {
public static void init(Context context) {
- if(!(Thread.getDefaultUncaughtExceptionHandler() instanceof ExceptionHandler)) {
- Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(context));
+ if (!(Thread.getDefaultUncaughtExceptionHandler() instanceof ExceptionHandler)) {
+ Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(
+ context));
}
}
-
- public static void checkForCrash(Context context, final XmppConnectionService service) {
+
+ public static void checkForCrash(Context context,
+ final XmppConnectionService service) {
try {
- final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
- boolean neverSend = preferences.getBoolean("never_send",false);
+ final SharedPreferences preferences = PreferenceManager
+ .getDefaultSharedPreferences(context);
+ boolean neverSend = preferences.getBoolean("never_send", false);
if (neverSend) {
return;
}
List<Account> accounts = service.getAccounts();
Account account = null;
- for(int i = 0; i < accounts.size(); ++i) {
+ for (int i = 0; i < accounts.size(); ++i) {
if (!accounts.get(i).isOptionSet(Account.OPTION_DISABLED)) {
account = accounts.get(i);
break;
}
}
- if (account==null) {
+ if (account == null) {
return;
}
final Account finalAccount = account;
FileInputStream file = context.openFileInput("stacktrace.txt");
- InputStreamReader inputStreamReader = new InputStreamReader(
- file);
- BufferedReader stacktrace = new BufferedReader(
- inputStreamReader);
- final StringBuilder report = new StringBuilder();
- PackageManager pm = context.getPackageManager();
- PackageInfo packageInfo = null;
- try {
- packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
- report.append("Version: "+packageInfo.versionName+'\n');
- report.append("Last Update: "+DateUtils.formatDateTime(context, packageInfo.lastUpdateTime, DateUtils.FORMAT_SHOW_TIME|DateUtils.FORMAT_SHOW_DATE)+'\n');
- } catch (NameNotFoundException e) {}
- String line;
- while((line = stacktrace.readLine()) != null) {
- report.append(line);
- report.append('\n');
- }
- file.close();
- context.deleteFile("stacktrace.txt");
+ InputStreamReader inputStreamReader = new InputStreamReader(file);
+ BufferedReader stacktrace = new BufferedReader(inputStreamReader);
+ final StringBuilder report = new StringBuilder();
+ PackageManager pm = context.getPackageManager();
+ PackageInfo packageInfo = null;
+ try {
+ packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
+ report.append("Version: " + packageInfo.versionName + '\n');
+ report.append("Last Update: "
+ + DateUtils.formatDateTime(context,
+ packageInfo.lastUpdateTime,
+ DateUtils.FORMAT_SHOW_TIME
+ | DateUtils.FORMAT_SHOW_DATE) + '\n');
+ } catch (NameNotFoundException e) {
+ }
+ String line;
+ while ((line = stacktrace.readLine()) != null) {
+ report.append(line);
+ report.append('\n');
+ }
+ file.close();
+ context.deleteFile("stacktrace.txt");
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(context.getString(R.string.crash_report_title));
builder.setMessage(context.getText(R.string.crash_report_message));
- builder.setPositiveButton(context.getText(R.string.send_now), new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
-
- Log.d("xmppService","using account="+finalAccount.getJid()+" to send in stack trace");
- Conversation conversation = service.findOrCreateConversation(finalAccount, "bugs@siacs.eu", false);
- Message message = new Message(conversation, report.toString(), Message.ENCRYPTION_NONE);
- service.sendMessage(message);
- }
- });
- builder.setNegativeButton(context.getText(R.string.send_never),new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- preferences.edit().putBoolean("never_send", true).commit();
- }
- });
+ builder.setPositiveButton(context.getText(R.string.send_now),
+ new OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+
+ Log.d(Config.LOGTAG, "using account="
+ + finalAccount.getJid()
+ + " to send in stack trace");
+ Conversation conversation = service
+ .findOrCreateConversation(finalAccount,
+ "bugs@siacs.eu", false);
+ Message message = new Message(conversation, report
+ .toString(), Message.ENCRYPTION_NONE);
+ service.sendMessage(message);
+ }
+ });
+ builder.setNegativeButton(context.getText(R.string.send_never),
+ new OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ preferences.edit().putBoolean("never_send", true)
+ .commit();
+ }
+ });
builder.create().show();
} catch (FileNotFoundException e) {
return;
} catch (IOException e) {
return;
}
-
+
}
}
diff --git a/src/eu/siacs/conversations/utils/PRNGFixes.java b/src/eu/siacs/conversations/utils/PRNGFixes.java
index cf28ff30..8fe67234 100644
--- a/src/eu/siacs/conversations/utils/PRNGFixes.java
+++ b/src/eu/siacs/conversations/utils/PRNGFixes.java
@@ -21,306 +21,307 @@ import java.security.Security;
/**
* Fixes for the output of the default PRNG having low entropy.
- *
+ *
* The fixes need to be applied via {@link #apply()} before any use of Java
* Cryptography Architecture primitives. A good place to invoke them is in the
* application's {@code onCreate}.
*/
public final class PRNGFixes {
- private static final int VERSION_CODE_JELLY_BEAN = 16;
- private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18;
- private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL =
- getBuildFingerprintAndDeviceSerial();
+ private static final int VERSION_CODE_JELLY_BEAN = 16;
+ private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18;
+ private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL = getBuildFingerprintAndDeviceSerial();
- /** Hidden constructor to prevent instantiation. */
- private PRNGFixes() {}
+ /** Hidden constructor to prevent instantiation. */
+ private PRNGFixes() {
+ }
- /**
- * Applies all fixes.
- *
- * @throws SecurityException if a fix is needed but could not be applied.
- */
- public static void apply() {
- applyOpenSSLFix();
- installLinuxPRNGSecureRandom();
- }
+ /**
+ * Applies all fixes.
+ *
+ * @throws SecurityException
+ * if a fix is needed but could not be applied.
+ */
+ public static void apply() {
+ applyOpenSSLFix();
+ installLinuxPRNGSecureRandom();
+ }
- /**
- * Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the
- * fix is not needed.
- *
- * @throws SecurityException if the fix is needed but could not be applied.
- */
- private static void applyOpenSSLFix() throws SecurityException {
- if ((Build.VERSION.SDK_INT < VERSION_CODE_JELLY_BEAN)
- || (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2)) {
- // No need to apply the fix
- return;
- }
+ /**
+ * Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the
+ * fix is not needed.
+ *
+ * @throws SecurityException
+ * if the fix is needed but could not be applied.
+ */
+ private static void applyOpenSSLFix() throws SecurityException {
+ if ((Build.VERSION.SDK_INT < VERSION_CODE_JELLY_BEAN)
+ || (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2)) {
+ // No need to apply the fix
+ return;
+ }
- try {
- // Mix in the device- and invocation-specific seed.
- Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
- .getMethod("RAND_seed", byte[].class)
- .invoke(null, generateSeed());
+ try {
+ // Mix in the device- and invocation-specific seed.
+ Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
+ .getMethod("RAND_seed", byte[].class)
+ .invoke(null, generateSeed());
- // Mix output of Linux PRNG into OpenSSL's PRNG
- int bytesRead = (Integer) Class.forName(
- "org.apache.harmony.xnet.provider.jsse.NativeCrypto")
- .getMethod("RAND_load_file", String.class, long.class)
- .invoke(null, "/dev/urandom", 1024);
- if (bytesRead != 1024) {
- throw new IOException(
- "Unexpected number of bytes read from Linux PRNG: "
- + bytesRead);
- }
- } catch (Exception e) {
- throw new SecurityException("Failed to seed OpenSSL PRNG", e);
- }
- }
+ // Mix output of Linux PRNG into OpenSSL's PRNG
+ int bytesRead = (Integer) Class
+ .forName(
+ "org.apache.harmony.xnet.provider.jsse.NativeCrypto")
+ .getMethod("RAND_load_file", String.class, long.class)
+ .invoke(null, "/dev/urandom", 1024);
+ if (bytesRead != 1024) {
+ throw new IOException(
+ "Unexpected number of bytes read from Linux PRNG: "
+ + bytesRead);
+ }
+ } catch (Exception e) {
+ throw new SecurityException("Failed to seed OpenSSL PRNG", e);
+ }
+ }
- /**
- * Installs a Linux PRNG-backed {@code SecureRandom} implementation as the
- * default. Does nothing if the implementation is already the default or if
- * there is not need to install the implementation.
- *
- * @throws SecurityException if the fix is needed but could not be applied.
- */
- private static void installLinuxPRNGSecureRandom()
- throws SecurityException {
- if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) {
- // No need to apply the fix
- return;
- }
+ /**
+ * Installs a Linux PRNG-backed {@code SecureRandom} implementation as the
+ * default. Does nothing if the implementation is already the default or if
+ * there is not need to install the implementation.
+ *
+ * @throws SecurityException
+ * if the fix is needed but could not be applied.
+ */
+ private static void installLinuxPRNGSecureRandom() throws SecurityException {
+ if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) {
+ // No need to apply the fix
+ return;
+ }
- // Install a Linux PRNG-based SecureRandom implementation as the
- // default, if not yet installed.
- Provider[] secureRandomProviders =
- Security.getProviders("SecureRandom.SHA1PRNG");
- if ((secureRandomProviders == null)
- || (secureRandomProviders.length < 1)
- || (!LinuxPRNGSecureRandomProvider.class.equals(
- secureRandomProviders[0].getClass()))) {
- Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1);
- }
+ // Install a Linux PRNG-based SecureRandom implementation as the
+ // default, if not yet installed.
+ Provider[] secureRandomProviders = Security
+ .getProviders("SecureRandom.SHA1PRNG");
+ if ((secureRandomProviders == null)
+ || (secureRandomProviders.length < 1)
+ || (!LinuxPRNGSecureRandomProvider.class
+ .equals(secureRandomProviders[0].getClass()))) {
+ Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1);
+ }
- // Assert that new SecureRandom() and
- // SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed
- // by the Linux PRNG-based SecureRandom implementation.
- SecureRandom rng1 = new SecureRandom();
- if (!LinuxPRNGSecureRandomProvider.class.equals(
- rng1.getProvider().getClass())) {
- throw new SecurityException(
- "new SecureRandom() backed by wrong Provider: "
- + rng1.getProvider().getClass());
- }
+ // Assert that new SecureRandom() and
+ // SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed
+ // by the Linux PRNG-based SecureRandom implementation.
+ SecureRandom rng1 = new SecureRandom();
+ if (!LinuxPRNGSecureRandomProvider.class.equals(rng1.getProvider()
+ .getClass())) {
+ throw new SecurityException(
+ "new SecureRandom() backed by wrong Provider: "
+ + rng1.getProvider().getClass());
+ }
- SecureRandom rng2;
- try {
- rng2 = SecureRandom.getInstance("SHA1PRNG");
- } catch (NoSuchAlgorithmException e) {
- throw new SecurityException("SHA1PRNG not available", e);
- }
- if (!LinuxPRNGSecureRandomProvider.class.equals(
- rng2.getProvider().getClass())) {
- throw new SecurityException(
- "SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong"
- + " Provider: " + rng2.getProvider().getClass());
- }
- }
+ SecureRandom rng2;
+ try {
+ rng2 = SecureRandom.getInstance("SHA1PRNG");
+ } catch (NoSuchAlgorithmException e) {
+ throw new SecurityException("SHA1PRNG not available", e);
+ }
+ if (!LinuxPRNGSecureRandomProvider.class.equals(rng2.getProvider()
+ .getClass())) {
+ throw new SecurityException(
+ "SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong"
+ + " Provider: " + rng2.getProvider().getClass());
+ }
+ }
- /**
- * {@code Provider} of {@code SecureRandom} engines which pass through
- * all requests to the Linux PRNG.
- */
- private static class LinuxPRNGSecureRandomProvider extends Provider {
+ /**
+ * {@code Provider} of {@code SecureRandom} engines which pass through all
+ * requests to the Linux PRNG.
+ */
+ private static class LinuxPRNGSecureRandomProvider extends Provider {
- public LinuxPRNGSecureRandomProvider() {
- super("LinuxPRNG",
- 1.0,
- "A Linux-specific random number provider that uses"
- + " /dev/urandom");
- // Although /dev/urandom is not a SHA-1 PRNG, some apps
- // explicitly request a SHA1PRNG SecureRandom and we thus need to
- // prevent them from getting the default implementation whose output
- // may have low entropy.
- put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom.class.getName());
- put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
- }
- }
+ public LinuxPRNGSecureRandomProvider() {
+ super("LinuxPRNG", 1.0,
+ "A Linux-specific random number provider that uses"
+ + " /dev/urandom");
+ // Although /dev/urandom is not a SHA-1 PRNG, some apps
+ // explicitly request a SHA1PRNG SecureRandom and we thus need to
+ // prevent them from getting the default implementation whose output
+ // may have low entropy.
+ put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom.class.getName());
+ put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
+ }
+ }
- /**
- * {@link SecureRandomSpi} which passes all requests to the Linux PRNG
- * ({@code /dev/urandom}).
- */
- public static class LinuxPRNGSecureRandom extends SecureRandomSpi {
+ /**
+ * {@link SecureRandomSpi} which passes all requests to the Linux PRNG (
+ * {@code /dev/urandom}).
+ */
+ public static class LinuxPRNGSecureRandom extends SecureRandomSpi {
- /*
- * IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed
- * are passed through to the Linux PRNG (/dev/urandom). Instances of
- * this class seed themselves by mixing in the current time, PID, UID,
- * build fingerprint, and hardware serial number (where available) into
- * Linux PRNG.
- *
- * Concurrency: Read requests to the underlying Linux PRNG are
- * serialized (on sLock) to ensure that multiple threads do not get
- * duplicated PRNG output.
- */
+ /*
+ * IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed
+ * are passed through to the Linux PRNG (/dev/urandom). Instances of
+ * this class seed themselves by mixing in the current time, PID, UID,
+ * build fingerprint, and hardware serial number (where available) into
+ * Linux PRNG.
+ *
+ * Concurrency: Read requests to the underlying Linux PRNG are
+ * serialized (on sLock) to ensure that multiple threads do not get
+ * duplicated PRNG output.
+ */
- private static final File URANDOM_FILE = new File("/dev/urandom");
+ private static final File URANDOM_FILE = new File("/dev/urandom");
- private static final Object sLock = new Object();
+ private static final Object sLock = new Object();
- /**
- * Input stream for reading from Linux PRNG or {@code null} if not yet
- * opened.
- *
- * @GuardedBy("sLock")
- */
- private static DataInputStream sUrandomIn;
+ /**
+ * Input stream for reading from Linux PRNG or {@code null} if not yet
+ * opened.
+ *
+ * @GuardedBy("sLock")
+ */
+ private static DataInputStream sUrandomIn;
- /**
- * Output stream for writing to Linux PRNG or {@code null} if not yet
- * opened.
- *
- * @GuardedBy("sLock")
- */
- private static OutputStream sUrandomOut;
+ /**
+ * Output stream for writing to Linux PRNG or {@code null} if not yet
+ * opened.
+ *
+ * @GuardedBy("sLock")
+ */
+ private static OutputStream sUrandomOut;
- /**
- * Whether this engine instance has been seeded. This is needed because
- * each instance needs to seed itself if the client does not explicitly
- * seed it.
- */
- private boolean mSeeded;
+ /**
+ * Whether this engine instance has been seeded. This is needed because
+ * each instance needs to seed itself if the client does not explicitly
+ * seed it.
+ */
+ private boolean mSeeded;
- @Override
- protected void engineSetSeed(byte[] bytes) {
- try {
- OutputStream out;
- synchronized (sLock) {
- out = getUrandomOutputStream();
- }
- out.write(bytes);
- out.flush();
- } catch (IOException e) {
- // On a small fraction of devices /dev/urandom is not writable.
- // Log and ignore.
- Log.w(PRNGFixes.class.getSimpleName(),
- "Failed to mix seed into " + URANDOM_FILE);
- } finally {
- mSeeded = true;
- }
- }
+ @Override
+ protected void engineSetSeed(byte[] bytes) {
+ try {
+ OutputStream out;
+ synchronized (sLock) {
+ out = getUrandomOutputStream();
+ }
+ out.write(bytes);
+ out.flush();
+ } catch (IOException e) {
+ // On a small fraction of devices /dev/urandom is not writable.
+ // Log and ignore.
+ Log.w(PRNGFixes.class.getSimpleName(),
+ "Failed to mix seed into " + URANDOM_FILE);
+ } finally {
+ mSeeded = true;
+ }
+ }
- @Override
- protected void engineNextBytes(byte[] bytes) {
- if (!mSeeded) {
- // Mix in the device- and invocation-specific seed.
- engineSetSeed(generateSeed());
- }
+ @Override
+ protected void engineNextBytes(byte[] bytes) {
+ if (!mSeeded) {
+ // Mix in the device- and invocation-specific seed.
+ engineSetSeed(generateSeed());
+ }
- try {
- DataInputStream in;
- synchronized (sLock) {
- in = getUrandomInputStream();
- }
- synchronized (in) {
- in.readFully(bytes);
- }
- } catch (IOException e) {
- throw new SecurityException(
- "Failed to read from " + URANDOM_FILE, e);
- }
- }
+ try {
+ DataInputStream in;
+ synchronized (sLock) {
+ in = getUrandomInputStream();
+ }
+ synchronized (in) {
+ in.readFully(bytes);
+ }
+ } catch (IOException e) {
+ throw new SecurityException("Failed to read from "
+ + URANDOM_FILE, e);
+ }
+ }
- @Override
- protected byte[] engineGenerateSeed(int size) {
- byte[] seed = new byte[size];
- engineNextBytes(seed);
- return seed;
- }
+ @Override
+ protected byte[] engineGenerateSeed(int size) {
+ byte[] seed = new byte[size];
+ engineNextBytes(seed);
+ return seed;
+ }
- private DataInputStream getUrandomInputStream() {
- synchronized (sLock) {
- if (sUrandomIn == null) {
- // NOTE: Consider inserting a BufferedInputStream between
- // DataInputStream and FileInputStream if you need higher
- // PRNG output performance and can live with future PRNG
- // output being pulled into this process prematurely.
- try {
- sUrandomIn = new DataInputStream(
- new FileInputStream(URANDOM_FILE));
- } catch (IOException e) {
- throw new SecurityException("Failed to open "
- + URANDOM_FILE + " for reading", e);
- }
- }
- return sUrandomIn;
- }
- }
+ private DataInputStream getUrandomInputStream() {
+ synchronized (sLock) {
+ if (sUrandomIn == null) {
+ // NOTE: Consider inserting a BufferedInputStream between
+ // DataInputStream and FileInputStream if you need higher
+ // PRNG output performance and can live with future PRNG
+ // output being pulled into this process prematurely.
+ try {
+ sUrandomIn = new DataInputStream(new FileInputStream(
+ URANDOM_FILE));
+ } catch (IOException e) {
+ throw new SecurityException("Failed to open "
+ + URANDOM_FILE + " for reading", e);
+ }
+ }
+ return sUrandomIn;
+ }
+ }
- private OutputStream getUrandomOutputStream() throws IOException {
- synchronized (sLock) {
- if (sUrandomOut == null) {
- sUrandomOut = new FileOutputStream(URANDOM_FILE);
- }
- return sUrandomOut;
- }
- }
- }
+ private OutputStream getUrandomOutputStream() throws IOException {
+ synchronized (sLock) {
+ if (sUrandomOut == null) {
+ sUrandomOut = new FileOutputStream(URANDOM_FILE);
+ }
+ return sUrandomOut;
+ }
+ }
+ }
- /**
- * Generates a device- and invocation-specific seed to be mixed into the
- * Linux PRNG.
- */
- private static byte[] generateSeed() {
- try {
- ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream();
- DataOutputStream seedBufferOut =
- new DataOutputStream(seedBuffer);
- seedBufferOut.writeLong(System.currentTimeMillis());
- seedBufferOut.writeLong(System.nanoTime());
- seedBufferOut.writeInt(Process.myPid());
- seedBufferOut.writeInt(Process.myUid());
- seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL);
- seedBufferOut.close();
- return seedBuffer.toByteArray();
- } catch (IOException e) {
- throw new SecurityException("Failed to generate seed", e);
- }
- }
+ /**
+ * Generates a device- and invocation-specific seed to be mixed into the
+ * Linux PRNG.
+ */
+ private static byte[] generateSeed() {
+ try {
+ ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream();
+ DataOutputStream seedBufferOut = new DataOutputStream(seedBuffer);
+ seedBufferOut.writeLong(System.currentTimeMillis());
+ seedBufferOut.writeLong(System.nanoTime());
+ seedBufferOut.writeInt(Process.myPid());
+ seedBufferOut.writeInt(Process.myUid());
+ seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL);
+ seedBufferOut.close();
+ return seedBuffer.toByteArray();
+ } catch (IOException e) {
+ throw new SecurityException("Failed to generate seed", e);
+ }
+ }
- /**
- * Gets the hardware serial number of this device.
- *
- * @return serial number or {@code null} if not available.
- */
- private static String getDeviceSerialNumber() {
- // We're using the Reflection API because Build.SERIAL is only available
- // since API Level 9 (Gingerbread, Android 2.3).
- try {
- return (String) Build.class.getField("SERIAL").get(null);
- } catch (Exception ignored) {
- return null;
- }
- }
+ /**
+ * Gets the hardware serial number of this device.
+ *
+ * @return serial number or {@code null} if not available.
+ */
+ private static String getDeviceSerialNumber() {
+ // We're using the Reflection API because Build.SERIAL is only available
+ // since API Level 9 (Gingerbread, Android 2.3).
+ try {
+ return (String) Build.class.getField("SERIAL").get(null);
+ } catch (Exception ignored) {
+ return null;
+ }
+ }
- private static byte[] getBuildFingerprintAndDeviceSerial() {
- StringBuilder result = new StringBuilder();
- String fingerprint = Build.FINGERPRINT;
- if (fingerprint != null) {
- result.append(fingerprint);
- }
- String serial = getDeviceSerialNumber();
- if (serial != null) {
- result.append(serial);
- }
- try {
- return result.toString().getBytes("UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException("UTF-8 encoding not supported");
- }
- }
+ private static byte[] getBuildFingerprintAndDeviceSerial() {
+ StringBuilder result = new StringBuilder();
+ String fingerprint = Build.FINGERPRINT;
+ if (fingerprint != null) {
+ result.append(fingerprint);
+ }
+ String serial = getDeviceSerialNumber();
+ if (serial != null) {
+ result.append(serial);
+ }
+ try {
+ return result.toString().getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 encoding not supported");
+ }
+ }
} \ No newline at end of file
diff --git a/src/eu/siacs/conversations/utils/PhoneHelper.java b/src/eu/siacs/conversations/utils/PhoneHelper.java
index 63c17761..25cff099 100644
--- a/src/eu/siacs/conversations/utils/PhoneHelper.java
+++ b/src/eu/siacs/conversations/utils/PhoneHelper.java
@@ -2,6 +2,7 @@ package eu.siacs.conversations.utils;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
import android.content.Context;
import android.content.CursorLoader;
@@ -18,7 +19,7 @@ public class PhoneHelper {
public static void loadPhoneContacts(Context context,
final OnPhoneContactsLoadedListener listener) {
final List<Bundle> phoneContacts = new ArrayList<Bundle>();
-
+
final String[] PROJECTION = new String[] { ContactsContract.Data._ID,
ContactsContract.Data.DISPLAY_NAME,
ContactsContract.Data.PHOTO_THUMBNAIL_URI,
@@ -38,7 +39,7 @@ public class PhoneHelper {
@Override
public void onLoadComplete(Loader<Cursor> arg0, Cursor cursor) {
- if (cursor==null) {
+ if (cursor == null) {
return;
}
while (cursor.moveToNext()) {
@@ -55,8 +56,10 @@ public class PhoneHelper {
.getColumnIndex(ContactsContract.Data.PHOTO_THUMBNAIL_URI)));
contact.putString("lookup", cursor.getString(cursor
.getColumnIndex(ContactsContract.Data.LOOKUP_KEY)));
-
- contact.putString("jid",cursor.getString(cursor
+
+ contact.putString(
+ "jid",
+ cursor.getString(cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA)));
phoneContacts.add(contact);
}
@@ -65,12 +68,17 @@ public class PhoneHelper {
}
}
});
- mCursorLoader.startLoading();
+ try {
+ mCursorLoader.startLoading();
+ } catch (RejectedExecutionException e) {
+ if (listener != null) {
+ listener.onPhoneContactsLoaded(phoneContacts);
+ }
+ }
}
public static Uri getSefliUri(Context context) {
- String[] mProjection = new String[] { Profile._ID,
- Profile.PHOTO_URI };
+ String[] mProjection = new String[] { Profile._ID, Profile.PHOTO_URI };
Cursor mProfileCursor = context.getContentResolver().query(
Profile.CONTENT_URI, mProjection, null, null, null);
diff --git a/src/eu/siacs/conversations/utils/UIHelper.java b/src/eu/siacs/conversations/utils/UIHelper.java
index 7a807b2f..54c370ef 100644
--- a/src/eu/siacs/conversations/utils/UIHelper.java
+++ b/src/eu/siacs/conversations/utils/UIHelper.java
@@ -118,9 +118,13 @@ public class UIHelper {
}
private static int getNameColor(String name) {
- /*int holoColors[] = { 0xFF1da9da, 0xFFb368d9, 0xFF83b600, 0xFFffa713,
- 0xFFe92727 };*/
- int holoColors[] = {0xFFe91e63, 0xFF9c27b0, 0xFF673ab7, 0xFF3f51b5, 0xFF5677fc, 0xFF03a9f4, 0xFF00bcd4, 0xFF009688, 0xFFff5722, 0xFF795548, 0xFF607d8b};
+ /*
+ * int holoColors[] = { 0xFF1da9da, 0xFFb368d9, 0xFF83b600, 0xFFffa713,
+ * 0xFFe92727 };
+ */
+ int holoColors[] = { 0xFFe91e63, 0xFF9c27b0, 0xFF673ab7, 0xFF3f51b5,
+ 0xFF5677fc, 0xFF03a9f4, 0xFF00bcd4, 0xFF009688, 0xFFff5722,
+ 0xFF795548, 0xFF607d8b };
return holoColors[(int) ((name.hashCode() & 0xffffffffl) % holoColors.length)];
}
@@ -211,14 +215,14 @@ public class UIHelper {
List<User> members = conversation.getMucOptions().getUsers();
if (members.size() == 0) {
return getUnknownContactPicture(
- new String[] { conversation.getName(false) }, size,
- bgColor, fgColor);
+ new String[] { conversation.getName() }, size, bgColor,
+ fgColor);
}
ArrayList<String> names = new ArrayList<String>();
names.add(conversation.getMucOptions().getActualNick());
- for(User user : members) {
+ for (User user : members) {
names.add(user.getName());
- if (names.size() > 4 ) {
+ if (names.size() > 4) {
break;
}
}
@@ -328,7 +332,6 @@ public class UIHelper {
SharedPreferences preferences = PreferenceManager
.getDefaultSharedPreferences(context);
- boolean useSubject = preferences.getBoolean("use_subject_in_muc", true);
boolean showNofifications = preferences.getBoolean("show_notification",
true);
boolean vibrate = preferences.getBoolean("vibrate_on_notification",
@@ -377,7 +380,7 @@ public class UIHelper {
Conversation conversation = unread.get(0);
targetUuid = conversation.getUuid();
mBuilder.setLargeIcon(conversation.getImage(context, 64));
- mBuilder.setContentTitle(conversation.getName(useSubject));
+ mBuilder.setContentTitle(conversation.getName());
if (notify) {
mBuilder.setTicker(conversation.getLatestMessage()
.getReadableBody(context));
@@ -409,12 +412,12 @@ public class UIHelper {
for (int i = 0; i < unread.size(); ++i) {
targetUuid = unread.get(i).getUuid();
if (i < unread.size() - 1) {
- names.append(unread.get(i).getName(useSubject) + ", ");
+ names.append(unread.get(i).getName() + ", ");
} else {
- names.append(unread.get(i).getName(useSubject));
+ names.append(unread.get(i).getName());
}
style.addLine(Html.fromHtml("<b>"
- + unread.get(i).getName(useSubject)
+ + unread.get(i).getName()
+ "</b> "
+ unread.get(i).getLatestMessage()
.getReadableBody(context)));
@@ -541,4 +544,45 @@ public class UIHelper {
return getContactPicture(account.getJid(), size, context, false);
}
}
+
+ 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;
+ }
}
diff --git a/src/eu/siacs/conversations/utils/Validator.java b/src/eu/siacs/conversations/utils/Validator.java
index a1a119e7..00130fa2 100644
--- a/src/eu/siacs/conversations/utils/Validator.java
+++ b/src/eu/siacs/conversations/utils/Validator.java
@@ -4,9 +4,9 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Validator {
- public static final Pattern VALID_JID =
- Pattern.compile("^[^@/<>'\"\\s]+@[^@/<>'\"\\s]+$", Pattern.CASE_INSENSITIVE);
-
+ public static final Pattern VALID_JID = Pattern.compile(
+ "^[^@/<>'\"\\s]+@[^@/<>'\"\\s]+$", Pattern.CASE_INSENSITIVE);
+
public static boolean isValidJid(String jid) {
Matcher matcher = VALID_JID.matcher(jid);
return matcher.find();
diff --git a/src/eu/siacs/conversations/utils/zlib/ZLibInputStream.java b/src/eu/siacs/conversations/utils/zlib/ZLibInputStream.java
index 2eebf6f4..b777c10c 100644
--- a/src/eu/siacs/conversations/utils/zlib/ZLibInputStream.java
+++ b/src/eu/siacs/conversations/utils/zlib/ZLibInputStream.java
@@ -12,41 +12,43 @@ import java.util.zip.InflaterInputStream;
*/
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);
- }
+ /**
+ * 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();
- }
+ /**
+ * 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/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java b/src/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java
index cc64a5e6..8b3f5e68 100644
--- a/src/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java
+++ b/src/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java
@@ -9,76 +9,87 @@ 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
+ * <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>
+ * 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.
- */
+ /**
+ * The reflection based flush method.
+ */
- private final static Method method;
- /**
- * SUPPORTED is true if a flush compatible method exists.
- */
- public final static boolean SUPPORTED;
+ 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);
- }
+ /**
+ * 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));
- }
+ /**
+ * 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);
+ /**
+ * 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");
}
- } 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();
- }
+ super.flush();
+ }
}
diff --git a/src/eu/siacs/conversations/xml/Element.java b/src/eu/siacs/conversations/xml/Element.java
index cc21a780..4e11ee2c 100644
--- a/src/eu/siacs/conversations/xml/Element.java
+++ b/src/eu/siacs/conversations/xml/Element.java
@@ -139,10 +139,10 @@ public class Element {
}
public void setAttribute(String name, long value) {
- this.setAttribute(name, ""+value);
+ this.setAttribute(name, Long.toString(value));
}
-
+
public void setAttribute(String name, int value) {
- this.setAttribute(name, ""+value);
+ this.setAttribute(name, Integer.toString(value));
}
}
diff --git a/src/eu/siacs/conversations/xml/Tag.java b/src/eu/siacs/conversations/xml/Tag.java
index a9eecad6..b9ef979f 100644
--- a/src/eu/siacs/conversations/xml/Tag.java
+++ b/src/eu/siacs/conversations/xml/Tag.java
@@ -12,77 +12,78 @@ public class Tag {
public static final int START = 0;
public static final int END = 1;
public static final int EMPTY = 2;
-
+
protected int type;
protected String name;
protected Hashtable<String, String> attributes = new Hashtable<String, String>();
-
+
protected Tag(int type, String name) {
this.type = type;
this.name = name;
}
-
public static Tag no(String text) {
- return new Tag(NO,text);
+ return new Tag(NO, text);
}
-
+
public static Tag start(String name) {
- return new Tag(START,name);
+ return new Tag(START, name);
}
-
+
public static Tag end(String name) {
- return new Tag(END,name);
+ return new Tag(END, name);
}
-
+
public static Tag empty(String name) {
- return new Tag(EMPTY,name);
+ return new Tag(EMPTY, name);
}
-
+
public String getName() {
return name;
}
-
+
public String getAttribute(String attrName) {
return this.attributes.get(attrName);
}
-
+
public Tag setAttribute(String attrName, String attrValue) {
this.attributes.put(attrName, attrValue);
return this;
}
-
+
public Tag setAtttributes(Hashtable<String, String> attributes) {
this.attributes = attributes;
return this;
}
-
+
public boolean isStart(String needle) {
- if (needle==null) return false;
+ if (needle == null)
+ return false;
return (this.type == START) && (needle.equals(this.name));
}
-
+
public boolean isEnd(String needle) {
- if (needle==null) return false;
+ if (needle == null)
+ return false;
return (this.type == END) && (needle.equals(this.name));
}
-
+
public boolean isNo() {
return (this.type == NO);
}
-
+
public String toString() {
StringBuilder tagOutput = new StringBuilder();
tagOutput.append('<');
- if (type==END) {
+ if (type == END) {
tagOutput.append('/');
}
tagOutput.append(name);
- if(type!=END) {
+ if (type != END) {
Set<Entry<String, String>> attributeSet = attributes.entrySet();
Iterator<Entry<String, String>> it = attributeSet.iterator();
- while(it.hasNext()) {
- Entry<String,String> entry = it.next();
+ while (it.hasNext()) {
+ Entry<String, String> entry = it.next();
tagOutput.append(' ');
tagOutput.append(entry.getKey());
tagOutput.append("=\"");
@@ -90,7 +91,7 @@ public class Tag {
tagOutput.append('"');
}
}
- if (type==EMPTY) {
+ if (type == EMPTY) {
tagOutput.append('/');
}
tagOutput.append('>');
diff --git a/src/eu/siacs/conversations/xml/TagWriter.java b/src/eu/siacs/conversations/xml/TagWriter.java
index 4828d5d9..f11c1846 100644
--- a/src/eu/siacs/conversations/xml/TagWriter.java
+++ b/src/eu/siacs/conversations/xml/TagWriter.java
@@ -8,22 +8,23 @@ import java.util.concurrent.LinkedBlockingQueue;
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
public class TagWriter {
-
+
private OutputStream plainOutputStream;
private OutputStreamWriter outputStream;
private boolean finshed = false;
private LinkedBlockingQueue<AbstractStanza> writeQueue = new LinkedBlockingQueue<AbstractStanza>();
private Thread asyncStanzaWriter = new Thread() {
private boolean shouldStop = false;
+
@Override
public void run() {
- while(!shouldStop) {
- if ((finshed)&&(writeQueue.size() == 0)) {
+ while (!shouldStop) {
+ if ((finshed) && (writeQueue.size() == 0)) {
return;
}
try {
AbstractStanza output = writeQueue.take();
- if (outputStream==null) {
+ if (outputStream == null) {
shouldStop = true;
} else {
outputStream.write(output.toString());
@@ -37,12 +38,12 @@ public class TagWriter {
}
}
};
-
+
public TagWriter() {
}
-
+
public void setOutputStream(OutputStream out) throws IOException {
- if (out==null) {
+ if (out == null) {
throw new IOException();
}
this.plainOutputStream = out;
@@ -50,23 +51,23 @@ public class TagWriter {
}
public OutputStream getOutputStream() throws IOException {
- if (this.plainOutputStream==null) {
+ if (this.plainOutputStream == null) {
throw new IOException();
}
return this.plainOutputStream;
}
public TagWriter beginDocument() throws IOException {
- if (outputStream==null) {
+ if (outputStream == null) {
throw new IOException("output stream was null");
}
outputStream.write("<?xml version='1.0'?>");
outputStream.flush();
return this;
}
-
+
public TagWriter writeTag(Tag tag) throws IOException {
- if (outputStream==null) {
+ if (outputStream == null) {
throw new IOException("output stream was null");
}
outputStream.write(tag.toString());
@@ -75,34 +76,34 @@ public class TagWriter {
}
public TagWriter writeElement(Element element) throws IOException {
- if (outputStream==null) {
+ if (outputStream == null) {
throw new IOException("output stream was null");
}
outputStream.write(element.toString());
outputStream.flush();
return this;
}
-
+
public TagWriter writeStanzaAsync(AbstractStanza stanza) {
- if (finshed) {
- return this;
- } else {
- if (!asyncStanzaWriter.isAlive()) {
- try {
- asyncStanzaWriter.start();
- } catch (IllegalThreadStateException e) {
- //already started
- }
+ if (finshed) {
+ return this;
+ } else {
+ if (!asyncStanzaWriter.isAlive()) {
+ try {
+ asyncStanzaWriter.start();
+ } catch (IllegalThreadStateException e) {
+ // already started
}
- writeQueue.add(stanza);
- return this;
}
+ writeQueue.add(stanza);
+ return this;
+ }
}
-
+
public void finish() {
this.finshed = true;
}
-
+
public boolean finished() {
return (this.writeQueue.size() == 0);
}
diff --git a/src/eu/siacs/conversations/xml/XmlReader.java b/src/eu/siacs/conversations/xml/XmlReader.java
index cf6b8c73..52d3d46a 100644
--- a/src/eu/siacs/conversations/xml/XmlReader.java
+++ b/src/eu/siacs/conversations/xml/XmlReader.java
@@ -7,13 +7,14 @@ import java.io.InputStreamReader;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import eu.siacs.conversations.Config;
+
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import android.util.Xml;
public class XmlReader {
- private static final String LOGTAG = "xmppService";
private XmlPullParser parser;
private PowerManager.WakeLock wakeLock;
private InputStream is;
@@ -21,15 +22,16 @@ public class XmlReader {
public XmlReader(WakeLock wakeLock) {
this.parser = Xml.newPullParser();
try {
- this.parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES,true);
+ this.parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES,
+ true);
} catch (XmlPullParserException e) {
- Log.d(LOGTAG,"error setting namespace feature on parser");
+ Log.d(Config.LOGTAG, "error setting namespace feature on parser");
}
this.wakeLock = wakeLock;
}
-
+
public void setInputStream(InputStream inputStream) throws IOException {
- if (inputStream==null) {
+ if (inputStream == null) {
throw new IOException();
}
this.is = inputStream;
@@ -41,14 +43,14 @@ public class XmlReader {
}
public InputStream getInputStream() throws IOException {
- if (this.is==null) {
+ if (this.is == null) {
throw new IOException();
}
return is;
}
public void reset() throws IOException {
- if (this.is==null) {
+ if (this.is == null) {
throw new IOException();
}
try {
@@ -57,62 +59,74 @@ public class XmlReader {
throw new IOException("error resetting parser");
}
}
-
+
public Tag readTag() throws XmlPullParserException, IOException {
if (wakeLock.isHeld()) {
- try { wakeLock.release();} catch (RuntimeException re) {}
+ try {
+ wakeLock.release();
+ } catch (RuntimeException re) {
+ }
}
try {
- while(this.is != null && parser.next() != XmlPullParser.END_DOCUMENT) {
- wakeLock.acquire();
- if (parser.getEventType() == XmlPullParser.START_TAG) {
- Tag tag = Tag.start(parser.getName());
- for(int i = 0; i < parser.getAttributeCount(); ++i) {
- tag.setAttribute(parser.getAttributeName(i), parser.getAttributeValue(i));
- }
- String xmlns = parser.getNamespace();
- if (xmlns!=null) {
- tag.setAttribute("xmlns",xmlns);
- }
- return tag;
- } else if (parser.getEventType() == XmlPullParser.END_TAG) {
- Tag tag = Tag.end(parser.getName());
- return tag;
- } else if (parser.getEventType() == XmlPullParser.TEXT) {
- Tag tag = Tag.no(parser.getText());
- return tag;
+ while (this.is != null
+ && parser.next() != XmlPullParser.END_DOCUMENT) {
+ wakeLock.acquire();
+ if (parser.getEventType() == XmlPullParser.START_TAG) {
+ Tag tag = Tag.start(parser.getName());
+ for (int i = 0; i < parser.getAttributeCount(); ++i) {
+ tag.setAttribute(parser.getAttributeName(i),
+ parser.getAttributeValue(i));
}
+ String xmlns = parser.getNamespace();
+ if (xmlns != null) {
+ tag.setAttribute("xmlns", xmlns);
+ }
+ return tag;
+ } else if (parser.getEventType() == XmlPullParser.END_TAG) {
+ Tag tag = Tag.end(parser.getName());
+ return tag;
+ } else if (parser.getEventType() == XmlPullParser.TEXT) {
+ Tag tag = Tag.no(parser.getText());
+ return tag;
}
+ }
if (wakeLock.isHeld()) {
- try { wakeLock.release();} catch (RuntimeException re) {}
+ try {
+ wakeLock.release();
+ } catch (RuntimeException re) {
+ }
}
} catch (ArrayIndexOutOfBoundsException e) {
- throw new IOException("xml parser mishandled ArrayIndexOufOfBounds", e);
+ throw new IOException(
+ "xml parser mishandled ArrayIndexOufOfBounds", e);
} catch (StringIndexOutOfBoundsException e) {
- throw new IOException("xml parser mishandled StringIndexOufOfBounds", e);
+ throw new IOException(
+ "xml parser mishandled StringIndexOufOfBounds", e);
} catch (NullPointerException e) {
- throw new IOException("xml parser mishandled NullPointerException", e);
+ throw new IOException("xml parser mishandled NullPointerException",
+ e);
} catch (IndexOutOfBoundsException e) {
throw new IOException("xml parser mishandled IndexOutOfBound", e);
}
return null;
}
- public Element readElement(Tag currentTag) throws XmlPullParserException, IOException {
+ public Element readElement(Tag currentTag) throws XmlPullParserException,
+ IOException {
Element element = new Element(currentTag.getName());
element.setAttributes(currentTag.getAttributes());
Tag nextTag = this.readTag();
if (nextTag == null) {
throw new IOException("unterupted mid tag");
}
- if(nextTag.isNo()) {
+ if (nextTag.isNo()) {
element.setContent(nextTag.getName());
nextTag = this.readTag();
if (nextTag == null) {
throw new IOException("unterupted mid tag");
}
}
- while(!nextTag.isEnd(element.getName())) {
+ while (!nextTag.isEnd(element.getName())) {
if (!nextTag.isNo()) {
Element child = this.readElement(nextTag);
element.addChild(child);
diff --git a/src/eu/siacs/conversations/xmpp/OnMessageAcknowledged.java b/src/eu/siacs/conversations/xmpp/OnMessageAcknowledged.java
new file mode 100644
index 00000000..5f670d93
--- /dev/null
+++ b/src/eu/siacs/conversations/xmpp/OnMessageAcknowledged.java
@@ -0,0 +1,7 @@
+package eu.siacs.conversations.xmpp;
+
+import eu.siacs.conversations.entities.Account;
+
+public interface OnMessageAcknowledged {
+ public void onMessageAcknowledged(Account account, String id);
+}
diff --git a/src/eu/siacs/conversations/xmpp/XmppConnection.java b/src/eu/siacs/conversations/xmpp/XmppConnection.java
index ba7a9245..e7b25e26 100644
--- a/src/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -31,6 +31,8 @@ import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.util.Log;
+import android.util.SparseArray;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.CryptoHelper;
@@ -47,6 +49,8 @@ import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
+import eu.siacs.conversations.xmpp.stanzas.csi.ActivePacket;
+import eu.siacs.conversations.xmpp.stanzas.csi.InactivePacket;
import eu.siacs.conversations.xmpp.stanzas.streammgmt.AckPacket;
import eu.siacs.conversations.xmpp.stanzas.streammgmt.EnablePacket;
import eu.siacs.conversations.xmpp.stanzas.streammgmt.RequestPacket;
@@ -55,7 +59,6 @@ import eu.siacs.conversations.xmpp.stanzas.streammgmt.ResumePacket;
public class XmppConnection implements Runnable {
protected Account account;
- private static final String LOGTAG = "xmppService";
private WakeLock wakeLock;
@@ -64,7 +67,7 @@ public class XmppConnection implements Runnable {
private Socket socket;
private XmlReader tagReader;
private TagWriter tagWriter;
-
+
private Features features = new Features(this);
private boolean shouldBind = true;
@@ -74,7 +77,8 @@ public class XmppConnection implements Runnable {
private String streamId = null;
private int smVersion = 3;
-
+ private SparseArray<String> messageReceipts = new SparseArray<String>();
+
private boolean usingCompression = false;
private int stanzasReceived = 0;
@@ -98,14 +102,15 @@ public class XmppConnection implements Runnable {
private OnMessagePacketReceived messageListener = null;
private OnStatusChanged statusListener = null;
private OnBindListener bindListener = null;
+ private OnMessageAcknowledged acknowledgedListener = null;
private MemorizingTrustManager mMemorizingTrustManager;
public XmppConnection(Account account, XmppConnectionService service) {
this.mRandom = service.getRNG();
this.mMemorizingTrustManager = service.getMemorizingTrustManager();
this.account = account;
- this.wakeLock = service.getPowerManager().newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
- account.getJid());
+ this.wakeLock = service.getPowerManager().newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, account.getJid());
tagWriter = new TagWriter();
}
@@ -128,7 +133,7 @@ public class XmppConnection implements Runnable {
}
protected void connect() {
- Log.d(LOGTAG, account.getJid() + ": connecting");
+ Log.d(Config.LOGTAG, account.getJid() + ": connecting");
usingCompression = false;
lastConnect = SystemClock.elapsedRealtime();
lastPingSent = SystemClock.elapsedRealtime();
@@ -142,7 +147,7 @@ public class XmppConnection implements Runnable {
this.changeStatus(Account.STATUS_CONNECTING);
Bundle namePort = DNSHelper.getSRVRecord(account.getServer());
if ("timeout".equals(namePort.getString("error"))) {
- Log.d(LOGTAG, account.getJid() + ": dns timeout");
+ Log.d(Config.LOGTAG, account.getJid() + ": dns timeout");
this.changeStatus(Account.STATUS_OFFLINE);
return;
}
@@ -151,13 +156,14 @@ public class XmppConnection implements Runnable {
int srvRecordPort = namePort.getInt("port");
if (srvRecordServer != null) {
if (srvIpServer != null) {
- Log.d(LOGTAG, account.getJid() + ": using values from dns "
- + srvRecordServer + "[" + srvIpServer + "]:"
- + srvRecordPort);
+ Log.d(Config.LOGTAG, account.getJid()
+ + ": using values from dns " + srvRecordServer
+ + "[" + srvIpServer + "]:" + srvRecordPort);
socket = new Socket(srvIpServer, srvRecordPort);
} else {
- Log.d(LOGTAG, account.getJid() + ": using values from dns "
- + srvRecordServer + ":" + srvRecordPort);
+ Log.d(Config.LOGTAG, account.getJid()
+ + ": using values from dns " + srvRecordServer
+ + ":" + srvRecordPort);
socket = new Socket(srvRecordServer, srvRecordPort);
}
} else {
@@ -175,7 +181,8 @@ public class XmppConnection implements Runnable {
processStream(nextTag);
break;
} else {
- Log.d(LOGTAG, "found unexpected tag: " + nextTag.getName());
+ Log.d(Config.LOGTAG,
+ "found unexpected tag: " + nextTag.getName());
return;
}
}
@@ -185,27 +192,39 @@ public class XmppConnection implements Runnable {
} catch (UnknownHostException e) {
this.changeStatus(Account.STATUS_SERVER_NOT_FOUND);
if (wakeLock.isHeld()) {
- try { wakeLock.release();} catch (RuntimeException re) {}
+ try {
+ wakeLock.release();
+ } catch (RuntimeException re) {
+ }
}
return;
} catch (IOException e) {
this.changeStatus(Account.STATUS_OFFLINE);
if (wakeLock.isHeld()) {
- try { wakeLock.release();} catch (RuntimeException re) {}
+ try {
+ wakeLock.release();
+ } catch (RuntimeException re) {
+ }
}
return;
} catch (NoSuchAlgorithmException e) {
this.changeStatus(Account.STATUS_OFFLINE);
- Log.d(LOGTAG, "compression exception " + e.getMessage());
+ Log.d(Config.LOGTAG, "compression exception " + e.getMessage());
if (wakeLock.isHeld()) {
- try { wakeLock.release();} catch (RuntimeException re) {}
+ try {
+ wakeLock.release();
+ } catch (RuntimeException re) {
+ }
}
return;
} catch (XmlPullParserException e) {
this.changeStatus(Account.STATUS_OFFLINE);
- Log.d(LOGTAG, "xml exception " + e.getMessage());
+ Log.d(Config.LOGTAG, "xml exception " + e.getMessage());
if (wakeLock.isHeld()) {
- try { wakeLock.release();} catch (RuntimeException re) {}
+ try {
+ wakeLock.release();
+ } catch (RuntimeException re) {
+ }
}
return;
}
@@ -230,7 +249,7 @@ public class XmppConnection implements Runnable {
} else if (nextTag.isStart("compressed")) {
switchOverToZLib(nextTag);
} else if (nextTag.isStart("success")) {
- Log.d(LOGTAG, account.getJid() + ": logged in");
+ Log.d(Config.LOGTAG, account.getJid() + ": logged in");
tagReader.readTag();
tagReader.reset();
sendStartStream();
@@ -245,18 +264,18 @@ public class XmppConnection implements Runnable {
response.setAttribute("xmlns",
"urn:ietf:params:xml:ns:xmpp-sasl");
response.setContent(CryptoHelper.saslDigestMd5(account,
- challange,mRandom));
+ challange, mRandom));
tagWriter.writeElement(response);
} else if (nextTag.isStart("enabled")) {
- this.stanzasSent = 0;
Element enabled = tagReader.readElement(nextTag);
if ("true".equals(enabled.getAttribute("resume"))) {
this.streamId = enabled.getAttribute("id");
- Log.d(LOGTAG, account.getJid() + ": stream managment("
- + smVersion + ") enabled (resumable)");
+ Log.d(Config.LOGTAG, account.getJid()
+ + ": stream managment(" + smVersion
+ + ") enabled (resumable)");
} else {
- Log.d(LOGTAG, account.getJid() + ": stream managment("
- + smVersion + ") enabled");
+ Log.d(Config.LOGTAG, account.getJid()
+ + ": stream managment(" + smVersion + ") enabled");
}
this.lastSessionStarted = SystemClock.elapsedRealtime();
this.stanzasReceived = 0;
@@ -264,9 +283,30 @@ public class XmppConnection implements Runnable {
tagWriter.writeStanzaAsync(r);
} else if (nextTag.isStart("resumed")) {
lastPaketReceived = SystemClock.elapsedRealtime();
- Log.d(LOGTAG, account.getJid() + ": session resumed");
- tagReader.readElement(nextTag);
- sendPing();
+ Element resumed = tagReader.readElement(nextTag);
+ String h = resumed.getAttribute("h");
+ try {
+ int serverCount = Integer.parseInt(h);
+ if (serverCount != stanzasSent) {
+ Log.d(Config.LOGTAG, account.getJid()
+ + ": session resumed with lost packages");
+ stanzasSent = serverCount;
+ } else {
+ Log.d(Config.LOGTAG, account.getJid()
+ + ": session resumed");
+ }
+ if (acknowledgedListener != null) {
+ for (int i = 0; i < messageReceipts.size(); ++i) {
+ if (serverCount >= messageReceipts.keyAt(i)) {
+ acknowledgedListener.onMessageAcknowledged(
+ account, messageReceipts.valueAt(i));
+ }
+ }
+ }
+ messageReceipts.clear();
+ } catch (NumberFormatException e) {
+
+ }
changeStatus(Account.STATUS_ONLINE);
} else if (nextTag.isStart("r")) {
tagReader.readElement(nextTag);
@@ -276,12 +316,17 @@ public class XmppConnection implements Runnable {
Element ack = tagReader.readElement(nextTag);
lastPaketReceived = SystemClock.elapsedRealtime();
int serverSequence = Integer.parseInt(ack.getAttribute("h"));
- if (serverSequence > this.stanzasSent) {
- this.stanzasSent = serverSequence;
+ String msgId = this.messageReceipts.get(serverSequence);
+ if (msgId != null) {
+ if (this.acknowledgedListener != null) {
+ this.acknowledgedListener.onMessageAcknowledged(
+ account, msgId);
+ }
+ this.messageReceipts.remove(serverSequence);
}
} else if (nextTag.isStart("failed")) {
tagReader.readElement(nextTag);
- Log.d(LOGTAG, account.getJid() + ": resumption failed");
+ Log.d(Config.LOGTAG, account.getJid() + ": resumption failed");
streamId = null;
if (account.getStatus() != Account.STATUS_ONLINE) {
sendBindRequest();
@@ -321,7 +366,7 @@ public class XmppConnection implements Runnable {
}
element.setAttributes(currentTag.getAttributes());
Tag nextTag = tagReader.readTag();
- if (nextTag==null) {
+ if (nextTag == null) {
throw new IOException("interrupted mid tag");
}
while (!nextTag.isEnd(element.getName())) {
@@ -335,7 +380,7 @@ public class XmppConnection implements Runnable {
element.addChild(child);
}
nextTag = tagReader.readTag();
- if (nextTag==null) {
+ if (nextTag == null) {
throw new IOException("interrupted mid tag");
}
}
@@ -420,7 +465,7 @@ public class XmppConnection implements Runnable {
.setInputStream(new ZLibInputStream(tagReader.getInputStream()));
sendStartStream();
- Log.d(LOGTAG, account.getJid() + ": compression enabled");
+ Log.d(Config.LOGTAG, account.getJid() + ": compression enabled");
usingCompression = true;
processStream(tagReader.readTag());
}
@@ -436,23 +481,30 @@ public class XmppConnection implements Runnable {
tagReader.readTag();
try {
SSLContext sc = SSLContext.getInstance("TLS");
- sc.init(null, new X509TrustManager[] { this.mMemorizingTrustManager }, mRandom);
+ sc.init(null,
+ new X509TrustManager[] { this.mMemorizingTrustManager },
+ mRandom);
SSLSocketFactory factory = sc.getSocketFactory();
-
- HostnameVerifier verifier = this.mMemorizingTrustManager.wrapHostnameVerifier(new org.apache.http.conn.ssl.StrictHostnameVerifier());
+
+ HostnameVerifier verifier = this.mMemorizingTrustManager
+ .wrapHostnameVerifier(new org.apache.http.conn.ssl.StrictHostnameVerifier());
SSLSocket sslSocket = (SSLSocket) factory.createSocket(socket,
socket.getInetAddress().getHostAddress(), socket.getPort(),
true);
-
- if (verifier != null && !verifier.verify(account.getServer(), sslSocket.getSession())) {
- Log.d(LOGTAG, account.getJid() + ": host mismatch in TLS connection");
+
+ if (verifier != null
+ && !verifier.verify(account.getServer(),
+ sslSocket.getSession())) {
+ Log.d(Config.LOGTAG, account.getJid()
+ + ": host mismatch in TLS connection");
sslSocket.close();
throw new IOException();
}
tagReader.setInputStream(sslSocket.getInputStream());
tagWriter.setOutputStream(sslSocket.getOutputStream());
sendStartStream();
- Log.d(LOGTAG, account.getJid() + ": TLS connection established");
+ Log.d(Config.LOGTAG, account.getJid()
+ + ": TLS connection established");
processStream(tagReader.readTag());
sslSocket.close();
} catch (NoSuchAlgorithmException e1) {
@@ -578,7 +630,7 @@ public class XmppConnection implements Runnable {
changeStatus(Account.STATUS_REGISTRATION_CONFLICT);
} else {
changeStatus(Account.STATUS_REGISTRATION_FAILED);
- Log.d(LOGTAG, packet.toString());
+ Log.d(Config.LOGTAG, packet.toString());
}
disconnect(true);
}
@@ -586,7 +638,7 @@ public class XmppConnection implements Runnable {
} else {
changeStatus(Account.STATUS_REGISTRATION_FAILED);
disconnect(true);
- Log.d(LOGTAG, account.getJid()
+ Log.d(Config.LOGTAG, account.getJid()
+ ": could not register. instructions are"
+ instructions.getContent());
}
@@ -602,18 +654,23 @@ public class XmppConnection implements Runnable {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
Element bind = packet.findChild("bind");
- if (bind!=null) {
+ if (bind != null) {
Element jid = bind.findChild("jid");
- if (jid!=null) {
+ if (jid != null) {
account.setResource(jid.getContent().split("/")[1]);
if (streamFeatures.hasChild("sm", "urn:xmpp:sm:3")) {
smVersion = 3;
EnablePacket enable = new EnablePacket(smVersion);
tagWriter.writeStanzaAsync(enable);
- } else if (streamFeatures.hasChild("sm", "urn:xmpp:sm:2")) {
+ stanzasSent = 0;
+ messageReceipts.clear();
+ } else if (streamFeatures.hasChild("sm",
+ "urn:xmpp:sm:2")) {
smVersion = 2;
EnablePacket enable = new EnablePacket(smVersion);
tagWriter.writeStanzaAsync(enable);
+ stanzasSent = 0;
+ messageReceipts.clear();
}
sendServiceDiscoveryInfo(account.getServer());
sendServiceDiscoveryItems(account.getServer());
@@ -630,7 +687,8 @@ public class XmppConnection implements Runnable {
}
});
if (this.streamFeatures.hasChild("session")) {
- Log.d(LOGTAG, account.getJid() + ": sending deprecated session");
+ Log.d(Config.LOGTAG, account.getJid()
+ + ": sending deprecated session");
IqPacket startSession = new IqPacket(IqPacket.TYPE_SET);
startSession.addChild("session",
"urn:ietf:params:xml:ns:xmpp-session");
@@ -695,18 +753,26 @@ public class XmppConnection implements Runnable {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
if (!packet.hasChild("error")) {
- Log.d(LOGTAG, account.getJid()
+ Log.d(Config.LOGTAG, account.getJid()
+ ": successfully enabled carbons");
} else {
- Log.d(LOGTAG, account.getJid()
+ Log.d(Config.LOGTAG, account.getJid()
+ ": error enableing carbons " + packet.toString());
}
}
});
}
- private void processStreamError(Tag currentTag) {
- Log.d(LOGTAG, "processStreamError");
+ private void processStreamError(Tag currentTag)
+ throws XmlPullParserException, IOException {
+ Element streamError = tagReader.readElement(currentTag);
+ if (streamError != null && streamError.hasChild("conflict")) {
+ String resource = account.getResource().split("\\.")[0];
+ account.setResource(resource + "." + nextRandomId());
+ Log.d(Config.LOGTAG,
+ account.getJid() + ": switching resource due to conflict ("
+ + account.getResource() + ")");
+ }
}
private void sendStartStream() throws IOException {
@@ -748,12 +814,21 @@ public class XmppConnection implements Runnable {
public void sendPresencePacket(PresencePacket packet) {
this.sendPacket(packet, null);
}
-
+
private synchronized void sendPacket(final AbstractStanza packet,
PacketReceived callback) {
- // TODO dont increment stanza count if packet = request packet or ack;
- ++stanzasSent;
+ if (packet.getName().equals("iq") || packet.getName().equals("message")
+ || packet.getName().equals("presence")) {
+ ++stanzasSent;
+ }
tagWriter.writeStanzaAsync(packet);
+ if (packet instanceof MessagePacket && packet.getId() != null
+ && this.streamId != null) {
+ Log.d(Config.LOGTAG, "request delivery report for stanza "
+ + stanzasSent);
+ this.messageReceipts.put(stanzasSent, packet.getId());
+ tagWriter.writeStanzaAsync(new RequestPacket(this.smVersion));
+ }
if (callback != null) {
if (packet.getId() == null) {
packet.setId(nextRandomId());
@@ -802,9 +877,13 @@ public class XmppConnection implements Runnable {
this.bindListener = listener;
}
+ public void setOnMessageAcknowledgeListener(OnMessageAcknowledged listener) {
+ this.acknowledgedListener = listener;
+ }
+
public void disconnect(boolean force) {
changeStatus(Account.STATUS_OFFLINE);
- Log.d(LOGTAG, "disconnecting");
+ Log.d(Config.LOGTAG, "disconnecting");
try {
if (force) {
socket.close();
@@ -818,20 +897,21 @@ public class XmppConnection implements Runnable {
tagWriter.finish();
try {
while (!tagWriter.finished()) {
- Log.d(LOGTAG, "not yet finished");
+ Log.d(Config.LOGTAG, "not yet finished");
Thread.sleep(100);
}
tagWriter.writeTag(Tag.end("stream:stream"));
} catch (IOException e) {
- Log.d(LOGTAG, "io exception during disconnect");
+ Log.d(Config.LOGTAG,
+ "io exception during disconnect");
} catch (InterruptedException e) {
- Log.d(LOGTAG, "interrupted");
+ Log.d(Config.LOGTAG, "interrupted");
}
}
}
}).start();
} catch (IOException e) {
- Log.d(LOGTAG, "io exception during disconnect");
+ Log.d(Config.LOGTAG, "io exception during disconnect");
}
}
@@ -844,10 +924,10 @@ public class XmppConnection implements Runnable {
}
return items;
}
-
+
public String findDiscoItemByFeature(String feature) {
List<String> items = findDiscoItemsByFeature(feature);
- if (items.size()>=1) {
+ if (items.size() >= 1) {
return items.get(0);
}
return null;
@@ -856,7 +936,7 @@ public class XmppConnection implements Runnable {
public void r() {
this.tagWriter.writeStanzaAsync(new RequestPacket(smVersion));
}
-
+
public String getMucServer() {
return findDiscoItemByFeature("http://jabber.org/protocol/muc");
}
@@ -870,28 +950,29 @@ public class XmppConnection implements Runnable {
public int getAttempt() {
return this.attempt;
}
-
+
public Features getFeatures() {
return this.features;
}
-
+
public class Features {
XmppConnection connection;
+
public Features(XmppConnection connection) {
this.connection = connection;
}
-
+
private boolean hasDiscoFeature(String server, String feature) {
if (!connection.disco.containsKey(server)) {
return false;
}
return connection.disco.get(server).contains(feature);
}
-
+
public boolean carbons() {
return hasDiscoFeature(account.getServer(), "urn:xmpp:carbons:2");
}
-
+
public boolean sm() {
if (connection.streamFeatures == null) {
return false;
@@ -899,11 +980,21 @@ public class XmppConnection implements Runnable {
return connection.streamFeatures.hasChild("sm");
}
}
-
+
+ public boolean csi() {
+ if (connection.streamFeatures == null) {
+ return false;
+ } else {
+ return connection.streamFeatures.hasChild("csi",
+ "urn:xmpp:csi:0");
+ }
+ }
+
public boolean pubsub() {
- return hasDiscoFeature(account.getServer(), "http://jabber.org/protocol/pubsub#publish");
+ return hasDiscoFeature(account.getServer(),
+ "http://jabber.org/protocol/pubsub#publish");
}
-
+
public boolean rosterVersioning() {
if (connection.streamFeatures == null) {
return false;
@@ -911,11 +1002,12 @@ public class XmppConnection implements Runnable {
return connection.streamFeatures.hasChild("ver");
}
}
-
+
public boolean streamhost() {
- return connection.findDiscoItemByFeature("http://jabber.org/protocol/bytestreams") != null;
+ return connection
+ .findDiscoItemByFeature("http://jabber.org/protocol/bytestreams") != null;
}
-
+
public boolean compression() {
return connection.usingCompression;
}
@@ -930,16 +1022,24 @@ public class XmppConnection implements Runnable {
}
return System.currentTimeMillis() - diff;
}
-
+
public long getLastConnect() {
return this.lastConnect;
}
-
+
public long getLastPingSent() {
return this.lastPingSent;
}
-
+
public long getLastPacketReceived() {
return this.lastPaketReceived;
}
+
+ public void sendActive() {
+ this.sendPacket(new ActivePacket(), null);
+ }
+
+ public void sendInactive() {
+ this.sendPacket(new InactivePacket(), null);
+ }
}
diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java b/src/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java
index 80ffeaaa..3e7c7b68 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java
@@ -6,11 +6,11 @@ import java.util.List;
import eu.siacs.conversations.xml.Element;
public class JingleCandidate {
-
+
public static int TYPE_UNKNOWN;
public static int TYPE_DIRECT = 0;
public static int TYPE_PROXY = 1;
-
+
private boolean ours;
private boolean usedByCounterpart = false;
private String cid;
@@ -19,12 +19,12 @@ public class JingleCandidate {
private int type;
private String jid;
private int priority;
-
- public JingleCandidate(String cid,boolean ours) {
+
+ public JingleCandidate(String cid, boolean ours) {
this.ours = ours;
this.cid = cid;
}
-
+
public String getCid() {
return cid;
}
@@ -32,15 +32,15 @@ public class JingleCandidate {
public void setHost(String host) {
this.host = host;
}
-
+
public String getHost() {
return this.host;
}
-
+
public void setJid(String jid) {
this.jid = jid;
}
-
+
public String getJid() {
return this.jid;
}
@@ -48,15 +48,15 @@ public class JingleCandidate {
public void setPort(int port) {
this.port = port;
}
-
+
public int getPort() {
return this.port;
}
-
+
public void setType(int type) {
this.type = type;
}
-
+
public void setType(String type) {
if ("proxy".equals(type)) {
this.type = TYPE_PROXY;
@@ -70,42 +70,46 @@ public class JingleCandidate {
public void setPriority(int i) {
this.priority = i;
}
-
+
public int getPriority() {
return this.priority;
}
-
+
public boolean equals(JingleCandidate other) {
return this.getCid().equals(other.getCid());
}
-
+
public boolean equalValues(JingleCandidate other) {
- return other.getHost().equals(this.getHost())&&(other.getPort()==this.getPort());
+ return other.getHost().equals(this.getHost())
+ && (other.getPort() == this.getPort());
}
-
+
public boolean isOurs() {
return ours;
}
-
+
public int getType() {
return this.type;
}
public static List<JingleCandidate> parse(List<Element> canditates) {
List<JingleCandidate> parsedCandidates = new ArrayList<JingleCandidate>();
- for(Element c : canditates) {
+ for (Element c : canditates) {
parsedCandidates.add(JingleCandidate.parse(c));
}
return parsedCandidates;
}
-
+
public static JingleCandidate parse(Element candidate) {
- JingleCandidate parsedCandidate = new JingleCandidate(candidate.getAttribute("cid"), false);
+ JingleCandidate parsedCandidate = new JingleCandidate(
+ candidate.getAttribute("cid"), false);
parsedCandidate.setHost(candidate.getAttribute("host"));
parsedCandidate.setJid(candidate.getAttribute("jid"));
parsedCandidate.setType(candidate.getAttribute("type"));
- parsedCandidate.setPriority(Integer.parseInt(candidate.getAttribute("priority")));
- parsedCandidate.setPort(Integer.parseInt(candidate.getAttribute("port")));
+ parsedCandidate.setPriority(Integer.parseInt(candidate
+ .getAttribute("priority")));
+ parsedCandidate
+ .setPort(Integer.parseInt(candidate.getAttribute("port")));
return parsedCandidate;
}
@@ -113,26 +117,27 @@ public class JingleCandidate {
Element element = new Element("candidate");
element.setAttribute("cid", this.getCid());
element.setAttribute("host", this.getHost());
- element.setAttribute("port", ""+this.getPort());
+ element.setAttribute("port", Integer.toString(this.getPort()));
element.setAttribute("jid", this.getJid());
- element.setAttribute("priority",""+this.getPriority());
- if (this.getType()==TYPE_DIRECT) {
- element.setAttribute("type","direct");
- } else if (this.getType()==TYPE_PROXY) {
- element.setAttribute("type","proxy");
+ element.setAttribute("priority", Integer.toString(this.getPriority()));
+ if (this.getType() == TYPE_DIRECT) {
+ element.setAttribute("type", "direct");
+ } else if (this.getType() == TYPE_PROXY) {
+ element.setAttribute("type", "proxy");
}
return element;
}
public void flagAsUsedByCounterpart() {
- this.usedByCounterpart = true;
+ this.usedByCounterpart = true;
}
public boolean isUsedByCounterpart() {
return this.usedByCounterpart;
}
-
+
public String toString() {
- return this.getHost()+":"+this.getPort()+" (prio="+this.getPriority()+")";
+ return this.getHost() + ":" + this.getPort() + " (prio="
+ + this.getPriority() + ")";
}
}
diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
index bfdbb7cc..f42482e8 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
@@ -12,8 +12,10 @@ import android.content.Intent;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.util.Log;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Downloadable;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xml.Element;
@@ -23,7 +25,7 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
import eu.siacs.conversations.xmpp.jingle.stanzas.Reason;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
-public class JingleConnection {
+public class JingleConnection implements Downloadable {
private final String[] extensions = { "webp", "jpeg", "jpg", "png" };
private final String[] cryptoExtensions = { "pgp", "gpg", "otr" };
@@ -94,16 +96,17 @@ public class JingleConnection {
BitmapFactory.decodeFile(file.getAbsolutePath(), options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
- message.setBody("" + file.getSize() + "," + imageWidth + ","
- + imageHeight);
+ message.setBody(Long.toString(file.getSize()) + ','
+ + imageWidth + ',' + imageHeight);
mXmppConnectionService.databaseBackend.createMessage(message);
mXmppConnectionService.markMessage(message,
Message.STATUS_RECEIVED);
}
- Log.d("xmppService",
+ Log.d(Config.LOGTAG,
"sucessfully transmitted file:" + file.getAbsolutePath());
- if (message.getEncryption()!=Message.ENCRYPTION_PGP) {
- Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+ if (message.getEncryption() != Message.ENCRYPTION_PGP) {
+ Intent intent = new Intent(
+ Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(file));
mXmppConnectionService.sendBroadcast(intent);
}
@@ -121,17 +124,17 @@ public class JingleConnection {
@Override
public void success() {
if (initiator.equals(account.getFullJid())) {
- Log.d("xmppService", "we were initiating. sending file");
+ Log.d(Config.LOGTAG, "we were initiating. sending file");
transport.send(file, onFileTransmissionSatusChanged);
} else {
transport.receive(file, onFileTransmissionSatusChanged);
- Log.d("xmppService", "we were responding. receiving file");
+ Log.d(Config.LOGTAG, "we were responding. receiving file");
}
}
@Override
public void failed() {
- Log.d("xmppService", "proxy activation failed");
+ Log.d(Config.LOGTAG, "proxy activation failed");
}
};
@@ -177,13 +180,13 @@ public class JingleConnection {
returnResult = this.receiveFallbackToIbb(packet);
} else {
returnResult = false;
- Log.d("xmppService", "trying to fallback to something unknown"
+ Log.d(Config.LOGTAG, "trying to fallback to something unknown"
+ packet.toString());
}
} else if (packet.isAction("transport-accept")) {
returnResult = this.receiveTransportAccept(packet);
} else {
- Log.d("xmppService", "packet arrived in connection. action was "
+ Log.d(Config.LOGTAG, "packet arrived in connection. action was "
+ packet.getAction());
returnResult = false;
}
@@ -224,14 +227,14 @@ public class JingleConnection {
@Override
public void failed() {
- Log.d("xmppService",
+ Log.d(Config.LOGTAG,
"connection to our own primary candidete failed");
sendInitRequest();
}
@Override
public void established() {
- Log.d("xmppService",
+ Log.d(Config.LOGTAG,
"succesfully connected to our own primary candidate");
mergeCandidate(candidate);
sendInitRequest();
@@ -239,7 +242,7 @@ public class JingleConnection {
});
mergeCandidate(candidate);
} else {
- Log.d("xmppService",
+ Log.d(Config.LOGTAG,
"no primary candidate of our own was found");
sendInitRequest();
}
@@ -257,7 +260,7 @@ public class JingleConnection {
this.message = new Message(conversation, "", Message.ENCRYPTION_NONE);
this.message.setType(Message.TYPE_IMAGE);
this.message.setStatus(Message.STATUS_RECEIVED_OFFER);
- this.message.setJingleConnection(this);
+ this.message.setDownloadable(this);
String[] fromParts = packet.getFrom().split("/");
this.message.setPresence(fromParts[1]);
this.account = account;
@@ -288,7 +291,7 @@ public class JingleConnection {
filename[filename.length - 2])) {
supportedFile = true;
if (filename[filename.length - 1].equals("otr")) {
- Log.d("xmppService", "receiving otr file");
+ Log.d(Config.LOGTAG, "receiving otr file");
this.message
.setEncryption(Message.ENCRYPTION_OTR);
} else {
@@ -300,17 +303,17 @@ public class JingleConnection {
}
if (supportedFile) {
long size = Long.parseLong(fileSize.getContent());
- message.setBody("" + size);
+ message.setBody(Long.toString(size));
conversation.getMessages().add(message);
if (size <= this.mJingleConnectionManager
.getAutoAcceptFileSize()) {
- Log.d("xmppService", "auto accepting file from "
+ Log.d(Config.LOGTAG, "auto accepting file from "
+ packet.getFrom());
this.acceptedAutomatically = true;
this.sendAccept();
} else {
message.markUnread();
- Log.d("xmppService",
+ Log.d(Config.LOGTAG,
"not auto accepting new file offer with size: "
+ size
+ " allowed size:"
@@ -400,7 +403,7 @@ public class JingleConnection {
@Override
public void failed() {
- Log.d("xmppService",
+ Log.d(Config.LOGTAG,
"connection to our own primary candidate failed");
content.socks5transport().setChildren(
getCandidatesAsElements());
@@ -411,7 +414,7 @@ public class JingleConnection {
@Override
public void established() {
- Log.d("xmppService",
+ Log.d(Config.LOGTAG,
"connected to primary candidate");
mergeCandidate(candidate);
content.socks5transport().setChildren(
@@ -422,7 +425,7 @@ public class JingleConnection {
}
});
} else {
- Log.d("xmppService",
+ Log.d(Config.LOGTAG,
"did not find a primary candidate for ourself");
content.socks5transport().setChildren(
getCandidatesAsElements());
@@ -446,7 +449,7 @@ public class JingleConnection {
}
private void sendJinglePacket(JinglePacket packet) {
- // Log.d("xmppService",packet.toString());
+ // Log.d(Config.LOGTAG,packet.toString());
account.getXmppConnection().sendIqPacket(packet, responseListener);
}
@@ -470,14 +473,14 @@ public class JingleConnection {
} else {
String cid = content.socks5transport()
.findChild("activated").getAttribute("cid");
- Log.d("xmppService", "received proxy activated (" + cid
+ Log.d(Config.LOGTAG, "received proxy activated (" + cid
+ ")prior to choosing our own transport");
JingleSocks5Transport connection = this.connections
.get(cid);
if (connection != null) {
connection.setActivated(true);
} else {
- Log.d("xmppService", "activated connection not found");
+ Log.d(Config.LOGTAG, "activated connection not found");
this.sendCancel();
this.cancel();
}
@@ -487,7 +490,7 @@ public class JingleConnection {
onProxyActivated.failed();
return true;
} else if (content.socks5transport().hasChild("candidate-error")) {
- Log.d("xmppService", "received candidate error");
+ Log.d(Config.LOGTAG, "received candidate error");
this.receivedCandidate = true;
if ((status == STATUS_ACCEPTED) && (this.sentCandidate)) {
this.connect();
@@ -497,14 +500,14 @@ public class JingleConnection {
String cid = content.socks5transport()
.findChild("candidate-used").getAttribute("cid");
if (cid != null) {
- Log.d("xmppService", "candidate used by counterpart:" + cid);
+ Log.d(Config.LOGTAG, "candidate used by counterpart:" + cid);
JingleCandidate candidate = getCandidate(cid);
candidate.flagAsUsedByCounterpart();
this.receivedCandidate = true;
if ((status == STATUS_ACCEPTED) && (this.sentCandidate)) {
this.connect();
} else {
- Log.d("xmppService",
+ Log.d(Config.LOGTAG,
"ignoring because file is already in transmission or we havent sent our candidate yet");
}
return true;
@@ -523,7 +526,7 @@ public class JingleConnection {
final JingleSocks5Transport connection = chooseConnection();
this.transport = connection;
if (connection == null) {
- Log.d("xmppService", "could not find suitable candidate");
+ Log.d(Config.LOGTAG, "could not find suitable candidate");
this.disconnect();
if (this.initiator.equals(account.getFullJid())) {
this.sendFallbackToIbb();
@@ -532,7 +535,7 @@ public class JingleConnection {
this.status = STATUS_TRANSMITTING;
if (connection.needsActivation()) {
if (connection.getCandidate().isOurs()) {
- Log.d("xmppService", "candidate "
+ Log.d(Config.LOGTAG, "candidate "
+ connection.getCandidate().getCid()
+ " was our proxy. going to activate");
IqPacket activation = new IqPacket(IqPacket.TYPE_SET);
@@ -557,17 +560,17 @@ public class JingleConnection {
}
});
} else {
- Log.d("xmppService",
+ Log.d(Config.LOGTAG,
"candidate "
+ connection.getCandidate().getCid()
+ " was a proxy. waiting for other party to activate");
}
} else {
if (initiator.equals(account.getFullJid())) {
- Log.d("xmppService", "we were initiating. sending file");
+ Log.d(Config.LOGTAG, "we were initiating. sending file");
connection.send(file, onFileTransmissionSatusChanged);
} else {
- Log.d("xmppService", "we were responding. receiving file");
+ Log.d(Config.LOGTAG, "we were responding. receiving file");
connection.receive(file, onFileTransmissionSatusChanged);
}
}
@@ -579,11 +582,11 @@ public class JingleConnection {
for (Entry<String, JingleSocks5Transport> cursor : connections
.entrySet()) {
JingleSocks5Transport currentConnection = cursor.getValue();
- // Log.d("xmppService","comparing candidate: "+currentConnection.getCandidate().toString());
+ // Log.d(Config.LOGTAG,"comparing candidate: "+currentConnection.getCandidate().toString());
if (currentConnection.isEstablished()
&& (currentConnection.getCandidate().isUsedByCounterpart() || (!currentConnection
.getCandidate().isOurs()))) {
- // Log.d("xmppService","is usable");
+ // Log.d(Config.LOGTAG,"is usable");
if (connection == null) {
connection = currentConnection;
} else {
@@ -592,7 +595,7 @@ public class JingleConnection {
connection = currentConnection;
} else if (connection.getCandidate().getPriority() == currentConnection
.getCandidate().getPriority()) {
- // Log.d("xmppService","found two candidates with same priority");
+ // Log.d(Config.LOGTAG,"found two candidates with same priority");
if (initiator.equals(account.getFullJid())) {
if (currentConnection.getCandidate().isOurs()) {
connection = currentConnection;
@@ -628,7 +631,7 @@ public class JingleConnection {
this.transportId = this.mJingleConnectionManager.nextRandomId();
content.setTransportId(this.transportId);
content.ibbTransport().setAttribute("block-size",
- "" + this.ibbBlockSize);
+ Integer.toString(this.ibbBlockSize));
packet.setContent(content);
this.sendJinglePacket(packet);
}
@@ -650,7 +653,7 @@ public class JingleConnection {
Content content = new Content("initiator", "a-file-offer");
content.setTransportId(this.transportId);
content.ibbTransport().setAttribute("block-size",
- "" + this.ibbBlockSize);
+ Integer.toString(this.ibbBlockSize));
answer.setContent(content);
this.sendJinglePacket(answer);
return true;
@@ -672,7 +675,7 @@ public class JingleConnection {
@Override
public void failed() {
- Log.d("xmppService", "ibb open failed");
+ Log.d(Config.LOGTAG, "ibb open failed");
}
@Override
@@ -742,7 +745,7 @@ public class JingleConnection {
@Override
public void failed() {
- Log.d("xmppService",
+ Log.d(Config.LOGTAG,
"connection failed with " + candidate.getHost() + ":"
+ candidate.getPort());
connectNextCandidate();
@@ -750,7 +753,7 @@ public class JingleConnection {
@Override
public void established() {
- Log.d("xmppService",
+ Log.d(Config.LOGTAG,
"established connection with " + candidate.getHost()
+ ":" + candidate.getPort());
sendCandidateUsed(candidate.getCid());
@@ -864,7 +867,7 @@ public class JingleConnection {
return this.transport;
}
- public void accept() {
+ public void start() {
if (status == STATUS_INITIATED) {
new Thread(new Runnable() {
@@ -874,7 +877,7 @@ public class JingleConnection {
}
}).start();
} else {
- Log.d("xmppService", "status (" + status + ") was not ok");
+ Log.d(Config.LOGTAG, "status (" + status + ") was not ok");
}
}
}
diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
index f01d7fa9..79090af6 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
@@ -7,6 +7,7 @@ import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import android.annotation.SuppressLint;
import android.util.Log;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.services.XmppConnectionService;
@@ -33,18 +34,20 @@ public class JingleConnectionManager {
public void deliverPacket(Account account, JinglePacket packet) {
if (packet.isAction("session-initiate")) {
JingleConnection connection = new JingleConnection(this);
- connection.init(account,packet);
+ connection.init(account, packet);
connections.add(connection);
} else {
for (JingleConnection connection : connections) {
- if (connection.getAccountJid().equals(account.getFullJid()) && connection
- .getSessionId().equals(packet.getSessionId()) && connection
- .getCounterPart().equals(packet.getFrom())) {
+ if (connection.getAccountJid().equals(account.getFullJid())
+ && connection.getSessionId().equals(
+ packet.getSessionId())
+ && connection.getCounterPart().equals(packet.getFrom())) {
connection.deliverPacket(packet);
return;
}
}
- account.getXmppConnection().sendIqPacket(packet.generateRespone(IqPacket.TYPE_ERROR), null);
+ account.getXmppConnection().sendIqPacket(
+ packet.generateRespone(IqPacket.TYPE_ERROR), null);
}
}
@@ -60,7 +63,7 @@ public class JingleConnectionManager {
this.connections.add(connection);
return connection;
}
-
+
public void finishConnection(JingleConnection connection) {
this.connections.remove(connection);
}
@@ -90,12 +93,17 @@ public class JingleConnectionManager {
.findChild("streamhost",
"http://jabber.org/protocol/bytestreams");
if (streamhost != null) {
- JingleCandidate candidate = new JingleCandidate(nextRandomId(),true);
- candidate.setHost(streamhost.getAttribute("host"));
- candidate.setPort(Integer.parseInt(streamhost.getAttribute("port")));
- candidate.setType(JingleCandidate.TYPE_PROXY);
+ JingleCandidate candidate = new JingleCandidate(
+ nextRandomId(), true);
+ candidate.setHost(streamhost
+ .getAttribute("host"));
+ candidate.setPort(Integer
+ .parseInt(streamhost
+ .getAttribute("port")));
+ candidate
+ .setType(JingleCandidate.TYPE_PROXY);
candidate.setJid(proxy);
- candidate.setPriority(655360+65535);
+ candidate.setPriority(655360 + 65535);
primaryCandidates.put(account.getJid(),
candidate);
listener.onPrimaryCandidateFound(true,
@@ -119,9 +127,10 @@ public class JingleConnectionManager {
public String nextRandomId() {
return new BigInteger(50, random).toString(32);
}
-
+
public long getAutoAcceptFileSize() {
- String config = this.xmppConnectionService.getPreferences().getString("auto_accept_file_size", "524288");
+ String config = this.xmppConnectionService.getPreferences().getString(
+ "auto_accept_file_size", "524288");
try {
return Long.parseLong(config);
} catch (NumberFormatException e) {
@@ -132,32 +141,35 @@ public class JingleConnectionManager {
public void deliverIbbPacket(Account account, IqPacket packet) {
String sid = null;
Element payload = null;
- if (packet.hasChild("open","http://jabber.org/protocol/ibb")) {
- payload = packet.findChild("open","http://jabber.org/protocol/ibb");
+ if (packet.hasChild("open", "http://jabber.org/protocol/ibb")) {
+ payload = packet
+ .findChild("open", "http://jabber.org/protocol/ibb");
sid = payload.getAttribute("sid");
- } else if (packet.hasChild("data","http://jabber.org/protocol/ibb")) {
- payload = packet.findChild("data","http://jabber.org/protocol/ibb");
+ } else if (packet.hasChild("data", "http://jabber.org/protocol/ibb")) {
+ payload = packet
+ .findChild("data", "http://jabber.org/protocol/ibb");
sid = payload.getAttribute("sid");
}
- if (sid!=null) {
+ if (sid != null) {
for (JingleConnection connection : connections) {
if (connection.hasTransportId(sid)) {
JingleTransport transport = connection.getTransport();
if (transport instanceof JingleInbandTransport) {
JingleInbandTransport inbandTransport = (JingleInbandTransport) transport;
- inbandTransport.deliverPayload(packet,payload);
+ inbandTransport.deliverPayload(packet, payload);
return;
}
}
}
- Log.d("xmppService","couldnt deliver payload: "+payload.toString());
+ Log.d(Config.LOGTAG,
+ "couldnt deliver payload: " + payload.toString());
} else {
- Log.d("xmppService","no sid found in incomming ibb packet");
+ Log.d(Config.LOGTAG, "no sid found in incomming ibb packet");
}
}
-
+
public void cancelInTransmission() {
- for(JingleConnection connection : this.connections) {
+ for (JingleConnection connection : this.connections) {
if (connection.getStatus() == JingleConnection.STATUS_TRANSMITTING) {
connection.cancel();
}
diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleFile.java b/src/eu/siacs/conversations/xmpp/jingle/JingleFile.java
index 3672351b..9253814b 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/JingleFile.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/JingleFile.java
@@ -5,60 +5,63 @@ import java.security.Key;
import javax.crypto.spec.SecretKeySpec;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.utils.CryptoHelper;
import android.util.Log;
public class JingleFile extends File {
-
+
private static final long serialVersionUID = 2247012619505115863L;
-
+
private long expectedSize = 0;
private String sha1sum;
private Key aeskey;
-
+
public JingleFile(String path) {
super(path);
}
-
+
public long getSize() {
return super.length();
}
-
+
public long getExpectedSize() {
- if (this.aeskey!=null) {
- return (this.expectedSize/16 + 1) * 16;
+ if (this.aeskey != null) {
+ return (this.expectedSize / 16 + 1) * 16;
} else {
return this.expectedSize;
}
}
-
+
public void setExpectedSize(long size) {
this.expectedSize = size;
}
-
+
public String getSha1Sum() {
return this.sha1sum;
}
-
+
public void setSha1Sum(String sum) {
this.sha1sum = sum;
}
-
+
public void setKey(byte[] key) {
- if (key.length>=32) {
+ if (key.length >= 32) {
byte[] secretKey = new byte[32];
System.arraycopy(key, 0, secretKey, 0, 32);
this.aeskey = new SecretKeySpec(secretKey, "AES");
- } else if (key.length>=16) {
+ } else if (key.length >= 16) {
byte[] secretKey = new byte[16];
System.arraycopy(key, 0, secretKey, 0, 16);
this.aeskey = new SecretKeySpec(secretKey, "AES");
} else {
- Log.d("xmppService","weird key");
+ Log.d(Config.LOGTAG, "weird key");
}
- Log.d("xmppService","using aes key "+CryptoHelper.bytesToHex(this.aeskey.getEncoded()));
+ Log.d(Config.LOGTAG,
+ "using aes key "
+ + CryptoHelper.bytesToHex(this.aeskey.getEncoded()));
}
-
+
public Key getKey() {
return this.aeskey;
}
diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java b/src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java
index b859e7c7..c5498075 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java
@@ -32,7 +32,7 @@ public class JingleInbandTransport extends JingleTransport {
private OutputStream fileOutputStream;
private long remainingSize;
private MessageDigest digest;
-
+
private OnFileTransmissionStatusChanged onFileTransmissionStatusChanged;
private OnIqPacketReceived onAckReceived = new OnIqPacketReceived() {
@@ -59,7 +59,7 @@ public class JingleInbandTransport extends JingleTransport {
Element open = iq.addChild("open", "http://jabber.org/protocol/ibb");
open.setAttribute("sid", this.sessionId);
open.setAttribute("stanza", "iq");
- open.setAttribute("block-size", "" + this.blockSize);
+ open.setAttribute("block-size", Integer.toString(this.blockSize));
this.account.getXmppConnection().sendIqPacket(iq,
new OnIqPacketReceived() {
@@ -77,7 +77,8 @@ public class JingleInbandTransport extends JingleTransport {
}
@Override
- public void receive(JingleFile file, OnFileTransmissionStatusChanged callback) {
+ public void receive(JingleFile file,
+ OnFileTransmissionStatusChanged callback) {
this.onFileTransmissionStatusChanged = callback;
this.file = file;
try {
@@ -86,7 +87,7 @@ public class JingleInbandTransport extends JingleTransport {
file.getParentFile().mkdirs();
file.createNewFile();
this.fileOutputStream = getOutputStream(file);
- if (this.fileOutputStream==null) {
+ if (this.fileOutputStream == null) {
callback.onFileTransferAborted();
return;
}
@@ -106,7 +107,7 @@ public class JingleInbandTransport extends JingleTransport {
this.digest = MessageDigest.getInstance("SHA-1");
this.digest.reset();
fileInputStream = this.getInputStream(file);
- if (fileInputStream==null) {
+ if (fileInputStream == null) {
callback.onFileTransferAborted();
return;
}
@@ -133,8 +134,9 @@ public class JingleInbandTransport extends JingleTransport {
iq.setTo(this.counterpart);
Element data = iq.addChild("data",
"http://jabber.org/protocol/ibb");
- data.setAttribute("seq", "" + this.seq);
- data.setAttribute("block-size", "" + this.blockSize);
+ data.setAttribute("seq", Integer.toString(this.seq));
+ data.setAttribute("block-size",
+ Integer.toString(this.blockSize));
data.setAttribute("sid", this.sessionId);
data.setContent(base64);
this.account.getXmppConnection().sendIqPacket(iq,
@@ -150,7 +152,8 @@ public class JingleInbandTransport extends JingleTransport {
try {
byte[] buffer = Base64.decode(data, Base64.NO_WRAP);
if (this.remainingSize < buffer.length) {
- buffer = Arrays.copyOfRange(buffer, 0, (int) this.remainingSize);
+ buffer = Arrays
+ .copyOfRange(buffer, 0, (int) this.remainingSize);
}
this.remainingSize -= buffer.length;
diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java b/src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java
index d2c84325..63f5a507 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java
@@ -21,7 +21,8 @@ public class JingleSocks5Transport extends JingleTransport {
private boolean activated = false;
protected Socket socket;
- public JingleSocks5Transport(JingleConnection jingleConnection, JingleCandidate candidate) {
+ public JingleSocks5Transport(JingleConnection jingleConnection,
+ JingleCandidate candidate) {
this.candidate = candidate;
try {
MessageDigest mDigest = MessageDigest.getInstance("SHA-1");
@@ -44,11 +45,12 @@ public class JingleSocks5Transport extends JingleTransport {
public void connect(final OnTransportConnected callback) {
new Thread(new Runnable() {
-
+
@Override
public void run() {
try {
- socket = new Socket(candidate.getHost(), candidate.getPort());
+ socket = new Socket(candidate.getHost(),
+ candidate.getPort());
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
byte[] login = { 0x05, 0x01, 0x00 };
@@ -56,9 +58,10 @@ public class JingleSocks5Transport extends JingleTransport {
byte[] reply = new byte[2];
outputStream.write(login);
inputStream.read(reply);
+ final String connect = Character.toString('\u0005')
+ + '\u0001' + '\u0000' + '\u0003' + '\u0028'
+ + destination + '\u0000' + '\u0000';
if (Arrays.equals(reply, expectedReply)) {
- String connect = "" + '\u0005' + '\u0001' + '\u0000' + '\u0003'
- + '\u0028' + destination + '\u0000' + '\u0000';
outputStream.write(connect.getBytes());
byte[] result = new byte[2];
inputStream.read(result);
@@ -80,12 +83,13 @@ public class JingleSocks5Transport extends JingleTransport {
}
}
}).start();
-
+
}
- public void send(final JingleFile file, final OnFileTransmissionStatusChanged callback) {
+ public void send(final JingleFile file,
+ final OnFileTransmissionStatusChanged callback) {
new Thread(new Runnable() {
-
+
@Override
public void run() {
InputStream fileInputStream = null;
@@ -93,7 +97,7 @@ public class JingleSocks5Transport extends JingleTransport {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
fileInputStream = getInputStream(file);
- if (fileInputStream==null) {
+ if (fileInputStream == null) {
callback.onFileTransferAborted();
return;
}
@@ -105,7 +109,7 @@ public class JingleSocks5Transport extends JingleTransport {
}
outputStream.flush();
file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
- if (callback!=null) {
+ if (callback != null) {
callback.onFileTransmitted(file);
}
} catch (FileNotFoundException e) {
@@ -125,12 +129,13 @@ public class JingleSocks5Transport extends JingleTransport {
}
}
}).start();
-
+
}
-
- public void receive(final JingleFile file, final OnFileTransmissionStatusChanged callback) {
+
+ public void receive(final JingleFile file,
+ final OnFileTransmissionStatusChanged callback) {
new Thread(new Runnable() {
-
+
@Override
public void run() {
try {
@@ -141,22 +146,22 @@ public class JingleSocks5Transport extends JingleTransport {
file.getParentFile().mkdirs();
file.createNewFile();
OutputStream fileOutputStream = getOutputStream(file);
- if (fileOutputStream==null) {
+ if (fileOutputStream == null) {
callback.onFileTransferAborted();
return;
}
long remainingSize = file.getExpectedSize();
byte[] buffer = new byte[8192];
int count = buffer.length;
- while(remainingSize > 0) {
+ while (remainingSize > 0) {
count = inputStream.read(buffer);
- if (count==-1) {
+ if (count == -1) {
callback.onFileTransferAborted();
return;
} else {
fileOutputStream.write(buffer, 0, count);
digest.update(buffer, 0, count);
- remainingSize-=count;
+ remainingSize -= count;
}
}
fileOutputStream.flush();
@@ -177,25 +182,25 @@ public class JingleSocks5Transport extends JingleTransport {
public boolean isProxy() {
return this.candidate.getType() == JingleCandidate.TYPE_PROXY;
}
-
+
public boolean needsActivation() {
return (this.isProxy() && !this.activated);
}
public void disconnect() {
- if (this.socket!=null) {
+ if (this.socket != null) {
try {
this.socket.close();
} catch (IOException e) {
-
+
}
}
}
-
+
public boolean isEstablished() {
return this.isEstablished;
}
-
+
public JingleCandidate getCandidate() {
return this.candidate;
}
diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleTransport.java b/src/eu/siacs/conversations/xmpp/jingle/JingleTransport.java
index 1acdfc39..07dc8ecc 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/JingleTransport.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/JingleTransport.java
@@ -15,61 +15,72 @@ import javax.crypto.CipherInputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
+import eu.siacs.conversations.Config;
+
import android.util.Log;
public abstract class JingleTransport {
public abstract void connect(final OnTransportConnected callback);
- public abstract void receive(final JingleFile file, final OnFileTransmissionStatusChanged callback);
- public abstract void send(final JingleFile file, final OnFileTransmissionStatusChanged callback);
- private byte[] iv = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0xf};
-
- protected InputStream getInputStream(JingleFile file) throws FileNotFoundException {
+
+ public abstract void receive(final JingleFile file,
+ final OnFileTransmissionStatusChanged callback);
+
+ public abstract void send(final JingleFile file,
+ final OnFileTransmissionStatusChanged callback);
+
+ private byte[] iv = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0xf };
+
+ protected InputStream getInputStream(JingleFile file)
+ throws FileNotFoundException {
if (file.getKey() == null) {
return new FileInputStream(file);
} else {
try {
IvParameterSpec ips = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- cipher.init(Cipher.ENCRYPT_MODE, file.getKey(),ips);
- Log.d("xmppService","opening encrypted input stream");
+ cipher.init(Cipher.ENCRYPT_MODE, file.getKey(), ips);
+ Log.d(Config.LOGTAG, "opening encrypted input stream");
return new CipherInputStream(new FileInputStream(file), cipher);
} catch (NoSuchAlgorithmException e) {
- Log.d("xmppService","no such algo: "+e.getMessage());
+ Log.d(Config.LOGTAG, "no such algo: " + e.getMessage());
return null;
} catch (NoSuchPaddingException e) {
- Log.d("xmppService","no such padding: "+e.getMessage());
+ Log.d(Config.LOGTAG, "no such padding: " + e.getMessage());
return null;
} catch (InvalidKeyException e) {
- Log.d("xmppService","invalid key: "+e.getMessage());
+ Log.d(Config.LOGTAG, "invalid key: " + e.getMessage());
return null;
} catch (InvalidAlgorithmParameterException e) {
- Log.d("xmppService","invavid iv:"+e.getMessage());
+ Log.d(Config.LOGTAG, "invavid iv:" + e.getMessage());
return null;
}
}
}
-
- protected OutputStream getOutputStream(JingleFile file) throws FileNotFoundException {
+
+ protected OutputStream getOutputStream(JingleFile file)
+ throws FileNotFoundException {
if (file.getKey() == null) {
return new FileOutputStream(file);
} else {
try {
IvParameterSpec ips = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- cipher.init(Cipher.DECRYPT_MODE, file.getKey(),ips);
- Log.d("xmppService","opening encrypted output stream");
- return new CipherOutputStream(new FileOutputStream(file), cipher);
+ cipher.init(Cipher.DECRYPT_MODE, file.getKey(), ips);
+ Log.d(Config.LOGTAG, "opening encrypted output stream");
+ return new CipherOutputStream(new FileOutputStream(file),
+ cipher);
} catch (NoSuchAlgorithmException e) {
- Log.d("xmppService","no such algo: "+e.getMessage());
+ Log.d(Config.LOGTAG, "no such algo: " + e.getMessage());
return null;
} catch (NoSuchPaddingException e) {
- Log.d("xmppService","no such padding: "+e.getMessage());
+ Log.d(Config.LOGTAG, "no such padding: " + e.getMessage());
return null;
} catch (InvalidKeyException e) {
- Log.d("xmppService","invalid key: "+e.getMessage());
+ Log.d(Config.LOGTAG, "invalid key: " + e.getMessage());
return null;
} catch (InvalidAlgorithmParameterException e) {
- Log.d("xmppService","invavid iv:"+e.getMessage());
+ Log.d(Config.LOGTAG, "invavid iv:" + e.getMessage());
return null;
}
}
diff --git a/src/eu/siacs/conversations/xmpp/jingle/OnFileTransmissionStatusChanged.java b/src/eu/siacs/conversations/xmpp/jingle/OnFileTransmissionStatusChanged.java
index 84f10417..19fd4d97 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/OnFileTransmissionStatusChanged.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/OnFileTransmissionStatusChanged.java
@@ -2,5 +2,6 @@ package eu.siacs.conversations.xmpp.jingle;
public interface OnFileTransmissionStatusChanged {
public void onFileTransmitted(JingleFile file);
+
public void onFileTransferAborted();
}
diff --git a/src/eu/siacs/conversations/xmpp/jingle/OnPrimaryCandidateFound.java b/src/eu/siacs/conversations/xmpp/jingle/OnPrimaryCandidateFound.java
index b91a90ff..03a437b2 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/OnPrimaryCandidateFound.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/OnPrimaryCandidateFound.java
@@ -1,5 +1,6 @@
package eu.siacs.conversations.xmpp.jingle;
public interface OnPrimaryCandidateFound {
- public void onPrimaryCandidateFound(boolean success, JingleCandidate canditate);
+ public void onPrimaryCandidateFound(boolean success,
+ JingleCandidate canditate);
}
diff --git a/src/eu/siacs/conversations/xmpp/jingle/OnTransportConnected.java b/src/eu/siacs/conversations/xmpp/jingle/OnTransportConnected.java
index 7d9a084a..38f03c5d 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/OnTransportConnected.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/OnTransportConnected.java
@@ -2,5 +2,6 @@ package eu.siacs.conversations.xmpp.jingle;
public interface OnTransportConnected {
public void failed();
+
public void established();
}
diff --git a/src/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java b/src/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java
index 494ff0d6..d19e6dfd 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java
@@ -4,17 +4,17 @@ import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.jingle.JingleFile;
public class Content extends Element {
-
+
private String transportId;
-
+
private Content(String name) {
super(name);
}
-
+
public Content() {
super("content");
}
-
+
public Content(String creator, String name) {
super("content");
this.setAttribute("creator", creator);
@@ -24,39 +24,43 @@ public class Content extends Element {
public void setTransportId(String sid) {
this.transportId = sid;
}
-
+
public void setFileOffer(JingleFile actualFile, boolean otr) {
- Element description = this.addChild("description", "urn:xmpp:jingle:apps:file-transfer:3");
+ Element description = this.addChild("description",
+ "urn:xmpp:jingle:apps:file-transfer:3");
Element offer = description.addChild("offer");
Element file = offer.addChild("file");
- file.addChild("size").setContent(""+actualFile.getSize());
+ file.addChild("size").setContent(Long.toString(actualFile.getSize()));
if (otr) {
- file.addChild("name").setContent(actualFile.getName()+".otr");
+ file.addChild("name").setContent(actualFile.getName() + ".otr");
} else {
file.addChild("name").setContent(actualFile.getName());
}
}
-
+
public Element getFileOffer() {
- Element description = this.findChild("description", "urn:xmpp:jingle:apps:file-transfer:3");
- if (description==null) {
+ Element description = this.findChild("description",
+ "urn:xmpp:jingle:apps:file-transfer:3");
+ if (description == null) {
return null;
}
Element offer = description.findChild("offer");
- if (offer==null) {
+ if (offer == null) {
return null;
}
return offer.findChild("file");
}
-
+
public void setFileOffer(Element fileOffer) {
- Element description = this.findChild("description", "urn:xmpp:jingle:apps:file-transfer:3");
- if (description==null) {
- description = this.addChild("description", "urn:xmpp:jingle:apps:file-transfer:3");
+ Element description = this.findChild("description",
+ "urn:xmpp:jingle:apps:file-transfer:3");
+ if (description == null) {
+ description = this.addChild("description",
+ "urn:xmpp:jingle:apps:file-transfer:3");
}
description.addChild(fileOffer);
}
-
+
public String getTransportId() {
if (hasSocks5Transport()) {
this.transportId = socks5transport().getAttribute("sid");
@@ -65,30 +69,34 @@ public class Content extends Element {
}
return this.transportId;
}
-
+
public Element socks5transport() {
- Element transport = this.findChild("transport", "urn:xmpp:jingle:transports:s5b:1");
- if (transport==null) {
- transport = this.addChild("transport", "urn:xmpp:jingle:transports:s5b:1");
+ Element transport = this.findChild("transport",
+ "urn:xmpp:jingle:transports:s5b:1");
+ if (transport == null) {
+ transport = this.addChild("transport",
+ "urn:xmpp:jingle:transports:s5b:1");
transport.setAttribute("sid", this.transportId);
}
return transport;
}
-
+
public Element ibbTransport() {
- Element transport = this.findChild("transport", "urn:xmpp:jingle:transports:ibb:1");
- if (transport==null) {
- transport = this.addChild("transport", "urn:xmpp:jingle:transports:ibb:1");
+ Element transport = this.findChild("transport",
+ "urn:xmpp:jingle:transports:ibb:1");
+ if (transport == null) {
+ transport = this.addChild("transport",
+ "urn:xmpp:jingle:transports:ibb:1");
transport.setAttribute("sid", this.transportId);
}
return transport;
}
-
+
public boolean hasSocks5Transport() {
return this.hasChild("transport", "urn:xmpp:jingle:transports:s5b:1");
}
-
+
public boolean hasIbbTransport() {
- return this.hasChild("transport","urn:xmpp:jingle:transports:ibb:1");
+ return this.hasChild("transport", "urn:xmpp:jingle:transports:ibb:1");
}
}
diff --git a/src/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java b/src/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java
index 55700609..77a73643 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java
@@ -7,18 +7,18 @@ public class JinglePacket extends IqPacket {
Content content = null;
Reason reason = null;
Element jingle = new Element("jingle");
-
+
@Override
public Element addChild(Element child) {
if ("jingle".equals(child.getName())) {
Element contentElement = child.findChild("content");
- if (contentElement!=null) {
+ if (contentElement != null) {
this.content = new Content();
this.content.setChildren(contentElement.getChildren());
this.content.setAttributes(contentElement.getAttributes());
}
Element reasonElement = child.findChild("reason");
- if (reasonElement!=null) {
+ if (reasonElement != null) {
this.reason = new Reason();
this.reason.setChildren(reasonElement.getChildren());
this.reason.setAttributes(reasonElement.getAttributes());
@@ -27,33 +27,33 @@ public class JinglePacket extends IqPacket {
}
return child;
}
-
+
public JinglePacket setContent(Content content) {
this.content = content;
return this;
}
-
+
public Content getJingleContent() {
- if (this.content==null) {
+ if (this.content == null) {
this.content = new Content();
}
return this.content;
}
-
+
public JinglePacket setReason(Reason reason) {
this.reason = reason;
return this;
}
-
+
public Reason getReason() {
return this.reason;
}
-
+
private void build() {
this.children.clear();
this.jingle.clearChildren();
this.jingle.setAttribute("xmlns", "urn:xmpp:jingle:1");
- if (this.content!=null) {
+ if (this.content != null) {
jingle.addChild(this.content);
}
if (this.reason != null) {
@@ -66,11 +66,11 @@ public class JinglePacket extends IqPacket {
public String getSessionId() {
return this.jingle.getAttribute("sid");
}
-
+
public void setSessionId(String sid) {
this.jingle.setAttribute("sid", sid);
}
-
+
@Override
public String toString() {
this.build();
@@ -80,11 +80,11 @@ public class JinglePacket extends IqPacket {
public void setAction(String action) {
this.jingle.setAttribute("action", action);
}
-
+
public String getAction() {
return this.jingle.getAttribute("action");
}
-
+
public void setInitiator(String initiator) {
this.jingle.setAttribute("initiator", initiator);
}
diff --git a/src/eu/siacs/conversations/xmpp/jingle/stanzas/Reason.java b/src/eu/siacs/conversations/xmpp/jingle/stanzas/Reason.java
index 195e0db7..610d5e76 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/stanzas/Reason.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/stanzas/Reason.java
@@ -6,7 +6,7 @@ public class Reason extends Element {
private Reason(String name) {
super(name);
}
-
+
public Reason() {
super("reason");
}
diff --git a/src/eu/siacs/conversations/xmpp/pep/Avatar.java b/src/eu/siacs/conversations/xmpp/pep/Avatar.java
index 6d5c1431..154fadf6 100644
--- a/src/eu/siacs/conversations/xmpp/pep/Avatar.java
+++ b/src/eu/siacs/conversations/xmpp/pep/Avatar.java
@@ -11,48 +11,51 @@ public class Avatar {
public int width;
public long size;
public String owner;
+
public byte[] getImageAsBytes() {
return Base64.decode(image, Base64.DEFAULT);
}
+
public String getFilename() {
- if (type==null) {
+ if (type == null) {
return sha1sum;
} else if (type.equalsIgnoreCase("image/webp")) {
- return sha1sum+".webp";
+ return sha1sum + ".webp";
} else if (type.equalsIgnoreCase("image/png")) {
- return sha1sum+".png";
+ return sha1sum + ".png";
} else {
return sha1sum;
}
}
-
+
public static Avatar parseMetadata(Element items) {
Element item = items.findChild("item");
- if (item==null) {
+ if (item == null) {
return null;
}
Element metadata = item.findChild("metadata");
- if (metadata==null) {
+ if (metadata == null) {
return null;
}
String primaryId = item.getAttribute("id");
- if (primaryId==null) {
+ if (primaryId == null) {
return null;
}
- for(Element child : metadata.getChildren()) {
- if (child.getName().equals("info") && primaryId.equals(child.getAttribute("id"))) {
+ for (Element child : metadata.getChildren()) {
+ if (child.getName().equals("info")
+ && primaryId.equals(child.getAttribute("id"))) {
Avatar avatar = new Avatar();
String height = child.getAttribute("height");
String width = child.getAttribute("width");
String size = child.getAttribute("bytes");
try {
- if (height!=null) {
+ if (height != null) {
avatar.height = Integer.parseInt(height);
}
- if (width!=null) {
+ if (width != null) {
avatar.width = Integer.parseInt(width);
}
- if (size!=null) {
+ if (size != null) {
avatar.size = Long.parseLong(size);
}
} catch (NumberFormatException e) {
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java b/src/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java
index 204a6bec..eef41c79 100644
--- a/src/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java
+++ b/src/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java
@@ -15,20 +15,20 @@ public class AbstractStanza extends Element {
public String getFrom() {
return getAttribute("from");
}
-
+
public String getId() {
return this.getAttribute("id");
}
-
+
public void setTo(String to) {
setAttribute("to", to);
}
-
+
public void setFrom(String from) {
- setAttribute("from",from);
+ setAttribute("from", from);
}
-
+
public void setId(String id) {
- setAttribute("id",id);
+ setAttribute("id", id);
}
}
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/IqPacket.java b/src/eu/siacs/conversations/xmpp/stanzas/IqPacket.java
index 1d4e44d1..9df05e67 100644
--- a/src/eu/siacs/conversations/xmpp/stanzas/IqPacket.java
+++ b/src/eu/siacs/conversations/xmpp/stanzas/IqPacket.java
@@ -2,9 +2,8 @@ package eu.siacs.conversations.xmpp.stanzas;
import eu.siacs.conversations.xml.Element;
-
public class IqPacket extends AbstractStanza {
-
+
public static final int TYPE_ERROR = -1;
public static final int TYPE_SET = 0;
public static final int TYPE_RESULT = 1;
@@ -33,25 +32,25 @@ public class IqPacket extends AbstractStanza {
break;
}
}
-
+
public IqPacket() {
super("iq");
}
-
+
public Element query() {
Element query = findChild("query");
- if (query==null) {
+ if (query == null) {
query = addChild("query");
}
return query;
}
-
+
public Element query(String xmlns) {
Element query = query();
query.setAttribute("xmlns", xmlns);
return query();
}
-
+
public int getType() {
String type = getAttribute("type");
if ("error".equals(type)) {
@@ -66,7 +65,7 @@ public class IqPacket extends AbstractStanza {
return 1000;
}
}
-
+
public IqPacket generateRespone(int type) {
IqPacket packet = new IqPacket(type);
packet.setTo(this.getFrom());
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java b/src/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java
index 433b08c9..386d9dc8 100644
--- a/src/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java
+++ b/src/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java
@@ -9,20 +9,20 @@ public class MessagePacket extends AbstractStanza {
public static final int TYPE_GROUPCHAT = 3;
public static final int TYPE_ERROR = 4;
public static final int TYPE_HEADLINE = 5;
-
+
public MessagePacket() {
super("message");
}
-
+
public String getBody() {
Element body = this.findChild("body");
- if (body!=null) {
+ if (body != null) {
return body.getContent();
} else {
return null;
}
}
-
+
public void setBody(String text) {
this.children.remove(findChild("body"));
Element body = new Element("body");
@@ -33,7 +33,7 @@ public class MessagePacket extends AbstractStanza {
public void setType(int type) {
switch (type) {
case TYPE_CHAT:
- this.setAttribute("type","chat");
+ this.setAttribute("type", "chat");
break;
case TYPE_GROUPCHAT:
this.setAttribute("type", "groupchat");
@@ -43,14 +43,14 @@ public class MessagePacket extends AbstractStanza {
case TYPE_NORMAL:
break;
default:
- this.setAttribute("type","chat");
+ this.setAttribute("type", "chat");
break;
}
}
-
+
public int getType() {
String type = getAttribute("type");
- if (type==null) {
+ if (type == null) {
return TYPE_NORMAL;
} else if (type.equals("normal")) {
return TYPE_NORMAL;
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/PresencePacket.java b/src/eu/siacs/conversations/xmpp/stanzas/PresencePacket.java
index dfbab78c..7ea32099 100644
--- a/src/eu/siacs/conversations/xmpp/stanzas/PresencePacket.java
+++ b/src/eu/siacs/conversations/xmpp/stanzas/PresencePacket.java
@@ -1,8 +1,7 @@
package eu.siacs.conversations.xmpp.stanzas;
-
public class PresencePacket extends AbstractStanza {
-
+
public PresencePacket() {
super("presence");
}
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/csi/ActivePacket.java b/src/eu/siacs/conversations/xmpp/stanzas/csi/ActivePacket.java
new file mode 100644
index 00000000..78ab66d8
--- /dev/null
+++ b/src/eu/siacs/conversations/xmpp/stanzas/csi/ActivePacket.java
@@ -0,0 +1,10 @@
+package eu.siacs.conversations.xmpp.stanzas.csi;
+
+import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
+
+public class ActivePacket extends AbstractStanza {
+ public ActivePacket() {
+ super("active");
+ setAttribute("xmlns", "urn:xmpp:csi:0");
+ }
+}
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/csi/InactivePacket.java b/src/eu/siacs/conversations/xmpp/stanzas/csi/InactivePacket.java
new file mode 100644
index 00000000..f109280f
--- /dev/null
+++ b/src/eu/siacs/conversations/xmpp/stanzas/csi/InactivePacket.java
@@ -0,0 +1,10 @@
+package eu.siacs.conversations.xmpp.stanzas.csi;
+
+import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
+
+public class InactivePacket extends AbstractStanza {
+ public InactivePacket() {
+ super("inactive");
+ setAttribute("xmlns", "urn:xmpp:csi:0");
+ }
+}
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/AckPacket.java b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/AckPacket.java
index 6fe3ea2b..f93b5d87 100644
--- a/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/AckPacket.java
+++ b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/AckPacket.java
@@ -6,8 +6,8 @@ public class AckPacket extends AbstractStanza {
public AckPacket(int sequence, int smVersion) {
super("a");
- this.setAttribute("xmlns","urn:xmpp:sm:"+smVersion);
- this.setAttribute("h", ""+sequence);
+ this.setAttribute("xmlns", "urn:xmpp:sm:" + smVersion);
+ this.setAttribute("h", Integer.toString(sequence));
}
}
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/EnablePacket.java b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/EnablePacket.java
index 0ca7a4fd..78cd81ed 100644
--- a/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/EnablePacket.java
+++ b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/EnablePacket.java
@@ -6,7 +6,7 @@ public class EnablePacket extends AbstractStanza {
public EnablePacket(int smVersion) {
super("enable");
- this.setAttribute("xmlns","urn:xmpp:sm:"+smVersion);
+ this.setAttribute("xmlns", "urn:xmpp:sm:" + smVersion);
this.setAttribute("resume", "true");
}
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/RequestPacket.java b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/RequestPacket.java
index d42ae9b0..98cfc748 100644
--- a/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/RequestPacket.java
+++ b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/RequestPacket.java
@@ -6,7 +6,7 @@ public class RequestPacket extends AbstractStanza {
public RequestPacket(int smVersion) {
super("r");
- this.setAttribute("xmlns","urn:xmpp:sm:"+smVersion);
+ this.setAttribute("xmlns", "urn:xmpp:sm:" + smVersion);
}
}
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/ResumePacket.java b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/ResumePacket.java
index dcf32101..9cdcfa5e 100644
--- a/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/ResumePacket.java
+++ b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/ResumePacket.java
@@ -6,9 +6,9 @@ public class ResumePacket extends AbstractStanza {
public ResumePacket(String id, int sequence, int smVersion) {
super("resume");
- this.setAttribute("xmlns","urn:xmpp:sm:"+smVersion);
+ this.setAttribute("xmlns", "urn:xmpp:sm:" + smVersion);
this.setAttribute("previd", id);
- this.setAttribute("h", ""+sequence);
+ this.setAttribute("h", Integer.toString(sequence));
}
}