some code cleanup
This commit is contained in:
parent
8d456085e5
commit
1ac5be4855
|
@ -0,0 +1,21 @@
|
||||||
|
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;
|
||||||
|
|
||||||
|
private Config() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ import org.json.JSONObject;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.persistance.DatabaseBackend;
|
import eu.siacs.conversations.persistance.DatabaseBackend;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
||||||
|
@ -29,9 +30,7 @@ import net.java.otr4j.session.InstanceTag;
|
||||||
import net.java.otr4j.session.SessionID;
|
import net.java.otr4j.session.SessionID;
|
||||||
|
|
||||||
public class OtrEngine implements OtrEngineHost {
|
public class OtrEngine implements OtrEngineHost {
|
||||||
|
|
||||||
private static final String LOGTAG = "xmppService";
|
|
||||||
|
|
||||||
private Account account;
|
private Account account;
|
||||||
private OtrPolicy otrPolicy;
|
private OtrPolicy otrPolicy;
|
||||||
private KeyPair keyPair;
|
private KeyPair keyPair;
|
||||||
|
@ -45,17 +44,17 @@ public class OtrEngine implements OtrEngineHost {
|
||||||
this.otrPolicy.setAllowV3(true);
|
this.otrPolicy.setAllowV3(true);
|
||||||
this.keyPair = loadKey(account.getKeys());
|
this.keyPair = loadKey(account.getKeys());
|
||||||
}
|
}
|
||||||
|
|
||||||
private KeyPair loadKey(JSONObject keys) {
|
private KeyPair loadKey(JSONObject keys) {
|
||||||
if (keys == null) {
|
if (keys == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
BigInteger x = new BigInteger(keys.getString("otr_x"),16);
|
BigInteger x = new BigInteger(keys.getString("otr_x"), 16);
|
||||||
BigInteger y = new BigInteger(keys.getString("otr_y"),16);
|
BigInteger y = new BigInteger(keys.getString("otr_y"), 16);
|
||||||
BigInteger p = new BigInteger(keys.getString("otr_p"),16);
|
BigInteger p = new BigInteger(keys.getString("otr_p"), 16);
|
||||||
BigInteger q = new BigInteger(keys.getString("otr_q"),16);
|
BigInteger q = new BigInteger(keys.getString("otr_q"), 16);
|
||||||
BigInteger g = new BigInteger(keys.getString("otr_g"),16);
|
BigInteger g = new BigInteger(keys.getString("otr_g"), 16);
|
||||||
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
|
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
|
||||||
DSAPublicKeySpec pubKeySpec = new DSAPublicKeySpec(y, p, q, g);
|
DSAPublicKeySpec pubKeySpec = new DSAPublicKeySpec(y, p, q, g);
|
||||||
DSAPrivateKeySpec privateKeySpec = new DSAPrivateKeySpec(x, p, q, g);
|
DSAPrivateKeySpec privateKeySpec = new DSAPrivateKeySpec(x, p, q, g);
|
||||||
|
@ -70,26 +69,28 @@ public class OtrEngine implements OtrEngineHost {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveKey() {
|
private void saveKey() {
|
||||||
PublicKey publicKey = keyPair.getPublic();
|
PublicKey publicKey = keyPair.getPublic();
|
||||||
PrivateKey privateKey = keyPair.getPrivate();
|
PrivateKey privateKey = keyPair.getPrivate();
|
||||||
KeyFactory keyFactory;
|
KeyFactory keyFactory;
|
||||||
try {
|
try {
|
||||||
keyFactory = KeyFactory.getInstance("DSA");
|
keyFactory = KeyFactory.getInstance("DSA");
|
||||||
DSAPrivateKeySpec privateKeySpec = keyFactory.getKeySpec(privateKey, DSAPrivateKeySpec.class);
|
DSAPrivateKeySpec privateKeySpec = keyFactory.getKeySpec(
|
||||||
DSAPublicKeySpec publicKeySpec = keyFactory.getKeySpec(publicKey, DSAPublicKeySpec.class);
|
privateKey, DSAPrivateKeySpec.class);
|
||||||
this.account.setKey("otr_x",privateKeySpec.getX().toString(16));
|
DSAPublicKeySpec publicKeySpec = keyFactory.getKeySpec(publicKey,
|
||||||
this.account.setKey("otr_g",privateKeySpec.getG().toString(16));
|
DSAPublicKeySpec.class);
|
||||||
this.account.setKey("otr_p",privateKeySpec.getP().toString(16));
|
this.account.setKey("otr_x", privateKeySpec.getX().toString(16));
|
||||||
this.account.setKey("otr_q",privateKeySpec.getQ().toString(16));
|
this.account.setKey("otr_g", privateKeySpec.getG().toString(16));
|
||||||
this.account.setKey("otr_y",publicKeySpec.getY().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) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (InvalidKeySpecException e) {
|
} catch (InvalidKeySpecException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -123,18 +124,19 @@ public class OtrEngine implements OtrEngineHost {
|
||||||
}
|
}
|
||||||
return this.keyPair.getPublic();
|
return this.keyPair.getPublic();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyPair getLocalKeyPair(SessionID arg0) throws OtrException {
|
public KeyPair getLocalKeyPair(SessionID arg0) throws OtrException {
|
||||||
if (this.keyPair==null) {
|
if (this.keyPair == null) {
|
||||||
KeyPairGenerator kg;
|
KeyPairGenerator kg;
|
||||||
try {
|
try {
|
||||||
kg = KeyPairGenerator.getInstance("DSA");
|
kg = KeyPairGenerator.getInstance("DSA");
|
||||||
this.keyPair = kg.genKeyPair();
|
this.keyPair = kg.genKeyPair();
|
||||||
this.saveKey();
|
this.saveKey();
|
||||||
DatabaseBackend.getInstance(context).updateAccount(account);
|
DatabaseBackend.getInstance(context).updateAccount(account);
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} 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;
|
return this.keyPair;
|
||||||
|
@ -152,17 +154,18 @@ public class OtrEngine implements OtrEngineHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectMessage(SessionID session, String body) throws OtrException {
|
public void injectMessage(SessionID session, String body)
|
||||||
|
throws OtrException {
|
||||||
MessagePacket packet = new MessagePacket();
|
MessagePacket packet = new MessagePacket();
|
||||||
packet.setFrom(account.getFullJid());
|
packet.setFrom(account.getFullJid());
|
||||||
if (session.getUserID().isEmpty()) {
|
if (session.getUserID().isEmpty()) {
|
||||||
packet.setTo(session.getAccountID());
|
packet.setTo(session.getAccountID());
|
||||||
} else {
|
} else {
|
||||||
packet.setTo(session.getAccountID()+"/"+session.getUserID());
|
packet.setTo(session.getAccountID() + "/" + session.getUserID());
|
||||||
}
|
}
|
||||||
packet.setBody(body);
|
packet.setBody(body);
|
||||||
packet.addChild("private","urn:xmpp:carbons:2");
|
packet.addChild("private", "urn:xmpp:carbons:2");
|
||||||
packet.addChild("no-copy","urn:xmpp:hints");
|
packet.addChild("no-copy", "urn:xmpp:hints");
|
||||||
packet.setType(MessagePacket.TYPE_CHAT);
|
packet.setType(MessagePacket.TYPE_CHAT);
|
||||||
account.getXmppConnection().sendMessagePacket(packet);
|
account.getXmppConnection().sendMessagePacket(packet);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi.IOpenPgpCallback;
|
import org.openintents.openpgp.util.OpenPgpApi.IOpenPgpCallback;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.entities.Contact;
|
import eu.siacs.conversations.entities.Contact;
|
||||||
|
@ -38,7 +39,7 @@ public class PgpEngine {
|
||||||
|
|
||||||
public void decrypt(final Message message,
|
public void decrypt(final Message message,
|
||||||
final UiCallback<Message> callback) {
|
final UiCallback<Message> callback) {
|
||||||
Log.d("xmppService", "decrypting message " + message.getUuid());
|
Log.d(Config.LOGTAG, "decrypting message " + message.getUuid());
|
||||||
Intent params = new Intent();
|
Intent params = new Intent();
|
||||||
params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
|
params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
|
||||||
params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, message
|
params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, message
|
||||||
|
@ -65,7 +66,7 @@ public class PgpEngine {
|
||||||
callback.error(R.string.openpgp_error, message);
|
callback.error(R.string.openpgp_error, message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
||||||
callback.userInputRequried((PendingIntent) result
|
callback.userInputRequried((PendingIntent) result
|
||||||
|
@ -73,8 +74,9 @@ public class PgpEngine {
|
||||||
message);
|
message);
|
||||||
return;
|
return;
|
||||||
case OpenPgpApi.RESULT_CODE_ERROR:
|
case OpenPgpApi.RESULT_CODE_ERROR:
|
||||||
OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERROR);
|
OpenPgpError error = result
|
||||||
Log.d("xmppService",error.getMessage());
|
.getParcelableExtra(OpenPgpApi.RESULT_ERROR);
|
||||||
|
Log.d(Config.LOGTAG, error.getMessage());
|
||||||
callback.error(R.string.openpgp_error, message);
|
callback.error(R.string.openpgp_error, message);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
|
@ -109,7 +111,8 @@ public class PgpEngine {
|
||||||
message.setEncryption(Message.ENCRYPTION_DECRYPTED);
|
message.setEncryption(Message.ENCRYPTION_DECRYPTED);
|
||||||
PgpEngine.this.mXmppConnectionService
|
PgpEngine.this.mXmppConnectionService
|
||||||
.updateMessage(message);
|
.updateMessage(message);
|
||||||
PgpEngine.this.mXmppConnectionService.updateConversationUi();
|
PgpEngine.this.mXmppConnectionService
|
||||||
|
.updateConversationUi();
|
||||||
callback.success(message);
|
callback.success(message);
|
||||||
return;
|
return;
|
||||||
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
||||||
|
@ -177,7 +180,7 @@ public class PgpEngine {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
callback.error(R.string.openpgp_error, message);
|
callback.error(R.string.openpgp_error, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
||||||
callback.userInputRequried((PendingIntent) result
|
callback.userInputRequried((PendingIntent) result
|
||||||
|
@ -221,9 +224,9 @@ public class PgpEngine {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
Log.d("xmppService", "file not found: " + e.getMessage());
|
Log.d(Config.LOGTAG, "file not found: " + e.getMessage());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.d("xmppService", "io exception during file encrypt");
|
Log.d(Config.LOGTAG, "io exception during file encrypt");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,7 +270,7 @@ public class PgpEngine {
|
||||||
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
||||||
return 0;
|
return 0;
|
||||||
case OpenPgpApi.RESULT_CODE_ERROR:
|
case OpenPgpApi.RESULT_CODE_ERROR:
|
||||||
Log.d("xmppService",
|
Log.d(Config.LOGTAG,
|
||||||
"openpgp error: "
|
"openpgp error: "
|
||||||
+ ((OpenPgpError) result
|
+ ((OpenPgpError) result
|
||||||
.getParcelableExtra(OpenPgpApi.RESULT_ERROR))
|
.getParcelableExtra(OpenPgpApi.RESULT_ERROR))
|
||||||
|
|
|
@ -4,19 +4,18 @@ import android.content.ContentValues;
|
||||||
|
|
||||||
public abstract class AbstractEntity {
|
public abstract class AbstractEntity {
|
||||||
|
|
||||||
|
|
||||||
public static final String UUID = "uuid";
|
public static final String UUID = "uuid";
|
||||||
|
|
||||||
protected String uuid;
|
protected String uuid;
|
||||||
|
|
||||||
public String getUuid() {
|
public String getUuid() {
|
||||||
return this.uuid;
|
return this.uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract ContentValues getContentValues();
|
public abstract ContentValues getContentValues();
|
||||||
|
|
||||||
public boolean equals(AbstractEntity entity) {
|
public boolean equals(AbstractEntity entity) {
|
||||||
return this.getUuid().equals(entity.getUuid());
|
return this.getUuid().equals(entity.getUuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,11 +82,12 @@ public class Account extends AbstractEntity {
|
||||||
|
|
||||||
public Account(String username, String server, String password) {
|
public Account(String username, String server, String password) {
|
||||||
this(java.util.UUID.randomUUID().toString(), username, server,
|
this(java.util.UUID.randomUUID().toString(), username, server,
|
||||||
password, 0, null, "",null);
|
password, 0, null, "", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Account(String uuid, String username, String server,
|
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.uuid = uuid;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.server = server;
|
this.server = server;
|
||||||
|
@ -151,7 +152,10 @@ public class Account extends AbstractEntity {
|
||||||
|
|
||||||
public boolean errorStatus() {
|
public boolean errorStatus() {
|
||||||
int s = getStatus();
|
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() {
|
public boolean hasErrorStatus() {
|
||||||
|
|
|
@ -8,30 +8,31 @@ import eu.siacs.conversations.utils.UIHelper;
|
||||||
import eu.siacs.conversations.xml.Element;
|
import eu.siacs.conversations.xml.Element;
|
||||||
|
|
||||||
public class Bookmark implements ListItem {
|
public class Bookmark implements ListItem {
|
||||||
|
|
||||||
private Account account;
|
private Account account;
|
||||||
private String jid;
|
private String jid;
|
||||||
private String nick;
|
private String nick;
|
||||||
private String name;
|
private String name;
|
||||||
private boolean autojoin;
|
private boolean autojoin;
|
||||||
private Conversation mJoinedConversation;
|
private Conversation mJoinedConversation;
|
||||||
|
|
||||||
public Bookmark(Account account, String jid) {
|
public Bookmark(Account account, String jid) {
|
||||||
this.account = account;
|
this.account = account;
|
||||||
this.jid = jid;
|
this.jid = jid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bookmark parse(Element element, Account account) {
|
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"));
|
bookmark.setName(element.getAttribute("name"));
|
||||||
String autojoin = element.getAttribute("autojoin");
|
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);
|
bookmark.setAutojoin(true);
|
||||||
} else {
|
} else {
|
||||||
bookmark.setAutojoin(false);
|
bookmark.setAutojoin(false);
|
||||||
}
|
}
|
||||||
Element nick = element.findChild("nick");
|
Element nick = element.findChild("nick");
|
||||||
if (nick!=null) {
|
if (nick != null) {
|
||||||
bookmark.setNick(nick.getContent());
|
bookmark.setNick(nick.getContent());
|
||||||
}
|
}
|
||||||
return bookmark;
|
return bookmark;
|
||||||
|
@ -40,25 +41,27 @@ public class Bookmark implements ListItem {
|
||||||
public void setAutojoin(boolean autojoin) {
|
public void setAutojoin(boolean autojoin) {
|
||||||
this.autojoin = autojoin;
|
this.autojoin = autojoin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNick(String nick) {
|
public void setNick(String nick) {
|
||||||
this.nick = nick;
|
this.nick = nick;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(ListItem another) {
|
public int compareTo(ListItem another) {
|
||||||
return this.getDisplayName().compareToIgnoreCase(another.getDisplayName());
|
return this.getDisplayName().compareToIgnoreCase(
|
||||||
|
another.getDisplayName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDisplayName() {
|
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();
|
return this.mJoinedConversation.getMucOptions().getSubject();
|
||||||
} else if (name!=null) {
|
} else if (name != null) {
|
||||||
return name;
|
return name;
|
||||||
} else {
|
} else {
|
||||||
return this.jid.split("@")[0];
|
return this.jid.split("@")[0];
|
||||||
|
@ -69,11 +72,11 @@ public class Bookmark implements ListItem {
|
||||||
public String getJid() {
|
public String getJid() {
|
||||||
return this.jid.toLowerCase(Locale.US);
|
return this.jid.toLowerCase(Locale.US);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getNick() {
|
public String getNick() {
|
||||||
return this.nick;
|
return this.nick;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean autojoin() {
|
public boolean autojoin() {
|
||||||
return autojoin;
|
return autojoin;
|
||||||
}
|
}
|
||||||
|
@ -81,8 +84,8 @@ public class Bookmark implements ListItem {
|
||||||
public boolean match(String needle) {
|
public boolean match(String needle) {
|
||||||
return needle == null
|
return needle == null
|
||||||
|| getJid().contains(needle.toLowerCase(Locale.US))
|
|| getJid().contains(needle.toLowerCase(Locale.US))
|
||||||
|| getDisplayName().toLowerCase(Locale.US)
|
|| getDisplayName().toLowerCase(Locale.US).contains(
|
||||||
.contains(needle.toLowerCase(Locale.US));
|
needle.toLowerCase(Locale.US));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Account getAccount() {
|
public Account getAccount() {
|
||||||
|
@ -91,10 +94,12 @@ public class Bookmark implements ListItem {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Bitmap getImage(int dpSize, Context context) {
|
public Bitmap getImage(int dpSize, Context context) {
|
||||||
if (this.mJoinedConversation==null) {
|
if (this.mJoinedConversation == null) {
|
||||||
return UIHelper.getContactPicture(getDisplayName(), dpSize, context, false);
|
return UIHelper.getContactPicture(getDisplayName(), dpSize,
|
||||||
|
context, false);
|
||||||
} else {
|
} else {
|
||||||
return UIHelper.getContactPicture(this.mJoinedConversation, dpSize, context, false);
|
return UIHelper.getContactPicture(this.mJoinedConversation, dpSize,
|
||||||
|
context, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +110,7 @@ public class Bookmark implements ListItem {
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Element toElement() {
|
public Element toElement() {
|
||||||
Element element = new Element("conference");
|
Element element = new Element("conference");
|
||||||
element.setAttribute("jid", this.getJid());
|
element.setAttribute("jid", this.getJid());
|
||||||
|
|
|
@ -106,7 +106,7 @@ public class Contact implements ListItem {
|
||||||
values.put(SYSTEMACCOUNT, systemAccount);
|
values.put(SYSTEMACCOUNT, systemAccount);
|
||||||
values.put(PHOTOURI, photoUri);
|
values.put(PHOTOURI, photoUri);
|
||||||
values.put(KEYS, keys.toString());
|
values.put(KEYS, keys.toString());
|
||||||
values.put(AVATAR,avatar);
|
values.put(AVATAR, avatar);
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ public class Contact implements ListItem {
|
||||||
public Account getAccount() {
|
public Account getAccount() {
|
||||||
return this.account;
|
return this.account;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Presences getPresences() {
|
public Presences getPresences() {
|
||||||
return this.presences;
|
return this.presences;
|
||||||
}
|
}
|
||||||
|
@ -309,7 +309,8 @@ public class Contact implements ListItem {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(ListItem another) {
|
public int compareTo(ListItem another) {
|
||||||
return this.getDisplayName().compareToIgnoreCase(another.getDisplayName());
|
return this.getDisplayName().compareToIgnoreCase(
|
||||||
|
another.getDisplayName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getServer() {
|
public String getServer() {
|
||||||
|
@ -323,9 +324,9 @@ public class Contact implements ListItem {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Bitmap getImage(int size, Context context) {
|
public Bitmap getImage(int size, Context context) {
|
||||||
if (this.avatar!=null) {
|
if (this.avatar != null) {
|
||||||
Bitmap bm = FileBackend.getAvatar(avatar, size, context);
|
Bitmap bm = FileBackend.getAvatar(avatar, size, context);
|
||||||
if (bm==null) {
|
if (bm == null) {
|
||||||
return UIHelper.getContactPicture(this, size, context, false);
|
return UIHelper.getContactPicture(this, size, context, false);
|
||||||
} else {
|
} else {
|
||||||
return bm;
|
return bm;
|
||||||
|
|
|
@ -88,7 +88,8 @@ public class Conversation extends AbstractEntity {
|
||||||
|
|
||||||
public List<Message> getMessages() {
|
public List<Message> getMessages() {
|
||||||
if (messages == null) {
|
if (messages == null) {
|
||||||
this.messages = new CopyOnWriteArrayList<Message>(); // prevent null pointer
|
this.messages = new CopyOnWriteArrayList<Message>(); // prevent null
|
||||||
|
// pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
// populate with Conversation (this)
|
// populate with Conversation (this)
|
||||||
|
@ -287,7 +288,7 @@ public class Conversation extends AbstractEntity {
|
||||||
public String getOtrFingerprint() {
|
public String getOtrFingerprint() {
|
||||||
if (this.otrFingerprint == null) {
|
if (this.otrFingerprint == null) {
|
||||||
try {
|
try {
|
||||||
if (getOtrSession()== null) {
|
if (getOtrSession() == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession()
|
DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession()
|
||||||
|
@ -403,15 +404,15 @@ public class Conversation extends AbstractEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bitmap getImage(Context context, int size) {
|
public Bitmap getImage(Context context, int size) {
|
||||||
if (mode==MODE_SINGLE) {
|
if (mode == MODE_SINGLE) {
|
||||||
return getContact().getImage(size, context);
|
return getContact().getImage(size, context);
|
||||||
} else {
|
} else {
|
||||||
return UIHelper.getContactPicture(this, size, context, false);
|
return UIHelper.getContactPicture(this, size, context, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasDuplicateMessage(Message message) {
|
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)) {
|
if (this.messages.get(i).equals(message)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import android.graphics.Bitmap;
|
||||||
|
|
||||||
public interface ListItem extends Comparable<ListItem> {
|
public interface ListItem extends Comparable<ListItem> {
|
||||||
public String getDisplayName();
|
public String getDisplayName();
|
||||||
|
|
||||||
public String getJid();
|
public String getJid();
|
||||||
|
|
||||||
public Bitmap getImage(int dpSize, Context context);
|
public Bitmap getImage(int dpSize, Context context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,7 +142,7 @@ public class Message extends AbstractEntity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBody() {
|
public String getBody() {
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,9 +299,9 @@ public class MucOptions {
|
||||||
return this.conversation.getContactJid().split("/")[0] + "/"
|
return this.conversation.getContactJid().split("/")[0] + "/"
|
||||||
+ this.joinnick;
|
+ this.joinnick;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTrueCounterpart(String counterpart) {
|
public String getTrueCounterpart(String counterpart) {
|
||||||
for(User user : this.getUsers()) {
|
for (User user : this.getUsers()) {
|
||||||
if (user.getName().equals(counterpart)) {
|
if (user.getName().equals(counterpart)) {
|
||||||
return user.getJid();
|
return user.getJid();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ public class Presences {
|
||||||
public static final int XA = 2;
|
public static final int XA = 2;
|
||||||
public static final int DND = 3;
|
public static final int DND = 3;
|
||||||
public static final int OFFLINE = 4;
|
public static final int OFFLINE = 4;
|
||||||
|
|
||||||
private Hashtable<String, Integer> presences = new Hashtable<String, Integer>();
|
private Hashtable<String, Integer> presences = new Hashtable<String, Integer>();
|
||||||
|
|
||||||
public Hashtable<String, Integer> getPresences() {
|
public Hashtable<String, Integer> getPresences() {
|
||||||
|
@ -28,23 +28,24 @@ public class Presences {
|
||||||
public void removePresence(String resource) {
|
public void removePresence(String resource) {
|
||||||
this.presences.remove(resource);
|
this.presences.remove(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearPresences() {
|
public void clearPresences() {
|
||||||
this.presences.clear();
|
this.presences.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMostAvailableStatus() {
|
public int getMostAvailableStatus() {
|
||||||
int status = OFFLINE;
|
int status = OFFLINE;
|
||||||
Iterator<Entry<String, Integer>> it = presences.entrySet().iterator();
|
Iterator<Entry<String, Integer>> it = presences.entrySet().iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Entry<String, Integer> entry = it.next();
|
Entry<String, Integer> entry = it.next();
|
||||||
if (entry.getValue()<status) status = entry.getValue();
|
if (entry.getValue() < status)
|
||||||
|
status = entry.getValue();
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int parseShow(Element show) {
|
public static int parseShow(Element show) {
|
||||||
if ((show == null)||(show.getContent() == null)) {
|
if ((show == null) || (show.getContent() == null)) {
|
||||||
return Presences.ONLINE;
|
return Presences.ONLINE;
|
||||||
} else if (show.getContent().equals("away")) {
|
} else if (show.getContent().equals("away")) {
|
||||||
return Presences.AWAY;
|
return Presences.AWAY;
|
||||||
|
@ -53,16 +54,16 @@ public class Presences {
|
||||||
} else if (show.getContent().equals("chat")) {
|
} else if (show.getContent().equals("chat")) {
|
||||||
return Presences.CHAT;
|
return Presences.CHAT;
|
||||||
} else if (show.getContent().equals("dnd")) {
|
} else if (show.getContent().equals("dnd")) {
|
||||||
return Presences.DND;
|
return Presences.DND;
|
||||||
} else {
|
} else {
|
||||||
return Presences.OFFLINE;
|
return Presences.OFFLINE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int size() {
|
public int size() {
|
||||||
return presences.size();
|
return presences.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] asStringArray() {
|
public String[] asStringArray() {
|
||||||
final String[] presencesArray = new String[presences.size()];
|
final String[] presencesArray = new String[presences.size()];
|
||||||
presences.keySet().toArray(presencesArray);
|
presences.keySet().toArray(presencesArray);
|
||||||
|
|
|
@ -9,16 +9,16 @@ public class Roster {
|
||||||
Account account;
|
Account account;
|
||||||
ConcurrentHashMap<String, Contact> contacts = new ConcurrentHashMap<String, Contact>();
|
ConcurrentHashMap<String, Contact> contacts = new ConcurrentHashMap<String, Contact>();
|
||||||
private String version = null;
|
private String version = null;
|
||||||
|
|
||||||
public Roster(Account account) {
|
public Roster(Account account) {
|
||||||
this.account = account;
|
this.account = account;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasContact(String jid) {
|
public boolean hasContact(String jid) {
|
||||||
String cleanJid = jid.split("/")[0];
|
String cleanJid = jid.split("/")[0];
|
||||||
return contacts.containsKey(cleanJid);
|
return contacts.containsKey(cleanJid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Contact getContact(String jid) {
|
public Contact getContact(String jid) {
|
||||||
String cleanJid = jid.split("/")[0].toLowerCase(Locale.getDefault());
|
String cleanJid = jid.split("/")[0].toLowerCase(Locale.getDefault());
|
||||||
if (contacts.containsKey(cleanJid)) {
|
if (contacts.containsKey(cleanJid)) {
|
||||||
|
@ -32,19 +32,19 @@ public class Roster {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearPresences() {
|
public void clearPresences() {
|
||||||
for(Contact contact : getContacts()) {
|
for (Contact contact : getContacts()) {
|
||||||
contact.clearPresences();
|
contact.clearPresences();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markAllAsNotInRoster() {
|
public void markAllAsNotInRoster() {
|
||||||
for(Contact contact : getContacts()) {
|
for (Contact contact : getContacts()) {
|
||||||
contact.resetOption(Contact.Options.IN_ROSTER);
|
contact.resetOption(Contact.Options.IN_ROSTER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearSystemAccounts() {
|
public void clearSystemAccounts() {
|
||||||
for(Contact contact : getContacts()) {
|
for (Contact contact : getContacts()) {
|
||||||
contact.setPhotoUri(null);
|
contact.setPhotoUri(null);
|
||||||
contact.setSystemName(null);
|
contact.setSystemName(null);
|
||||||
contact.setSystemAccount(null);
|
contact.setSystemAccount(null);
|
||||||
|
@ -58,13 +58,13 @@ public class Roster {
|
||||||
public void initContact(Contact contact) {
|
public void initContact(Contact contact) {
|
||||||
contact.setAccount(account);
|
contact.setAccount(account);
|
||||||
contact.setOption(Contact.Options.IN_ROSTER);
|
contact.setOption(Contact.Options.IN_ROSTER);
|
||||||
contacts.put(contact.getJid(),contact);
|
contacts.put(contact.getJid(), contact);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVersion(String version) {
|
public void setVersion(String version) {
|
||||||
this.version = version;
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getVersion() {
|
public String getVersion() {
|
||||||
return this.version;
|
return this.version;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,67 +10,69 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
||||||
|
|
||||||
public class IqGenerator extends AbstractGenerator {
|
public class IqGenerator extends AbstractGenerator {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public IqPacket discoResponse(IqPacket request) {
|
public IqPacket discoResponse(IqPacket request) {
|
||||||
IqPacket packet = new IqPacket(IqPacket.TYPE_RESULT);
|
IqPacket packet = new IqPacket(IqPacket.TYPE_RESULT);
|
||||||
packet.setId(request.getId());
|
packet.setId(request.getId());
|
||||||
packet.setTo(request.getFrom());
|
packet.setTo(request.getFrom());
|
||||||
Element query = packet.addChild("query","http://jabber.org/protocol/disco#info");
|
Element query = packet.addChild("query",
|
||||||
|
"http://jabber.org/protocol/disco#info");
|
||||||
query.setAttribute("node", request.query().getAttribute("node"));
|
query.setAttribute("node", request.query().getAttribute("node"));
|
||||||
Element identity = query.addChild("identity");
|
Element identity = query.addChild("identity");
|
||||||
identity.setAttribute("category","client");
|
identity.setAttribute("category", "client");
|
||||||
identity.setAttribute("type", this.IDENTITY_TYPE);
|
identity.setAttribute("type", this.IDENTITY_TYPE);
|
||||||
identity.setAttribute("name", IDENTITY_NAME);
|
identity.setAttribute("name", IDENTITY_NAME);
|
||||||
List<String> features = Arrays.asList(FEATURES);
|
List<String> features = Arrays.asList(FEATURES);
|
||||||
Collections.sort(features);
|
Collections.sort(features);
|
||||||
for(String feature : features) {
|
for (String feature : features) {
|
||||||
query.addChild("feature").setAttribute("var",feature);
|
query.addChild("feature").setAttribute("var", feature);
|
||||||
}
|
}
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IqPacket publish(String node, Element item) {
|
protected IqPacket publish(String node, Element item) {
|
||||||
IqPacket packet = new IqPacket(IqPacket.TYPE_SET);
|
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");
|
Element publish = pubsub.addChild("publish");
|
||||||
publish.setAttribute("node", node);
|
publish.setAttribute("node", node);
|
||||||
publish.addChild(item);
|
publish.addChild(item);
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IqPacket retrieve(String node, Element item) {
|
protected IqPacket retrieve(String node, Element item) {
|
||||||
IqPacket packet = new IqPacket(IqPacket.TYPE_GET);
|
IqPacket packet = new IqPacket(IqPacket.TYPE_GET);
|
||||||
Element pubsub = packet.addChild("pubsub", "http://jabber.org/protocol/pubsub");
|
Element pubsub = packet.addChild("pubsub",
|
||||||
Element items = pubsub.addChild("items");
|
"http://jabber.org/protocol/pubsub");
|
||||||
items.setAttribute("node", node);
|
Element items = pubsub.addChild("items");
|
||||||
if (item!=null) {
|
items.setAttribute("node", node);
|
||||||
|
if (item != null) {
|
||||||
items.addChild(item);
|
items.addChild(item);
|
||||||
}
|
}
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IqPacket publishAvatar(Avatar avatar) {
|
public IqPacket publishAvatar(Avatar avatar) {
|
||||||
Element item = new Element("item");
|
Element item = new Element("item");
|
||||||
item.setAttribute("id", avatar.sha1sum);
|
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);
|
data.setContent(avatar.image);
|
||||||
return publish("urn:xmpp:avatar:data", item);
|
return publish("urn:xmpp:avatar:data", item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IqPacket publishAvatarMetadata(Avatar avatar) {
|
public IqPacket publishAvatarMetadata(Avatar avatar) {
|
||||||
Element item = new Element("item");
|
Element item = new Element("item");
|
||||||
item.setAttribute("id", avatar.sha1sum);
|
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");
|
Element info = metadata.addChild("info");
|
||||||
info.setAttribute("bytes",avatar.size);
|
info.setAttribute("bytes", avatar.size);
|
||||||
info.setAttribute("id",avatar.sha1sum);
|
info.setAttribute("id", avatar.sha1sum);
|
||||||
info.setAttribute("height",avatar.height);
|
info.setAttribute("height", avatar.height);
|
||||||
info.setAttribute("width",avatar.height);
|
info.setAttribute("width", avatar.height);
|
||||||
info.setAttribute("type", avatar.type);
|
info.setAttribute("type", avatar.type);
|
||||||
return publish("urn:xmpp:avatar:metadata",item);
|
return publish("urn:xmpp:avatar:metadata", item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IqPacket retrieveAvatar(Avatar avatar) {
|
public IqPacket retrieveAvatar(Avatar avatar) {
|
||||||
Element item = new Element("item");
|
Element item = new Element("item");
|
||||||
item.setAttribute("id", avatar.sha1sum);
|
item.setAttribute("id", avatar.sha1sum);
|
||||||
|
@ -81,7 +83,7 @@ public class IqGenerator extends AbstractGenerator {
|
||||||
|
|
||||||
public IqPacket retrieveAvatarMetaData(String to) {
|
public IqPacket retrieveAvatarMetaData(String to) {
|
||||||
IqPacket packet = retrieve("urn:xmpp:avatar:metadata", null);
|
IqPacket packet = retrieve("urn:xmpp:avatar:metadata", null);
|
||||||
if (to!=null) {
|
if (to != null) {
|
||||||
packet.setTo(to);
|
packet.setTo(to);
|
||||||
}
|
}
|
||||||
return packet;
|
return packet;
|
||||||
|
|
|
@ -32,56 +32,56 @@ public class MessageGenerator {
|
||||||
packet.setFrom(account.getFullJid());
|
packet.setFrom(account.getFullJid());
|
||||||
packet.setId(message.getUuid());
|
packet.setId(message.getUuid());
|
||||||
if (addDelay) {
|
if (addDelay) {
|
||||||
addDelay(packet,message.getTimeSent());
|
addDelay(packet, message.getTimeSent());
|
||||||
}
|
}
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addDelay(MessagePacket packet, long timestamp) {
|
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"));
|
mDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
Element delay = packet.addChild("delay", "urn:xmpp:delay");
|
Element delay = packet.addChild("delay", "urn:xmpp:delay");
|
||||||
Date date = new Date(timestamp);
|
Date date = new Date(timestamp);
|
||||||
delay.setAttribute("stamp", mDateFormat.format(date));
|
delay.setAttribute("stamp", mDateFormat.format(date));
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagePacket generateOtrChat(Message message) {
|
public MessagePacket generateOtrChat(Message message) {
|
||||||
return generateOtrChat(message, false);
|
return generateOtrChat(message, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagePacket generateOtrChat(Message message, boolean addDelay) {
|
public MessagePacket generateOtrChat(Message message, boolean addDelay) {
|
||||||
Session otrSession = message.getConversation().getOtrSession();
|
Session otrSession = message.getConversation().getOtrSession();
|
||||||
if (otrSession==null) {
|
if (otrSession == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
MessagePacket packet = preparePacket(message,addDelay);
|
MessagePacket packet = preparePacket(message, addDelay);
|
||||||
packet.addChild("private", "urn:xmpp:carbons:2");
|
packet.addChild("private", "urn:xmpp:carbons:2");
|
||||||
packet.addChild("no-copy", "urn:xmpp:hints");
|
packet.addChild("no-copy", "urn:xmpp:hints");
|
||||||
try {
|
try {
|
||||||
packet.setBody(otrSession.transformSending(message
|
packet.setBody(otrSession.transformSending(message.getBody()));
|
||||||
.getBody()));
|
|
||||||
return packet;
|
return packet;
|
||||||
} catch (OtrException e) {
|
} catch (OtrException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagePacket generateChat(Message message) {
|
public MessagePacket generateChat(Message message) {
|
||||||
return generateChat(message, false);
|
return generateChat(message, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagePacket generateChat(Message message, boolean addDelay) {
|
public MessagePacket generateChat(Message message, boolean addDelay) {
|
||||||
MessagePacket packet = preparePacket(message,addDelay);
|
MessagePacket packet = preparePacket(message, addDelay);
|
||||||
packet.setBody(message.getBody());
|
packet.setBody(message.getBody());
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagePacket generatePgpChat(Message message) {
|
public MessagePacket generatePgpChat(Message message) {
|
||||||
return generatePgpChat(message, false);
|
return generatePgpChat(message, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagePacket generatePgpChat(Message message, boolean addDelay) {
|
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");
|
packet.setBody("This is an XEP-0027 encryted message");
|
||||||
if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
|
if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
|
||||||
packet.addChild("x", "jabber:x:encrypted").setContent(
|
packet.addChild("x", "jabber:x:encrypted").setContent(
|
||||||
|
@ -100,7 +100,7 @@ public class MessageGenerator {
|
||||||
error.addChild("not-acceptable");
|
error.addChild("not-acceptable");
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MessagePacket generateError(MessagePacket origin) {
|
private MessagePacket generateError(MessagePacket origin) {
|
||||||
MessagePacket packet = new MessagePacket();
|
MessagePacket packet = new MessagePacket();
|
||||||
packet.setId(origin.getId());
|
packet.setId(origin.getId());
|
||||||
|
@ -109,7 +109,7 @@ public class MessageGenerator {
|
||||||
packet.setType(MessagePacket.TYPE_ERROR);
|
packet.setType(MessagePacket.TYPE_ERROR);
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagePacket confirm(Account account, String to, String id) {
|
public MessagePacket confirm(Account account, String to, String id) {
|
||||||
MessagePacket packet = new MessagePacket();
|
MessagePacket packet = new MessagePacket();
|
||||||
packet.setType(MessagePacket.TYPE_NORMAL);
|
packet.setType(MessagePacket.TYPE_NORMAL);
|
||||||
|
@ -120,8 +120,9 @@ public class MessageGenerator {
|
||||||
received.setAttribute("id", id);
|
received.setAttribute("id", id);
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagePacket conferenceSubject(Conversation conversation,String subject) {
|
public MessagePacket conferenceSubject(Conversation conversation,
|
||||||
|
String subject) {
|
||||||
MessagePacket packet = new MessagePacket();
|
MessagePacket packet = new MessagePacket();
|
||||||
packet.setType(MessagePacket.TYPE_GROUPCHAT);
|
packet.setType(MessagePacket.TYPE_GROUPCHAT);
|
||||||
packet.setTo(conversation.getContactJid().split("/")[0]);
|
packet.setTo(conversation.getContactJid().split("/")[0]);
|
||||||
|
@ -131,7 +132,7 @@ public class MessageGenerator {
|
||||||
packet.setFrom(conversation.getAccount().getJid());
|
packet.setFrom(conversation.getAccount().getJid());
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagePacket directInvite(Conversation conversation, String contact) {
|
public MessagePacket directInvite(Conversation conversation, String contact) {
|
||||||
MessagePacket packet = new MessagePacket();
|
MessagePacket packet = new MessagePacket();
|
||||||
packet.setType(MessagePacket.TYPE_NORMAL);
|
packet.setType(MessagePacket.TYPE_NORMAL);
|
||||||
|
@ -141,7 +142,7 @@ public class MessageGenerator {
|
||||||
x.setAttribute("jid", conversation.getContactJid().split("/")[0]);
|
x.setAttribute("jid", conversation.getContactJid().split("/")[0]);
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagePacket invite(Conversation conversation, String contact) {
|
public MessagePacket invite(Conversation conversation, String contact) {
|
||||||
MessagePacket packet = new MessagePacket();
|
MessagePacket packet = new MessagePacket();
|
||||||
packet.setTo(conversation.getContactJid().split("/")[0]);
|
packet.setTo(conversation.getContactJid().split("/")[0]);
|
||||||
|
@ -154,13 +155,14 @@ public class MessageGenerator {
|
||||||
packet.addChild(x);
|
packet.addChild(x);
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagePacket received(Account account, MessagePacket originalMessage, String namespace) {
|
public MessagePacket received(Account account,
|
||||||
|
MessagePacket originalMessage, String namespace) {
|
||||||
MessagePacket receivedPacket = new MessagePacket();
|
MessagePacket receivedPacket = new MessagePacket();
|
||||||
receivedPacket.setType(MessagePacket.TYPE_NORMAL);
|
receivedPacket.setType(MessagePacket.TYPE_NORMAL);
|
||||||
receivedPacket.setTo(originalMessage.getFrom());
|
receivedPacket.setTo(originalMessage.getFrom());
|
||||||
receivedPacket.setFrom(account.getFullJid());
|
receivedPacket.setFrom(account.getFullJid());
|
||||||
Element received = receivedPacket.addChild("received",namespace);
|
Element received = receivedPacket.addChild("received", namespace);
|
||||||
received.setAttribute("id", originalMessage.getId());
|
received.setAttribute("id", originalMessage.getId());
|
||||||
return receivedPacket;
|
return receivedPacket;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ public class PresenceGenerator extends AbstractGenerator {
|
||||||
packet.setAttribute("from", contact.getAccount().getJid());
|
packet.setAttribute("from", contact.getAccount().getJid());
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PresencePacket requestPresenceUpdatesFrom(Contact contact) {
|
public PresencePacket requestPresenceUpdatesFrom(Contact contact) {
|
||||||
return subscription("subscribe", contact);
|
return subscription("subscribe", contact);
|
||||||
}
|
}
|
||||||
|
@ -41,9 +41,10 @@ public class PresenceGenerator extends AbstractGenerator {
|
||||||
}
|
}
|
||||||
String capHash = getCapHash();
|
String capHash = getCapHash();
|
||||||
if (capHash != null) {
|
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("hash", "sha-1");
|
||||||
cap.setAttribute("node","http://conversions.siacs.eu");
|
cap.setAttribute("node", "http://conversions.siacs.eu");
|
||||||
cap.setAttribute("ver", capHash);
|
cap.setAttribute("ver", capHash);
|
||||||
}
|
}
|
||||||
return packet;
|
return packet;
|
||||||
|
|
|
@ -13,17 +13,17 @@ import eu.siacs.conversations.services.XmppConnectionService;
|
||||||
import eu.siacs.conversations.xml.Element;
|
import eu.siacs.conversations.xml.Element;
|
||||||
|
|
||||||
public abstract class AbstractParser {
|
public abstract class AbstractParser {
|
||||||
|
|
||||||
protected XmppConnectionService mXmppConnectionService;
|
protected XmppConnectionService mXmppConnectionService;
|
||||||
|
|
||||||
protected AbstractParser(XmppConnectionService service) {
|
protected AbstractParser(XmppConnectionService service) {
|
||||||
this.mXmppConnectionService = service;
|
this.mXmppConnectionService = service;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected long getTimestamp(Element packet) {
|
protected long getTimestamp(Element packet) {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
ArrayList<String> stamps = new ArrayList<String>();
|
ArrayList<String> stamps = new ArrayList<String>();
|
||||||
for(Element child : packet.getChildren()) {
|
for (Element child : packet.getChildren()) {
|
||||||
if (child.getName().equals("delay")) {
|
if (child.getName().equals("delay")) {
|
||||||
stamps.add(child.getAttribute("stamp").replace("Z", "+0000"));
|
stamps.add(child.getAttribute("stamp").replace("Z", "+0000"));
|
||||||
}
|
}
|
||||||
|
@ -33,17 +33,18 @@ public abstract class AbstractParser {
|
||||||
try {
|
try {
|
||||||
String stamp = stamps.get(stamps.size() - 1);
|
String stamp = stamps.get(stamps.size() - 1);
|
||||||
if (stamp.contains(".")) {
|
if (stamp.contains(".")) {
|
||||||
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ",Locale.US)
|
Date date = new SimpleDateFormat(
|
||||||
.parse(stamp);
|
"yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US)
|
||||||
if (now<date.getTime()) {
|
.parse(stamp);
|
||||||
|
if (now < date.getTime()) {
|
||||||
return now;
|
return now;
|
||||||
} else {
|
} else {
|
||||||
return date.getTime();
|
return date.getTime();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ",Locale.US)
|
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ",
|
||||||
.parse(stamp);
|
Locale.US).parse(stamp);
|
||||||
if (now<date.getTime()) {
|
if (now < date.getTime()) {
|
||||||
return now;
|
return now;
|
||||||
} else {
|
} else {
|
||||||
return date.getTime();
|
return date.getTime();
|
||||||
|
@ -56,8 +57,9 @@ public abstract class AbstractParser {
|
||||||
return now;
|
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[] fromParts = packet.getAttribute("from").split("/");
|
||||||
String from = fromParts[0];
|
String from = fromParts[0];
|
||||||
String presence = null;
|
String presence = null;
|
||||||
|
@ -70,19 +72,19 @@ public abstract class AbstractParser {
|
||||||
long timestamp = getTimestamp(packet);
|
long timestamp = getTimestamp(packet);
|
||||||
if (timestamp >= contact.lastseen.time) {
|
if (timestamp >= contact.lastseen.time) {
|
||||||
contact.lastseen.time = timestamp;
|
contact.lastseen.time = timestamp;
|
||||||
if ((presence!=null)&&(presenceOverwrite)) {
|
if ((presence != null) && (presenceOverwrite)) {
|
||||||
contact.lastseen.presence = presence;
|
contact.lastseen.presence = presence;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String avatarData(Element items) {
|
protected String avatarData(Element items) {
|
||||||
Element item = items.findChild("item");
|
Element item = items.findChild("item");
|
||||||
if (item==null) {
|
if (item == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Element data = item.findChild("data","urn:xmpp:avatar:data");
|
Element data = item.findChild("data", "urn:xmpp:avatar:data");
|
||||||
if (data==null) {
|
if (data == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return data.getContent();
|
return data.getContent();
|
||||||
|
|
|
@ -12,7 +12,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
|
||||||
public IqParser(XmppConnectionService service) {
|
public IqParser(XmppConnectionService service) {
|
||||||
super(service);
|
super(service);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void rosterItems(Account account, Element query) {
|
public void rosterItems(Account account, Element query) {
|
||||||
String version = query.getAttribute("ver");
|
String version = query.getAttribute("ver");
|
||||||
if (version != null) {
|
if (version != null) {
|
||||||
|
@ -27,7 +27,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
|
||||||
if (!contact.getOption(Contact.Options.DIRTY_PUSH)) {
|
if (!contact.getOption(Contact.Options.DIRTY_PUSH)) {
|
||||||
contact.setServerName(name);
|
contact.setServerName(name);
|
||||||
}
|
}
|
||||||
if (subscription!=null) {
|
if (subscription != null) {
|
||||||
if (subscription.equals("remove")) {
|
if (subscription.equals("remove")) {
|
||||||
contact.resetOption(Contact.Options.IN_ROSTER);
|
contact.resetOption(Contact.Options.IN_ROSTER);
|
||||||
contact.resetOption(Contact.Options.DIRTY_DELETE);
|
contact.resetOption(Contact.Options.DIRTY_DELETE);
|
||||||
|
@ -42,14 +42,15 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
|
||||||
}
|
}
|
||||||
mXmppConnectionService.updateRosterUi();
|
mXmppConnectionService.updateRosterUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String avatarData(IqPacket packet) {
|
public String avatarData(IqPacket packet) {
|
||||||
Element pubsub = packet.findChild("pubsub", "http://jabber.org/protocol/pubsub");
|
Element pubsub = packet.findChild("pubsub",
|
||||||
if (pubsub==null) {
|
"http://jabber.org/protocol/pubsub");
|
||||||
|
if (pubsub == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Element items = pubsub.findChild("items");
|
Element items = pubsub.findChild("items");
|
||||||
if (items==null) {
|
if (items == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return super.avatarData(items);
|
return super.avatarData(items);
|
||||||
|
@ -63,20 +64,19 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
|
||||||
Element query = packet.findChild("query");
|
Element query = packet.findChild("query");
|
||||||
this.rosterItems(account, query);
|
this.rosterItems(account, query);
|
||||||
}
|
}
|
||||||
} else if (packet
|
} else if (packet.hasChild("open", "http://jabber.org/protocol/ibb")
|
||||||
.hasChild("open", "http://jabber.org/protocol/ibb")
|
|| packet.hasChild("data", "http://jabber.org/protocol/ibb")) {
|
||||||
|| packet
|
mXmppConnectionService.getJingleConnectionManager()
|
||||||
.hasChild("data", "http://jabber.org/protocol/ibb")) {
|
.deliverIbbPacket(account, packet);
|
||||||
mXmppConnectionService.getJingleConnectionManager().deliverIbbPacket(account, packet);
|
|
||||||
} else if (packet.hasChild("query",
|
} else if (packet.hasChild("query",
|
||||||
"http://jabber.org/protocol/disco#info")) {
|
"http://jabber.org/protocol/disco#info")) {
|
||||||
IqPacket response = mXmppConnectionService.getIqGenerator().discoResponse(packet);
|
IqPacket response = mXmppConnectionService.getIqGenerator()
|
||||||
|
.discoResponse(packet);
|
||||||
account.getXmppConnection().sendIqPacket(response, null);
|
account.getXmppConnection().sendIqPacket(response, null);
|
||||||
} else {
|
} else {
|
||||||
if ((packet.getType() == IqPacket.TYPE_GET)
|
if ((packet.getType() == IqPacket.TYPE_GET)
|
||||||
|| (packet.getType() == IqPacket.TYPE_SET)) {
|
|| (packet.getType() == IqPacket.TYPE_SET)) {
|
||||||
IqPacket response = packet
|
IqPacket response = packet.generateRespone(IqPacket.TYPE_ERROR);
|
||||||
.generateRespone(IqPacket.TYPE_ERROR);
|
|
||||||
Element error = response.addChild("error");
|
Element error = response.addChild("error");
|
||||||
error.setAttribute("type", "cancel");
|
error.setAttribute("type", "cancel");
|
||||||
error.addChild("feature-not-implemented",
|
error.addChild("feature-not-implemented",
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.os.SystemClock;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import net.java.otr4j.session.Session;
|
import net.java.otr4j.session.Session;
|
||||||
import net.java.otr4j.session.SessionStatus;
|
import net.java.otr4j.session.SessionStatus;
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.entities.Contact;
|
import eu.siacs.conversations.entities.Contact;
|
||||||
import eu.siacs.conversations.entities.Conversation;
|
import eu.siacs.conversations.entities.Conversation;
|
||||||
|
@ -18,7 +19,7 @@ import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
||||||
public class MessageParser extends AbstractParser implements
|
public class MessageParser extends AbstractParser implements
|
||||||
OnMessagePacketReceived {
|
OnMessagePacketReceived {
|
||||||
|
|
||||||
private long lastCarbonMessageReceived = -XmppConnectionService.CARBON_GRACE_PERIOD;
|
private long lastCarbonMessageReceived = -(Config.CARBON_GRACE_PERIOD * 1000);
|
||||||
|
|
||||||
public MessageParser(XmppConnectionService service) {
|
public MessageParser(XmppConnectionService service) {
|
||||||
super(service);
|
super(service);
|
||||||
|
@ -173,7 +174,8 @@ public class MessageParser extends AbstractParser implements
|
||||||
finishedMessage.setTrueCounterpart(conversation.getMucOptions()
|
finishedMessage.setTrueCounterpart(conversation.getMucOptions()
|
||||||
.getTrueCounterpart(counterPart));
|
.getTrueCounterpart(counterPart));
|
||||||
}
|
}
|
||||||
if (packet.hasChild("delay") && conversation.hasDuplicateMessage(finishedMessage)) {
|
if (packet.hasChild("delay")
|
||||||
|
&& conversation.hasDuplicateMessage(finishedMessage)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
finishedMessage.setTime(getTimestamp(packet));
|
finishedMessage.setTime(getTimestamp(packet));
|
||||||
|
@ -198,7 +200,8 @@ public class MessageParser extends AbstractParser implements
|
||||||
}
|
}
|
||||||
Element message = forwarded.findChild("message");
|
Element message = forwarded.findChild("message");
|
||||||
if ((message == null) || (!message.hasChild("body"))) {
|
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);
|
parseNormal(message, account);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -220,7 +223,7 @@ public class MessageParser extends AbstractParser implements
|
||||||
Conversation conversation = mXmppConnectionService
|
Conversation conversation = mXmppConnectionService
|
||||||
.findOrCreateConversation(account, parts[0], false);
|
.findOrCreateConversation(account, parts[0], false);
|
||||||
conversation.setLatestMarkableMessageId(getMarkableMessageId(packet));
|
conversation.setLatestMarkableMessageId(getMarkableMessageId(packet));
|
||||||
|
|
||||||
String pgpBody = getPgpBody(message);
|
String pgpBody = getPgpBody(message);
|
||||||
Message finishedMessage;
|
Message finishedMessage;
|
||||||
if (pgpBody != null) {
|
if (pgpBody != null) {
|
||||||
|
@ -243,7 +246,7 @@ public class MessageParser extends AbstractParser implements
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return finishedMessage;
|
return finishedMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,16 +310,18 @@ public class MessageParser extends AbstractParser implements
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
if (node.equals("urn:xmpp:avatar:metadata")) {
|
if (node.equals("urn:xmpp:avatar:metadata")) {
|
||||||
Avatar avatar = Avatar.parseMetadata(items);
|
Avatar avatar = Avatar.parseMetadata(items);
|
||||||
if (avatar!=null) {
|
if (avatar != null) {
|
||||||
avatar.owner = from;
|
avatar.owner = from;
|
||||||
if (mXmppConnectionService.getFileBackend().isAvatarCached(
|
if (mXmppConnectionService.getFileBackend().isAvatarCached(
|
||||||
avatar)) {
|
avatar)) {
|
||||||
if (account.getJid().equals(from)) {
|
if (account.getJid().equals(from)) {
|
||||||
if (account.setAvatar(avatar.getFilename())) {
|
if (account.setAvatar(avatar.getFilename())) {
|
||||||
mXmppConnectionService.databaseBackend.updateAccount(account);
|
mXmppConnectionService.databaseBackend
|
||||||
|
.updateAccount(account);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Contact contact = account.getRoster().getContact(from);
|
Contact contact = account.getRoster().getContact(
|
||||||
|
from);
|
||||||
contact.setAvatar(avatar.getFilename());
|
contact.setAvatar(avatar.getFilename());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -324,11 +329,11 @@ public class MessageParser extends AbstractParser implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.d("xmppService", account.getJid() + ": " + node + " from "
|
Log.d(Config.LOGTAG, account.getJid() + ": " + node + " from "
|
||||||
+ from);
|
+ from);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.d("xmppService", event.toString());
|
Log.d(Config.LOGTAG, event.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,7 +360,7 @@ public class MessageParser extends AbstractParser implements
|
||||||
boolean notify = true;
|
boolean notify = true;
|
||||||
if (mXmppConnectionService.getPreferences().getBoolean(
|
if (mXmppConnectionService.getPreferences().getBoolean(
|
||||||
"notification_grace_period_after_carbon_received", true)) {
|
"notification_grace_period_after_carbon_received", true)) {
|
||||||
notify = (SystemClock.elapsedRealtime() - lastCarbonMessageReceived) > XmppConnectionService.CARBON_GRACE_PERIOD;
|
notify = (SystemClock.elapsedRealtime() - lastCarbonMessageReceived) > (Config.CARBON_GRACE_PERIOD * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((packet.getType() == MessagePacket.TYPE_CHAT)) {
|
if ((packet.getType() == MessagePacket.TYPE_CHAT)) {
|
||||||
|
|
|
@ -26,7 +26,7 @@ public class PresenceParser extends AbstractParser implements
|
||||||
if (muc != null) {
|
if (muc != null) {
|
||||||
boolean before = muc.getMucOptions().online();
|
boolean before = muc.getMucOptions().online();
|
||||||
muc.getMucOptions().processPacket(packet, mPgpEngine);
|
muc.getMucOptions().processPacket(packet, mPgpEngine);
|
||||||
if (before!=muc.getMucOptions().online()) {
|
if (before != muc.getMucOptions().online()) {
|
||||||
mXmppConnectionService.updateConversationUi();
|
mXmppConnectionService.updateConversationUi();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ public class PresenceParser extends AbstractParser implements
|
||||||
if (muc != null) {
|
if (muc != null) {
|
||||||
boolean before = muc.getMucOptions().online();
|
boolean before = muc.getMucOptions().online();
|
||||||
muc.getMucOptions().processPacket(packet, mPgpEngine);
|
muc.getMucOptions().processPacket(packet, mPgpEngine);
|
||||||
if (before!=muc.getMucOptions().online()) {
|
if (before != muc.getMucOptions().online()) {
|
||||||
mXmppConnectionService.updateConversationUi();
|
mXmppConnectionService.updateConversationUi();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import android.util.Base64;
|
||||||
import android.util.Base64OutputStream;
|
import android.util.Base64OutputStream;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.LruCache;
|
import android.util.LruCache;
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.entities.Conversation;
|
import eu.siacs.conversations.entities.Conversation;
|
||||||
import eu.siacs.conversations.entities.Message;
|
import eu.siacs.conversations.entities.Message;
|
||||||
|
@ -44,8 +45,9 @@ public class FileBackend {
|
||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
private LruCache<String, Bitmap> thumbnailCache;
|
private LruCache<String, Bitmap> thumbnailCache;
|
||||||
|
|
||||||
private SimpleDateFormat imageDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS",Locale.US);
|
private SimpleDateFormat imageDateFormat = new SimpleDateFormat(
|
||||||
|
"yyyyMMdd_HHmmssSSS", Locale.US);
|
||||||
|
|
||||||
public FileBackend(Context context) {
|
public FileBackend(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
@ -85,14 +87,15 @@ public class FileBackend {
|
||||||
}
|
}
|
||||||
return new JingleFile(path + "/" + filename);
|
return new JingleFile(path + "/" + filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JingleFile getJingleFile(Message message) {
|
public JingleFile getJingleFile(Message message) {
|
||||||
return getJingleFile(message, true);
|
return getJingleFile(message, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JingleFile getJingleFile(Message message, boolean decrypted) {
|
public JingleFile getJingleFile(Message message, boolean decrypted) {
|
||||||
StringBuilder filename = new StringBuilder();
|
StringBuilder filename = new StringBuilder();
|
||||||
filename.append(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath());
|
filename.append(Environment.getExternalStoragePublicDirectory(
|
||||||
|
Environment.DIRECTORY_PICTURES).getAbsolutePath());
|
||||||
filename.append("/Conversations/");
|
filename.append("/Conversations/");
|
||||||
filename.append(message.getUuid());
|
filename.append(message.getUuid());
|
||||||
if ((decrypted) || (message.getEncryption() == Message.ENCRYPTION_NONE)) {
|
if ((decrypted) || (message.getEncryption() == Message.ENCRYPTION_NONE)) {
|
||||||
|
@ -106,7 +109,7 @@ public class FileBackend {
|
||||||
}
|
}
|
||||||
return new JingleFile(filename.toString());
|
return new JingleFile(filename.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bitmap resize(Bitmap originalBitmap, int size) {
|
public Bitmap resize(Bitmap originalBitmap, int size) {
|
||||||
int w = originalBitmap.getWidth();
|
int w = originalBitmap.getWidth();
|
||||||
int h = originalBitmap.getHeight();
|
int h = originalBitmap.getHeight();
|
||||||
|
@ -144,14 +147,15 @@ public class FileBackend {
|
||||||
private JingleFile copyImageToPrivateStorage(Message message, Uri image,
|
private JingleFile copyImageToPrivateStorage(Message message, Uri image,
|
||||||
int sampleSize) throws ImageCopyException {
|
int sampleSize) throws ImageCopyException {
|
||||||
try {
|
try {
|
||||||
InputStream is = context.getContentResolver().openInputStream(image);
|
InputStream is = context.getContentResolver()
|
||||||
|
.openInputStream(image);
|
||||||
JingleFile file = getJingleFile(message);
|
JingleFile file = getJingleFile(message);
|
||||||
file.getParentFile().mkdirs();
|
file.getParentFile().mkdirs();
|
||||||
file.createNewFile();
|
file.createNewFile();
|
||||||
Bitmap originalBitmap;
|
Bitmap originalBitmap;
|
||||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||||
int inSampleSize = (int) Math.pow(2, sampleSize);
|
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);
|
+ inSampleSize);
|
||||||
options.inSampleSize = inSampleSize;
|
options.inSampleSize = inSampleSize;
|
||||||
originalBitmap = BitmapFactory.decodeStream(is, null, options);
|
originalBitmap = BitmapFactory.decodeStream(is, null, options);
|
||||||
|
@ -194,17 +198,20 @@ public class FileBackend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getRotation(Uri image) {
|
private int getRotation(Uri image) {
|
||||||
if ("content".equals(image.getScheme())) {
|
if ("content".equals(image.getScheme())) {
|
||||||
Cursor cursor = context.getContentResolver().query(image,
|
Cursor cursor = context
|
||||||
new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
|
.getContentResolver()
|
||||||
|
.query(image,
|
||||||
|
new String[] { MediaStore.Images.ImageColumns.ORIENTATION },
|
||||||
|
null, null, null);
|
||||||
|
|
||||||
if (cursor.getCount() != 1) {
|
if (cursor.getCount() != 1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
cursor.moveToFirst();
|
cursor.moveToFirst();
|
||||||
return cursor.getInt(0);
|
return cursor.getInt(0);
|
||||||
} else {
|
} else {
|
||||||
ExifInterface exif;
|
ExifInterface exif;
|
||||||
try {
|
try {
|
||||||
|
@ -258,7 +265,7 @@ public class FileBackend {
|
||||||
try {
|
try {
|
||||||
this.deleteFile(file);
|
this.deleteFile(file);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.d("xmppService",
|
Log.d(Config.LOGTAG,
|
||||||
"error deleting file: " + file.getAbsolutePath());
|
"error deleting file: " + file.getAbsolutePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -273,28 +280,32 @@ public class FileBackend {
|
||||||
|
|
||||||
public Uri getTakePhotoUri() {
|
public Uri getTakePhotoUri() {
|
||||||
StringBuilder pathBuilder = new StringBuilder();
|
StringBuilder pathBuilder = new StringBuilder();
|
||||||
pathBuilder.append(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM));
|
pathBuilder.append(Environment
|
||||||
|
.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM));
|
||||||
pathBuilder.append('/');
|
pathBuilder.append('/');
|
||||||
pathBuilder.append("Camera");
|
pathBuilder.append("Camera");
|
||||||
pathBuilder.append('/');
|
pathBuilder.append('/');
|
||||||
pathBuilder.append("IMG_"+this.imageDateFormat.format(new Date())+".jpg");
|
pathBuilder.append("IMG_" + this.imageDateFormat.format(new Date())
|
||||||
Uri uri = Uri.parse("file://"+pathBuilder.toString());
|
+ ".jpg");
|
||||||
|
Uri uri = Uri.parse("file://" + pathBuilder.toString());
|
||||||
File file = new File(uri.toString());
|
File file = new File(uri.toString());
|
||||||
file.getParentFile().mkdirs();
|
file.getParentFile().mkdirs();
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Avatar getPepAvatar(Uri image, int size, Bitmap.CompressFormat format) {
|
public Avatar getPepAvatar(Uri image, int size, Bitmap.CompressFormat format) {
|
||||||
try {
|
try {
|
||||||
Avatar avatar = new Avatar();
|
Avatar avatar = new Avatar();
|
||||||
Bitmap bm = cropCenterSquare(image, size);
|
Bitmap bm = cropCenterSquare(image, size);
|
||||||
if (bm==null) {
|
if (bm == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
Base64OutputStream mBase64OutputSttream = new Base64OutputStream(mByteArrayOutputStream, Base64.DEFAULT);
|
Base64OutputStream mBase64OutputSttream = new Base64OutputStream(
|
||||||
|
mByteArrayOutputStream, Base64.DEFAULT);
|
||||||
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||||
DigestOutputStream mDigestOutputStream = new DigestOutputStream(mBase64OutputSttream, digest);
|
DigestOutputStream mDigestOutputStream = new DigestOutputStream(
|
||||||
|
mBase64OutputSttream, digest);
|
||||||
if (!bm.compress(format, 75, mDigestOutputStream)) {
|
if (!bm.compress(format, 75, mDigestOutputStream)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -309,25 +320,26 @@ public class FileBackend {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAvatarCached(Avatar avatar) {
|
public boolean isAvatarCached(Avatar avatar) {
|
||||||
File file = new File(getAvatarPath(context, avatar.getFilename()));
|
File file = new File(getAvatarPath(context, avatar.getFilename()));
|
||||||
return file.exists();
|
return file.exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean save(Avatar avatar) {
|
public boolean save(Avatar avatar) {
|
||||||
if (isAvatarCached(avatar)) {
|
if (isAvatarCached(avatar)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
String filename = getAvatarPath(context, avatar.getFilename());
|
String filename = getAvatarPath(context, avatar.getFilename());
|
||||||
File file = new File(filename+".tmp");
|
File file = new File(filename + ".tmp");
|
||||||
file.getParentFile().mkdirs();
|
file.getParentFile().mkdirs();
|
||||||
try {
|
try {
|
||||||
file.createNewFile();
|
file.createNewFile();
|
||||||
FileOutputStream mFileOutputStream = new FileOutputStream(file);
|
FileOutputStream mFileOutputStream = new FileOutputStream(file);
|
||||||
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||||
digest.reset();
|
digest.reset();
|
||||||
DigestOutputStream mDigestOutputStream = new DigestOutputStream(mFileOutputStream, digest);
|
DigestOutputStream mDigestOutputStream = new DigestOutputStream(
|
||||||
|
mFileOutputStream, digest);
|
||||||
mDigestOutputStream.write(avatar.getImageAsBytes());
|
mDigestOutputStream.write(avatar.getImageAsBytes());
|
||||||
mDigestOutputStream.flush();
|
mDigestOutputStream.flush();
|
||||||
mDigestOutputStream.close();
|
mDigestOutputStream.close();
|
||||||
|
@ -337,7 +349,7 @@ public class FileBackend {
|
||||||
file.renameTo(new File(filename));
|
file.renameTo(new File(filename));
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Log.d("xmppService","sha1sum mismatch for "+avatar.owner);
|
Log.d(Config.LOGTAG, "sha1sum mismatch for " + avatar.owner);
|
||||||
file.delete();
|
file.delete();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -349,9 +361,9 @@ public class FileBackend {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getAvatarPath(Context context, String avatar) {
|
public static String getAvatarPath(Context context, String avatar) {
|
||||||
return context.getFilesDir().getAbsolutePath() + "/avatars/"+avatar;
|
return context.getFilesDir().getAbsolutePath() + "/avatars/" + avatar;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bitmap cropCenterSquare(Uri image, int size) {
|
public Bitmap cropCenterSquare(Uri image, int size) {
|
||||||
|
@ -361,7 +373,7 @@ public class FileBackend {
|
||||||
InputStream is = context.getContentResolver()
|
InputStream is = context.getContentResolver()
|
||||||
.openInputStream(image);
|
.openInputStream(image);
|
||||||
Bitmap input = BitmapFactory.decodeStream(is, null, options);
|
Bitmap input = BitmapFactory.decodeStream(is, null, options);
|
||||||
if (input==null) {
|
if (input == null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return cropCenterSquare(input, size);
|
return cropCenterSquare(input, size);
|
||||||
|
@ -370,7 +382,7 @@ public class FileBackend {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bitmap cropCenterSquare(Bitmap input, int size) {
|
public static Bitmap cropCenterSquare(Bitmap input, int size) {
|
||||||
int w = input.getWidth();
|
int w = input.getWidth();
|
||||||
int h = input.getHeight();
|
int h = input.getHeight();
|
||||||
|
@ -381,8 +393,7 @@ public class FileBackend {
|
||||||
float outHeight = scale * h;
|
float outHeight = scale * h;
|
||||||
float left = (size - outWidth) / 2;
|
float left = (size - outWidth) / 2;
|
||||||
float top = (size - outHeight) / 2;
|
float top = (size - outHeight) / 2;
|
||||||
RectF target = new RectF(left, top, left + outWidth, top
|
RectF target = new RectF(left, top, left + outWidth, top + outHeight);
|
||||||
+ outHeight);
|
|
||||||
|
|
||||||
Bitmap output = Bitmap.createBitmap(size, size, input.getConfig());
|
Bitmap output = Bitmap.createBitmap(size, size, input.getConfig());
|
||||||
Canvas canvas = new Canvas(output);
|
Canvas canvas = new Canvas(output);
|
||||||
|
@ -412,11 +423,11 @@ public class FileBackend {
|
||||||
return inSampleSize;
|
return inSampleSize;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Uri getJingleFileUri(Message message) {
|
public Uri getJingleFileUri(Message message) {
|
||||||
File file = getJingleFile(message);
|
File file = getJingleFile(message);
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
return Uri.parse("file://"+file.getAbsolutePath());
|
return Uri.parse("file://" + file.getAbsolutePath());
|
||||||
} else {
|
} else {
|
||||||
return ImageProvider.getProviderUri(message);
|
return ImageProvider.getProviderUri(message);
|
||||||
}
|
}
|
||||||
|
@ -436,8 +447,9 @@ public class FileBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bitmap getAvatar(String avatar, int size, Context context) {
|
public static Bitmap getAvatar(String avatar, int size, Context context) {
|
||||||
Bitmap bm = BitmapFactory.decodeFile(FileBackend.getAvatarPath(context, avatar));
|
Bitmap bm = BitmapFactory.decodeFile(FileBackend.getAvatarPath(context,
|
||||||
if (bm==null) {
|
avatar));
|
||||||
|
if (bm == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return cropCenterSquare(bm, UIHelper.getRealPx(size, context));
|
return cropCenterSquare(bm, UIHelper.getRealPx(size, context));
|
||||||
|
|
|
@ -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() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,6 +3,7 @@ package eu.siacs.conversations.services;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
public class EventReceiver extends BroadcastReceiver {
|
public class EventReceiver extends BroadcastReceiver {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
|
|
@ -2,8 +2,8 @@ package eu.siacs.conversations.services;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.entities.Conversation;
|
import eu.siacs.conversations.entities.Conversation;
|
||||||
import eu.siacs.conversations.entities.Message;
|
import eu.siacs.conversations.entities.Message;
|
||||||
|
@ -27,7 +27,7 @@ public class ImageProvider extends ContentProvider {
|
||||||
DatabaseBackend databaseBackend = DatabaseBackend
|
DatabaseBackend databaseBackend = DatabaseBackend
|
||||||
.getInstance(getContext());
|
.getInstance(getContext());
|
||||||
String uuids = uri.getPath();
|
String uuids = uri.getPath();
|
||||||
Log.d("xmppService", "uuids = " + uuids+" mode="+mode);
|
Log.d(Config.LOGTAG, "uuids = " + uuids + " mode=" + mode);
|
||||||
if (uuids == null) {
|
if (uuids == null) {
|
||||||
throw new FileNotFoundException();
|
throw new FileNotFoundException();
|
||||||
}
|
}
|
||||||
|
@ -37,21 +37,21 @@ public class ImageProvider extends ContentProvider {
|
||||||
}
|
}
|
||||||
String conversationUuid = uuidsSplited[1];
|
String conversationUuid = uuidsSplited[1];
|
||||||
String messageUuid = uuidsSplited[2].split("\\.")[0];
|
String messageUuid = uuidsSplited[2].split("\\.")[0];
|
||||||
|
|
||||||
Log.d("xmppService","messageUuid="+messageUuid);
|
Log.d(Config.LOGTAG, "messageUuid=" + messageUuid);
|
||||||
|
|
||||||
Conversation conversation = databaseBackend
|
Conversation conversation = databaseBackend
|
||||||
.findConversationByUuid(conversationUuid);
|
.findConversationByUuid(conversationUuid);
|
||||||
if (conversation == null) {
|
if (conversation == null) {
|
||||||
throw new FileNotFoundException("conversation " + conversationUuid
|
throw new FileNotFoundException("conversation "
|
||||||
+ " could not be found");
|
+ conversationUuid + " could not be found");
|
||||||
}
|
}
|
||||||
Message message = databaseBackend.findMessageByUuid(messageUuid);
|
Message message = databaseBackend.findMessageByUuid(messageUuid);
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
throw new FileNotFoundException("message " + messageUuid
|
throw new FileNotFoundException("message " + messageUuid
|
||||||
+ " could not be found");
|
+ " could not be found");
|
||||||
}
|
}
|
||||||
|
|
||||||
Account account = databaseBackend.findAccountByUuid(conversation
|
Account account = databaseBackend.findAccountByUuid(conversation
|
||||||
.getAccountUuid());
|
.getAccountUuid());
|
||||||
if (account == null) {
|
if (account == null) {
|
||||||
|
@ -60,7 +60,7 @@ public class ImageProvider extends ContentProvider {
|
||||||
}
|
}
|
||||||
message.setConversation(conversation);
|
message.setConversation(conversation);
|
||||||
conversation.setAccount(account);
|
conversation.setAccount(account);
|
||||||
|
|
||||||
File file = fileBackend.getJingleFileLegacy(message);
|
File file = fileBackend.getJingleFileLegacy(message);
|
||||||
pfd = ParcelFileDescriptor.open(file,
|
pfd = ParcelFileDescriptor.open(file,
|
||||||
ParcelFileDescriptor.MODE_READ_ONLY);
|
ParcelFileDescriptor.MODE_READ_ONLY);
|
||||||
|
@ -100,13 +100,10 @@ public class ImageProvider extends ContentProvider {
|
||||||
public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
|
public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Uri getProviderUri(Message message) {
|
public static Uri getProviderUri(Message message) {
|
||||||
return Uri
|
return Uri.parse("content://eu.siacs.conversations.images/"
|
||||||
.parse("content://eu.siacs.conversations.images/"
|
+ message.getConversationUuid() + "/" + message.getUuid()
|
||||||
+ message.getConversationUuid()
|
+ ".webp");
|
||||||
+ "/"
|
|
||||||
+ message.getUuid()
|
|
||||||
+ ".webp");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,6 +20,7 @@ import de.duenndns.ssl.MemorizingTrustManager;
|
||||||
import net.java.otr4j.OtrException;
|
import net.java.otr4j.OtrException;
|
||||||
import net.java.otr4j.session.Session;
|
import net.java.otr4j.session.Session;
|
||||||
import net.java.otr4j.session.SessionStatus;
|
import net.java.otr4j.session.SessionStatus;
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.crypto.PgpEngine;
|
import eu.siacs.conversations.crypto.PgpEngine;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
|
@ -83,18 +84,11 @@ import android.util.Log;
|
||||||
|
|
||||||
public class XmppConnectionService extends Service {
|
public class XmppConnectionService extends Service {
|
||||||
|
|
||||||
protected static final String LOGTAG = "xmppService";
|
|
||||||
public DatabaseBackend databaseBackend;
|
public DatabaseBackend databaseBackend;
|
||||||
private FileBackend fileBackend;
|
private FileBackend fileBackend;
|
||||||
|
|
||||||
public long startDate;
|
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 static String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
|
||||||
|
|
||||||
private MemorizingTrustManager mMemorizingTrustManager;
|
private MemorizingTrustManager mMemorizingTrustManager;
|
||||||
|
@ -169,16 +163,17 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
if (connection != null && connection.getFeatures().csi()) {
|
if (connection != null && connection.getFeatures().csi()) {
|
||||||
if (checkListeners()) {
|
if (checkListeners()) {
|
||||||
Log.d(LOGTAG, account.getJid()
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
+ " sending csi//inactive");
|
+ " sending csi//inactive");
|
||||||
connection.sendInactive();
|
connection.sendInactive();
|
||||||
} else {
|
} else {
|
||||||
Log.d(LOGTAG, account.getJid() + " sending csi//active");
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
|
+ " sending csi//active");
|
||||||
connection.sendActive();
|
connection.sendActive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
syncDirtyContacts(account);
|
syncDirtyContacts(account);
|
||||||
scheduleWakeupCall(PING_MAX_INTERVAL, true);
|
scheduleWakeupCall(Config.PING_MAX_INTERVAL, true);
|
||||||
} else if (account.getStatus() == Account.STATUS_OFFLINE) {
|
} else if (account.getStatus() == Account.STATUS_OFFLINE) {
|
||||||
resetSendingToWaiting(account);
|
resetSendingToWaiting(account);
|
||||||
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
|
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
|
||||||
|
@ -192,7 +187,7 @@ public class XmppConnectionService extends Service {
|
||||||
&& (account.getStatus() != Account.STATUS_NO_INTERNET)) {
|
&& (account.getStatus() != Account.STATUS_NO_INTERNET)) {
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
int next = connection.getTimeToNextAttempt();
|
int next = connection.getTimeToNextAttempt();
|
||||||
Log.d(LOGTAG, account.getJid()
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
+ ": error connecting account. try again in "
|
+ ": error connecting account. try again in "
|
||||||
+ next + "s for the "
|
+ next + "s for the "
|
||||||
+ (connection.getAttempt() + 1) + " time");
|
+ (connection.getAttempt() + 1) + " time");
|
||||||
|
@ -355,10 +350,11 @@ public class XmppConnectionService extends Service {
|
||||||
.getLastPacketReceived();
|
.getLastPacketReceived();
|
||||||
long lastSent = account.getXmppConnection()
|
long lastSent = account.getXmppConnection()
|
||||||
.getLastPingSent();
|
.getLastPingSent();
|
||||||
if (lastSent - lastReceived >= PING_TIMEOUT * 1000) {
|
if (lastSent - lastReceived >= Config.PING_TIMEOUT * 1000) {
|
||||||
Log.d(LOGTAG, account.getJid() + ": ping timeout");
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
|
+ ": ping timeout");
|
||||||
this.reconnectAccount(account, true);
|
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();
|
account.getXmppConnection().sendPing();
|
||||||
this.scheduleWakeupCall(2, false);
|
this.scheduleWakeupCall(2, false);
|
||||||
}
|
}
|
||||||
|
@ -370,8 +366,8 @@ public class XmppConnectionService extends Service {
|
||||||
new Thread(account.getXmppConnection()).start();
|
new Thread(account.getXmppConnection()).start();
|
||||||
} else if ((account.getStatus() == Account.STATUS_CONNECTING)
|
} else if ((account.getStatus() == Account.STATUS_CONNECTING)
|
||||||
&& ((SystemClock.elapsedRealtime() - account
|
&& ((SystemClock.elapsedRealtime() - account
|
||||||
.getXmppConnection().getLastConnect()) / 1000 >= CONNECT_TIMEOUT)) {
|
.getXmppConnection().getLastConnect()) / 1000 >= Config.CONNECT_TIMEOUT)) {
|
||||||
Log.d(LOGTAG, account.getJid()
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
+ ": time out during connect reconnecting");
|
+ ": time out during connect reconnecting");
|
||||||
reconnectAccount(account, true);
|
reconnectAccount(account, true);
|
||||||
} else {
|
} else {
|
||||||
|
@ -380,7 +376,7 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// in any case. reschedule wakup call
|
// in any case. reschedule wakup call
|
||||||
this.scheduleWakeupCall(PING_MAX_INTERVAL, true);
|
this.scheduleWakeupCall(Config.PING_MAX_INTERVAL, true);
|
||||||
}
|
}
|
||||||
if (mOnAccountUpdate != null) {
|
if (mOnAccountUpdate != null) {
|
||||||
mOnAccountUpdate.onAccountUpdate();
|
mOnAccountUpdate.onAccountUpdate();
|
||||||
|
@ -450,7 +446,7 @@ public class XmppConnectionService extends Service {
|
||||||
.getSystemService(Context.ALARM_SERVICE);
|
.getSystemService(Context.ALARM_SERVICE);
|
||||||
Intent intent = new Intent(context, EventReceiver.class);
|
Intent intent = new Intent(context, EventReceiver.class);
|
||||||
alarmManager.cancel(PendingIntent.getBroadcast(context, 0, intent, 0));
|
alarmManager.cancel(PendingIntent.getBroadcast(context, 0, intent, 0));
|
||||||
Log.d(LOGTAG, "good bye");
|
Log.d(Config.LOGTAG, "good bye");
|
||||||
stopSelf();
|
stopSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -673,10 +669,10 @@ public class XmppConnectionService extends Service {
|
||||||
public void fetchRosterFromServer(Account account) {
|
public void fetchRosterFromServer(Account account) {
|
||||||
IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
|
IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
|
||||||
if (!"".equals(account.getRosterVersion())) {
|
if (!"".equals(account.getRosterVersion())) {
|
||||||
Log.d(LOGTAG, account.getJid() + ": fetching roster version "
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
+ account.getRosterVersion());
|
+ ": fetching roster version " + account.getRosterVersion());
|
||||||
} else {
|
} else {
|
||||||
Log.d(LOGTAG, account.getJid() + ": fetching roster");
|
Log.d(Config.LOGTAG, account.getJid() + ": fetching roster");
|
||||||
}
|
}
|
||||||
iqPacket.query("jabber:iq:roster").setAttribute("ver",
|
iqPacket.query("jabber:iq:roster").setAttribute("ver",
|
||||||
account.getRosterVersion());
|
account.getRosterVersion());
|
||||||
|
@ -1006,7 +1002,8 @@ public class XmppConnectionService extends Service {
|
||||||
XmppConnection connection = account.getXmppConnection();
|
XmppConnection connection = account.getXmppConnection();
|
||||||
if (connection != null && connection.getFeatures().csi()) {
|
if (connection != null && connection.getFeatures().csi()) {
|
||||||
connection.sendActive();
|
connection.sendActive();
|
||||||
Log.d(LOGTAG, account.getJid() + " sending csi//active");
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
|
+ " sending csi//active");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1018,7 +1015,8 @@ public class XmppConnectionService extends Service {
|
||||||
XmppConnection connection = account.getXmppConnection();
|
XmppConnection connection = account.getXmppConnection();
|
||||||
if (connection != null && connection.getFeatures().csi()) {
|
if (connection != null && connection.getFeatures().csi()) {
|
||||||
connection.sendInactive();
|
connection.sendInactive();
|
||||||
Log.d(LOGTAG, account.getJid() + " sending csi//inactive");
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
|
+ " sending csi//inactive");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1040,7 +1038,7 @@ public class XmppConnectionService extends Service {
|
||||||
account.pendingConferenceJoins.remove(conversation);
|
account.pendingConferenceJoins.remove(conversation);
|
||||||
account.pendingConferenceLeaves.remove(conversation);
|
account.pendingConferenceLeaves.remove(conversation);
|
||||||
if (account.getStatus() == Account.STATUS_ONLINE) {
|
if (account.getStatus() == Account.STATUS_ONLINE) {
|
||||||
Log.d(LOGTAG,
|
Log.d(Config.LOGTAG,
|
||||||
"joining conversation " + conversation.getContactJid());
|
"joining conversation " + conversation.getContactJid());
|
||||||
String nick = conversation.getMucOptions().getProposedNick();
|
String nick = conversation.getMucOptions().getProposedNick();
|
||||||
conversation.getMucOptions().setJoinNick(nick);
|
conversation.getMucOptions().setJoinNick(nick);
|
||||||
|
@ -1142,8 +1140,8 @@ public class XmppConnectionService extends Service {
|
||||||
sendPresencePacket(conversation.getAccount(), packet);
|
sendPresencePacket(conversation.getAccount(), packet);
|
||||||
conversation.getMucOptions().setOffline();
|
conversation.getMucOptions().setOffline();
|
||||||
conversation.deregisterWithBookmark();
|
conversation.deregisterWithBookmark();
|
||||||
Log.d(LOGTAG, conversation.getAccount().getJid() + " leaving muc "
|
Log.d(Config.LOGTAG, conversation.getAccount().getJid()
|
||||||
+ conversation.getContactJid());
|
+ " leaving muc " + conversation.getContactJid());
|
||||||
} else {
|
} else {
|
||||||
account.pendingConferenceLeaves.add(conversation);
|
account.pendingConferenceLeaves.add(conversation);
|
||||||
}
|
}
|
||||||
|
@ -1184,7 +1182,6 @@ public class XmppConnectionService extends Service {
|
||||||
pushContactToServer(contact);
|
pushContactToServer(contact);
|
||||||
}
|
}
|
||||||
if (contact.getOption(Contact.Options.DIRTY_DELETE)) {
|
if (contact.getOption(Contact.Options.DIRTY_DELETE)) {
|
||||||
Log.d(LOGTAG, "dirty delete");
|
|
||||||
deleteContactOnServer(contact);
|
deleteContactOnServer(contact);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1204,9 +1201,10 @@ public class XmppConnectionService extends Service {
|
||||||
Account account = conversation.getAccount();
|
Account account = conversation.getAccount();
|
||||||
List<Message> messages = conversation.getMessages();
|
List<Message> messages = conversation.getMessages();
|
||||||
Session otrSession = conversation.getOtrSession();
|
Session otrSession = conversation.getOtrSession();
|
||||||
Log.d(LOGTAG, account.getJid() + " otr session established with "
|
Log.d(Config.LOGTAG,
|
||||||
+ conversation.getContactJid() + "/"
|
account.getJid() + " otr session established with "
|
||||||
+ otrSession.getSessionID().getUserID());
|
+ conversation.getContactJid() + "/"
|
||||||
|
+ otrSession.getSessionID().getUserID());
|
||||||
for (int i = 0; i < messages.size(); ++i) {
|
for (int i = 0; i < messages.size(); ++i) {
|
||||||
Message msg = messages.get(i);
|
Message msg = messages.get(i);
|
||||||
if ((msg.getStatus() == Message.STATUS_UNSEND || msg.getStatus() == Message.STATUS_WAITING)
|
if ((msg.getStatus() == Message.STATUS_UNSEND || msg.getStatus() == Message.STATUS_WAITING)
|
||||||
|
@ -1280,8 +1278,8 @@ public class XmppConnectionService extends Service {
|
||||||
|
|
||||||
public void publishAvatar(Account account, Uri image,
|
public void publishAvatar(Account account, Uri image,
|
||||||
final UiCallback<Avatar> callback) {
|
final UiCallback<Avatar> callback) {
|
||||||
final Bitmap.CompressFormat format = Defaults.AVATAR_FORMAT;
|
final Bitmap.CompressFormat format = Config.AVATAR_FORMAT;
|
||||||
final int size = Defaults.AVATAR_SIZE;
|
final int size = Config.AVATAR_SIZE;
|
||||||
final Avatar avatar = getFileBackend()
|
final Avatar avatar = getFileBackend()
|
||||||
.getPepAvatar(image, size, format);
|
.getPepAvatar(image, size, format);
|
||||||
if (avatar != null) {
|
if (avatar != null) {
|
||||||
|
@ -1341,7 +1339,7 @@ public class XmppConnectionService extends Service {
|
||||||
|
|
||||||
public void fetchAvatar(Account account, final Avatar avatar,
|
public void fetchAvatar(Account account, final Avatar avatar,
|
||||||
final UiCallback<Avatar> callback) {
|
final UiCallback<Avatar> callback) {
|
||||||
Log.d(LOGTAG, account.getJid() + ": retrieving avatar for "
|
Log.d(Config.LOGTAG, account.getJid() + ": retrieving avatar for "
|
||||||
+ avatar.owner);
|
+ avatar.owner);
|
||||||
IqPacket packet = this.mIqGenerator.retrieveAvatar(avatar);
|
IqPacket packet = this.mIqGenerator.retrieveAvatar(avatar);
|
||||||
sendIqPacket(account, packet, new OnIqPacketReceived() {
|
sendIqPacket(account, packet, new OnIqPacketReceived() {
|
||||||
|
@ -1439,7 +1437,8 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
Thread thread = new Thread(account.getXmppConnection());
|
Thread thread = new Thread(account.getXmppConnection());
|
||||||
thread.start();
|
thread.start();
|
||||||
scheduleWakeupCall((int) (CONNECT_TIMEOUT * 1.2), false);
|
scheduleWakeupCall((int) (Config.CONNECT_TIMEOUT * 1.2),
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
|
|
|
@ -23,13 +23,13 @@ import eu.siacs.conversations.entities.ListItem;
|
||||||
import eu.siacs.conversations.ui.adapter.ListItemAdapter;
|
import eu.siacs.conversations.ui.adapter.ListItemAdapter;
|
||||||
|
|
||||||
public class ChooseContactActivity extends XmppActivity {
|
public class ChooseContactActivity extends XmppActivity {
|
||||||
|
|
||||||
private ListView mListView;
|
private ListView mListView;
|
||||||
private ArrayList<ListItem> contacts = new ArrayList<ListItem>();
|
private ArrayList<ListItem> contacts = new ArrayList<ListItem>();
|
||||||
private ArrayAdapter<ListItem> mContactsAdapter;
|
private ArrayAdapter<ListItem> mContactsAdapter;
|
||||||
|
|
||||||
private EditText mSearchEditText;
|
private EditText mSearchEditText;
|
||||||
|
|
||||||
private TextWatcher mSearchTextWatcher = new TextWatcher() {
|
private TextWatcher mSearchTextWatcher = new TextWatcher() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -47,7 +47,7 @@ public class ChooseContactActivity extends XmppActivity {
|
||||||
int count) {
|
int count) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
|
private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -76,35 +76,35 @@ public class ChooseContactActivity extends XmppActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_choose_contact);
|
setContentView(R.layout.activity_choose_contact);
|
||||||
mListView = (ListView) findViewById(R.id.choose_contact_list);
|
mListView = (ListView) findViewById(R.id.choose_contact_list);
|
||||||
mContactsAdapter = new ListItemAdapter(getApplicationContext(), contacts);
|
mContactsAdapter = new ListItemAdapter(getApplicationContext(),
|
||||||
|
contacts);
|
||||||
mListView.setAdapter(mContactsAdapter);
|
mListView.setAdapter(mContactsAdapter);
|
||||||
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
|
public void onItemClick(AdapterView<?> arg0, View arg1,
|
||||||
long arg3) {
|
int position, long arg3) {
|
||||||
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
|
imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
|
||||||
InputMethodManager.HIDE_IMPLICIT_ONLY);
|
InputMethodManager.HIDE_IMPLICIT_ONLY);
|
||||||
Intent request = getIntent();
|
Intent request = getIntent();
|
||||||
Intent data = new Intent();
|
Intent data = new Intent();
|
||||||
data.putExtra("contact",contacts.get(position).getJid());
|
data.putExtra("contact", contacts.get(position).getJid());
|
||||||
data.putExtra("account",request.getStringExtra("account"));
|
data.putExtra("account", request.getStringExtra("account"));
|
||||||
data.putExtra("conversation",request.getStringExtra("conversation"));
|
data.putExtra("conversation",
|
||||||
|
request.getStringExtra("conversation"));
|
||||||
setResult(RESULT_OK, data);
|
setResult(RESULT_OK, data);
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
getMenuInflater().inflate(R.menu.choose_contact, menu);
|
getMenuInflater().inflate(R.menu.choose_contact, menu);
|
||||||
|
@ -121,7 +121,7 @@ public class ChooseContactActivity extends XmppActivity {
|
||||||
void onBackendConnected() {
|
void onBackendConnected() {
|
||||||
filterContacts(null);
|
filterContacts(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void filterContacts(String needle) {
|
protected void filterContacts(String needle) {
|
||||||
this.contacts.clear();
|
this.contacts.clear();
|
||||||
for (Account account : xmppConnectionService.getAccounts()) {
|
for (Account account : xmppConnectionService.getAccounts()) {
|
||||||
|
|
|
@ -250,7 +250,8 @@ public class ConferenceDetailsActivity extends XmppActivity {
|
||||||
if (contact.showInRoster()) {
|
if (contact.showInRoster()) {
|
||||||
bm = contact.getImage(48, this);
|
bm = contact.getImage(48, this);
|
||||||
name.setText(contact.getDisplayName());
|
name.setText(contact.getDisplayName());
|
||||||
role.setText(user.getName() + " \u2022 " + getReadableRole(user.getRole()));
|
role.setText(user.getName() + " \u2022 "
|
||||||
|
+ getReadableRole(user.getRole()));
|
||||||
} else {
|
} else {
|
||||||
bm = UIHelper.getContactPicture(user.getName(), 48, this,
|
bm = UIHelper.getContactPicture(user.getName(), 48, this,
|
||||||
false);
|
false);
|
||||||
|
|
|
@ -111,7 +111,8 @@ public class ContactDetailsActivity extends XmppActivity {
|
||||||
public void onCheckedChanged(CompoundButton buttonView,
|
public void onCheckedChanged(CompoundButton buttonView,
|
||||||
boolean isChecked) {
|
boolean isChecked) {
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
if (contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
|
if (contact
|
||||||
|
.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
|
||||||
xmppConnectionService.sendPresencePacket(contact
|
xmppConnectionService.sendPresencePacket(contact
|
||||||
.getAccount(),
|
.getAccount(),
|
||||||
xmppConnectionService.getPresenceGenerator()
|
xmppConnectionService.getPresenceGenerator()
|
||||||
|
@ -146,7 +147,7 @@ public class ContactDetailsActivity extends XmppActivity {
|
||||||
};
|
};
|
||||||
|
|
||||||
private OnAccountUpdate accountUpdate = new OnAccountUpdate() {
|
private OnAccountUpdate accountUpdate = new OnAccountUpdate() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAccountUpdate() {
|
public void onAccountUpdate() {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
|
@ -269,7 +270,7 @@ public class ContactDetailsActivity extends XmppActivity {
|
||||||
|
|
||||||
send.setOnCheckedChangeListener(this.mOnSendCheckedChange);
|
send.setOnCheckedChangeListener(this.mOnSendCheckedChange);
|
||||||
receive.setOnCheckedChangeListener(this.mOnReceiveCheckedChange);
|
receive.setOnCheckedChangeListener(this.mOnReceiveCheckedChange);
|
||||||
|
|
||||||
lastseen.setText(UIHelper.lastseen(getApplicationContext(),
|
lastseen.setText(UIHelper.lastseen(getApplicationContext(),
|
||||||
contact.lastseen.time));
|
contact.lastseen.time));
|
||||||
|
|
||||||
|
@ -363,7 +364,8 @@ public class ContactDetailsActivity extends XmppActivity {
|
||||||
@Override
|
@Override
|
||||||
public void onBackendConnected() {
|
public void onBackendConnected() {
|
||||||
xmppConnectionService.setOnRosterUpdateListener(this.rosterUpdate);
|
xmppConnectionService.setOnRosterUpdateListener(this.rosterUpdate);
|
||||||
xmppConnectionService.setOnAccountListChangedListener(this.accountUpdate );
|
xmppConnectionService
|
||||||
|
.setOnAccountListChangedListener(this.accountUpdate);
|
||||||
if ((accountJid != null) && (contactJid != null)) {
|
if ((accountJid != null) && (contactJid != null)) {
|
||||||
Account account = xmppConnectionService
|
Account account = xmppConnectionService
|
||||||
.findAccountByJid(accountJid);
|
.findAccountByJid(accountJid);
|
||||||
|
|
|
@ -35,7 +35,6 @@ import android.graphics.drawable.Drawable;
|
||||||
import android.support.v4.widget.SlidingPaneLayout;
|
import android.support.v4.widget.SlidingPaneLayout;
|
||||||
import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener;
|
import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
@ -81,7 +80,7 @@ public class ConversationActivity extends XmppActivity {
|
||||||
private ArrayAdapter<Conversation> listAdapter;
|
private ArrayAdapter<Conversation> listAdapter;
|
||||||
|
|
||||||
private OnConversationUpdate onConvChanged = new OnConversationUpdate() {
|
private OnConversationUpdate onConvChanged = new OnConversationUpdate() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConversationUpdate() {
|
public void onConversationUpdate() {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
|
@ -111,7 +110,7 @@ public class ConversationActivity extends XmppActivity {
|
||||||
protected ConversationActivity activity = this;
|
protected ConversationActivity activity = this;
|
||||||
private DisplayMetrics metrics;
|
private DisplayMetrics metrics;
|
||||||
private Toast prepareImageToast;
|
private Toast prepareImageToast;
|
||||||
|
|
||||||
private Uri pendingImageUri = null;
|
private Uri pendingImageUri = null;
|
||||||
|
|
||||||
public List<Conversation> getConversationList() {
|
public List<Conversation> getConversationList() {
|
||||||
|
@ -148,7 +147,7 @@ public class ConversationActivity extends XmppActivity {
|
||||||
setContentView(R.layout.fragment_conversations_overview);
|
setContentView(R.layout.fragment_conversations_overview);
|
||||||
|
|
||||||
listView = (ListView) findViewById(R.id.list);
|
listView = (ListView) findViewById(R.id.list);
|
||||||
|
|
||||||
getActionBar().setDisplayHomeAsUpEnabled(false);
|
getActionBar().setDisplayHomeAsUpEnabled(false);
|
||||||
getActionBar().setHomeButtonEnabled(false);
|
getActionBar().setHomeButtonEnabled(false);
|
||||||
|
|
||||||
|
@ -179,7 +178,7 @@ public class ConversationActivity extends XmppActivity {
|
||||||
public void onPanelOpened(View arg0) {
|
public void onPanelOpened(View arg0) {
|
||||||
paneShouldBeOpen = true;
|
paneShouldBeOpen = true;
|
||||||
ActionBar ab = getActionBar();
|
ActionBar ab = getActionBar();
|
||||||
if (ab!=null) {
|
if (ab != null) {
|
||||||
ab.setDisplayHomeAsUpEnabled(false);
|
ab.setDisplayHomeAsUpEnabled(false);
|
||||||
ab.setHomeButtonEnabled(false);
|
ab.setHomeButtonEnabled(false);
|
||||||
ab.setTitle(R.string.app_name);
|
ab.setTitle(R.string.app_name);
|
||||||
|
@ -194,11 +193,11 @@ public class ConversationActivity extends XmppActivity {
|
||||||
if ((conversationList.size() > 0)
|
if ((conversationList.size() > 0)
|
||||||
&& (getSelectedConversation() != null)) {
|
&& (getSelectedConversation() != null)) {
|
||||||
ActionBar ab = getActionBar();
|
ActionBar ab = getActionBar();
|
||||||
if (ab!=null) {
|
if (ab != null) {
|
||||||
ab.setDisplayHomeAsUpEnabled(true);
|
ab.setDisplayHomeAsUpEnabled(true);
|
||||||
ab.setHomeButtonEnabled(true);
|
ab.setHomeButtonEnabled(true);
|
||||||
ab.setTitle(
|
ab.setTitle(getSelectedConversation().getName(
|
||||||
getSelectedConversation().getName(useSubject));
|
useSubject));
|
||||||
}
|
}
|
||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
if (!getSelectedConversation().isRead()) {
|
if (!getSelectedConversation().isRead()) {
|
||||||
|
@ -232,7 +231,8 @@ public class ConversationActivity extends XmppActivity {
|
||||||
MenuItem menuClearHistory = (MenuItem) menu
|
MenuItem menuClearHistory = (MenuItem) menu
|
||||||
.findItem(R.id.action_clear_history);
|
.findItem(R.id.action_clear_history);
|
||||||
MenuItem menuAdd = (MenuItem) menu.findItem(R.id.action_add);
|
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);
|
||||||
|
|
||||||
if ((spl.isOpen() && (spl.isSlideable()))) {
|
if ((spl.isOpen() && (spl.isSlideable()))) {
|
||||||
menuArchive.setVisible(false);
|
menuArchive.setVisible(false);
|
||||||
|
@ -267,11 +267,12 @@ public class ConversationActivity extends XmppActivity {
|
||||||
@Override
|
@Override
|
||||||
public void onPresenceSelected() {
|
public void onPresenceSelected() {
|
||||||
if (attachmentChoice == ATTACHMENT_CHOICE_TAKE_PHOTO) {
|
if (attachmentChoice == ATTACHMENT_CHOICE_TAKE_PHOTO) {
|
||||||
pendingImageUri = xmppConnectionService.getFileBackend().getTakePhotoUri();
|
pendingImageUri = xmppConnectionService.getFileBackend()
|
||||||
Log.d("xmppService",pendingImageUri.toString());
|
.getTakePhotoUri();
|
||||||
Intent takePictureIntent = new Intent(
|
Intent takePictureIntent = new Intent(
|
||||||
MediaStore.ACTION_IMAGE_CAPTURE);
|
MediaStore.ACTION_IMAGE_CAPTURE);
|
||||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,pendingImageUri);
|
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
|
||||||
|
pendingImageUri);
|
||||||
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
|
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
|
||||||
startActivityForResult(takePictureIntent,
|
startActivityForResult(takePictureIntent,
|
||||||
REQUEST_IMAGE_CAPTURE);
|
REQUEST_IMAGE_CAPTURE);
|
||||||
|
@ -353,7 +354,7 @@ public class ConversationActivity extends XmppActivity {
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_attach_file:
|
case R.id.action_attach_file:
|
||||||
View menuAttachFile = findViewById(R.id.action_attach_file);
|
View menuAttachFile = findViewById(R.id.action_attach_file);
|
||||||
if (menuAttachFile==null) {
|
if (menuAttachFile == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
PopupMenu attachFilePopup = new PopupMenu(this, menuAttachFile);
|
PopupMenu attachFilePopup = new PopupMenu(this, menuAttachFile);
|
||||||
|
@ -405,7 +406,7 @@ public class ConversationActivity extends XmppActivity {
|
||||||
case R.id.action_security:
|
case R.id.action_security:
|
||||||
final Conversation conversation = getSelectedConversation();
|
final Conversation conversation = getSelectedConversation();
|
||||||
View menuItemView = findViewById(R.id.action_security);
|
View menuItemView = findViewById(R.id.action_security);
|
||||||
if (menuItemView==null) {
|
if (menuItemView == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
PopupMenu popup = new PopupMenu(this, menuItemView);
|
PopupMenu popup = new PopupMenu(this, menuItemView);
|
||||||
|
@ -527,11 +528,11 @@ public class ConversationActivity extends XmppActivity {
|
||||||
ConversationFragment selectedFragment = new ConversationFragment();
|
ConversationFragment selectedFragment = new ConversationFragment();
|
||||||
if (!isFinishing()) {
|
if (!isFinishing()) {
|
||||||
|
|
||||||
FragmentTransaction transaction = getFragmentManager()
|
FragmentTransaction transaction = getFragmentManager()
|
||||||
.beginTransaction();
|
.beginTransaction();
|
||||||
transaction.replace(R.id.selected_conversation, selectedFragment,
|
transaction.replace(R.id.selected_conversation, selectedFragment,
|
||||||
"conversation");
|
"conversation");
|
||||||
|
|
||||||
transaction.commitAllowingStateLoss();
|
transaction.commitAllowingStateLoss();
|
||||||
}
|
}
|
||||||
return selectedFragment;
|
return selectedFragment;
|
||||||
|
@ -553,7 +554,8 @@ public class ConversationActivity extends XmppActivity {
|
||||||
if (xmppConnectionServiceBound) {
|
if (xmppConnectionServiceBound) {
|
||||||
if ((Intent.ACTION_VIEW.equals(intent.getAction()) && (VIEW_CONVERSATION
|
if ((Intent.ACTION_VIEW.equals(intent.getAction()) && (VIEW_CONVERSATION
|
||||||
.equals(intent.getType())))) {
|
.equals(intent.getType())))) {
|
||||||
String convToView = (String) intent.getExtras().get(CONVERSATION);
|
String convToView = (String) intent.getExtras().get(
|
||||||
|
CONVERSATION);
|
||||||
updateConversationList();
|
updateConversationList();
|
||||||
for (int i = 0; i < conversationList.size(); ++i) {
|
for (int i = 0; i < conversationList.size(); ++i) {
|
||||||
if (conversationList.get(i).getUuid().equals(convToView)) {
|
if (conversationList.get(i).getUuid().equals(convToView)) {
|
||||||
|
@ -600,9 +602,10 @@ public class ConversationActivity extends XmppActivity {
|
||||||
if (conversationList.size() == 0) {
|
if (conversationList.size() == 0) {
|
||||||
updateConversationList();
|
updateConversationList();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getSelectedConversation()!=null && pendingImageUri !=null) {
|
if (getSelectedConversation() != null && pendingImageUri != null) {
|
||||||
attachImageToConversation(getSelectedConversation(), pendingImageUri);
|
attachImageToConversation(getSelectedConversation(),
|
||||||
|
pendingImageUri);
|
||||||
pendingImageUri = null;
|
pendingImageUri = null;
|
||||||
} else {
|
} else {
|
||||||
pendingImageUri = null;
|
pendingImageUri = null;
|
||||||
|
@ -670,7 +673,8 @@ public class ConversationActivity extends XmppActivity {
|
||||||
} else if (requestCode == REQUEST_ATTACH_FILE_DIALOG) {
|
} else if (requestCode == REQUEST_ATTACH_FILE_DIALOG) {
|
||||||
pendingImageUri = data.getData();
|
pendingImageUri = data.getData();
|
||||||
if (xmppConnectionServiceBound) {
|
if (xmppConnectionServiceBound) {
|
||||||
attachImageToConversation(getSelectedConversation(),pendingImageUri);
|
attachImageToConversation(getSelectedConversation(),
|
||||||
|
pendingImageUri);
|
||||||
pendingImageUri = null;
|
pendingImageUri = null;
|
||||||
}
|
}
|
||||||
} else if (requestCode == REQUEST_SEND_PGP_IMAGE) {
|
} else if (requestCode == REQUEST_SEND_PGP_IMAGE) {
|
||||||
|
@ -686,10 +690,12 @@ public class ConversationActivity extends XmppActivity {
|
||||||
// encryptTextMessage();
|
// encryptTextMessage();
|
||||||
} else if (requestCode == REQUEST_IMAGE_CAPTURE) {
|
} else if (requestCode == REQUEST_IMAGE_CAPTURE) {
|
||||||
if (xmppConnectionServiceBound) {
|
if (xmppConnectionServiceBound) {
|
||||||
attachImageToConversation(getSelectedConversation(), pendingImageUri);
|
attachImageToConversation(getSelectedConversation(),
|
||||||
|
pendingImageUri);
|
||||||
pendingImageUri = null;
|
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);
|
intent.setData(pendingImageUri);
|
||||||
sendBroadcast(intent);
|
sendBroadcast(intent);
|
||||||
} else if (requestCode == REQUEST_RECORD_AUDIO) {
|
} else if (requestCode == REQUEST_RECORD_AUDIO) {
|
||||||
|
@ -700,7 +706,7 @@ public class ConversationActivity extends XmppActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void attachAudioToConversation(Conversation conversation, Uri uri) {
|
private void attachAudioToConversation(Conversation conversation, Uri uri) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void attachImageToConversation(Conversation conversation, Uri uri) {
|
private void attachImageToConversation(Conversation conversation, Uri uri) {
|
||||||
|
@ -744,7 +750,8 @@ public class ConversationActivity extends XmppActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateConversationList() {
|
public void updateConversationList() {
|
||||||
xmppConnectionService.populateWithOrderedConversations(conversationList);
|
xmppConnectionService
|
||||||
|
.populateWithOrderedConversations(conversationList);
|
||||||
listView.invalidateViews();
|
listView.invalidateViews();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,7 +768,8 @@ public class ConversationActivity extends XmppActivity {
|
||||||
try {
|
try {
|
||||||
this.startIntentSenderForResult(pi.getIntentSender(), requestCode,
|
this.startIntentSenderForResult(pi.getIntentSender(), requestCode,
|
||||||
null, 0, 0, 0);
|
null, 0, 0, 0);
|
||||||
} catch (SendIntentException e1) {}
|
} catch (SendIntentException e1) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> {
|
class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> {
|
||||||
|
|
|
@ -201,7 +201,8 @@ public class EditAccountActivity extends XmppActivity {
|
||||||
this.mSaveButton.setEnabled(true);
|
this.mSaveButton.setEnabled(true);
|
||||||
this.mSaveButton.setTextColor(getPrimaryTextColor());
|
this.mSaveButton.setTextColor(getPrimaryTextColor());
|
||||||
if (jidToEdit != null) {
|
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);
|
this.mSaveButton.setText(R.string.save);
|
||||||
} else {
|
} else {
|
||||||
this.mSaveButton.setText(R.string.connect);
|
this.mSaveButton.setText(R.string.connect);
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class PublishProfilePictureActivity extends XmppActivity {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (mInitialAccountSetup) {
|
if (mInitialAccountSetup) {
|
||||||
startActivity(new Intent(getApplicationContext(),
|
startActivity(new Intent(getApplicationContext(),
|
||||||
StartConversationActivity.class));
|
StartConversationActivity.class));
|
||||||
}
|
}
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ public class PublishProfilePictureActivity extends XmppActivity {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (mInitialAccountSetup) {
|
if (mInitialAccountSetup) {
|
||||||
startActivity(new Intent(getApplicationContext(),
|
startActivity(new Intent(getApplicationContext(),
|
||||||
StartConversationActivity.class));
|
StartConversationActivity.class));
|
||||||
}
|
}
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ public class SettingsActivity extends XmppActivity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void onBackendConnected() {
|
void onBackendConnected() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -340,7 +340,7 @@ public class StartConversationActivity extends XmppActivity {
|
||||||
String contactJid = jid.getText().toString();
|
String contactJid = jid.getText().toString();
|
||||||
Account account = xmppConnectionService
|
Account account = xmppConnectionService
|
||||||
.findAccountByJid(accountJid);
|
.findAccountByJid(accountJid);
|
||||||
if (account==null) {
|
if (account == null) {
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import android.app.PendingIntent;
|
||||||
|
|
||||||
public interface UiCallback<T> {
|
public interface UiCallback<T> {
|
||||||
public void success(T object);
|
public void success(T object);
|
||||||
|
|
||||||
public void error(int errorCode, T object);
|
public void error(int errorCode, T object);
|
||||||
|
|
||||||
public void userInputRequried(PendingIntent pi, T object);
|
public void userInputRequried(PendingIntent pi, T object);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package eu.siacs.conversations.ui;
|
package eu.siacs.conversations.ui;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.entities.Contact;
|
import eu.siacs.conversations.entities.Contact;
|
||||||
|
@ -34,8 +35,6 @@ public abstract class XmppActivity extends Activity {
|
||||||
protected static final int REQUEST_ANNOUNCE_PGP = 0x0101;
|
protected static final int REQUEST_ANNOUNCE_PGP = 0x0101;
|
||||||
protected static final int REQUEST_INVITE_TO_CONVERSATION = 0x0102;
|
protected static final int REQUEST_INVITE_TO_CONVERSATION = 0x0102;
|
||||||
|
|
||||||
protected final static String LOGTAG = "xmppService";
|
|
||||||
|
|
||||||
public XmppConnectionService xmppConnectionService;
|
public XmppConnectionService xmppConnectionService;
|
||||||
public boolean xmppConnectionServiceBound = false;
|
public boolean xmppConnectionServiceBound = false;
|
||||||
protected boolean handledViewIntent = false;
|
protected boolean handledViewIntent = false;
|
||||||
|
@ -370,7 +369,7 @@ public abstract class XmppActivity extends Activity {
|
||||||
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
||||||
xmppConnectionService.invite(conversation, contactJid);
|
xmppConnectionService.invite(conversation, contactJid);
|
||||||
}
|
}
|
||||||
Log.d("xmppService", "inviting " + contactJid + " to "
|
Log.d(Config.LOGTAG, "inviting " + contactJid + " to "
|
||||||
+ conversation.getName(true));
|
+ conversation.getName(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
public class AccountAdapter extends ArrayAdapter<Account> {
|
public class AccountAdapter extends ArrayAdapter<Account> {
|
||||||
|
|
||||||
private XmppActivity activity;
|
private XmppActivity activity;
|
||||||
|
|
||||||
public AccountAdapter(XmppActivity activity, List<Account> objects) {
|
public AccountAdapter(XmppActivity activity, List<Account> objects) {
|
||||||
super(activity, 0, objects);
|
super(activity, 0, objects);
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
|
@ -34,7 +34,7 @@ public class AccountAdapter extends ArrayAdapter<Account> {
|
||||||
jid.setText(account.getJid());
|
jid.setText(account.getJid());
|
||||||
TextView statusView = (TextView) view.findViewById(R.id.account_status);
|
TextView statusView = (TextView) view.findViewById(R.id.account_status);
|
||||||
ImageView imageView = (ImageView) view.findViewById(R.id.account_image);
|
ImageView imageView = (ImageView) view.findViewById(R.id.account_image);
|
||||||
imageView.setImageBitmap(account.getImage(activity,48));
|
imageView.setImageBitmap(account.getImage(activity, 48));
|
||||||
switch (account.getStatus()) {
|
switch (account.getStatus()) {
|
||||||
case Account.STATUS_DISABLED:
|
case Account.STATUS_DISABLED:
|
||||||
statusView.setText(getContext().getString(
|
statusView.setText(getContext().getString(
|
||||||
|
|
|
@ -19,7 +19,8 @@ public class KnownHostsAdapter extends ArrayAdapter<String> {
|
||||||
final String[] split = constraint.toString().split("@");
|
final String[] split = constraint.toString().split("@");
|
||||||
if (split.length == 1) {
|
if (split.length == 1) {
|
||||||
for (String domain : domains) {
|
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) {
|
} else if (split.length == 2) {
|
||||||
for (String domain : domains) {
|
for (String domain : domains) {
|
||||||
|
@ -27,7 +28,8 @@ public class KnownHostsAdapter extends ArrayAdapter<String> {
|
||||||
suggestions.clear();
|
suggestions.clear();
|
||||||
break;
|
break;
|
||||||
} else if (domain.contains(split[1])) {
|
} else if (domain.contains(split[1])) {
|
||||||
suggestions.add(split[0].toLowerCase(Locale.getDefault()) + "@" + domain);
|
suggestions.add(split[0].toLowerCase(Locale
|
||||||
|
.getDefault()) + "@" + domain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -14,7 +14,6 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.text.Html;
|
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.style.ForegroundColorSpan;
|
import android.text.style.ForegroundColorSpan;
|
||||||
|
@ -68,8 +67,9 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||||
public void setOnContactPictureClicked(OnContactPictureClicked listener) {
|
public void setOnContactPictureClicked(OnContactPictureClicked listener) {
|
||||||
this.mOnContactPictureClickedListener = listener;
|
this.mOnContactPictureClickedListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOnContactPictureLongClicked(OnContactPictureLongClicked listener) {
|
public void setOnContactPictureLongClicked(
|
||||||
|
OnContactPictureLongClicked listener) {
|
||||||
this.mOnContactPictureLongClickedListener = listener;
|
this.mOnContactPictureLongClickedListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +219,8 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||||
} else {
|
} else {
|
||||||
String privateMarker;
|
String privateMarker;
|
||||||
if (message.getStatus() <= Message.STATUS_RECEIVED) {
|
if (message.getStatus() <= Message.STATUS_RECEIVED) {
|
||||||
privateMarker = activity.getString(R.string.private_message);
|
privateMarker = activity
|
||||||
|
.getString(R.string.private_message);
|
||||||
} else {
|
} else {
|
||||||
String to;
|
String to;
|
||||||
if (message.getPresence() != null) {
|
if (message.getPresence() != null) {
|
||||||
|
@ -227,11 +228,18 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||||
} else {
|
} else {
|
||||||
to = message.getCounterpart();
|
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());
|
SpannableString span = new SpannableString(privateMarker + " "
|
||||||
span.setSpan(new ForegroundColorSpan(activity.getSecondaryTextColor()), 0, privateMarker.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
+ message.getBody());
|
||||||
span.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, privateMarker.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
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);
|
viewHolder.messageBody.setText(span);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -401,10 +409,11 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||||
contact, getContext()));
|
contact, getContext()));
|
||||||
} else {
|
} else {
|
||||||
String name = item.getPresence();
|
String name = item.getPresence();
|
||||||
if (name==null) {
|
if (name == null) {
|
||||||
name = item.getCounterpart();
|
name = item.getCounterpart();
|
||||||
}
|
}
|
||||||
viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(name, getContext()));
|
viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(
|
||||||
|
name, getContext()));
|
||||||
}
|
}
|
||||||
viewHolder.contact_picture
|
viewHolder.contact_picture
|
||||||
.setOnClickListener(new OnClickListener() {
|
.setOnClickListener(new OnClickListener() {
|
||||||
|
@ -419,18 +428,20 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
viewHolder.contact_picture.setOnLongClickListener(new OnLongClickListener() {
|
viewHolder.contact_picture
|
||||||
|
.setOnLongClickListener(new OnLongClickListener() {
|
||||||
@Override
|
|
||||||
public boolean onLongClick(View v) {
|
@Override
|
||||||
if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) {
|
public boolean onLongClick(View v) {
|
||||||
MessageAdapter.this.mOnContactPictureLongClickedListener.onContactPictureLongClicked(item);
|
if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) {
|
||||||
return true;
|
MessageAdapter.this.mOnContactPictureLongClickedListener
|
||||||
} else {
|
.onContactPictureLongClicked(item);
|
||||||
return false;
|
return true;
|
||||||
}
|
} else {
|
||||||
}
|
return false;
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,7 +540,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||||
public interface OnContactPictureClicked {
|
public interface OnContactPictureClicked {
|
||||||
public void onContactPictureClicked(Message message);
|
public void onContactPictureClicked(Message message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface OnContactPictureLongClicked {
|
public interface OnContactPictureLongClicked {
|
||||||
public void onContactPictureLongClicked(Message message);
|
public void onContactPictureLongClicked(Message message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import eu.siacs.conversations.entities.Account;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
|
|
||||||
public class CryptoHelper {
|
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[] hexArray = "0123456789abcdef".toCharArray();
|
||||||
final protected static char[] vowels = "aeiou".toCharArray();
|
final protected static char[] vowels = "aeiou".toCharArray();
|
||||||
final protected static char[] consonants = "bcdfghjklmnpqrstvwxyz"
|
final protected static char[] consonants = "bcdfghjklmnpqrstvwxyz"
|
||||||
|
@ -26,7 +26,7 @@ public class CryptoHelper {
|
||||||
}
|
}
|
||||||
return new String(hexChars);
|
return new String(hexChars);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] hexToBytes(String hexString) {
|
public static byte[] hexToBytes(String hexString) {
|
||||||
byte[] array = new BigInteger(hexString, 16).toByteArray();
|
byte[] array = new BigInteger(hexString, 16).toByteArray();
|
||||||
if (array[0] == 0) {
|
if (array[0] == 0) {
|
||||||
|
@ -42,13 +42,14 @@ public class CryptoHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] concatenateByteArrays(byte[] a, byte[] b) {
|
private static byte[] concatenateByteArrays(byte[] a, byte[] b) {
|
||||||
byte[] result = new byte[a.length + b.length];
|
byte[] result = new byte[a.length + b.length];
|
||||||
System.arraycopy(a, 0, result, 0, a.length);
|
System.arraycopy(a, 0, result, 0, a.length);
|
||||||
System.arraycopy(b, 0, result, a.length, b.length);
|
System.arraycopy(b, 0, result, a.length, b.length);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String saslDigestMd5(Account account, String challenge, SecureRandom random) {
|
public static String saslDigestMd5(Account account, String challenge,
|
||||||
|
SecureRandom random) {
|
||||||
try {
|
try {
|
||||||
String[] challengeParts = new String(Base64.decode(challenge,
|
String[] challengeParts = new String(Base64.decode(challenge,
|
||||||
Base64.DEFAULT)).split(",");
|
Base64.DEFAULT)).split(",");
|
||||||
|
@ -61,28 +62,29 @@ public class CryptoHelper {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String digestUri = "xmpp/"+account.getServer();
|
String digestUri = "xmpp/" + account.getServer();
|
||||||
String nonceCount = "00000001";
|
String nonceCount = "00000001";
|
||||||
String x = account.getUsername() + ":" + account.getServer() + ":"
|
String x = account.getUsername() + ":" + account.getServer() + ":"
|
||||||
+ account.getPassword();
|
+ account.getPassword();
|
||||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||||
byte[] y = md
|
byte[] y = md.digest(x.getBytes(Charset.defaultCharset()));
|
||||||
.digest(x.getBytes(Charset.defaultCharset()));
|
|
||||||
String cNonce = new BigInteger(100, random).toString(32);
|
String cNonce = new BigInteger(100, random).toString(32);
|
||||||
byte[] a1 = concatenateByteArrays(y,(":"+nonce+":"+cNonce).getBytes(Charset.defaultCharset()));
|
byte[] a1 = concatenateByteArrays(y,
|
||||||
String a2 = "AUTHENTICATE:"+digestUri;
|
(":" + nonce + ":" + cNonce).getBytes(Charset
|
||||||
|
.defaultCharset()));
|
||||||
|
String a2 = "AUTHENTICATE:" + digestUri;
|
||||||
String ha1 = bytesToHex(md.digest(a1));
|
String ha1 = bytesToHex(md.digest(a1));
|
||||||
String ha2 = bytesToHex(md.digest(a2.getBytes(Charset
|
String ha2 = bytesToHex(md.digest(a2.getBytes(Charset
|
||||||
.defaultCharset())));
|
.defaultCharset())));
|
||||||
String kd = ha1 + ":" + nonce + ":"+nonceCount+":" + cNonce + ":auth:"
|
String kd = ha1 + ":" + nonce + ":" + nonceCount + ":" + cNonce
|
||||||
+ ha2;
|
+ ":auth:" + ha2;
|
||||||
String response = bytesToHex(md.digest(kd.getBytes(Charset
|
String response = bytesToHex(md.digest(kd.getBytes(Charset
|
||||||
.defaultCharset())));
|
.defaultCharset())));
|
||||||
String saslString = "username=\"" + account.getUsername()
|
String saslString = "username=\"" + account.getUsername()
|
||||||
+ "\",realm=\"" + account.getServer() + "\",nonce=\""
|
+ "\",realm=\"" + account.getServer() + "\",nonce=\""
|
||||||
+ nonce + "\",cnonce=\"" + cNonce
|
+ nonce + "\",cnonce=\"" + cNonce + "\",nc=" + nonceCount
|
||||||
+ "\",nc="+nonceCount+",qop=auth,digest-uri=\""+digestUri+"\",response=" + response
|
+ ",qop=auth,digest-uri=\"" + digestUri + "\",response="
|
||||||
+ ",charset=utf-8";
|
+ response + ",charset=utf-8";
|
||||||
return Base64.encodeToString(
|
return Base64.encodeToString(
|
||||||
saslString.getBytes(Charset.defaultCharset()),
|
saslString.getBytes(Charset.defaultCharset()),
|
||||||
Base64.NO_WRAP);
|
Base64.NO_WRAP);
|
||||||
|
|
|
@ -10,6 +10,7 @@ import de.measite.minidns.record.A;
|
||||||
import de.measite.minidns.record.AAAA;
|
import de.measite.minidns.record.AAAA;
|
||||||
import de.measite.minidns.record.Data;
|
import de.measite.minidns.record.Data;
|
||||||
import de.measite.minidns.util.NameUtil;
|
import de.measite.minidns.util.NameUtil;
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
@ -47,14 +48,11 @@ public class DNSHelper {
|
||||||
Bundle namePort = new Bundle();
|
Bundle namePort = new Bundle();
|
||||||
try {
|
try {
|
||||||
String qname = "_xmpp-client._tcp." + host;
|
String qname = "_xmpp-client._tcp." + host;
|
||||||
Log.d("xmppService", "using dns server: " + dnsServer.getHostAddress()
|
Log.d(Config.LOGTAG,
|
||||||
+ " to look up " + host);
|
"using dns server: " + dnsServer.getHostAddress()
|
||||||
DNSMessage message =
|
+ " to look up " + host);
|
||||||
client.query(
|
DNSMessage message = client.query(qname, TYPE.SRV, CLASS.IN,
|
||||||
qname,
|
dnsServer.getHostAddress());
|
||||||
TYPE.SRV,
|
|
||||||
CLASS.IN,
|
|
||||||
dnsServer.getHostAddress());
|
|
||||||
|
|
||||||
// How should we handle priorities and weight?
|
// How should we handle priorities and weight?
|
||||||
// Wikipedia has a nice article about priorities vs. weights:
|
// 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
|
// a random order respecting the weight, and dump that priority by
|
||||||
// priority
|
// priority
|
||||||
|
|
||||||
TreeMap<Integer, ArrayList<SRV>> priorities =
|
TreeMap<Integer, ArrayList<SRV>> priorities = new TreeMap<Integer, ArrayList<SRV>>();
|
||||||
new TreeMap<Integer, ArrayList<SRV>>();
|
TreeMap<String, ArrayList<String>> ips4 = new TreeMap<String, ArrayList<String>>();
|
||||||
TreeMap<String, ArrayList<String>> ips4 =
|
TreeMap<String, ArrayList<String>> ips6 = new TreeMap<String, ArrayList<String>>();
|
||||||
new TreeMap<String, ArrayList<String>>();
|
|
||||||
TreeMap<String, ArrayList<String>> ips6 =
|
|
||||||
new TreeMap<String, ArrayList<String>>();
|
|
||||||
|
|
||||||
for (Record[] rrset : new Record[][]{ message.getAnswers(),
|
for (Record[] rrset : new Record[][] { message.getAnswers(),
|
||||||
message.getAdditionalResourceRecords()}) {
|
message.getAdditionalResourceRecords() }) {
|
||||||
for (Record rr : rrset) {
|
for (Record rr : rrset) {
|
||||||
Data d = rr.getPayload();
|
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;
|
SRV srv = (SRV) d;
|
||||||
if (!priorities.containsKey(srv.getPriority())) {
|
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);
|
priorities.get(srv.getPriority()).add(srv);
|
||||||
}
|
}
|
||||||
|
@ -100,8 +97,9 @@ public class DNSHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
Random rnd = new Random();
|
Random rnd = new Random();
|
||||||
ArrayList<SRV> result = new ArrayList<SRV>(priorities.size() * 2 + 1);
|
ArrayList<SRV> result = new ArrayList<SRV>(
|
||||||
for (ArrayList<SRV> s: priorities.values()) {
|
priorities.size() * 2 + 1);
|
||||||
|
for (ArrayList<SRV> s : priorities.values()) {
|
||||||
|
|
||||||
// trivial case
|
// trivial case
|
||||||
if (s.size() <= 1) {
|
if (s.size() <= 1) {
|
||||||
|
@ -110,18 +108,20 @@ public class DNSHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
long totalweight = 0l;
|
long totalweight = 0l;
|
||||||
for (SRV srv: s) {
|
for (SRV srv : s) {
|
||||||
totalweight += srv.getWeight();
|
totalweight += srv.getWeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
while (totalweight > 0l && s.size() > 0) {
|
while (totalweight > 0l && s.size() > 0) {
|
||||||
long p = (rnd.nextLong() & 0x7fffffffffffffffl) % totalweight;
|
long p = (rnd.nextLong() & 0x7fffffffffffffffl)
|
||||||
|
% totalweight;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (p > 0) {
|
while (p > 0) {
|
||||||
p -= s.get(i++).getPriority();
|
p -= s.get(i++).getPriority();
|
||||||
}
|
}
|
||||||
i--;
|
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);
|
SRV srv = s.remove(i);
|
||||||
totalweight -= srv.getWeight();
|
totalweight -= srv.getWeight();
|
||||||
result.add(srv);
|
result.add(srv);
|
||||||
|
@ -164,10 +164,10 @@ public class DNSHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (SocketTimeoutException e) {
|
} catch (SocketTimeoutException e) {
|
||||||
Log.d("xmppService", "timeout during dns");
|
Log.d(Config.LOGTAG, "timeout during dns");
|
||||||
namePort.putString("error", "timeout");
|
namePort.putString("error", "timeout");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d("xmppService","unhandled exception in sub project");
|
Log.d(Config.LOGTAG, "unhandled exception in sub project");
|
||||||
namePort.putString("error", "unhandled");
|
namePort.putString("error", "unhandled");
|
||||||
}
|
}
|
||||||
return namePort;
|
return namePort;
|
||||||
|
|
|
@ -11,22 +11,25 @@ import java.lang.Thread.UncaughtExceptionHandler;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
public class ExceptionHandler implements UncaughtExceptionHandler {
|
public class ExceptionHandler implements UncaughtExceptionHandler {
|
||||||
|
|
||||||
private UncaughtExceptionHandler defaultHandler;
|
private UncaughtExceptionHandler defaultHandler;
|
||||||
private Context context;
|
private Context context;
|
||||||
|
|
||||||
public ExceptionHandler(Context context) {
|
public ExceptionHandler(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
|
this.defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void uncaughtException(Thread thread, Throwable ex) {
|
public void uncaughtException(Thread thread, Throwable ex) {
|
||||||
Writer result = new StringWriter();
|
Writer result = new StringWriter();
|
||||||
PrintWriter printWriter = new PrintWriter(result);
|
PrintWriter printWriter = new PrintWriter(result);
|
||||||
ex.printStackTrace(printWriter);
|
ex.printStackTrace(printWriter);
|
||||||
String stacktrace = result.toString();
|
String stacktrace = result.toString();
|
||||||
printWriter.close();
|
printWriter.close();
|
||||||
try {
|
try {
|
||||||
OutputStream os = context.openFileOutput("stacktrace.txt",Context.MODE_PRIVATE);
|
OutputStream os = context.openFileOutput("stacktrace.txt",
|
||||||
|
Context.MODE_PRIVATE);
|
||||||
os.write(stacktrace.getBytes());
|
os.write(stacktrace.getBytes());
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
|
|
|
@ -7,6 +7,7 @@ import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.entities.Conversation;
|
import eu.siacs.conversations.entities.Conversation;
|
||||||
|
@ -26,77 +27,91 @@ import android.util.Log;
|
||||||
|
|
||||||
public class ExceptionHelper {
|
public class ExceptionHelper {
|
||||||
public static void init(Context context) {
|
public static void init(Context context) {
|
||||||
if(!(Thread.getDefaultUncaughtExceptionHandler() instanceof ExceptionHandler)) {
|
if (!(Thread.getDefaultUncaughtExceptionHandler() instanceof ExceptionHandler)) {
|
||||||
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(context));
|
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(
|
||||||
|
context));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void checkForCrash(Context context, final XmppConnectionService service) {
|
public static void checkForCrash(Context context,
|
||||||
|
final XmppConnectionService service) {
|
||||||
try {
|
try {
|
||||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
final SharedPreferences preferences = PreferenceManager
|
||||||
boolean neverSend = preferences.getBoolean("never_send",false);
|
.getDefaultSharedPreferences(context);
|
||||||
|
boolean neverSend = preferences.getBoolean("never_send", false);
|
||||||
if (neverSend) {
|
if (neverSend) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<Account> accounts = service.getAccounts();
|
List<Account> accounts = service.getAccounts();
|
||||||
Account account = null;
|
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)) {
|
if (!accounts.get(i).isOptionSet(Account.OPTION_DISABLED)) {
|
||||||
account = accounts.get(i);
|
account = accounts.get(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (account==null) {
|
if (account == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Account finalAccount = account;
|
final Account finalAccount = account;
|
||||||
FileInputStream file = context.openFileInput("stacktrace.txt");
|
FileInputStream file = context.openFileInput("stacktrace.txt");
|
||||||
InputStreamReader inputStreamReader = new InputStreamReader(
|
InputStreamReader inputStreamReader = new InputStreamReader(file);
|
||||||
file);
|
BufferedReader stacktrace = new BufferedReader(inputStreamReader);
|
||||||
BufferedReader stacktrace = new BufferedReader(
|
final StringBuilder report = new StringBuilder();
|
||||||
inputStreamReader);
|
PackageManager pm = context.getPackageManager();
|
||||||
final StringBuilder report = new StringBuilder();
|
PackageInfo packageInfo = null;
|
||||||
PackageManager pm = context.getPackageManager();
|
try {
|
||||||
PackageInfo packageInfo = null;
|
packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
|
||||||
try {
|
report.append("Version: " + packageInfo.versionName + '\n');
|
||||||
packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
|
report.append("Last Update: "
|
||||||
report.append("Version: "+packageInfo.versionName+'\n');
|
+ DateUtils.formatDateTime(context,
|
||||||
report.append("Last Update: "+DateUtils.formatDateTime(context, packageInfo.lastUpdateTime, DateUtils.FORMAT_SHOW_TIME|DateUtils.FORMAT_SHOW_DATE)+'\n');
|
packageInfo.lastUpdateTime,
|
||||||
} catch (NameNotFoundException e) {}
|
DateUtils.FORMAT_SHOW_TIME
|
||||||
String line;
|
| DateUtils.FORMAT_SHOW_DATE) + '\n');
|
||||||
while((line = stacktrace.readLine()) != null) {
|
} catch (NameNotFoundException e) {
|
||||||
report.append(line);
|
}
|
||||||
report.append('\n');
|
String line;
|
||||||
}
|
while ((line = stacktrace.readLine()) != null) {
|
||||||
file.close();
|
report.append(line);
|
||||||
context.deleteFile("stacktrace.txt");
|
report.append('\n');
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
context.deleteFile("stacktrace.txt");
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||||
builder.setTitle(context.getString(R.string.crash_report_title));
|
builder.setTitle(context.getString(R.string.crash_report_title));
|
||||||
builder.setMessage(context.getText(R.string.crash_report_message));
|
builder.setMessage(context.getText(R.string.crash_report_message));
|
||||||
builder.setPositiveButton(context.getText(R.string.send_now), new OnClickListener() {
|
builder.setPositiveButton(context.getText(R.string.send_now),
|
||||||
|
new OnClickListener() {
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
@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);
|
Log.d(Config.LOGTAG, "using account="
|
||||||
Message message = new Message(conversation, report.toString(), Message.ENCRYPTION_NONE);
|
+ finalAccount.getJid()
|
||||||
service.sendMessage(message);
|
+ " to send in stack trace");
|
||||||
}
|
Conversation conversation = service
|
||||||
});
|
.findOrCreateConversation(finalAccount,
|
||||||
builder.setNegativeButton(context.getText(R.string.send_never),new OnClickListener() {
|
"bugs@siacs.eu", false);
|
||||||
|
Message message = new Message(conversation, report
|
||||||
@Override
|
.toString(), Message.ENCRYPTION_NONE);
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
service.sendMessage(message);
|
||||||
preferences.edit().putBoolean("never_send", true).commit();
|
}
|
||||||
}
|
});
|
||||||
});
|
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();
|
builder.create().show();
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
return;
|
return;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,306 +21,307 @@ import java.security.Security;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fixes for the output of the default PRNG having low entropy.
|
* 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
|
* 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
|
* Cryptography Architecture primitives. A good place to invoke them is in the
|
||||||
* application's {@code onCreate}.
|
* application's {@code onCreate}.
|
||||||
*/
|
*/
|
||||||
public final class PRNGFixes {
|
public final class PRNGFixes {
|
||||||
|
|
||||||
private static final int VERSION_CODE_JELLY_BEAN = 16;
|
private static final int VERSION_CODE_JELLY_BEAN = 16;
|
||||||
private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18;
|
private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18;
|
||||||
private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL =
|
private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL = getBuildFingerprintAndDeviceSerial();
|
||||||
getBuildFingerprintAndDeviceSerial();
|
|
||||||
|
|
||||||
/** Hidden constructor to prevent instantiation. */
|
/** Hidden constructor to prevent instantiation. */
|
||||||
private PRNGFixes() {}
|
private PRNGFixes() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies all fixes.
|
* Applies all fixes.
|
||||||
*
|
*
|
||||||
* @throws SecurityException if a fix is needed but could not be applied.
|
* @throws SecurityException
|
||||||
*/
|
* if a fix is needed but could not be applied.
|
||||||
public static void apply() {
|
*/
|
||||||
applyOpenSSLFix();
|
public static void apply() {
|
||||||
installLinuxPRNGSecureRandom();
|
applyOpenSSLFix();
|
||||||
}
|
installLinuxPRNGSecureRandom();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the
|
* Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the
|
||||||
* fix is not needed.
|
* fix is not needed.
|
||||||
*
|
*
|
||||||
* @throws SecurityException if the fix is needed but could not be applied.
|
* @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)
|
private static void applyOpenSSLFix() throws SecurityException {
|
||||||
|| (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2)) {
|
if ((Build.VERSION.SDK_INT < VERSION_CODE_JELLY_BEAN)
|
||||||
// No need to apply the fix
|
|| (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2)) {
|
||||||
return;
|
// No need to apply the fix
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Mix in the device- and invocation-specific seed.
|
// Mix in the device- and invocation-specific seed.
|
||||||
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
||||||
.getMethod("RAND_seed", byte[].class)
|
.getMethod("RAND_seed", byte[].class)
|
||||||
.invoke(null, generateSeed());
|
.invoke(null, generateSeed());
|
||||||
|
|
||||||
// Mix output of Linux PRNG into OpenSSL's PRNG
|
// Mix output of Linux PRNG into OpenSSL's PRNG
|
||||||
int bytesRead = (Integer) Class.forName(
|
int bytesRead = (Integer) Class
|
||||||
"org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
.forName(
|
||||||
.getMethod("RAND_load_file", String.class, long.class)
|
"org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
||||||
.invoke(null, "/dev/urandom", 1024);
|
.getMethod("RAND_load_file", String.class, long.class)
|
||||||
if (bytesRead != 1024) {
|
.invoke(null, "/dev/urandom", 1024);
|
||||||
throw new IOException(
|
if (bytesRead != 1024) {
|
||||||
"Unexpected number of bytes read from Linux PRNG: "
|
throw new IOException(
|
||||||
+ bytesRead);
|
"Unexpected number of bytes read from Linux PRNG: "
|
||||||
}
|
+ bytesRead);
|
||||||
} catch (Exception e) {
|
}
|
||||||
throw new SecurityException("Failed to seed OpenSSL PRNG", e);
|
} catch (Exception e) {
|
||||||
}
|
throw new SecurityException("Failed to seed OpenSSL PRNG", e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs a Linux PRNG-backed {@code SecureRandom} implementation as the
|
* Installs a Linux PRNG-backed {@code SecureRandom} implementation as the
|
||||||
* default. Does nothing if the implementation is already the default or if
|
* default. Does nothing if the implementation is already the default or if
|
||||||
* there is not need to install the implementation.
|
* there is not need to install the implementation.
|
||||||
*
|
*
|
||||||
* @throws SecurityException if the fix is needed but could not be applied.
|
* @throws SecurityException
|
||||||
*/
|
* if the fix is needed but could not be applied.
|
||||||
private static void installLinuxPRNGSecureRandom()
|
*/
|
||||||
throws SecurityException {
|
private static void installLinuxPRNGSecureRandom() throws SecurityException {
|
||||||
if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) {
|
if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) {
|
||||||
// No need to apply the fix
|
// No need to apply the fix
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install a Linux PRNG-based SecureRandom implementation as the
|
// Install a Linux PRNG-based SecureRandom implementation as the
|
||||||
// default, if not yet installed.
|
// default, if not yet installed.
|
||||||
Provider[] secureRandomProviders =
|
Provider[] secureRandomProviders = Security
|
||||||
Security.getProviders("SecureRandom.SHA1PRNG");
|
.getProviders("SecureRandom.SHA1PRNG");
|
||||||
if ((secureRandomProviders == null)
|
if ((secureRandomProviders == null)
|
||||||
|| (secureRandomProviders.length < 1)
|
|| (secureRandomProviders.length < 1)
|
||||||
|| (!LinuxPRNGSecureRandomProvider.class.equals(
|
|| (!LinuxPRNGSecureRandomProvider.class
|
||||||
secureRandomProviders[0].getClass()))) {
|
.equals(secureRandomProviders[0].getClass()))) {
|
||||||
Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1);
|
Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assert that new SecureRandom() and
|
// Assert that new SecureRandom() and
|
||||||
// SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed
|
// SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed
|
||||||
// by the Linux PRNG-based SecureRandom implementation.
|
// by the Linux PRNG-based SecureRandom implementation.
|
||||||
SecureRandom rng1 = new SecureRandom();
|
SecureRandom rng1 = new SecureRandom();
|
||||||
if (!LinuxPRNGSecureRandomProvider.class.equals(
|
if (!LinuxPRNGSecureRandomProvider.class.equals(rng1.getProvider()
|
||||||
rng1.getProvider().getClass())) {
|
.getClass())) {
|
||||||
throw new SecurityException(
|
throw new SecurityException(
|
||||||
"new SecureRandom() backed by wrong Provider: "
|
"new SecureRandom() backed by wrong Provider: "
|
||||||
+ rng1.getProvider().getClass());
|
+ rng1.getProvider().getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
SecureRandom rng2;
|
SecureRandom rng2;
|
||||||
try {
|
try {
|
||||||
rng2 = SecureRandom.getInstance("SHA1PRNG");
|
rng2 = SecureRandom.getInstance("SHA1PRNG");
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
throw new SecurityException("SHA1PRNG not available", e);
|
throw new SecurityException("SHA1PRNG not available", e);
|
||||||
}
|
}
|
||||||
if (!LinuxPRNGSecureRandomProvider.class.equals(
|
if (!LinuxPRNGSecureRandomProvider.class.equals(rng2.getProvider()
|
||||||
rng2.getProvider().getClass())) {
|
.getClass())) {
|
||||||
throw new SecurityException(
|
throw new SecurityException(
|
||||||
"SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong"
|
"SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong"
|
||||||
+ " Provider: " + rng2.getProvider().getClass());
|
+ " Provider: " + rng2.getProvider().getClass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code Provider} of {@code SecureRandom} engines which pass through
|
* {@code Provider} of {@code SecureRandom} engines which pass through all
|
||||||
* all requests to the Linux PRNG.
|
* requests to the Linux PRNG.
|
||||||
*/
|
*/
|
||||||
private static class LinuxPRNGSecureRandomProvider extends Provider {
|
private static class LinuxPRNGSecureRandomProvider extends Provider {
|
||||||
|
|
||||||
public LinuxPRNGSecureRandomProvider() {
|
public LinuxPRNGSecureRandomProvider() {
|
||||||
super("LinuxPRNG",
|
super("LinuxPRNG", 1.0,
|
||||||
1.0,
|
"A Linux-specific random number provider that uses"
|
||||||
"A Linux-specific random number provider that uses"
|
+ " /dev/urandom");
|
||||||
+ " /dev/urandom");
|
// Although /dev/urandom is not a SHA-1 PRNG, some apps
|
||||||
// Although /dev/urandom is not a SHA-1 PRNG, some apps
|
// explicitly request a SHA1PRNG SecureRandom and we thus need to
|
||||||
// explicitly request a SHA1PRNG SecureRandom and we thus need to
|
// prevent them from getting the default implementation whose output
|
||||||
// prevent them from getting the default implementation whose output
|
// may have low entropy.
|
||||||
// may have low entropy.
|
put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom.class.getName());
|
||||||
put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom.class.getName());
|
put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
|
||||||
put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link SecureRandomSpi} which passes all requests to the Linux PRNG
|
* {@link SecureRandomSpi} which passes all requests to the Linux PRNG (
|
||||||
* ({@code /dev/urandom}).
|
* {@code /dev/urandom}).
|
||||||
*/
|
*/
|
||||||
public static class LinuxPRNGSecureRandom extends SecureRandomSpi {
|
public static class LinuxPRNGSecureRandom extends SecureRandomSpi {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed
|
* IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed
|
||||||
* are passed through to the Linux PRNG (/dev/urandom). Instances of
|
* are passed through to the Linux PRNG (/dev/urandom). Instances of
|
||||||
* this class seed themselves by mixing in the current time, PID, UID,
|
* this class seed themselves by mixing in the current time, PID, UID,
|
||||||
* build fingerprint, and hardware serial number (where available) into
|
* build fingerprint, and hardware serial number (where available) into
|
||||||
* Linux PRNG.
|
* Linux PRNG.
|
||||||
*
|
*
|
||||||
* Concurrency: Read requests to the underlying Linux PRNG are
|
* Concurrency: Read requests to the underlying Linux PRNG are
|
||||||
* serialized (on sLock) to ensure that multiple threads do not get
|
* serialized (on sLock) to ensure that multiple threads do not get
|
||||||
* duplicated PRNG output.
|
* 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
|
* Input stream for reading from Linux PRNG or {@code null} if not yet
|
||||||
* opened.
|
* opened.
|
||||||
*
|
*
|
||||||
* @GuardedBy("sLock")
|
* @GuardedBy("sLock")
|
||||||
*/
|
*/
|
||||||
private static DataInputStream sUrandomIn;
|
private static DataInputStream sUrandomIn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Output stream for writing to Linux PRNG or {@code null} if not yet
|
* Output stream for writing to Linux PRNG or {@code null} if not yet
|
||||||
* opened.
|
* opened.
|
||||||
*
|
*
|
||||||
* @GuardedBy("sLock")
|
* @GuardedBy("sLock")
|
||||||
*/
|
*/
|
||||||
private static OutputStream sUrandomOut;
|
private static OutputStream sUrandomOut;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this engine instance has been seeded. This is needed because
|
* Whether this engine instance has been seeded. This is needed because
|
||||||
* each instance needs to seed itself if the client does not explicitly
|
* each instance needs to seed itself if the client does not explicitly
|
||||||
* seed it.
|
* seed it.
|
||||||
*/
|
*/
|
||||||
private boolean mSeeded;
|
private boolean mSeeded;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void engineSetSeed(byte[] bytes) {
|
protected void engineSetSeed(byte[] bytes) {
|
||||||
try {
|
try {
|
||||||
OutputStream out;
|
OutputStream out;
|
||||||
synchronized (sLock) {
|
synchronized (sLock) {
|
||||||
out = getUrandomOutputStream();
|
out = getUrandomOutputStream();
|
||||||
}
|
}
|
||||||
out.write(bytes);
|
out.write(bytes);
|
||||||
out.flush();
|
out.flush();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// On a small fraction of devices /dev/urandom is not writable.
|
// On a small fraction of devices /dev/urandom is not writable.
|
||||||
// Log and ignore.
|
// Log and ignore.
|
||||||
Log.w(PRNGFixes.class.getSimpleName(),
|
Log.w(PRNGFixes.class.getSimpleName(),
|
||||||
"Failed to mix seed into " + URANDOM_FILE);
|
"Failed to mix seed into " + URANDOM_FILE);
|
||||||
} finally {
|
} finally {
|
||||||
mSeeded = true;
|
mSeeded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void engineNextBytes(byte[] bytes) {
|
protected void engineNextBytes(byte[] bytes) {
|
||||||
if (!mSeeded) {
|
if (!mSeeded) {
|
||||||
// Mix in the device- and invocation-specific seed.
|
// Mix in the device- and invocation-specific seed.
|
||||||
engineSetSeed(generateSeed());
|
engineSetSeed(generateSeed());
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DataInputStream in;
|
DataInputStream in;
|
||||||
synchronized (sLock) {
|
synchronized (sLock) {
|
||||||
in = getUrandomInputStream();
|
in = getUrandomInputStream();
|
||||||
}
|
}
|
||||||
synchronized (in) {
|
synchronized (in) {
|
||||||
in.readFully(bytes);
|
in.readFully(bytes);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new SecurityException(
|
throw new SecurityException("Failed to read from "
|
||||||
"Failed to read from " + URANDOM_FILE, e);
|
+ URANDOM_FILE, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] engineGenerateSeed(int size) {
|
protected byte[] engineGenerateSeed(int size) {
|
||||||
byte[] seed = new byte[size];
|
byte[] seed = new byte[size];
|
||||||
engineNextBytes(seed);
|
engineNextBytes(seed);
|
||||||
return seed;
|
return seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataInputStream getUrandomInputStream() {
|
private DataInputStream getUrandomInputStream() {
|
||||||
synchronized (sLock) {
|
synchronized (sLock) {
|
||||||
if (sUrandomIn == null) {
|
if (sUrandomIn == null) {
|
||||||
// NOTE: Consider inserting a BufferedInputStream between
|
// NOTE: Consider inserting a BufferedInputStream between
|
||||||
// DataInputStream and FileInputStream if you need higher
|
// DataInputStream and FileInputStream if you need higher
|
||||||
// PRNG output performance and can live with future PRNG
|
// PRNG output performance and can live with future PRNG
|
||||||
// output being pulled into this process prematurely.
|
// output being pulled into this process prematurely.
|
||||||
try {
|
try {
|
||||||
sUrandomIn = new DataInputStream(
|
sUrandomIn = new DataInputStream(new FileInputStream(
|
||||||
new FileInputStream(URANDOM_FILE));
|
URANDOM_FILE));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new SecurityException("Failed to open "
|
throw new SecurityException("Failed to open "
|
||||||
+ URANDOM_FILE + " for reading", e);
|
+ URANDOM_FILE + " for reading", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sUrandomIn;
|
return sUrandomIn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private OutputStream getUrandomOutputStream() throws IOException {
|
private OutputStream getUrandomOutputStream() throws IOException {
|
||||||
synchronized (sLock) {
|
synchronized (sLock) {
|
||||||
if (sUrandomOut == null) {
|
if (sUrandomOut == null) {
|
||||||
sUrandomOut = new FileOutputStream(URANDOM_FILE);
|
sUrandomOut = new FileOutputStream(URANDOM_FILE);
|
||||||
}
|
}
|
||||||
return sUrandomOut;
|
return sUrandomOut;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a device- and invocation-specific seed to be mixed into the
|
* Generates a device- and invocation-specific seed to be mixed into the
|
||||||
* Linux PRNG.
|
* Linux PRNG.
|
||||||
*/
|
*/
|
||||||
private static byte[] generateSeed() {
|
private static byte[] generateSeed() {
|
||||||
try {
|
try {
|
||||||
ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream();
|
ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream();
|
||||||
DataOutputStream seedBufferOut =
|
DataOutputStream seedBufferOut = new DataOutputStream(seedBuffer);
|
||||||
new DataOutputStream(seedBuffer);
|
seedBufferOut.writeLong(System.currentTimeMillis());
|
||||||
seedBufferOut.writeLong(System.currentTimeMillis());
|
seedBufferOut.writeLong(System.nanoTime());
|
||||||
seedBufferOut.writeLong(System.nanoTime());
|
seedBufferOut.writeInt(Process.myPid());
|
||||||
seedBufferOut.writeInt(Process.myPid());
|
seedBufferOut.writeInt(Process.myUid());
|
||||||
seedBufferOut.writeInt(Process.myUid());
|
seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL);
|
||||||
seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL);
|
seedBufferOut.close();
|
||||||
seedBufferOut.close();
|
return seedBuffer.toByteArray();
|
||||||
return seedBuffer.toByteArray();
|
} catch (IOException e) {
|
||||||
} catch (IOException e) {
|
throw new SecurityException("Failed to generate seed", e);
|
||||||
throw new SecurityException("Failed to generate seed", e);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the hardware serial number of this device.
|
* Gets the hardware serial number of this device.
|
||||||
*
|
*
|
||||||
* @return serial number or {@code null} if not available.
|
* @return serial number or {@code null} if not available.
|
||||||
*/
|
*/
|
||||||
private static String getDeviceSerialNumber() {
|
private static String getDeviceSerialNumber() {
|
||||||
// We're using the Reflection API because Build.SERIAL is only available
|
// We're using the Reflection API because Build.SERIAL is only available
|
||||||
// since API Level 9 (Gingerbread, Android 2.3).
|
// since API Level 9 (Gingerbread, Android 2.3).
|
||||||
try {
|
try {
|
||||||
return (String) Build.class.getField("SERIAL").get(null);
|
return (String) Build.class.getField("SERIAL").get(null);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] getBuildFingerprintAndDeviceSerial() {
|
private static byte[] getBuildFingerprintAndDeviceSerial() {
|
||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
String fingerprint = Build.FINGERPRINT;
|
String fingerprint = Build.FINGERPRINT;
|
||||||
if (fingerprint != null) {
|
if (fingerprint != null) {
|
||||||
result.append(fingerprint);
|
result.append(fingerprint);
|
||||||
}
|
}
|
||||||
String serial = getDeviceSerialNumber();
|
String serial = getDeviceSerialNumber();
|
||||||
if (serial != null) {
|
if (serial != null) {
|
||||||
result.append(serial);
|
result.append(serial);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return result.toString().getBytes("UTF-8");
|
return result.toString().getBytes("UTF-8");
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
throw new RuntimeException("UTF-8 encoding not supported");
|
throw new RuntimeException("UTF-8 encoding not supported");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,7 +18,7 @@ public class PhoneHelper {
|
||||||
public static void loadPhoneContacts(Context context,
|
public static void loadPhoneContacts(Context context,
|
||||||
final OnPhoneContactsLoadedListener listener) {
|
final OnPhoneContactsLoadedListener listener) {
|
||||||
final List<Bundle> phoneContacts = new ArrayList<Bundle>();
|
final List<Bundle> phoneContacts = new ArrayList<Bundle>();
|
||||||
|
|
||||||
final String[] PROJECTION = new String[] { ContactsContract.Data._ID,
|
final String[] PROJECTION = new String[] { ContactsContract.Data._ID,
|
||||||
ContactsContract.Data.DISPLAY_NAME,
|
ContactsContract.Data.DISPLAY_NAME,
|
||||||
ContactsContract.Data.PHOTO_THUMBNAIL_URI,
|
ContactsContract.Data.PHOTO_THUMBNAIL_URI,
|
||||||
|
@ -38,7 +38,7 @@ public class PhoneHelper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadComplete(Loader<Cursor> arg0, Cursor cursor) {
|
public void onLoadComplete(Loader<Cursor> arg0, Cursor cursor) {
|
||||||
if (cursor==null) {
|
if (cursor == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
|
@ -55,8 +55,10 @@ public class PhoneHelper {
|
||||||
.getColumnIndex(ContactsContract.Data.PHOTO_THUMBNAIL_URI)));
|
.getColumnIndex(ContactsContract.Data.PHOTO_THUMBNAIL_URI)));
|
||||||
contact.putString("lookup", cursor.getString(cursor
|
contact.putString("lookup", cursor.getString(cursor
|
||||||
.getColumnIndex(ContactsContract.Data.LOOKUP_KEY)));
|
.getColumnIndex(ContactsContract.Data.LOOKUP_KEY)));
|
||||||
|
|
||||||
contact.putString("jid",cursor.getString(cursor
|
contact.putString(
|
||||||
|
"jid",
|
||||||
|
cursor.getString(cursor
|
||||||
.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA)));
|
.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA)));
|
||||||
phoneContacts.add(contact);
|
phoneContacts.add(contact);
|
||||||
}
|
}
|
||||||
|
@ -69,8 +71,7 @@ public class PhoneHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Uri getSefliUri(Context context) {
|
public static Uri getSefliUri(Context context) {
|
||||||
String[] mProjection = new String[] { Profile._ID,
|
String[] mProjection = new String[] { Profile._ID, Profile.PHOTO_URI };
|
||||||
Profile.PHOTO_URI };
|
|
||||||
Cursor mProfileCursor = context.getContentResolver().query(
|
Cursor mProfileCursor = context.getContentResolver().query(
|
||||||
Profile.CONTENT_URI, mProjection, null, null, null);
|
Profile.CONTENT_URI, mProjection, null, null, null);
|
||||||
|
|
||||||
|
|
|
@ -118,9 +118,13 @@ public class UIHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getNameColor(String name) {
|
private static int getNameColor(String name) {
|
||||||
/*int holoColors[] = { 0xFF1da9da, 0xFFb368d9, 0xFF83b600, 0xFFffa713,
|
/*
|
||||||
0xFFe92727 };*/
|
* int holoColors[] = { 0xFF1da9da, 0xFFb368d9, 0xFF83b600, 0xFFffa713,
|
||||||
int holoColors[] = {0xFFe91e63, 0xFF9c27b0, 0xFF673ab7, 0xFF3f51b5, 0xFF5677fc, 0xFF03a9f4, 0xFF00bcd4, 0xFF009688, 0xFFff5722, 0xFF795548, 0xFF607d8b};
|
* 0xFFe92727 };
|
||||||
|
*/
|
||||||
|
int holoColors[] = { 0xFFe91e63, 0xFF9c27b0, 0xFF673ab7, 0xFF3f51b5,
|
||||||
|
0xFF5677fc, 0xFF03a9f4, 0xFF00bcd4, 0xFF009688, 0xFFff5722,
|
||||||
|
0xFF795548, 0xFF607d8b };
|
||||||
return holoColors[(int) ((name.hashCode() & 0xffffffffl) % holoColors.length)];
|
return holoColors[(int) ((name.hashCode() & 0xffffffffl) % holoColors.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,9 +220,9 @@ public class UIHelper {
|
||||||
}
|
}
|
||||||
ArrayList<String> names = new ArrayList<String>();
|
ArrayList<String> names = new ArrayList<String>();
|
||||||
names.add(conversation.getMucOptions().getActualNick());
|
names.add(conversation.getMucOptions().getActualNick());
|
||||||
for(User user : members) {
|
for (User user : members) {
|
||||||
names.add(user.getName());
|
names.add(user.getName());
|
||||||
if (names.size() > 4 ) {
|
if (names.size() > 4) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@ import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class Validator {
|
public class Validator {
|
||||||
public static final Pattern VALID_JID =
|
public static final Pattern VALID_JID = Pattern.compile(
|
||||||
Pattern.compile("^[^@/<>'\"\\s]+@[^@/<>'\"\\s]+$", Pattern.CASE_INSENSITIVE);
|
"^[^@/<>'\"\\s]+@[^@/<>'\"\\s]+$", Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
public static boolean isValidJid(String jid) {
|
public static boolean isValidJid(String jid) {
|
||||||
Matcher matcher = VALID_JID.matcher(jid);
|
Matcher matcher = VALID_JID.matcher(jid);
|
||||||
return matcher.find();
|
return matcher.find();
|
||||||
|
|
|
@ -12,41 +12,43 @@ import java.util.zip.InflaterInputStream;
|
||||||
*/
|
*/
|
||||||
public class ZLibInputStream extends InflaterInputStream {
|
public class ZLibInputStream extends InflaterInputStream {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a ZLibInputStream, reading data from the underlying stream.
|
* Construct a ZLibInputStream, reading data from the underlying stream.
|
||||||
*
|
*
|
||||||
* @param is The {@code InputStream} to read data from.
|
* @param is
|
||||||
* @throws IOException If an {@code IOException} occurs.
|
* The {@code InputStream} to read data from.
|
||||||
*/
|
* @throws IOException
|
||||||
public ZLibInputStream(InputStream is) throws IOException {
|
* If an {@code IOException} occurs.
|
||||||
super(is, new Inflater(), 512);
|
*/
|
||||||
}
|
public ZLibInputStream(InputStream is) throws IOException {
|
||||||
|
super(is, new Inflater(), 512);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide a more InputStream compatible version of available.
|
* Provide a more InputStream compatible version of available. A return
|
||||||
* A return value of 1 means that it is likly to read one byte without
|
* value of 1 means that it is likly to read one byte without blocking, 0
|
||||||
* blocking, 0 means that the system is known to block for more input.
|
* means that the system is known to block for more input.
|
||||||
*
|
*
|
||||||
* @return 0 if no data is available, 1 otherwise
|
* @return 0 if no data is available, 1 otherwise
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int available() throws IOException {
|
public int available() throws IOException {
|
||||||
/* This is one of the funny code blocks.
|
/*
|
||||||
* InflaterInputStream.available violates the contract of
|
* This is one of the funny code blocks. InflaterInputStream.available
|
||||||
* InputStream.available, which breaks kXML2.
|
* 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
|
* 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
|
* google guys for mixing a sun bug with a xml reader that can't handle
|
||||||
* it....
|
* it....
|
||||||
*
|
*
|
||||||
* Anyway, this simple if breaks suns distorted reality, but helps
|
* Anyway, this simple if breaks suns distorted reality, but helps to
|
||||||
* to use the api as intended.
|
* use the api as intended.
|
||||||
*/
|
*/
|
||||||
if (inf.needsInput()) {
|
if (inf.needsInput()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return super.available();
|
return super.available();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,76 +9,87 @@ import java.util.zip.Deflater;
|
||||||
import java.util.zip.DeflaterOutputStream;
|
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
|
* Implementation, preferable via reflection. The @hide was remove in API level
|
||||||
* 19. This class might thus go away in the future.</p>
|
* 19. This class might thus go away in the future.
|
||||||
* <p>Please use {@link ZLibOutputStream#SUPPORTED} to check for flush
|
* </p>
|
||||||
* compatibility.</p>
|
* <p>
|
||||||
|
* Please use {@link ZLibOutputStream#SUPPORTED} to check for flush
|
||||||
|
* compatibility.
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
public class ZLibOutputStream extends DeflaterOutputStream {
|
public class ZLibOutputStream extends DeflaterOutputStream {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The reflection based flush method.
|
* The reflection based flush method.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private final static Method method;
|
private final static Method method;
|
||||||
/**
|
/**
|
||||||
* SUPPORTED is true if a flush compatible method exists.
|
* SUPPORTED is true if a flush compatible method exists.
|
||||||
*/
|
*/
|
||||||
public final static boolean SUPPORTED;
|
public final static boolean SUPPORTED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static block to initialize {@link #SUPPORTED} and {@link #method}.
|
* Static block to initialize {@link #SUPPORTED} and {@link #method}.
|
||||||
*/
|
*/
|
||||||
static {
|
static {
|
||||||
Method m = null;
|
Method m = null;
|
||||||
try {
|
try {
|
||||||
m = Deflater.class.getMethod("deflate", byte[].class, int.class, int.class, int.class);
|
m = Deflater.class.getMethod("deflate", byte[].class, int.class,
|
||||||
} catch (SecurityException e) {
|
int.class, int.class);
|
||||||
} catch (NoSuchMethodException e) {
|
} catch (SecurityException e) {
|
||||||
}
|
} catch (NoSuchMethodException e) {
|
||||||
method = m;
|
|
||||||
SUPPORTED = (method != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new ZLib compatible output stream wrapping the given low level
|
|
||||||
* stream. ZLib compatiblity means we will send a zlib header.
|
|
||||||
* @param os OutputStream The underlying stream.
|
|
||||||
* @throws IOException In case of a lowlevel transfer problem.
|
|
||||||
* @throws NoSuchAlgorithmException In case of a {@link Deflater} error.
|
|
||||||
*/
|
|
||||||
public ZLibOutputStream(OutputStream os) throws IOException,
|
|
||||||
NoSuchAlgorithmException {
|
|
||||||
super(os, new Deflater(Deflater.BEST_COMPRESSION));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flush the given stream, preferring Java7 FLUSH_SYNC if available.
|
|
||||||
* @throws IOException In case of a lowlevel exception.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void flush() throws IOException {
|
|
||||||
if (!SUPPORTED) {
|
|
||||||
super.flush();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
int count = 0;
|
|
||||||
do {
|
|
||||||
count = (Integer) method.invoke(def, buf, 0, buf.length, 3);
|
|
||||||
if (count > 0) {
|
|
||||||
out.write(buf, 0, count);
|
|
||||||
}
|
}
|
||||||
} while (count > 0);
|
method = m;
|
||||||
} catch (IllegalArgumentException e) {
|
SUPPORTED = (method != null);
|
||||||
throw new IOException("Can't flush");
|
}
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
throw new IOException("Can't flush");
|
/**
|
||||||
} catch (InvocationTargetException e) {
|
* Create a new ZLib compatible output stream wrapping the given low level
|
||||||
throw new IOException("Can't flush");
|
* stream. ZLib compatiblity means we will send a zlib header.
|
||||||
}
|
*
|
||||||
super.flush();
|
* @param os
|
||||||
}
|
* OutputStream The underlying stream.
|
||||||
|
* @throws IOException
|
||||||
|
* In case of a lowlevel transfer problem.
|
||||||
|
* @throws NoSuchAlgorithmException
|
||||||
|
* In case of a {@link Deflater} error.
|
||||||
|
*/
|
||||||
|
public ZLibOutputStream(OutputStream os) throws IOException,
|
||||||
|
NoSuchAlgorithmException {
|
||||||
|
super(os, new Deflater(Deflater.BEST_COMPRESSION));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush the given stream, preferring Java7 FLUSH_SYNC if available.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* In case of a lowlevel exception.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void flush() throws IOException {
|
||||||
|
if (!SUPPORTED) {
|
||||||
|
super.flush();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int count = 0;
|
||||||
|
do {
|
||||||
|
count = (Integer) method.invoke(def, buf, 0, buf.length, 3);
|
||||||
|
if (count > 0) {
|
||||||
|
out.write(buf, 0, count);
|
||||||
|
}
|
||||||
|
} while (count > 0);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new IOException("Can't flush");
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new IOException("Can't flush");
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw new IOException("Can't flush");
|
||||||
|
}
|
||||||
|
super.flush();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,10 +146,10 @@ public class Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAttribute(String name, long value) {
|
public void setAttribute(String name, long value) {
|
||||||
this.setAttribute(name, ""+value);
|
this.setAttribute(name, "" + value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAttribute(String name, int value) {
|
public void setAttribute(String name, int value) {
|
||||||
this.setAttribute(name, ""+value);
|
this.setAttribute(name, "" + value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,77 +10,78 @@ public class Tag {
|
||||||
public static final int START = 0;
|
public static final int START = 0;
|
||||||
public static final int END = 1;
|
public static final int END = 1;
|
||||||
public static final int EMPTY = 2;
|
public static final int EMPTY = 2;
|
||||||
|
|
||||||
protected int type;
|
protected int type;
|
||||||
protected String name;
|
protected String name;
|
||||||
protected Hashtable<String, String> attributes = new Hashtable<String, String>();
|
protected Hashtable<String, String> attributes = new Hashtable<String, String>();
|
||||||
|
|
||||||
protected Tag(int type, String name) {
|
protected Tag(int type, String name) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Tag no(String text) {
|
public static Tag no(String text) {
|
||||||
return new Tag(NO,text);
|
return new Tag(NO, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Tag start(String name) {
|
public static Tag start(String name) {
|
||||||
return new Tag(START,name);
|
return new Tag(START, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Tag end(String name) {
|
public static Tag end(String name) {
|
||||||
return new Tag(END,name);
|
return new Tag(END, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Tag empty(String name) {
|
public static Tag empty(String name) {
|
||||||
return new Tag(EMPTY,name);
|
return new Tag(EMPTY, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAttribute(String attrName) {
|
public String getAttribute(String attrName) {
|
||||||
return this.attributes.get(attrName);
|
return this.attributes.get(attrName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tag setAttribute(String attrName, String attrValue) {
|
public Tag setAttribute(String attrName, String attrValue) {
|
||||||
this.attributes.put(attrName, attrValue);
|
this.attributes.put(attrName, attrValue);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tag setAtttributes(Hashtable<String, String> attributes) {
|
public Tag setAtttributes(Hashtable<String, String> attributes) {
|
||||||
this.attributes = attributes;
|
this.attributes = attributes;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isStart(String needle) {
|
public boolean isStart(String needle) {
|
||||||
if (needle==null) return false;
|
if (needle == null)
|
||||||
|
return false;
|
||||||
return (this.type == START) && (needle.equals(this.name));
|
return (this.type == START) && (needle.equals(this.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEnd(String needle) {
|
public boolean isEnd(String needle) {
|
||||||
if (needle==null) return false;
|
if (needle == null)
|
||||||
|
return false;
|
||||||
return (this.type == END) && (needle.equals(this.name));
|
return (this.type == END) && (needle.equals(this.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNo() {
|
public boolean isNo() {
|
||||||
return (this.type == NO);
|
return (this.type == NO);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder tagOutput = new StringBuilder();
|
StringBuilder tagOutput = new StringBuilder();
|
||||||
tagOutput.append('<');
|
tagOutput.append('<');
|
||||||
if (type==END) {
|
if (type == END) {
|
||||||
tagOutput.append('/');
|
tagOutput.append('/');
|
||||||
}
|
}
|
||||||
tagOutput.append(name);
|
tagOutput.append(name);
|
||||||
if(type!=END) {
|
if (type != END) {
|
||||||
Set<Entry<String, String>> attributeSet = attributes.entrySet();
|
Set<Entry<String, String>> attributeSet = attributes.entrySet();
|
||||||
Iterator<Entry<String, String>> it = attributeSet.iterator();
|
Iterator<Entry<String, String>> it = attributeSet.iterator();
|
||||||
while(it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Entry<String,String> entry = it.next();
|
Entry<String, String> entry = it.next();
|
||||||
tagOutput.append(' ');
|
tagOutput.append(' ');
|
||||||
tagOutput.append(entry.getKey());
|
tagOutput.append(entry.getKey());
|
||||||
tagOutput.append("=\"");
|
tagOutput.append("=\"");
|
||||||
|
@ -88,7 +89,7 @@ public class Tag {
|
||||||
tagOutput.append('"');
|
tagOutput.append('"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type==EMPTY) {
|
if (type == EMPTY) {
|
||||||
tagOutput.append('/');
|
tagOutput.append('/');
|
||||||
}
|
}
|
||||||
tagOutput.append('>');
|
tagOutput.append('>');
|
||||||
|
|
|
@ -8,22 +8,23 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
|
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
|
||||||
|
|
||||||
public class TagWriter {
|
public class TagWriter {
|
||||||
|
|
||||||
private OutputStream plainOutputStream;
|
private OutputStream plainOutputStream;
|
||||||
private OutputStreamWriter outputStream;
|
private OutputStreamWriter outputStream;
|
||||||
private boolean finshed = false;
|
private boolean finshed = false;
|
||||||
private LinkedBlockingQueue<AbstractStanza> writeQueue = new LinkedBlockingQueue<AbstractStanza>();
|
private LinkedBlockingQueue<AbstractStanza> writeQueue = new LinkedBlockingQueue<AbstractStanza>();
|
||||||
private Thread asyncStanzaWriter = new Thread() {
|
private Thread asyncStanzaWriter = new Thread() {
|
||||||
private boolean shouldStop = false;
|
private boolean shouldStop = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
while(!shouldStop) {
|
while (!shouldStop) {
|
||||||
if ((finshed)&&(writeQueue.size() == 0)) {
|
if ((finshed) && (writeQueue.size() == 0)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
AbstractStanza output = writeQueue.take();
|
AbstractStanza output = writeQueue.take();
|
||||||
if (outputStream==null) {
|
if (outputStream == null) {
|
||||||
shouldStop = true;
|
shouldStop = true;
|
||||||
} else {
|
} else {
|
||||||
outputStream.write(output.toString());
|
outputStream.write(output.toString());
|
||||||
|
@ -37,12 +38,12 @@ public class TagWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public TagWriter() {
|
public TagWriter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOutputStream(OutputStream out) throws IOException {
|
public void setOutputStream(OutputStream out) throws IOException {
|
||||||
if (out==null) {
|
if (out == null) {
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
this.plainOutputStream = out;
|
this.plainOutputStream = out;
|
||||||
|
@ -50,23 +51,23 @@ public class TagWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public OutputStream getOutputStream() throws IOException {
|
public OutputStream getOutputStream() throws IOException {
|
||||||
if (this.plainOutputStream==null) {
|
if (this.plainOutputStream == null) {
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
return this.plainOutputStream;
|
return this.plainOutputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TagWriter beginDocument() throws IOException {
|
public TagWriter beginDocument() throws IOException {
|
||||||
if (outputStream==null) {
|
if (outputStream == null) {
|
||||||
throw new IOException("output stream was null");
|
throw new IOException("output stream was null");
|
||||||
}
|
}
|
||||||
outputStream.write("<?xml version='1.0'?>");
|
outputStream.write("<?xml version='1.0'?>");
|
||||||
outputStream.flush();
|
outputStream.flush();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TagWriter writeTag(Tag tag) throws IOException {
|
public TagWriter writeTag(Tag tag) throws IOException {
|
||||||
if (outputStream==null) {
|
if (outputStream == null) {
|
||||||
throw new IOException("output stream was null");
|
throw new IOException("output stream was null");
|
||||||
}
|
}
|
||||||
outputStream.write(tag.toString());
|
outputStream.write(tag.toString());
|
||||||
|
@ -75,34 +76,34 @@ public class TagWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public TagWriter writeElement(Element element) throws IOException {
|
public TagWriter writeElement(Element element) throws IOException {
|
||||||
if (outputStream==null) {
|
if (outputStream == null) {
|
||||||
throw new IOException("output stream was null");
|
throw new IOException("output stream was null");
|
||||||
}
|
}
|
||||||
outputStream.write(element.toString());
|
outputStream.write(element.toString());
|
||||||
outputStream.flush();
|
outputStream.flush();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TagWriter writeStanzaAsync(AbstractStanza stanza) {
|
public TagWriter writeStanzaAsync(AbstractStanza stanza) {
|
||||||
if (finshed) {
|
if (finshed) {
|
||||||
return this;
|
return this;
|
||||||
} else {
|
} else {
|
||||||
if (!asyncStanzaWriter.isAlive()) {
|
if (!asyncStanzaWriter.isAlive()) {
|
||||||
try {
|
try {
|
||||||
asyncStanzaWriter.start();
|
asyncStanzaWriter.start();
|
||||||
} catch (IllegalThreadStateException e) {
|
} catch (IllegalThreadStateException e) {
|
||||||
//already started
|
// already started
|
||||||
}
|
|
||||||
}
|
}
|
||||||
writeQueue.add(stanza);
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
writeQueue.add(stanza);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finish() {
|
public void finish() {
|
||||||
this.finshed = true;
|
this.finshed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean finished() {
|
public boolean finished() {
|
||||||
return (this.writeQueue.size() == 0);
|
return (this.writeQueue.size() == 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,14 @@ import java.io.InputStreamReader;
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
|
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.PowerManager.WakeLock;
|
import android.os.PowerManager.WakeLock;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Xml;
|
import android.util.Xml;
|
||||||
|
|
||||||
public class XmlReader {
|
public class XmlReader {
|
||||||
private static final String LOGTAG = "xmppService";
|
|
||||||
private XmlPullParser parser;
|
private XmlPullParser parser;
|
||||||
private PowerManager.WakeLock wakeLock;
|
private PowerManager.WakeLock wakeLock;
|
||||||
private InputStream is;
|
private InputStream is;
|
||||||
|
@ -21,15 +22,16 @@ public class XmlReader {
|
||||||
public XmlReader(WakeLock wakeLock) {
|
public XmlReader(WakeLock wakeLock) {
|
||||||
this.parser = Xml.newPullParser();
|
this.parser = Xml.newPullParser();
|
||||||
try {
|
try {
|
||||||
this.parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES,true);
|
this.parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES,
|
||||||
|
true);
|
||||||
} catch (XmlPullParserException e) {
|
} 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;
|
this.wakeLock = wakeLock;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInputStream(InputStream inputStream) throws IOException {
|
public void setInputStream(InputStream inputStream) throws IOException {
|
||||||
if (inputStream==null) {
|
if (inputStream == null) {
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
this.is = inputStream;
|
this.is = inputStream;
|
||||||
|
@ -41,14 +43,14 @@ public class XmlReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream getInputStream() throws IOException {
|
public InputStream getInputStream() throws IOException {
|
||||||
if (this.is==null) {
|
if (this.is == null) {
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() throws IOException {
|
public void reset() throws IOException {
|
||||||
if (this.is==null) {
|
if (this.is == null) {
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -57,62 +59,74 @@ public class XmlReader {
|
||||||
throw new IOException("error resetting parser");
|
throw new IOException("error resetting parser");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tag readTag() throws XmlPullParserException, IOException {
|
public Tag readTag() throws XmlPullParserException, IOException {
|
||||||
if (wakeLock.isHeld()) {
|
if (wakeLock.isHeld()) {
|
||||||
try { wakeLock.release();} catch (RuntimeException re) {}
|
try {
|
||||||
|
wakeLock.release();
|
||||||
|
} catch (RuntimeException re) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
while(this.is != null && parser.next() != XmlPullParser.END_DOCUMENT) {
|
while (this.is != null
|
||||||
wakeLock.acquire();
|
&& parser.next() != XmlPullParser.END_DOCUMENT) {
|
||||||
if (parser.getEventType() == XmlPullParser.START_TAG) {
|
wakeLock.acquire();
|
||||||
Tag tag = Tag.start(parser.getName());
|
if (parser.getEventType() == XmlPullParser.START_TAG) {
|
||||||
for(int i = 0; i < parser.getAttributeCount(); ++i) {
|
Tag tag = Tag.start(parser.getName());
|
||||||
tag.setAttribute(parser.getAttributeName(i), parser.getAttributeValue(i));
|
for (int i = 0; i < parser.getAttributeCount(); ++i) {
|
||||||
}
|
tag.setAttribute(parser.getAttributeName(i),
|
||||||
String xmlns = parser.getNamespace();
|
parser.getAttributeValue(i));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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()) {
|
if (wakeLock.isHeld()) {
|
||||||
try { wakeLock.release();} catch (RuntimeException re) {}
|
try {
|
||||||
|
wakeLock.release();
|
||||||
|
} catch (RuntimeException re) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (ArrayIndexOutOfBoundsException e) {
|
} catch (ArrayIndexOutOfBoundsException e) {
|
||||||
throw new IOException("xml parser mishandled ArrayIndexOufOfBounds", e);
|
throw new IOException(
|
||||||
|
"xml parser mishandled ArrayIndexOufOfBounds", e);
|
||||||
} catch (StringIndexOutOfBoundsException e) {
|
} catch (StringIndexOutOfBoundsException e) {
|
||||||
throw new IOException("xml parser mishandled StringIndexOufOfBounds", e);
|
throw new IOException(
|
||||||
|
"xml parser mishandled StringIndexOufOfBounds", e);
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
throw new IOException("xml parser mishandled NullPointerException", e);
|
throw new IOException("xml parser mishandled NullPointerException",
|
||||||
|
e);
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
throw new IOException("xml parser mishandled IndexOutOfBound", e);
|
throw new IOException("xml parser mishandled IndexOutOfBound", e);
|
||||||
}
|
}
|
||||||
return null;
|
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 element = new Element(currentTag.getName());
|
||||||
element.setAttributes(currentTag.getAttributes());
|
element.setAttributes(currentTag.getAttributes());
|
||||||
Tag nextTag = this.readTag();
|
Tag nextTag = this.readTag();
|
||||||
if (nextTag == null) {
|
if (nextTag == null) {
|
||||||
throw new IOException("unterupted mid tag");
|
throw new IOException("unterupted mid tag");
|
||||||
}
|
}
|
||||||
if(nextTag.isNo()) {
|
if (nextTag.isNo()) {
|
||||||
element.setContent(nextTag.getName());
|
element.setContent(nextTag.getName());
|
||||||
nextTag = this.readTag();
|
nextTag = this.readTag();
|
||||||
if (nextTag == null) {
|
if (nextTag == null) {
|
||||||
throw new IOException("unterupted mid tag");
|
throw new IOException("unterupted mid tag");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while(!nextTag.isEnd(element.getName())) {
|
while (!nextTag.isEnd(element.getName())) {
|
||||||
if (!nextTag.isNo()) {
|
if (!nextTag.isNo()) {
|
||||||
Element child = this.readElement(nextTag);
|
Element child = this.readElement(nextTag);
|
||||||
element.addChild(child);
|
element.addChild(child);
|
||||||
|
|
|
@ -32,6 +32,7 @@ import android.os.PowerManager.WakeLock;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.services.XmppConnectionService;
|
import eu.siacs.conversations.services.XmppConnectionService;
|
||||||
import eu.siacs.conversations.utils.CryptoHelper;
|
import eu.siacs.conversations.utils.CryptoHelper;
|
||||||
|
@ -58,7 +59,6 @@ import eu.siacs.conversations.xmpp.stanzas.streammgmt.ResumePacket;
|
||||||
public class XmppConnection implements Runnable {
|
public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
protected Account account;
|
protected Account account;
|
||||||
private static final String LOGTAG = "xmppService";
|
|
||||||
|
|
||||||
private WakeLock wakeLock;
|
private WakeLock wakeLock;
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ public class XmppConnection implements Runnable {
|
||||||
private Socket socket;
|
private Socket socket;
|
||||||
private XmlReader tagReader;
|
private XmlReader tagReader;
|
||||||
private TagWriter tagWriter;
|
private TagWriter tagWriter;
|
||||||
|
|
||||||
private Features features = new Features(this);
|
private Features features = new Features(this);
|
||||||
|
|
||||||
private boolean shouldBind = true;
|
private boolean shouldBind = true;
|
||||||
|
@ -78,7 +78,7 @@ public class XmppConnection implements Runnable {
|
||||||
private String streamId = null;
|
private String streamId = null;
|
||||||
private int smVersion = 3;
|
private int smVersion = 3;
|
||||||
private SparseArray<String> messageReceipts = new SparseArray<String>();
|
private SparseArray<String> messageReceipts = new SparseArray<String>();
|
||||||
|
|
||||||
private boolean usingCompression = false;
|
private boolean usingCompression = false;
|
||||||
|
|
||||||
private int stanzasReceived = 0;
|
private int stanzasReceived = 0;
|
||||||
|
@ -109,8 +109,8 @@ public class XmppConnection implements Runnable {
|
||||||
this.mRandom = service.getRNG();
|
this.mRandom = service.getRNG();
|
||||||
this.mMemorizingTrustManager = service.getMemorizingTrustManager();
|
this.mMemorizingTrustManager = service.getMemorizingTrustManager();
|
||||||
this.account = account;
|
this.account = account;
|
||||||
this.wakeLock = service.getPowerManager().newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
|
this.wakeLock = service.getPowerManager().newWakeLock(
|
||||||
account.getJid());
|
PowerManager.PARTIAL_WAKE_LOCK, account.getJid());
|
||||||
tagWriter = new TagWriter();
|
tagWriter = new TagWriter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void connect() {
|
protected void connect() {
|
||||||
Log.d(LOGTAG, account.getJid() + ": connecting");
|
Log.d(Config.LOGTAG, account.getJid() + ": connecting");
|
||||||
usingCompression = false;
|
usingCompression = false;
|
||||||
lastConnect = SystemClock.elapsedRealtime();
|
lastConnect = SystemClock.elapsedRealtime();
|
||||||
lastPingSent = SystemClock.elapsedRealtime();
|
lastPingSent = SystemClock.elapsedRealtime();
|
||||||
|
@ -147,7 +147,7 @@ public class XmppConnection implements Runnable {
|
||||||
this.changeStatus(Account.STATUS_CONNECTING);
|
this.changeStatus(Account.STATUS_CONNECTING);
|
||||||
Bundle namePort = DNSHelper.getSRVRecord(account.getServer());
|
Bundle namePort = DNSHelper.getSRVRecord(account.getServer());
|
||||||
if ("timeout".equals(namePort.getString("error"))) {
|
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);
|
this.changeStatus(Account.STATUS_OFFLINE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -156,13 +156,14 @@ public class XmppConnection implements Runnable {
|
||||||
int srvRecordPort = namePort.getInt("port");
|
int srvRecordPort = namePort.getInt("port");
|
||||||
if (srvRecordServer != null) {
|
if (srvRecordServer != null) {
|
||||||
if (srvIpServer != null) {
|
if (srvIpServer != null) {
|
||||||
Log.d(LOGTAG, account.getJid() + ": using values from dns "
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
+ srvRecordServer + "[" + srvIpServer + "]:"
|
+ ": using values from dns " + srvRecordServer
|
||||||
+ srvRecordPort);
|
+ "[" + srvIpServer + "]:" + srvRecordPort);
|
||||||
socket = new Socket(srvIpServer, srvRecordPort);
|
socket = new Socket(srvIpServer, srvRecordPort);
|
||||||
} else {
|
} else {
|
||||||
Log.d(LOGTAG, account.getJid() + ": using values from dns "
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
+ srvRecordServer + ":" + srvRecordPort);
|
+ ": using values from dns " + srvRecordServer
|
||||||
|
+ ":" + srvRecordPort);
|
||||||
socket = new Socket(srvRecordServer, srvRecordPort);
|
socket = new Socket(srvRecordServer, srvRecordPort);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -180,7 +181,8 @@ public class XmppConnection implements Runnable {
|
||||||
processStream(nextTag);
|
processStream(nextTag);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
Log.d(LOGTAG, "found unexpected tag: " + nextTag.getName());
|
Log.d(Config.LOGTAG,
|
||||||
|
"found unexpected tag: " + nextTag.getName());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,27 +192,39 @@ public class XmppConnection implements Runnable {
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
this.changeStatus(Account.STATUS_SERVER_NOT_FOUND);
|
this.changeStatus(Account.STATUS_SERVER_NOT_FOUND);
|
||||||
if (wakeLock.isHeld()) {
|
if (wakeLock.isHeld()) {
|
||||||
try { wakeLock.release();} catch (RuntimeException re) {}
|
try {
|
||||||
|
wakeLock.release();
|
||||||
|
} catch (RuntimeException re) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
this.changeStatus(Account.STATUS_OFFLINE);
|
this.changeStatus(Account.STATUS_OFFLINE);
|
||||||
if (wakeLock.isHeld()) {
|
if (wakeLock.isHeld()) {
|
||||||
try { wakeLock.release();} catch (RuntimeException re) {}
|
try {
|
||||||
|
wakeLock.release();
|
||||||
|
} catch (RuntimeException re) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
this.changeStatus(Account.STATUS_OFFLINE);
|
this.changeStatus(Account.STATUS_OFFLINE);
|
||||||
Log.d(LOGTAG, "compression exception " + e.getMessage());
|
Log.d(Config.LOGTAG, "compression exception " + e.getMessage());
|
||||||
if (wakeLock.isHeld()) {
|
if (wakeLock.isHeld()) {
|
||||||
try { wakeLock.release();} catch (RuntimeException re) {}
|
try {
|
||||||
|
wakeLock.release();
|
||||||
|
} catch (RuntimeException re) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} catch (XmlPullParserException e) {
|
} catch (XmlPullParserException e) {
|
||||||
this.changeStatus(Account.STATUS_OFFLINE);
|
this.changeStatus(Account.STATUS_OFFLINE);
|
||||||
Log.d(LOGTAG, "xml exception " + e.getMessage());
|
Log.d(Config.LOGTAG, "xml exception " + e.getMessage());
|
||||||
if (wakeLock.isHeld()) {
|
if (wakeLock.isHeld()) {
|
||||||
try { wakeLock.release();} catch (RuntimeException re) {}
|
try {
|
||||||
|
wakeLock.release();
|
||||||
|
} catch (RuntimeException re) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -235,7 +249,7 @@ public class XmppConnection implements Runnable {
|
||||||
} else if (nextTag.isStart("compressed")) {
|
} else if (nextTag.isStart("compressed")) {
|
||||||
switchOverToZLib(nextTag);
|
switchOverToZLib(nextTag);
|
||||||
} else if (nextTag.isStart("success")) {
|
} else if (nextTag.isStart("success")) {
|
||||||
Log.d(LOGTAG, account.getJid() + ": logged in");
|
Log.d(Config.LOGTAG, account.getJid() + ": logged in");
|
||||||
tagReader.readTag();
|
tagReader.readTag();
|
||||||
tagReader.reset();
|
tagReader.reset();
|
||||||
sendStartStream();
|
sendStartStream();
|
||||||
|
@ -250,17 +264,18 @@ public class XmppConnection implements Runnable {
|
||||||
response.setAttribute("xmlns",
|
response.setAttribute("xmlns",
|
||||||
"urn:ietf:params:xml:ns:xmpp-sasl");
|
"urn:ietf:params:xml:ns:xmpp-sasl");
|
||||||
response.setContent(CryptoHelper.saslDigestMd5(account,
|
response.setContent(CryptoHelper.saslDigestMd5(account,
|
||||||
challange,mRandom));
|
challange, mRandom));
|
||||||
tagWriter.writeElement(response);
|
tagWriter.writeElement(response);
|
||||||
} else if (nextTag.isStart("enabled")) {
|
} else if (nextTag.isStart("enabled")) {
|
||||||
Element enabled = tagReader.readElement(nextTag);
|
Element enabled = tagReader.readElement(nextTag);
|
||||||
if ("true".equals(enabled.getAttribute("resume"))) {
|
if ("true".equals(enabled.getAttribute("resume"))) {
|
||||||
this.streamId = enabled.getAttribute("id");
|
this.streamId = enabled.getAttribute("id");
|
||||||
Log.d(LOGTAG, account.getJid() + ": stream managment("
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
+ smVersion + ") enabled (resumable)");
|
+ ": stream managment(" + smVersion
|
||||||
|
+ ") enabled (resumable)");
|
||||||
} else {
|
} else {
|
||||||
Log.d(LOGTAG, account.getJid() + ": stream managment("
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
+ smVersion + ") enabled");
|
+ ": stream managment(" + smVersion + ") enabled");
|
||||||
}
|
}
|
||||||
this.lastSessionStarted = SystemClock.elapsedRealtime();
|
this.lastSessionStarted = SystemClock.elapsedRealtime();
|
||||||
this.stanzasReceived = 0;
|
this.stanzasReceived = 0;
|
||||||
|
@ -272,22 +287,25 @@ public class XmppConnection implements Runnable {
|
||||||
String h = resumed.getAttribute("h");
|
String h = resumed.getAttribute("h");
|
||||||
try {
|
try {
|
||||||
int serverCount = Integer.parseInt(h);
|
int serverCount = Integer.parseInt(h);
|
||||||
if (serverCount!=stanzasSent) {
|
if (serverCount != stanzasSent) {
|
||||||
Log.d(LOGTAG,account.getJid() + ": session resumed with lost packages");
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
|
+ ": session resumed with lost packages");
|
||||||
stanzasSent = serverCount;
|
stanzasSent = serverCount;
|
||||||
} else {
|
} else {
|
||||||
Log.d(LOGTAG, account.getJid() + ": session resumed");
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
|
+ ": session resumed");
|
||||||
}
|
}
|
||||||
if (acknowledgedListener!=null) {
|
if (acknowledgedListener != null) {
|
||||||
for(int i = 0; i < messageReceipts.size(); ++i) {
|
for (int i = 0; i < messageReceipts.size(); ++i) {
|
||||||
if (serverCount>=messageReceipts.keyAt(i)) {
|
if (serverCount >= messageReceipts.keyAt(i)) {
|
||||||
acknowledgedListener.onMessageAcknowledged(account, messageReceipts.valueAt(i));
|
acknowledgedListener.onMessageAcknowledged(
|
||||||
|
account, messageReceipts.valueAt(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
messageReceipts.clear();
|
messageReceipts.clear();
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
|
|
||||||
}
|
}
|
||||||
changeStatus(Account.STATUS_ONLINE);
|
changeStatus(Account.STATUS_ONLINE);
|
||||||
} else if (nextTag.isStart("r")) {
|
} else if (nextTag.isStart("r")) {
|
||||||
|
@ -301,13 +319,14 @@ public class XmppConnection implements Runnable {
|
||||||
String msgId = this.messageReceipts.get(serverSequence);
|
String msgId = this.messageReceipts.get(serverSequence);
|
||||||
if (msgId != null) {
|
if (msgId != null) {
|
||||||
if (this.acknowledgedListener != null) {
|
if (this.acknowledgedListener != null) {
|
||||||
this.acknowledgedListener.onMessageAcknowledged(account, msgId);
|
this.acknowledgedListener.onMessageAcknowledged(
|
||||||
|
account, msgId);
|
||||||
}
|
}
|
||||||
this.messageReceipts.remove(serverSequence);
|
this.messageReceipts.remove(serverSequence);
|
||||||
}
|
}
|
||||||
} else if (nextTag.isStart("failed")) {
|
} else if (nextTag.isStart("failed")) {
|
||||||
tagReader.readElement(nextTag);
|
tagReader.readElement(nextTag);
|
||||||
Log.d(LOGTAG, account.getJid() + ": resumption failed");
|
Log.d(Config.LOGTAG, account.getJid() + ": resumption failed");
|
||||||
streamId = null;
|
streamId = null;
|
||||||
if (account.getStatus() != Account.STATUS_ONLINE) {
|
if (account.getStatus() != Account.STATUS_ONLINE) {
|
||||||
sendBindRequest();
|
sendBindRequest();
|
||||||
|
@ -347,7 +366,7 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
element.setAttributes(currentTag.getAttributes());
|
element.setAttributes(currentTag.getAttributes());
|
||||||
Tag nextTag = tagReader.readTag();
|
Tag nextTag = tagReader.readTag();
|
||||||
if (nextTag==null) {
|
if (nextTag == null) {
|
||||||
throw new IOException("interrupted mid tag");
|
throw new IOException("interrupted mid tag");
|
||||||
}
|
}
|
||||||
while (!nextTag.isEnd(element.getName())) {
|
while (!nextTag.isEnd(element.getName())) {
|
||||||
|
@ -361,7 +380,7 @@ public class XmppConnection implements Runnable {
|
||||||
element.addChild(child);
|
element.addChild(child);
|
||||||
}
|
}
|
||||||
nextTag = tagReader.readTag();
|
nextTag = tagReader.readTag();
|
||||||
if (nextTag==null) {
|
if (nextTag == null) {
|
||||||
throw new IOException("interrupted mid tag");
|
throw new IOException("interrupted mid tag");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -446,7 +465,7 @@ public class XmppConnection implements Runnable {
|
||||||
.setInputStream(new ZLibInputStream(tagReader.getInputStream()));
|
.setInputStream(new ZLibInputStream(tagReader.getInputStream()));
|
||||||
|
|
||||||
sendStartStream();
|
sendStartStream();
|
||||||
Log.d(LOGTAG, account.getJid() + ": compression enabled");
|
Log.d(Config.LOGTAG, account.getJid() + ": compression enabled");
|
||||||
usingCompression = true;
|
usingCompression = true;
|
||||||
processStream(tagReader.readTag());
|
processStream(tagReader.readTag());
|
||||||
}
|
}
|
||||||
|
@ -462,23 +481,30 @@ public class XmppConnection implements Runnable {
|
||||||
tagReader.readTag();
|
tagReader.readTag();
|
||||||
try {
|
try {
|
||||||
SSLContext sc = SSLContext.getInstance("TLS");
|
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();
|
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,
|
SSLSocket sslSocket = (SSLSocket) factory.createSocket(socket,
|
||||||
socket.getInetAddress().getHostAddress(), socket.getPort(),
|
socket.getInetAddress().getHostAddress(), socket.getPort(),
|
||||||
true);
|
true);
|
||||||
|
|
||||||
if (verifier != null && !verifier.verify(account.getServer(), sslSocket.getSession())) {
|
if (verifier != null
|
||||||
Log.d(LOGTAG, account.getJid() + ": host mismatch in TLS connection");
|
&& !verifier.verify(account.getServer(),
|
||||||
|
sslSocket.getSession())) {
|
||||||
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
|
+ ": host mismatch in TLS connection");
|
||||||
sslSocket.close();
|
sslSocket.close();
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
tagReader.setInputStream(sslSocket.getInputStream());
|
tagReader.setInputStream(sslSocket.getInputStream());
|
||||||
tagWriter.setOutputStream(sslSocket.getOutputStream());
|
tagWriter.setOutputStream(sslSocket.getOutputStream());
|
||||||
sendStartStream();
|
sendStartStream();
|
||||||
Log.d(LOGTAG, account.getJid() + ": TLS connection established");
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
|
+ ": TLS connection established");
|
||||||
processStream(tagReader.readTag());
|
processStream(tagReader.readTag());
|
||||||
sslSocket.close();
|
sslSocket.close();
|
||||||
} catch (NoSuchAlgorithmException e1) {
|
} catch (NoSuchAlgorithmException e1) {
|
||||||
|
@ -604,7 +630,7 @@ public class XmppConnection implements Runnable {
|
||||||
changeStatus(Account.STATUS_REGISTRATION_CONFLICT);
|
changeStatus(Account.STATUS_REGISTRATION_CONFLICT);
|
||||||
} else {
|
} else {
|
||||||
changeStatus(Account.STATUS_REGISTRATION_FAILED);
|
changeStatus(Account.STATUS_REGISTRATION_FAILED);
|
||||||
Log.d(LOGTAG, packet.toString());
|
Log.d(Config.LOGTAG, packet.toString());
|
||||||
}
|
}
|
||||||
disconnect(true);
|
disconnect(true);
|
||||||
}
|
}
|
||||||
|
@ -612,7 +638,7 @@ public class XmppConnection implements Runnable {
|
||||||
} else {
|
} else {
|
||||||
changeStatus(Account.STATUS_REGISTRATION_FAILED);
|
changeStatus(Account.STATUS_REGISTRATION_FAILED);
|
||||||
disconnect(true);
|
disconnect(true);
|
||||||
Log.d(LOGTAG, account.getJid()
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
+ ": could not register. instructions are"
|
+ ": could not register. instructions are"
|
||||||
+ instructions.getContent());
|
+ instructions.getContent());
|
||||||
}
|
}
|
||||||
|
@ -628,9 +654,9 @@ public class XmppConnection implements Runnable {
|
||||||
@Override
|
@Override
|
||||||
public void onIqPacketReceived(Account account, IqPacket packet) {
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||||
Element bind = packet.findChild("bind");
|
Element bind = packet.findChild("bind");
|
||||||
if (bind!=null) {
|
if (bind != null) {
|
||||||
Element jid = bind.findChild("jid");
|
Element jid = bind.findChild("jid");
|
||||||
if (jid!=null) {
|
if (jid != null) {
|
||||||
account.setResource(jid.getContent().split("/")[1]);
|
account.setResource(jid.getContent().split("/")[1]);
|
||||||
if (streamFeatures.hasChild("sm", "urn:xmpp:sm:3")) {
|
if (streamFeatures.hasChild("sm", "urn:xmpp:sm:3")) {
|
||||||
smVersion = 3;
|
smVersion = 3;
|
||||||
|
@ -638,7 +664,8 @@ public class XmppConnection implements Runnable {
|
||||||
tagWriter.writeStanzaAsync(enable);
|
tagWriter.writeStanzaAsync(enable);
|
||||||
stanzasSent = 0;
|
stanzasSent = 0;
|
||||||
messageReceipts.clear();
|
messageReceipts.clear();
|
||||||
} else if (streamFeatures.hasChild("sm", "urn:xmpp:sm:2")) {
|
} else if (streamFeatures.hasChild("sm",
|
||||||
|
"urn:xmpp:sm:2")) {
|
||||||
smVersion = 2;
|
smVersion = 2;
|
||||||
EnablePacket enable = new EnablePacket(smVersion);
|
EnablePacket enable = new EnablePacket(smVersion);
|
||||||
tagWriter.writeStanzaAsync(enable);
|
tagWriter.writeStanzaAsync(enable);
|
||||||
|
@ -660,7 +687,8 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (this.streamFeatures.hasChild("session")) {
|
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);
|
IqPacket startSession = new IqPacket(IqPacket.TYPE_SET);
|
||||||
startSession.addChild("session",
|
startSession.addChild("session",
|
||||||
"urn:ietf:params:xml:ns:xmpp-session");
|
"urn:ietf:params:xml:ns:xmpp-session");
|
||||||
|
@ -725,10 +753,10 @@ public class XmppConnection implements Runnable {
|
||||||
@Override
|
@Override
|
||||||
public void onIqPacketReceived(Account account, IqPacket packet) {
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||||
if (!packet.hasChild("error")) {
|
if (!packet.hasChild("error")) {
|
||||||
Log.d(LOGTAG, account.getJid()
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
+ ": successfully enabled carbons");
|
+ ": successfully enabled carbons");
|
||||||
} else {
|
} else {
|
||||||
Log.d(LOGTAG, account.getJid()
|
Log.d(Config.LOGTAG, account.getJid()
|
||||||
+ ": error enableing carbons " + packet.toString());
|
+ ": error enableing carbons " + packet.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -736,7 +764,7 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processStreamError(Tag currentTag) {
|
private void processStreamError(Tag currentTag) {
|
||||||
Log.d(LOGTAG, "processStreamError");
|
Log.d(Config.LOGTAG, "processStreamError");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendStartStream() throws IOException {
|
private void sendStartStream() throws IOException {
|
||||||
|
@ -778,15 +806,18 @@ public class XmppConnection implements Runnable {
|
||||||
public void sendPresencePacket(PresencePacket packet) {
|
public void sendPresencePacket(PresencePacket packet) {
|
||||||
this.sendPacket(packet, null);
|
this.sendPacket(packet, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void sendPacket(final AbstractStanza packet,
|
private synchronized void sendPacket(final AbstractStanza packet,
|
||||||
PacketReceived callback) {
|
PacketReceived callback) {
|
||||||
if (packet.getName().equals("iq") || packet.getName().equals("message") || packet.getName().equals("presence")) {
|
if (packet.getName().equals("iq") || packet.getName().equals("message")
|
||||||
|
|| packet.getName().equals("presence")) {
|
||||||
++stanzasSent;
|
++stanzasSent;
|
||||||
}
|
}
|
||||||
tagWriter.writeStanzaAsync(packet);
|
tagWriter.writeStanzaAsync(packet);
|
||||||
if (packet instanceof MessagePacket && packet.getId() != null && this.streamId != null) {
|
if (packet instanceof MessagePacket && packet.getId() != null
|
||||||
Log.d(LOGTAG,"request delivery report for stanza "+stanzasSent);
|
&& this.streamId != null) {
|
||||||
|
Log.d(Config.LOGTAG, "request delivery report for stanza "
|
||||||
|
+ stanzasSent);
|
||||||
this.messageReceipts.put(stanzasSent, packet.getId());
|
this.messageReceipts.put(stanzasSent, packet.getId());
|
||||||
tagWriter.writeStanzaAsync(new RequestPacket(this.smVersion));
|
tagWriter.writeStanzaAsync(new RequestPacket(this.smVersion));
|
||||||
}
|
}
|
||||||
|
@ -837,14 +868,14 @@ public class XmppConnection implements Runnable {
|
||||||
public void setOnBindListener(OnBindListener listener) {
|
public void setOnBindListener(OnBindListener listener) {
|
||||||
this.bindListener = listener;
|
this.bindListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOnMessageAcknowledgeListener(OnMessageAcknowledged listener) {
|
public void setOnMessageAcknowledgeListener(OnMessageAcknowledged listener) {
|
||||||
this.acknowledgedListener = listener;
|
this.acknowledgedListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect(boolean force) {
|
public void disconnect(boolean force) {
|
||||||
changeStatus(Account.STATUS_OFFLINE);
|
changeStatus(Account.STATUS_OFFLINE);
|
||||||
Log.d(LOGTAG, "disconnecting");
|
Log.d(Config.LOGTAG, "disconnecting");
|
||||||
try {
|
try {
|
||||||
if (force) {
|
if (force) {
|
||||||
socket.close();
|
socket.close();
|
||||||
|
@ -858,20 +889,21 @@ public class XmppConnection implements Runnable {
|
||||||
tagWriter.finish();
|
tagWriter.finish();
|
||||||
try {
|
try {
|
||||||
while (!tagWriter.finished()) {
|
while (!tagWriter.finished()) {
|
||||||
Log.d(LOGTAG, "not yet finished");
|
Log.d(Config.LOGTAG, "not yet finished");
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
}
|
}
|
||||||
tagWriter.writeTag(Tag.end("stream:stream"));
|
tagWriter.writeTag(Tag.end("stream:stream"));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.d(LOGTAG, "io exception during disconnect");
|
Log.d(Config.LOGTAG,
|
||||||
|
"io exception during disconnect");
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Log.d(LOGTAG, "interrupted");
|
Log.d(Config.LOGTAG, "interrupted");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.d(LOGTAG, "io exception during disconnect");
|
Log.d(Config.LOGTAG, "io exception during disconnect");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,10 +916,10 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String findDiscoItemByFeature(String feature) {
|
public String findDiscoItemByFeature(String feature) {
|
||||||
List<String> items = findDiscoItemsByFeature(feature);
|
List<String> items = findDiscoItemsByFeature(feature);
|
||||||
if (items.size()>=1) {
|
if (items.size() >= 1) {
|
||||||
return items.get(0);
|
return items.get(0);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -896,7 +928,7 @@ public class XmppConnection implements Runnable {
|
||||||
public void r() {
|
public void r() {
|
||||||
this.tagWriter.writeStanzaAsync(new RequestPacket(smVersion));
|
this.tagWriter.writeStanzaAsync(new RequestPacket(smVersion));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMucServer() {
|
public String getMucServer() {
|
||||||
return findDiscoItemByFeature("http://jabber.org/protocol/muc");
|
return findDiscoItemByFeature("http://jabber.org/protocol/muc");
|
||||||
}
|
}
|
||||||
|
@ -910,28 +942,29 @@ public class XmppConnection implements Runnable {
|
||||||
public int getAttempt() {
|
public int getAttempt() {
|
||||||
return this.attempt;
|
return this.attempt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Features getFeatures() {
|
public Features getFeatures() {
|
||||||
return this.features;
|
return this.features;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Features {
|
public class Features {
|
||||||
XmppConnection connection;
|
XmppConnection connection;
|
||||||
|
|
||||||
public Features(XmppConnection connection) {
|
public Features(XmppConnection connection) {
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasDiscoFeature(String server, String feature) {
|
private boolean hasDiscoFeature(String server, String feature) {
|
||||||
if (!connection.disco.containsKey(server)) {
|
if (!connection.disco.containsKey(server)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return connection.disco.get(server).contains(feature);
|
return connection.disco.get(server).contains(feature);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean carbons() {
|
public boolean carbons() {
|
||||||
return hasDiscoFeature(account.getServer(), "urn:xmpp:carbons:2");
|
return hasDiscoFeature(account.getServer(), "urn:xmpp:carbons:2");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean sm() {
|
public boolean sm() {
|
||||||
if (connection.streamFeatures == null) {
|
if (connection.streamFeatures == null) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -939,19 +972,21 @@ public class XmppConnection implements Runnable {
|
||||||
return connection.streamFeatures.hasChild("sm");
|
return connection.streamFeatures.hasChild("sm");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean csi() {
|
public boolean csi() {
|
||||||
if (connection.streamFeatures == null) {
|
if (connection.streamFeatures == null) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return connection.streamFeatures.hasChild("csi","urn:xmpp:csi:0");
|
return connection.streamFeatures.hasChild("csi",
|
||||||
|
"urn:xmpp:csi:0");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean pubsub() {
|
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() {
|
public boolean rosterVersioning() {
|
||||||
if (connection.streamFeatures == null) {
|
if (connection.streamFeatures == null) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -959,11 +994,12 @@ public class XmppConnection implements Runnable {
|
||||||
return connection.streamFeatures.hasChild("ver");
|
return connection.streamFeatures.hasChild("ver");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean streamhost() {
|
public boolean streamhost() {
|
||||||
return connection.findDiscoItemByFeature("http://jabber.org/protocol/bytestreams") != null;
|
return connection
|
||||||
|
.findDiscoItemByFeature("http://jabber.org/protocol/bytestreams") != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean compression() {
|
public boolean compression() {
|
||||||
return connection.usingCompression;
|
return connection.usingCompression;
|
||||||
}
|
}
|
||||||
|
@ -978,15 +1014,15 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
return System.currentTimeMillis() - diff;
|
return System.currentTimeMillis() - diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getLastConnect() {
|
public long getLastConnect() {
|
||||||
return this.lastConnect;
|
return this.lastConnect;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getLastPingSent() {
|
public long getLastPingSent() {
|
||||||
return this.lastPingSent;
|
return this.lastPingSent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getLastPacketReceived() {
|
public long getLastPacketReceived() {
|
||||||
return this.lastPaketReceived;
|
return this.lastPaketReceived;
|
||||||
}
|
}
|
||||||
|
@ -994,7 +1030,7 @@ public class XmppConnection implements Runnable {
|
||||||
public void sendActive() {
|
public void sendActive() {
|
||||||
this.sendPacket(new ActivePacket(), null);
|
this.sendPacket(new ActivePacket(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendInactive() {
|
public void sendInactive() {
|
||||||
this.sendPacket(new InactivePacket(), null);
|
this.sendPacket(new InactivePacket(), null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,11 @@ import java.util.List;
|
||||||
import eu.siacs.conversations.xml.Element;
|
import eu.siacs.conversations.xml.Element;
|
||||||
|
|
||||||
public class JingleCandidate {
|
public class JingleCandidate {
|
||||||
|
|
||||||
public static int TYPE_UNKNOWN;
|
public static int TYPE_UNKNOWN;
|
||||||
public static int TYPE_DIRECT = 0;
|
public static int TYPE_DIRECT = 0;
|
||||||
public static int TYPE_PROXY = 1;
|
public static int TYPE_PROXY = 1;
|
||||||
|
|
||||||
private boolean ours;
|
private boolean ours;
|
||||||
private boolean usedByCounterpart = false;
|
private boolean usedByCounterpart = false;
|
||||||
private String cid;
|
private String cid;
|
||||||
|
@ -19,12 +19,12 @@ public class JingleCandidate {
|
||||||
private int type;
|
private int type;
|
||||||
private String jid;
|
private String jid;
|
||||||
private int priority;
|
private int priority;
|
||||||
|
|
||||||
public JingleCandidate(String cid,boolean ours) {
|
public JingleCandidate(String cid, boolean ours) {
|
||||||
this.ours = ours;
|
this.ours = ours;
|
||||||
this.cid = cid;
|
this.cid = cid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCid() {
|
public String getCid() {
|
||||||
return cid;
|
return cid;
|
||||||
}
|
}
|
||||||
|
@ -32,15 +32,15 @@ public class JingleCandidate {
|
||||||
public void setHost(String host) {
|
public void setHost(String host) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHost() {
|
public String getHost() {
|
||||||
return this.host;
|
return this.host;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setJid(String jid) {
|
public void setJid(String jid) {
|
||||||
this.jid = jid;
|
this.jid = jid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getJid() {
|
public String getJid() {
|
||||||
return this.jid;
|
return this.jid;
|
||||||
}
|
}
|
||||||
|
@ -48,15 +48,15 @@ public class JingleCandidate {
|
||||||
public void setPort(int port) {
|
public void setPort(int port) {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPort() {
|
public int getPort() {
|
||||||
return this.port;
|
return this.port;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setType(int type) {
|
public void setType(int type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setType(String type) {
|
public void setType(String type) {
|
||||||
if ("proxy".equals(type)) {
|
if ("proxy".equals(type)) {
|
||||||
this.type = TYPE_PROXY;
|
this.type = TYPE_PROXY;
|
||||||
|
@ -70,42 +70,46 @@ public class JingleCandidate {
|
||||||
public void setPriority(int i) {
|
public void setPriority(int i) {
|
||||||
this.priority = i;
|
this.priority = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPriority() {
|
public int getPriority() {
|
||||||
return this.priority;
|
return this.priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(JingleCandidate other) {
|
public boolean equals(JingleCandidate other) {
|
||||||
return this.getCid().equals(other.getCid());
|
return this.getCid().equals(other.getCid());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equalValues(JingleCandidate other) {
|
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() {
|
public boolean isOurs() {
|
||||||
return ours;
|
return ours;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getType() {
|
public int getType() {
|
||||||
return this.type;
|
return this.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<JingleCandidate> parse(List<Element> canditates) {
|
public static List<JingleCandidate> parse(List<Element> canditates) {
|
||||||
List<JingleCandidate> parsedCandidates = new ArrayList<JingleCandidate>();
|
List<JingleCandidate> parsedCandidates = new ArrayList<JingleCandidate>();
|
||||||
for(Element c : canditates) {
|
for (Element c : canditates) {
|
||||||
parsedCandidates.add(JingleCandidate.parse(c));
|
parsedCandidates.add(JingleCandidate.parse(c));
|
||||||
}
|
}
|
||||||
return parsedCandidates;
|
return parsedCandidates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JingleCandidate parse(Element candidate) {
|
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.setHost(candidate.getAttribute("host"));
|
||||||
parsedCandidate.setJid(candidate.getAttribute("jid"));
|
parsedCandidate.setJid(candidate.getAttribute("jid"));
|
||||||
parsedCandidate.setType(candidate.getAttribute("type"));
|
parsedCandidate.setType(candidate.getAttribute("type"));
|
||||||
parsedCandidate.setPriority(Integer.parseInt(candidate.getAttribute("priority")));
|
parsedCandidate.setPriority(Integer.parseInt(candidate
|
||||||
parsedCandidate.setPort(Integer.parseInt(candidate.getAttribute("port")));
|
.getAttribute("priority")));
|
||||||
|
parsedCandidate
|
||||||
|
.setPort(Integer.parseInt(candidate.getAttribute("port")));
|
||||||
return parsedCandidate;
|
return parsedCandidate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,26 +117,27 @@ public class JingleCandidate {
|
||||||
Element element = new Element("candidate");
|
Element element = new Element("candidate");
|
||||||
element.setAttribute("cid", this.getCid());
|
element.setAttribute("cid", this.getCid());
|
||||||
element.setAttribute("host", this.getHost());
|
element.setAttribute("host", this.getHost());
|
||||||
element.setAttribute("port", ""+this.getPort());
|
element.setAttribute("port", "" + this.getPort());
|
||||||
element.setAttribute("jid", this.getJid());
|
element.setAttribute("jid", this.getJid());
|
||||||
element.setAttribute("priority",""+this.getPriority());
|
element.setAttribute("priority", "" + this.getPriority());
|
||||||
if (this.getType()==TYPE_DIRECT) {
|
if (this.getType() == TYPE_DIRECT) {
|
||||||
element.setAttribute("type","direct");
|
element.setAttribute("type", "direct");
|
||||||
} else if (this.getType()==TYPE_PROXY) {
|
} else if (this.getType() == TYPE_PROXY) {
|
||||||
element.setAttribute("type","proxy");
|
element.setAttribute("type", "proxy");
|
||||||
}
|
}
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flagAsUsedByCounterpart() {
|
public void flagAsUsedByCounterpart() {
|
||||||
this.usedByCounterpart = true;
|
this.usedByCounterpart = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isUsedByCounterpart() {
|
public boolean isUsedByCounterpart() {
|
||||||
return this.usedByCounterpart;
|
return this.usedByCounterpart;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.getHost()+":"+this.getPort()+" (prio="+this.getPriority()+")";
|
return this.getHost() + ":" + this.getPort() + " (prio="
|
||||||
|
+ this.getPriority() + ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import android.content.Intent;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.entities.Conversation;
|
import eu.siacs.conversations.entities.Conversation;
|
||||||
import eu.siacs.conversations.entities.Message;
|
import eu.siacs.conversations.entities.Message;
|
||||||
|
@ -100,10 +101,11 @@ public class JingleConnection {
|
||||||
mXmppConnectionService.markMessage(message,
|
mXmppConnectionService.markMessage(message,
|
||||||
Message.STATUS_RECEIVED);
|
Message.STATUS_RECEIVED);
|
||||||
}
|
}
|
||||||
Log.d("xmppService",
|
Log.d(Config.LOGTAG,
|
||||||
"sucessfully transmitted file:" + file.getAbsolutePath());
|
"sucessfully transmitted file:" + file.getAbsolutePath());
|
||||||
if (message.getEncryption()!=Message.ENCRYPTION_PGP) {
|
if (message.getEncryption() != Message.ENCRYPTION_PGP) {
|
||||||
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
|
Intent intent = new Intent(
|
||||||
|
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
|
||||||
intent.setData(Uri.fromFile(file));
|
intent.setData(Uri.fromFile(file));
|
||||||
mXmppConnectionService.sendBroadcast(intent);
|
mXmppConnectionService.sendBroadcast(intent);
|
||||||
}
|
}
|
||||||
|
@ -121,17 +123,17 @@ public class JingleConnection {
|
||||||
@Override
|
@Override
|
||||||
public void success() {
|
public void success() {
|
||||||
if (initiator.equals(account.getFullJid())) {
|
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);
|
transport.send(file, onFileTransmissionSatusChanged);
|
||||||
} else {
|
} else {
|
||||||
transport.receive(file, onFileTransmissionSatusChanged);
|
transport.receive(file, onFileTransmissionSatusChanged);
|
||||||
Log.d("xmppService", "we were responding. receiving file");
|
Log.d(Config.LOGTAG, "we were responding. receiving file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed() {
|
public void failed() {
|
||||||
Log.d("xmppService", "proxy activation failed");
|
Log.d(Config.LOGTAG, "proxy activation failed");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -177,13 +179,13 @@ public class JingleConnection {
|
||||||
returnResult = this.receiveFallbackToIbb(packet);
|
returnResult = this.receiveFallbackToIbb(packet);
|
||||||
} else {
|
} else {
|
||||||
returnResult = false;
|
returnResult = false;
|
||||||
Log.d("xmppService", "trying to fallback to something unknown"
|
Log.d(Config.LOGTAG, "trying to fallback to something unknown"
|
||||||
+ packet.toString());
|
+ packet.toString());
|
||||||
}
|
}
|
||||||
} else if (packet.isAction("transport-accept")) {
|
} else if (packet.isAction("transport-accept")) {
|
||||||
returnResult = this.receiveTransportAccept(packet);
|
returnResult = this.receiveTransportAccept(packet);
|
||||||
} else {
|
} else {
|
||||||
Log.d("xmppService", "packet arrived in connection. action was "
|
Log.d(Config.LOGTAG, "packet arrived in connection. action was "
|
||||||
+ packet.getAction());
|
+ packet.getAction());
|
||||||
returnResult = false;
|
returnResult = false;
|
||||||
}
|
}
|
||||||
|
@ -224,14 +226,14 @@ public class JingleConnection {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed() {
|
public void failed() {
|
||||||
Log.d("xmppService",
|
Log.d(Config.LOGTAG,
|
||||||
"connection to our own primary candidete failed");
|
"connection to our own primary candidete failed");
|
||||||
sendInitRequest();
|
sendInitRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void established() {
|
public void established() {
|
||||||
Log.d("xmppService",
|
Log.d(Config.LOGTAG,
|
||||||
"succesfully connected to our own primary candidate");
|
"succesfully connected to our own primary candidate");
|
||||||
mergeCandidate(candidate);
|
mergeCandidate(candidate);
|
||||||
sendInitRequest();
|
sendInitRequest();
|
||||||
|
@ -239,7 +241,7 @@ public class JingleConnection {
|
||||||
});
|
});
|
||||||
mergeCandidate(candidate);
|
mergeCandidate(candidate);
|
||||||
} else {
|
} else {
|
||||||
Log.d("xmppService",
|
Log.d(Config.LOGTAG,
|
||||||
"no primary candidate of our own was found");
|
"no primary candidate of our own was found");
|
||||||
sendInitRequest();
|
sendInitRequest();
|
||||||
}
|
}
|
||||||
|
@ -288,7 +290,7 @@ public class JingleConnection {
|
||||||
filename[filename.length - 2])) {
|
filename[filename.length - 2])) {
|
||||||
supportedFile = true;
|
supportedFile = true;
|
||||||
if (filename[filename.length - 1].equals("otr")) {
|
if (filename[filename.length - 1].equals("otr")) {
|
||||||
Log.d("xmppService", "receiving otr file");
|
Log.d(Config.LOGTAG, "receiving otr file");
|
||||||
this.message
|
this.message
|
||||||
.setEncryption(Message.ENCRYPTION_OTR);
|
.setEncryption(Message.ENCRYPTION_OTR);
|
||||||
} else {
|
} else {
|
||||||
|
@ -304,13 +306,13 @@ public class JingleConnection {
|
||||||
conversation.getMessages().add(message);
|
conversation.getMessages().add(message);
|
||||||
if (size <= this.mJingleConnectionManager
|
if (size <= this.mJingleConnectionManager
|
||||||
.getAutoAcceptFileSize()) {
|
.getAutoAcceptFileSize()) {
|
||||||
Log.d("xmppService", "auto accepting file from "
|
Log.d(Config.LOGTAG, "auto accepting file from "
|
||||||
+ packet.getFrom());
|
+ packet.getFrom());
|
||||||
this.acceptedAutomatically = true;
|
this.acceptedAutomatically = true;
|
||||||
this.sendAccept();
|
this.sendAccept();
|
||||||
} else {
|
} else {
|
||||||
message.markUnread();
|
message.markUnread();
|
||||||
Log.d("xmppService",
|
Log.d(Config.LOGTAG,
|
||||||
"not auto accepting new file offer with size: "
|
"not auto accepting new file offer with size: "
|
||||||
+ size
|
+ size
|
||||||
+ " allowed size:"
|
+ " allowed size:"
|
||||||
|
@ -400,7 +402,7 @@ public class JingleConnection {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed() {
|
public void failed() {
|
||||||
Log.d("xmppService",
|
Log.d(Config.LOGTAG,
|
||||||
"connection to our own primary candidate failed");
|
"connection to our own primary candidate failed");
|
||||||
content.socks5transport().setChildren(
|
content.socks5transport().setChildren(
|
||||||
getCandidatesAsElements());
|
getCandidatesAsElements());
|
||||||
|
@ -411,7 +413,7 @@ public class JingleConnection {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void established() {
|
public void established() {
|
||||||
Log.d("xmppService",
|
Log.d(Config.LOGTAG,
|
||||||
"connected to primary candidate");
|
"connected to primary candidate");
|
||||||
mergeCandidate(candidate);
|
mergeCandidate(candidate);
|
||||||
content.socks5transport().setChildren(
|
content.socks5transport().setChildren(
|
||||||
|
@ -422,7 +424,7 @@ public class JingleConnection {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Log.d("xmppService",
|
Log.d(Config.LOGTAG,
|
||||||
"did not find a primary candidate for ourself");
|
"did not find a primary candidate for ourself");
|
||||||
content.socks5transport().setChildren(
|
content.socks5transport().setChildren(
|
||||||
getCandidatesAsElements());
|
getCandidatesAsElements());
|
||||||
|
@ -446,7 +448,7 @@ public class JingleConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendJinglePacket(JinglePacket packet) {
|
private void sendJinglePacket(JinglePacket packet) {
|
||||||
// Log.d("xmppService",packet.toString());
|
// Log.d(Config.LOGTAG,packet.toString());
|
||||||
account.getXmppConnection().sendIqPacket(packet, responseListener);
|
account.getXmppConnection().sendIqPacket(packet, responseListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,14 +472,14 @@ public class JingleConnection {
|
||||||
} else {
|
} else {
|
||||||
String cid = content.socks5transport()
|
String cid = content.socks5transport()
|
||||||
.findChild("activated").getAttribute("cid");
|
.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");
|
+ ")prior to choosing our own transport");
|
||||||
JingleSocks5Transport connection = this.connections
|
JingleSocks5Transport connection = this.connections
|
||||||
.get(cid);
|
.get(cid);
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
connection.setActivated(true);
|
connection.setActivated(true);
|
||||||
} else {
|
} else {
|
||||||
Log.d("xmppService", "activated connection not found");
|
Log.d(Config.LOGTAG, "activated connection not found");
|
||||||
this.sendCancel();
|
this.sendCancel();
|
||||||
this.cancel();
|
this.cancel();
|
||||||
}
|
}
|
||||||
|
@ -487,7 +489,7 @@ public class JingleConnection {
|
||||||
onProxyActivated.failed();
|
onProxyActivated.failed();
|
||||||
return true;
|
return true;
|
||||||
} else if (content.socks5transport().hasChild("candidate-error")) {
|
} else if (content.socks5transport().hasChild("candidate-error")) {
|
||||||
Log.d("xmppService", "received candidate error");
|
Log.d(Config.LOGTAG, "received candidate error");
|
||||||
this.receivedCandidate = true;
|
this.receivedCandidate = true;
|
||||||
if ((status == STATUS_ACCEPTED) && (this.sentCandidate)) {
|
if ((status == STATUS_ACCEPTED) && (this.sentCandidate)) {
|
||||||
this.connect();
|
this.connect();
|
||||||
|
@ -497,14 +499,14 @@ public class JingleConnection {
|
||||||
String cid = content.socks5transport()
|
String cid = content.socks5transport()
|
||||||
.findChild("candidate-used").getAttribute("cid");
|
.findChild("candidate-used").getAttribute("cid");
|
||||||
if (cid != null) {
|
if (cid != null) {
|
||||||
Log.d("xmppService", "candidate used by counterpart:" + cid);
|
Log.d(Config.LOGTAG, "candidate used by counterpart:" + cid);
|
||||||
JingleCandidate candidate = getCandidate(cid);
|
JingleCandidate candidate = getCandidate(cid);
|
||||||
candidate.flagAsUsedByCounterpart();
|
candidate.flagAsUsedByCounterpart();
|
||||||
this.receivedCandidate = true;
|
this.receivedCandidate = true;
|
||||||
if ((status == STATUS_ACCEPTED) && (this.sentCandidate)) {
|
if ((status == STATUS_ACCEPTED) && (this.sentCandidate)) {
|
||||||
this.connect();
|
this.connect();
|
||||||
} else {
|
} else {
|
||||||
Log.d("xmppService",
|
Log.d(Config.LOGTAG,
|
||||||
"ignoring because file is already in transmission or we havent sent our candidate yet");
|
"ignoring because file is already in transmission or we havent sent our candidate yet");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -523,7 +525,7 @@ public class JingleConnection {
|
||||||
final JingleSocks5Transport connection = chooseConnection();
|
final JingleSocks5Transport connection = chooseConnection();
|
||||||
this.transport = connection;
|
this.transport = connection;
|
||||||
if (connection == null) {
|
if (connection == null) {
|
||||||
Log.d("xmppService", "could not find suitable candidate");
|
Log.d(Config.LOGTAG, "could not find suitable candidate");
|
||||||
this.disconnect();
|
this.disconnect();
|
||||||
if (this.initiator.equals(account.getFullJid())) {
|
if (this.initiator.equals(account.getFullJid())) {
|
||||||
this.sendFallbackToIbb();
|
this.sendFallbackToIbb();
|
||||||
|
@ -532,7 +534,7 @@ public class JingleConnection {
|
||||||
this.status = STATUS_TRANSMITTING;
|
this.status = STATUS_TRANSMITTING;
|
||||||
if (connection.needsActivation()) {
|
if (connection.needsActivation()) {
|
||||||
if (connection.getCandidate().isOurs()) {
|
if (connection.getCandidate().isOurs()) {
|
||||||
Log.d("xmppService", "candidate "
|
Log.d(Config.LOGTAG, "candidate "
|
||||||
+ connection.getCandidate().getCid()
|
+ connection.getCandidate().getCid()
|
||||||
+ " was our proxy. going to activate");
|
+ " was our proxy. going to activate");
|
||||||
IqPacket activation = new IqPacket(IqPacket.TYPE_SET);
|
IqPacket activation = new IqPacket(IqPacket.TYPE_SET);
|
||||||
|
@ -557,17 +559,17 @@ public class JingleConnection {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Log.d("xmppService",
|
Log.d(Config.LOGTAG,
|
||||||
"candidate "
|
"candidate "
|
||||||
+ connection.getCandidate().getCid()
|
+ connection.getCandidate().getCid()
|
||||||
+ " was a proxy. waiting for other party to activate");
|
+ " was a proxy. waiting for other party to activate");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (initiator.equals(account.getFullJid())) {
|
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);
|
connection.send(file, onFileTransmissionSatusChanged);
|
||||||
} else {
|
} else {
|
||||||
Log.d("xmppService", "we were responding. receiving file");
|
Log.d(Config.LOGTAG, "we were responding. receiving file");
|
||||||
connection.receive(file, onFileTransmissionSatusChanged);
|
connection.receive(file, onFileTransmissionSatusChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -579,11 +581,11 @@ public class JingleConnection {
|
||||||
for (Entry<String, JingleSocks5Transport> cursor : connections
|
for (Entry<String, JingleSocks5Transport> cursor : connections
|
||||||
.entrySet()) {
|
.entrySet()) {
|
||||||
JingleSocks5Transport currentConnection = cursor.getValue();
|
JingleSocks5Transport currentConnection = cursor.getValue();
|
||||||
// Log.d("xmppService","comparing candidate: "+currentConnection.getCandidate().toString());
|
// Log.d(Config.LOGTAG,"comparing candidate: "+currentConnection.getCandidate().toString());
|
||||||
if (currentConnection.isEstablished()
|
if (currentConnection.isEstablished()
|
||||||
&& (currentConnection.getCandidate().isUsedByCounterpart() || (!currentConnection
|
&& (currentConnection.getCandidate().isUsedByCounterpart() || (!currentConnection
|
||||||
.getCandidate().isOurs()))) {
|
.getCandidate().isOurs()))) {
|
||||||
// Log.d("xmppService","is usable");
|
// Log.d(Config.LOGTAG,"is usable");
|
||||||
if (connection == null) {
|
if (connection == null) {
|
||||||
connection = currentConnection;
|
connection = currentConnection;
|
||||||
} else {
|
} else {
|
||||||
|
@ -592,7 +594,7 @@ public class JingleConnection {
|
||||||
connection = currentConnection;
|
connection = currentConnection;
|
||||||
} else if (connection.getCandidate().getPriority() == currentConnection
|
} else if (connection.getCandidate().getPriority() == currentConnection
|
||||||
.getCandidate().getPriority()) {
|
.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 (initiator.equals(account.getFullJid())) {
|
||||||
if (currentConnection.getCandidate().isOurs()) {
|
if (currentConnection.getCandidate().isOurs()) {
|
||||||
connection = currentConnection;
|
connection = currentConnection;
|
||||||
|
@ -672,7 +674,7 @@ public class JingleConnection {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed() {
|
public void failed() {
|
||||||
Log.d("xmppService", "ibb open failed");
|
Log.d(Config.LOGTAG, "ibb open failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -742,7 +744,7 @@ public class JingleConnection {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed() {
|
public void failed() {
|
||||||
Log.d("xmppService",
|
Log.d(Config.LOGTAG,
|
||||||
"connection failed with " + candidate.getHost() + ":"
|
"connection failed with " + candidate.getHost() + ":"
|
||||||
+ candidate.getPort());
|
+ candidate.getPort());
|
||||||
connectNextCandidate();
|
connectNextCandidate();
|
||||||
|
@ -750,7 +752,7 @@ public class JingleConnection {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void established() {
|
public void established() {
|
||||||
Log.d("xmppService",
|
Log.d(Config.LOGTAG,
|
||||||
"established connection with " + candidate.getHost()
|
"established connection with " + candidate.getHost()
|
||||||
+ ":" + candidate.getPort());
|
+ ":" + candidate.getPort());
|
||||||
sendCandidateUsed(candidate.getCid());
|
sendCandidateUsed(candidate.getCid());
|
||||||
|
@ -874,7 +876,7 @@ public class JingleConnection {
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
} else {
|
} else {
|
||||||
Log.d("xmppService", "status (" + status + ") was not ok");
|
Log.d(Config.LOGTAG, "status (" + status + ") was not ok");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.entities.Message;
|
import eu.siacs.conversations.entities.Message;
|
||||||
import eu.siacs.conversations.services.XmppConnectionService;
|
import eu.siacs.conversations.services.XmppConnectionService;
|
||||||
|
@ -33,18 +34,20 @@ public class JingleConnectionManager {
|
||||||
public void deliverPacket(Account account, JinglePacket packet) {
|
public void deliverPacket(Account account, JinglePacket packet) {
|
||||||
if (packet.isAction("session-initiate")) {
|
if (packet.isAction("session-initiate")) {
|
||||||
JingleConnection connection = new JingleConnection(this);
|
JingleConnection connection = new JingleConnection(this);
|
||||||
connection.init(account,packet);
|
connection.init(account, packet);
|
||||||
connections.add(connection);
|
connections.add(connection);
|
||||||
} else {
|
} else {
|
||||||
for (JingleConnection connection : connections) {
|
for (JingleConnection connection : connections) {
|
||||||
if (connection.getAccountJid().equals(account.getFullJid()) && connection
|
if (connection.getAccountJid().equals(account.getFullJid())
|
||||||
.getSessionId().equals(packet.getSessionId()) && connection
|
&& connection.getSessionId().equals(
|
||||||
.getCounterPart().equals(packet.getFrom())) {
|
packet.getSessionId())
|
||||||
|
&& connection.getCounterPart().equals(packet.getFrom())) {
|
||||||
connection.deliverPacket(packet);
|
connection.deliverPacket(packet);
|
||||||
return;
|
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);
|
this.connections.add(connection);
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finishConnection(JingleConnection connection) {
|
public void finishConnection(JingleConnection connection) {
|
||||||
this.connections.remove(connection);
|
this.connections.remove(connection);
|
||||||
}
|
}
|
||||||
|
@ -90,12 +93,17 @@ public class JingleConnectionManager {
|
||||||
.findChild("streamhost",
|
.findChild("streamhost",
|
||||||
"http://jabber.org/protocol/bytestreams");
|
"http://jabber.org/protocol/bytestreams");
|
||||||
if (streamhost != null) {
|
if (streamhost != null) {
|
||||||
JingleCandidate candidate = new JingleCandidate(nextRandomId(),true);
|
JingleCandidate candidate = new JingleCandidate(
|
||||||
candidate.setHost(streamhost.getAttribute("host"));
|
nextRandomId(), true);
|
||||||
candidate.setPort(Integer.parseInt(streamhost.getAttribute("port")));
|
candidate.setHost(streamhost
|
||||||
candidate.setType(JingleCandidate.TYPE_PROXY);
|
.getAttribute("host"));
|
||||||
|
candidate.setPort(Integer
|
||||||
|
.parseInt(streamhost
|
||||||
|
.getAttribute("port")));
|
||||||
|
candidate
|
||||||
|
.setType(JingleCandidate.TYPE_PROXY);
|
||||||
candidate.setJid(proxy);
|
candidate.setJid(proxy);
|
||||||
candidate.setPriority(655360+65535);
|
candidate.setPriority(655360 + 65535);
|
||||||
primaryCandidates.put(account.getJid(),
|
primaryCandidates.put(account.getJid(),
|
||||||
candidate);
|
candidate);
|
||||||
listener.onPrimaryCandidateFound(true,
|
listener.onPrimaryCandidateFound(true,
|
||||||
|
@ -119,9 +127,10 @@ public class JingleConnectionManager {
|
||||||
public String nextRandomId() {
|
public String nextRandomId() {
|
||||||
return new BigInteger(50, random).toString(32);
|
return new BigInteger(50, random).toString(32);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getAutoAcceptFileSize() {
|
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 {
|
try {
|
||||||
return Long.parseLong(config);
|
return Long.parseLong(config);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
|
@ -132,32 +141,35 @@ public class JingleConnectionManager {
|
||||||
public void deliverIbbPacket(Account account, IqPacket packet) {
|
public void deliverIbbPacket(Account account, IqPacket packet) {
|
||||||
String sid = null;
|
String sid = null;
|
||||||
Element payload = null;
|
Element payload = null;
|
||||||
if (packet.hasChild("open","http://jabber.org/protocol/ibb")) {
|
if (packet.hasChild("open", "http://jabber.org/protocol/ibb")) {
|
||||||
payload = packet.findChild("open","http://jabber.org/protocol/ibb");
|
payload = packet
|
||||||
|
.findChild("open", "http://jabber.org/protocol/ibb");
|
||||||
sid = payload.getAttribute("sid");
|
sid = payload.getAttribute("sid");
|
||||||
} else if (packet.hasChild("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");
|
payload = packet
|
||||||
|
.findChild("data", "http://jabber.org/protocol/ibb");
|
||||||
sid = payload.getAttribute("sid");
|
sid = payload.getAttribute("sid");
|
||||||
}
|
}
|
||||||
if (sid!=null) {
|
if (sid != null) {
|
||||||
for (JingleConnection connection : connections) {
|
for (JingleConnection connection : connections) {
|
||||||
if (connection.hasTransportId(sid)) {
|
if (connection.hasTransportId(sid)) {
|
||||||
JingleTransport transport = connection.getTransport();
|
JingleTransport transport = connection.getTransport();
|
||||||
if (transport instanceof JingleInbandTransport) {
|
if (transport instanceof JingleInbandTransport) {
|
||||||
JingleInbandTransport inbandTransport = (JingleInbandTransport) transport;
|
JingleInbandTransport inbandTransport = (JingleInbandTransport) transport;
|
||||||
inbandTransport.deliverPayload(packet,payload);
|
inbandTransport.deliverPayload(packet, payload);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log.d("xmppService","couldnt deliver payload: "+payload.toString());
|
Log.d(Config.LOGTAG,
|
||||||
|
"couldnt deliver payload: " + payload.toString());
|
||||||
} else {
|
} 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() {
|
public void cancelInTransmission() {
|
||||||
for(JingleConnection connection : this.connections) {
|
for (JingleConnection connection : this.connections) {
|
||||||
if (connection.getStatus() == JingleConnection.STATUS_TRANSMITTING) {
|
if (connection.getStatus() == JingleConnection.STATUS_TRANSMITTING) {
|
||||||
connection.cancel();
|
connection.cancel();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,60 +5,63 @@ import java.security.Key;
|
||||||
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.utils.CryptoHelper;
|
import eu.siacs.conversations.utils.CryptoHelper;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public class JingleFile extends File {
|
public class JingleFile extends File {
|
||||||
|
|
||||||
private static final long serialVersionUID = 2247012619505115863L;
|
private static final long serialVersionUID = 2247012619505115863L;
|
||||||
|
|
||||||
private long expectedSize = 0;
|
private long expectedSize = 0;
|
||||||
private String sha1sum;
|
private String sha1sum;
|
||||||
private Key aeskey;
|
private Key aeskey;
|
||||||
|
|
||||||
public JingleFile(String path) {
|
public JingleFile(String path) {
|
||||||
super(path);
|
super(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getSize() {
|
public long getSize() {
|
||||||
return super.length();
|
return super.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getExpectedSize() {
|
public long getExpectedSize() {
|
||||||
if (this.aeskey!=null) {
|
if (this.aeskey != null) {
|
||||||
return (this.expectedSize/16 + 1) * 16;
|
return (this.expectedSize / 16 + 1) * 16;
|
||||||
} else {
|
} else {
|
||||||
return this.expectedSize;
|
return this.expectedSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setExpectedSize(long size) {
|
public void setExpectedSize(long size) {
|
||||||
this.expectedSize = size;
|
this.expectedSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSha1Sum() {
|
public String getSha1Sum() {
|
||||||
return this.sha1sum;
|
return this.sha1sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSha1Sum(String sum) {
|
public void setSha1Sum(String sum) {
|
||||||
this.sha1sum = sum;
|
this.sha1sum = sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setKey(byte[] key) {
|
public void setKey(byte[] key) {
|
||||||
if (key.length>=32) {
|
if (key.length >= 32) {
|
||||||
byte[] secretKey = new byte[32];
|
byte[] secretKey = new byte[32];
|
||||||
System.arraycopy(key, 0, secretKey, 0, 32);
|
System.arraycopy(key, 0, secretKey, 0, 32);
|
||||||
this.aeskey = new SecretKeySpec(secretKey, "AES");
|
this.aeskey = new SecretKeySpec(secretKey, "AES");
|
||||||
} else if (key.length>=16) {
|
} else if (key.length >= 16) {
|
||||||
byte[] secretKey = new byte[16];
|
byte[] secretKey = new byte[16];
|
||||||
System.arraycopy(key, 0, secretKey, 0, 16);
|
System.arraycopy(key, 0, secretKey, 0, 16);
|
||||||
this.aeskey = new SecretKeySpec(secretKey, "AES");
|
this.aeskey = new SecretKeySpec(secretKey, "AES");
|
||||||
} else {
|
} 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() {
|
public Key getKey() {
|
||||||
return this.aeskey;
|
return this.aeskey;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ public class JingleInbandTransport extends JingleTransport {
|
||||||
private OutputStream fileOutputStream;
|
private OutputStream fileOutputStream;
|
||||||
private long remainingSize;
|
private long remainingSize;
|
||||||
private MessageDigest digest;
|
private MessageDigest digest;
|
||||||
|
|
||||||
private OnFileTransmissionStatusChanged onFileTransmissionStatusChanged;
|
private OnFileTransmissionStatusChanged onFileTransmissionStatusChanged;
|
||||||
|
|
||||||
private OnIqPacketReceived onAckReceived = new OnIqPacketReceived() {
|
private OnIqPacketReceived onAckReceived = new OnIqPacketReceived() {
|
||||||
|
@ -77,7 +77,8 @@ public class JingleInbandTransport extends JingleTransport {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void receive(JingleFile file, OnFileTransmissionStatusChanged callback) {
|
public void receive(JingleFile file,
|
||||||
|
OnFileTransmissionStatusChanged callback) {
|
||||||
this.onFileTransmissionStatusChanged = callback;
|
this.onFileTransmissionStatusChanged = callback;
|
||||||
this.file = file;
|
this.file = file;
|
||||||
try {
|
try {
|
||||||
|
@ -86,7 +87,7 @@ public class JingleInbandTransport extends JingleTransport {
|
||||||
file.getParentFile().mkdirs();
|
file.getParentFile().mkdirs();
|
||||||
file.createNewFile();
|
file.createNewFile();
|
||||||
this.fileOutputStream = getOutputStream(file);
|
this.fileOutputStream = getOutputStream(file);
|
||||||
if (this.fileOutputStream==null) {
|
if (this.fileOutputStream == null) {
|
||||||
callback.onFileTransferAborted();
|
callback.onFileTransferAborted();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -106,7 +107,7 @@ public class JingleInbandTransport extends JingleTransport {
|
||||||
this.digest = MessageDigest.getInstance("SHA-1");
|
this.digest = MessageDigest.getInstance("SHA-1");
|
||||||
this.digest.reset();
|
this.digest.reset();
|
||||||
fileInputStream = this.getInputStream(file);
|
fileInputStream = this.getInputStream(file);
|
||||||
if (fileInputStream==null) {
|
if (fileInputStream == null) {
|
||||||
callback.onFileTransferAborted();
|
callback.onFileTransferAborted();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -150,7 +151,8 @@ public class JingleInbandTransport extends JingleTransport {
|
||||||
try {
|
try {
|
||||||
byte[] buffer = Base64.decode(data, Base64.NO_WRAP);
|
byte[] buffer = Base64.decode(data, Base64.NO_WRAP);
|
||||||
if (this.remainingSize < buffer.length) {
|
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;
|
this.remainingSize -= buffer.length;
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,8 @@ public class JingleSocks5Transport extends JingleTransport {
|
||||||
private boolean activated = false;
|
private boolean activated = false;
|
||||||
protected Socket socket;
|
protected Socket socket;
|
||||||
|
|
||||||
public JingleSocks5Transport(JingleConnection jingleConnection, JingleCandidate candidate) {
|
public JingleSocks5Transport(JingleConnection jingleConnection,
|
||||||
|
JingleCandidate candidate) {
|
||||||
this.candidate = candidate;
|
this.candidate = candidate;
|
||||||
try {
|
try {
|
||||||
MessageDigest mDigest = MessageDigest.getInstance("SHA-1");
|
MessageDigest mDigest = MessageDigest.getInstance("SHA-1");
|
||||||
|
@ -44,11 +45,12 @@ public class JingleSocks5Transport extends JingleTransport {
|
||||||
|
|
||||||
public void connect(final OnTransportConnected callback) {
|
public void connect(final OnTransportConnected callback) {
|
||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
socket = new Socket(candidate.getHost(), candidate.getPort());
|
socket = new Socket(candidate.getHost(),
|
||||||
|
candidate.getPort());
|
||||||
inputStream = socket.getInputStream();
|
inputStream = socket.getInputStream();
|
||||||
outputStream = socket.getOutputStream();
|
outputStream = socket.getOutputStream();
|
||||||
byte[] login = { 0x05, 0x01, 0x00 };
|
byte[] login = { 0x05, 0x01, 0x00 };
|
||||||
|
@ -57,8 +59,9 @@ public class JingleSocks5Transport extends JingleTransport {
|
||||||
outputStream.write(login);
|
outputStream.write(login);
|
||||||
inputStream.read(reply);
|
inputStream.read(reply);
|
||||||
if (Arrays.equals(reply, expectedReply)) {
|
if (Arrays.equals(reply, expectedReply)) {
|
||||||
String connect = "" + '\u0005' + '\u0001' + '\u0000' + '\u0003'
|
String connect = "" + '\u0005' + '\u0001' + '\u0000'
|
||||||
+ '\u0028' + destination + '\u0000' + '\u0000';
|
+ '\u0003' + '\u0028' + destination + '\u0000'
|
||||||
|
+ '\u0000';
|
||||||
outputStream.write(connect.getBytes());
|
outputStream.write(connect.getBytes());
|
||||||
byte[] result = new byte[2];
|
byte[] result = new byte[2];
|
||||||
inputStream.read(result);
|
inputStream.read(result);
|
||||||
|
@ -80,12 +83,13 @@ public class JingleSocks5Transport extends JingleTransport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void send(final JingleFile file, final OnFileTransmissionStatusChanged callback) {
|
public void send(final JingleFile file,
|
||||||
|
final OnFileTransmissionStatusChanged callback) {
|
||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
InputStream fileInputStream = null;
|
InputStream fileInputStream = null;
|
||||||
|
@ -93,7 +97,7 @@ public class JingleSocks5Transport extends JingleTransport {
|
||||||
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||||
digest.reset();
|
digest.reset();
|
||||||
fileInputStream = getInputStream(file);
|
fileInputStream = getInputStream(file);
|
||||||
if (fileInputStream==null) {
|
if (fileInputStream == null) {
|
||||||
callback.onFileTransferAborted();
|
callback.onFileTransferAborted();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +109,7 @@ public class JingleSocks5Transport extends JingleTransport {
|
||||||
}
|
}
|
||||||
outputStream.flush();
|
outputStream.flush();
|
||||||
file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
|
file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
|
||||||
if (callback!=null) {
|
if (callback != null) {
|
||||||
callback.onFileTransmitted(file);
|
callback.onFileTransmitted(file);
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
|
@ -125,12 +129,13 @@ public class JingleSocks5Transport extends JingleTransport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void receive(final JingleFile file, final OnFileTransmissionStatusChanged callback) {
|
public void receive(final JingleFile file,
|
||||||
|
final OnFileTransmissionStatusChanged callback) {
|
||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
@ -141,22 +146,22 @@ public class JingleSocks5Transport extends JingleTransport {
|
||||||
file.getParentFile().mkdirs();
|
file.getParentFile().mkdirs();
|
||||||
file.createNewFile();
|
file.createNewFile();
|
||||||
OutputStream fileOutputStream = getOutputStream(file);
|
OutputStream fileOutputStream = getOutputStream(file);
|
||||||
if (fileOutputStream==null) {
|
if (fileOutputStream == null) {
|
||||||
callback.onFileTransferAborted();
|
callback.onFileTransferAborted();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
long remainingSize = file.getExpectedSize();
|
long remainingSize = file.getExpectedSize();
|
||||||
byte[] buffer = new byte[8192];
|
byte[] buffer = new byte[8192];
|
||||||
int count = buffer.length;
|
int count = buffer.length;
|
||||||
while(remainingSize > 0) {
|
while (remainingSize > 0) {
|
||||||
count = inputStream.read(buffer);
|
count = inputStream.read(buffer);
|
||||||
if (count==-1) {
|
if (count == -1) {
|
||||||
callback.onFileTransferAborted();
|
callback.onFileTransferAborted();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
fileOutputStream.write(buffer, 0, count);
|
fileOutputStream.write(buffer, 0, count);
|
||||||
digest.update(buffer, 0, count);
|
digest.update(buffer, 0, count);
|
||||||
remainingSize-=count;
|
remainingSize -= count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fileOutputStream.flush();
|
fileOutputStream.flush();
|
||||||
|
@ -177,25 +182,25 @@ public class JingleSocks5Transport extends JingleTransport {
|
||||||
public boolean isProxy() {
|
public boolean isProxy() {
|
||||||
return this.candidate.getType() == JingleCandidate.TYPE_PROXY;
|
return this.candidate.getType() == JingleCandidate.TYPE_PROXY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean needsActivation() {
|
public boolean needsActivation() {
|
||||||
return (this.isProxy() && !this.activated);
|
return (this.isProxy() && !this.activated);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
if (this.socket!=null) {
|
if (this.socket != null) {
|
||||||
try {
|
try {
|
||||||
this.socket.close();
|
this.socket.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEstablished() {
|
public boolean isEstablished() {
|
||||||
return this.isEstablished;
|
return this.isEstablished;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JingleCandidate getCandidate() {
|
public JingleCandidate getCandidate() {
|
||||||
return this.candidate;
|
return this.candidate;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,61 +15,72 @@ import javax.crypto.CipherInputStream;
|
||||||
import javax.crypto.NoSuchPaddingException;
|
import javax.crypto.NoSuchPaddingException;
|
||||||
import javax.crypto.spec.IvParameterSpec;
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public abstract class JingleTransport {
|
public abstract class JingleTransport {
|
||||||
public abstract void connect(final OnTransportConnected callback);
|
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);
|
public abstract void receive(final JingleFile file,
|
||||||
private byte[] iv = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0xf};
|
final OnFileTransmissionStatusChanged callback);
|
||||||
|
|
||||||
protected InputStream getInputStream(JingleFile file) throws FileNotFoundException {
|
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) {
|
if (file.getKey() == null) {
|
||||||
return new FileInputStream(file);
|
return new FileInputStream(file);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
IvParameterSpec ips = new IvParameterSpec(iv);
|
IvParameterSpec ips = new IvParameterSpec(iv);
|
||||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, file.getKey(),ips);
|
cipher.init(Cipher.ENCRYPT_MODE, file.getKey(), ips);
|
||||||
Log.d("xmppService","opening encrypted input stream");
|
Log.d(Config.LOGTAG, "opening encrypted input stream");
|
||||||
return new CipherInputStream(new FileInputStream(file), cipher);
|
return new CipherInputStream(new FileInputStream(file), cipher);
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
Log.d("xmppService","no such algo: "+e.getMessage());
|
Log.d(Config.LOGTAG, "no such algo: " + e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
} catch (NoSuchPaddingException e) {
|
} catch (NoSuchPaddingException e) {
|
||||||
Log.d("xmppService","no such padding: "+e.getMessage());
|
Log.d(Config.LOGTAG, "no such padding: " + e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
} catch (InvalidKeyException e) {
|
} catch (InvalidKeyException e) {
|
||||||
Log.d("xmppService","invalid key: "+e.getMessage());
|
Log.d(Config.LOGTAG, "invalid key: " + e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
} catch (InvalidAlgorithmParameterException e) {
|
} catch (InvalidAlgorithmParameterException e) {
|
||||||
Log.d("xmppService","invavid iv:"+e.getMessage());
|
Log.d(Config.LOGTAG, "invavid iv:" + e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected OutputStream getOutputStream(JingleFile file) throws FileNotFoundException {
|
protected OutputStream getOutputStream(JingleFile file)
|
||||||
|
throws FileNotFoundException {
|
||||||
if (file.getKey() == null) {
|
if (file.getKey() == null) {
|
||||||
return new FileOutputStream(file);
|
return new FileOutputStream(file);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
IvParameterSpec ips = new IvParameterSpec(iv);
|
IvParameterSpec ips = new IvParameterSpec(iv);
|
||||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||||
cipher.init(Cipher.DECRYPT_MODE, file.getKey(),ips);
|
cipher.init(Cipher.DECRYPT_MODE, file.getKey(), ips);
|
||||||
Log.d("xmppService","opening encrypted output stream");
|
Log.d(Config.LOGTAG, "opening encrypted output stream");
|
||||||
return new CipherOutputStream(new FileOutputStream(file), cipher);
|
return new CipherOutputStream(new FileOutputStream(file),
|
||||||
|
cipher);
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
Log.d("xmppService","no such algo: "+e.getMessage());
|
Log.d(Config.LOGTAG, "no such algo: " + e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
} catch (NoSuchPaddingException e) {
|
} catch (NoSuchPaddingException e) {
|
||||||
Log.d("xmppService","no such padding: "+e.getMessage());
|
Log.d(Config.LOGTAG, "no such padding: " + e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
} catch (InvalidKeyException e) {
|
} catch (InvalidKeyException e) {
|
||||||
Log.d("xmppService","invalid key: "+e.getMessage());
|
Log.d(Config.LOGTAG, "invalid key: " + e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
} catch (InvalidAlgorithmParameterException e) {
|
} catch (InvalidAlgorithmParameterException e) {
|
||||||
Log.d("xmppService","invavid iv:"+e.getMessage());
|
Log.d(Config.LOGTAG, "invavid iv:" + e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,5 +2,6 @@ package eu.siacs.conversations.xmpp.jingle;
|
||||||
|
|
||||||
public interface OnFileTransmissionStatusChanged {
|
public interface OnFileTransmissionStatusChanged {
|
||||||
public void onFileTransmitted(JingleFile file);
|
public void onFileTransmitted(JingleFile file);
|
||||||
|
|
||||||
public void onFileTransferAborted();
|
public void onFileTransferAborted();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package eu.siacs.conversations.xmpp.jingle;
|
package eu.siacs.conversations.xmpp.jingle;
|
||||||
|
|
||||||
public interface OnPrimaryCandidateFound {
|
public interface OnPrimaryCandidateFound {
|
||||||
public void onPrimaryCandidateFound(boolean success, JingleCandidate canditate);
|
public void onPrimaryCandidateFound(boolean success,
|
||||||
|
JingleCandidate canditate);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,5 +2,6 @@ package eu.siacs.conversations.xmpp.jingle;
|
||||||
|
|
||||||
public interface OnTransportConnected {
|
public interface OnTransportConnected {
|
||||||
public void failed();
|
public void failed();
|
||||||
|
|
||||||
public void established();
|
public void established();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,17 +4,17 @@ import eu.siacs.conversations.xml.Element;
|
||||||
import eu.siacs.conversations.xmpp.jingle.JingleFile;
|
import eu.siacs.conversations.xmpp.jingle.JingleFile;
|
||||||
|
|
||||||
public class Content extends Element {
|
public class Content extends Element {
|
||||||
|
|
||||||
private String transportId;
|
private String transportId;
|
||||||
|
|
||||||
private Content(String name) {
|
private Content(String name) {
|
||||||
super(name);
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Content() {
|
public Content() {
|
||||||
super("content");
|
super("content");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Content(String creator, String name) {
|
public Content(String creator, String name) {
|
||||||
super("content");
|
super("content");
|
||||||
this.setAttribute("creator", creator);
|
this.setAttribute("creator", creator);
|
||||||
|
@ -24,39 +24,43 @@ public class Content extends Element {
|
||||||
public void setTransportId(String sid) {
|
public void setTransportId(String sid) {
|
||||||
this.transportId = sid;
|
this.transportId = sid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFileOffer(JingleFile actualFile, boolean otr) {
|
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 offer = description.addChild("offer");
|
||||||
Element file = offer.addChild("file");
|
Element file = offer.addChild("file");
|
||||||
file.addChild("size").setContent(""+actualFile.getSize());
|
file.addChild("size").setContent("" + actualFile.getSize());
|
||||||
if (otr) {
|
if (otr) {
|
||||||
file.addChild("name").setContent(actualFile.getName()+".otr");
|
file.addChild("name").setContent(actualFile.getName() + ".otr");
|
||||||
} else {
|
} else {
|
||||||
file.addChild("name").setContent(actualFile.getName());
|
file.addChild("name").setContent(actualFile.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Element getFileOffer() {
|
public Element getFileOffer() {
|
||||||
Element description = this.findChild("description", "urn:xmpp:jingle:apps:file-transfer:3");
|
Element description = this.findChild("description",
|
||||||
if (description==null) {
|
"urn:xmpp:jingle:apps:file-transfer:3");
|
||||||
|
if (description == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Element offer = description.findChild("offer");
|
Element offer = description.findChild("offer");
|
||||||
if (offer==null) {
|
if (offer == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return offer.findChild("file");
|
return offer.findChild("file");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFileOffer(Element fileOffer) {
|
public void setFileOffer(Element fileOffer) {
|
||||||
Element description = this.findChild("description", "urn:xmpp:jingle:apps:file-transfer:3");
|
Element description = this.findChild("description",
|
||||||
if (description==null) {
|
"urn:xmpp:jingle:apps:file-transfer:3");
|
||||||
description = this.addChild("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);
|
description.addChild(fileOffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTransportId() {
|
public String getTransportId() {
|
||||||
if (hasSocks5Transport()) {
|
if (hasSocks5Transport()) {
|
||||||
this.transportId = socks5transport().getAttribute("sid");
|
this.transportId = socks5transport().getAttribute("sid");
|
||||||
|
@ -65,30 +69,34 @@ public class Content extends Element {
|
||||||
}
|
}
|
||||||
return this.transportId;
|
return this.transportId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Element socks5transport() {
|
public Element socks5transport() {
|
||||||
Element transport = this.findChild("transport", "urn:xmpp:jingle:transports:s5b:1");
|
Element transport = this.findChild("transport",
|
||||||
if (transport==null) {
|
"urn:xmpp:jingle:transports:s5b:1");
|
||||||
transport = this.addChild("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);
|
transport.setAttribute("sid", this.transportId);
|
||||||
}
|
}
|
||||||
return transport;
|
return transport;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Element ibbTransport() {
|
public Element ibbTransport() {
|
||||||
Element transport = this.findChild("transport", "urn:xmpp:jingle:transports:ibb:1");
|
Element transport = this.findChild("transport",
|
||||||
if (transport==null) {
|
"urn:xmpp:jingle:transports:ibb:1");
|
||||||
transport = this.addChild("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);
|
transport.setAttribute("sid", this.transportId);
|
||||||
}
|
}
|
||||||
return transport;
|
return transport;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasSocks5Transport() {
|
public boolean hasSocks5Transport() {
|
||||||
return this.hasChild("transport", "urn:xmpp:jingle:transports:s5b:1");
|
return this.hasChild("transport", "urn:xmpp:jingle:transports:s5b:1");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasIbbTransport() {
|
public boolean hasIbbTransport() {
|
||||||
return this.hasChild("transport","urn:xmpp:jingle:transports:ibb:1");
|
return this.hasChild("transport", "urn:xmpp:jingle:transports:ibb:1");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,18 +7,18 @@ public class JinglePacket extends IqPacket {
|
||||||
Content content = null;
|
Content content = null;
|
||||||
Reason reason = null;
|
Reason reason = null;
|
||||||
Element jingle = new Element("jingle");
|
Element jingle = new Element("jingle");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Element addChild(Element child) {
|
public Element addChild(Element child) {
|
||||||
if ("jingle".equals(child.getName())) {
|
if ("jingle".equals(child.getName())) {
|
||||||
Element contentElement = child.findChild("content");
|
Element contentElement = child.findChild("content");
|
||||||
if (contentElement!=null) {
|
if (contentElement != null) {
|
||||||
this.content = new Content();
|
this.content = new Content();
|
||||||
this.content.setChildren(contentElement.getChildren());
|
this.content.setChildren(contentElement.getChildren());
|
||||||
this.content.setAttributes(contentElement.getAttributes());
|
this.content.setAttributes(contentElement.getAttributes());
|
||||||
}
|
}
|
||||||
Element reasonElement = child.findChild("reason");
|
Element reasonElement = child.findChild("reason");
|
||||||
if (reasonElement!=null) {
|
if (reasonElement != null) {
|
||||||
this.reason = new Reason();
|
this.reason = new Reason();
|
||||||
this.reason.setChildren(reasonElement.getChildren());
|
this.reason.setChildren(reasonElement.getChildren());
|
||||||
this.reason.setAttributes(reasonElement.getAttributes());
|
this.reason.setAttributes(reasonElement.getAttributes());
|
||||||
|
@ -27,33 +27,33 @@ public class JinglePacket extends IqPacket {
|
||||||
}
|
}
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JinglePacket setContent(Content content) {
|
public JinglePacket setContent(Content content) {
|
||||||
this.content = content;
|
this.content = content;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Content getJingleContent() {
|
public Content getJingleContent() {
|
||||||
if (this.content==null) {
|
if (this.content == null) {
|
||||||
this.content = new Content();
|
this.content = new Content();
|
||||||
}
|
}
|
||||||
return this.content;
|
return this.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JinglePacket setReason(Reason reason) {
|
public JinglePacket setReason(Reason reason) {
|
||||||
this.reason = reason;
|
this.reason = reason;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Reason getReason() {
|
public Reason getReason() {
|
||||||
return this.reason;
|
return this.reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void build() {
|
private void build() {
|
||||||
this.children.clear();
|
this.children.clear();
|
||||||
this.jingle.clearChildren();
|
this.jingle.clearChildren();
|
||||||
this.jingle.setAttribute("xmlns", "urn:xmpp:jingle:1");
|
this.jingle.setAttribute("xmlns", "urn:xmpp:jingle:1");
|
||||||
if (this.content!=null) {
|
if (this.content != null) {
|
||||||
jingle.addChild(this.content);
|
jingle.addChild(this.content);
|
||||||
}
|
}
|
||||||
if (this.reason != null) {
|
if (this.reason != null) {
|
||||||
|
@ -66,11 +66,11 @@ public class JinglePacket extends IqPacket {
|
||||||
public String getSessionId() {
|
public String getSessionId() {
|
||||||
return this.jingle.getAttribute("sid");
|
return this.jingle.getAttribute("sid");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSessionId(String sid) {
|
public void setSessionId(String sid) {
|
||||||
this.jingle.setAttribute("sid", sid);
|
this.jingle.setAttribute("sid", sid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
this.build();
|
this.build();
|
||||||
|
@ -80,11 +80,11 @@ public class JinglePacket extends IqPacket {
|
||||||
public void setAction(String action) {
|
public void setAction(String action) {
|
||||||
this.jingle.setAttribute("action", action);
|
this.jingle.setAttribute("action", action);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAction() {
|
public String getAction() {
|
||||||
return this.jingle.getAttribute("action");
|
return this.jingle.getAttribute("action");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInitiator(String initiator) {
|
public void setInitiator(String initiator) {
|
||||||
this.jingle.setAttribute("initiator", initiator);
|
this.jingle.setAttribute("initiator", initiator);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ public class Reason extends Element {
|
||||||
private Reason(String name) {
|
private Reason(String name) {
|
||||||
super(name);
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Reason() {
|
public Reason() {
|
||||||
super("reason");
|
super("reason");
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,48 +11,51 @@ public class Avatar {
|
||||||
public int width;
|
public int width;
|
||||||
public long size;
|
public long size;
|
||||||
public String owner;
|
public String owner;
|
||||||
|
|
||||||
public byte[] getImageAsBytes() {
|
public byte[] getImageAsBytes() {
|
||||||
return Base64.decode(image, Base64.DEFAULT);
|
return Base64.decode(image, Base64.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFilename() {
|
public String getFilename() {
|
||||||
if (type==null) {
|
if (type == null) {
|
||||||
return sha1sum;
|
return sha1sum;
|
||||||
} else if (type.equalsIgnoreCase("image/webp")) {
|
} else if (type.equalsIgnoreCase("image/webp")) {
|
||||||
return sha1sum+".webp";
|
return sha1sum + ".webp";
|
||||||
} else if (type.equalsIgnoreCase("image/png")) {
|
} else if (type.equalsIgnoreCase("image/png")) {
|
||||||
return sha1sum+".png";
|
return sha1sum + ".png";
|
||||||
} else {
|
} else {
|
||||||
return sha1sum;
|
return sha1sum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Avatar parseMetadata(Element items) {
|
public static Avatar parseMetadata(Element items) {
|
||||||
Element item = items.findChild("item");
|
Element item = items.findChild("item");
|
||||||
if (item==null) {
|
if (item == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Element metadata = item.findChild("metadata");
|
Element metadata = item.findChild("metadata");
|
||||||
if (metadata==null) {
|
if (metadata == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String primaryId = item.getAttribute("id");
|
String primaryId = item.getAttribute("id");
|
||||||
if (primaryId==null) {
|
if (primaryId == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
for(Element child : metadata.getChildren()) {
|
for (Element child : metadata.getChildren()) {
|
||||||
if (child.getName().equals("info") && primaryId.equals(child.getAttribute("id"))) {
|
if (child.getName().equals("info")
|
||||||
|
&& primaryId.equals(child.getAttribute("id"))) {
|
||||||
Avatar avatar = new Avatar();
|
Avatar avatar = new Avatar();
|
||||||
String height = child.getAttribute("height");
|
String height = child.getAttribute("height");
|
||||||
String width = child.getAttribute("width");
|
String width = child.getAttribute("width");
|
||||||
String size = child.getAttribute("bytes");
|
String size = child.getAttribute("bytes");
|
||||||
try {
|
try {
|
||||||
if (height!=null) {
|
if (height != null) {
|
||||||
avatar.height = Integer.parseInt(height);
|
avatar.height = Integer.parseInt(height);
|
||||||
}
|
}
|
||||||
if (width!=null) {
|
if (width != null) {
|
||||||
avatar.width = Integer.parseInt(width);
|
avatar.width = Integer.parseInt(width);
|
||||||
}
|
}
|
||||||
if (size!=null) {
|
if (size != null) {
|
||||||
avatar.size = Long.parseLong(size);
|
avatar.size = Long.parseLong(size);
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
|
|
|
@ -15,20 +15,20 @@ public class AbstractStanza extends Element {
|
||||||
public String getFrom() {
|
public String getFrom() {
|
||||||
return getAttribute("from");
|
return getAttribute("from");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return this.getAttribute("id");
|
return this.getAttribute("id");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTo(String to) {
|
public void setTo(String to) {
|
||||||
setAttribute("to", to);
|
setAttribute("to", to);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFrom(String from) {
|
public void setFrom(String from) {
|
||||||
setAttribute("from",from);
|
setAttribute("from", from);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(String id) {
|
public void setId(String id) {
|
||||||
setAttribute("id",id);
|
setAttribute("id", id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,8 @@ package eu.siacs.conversations.xmpp.stanzas;
|
||||||
|
|
||||||
import eu.siacs.conversations.xml.Element;
|
import eu.siacs.conversations.xml.Element;
|
||||||
|
|
||||||
|
|
||||||
public class IqPacket extends AbstractStanza {
|
public class IqPacket extends AbstractStanza {
|
||||||
|
|
||||||
public static final int TYPE_ERROR = -1;
|
public static final int TYPE_ERROR = -1;
|
||||||
public static final int TYPE_SET = 0;
|
public static final int TYPE_SET = 0;
|
||||||
public static final int TYPE_RESULT = 1;
|
public static final int TYPE_RESULT = 1;
|
||||||
|
@ -33,25 +32,25 @@ public class IqPacket extends AbstractStanza {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IqPacket() {
|
public IqPacket() {
|
||||||
super("iq");
|
super("iq");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Element query() {
|
public Element query() {
|
||||||
Element query = findChild("query");
|
Element query = findChild("query");
|
||||||
if (query==null) {
|
if (query == null) {
|
||||||
query = addChild("query");
|
query = addChild("query");
|
||||||
}
|
}
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Element query(String xmlns) {
|
public Element query(String xmlns) {
|
||||||
Element query = query();
|
Element query = query();
|
||||||
query.setAttribute("xmlns", xmlns);
|
query.setAttribute("xmlns", xmlns);
|
||||||
return query();
|
return query();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getType() {
|
public int getType() {
|
||||||
String type = getAttribute("type");
|
String type = getAttribute("type");
|
||||||
if ("error".equals(type)) {
|
if ("error".equals(type)) {
|
||||||
|
@ -66,7 +65,7 @@ public class IqPacket extends AbstractStanza {
|
||||||
return 1000;
|
return 1000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IqPacket generateRespone(int type) {
|
public IqPacket generateRespone(int type) {
|
||||||
IqPacket packet = new IqPacket(type);
|
IqPacket packet = new IqPacket(type);
|
||||||
packet.setTo(this.getFrom());
|
packet.setTo(this.getFrom());
|
||||||
|
|
|
@ -9,20 +9,20 @@ public class MessagePacket extends AbstractStanza {
|
||||||
public static final int TYPE_GROUPCHAT = 3;
|
public static final int TYPE_GROUPCHAT = 3;
|
||||||
public static final int TYPE_ERROR = 4;
|
public static final int TYPE_ERROR = 4;
|
||||||
public static final int TYPE_HEADLINE = 5;
|
public static final int TYPE_HEADLINE = 5;
|
||||||
|
|
||||||
public MessagePacket() {
|
public MessagePacket() {
|
||||||
super("message");
|
super("message");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBody() {
|
public String getBody() {
|
||||||
Element body = this.findChild("body");
|
Element body = this.findChild("body");
|
||||||
if (body!=null) {
|
if (body != null) {
|
||||||
return body.getContent();
|
return body.getContent();
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBody(String text) {
|
public void setBody(String text) {
|
||||||
this.children.remove(findChild("body"));
|
this.children.remove(findChild("body"));
|
||||||
Element body = new Element("body");
|
Element body = new Element("body");
|
||||||
|
@ -33,7 +33,7 @@ public class MessagePacket extends AbstractStanza {
|
||||||
public void setType(int type) {
|
public void setType(int type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TYPE_CHAT:
|
case TYPE_CHAT:
|
||||||
this.setAttribute("type","chat");
|
this.setAttribute("type", "chat");
|
||||||
break;
|
break;
|
||||||
case TYPE_GROUPCHAT:
|
case TYPE_GROUPCHAT:
|
||||||
this.setAttribute("type", "groupchat");
|
this.setAttribute("type", "groupchat");
|
||||||
|
@ -43,14 +43,14 @@ public class MessagePacket extends AbstractStanza {
|
||||||
case TYPE_NORMAL:
|
case TYPE_NORMAL:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this.setAttribute("type","chat");
|
this.setAttribute("type", "chat");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getType() {
|
public int getType() {
|
||||||
String type = getAttribute("type");
|
String type = getAttribute("type");
|
||||||
if (type==null) {
|
if (type == null) {
|
||||||
return TYPE_NORMAL;
|
return TYPE_NORMAL;
|
||||||
} else if (type.equals("normal")) {
|
} else if (type.equals("normal")) {
|
||||||
return TYPE_NORMAL;
|
return TYPE_NORMAL;
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package eu.siacs.conversations.xmpp.stanzas;
|
package eu.siacs.conversations.xmpp.stanzas;
|
||||||
|
|
||||||
|
|
||||||
public class PresencePacket extends AbstractStanza {
|
public class PresencePacket extends AbstractStanza {
|
||||||
|
|
||||||
public PresencePacket() {
|
public PresencePacket() {
|
||||||
super("presence");
|
super("presence");
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ public class AckPacket extends AbstractStanza {
|
||||||
|
|
||||||
public AckPacket(int sequence, int smVersion) {
|
public AckPacket(int sequence, int smVersion) {
|
||||||
super("a");
|
super("a");
|
||||||
this.setAttribute("xmlns","urn:xmpp:sm:"+smVersion);
|
this.setAttribute("xmlns", "urn:xmpp:sm:" + smVersion);
|
||||||
this.setAttribute("h", ""+sequence);
|
this.setAttribute("h", "" + sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ public class EnablePacket extends AbstractStanza {
|
||||||
|
|
||||||
public EnablePacket(int smVersion) {
|
public EnablePacket(int smVersion) {
|
||||||
super("enable");
|
super("enable");
|
||||||
this.setAttribute("xmlns","urn:xmpp:sm:"+smVersion);
|
this.setAttribute("xmlns", "urn:xmpp:sm:" + smVersion);
|
||||||
this.setAttribute("resume", "true");
|
this.setAttribute("resume", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ public class RequestPacket extends AbstractStanza {
|
||||||
|
|
||||||
public RequestPacket(int smVersion) {
|
public RequestPacket(int smVersion) {
|
||||||
super("r");
|
super("r");
|
||||||
this.setAttribute("xmlns","urn:xmpp:sm:"+smVersion);
|
this.setAttribute("xmlns", "urn:xmpp:sm:" + smVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,9 @@ public class ResumePacket extends AbstractStanza {
|
||||||
|
|
||||||
public ResumePacket(String id, int sequence, int smVersion) {
|
public ResumePacket(String id, int sequence, int smVersion) {
|
||||||
super("resume");
|
super("resume");
|
||||||
this.setAttribute("xmlns","urn:xmpp:sm:"+smVersion);
|
this.setAttribute("xmlns", "urn:xmpp:sm:" + smVersion);
|
||||||
this.setAttribute("previd", id);
|
this.setAttribute("previd", id);
|
||||||
this.setAttribute("h", ""+sequence);
|
this.setAttribute("h", "" + sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue