From a88c2d48c0ac3562fcc957b20a76fca97b93bf32 Mon Sep 17 00:00:00 2001 From: fiaxh Date: Tue, 23 Feb 2016 23:57:51 +0100 Subject: No possibility of multiple invocation of log export --- src/main/java/eu/siacs/conversations/services/ExportLogsService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main/java/eu/siacs/conversations/services/ExportLogsService.java b/src/main/java/eu/siacs/conversations/services/ExportLogsService.java index 76983a905..87e65931b 100644 --- a/src/main/java/eu/siacs/conversations/services/ExportLogsService.java +++ b/src/main/java/eu/siacs/conversations/services/ExportLogsService.java @@ -45,9 +45,9 @@ public class ExportLogsService extends Service { new Thread(new Runnable() { @Override public void run() { - running.set(false); export(); stopForeground(true); + running.set(false); stopSelf(); } }).start(); -- cgit v1.2.3 From e1a2f248afcc9fd884015da78decd5c0c8c83552 Mon Sep 17 00:00:00 2001 From: fiaxh Date: Tue, 23 Feb 2016 23:58:42 +0100 Subject: Request WRITE_EXTERNAL_STORAGE for ExportLogsPreference in >= M --- .../conversations/ui/ExportLogsPreference.java | 7 ++++++ .../siacs/conversations/ui/SettingsActivity.java | 26 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) (limited to 'src') diff --git a/src/main/java/eu/siacs/conversations/ui/ExportLogsPreference.java b/src/main/java/eu/siacs/conversations/ui/ExportLogsPreference.java index a4e178bd3..bedb4172d 100644 --- a/src/main/java/eu/siacs/conversations/ui/ExportLogsPreference.java +++ b/src/main/java/eu/siacs/conversations/ui/ExportLogsPreference.java @@ -1,7 +1,10 @@ package eu.siacs.conversations.ui; +import android.Manifest; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Build; import android.preference.Preference; import android.util.AttributeSet; @@ -22,6 +25,10 @@ public class ExportLogsPreference extends Preference { } protected void onClick() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M + && getContext().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + return; + } final Intent startIntent = new Intent(getContext(), ExportLogsService.class); getContext().startService(startIntent); super.onClick(); diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java index 07c328b9a..c028d0d69 100644 --- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java @@ -3,8 +3,10 @@ package eu.siacs.conversations.ui; import android.app.AlertDialog; import android.app.FragmentManager; import android.content.DialogInterface; +import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.preference.ListPreference; @@ -25,10 +27,13 @@ import de.duenndns.ssl.MemorizingTrustManager; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.services.ExportLogsService; import eu.siacs.conversations.xmpp.XmppConnection; public class SettingsActivity extends XmppActivity implements OnSharedPreferenceChangeListener { + + public static final int REQUEST_WRITE_LOGS = 0xbf8701; private SettingsFragment mSettingsFragment; @Override @@ -130,6 +135,15 @@ public class SettingsActivity extends XmppActivity implements return true; } }); + + final Preference exportLogsPreference = mSettingsFragment.findPreference("export_logs"); + exportLogsPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + hasStoragePermission(REQUEST_WRITE_LOGS); + return true; + } + }); } @Override @@ -179,6 +193,18 @@ public class SettingsActivity extends XmppActivity implements } + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + if (grantResults.length > 0) + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + if (requestCode == REQUEST_WRITE_LOGS) { + getApplicationContext().startService(new Intent(getApplicationContext(), ExportLogsService.class)); + } + } else { + Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show(); + } + } + private void displayToast(final String msg) { runOnUiThread(new Runnable() { @Override -- cgit v1.2.3 From 60ab03afb119a61503f101da91f54f15124f9373 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 27 Feb 2016 10:25:31 +0100 Subject: changed single_account config into more simple lock_settings --- src/main/java/eu/siacs/conversations/Config.java | 2 +- .../siacs/conversations/ui/ConferenceDetailsActivity.java | 2 +- .../eu/siacs/conversations/ui/ContactDetailsActivity.java | 2 +- .../eu/siacs/conversations/ui/ConversationActivity.java | 2 +- .../eu/siacs/conversations/ui/EditAccountActivity.java | 9 ++++++++- .../eu/siacs/conversations/ui/ManageAccountActivity.java | 4 ++-- .../siacs/conversations/ui/StartConversationActivity.java | 2 +- src/main/java/eu/siacs/conversations/ui/XmppActivity.java | 14 ++++++++++++++ 8 files changed, 29 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index caadef800..30951223f 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -45,7 +45,7 @@ public final class Config { public static final String CONFERENCE_DOMAIN_LOCK = null; //only allow conference creation for this domain public static final boolean LOCK_DOMAINS_IN_CONVERSATIONS = false; //only add contacts and conferences for own domains - public static final boolean SINGLE_ACCOUNT = false; //set to true to allow only one account + public static final boolean LOCK_SETTINGS = false; //set to true to disallow account and settings editing public static final boolean DISALLOW_REGISTRATION_IN_UI = false; //hide the register checkbox public static final boolean ALLOW_NON_TLS_CONNECTIONS = false; //very dangerous. you should have a good reason to set this to true diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index a83ca8bab..adbb09537 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -333,7 +333,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.muc_details, menu); - return true; + return super.onCreateOptionsMenu(menu); } @Override diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java index 64653acda..4165b4be5 100644 --- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java @@ -297,7 +297,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd edit.setVisible(false); delete.setVisible(false); } - return true; + return super.onCreateOptionsMenu(menu); } private void populateView() { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 7b2565c3b..55a127109 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -420,7 +420,7 @@ public class ConversationActivity extends XmppActivity } } } - return true; + return super.onCreateOptionsMenu(menu); } protected void selectPresenceToAttachFile(final int attachmentChoice, final int encryption) { diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 266ae8406..b6f1b430c 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -499,7 +499,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate clearDevices.setVisible(false); mamPrefs.setVisible(false); } - return true; + return super.onCreateOptionsMenu(menu); } @Override @@ -621,6 +621,13 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mNamePort.setVisibility(mShowOptions ? View.VISIBLE : View.GONE); } + mPassword.setEnabled(!Config.LOCK_SETTINGS); + mAccountJid.setEnabled(!Config.LOCK_SETTINGS); + mHostname.setEnabled(!Config.LOCK_SETTINGS); + mPort.setEnabled(!Config.LOCK_SETTINGS); + mPasswordConfirm.setEnabled(!Config.LOCK_SETTINGS); + mRegisterNew.setEnabled(!Config.LOCK_SETTINGS); + if (!mInitMode) { this.mAvatar.setVisibility(View.VISIBLE); this.mAvatar.setImageBitmap(avatarService().get(this.mAccount, getPixel(72))); diff --git a/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java index 1fc1924dd..feac2c622 100644 --- a/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java @@ -155,9 +155,9 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda addAccount.setVisible(false); addAccountWithCertificate.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); } else { - addAccount.setVisible(!Config.SINGLE_ACCOUNT); + addAccount.setVisible(!Config.LOCK_SETTINGS); } - addAccountWithCertificate.setVisible(!Config.SINGLE_ACCOUNT); + addAccountWithCertificate.setVisible(!Config.LOCK_SETTINGS); if (!accountsLeftToEnable()) { enableAll.setVisible(false); diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index 48baf914e..256f68c63 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -533,7 +533,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU mSearchEditText.append(mInitialJid); filter(mInitialJid); } - return true; + return super.onCreateOptionsMenu(menu); } @Override diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index 003b802c5..38b268190 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -42,6 +42,7 @@ import android.preference.PreferenceManager; import android.text.InputType; import android.util.DisplayMetrics; import android.util.Log; +import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.inputmethod.InputMethodManager; @@ -377,6 +378,19 @@ public abstract class XmppActivity extends Activity { } } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + final MenuItem menuSettings = menu.findItem(R.id.action_settings); + final MenuItem menuManageAccounts = menu.findItem(R.id.action_accounts); + if (menuSettings != null) { + menuSettings.setVisible(!Config.LOCK_SETTINGS); + } + if (menuManageAccounts != null) { + menuManageAccounts.setVisible(!Config.LOCK_SETTINGS); + } + return super.onCreateOptionsMenu(menu); + } + protected boolean showBatteryOptimizationWarning() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE); -- cgit v1.2.3 From 24a9ac290846c4facdf1d00f471dcaf34eea2be7 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 27 Feb 2016 15:41:34 +0100 Subject: always search offline contacts as well. fixes #1653 --- src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index 256f68c63..7d650e5bb 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -740,6 +740,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU Presence.Status s = p == null ? Presence.Status.OFFLINE : p.getStatus(); if (contact.showInRoster() && contact.match(needle) && (!this.mHideOfflineContacts + || (needle != null && !needle.trim().isEmpty()) || s.compareTo(Presence.Status.OFFLINE) < 0)) { this.contacts.add(contact); } -- cgit v1.2.3 From 4ba41540fd3e6efa6b176716c292378df4e9b724 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 28 Feb 2016 20:45:50 +0100 Subject: made hashtable in roster store jids instead of strings --- .../java/eu/siacs/conversations/entities/Roster.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/main/java/eu/siacs/conversations/entities/Roster.java b/src/main/java/eu/siacs/conversations/entities/Roster.java index 628a31d1c..d3ad91816 100644 --- a/src/main/java/eu/siacs/conversations/entities/Roster.java +++ b/src/main/java/eu/siacs/conversations/entities/Roster.java @@ -9,7 +9,7 @@ import eu.siacs.conversations.xmpp.jid.Jid; public class Roster { final Account account; - final HashMap contacts = new HashMap<>(); + final HashMap contacts = new HashMap<>(); private String version = null; public Roster(Account account) { @@ -21,7 +21,7 @@ public class Roster { return null; } synchronized (this.contacts) { - Contact contact = contacts.get(jid.toBareJid().toString()); + Contact contact = contacts.get(jid.toBareJid()); if (contact != null && contact.showInRoster()) { return contact; } else { @@ -32,15 +32,13 @@ public class Roster { public Contact getContact(final Jid jid) { synchronized (this.contacts) { - final Jid bareJid = jid.toBareJid(); - if (contacts.containsKey(bareJid.toString())) { - return contacts.get(bareJid.toString()); - } else { - Contact contact = new Contact(bareJid); + if (!contacts.containsKey(jid.toBareJid())) { + Contact contact = new Contact(jid.toBareJid()); contact.setAccount(account); - contacts.put(bareJid.toString(), contact); + contacts.put(contact.getJid().toBareJid(), contact); return contact; } + return contacts.get(jid.toBareJid()); } } @@ -80,7 +78,7 @@ public class Roster { contact.setAccount(account); contact.setOption(Contact.Options.IN_ROSTER); synchronized (this.contacts) { - contacts.put(contact.getJid().toBareJid().toString(), contact); + contacts.put(contact.getJid().toBareJid(), contact); } } -- cgit v1.2.3 From 199ae3a4d8253fb00cdef5556763a46a319a2d46 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 28 Feb 2016 23:10:50 +0100 Subject: rename purge keys positive button to 'purge keys' --- src/main/java/eu/siacs/conversations/ui/XmppActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index 38b268190..5682f7853 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -799,7 +799,7 @@ public abstract class XmppActivity extends Activity { + "\n\n" + CryptoHelper.prettifyFingerprint(fingerprint.substring(2)) + "\n\n" + getString(R.string.purge_key_desc_part2)); builder.setNegativeButton(getString(R.string.cancel), null); - builder.setPositiveButton(getString(R.string.accept), + builder.setPositiveButton(getString(R.string.purge_key), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { -- cgit v1.2.3 From 9e0466d1e643c07d1c3de088ddf2e5655899a50c Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 29 Feb 2016 13:18:07 +0100 Subject: refactored omemo to take multiple recipients --- .../crypto/axolotl/AxolotlService.java | 154 ++++++++++++-------- .../siacs/conversations/entities/Conversation.java | 20 +-- .../siacs/conversations/entities/MucOptions.java | 11 ++ .../siacs/conversations/generator/IqGenerator.java | 7 + .../siacs/conversations/parser/MessageParser.java | 14 +- .../siacs/conversations/parser/PresenceParser.java | 8 +- .../services/XmppConnectionService.java | 40 +++++- .../conversations/ui/ConversationActivity.java | 21 +-- .../siacs/conversations/ui/TrustKeysActivity.java | 156 ++++++++++++--------- .../xmpp/jingle/JingleConnection.java | 2 +- src/main/res/layout/activity_trust_keys.xml | 29 +--- src/main/res/layout/keys_card.xml | 31 ++++ 12 files changed, 320 insertions(+), 173 deletions(-) create mode 100644 src/main/res/layout/keys_card.xml (limited to 'src') diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java index 949975aa4..8658dfe20 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java @@ -81,13 +81,14 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { } } - public boolean fetchMapHasErrors(Contact contact) { - Jid jid = contact.getJid().toBareJid(); - if (deviceIds.get(jid) != null) { - for (Integer foreignId : this.deviceIds.get(jid)) { - AxolotlAddress address = new AxolotlAddress(jid.toString(), foreignId); - if (fetchStatusMap.getAll(address).containsValue(FetchStatus.ERROR)) { - return true; + public boolean fetchMapHasErrors(List jids) { + for(Jid jid : jids) { + if (deviceIds.get(jid) != null) { + for (Integer foreignId : this.deviceIds.get(jid)) { + AxolotlAddress address = new AxolotlAddress(jid.toString(), foreignId); + if (fetchStatusMap.getAll(address).containsValue(FetchStatus.ERROR)) { + return true; + } } } } @@ -242,12 +243,29 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { return axolotlStore.getContactKeysWithTrust(account.getJid().toBareJid().toString(), trust); } - public Set getKeysWithTrust(XmppAxolotlSession.Trust trust, Contact contact) { - return axolotlStore.getContactKeysWithTrust(contact.getJid().toBareJid().toString(), trust); + public Set getKeysWithTrust(XmppAxolotlSession.Trust trust, Jid jid) { + return axolotlStore.getContactKeysWithTrust(jid.toBareJid().toString(), trust); + } + + public Set getKeysWithTrust(XmppAxolotlSession.Trust trust, List jids) { + Set keys = new HashSet<>(); + for(Jid jid : jids) { + keys.addAll(axolotlStore.getContactKeysWithTrust(jid.toString(), trust)); + } + return keys; } - public long getNumTrustedKeys(Contact contact) { - return axolotlStore.getContactNumTrustedKeys(contact.getJid().toBareJid().toString()); + public long getNumTrustedKeys(Jid jid) { + return axolotlStore.getContactNumTrustedKeys(jid.toBareJid().toString()); + } + + public boolean anyTargetHasNoTrustedKeys(List jids) { + for(Jid jid : jids) { + if (axolotlStore.getContactNumTrustedKeys(jid.toBareJid().toString()) == 0) { + return true; + } + } + return false; } private AxolotlAddress getAddressForJid(Jid jid) { @@ -259,11 +277,19 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { return new HashSet<>(this.sessions.getAll(ownAddress).values()); } - private Set findSessionsforContact(Contact contact) { + private Set findSessionsForContact(Contact contact) { AxolotlAddress contactAddress = getAddressForJid(contact.getJid()); return new HashSet<>(this.sessions.getAll(contactAddress).values()); } + private Set findSessionsForConversation(Conversation conversation) { + HashSet sessions = new HashSet<>(); + for(Jid jid : getCryptoTargets(conversation)) { + sessions.addAll(this.sessions.getAll(getAddressForJid(jid)).values()); + } + return sessions; + } + public Set getFingerprintsForOwnSessions() { Set fingerprints = new HashSet<>(); for (XmppAxolotlSession session : findOwnSessions()) { @@ -274,15 +300,14 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { public Set getFingerprintsForContact(final Contact contact) { Set fingerprints = new HashSet<>(); - for (XmppAxolotlSession session : findSessionsforContact(contact)) { + for (XmppAxolotlSession session : findSessionsForContact(contact)) { fingerprints.add(session.getFingerprint()); } return fingerprints; } - private boolean hasAny(Contact contact) { - AxolotlAddress contactAddress = getAddressForJid(contact.getJid()); - return sessions.hasAny(contactAddress); + private boolean hasAny(Jid jid) { + return sessions.hasAny(getAddressForJid(jid)); } public boolean isPepBroken() { @@ -594,10 +619,25 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { }); } - public boolean isContactAxolotlCapable(Contact contact) { - Jid jid = contact.getJid().toBareJid(); - return hasAny(contact) || - (deviceIds.containsKey(jid) && !deviceIds.get(jid).isEmpty()); + public boolean isConversationAxolotlCapable(Conversation conversation) { + final List jids = getCryptoTargets(conversation); + for(Jid jid : jids) { + if (!hasAny(jid) && (!deviceIds.containsKey(jid) || deviceIds.get(jid).isEmpty())) { + return false; + } + } + return jids.size() > 0; + } + + public List getCryptoTargets(Conversation conversation) { + final List jids; + if (conversation.getMode() == Conversation.MODE_SINGLE) { + jids = Arrays.asList(conversation.getJid().toBareJid()); + } else { + jids = conversation.getMucOptions().getMembers(); + jids.remove(account.getJid().toBareJid()); + } + return jids; } public XmppAxolotlSession.Trust getFingerprintTrust(String fingerprint) { @@ -753,33 +793,31 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { } public Set findDevicesWithoutSession(final Conversation conversation) { - return findDevicesWithoutSession(conversation.getContact().getJid().toBareJid()); - } - - public Set findDevicesWithoutSession(final Jid contactJid) { - Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Finding devices without session for " + contactJid); Set addresses = new HashSet<>(); - if (deviceIds.get(contactJid) != null) { - for (Integer foreignId : this.deviceIds.get(contactJid)) { - AxolotlAddress address = new AxolotlAddress(contactJid.toString(), foreignId); - if (sessions.get(address) == null) { - IdentityKey identityKey = axolotlStore.loadSession(address).getSessionState().getRemoteIdentityKey(); - if (identityKey != null) { - Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Already have session for " + address.toString() + ", adding to cache..."); - XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address, identityKey); - sessions.put(address, session); - } else { - Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Found device " + contactJid + ":" + foreignId); - if (fetchStatusMap.get(address) != FetchStatus.ERROR) { - addresses.add(address); + for(Jid jid : getCryptoTargets(conversation)) { + Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Finding devices without session for " + jid); + if (deviceIds.get(jid) != null) { + for (Integer foreignId : this.deviceIds.get(jid)) { + AxolotlAddress address = new AxolotlAddress(jid.toString(), foreignId); + if (sessions.get(address) == null) { + IdentityKey identityKey = axolotlStore.loadSession(address).getSessionState().getRemoteIdentityKey(); + if (identityKey != null) { + Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Already have session for " + address.toString() + ", adding to cache..."); + XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address, identityKey); + sessions.put(address, session); } else { - Log.d(Config.LOGTAG,getLogprefix(account)+"skipping over "+address+" because it's broken"); + Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Found device " + jid + ":" + foreignId); + if (fetchStatusMap.get(address) != FetchStatus.ERROR) { + addresses.add(address); + } else { + Log.d(Config.LOGTAG, getLogprefix(account) + "skipping over " + address + " because it's broken"); + } } } } + } else { + Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Have no target devices in PEP!"); } - } else { - Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Have no target devices in PEP!"); } if (deviceIds.get(account.getJid().toBareJid()) != null) { for (Integer ownId : this.deviceIds.get(account.getJid().toBareJid())) { @@ -827,7 +865,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { } public boolean trustedSessionVerified(final Conversation conversation) { - Set sessions = findSessionsforContact(conversation.getContact()); + Set sessions = findSessionsForConversation(conversation); sessions.addAll(findOwnSessions()); boolean verified = false; for(XmppAxolotlSession session : sessions) { @@ -842,26 +880,32 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { return verified; } - public boolean hasPendingKeyFetches(Account account, Contact contact) { + public boolean hasPendingKeyFetches(Account account, List jids) { AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toString(), 0); - AxolotlAddress foreignAddress = new AxolotlAddress(contact.getJid().toBareJid().toString(), 0); - return fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING) - || fetchStatusMap.getAll(foreignAddress).containsValue(FetchStatus.PENDING); - + if (fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING)) { + return true; + } + for(Jid jid : jids) { + AxolotlAddress foreignAddress = new AxolotlAddress(jid.toBareJid().toString(), 0); + if (fetchStatusMap.getAll(foreignAddress).containsValue(FetchStatus.PENDING)) { + return true; + } + } + return false; } @Nullable - private XmppAxolotlMessage buildHeader(Contact contact) { + private XmppAxolotlMessage buildHeader(Conversation conversation) { final XmppAxolotlMessage axolotlMessage = new XmppAxolotlMessage( - contact.getJid().toBareJid(), getOwnDeviceId()); + account.getJid().toBareJid(), getOwnDeviceId()); - Set contactSessions = findSessionsforContact(contact); + Set remoteSessions = findSessionsForConversation(conversation); Set ownSessions = findOwnSessions(); - if (contactSessions.isEmpty()) { + if (remoteSessions.isEmpty()) { return null; } Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Building axolotl foreign keyElements..."); - for (XmppAxolotlSession session : contactSessions) { + for (XmppAxolotlSession session : remoteSessions) { Log.v(Config.LOGTAG, AxolotlService.getLogprefix(account) + session.getRemoteAddress().toString()); axolotlMessage.addDevice(session); } @@ -876,7 +920,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { @Nullable public XmppAxolotlMessage encrypt(Message message) { - XmppAxolotlMessage axolotlMessage = buildHeader(message.getContact()); + XmppAxolotlMessage axolotlMessage = buildHeader(message.getConversation()); if (axolotlMessage != null) { final String content; @@ -913,11 +957,11 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { }); } - public void prepareKeyTransportMessage(final Contact contact, final OnMessageCreatedCallback onMessageCreatedCallback) { + public void prepareKeyTransportMessage(final Conversation conversation, final OnMessageCreatedCallback onMessageCreatedCallback) { executor.execute(new Runnable() { @Override public void run() { - XmppAxolotlMessage axolotlMessage = buildHeader(contact); + XmppAxolotlMessage axolotlMessage = buildHeader(conversation); onMessageCreatedCallback.run(axolotlMessage); } }); diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 796b36f9f..f05b3f911 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -659,8 +659,8 @@ public class Conversation extends AbstractEntity implements Blockable { final AxolotlService axolotlService = getAccount().getAxolotlService(); int next = this.getIntAttribute(ATTRIBUTE_NEXT_ENCRYPTION, -1); if (next == -1) { - if (Config.X509_VERIFICATION && mode == MODE_SINGLE) { - if (axolotlService != null && axolotlService.isContactAxolotlCapable(getContact())) { + if (Config.X509_VERIFICATION) { + if (axolotlService != null && axolotlService.isConversationAxolotlCapable(this)) { return Message.ENCRYPTION_AXOLOTL; } else { return Message.ENCRYPTION_NONE; @@ -673,16 +673,20 @@ public class Conversation extends AbstractEntity implements Blockable { next = outgoing; } } - if (!Config.supportUnencrypted() - && (mode == MODE_SINGLE || Config.supportOpenPgpOnly()) - && next <= 0) { - if (Config.supportOmemo() && (axolotlService != null && axolotlService.isContactAxolotlCapable(getContact()) || !Config.multipleEncryptionChoices())) { + + if (!Config.supportUnencrypted() && next <= 0) { + if (Config.supportOmemo() + && (axolotlService != null && axolotlService.isConversationAxolotlCapable(this) || !Config.multipleEncryptionChoices())) { return Message.ENCRYPTION_AXOLOTL; - } else if (Config.supportOtr()) { + } else if (Config.supportOtr() && mode == MODE_SINGLE) { return Message.ENCRYPTION_OTR; - } else if (Config.supportOpenPgp()) { + } else if (Config.supportOpenPgp() + && (mode == MODE_SINGLE) || !Config.multipleEncryptionChoices()) { return Message.ENCRYPTION_PGP; } + } else if (next == Message.ENCRYPTION_AXOLOTL + && (!Config.supportOmemo() || axolotlService == null || !axolotlService.isConversationAxolotlCapable(this))) { + next = Message.ENCRYPTION_NONE; } return next; } diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index 3567c14f4..059573c63 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -4,9 +4,11 @@ import android.annotation.SuppressLint; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import eu.siacs.conversations.R; import eu.siacs.conversations.xmpp.forms.Data; @@ -245,6 +247,7 @@ public class MucOptions { private Account account; private final Map users = Collections.synchronizedMap(new LinkedHashMap()); + private final Set members = Collections.synchronizedSet(new HashSet()); private List features = new ArrayList<>(); private Data form = new Data(); private Conversation conversation; @@ -501,4 +504,12 @@ public class MucOptions { public Conversation getConversation() { return this.conversation; } + + public void putMember(Jid jid) { + members.add(jid); + } + + public List getMembers() { + return new ArrayList<>(members); + } } diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 4395a5460..a3b0f6506 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -335,4 +335,11 @@ public class IqGenerator extends AbstractGenerator { enable.addChild(data); return packet; } + + public IqPacket queryAffiliation(Conversation conversation, String affiliation) { + IqPacket packet = new IqPacket(IqPacket.TYPE.GET); + packet.setTo(conversation.getJid().toBareJid()); + packet.query("http://jabber.org/protocol/muc#admin").addChild("item").setAttribute("affiliation",affiliation); + return packet; + } } diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index aa9d7f6c3..fd2d070ce 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -103,7 +103,7 @@ public class MessageParser extends AbstractParser implements } } - private Message parseAxolotlChat(Element axolotlMessage, Jid from, String id, Conversation conversation, int status) { + private Message parseAxolotlChat(Element axolotlMessage, Jid from, Conversation conversation, int status) { Message finishedMessage = null; AxolotlService service = conversation.getAccount().getAxolotlService(); XmppAxolotlMessage xmppAxolotlMessage = XmppAxolotlMessage.fromElement(axolotlMessage, from.toBareJid()); @@ -357,7 +357,17 @@ public class MessageParser extends AbstractParser implements } else if (pgpEncrypted != null && Config.supportOpenPgp()) { message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status); } else if (axolotlEncrypted != null && Config.supportOmemo()) { - message = parseAxolotlChat(axolotlEncrypted, from, remoteMsgId, conversation, status); + Jid origin; + if (conversation.getMode() == Conversation.MODE_MULTI) { + origin = conversation.getMucOptions().getTrueCounterpart(counterpart.getResourcepart()); + if (origin == null) { + Log.d(Config.LOGTAG,"axolotl message in non anonymous conference received"); + return; + } + } else { + origin = from; + } + message = parseAxolotlChat(axolotlEncrypted, origin, conversation, status); if (message == null) { return; } diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index 63d28c97b..c2782d232 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -64,10 +64,14 @@ public class PresenceParser extends AbstractParser implements Element item = x.findChild("item"); if (item != null && !from.isBareJid()) { mucOptions.setError(MucOptions.Error.NONE); - MucOptions.User user = new MucOptions.User(mucOptions,from); + MucOptions.User user = new MucOptions.User(mucOptions, from); user.setAffiliation(item.getAttribute("affiliation")); user.setRole(item.getAttribute("role")); - user.setJid(item.getAttributeAsJid("jid")); + Jid real = item.getAttributeAsJid("jid"); + if (real != null) { + user.setJid(real); + mucOptions.putMember(real.toBareJid()); + } if (codes.contains(MucOptions.STATUS_CODE_SELF_PRESENCE) || packet.getFrom().equals(mucOptions.getConversation().getJid())) { mucOptions.setOnline(); mucOptions.setSelf(user); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index dde8ad280..0518f992e 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1784,6 +1784,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa Account account = conversation.getAccount(); final String nick = conversation.getMucOptions().getProposedNick(); final Jid joinJid = conversation.getMucOptions().createJoinJid(nick); + final MucOptions mucOptions = conversation.getMucOptions(); Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": joining conversation " + joinJid.toString()); PresencePacket packet = new PresencePacket(); packet.setFrom(conversation.getAccount().getJid()); @@ -1793,7 +1794,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa x.addChild("password").setContent(conversation.getMucOptions().getPassword()); } - if (conversation.getMucOptions().mamSupport()) { + if (mucOptions.mamSupport()) { // Use MAM instead of the limited muc history to get history x.addChild("history").setAttribute("maxchars", "0"); } else { @@ -1812,9 +1813,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa conversation.setContactJid(joinJid); databaseBackend.updateConversation(conversation); } - if (conversation.getMucOptions().mamSupport()) { + + if (mucOptions.mamSupport()) { getMessageArchiveService().catchupMUC(conversation); } + if (mucOptions.membersOnly() && mucOptions.nonanonymous()) { + fetchConferenceMembers(conversation); + } sendUnsentMessages(conversation); } @@ -1838,6 +1843,37 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } + private void fetchConferenceMembers(final Conversation conversation) { + final Account account = conversation.getAccount(); + final String[] affiliations = {"member","admin","owner"}; + OnIqPacketReceived callback = new OnIqPacketReceived() { + + private int i = 0; + + @Override + public void onIqPacketReceived(Account account, IqPacket packet) { + Element query = packet.query("http://jabber.org/protocol/muc#admin"); + if (packet.getType() == IqPacket.TYPE.RESULT && query != null) { + for(Element child : query.getChildren()) { + if ("item".equals(child.getName())) { + conversation.getMucOptions().putMember(child.getAttributeAsJid("jid")); + } + } + } else { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not request affiliation "+affiliations[i]+" in "+conversation.getJid().toBareJid()); + } + ++i; + if (i >= affiliations.length) { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": retrieved members for "+conversation.getJid().toBareJid()+": "+conversation.getMucOptions().getMembers()); + } + } + }; + for(String affiliation : affiliations) { + sendIqPacket(account, mIqGenerator.queryAffiliation(conversation, affiliation), callback); + } + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": fetching members for "+conversation.getName()); + } + public void providePasswordForMuc(Conversation conversation, String password) { if (conversation.getMode() == Conversation.MODE_MULTI) { conversation.getMucOptions().setPassword(password); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 55a127109..e4ffb3e46 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -408,7 +408,7 @@ public class ConversationActivity extends XmppActivity menuContactDetails.setVisible(false); menuAttach.setVisible(getSelectedConversation().getAccount().httpUploadAvailable() && getSelectedConversation().getMucOptions().participating()); menuInviteContact.setVisible(getSelectedConversation().getMucOptions().canInvite()); - menuSecure.setVisible(Config.supportOpenPgp() && Config.multipleEncryptionChoices()); //only if pgp is supported we have a choice + menuSecure.setVisible((Config.supportOpenPgp() || Config.supportOmemo()) && Config.multipleEncryptionChoices()); //only if pgp is supported we have a choice } else { menuMucDetails.setVisible(false); menuSecure.setVisible(Config.multipleEncryptionChoices()); @@ -856,8 +856,8 @@ public class ConversationActivity extends XmppActivity axolotl.setVisible(Config.supportOmemo()); if (conversation.getMode() == Conversation.MODE_MULTI) { otr.setVisible(false); - axolotl.setVisible(false); - } else if (!conversation.getAccount().getAxolotlService().isContactAxolotlCapable(conversation.getContact())) { + } + if (!conversation.getAccount().getAxolotlService().isConversationAxolotlCapable(conversation)) { axolotl.setEnabled(false); } switch (conversation.getNextEncryption()) { @@ -1530,18 +1530,21 @@ public class ConversationActivity extends XmppActivity protected boolean trustKeysIfNeeded(int requestCode, int attachmentChoice) { AxolotlService axolotlService = mSelectedConversation.getAccount().getAxolotlService(); - Contact contact = mSelectedConversation.getContact(); + final List targets = axolotlService.getCryptoTargets(mSelectedConversation); boolean hasUndecidedOwn = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED).isEmpty(); - boolean hasUndecidedContact = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED,contact).isEmpty(); + boolean hasUndecidedContacts = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, targets).isEmpty(); boolean hasPendingKeys = !axolotlService.findDevicesWithoutSession(mSelectedConversation).isEmpty(); - boolean hasNoTrustedKeys = axolotlService.getNumTrustedKeys(mSelectedConversation.getContact()) == 0; - if(hasUndecidedOwn || hasUndecidedContact || hasPendingKeys || hasNoTrustedKeys) { + boolean hasNoTrustedKeys = axolotlService.anyTargetHasNoTrustedKeys(targets); + if(hasUndecidedOwn || hasUndecidedContacts || hasPendingKeys || hasNoTrustedKeys) { axolotlService.createSessionsIfNeeded(mSelectedConversation); Intent intent = new Intent(getApplicationContext(), TrustKeysActivity.class); - intent.putExtra("contact", mSelectedConversation.getContact().getJid().toBareJid().toString()); + String[] contacts = new String[targets.size()]; + for(int i = 0; i < contacts.length; ++i) { + contacts[i] = targets.get(i).toString(); + } + intent.putExtra("contacts", contacts); intent.putExtra(EXTRA_ACCOUNT, mSelectedConversation.getAccount().getJid().toBareJid().toString()); intent.putExtra("choice", attachmentChoice); - intent.putExtra("has_no_trusted", hasNoTrustedKeys); startActivityForResult(intent, requestCode); return true; } else { diff --git a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java index eec30798e..8919ac79c 100644 --- a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java @@ -12,7 +12,9 @@ import android.widget.Toast; import org.whispersystems.libaxolotl.IdentityKey; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; @@ -20,32 +22,28 @@ import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; import eu.siacs.conversations.entities.Account; -import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdated { private Jid accountJid; - private Jid contactJid; + private List contactJids; - private Contact contact; private Account mAccount; private TextView keyErrorMessage; private LinearLayout keyErrorMessageCard; private TextView ownKeysTitle; private LinearLayout ownKeys; private LinearLayout ownKeysCard; - private TextView foreignKeysTitle; private LinearLayout foreignKeys; - private LinearLayout foreignKeysCard; private Button mSaveButton; private Button mCancelButton; private AxolotlService.FetchStatus lastFetchReport = AxolotlService.FetchStatus.SUCCESS; private final Map ownKeysToTrust = new HashMap<>(); - private final Map foreignKeysToTrust = new HashMap<>(); + private final Map> foreignKeysToTrust = new HashMap<>(); private final OnClickListener mSaveButtonListener = new OnClickListener() { @Override @@ -69,15 +67,6 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate populateView(); } - @Override - protected String getShareableUri() { - if (contact != null) { - return contact.getShareableUri(); - } else { - return ""; - } - } - @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -86,9 +75,13 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate this.accountJid = Jid.fromString(getIntent().getExtras().getString(EXTRA_ACCOUNT)); } catch (final InvalidJidException ignored) { } - try { - this.contactJid = Jid.fromString(getIntent().getExtras().getString("contact")); - } catch (final InvalidJidException ignored) { + this.contactJids = new ArrayList<>(); + for(String jid : getIntent().getStringArrayExtra("contacts")) { + try { + this.contactJids.add(Jid.fromString(jid)); + } catch (InvalidJidException e) { + e.printStackTrace(); + } } keyErrorMessageCard = (LinearLayout) findViewById(R.id.key_error_message_card); @@ -96,9 +89,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate ownKeysTitle = (TextView) findViewById(R.id.own_keys_title); ownKeys = (LinearLayout) findViewById(R.id.own_keys_details); ownKeysCard = (LinearLayout) findViewById(R.id.own_keys_card); - foreignKeysTitle = (TextView) findViewById(R.id.foreign_keys_title); - foreignKeys = (LinearLayout) findViewById(R.id.foreign_keys_details); - foreignKeysCard = (LinearLayout) findViewById(R.id.foreign_keys_card); + foreignKeys = (LinearLayout) findViewById(R.id.foreign_keys); mCancelButton = (Button) findViewById(R.id.cancel_button); mCancelButton.setOnClickListener(mCancelButtonListener); mSaveButton = (Button) findViewById(R.id.save_button); @@ -119,7 +110,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate boolean hasForeignKeys = false; for(final String fingerprint : ownKeysToTrust.keySet()) { hasOwnKeys = true; - addFingerprintRowWithListeners(ownKeys, contact.getAccount(), fingerprint, false, + addFingerprintRowWithListeners(ownKeys, mAccount, fingerprint, false, XmppAxolotlSession.Trust.fromBoolean(ownKeysToTrust.get(fingerprint)), false, new CompoundButton.OnCheckedChangeListener() { @Override @@ -132,30 +123,36 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate null ); } - for(final String fingerprint : foreignKeysToTrust.keySet()) { - hasForeignKeys = true; - addFingerprintRowWithListeners(foreignKeys, contact.getAccount(), fingerprint, false, - XmppAxolotlSession.Trust.fromBoolean(foreignKeysToTrust.get(fingerprint)), false, - new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - foreignKeysToTrust.put(fingerprint, isChecked); - lockOrUnlockAsNeeded(); - } - }, - null, - null - ); - } - if(hasOwnKeys) { - ownKeysTitle.setText(accountJid.toString()); - ownKeysCard.setVisibility(View.VISIBLE); - } - if(hasForeignKeys) { - foreignKeysTitle.setText(contactJid.toString()); - foreignKeysCard.setVisibility(View.VISIBLE); + synchronized (this.foreignKeysToTrust) { + for (Map.Entry> entry : foreignKeysToTrust.entrySet()) { + final LinearLayout layout = (LinearLayout) getLayoutInflater().inflate(R.layout.keys_card, foreignKeys, false); + final TextView header = (TextView) layout.findViewById(R.id.foreign_keys_title); + final LinearLayout keysContainer = (LinearLayout) layout.findViewById(R.id.foreign_keys_details); + header.setText(entry.getKey().toString()); + final Map fingerprints = entry.getValue(); + for (final String fingerprint : fingerprints.keySet()) { + hasForeignKeys = true; + addFingerprintRowWithListeners(keysContainer, mAccount, fingerprint, false, + XmppAxolotlSession.Trust.fromBoolean(fingerprints.get(fingerprint)), false, + new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + fingerprints.put(fingerprint, isChecked); + lockOrUnlockAsNeeded(); + } + }, + null, + null + ); + } + foreignKeys.addView(layout); + } } + + ownKeysTitle.setText(accountJid.toString()); + ownKeysCard.setVisibility(hasOwnKeys ? View.VISIBLE : View.GONE); + foreignKeys.setVisibility(hasForeignKeys ? View.VISIBLE : View.GONE); if(hasPendingKeyFetches()) { setFetching(); lock(); @@ -163,13 +160,15 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate if (!hasForeignKeys && hasNoOtherTrustedKeys()) { keyErrorMessageCard.setVisibility(View.VISIBLE); if (lastFetchReport == AxolotlService.FetchStatus.ERROR - || contact.getAccount().getAxolotlService().fetchMapHasErrors(contact)) { + || mAccount.getAxolotlService().fetchMapHasErrors(contactJids)) { keyErrorMessage.setText(R.string.error_no_keys_to_trust_server_error); } else { keyErrorMessage.setText(R.string.error_no_keys_to_trust); } - ownKeys.removeAllViews(); ownKeysCard.setVisibility(View.GONE); - foreignKeys.removeAllViews(); foreignKeysCard.setVisibility(View.GONE); + ownKeys.removeAllViews(); + ownKeysCard.setVisibility(View.GONE); + foreignKeys.removeAllViews(); + foreignKeys.setVisibility(View.GONE); } lockOrUnlockAsNeeded(); setDone(); @@ -178,45 +177,56 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate private boolean reloadFingerprints() { ownKeysToTrust.clear(); - foreignKeysToTrust.clear(); AxolotlService service = this.mAccount.getAxolotlService(); Set ownKeysSet = service.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED); - Set foreignKeysSet = service.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, contact); - if (hasNoOtherTrustedKeys() && ownKeysSet.size() == 0) { - foreignKeysSet.addAll(service.getKeysWithTrust(XmppAxolotlSession.Trust.UNTRUSTED, contact)); - } for(final IdentityKey identityKey : ownKeysSet) { if(!ownKeysToTrust.containsKey(identityKey)) { ownKeysToTrust.put(identityKey.getFingerprint().replaceAll("\\s", ""), false); } } - for(final IdentityKey identityKey : foreignKeysSet) { - if(!foreignKeysToTrust.containsKey(identityKey)) { - foreignKeysToTrust.put(identityKey.getFingerprint().replaceAll("\\s", ""), false); + synchronized (this.foreignKeysToTrust) { + foreignKeysToTrust.clear(); + for (Jid jid : contactJids) { + Set foreignKeysSet = service.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, jid); + if (hasNoOtherTrustedKeys(jid) && ownKeysSet.size() == 0) { + foreignKeysSet.addAll(service.getKeysWithTrust(XmppAxolotlSession.Trust.UNTRUSTED, jid)); + } + Map foreignFingerprints = new HashMap<>(); + for (final IdentityKey identityKey : foreignKeysSet) { + if (!foreignFingerprints.containsKey(identityKey)) { + foreignFingerprints.put(identityKey.getFingerprint().replaceAll("\\s", ""), false); + } + } + if (foreignFingerprints.size() > 0) { + foreignKeysToTrust.put(jid, foreignFingerprints); + } } } - return ownKeysSet.size() + foreignKeysSet.size() > 0; + return ownKeysSet.size() + foreignKeysToTrust.size() > 0; } @Override public void onBackendConnected() { - if ((accountJid != null) && (contactJid != null)) { + if (accountJid != null) { this.mAccount = xmppConnectionService.findAccountByJid(accountJid); if (this.mAccount == null) { return; } - this.contact = this.mAccount.getRoster().getContact(contactJid); reloadFingerprints(); populateView(); } } private boolean hasNoOtherTrustedKeys() { + return mAccount == null || mAccount.getAxolotlService().anyTargetHasNoTrustedKeys(contactJids); + } + + private boolean hasNoOtherTrustedKeys(Jid contact) { return mAccount == null || mAccount.getAxolotlService().getNumTrustedKeys(contact) == 0; } private boolean hasPendingKeyFetches() { - return mAccount != null && contact != null && mAccount.getAxolotlService().hasPendingKeyFetches(mAccount,contact); + return mAccount != null && mAccount.getAxolotlService().hasPendingKeyFetches(mAccount, contactJids); } @@ -262,14 +272,18 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate private void commitTrusts() { for(final String fingerprint :ownKeysToTrust.keySet()) { - contact.getAccount().getAxolotlService().setFingerprintTrust( + mAccount.getAxolotlService().setFingerprintTrust( fingerprint, XmppAxolotlSession.Trust.fromBoolean(ownKeysToTrust.get(fingerprint))); } - for(final String fingerprint:foreignKeysToTrust.keySet()) { - contact.getAccount().getAxolotlService().setFingerprintTrust( - fingerprint, - XmppAxolotlSession.Trust.fromBoolean(foreignKeysToTrust.get(fingerprint))); + synchronized (this.foreignKeysToTrust) { + for (Map value : foreignKeysToTrust.values()) { + for (final String fingerprint : value.keySet()) { + mAccount.getAxolotlService().setFingerprintTrust( + fingerprint, + XmppAxolotlSession.Trust.fromBoolean(value.get(fingerprint))); + } + } } } @@ -284,11 +298,17 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate } private void lockOrUnlockAsNeeded() { - if (hasNoOtherTrustedKeys() && !foreignKeysToTrust.values().contains(true)){ - lock(); - } else { - unlock(); + synchronized (this.foreignKeysToTrust) { + for (Jid jid : contactJids) { + Map fingerprints = foreignKeysToTrust.get(jid); + if (hasNoOtherTrustedKeys(jid) && (fingerprints == null || !fingerprints.values().contains(true))) { + lock(); + return; + } + } } + unlock(); + } private void setDone() { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index 56582f974..a8e081a72 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -218,7 +218,7 @@ public class JingleConnection implements Transferable { public void init(final Message message) { if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) { Conversation conversation = message.getConversation(); - conversation.getAccount().getAxolotlService().prepareKeyTransportMessage(conversation.getContact(), new OnMessageCreatedCallback() { + conversation.getAccount().getAxolotlService().prepareKeyTransportMessage(conversation, new OnMessageCreatedCallback() { @Override public void run(XmppAxolotlMessage xmppAxolotlMessage) { if (xmppAxolotlMessage != null) { diff --git a/src/main/res/layout/activity_trust_keys.xml b/src/main/res/layout/activity_trust_keys.xml index 6f8a1bc9c..d7bb76281 100644 --- a/src/main/res/layout/activity_trust_keys.xml +++ b/src/main/res/layout/activity_trust_keys.xml @@ -80,34 +80,11 @@ - - - - - + android:visibility="gone" + android:orientation="vertical"> diff --git a/src/main/res/layout/keys_card.xml b/src/main/res/layout/keys_card.xml new file mode 100644 index 000000000..7a5028162 --- /dev/null +++ b/src/main/res/layout/keys_card.xml @@ -0,0 +1,31 @@ + + + + + + + + + \ No newline at end of file -- cgit v1.2.3 From 134c75ae01eee45882d17a4d2fc721f4ccf3ca80 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 29 Feb 2016 16:32:24 +0100 Subject: use correct jid when leaving a conference. fixes #1732 --- src/main/java/eu/siacs/conversations/entities/MucOptions.java | 2 +- .../eu/siacs/conversations/services/XmppConnectionService.java | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index 059573c63..4fe26743e 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -248,7 +248,7 @@ public class MucOptions { private Account account; private final Map users = Collections.synchronizedMap(new LinkedHashMap()); private final Set members = Collections.synchronizedSet(new HashSet()); - private List features = new ArrayList<>(); + private final List features = new ArrayList<>(); private Data form = new Data(); private Conversation conversation; private boolean isOnline = false; diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 0518f992e..85eb479fd 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1782,9 +1782,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa private void join(Conversation conversation) { Account account = conversation.getAccount(); - final String nick = conversation.getMucOptions().getProposedNick(); - final Jid joinJid = conversation.getMucOptions().createJoinJid(nick); final MucOptions mucOptions = conversation.getMucOptions(); + final Jid joinJid = mucOptions.getSelf().getFullJid(); Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": joining conversation " + joinJid.toString()); PresencePacket packet = new PresencePacket(); packet.setFrom(conversation.getAccount().getJid()); @@ -1947,7 +1946,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa account.pendingConferenceLeaves.remove(conversation); if (account.getStatus() == Account.State.ONLINE || now) { PresencePacket packet = new PresencePacket(); - packet.setTo(conversation.getJid()); + packet.setTo(conversation.getMucOptions().getSelf().getFullJid()); packet.setFrom(conversation.getAccount().getJid()); packet.setAttribute("type", "unavailable"); sendPresencePacket(conversation.getAccount(), packet); @@ -2047,9 +2046,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa sendIqPacket(conversation.getAccount(), request, new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { - if (packet.getType() == IqPacket.TYPE.RESULT) { + Element query = packet.findChild("query","http://jabber.org/protocol/disco#info"); + if (packet.getType() == IqPacket.TYPE.RESULT && query != null) { ArrayList features = new ArrayList<>(); - Element query = packet.query(); for (Element child : query.getChildren()) { if (child != null && child.getName().equals("feature")) { String var = child.getAttribute("var"); @@ -2066,6 +2065,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa if (callback != null) { callback.onConferenceConfigurationFetched(conversation); } + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": fetched muc configuration for "+conversation.getJid().toBareJid()+" - "+features.toString()); updateConversationUi(); } else if (packet.getType() == IqPacket.TYPE.ERROR) { if (callback != null) { -- cgit v1.2.3 From 198dc2c6b444671ec71deb10fbbaaced6e03dced Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 1 Mar 2016 11:26:59 +0100 Subject: let users confirm each member in a conference even if that contact is already trusted --- .../crypto/axolotl/AxolotlService.java | 2 +- .../siacs/conversations/entities/Conversation.java | 72 +++++++++++++++++++--- .../conversations/ui/ConversationActivity.java | 4 +- .../siacs/conversations/ui/TrustKeysActivity.java | 50 ++++++++++----- src/main/res/layout/keys_card.xml | 60 ++++++++++-------- src/main/res/values/strings.xml | 1 + 6 files changed, 137 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java index 8658dfe20..cc5c2491b 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java @@ -284,7 +284,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { private Set findSessionsForConversation(Conversation conversation) { HashSet sessions = new HashSet<>(); - for(Jid jid : getCryptoTargets(conversation)) { + for(Jid jid : conversation.getAcceptedCryptoTargets()) { sessions.addAll(this.sessions.getAll(getAddressForJid(jid)).values()); } return sessions; diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index f05b3f911..0252ea749 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -9,11 +9,13 @@ import net.java.otr4j.session.SessionID; import net.java.otr4j.session.SessionImpl; import net.java.otr4j.session.SessionStatus; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.security.interfaces.DSAPublicKey; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; @@ -48,6 +50,7 @@ public class Conversation extends AbstractEntity implements Blockable { public static final String ATTRIBUTE_MUC_PASSWORD = "muc_password"; public static final String ATTRIBUTE_MUTED_TILL = "muted_till"; public static final String ATTRIBUTE_ALWAYS_NOTIFY = "always_notify"; + public static final String ATTRIBUTE_CRYPTO_TARGETS = "crypto_targets"; private String name; private String contactUuid; @@ -313,6 +316,18 @@ public class Conversation extends AbstractEntity implements Blockable { return getLongAttribute("last_clear_history", 0); } + public List getAcceptedCryptoTargets() { + if (mode == MODE_SINGLE) { + return Arrays.asList(getJid().toBareJid()); + } else { + return getJidListAttribute(ATTRIBUTE_CRYPTO_TARGETS); + } + } + + public void setAcceptedCryptoTargets(List acceptedTargets) { + setAttribute(ATTRIBUTE_CRYPTO_TARGETS, acceptedTargets); + } + public void setCorrectingMessage(Message correctingMessage) { this.correctingMessage = correctingMessage; } @@ -794,20 +809,59 @@ public class Conversation extends AbstractEntity implements Blockable { } public boolean setAttribute(String key, String value) { - try { - this.attributes.put(key, value); - return true; - } catch (JSONException e) { - return false; + synchronized (this.attributes) { + try { + this.attributes.put(key, value); + return true; + } catch (JSONException e) { + return false; + } + } + } + + public boolean setAttribute(String key, List jids) { + JSONArray array = new JSONArray(); + for(Jid jid : jids) { + array.put(jid.toBareJid().toString()); + } + synchronized (this.attributes) { + try { + this.attributes.put(key, array); + return true; + } catch (JSONException e) { + e.printStackTrace(); + return false; + } } } public String getAttribute(String key) { - try { - return this.attributes.getString(key); - } catch (JSONException e) { - return null; + synchronized (this.attributes) { + try { + return this.attributes.getString(key); + } catch (JSONException e) { + return null; + } + } + } + + public List getJidListAttribute(String key) { + ArrayList list = new ArrayList<>(); + synchronized (this.attributes) { + try { + JSONArray array = this.attributes.getJSONArray(key); + for (int i = 0; i < array.length(); ++i) { + try { + list.add(Jid.fromString(array.getString(i))); + } catch (InvalidJidException e) { + //ignored + } + } + } catch (JSONException e) { + //ignored + } } + return list; } public int getIntAttribute(String key, int defaultValue) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index e4ffb3e46..eac531242 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -1531,11 +1531,12 @@ public class ConversationActivity extends XmppActivity protected boolean trustKeysIfNeeded(int requestCode, int attachmentChoice) { AxolotlService axolotlService = mSelectedConversation.getAccount().getAxolotlService(); final List targets = axolotlService.getCryptoTargets(mSelectedConversation); + boolean hasUnaccepted = !mSelectedConversation.getAcceptedCryptoTargets().containsAll(targets); boolean hasUndecidedOwn = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED).isEmpty(); boolean hasUndecidedContacts = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, targets).isEmpty(); boolean hasPendingKeys = !axolotlService.findDevicesWithoutSession(mSelectedConversation).isEmpty(); boolean hasNoTrustedKeys = axolotlService.anyTargetHasNoTrustedKeys(targets); - if(hasUndecidedOwn || hasUndecidedContacts || hasPendingKeys || hasNoTrustedKeys) { + if(hasUndecidedOwn || hasUndecidedContacts || hasPendingKeys || hasNoTrustedKeys || hasUnaccepted) { axolotlService.createSessionsIfNeeded(mSelectedConversation); Intent intent = new Intent(getApplicationContext(), TrustKeysActivity.class); String[] contacts = new String[targets.size()]; @@ -1545,6 +1546,7 @@ public class ConversationActivity extends XmppActivity intent.putExtra("contacts", contacts); intent.putExtra(EXTRA_ACCOUNT, mSelectedConversation.getAccount().getJid().toBareJid().toString()); intent.putExtra("choice", attachmentChoice); + intent.putExtra("conversation",mSelectedConversation.getUuid()); startActivityForResult(intent, requestCode); return true; } else { diff --git a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java index 8919ac79c..9bccca78b 100644 --- a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java @@ -10,6 +10,8 @@ import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; +import android.util.Log; + import org.whispersystems.libaxolotl.IdentityKey; import java.util.ArrayList; @@ -18,19 +20,21 @@ import java.util.List; import java.util.Map; import java.util.Set; +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdated { - private Jid accountJid; private List contactJids; private Account mAccount; + private Conversation mConversation; private TextView keyErrorMessage; private LinearLayout keyErrorMessageCard; private TextView ownKeysTitle; @@ -71,10 +75,6 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_trust_keys); - try { - this.accountJid = Jid.fromString(getIntent().getExtras().getString(EXTRA_ACCOUNT)); - } catch (final InvalidJidException ignored) { - } this.contactJids = new ArrayList<>(); for(String jid : getIntent().getStringArrayExtra("contacts")) { try { @@ -126,13 +126,15 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate synchronized (this.foreignKeysToTrust) { for (Map.Entry> entry : foreignKeysToTrust.entrySet()) { + hasForeignKeys = true; final LinearLayout layout = (LinearLayout) getLayoutInflater().inflate(R.layout.keys_card, foreignKeys, false); + final Jid jid = entry.getKey(); final TextView header = (TextView) layout.findViewById(R.id.foreign_keys_title); final LinearLayout keysContainer = (LinearLayout) layout.findViewById(R.id.foreign_keys_details); - header.setText(entry.getKey().toString()); + final TextView informNoKeys = (TextView) layout.findViewById(R.id.no_keys_to_accept); + header.setText(jid.toString()); final Map fingerprints = entry.getValue(); for (final String fingerprint : fingerprints.keySet()) { - hasForeignKeys = true; addFingerprintRowWithListeners(keysContainer, mAccount, fingerprint, false, XmppAxolotlSession.Trust.fromBoolean(fingerprints.get(fingerprint)), false, new CompoundButton.OnCheckedChangeListener() { @@ -146,11 +148,17 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate null ); } + if (fingerprints.size() == 0) { + informNoKeys.setVisibility(View.VISIBLE); + informNoKeys.setText(getString(R.string.no_keys_just_confirm,mAccount.getRoster().getContact(jid).getDisplayName())); + } else { + informNoKeys.setVisibility(View.GONE); + } foreignKeys.addView(layout); } } - ownKeysTitle.setText(accountJid.toString()); + ownKeysTitle.setText(mAccount.getJid().toBareJid().toString()); ownKeysCard.setVisibility(hasOwnKeys ? View.VISIBLE : View.GONE); foreignKeys.setVisibility(hasForeignKeys ? View.VISIBLE : View.GONE); if(hasPendingKeyFetches()) { @@ -176,6 +184,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate } private boolean reloadFingerprints() { + List acceptedTargets = mConversation == null ? new ArrayList() : mConversation.getAcceptedCryptoTargets(); ownKeysToTrust.clear(); AxolotlService service = this.mAccount.getAxolotlService(); Set ownKeysSet = service.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED); @@ -197,7 +206,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate foreignFingerprints.put(identityKey.getFingerprint().replaceAll("\\s", ""), false); } } - if (foreignFingerprints.size() > 0) { + if (foreignFingerprints.size() > 0 || !acceptedTargets.contains(jid)) { foreignKeysToTrust.put(jid, foreignFingerprints); } } @@ -207,11 +216,11 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate @Override public void onBackendConnected() { - if (accountJid != null) { - this.mAccount = xmppConnectionService.findAccountByJid(accountJid); - if (this.mAccount == null) { - return; - } + Intent intent = getIntent(); + this.mAccount = extractAccount(intent); + if (this.mAccount != null && intent != null) { + String uuid = intent.getStringExtra("conversation"); + this.mConversation = xmppConnectionService.findConversationByUuid(uuid); reloadFingerprints(); populateView(); } @@ -276,8 +285,14 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate fingerprint, XmppAxolotlSession.Trust.fromBoolean(ownKeysToTrust.get(fingerprint))); } + List acceptedTargets = mConversation == null ? new ArrayList() : mConversation.getAcceptedCryptoTargets(); synchronized (this.foreignKeysToTrust) { - for (Map value : foreignKeysToTrust.values()) { + for (Map.Entry> entry : foreignKeysToTrust.entrySet()) { + Jid jid = entry.getKey(); + Map value = entry.getValue(); + if (!acceptedTargets.contains(jid)) { + acceptedTargets.add(jid); + } for (final String fingerprint : value.keySet()) { mAccount.getAxolotlService().setFingerprintTrust( fingerprint, @@ -285,6 +300,11 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate } } } + if (mConversation != null && mConversation.getMode() == Conversation.MODE_MULTI) { + Log.d(Config.LOGTAG,"commiting accepted crypto targets: "+acceptedTargets); + mConversation.setAcceptedCryptoTargets(acceptedTargets); + //xmppConnectionService.updateConversation(mConversation); + } } private void unlock() { diff --git a/src/main/res/layout/keys_card.xml b/src/main/res/layout/keys_card.xml index 7a5028162..d3271d1bc 100644 --- a/src/main/res/layout/keys_card.xml +++ b/src/main/res/layout/keys_card.xml @@ -1,31 +1,39 @@ - + - + - - + + + \ No newline at end of file diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index a25c1a849..69609f880 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -599,4 +599,5 @@ This field is required Correct message Send corrected message + You already trust this contact. By selecting \'done\' you are just confirming that %s is part of this conference. -- cgit v1.2.3 From fd246f7e5aa6fa1012c22fa33cd87915260a10cb Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 1 Mar 2016 12:22:20 +0100 Subject: properly persist accepted crypto targets --- src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src') diff --git a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java index 9bccca78b..cc4ba7b23 100644 --- a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java @@ -10,8 +10,6 @@ import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; -import android.util.Log; - import org.whispersystems.libaxolotl.IdentityKey; import java.util.ArrayList; @@ -20,7 +18,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; @@ -301,9 +298,8 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate } } if (mConversation != null && mConversation.getMode() == Conversation.MODE_MULTI) { - Log.d(Config.LOGTAG,"commiting accepted crypto targets: "+acceptedTargets); mConversation.setAcceptedCryptoTargets(acceptedTargets); - //xmppConnectionService.updateConversation(mConversation); + xmppConnectionService.updateConversation(mConversation); } } -- cgit v1.2.3 From 15a1873d97b49293d025be09d9b135c6871a6da5 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 1 Mar 2016 18:58:33 +0100 Subject: removed unused config variable --- src/main/java/eu/siacs/conversations/Config.java | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 30951223f..e39cd6549 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -22,10 +22,6 @@ public final class Config { return (ENCRYPTION_MASK & OPENPGP) != 0; } - public static boolean supportOpenPgpOnly() { - return supportOpenPgp() && !multipleEncryptionChoices(); - } - public static boolean supportOtr() { return (ENCRYPTION_MASK & OTR) != 0; } -- cgit v1.2.3 From aaf64732b0e04d0b95407c5420da08c8c1752ec6 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 1 Mar 2016 19:00:18 +0100 Subject: expert option to treat vibrate as silent mode for XA. fixes #1530 --- .../conversations/services/XmppConnectionService.java | 10 +++++++++- .../java/eu/siacs/conversations/ui/SettingsActivity.java | 15 +++++++++------ src/main/res/values/strings.xml | 2 ++ src/main/res/xml/preferences.xml | 6 ++++++ 4 files changed, 26 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 85eb479fd..07a7e10b8 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -611,6 +611,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return getPreferences().getBoolean("xa_on_silent_mode", false); } + private boolean treatVibrateAsSilent() { + return getPreferences().getBoolean("treat_vibrate_as_silent", false); + } + private boolean awayWhenScreenOff() { return getPreferences().getBoolean("away_when_screen_off", false); } @@ -645,7 +649,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa private boolean isPhoneSilenced() { AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - return audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT; + if (treatVibrateAsSilent()) { + return audioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; + } else { + return audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT; + } } private void resetAllAttemptCounts(boolean reallyAll) { diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java index c028d0d69..750a74212 100644 --- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java @@ -21,6 +21,7 @@ import java.security.KeyStoreException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.Locale; import de.duenndns.ssl.MemorizingTrustManager; @@ -154,8 +155,13 @@ public class SettingsActivity extends XmppActivity implements } @Override - public void onSharedPreferenceChanged(SharedPreferences preferences, - String name) { + public void onSharedPreferenceChanged(SharedPreferences preferences, String name) { + final List resendPresence = Arrays.asList( + "confirm_messages", + "xa_on_silent_mode", + "away_when_screen_off", + "allow_message_correction", + "treat_vibrate_as_silent"); if (name.equals("resource")) { String resource = preferences.getString("resource", "mobile") .toLowerCase(Locale.US); @@ -174,10 +180,7 @@ public class SettingsActivity extends XmppActivity implements } } else if (name.equals("keep_foreground_service")) { xmppConnectionService.toggleForegroundService(); - } else if (name.equals("confirm_messages") - || name.equals("xa_on_silent_mode") - || name.equals("away_when_screen_off") - || name.equals("allow_message_correction")) { + } else if (resendPresence.contains(name)) { if (xmppConnectionServiceBound) { if (name.equals("away_when_screen_off")) { xmppConnectionService.toggleScreenEventReceiver(); diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 69609f880..6a36233ce 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -536,6 +536,8 @@ Marks your resource as away when the screen is turned off Not available in silent mode Marks your resource as not available when device is in silent mode + Treat vibrate as silent mode + Marks your resource as not available when device is on vibrate Extended connection settings Show hostname and port settings when setting up an account xmpp.example.com diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml index 357995735..f505baf7c 100644 --- a/src/main/res/xml/preferences.xml +++ b/src/main/res/xml/preferences.xml @@ -189,6 +189,12 @@ android:key="xa_on_silent_mode" android:summary="@string/pref_xa_on_silent_mode_summary" android:title="@string/pref_xa_on_silent_mode"/> + Date: Thu, 3 Mar 2016 11:14:59 +0100 Subject: don't break with srcoll events on empty message lists --- .../java/eu/siacs/conversations/ui/ConversationFragment.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 15e4b9852..09d98e836 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -123,7 +123,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa private int getIndexOf(String uuid, List messages) { if (uuid == null) { - return 0; + return messages.size() - 1; } for(int i = 0; i < messages.size(); ++i) { if (uuid.equals(messages.get(i).getUuid())) { @@ -164,7 +164,12 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public void run() { final int oldPosition = messagesView.getFirstVisiblePosition(); - Message message = messageList.get(oldPosition); + final Message message; + if (oldPosition < messageList.size()) { + message = messageList.get(oldPosition); + } else { + message = null; + } String uuid = message != null ? message.getUuid() : null; View v = messagesView.getChildAt(0); final int pxOffset = (v == null) ? 0 : v.getTop(); -- cgit v1.2.3 From 4cb2d0ca932de2bb387c5f843ad6df608b04c03b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 3 Mar 2016 13:31:59 +0100 Subject: avoid unnecessary disconnect. prevent NetworkOnMainThreadException --- .../java/eu/siacs/conversations/services/XmppConnectionService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 07a7e10b8..cc269b671 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -2554,9 +2554,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa private void reconnectAccount(final Account account, final boolean force, final boolean interactive) { synchronized (account) { XmppConnection connection = account.getXmppConnection(); - if (connection != null) { - disconnect(account, force); - } else { + if (connection == null) { connection = createConnection(account); account.setXmppConnection(connection); } @@ -2570,6 +2568,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } if (!force) { + disconnect(account, false); try { Log.d(Config.LOGTAG, "wait for disconnect"); Thread.sleep(500); //sleep wait for disconnect @@ -2582,6 +2581,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa thread.start(); scheduleWakeUpCall(Config.CONNECT_DISCO_TIMEOUT, account.getUuid().hashCode()); } else { + disconnect(account, force); account.getRoster().clearPresences(); connection.resetEverything(); } -- cgit v1.2.3 From bc5f64bffe3deb260824f6eae33238c10ab71244 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 3 Mar 2016 13:33:02 +0100 Subject: moved avatarfetcher reset code to bind --- .../conversations/services/XmppConnectionService.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index cc269b671..ecf5504ba 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -254,6 +254,14 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa @Override public void onBind(final Account account) { + synchronized (mInProgressAvatarFetches) { + for (Iterator iterator = mInProgressAvatarFetches.iterator(); iterator.hasNext(); ) { + final String KEY = iterator.next(); + if (KEY.startsWith(account.getJid().toBareJid() + "_")) { + iterator.remove(); + } + } + } account.getRoster().clearPresences(); mJingleConnectionManager.cancelInTransmission(); fetchRosterFromServer(account); @@ -2559,14 +2567,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa account.setXmppConnection(connection); } if (!account.isOptionSet(Account.OPTION_DISABLED)) { - synchronized (this.mInProgressAvatarFetches) { - for (Iterator iterator = this.mInProgressAvatarFetches.iterator(); iterator.hasNext(); ) { - final String KEY = iterator.next(); - if (KEY.startsWith(account.getJid().toBareJid() + "_")) { - iterator.remove(); - } - } - } if (!force) { disconnect(account, false); try { -- cgit v1.2.3