basic pgp support.
This commit is contained in:
parent
bfee69b00b
commit
37d1a53806
|
@ -9,9 +9,9 @@ package de.gultsch.chat;
|
||||||
|
|
||||||
public final class R {
|
public final class R {
|
||||||
public static final class array {
|
public static final class array {
|
||||||
public static final int conversation_encryption_type_entries=0x7f050000;
|
public static final int conversation_encryption_type_entries=0x7f060000;
|
||||||
public static final int conversation_encryption_type_values=0x7f050001;
|
public static final int conversation_encryption_type_values=0x7f060001;
|
||||||
public static final int manage_account_options=0x7f050002;
|
public static final int manage_account_options=0x7f060002;
|
||||||
}
|
}
|
||||||
public static final class attr {
|
public static final class attr {
|
||||||
}
|
}
|
||||||
|
@ -22,24 +22,25 @@ public final class R {
|
||||||
screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.
|
screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
public static final int activity_horizontal_margin=0x7f060000;
|
public static final int activity_horizontal_margin=0x7f070000;
|
||||||
public static final int activity_vertical_margin=0x7f060001;
|
public static final int activity_vertical_margin=0x7f070001;
|
||||||
}
|
}
|
||||||
public static final class drawable {
|
public static final class drawable {
|
||||||
public static final int es_slidingpane_shadow=0x7f020000;
|
public static final int es_slidingpane_shadow=0x7f020000;
|
||||||
public static final int ic_action_add=0x7f020001;
|
public static final int ic_action_add=0x7f020001;
|
||||||
public static final int ic_action_add_person=0x7f020002;
|
public static final int ic_action_add_person=0x7f020002;
|
||||||
public static final int ic_action_delete=0x7f020003;
|
public static final int ic_action_cancel_launchersize=0x7f020003;
|
||||||
public static final int ic_action_refresh=0x7f020004;
|
public static final int ic_action_delete=0x7f020004;
|
||||||
public static final int ic_action_secure=0x7f020005;
|
public static final int ic_action_refresh=0x7f020005;
|
||||||
public static final int ic_action_send=0x7f020006;
|
public static final int ic_action_secure=0x7f020006;
|
||||||
public static final int ic_action_send_now=0x7f020007;
|
public static final int ic_action_send=0x7f020007;
|
||||||
public static final int ic_action_unsecure=0x7f020008;
|
public static final int ic_action_send_now=0x7f020008;
|
||||||
public static final int ic_launcher=0x7f020009;
|
public static final int ic_action_unsecure=0x7f020009;
|
||||||
public static final int ic_profile=0x7f02000a;
|
public static final int ic_launcher=0x7f02000a;
|
||||||
public static final int message_border=0x7f02000b;
|
public static final int ic_profile=0x7f02000b;
|
||||||
public static final int notification=0x7f02000c;
|
public static final int message_border=0x7f02000c;
|
||||||
public static final int section_header=0x7f02000d;
|
public static final int notification=0x7f02000d;
|
||||||
|
public static final int section_header=0x7f02000e;
|
||||||
}
|
}
|
||||||
public static final class id {
|
public static final class id {
|
||||||
public static final int account_confirm_password_desc=0x7f0a001c;
|
public static final int account_confirm_password_desc=0x7f0a001c;
|
||||||
|
@ -57,9 +58,10 @@ public final class R {
|
||||||
public static final int action_add_account=0x7f0a0034;
|
public static final int action_add_account=0x7f0a0034;
|
||||||
public static final int action_archive=0x7f0a002e;
|
public static final int action_archive=0x7f0a002e;
|
||||||
public static final int action_details=0x7f0a002d;
|
public static final int action_details=0x7f0a002d;
|
||||||
public static final int action_refresh_contacts=0x7f0a0038;
|
public static final int action_refresh_contacts=0x7f0a0039;
|
||||||
public static final int action_security=0x7f0a002c;
|
public static final int action_security=0x7f0a002c;
|
||||||
public static final int action_settings=0x7f0a0030;
|
public static final int action_settings=0x7f0a0030;
|
||||||
|
public static final int announce_pgp=0x7f0a0038;
|
||||||
public static final int contactList=0x7f0a0006;
|
public static final int contactList=0x7f0a0006;
|
||||||
public static final int contact_display_name=0x7f0a0008;
|
public static final int contact_display_name=0x7f0a0008;
|
||||||
public static final int contact_jid=0x7f0a0009;
|
public static final int contact_jid=0x7f0a0009;
|
||||||
|
@ -123,17 +125,21 @@ public final class R {
|
||||||
public static final int newconversation=0x7f090004;
|
public static final int newconversation=0x7f090004;
|
||||||
}
|
}
|
||||||
public static final class string {
|
public static final class string {
|
||||||
public static final int action_accounts=0x7f070003;
|
public static final int action_accounts=0x7f050005;
|
||||||
public static final int action_add=0x7f070002;
|
public static final int action_add=0x7f050004;
|
||||||
public static final int action_add_account=0x7f070007;
|
public static final int action_add_account=0x7f050009;
|
||||||
public static final int action_archive=0x7f070004;
|
public static final int action_archive=0x7f050006;
|
||||||
public static final int action_details=0x7f070005;
|
public static final int action_details=0x7f050007;
|
||||||
public static final int action_secure=0x7f070006;
|
public static final int action_secure=0x7f050008;
|
||||||
public static final int action_settings=0x7f070001;
|
public static final int action_settings=0x7f050003;
|
||||||
public static final int app_name=0x7f070000;
|
public static final int announce_pgp=0x7f05000d;
|
||||||
public static final int just_now=0x7f070009;
|
public static final int app_name=0x7f050002;
|
||||||
public static final int sending=0x7f07000a;
|
public static final int encrypted_message=0x7f05000e;
|
||||||
public static final int title_activity_new_conversation=0x7f070008;
|
public static final int just_now=0x7f05000b;
|
||||||
|
public static final int openpgp_install_openkeychain_via=0x7f050001;
|
||||||
|
public static final int openpgp_list_preference_none=0x7f050000;
|
||||||
|
public static final int sending=0x7f05000c;
|
||||||
|
public static final int title_activity_new_conversation=0x7f05000a;
|
||||||
}
|
}
|
||||||
public static final class style {
|
public static final class style {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -84,5 +84,4 @@
|
||||||
android:typeface="monospace"/>
|
android:typeface="monospace"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
|
@ -24,6 +24,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Hi, how are you?"
|
android:text="Hi, how are you?"
|
||||||
|
android:autoLink="all"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
android:id="@+id/message_body"
|
android:id="@+id/message_body"
|
||||||
android:textColor="#333333"/>
|
android:textColor="#333333"/>
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
android:text="Hi, how are you?"
|
android:text="Hi, how are you?"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
android:id="@+id/message_body"
|
android:id="@+id/message_body"
|
||||||
|
android:autoLink="all"
|
||||||
android:textColor="#333333"/>
|
android:textColor="#333333"/>
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -16,4 +16,10 @@
|
||||||
android:showAsAction="always"
|
android:showAsAction="always"
|
||||||
android:visible="false"/>
|
android:visible="false"/>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/announce_pgp"
|
||||||
|
android:orderInCategory="75"
|
||||||
|
android:showAsAction="never"
|
||||||
|
android:title="@string/announce_pgp" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
|
|
@ -12,4 +12,6 @@
|
||||||
<string name="title_activity_new_conversation">New Conversation</string>
|
<string name="title_activity_new_conversation">New Conversation</string>
|
||||||
<string name="just_now">just now</string>
|
<string name="just_now">just now</string>
|
||||||
<string name="sending">sending…</string>
|
<string name="sending">sending…</string>
|
||||||
|
<string name="announce_pgp">Renew PGP announcement</string>
|
||||||
|
<string name="encrypted_message">This message is encrypted. Click to decrypt.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -93,8 +93,6 @@ public class OtrEngine implements OtrEngineHost {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (InvalidKeySpecException e) {
|
} catch (InvalidKeySpecException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (JSONException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
package de.gultsch.chat.crypto;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import org.openintents.openpgp.OpenPgpError;
|
||||||
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
|
import org.openintents.openpgp.util.OpenPgpConstants;
|
||||||
|
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class PgpEngine {
|
||||||
|
private OpenPgpApi api;
|
||||||
|
|
||||||
|
public PgpEngine(OpenPgpApi api) {
|
||||||
|
this.api = api;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String decrypt(String message) throws UserInputRequiredException,
|
||||||
|
OpenPgpException {
|
||||||
|
InputStream is = new ByteArrayInputStream(message.getBytes());
|
||||||
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
Bundle result = api.decryptAndVerify(is, os);
|
||||||
|
switch (result.getInt(OpenPgpConstants.RESULT_CODE)) {
|
||||||
|
case OpenPgpConstants.RESULT_CODE_SUCCESS:
|
||||||
|
return os.toString();
|
||||||
|
case OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
||||||
|
throw new UserInputRequiredException(
|
||||||
|
(PendingIntent) result
|
||||||
|
.getParcelable(OpenPgpConstants.RESULT_INTENT));
|
||||||
|
case OpenPgpConstants.RESULT_CODE_ERROR:
|
||||||
|
throw new OpenPgpException(
|
||||||
|
(OpenPgpError) result
|
||||||
|
.getParcelable(OpenPgpConstants.RESULT_ERRORS));
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String encrypt(long keyId, String message) {
|
||||||
|
Bundle params = new Bundle();
|
||||||
|
params.putBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true);
|
||||||
|
long[] keyIds = { keyId };
|
||||||
|
params.putLongArray(OpenPgpConstants.PARAMS_KEY_IDS, keyIds);
|
||||||
|
|
||||||
|
InputStream is = new ByteArrayInputStream(message.getBytes());
|
||||||
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
Bundle result = api.encrypt(params, is, os);
|
||||||
|
StringBuilder encryptedMessageBody = new StringBuilder();
|
||||||
|
String[] lines = os.toString().split("\n");
|
||||||
|
for (int i = 3; i < lines.length - 1; ++i) {
|
||||||
|
encryptedMessageBody.append(lines[i].trim());
|
||||||
|
}
|
||||||
|
return encryptedMessageBody.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long fetchKeyId(String status, String signature)
|
||||||
|
throws OpenPgpException {
|
||||||
|
StringBuilder pgpSig = new StringBuilder();
|
||||||
|
pgpSig.append("-----BEGIN PGP SIGNED MESSAGE-----");
|
||||||
|
pgpSig.append('\n');
|
||||||
|
pgpSig.append("Hash: SHA1");
|
||||||
|
pgpSig.append('\n');
|
||||||
|
pgpSig.append('\n');
|
||||||
|
pgpSig.append(status);
|
||||||
|
pgpSig.append('\n');
|
||||||
|
pgpSig.append("-----BEGIN PGP SIGNATURE-----");
|
||||||
|
pgpSig.append('\n');
|
||||||
|
pgpSig.append('\n');
|
||||||
|
pgpSig.append(signature.replace("\n", "").trim());
|
||||||
|
pgpSig.append('\n');
|
||||||
|
pgpSig.append("-----END PGP SIGNATURE-----");
|
||||||
|
Bundle params = new Bundle();
|
||||||
|
params.putBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true);
|
||||||
|
InputStream is = new ByteArrayInputStream(pgpSig.toString().getBytes());
|
||||||
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
Bundle result = api.decryptAndVerify(params, is, os);
|
||||||
|
switch (result.getInt(OpenPgpConstants.RESULT_CODE)) {
|
||||||
|
case OpenPgpConstants.RESULT_CODE_SUCCESS:
|
||||||
|
OpenPgpSignatureResult sigResult = result
|
||||||
|
.getParcelable(OpenPgpConstants.RESULT_SIGNATURE);
|
||||||
|
return sigResult.getKeyId();
|
||||||
|
case OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
||||||
|
break;
|
||||||
|
case OpenPgpConstants.RESULT_CODE_ERROR:
|
||||||
|
throw new OpenPgpException(
|
||||||
|
(OpenPgpError) result
|
||||||
|
.getParcelable(OpenPgpConstants.RESULT_ERRORS));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateSignature(String status)
|
||||||
|
throws UserInputRequiredException {
|
||||||
|
Bundle params = new Bundle();
|
||||||
|
params.putBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true);
|
||||||
|
InputStream is = new ByteArrayInputStream(status.getBytes());
|
||||||
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
Bundle result = api.sign(params, is, os);
|
||||||
|
StringBuilder signatureBuilder = new StringBuilder();
|
||||||
|
switch (result.getInt(OpenPgpConstants.RESULT_CODE)) {
|
||||||
|
case OpenPgpConstants.RESULT_CODE_SUCCESS:
|
||||||
|
String[] lines = os.toString().split("\n");
|
||||||
|
for (int i = 7; i < lines.length - 1; ++i) {
|
||||||
|
signatureBuilder.append(lines[i].trim());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
||||||
|
UserInputRequiredException exception = new UserInputRequiredException(
|
||||||
|
(PendingIntent) result
|
||||||
|
.getParcelable(OpenPgpConstants.RESULT_INTENT));
|
||||||
|
throw exception;
|
||||||
|
case OpenPgpConstants.RESULT_CODE_ERROR:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return signatureBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UserInputRequiredException extends Exception {
|
||||||
|
private static final long serialVersionUID = -6913480043269132016L;
|
||||||
|
private PendingIntent pi;
|
||||||
|
|
||||||
|
public UserInputRequiredException(PendingIntent pi) {
|
||||||
|
this.pi = pi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PendingIntent getPendingIntent() {
|
||||||
|
return this.pi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OpenPgpException extends Exception {
|
||||||
|
private static final long serialVersionUID = -7324789703473056077L;
|
||||||
|
private OpenPgpError error;
|
||||||
|
|
||||||
|
public OpenPgpException(OpenPgpError openPgpError) {
|
||||||
|
this.error = openPgpError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenPgpError getOpenPgpError() {
|
||||||
|
return this.error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -137,8 +137,13 @@ public class Account extends AbstractEntity{
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setKey(String keyName, String keyValue) throws JSONException {
|
public boolean setKey(String keyName, String keyValue) {
|
||||||
|
try {
|
||||||
this.keys.put(keyName, keyValue);
|
this.keys.put(keyName, keyValue);
|
||||||
|
return true;
|
||||||
|
} catch (JSONException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -221,6 +221,26 @@ public class Contact extends AbstractEntity implements Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPgpKeyId(long keyId) {
|
||||||
|
try {
|
||||||
|
this.keys.put("pgp_keyid", keyId);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPgpKeyId() {
|
||||||
|
if (this.keys.has("pgp_keyid")) {
|
||||||
|
try {
|
||||||
|
return this.keys.getLong("pgp_keyid");
|
||||||
|
} catch (JSONException e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setSubscriptionOption(int option) {
|
public void setSubscriptionOption(int option) {
|
||||||
this.subscription |= 1 << option;
|
this.subscription |= 1 << option;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ public class Message extends AbstractEntity {
|
||||||
public static final int ENCRYPTION_NONE = 0;
|
public static final int ENCRYPTION_NONE = 0;
|
||||||
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 String CONVERSATION = "conversationUuid";
|
public static String CONVERSATION = "conversationUuid";
|
||||||
public static String COUNTERPART = "counterpart";
|
public static String COUNTERPART = "counterpart";
|
||||||
|
@ -137,4 +138,7 @@ public class Message extends AbstractEntity {
|
||||||
this.encryption = encryption;
|
this.encryption = encryption;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBody(String body) {
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,16 @@
|
||||||
package de.gultsch.chat.services;
|
package de.gultsch.chat.services;
|
||||||
|
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.io.Writer;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -8,11 +19,21 @@ import java.util.Hashtable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.openintents.openpgp.IOpenPgpService;
|
||||||
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
|
import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
||||||
|
import org.openintents.openpgp.OpenPgpError;
|
||||||
|
|
||||||
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.SessionImpl;
|
import net.java.otr4j.session.SessionImpl;
|
||||||
import net.java.otr4j.session.SessionStatus;
|
import net.java.otr4j.session.SessionStatus;
|
||||||
|
|
||||||
|
import de.gultsch.chat.crypto.PgpEngine;
|
||||||
|
import de.gultsch.chat.crypto.PgpEngine.OpenPgpException;
|
||||||
|
import de.gultsch.chat.crypto.PgpEngine.UserInputRequiredException;
|
||||||
import de.gultsch.chat.entities.Account;
|
import de.gultsch.chat.entities.Account;
|
||||||
import de.gultsch.chat.entities.Contact;
|
import de.gultsch.chat.entities.Contact;
|
||||||
import de.gultsch.chat.entities.Conversation;
|
import de.gultsch.chat.entities.Conversation;
|
||||||
|
@ -46,7 +67,9 @@ import android.database.DatabaseUtils;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
|
import android.os.RemoteException;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
@ -84,7 +107,12 @@ public class XmppConnectionService extends Service {
|
||||||
Message message = null;
|
Message message = null;
|
||||||
boolean notify = false;
|
boolean notify = false;
|
||||||
if ((packet.getType() == MessagePacket.TYPE_CHAT)) {
|
if ((packet.getType() == MessagePacket.TYPE_CHAT)) {
|
||||||
if (packet.hasChild("body")
|
String pgpBody = MessageParser.getPgpBody(packet);
|
||||||
|
if (pgpBody != null) {
|
||||||
|
message = MessageParser.parsePgpChat(pgpBody, packet,
|
||||||
|
account, service);
|
||||||
|
notify = false;
|
||||||
|
} else if (packet.hasChild("body")
|
||||||
&& (packet.getBody().startsWith("?OTR"))) {
|
&& (packet.getBody().startsWith("?OTR"))) {
|
||||||
message = MessageParser.parseOtrChat(packet, account,
|
message = MessageParser.parseOtrChat(packet, account,
|
||||||
service);
|
service);
|
||||||
|
@ -164,6 +192,13 @@ public class XmppConnectionService extends Service {
|
||||||
if (convChangedListener != null) {
|
if (convChangedListener != null) {
|
||||||
convChangedListener.onConversationListChanged();
|
convChangedListener.onConversationListChanged();
|
||||||
}
|
}
|
||||||
|
if (account.getKeys().has("pgp_signature")) {
|
||||||
|
try {
|
||||||
|
sendPgpPresence(account, account.getKeys().getString("pgp_signature"));
|
||||||
|
} catch (JSONException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -195,6 +230,18 @@ public class XmppConnectionService extends Service {
|
||||||
} else if (show.getContent().equals("dnd")) {
|
} else if (show.getContent().equals("dnd")) {
|
||||||
contact.updatePresence(fromParts[1], Presences.DND);
|
contact.updatePresence(fromParts[1], Presences.DND);
|
||||||
}
|
}
|
||||||
|
Element x = packet.findChild("x");
|
||||||
|
if ((x != null)
|
||||||
|
&& (x.getAttribute("xmlns").equals("jabber:x:signed"))) {
|
||||||
|
try {
|
||||||
|
Log.d(LOGTAG,"pgp signature for contact" +packet.getAttribute("from"));
|
||||||
|
contact.setPgpKeyId(getPgpEngine().fetchKeyId(packet.findChild("status")
|
||||||
|
.getContent(), x.getContent()));
|
||||||
|
databaseBackend.updateContact(contact);
|
||||||
|
} catch (OpenPgpException e) {
|
||||||
|
Log.d(LOGTAG,"faulty pgp. just ignore");
|
||||||
|
}
|
||||||
|
}
|
||||||
databaseBackend.updateContact(contact);
|
databaseBackend.updateContact(contact);
|
||||||
} else if (type.equals("unavailable")) {
|
} else if (type.equals("unavailable")) {
|
||||||
if (fromParts.length != 2) {
|
if (fromParts.length != 2) {
|
||||||
|
@ -242,6 +289,23 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private OpenPgpServiceConnection pgpServiceConnection;
|
||||||
|
private PgpEngine mPgpEngine = null;
|
||||||
|
|
||||||
|
public PgpEngine getPgpEngine() {
|
||||||
|
if (pgpServiceConnection.isBound()) {
|
||||||
|
if (this.mPgpEngine == null) {
|
||||||
|
this.mPgpEngine = new PgpEngine(new OpenPgpApi(
|
||||||
|
getApplicationContext(),
|
||||||
|
pgpServiceConnection.getService()));
|
||||||
|
}
|
||||||
|
return mPgpEngine;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void processRosterItems(Account account, Element elements) {
|
private void processRosterItems(Account account, Element elements) {
|
||||||
for (Element item : elements.getChildren()) {
|
for (Element item : elements.getChildren()) {
|
||||||
if (item.getName().equals("item")) {
|
if (item.getName().equals("item")) {
|
||||||
|
@ -307,6 +371,9 @@ public class XmppConnectionService extends Service {
|
||||||
|
|
||||||
getContentResolver().registerContentObserver(
|
getContentResolver().registerContentObserver(
|
||||||
ContactsContract.Contacts.CONTENT_URI, true, contactObserver);
|
ContactsContract.Contacts.CONTENT_URI, true, contactObserver);
|
||||||
|
this.pgpServiceConnection = new OpenPgpServiceConnection(
|
||||||
|
getApplicationContext(), "org.sufficientlysecure.keychain");
|
||||||
|
this.pgpServiceConnection.bindToService();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -332,7 +399,8 @@ public class XmppConnectionService extends Service {
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendMessage(Account account, Message message, String presence) {
|
public void sendMessage(Message message, String presence) {
|
||||||
|
Account account = message.getConversation().getAccount();
|
||||||
Conversation conv = message.getConversation();
|
Conversation conv = message.getConversation();
|
||||||
boolean saveInDb = false;
|
boolean saveInDb = false;
|
||||||
boolean addToConversation = false;
|
boolean addToConversation = false;
|
||||||
|
@ -352,6 +420,25 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
saveInDb = true;
|
saveInDb = true;
|
||||||
addToConversation = true;
|
addToConversation = true;
|
||||||
|
} else if (message.getEncryption() == Message.ENCRYPTION_PGP) {
|
||||||
|
long keyId = message.getConversation().getContact()
|
||||||
|
.getPgpKeyId();
|
||||||
|
packet = new MessagePacket();
|
||||||
|
packet.setType(MessagePacket.TYPE_CHAT);
|
||||||
|
packet.setFrom(message.getConversation().getAccount()
|
||||||
|
.getFullJid());
|
||||||
|
packet.setTo(message.getCounterpart());
|
||||||
|
packet.setBody("This is an XEP-0027 encryted message");
|
||||||
|
Element x = new Element("x");
|
||||||
|
x.setAttribute("xmlns", "jabber:x:encrypted");
|
||||||
|
x.setContent(this.getPgpEngine().encrypt(keyId,
|
||||||
|
message.getBody()));
|
||||||
|
packet.addChild(x);
|
||||||
|
account.getXmppConnection().sendMessagePacket(packet);
|
||||||
|
message.setStatus(Message.STATUS_SEND);
|
||||||
|
message.setEncryption(Message.ENCRYPTION_DECRYPTED);
|
||||||
|
saveInDb = true;
|
||||||
|
addToConversation = true;
|
||||||
} else {
|
} else {
|
||||||
// don't encrypt
|
// don't encrypt
|
||||||
if (message.getConversation().getMode() == Conversation.MODE_SINGLE) {
|
if (message.getConversation().getMode() == Conversation.MODE_SINGLE) {
|
||||||
|
@ -777,6 +864,10 @@ public class XmppConnectionService extends Service {
|
||||||
databaseBackend.updateContact(contact);
|
databaseBackend.updateContact(contact);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateMessage(Message message) {
|
||||||
|
databaseBackend.updateMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
public void createContact(Contact contact) {
|
public void createContact(Contact contact) {
|
||||||
SharedPreferences sharedPref = PreferenceManager
|
SharedPreferences sharedPref = PreferenceManager
|
||||||
.getDefaultSharedPreferences(getApplicationContext());
|
.getDefaultSharedPreferences(getApplicationContext());
|
||||||
|
@ -841,4 +932,27 @@ public class XmppConnectionService extends Service {
|
||||||
Log.d(LOGTAG, packet.toString());
|
Log.d(LOGTAG, packet.toString());
|
||||||
contact.getAccount().getXmppConnection().sendPresencePacket(packet);
|
contact.getAccount().getXmppConnection().sendPresencePacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendPgpPresence(Account account, String signature) {
|
||||||
|
PresencePacket packet = new PresencePacket();
|
||||||
|
packet.setAttribute("from", account.getFullJid());
|
||||||
|
Element status = new Element("status");
|
||||||
|
status.setContent("online");
|
||||||
|
packet.addChild(status);
|
||||||
|
Element x = new Element("x");
|
||||||
|
x.setAttribute("xmlns", "jabber:x:signed");
|
||||||
|
x.setContent(signature);
|
||||||
|
packet.addChild(x);
|
||||||
|
account.getXmppConnection().sendPresencePacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generatePgpAnnouncement(Account account)
|
||||||
|
throws PgpEngine.UserInputRequiredException {
|
||||||
|
if (account.getStatus() == Account.STATUS_ONLINE) {
|
||||||
|
String signature = getPgpEngine().generateSignature("online");
|
||||||
|
account.setKey("pgp_signature", signature);
|
||||||
|
databaseBackend.updateAccount(account);
|
||||||
|
sendPgpPresence(account, signature);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -5,8 +5,13 @@ import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
|
import org.openintents.openpgp.util.OpenPgpConstants;
|
||||||
|
|
||||||
import de.gultsch.chat.R;
|
import de.gultsch.chat.R;
|
||||||
import de.gultsch.chat.R.id;
|
import de.gultsch.chat.R.id;
|
||||||
|
import de.gultsch.chat.crypto.PgpEngine;
|
||||||
|
import de.gultsch.chat.crypto.PgpEngine.UserInputRequiredException;
|
||||||
import de.gultsch.chat.entities.Account;
|
import de.gultsch.chat.entities.Account;
|
||||||
import de.gultsch.chat.entities.Contact;
|
import de.gultsch.chat.entities.Contact;
|
||||||
import de.gultsch.chat.entities.Conversation;
|
import de.gultsch.chat.entities.Conversation;
|
||||||
|
@ -20,6 +25,7 @@ import android.app.NotificationManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.IntentSender.SendIntentException;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
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;
|
||||||
|
@ -45,7 +51,8 @@ public class ConversationActivity extends XmppActivity {
|
||||||
public static final String VIEW_CONVERSATION = "viewConversation";
|
public static final String VIEW_CONVERSATION = "viewConversation";
|
||||||
public static final String CONVERSATION = "conversationUuid";
|
public static final String CONVERSATION = "conversationUuid";
|
||||||
|
|
||||||
public static final int INSERT_CONTACT = 0x9889;
|
public static final int REQUEST_SEND_MESSAGE = 0x75441;
|
||||||
|
public static final int REQUEST_DECRYPT_PGP = 0x76783;
|
||||||
|
|
||||||
protected SlidingPaneLayout spl;
|
protected SlidingPaneLayout spl;
|
||||||
|
|
||||||
|
@ -354,6 +361,9 @@ public class ConversationActivity extends XmppActivity {
|
||||||
case Message.ENCRYPTION_PGP:
|
case Message.ENCRYPTION_PGP:
|
||||||
popup.getMenu().findItem(R.id.encryption_choice_pgp).setChecked(true);
|
popup.getMenu().findItem(R.id.encryption_choice_pgp).setChecked(true);
|
||||||
break;
|
break;
|
||||||
|
case Message.ENCRYPTION_DECRYPTED:
|
||||||
|
popup.getMenu().findItem(R.id.encryption_choice_pgp).setChecked(true);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
popup.getMenu().findItem(R.id.encryption_choice_none).setChecked(true);
|
popup.getMenu().findItem(R.id.encryption_choice_none).setChecked(true);
|
||||||
break;
|
break;
|
||||||
|
@ -459,11 +469,4 @@ public class ConversationActivity extends XmppActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
if (requestCode==INSERT_CONTACT) {
|
|
||||||
Log.d("xmppService","contact inserted");
|
|
||||||
this.contactInserted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,17 +3,16 @@ package de.gultsch.chat.ui;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Hashtable;
|
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 javax.crypto.spec.PSource;
|
|
||||||
|
|
||||||
import net.java.otr4j.OtrException;
|
|
||||||
import net.java.otr4j.session.SessionStatus;
|
import net.java.otr4j.session.SessionStatus;
|
||||||
|
|
||||||
import de.gultsch.chat.R;
|
import de.gultsch.chat.R;
|
||||||
|
import de.gultsch.chat.crypto.PgpEngine.OpenPgpException;
|
||||||
|
import de.gultsch.chat.crypto.PgpEngine.UserInputRequiredException;
|
||||||
import de.gultsch.chat.entities.Contact;
|
import de.gultsch.chat.entities.Contact;
|
||||||
import de.gultsch.chat.entities.Conversation;
|
import de.gultsch.chat.entities.Conversation;
|
||||||
import de.gultsch.chat.entities.Message;
|
import de.gultsch.chat.entities.Message;
|
||||||
|
@ -23,18 +22,20 @@ import de.gultsch.chat.utils.UIHelper;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
import android.content.IntentSender;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.IntentSender.SendIntentException;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
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.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.View.OnLayoutChangeListener;
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
@ -42,6 +43,7 @@ import android.widget.LinearLayout;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
public class ConversationFragment extends Fragment {
|
public class ConversationFragment extends Fragment {
|
||||||
|
@ -54,27 +56,45 @@ public class ConversationFragment extends Fragment {
|
||||||
protected Contact contact;
|
protected Contact contact;
|
||||||
protected BitmapCache mBitmapCache = new BitmapCache();
|
protected BitmapCache mBitmapCache = new BitmapCache();
|
||||||
|
|
||||||
|
protected String queuedPqpMessage = null;
|
||||||
|
|
||||||
private EditText chatMsg;
|
private EditText chatMsg;
|
||||||
|
|
||||||
protected Bitmap selfBitmap;
|
protected Bitmap selfBitmap;
|
||||||
|
|
||||||
|
private IntentSender askForPassphraseIntent = null;
|
||||||
|
|
||||||
private OnClickListener sendMsgListener = new OnClickListener() {
|
private OnClickListener sendMsgListener = new OnClickListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
ConversationActivity activity = (ConversationActivity) getActivity();
|
|
||||||
final XmppConnectionService xmppService = activity.xmppConnectionService;
|
|
||||||
if (chatMsg.getText().length() < 1)
|
if (chatMsg.getText().length() < 1)
|
||||||
return;
|
return;
|
||||||
Message message = new Message(conversation, chatMsg.getText()
|
Message message = new Message(conversation, chatMsg.getText()
|
||||||
.toString(), conversation.nextMessageEncryption);
|
.toString(), conversation.nextMessageEncryption);
|
||||||
if (conversation.nextMessageEncryption == Message.ENCRYPTION_OTR) {
|
if (conversation.nextMessageEncryption == Message.ENCRYPTION_OTR) {
|
||||||
sendOtrMessage(message);
|
sendOtrMessage(message);
|
||||||
|
} else if (conversation.nextMessageEncryption == Message.ENCRYPTION_PGP) {
|
||||||
|
sendPgpMessage(message);
|
||||||
} else {
|
} else {
|
||||||
sendPlainTextMessage(message);
|
sendPlainTextMessage(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
protected OnClickListener clickToDecryptListener = new OnClickListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Log.d("gultsch","clicked to decrypt");
|
||||||
|
if (askForPassphraseIntent!=null) {
|
||||||
|
try {
|
||||||
|
getActivity().startIntentSenderForResult(askForPassphraseIntent, ConversationActivity.REQUEST_DECRYPT_PGP, null, 0, 0, 0);
|
||||||
|
} catch (SendIntentException e) {
|
||||||
|
Log.d("gultsch","couldnt fire intent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public void updateChatMsgHint() {
|
public void updateChatMsgHint() {
|
||||||
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
||||||
|
@ -89,6 +109,10 @@ public class ConversationFragment extends Fragment {
|
||||||
break;
|
break;
|
||||||
case Message.ENCRYPTION_PGP:
|
case Message.ENCRYPTION_PGP:
|
||||||
chatMsg.setHint("Send openPGP encryted messeage");
|
chatMsg.setHint("Send openPGP encryted messeage");
|
||||||
|
break;
|
||||||
|
case Message.ENCRYPTION_DECRYPTED:
|
||||||
|
chatMsg.setHint("Send openPGP encryted messeage");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -155,23 +179,28 @@ public class ConversationFragment extends Fragment {
|
||||||
viewHolder.imageView = (ImageView) view
|
viewHolder.imageView = (ImageView) view
|
||||||
.findViewById(R.id.message_photo);
|
.findViewById(R.id.message_photo);
|
||||||
if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
|
if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
|
||||||
Uri uri = item.getConversation().getProfilePhotoUri();
|
Uri uri = item.getConversation()
|
||||||
|
.getProfilePhotoUri();
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
viewHolder.imageView
|
viewHolder.imageView
|
||||||
.setImageBitmap(mBitmapCache.get(item
|
.setImageBitmap(mBitmapCache.get(item
|
||||||
.getConversation().getName(), uri));
|
.getConversation().getName(),
|
||||||
|
uri));
|
||||||
} else {
|
} else {
|
||||||
viewHolder.imageView
|
viewHolder.imageView
|
||||||
.setImageBitmap(mBitmapCache.get(item
|
.setImageBitmap(mBitmapCache.get(item
|
||||||
.getConversation().getName(), null));
|
.getConversation().getName(),
|
||||||
|
null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ERROR:
|
case ERROR:
|
||||||
view = (View) inflater.inflate(R.layout.message_error, null);
|
view = (View) inflater.inflate(R.layout.message_error,
|
||||||
|
null);
|
||||||
viewHolder.imageView = (ImageView) view
|
viewHolder.imageView = (ImageView) view
|
||||||
.findViewById(R.id.message_photo);
|
.findViewById(R.id.message_photo);
|
||||||
viewHolder.imageView.setImageBitmap(mBitmapCache.getError());
|
viewHolder.imageView.setImageBitmap(mBitmapCache
|
||||||
|
.getError());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
viewHolder = null;
|
viewHolder = null;
|
||||||
|
@ -199,7 +228,15 @@ public class ConversationFragment extends Fragment {
|
||||||
}
|
}
|
||||||
String body = item.getBody();
|
String body = item.getBody();
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
|
if (item.getEncryption() == Message.ENCRYPTION_PGP) {
|
||||||
|
viewHolder.messageBody.setText(getString(R.string.encrypted_message));
|
||||||
|
viewHolder.messageBody.setTextColor(0xff33B5E5);
|
||||||
|
viewHolder.messageBody.setOnClickListener(clickToDecryptListener);
|
||||||
|
} else {
|
||||||
viewHolder.messageBody.setText(body.trim());
|
viewHolder.messageBody.setText(body.trim());
|
||||||
|
viewHolder.messageBody.setTextColor(0xff000000);
|
||||||
|
viewHolder.messageBody.setOnClickListener(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (item.getStatus() == Message.STATUS_UNSEND) {
|
if (item.getStatus() == Message.STATUS_UNSEND) {
|
||||||
viewHolder.time.setTypeface(null, Typeface.ITALIC);
|
viewHolder.time.setTypeface(null, Typeface.ITALIC);
|
||||||
|
@ -280,17 +317,38 @@ public class ConversationFragment extends Fragment {
|
||||||
activity.updateConversationList();
|
activity.updateConversationList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (queuedPqpMessage != null) {
|
||||||
|
this.conversation.nextMessageEncryption = Message.ENCRYPTION_PGP;
|
||||||
|
Message message = new Message(conversation, queuedPqpMessage,
|
||||||
|
Message.ENCRYPTION_PGP);
|
||||||
|
sendPgpMessage(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateMessages() {
|
public void updateMessages() {
|
||||||
ConversationActivity activity = (ConversationActivity) getActivity();
|
ConversationActivity activity = (ConversationActivity) getActivity();
|
||||||
|
List<Message> encryptedMessages = new LinkedList<Message>();
|
||||||
|
for(Message message : this.conversation.getMessages()) {
|
||||||
|
if (message.getEncryption() == Message.ENCRYPTION_PGP) {
|
||||||
|
encryptedMessages.add(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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();
|
||||||
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) {
|
||||||
|
conversation.nextMessageEncryption = Message.ENCRYPTION_PGP;
|
||||||
|
} else {
|
||||||
conversation.nextMessageEncryption = latestEncryption;
|
conversation.nextMessageEncryption = latestEncryption;
|
||||||
|
}
|
||||||
makeFingerprintWarning(latestEncryption);
|
makeFingerprintWarning(latestEncryption);
|
||||||
}
|
}
|
||||||
getActivity().invalidateOptionsMenu();
|
getActivity().invalidateOptionsMenu();
|
||||||
|
@ -339,17 +397,47 @@ public class ConversationFragment extends Fragment {
|
||||||
|
|
||||||
protected void sendPlainTextMessage(Message message) {
|
protected void sendPlainTextMessage(Message message) {
|
||||||
ConversationActivity activity = (ConversationActivity) getActivity();
|
ConversationActivity activity = (ConversationActivity) getActivity();
|
||||||
activity.xmppConnectionService.sendMessage(conversation.getAccount(),
|
activity.xmppConnectionService.sendMessage(message, null);
|
||||||
message, null);
|
|
||||||
chatMsg.setText("");
|
chatMsg.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void sendPgpMessage(final Message message) {
|
||||||
|
ConversationActivity activity = (ConversationActivity) getActivity();
|
||||||
|
final XmppConnectionService xmppService = activity.xmppConnectionService;
|
||||||
|
Contact contact = message.getConversation().getContact();
|
||||||
|
if (contact.getPgpKeyId() != 0) {
|
||||||
|
xmppService.sendMessage(message, null);
|
||||||
|
chatMsg.setText("");
|
||||||
|
} else {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
|
builder.setTitle("No openPGP key found");
|
||||||
|
builder.setIconAttribute(android.R.attr.alertDialogIcon);
|
||||||
|
builder.setMessage("There is no openPGP key assoziated with this contact");
|
||||||
|
builder.setNegativeButton("Cancel", null);
|
||||||
|
builder.setPositiveButton("Send plain text",
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
conversation.nextMessageEncryption = Message.ENCRYPTION_NONE;
|
||||||
|
message.setEncryption(Message.ENCRYPTION_NONE);
|
||||||
|
xmppService.sendMessage(message, null);
|
||||||
|
chatMsg.setText("");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.create().show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resendPgpMessage(String msg) {
|
||||||
|
this.queuedPqpMessage = msg;
|
||||||
|
}
|
||||||
|
|
||||||
protected void sendOtrMessage(final Message message) {
|
protected void sendOtrMessage(final Message message) {
|
||||||
ConversationActivity activity = (ConversationActivity) getActivity();
|
ConversationActivity activity = (ConversationActivity) getActivity();
|
||||||
final XmppConnectionService xmppService = activity.xmppConnectionService;
|
final XmppConnectionService xmppService = activity.xmppConnectionService;
|
||||||
if (conversation.hasValidOtrSession()) {
|
if (conversation.hasValidOtrSession()) {
|
||||||
activity.xmppConnectionService.sendMessage(
|
activity.xmppConnectionService.sendMessage(message, null);
|
||||||
conversation.getAccount(), message, null);
|
|
||||||
chatMsg.setText("");
|
chatMsg.setText("");
|
||||||
} else {
|
} else {
|
||||||
Hashtable<String, Integer> presences;
|
Hashtable<String, Integer> presences;
|
||||||
|
@ -372,17 +460,15 @@ public class ConversationFragment extends Fragment {
|
||||||
int which) {
|
int which) {
|
||||||
conversation.nextMessageEncryption = Message.ENCRYPTION_NONE;
|
conversation.nextMessageEncryption = Message.ENCRYPTION_NONE;
|
||||||
message.setEncryption(Message.ENCRYPTION_NONE);
|
message.setEncryption(Message.ENCRYPTION_NONE);
|
||||||
xmppService.sendMessage(
|
xmppService.sendMessage(message, null);
|
||||||
conversation.getAccount(), message,
|
|
||||||
null);
|
|
||||||
chatMsg.setText("");
|
chatMsg.setText("");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
builder.setNegativeButton("Cancel", null);
|
builder.setNegativeButton("Cancel", null);
|
||||||
builder.create().show();
|
builder.create().show();
|
||||||
} else if (presences.size() == 1) {
|
} else if (presences.size() == 1) {
|
||||||
xmppService.sendMessage(conversation.getAccount(), message,
|
xmppService.sendMessage(message, (String) presences.keySet()
|
||||||
(String) presences.keySet().toArray()[0]);
|
.toArray()[0]);
|
||||||
chatMsg.setText("");
|
chatMsg.setText("");
|
||||||
} else {
|
} else {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(
|
AlertDialog.Builder builder = new AlertDialog.Builder(
|
||||||
|
@ -396,8 +482,7 @@ public class ConversationFragment extends Fragment {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog,
|
public void onClick(DialogInterface dialog,
|
||||||
int which) {
|
int which) {
|
||||||
xmppService.sendMessage(
|
xmppService.sendMessage(message,
|
||||||
conversation.getAccount(), message,
|
|
||||||
presencesArray[which]);
|
presencesArray[which]);
|
||||||
chatMsg.setText("");
|
chatMsg.setText("");
|
||||||
}
|
}
|
||||||
|
@ -446,4 +531,48 @@ public class ConversationFragment extends Fragment {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DecryptMessage extends AsyncTask<Message, Void, Boolean> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackground(Message... params) {
|
||||||
|
XmppActivity activity = (XmppActivity) getActivity();
|
||||||
|
askForPassphraseIntent = null;
|
||||||
|
for(int i = 0; i < params.length; ++i) {
|
||||||
|
if (params[i].getEncryption() == Message.ENCRYPTION_PGP) {
|
||||||
|
String body = params[i].getBody();
|
||||||
|
String decrypted = null;
|
||||||
|
try {
|
||||||
|
if (activity==null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Log.d("gultsch","calling to decrypt message id #"+params[i].getUuid());
|
||||||
|
decrypted = activity.xmppConnectionService.getPgpEngine().decrypt(body);
|
||||||
|
} catch (UserInputRequiredException e) {
|
||||||
|
askForPassphraseIntent = e.getPendingIntent().getIntentSender();
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} catch (OpenPgpException e) {
|
||||||
|
Log.d("gultsch","error decrypting pgp");
|
||||||
|
}
|
||||||
|
if (decrypted!=null) {
|
||||||
|
params[i].setBody(decrypted);
|
||||||
|
params[i].setEncryption(Message.ENCRYPTION_DECRYPTED);
|
||||||
|
activity.xmppConnectionService.updateMessage(params[i]);
|
||||||
|
}
|
||||||
|
if (activity!=null) {
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
messageListAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ public class DialogContactDetails extends DialogFragment {
|
||||||
intent.putExtra(Intents.Insert.IM_HANDLE,contact.getJid());
|
intent.putExtra(Intents.Insert.IM_HANDLE,contact.getJid());
|
||||||
intent.putExtra(Intents.Insert.IM_PROTOCOL,CommonDataKinds.Im.PROTOCOL_JABBER);
|
intent.putExtra(Intents.Insert.IM_PROTOCOL,CommonDataKinds.Im.PROTOCOL_JABBER);
|
||||||
intent.putExtra("finishActivityOnSaveCompleted", true);
|
intent.putExtra("finishActivityOnSaveCompleted", true);
|
||||||
getActivity().startActivityForResult(intent,ConversationActivity.INSERT_CONTACT);
|
getActivity().startActivityForResult(intent,0);
|
||||||
mDetailsDialog.dismiss();
|
mDetailsDialog.dismiss();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,8 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.gultsch.chat.R;
|
import de.gultsch.chat.R;
|
||||||
|
import de.gultsch.chat.crypto.PgpEngine;
|
||||||
|
import de.gultsch.chat.crypto.PgpEngine.UserInputRequiredException;
|
||||||
import de.gultsch.chat.entities.Account;
|
import de.gultsch.chat.entities.Account;
|
||||||
import de.gultsch.chat.ui.EditAccount.EditAccountListener;
|
import de.gultsch.chat.ui.EditAccount.EditAccountListener;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
@ -12,6 +14,7 @@ import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.DialogInterface.OnClickListener;
|
import android.content.DialogInterface.OnClickListener;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.IntentSender.SendIntentException;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.ActionMode;
|
import android.view.ActionMode;
|
||||||
|
@ -31,6 +34,8 @@ import android.widget.TextView;
|
||||||
|
|
||||||
public class ManageAccountActivity extends XmppActivity implements ActionMode.Callback {
|
public class ManageAccountActivity extends XmppActivity implements ActionMode.Callback {
|
||||||
|
|
||||||
|
public static final int REQUEST_ANNOUNCE_PGP = 0x73731;
|
||||||
|
|
||||||
protected boolean isActionMode = false;
|
protected boolean isActionMode = false;
|
||||||
protected ActionMode actionMode;
|
protected ActionMode actionMode;
|
||||||
protected Account selectedAccountForActionMode = null;
|
protected Account selectedAccountForActionMode = null;
|
||||||
|
@ -231,6 +236,17 @@ public class ManageAccountActivity extends XmppActivity implements ActionMode.Ca
|
||||||
});
|
});
|
||||||
builder.setNegativeButton("Cancel",null);
|
builder.setNegativeButton("Cancel",null);
|
||||||
builder.create().show();
|
builder.create().show();
|
||||||
|
} else if (item.getItemId()==R.id.announce_pgp) {
|
||||||
|
mode.finish();
|
||||||
|
try {
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -279,4 +295,18 @@ public class ManageAccountActivity extends XmppActivity implements ActionMode.Ca
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
if (requestCode == REQUEST_ANNOUNCE_PGP) {
|
||||||
|
try {
|
||||||
|
xmppConnectionService.generatePgpAnnouncement(selectedAccountForActionMode);
|
||||||
|
} catch (UserInputRequiredException e) {
|
||||||
|
Log.d("gultsch","already came back. ignoring");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,12 @@ public class MessageParser {
|
||||||
return new Message(conversation, packet.getFrom(), body, Message.ENCRYPTION_NONE, Message.STATUS_RECIEVED);
|
return new Message(conversation, packet.getFrom(), body, Message.ENCRYPTION_NONE, Message.STATUS_RECIEVED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Message parsePgpChat(String pgpBody, MessagePacket packet, Account account, XmppConnectionService service) {
|
||||||
|
String[] fromParts = packet.getFrom().split("/");
|
||||||
|
Conversation conversation = service.findOrCreateConversation(account, fromParts[0],false);
|
||||||
|
return new Message(conversation, packet.getFrom(), pgpBody, Message.ENCRYPTION_PGP, Message.STATUS_RECIEVED);
|
||||||
|
}
|
||||||
|
|
||||||
public static Message parseOtrChat(MessagePacket packet, Account account, XmppConnectionService service) {
|
public static Message parseOtrChat(MessagePacket packet, Account account, XmppConnectionService service) {
|
||||||
String[] fromParts = packet.getFrom().split("/");
|
String[] fromParts = packet.getFrom().split("/");
|
||||||
Conversation conversation = service.findOrCreateConversation(account, fromParts[0],false);
|
Conversation conversation = service.findOrCreateConversation(account, fromParts[0],false);
|
||||||
|
@ -131,4 +137,13 @@ public class MessageParser {
|
||||||
}
|
}
|
||||||
return new Message(conversation, packet.getFrom(), displayError, Message.ENCRYPTION_NONE, Message.STATUS_ERROR);
|
return new Message(conversation, packet.getFrom(), displayError, Message.ENCRYPTION_NONE, Message.STATUS_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getPgpBody(MessagePacket packet) {
|
||||||
|
for(Element child : packet.getChildren()) {
|
||||||
|
if (child.getName().equals("x")&&child.getAttribute("xmlns").equals("jabber:x:encrypted")) {
|
||||||
|
return child.getContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue