reworked openpgp integration part #1

This commit is contained in:
Daniel Gultsch 2014-05-01 22:33:49 +02:00
parent 4b66b4b5d1
commit 37c8e157d0
11 changed files with 445 additions and 269 deletions

@ -1 +1 @@
Subproject commit 098823bd525bdbf215060dba1ed248af853bbfac Subproject commit e0a0bf04ee6fa4794a82b44dae905bc814d85491

View file

@ -12,5 +12,5 @@
# Project target. # Project target.
target=android-19 target=android-19
android.library.reference.1=libs/openpgp-keychain/OpenPGP-Keychain-API/libraries/openpgp-api-library android.library.reference.1=libs/minidns
android.library.reference.2=libs/minidns android.library.reference.2=libs/openpgp-keychain/OpenKeychain-API/libraries/openpgp-api-library

View file

@ -78,4 +78,5 @@
<string name="contact_offline_otr">Sending OTR encrypted messages to an offline contact is unfortunately not supported.\nWould you like to send the message in plain text?</string> <string name="contact_offline_otr">Sending OTR encrypted messages to an offline contact is unfortunately not supported.\nWould you like to send the message in plain text?</string>
<string name="contact_offline_file">Sending files to an offline contact is unfortunately not supported.</string> <string name="contact_offline_file">Sending files to an offline contact is unfortunately not supported.</string>
<string name="send_unencrypted">Send unencrypted</string> <string name="send_unencrypted">Send unencrypted</string>
<string name="decryption_failed">Decrpytion failed. Maybe you dont have the proper private key.</string>
</resources> </resources>

View file

@ -0,0 +1,11 @@
package eu.siacs.conversations.crypto;
import org.openintents.openpgp.OpenPgpError;
import android.app.PendingIntent;
public interface OnPgpEngineResult {
public void success();
public void error(OpenPgpError openPgpError);
public void userInputRequried(PendingIntent pi);
}

View file

@ -3,12 +3,16 @@ package eu.siacs.conversations.crypto;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult; 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 eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Message;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Intent; import android.content.Intent;
@ -21,66 +25,80 @@ public class PgpEngine {
this.api = api; this.api = api;
} }
public String decrypt(Account account, String message) throws UserInputRequiredException, public void decrypt(final Message message, final OnPgpEngineResult callback) {
OpenPgpException {
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, account.getJid()); params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, message
InputStream is = new ByteArrayInputStream(message.getBytes()); .getConversation().getAccount().getJid());
ByteArrayOutputStream os = new ByteArrayOutputStream(); InputStream is = new ByteArrayInputStream(message.getBody().getBytes());
Intent result = api.executeApi(params, is, os); final OutputStream os = new ByteArrayOutputStream();
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { api.executeApiAsync(params, is, os, new IOpenPgpCallback() {
case OpenPgpApi.RESULT_CODE_SUCCESS:
return os.toString(); @Override
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: public void onReturn(Intent result) {
throw new UserInputRequiredException((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT)); switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
case OpenPgpApi.RESULT_CODE_ERROR: OpenPgpApi.RESULT_CODE_ERROR)) {
throw new OpenPgpException( case OpenPgpApi.RESULT_CODE_SUCCESS:
(OpenPgpError) result.getParcelableExtra(OpenPgpApi.RESULT_ERROR)); message.setBody(os.toString());
default: message.setEncryption(Message.ENCRYPTION_DECRYPTED);
return null; callback.success();
} return;
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
callback.userInputRequried((PendingIntent) result
.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
return;
case OpenPgpApi.RESULT_CODE_ERROR:
callback.error((OpenPgpError) result
.getParcelableExtra(OpenPgpApi.RESULT_ERROR));
return;
default:
return;
}
}
});
} }
public String encrypt(Account account, long keyId, String message) throws UserInputRequiredException, OpenPgpException { public void encrypt(Account account, long keyId, Message message,
Log.d("xmppService","called to pgpengine::encrypt"); final OnPgpEngineResult callback) {
long[] keys = {keyId}; Log.d("xmppService", "called to pgpengine::encrypt");
long[] keys = { keyId };
Intent params = new Intent(); Intent params = new Intent();
params.setAction(OpenPgpApi.ACTION_ENCRYPT); params.setAction(OpenPgpApi.ACTION_ENCRYPT);
params.putExtra(OpenPgpApi.EXTRA_KEY_IDS,keys); params.putExtra(OpenPgpApi.EXTRA_KEY_IDS, keys);
params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid()); params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid());
InputStream is = new ByteArrayInputStream(message.getBytes()); InputStream is = new ByteArrayInputStream(message.getBody().getBytes());
ByteArrayOutputStream os = new ByteArrayOutputStream(); ByteArrayOutputStream os = new ByteArrayOutputStream();
Intent result = api.executeApi(params, is, os); Intent result = api.executeApi(params, is, os);
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
OpenPgpApi.RESULT_CODE_ERROR)) {
case OpenPgpApi.RESULT_CODE_SUCCESS: case OpenPgpApi.RESULT_CODE_SUCCESS:
StringBuilder encryptedMessageBody = new StringBuilder(); StringBuilder encryptedMessageBody = new StringBuilder();
String[] lines = os.toString().split("\n"); String[] lines = os.toString().split("\n");
for (int i = 3; i < lines.length - 1; ++i) { for (int i = 3; i < lines.length - 1; ++i) {
encryptedMessageBody.append(lines[i].trim()); encryptedMessageBody.append(lines[i].trim());
} }
Log.d("xmppService","encrpyted message: "+encryptedMessageBody.toString()); message.setEncryptedBody(encryptedMessageBody.toString());
return encryptedMessageBody.toString(); callback.success();
return;
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
Log.d("xmppService","user input required"); callback.userInputRequried((PendingIntent) result
throw new UserInputRequiredException((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT)); .getParcelableExtra(OpenPgpApi.RESULT_INTENT));
return;
case OpenPgpApi.RESULT_CODE_ERROR: case OpenPgpApi.RESULT_CODE_ERROR:
OpenPgpError error = (OpenPgpError) result.getParcelableExtra(OpenPgpApi.RESULT_ERROR); callback.error((OpenPgpError) result
throw new OpenPgpException(error); .getParcelableExtra(OpenPgpApi.RESULT_ERROR));
default: return;
return null;
} }
} }
public long fetchKeyId(Account account, String status, String signature) public long fetchKeyId(Account account, String status, String signature) {
throws OpenPgpException { if ((signature == null) || (api == null)) {
if ((signature==null)||(api==null)) {
return 0; return 0;
} }
if (status==null) { if (status == null) {
status=""; status = "";
} }
StringBuilder pgpSig = new StringBuilder(); StringBuilder pgpSig = new StringBuilder();
pgpSig.append("-----BEGIN PGP SIGNED MESSAGE-----"); pgpSig.append("-----BEGIN PGP SIGNED MESSAGE-----");
@ -97,75 +115,90 @@ public class PgpEngine {
Intent params = new Intent(); Intent params = new Intent();
params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY); params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid());
InputStream is = new ByteArrayInputStream(pgpSig.toString().getBytes()); InputStream is = new ByteArrayInputStream(pgpSig.toString().getBytes());
ByteArrayOutputStream os = new ByteArrayOutputStream(); ByteArrayOutputStream os = new ByteArrayOutputStream();
Intent result = api.executeApi(params, is, os); Intent result = api.executeApi(params, is, os);
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
OpenPgpApi.RESULT_CODE_ERROR)) {
case OpenPgpApi.RESULT_CODE_SUCCESS: case OpenPgpApi.RESULT_CODE_SUCCESS:
OpenPgpSignatureResult sigResult OpenPgpSignatureResult sigResult = result
= result.getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE); .getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE);
if (sigResult==null) { if (sigResult != null) {
return 0;
} else {
return sigResult.getKeyId(); return sigResult.getKeyId();
} else {
return 0;
} }
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
break; Log.d("xmppService","user interaction required");
return 0;
case OpenPgpApi.RESULT_CODE_ERROR: case OpenPgpApi.RESULT_CODE_ERROR:
throw new OpenPgpException( Log.d("xmppService","pgp error");
(OpenPgpError) result.getParcelableExtra(OpenPgpApi.RESULT_ERROR)); return 0;
} }
return 0; return 0;
} }
public String generateSignature(Account account, String status) public void generateSignature(final Account account, String status,
throws UserInputRequiredException { final OnPgpEngineResult callback) {
Intent params = new Intent(); Intent params = new Intent();
params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
params.setAction(OpenPgpApi.ACTION_SIGN); params.setAction(OpenPgpApi.ACTION_SIGN);
params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid()); params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid());
InputStream is = new ByteArrayInputStream(status.getBytes()); InputStream is = new ByteArrayInputStream(status.getBytes());
ByteArrayOutputStream os = new ByteArrayOutputStream(); final OutputStream os = new ByteArrayOutputStream();
Intent result = api.executeApi(params, is, os); api.executeApiAsync(params, is, os, new IOpenPgpCallback() {
StringBuilder signatureBuilder = new StringBuilder();
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) { @Override
case OpenPgpApi.RESULT_CODE_SUCCESS: public void onReturn(Intent result) {
String[] lines = os.toString().split("\n"); switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
for (int i = 7; i < lines.length - 1; ++i) { case OpenPgpApi.RESULT_CODE_SUCCESS:
signatureBuilder.append(lines[i].trim()); StringBuilder signatureBuilder = new StringBuilder();
String[] lines = os.toString().split("\n");
for (int i = 7; i < lines.length - 1; ++i) {
signatureBuilder.append(lines[i].trim());
}
account.setKey("pgp_signature", signatureBuilder.toString());
callback.success();
return;
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
callback.userInputRequried((PendingIntent) result
.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
return;
case OpenPgpApi.RESULT_CODE_ERROR:
callback.error((OpenPgpError) result
.getParcelableExtra(OpenPgpApi.RESULT_ERROR));
return;
}
} }
break; });
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
throw new UserInputRequiredException((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
case OpenPgpApi.RESULT_CODE_ERROR:
break;
}
return signatureBuilder.toString();
} }
public class UserInputRequiredException extends Exception { public void hasKey(Account account, long keyId, final OnPgpEngineResult callback) {
private static final long serialVersionUID = -6913480043269132016L; Intent params = new Intent();
private PendingIntent pi; params.setAction(OpenPgpApi.ACTION_GET_KEY);
params.putExtra(OpenPgpApi.EXTRA_KEY_ID, keyId);
public UserInputRequiredException(PendingIntent pi) { params.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, account.getJid());
this.pi = pi; InputStream is = new ByteArrayInputStream(new byte[0]);
} OutputStream os = new ByteArrayOutputStream();
api.executeApiAsync(params, is, os, new IOpenPgpCallback() {
public PendingIntent getPendingIntent() {
return this.pi; @Override
} public void onReturn(Intent result) {
} switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
case OpenPgpApi.RESULT_CODE_SUCCESS:
public class OpenPgpException extends Exception { callback.success();
private static final long serialVersionUID = -7324789703473056077L; return;
private OpenPgpError error; case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
callback.userInputRequried((PendingIntent) result
public OpenPgpException(OpenPgpError openPgpError) { .getParcelableExtra(OpenPgpApi.RESULT_INTENT));
this.error = openPgpError; return;
} case OpenPgpApi.RESULT_CODE_ERROR:
callback.error((OpenPgpError) result
public OpenPgpError getOpenPgpError() { .getParcelableExtra(OpenPgpApi.RESULT_ERROR));
return this.error; return;
} }
}
});
} }
} }

View file

@ -275,4 +275,16 @@ public class Account extends AbstractEntity{
public int countPresences() { public int countPresences() {
return this.presences.size(); return this.presences.size();
} }
public String getPgpSignature() {
if (keys.has("pgp_signature")) {
try {
return keys.getString("pgp_signature");
} catch (JSONException e) {
return null;
}
} else {
return null;
}
}
} }

View file

@ -24,6 +24,7 @@ public class Message extends AbstractEntity {
public static final int ENCRYPTION_PGP = 1; public static final int ENCRYPTION_PGP = 1;
public static final int ENCRYPTION_OTR = 2; public static final int ENCRYPTION_OTR = 2;
public static final int ENCRYPTION_DECRYPTED = 3; public static final int ENCRYPTION_DECRYPTED = 3;
public static final int ENCRYPTION_DECRYPTION_FAILED = 4;
public static final int TYPE_TEXT = 0; public static final int TYPE_TEXT = 0;
public static final int TYPE_IMAGE = 1; public static final int TYPE_IMAGE = 1;

View file

@ -10,6 +10,7 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Random; import java.util.Random;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpServiceConnection; import org.openintents.openpgp.util.OpenPgpServiceConnection;
@ -17,8 +18,8 @@ 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.crypto.OnPgpEngineResult;
import eu.siacs.conversations.crypto.PgpEngine; import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.crypto.PgpEngine.OpenPgpException;
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;
@ -88,8 +89,9 @@ public class XmppConnectionService extends Service {
private List<Account> accounts; private List<Account> accounts;
private List<Conversation> conversations = null; private List<Conversation> conversations = null;
private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(this); private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(
this);
public OnConversationListChangedListener convChangedListener = null; public OnConversationListChangedListener convChangedListener = null;
private int convChangedListenerCount = 0; private int convChangedListenerCount = 0;
private OnAccountListChangedListener accountChangedListener = null; private OnAccountListChangedListener accountChangedListener = null;
@ -123,8 +125,9 @@ public class XmppConnectionService extends Service {
MessagePacket packet) { MessagePacket packet) {
Message message = null; Message message = null;
boolean notify = true; boolean notify = true;
if(getPreferences().getBoolean("notification_grace_period_after_carbon_received", true)){ if (getPreferences().getBoolean(
notify=(SystemClock.elapsedRealtime() - lastCarbonMessageReceived) > CARBON_GRACE_PERIOD; "notification_grace_period_after_carbon_received", true)) {
notify = (SystemClock.elapsedRealtime() - lastCarbonMessageReceived) > CARBON_GRACE_PERIOD;
} }
if ((packet.getType() == MessagePacket.TYPE_CHAT)) { if ((packet.getType() == MessagePacket.TYPE_CHAT)) {
@ -133,7 +136,8 @@ public class XmppConnectionService extends Service {
message = MessageParser.parsePgpChat(pgpBody, packet, message = MessageParser.parsePgpChat(pgpBody, packet,
account, service); account, service);
message.markUnread(); message.markUnread();
} else if ((packet.getBody()!=null) && (packet.getBody().startsWith("?OTR"))) { } else if ((packet.getBody() != null)
&& (packet.getBody().startsWith("?OTR"))) {
message = MessageParser.parseOtrChat(packet, account, message = MessageParser.parseOtrChat(packet, account,
service); service);
if (message != null) { if (message != null) {
@ -149,7 +153,8 @@ public class XmppConnectionService extends Service {
service); service);
if (message != null) { if (message != null) {
if (message.getStatus() == Message.STATUS_SEND) { if (message.getStatus() == Message.STATUS_SEND) {
lastCarbonMessageReceived = SystemClock.elapsedRealtime(); lastCarbonMessageReceived = SystemClock
.elapsedRealtime();
notify = false; notify = false;
message.getConversation().markRead(); message.getConversation().markRead();
} else { } else {
@ -242,7 +247,8 @@ public class XmppConnectionService extends Service {
databaseBackend.updateAccount(account); databaseBackend.updateAccount(account);
reconnectAccount(account, true); reconnectAccount(account, true);
} else { } else {
UIHelper.showErrorNotification(getApplicationContext(), getAccounts()); UIHelper.showErrorNotification(getApplicationContext(),
getAccounts());
} }
} }
}; };
@ -250,20 +256,25 @@ public class XmppConnectionService extends Service {
private OnPresencePacketReceived presenceListener = new OnPresencePacketReceived() { private OnPresencePacketReceived presenceListener = new OnPresencePacketReceived() {
@Override @Override
public void onPresencePacketReceived(Account account, public void onPresencePacketReceived(final Account account,
PresencePacket packet) { PresencePacket packet) {
if (packet.hasChild("x","http://jabber.org/protocol/muc#user")) { if (packet.hasChild("x", "http://jabber.org/protocol/muc#user")) {
Conversation muc = findMuc( Conversation muc = findMuc(
packet.getAttribute("from").split("/")[0], account); packet.getAttribute("from").split("/")[0], account);
if (muc != null) { if (muc != null) {
muc.getMucOptions().processPacket(packet); muc.getMucOptions().processPacket(packet);
} else { } else {
Log.d(LOGTAG,account.getJid()+": could not find muc for received muc package "+packet.toString()); Log.d(LOGTAG, account.getJid()
+ ": could not find muc for received muc package "
+ packet.toString());
} }
} else if (packet.hasChild("x","http://jabber.org/protocol/muc")) { } else if (packet.hasChild("x", "http://jabber.org/protocol/muc")) {
Conversation muc = findMuc(packet.getAttribute("from").split("/")[0], account); Conversation muc = findMuc(
packet.getAttribute("from").split("/")[0], account);
if (muc != null) { if (muc != null) {
Log.d(LOGTAG,account.getJid()+": reading muc status packet "+packet.toString()); Log.d(LOGTAG,
account.getJid() + ": reading muc status packet "
+ packet.toString());
int error = muc.getMucOptions().getError(); int error = muc.getMucOptions().getError();
muc.getMucOptions().processPacket(packet); muc.getMucOptions().processPacket(packet);
if ((muc.getMucOptions().getError() != error) if ((muc.getMucOptions().getError() != error)
@ -276,50 +287,52 @@ public class XmppConnectionService extends Service {
String[] fromParts = packet.getAttribute("from").split("/"); String[] fromParts = packet.getAttribute("from").split("/");
String type = packet.getAttribute("type"); String type = packet.getAttribute("type");
if (fromParts[0].equals(account.getJid())) { if (fromParts[0].equals(account.getJid())) {
if (fromParts.length==2) { if (fromParts.length == 2) {
if (type == null) { if (type == null) {
account.updatePresence(fromParts[1],Presences.parseShow(packet.findChild("show"))); account.updatePresence(fromParts[1], Presences
.parseShow(packet.findChild("show")));
} else if (type.equals("unavailable")) { } else if (type.equals("unavailable")) {
account.removePresence(fromParts[1]); account.removePresence(fromParts[1]);
} }
} }
} else { } else {
Contact contact = findContact(account, fromParts[0]); Contact contact = findContact(account, fromParts[0]);
if (contact == null) { if (contact == null) {
if ("subscribe".equals(type)) { if ("subscribe".equals(type)) {
account.getXmppConnection().addPendingSubscription(fromParts[0]); account.getXmppConnection().addPendingSubscription(
fromParts[0]);
} else { } else {
//Log.d(LOGTAG,packet.getFrom()+ " could not be found"); // Log.d(LOGTAG,packet.getFrom()+
// " could not be found");
} }
return; return;
} }
if (type == null) { if (type == null) {
if (fromParts.length == 2) { if (fromParts.length == 2) {
contact.updatePresence(fromParts[1], Presences.parseShow(packet.findChild("show"))); contact.updatePresence(fromParts[1], Presences
.parseShow(packet.findChild("show")));
PgpEngine pgp = getPgpEngine(); PgpEngine pgp = getPgpEngine();
if (pgp != null) { if (pgp != null) {
Element x = packet.findChild("x","jabber:x:signed"); Element x = packet.findChild("x",
"jabber:x:signed");
if (x != null) { if (x != null) {
try { Element status = packet.findChild("status");
Element status = packet.findChild("status"); String msg;
String msg; if (status != null) {
if (status!=null) { msg = status.getContent();
msg = status.getContent(); } else {
} else { msg = "";
msg = "";
}
contact.setPgpKeyId(pgp.fetchKeyId(account,msg, x
.getContent()));
} catch (OpenPgpException e) {
Log.d(LOGTAG, "faulty pgp. just ignore");
} }
contact.setPgpKeyId(pgp.fetchKeyId(account,msg,x.getContent()));
Log.d("xmppService","fetched key id for "+contact.getDisplayName()+" was:"+contact.getPgpKeyId());
} }
} }
replaceContactInConversation(account,contact.getJid(), contact); replaceContactInConversation(account,
databaseBackend.updateContact(contact,true); contact.getJid(), contact);
databaseBackend.updateContact(contact, true);
} else { } else {
//Log.d(LOGTAG,"presence without resource "+packet.toString()); // Log.d(LOGTAG,"presence without resource "+packet.toString());
} }
} else if (type.equals("unavailable")) { } else if (type.equals("unavailable")) {
if (fromParts.length != 2) { if (fromParts.length != 2) {
@ -327,19 +340,21 @@ public class XmppConnectionService extends Service {
} else { } else {
contact.removePresence(fromParts[1]); contact.removePresence(fromParts[1]);
} }
replaceContactInConversation(account,contact.getJid(), contact); replaceContactInConversation(account, contact.getJid(),
databaseBackend.updateContact(contact,true); contact);
databaseBackend.updateContact(contact, true);
} else if (type.equals("subscribe")) { } else if (type.equals("subscribe")) {
Log.d(LOGTAG,"received subscribe packet from "+packet.getFrom()); Log.d(LOGTAG, "received subscribe packet from "
+ packet.getFrom());
if (contact if (contact
.getSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT)) { .getSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT)) {
Log.d(LOGTAG,"preemptive grant; granting"); Log.d(LOGTAG, "preemptive grant; granting");
sendPresenceUpdatesTo(contact); sendPresenceUpdatesTo(contact);
contact.setSubscriptionOption(Contact.Subscription.FROM); contact.setSubscriptionOption(Contact.Subscription.FROM);
contact.resetSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT); contact.resetSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT);
replaceContactInConversation(account,contact.getJid(), replaceContactInConversation(account,
contact); contact.getJid(), contact);
databaseBackend.updateContact(contact,false); databaseBackend.updateContact(contact, false);
if ((contact if ((contact
.getSubscriptionOption(Contact.Subscription.ASKING)) .getSubscriptionOption(Contact.Subscription.ASKING))
&& (!contact && (!contact
@ -347,10 +362,11 @@ public class XmppConnectionService extends Service {
requestPresenceUpdatesFrom(contact); requestPresenceUpdatesFrom(contact);
} }
} else { } else {
account.getXmppConnection().addPendingSubscription(fromParts[0]); account.getXmppConnection().addPendingSubscription(
fromParts[0]);
} }
} else { } else {
//Log.d(LOGTAG, packet.toString()); // Log.d(LOGTAG, packet.toString());
} }
} }
} }
@ -368,16 +384,20 @@ public class XmppConnectionService extends Service {
processRosterItems(account, query); processRosterItems(account, query);
mergePhoneContactsWithRoster(null); mergePhoneContactsWithRoster(null);
} }
} else if (packet.hasChild("open","http://jabber.org/protocol/ibb")||packet.hasChild("data","http://jabber.org/protocol/ibb")) { } else if (packet
XmppConnectionService.this.mJingleConnectionManager.deliverIbbPacket(account,packet); .hasChild("open", "http://jabber.org/protocol/ibb")
|| packet
.hasChild("data", "http://jabber.org/protocol/ibb")) {
XmppConnectionService.this.mJingleConnectionManager
.deliverIbbPacket(account, packet);
} else { } else {
Log.d(LOGTAG,"iq packet arrived "+packet.toString()); Log.d(LOGTAG, "iq packet arrived " + packet.toString());
} }
} }
}; };
private OnJinglePacketReceived jingleListener = new OnJinglePacketReceived() { private OnJinglePacketReceived jingleListener = new OnJinglePacketReceived() {
@Override @Override
public void onJinglePacketReceived(Account account, JinglePacket packet) { public void onJinglePacketReceived(Account account, JinglePacket packet) {
mJingleConnectionManager.deliverPacket(account, packet); mJingleConnectionManager.deliverPacket(account, packet);
@ -408,32 +428,33 @@ public class XmppConnectionService extends Service {
public FileBackend getFileBackend() { public FileBackend getFileBackend() {
return this.fileBackend; return this.fileBackend;
} }
public void attachImageToConversation(final Conversation conversation, final String presence, final Uri uri) { public void attachImageToConversation(final Conversation conversation,
final String presence, final Uri uri) {
new Thread(new Runnable() { new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
Message message = new Message(conversation, "", Message.ENCRYPTION_NONE); Message message = new Message(conversation, "",
Message.ENCRYPTION_NONE);
message.setPresence(presence); message.setPresence(presence);
message.setType(Message.TYPE_IMAGE); message.setType(Message.TYPE_IMAGE);
message.setStatus(Message.STATUS_PREPARING); message.setStatus(Message.STATUS_PREPARING);
conversation.getMessages().add(message); conversation.getMessages().add(message);
if (convChangedListener!=null) { if (convChangedListener != null) {
convChangedListener.onConversationListChanged(); convChangedListener.onConversationListChanged();
} }
getFileBackend().copyImageToPrivateStorage(message, uri); getFileBackend().copyImageToPrivateStorage(message, uri);
message.setStatus(Message.STATUS_OFFERED); message.setStatus(Message.STATUS_OFFERED);
databaseBackend.createMessage(message); databaseBackend.createMessage(message);
if (convChangedListener!=null) { if (convChangedListener != null) {
convChangedListener.onConversationListChanged(); convChangedListener.onConversationListChanged();
} }
sendMessage(message, null); sendMessage(message, null);
} }
}).start(); }).start();
} }
protected Conversation findMuc(String name, Account account) { protected Conversation findMuc(String name, Account account) {
for (Conversation conversation : this.conversations) { for (Conversation conversation : this.conversations) {
if (conversation.getContactJid().split("/")[0].equals(name) if (conversation.getContactJid().split("/")[0].equals(name)
@ -468,21 +489,24 @@ public class XmppConnectionService extends Service {
} else { } else {
if (subscription.equals("remove")) { if (subscription.equals("remove")) {
databaseBackend.deleteContact(contact); databaseBackend.deleteContact(contact);
replaceContactInConversation(account,contact.getJid(), null); replaceContactInConversation(account, contact.getJid(),
null);
} else { } else {
contact.parseSubscriptionFromElement(item); contact.parseSubscriptionFromElement(item);
databaseBackend.updateContact(contact,false); databaseBackend.updateContact(contact, false);
replaceContactInConversation(account,contact.getJid(), contact); replaceContactInConversation(account, contact.getJid(),
contact);
} }
} }
} }
} }
} }
private void replaceContactInConversation(Account account, String jid, Contact contact) { private void replaceContactInConversation(Account account, String jid,
Contact contact) {
List<Conversation> conversations = getConversations(); List<Conversation> conversations = getConversations();
for (Conversation c : conversations) { for (Conversation c : conversations) {
if (c.getContactJid().equals(jid)&&(c.getAccount()==account)) { if (c.getContactJid().equals(jid) && (c.getAccount() == account)) {
c.setContact(contact); c.setContact(contact);
break; break;
} }
@ -575,12 +599,13 @@ public class XmppConnectionService extends Service {
@Override @Override
public void onCreate() { public void onCreate() {
ExceptionHelper.init(getApplicationContext()); ExceptionHelper.init(getApplicationContext());
this.databaseBackend = DatabaseBackend.getInstance(getApplicationContext()); this.databaseBackend = DatabaseBackend
.getInstance(getApplicationContext());
this.fileBackend = new FileBackend(getApplicationContext()); this.fileBackend = new FileBackend(getApplicationContext());
this.accounts = databaseBackend.getAccounts(); this.accounts = databaseBackend.getAccounts();
this.getConversations(); this.getConversations();
getContentResolver().registerContentObserver( getContentResolver().registerContentObserver(
ContactsContract.Contacts.CONTENT_URI, true, contactObserver); ContactsContract.Contacts.CONTENT_URI, true, contactObserver);
this.pgpServiceConnection = new OpenPgpServiceConnection( this.pgpServiceConnection = new OpenPgpServiceConnection(
@ -644,7 +669,8 @@ public class XmppConnectionService extends Service {
public XmppConnection createConnection(Account account) { public XmppConnection createConnection(Account account) {
SharedPreferences sharedPref = getPreferences(); SharedPreferences sharedPref = getPreferences();
account.setResource(sharedPref.getString("resource", "mobile").toLowerCase(Locale.getDefault())); account.setResource(sharedPref.getString("resource", "mobile")
.toLowerCase(Locale.getDefault()));
XmppConnection connection = new XmppConnection(account, this.pm); XmppConnection connection = new XmppConnection(account, this.pm);
connection.setOnMessagePacketReceivedListener(this.messageListener); connection.setOnMessagePacketReceivedListener(this.messageListener);
connection.setOnStatusChangedListener(this.statusListener); connection.setOnStatusChangedListener(this.statusListener);
@ -697,7 +723,8 @@ public class XmppConnectionService extends Service {
if (message.getEncryption() == Message.ENCRYPTION_OTR) { if (message.getEncryption() == Message.ENCRYPTION_OTR) {
if (!conv.hasValidOtrSession()) { if (!conv.hasValidOtrSession()) {
// starting otr session. messages will be send later // starting otr session. messages will be send later
conv.startOtrSession(getApplicationContext(), presence,true); conv.startOtrSession(getApplicationContext(), presence,
true);
} else if (conv.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) { } else if (conv.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) {
// otr session aleary exists, creating message packet // otr session aleary exists, creating message packet
// accordingly // accordingly
@ -718,7 +745,8 @@ public class XmppConnectionService extends Service {
.getFullJid()); .getFullJid());
packet.setTo(message.getCounterpart()); packet.setTo(message.getCounterpart());
packet.setBody("This is an XEP-0027 encryted message"); packet.setBody("This is an XEP-0027 encryted message");
packet.addChild("x", "jabber:x:encrypted").setContent(message.getEncryptedBody()); packet.addChild("x", "jabber:x:encrypted").setContent(
message.getEncryptedBody());
message.setStatus(Message.STATUS_SEND); message.setStatus(Message.STATUS_SEND);
message.setEncryption(Message.ENCRYPTION_DECRYPTED); message.setEncryption(Message.ENCRYPTION_DECRYPTED);
saveInDb = true; saveInDb = true;
@ -751,7 +779,7 @@ public class XmppConnectionService extends Service {
convChangedListener.onConversationListChanged(); convChangedListener.onConversationListChanged();
} }
} }
if ((send)&&(packet!=null)) { if ((send) && (packet != null)) {
account.getXmppConnection().sendMessagePacket(packet); account.getXmppConnection().sendMessagePacket(packet);
} }
@ -759,7 +787,8 @@ public class XmppConnectionService extends Service {
private void sendUnsendMessages(Conversation conversation) { private void sendUnsendMessages(Conversation conversation) {
for (int i = 0; i < conversation.getMessages().size(); ++i) { for (int i = 0; i < conversation.getMessages().size(); ++i) {
if ((conversation.getMessages().get(i).getStatus() == Message.STATUS_UNSEND)&&(conversation.getMessages().get(i).getEncryption() == Message.ENCRYPTION_NONE)) { if ((conversation.getMessages().get(i).getStatus() == Message.STATUS_UNSEND)
&& (conversation.getMessages().get(i).getEncryption() == Message.ENCRYPTION_NONE)) {
Message message = conversation.getMessages().get(i); Message message = conversation.getMessages().get(i);
MessagePacket packet = prepareMessagePacket( MessagePacket packet = prepareMessagePacket(
conversation.getAccount(), message, null); conversation.getAccount(), message, null);
@ -792,8 +821,8 @@ public class XmppConnectionService extends Service {
+ ": could not encrypt message to " + ": could not encrypt message to "
+ message.getCounterpart()); + message.getCounterpart());
} }
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.setTo(otrSession.getSessionID().getAccountID() + "/" packet.setTo(otrSession.getSessionID().getAccountID() + "/"
+ otrSession.getSessionID().getUserID()); + otrSession.getSessionID().getUserID());
packet.setFrom(account.getFullJid()); packet.setFrom(account.getFullJid());
@ -840,7 +869,8 @@ public class XmppConnectionService extends Service {
} else { } else {
Log.d(LOGTAG, account.getJid() + ": fetching roster"); Log.d(LOGTAG, account.getJid() + ": fetching roster");
} }
iqPacket.query("jabber:iq:roster").setAttribute("ver", account.getRosterVersion()); iqPacket.query("jabber:iq:roster").setAttribute("ver",
account.getRosterVersion());
account.getXmppConnection().sendIqPacket(iqPacket, account.getXmppConnection().sendIqPacket(iqPacket,
new OnIqPacketReceived() { new OnIqPacketReceived() {
@ -870,8 +900,8 @@ public class XmppConnectionService extends Service {
.getContacts(mWhere.toString()); .getContacts(mWhere.toString());
for (Contact contact : contactsToDelete) { for (Contact contact : contactsToDelete) {
databaseBackend.deleteContact(contact); databaseBackend.deleteContact(contact);
replaceContactInConversation(account,contact.getJid(), replaceContactInConversation(account,
null); contact.getJid(), null);
} }
} else { } else {
@ -914,16 +944,19 @@ public class XmppConnectionService extends Service {
.getString("photouri")); .getString("photouri"));
contact.setDisplayName(phoneContact contact.setDisplayName(phoneContact
.getString("displayname")); .getString("displayname"));
databaseBackend.updateContact(contact,false); databaseBackend.updateContact(contact, false);
replaceContactInConversation(contact.getAccount(),contact.getJid(), replaceContactInConversation(
contact.getAccount(), contact.getJid(),
contact); contact);
} else { } else {
if ((contact.getSystemAccount() != null) if ((contact.getSystemAccount() != null)
|| (contact.getProfilePhoto() != null)) { || (contact.getProfilePhoto() != null)) {
contact.setSystemAccount(null); contact.setSystemAccount(null);
contact.setPhotoUri(null); contact.setPhotoUri(null);
databaseBackend.updateContact(contact,false); databaseBackend.updateContact(contact,
replaceContactInConversation(contact.getAccount(), false);
replaceContactInConversation(
contact.getAccount(),
contact.getJid(), contact); contact.getJid(), contact);
} }
} }
@ -1014,7 +1047,8 @@ public class XmppConnectionService extends Service {
this.databaseBackend.createConversation(conversation); this.databaseBackend.createConversation(conversation);
} }
this.conversations.add(conversation); this.conversations.add(conversation);
if ((account.getStatus() == Account.STATUS_ONLINE)&&(conversation.getMode() == Conversation.MODE_MULTI)) { if ((account.getStatus() == Account.STATUS_ONLINE)
&& (conversation.getMode() == Conversation.MODE_MULTI)) {
joinMuc(conversation); joinMuc(conversation);
} }
if (this.convChangedListener != null) { if (this.convChangedListener != null) {
@ -1035,7 +1069,7 @@ public class XmppConnectionService extends Service {
this.convChangedListener.onConversationListChanged(); this.convChangedListener.onConversationListChanged();
} }
} }
public void clearConversationHistory(Conversation conversation) { public void clearConversationHistory(Conversation conversation) {
this.databaseBackend.deleteMessagesInConversation(conversation); this.databaseBackend.deleteMessagesInConversation(conversation);
this.fileBackend.removeFiles(conversation); this.fileBackend.removeFiles(conversation);
@ -1060,9 +1094,11 @@ public class XmppConnectionService extends Service {
public void deleteContact(Contact contact) { public void deleteContact(Contact contact) {
IqPacket iq = new IqPacket(IqPacket.TYPE_SET); IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
Element query = iq.query("jabber:iq:roster"); Element query = iq.query("jabber:iq:roster");
query.addChild("item").setAttribute("jid", contact.getJid()).setAttribute("subscription", "remove"); query.addChild("item").setAttribute("jid", contact.getJid())
.setAttribute("subscription", "remove");
contact.getAccount().getXmppConnection().sendIqPacket(iq, null); contact.getAccount().getXmppConnection().sendIqPacket(iq, null);
replaceContactInConversation(contact.getAccount(),contact.getJid(), null); replaceContactInConversation(contact.getAccount(), contact.getJid(),
null);
databaseBackend.deleteContact(contact); databaseBackend.deleteContact(contact);
} }
@ -1092,7 +1128,7 @@ public class XmppConnectionService extends Service {
public void removeOnConversationListChangedListener() { public void removeOnConversationListChangedListener() {
this.convChangedListenerCount--; this.convChangedListenerCount--;
if (this.convChangedListenerCount==0) { if (this.convChangedListenerCount == 0) {
this.convChangedListener = null; this.convChangedListener = null;
} }
} }
@ -1159,6 +1195,9 @@ public class XmppConnectionService extends Service {
renameListener.onRename(success); renameListener.onRename(success);
} }
if (success) { if (success) {
String jid = conversation.getContactJid().split("/")[0] + "/"
+ nick;
conversation.setContactJid(jid);
databaseBackend.updateConversation(conversation); databaseBackend.updateConversation(conversation);
} }
} }
@ -1184,10 +1223,11 @@ public class XmppConnectionService extends Service {
public void leaveMuc(Conversation conversation) { public void leaveMuc(Conversation conversation) {
PresencePacket packet = new PresencePacket(); PresencePacket packet = new PresencePacket();
packet.setAttribute("to", conversation.getContactJid().split("/")[0] + "/" + conversation.getMucOptions().getNick()); packet.setAttribute("to", conversation.getContactJid().split("/")[0]
+ "/" + conversation.getMucOptions().getNick());
packet.setAttribute("from", conversation.getAccount().getFullJid()); packet.setAttribute("from", conversation.getAccount().getFullJid());
packet.setAttribute("type", "unavailable"); packet.setAttribute("type", "unavailable");
Log.d(LOGTAG,"send leaving muc " + packet); Log.d(LOGTAG, "send leaving muc " + packet);
conversation.getAccount().getXmppConnection() conversation.getAccount().getXmppConnection()
.sendPresencePacket(packet); .sendPresencePacket(packet);
conversation.getMucOptions().setOffline(); conversation.getMucOptions().setOffline();
@ -1219,8 +1259,9 @@ public class XmppConnectionService extends Service {
} }
public void updateContact(Contact contact) { public void updateContact(Contact contact) {
databaseBackend.updateContact(contact,false); databaseBackend.updateContact(contact, false);
replaceContactInConversation(contact.getAccount(),contact.getJid(), contact); replaceContactInConversation(contact.getAccount(), contact.getJid(),
contact);
} }
public void updateMessage(Message message) { public void updateMessage(Message message) {
@ -1247,12 +1288,14 @@ public class XmppConnectionService extends Service {
account.getXmppConnection().sendIqPacket(iq, null); account.getXmppConnection().sendIqPacket(iq, null);
if (autoGrant) { if (autoGrant) {
requestPresenceUpdatesFrom(contact); requestPresenceUpdatesFrom(contact);
if (account.getXmppConnection().hasPendingSubscription(contact.getJid())) { if (account.getXmppConnection().hasPendingSubscription(
Log.d("xmppService","contact had pending subscription"); contact.getJid())) {
Log.d("xmppService", "contact had pending subscription");
sendPresenceUpdatesTo(contact); sendPresenceUpdatesTo(contact);
} }
} }
replaceContactInConversation(contact.getAccount(),contact.getJid(), contact); replaceContactInConversation(contact.getAccount(), contact.getJid(),
contact);
} }
public void requestPresenceUpdatesFrom(Contact contact) { public void requestPresenceUpdatesFrom(Contact contact) {
@ -1308,23 +1351,13 @@ public class XmppConnectionService extends Service {
account.getXmppConnection().sendPresencePacket(packet); account.getXmppConnection().sendPresencePacket(packet);
} }
public void generatePgpAnnouncement(Account account)
throws PgpEngine.UserInputRequiredException {
if (account.getStatus() == Account.STATUS_ONLINE) {
String signature = getPgpEngine().generateSignature(account,"online");
account.setKey("pgp_signature", signature);
databaseBackend.updateAccount(account);
sendPgpPresence(account, signature);
}
}
public void updateConversation(Conversation conversation) { public void updateConversation(Conversation conversation) {
this.databaseBackend.updateConversation(conversation); this.databaseBackend.updateConversation(conversation);
} }
public Contact findContact(String uuid) { public Contact findContact(String uuid) {
Contact contact = this.databaseBackend.getContact(uuid); Contact contact = this.databaseBackend.getContact(uuid);
if (contact!=null) { if (contact != null) {
for (Account account : getAccounts()) { for (Account account : getAccounts()) {
if (contact.getAccountUuid().equals(account.getUuid())) { if (contact.getAccountUuid().equals(account.getUuid())) {
contact.setAccount(account); contact.setAccount(account);
@ -1398,12 +1431,14 @@ public class XmppConnectionService extends Service {
} }
} }
public boolean markMessage(Account account, String recipient, String uuid, int status) { public boolean markMessage(Account account, String recipient, String uuid,
int status) {
boolean marked = false; boolean marked = false;
for(Conversation conversation : getConversations()) { for (Conversation conversation : getConversations()) {
if (conversation.getContactJid().equals(recipient)&&conversation.getAccount().equals(account)) { if (conversation.getContactJid().equals(recipient)
for(Message message : conversation.getMessages()) { && conversation.getAccount().equals(account)) {
for (Message message : conversation.getMessages()) {
if (message.getUuid().equals(uuid)) { if (message.getUuid().equals(uuid)) {
markMessage(message, status); markMessage(message, status);
marked = true; marked = true;
@ -1415,16 +1450,17 @@ public class XmppConnectionService extends Service {
} }
return marked; return marked;
} }
public void markMessage(Message message, int status) { public void markMessage(Message message, int status) {
message.setStatus(status); message.setStatus(status);
databaseBackend.updateMessage(message); databaseBackend.updateMessage(message);
if (convChangedListener!=null) { if (convChangedListener != null) {
convChangedListener.onConversationListChanged(); convChangedListener.onConversationListChanged();
} }
} }
public SharedPreferences getPreferences() { public SharedPreferences getPreferences() {
return PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); return PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
} }
} }

View file

@ -1,18 +1,17 @@
package eu.siacs.conversations.ui; package eu.siacs.conversations.ui;
import java.io.FileNotFoundException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.openintents.openpgp.OpenPgpError;
import net.java.otr4j.session.SessionStatus; import net.java.otr4j.session.SessionStatus;
import eu.siacs.conversations.R; import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine.OpenPgpException; import eu.siacs.conversations.crypto.OnPgpEngineResult;
import eu.siacs.conversations.crypto.PgpEngine.UserInputRequiredException; import eu.siacs.conversations.crypto.PgpEngine;
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;
@ -24,6 +23,7 @@ import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.jingle.JingleConnection; import eu.siacs.conversations.xmpp.jingle.JingleConnection;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Fragment; import android.app.Fragment;
import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
@ -33,7 +33,6 @@ import android.content.IntentSender.SendIntentException;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
@ -245,6 +244,7 @@ public class ConversationFragment extends Fragment {
} else { } else {
viewHolder = (ViewHolder) view.getTag(); viewHolder = (ViewHolder) view.getTag();
} }
if (type == RECIEVED) { if (type == RECIEVED) {
if (item.getConversation().getMode() == Conversation.MODE_MULTI) { if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
if (item.getCounterpart() != null) { if (item.getCounterpart() != null) {
@ -267,8 +267,14 @@ public class ConversationFragment extends Fragment {
viewHolder.indicator.setVisibility(View.VISIBLE); viewHolder.indicator.setVisibility(View.VISIBLE);
} }
String filesize = "";
if (item.getType() == Message.TYPE_IMAGE) { if (item.getType() == Message.TYPE_IMAGE) {
String[] fileParams = item.getBody().split(",");
if (fileParams.length>=1) {
long size = Long.parseLong(fileParams[0]);
filesize = size/1024+" KB \u00B7 ";
}
if ((item.getStatus() == Message.STATUS_PREPARING)||(item.getStatus() == Message.STATUS_RECIEVING)) { if ((item.getStatus() == Message.STATUS_PREPARING)||(item.getStatus() == Message.STATUS_RECIEVING)) {
viewHolder.image.setVisibility(View.GONE); viewHolder.image.setVisibility(View.GONE);
viewHolder.messageBody.setVisibility(View.VISIBLE); viewHolder.messageBody.setVisibility(View.VISIBLE);
@ -299,11 +305,10 @@ public class ConversationFragment extends Fragment {
} else { } else {
viewHolder.messageBody.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.GONE);
viewHolder.image.setVisibility(View.VISIBLE); viewHolder.image.setVisibility(View.VISIBLE);
String[] params = item.getBody().split(","); if (fileParams.length==3) {
if (params.length==3) {
double target = metrics.density * 288; double target = metrics.density * 288;
int w = Integer.parseInt(params[1]); int w = Integer.parseInt(fileParams[1]);
int h = Integer.parseInt(params[2]); int h = Integer.parseInt(fileParams[2]);
int scalledW; int scalledW;
int scalledH; int scalledH;
if (w <= h) { if (w <= h) {
@ -341,11 +346,10 @@ public class ConversationFragment extends Fragment {
viewHolder.messageBody.setTextColor(0xff33B5E5); viewHolder.messageBody.setTextColor(0xff33B5E5);
viewHolder.messageBody.setTypeface(null, viewHolder.messageBody.setTypeface(null,
Typeface.ITALIC); Typeface.ITALIC);
} else if ((item.getEncryption() == Message.ENCRYPTION_OTR)||(item.getEncryption() == Message.ENCRYPTION_DECRYPTED)) { } else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
viewHolder.messageBody.setText(body.trim()); viewHolder.messageBody.setText(getString(R.string.decryption_failed));
viewHolder.messageBody.setTextColor(0xff333333); viewHolder.messageBody.setTextColor(0xFFe92727);
viewHolder.messageBody.setTypeface(null, viewHolder.messageBody.setTypeface(null,Typeface.NORMAL);
Typeface.NORMAL);
} else { } else {
viewHolder.messageBody.setText(body.trim()); viewHolder.messageBody.setText(body.trim());
viewHolder.messageBody.setTextColor(0xff333333); viewHolder.messageBody.setTextColor(0xff333333);
@ -358,21 +362,21 @@ public class ConversationFragment extends Fragment {
case Message.STATUS_UNSEND: case Message.STATUS_UNSEND:
viewHolder.time.setTypeface(null, Typeface.ITALIC); viewHolder.time.setTypeface(null, Typeface.ITALIC);
viewHolder.time.setTextColor(0xFF8e8e8e); viewHolder.time.setTextColor(0xFF8e8e8e);
viewHolder.time.setText("sending\u2026"); viewHolder.time.setText(filesize+"sending\u2026");
break; break;
case Message.STATUS_OFFERED: case Message.STATUS_OFFERED:
viewHolder.time.setTypeface(null, Typeface.ITALIC); viewHolder.time.setTypeface(null, Typeface.ITALIC);
viewHolder.time.setTextColor(0xFF8e8e8e); viewHolder.time.setTextColor(0xFF8e8e8e);
viewHolder.time.setText("offering\u2026"); viewHolder.time.setText(filesize+"offering\u2026");
break; break;
case Message.STATUS_SEND_FAILED: case Message.STATUS_SEND_FAILED:
viewHolder.time.setText(getString(R.string.send_failed) + " \u00B7 " + UIHelper.readableTimeDifference(item viewHolder.time.setText(filesize+getString(R.string.send_failed) + " \u00B7 " + UIHelper.readableTimeDifference(item
.getTimeSent())); .getTimeSent()));
viewHolder.time.setTextColor(0xFFe92727); viewHolder.time.setTextColor(0xFFe92727);
viewHolder.time.setTypeface(null,Typeface.NORMAL); viewHolder.time.setTypeface(null,Typeface.NORMAL);
break; break;
case Message.STATUS_SEND_REJECTED: case Message.STATUS_SEND_REJECTED:
viewHolder.time.setText(getString(R.string.send_rejected)); viewHolder.time.setText(filesize+getString(R.string.send_rejected));
viewHolder.time.setTextColor(0xFFe92727); viewHolder.time.setTextColor(0xFFe92727);
viewHolder.time.setTypeface(null,Typeface.NORMAL); viewHolder.time.setTypeface(null,Typeface.NORMAL);
break; break;
@ -380,7 +384,7 @@ public class ConversationFragment extends Fragment {
viewHolder.time.setTypeface(null, Typeface.NORMAL); viewHolder.time.setTypeface(null, Typeface.NORMAL);
viewHolder.time.setTextColor(0xFF8e8e8e); viewHolder.time.setTextColor(0xFF8e8e8e);
if (item.getConversation().getMode() == Conversation.MODE_SINGLE) { if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
viewHolder.time.setText(UIHelper viewHolder.time.setText(filesize+UIHelper
.readableTimeDifference(item.getTimeSent())); .readableTimeDifference(item.getTimeSent()));
} else { } else {
viewHolder.time.setText(item.getCounterpart() viewHolder.time.setText(item.getCounterpart()
@ -470,21 +474,47 @@ public class ConversationFragment extends Fragment {
}); });
} }
} }
private void decryptMessage(final Message message) {
Log.d("xmppService","called to decrypt");
PgpEngine engine = activity.xmppConnectionService.getPgpEngine();
if (engine!=null) {
engine.decrypt(message,new OnPgpEngineResult() {
@Override
public void userInputRequried(PendingIntent pi) {
askForPassphraseIntent = pi.getIntentSender();
pgpInfo.setVisibility(View.VISIBLE);
}
@Override
public void success() {
Log.d("xmppService","successfully decrypted");
activity.xmppConnectionService.databaseBackend.updateMessage(message);
updateMessages();
}
@Override
public void error(OpenPgpError openPgpError) {
Log.d("xmppService","decryption error"+openPgpError.getMessage());
message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
//updateMessages();
}
});
} else {
Log.d("xmppService","engine was null");
}
}
public void updateMessages() { public void updateMessages() {
ConversationActivity activity = (ConversationActivity) getActivity(); ConversationActivity activity = (ConversationActivity) getActivity();
if (this.conversation != null) { if (this.conversation != null) {
List<Message> encryptedMessages = new LinkedList<Message>();
for (Message message : this.conversation.getMessages()) { for (Message message : this.conversation.getMessages()) {
if (message.getEncryption() == Message.ENCRYPTION_PGP) { if (message.getEncryption() == Message.ENCRYPTION_PGP) {
encryptedMessages.add(message); decryptMessage(message);
break;
} }
} }
if (encryptedMessages.size() > 0) {
DecryptMessage task = new DecryptMessage();
Message[] msgs = new Message[encryptedMessages.size()];
task.execute(encryptedMessages.toArray(msgs));
}
this.messageList.clear(); this.messageList.clear();
this.messageList.addAll(this.conversation.getMessages()); this.messageList.addAll(this.conversation.getMessages());
this.messageListAdapter.notifyDataSetChanged(); this.messageListAdapter.notifyDataSetChanged();
@ -492,7 +522,7 @@ public class ConversationFragment extends Fragment {
if (messageList.size() >= 1) { if (messageList.size() >= 1) {
int latestEncryption = this.conversation.getLatestMessage() int latestEncryption = this.conversation.getLatestMessage()
.getEncryption(); .getEncryption();
if (latestEncryption == Message.ENCRYPTION_DECRYPTED) { if ((latestEncryption == Message.ENCRYPTION_DECRYPTED)||(latestEncryption == Message.ENCRYPTION_DECRYPTION_FAILED)) {
conversation.nextMessageEncryption = Message.ENCRYPTION_PGP; conversation.nextMessageEncryption = Message.ENCRYPTION_PGP;
} else { } else {
conversation.nextMessageEncryption = latestEncryption; conversation.nextMessageEncryption = latestEncryption;
@ -566,25 +596,63 @@ public class ConversationFragment extends Fragment {
protected void sendPgpMessage(final Message message) { protected void sendPgpMessage(final Message message) {
ConversationActivity activity = (ConversationActivity) getActivity(); ConversationActivity activity = (ConversationActivity) getActivity();
final XmppConnectionService xmppService = activity.xmppConnectionService; final XmppConnectionService xmppService = activity.xmppConnectionService;
Contact contact = message.getConversation().getContact(); final Contact contact = message.getConversation().getContact();
Account account = message.getConversation().getAccount(); final Account account = message.getConversation().getAccount();
if (activity.hasPgp()) { if (activity.hasPgp()) {
if (contact.getPgpKeyId() != 0) { if (contact.getPgpKeyId() != 0) {
try { xmppService.getPgpEngine().hasKey(account,contact.getPgpKeyId(), new OnPgpEngineResult() {
message.setEncryptedBody(xmppService.getPgpEngine().encrypt(account, contact.getPgpKeyId(), message.getBody()));
xmppService.sendMessage(message, null); @Override
chatMsg.setText(""); public void userInputRequried(PendingIntent pi) {
} catch (UserInputRequiredException e) { Log.d("xmppService","hasKey returned user input required");
try { try {
getActivity().startIntentSenderForResult(e.getPendingIntent().getIntentSender(), getActivity().startIntentSenderForResult(pi.getIntentSender(),
ConversationActivity.REQUEST_SEND_MESSAGE, null, 0, ConversationActivity.REQUEST_SEND_MESSAGE, null, 0,
0, 0); 0, 0);
} catch (SendIntentException e1) { } catch (SendIntentException e1) {
Log.d("xmppService","failed to start intent to send message"); Log.d("xmppService","failed to start intent to send message");
}
} }
} catch (OpenPgpException e) {
Log.d("xmppService","error encrypting with pgp: "+e.getOpenPgpError().getMessage()); @Override
} public void success() {
Log.d("xmppService","hasKey returned success");
xmppService.getPgpEngine().encrypt(account, contact.getPgpKeyId(), message,new OnPgpEngineResult() {
@Override
public void userInputRequried(PendingIntent pi) {
try {
getActivity().startIntentSenderForResult(pi.getIntentSender(),
ConversationActivity.REQUEST_SEND_MESSAGE, null, 0,
0, 0);
} catch (SendIntentException e1) {
Log.d("xmppService","failed to start intent to send message");
}
}
@Override
public void success() {
xmppService.sendMessage(message, null);
chatMsg.setText("");
}
@Override
public void error(OpenPgpError openPgpError) {
// TODO Auto-generated method stub
}
});
}
@Override
public void error(OpenPgpError openPgpError) {
Log.d("xmppService","openpgp error"+openPgpError.getMessage());
}
});
} else { } else {
AlertDialog.Builder builder = new AlertDialog.Builder( AlertDialog.Builder builder = new AlertDialog.Builder(
getActivity()); getActivity());
@ -667,7 +735,7 @@ public class ConversationFragment extends Fragment {
} }
} }
class DecryptMessage extends AsyncTask<Message, Void, Boolean> { /*class DecryptMessage extends AsyncTask<Message, Void, Boolean> {
@Override @Override
protected Boolean doInBackground(Message... params) { protected Boolean doInBackground(Message... params) {
@ -729,7 +797,7 @@ public class ConversationFragment extends Fragment {
return true; return true;
} }
} }*/
public void setText(String text) { public void setText(String text) {
this.pastedText = text; this.pastedText = text;

View file

@ -3,15 +3,18 @@ package eu.siacs.conversations.ui;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.openintents.openpgp.OpenPgpError;
import eu.siacs.conversations.R; import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.OnPgpEngineResult;
import eu.siacs.conversations.crypto.PgpEngine; import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.crypto.PgpEngine.UserInputRequiredException;
import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.ui.EditAccount.EditAccountListener; import eu.siacs.conversations.ui.EditAccount.EditAccountListener;
import eu.siacs.conversations.xmpp.OnTLSExceptionReceived; import eu.siacs.conversations.xmpp.OnTLSExceptionReceived;
import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.XmppConnection;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener; import android.content.DialogInterface.OnClickListener;
@ -278,15 +281,7 @@ public class ManageAccountActivity extends XmppActivity {
} else if (item.getItemId()==R.id.mgmt_account_announce_pgp) { } else if (item.getItemId()==R.id.mgmt_account_announce_pgp) {
if (activity.hasPgp()) { if (activity.hasPgp()) {
mode.finish(); mode.finish();
try { announcePgp();
xmppConnectionService.generatePgpAnnouncement(selectedAccountForActionMode);
} catch (PgpEngine.UserInputRequiredException e) {
try {
startIntentSenderForResult(e.getPendingIntent().getIntentSender(), REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
} catch (SendIntentException e1) {
Log.d("gultsch","sending intent failed");
}
}
} }
} else if (item.getItemId() == R.id.mgmt_otr_key) { } else if (item.getItemId() == R.id.mgmt_otr_key) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity); AlertDialog.Builder builder = new AlertDialog.Builder(activity);
@ -367,6 +362,33 @@ public class ManageAccountActivity extends XmppActivity {
}); });
} }
private void announcePgp() {
final Account account = selectedAccountForActionMode;
xmppConnectionService.getPgpEngine().generateSignature(account, "online", new OnPgpEngineResult() {
@Override
public void userInputRequried(PendingIntent pi) {
try {
startIntentSenderForResult(pi.getIntentSender(), REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
} catch (SendIntentException e) {
Log.d("xmppService","coulnd start intent for pgp anncouncment");
}
}
@Override
public void success() {
xmppConnectionService.databaseBackend.updateAccount(account);
xmppConnectionService.sendPgpPresence(account, account.getPgpSignature());
}
@Override
public void error(OpenPgpError openPgpError) {
// TODO Auto-generated method stub
}
});
}
@Override @Override
protected void onStop() { protected void onStop() {
if (xmppConnectionServiceBound) { if (xmppConnectionServiceBound) {
@ -465,15 +487,7 @@ public class ManageAccountActivity extends XmppActivity {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
if (requestCode == REQUEST_ANNOUNCE_PGP) { if (requestCode == REQUEST_ANNOUNCE_PGP) {
try { announcePgp();
xmppConnectionService.generatePgpAnnouncement(selectedAccountForActionMode);
} catch (UserInputRequiredException e) {
try {
startIntentSenderForResult(e.getPendingIntent().getIntentSender(), REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
} catch (SendIntentException e1) {
Log.d(LOGTAG,"sending intent failed");
}
}
} }
} }
} }

View file

@ -44,7 +44,7 @@ public class JingleConnectionManager {
return; return;
} }
} }
Log.d("xmppService","delivering packet failed "+packet.toString()); account.getXmppConnection().sendIqPacket(packet.generateRespone(IqPacket.TYPE_ERROR), null);
} }
} }