From 868d9f890cd6c0da9d2fcbc030fb099db6585f55 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 22 Nov 2014 19:53:37 +0100 Subject: update android gradle plugin to 0.14.4 to work with AS >= 0.9.0 plugin >= 0.14.0 is required also update gradle to 2.2. --- build.gradle | 21 ++++++++------------- gradle/wrapper/gradle-wrapper.properties | 4 ++-- libs/minidns/build.gradle | 7 +++++-- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/build.gradle b/build.gradle index 876cdf0a..23aafae7 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:0.12.2' + classpath 'com.android.tools.build:gradle:0.14.4' } } @@ -81,18 +81,13 @@ android { buildTypes.release.signingConfig = null } - buildTypes { - applicationVariants.all { variant -> - def fileName = variant.packageApplication.outputFile.name.replace(".apk", - "-" + defaultConfig.versionName + ".apk") - variant.packageApplication.outputFile = new - File(variant.packageApplication.outputFile.parent, fileName) - if (variant.zipAlign) { - if (variant.name.equals('release')) { - variant.outputFile = new File(variant.outputFile.parent, - rootProject.name + "-" + defaultConfig.versionName + ".apk") - } - } + applicationVariants.all { variant -> + if (variant.name.equals('release')) { + variant.outputs.each { output -> + output.zipAlign.outputFile = new File(output.outputFile.parent, rootProject.name + "-${variant.versionName}.apk") + output.packageApplication.outputFile = new File(output.outputFile.parent, output.packageApplication.outputFile.name + .replace(".apk", "-${variant.versionName}.apk")) + } } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1e61d1fd..c35d5967 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Apr 10 15:27:10 PDT 2013 +#Sat Nov 22 17:47:57 CET 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-all.zip diff --git a/libs/minidns/build.gradle b/libs/minidns/build.gradle index 5941beaf..c9b93467 100644 --- a/libs/minidns/build.gradle +++ b/libs/minidns/build.gradle @@ -19,7 +19,10 @@ group = 'de.measite.minidns' description = "A minimal DNS client library with support for A, AAAA, NS and SRV records" sourceCompatibility = 1.7 version = 'git tag --points-at HEAD'.execute().text.trim() -isSNAPSHOT = 'git rev-parse --abbrev-ref HEAD'.execute().text.trim() == 'master' + +ext { + isSNAPSHOT = 'git rev-parse --abbrev-ref HEAD'.execute().text.trim() == 'master' +} if (isSNAPSHOT) { version = version + '-SNAPSHOT' @@ -74,4 +77,4 @@ modifyPom { } dependencies { -} \ No newline at end of file +} -- cgit v1.2.3 From c36d564b6999aa80ffffb9d94468a2d9b0ce0d21 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 5 Dec 2014 23:26:58 +0100 Subject: update android gradle plugin to 1.0.0-rc4 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 23aafae7..6718e140 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:0.14.4' + classpath 'com.android.tools.build:gradle:1.0.0-rc4' } } -- cgit v1.2.3 From 0193cdb194b76acbc75742e46d186e5bc4a0b159 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 9 Dec 2014 11:12:33 +0100 Subject: update gradle to 2.2.1 and android gradle plugin to 1.0.0 --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 6718e140..49d439d0 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:1.0.0-rc4' + classpath 'com.android.tools.build:gradle:1.0.0' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c35d5967..81cfe7fe 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip -- cgit v1.2.3 From 9d52f627670e5785e44b8b163dc29fadba007e44 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Tue, 9 Dec 2014 14:14:15 +0100 Subject: cleanup: removed stream compression --- .../conversations/utils/zlib/ZLibInputStream.java | 54 ------------ .../conversations/utils/zlib/ZLibOutputStream.java | 95 ---------------------- .../siacs/conversations/xmpp/XmppConnection.java | 56 ------------- 3 files changed, 205 deletions(-) delete mode 100644 src/main/java/eu/siacs/conversations/utils/zlib/ZLibInputStream.java delete mode 100644 src/main/java/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java diff --git a/src/main/java/eu/siacs/conversations/utils/zlib/ZLibInputStream.java b/src/main/java/eu/siacs/conversations/utils/zlib/ZLibInputStream.java deleted file mode 100644 index b777c10c..00000000 --- a/src/main/java/eu/siacs/conversations/utils/zlib/ZLibInputStream.java +++ /dev/null @@ -1,54 +0,0 @@ -package eu.siacs.conversations.utils.zlib; - -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.Inflater; -import java.util.zip.InflaterInputStream; - -/** - * ZLibInputStream is a zlib and input stream compatible version of an - * InflaterInputStream. This class solves the incompatibility between - * {@link InputStream#available()} and {@link InflaterInputStream#available()}. - */ -public class ZLibInputStream extends InflaterInputStream { - - /** - * Construct a ZLibInputStream, reading data from the underlying stream. - * - * @param is - * The {@code InputStream} to read data from. - * @throws IOException - * If an {@code IOException} occurs. - */ - public ZLibInputStream(InputStream is) throws IOException { - super(is, new Inflater(), 512); - } - - /** - * Provide a more InputStream compatible version of available. A return - * value of 1 means that it is likly to read one byte without blocking, 0 - * means that the system is known to block for more input. - * - * @return 0 if no data is available, 1 otherwise - * @throws IOException - */ - @Override - public int available() throws IOException { - /* - * This is one of the funny code blocks. InflaterInputStream.available - * violates the contract of InputStream.available, which breaks kXML2. - * - * I'm not sure who's to blame, oracle/sun for a broken api or the - * google guys for mixing a sun bug with a xml reader that can't handle - * it.... - * - * Anyway, this simple if breaks suns distorted reality, but helps to - * use the api as intended. - */ - if (inf.needsInput()) { - return 0; - } - return super.available(); - } - -} diff --git a/src/main/java/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java b/src/main/java/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java deleted file mode 100644 index 8b3f5e68..00000000 --- a/src/main/java/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java +++ /dev/null @@ -1,95 +0,0 @@ -package eu.siacs.conversations.utils.zlib; - -import java.io.IOException; -import java.io.OutputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.security.NoSuchAlgorithmException; -import java.util.zip.Deflater; -import java.util.zip.DeflaterOutputStream; - -/** - *

- * Android 2.2 includes Java7 FLUSH_SYNC option, which will be used by this - * Implementation, preferable via reflection. The @hide was remove in API level - * 19. This class might thus go away in the future. - *

- *

- * Please use {@link ZLibOutputStream#SUPPORTED} to check for flush - * compatibility. - *

- */ -public class ZLibOutputStream extends DeflaterOutputStream { - - /** - * The reflection based flush method. - */ - - private final static Method method; - /** - * SUPPORTED is true if a flush compatible method exists. - */ - public final static boolean SUPPORTED; - - /** - * Static block to initialize {@link #SUPPORTED} and {@link #method}. - */ - static { - Method m = null; - try { - m = Deflater.class.getMethod("deflate", byte[].class, int.class, - int.class, int.class); - } catch (SecurityException e) { - } catch (NoSuchMethodException e) { - } - method = m; - SUPPORTED = (method != null); - } - - /** - * Create a new ZLib compatible output stream wrapping the given low level - * stream. ZLib compatiblity means we will send a zlib header. - * - * @param os - * OutputStream The underlying stream. - * @throws IOException - * In case of a lowlevel transfer problem. - * @throws NoSuchAlgorithmException - * In case of a {@link Deflater} error. - */ - public ZLibOutputStream(OutputStream os) throws IOException, - NoSuchAlgorithmException { - super(os, new Deflater(Deflater.BEST_COMPRESSION)); - } - - /** - * Flush the given stream, preferring Java7 FLUSH_SYNC if available. - * - * @throws IOException - * In case of a lowlevel exception. - */ - @Override - public void flush() throws IOException { - if (!SUPPORTED) { - super.flush(); - return; - } - try { - int count = 0; - do { - count = (Integer) method.invoke(def, buf, 0, buf.length, 3); - if (count > 0) { - out.write(buf, 0, count); - } - } while (count > 0); - } catch (IllegalArgumentException e) { - throw new IOException("Can't flush"); - } catch (IllegalAccessException e) { - throw new IOException("Can't flush"); - } catch (InvocationTargetException e) { - throw new IOException("Can't flush"); - } - super.flush(); - } - -} diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index fb151427..adb96fa2 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -50,8 +50,6 @@ import eu.siacs.conversations.crypto.sasl.ScramSha1; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.DNSHelper; -import eu.siacs.conversations.utils.zlib.ZLibInputStream; -import eu.siacs.conversations.utils.zlib.ZLibOutputStream; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Tag; import eu.siacs.conversations.xml.TagWriter; @@ -92,7 +90,6 @@ public class XmppConnection implements Runnable { private int smVersion = 3; private SparseArray messageReceipts = new SparseArray<>(); - private boolean enabledCompression = false; private boolean enabledEncryption = false; private boolean enabledCarbons = false; @@ -144,7 +141,6 @@ public class XmppConnection implements Runnable { protected void connect() { Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": connecting"); - enabledCompression = false; enabledEncryption = false; lastConnect = SystemClock.elapsedRealtime(); lastPingSent = SystemClock.elapsedRealtime(); @@ -261,8 +257,6 @@ public class XmppConnection implements Runnable { processStreamFeatures(nextTag); } else if (nextTag.isStart("proceed")) { switchOverToTls(nextTag); - } else if (nextTag.isStart("compressed")) { - switchOverToZLib(nextTag); } else if (nextTag.isStart("success")) { final String challenge = tagReader.readElement(nextTag).getContent(); try { @@ -498,28 +492,6 @@ public class XmppConnection implements Runnable { } } - private void sendCompressionZlib() throws IOException { - Element compress = new Element("compress"); - compress.setAttribute("xmlns", "http://jabber.org/protocol/compress"); - compress.addChild("method").setContent("zlib"); - tagWriter.writeElement(compress); - } - - private void switchOverToZLib(final Tag currentTag) - throws XmlPullParserException, IOException, - NoSuchAlgorithmException { - tagReader.readTag(); // read tag close - tagWriter.setOutputStream(new ZLibOutputStream(tagWriter - .getOutputStream())); - tagReader - .setInputStream(new ZLibInputStream(tagReader.getInputStream())); - - sendStartStream(); - Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": compression enabled"); - enabledCompression = true; - processStream(tagReader.readTag()); - } - private void sendStartTLS() throws IOException { Tag startTLS = Tag.empty("starttls"); startTLS.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-tls"); @@ -601,8 +573,6 @@ public class XmppConnection implements Runnable { this.streamFeatures = tagReader.readElement(currentTag); if (this.streamFeatures.hasChild("starttls") && !enabledEncryption) { sendStartTLS(); - } else if (compressionAvailable()) { - sendCompressionZlib(); } else if (this.streamFeatures.hasChild("register") && account.isOptionSet(Account.OPTION_REGISTER) && enabledEncryption) { @@ -658,28 +628,6 @@ public class XmppConnection implements Runnable { } } - private boolean compressionAvailable() { - if (!this.streamFeatures.hasChild("compression", - "http://jabber.org/features/compress")) - return false; - if (!ZLibOutputStream.SUPPORTED) - return false; - if (!account.isOptionSet(Account.OPTION_USECOMPRESSION)) - return false; - - Element compression = this.streamFeatures.findChild("compression", - "http://jabber.org/features/compress"); - for (Element child : compression.getChildren()) { - if (!"method".equals(child.getName())) - continue; - - if ("zlib".equalsIgnoreCase(child.getContent())) { - return true; - } - } - return false; - } - private List extractMechanisms(Element stream) { ArrayList mechanisms = new ArrayList<>(stream .getChildren().size()); @@ -1147,9 +1095,5 @@ public class XmppConnection implements Runnable { return connection .findDiscoItemByFeature("http://jabber.org/protocol/bytestreams") != null; } - - public boolean compression() { - return connection.enabledCompression; - } } } -- cgit v1.2.3 From 78370094e9c9c2f58cb5f969217db555f9a283c2 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Tue, 9 Dec 2014 14:21:35 +0100 Subject: cleanup: removed unused emoticon parsing --- src/main/java/eu/siacs/conversations/Config.java | 1 - .../ui/adapter/ConversationAdapter.java | 6 +--- .../conversations/ui/adapter/MessageAdapter.java | 6 +--- .../eu/siacs/conversations/utils/UIHelper.java | 42 ---------------------- 4 files changed, 2 insertions(+), 53 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 7af29451..d777e5cc 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -18,7 +18,6 @@ public final class Config { public static final int MESSAGE_MERGE_WINDOW = 20; - public static final boolean PARSE_EMOTICONS = false; public static final int PROGRESS_UI_UPDATE_INTERVAL = 750; public static final boolean NO_PROXY_LOOKUP = false; //useful to debug ibb diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java index b81544e6..f728e800 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java @@ -2,7 +2,6 @@ package eu.siacs.conversations.ui.adapter; import java.util.List; -import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Downloadable; @@ -139,10 +138,7 @@ public class ConversationAdapter extends ArrayAdapter { } else { if ((message.getEncryption() != Message.ENCRYPTION_PGP) && (message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED)) { - String body = Config.PARSE_EMOTICONS ? UIHelper - .transformAsciiEmoticons(message.getBody()) : message - .getBody(); - mLastMessage.setText(body); + mLastMessage.setText(message.getBody()); } else { mLastMessage.setText(R.string.encrypted_message_received); } diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index 60046468..32062699 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -23,7 +23,6 @@ import android.widget.Toast; import java.util.List; -import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; @@ -225,10 +224,7 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.messageBody.setVisibility(View.VISIBLE); if (message.getBody() != null) { if (message.getType() != Message.TYPE_PRIVATE) { - String body = Config.PARSE_EMOTICONS ? UIHelper - .transformAsciiEmoticons(message.getMergedBody()) - : message.getMergedBody(); - viewHolder.messageBody.setText(body); + viewHolder.messageBody.setText(message.getMergedBody()); } else { String privateMarker; if (message.getStatus() <= Message.STATUS_RECEIVED) { diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index 28a2bb4c..2f1383b8 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -2,7 +2,6 @@ package eu.siacs.conversations.utils; import java.util.Calendar; import java.util.Date; -import java.util.regex.Pattern; import eu.siacs.conversations.R; import android.content.Context; @@ -86,47 +85,6 @@ public class UIHelper { } } - private final static class EmoticonPattern { - Pattern pattern; - String replacement; - - EmoticonPattern(String ascii, int unicode) { - this.pattern = Pattern.compile("(?<=(^|\\s))" + ascii - + "(?=(\\s|$))"); - this.replacement = new String(new int[] { unicode, }, 0, 1); - } - - String replaceAll(String body) { - return pattern.matcher(body).replaceAll(replacement); - } - } - - private static final EmoticonPattern[] patterns = new EmoticonPattern[] { - new EmoticonPattern(":-?D", 0x1f600), - new EmoticonPattern("\\^\\^", 0x1f601), - new EmoticonPattern(":'D", 0x1f602), - new EmoticonPattern("\\]-?D", 0x1f608), - new EmoticonPattern(";-?\\)", 0x1f609), - new EmoticonPattern(":-?\\)", 0x1f60a), - new EmoticonPattern("[B8]-?\\)", 0x1f60e), - new EmoticonPattern(":-?\\|", 0x1f610), - new EmoticonPattern(":-?[/\\\\]", 0x1f615), - new EmoticonPattern(":-?\\*", 0x1f617), - new EmoticonPattern(":-?[Ppb]", 0x1f61b), - new EmoticonPattern(":-?\\(", 0x1f61e), - new EmoticonPattern(":-?[0Oo]", 0x1f62e), - new EmoticonPattern("\\\\o/", 0x1F631), }; - - public static String transformAsciiEmoticons(String body) { - if (body != null) { - for (EmoticonPattern p : patterns) { - body = p.replaceAll(body); - } - body = body.trim(); - } - return body; - } - public static int getColorForName(String name) { if (name.isEmpty()) { return 0xFF202020; -- cgit v1.2.3 From 920067b8edf1d1ae950368db15e969ccc1a2bf56 Mon Sep 17 00:00:00 2001 From: kruks23 Date: Tue, 9 Dec 2014 18:33:13 +0100 Subject: Update spanish translations. --- src/main/res/values-es/strings.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index 792f7671..aad54aeb 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -104,7 +104,7 @@ Notificaciones Carbons Deshabilita las notificaciones durante un corto periodo de tiempo después de recibir la copia del mensaje carbon Opciones avanzadas - Nunca enviar informe de fallos + Nunca enviar errores Si envías registros de error ayudas al desarrollo de Conversations Confirmar Mensajes Permitir a tus contactos saber cuando recibes y lees un mensaje @@ -258,7 +258,7 @@ Por favor, cuidado con estas opciones Acerca de Conversations Información de compilación y licencia - Incrementar tamaño de fuente + Tamaño de fuente grande Usar fuentes grandes en toda la aplicación Botón enviar indica estado Solicitar entrega de mensaje @@ -308,13 +308,13 @@ ¡No se ha encontrado una sesión OTR válida! Conversations Pulsa para deshabilitar servicio en primer plano - Mantener servicio en primer plano - Previene que el sistema cierre la conexión + Servicio en primer plano + Mantener el servicio en primier plano previene que el sistema cierre la conexión Seleccionar archivo - Recibiendo archivo %1$s (%2$d%% completedo) + Recibiendo archivo %1$s (%2$d%% completado) Descargar archivo %s Abrir archivo %s - Enviando (%1$d%% completedo) + Enviando (%1$d%% completado) Preparando transferencia de archivo Archivo ofrecido para descarga Archivo %s -- cgit v1.2.3 From 338fd9e7b3d4661ca132b6074e2168223f65eb0c Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 9 Dec 2014 19:25:59 +0100 Subject: gradle: fix Cannot set property outputFile on null object. --- build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 51327d45..e7cb1097 100644 --- a/build.gradle +++ b/build.gradle @@ -84,7 +84,9 @@ android { applicationVariants.all { variant -> if (variant.name.equals('release')) { variant.outputs.each { output -> - output.zipAlign.outputFile = new File(output.outputFile.parent, rootProject.name + "-${variant.versionName}.apk") + if (output.zipAlign != null) { + output.zipAlign.outputFile = new File(output.outputFile.parent, rootProject.name + "-${variant.versionName}.apk") + } output.packageApplication.outputFile = new File(output.outputFile.parent, output.packageApplication.outputFile.name .replace(".apk", "-${variant.versionName}.apk")) } -- cgit v1.2.3 From 05d1f46c15e5f29531f2d8c237f34cd08da80ef7 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Tue, 9 Dec 2014 20:22:21 +0100 Subject: recreate activity after theme has changed. fixed #764 --- .../eu/siacs/conversations/ui/ConversationActivity.java | 9 +++++++++ src/main/java/eu/siacs/conversations/ui/XmppActivity.java | 14 +++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 5b0fa562..b2bf2fd8 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -675,6 +675,15 @@ public class ConversationActivity extends XmppActivity implements } } + @Override + public void onResume() { + super.onResume(); + int theme = findTheme(); + if (this.mTheme != theme) { + recreate(); + } + } + @Override public void onSaveInstanceState(final Bundle savedInstanceState) { Conversation conversation = getSelectedConversation(); diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index 5fba1664..e6ae2a1c 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -94,6 +94,7 @@ public abstract class XmppActivity extends Activity { protected boolean mUseSubject = true; private DisplayMetrics metrics; + protected int mTheme; protected interface OnValueEdited { public void onValueEdited(String value); @@ -292,9 +293,8 @@ public abstract class XmppActivity extends Activity { mPrimaryColor = getResources().getColor(R.color.primary); mSecondaryBackgroundColor = getResources().getColor( R.color.secondarybackground); - if (getPreferences().getBoolean("use_larger_font", false)) { - setTheme(R.style.ConversationsTheme_LargerText); - } + this.mTheme = findTheme(); + setTheme(this.mTheme); mUseSubject = getPreferences().getBoolean("use_subject", true); } @@ -721,6 +721,14 @@ public abstract class XmppActivity extends Activity { } } + protected int findTheme() { + if (getPreferences().getBoolean("use_larger_font", false)) { + return R.style.ConversationsTheme_LargerText; + } else { + return R.style.ConversationsTheme; + } + } + @Override public void onPause() { super.onPause(); -- cgit v1.2.3 From 2b958e51df8655d63b713efa10870c40bdc42856 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Wed, 10 Dec 2014 14:07:56 +0100 Subject: removed unnecessary otr error response --- src/main/java/eu/siacs/conversations/parser/MessageParser.java | 4 ---- .../eu/siacs/conversations/services/XmppConnectionService.java | 8 -------- 2 files changed, 12 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 782675da..3ae82e48 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -124,10 +124,6 @@ public class MessageParser extends AbstractParser implements finishedMessage.setCounterpart(from); return finishedMessage; } catch (Exception e) { - String receivedId = packet.getId(); - if (receivedId != null) { - mXmppConnectionService.replyWithNotAcceptable(account, packet); - } conversation.resetOtrSession(); return null; } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 41a40224..2f44375e 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1969,14 +1969,6 @@ public class XmppConnectionService extends Service { return this.mBitmapCache; } - public void replyWithNotAcceptable(Account account, MessagePacket packet) { - if (account.getStatus() == Account.State.ONLINE) { - MessagePacket error = this.mMessageGenerator - .generateNotAcceptable(packet); - sendMessagePacket(account, error); - } - } - public void syncRosterToDisk(final Account account) { new Thread(new Runnable() { -- cgit v1.2.3 From 34558cc2779e5fd3cb8a2afa39be0efcc5314d88 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Thu, 4 Dec 2014 16:20:28 +0100 Subject: store last message received date in conversation --- .../siacs/conversations/entities/Conversation.java | 9 ++++ .../conversations/generator/AbstractGenerator.java | 10 ++++ .../siacs/conversations/parser/AbstractParser.java | 56 +++++++++------------- .../siacs/conversations/parser/MessageParser.java | 3 +- .../services/XmppConnectionService.java | 24 ++-------- 5 files changed, 48 insertions(+), 54 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index a7da0bc2..725ed27b 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -43,6 +43,7 @@ public class Conversation extends AbstractEntity { public static final String ATTRIBUTE_NEXT_ENCRYPTION = "next_encryption"; public static final String ATTRIBUTE_MUC_PASSWORD = "muc_password"; public static final String ATTRIBUTE_MUTED_TILL = "muted_till"; + public static final String ATTRIBUTE_LAST_MESSAGE_RECEIVED = "last_message_received"; private String name; private String contactUuid; @@ -470,6 +471,14 @@ public class Conversation extends AbstractEntity { } } + public void setLastMessageReceived(long value) { + this.setAttribute(ATTRIBUTE_LAST_MESSAGE_RECEIVED, String.valueOf(value)); + } + + public long getLastMessageReceived() { + return getLongAttribute(ATTRIBUTE_LAST_MESSAGE_RECEIVED,0); + } + public void setMutedTill(long value) { this.setAttribute(ATTRIBUTE_MUTED_TILL, String.valueOf(value)); } diff --git a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java index f46e7ba4..b200b2a1 100644 --- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java @@ -4,9 +4,12 @@ import android.util.Base64; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Locale; +import java.util.TimeZone; import eu.siacs.conversations.services.XmppConnectionService; @@ -23,6 +26,8 @@ public abstract class AbstractGenerator { public final String IDENTITY_NAME = "Conversations 0.9.3"; public final String IDENTITY_TYPE = "phone"; + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US); + protected XmppConnectionService mXmppConnectionService; protected AbstractGenerator(XmppConnectionService service) { @@ -46,4 +51,9 @@ public abstract class AbstractGenerator { byte[] sha1 = md.digest(s.toString().getBytes()); return new String(Base64.encode(sha1, Base64.DEFAULT)).trim(); } + + public static String getTimestamp(long time) { + DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC")); + return DATE_FORMAT.format(time); + } } diff --git a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java index eedfca16..c80346b7 100644 --- a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java +++ b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java @@ -24,50 +24,40 @@ public abstract class AbstractParser { protected long getTimestamp(Element packet) { long now = System.currentTimeMillis(); - ArrayList stamps = new ArrayList<>(); - for (Element child : packet.getChildren()) { - if (child.getName().equals("delay")) { - stamps.add(child.getAttribute("stamp").replace("Z", "+0000")); - } + Element delay = packet.findChild("delay"); + if (delay == null) { + return now; } - Collections.sort(stamps); - if (stamps.size() >= 1) { - try { - String stamp = stamps.get(stamps.size() - 1); - if (stamp.contains(".")) { - Date date = new SimpleDateFormat( - "yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US) - .parse(stamp); - if (now < date.getTime()) { - return now; - } else { - return date.getTime(); - } - } else { - Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", - Locale.US).parse(stamp); - if (now < date.getTime()) { - return now; - } else { - return date.getTime(); - } - } - } catch (ParseException e) { - return now; - } - } else { + String stamp = delay.getAttribute("stamp"); + if (stamp == null) { + return now; + } + try { + long time = parseTimestamp(stamp).getTime(); + return now < time ? now : time; + } catch (ParseException e) { return now; } } + public static Date parseTimestamp(String timestamp) throws ParseException { + timestamp = timestamp.replace("Z", "+0000"); + SimpleDateFormat dateFormat; + if (timestamp.contains(".")) { + dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US); + } else { + dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ",Locale.US); + } + return dateFormat.parse(timestamp); + } + protected void updateLastseen(final Element packet, final Account account, final boolean presenceOverwrite) { Jid from; try { from = Jid.fromString(packet.getAttribute("from")).toBareJid(); } catch (final InvalidJidException e) { - // TODO: Handle this? - from = null; + return; } String presence = from == null || from.isBareJid() ? "" : from.getResourcepart(); Contact contact = account.getRoster().getContact(from); diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 3ae82e48..fd9e1b6c 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -14,7 +14,6 @@ import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnMessagePacketReceived; -import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.pep.Avatar; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; @@ -487,6 +486,8 @@ public class MessageParser extends AbstractParser implements } Conversation conversation = message.getConversation(); conversation.add(message); + conversation.setLastMessageReceived(System.currentTimeMillis()); + mXmppConnectionService.updateConversation(conversation); if (message.getStatus() == Message.STATUS_RECEIVED && conversation.getOtrSession() != null diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 2f44375e..b9da4a81 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -32,20 +32,14 @@ import net.java.otr4j.session.SessionStatus; import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpServiceConnection; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.OutputStream; import java.math.BigInteger; import java.security.SecureRandom; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.Date; import java.util.Hashtable; import java.util.List; import java.util.Locale; -import java.util.TimeZone; import java.util.concurrent.CopyOnWriteArrayList; import de.duenndns.ssl.MemorizingTrustManager; @@ -1251,27 +1245,17 @@ public class XmppConnectionService extends Service { PresencePacket packet = new PresencePacket(); packet.setFrom(conversation.getAccount().getJid()); packet.setTo(joinJid); - Element x = new Element("x"); - x.setAttribute("xmlns", "http://jabber.org/protocol/muc"); + Element x = packet.addChild("x","http://jabber.org/protocol/muc"); if (conversation.getMucOptions().getPassword() != null) { - Element password = x.addChild("password"); - password.setContent(conversation.getMucOptions().getPassword()); + x.addChild("password").setContent(conversation.getMucOptions().getPassword()); } + x.addChild("history").setAttribute("since",PresenceGenerator.getTimestamp(conversation.getLastMessageReceived())); String sig = account.getPgpSignature(); if (sig != null) { packet.addChild("status").setContent("online"); packet.addChild("x", "jabber:x:signed").setContent(sig); } - if (conversation.getMessages().size() != 0) { - final SimpleDateFormat mDateFormat = new SimpleDateFormat( - "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US); - mDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - Date date = new Date(conversation.getLatestMessage() - .getTimeSent() + 1000); - x.addChild("history").setAttribute("since", - mDateFormat.format(date)); - } - packet.addChild(x); + Log.d(Config.LOGTAG,packet.toString()); sendPresencePacket(account, packet); if (!joinJid.equals(conversation.getContactJid())) { conversation.setContactJid(joinJid); -- cgit v1.2.3 From 4a94389f052afab8b0424bd56af3e0741a9ee430 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Fri, 5 Dec 2014 01:54:16 +0100 Subject: very basic mam support --- .../eu/siacs/conversations/entities/Bookmark.java | 4 +- .../siacs/conversations/generator/IqGenerator.java | 18 +++ .../siacs/conversations/parser/MessageParser.java | 66 +++++++++- .../services/MessageArchiveService.java | 137 +++++++++++++++++++++ .../services/XmppConnectionService.java | 30 ++++- .../java/eu/siacs/conversations/xml/Element.java | 5 + .../xmpp/OnAdvancedStreamFeaturesAvailable.java | 7 ++ .../siacs/conversations/xmpp/XmppConnection.java | 8 ++ .../eu/siacs/conversations/xmpp/forms/Data.java | 10 ++ 9 files changed, 277 insertions(+), 8 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/services/MessageArchiveService.java create mode 100644 src/main/java/eu/siacs/conversations/xmpp/OnAdvancedStreamFeaturesAvailable.java diff --git a/src/main/java/eu/siacs/conversations/entities/Bookmark.java b/src/main/java/eu/siacs/conversations/entities/Bookmark.java index 559e2f2d..70d852fe 100644 --- a/src/main/java/eu/siacs/conversations/entities/Bookmark.java +++ b/src/main/java/eu/siacs/conversations/entities/Bookmark.java @@ -102,9 +102,7 @@ public class Bookmark extends Element implements ListItem { } public boolean autojoin() { - String autojoin = this.getAttribute("autojoin"); - return (autojoin != null && (autojoin.equalsIgnoreCase("true") || autojoin - .equalsIgnoreCase("1"))); + return this.getAttributeAsBoolean("autojoin"); } public String getPassword() { diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 5d674748..56a0776f 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -4,8 +4,10 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xmpp.forms.Data; import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.pep.Avatar; import eu.siacs.conversations.xmpp.stanzas.IqPacket; @@ -94,4 +96,20 @@ public class IqGenerator extends AbstractGenerator { } return packet; } + + public IqPacket queryMessageArchiveManagement(MessageArchiveService.Query mam) { + final IqPacket packet = new IqPacket(IqPacket.TYPE_SET); + Element query = packet.query("urn:xmpp:mam:0"); + query.setAttribute("queryid",mam.getQueryId()); + Data data = new Data(); + data.setFormType("urn:xmpp:mam:0"); + data.put("with",mam.getWith().toString()); + data.put("start",getTimestamp(mam.getStart())); + data.put("end",getTimestamp(mam.getEnd())); + query.addChild(data); + if (mam.getAfter() != null) { + query.addChild("set", "http://jabber.org/protocol/rsm").addChild("after").setContent(mam.getAfter()); + } + 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 fd9e1b6c..b902db51 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -272,6 +272,58 @@ public class MessageParser extends AbstractParser implements return finishedMessage; } + private Message parseMamMessage(MessagePacket packet, final Account account) { + final Element result = packet.findChild("result","urn:xmpp:mam:0"); + if (result == null ) { + return null; + } + final Element forwarded = result.findChild("forwarded","urn:xmpp:forward:0"); + if (forwarded == null) { + return null; + } + final Element message = forwarded.findChild("message"); + if (message == null) { + return null; + } + final Element body = message.findChild("body"); + if (body == null || message.hasChild("private","urn:xmpp:carbons:2") || message.hasChild("no-copy","urn:xmpp:hints")) { + return null; + } + int encryption; + String content = getPgpBody(message); + if (content != null) { + encryption = Message.ENCRYPTION_PGP; + } else { + encryption = Message.ENCRYPTION_NONE; + content = body.getContent(); + } + if (content == null) { + return null; + } + final long timestamp = getTimestamp(forwarded); + final Jid to = message.getAttributeAsJid("to"); + final Jid from = message.getAttributeAsJid("from"); + Jid counterpart; + int status; + Conversation conversation; + if (from!=null && to != null && from.toBareJid().equals(account.getJid().toBareJid())) { + status = Message.STATUS_SEND; + conversation = this.mXmppConnectionService.findOrCreateConversation(account,to.toBareJid(),false); + counterpart = to; + } else if (from !=null && to != null) { + status = Message.STATUS_RECEIVED; + conversation = this.mXmppConnectionService.findOrCreateConversation(account,from.toBareJid(),false); + counterpart = from; + } else { + return null; + } + Message finishedMessage = new Message(conversation,content,encryption,status); + finishedMessage.setTime(timestamp); + finishedMessage.setCounterpart(counterpart); + Log.d(Config.LOGTAG,"received mam message "+content); + return finishedMessage; + } + private void parseError(final MessagePacket packet, final Account account) { final Jid from = packet.getFrom(); mXmppConnectionService.markMessage(account, from.toBareJid(), @@ -445,6 +497,17 @@ public class MessageParser extends AbstractParser implements message.markUnread(); } } + } else if (packet.hasChild("result","urn:xmpp:mam:0")) { + message = parseMamMessage(packet, account); + if (message != null) { + Conversation conversation = message.getConversation(); + conversation.add(message); + mXmppConnectionService.databaseBackend.createMessage(message); + } + return; + } else if (packet.hasChild("fin","urn:xmpp:mam:0")) { + Element fin = packet.findChild("fin","urn:xmpp:mam:0"); + mXmppConnectionService.getMessageArchiveService().processFin(fin); } else { parseNonMessage(packet, account); } @@ -493,7 +556,6 @@ public class MessageParser extends AbstractParser implements && conversation.getOtrSession() != null && !conversation.getOtrSession().getSessionID().getUserID() .equals(message.getCounterpart().getResourcepart())) { - Log.d(Config.LOGTAG, "ending because of reasons"); conversation.endOtrIfNeeded(); } @@ -506,7 +568,7 @@ public class MessageParser extends AbstractParser implements if (message.trusted() && message.bodyContainsDownloadable()) { this.mXmppConnectionService.getHttpConnectionManager() .createNewConnection(message); - } else { + } else if (!message.isRead()) { mXmppConnectionService.getNotificationService().push(message); } mXmppConnectionService.updateConversationUi(); diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java new file mode 100644 index 00000000..4f47cdbe --- /dev/null +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -0,0 +1,137 @@ +package eu.siacs.conversations.services; + +import android.util.Log; + +import java.math.BigInteger; +import java.util.HashSet; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xmpp.OnIqPacketReceived; +import eu.siacs.conversations.xmpp.jid.Jid; +import eu.siacs.conversations.xmpp.stanzas.IqPacket; + +public class MessageArchiveService { + + private final XmppConnectionService mXmppConnectionService; + + private final HashSet queries = new HashSet(); + + public MessageArchiveService(final XmppConnectionService service) { + this.mXmppConnectionService = service; + } + + public void query(final Conversation conversation) { + synchronized (this.queries) { + final Account account = conversation.getAccount(); + long start = conversation.getLastMessageReceived(); + long end = account.getXmppConnection().getLastSessionEstablished(); + final Query query = new Query(conversation, start, end); + this.queries.add(query); + IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(query); + this.mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() { + @Override + public void onIqPacketReceived(Account account, IqPacket packet) { + Log.d(Config.LOGTAG, packet.toString()); + } + }); + } + } + + public void processFin(Element fin) { + if (fin == null) { + return; + } + Query query = findQuery(fin.getAttribute("queryid")); + if (query == null) { + return; + } + Log.d(Config.LOGTAG,"fin "+fin.toString()); + boolean complete = fin.getAttributeAsBoolean("complete"); + Element set = fin.findChild("set","http://jabber.org/protocol/rsm"); + Element last = set == null ? null : set.findChild("last"); + if (complete || last == null) { + Log.d(Config.LOGTAG,"completed mam query for "+query.getWith().toString()); + synchronized (this.queries) { + this.queries.remove(query); + } + } else { + Query nextQuery = query.next(last == null ? null : last.getContent()); + IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(nextQuery); + synchronized (this.queries) { + this.queries.remove(query); + this.queries.add(nextQuery); + } + Log.d(Config.LOGTAG,packet.toString()); + this.mXmppConnectionService.sendIqPacket(query.getConversation().getAccount(),packet,new OnIqPacketReceived() { + @Override + public void onIqPacketReceived(Account account, IqPacket packet) { + Log.d(Config.LOGTAG,packet.toString()); + } + }); + } + } + + private Query findQuery(String id) { + if (id == null) { + return null; + } + synchronized (this.queries) { + for(Query query : this.queries) { + if (query.getQueryId().equals(id)) { + return query; + } + } + return null; + } + } + + public class Query { + private long start; + private long end; + private Jid with; + private String queryId; + private String after = null; + private Conversation conversation; + + public Query(Conversation conversation, long start, long end) { + this.conversation = conversation; + this.with = conversation.getContactJid().toBareJid(); + this.start = start; + this.end = end; + this.queryId = new BigInteger(50, mXmppConnectionService.getRNG()).toString(32); + } + + public Query next(String after) { + Query query = new Query(this.conversation,this.start,this.end); + query.after = after; + return query; + } + + public String getAfter() { + return after; + } + + public String getQueryId() { + return queryId; + } + + public Jid getWith() { + return with; + } + + public long getStart() { + return start; + } + + public long getEnd() { + return end; + } + + public Conversation getConversation() { + return conversation; + } + } +} diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index b9da4a81..9d73868c 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -73,6 +73,7 @@ import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener; import eu.siacs.conversations.utils.PRNGFixes; import eu.siacs.conversations.utils.PhoneHelper; import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesAvailable; import eu.siacs.conversations.xmpp.OnBindListener; import eu.siacs.conversations.xmpp.OnContactStatusChanged; import eu.siacs.conversations.xmpp.OnIqPacketReceived; @@ -141,6 +142,7 @@ public class XmppConnectionService extends Service { private HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager( this); private AvatarService mAvatarService = new AvatarService(this); + private MessageArchiveService mMessageArchiveService = new MessageArchiveService(this); private OnConversationUpdate mOnConversationUpdate = null; private Integer convChangedListenerCount = 0; private OnAccountUpdate mOnAccountUpdate = null; @@ -203,6 +205,12 @@ public class XmppConnectionService extends Service { getNotificationService().updateErrorNotification(); } }; + private OnAdvancedStreamFeaturesAvailable onAdvancedStreamFeaturesAvailable = new OnAdvancedStreamFeaturesAvailable() { + @Override + public void onAdvancedStreamFeaturesAvailable(Account account) { + queryMessagesFromArchive(account); + } + }; private int accountChangedListenerCount = 0; private OnRosterUpdate mOnRosterUpdate = null; private int rosterChangedListenerCount = 0; @@ -583,8 +591,8 @@ public class XmppConnectionService extends Service { connection.setOnUnregisteredIqPacketReceivedListener(this.mIqParser); connection.setOnJinglePacketReceivedListener(this.jingleListener); connection.setOnBindListener(this.mOnBindListener); - connection - .setOnMessageAcknowledgeListener(this.mOnMessageAcknowledgedListener); + connection.setOnMessageAcknowledgeListener(this.mOnMessageAcknowledgedListener); + connection.setOnAdvancedStreamFeaturesAvailableListener(this.onAdvancedStreamFeaturesAvailable); return connection; } @@ -1231,6 +1239,19 @@ public class XmppConnectionService extends Service { } } + private void queryMessagesFromArchive(final Account account) { + if (account.getXmppConnection() != null && account.getXmppConnection().getFeatures().mam()) { + List conversations = getConversations(); + for (Conversation conversation : conversations) { + if (conversation.getMode() == Conversation.MODE_SINGLE && conversation.getAccount() == account) { + this.mMessageArchiveService.query(conversation); + } + } + } else { + Log.d(Config.LOGTAG,"no mam available"); + } + } + public void joinMuc(Conversation conversation) { Account account = conversation.getAccount(); account.pendingConferenceJoins.remove(conversation); @@ -1255,7 +1276,6 @@ public class XmppConnectionService extends Service { packet.addChild("status").setContent("online"); packet.addChild("x", "jabber:x:signed").setContent(sig); } - Log.d(Config.LOGTAG,packet.toString()); sendPresencePacket(account, packet); if (!joinJid.equals(conversation.getContactJid())) { conversation.setContactJid(joinJid); @@ -2033,6 +2053,10 @@ public class XmppConnectionService extends Service { return this.mJingleConnectionManager; } + public MessageArchiveService getMessageArchiveService() { + return this.mMessageArchiveService; + } + public List findContacts(Jid jid) { ArrayList contacts = new ArrayList<>(); for (Account account : getAccounts()) { diff --git a/src/main/java/eu/siacs/conversations/xml/Element.java b/src/main/java/eu/siacs/conversations/xml/Element.java index 02c3e695..c25b9017 100644 --- a/src/main/java/eu/siacs/conversations/xml/Element.java +++ b/src/main/java/eu/siacs/conversations/xml/Element.java @@ -159,4 +159,9 @@ public class Element { public void setAttribute(String name, int value) { this.setAttribute(name, Integer.toString(value)); } + + public boolean getAttributeAsBoolean(String name) { + String attr = getAttribute(name); + return (attr != null && (attr.equalsIgnoreCase("true") || attr.equalsIgnoreCase("1"))); + } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/OnAdvancedStreamFeaturesAvailable.java b/src/main/java/eu/siacs/conversations/xmpp/OnAdvancedStreamFeaturesAvailable.java new file mode 100644 index 00000000..a41bce86 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/xmpp/OnAdvancedStreamFeaturesAvailable.java @@ -0,0 +1,7 @@ +package eu.siacs.conversations.xmpp; + +import eu.siacs.conversations.entities.Account; + +public interface OnAdvancedStreamFeaturesAvailable { + public void onAdvancedStreamFeaturesAvailable(final Account account); +} diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index adb96fa2..0e5d26ed 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -107,6 +107,7 @@ public class XmppConnection implements Runnable { private OnMessagePacketReceived messageListener = null; private OnStatusChanged statusListener = null; private OnBindListener bindListener = null; + private OnAdvancedStreamFeaturesAvailable advancedStreamFeaturesAvailableListener = null; private OnMessageAcknowledged acknowledgedListener = null; private XmppConnectionService mXmppConnectionService = null; @@ -771,6 +772,9 @@ public class XmppConnection implements Runnable { if (account.getServer().equals(server.toDomainJid())) { enableAdvancedStreamFeatures(); + if (advancedStreamFeaturesAvailableListener != null) { + advancedStreamFeaturesAvailableListener.onAdvancedStreamFeaturesAvailable(account); + } } } }); @@ -943,6 +947,10 @@ public class XmppConnection implements Runnable { this.acknowledgedListener = listener; } + public void setOnAdvancedStreamFeaturesAvailableListener(OnAdvancedStreamFeaturesAvailable listener) { + this.advancedStreamFeaturesAvailableListener = listener; + } + public void disconnect(boolean force) { Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting"); try { diff --git a/src/main/java/eu/siacs/conversations/xmpp/forms/Data.java b/src/main/java/eu/siacs/conversations/xmpp/forms/Data.java index ff9acb3f..44794c80 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/forms/Data.java +++ b/src/main/java/eu/siacs/conversations/xmpp/forms/Data.java @@ -37,6 +37,7 @@ public class Data extends Element { Field field = getFieldByName(name); if (field == null) { field = new Field(name); + this.addChild(field); } field.setValue(value); } @@ -45,6 +46,7 @@ public class Data extends Element { Field field = getFieldByName(name); if (field == null) { field = new Field(name); + this.addChild(field); } field.setValues(values); } @@ -72,4 +74,12 @@ public class Data extends Element { data.setChildren(element.getChildren()); return data; } + + public void setFormType(String formType) { + this.put("FORM_TYPE",formType); + } + + public String getFormType() { + return this.getAttribute("FORM_TYPE"); + } } -- cgit v1.2.3 From 0ab530932ae559d9b2a0dd8cbc57530fa8552319 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Mon, 8 Dec 2014 21:59:14 +0100 Subject: added max history age (default 1w). automatically sort newly added mam messages --- src/main/java/eu/siacs/conversations/Config.java | 2 + .../conversations/entities/AbstractEntity.java | 1 - .../siacs/conversations/entities/Conversation.java | 39 +++++++++++++++++- .../eu/siacs/conversations/entities/Message.java | 5 +++ .../siacs/conversations/parser/MessageParser.java | 7 +++- .../services/MessageArchiveService.java | 48 +++++++++++++++++----- .../services/XmppConnectionService.java | 25 ++--------- .../xmpp/OnAdvancedStreamFeaturesAvailable.java | 7 ---- .../xmpp/OnAdvancedStreamFeaturesLoaded.java | 7 ++++ .../siacs/conversations/xmpp/XmppConnection.java | 16 +++++--- 10 files changed, 109 insertions(+), 48 deletions(-) delete mode 100644 src/main/java/eu/siacs/conversations/xmpp/OnAdvancedStreamFeaturesAvailable.java create mode 100644 src/main/java/eu/siacs/conversations/xmpp/OnAdvancedStreamFeaturesLoaded.java diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index d777e5cc..e9e73db9 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -22,6 +22,8 @@ public final class Config { public static final boolean NO_PROXY_LOOKUP = false; //useful to debug ibb + public static final long MAX_HISTORY_AGE = 7 * 24 * 60 * 60 * 1000; + private Config() { } diff --git a/src/main/java/eu/siacs/conversations/entities/AbstractEntity.java b/src/main/java/eu/siacs/conversations/entities/AbstractEntity.java index 92b8a729..957b0a14 100644 --- a/src/main/java/eu/siacs/conversations/entities/AbstractEntity.java +++ b/src/main/java/eu/siacs/conversations/entities/AbstractEntity.java @@ -17,5 +17,4 @@ public abstract class AbstractEntity { public boolean equals(AbstractEntity entity) { return this.getUuid().equals(entity.getUuid()); } - } diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 725ed27b..63f341e7 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -16,6 +16,8 @@ import org.json.JSONObject; import java.security.interfaces.DSAPublicKey; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import eu.siacs.conversations.xmpp.jid.InvalidJidException; @@ -471,12 +473,25 @@ public class Conversation extends AbstractEntity { } } - public void setLastMessageReceived(long value) { + public boolean setLastMessageReceived(long value) { + long before = getLastMessageReceived(); this.setAttribute(ATTRIBUTE_LAST_MESSAGE_RECEIVED, String.valueOf(value)); + return (value - before > 1000); } public long getLastMessageReceived() { - return getLongAttribute(ATTRIBUTE_LAST_MESSAGE_RECEIVED,0); + long timestamp = getLongAttribute(ATTRIBUTE_LAST_MESSAGE_RECEIVED,0); + if (timestamp == 0) { + synchronized (this.messages) { + for(int i = this.messages.size() - 1; i >= 0; --i) { + Message message = this.messages.get(i); + if (message.getStatus() == Message.STATUS_RECEIVED) { + return message.getTimeSent(); + } + } + } + } + return timestamp; } public void setMutedTill(long value) { @@ -544,6 +559,26 @@ public class Conversation extends AbstractEntity { } } + public void sort() { + synchronized (this.messages) { + for(Message message : this.messages) { + message.untie(); + } + Collections.sort(this.messages,new Comparator() { + @Override + public int compare(Message left, Message right) { + if (left.getTimeSent() < right.getTimeSent()) { + return -1; + } else if (left.getTimeSent() > right.getTimeSent()) { + return 1; + } else { + return 0; + } + } + }); + } + } + public class Smp { public static final int STATUS_NONE = 0; public static final int STATUS_CONTACT_REQUESTED = 1; diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 47861d06..1213f66a 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -493,6 +493,11 @@ public class Message extends AbstractEntity { } } + public void untie() { + this.mNextMessage = null; + this.mPreviousMessage = null; + } + public class ImageParams { public URL url; public long size = 0; diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index b902db51..3714ac90 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -549,8 +549,11 @@ public class MessageParser extends AbstractParser implements } Conversation conversation = message.getConversation(); conversation.add(message); - conversation.setLastMessageReceived(System.currentTimeMillis()); - mXmppConnectionService.updateConversation(conversation); + if (account.getXmppConnection() != null && account.getXmppConnection().getFeatures().advancedStreamFeaturesLoaded()) { + if (conversation.setLastMessageReceived(System.currentTimeMillis())) { + mXmppConnectionService.updateConversation(conversation); + } + } if (message.getStatus() == Message.STATUS_RECEIVED && conversation.getOtrSession() != null diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index 4f47cdbe..c77262cb 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -4,16 +4,18 @@ import android.util.Log; import java.math.BigInteger; import java.util.HashSet; +import java.util.List; import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded; import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.stanzas.IqPacket; -public class MessageArchiveService { +public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { private final XmppConnectionService mXmppConnectionService; @@ -28,18 +30,31 @@ public class MessageArchiveService { final Account account = conversation.getAccount(); long start = conversation.getLastMessageReceived(); long end = account.getXmppConnection().getLastSessionEstablished(); + if (end - start >= Config.MAX_HISTORY_AGE) { + start = end - Config.MAX_HISTORY_AGE; + } final Query query = new Query(conversation, start, end); this.queries.add(query); IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(query); this.mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { - Log.d(Config.LOGTAG, packet.toString()); + if (packet.getType() == IqPacket.TYPE_ERROR) { + finalizeQuery(query); + } } }); } } + private void finalizeQuery(Query query) { + synchronized (this.queries) { + this.queries.remove(query); + } + query.getConversation().sort(); + this.mXmppConnectionService.updateConversationUi(); + } + public void processFin(Element fin) { if (fin == null) { return; @@ -48,27 +63,26 @@ public class MessageArchiveService { if (query == null) { return; } - Log.d(Config.LOGTAG,"fin "+fin.toString()); boolean complete = fin.getAttributeAsBoolean("complete"); Element set = fin.findChild("set","http://jabber.org/protocol/rsm"); Element last = set == null ? null : set.findChild("last"); if (complete || last == null) { - Log.d(Config.LOGTAG,"completed mam query for "+query.getWith().toString()); - synchronized (this.queries) { - this.queries.remove(query); - } + final Account account = query.getConversation().getAccount(); + Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": completed mam query for "+query.getWith().toString()); + this.finalizeQuery(query); } else { - Query nextQuery = query.next(last == null ? null : last.getContent()); + final Query nextQuery = query.next(last == null ? null : last.getContent()); IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(nextQuery); synchronized (this.queries) { this.queries.remove(query); this.queries.add(nextQuery); } - Log.d(Config.LOGTAG,packet.toString()); this.mXmppConnectionService.sendIqPacket(query.getConversation().getAccount(),packet,new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { - Log.d(Config.LOGTAG,packet.toString()); + if (packet.getType() == IqPacket.TYPE_ERROR) { + finalizeQuery(nextQuery); + } } }); } @@ -88,6 +102,20 @@ public class MessageArchiveService { } } + @Override + public void onAdvancedStreamFeaturesAvailable(Account account) { + if (account.getXmppConnection() != null && account.getXmppConnection().getFeatures().mam()) { + List conversations = mXmppConnectionService.getConversations(); + for (Conversation conversation : conversations) { + if (conversation.getMode() == Conversation.MODE_SINGLE && conversation.getAccount() == account) { + this.query(conversation); + } + } + } else { + Log.d(Config.LOGTAG,"no mam available"); + } + } + public class Query { private long start; private long end; diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 9d73868c..3e2c1b8b 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -73,7 +73,7 @@ import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener; import eu.siacs.conversations.utils.PRNGFixes; import eu.siacs.conversations.utils.PhoneHelper; import eu.siacs.conversations.xml.Element; -import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesAvailable; +import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded; import eu.siacs.conversations.xmpp.OnBindListener; import eu.siacs.conversations.xmpp.OnContactStatusChanged; import eu.siacs.conversations.xmpp.OnIqPacketReceived; @@ -205,12 +205,7 @@ public class XmppConnectionService extends Service { getNotificationService().updateErrorNotification(); } }; - private OnAdvancedStreamFeaturesAvailable onAdvancedStreamFeaturesAvailable = new OnAdvancedStreamFeaturesAvailable() { - @Override - public void onAdvancedStreamFeaturesAvailable(Account account) { - queryMessagesFromArchive(account); - } - }; + private int accountChangedListenerCount = 0; private OnRosterUpdate mOnRosterUpdate = null; private int rosterChangedListenerCount = 0; @@ -592,7 +587,7 @@ public class XmppConnectionService extends Service { connection.setOnJinglePacketReceivedListener(this.jingleListener); connection.setOnBindListener(this.mOnBindListener); connection.setOnMessageAcknowledgeListener(this.mOnMessageAcknowledgedListener); - connection.setOnAdvancedStreamFeaturesAvailableListener(this.onAdvancedStreamFeaturesAvailable); + connection.addOnAdvancedStreamFeaturesAvailableListener(this.mMessageArchiveService); return connection; } @@ -1027,6 +1022,7 @@ public class XmppConnectionService extends Service { } this.databaseBackend.createConversation(conversation); } + this.mMessageArchiveService.query(conversation); this.conversations.add(conversation); updateConversationUi(); return conversation; @@ -1239,19 +1235,6 @@ public class XmppConnectionService extends Service { } } - private void queryMessagesFromArchive(final Account account) { - if (account.getXmppConnection() != null && account.getXmppConnection().getFeatures().mam()) { - List conversations = getConversations(); - for (Conversation conversation : conversations) { - if (conversation.getMode() == Conversation.MODE_SINGLE && conversation.getAccount() == account) { - this.mMessageArchiveService.query(conversation); - } - } - } else { - Log.d(Config.LOGTAG,"no mam available"); - } - } - public void joinMuc(Conversation conversation) { Account account = conversation.getAccount(); account.pendingConferenceJoins.remove(conversation); diff --git a/src/main/java/eu/siacs/conversations/xmpp/OnAdvancedStreamFeaturesAvailable.java b/src/main/java/eu/siacs/conversations/xmpp/OnAdvancedStreamFeaturesAvailable.java deleted file mode 100644 index a41bce86..00000000 --- a/src/main/java/eu/siacs/conversations/xmpp/OnAdvancedStreamFeaturesAvailable.java +++ /dev/null @@ -1,7 +0,0 @@ -package eu.siacs.conversations.xmpp; - -import eu.siacs.conversations.entities.Account; - -public interface OnAdvancedStreamFeaturesAvailable { - public void onAdvancedStreamFeaturesAvailable(final Account account); -} diff --git a/src/main/java/eu/siacs/conversations/xmpp/OnAdvancedStreamFeaturesLoaded.java b/src/main/java/eu/siacs/conversations/xmpp/OnAdvancedStreamFeaturesLoaded.java new file mode 100644 index 00000000..e45eba73 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/xmpp/OnAdvancedStreamFeaturesLoaded.java @@ -0,0 +1,7 @@ +package eu.siacs.conversations.xmpp; + +import eu.siacs.conversations.entities.Account; + +public interface OnAdvancedStreamFeaturesLoaded { + public void onAdvancedStreamFeaturesAvailable(final Account account); +} diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 0e5d26ed..af0499c6 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -107,7 +107,7 @@ public class XmppConnection implements Runnable { private OnMessagePacketReceived messageListener = null; private OnStatusChanged statusListener = null; private OnBindListener bindListener = null; - private OnAdvancedStreamFeaturesAvailable advancedStreamFeaturesAvailableListener = null; + private ArrayList advancedStreamFeaturesLoadedListeners = new ArrayList<>(); private OnMessageAcknowledged acknowledgedListener = null; private XmppConnectionService mXmppConnectionService = null; @@ -772,8 +772,8 @@ public class XmppConnection implements Runnable { if (account.getServer().equals(server.toDomainJid())) { enableAdvancedStreamFeatures(); - if (advancedStreamFeaturesAvailableListener != null) { - advancedStreamFeaturesAvailableListener.onAdvancedStreamFeaturesAvailable(account); + for(OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) { + listener.onAdvancedStreamFeaturesAvailable(account); } } } @@ -947,8 +947,10 @@ public class XmppConnection implements Runnable { this.acknowledgedListener = listener; } - public void setOnAdvancedStreamFeaturesAvailableListener(OnAdvancedStreamFeaturesAvailable listener) { - this.advancedStreamFeaturesAvailableListener = listener; + public void addOnAdvancedStreamFeaturesAvailableListener(OnAdvancedStreamFeaturesLoaded listener) { + if (!this.advancedStreamFeaturesLoadedListeners.contains(listener)) { + this.advancedStreamFeaturesLoadedListeners.add(listener); + } } public void disconnect(boolean force) { @@ -1095,6 +1097,10 @@ public class XmppConnection implements Runnable { return hasDiscoFeature(account.getServer(), "urn:xmpp:mam:0"); } + public boolean advancedStreamFeaturesLoaded() { + return disco.containsKey(account.getServer().toString()); + } + public boolean rosterVersioning() { return connection.streamFeatures != null && connection.streamFeatures.hasChild("ver"); } -- cgit v1.2.3 From ccdb0fd9717fcc79374b55e741bc03eb02fe526d Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Tue, 9 Dec 2014 21:41:49 +0100 Subject: save server id from mam messages. check for dups before adding mam --- .../eu/siacs/conversations/entities/Message.java | 29 +++++++++++++++++++--- .../siacs/conversations/parser/MessageParser.java | 9 ++++++- .../conversations/persistance/DatabaseBackend.java | 7 +++++- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 1213f66a..2cced3b3 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -45,6 +45,7 @@ public class Message extends AbstractEntity { public static String STATUS = "status"; public static String TYPE = "type"; public static String REMOTE_MSG_ID = "remoteMsgId"; + public static String SERVER_MSG_ID = "serverMsgId"; public static String RELATIVE_FILE_PATH = "relativeFilePath"; public boolean markable = false; protected String conversationUuid; @@ -59,6 +60,7 @@ public class Message extends AbstractEntity { protected String relativeFilePath; protected boolean read = true; protected String remoteMsgId = null; + protected String serverMsgId = null; protected Conversation conversation = null; protected Downloadable downloadable = null; private Message mNextMessage = null; @@ -83,13 +85,15 @@ public class Message extends AbstractEntity { status, TYPE_TEXT, null, + null, null); this.conversation = conversation; } private Message(final String uuid, final String conversationUUid, final Jid counterpart, final Jid trueCounterpart, final String body, final long timeSent, - final int encryption, final int status, final int type, final String remoteMsgId, final String relativeFilePath) { + final int encryption, final int status, final int type, final String remoteMsgId, + final String relativeFilePath, final String serverMsgId) { this.uuid = uuid; this.conversationUuid = conversationUUid; this.counterpart = counterpart; @@ -101,6 +105,7 @@ public class Message extends AbstractEntity { this.type = type; this.remoteMsgId = remoteMsgId; this.relativeFilePath = relativeFilePath; + this.serverMsgId = serverMsgId; } public static Message fromCursor(Cursor cursor) { @@ -136,7 +141,8 @@ public class Message extends AbstractEntity { cursor.getInt(cursor.getColumnIndex(STATUS)), cursor.getInt(cursor.getColumnIndex(TYPE)), cursor.getString(cursor.getColumnIndex(REMOTE_MSG_ID)), - cursor.getString(cursor.getColumnIndex(RELATIVE_FILE_PATH))); + cursor.getString(cursor.getColumnIndex(RELATIVE_FILE_PATH)), + cursor.getString(cursor.getColumnIndex(SERVER_MSG_ID))); } public static Message createStatusMessage(Conversation conversation) { @@ -168,6 +174,7 @@ public class Message extends AbstractEntity { values.put(TYPE, type); values.put(REMOTE_MSG_ID, remoteMsgId); values.put(RELATIVE_FILE_PATH, relativeFilePath); + values.put(SERVER_MSG_ID,serverMsgId); return values; } @@ -248,6 +255,14 @@ public class Message extends AbstractEntity { this.remoteMsgId = id; } + public String getServerMsgId() { + return this.serverMsgId; + } + + public void setServerMsgId(String id) { + this.serverMsgId = id; + } + public boolean isRead() { return this.read; } @@ -293,7 +308,15 @@ public class Message extends AbstractEntity { } public boolean equals(Message message) { - return (this.remoteMsgId != null) && (this.body != null) && (this.counterpart != null) && this.remoteMsgId.equals(message.getRemoteMsgId()) && this.body.equals(message.getBody()) && this.counterpart.equals(message.getCounterpart()); + if (this.serverMsgId != null && message.getServerMsgId() != null) { + return this.serverMsgId.equals(message.getServerMsgId()); + } else { + return this.body != null + && this.counterpart != null + && ((this.remoteMsgId != null && this.remoteMsgId.equals(message.getRemoteMsgId())) + || this.uuid.equals(message.getRemoteMsgId())) && this.body.equals(message.getBody()) + && this.counterpart.equals(message.getCounterpart()); + } } public Message next() { diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 3714ac90..9944f364 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -320,7 +320,14 @@ public class MessageParser extends AbstractParser implements Message finishedMessage = new Message(conversation,content,encryption,status); finishedMessage.setTime(timestamp); finishedMessage.setCounterpart(counterpart); - Log.d(Config.LOGTAG,"received mam message "+content); + finishedMessage.setRemoteMsgId(message.getAttribute("id")); + finishedMessage.setServerMsgId(result.getAttribute("id")); + if (conversation.hasDuplicateMessage(finishedMessage)) { + Log.d(Config.LOGTAG, "received mam message " + content+ " (duplicate)"); + return null; + } else { + Log.d(Config.LOGTAG, "received mam message " + content); + } return finishedMessage; } diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 55fcff2e..aa07d9c0 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -22,7 +22,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { private static DatabaseBackend instance = null; private static final String DATABASE_NAME = "history"; - private static final int DATABASE_VERSION = 11; + private static final int DATABASE_VERSION = 12; private static String CREATE_CONTATCS_STATEMENT = "create table " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " @@ -65,6 +65,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { + Message.BODY + " TEXT, " + Message.ENCRYPTION + " NUMBER, " + Message.STATUS + " NUMBER," + Message.TYPE + " NUMBER, " + Message.RELATIVE_FILE_PATH + " TEXT, " + + Message.SERVER_MSG_ID + " TEXT, " + Message.REMOTE_MSG_ID + " TEXT, FOREIGN KEY(" + Message.CONVERSATION + ") REFERENCES " + Conversation.TABLENAME + "(" + Conversation.UUID @@ -121,6 +122,10 @@ public class DatabaseBackend extends SQLiteOpenHelper { db.execSQL("delete from "+Contact.TABLENAME); db.execSQL("update "+Account.TABLENAME+" set "+Account.ROSTERVERSION+" = NULL"); } + if (oldVersion < 12 && newVersion >= 12) { + db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + + Message.SERVER_MSG_ID + " TEXT"); + } } public static synchronized DatabaseBackend getInstance(Context context) { -- cgit v1.2.3 From 1dcdc79a71ae36aadba4c8a82aded46cca9dcf61 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Tue, 9 Dec 2014 22:50:53 +0100 Subject: changed lastMessageReceived into lastMessageTransmitted to account for sent messages as well. (will trigger on sm ack) --- .../siacs/conversations/entities/Conversation.java | 18 ++++++++++------ .../siacs/conversations/parser/MessageParser.java | 2 +- .../services/MessageArchiveService.java | 8 +++++-- .../services/XmppConnectionService.java | 25 +++++++++++----------- 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 63f341e7..e254cfc2 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -45,7 +45,7 @@ public class Conversation extends AbstractEntity { public static final String ATTRIBUTE_NEXT_ENCRYPTION = "next_encryption"; public static final String ATTRIBUTE_MUC_PASSWORD = "muc_password"; public static final String ATTRIBUTE_MUTED_TILL = "muted_till"; - public static final String ATTRIBUTE_LAST_MESSAGE_RECEIVED = "last_message_received"; + public static final String ATTRIBUTE_LAST_MESSAGE_TRANSMITTED = "last_message_transmitted"; private String name; private String contactUuid; @@ -473,14 +473,18 @@ public class Conversation extends AbstractEntity { } } - public boolean setLastMessageReceived(long value) { - long before = getLastMessageReceived(); - this.setAttribute(ATTRIBUTE_LAST_MESSAGE_RECEIVED, String.valueOf(value)); - return (value - before > 1000); + public boolean setLastMessageTransmitted(long value) { + long before = getLastMessageTransmitted(); + if (value - before > 1000) { + this.setAttribute(ATTRIBUTE_LAST_MESSAGE_TRANSMITTED, String.valueOf(value)); + return true; + } else { + return false; + } } - public long getLastMessageReceived() { - long timestamp = getLongAttribute(ATTRIBUTE_LAST_MESSAGE_RECEIVED,0); + public long getLastMessageTransmitted() { + long timestamp = getLongAttribute(ATTRIBUTE_LAST_MESSAGE_TRANSMITTED,0); if (timestamp == 0) { synchronized (this.messages) { for(int i = this.messages.size() - 1; i >= 0; --i) { diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 9944f364..74d38ce4 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -557,7 +557,7 @@ public class MessageParser extends AbstractParser implements Conversation conversation = message.getConversation(); conversation.add(message); if (account.getXmppConnection() != null && account.getXmppConnection().getFeatures().advancedStreamFeaturesLoaded()) { - if (conversation.setLastMessageReceived(System.currentTimeMillis())) { + if (conversation.setLastMessageTransmitted(System.currentTimeMillis())) { mXmppConnectionService.updateConversation(conversation); } } diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index c77262cb..c93a6e75 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -28,7 +28,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { public void query(final Conversation conversation) { synchronized (this.queries) { final Account account = conversation.getAccount(); - long start = conversation.getLastMessageReceived(); + long start = conversation.getLastMessageTransmitted(); long end = account.getXmppConnection().getLastSessionEstablished(); if (end - start >= Config.MAX_HISTORY_AGE) { start = end - Config.MAX_HISTORY_AGE; @@ -51,7 +51,11 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { synchronized (this.queries) { this.queries.remove(query); } - query.getConversation().sort(); + final Conversation conversation = query.getConversation(); + conversation.sort(); + if (conversation.setLastMessageTransmitted(query.getEnd())) { + this.mXmppConnectionService.databaseBackend.updateConversation(conversation); + } this.mXmppConnectionService.updateConversationUi(); } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 3e2c1b8b..86b6be56 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -73,7 +73,6 @@ import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener; import eu.siacs.conversations.utils.PRNGFixes; import eu.siacs.conversations.utils.PhoneHelper; import eu.siacs.conversations.xml.Element; -import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded; import eu.siacs.conversations.xmpp.OnBindListener; import eu.siacs.conversations.xmpp.OnContactStatusChanged; import eu.siacs.conversations.xmpp.OnIqPacketReceived; @@ -257,15 +256,17 @@ public class XmppConnectionService extends Service { @Override public void onMessageAcknowledged(Account account, String uuid) { - for (Conversation conversation : getConversations()) { + for (final Conversation conversation : getConversations()) { if (conversation.getAccount() == account) { - for (Message message : conversation.getMessages()) { - if ((message.getStatus() == Message.STATUS_UNSEND || message - .getStatus() == Message.STATUS_WAITING) - && message.getUuid().equals(uuid)) { + for (final Message message : conversation.getMessages()) { + final int s = message.getStatus(); + if ((s == Message.STATUS_UNSEND || s == Message.STATUS_WAITING) && message.getUuid().equals(uuid)) { markMessage(message, Message.STATUS_SEND); + if (conversation.setLastMessageTransmitted(System.currentTimeMillis())) { + databaseBackend.updateConversation(conversation); + } return; - } + } } } } @@ -854,11 +855,11 @@ public class XmppConnectionService extends Service { break; } final Contact contact = account.getRoster() - .getContact(jid); + .getContact(jid); String systemAccount = phoneContact - .getInt("phoneid") - + "#" - + phoneContact.getString("lookup"); + .getInt("phoneid") + + "#" + + phoneContact.getString("lookup"); contact.setSystemAccount(systemAccount); contact.setPhotoUri(phoneContact .getString("photouri")); @@ -1253,7 +1254,7 @@ public class XmppConnectionService extends Service { if (conversation.getMucOptions().getPassword() != null) { x.addChild("password").setContent(conversation.getMucOptions().getPassword()); } - x.addChild("history").setAttribute("since",PresenceGenerator.getTimestamp(conversation.getLastMessageReceived())); + x.addChild("history").setAttribute("since",PresenceGenerator.getTimestamp(conversation.getLastMessageTransmitted())); String sig = account.getPgpSignature(); if (sig != null) { packet.addChild("status").setContent("online"); -- cgit v1.2.3 From f2510ae9f6598e70308b7e2a543010b1660dc876 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Wed, 10 Dec 2014 14:06:20 +0100 Subject: mark otr messages as no-store for mam --- src/main/java/eu/siacs/conversations/crypto/OtrEngine.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/eu/siacs/conversations/crypto/OtrEngine.java b/src/main/java/eu/siacs/conversations/crypto/OtrEngine.java index 642d0ed0..3894e205 100644 --- a/src/main/java/eu/siacs/conversations/crypto/OtrEngine.java +++ b/src/main/java/eu/siacs/conversations/crypto/OtrEngine.java @@ -180,6 +180,7 @@ public class OtrEngine implements OtrEngineHost { packet.setBody(body); packet.addChild("private", "urn:xmpp:carbons:2"); packet.addChild("no-copy", "urn:xmpp:hints"); + packet.addChild("no-store", "urn:xmpp:hints"); packet.setType(MessagePacket.TYPE_CHAT); account.getXmppConnection().sendMessagePacket(packet); } -- cgit v1.2.3 From b523518e4b5a98d5a30aed2ec246fc83c42f5f6c Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sat, 13 Dec 2014 12:25:52 +0100 Subject: various mam improvments --- src/main/java/eu/siacs/conversations/Config.java | 4 +- .../siacs/conversations/entities/Conversation.java | 2 + .../siacs/conversations/generator/IqGenerator.java | 7 +- .../siacs/conversations/parser/MessageParser.java | 6 +- .../services/MessageArchiveService.java | 133 ++++++++++++++++----- .../services/XmppConnectionService.java | 17 ++- 6 files changed, 130 insertions(+), 39 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index e9e73db9..c491d632 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -22,7 +22,9 @@ public final class Config { public static final boolean NO_PROXY_LOOKUP = false; //useful to debug ibb - public static final long MAX_HISTORY_AGE = 7 * 24 * 60 * 60 * 1000; + private static final long MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000; + public static final long MAX_HISTORY_AGE = 7 * MILLISECONDS_IN_DAY; + public static final long MAX_CATCHUP = MILLISECONDS_IN_DAY / 2; private Config() { diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index e254cfc2..a30847b9 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -3,6 +3,7 @@ package eu.siacs.conversations.entities; import android.content.ContentValues; import android.database.Cursor; import android.os.SystemClock; +import android.util.Log; import net.java.otr4j.OtrException; import net.java.otr4j.crypto.OtrCryptoEngineImpl; @@ -20,6 +21,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; +import eu.siacs.conversations.Config; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 56a0776f..4f87b2b0 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -1,9 +1,12 @@ package eu.siacs.conversations.generator; +import android.util.Log; + import java.util.Arrays; import java.util.Collections; import java.util.List; +import eu.siacs.conversations.Config; import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xml.Element; @@ -103,7 +106,9 @@ public class IqGenerator extends AbstractGenerator { query.setAttribute("queryid",mam.getQueryId()); Data data = new Data(); data.setFormType("urn:xmpp:mam:0"); - data.put("with",mam.getWith().toString()); + if (mam.getWith()!=null) { + data.put("with", mam.getWith().toString()); + } data.put("start",getTimestamp(mam.getStart())); data.put("end",getTimestamp(mam.getEnd())); query.addChild(data); diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 74d38ce4..cd4c6401 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -10,6 +10,7 @@ import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.xml.Element; @@ -303,16 +304,17 @@ public class MessageParser extends AbstractParser implements final long timestamp = getTimestamp(forwarded); final Jid to = message.getAttributeAsJid("to"); final Jid from = message.getAttributeAsJid("from"); + final MessageArchiveService.Query query = this.mXmppConnectionService.getMessageArchiveService().findQuery(result.getAttribute("queryid")); Jid counterpart; int status; Conversation conversation; if (from!=null && to != null && from.toBareJid().equals(account.getJid().toBareJid())) { status = Message.STATUS_SEND; - conversation = this.mXmppConnectionService.findOrCreateConversation(account,to.toBareJid(),false); + conversation = this.mXmppConnectionService.findOrCreateConversation(account,to.toBareJid(),false,query); counterpart = to; } else if (from !=null && to != null) { status = Message.STATUS_RECEIVED; - conversation = this.mXmppConnectionService.findOrCreateConversation(account,from.toBareJid(),false); + conversation = this.mXmppConnectionService.findOrCreateConversation(account,from.toBareJid(),false,query); counterpart = from; } else { return null; diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index c93a6e75..3b84d411 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -9,6 +9,8 @@ import java.util.List; import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.generator.AbstractGenerator; +import eu.siacs.conversations.parser.AbstractParser; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded; import eu.siacs.conversations.xmpp.OnIqPacketReceived; @@ -25,26 +27,69 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { this.mXmppConnectionService = service; } + public void catchup(final Account account) { + long startCatchup = getLastMessageTransmitted(account); + long endCatchup = account.getXmppConnection().getLastSessionEstablished(); + if (startCatchup == 0) { + return; + } else if (endCatchup - startCatchup >= Config.MAX_CATCHUP) { + startCatchup = endCatchup - Config.MAX_CATCHUP; + List conversations = mXmppConnectionService.getConversations(); + for (Conversation conversation : conversations) { + if (conversation.getMode() == Conversation.MODE_SINGLE && conversation.getAccount() == account && startCatchup > conversation.getLastMessageTransmitted()) { + this.query(conversation,startCatchup); + } + } + } + final Query query = new Query(account, startCatchup, endCatchup); + this.queries.add(query); + this.execute(query); + } + + private long getLastMessageTransmitted(final Account account) { + long timestamp = 0; + for(final Conversation conversation : mXmppConnectionService.getConversations()) { + if (conversation.getAccount() == account) { + long tmp = conversation.getLastMessageTransmitted(); + if (tmp > timestamp) { + timestamp = tmp; + } + } + } + return timestamp; + } + public void query(final Conversation conversation) { + query(conversation,conversation.getAccount().getXmppConnection().getLastSessionEstablished()); + } + + public void query(final Conversation conversation, long end) { synchronized (this.queries) { final Account account = conversation.getAccount(); long start = conversation.getLastMessageTransmitted(); - long end = account.getXmppConnection().getLastSessionEstablished(); - if (end - start >= Config.MAX_HISTORY_AGE) { + if (start > end) { + return; + } else if (end - start >= Config.MAX_HISTORY_AGE) { start = end - Config.MAX_HISTORY_AGE; } final Query query = new Query(conversation, start, end); this.queries.add(query); - IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(query); - this.mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() { + this.execute(query); + } + } + + private void execute(final Query query) { + Log.d(Config.LOGTAG,query.getAccount().getJid().toBareJid().toString()+": running mam query "+query.toString()); + IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(query); + this.mXmppConnectionService.sendIqPacket(query.getAccount(), packet, new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { if (packet.getType() == IqPacket.TYPE_ERROR) { + Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": error executing mam: "+packet.toString()); finalizeQuery(query); } } }); - } } private void finalizeQuery(Query query) { @@ -52,11 +97,22 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { this.queries.remove(query); } final Conversation conversation = query.getConversation(); - conversation.sort(); - if (conversation.setLastMessageTransmitted(query.getEnd())) { - this.mXmppConnectionService.databaseBackend.updateConversation(conversation); + if (conversation != null) { + conversation.sort(); + if (conversation.setLastMessageTransmitted(query.getEnd())) { + this.mXmppConnectionService.databaseBackend.updateConversation(conversation); + } + this.mXmppConnectionService.updateConversationUi(); + } else { + for(Conversation tmp : this.mXmppConnectionService.getConversations()) { + if (tmp.getAccount() == query.getAccount()) { + tmp.sort(); + if (tmp.setLastMessageTransmitted(query.getEnd())) { + this.mXmppConnectionService.databaseBackend.updateConversation(tmp); + } + } + } } - this.mXmppConnectionService.updateConversationUi(); } public void processFin(Element fin) { @@ -71,28 +127,18 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { Element set = fin.findChild("set","http://jabber.org/protocol/rsm"); Element last = set == null ? null : set.findChild("last"); if (complete || last == null) { - final Account account = query.getConversation().getAccount(); - Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": completed mam query for "+query.getWith().toString()); this.finalizeQuery(query); } else { final Query nextQuery = query.next(last == null ? null : last.getContent()); - IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(nextQuery); + this.execute(nextQuery); synchronized (this.queries) { this.queries.remove(query); this.queries.add(nextQuery); } - this.mXmppConnectionService.sendIqPacket(query.getConversation().getAccount(),packet,new OnIqPacketReceived() { - @Override - public void onIqPacketReceived(Account account, IqPacket packet) { - if (packet.getType() == IqPacket.TYPE_ERROR) { - finalizeQuery(nextQuery); - } - } - }); } } - private Query findQuery(String id) { + public Query findQuery(String id) { if (id == null) { return null; } @@ -109,36 +155,37 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { @Override public void onAdvancedStreamFeaturesAvailable(Account account) { if (account.getXmppConnection() != null && account.getXmppConnection().getFeatures().mam()) { - List conversations = mXmppConnectionService.getConversations(); - for (Conversation conversation : conversations) { - if (conversation.getMode() == Conversation.MODE_SINGLE && conversation.getAccount() == account) { - this.query(conversation); - } - } - } else { - Log.d(Config.LOGTAG,"no mam available"); + this.catchup(account); } } public class Query { private long start; private long end; - private Jid with; + private Jid with = null; private String queryId; private String after = null; + private Account account; private Conversation conversation; public Query(Conversation conversation, long start, long end) { + this(conversation.getAccount(), start, end); this.conversation = conversation; this.with = conversation.getContactJid().toBareJid(); + } + + public Query(Account account, long start, long end) { + this.account = account; this.start = start; this.end = end; this.queryId = new BigInteger(50, mXmppConnectionService.getRNG()).toString(32); } public Query next(String after) { - Query query = new Query(this.conversation,this.start,this.end); + Query query = new Query(this.account,this.start,this.end); query.after = after; + query.conversation = conversation; + query.with = with; return query; } @@ -165,5 +212,29 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { public Conversation getConversation() { return conversation; } + + public Account getAccount() { + return this.account; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("with="); + if (this.with==null) { + builder.append("*"); + } else { + builder.append(with.toString()); + } + builder.append(", start="); + builder.append(AbstractGenerator.getTimestamp(this.start)); + builder.append(", end="); + builder.append(AbstractGenerator.getTimestamp(this.end)); + if (this.after!=null) { + builder.append(", after="); + builder.append(this.after); + } + return builder.toString(); + } } } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 86b6be56..7df97f5a 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -988,8 +988,11 @@ public class XmppConnectionService extends Service { return null; } - public Conversation findOrCreateConversation(final Account account, final Jid jid, - final boolean muc) { + public Conversation findOrCreateConversation(final Account account, final Jid jid,final boolean muc) { + return this.findOrCreateConversation(account,jid,muc,null); + } + + public Conversation findOrCreateConversation(final Account account, final Jid jid,final boolean muc, final MessageArchiveService.Query query) { synchronized (this.conversations) { Conversation conversation = find(account, jid); if (conversation != null) { @@ -1023,7 +1026,13 @@ public class XmppConnectionService extends Service { } this.databaseBackend.createConversation(conversation); } - this.mMessageArchiveService.query(conversation); + if (query == null) { + this.mMessageArchiveService.query(conversation); + } else { + if (query.getConversation() == null) { + this.mMessageArchiveService.query(conversation,query.getStart()); + } + } this.conversations.add(conversation); updateConversationUi(); return conversation; @@ -1303,7 +1312,7 @@ public class XmppConnectionService extends Service { @Override public void onFailure() { - callback.error(R.string.nick_in_use,conversation); + callback.error(R.string.nick_in_use, conversation); } }); -- cgit v1.2.3 From 1ffdae80a6012bf15cedf3b6949c74687b999cfd Mon Sep 17 00:00:00 2001 From: kruks23 Date: Sat, 13 Dec 2014 13:24:17 +0100 Subject: Update spanish translations. --- src/main/res/values-es/strings.xml | 66 +++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index aad54aeb..e02c0f02 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -7,7 +7,7 @@ Gestionar cuentas Terminar conversación Detalles del contacto - Detalles de la conferencia + Detalles de conversación en grupo Conversación segura Añadir cuenta Editar contacto @@ -15,7 +15,7 @@ Añadir a contactos del teléfono Gestionar Cuentas Ajustes - Detalles de Conferencia + Detalles de Conversación en grupo Detalles del Contacto Conversations Compartir con Conversación @@ -34,7 +34,7 @@ Participante Visitante ¿Quieres eliminar a %s de tu lista? La conversación asociada a esta cuenta no se eliminará. - ¿Quieres eliminar %s de tus marcadores? La conversación de la conferencia asociada con este marcador no se eliminará. + ¿Quieres eliminar %s de tus marcadores? La conversación asociada con este marcador no se eliminará. Registrar nueva cuenta en servidor Compartir con Comenzar conversación @@ -67,8 +67,8 @@ Terminar esta conversación más tarde Selecciona recurso del contacto Enviar mensaje de texto - Enviar mensaje encriptado con OTR - Enviar mensaje encriptado con OpenPGP + Enviar mensaje cifrado con OTR + Enviar mensaje cifrado con OpenPGP Tu apodo se ha modificado Descargar imagen Archivo de imagen ofrecido para descarga @@ -84,7 +84,7 @@ Conversations no ha podido encriptar tus mensajes porque el contacto no está anunciando su clave publica.\n\nPor favor, pide a tu contacto que configure OpenPGP. Claves OpenPGP no encontradas Conversations no ha podido encriptar tus mensajes porque tus contactos no están anunciando su clave publica.\n\nPor favor, pide a tus contactos que configuren OpenPGP. - Mensaje encriptado recibido. Pulsa para ver. + Mensaje cifrado recibido. Pulsa para ver. Imagen encriptada recibida. Pulsa para ver. Imagen recibida. Pulsa para ver General @@ -99,12 +99,12 @@ Vibra cuando llega un nuevo mensaje Sonido Reproduce tono con la notificación - Notificaciones de conferencia - Siempre notifica cuando llega un mensaje de conferencia y no solo cuando llega un mensaje destacado + Notif. conversación grupo + Siempre notifica cuando llega un mensaje a una conversación en grupo y no solo cuando llega un mensaje destacado Notificaciones Carbons Deshabilita las notificaciones durante un corto periodo de tiempo después de recibir la copia del mensaje carbon Opciones avanzadas - Nunca enviar errores + Nunca informar de errores Si envías registros de error ayudas al desarrollo de Conversations Confirmar Mensajes Permitir a tus contactos saber cuando recibes y lees un mensaje @@ -171,7 +171,7 @@ Ausencia extendida No molestar Desconectado - Conferencia + Conversación en grupo Otros Miembros XEP-0280: Message Carbons XEP-0198: Stream Management @@ -187,31 +187,31 @@ Visto última vez hace 1 día Visto última vez hace %d días Nunca visto - Mensaje encriptado. Por favor instala OpenKeychain para desencriptar. + Mensaje cifrado. Por favor instala OpenKeychain para desencriptar. Huella digital OTR desconocida - Encontrado mensaje encriptado con OpenPGP + Encontrado mensaje cifrado con OpenPGP Error al recibir Tu huella digital Huella digital OTR Verificar Desencriptar - Conferencias + Convers. Grupo Buscar Crear Contacto - Unirse a Conferencia + Unirse a Conversación grupo Eliminar Contacto Ver detalles del contacto Crear El contacto ya existe Unirse - Dirección de la Conferencia - nombre@conferencia.ejemplo.com + Dirección + nombre@salas.ejemplo.com Guardar en marcadores Eliminar marcador Este marcador ya exsite - Editar asunto de la conferencia - Conferencia no encontrada + Editar asunto de la conversación + Conversación en grupo no encontrada Salir El contacto te ha añadido a su lista de contactos Añadir contacto @@ -238,19 +238,19 @@ Deshabilitar notificaciones para esta conversación Las notificaciones están deshabilitadas Habilitar - La conferencia requiere contraseña + La conversación en grupo requiere contraseña Introduce la contraseña Suscripción de actualizaciones de presencia del contacto perdida Por favor, solicita la suscripción de presencia a tu contacto primero.\n\nEsto será usado para determinar qué cliente(s) está usando tu contacto. Solicitar ahora Eliminar huella digital OTR - ¿Estás seguro que quieres eliminar esta huella digital OTR? + ¿Estás seguro de que quieres eliminar esta huella digital OTR? Ignorar Aviso: Enviando esto sin suscripción de presencia por ambas partes podría causar problemas inesperados.\n\nVerficia la suscripción de presencia en detalles del contacto. Ajustes de encriptación - Forzar encriptación end-to-end - Siempre enviar mensajes encriptados (excepto para conferencias) - No guardar mensajes encriptados + Forzar cifrado end-to-end + Siempre enviar mensajes cifrados (excepto para conversaciones en grupo) + No guardar mensajes cifrados Aviso: Esto podría llevar a pérdida de mensajes Habilitar SSL heredado Habilita soporte SSLv3 para servidores heredados. Advertencia: SSLv3 se considera no seguro. @@ -265,12 +265,12 @@ Cuando el contacto reciba el mensaje será indicado con una marca verde. Cuidado, esto podría no funcionar en todos los casos. El color del botón enviar indica el estado del contacto Otros - Nombre de conferencia - Usar el asunto de la conferencia en lugar del identificador jabber como nombre de conferencia + Nombre conversación grupo + Usar el asunto de la conversación en lugar del identificador jabber como nombre en las conversaciones en grupo ¡Huella digital OTR copiada al portapapeles! - Tu entrada a esta conferencia ha sido prohibida - Esta conferencia es solo para miembros - Has sido expulsado de esta conferencia + Tu entrada a esta conversación ha sido prohibida + Esta conversación es solo para miembros + Has sido expulsado de esta conversación Usando cuenta %s Comprobando imagen en servidor HTTP El archivo de imagen ha sido eliminado @@ -309,7 +309,7 @@ Conversations Pulsa para deshabilitar servicio en primer plano Servicio en primer plano - Mantener el servicio en primier plano previene que el sistema cierre la conexión + Mantener el servicio en primer plano previene que el sistema cierre la conexión Seleccionar archivo Recibiendo archivo %1$s (%2$d%% completado) Descargar archivo %s @@ -328,10 +328,10 @@ Mostrar etiquetas Muestra información en forma de etiquetas debajo de los contactos Habilitar notificaciones - Crear conferencia con… - No se ha encontrado el servidor de conferencias - ¡La creación de la conferencia ha fallado! - ¡Conferencia creada! + Crear conversación en grupo + No se ha encontrado el servidor para crear la conversación en grupo + ¡La creación de la conversación en grupo ha fallado! + ¡Conversación en grupo creada! ¡Secreto aceptado! Reinicializar Imagen de perfil -- cgit v1.2.3 From 2368ba518dbe16a2718de0b65470d9a7348f0bea Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sat, 13 Dec 2014 13:52:57 +0100 Subject: refactored phone contacts merger --- .../services/XmppConnectionService.java | 71 ++++++++++++---------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 2f44375e..2d5d0154 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -97,7 +97,7 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; import eu.siacs.conversations.xmpp.stanzas.PresencePacket; -public class XmppConnectionService extends Service { +public class XmppConnectionService extends Service implements OnPhoneContactsLoadedListener { public static String ACTION_CLEAR_NOTIFICATION = "clear_notification"; private static String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts"; @@ -276,6 +276,7 @@ public class XmppConnectionService extends Service { }; private LruCache mBitmapCache; private IqGenerator mIqGenerator = new IqGenerator(this); + private Thread mPhoneContactMergerThread; public PgpEngine getPgpEngine() { if (pgpServiceConnection.isBound()) { @@ -384,7 +385,7 @@ public class XmppConnectionService extends Service { public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null && intent.getAction() != null) { if (intent.getAction().equals(ACTION_MERGE_PHONE_CONTACTS)) { - mergePhoneContactsWithRoster(); + PhoneHelper.loadPhoneContacts(getApplicationContext(), this); return START_STICKY; } else if (intent.getAction().equals(Intent.ACTION_SHUTDOWN)) { logoutAndSave(); @@ -496,7 +497,7 @@ public class XmppConnectionService extends Service { this.databaseBackend.readRoster(account.getRoster()); } initConversations(); - this.mergePhoneContactsWithRoster(); + PhoneHelper.loadPhoneContacts(getApplicationContext(),this); getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, contactObserver); this.fileObserver.startWatching(); @@ -839,39 +840,43 @@ public class XmppConnectionService extends Service { sendIqPacket(account, iqPacket, null); } - private void mergePhoneContactsWithRoster() { - PhoneHelper.loadPhoneContacts(getApplicationContext(), - new OnPhoneContactsLoadedListener() { - @Override - public void onPhoneContactsLoaded(List phoneContacts) { - for (Account account : accounts) { - account.getRoster().clearSystemAccounts(); + public void onPhoneContactsLoaded(final List phoneContacts) { + if (mPhoneContactMergerThread != null) { + mPhoneContactMergerThread.interrupt(); + } + mPhoneContactMergerThread = new Thread(new Runnable() { + @Override + public void run() { + Log.d(Config.LOGTAG,"start merging phone contacts with roster"); + for (Account account : accounts) { + account.getRoster().clearSystemAccounts(); + for (Bundle phoneContact : phoneContacts) { + if (Thread.interrupted()) { + Log.d(Config.LOGTAG,"interrupted merging phone contacts"); + return; } - for (Bundle phoneContact : phoneContacts) { - for (Account account : accounts) { - Jid jid; - try { - jid = Jid.fromString(phoneContact.getString("jid")); - } catch (final InvalidJidException e) { - // TODO: Warn if contact import fails here? - break; - } - final Contact contact = account.getRoster() - .getContact(jid); - String systemAccount = phoneContact - .getInt("phoneid") - + "#" - + phoneContact.getString("lookup"); - contact.setSystemAccount(systemAccount); - contact.setPhotoUri(phoneContact - .getString("photouri")); - contact.setSystemName(phoneContact - .getString("displayname")); - getAvatarService().clear(contact); - } + Jid jid; + try { + jid = Jid.fromString(phoneContact.getString("jid")); + } catch (final InvalidJidException e) { + break; } + final Contact contact = account.getRoster() + .getContact(jid); + String systemAccount = phoneContact.getInt("phoneid") + + "#" + + phoneContact.getString("lookup"); + contact.setSystemAccount(systemAccount); + contact.setPhotoUri(phoneContact.getString("photouri")); + getAvatarService().clear(contact); + contact.setSystemName(phoneContact.getString("displayname")); } - }); + } + Log.d(Config.LOGTAG,"finished merging phone contacts"); + updateAccountUi(); + } + }); + mPhoneContactMergerThread.start(); } private void initConversations() { -- cgit v1.2.3 From 899802646cbf27622c1eef8c941a84fd60af2424 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sat, 13 Dec 2014 15:32:11 +0100 Subject: reverse through mam history when loading larger chuncks --- .../siacs/conversations/entities/Conversation.java | 6 +- .../eu/siacs/conversations/entities/Message.java | 13 ++-- .../siacs/conversations/generator/IqGenerator.java | 6 +- .../services/MessageArchiveService.java | 73 ++++++++++++++++++---- .../services/XmppConnectionService.java | 3 + 5 files changed, 79 insertions(+), 22 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index a30847b9..0b5460a8 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -567,9 +567,6 @@ public class Conversation extends AbstractEntity { public void sort() { synchronized (this.messages) { - for(Message message : this.messages) { - message.untie(); - } Collections.sort(this.messages,new Comparator() { @Override public int compare(Message left, Message right) { @@ -582,6 +579,9 @@ public class Conversation extends AbstractEntity { } } }); + for(Message message : this.messages) { + message.untie(); + } } } diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 2cced3b3..c7a92d84 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -320,8 +320,8 @@ public class Message extends AbstractEntity { } public Message next() { - if (this.mNextMessage == null) { - synchronized (this.conversation.messages) { + synchronized (this.conversation.messages) { + if (this.mNextMessage == null) { int index = this.conversation.messages.indexOf(this); if (index < 0 || index >= this.conversation.getMessages().size() - 1) { @@ -331,13 +331,14 @@ public class Message extends AbstractEntity { .get(index + 1); } } + return this.mNextMessage; } - return this.mNextMessage; } public Message prev() { - if (this.mPreviousMessage == null) { - synchronized (this.conversation.messages) { + synchronized (this.conversation.messages) { + if (this.mPreviousMessage == null) { + int index = this.conversation.messages.indexOf(this); if (index <= 0 || index > this.conversation.messages.size()) { this.mPreviousMessage = null; @@ -346,8 +347,8 @@ public class Message extends AbstractEntity { .get(index - 1); } } + return this.mPreviousMessage; } - return this.mPreviousMessage; } public boolean mergeable(final Message message) { diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 4f87b2b0..f473d1fe 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -112,8 +112,10 @@ public class IqGenerator extends AbstractGenerator { data.put("start",getTimestamp(mam.getStart())); data.put("end",getTimestamp(mam.getEnd())); query.addChild(data); - if (mam.getAfter() != null) { - query.addChild("set", "http://jabber.org/protocol/rsm").addChild("after").setContent(mam.getAfter()); + if (mam.getPagingOrder() == MessageArchiveService.PagingOrder.NORMAL) { + query.addChild("set", "http://jabber.org/protocol/rsm").addChild("after").setContent(mam.getReference()); + } else { + query.addChild("set", "http://jabber.org/protocol/rsm").addChild("before").setContent(mam.getReference()); } return packet; } diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index 3b84d411..9dfe179c 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -23,6 +23,11 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { private final HashSet queries = new HashSet(); + public enum PagingOrder { + NORMAL, + REVERSE + }; + public MessageArchiveService(final XmppConnectionService service) { this.mXmppConnectionService = service; } @@ -72,7 +77,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { } else if (end - start >= Config.MAX_HISTORY_AGE) { start = end - Config.MAX_HISTORY_AGE; } - final Query query = new Query(conversation, start, end); + final Query query = new Query(conversation, start, end,PagingOrder.REVERSE); this.queries.add(query); this.execute(query); } @@ -115,6 +120,17 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { } } + public boolean queryInProgress(Conversation conversation) { + synchronized (this.queries) { + for(Query query : queries) { + if (query.conversation == conversation) { + return true; + } + } + return false; + } + } + public void processFin(Element fin) { if (fin == null) { return; @@ -126,11 +142,19 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { boolean complete = fin.getAttributeAsBoolean("complete"); Element set = fin.findChild("set","http://jabber.org/protocol/rsm"); Element last = set == null ? null : set.findChild("last"); - if (complete || last == null) { + Element first = set == null ? null : set.findChild("first"); + Element relevant = query.getPagingOrder() == PagingOrder.NORMAL ? last : first; + if (complete || relevant == null) { this.finalizeQuery(query); } else { - final Query nextQuery = query.next(last == null ? null : last.getContent()); + final Query nextQuery; + if (query.getPagingOrder() == PagingOrder.NORMAL) { + nextQuery = query.next(last == null ? null : last.getContent()); + } else { + nextQuery = query.prev(first == null ? null : first.getContent()); + } this.execute(nextQuery); + this.finalizeQuery(query); synchronized (this.queries) { this.queries.remove(query); this.queries.add(nextQuery); @@ -164,9 +188,11 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { private long end; private Jid with = null; private String queryId; - private String after = null; + private String reference = null; private Account account; private Conversation conversation; + private PagingOrder pagingOrder = PagingOrder.NORMAL; + public Query(Conversation conversation, long start, long end) { this(conversation.getAccount(), start, end); @@ -174,6 +200,11 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { this.with = conversation.getContactJid().toBareJid(); } + public Query(Conversation conversation, long start, long end, PagingOrder order) { + this(conversation,start,end); + this.pagingOrder = order; + } + public Query(Account account, long start, long end) { this.account = account; this.start = start; @@ -181,16 +212,32 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { this.queryId = new BigInteger(50, mXmppConnectionService.getRNG()).toString(32); } - public Query next(String after) { + private Query page(String reference) { Query query = new Query(this.account,this.start,this.end); - query.after = after; + query.reference = reference; query.conversation = conversation; query.with = with; return query; } - public String getAfter() { - return after; + public Query next(String reference) { + Query query = page(reference); + query.pagingOrder = PagingOrder.NORMAL; + return query; + } + + public Query prev(String reference) { + Query query = page(reference); + query.pagingOrder = PagingOrder.REVERSE; + return query; + } + + public String getReference() { + return reference; + } + + public PagingOrder getPagingOrder() { + return this.pagingOrder; } public String getQueryId() { @@ -230,9 +277,13 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { builder.append(AbstractGenerator.getTimestamp(this.start)); builder.append(", end="); builder.append(AbstractGenerator.getTimestamp(this.end)); - if (this.after!=null) { - builder.append(", after="); - builder.append(this.after); + if (this.reference!=null) { + if (this.pagingOrder == PagingOrder.NORMAL) { + builder.append(", after="); + } else { + builder.append(", before="); + } + builder.append(this.reference); } return builder.toString(); } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 16a92d4f..43e4a377 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -956,6 +956,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } public int loadMoreMessages(Conversation conversation, long timestamp) { + if (this.getMessageArchiveService().queryInProgress(conversation)) { + return 0; + } List messages = databaseBackend.getMessages(conversation, 50, timestamp); for (Message message : messages) { -- cgit v1.2.3 From 6148f04d7b3903a956ebb8f43b612438b6424d57 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sat, 13 Dec 2014 20:05:46 +0100 Subject: fixed regression --- src/main/java/eu/siacs/conversations/generator/IqGenerator.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index f473d1fe..4819f96e 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -112,10 +112,10 @@ public class IqGenerator extends AbstractGenerator { data.put("start",getTimestamp(mam.getStart())); data.put("end",getTimestamp(mam.getEnd())); query.addChild(data); - if (mam.getPagingOrder() == MessageArchiveService.PagingOrder.NORMAL) { - query.addChild("set", "http://jabber.org/protocol/rsm").addChild("after").setContent(mam.getReference()); - } else { + if (mam.getPagingOrder() == MessageArchiveService.PagingOrder.REVERSE) { query.addChild("set", "http://jabber.org/protocol/rsm").addChild("before").setContent(mam.getReference()); + } else if (mam.getReference() != null) { + query.addChild("set", "http://jabber.org/protocol/rsm").addChild("after").setContent(mam.getReference()); } return packet; } -- cgit v1.2.3 From fc293aaede58028c73ab7f69f07c991797442f07 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sat, 13 Dec 2014 22:17:27 +0100 Subject: avoiding concurrent modification --- .../java/eu/siacs/conversations/services/XmppConnectionService.java | 4 ++-- src/main/java/eu/siacs/conversations/utils/PhoneHelper.java | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 43e4a377..048904a9 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -383,7 +383,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null && intent.getAction() != null) { if (intent.getAction().equals(ACTION_MERGE_PHONE_CONTACTS)) { - PhoneHelper.loadPhoneContacts(getApplicationContext(), this); + PhoneHelper.loadPhoneContacts(getApplicationContext(), new ArrayList(), this); return START_STICKY; } else if (intent.getAction().equals(Intent.ACTION_SHUTDOWN)) { logoutAndSave(); @@ -495,7 +495,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa this.databaseBackend.readRoster(account.getRoster()); } initConversations(); - PhoneHelper.loadPhoneContacts(getApplicationContext(),this); + PhoneHelper.loadPhoneContacts(getApplicationContext(),new ArrayList(), this); getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, contactObserver); this.fileObserver.startWatching(); diff --git a/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java b/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java index 87973159..9a5cbaaf 100644 --- a/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java @@ -16,10 +16,7 @@ import android.provider.ContactsContract.Profile; public class PhoneHelper { - public static void loadPhoneContacts(Context context, - final OnPhoneContactsLoadedListener listener) { - final List phoneContacts = new ArrayList(); - + public static void loadPhoneContacts(Context context,final List phoneContacts, final OnPhoneContactsLoadedListener listener) { final String[] PROJECTION = new String[] { ContactsContract.Data._ID, ContactsContract.Data.DISPLAY_NAME, ContactsContract.Data.PHOTO_URI, -- cgit v1.2.3 From de06cb38d190e9853e8557e07eaff1c8ba881e2a Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sun, 14 Dec 2014 18:10:46 +0100 Subject: refactored the way certain messages are being found within a conversation --- .../siacs/conversations/entities/Conversation.java | 114 ++++++++++++++-- .../eu/siacs/conversations/entities/Message.java | 10 +- .../services/XmppConnectionService.java | 151 ++++++++++----------- .../conversations/ui/ConversationActivity.java | 6 +- .../conversations/ui/ConversationFragment.java | 29 ++-- 5 files changed, 193 insertions(+), 117 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 0b5460a8..ac1343a8 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -77,6 +77,104 @@ public class Conversation extends AbstractEntity { private Bookmark bookmark; + public Message findUnsentMessageWithUuid(String uuid) { + synchronized(this.messages) { + for (final Message message : this.messages) { + final int s = message.getStatus(); + if ((s == Message.STATUS_UNSEND || s == Message.STATUS_WAITING) && message.getUuid().equals(uuid)) { + return message; + } + } + } + return null; + } + + public void findWaitingMessages(OnMessageFound onMessageFound) { + synchronized (this.messages) { + for(Message message : this.messages) { + if (message.getStatus() == Message.STATUS_WAITING) { + onMessageFound.onMessageFound(message); + } + } + } + } + + public void findMessagesWithFiles(OnMessageFound onMessageFound) { + synchronized (this.messages) { + for (Message message : this.messages) { + if ((message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) + && message.getEncryption() != Message.ENCRYPTION_PGP) { + onMessageFound.onMessageFound(message); + } + } + } + } + + public Message findMessageWithFileAndUuid(String uuid) { + synchronized (this.messages) { + for (Message message : this.messages) { + if (message.getType() == Message.TYPE_IMAGE + && message.getEncryption() != Message.ENCRYPTION_PGP + && message.getUuid().equals(uuid)) { + return message; + } + } + } + return null; + } + + public void clearMessages() { + synchronized (this.messages) { + this.messages.clear(); + } + } + + public void findUnsentMessagesWithOtrEncryption(OnMessageFound onMessageFound) { + synchronized (this.messages) { + for (Message message : this.messages) { + if ((message.getStatus() == Message.STATUS_UNSEND || message.getStatus() == Message.STATUS_WAITING) + && (message.getEncryption() == Message.ENCRYPTION_OTR)) { + onMessageFound.onMessageFound(message); + } + } + } + } + + public void findUnsentTextMessages(OnMessageFound onMessageFound) { + synchronized (this.messages) { + for (Message message : this.messages) { + if (message.getType() != Message.TYPE_IMAGE + && message.getStatus() == Message.STATUS_UNSEND) { + onMessageFound.onMessageFound(message); + } + } + } + } + + public Message findSentMessageWithUuid(String uuid) { + synchronized (this.messages) { + for (Message message : this.messages) { + if (uuid.equals(message.getUuid()) + || (message.getStatus() >= Message.STATUS_SEND && uuid + .equals(message.getRemoteMsgId()))) { + return message; + } + } + } + return null; + } + + public void populateWithMessages(List messages) { + synchronized (this.messages) { + messages.clear(); + messages.addAll(this.messages); + } + } + + public interface OnMessageFound { + public void onMessageFound(final Message message); + } + public Conversation(final String name, final Account account, final Jid contactJid, final int mode) { this(java.util.UUID.randomUUID().toString(), name, null, account @@ -103,10 +201,6 @@ public class Conversation extends AbstractEntity { } } - public List getMessages() { - return messages; - } - public boolean isRead() { return (this.messages == null) || (this.messages.size() == 0) || this.messages.get(this.messages.size() - 1).isRead(); } @@ -455,9 +549,11 @@ public class Conversation extends AbstractEntity { } public boolean hasDuplicateMessage(Message message) { - for (int i = this.getMessages().size() - 1; i >= 0; --i) { - if (this.messages.get(i).equals(message)) { - return true; + synchronized (this.messages) { + for (int i = this.messages.size() - 1; i >= 0; --i) { + if (this.messages.get(i).equals(message)) { + return true; + } } } return false; @@ -465,7 +561,7 @@ public class Conversation extends AbstractEntity { public Message findSentMessageWithBody(String body) { synchronized (this.messages) { - for (int i = this.getMessages().size() - 1; i >= 0; --i) { + for (int i = this.messages.size() - 1; i >= 0; --i) { Message message = this.messages.get(i); if ((message.getStatus() == Message.STATUS_UNSEND || message.getStatus() == Message.STATUS_SEND) && message.getBody() != null && message.getBody().equals(body)) { return message; @@ -567,7 +663,7 @@ public class Conversation extends AbstractEntity { public void sort() { synchronized (this.messages) { - Collections.sort(this.messages,new Comparator() { + Collections.sort(this.messages, new Comparator() { @Override public int compare(Message left, Message right) { if (left.getTimeSent() < right.getTimeSent()) { diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index c7a92d84..5b937138 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -323,12 +323,10 @@ public class Message extends AbstractEntity { synchronized (this.conversation.messages) { if (this.mNextMessage == null) { int index = this.conversation.messages.indexOf(this); - if (index < 0 - || index >= this.conversation.getMessages().size() - 1) { + if (index < 0 || index >= this.conversation.messages.size() - 1) { this.mNextMessage = null; } else { - this.mNextMessage = this.conversation.messages - .get(index + 1); + this.mNextMessage = this.conversation.messages.get(index + 1); } } return this.mNextMessage; @@ -338,13 +336,11 @@ public class Message extends AbstractEntity { public Message prev() { synchronized (this.conversation.messages) { if (this.mPreviousMessage == null) { - int index = this.conversation.messages.indexOf(this); if (index <= 0 || index > this.conversation.messages.size()) { this.mPreviousMessage = null; } else { - this.mPreviousMessage = this.conversation.messages - .get(index - 1); + this.mPreviousMessage = this.conversation.messages.get(index - 1); } } return this.mPreviousMessage; diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 048904a9..9b1ecdea 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -120,7 +120,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa conversation.resetOtrSession(); } if (online && (contact.getPresences().size() == 1)) { - sendUnsendMessages(conversation); + sendUnsentMessages(conversation); } } } @@ -165,7 +165,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa for (Conversation conversation : conversations) { if (conversation.getAccount() == account) { conversation.startOtrIfNeeded(); - sendUnsendMessages(conversation); + sendUnsentMessages(conversation); } } if (connection != null && connection.getFeatures().csi()) { @@ -258,14 +258,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa public void onMessageAcknowledged(Account account, String uuid) { for (final Conversation conversation : getConversations()) { if (conversation.getAccount() == account) { - for (final Message message : conversation.getMessages()) { - final int s = message.getStatus(); - if ((s == Message.STATUS_UNSEND || s == Message.STATUS_WAITING) && message.getUuid().equals(uuid)) { - markMessage(message, Message.STATUS_SEND); - if (conversation.setLastMessageTransmitted(System.currentTimeMillis())) { - databaseBackend.updateConversation(conversation); - } - return; + Message message = conversation.findUnsentMessageWithUuid(uuid); + if (message != null) { + markMessage(message, Message.STATUS_SEND); + if (conversation.setLastMessageTransmitted(System.currentTimeMillis())) { + databaseBackend.updateConversation(conversation); } } } @@ -640,12 +637,22 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { message.getConversation().endOtrIfNeeded(); - failWaitingOtrMessages(message.getConversation()); + message.getConversation().findUnsentMessagesWithOtrEncryption(new Conversation.OnMessageFound() { + @Override + public void onMessageFound(Message message) { + markMessage(message,Message.STATUS_SEND_FAILED); + } + }); packet = mMessageGenerator.generatePgpChat(message); send = true; } else { message.getConversation().endOtrIfNeeded(); - failWaitingOtrMessages(message.getConversation()); + message.getConversation().findUnsentMessagesWithOtrEncryption(new Conversation.OnMessageFound() { + @Override + public void onMessageFound(Message message) { + markMessage(message,Message.STATUS_SEND_FAILED); + } + }); packet = mMessageGenerator.generateChat(message); send = true; } @@ -688,13 +695,14 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa updateConversationUi(); } - private void sendUnsendMessages(Conversation conversation) { - for (int i = 0; i < conversation.getMessages().size(); ++i) { - int status = conversation.getMessages().get(i).getStatus(); - if (status == Message.STATUS_WAITING) { - resendMessage(conversation.getMessages().get(i)); + private void sendUnsentMessages(Conversation conversation) { + conversation.findWaitingMessages(new Conversation.OnMessageFound() { + + @Override + public void onMessageFound(Message message) { + resendMessage(message); } - } + }); } private void resendMessage(Message message) { @@ -898,28 +906,26 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } private void checkDeletedFiles(Conversation conversation) { - for (Message message : conversation.getMessages()) { - if ((message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) - && message.getEncryption() != Message.ENCRYPTION_PGP) { + conversation.findMessagesWithFiles(new Conversation.OnMessageFound() { + + @Override + public void onMessageFound(Message message) { if (!getFileBackend().isFileAvailable(message)) { message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_DELETED)); } - } - } + } + }); } private void markFileDeleted(String uuid) { for (Conversation conversation : getConversations()) { - for (Message message : conversation.getMessages()) { - if (message.getType() == Message.TYPE_IMAGE - && message.getEncryption() != Message.ENCRYPTION_PGP - && message.getUuid().equals(uuid)) { - if (!getFileBackend().isFileAvailable(message)) { - message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_DELETED)); - updateConversationUi(); - } - return; - } + Message message = conversation.findMessageWithFileAndUuid(uuid); + if (message != null) { + if (!getFileBackend().isFileAvailable(message)) { + message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_DELETED)); + updateConversationUi(); + } + return; } } } @@ -1067,12 +1073,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } - public void clearConversationHistory(Conversation conversation) { - this.databaseBackend.deleteMessagesInConversation(conversation); - conversation.getMessages().clear(); - updateConversationUi(); - } - public void createAccount(Account account) { account.initOtrEngine(this); databaseBackend.createAccount(account); @@ -1533,36 +1533,35 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } public void onOtrSessionEstablished(Conversation conversation) { - Account account = conversation.getAccount(); - List messages = conversation.getMessages(); - Session otrSession = conversation.getOtrSession(); + final Account account = conversation.getAccount(); + final Session otrSession = conversation.getOtrSession(); Log.d(Config.LOGTAG, account.getJid().toBareJid() + " otr session established with " - + conversation.getContactJid() + "/" - + otrSession.getSessionID().getUserID()); - for (Message msg : messages) { - if ((msg.getStatus() == Message.STATUS_UNSEND || msg.getStatus() == Message.STATUS_WAITING) - && (msg.getEncryption() == Message.ENCRYPTION_OTR)) { + + conversation.getContactJid() + "/" + + otrSession.getSessionID().getUserID()); + conversation.findUnsentMessagesWithOtrEncryption(new Conversation.OnMessageFound() { + + @Override + public void onMessageFound(Message message) { SessionID id = otrSession.getSessionID(); try { - msg.setCounterpart(Jid.fromString(id.getAccountID() + "/" + id.getUserID())); + message.setCounterpart(Jid.fromString(id.getAccountID() + "/" + id.getUserID())); } catch (InvalidJidException e) { - break; + return; } - if (msg.getType() == Message.TYPE_TEXT) { - MessagePacket outPacket = mMessageGenerator - .generateOtrChat(msg, true); + if (message.getType() == Message.TYPE_TEXT) { + MessagePacket outPacket = mMessageGenerator.generateOtrChat(message, true); if (outPacket != null) { - msg.setStatus(Message.STATUS_SEND); - databaseBackend.updateMessage(msg); + message.setStatus(Message.STATUS_SEND); + databaseBackend.updateMessage(message); sendMessagePacket(account, outPacket); } - } else if (msg.getType() == Message.TYPE_IMAGE || msg.getType() == Message.TYPE_FILE) { - mJingleConnectionManager.createNewConnection(msg); + } else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) { + mJingleConnectionManager.createNewConnection(message); } - } - } - updateConversationUi(); + updateConversationUi(); + } + }); } public boolean renewSymmetricKey(Conversation conversation) { @@ -1817,12 +1816,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa public void resetSendingToWaiting(Account account) { for (Conversation conversation : getConversations()) { if (conversation.getAccount() == account) { - for (Message message : conversation.getMessages()) { - if (message.getType() != Message.TYPE_IMAGE - && message.getStatus() == Message.STATUS_UNSEND) { + conversation.findUnsentTextMessages(new Conversation.OnMessageFound() { + + @Override + public void onMessageFound(Message message) { markMessage(message, Message.STATUS_WAITING); - } - } + } + }); } } } @@ -1847,15 +1847,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa if (uuid == null) { return false; } else { - for (Message message : conversation.getMessages()) { - if (uuid.equals(message.getUuid()) - || (message.getStatus() >= Message.STATUS_SEND && uuid - .equals(message.getRemoteMsgId()))) { - markMessage(message, status); - return true; - } + Message message = conversation.findSentMessageWithUuid(uuid); + if (message!=null) { + markMessage(message,status); + return true; + } else { + return false; } - return false; } } @@ -1949,15 +1947,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } - public void failWaitingOtrMessages(Conversation conversation) { - for (Message message : conversation.getMessages()) { - if (message.getEncryption() == Message.ENCRYPTION_OTR - && message.getStatus() == Message.STATUS_WAITING) { - markMessage(message, Message.STATUS_SEND_FAILED); - } - } - } - public SecureRandom getRNG() { return this.mRandom; } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index b2bf2fd8..a5efe12e 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -491,10 +491,12 @@ public class ConversationActivity extends XmppActivity implements @Override public void onClick(DialogInterface dialog, int which) { - ConversationActivity.this.xmppConnectionService - .clearConversationHistory(conversation); + conversation.clearMessages(); if (endConversationCheckBox.isChecked()) { endConversation(conversation); + } else { + updateConversationList(); + ConversationActivity.this.mConversationFragment.updateMessages(); } } }); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 0edc6b6f..7f4b5c54 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -120,8 +120,7 @@ public class ConversationFragment extends Fragment { long timestamp = ConversationFragment.this.messageList.get(0).getTimeSent(); messagesLoaded = false; int size = activity.xmppConnectionService.loadMoreMessages(conversation, timestamp); - ConversationFragment.this.messageList.clear(); - ConversationFragment.this.messageList.addAll(conversation.getMessages()); + conversation.populateWithMessages(ConversationFragment.this.messageList); updateStatusMessages(); messageListAdapter.notifyDataSetChanged(); if (size != 0) { @@ -580,25 +579,19 @@ public class ConversationFragment extends Fragment { break; } } - this.messageList.clear(); - if (this.conversation.getMessages().size() == 0) { - messagesLoaded = false; - } else { - this.messageList.addAll(this.conversation.getMessages()); - messagesLoaded = true; - for (Message message : this.messageList) { - if (message.getEncryption() == Message.ENCRYPTION_PGP - && (message.getStatus() == Message.STATUS_RECEIVED || message - .getStatus() >= Message.STATUS_SEND) - && message.getDownloadable() == null) { - if (!mEncryptedMessages.contains(message)) { - mEncryptedMessages.add(message); - } + conversation.populateWithMessages(ConversationFragment.this.messageList); + for (Message message : this.messageList) { + if (message.getEncryption() == Message.ENCRYPTION_PGP + && (message.getStatus() == Message.STATUS_RECEIVED || message + .getStatus() >= Message.STATUS_SEND) + && message.getDownloadable() == null) { + if (!mEncryptedMessages.contains(message)) { + mEncryptedMessages.add(message); } } - decryptNext(); - updateStatusMessages(); } + decryptNext(); + updateStatusMessages(); this.messageListAdapter.notifyDataSetChanged(); updateChatMsgHint(); if (!activity.isConversationsOverviewVisable() || !activity.isConversationsOverviewHideable()) { -- cgit v1.2.3 From 50410dad334643945e4978117d81dc3cbf4c3157 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sun, 14 Dec 2014 18:31:52 +0100 Subject: possible dns fixes --- src/main/java/eu/siacs/conversations/utils/DNSHelper.java | 13 +++++++++++-- .../java/eu/siacs/conversations/xmpp/XmppConnection.java | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/utils/DNSHelper.java b/src/main/java/eu/siacs/conversations/utils/DNSHelper.java index 8c1a8dea..2aa6f573 100644 --- a/src/main/java/eu/siacs/conversations/utils/DNSHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/DNSHelper.java @@ -143,12 +143,21 @@ public class DNSHelper { Bundle namePort = new Bundle(); namePort.putString("name", srv.getName()); namePort.putInt("port", srv.getPort()); + if (ips6.containsKey(srv.getName())) { + ArrayList ip = ips6.get(srv.getName()); + Collections.shuffle(ip, rnd); + namePort.putString("ip", ip.get(0)); + values.add(namePort); + } if (ips4.containsKey(srv.getName())) { ArrayList ip = ips4.get(srv.getName()); Collections.shuffle(ip, rnd); - namePort.putString("ipv4", ip.get(0)); + namePort.putString("ip", ip.get(0)); + values.add(namePort); + } + if (!ips6.containsKey(srv.getName()) && !ips4.containsKey(srv.getName())) { + values.add(namePort); } - values.add(namePort); } bundle.putParcelableArrayList("values", values); } catch (SocketTimeoutException e) { diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index af0499c6..b090d651 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -171,7 +171,7 @@ public class XmppConnection implements Runnable { srvRecordServer = ""; } int srvRecordPort = namePort.getInt("port"); - String srvIpServer = namePort.getString("ipv4"); + String srvIpServer = namePort.getString("ip"); InetSocketAddress addr; if (srvIpServer != null) { addr = new InetSocketAddress(srvIpServer, srvRecordPort); -- cgit v1.2.3 From 5cbae258084a5f77857c5f535451fe3b459ce0d1 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sun, 14 Dec 2014 19:02:29 +0100 Subject: more patches for dns helper --- .../eu/siacs/conversations/utils/DNSHelper.java | 32 +++++++++++++--------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/utils/DNSHelper.java b/src/main/java/eu/siacs/conversations/utils/DNSHelper.java index 2aa6f573..a09b4d0f 100644 --- a/src/main/java/eu/siacs/conversations/utils/DNSHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/DNSHelper.java @@ -140,23 +140,17 @@ public class DNSHelper { } ArrayList values = new ArrayList<>(); for (SRV srv : result) { - Bundle namePort = new Bundle(); - namePort.putString("name", srv.getName()); - namePort.putInt("port", srv.getPort()); + boolean added = false; if (ips6.containsKey(srv.getName())) { - ArrayList ip = ips6.get(srv.getName()); - Collections.shuffle(ip, rnd); - namePort.putString("ip", ip.get(0)); - values.add(namePort); + values.add(createNamePortBundle(srv.getName(),srv.getPort(),ips6)); + added = true; } if (ips4.containsKey(srv.getName())) { - ArrayList ip = ips4.get(srv.getName()); - Collections.shuffle(ip, rnd); - namePort.putString("ip", ip.get(0)); - values.add(namePort); + values.add(createNamePortBundle(srv.getName(),srv.getPort(),ips4)); + added = true; } - if (!ips6.containsKey(srv.getName()) && !ips4.containsKey(srv.getName())) { - values.add(namePort); + if (!added) { + values.add(createNamePortBundle(srv.getName(),srv.getPort(),null)); } } bundle.putParcelableArrayList("values", values); @@ -168,6 +162,18 @@ public class DNSHelper { return bundle; } + private static Bundle createNamePortBundle(String name, int port, TreeMap> ips) { + Bundle namePort = new Bundle(); + namePort.putString("name", name); + namePort.putInt("port", port); + if (ips!=null) { + ArrayList ip = ips.get(name); + Collections.shuffle(ip, new Random()); + namePort.putString("ip", ip.get(0)); + } + return namePort; + } + final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); public static String bytesToHex(byte[] bytes) { -- cgit v1.2.3 From a6d4b0aec5ab5d8df887e7e0aefaaeef7c42a8b9 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Sun, 14 Dec 2014 02:02:17 -0500 Subject: Add quiet hours feature --- .../services/NotificationService.java | 75 ++++++++++------ .../eu/siacs/conversations/ui/TimePreference.java | 99 ++++++++++++++++++++++ src/main/res/values/strings.xml | 6 ++ src/main/res/xml/preferences.xml | 25 +++++- 4 files changed, 176 insertions(+), 29 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/ui/TimePreference.java diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index f649f9d4..69df87fb 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -19,6 +19,7 @@ import android.util.DisplayMetrics; import java.io.FileNotFoundException; import java.util.ArrayList; +import java.util.Calendar; import java.util.LinkedHashMap; import java.util.List; import java.util.regex.Matcher; @@ -33,12 +34,13 @@ import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.ui.ConversationActivity; import eu.siacs.conversations.ui.ManageAccountActivity; +import eu.siacs.conversations.ui.TimePreference; public class NotificationService { private XmppConnectionService mXmppConnectionService; - private LinkedHashMap> notifications = new LinkedHashMap>(); + private final LinkedHashMap> notifications = new LinkedHashMap<>(); public static int NOTIFICATION_ID = 0x2342; public static int FOREGROUND_NOTIFICATION_ID = 0x8899; @@ -54,18 +56,39 @@ public class NotificationService { public boolean notify(Message message) { return (message.getStatus() == Message.STATUS_RECEIVED) - && notificationsEnabled() - && !message.getConversation().isMuted() - && (message.getConversation().getMode() == Conversation.MODE_SINGLE + && notificationsEnabled() + && !isQuietHours() + && !message.getConversation().isMuted() + && (message.getConversation().getMode() == Conversation.MODE_SINGLE || conferenceNotificationsEnabled() || wasHighlightedOrPrivate(message) - ); + ); } public boolean notificationsEnabled() { return mXmppConnectionService.getPreferences().getBoolean("show_notification", true); } + public boolean isQuietHours() { + if (!mXmppConnectionService.getPreferences().getBoolean("enable_quiet_hours", false)) { + return false; + } + final Calendar startTime = Calendar.getInstance(); + startTime.setTimeInMillis(mXmppConnectionService.getPreferences().getLong("quiet_hours_start", TimePreference.DEFAULT_VALUE)); + final Calendar endTime = Calendar.getInstance(); + endTime.setTimeInMillis(mXmppConnectionService.getPreferences().getLong("quiet_hours_end", TimePreference.DEFAULT_VALUE)); + final Calendar nowTime = Calendar.getInstance(); + + startTime.set(nowTime.get(Calendar.YEAR), nowTime.get(Calendar.MONTH), nowTime.get(Calendar.DATE)); + endTime.set(nowTime.get(Calendar.YEAR), nowTime.get(Calendar.MONTH), nowTime.get(Calendar.DATE)); + + if (endTime.before(startTime)) { + endTime.add(Calendar.DATE, 1); + } + + return nowTime.after(startTime) && nowTime.before(endTime); + } + public boolean conferenceNotificationsEnabled() { return mXmppConnectionService.getPreferences().getBoolean("always_notify_in_conference", false); } @@ -75,19 +98,19 @@ public class NotificationService { return; } PowerManager pm = (PowerManager) mXmppConnectionService - .getSystemService(Context.POWER_SERVICE); + .getSystemService(Context.POWER_SERVICE); boolean isScreenOn = pm.isScreenOn(); if (this.mIsInForeground && isScreenOn && this.mOpenConversation == message.getConversation()) { return; - } + } synchronized (notifications) { String conversationUuid = message.getConversationUuid(); if (notifications.containsKey(conversationUuid)) { notifications.get(conversationUuid).add(message); } else { - ArrayList mList = new ArrayList(); + ArrayList mList = new ArrayList<>(); mList.add(message); notifications.put(conversationUuid, mList); } @@ -115,7 +138,7 @@ public class NotificationService { private void updateNotification(boolean notify) { NotificationManager notificationManager = (NotificationManager) mXmppConnectionService - .getSystemService(Context.NOTIFICATION_SERVICE); + .getSystemService(Context.NOTIFICATION_SERVICE); SharedPreferences preferences = mXmppConnectionService.getPreferences(); String ringtone = preferences.getString("notification_ringtone", null); @@ -167,7 +190,7 @@ public class NotificationService { conversation = messages.get(0).getConversation(); String name = conversation.getName(); style.addLine(Html.fromHtml("" + name + " " - + getReadableBody(messages.get(0)))); + + getReadableBody(messages.get(0)))); names.append(name); names.append(", "); } @@ -183,7 +206,7 @@ public class NotificationService { mBuilder.setStyle(style); if (conversation != null) { mBuilder.setContentIntent(createContentIntent(conversation - .getUuid())); + .getUuid())); } return mBuilder; } @@ -204,23 +227,23 @@ public class NotificationService { modifyForTextOnly(mBuilder, messages, notify); } mBuilder.setContentIntent(createContentIntent(conversation - .getUuid())); + .getUuid())); } return mBuilder; } private void modifyForImage(Builder builder, Message message, - ArrayList messages, boolean notify) { + ArrayList messages, boolean notify) { try { Bitmap bitmap = mXmppConnectionService.getFileBackend() - .getThumbnail(message, getPixel(288), false); - ArrayList tmp = new ArrayList(); + .getThumbnail(message, getPixel(288), false); + ArrayList tmp = new ArrayList<>(); for (Message msg : messages) { if (msg.getType() == Message.TYPE_TEXT && msg.getDownloadable() == null) { tmp.add(msg); - } + } } BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle(); bigPictureStyle.bigPicture(bitmap); @@ -237,7 +260,7 @@ public class NotificationService { } private void modifyForTextOnly(Builder builder, - ArrayList messages, boolean notify) { + ArrayList messages, boolean notify) { builder.setStyle(new NotificationCompat.BigTextStyle() .bigText(getMergedBodies(messages))); builder.setContentText(getReadableBody(messages.get(0))); @@ -252,7 +275,7 @@ public class NotificationService { && message.getDownloadable() == null && message.getEncryption() != Message.ENCRYPTION_PGP) { return message; - } + } } return null; } @@ -271,7 +294,7 @@ public class NotificationService { private String getReadableBody(Message message) { if (message.getDownloadable() != null && (message.getDownloadable().getStatus() == Downloadable.STATUS_OFFER || message - .getDownloadable().getStatus() == Downloadable.STATUS_OFFER_CHECK_FILESIZE)) { + .getDownloadable().getStatus() == Downloadable.STATUS_OFFER_CHECK_FILESIZE)) { if (message.getType() == Message.TYPE_FILE) { return mXmppConnectionService.getString(R.string.file_offered_for_download); } else { @@ -283,13 +306,13 @@ public class NotificationService { R.string.encrypted_message_received).toString(); } else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { return mXmppConnectionService.getText(R.string.decryption_failed) - .toString(); + .toString(); } else if (message.getType() == Message.TYPE_FILE) { DownloadableFile file = mXmppConnectionService.getFileBackend().getFile(message); return mXmppConnectionService.getString(R.string.file,file.getMimeType()); } else if (message.getType() == Message.TYPE_IMAGE) { return mXmppConnectionService.getText(R.string.image_file) - .toString(); + .toString(); } else { return message.getBody().trim(); } @@ -297,7 +320,7 @@ public class NotificationService { private PendingIntent createContentIntent(String conversationUuid) { TaskStackBuilder stackBuilder = TaskStackBuilder - .create(mXmppConnectionService); + .create(mXmppConnectionService); stackBuilder.addParentStack(ConversationActivity.class); Intent viewConversationIntent = new Intent(mXmppConnectionService, @@ -311,9 +334,7 @@ public class NotificationService { stackBuilder.addNextIntent(viewConversationIntent); - PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, - PendingIntent.FLAG_UPDATE_CURRENT); - return resultPendingIntent; + return stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); } private PendingIntent createDeleteIntent() { @@ -360,7 +381,7 @@ public class NotificationService { private int getPixel(int dp) { DisplayMetrics metrics = mXmppConnectionService.getResources() - .getDisplayMetrics(); + .getDisplayMetrics(); return ((int) (dp * metrics.density)); } @@ -370,7 +391,7 @@ public class NotificationService { private boolean inMiniGracePeriod(Account account) { int miniGrace = account.getStatus() == Account.State.ONLINE ? Config.MINI_GRACE_PERIOD - : Config.MINI_GRACE_PERIOD * 2; + : Config.MINI_GRACE_PERIOD * 2; return SystemClock.elapsedRealtime() < (this.mLastNotification + miniGrace); } diff --git a/src/main/java/eu/siacs/conversations/ui/TimePreference.java b/src/main/java/eu/siacs/conversations/ui/TimePreference.java new file mode 100644 index 00000000..44a36224 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/TimePreference.java @@ -0,0 +1,99 @@ +package eu.siacs.conversations.ui; + +import android.content.Context; +import android.content.res.TypedArray; +import android.preference.DialogPreference; +import android.util.AttributeSet; +import android.view.View; +import android.widget.TimePicker; + +import java.text.DateFormat; +import java.util.Calendar; +import java.util.Date; + +public class TimePreference extends DialogPreference { + private TimePicker picker = null; + public final static long DEFAULT_VALUE = 0; + + public TimePreference(final Context context, final AttributeSet attrs) { + super(context, attrs, 0); + } + + protected void setTime(final long time) { + persistLong(time); + notifyDependencyChange(shouldDisableDependents()); + notifyChanged(); + } + + protected void updateSummary() { + final long time = getPersistedLong(DEFAULT_VALUE); + final DateFormat dateFormat = android.text.format.DateFormat.getTimeFormat(getContext()); + final Date date = new Date(time); + setSummary(dateFormat.format(date.getTime())); + } + + @Override + protected View onCreateDialogView() { + picker = new TimePicker(getContext()); + picker.setIs24HourView(android.text.format.DateFormat.is24HourFormat(getContext())); + return picker; + } + + protected Calendar getPersistedTime() { + final Calendar c = Calendar.getInstance(); + c.setTimeInMillis(getPersistedLong(DEFAULT_VALUE)); + + return c; + } + + @SuppressWarnings("NullableProblems") + @Override + protected void onBindDialogView(final View v) { + super.onBindDialogView(v); + final Calendar c = getPersistedTime(); + + picker.setCurrentHour(c.get(Calendar.HOUR_OF_DAY)); + picker.setCurrentMinute(c.get(Calendar.MINUTE)); + } + + @Override + protected void onDialogClosed(final boolean positiveResult) { + super.onDialogClosed(positiveResult); + + if (positiveResult) { + final Calendar c = Calendar.getInstance(); + c.set(Calendar.MINUTE, picker.getCurrentMinute()); + c.set(Calendar.HOUR_OF_DAY, picker.getCurrentHour()); + + + if (!callChangeListener(c.getTimeInMillis())) { + return; + } + + setTime(c.getTimeInMillis()); + updateSummary(); + } + } + + @Override + protected Object onGetDefaultValue(final TypedArray a, final int index) { + return a.getInteger(index, 0); + } + + @Override + protected void onSetInitialValue(final boolean restorePersistedValue, final Object defaultValue) { + long time; + if (defaultValue == null) { + time = restorePersistedValue ? getPersistedLong(DEFAULT_VALUE) : DEFAULT_VALUE; + } else if (defaultValue instanceof Long) { + time = restorePersistedValue ? getPersistedLong((Long) defaultValue) : (Long) defaultValue; + } else if (defaultValue instanceof Calendar) { + time = restorePersistedValue ? getPersistedLong(((Calendar)defaultValue).getTimeInMillis()) : ((Calendar)defaultValue).getTimeInMillis(); + } else { + time = restorePersistedValue ? getPersistedLong(DEFAULT_VALUE) : DEFAULT_VALUE; + } + + setTime(time); + updateSummary(); + } +} diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 6b639452..02be6348 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -41,6 +41,7 @@ Invite Contact Contacts Cancel + Set Add Edit Delete @@ -282,6 +283,11 @@ \n\nhttps://developer.android.com/tools/support-library\n(Apache License, Version 2.0) \n\nhttps://github.com/zxing/zxing\n(Apache License, Version 2.0) + Quiet Hours + Start time + End time + Enable quiet hours + Notifications will be silenced during quiet hours Increase font size Use larger font sizes across the entire app Send button indicates status diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml index f927d915..9974f14d 100644 --- a/src/main/res/xml/preferences.xml +++ b/src/main/res/xml/preferences.xml @@ -35,7 +35,29 @@ android:key="show_notification" android:summary="@string/pref_notifications_summary" android:title="@string/pref_notifications" /> - + + + + + - -- cgit v1.2.3 From f8a496a5f1e225585d0ecaec68fb81e8cffa3083 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sun, 14 Dec 2014 23:23:32 +0100 Subject: run mam queries only when online --- .../services/MessageArchiveService.java | 34 +++++++++++++++++++--- .../services/XmppConnectionService.java | 1 + 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index 9dfe179c..fe1871ea 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -3,7 +3,9 @@ package eu.siacs.conversations.services; import android.util.Log; import java.math.BigInteger; +import java.util.ArrayList; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import eu.siacs.conversations.Config; @@ -22,6 +24,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { private final XmppConnectionService mXmppConnectionService; private final HashSet queries = new HashSet(); + private ArrayList pendingQueries = new ArrayList(); public enum PagingOrder { NORMAL, @@ -83,18 +86,41 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { } } + public void executePendingQueries(final Account account) { + List pending = new ArrayList<>(); + synchronized(this.pendingQueries) { + for(Iterator iterator = this.pendingQueries.iterator(); iterator.hasNext();) { + Query query = iterator.next(); + if (query.getAccount() == account) { + pending.add(query); + iterator.remove(); + } + } + } + for(Query query : pending) { + this.execute(query); + } + } + private void execute(final Query query) { - Log.d(Config.LOGTAG,query.getAccount().getJid().toBareJid().toString()+": running mam query "+query.toString()); - IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(query); - this.mXmppConnectionService.sendIqPacket(query.getAccount(), packet, new OnIqPacketReceived() { + final Account account= query.getAccount(); + if (account.getStatus() == Account.State.ONLINE) { + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": running mam query " + query.toString()); + IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(query); + this.mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { if (packet.getType() == IqPacket.TYPE_ERROR) { - Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": error executing mam: "+packet.toString()); + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": error executing mam: " + packet.toString()); finalizeQuery(query); } } }); + } else { + synchronized (this.pendingQueries) { + this.pendingQueries.add(query); + } + } } private void finalizeQuery(Query query) { diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 9b1ecdea..b7ca699c 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -160,6 +160,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa for (Conversation conversation : account.pendingConferenceJoins) { joinMuc(conversation); } + mMessageArchiveService.executePendingQueries(account); mJingleConnectionManager.cancelInTransmission(); List conversations = getConversations(); for (Conversation conversation : conversations) { -- cgit v1.2.3 From 9f6537acdcdd3f426f7bf05e5a4a54618c98f5c7 Mon Sep 17 00:00:00 2001 From: drizzt Date: Mon, 15 Dec 2014 14:19:18 +0100 Subject: fixed typo in italian translation s/gallaria/galleria/ --- src/main/res/values-it/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml index dab7471d..703dab9d 100644 --- a/src/main/res/values-it/strings.xml +++ b/src/main/res/values-it/strings.xml @@ -217,7 +217,7 @@ Add back %s ha letto fino a questo punto Pubblica - Tocca l\'avatar per selezionare l\'immagine dalla gallaria + Tocca l\'avatar per selezionare l\'immagine dalla galleria Nota bene: tutti i contatti sottoscritti agli aggiornamenti della tua presenza avranno il permesso di vedere questa immagine. Pubblicazione… Il server ha rifiutato la tua pubblicazione -- cgit v1.2.3 From 209e62d68be4cbc1514928730095c2576f2cf41a Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Mon, 15 Dec 2014 16:55:38 +0100 Subject: avoid npe on weird platform bugs --- .../conversations/ui/adapter/MessageAdapter.java | 60 +++++++++++----------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index 32062699..478586b9 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -268,7 +268,7 @@ public class MessageAdapter extends ArrayAdapter { @Override public void onClick(View v) { - startDonwloadable(message); + startDownloadable(message); } }); viewHolder.download_button.setOnLongClickListener(openContextMenu); @@ -284,7 +284,7 @@ public class MessageAdapter extends ArrayAdapter { @Override public void onClick(View v) { - openDonwloadable(file); + openDownloadable(file); } }); viewHolder.download_button.setOnLongClickListener(openContextMenu); @@ -438,6 +438,8 @@ public class MessageAdapter extends ArrayAdapter { } view.setLayoutParams(view.getLayoutParams()); return view; + } else if (viewHolder.messageBody == null || viewHolder.image == null) { + return view; //avoiding weird platform bugs } else if (type == RECEIVED) { Contact contact = message.getContact(); if (contact != null) { @@ -446,38 +448,36 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(getDisplayedMucCounterpart(message.getCounterpart()), activity.getPixel(48))); } - } else if (type == SENT && viewHolder.contact_picture != null) { + } else if (type == SENT) { viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(account, activity.getPixel(48))); } - if (viewHolder != null && viewHolder.contact_picture != null) { - viewHolder.contact_picture - .setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - if (MessageAdapter.this.mOnContactPictureClickedListener != null) { - MessageAdapter.this.mOnContactPictureClickedListener - .onContactPictureClicked(message); - } + viewHolder.contact_picture + .setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (MessageAdapter.this.mOnContactPictureClickedListener != null) { + MessageAdapter.this.mOnContactPictureClickedListener + .onContactPictureClicked(message); } - }); - viewHolder.contact_picture - .setOnLongClickListener(new OnLongClickListener() { - - @Override - public boolean onLongClick(View v) { - if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) { - MessageAdapter.this.mOnContactPictureLongClickedListener - .onContactPictureLongClicked(message); - return true; - } else { - return false; - } + + } + }); + viewHolder.contact_picture + .setOnLongClickListener(new OnLongClickListener() { + + @Override + public boolean onLongClick(View v) { + if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) { + MessageAdapter.this.mOnContactPictureLongClickedListener + .onContactPictureLongClicked(message); + return true; + } else { + return false; } - }); - } + } + }); if (message.getDownloadable() != null && message.getDownloadable().getStatus() != Downloadable.STATUS_UPLOADING) { Downloadable d = message.getDownloadable(); @@ -546,7 +546,7 @@ public class MessageAdapter extends ArrayAdapter { return view; } - public void startDonwloadable(Message message) { + public void startDownloadable(Message message) { Downloadable downloadable = message.getDownloadable(); if (downloadable != null) { if (!downloadable.start()) { @@ -556,7 +556,7 @@ public class MessageAdapter extends ArrayAdapter { } } - public void openDonwloadable(DownloadableFile file) { + public void openDownloadable(DownloadableFile file) { if (!file.exists()) { Toast.makeText(activity,R.string.file_deleted,Toast.LENGTH_SHORT).show(); return; -- cgit v1.2.3 From 2bd4621245dfcf1a64f68e1c3d1ae82e44cbe4b9 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Mon, 15 Dec 2014 17:14:27 +0100 Subject: fixed history deletion. fixed #780 --- .../eu/siacs/conversations/services/XmppConnectionService.java | 10 ++++++++++ .../java/eu/siacs/conversations/ui/ConversationActivity.java | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index b7ca699c..ef93dcc7 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -2086,6 +2086,16 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } + public void clearConversationHistory(final Conversation conversation) { + conversation.clearMessages(); + new Thread(new Runnable() { + @Override + public void run() { + databaseBackend.deleteMessagesInConversation(conversation); + } + }).start(); + } + public interface OnConversationUpdate { public void onConversationUpdate(); } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index a5efe12e..6656de2b 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -491,7 +491,7 @@ public class ConversationActivity extends XmppActivity implements @Override public void onClick(DialogInterface dialog, int which) { - conversation.clearMessages(); + ConversationActivity.this.xmppConnectionService.clearConversationHistory(conversation); if (endConversationCheckBox.isChecked()) { endConversation(conversation); } else { -- cgit v1.2.3 From af0f8e87bba814039208fb7e7f591b7cfe36044e Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Mon, 15 Dec 2014 11:20:22 -0500 Subject: Make silent notification when quiet hours are on Notify, just don't play a sound or vibrate Also make the Java annoyingly verbose... I can't help myself... ahh! --- .../services/NotificationService.java | 132 ++++++++++----------- 1 file changed, 64 insertions(+), 68 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index 69df87fb..e13ef1b3 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -54,10 +54,9 @@ public class NotificationService { this.mXmppConnectionService = service; } - public boolean notify(Message message) { + public boolean notify(final Message message) { return (message.getStatus() == Message.STATUS_RECEIVED) && notificationsEnabled() - && !isQuietHours() && !message.getConversation().isMuted() && (message.getConversation().getMode() == Conversation.MODE_SINGLE || conferenceNotificationsEnabled() @@ -93,28 +92,28 @@ public class NotificationService { return mXmppConnectionService.getPreferences().getBoolean("always_notify_in_conference", false); } - public void push(Message message) { + public void push(final Message message) { if (!notify(message)) { return; } - PowerManager pm = (PowerManager) mXmppConnectionService + final PowerManager pm = (PowerManager) mXmppConnectionService .getSystemService(Context.POWER_SERVICE); - boolean isScreenOn = pm.isScreenOn(); + final boolean isScreenOn = pm.isScreenOn(); if (this.mIsInForeground && isScreenOn && this.mOpenConversation == message.getConversation()) { return; } synchronized (notifications) { - String conversationUuid = message.getConversationUuid(); + final String conversationUuid = message.getConversationUuid(); if (notifications.containsKey(conversationUuid)) { notifications.get(conversationUuid).add(message); } else { - ArrayList mList = new ArrayList<>(); + final ArrayList mList = new ArrayList<>(); mList.add(message); notifications.put(conversationUuid, mList); } - Account account = message.getConversation().getAccount(); + final Account account = message.getConversation().getAccount(); updateNotification((!(this.mIsInForeground && this.mOpenConversation == null) || !isScreenOn) && !account.inGracePeriod() && !this.inMiniGracePeriod(account)); @@ -129,21 +128,20 @@ public class NotificationService { } } - public void clear(Conversation conversation) { + public void clear(final Conversation conversation) { synchronized (notifications) { notifications.remove(conversation.getUuid()); updateNotification(false); } } - private void updateNotification(boolean notify) { - NotificationManager notificationManager = (NotificationManager) mXmppConnectionService + private void updateNotification(final boolean notify) { + final NotificationManager notificationManager = (NotificationManager) mXmppConnectionService .getSystemService(Context.NOTIFICATION_SERVICE); - SharedPreferences preferences = mXmppConnectionService.getPreferences(); + final SharedPreferences preferences = mXmppConnectionService.getPreferences(); - String ringtone = preferences.getString("notification_ringtone", null); - boolean vibrate = preferences.getBoolean("vibrate_on_notification", - true); + final String ringtone = preferences.getString("notification_ringtone", null); + final boolean vibrate = preferences.getBoolean("vibrate_on_notification", true); if (notifications.size() == 0) { notificationManager.cancel(NOTIFICATION_ID); @@ -151,16 +149,16 @@ public class NotificationService { if (notify) { this.markLastNotification(); } - Builder mBuilder; + final Builder mBuilder; if (notifications.size() == 1) { mBuilder = buildSingleConversations(notify); } else { mBuilder = buildMultipleConversation(); } - if (notify) { + if (notify && !isQuietHours()) { if (vibrate) { - int dat = 70; - long[] pattern = {0, 3 * dat, dat, dat}; + final int dat = 70; + final long[] pattern = {0, 3 * dat, dat, dat}; mBuilder.setVibrate(pattern); } if (ringtone != null) { @@ -170,20 +168,20 @@ public class NotificationService { mBuilder.setSmallIcon(R.drawable.ic_notification); mBuilder.setDeleteIntent(createDeleteIntent()); mBuilder.setLights(0xffffffff, 2000, 4000); - Notification notification = mBuilder.build(); + final Notification notification = mBuilder.build(); notificationManager.notify(NOTIFICATION_ID, notification); } } private Builder buildMultipleConversation() { - Builder mBuilder = new NotificationCompat.Builder( + final Builder mBuilder = new NotificationCompat.Builder( mXmppConnectionService); NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle(); style.setBigContentTitle(notifications.size() + " " + mXmppConnectionService .getString(R.string.unread_conversations)); - StringBuilder names = new StringBuilder(); + final StringBuilder names = new StringBuilder(); Conversation conversation = null; for (ArrayList messages : notifications.values()) { if (messages.size() > 0) { @@ -211,16 +209,16 @@ public class NotificationService { return mBuilder; } - private Builder buildSingleConversations(boolean notify) { - Builder mBuilder = new NotificationCompat.Builder( + private Builder buildSingleConversations(final boolean notify) { + final Builder mBuilder = new NotificationCompat.Builder( mXmppConnectionService); - ArrayList messages = notifications.values().iterator().next(); + final ArrayList messages = notifications.values().iterator().next(); if (messages.size() >= 1) { - Conversation conversation = messages.get(0).getConversation(); + final Conversation conversation = messages.get(0).getConversation(); mBuilder.setLargeIcon(mXmppConnectionService.getAvatarService() .get(conversation, getPixel(64))); mBuilder.setContentTitle(conversation.getName()); - Message message; + final Message message; if ((message = getImage(messages)) != null) { modifyForImage(mBuilder, message, messages, notify); } else { @@ -230,22 +228,21 @@ public class NotificationService { .getUuid())); } return mBuilder; - } - private void modifyForImage(Builder builder, Message message, - ArrayList messages, boolean notify) { + private void modifyForImage(final Builder builder, final Message message, + final ArrayList messages, final boolean notify) { try { - Bitmap bitmap = mXmppConnectionService.getFileBackend() + final Bitmap bitmap = mXmppConnectionService.getFileBackend() .getThumbnail(message, getPixel(288), false); - ArrayList tmp = new ArrayList<>(); - for (Message msg : messages) { + final ArrayList tmp = new ArrayList<>(); + for (final Message msg : messages) { if (msg.getType() == Message.TYPE_TEXT && msg.getDownloadable() == null) { tmp.add(msg); } } - BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle(); + final BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle(); bigPictureStyle.bigPicture(bitmap); if (tmp.size() > 0) { bigPictureStyle.setSummaryText(getMergedBodies(tmp)); @@ -254,13 +251,13 @@ public class NotificationService { builder.setContentText(mXmppConnectionService.getString(R.string.image_file)); } builder.setStyle(bigPictureStyle); - } catch (FileNotFoundException e) { + } catch (final FileNotFoundException e) { modifyForTextOnly(builder, messages, notify); } } - private void modifyForTextOnly(Builder builder, - ArrayList messages, boolean notify) { + private void modifyForTextOnly(final Builder builder, + final ArrayList messages, final boolean notify) { builder.setStyle(new NotificationCompat.BigTextStyle() .bigText(getMergedBodies(messages))); builder.setContentText(getReadableBody(messages.get(0))); @@ -269,8 +266,8 @@ public class NotificationService { } } - private Message getImage(ArrayList messages) { - for (Message message : messages) { + private Message getImage(final ArrayList messages) { + for (final Message message : messages) { if (message.getType() == Message.TYPE_IMAGE && message.getDownloadable() == null && message.getEncryption() != Message.ENCRYPTION_PGP) { @@ -280,8 +277,8 @@ public class NotificationService { return null; } - private String getMergedBodies(ArrayList messages) { - StringBuilder text = new StringBuilder(); + private String getMergedBodies(final ArrayList messages) { + final StringBuilder text = new StringBuilder(); for (int i = 0; i < messages.size(); ++i) { text.append(getReadableBody(messages.get(i))); if (i != messages.size() - 1) { @@ -291,7 +288,7 @@ public class NotificationService { return text.toString(); } - private String getReadableBody(Message message) { + private String getReadableBody(final Message message) { if (message.getDownloadable() != null && (message.getDownloadable().getStatus() == Downloadable.STATUS_OFFER || message .getDownloadable().getStatus() == Downloadable.STATUS_OFFER_CHECK_FILESIZE)) { @@ -318,15 +315,15 @@ public class NotificationService { } } - private PendingIntent createContentIntent(String conversationUuid) { - TaskStackBuilder stackBuilder = TaskStackBuilder + private PendingIntent createContentIntent(final String conversationUuid) { + final TaskStackBuilder stackBuilder = TaskStackBuilder .create(mXmppConnectionService); stackBuilder.addParentStack(ConversationActivity.class); - Intent viewConversationIntent = new Intent(mXmppConnectionService, + final Intent viewConversationIntent = new Intent(mXmppConnectionService, ConversationActivity.class); viewConversationIntent.setAction(Intent.ACTION_VIEW); - if (conversationUuid!=null) { + if (conversationUuid != null) { viewConversationIntent.putExtra(ConversationActivity.CONVERSATION, conversationUuid); viewConversationIntent.setType(ConversationActivity.VIEW_CONVERSATION); @@ -338,30 +335,30 @@ public class NotificationService { } private PendingIntent createDeleteIntent() { - Intent intent = new Intent(mXmppConnectionService, + final Intent intent = new Intent(mXmppConnectionService, XmppConnectionService.class); intent.setAction(XmppConnectionService.ACTION_CLEAR_NOTIFICATION); return PendingIntent.getService(mXmppConnectionService, 0, intent, 0); } private PendingIntent createDisableForeground() { - Intent intent = new Intent(mXmppConnectionService, + final Intent intent = new Intent(mXmppConnectionService, XmppConnectionService.class); intent.setAction(XmppConnectionService.ACTION_DISABLE_FOREGROUND); return PendingIntent.getService(mXmppConnectionService, 0, intent, 0); } - private boolean wasHighlightedOrPrivate(Message message) { - String nick = message.getConversation().getMucOptions().getActualNick(); - Pattern highlight = generateNickHighlightPattern(nick); + private boolean wasHighlightedOrPrivate(final Message message) { + final String nick = message.getConversation().getMucOptions().getActualNick(); + final Pattern highlight = generateNickHighlightPattern(nick); if (message.getBody() == null || nick == null) { return false; } - Matcher m = highlight.matcher(message.getBody()); + final Matcher m = highlight.matcher(message.getBody()); return (m.find() || message.getType() == Message.TYPE_PRIVATE); } - private static Pattern generateNickHighlightPattern(String nick) { + private static Pattern generateNickHighlightPattern(final String nick) { // We expect a word boundary, i.e. space or start of string, followed by // the // nick (matched in case-insensitive manner), followed by optional @@ -371,16 +368,16 @@ public class NotificationService { Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE); } - public void setOpenConversation(Conversation conversation) { + public void setOpenConversation(final Conversation conversation) { this.mOpenConversation = conversation; } - public void setIsInForeground(boolean foreground) { + public void setIsInForeground(final boolean foreground) { this.mIsInForeground = foreground; } - private int getPixel(int dp) { - DisplayMetrics metrics = mXmppConnectionService.getResources() + private int getPixel(final int dp) { + final DisplayMetrics metrics = mXmppConnectionService.getResources() .getDisplayMetrics(); return ((int) (dp * metrics.density)); } @@ -389,14 +386,14 @@ public class NotificationService { this.mLastNotification = SystemClock.elapsedRealtime(); } - private boolean inMiniGracePeriod(Account account) { - int miniGrace = account.getStatus() == Account.State.ONLINE ? Config.MINI_GRACE_PERIOD + private boolean inMiniGracePeriod(final Account account) { + final int miniGrace = account.getStatus() == Account.State.ONLINE ? Config.MINI_GRACE_PERIOD : Config.MINI_GRACE_PERIOD * 2; return SystemClock.elapsedRealtime() < (this.mLastNotification + miniGrace); } public Notification createForegroundNotification() { - NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService); + final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService); mBuilder.setSmallIcon(R.drawable.ic_stat_communication_import_export); mBuilder.setContentTitle(mXmppConnectionService.getString(R.string.conversations_foreground_service)); mBuilder.setContentText(mXmppConnectionService.getString(R.string.touch_to_disable)); @@ -407,14 +404,14 @@ public class NotificationService { } public void updateErrorNotification() { - NotificationManager mNotificationManager = (NotificationManager) mXmppConnectionService.getSystemService(Context.NOTIFICATION_SERVICE); - List errors = new ArrayList<>(); - for (Account account : mXmppConnectionService.getAccounts()) { + final NotificationManager mNotificationManager = (NotificationManager) mXmppConnectionService.getSystemService(Context.NOTIFICATION_SERVICE); + final List errors = new ArrayList<>(); + for (final Account account : mXmppConnectionService.getAccounts()) { if (account.hasErrorStatus()) { errors.add(account); } } - NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService); + final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService); if (errors.size() == 0) { mNotificationManager.cancel(ERROR_NOTIFICATION_ID); return; @@ -431,13 +428,12 @@ public class NotificationService { TaskStackBuilder stackBuilder = TaskStackBuilder.create(mXmppConnectionService); stackBuilder.addParentStack(ConversationActivity.class); - Intent manageAccountsIntent = new Intent(mXmppConnectionService,ManageAccountActivity.class); + final Intent manageAccountsIntent = new Intent(mXmppConnectionService,ManageAccountActivity.class); stackBuilder.addNextIntent(manageAccountsIntent); - PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT); + final PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT); mBuilder.setContentIntent(resultPendingIntent); - Notification notification = mBuilder.build(); - mNotificationManager.notify(ERROR_NOTIFICATION_ID, notification); + mNotificationManager.notify(ERROR_NOTIFICATION_ID, mBuilder.build()); } } -- cgit v1.2.3 From e084266595855033d04950bf2fc1ea4ab244f1fe Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Mon, 15 Dec 2014 17:29:17 +0100 Subject: migrated more jid parsing to use getAttributeAsJid. added error logging --- .../java/eu/siacs/conversations/entities/Bookmark.java | 11 +---------- .../eu/siacs/conversations/parser/AbstractParser.java | 7 +------ src/main/java/eu/siacs/conversations/xml/Element.java | 4 ++++ .../conversations/xmpp/stanzas/AbstractStanza.java | 18 ++---------------- 4 files changed, 8 insertions(+), 32 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Bookmark.java b/src/main/java/eu/siacs/conversations/entities/Bookmark.java index 70d852fe..20905648 100644 --- a/src/main/java/eu/siacs/conversations/entities/Bookmark.java +++ b/src/main/java/eu/siacs/conversations/entities/Bookmark.java @@ -60,16 +60,7 @@ public class Bookmark extends Element implements ListItem { @Override public Jid getJid() { - final String jid = this.getAttribute("jid"); - if (jid != null) { - try { - return Jid.fromString(jid); - } catch (final InvalidJidException e) { - return null; - } - } else { - return null; - } + return this.getAttributeAsJid("jid"); } @Override diff --git a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java index c80346b7..39cbff4f 100644 --- a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java +++ b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java @@ -53,12 +53,7 @@ public abstract class AbstractParser { protected void updateLastseen(final Element packet, final Account account, final boolean presenceOverwrite) { - Jid from; - try { - from = Jid.fromString(packet.getAttribute("from")).toBareJid(); - } catch (final InvalidJidException e) { - return; - } + Jid from = packet.getAttributeAsJid("from"); String presence = from == null || from.isBareJid() ? "" : from.getResourcepart(); Contact contact = account.getRoster().getContact(from); long timestamp = getTimestamp(packet); diff --git a/src/main/java/eu/siacs/conversations/xml/Element.java b/src/main/java/eu/siacs/conversations/xml/Element.java index c25b9017..9455d9e8 100644 --- a/src/main/java/eu/siacs/conversations/xml/Element.java +++ b/src/main/java/eu/siacs/conversations/xml/Element.java @@ -1,9 +1,12 @@ package eu.siacs.conversations.xml; +import android.util.Log; + import java.util.ArrayList; import java.util.Hashtable; import java.util.List; +import eu.siacs.conversations.Config; import eu.siacs.conversations.utils.XmlHelper; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; @@ -111,6 +114,7 @@ public class Element { try { return Jid.fromString(jid); } catch (final InvalidJidException e) { + Log.e(Config.LOGTAG, "could not parse jid " + jid); return null; } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java b/src/main/java/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java index 9e051472..1a49b45e 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java +++ b/src/main/java/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java @@ -1,7 +1,6 @@ package eu.siacs.conversations.xmpp.stanzas; import eu.siacs.conversations.xml.Element; -import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; public class AbstractStanza extends Element { @@ -11,24 +10,11 @@ public class AbstractStanza extends Element { } public Jid getTo() { - try { - return Jid.fromString(getAttribute("to")); - } catch (final InvalidJidException e) { - return null; - } + return getAttributeAsJid("to"); } public Jid getFrom() { - String from = getAttribute("from"); - if (from == null) { - return null; - } else { - try { - return Jid.fromString(from); - } catch (final InvalidJidException e) { - return null; - } - } + return getAttributeAsJid("from"); } public String getId() { -- cgit v1.2.3 From ab2187dbdfa048102dd6e38c73f35c518b90a526 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Mon, 15 Dec 2014 17:36:16 +0100 Subject: fixed crashing on unparsed jids --- src/main/java/eu/siacs/conversations/parser/MessageParser.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index cd4c6401..e9d491b5 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -60,12 +60,12 @@ public class MessageParser extends AbstractParser implements } private Message parseOtrChat(MessagePacket packet, Account account) { - boolean properlyAddressed = (!packet.getTo().isBareJid()) - || (account.countPresences() == 1); - final Jid from = packet.getFrom(); - if (from == null) { + final Jid to = packet.getTo(); + final Jid from = packet.getFrom(); + if (to == null || from == null) { return null; } + boolean properlyAddressed = !to.isBareJid() || account.countPresences() == 1; Conversation conversation = mXmppConnectionService .findOrCreateConversation(account, from.toBareJid(), false); String presence; -- cgit v1.2.3 From ea61142d7e5c2059913b767f96ebee5053cdb4f7 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Mon, 15 Dec 2014 11:39:18 -0500 Subject: Make some magic number constants final --- .../java/eu/siacs/conversations/services/NotificationService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index e13ef1b3..9e21d160 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -42,9 +42,9 @@ public class NotificationService { private final LinkedHashMap> notifications = new LinkedHashMap<>(); - public static int NOTIFICATION_ID = 0x2342; - public static int FOREGROUND_NOTIFICATION_ID = 0x8899; - public static int ERROR_NOTIFICATION_ID = 0x5678; + public static final int NOTIFICATION_ID = 0x2342; + public static final int FOREGROUND_NOTIFICATION_ID = 0x8899; + public static final int ERROR_NOTIFICATION_ID = 0x5678; private Conversation mOpenConversation; private boolean mIsInForeground; -- cgit v1.2.3 From e2f50ab8558a32ff54b6c6c80da319b4a396e173 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Mon, 15 Dec 2014 23:06:29 +0100 Subject: go through mam history page by page. load mam dynamically on scroll --- src/main/java/eu/siacs/conversations/Config.java | 6 ++- .../siacs/conversations/parser/MessageParser.java | 7 +-- .../services/MessageArchiveService.java | 60 +++++++++++++++++----- .../services/XmppConnectionService.java | 42 +++++++++------ .../conversations/ui/ConversationFragment.java | 36 ++++++++++--- 5 files changed, 108 insertions(+), 43 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index c491d632..698c403f 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -18,13 +18,15 @@ public final class Config { public static final int MESSAGE_MERGE_WINDOW = 20; + public static final int PAGE_SIZE = 50; + public static final int PROGRESS_UI_UPDATE_INTERVAL = 750; public static final boolean NO_PROXY_LOOKUP = false; //useful to debug ibb private static final long MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000; - public static final long MAX_HISTORY_AGE = 7 * MILLISECONDS_IN_DAY; - public static final long MAX_CATCHUP = MILLISECONDS_IN_DAY / 2; + public static final long MAM_MAX_CATCHUP = MILLISECONDS_IN_DAY / 2; + public static final int MAM_MAX_MESSAGES = 500; private Config() { diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index e9d491b5..e55a4a28 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -324,11 +324,8 @@ public class MessageParser extends AbstractParser implements finishedMessage.setCounterpart(counterpart); finishedMessage.setRemoteMsgId(message.getAttribute("id")); finishedMessage.setServerMsgId(result.getAttribute("id")); - if (conversation.hasDuplicateMessage(finishedMessage)) { - Log.d(Config.LOGTAG, "received mam message " + content+ " (duplicate)"); - return null; - } else { - Log.d(Config.LOGTAG, "received mam message " + content); + if (query!=null) { + query.incrementCount(); } return finishedMessage; } diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index fe1871ea..66a2d48a 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -12,7 +12,6 @@ import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.generator.AbstractGenerator; -import eu.siacs.conversations.parser.AbstractParser; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded; import eu.siacs.conversations.xmpp.OnIqPacketReceived; @@ -40,8 +39,8 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { long endCatchup = account.getXmppConnection().getLastSessionEstablished(); if (startCatchup == 0) { return; - } else if (endCatchup - startCatchup >= Config.MAX_CATCHUP) { - startCatchup = endCatchup - Config.MAX_CATCHUP; + } else if (endCatchup - startCatchup >= Config.MAM_MAX_CATCHUP) { + startCatchup = endCatchup - Config.MAM_MAX_CATCHUP; List conversations = mXmppConnectionService.getConversations(); for (Conversation conversation : conversations) { if (conversation.getMode() == Conversation.MODE_SINGLE && conversation.getAccount() == account && startCatchup > conversation.getLastMessageTransmitted()) { @@ -67,22 +66,23 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { return timestamp; } - public void query(final Conversation conversation) { - query(conversation,conversation.getAccount().getXmppConnection().getLastSessionEstablished()); + public Query query(final Conversation conversation) { + return query(conversation,conversation.getAccount().getXmppConnection().getLastSessionEstablished()); } - public void query(final Conversation conversation, long end) { + public Query query(final Conversation conversation, long end) { + return this.query(conversation,conversation.getLastMessageTransmitted(),end); + } + + public Query query(Conversation conversation, long start, long end) { synchronized (this.queries) { - final Account account = conversation.getAccount(); - long start = conversation.getLastMessageTransmitted(); if (start > end) { - return; - } else if (end - start >= Config.MAX_HISTORY_AGE) { - start = end - Config.MAX_HISTORY_AGE; + return null; } final Query query = new Query(conversation, start, end,PagingOrder.REVERSE); this.queries.add(query); this.execute(query); + return query; } } @@ -133,7 +133,11 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { if (conversation.setLastMessageTransmitted(query.getEnd())) { this.mXmppConnectionService.databaseBackend.updateConversation(conversation); } - this.mXmppConnectionService.updateConversationUi(); + if (query.hasCallback()) { + query.callback(); + } else { + this.mXmppConnectionService.updateConversationUi(); + } } else { for(Conversation tmp : this.mXmppConnectionService.getConversations()) { if (tmp.getAccount() == query.getAccount()) { @@ -170,8 +174,10 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { Element last = set == null ? null : set.findChild("last"); Element first = set == null ? null : set.findChild("first"); Element relevant = query.getPagingOrder() == PagingOrder.NORMAL ? last : first; - if (complete || relevant == null) { + boolean abort = (query.getStart() == 0 && query.getTotalCount() >= Config.PAGE_SIZE) || query.getTotalCount() >= Config.MAM_MAX_MESSAGES; + if (complete || relevant == null || abort) { this.finalizeQuery(query); + Log.d(Config.LOGTAG,query.getAccount().getJid().toBareJid().toString()+": finished mam after "+query.getTotalCount()+" messages"); } else { final Query nextQuery; if (query.getPagingOrder() == PagingOrder.NORMAL) { @@ -210,6 +216,8 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { } public class Query { + private int totalCount = 0; + private int count = 0; private long start; private long end; private Jid with = null; @@ -218,6 +226,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { private Account account; private Conversation conversation; private PagingOrder pagingOrder = PagingOrder.NORMAL; + private XmppConnectionService.OnMoreMessagesLoaded callback = null; public Query(Conversation conversation, long start, long end) { @@ -243,6 +252,8 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { query.reference = reference; query.conversation = conversation; query.with = with; + query.totalCount = totalCount; + query.callback = callback; return query; } @@ -278,6 +289,16 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { return start; } + public void setCallback(XmppConnectionService.OnMoreMessagesLoaded callback) { + this.callback = callback; + } + + public void callback() { + if (this.callback != null) { + this.callback.onMoreMessagesLoaded(count,conversation); + } + } + public long getEnd() { return end; } @@ -290,6 +311,15 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { return this.account; } + public void incrementCount() { + this.count++; + this.totalCount++; + } + + public int getTotalCount() { + return this.totalCount; + } + @Override public String toString() { StringBuilder builder = new StringBuilder(); @@ -313,5 +343,9 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { } return builder.toString(); } + + public boolean hasCallback() { + return this.callback != null; + } } } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index ef93dcc7..4b09ac9d 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -246,8 +246,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa account.pendingConferenceLeaves.clear(); fetchRosterFromServer(account); fetchBookmarks(account); - sendPresencePacket(account, - mPresenceGenerator.sendPresence(account)); + sendPresencePacket(account,mPresenceGenerator.sendPresence(account)); connectMultiModeConversations(account); updateConversationUi(); } @@ -893,11 +892,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa accountLookupTable.put(account.getUuid(), account); } this.conversations.addAll(databaseBackend.getConversations(Conversation.STATUS_AVAILABLE)); - for (Conversation conv : this.conversations) { - Account account = accountLookupTable.get(conv.getAccountUuid()); - conv.setAccount(account); - conv.addAll(0, databaseBackend.getMessages(conv, 50)); - checkDeletedFiles(conv); + for (Conversation conversation : this.conversations) { + Account account = accountLookupTable.get(conversation.getAccountUuid()); + conversation.setAccount(account); + conversation.addAll(0, databaseBackend.getMessages(conversation, Config.PAGE_SIZE)); + checkDeletedFiles(conversation); } } } @@ -962,17 +961,29 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa }); } - public int loadMoreMessages(Conversation conversation, long timestamp) { + public void loadMoreMessages(Conversation conversation, long timestamp, final OnMoreMessagesLoaded callback) { if (this.getMessageArchiveService().queryInProgress(conversation)) { - return 0; + Log.d(Config.LOGTAG,"query in progress"); + return; + } + List messages = databaseBackend.getMessages(conversation, 50,timestamp); + if (messages.size() == 0 && (conversation.getAccount().getXmppConnection() != null && conversation.getAccount().getXmppConnection().getFeatures().mam())) { + Log.d(Config.LOGTAG,"load more messages with mam"); + MessageArchiveService.Query query = getMessageArchiveService().query(conversation,0,timestamp - 1); + if (query != null) { + query.setCallback(callback); + } + return; } - List messages = databaseBackend.getMessages(conversation, 50, - timestamp); for (Message message : messages) { message.setConversation(conversation); } conversation.addAll(0, messages); - return messages.size(); + callback.onMoreMessagesLoaded(messages.size(),conversation); + } + + public interface OnMoreMessagesLoaded { + public void onMoreMessagesLoaded(int count,Conversation conversation); } public List getAccounts() { @@ -1022,7 +1033,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } else { conversation.setMode(Conversation.MODE_SINGLE); } - conversation.addAll(0, databaseBackend.getMessages(conversation, 50)); + conversation.addAll(0, databaseBackend.getMessages(conversation, Config.PAGE_SIZE)); this.databaseBackend.updateConversation(conversation); } else { String conversationName; @@ -1244,13 +1255,14 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa Log.d(Config.LOGTAG, "app switched into background"); } - public void connectMultiModeConversations(Account account) { + private void connectMultiModeConversations(Account account) { List conversations = getConversations(); for (Conversation conversation : conversations) { if ((conversation.getMode() == Conversation.MODE_MULTI) && (conversation.getAccount() == account)) { + conversation.resetMucOptions(); joinMuc(conversation); - } + } } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 7f4b5c54..c333bab7 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -9,6 +9,7 @@ import android.content.Intent; import android.content.IntentSender; import android.content.IntentSender.SendIntentException; import android.os.Bundle; +import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Gravity; @@ -38,6 +39,7 @@ import java.util.List; import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentLinkedQueue; +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.PgpEngine; import eu.siacs.conversations.entities.Account; @@ -104,6 +106,7 @@ public class ConversationFragment extends Fragment { private TextView snackbarMessage; private TextView snackbarAction; private boolean messagesLoaded = false; + private OnScrollListener mOnScrollListener = new OnScrollListener() { @Override @@ -119,14 +122,30 @@ public class ConversationFragment extends Fragment { if (firstVisibleItem == 0 && messagesLoaded) { long timestamp = ConversationFragment.this.messageList.get(0).getTimeSent(); messagesLoaded = false; - int size = activity.xmppConnectionService.loadMoreMessages(conversation, timestamp); - conversation.populateWithMessages(ConversationFragment.this.messageList); - updateStatusMessages(); - messageListAdapter.notifyDataSetChanged(); - if (size != 0) { - messagesLoaded = true; - } - messagesView.setSelectionFromTop(size + 1, 0); + Log.d(Config.LOGTAG,"load more messages"); + activity.xmppConnectionService.loadMoreMessages(conversation, timestamp, new XmppConnectionService.OnMoreMessagesLoaded() { + @Override + public void onMoreMessagesLoaded(final int count, Conversation conversation) { + if (ConversationFragment.this.conversation != conversation) { + return; + } + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + int firstItem = messagesView.getFirstVisiblePosition(); + Log.d(Config.LOGTAG, "done loading more messages. first item: " + firstItem); + ConversationFragment.this.conversation.populateWithMessages(ConversationFragment.this.messageList); + updateStatusMessages(); + messageListAdapter.notifyDataSetChanged(); + if (count != 0) { + messagesLoaded = true; + } + messagesView.setSelectionFromTop(firstItem + count, 0); + } + }); + } + }); + } } } @@ -580,6 +599,7 @@ public class ConversationFragment extends Fragment { } } conversation.populateWithMessages(ConversationFragment.this.messageList); + this.messagesLoaded = this.messageList.size() > 0; for (Message message : this.messageList) { if (message.getEncryption() == Message.ENCRYPTION_PGP && (message.getStatus() == Message.STATUS_RECEIVED || message -- cgit v1.2.3 From f9c783085def547e82a8ab83826d74dd543ec0c2 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Mon, 15 Dec 2014 17:46:32 -0500 Subject: Update summary in TimePreference change listener Ensures the summary is updated even if we change the time preference programatically; also allows other places to stop the summary from being updated by setting a new listener. --- .../java/eu/siacs/conversations/ui/TimePreference.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/TimePreference.java b/src/main/java/eu/siacs/conversations/ui/TimePreference.java index 44a36224..e32b068c 100644 --- a/src/main/java/eu/siacs/conversations/ui/TimePreference.java +++ b/src/main/java/eu/siacs/conversations/ui/TimePreference.java @@ -3,6 +3,7 @@ package eu.siacs.conversations.ui; import android.content.Context; import android.content.res.TypedArray; import android.preference.DialogPreference; +import android.preference.Preference; import android.util.AttributeSet; import android.view.View; import android.widget.TimePicker; @@ -11,12 +12,13 @@ import java.text.DateFormat; import java.util.Calendar; import java.util.Date; -public class TimePreference extends DialogPreference { +public class TimePreference extends DialogPreference implements Preference.OnPreferenceChangeListener { private TimePicker picker = null; public final static long DEFAULT_VALUE = 0; public TimePreference(final Context context, final AttributeSet attrs) { super(context, attrs, 0); + this.setOnPreferenceChangeListener(this); } protected void setTime(final long time) { @@ -25,8 +27,7 @@ public class TimePreference extends DialogPreference { notifyChanged(); } - protected void updateSummary() { - final long time = getPersistedLong(DEFAULT_VALUE); + protected void updateSummary(final long time) { final DateFormat dateFormat = android.text.format.DateFormat.getTimeFormat(getContext()); final Date date = new Date(time); setSummary(dateFormat.format(date.getTime())); @@ -71,7 +72,6 @@ public class TimePreference extends DialogPreference { } setTime(c.getTimeInMillis()); - updateSummary(); } } @@ -94,6 +94,12 @@ public class TimePreference extends DialogPreference { } setTime(time); - updateSummary(); + updateSummary(time); + } + + @Override + public boolean onPreferenceChange(final Preference preference, final Object newValue) { + ((TimePreference) preference).updateSummary((Long)newValue); + return true; } } -- cgit v1.2.3 From 6659339effb3dc005792714e694ea08cdfe9bd97 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Mon, 15 Dec 2014 22:31:55 -0500 Subject: Allow sending of any filetype via intent Fixes #756 --- src/main/AndroidManifest.xml | 2 +- .../siacs/conversations/ui/ShareWithActivity.java | 60 +++++++++++++--------- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 937b6813..8fdfa85b 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -114,7 +114,7 @@ - + mConversations = new ArrayList(); + private List mConversations = new ArrayList<>(); - private UiCallback attachImageCallback = new UiCallback() { + private UiCallback attachFileCallback = new UiCallback() { @Override public void userInputRequried(PendingIntent pi, Message object) { @@ -78,11 +79,12 @@ public class ShareWithActivity extends XmppActivity { @Override protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getActionBar().setDisplayHomeAsUpEnabled(false); - getActionBar().setHomeButtonEnabled(false); + if (getActionBar() != null) { + getActionBar().setDisplayHomeAsUpEnabled(false); + getActionBar().setHomeButtonEnabled(false); + } setContentView(R.layout.share_with); setTitle(getString(R.string.title_activity_sharewith)); @@ -128,7 +130,7 @@ public class ShareWithActivity extends XmppActivity { @Override public void onStart() { if (getIntent().getType() != null - && getIntent().getType().startsWith("image/")) { + && !getIntent().getType().startsWith("text/")) { this.share.uri = (Uri) getIntent().getParcelableExtra( Intent.EXTRA_STREAM); } else { @@ -177,12 +179,22 @@ public class ShareWithActivity extends XmppActivity { selectPresence(conversation, new OnPresenceSelected() { @Override public void onPresenceSelected() { - Toast.makeText(getApplicationContext(), - getText(R.string.preparing_image), - Toast.LENGTH_LONG).show(); - ShareWithActivity.this.xmppConnectionService + final String type = URLConnection.guessContentTypeFromName(share.uri.getPath()); + if (type != null && type.startsWith("image/")) { + Toast.makeText(getApplicationContext(), + getText(R.string.preparing_image), + Toast.LENGTH_LONG).show(); + ShareWithActivity.this.xmppConnectionService .attachImageToConversation(conversation, share.uri, - attachImageCallback); + attachFileCallback); + } else { + Toast.makeText(getApplicationContext(), + getText(R.string.preparing_file), + Toast.LENGTH_LONG).show(); + ShareWithActivity.this.xmppConnectionService + .attachFileToConversation(conversation, share.uri, + attachFileCallback); + } switchToConversation(conversation, null, true); finish(); } @@ -195,4 +207,4 @@ public class ShareWithActivity extends XmppActivity { } -} \ No newline at end of file +} -- cgit v1.2.3 From 0b4987581f6aeebd2b8c729b83aaebf9998ec0d6 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Tue, 16 Dec 2014 18:03:16 -0500 Subject: Handle time comparisons using longs --- src/main/java/eu/siacs/conversations/Config.java | 2 +- .../conversations/services/NotificationService.java | 19 +++++++------------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 698c403f..90e4a899 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -24,7 +24,7 @@ public final class Config { public static final boolean NO_PROXY_LOOKUP = false; //useful to debug ibb - private static final long MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000; + public static final long MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000; public static final long MAM_MAX_CATCHUP = MILLISECONDS_IN_DAY / 2; public static final int MAM_MAX_MESSAGES = 500; diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index 9e21d160..c27ab72a 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -72,20 +72,15 @@ public class NotificationService { if (!mXmppConnectionService.getPreferences().getBoolean("enable_quiet_hours", false)) { return false; } - final Calendar startTime = Calendar.getInstance(); - startTime.setTimeInMillis(mXmppConnectionService.getPreferences().getLong("quiet_hours_start", TimePreference.DEFAULT_VALUE)); - final Calendar endTime = Calendar.getInstance(); - endTime.setTimeInMillis(mXmppConnectionService.getPreferences().getLong("quiet_hours_end", TimePreference.DEFAULT_VALUE)); - final Calendar nowTime = Calendar.getInstance(); + final long startTime = mXmppConnectionService.getPreferences().getLong("quiet_hours_start", TimePreference.DEFAULT_VALUE) % Config.MILLISECONDS_IN_DAY; + final long endTime = mXmppConnectionService.getPreferences().getLong("quiet_hours_end", TimePreference.DEFAULT_VALUE) % Config.MILLISECONDS_IN_DAY; + final long nowTime = Calendar.getInstance().getTimeInMillis() % Config.MILLISECONDS_IN_DAY; - startTime.set(nowTime.get(Calendar.YEAR), nowTime.get(Calendar.MONTH), nowTime.get(Calendar.DATE)); - endTime.set(nowTime.get(Calendar.YEAR), nowTime.get(Calendar.MONTH), nowTime.get(Calendar.DATE)); - - if (endTime.before(startTime)) { - endTime.add(Calendar.DATE, 1); + if (endTime < startTime) { + return nowTime > startTime || nowTime < endTime; + } else { + return nowTime > startTime && nowTime < endTime; } - - return nowTime.after(startTime) && nowTime.before(endTime); } public boolean conferenceNotificationsEnabled() { -- cgit v1.2.3 From 3f6638cb649b650fbf0217d8a060bf149a9b886f Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Wed, 17 Dec 2014 06:59:58 +0100 Subject: properly count mam messages --- src/main/java/eu/siacs/conversations/parser/MessageParser.java | 10 ++++++++-- .../eu/siacs/conversations/services/MessageArchiveService.java | 7 +++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index e55a4a28..a395be78 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -278,6 +278,10 @@ public class MessageParser extends AbstractParser implements if (result == null ) { return null; } + final MessageArchiveService.Query query = this.mXmppConnectionService.getMessageArchiveService().findQuery(result.getAttribute("queryid")); + if (query!=null) { + query.incrementTotalCount(); + } final Element forwarded = result.findChild("forwarded","urn:xmpp:forward:0"); if (forwarded == null) { return null; @@ -304,7 +308,6 @@ public class MessageParser extends AbstractParser implements final long timestamp = getTimestamp(forwarded); final Jid to = message.getAttributeAsJid("to"); final Jid from = message.getAttributeAsJid("from"); - final MessageArchiveService.Query query = this.mXmppConnectionService.getMessageArchiveService().findQuery(result.getAttribute("queryid")); Jid counterpart; int status; Conversation conversation; @@ -324,8 +327,11 @@ public class MessageParser extends AbstractParser implements finishedMessage.setCounterpart(counterpart); finishedMessage.setRemoteMsgId(message.getAttribute("id")); finishedMessage.setServerMsgId(result.getAttribute("id")); + if (conversation.hasDuplicateMessage(finishedMessage)) { + return null; + } if (query!=null) { - query.incrementCount(); + query.incrementMessageCount(); } return finishedMessage; } diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index 66a2d48a..27689027 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -311,11 +311,14 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { return this.account; } - public void incrementCount() { - this.count++; + public void incrementTotalCount() { this.totalCount++; } + public void incrementMessageCount() { + this.count++; + } + public int getTotalCount() { return this.totalCount; } -- cgit v1.2.3 From 1a7ed4ed7c56bc0af70ebdaf67f71da9205f6afd Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Wed, 17 Dec 2014 07:12:38 +0100 Subject: properly detect images in share with --- .../java/eu/siacs/conversations/ui/ShareWithActivity.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java index fffcfaca..be5eee99 100644 --- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java @@ -30,6 +30,7 @@ public class ShareWithActivity extends XmppActivity { private class Share { public Uri uri; + public boolean image; public String account; public String contact; public String text; @@ -129,10 +130,10 @@ public class ShareWithActivity extends XmppActivity { @Override public void onStart() { - if (getIntent().getType() != null - && !getIntent().getType().startsWith("text/")) { - this.share.uri = (Uri) getIntent().getParcelableExtra( - Intent.EXTRA_STREAM); + final String type = getIntent().getType(); + if (type != null && !type.startsWith("text/")) { + this.share.uri = (Uri) getIntent().getParcelableExtra(Intent.EXTRA_STREAM); + this.share.image = type.startsWith("image/") || URLConnection.guessContentTypeFromName(share.uri.getPath()).startsWith("image/"); } else { this.share.text = getIntent().getStringExtra(Intent.EXTRA_TEXT); } @@ -179,8 +180,7 @@ public class ShareWithActivity extends XmppActivity { selectPresence(conversation, new OnPresenceSelected() { @Override public void onPresenceSelected() { - final String type = URLConnection.guessContentTypeFromName(share.uri.getPath()); - if (type != null && type.startsWith("image/")) { + if (share.image) { Toast.makeText(getApplicationContext(), getText(R.string.preparing_image), Toast.LENGTH_LONG).show(); -- cgit v1.2.3 From 80435eca5cda499e0319cc4b248bb807693c952d Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Wed, 17 Dec 2014 09:32:51 +0100 Subject: smoothed out scrolling a bit --- .../services/XmppConnectionService.java | 39 ++++++++++++---------- .../conversations/ui/ConversationFragment.java | 28 +++++++++++++--- src/main/res/values/strings.xml | 1 + 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 4b09ac9d..e66f7110 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -961,29 +961,32 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa }); } - public void loadMoreMessages(Conversation conversation, long timestamp, final OnMoreMessagesLoaded callback) { - if (this.getMessageArchiveService().queryInProgress(conversation)) { - Log.d(Config.LOGTAG,"query in progress"); - return; - } - List messages = databaseBackend.getMessages(conversation, 50,timestamp); - if (messages.size() == 0 && (conversation.getAccount().getXmppConnection() != null && conversation.getAccount().getXmppConnection().getFeatures().mam())) { - Log.d(Config.LOGTAG,"load more messages with mam"); - MessageArchiveService.Query query = getMessageArchiveService().query(conversation,0,timestamp - 1); - if (query != null) { - query.setCallback(callback); + public void loadMoreMessages(final Conversation conversation, final long timestamp, final OnMoreMessagesLoaded callback) { + new Thread(new Runnable() { + @Override + public void run() { + if (XmppConnectionService.this.getMessageArchiveService().queryInProgress(conversation)) { + return; + } + final Account account = conversation.getAccount(); + List messages = databaseBackend.getMessages(conversation, 50,timestamp); + if (messages.size() > 0) { + conversation.addAll(0, messages); + callback.onMoreMessagesLoaded(messages.size(), conversation); + } else if (account.getStatus() == Account.State.ONLINE && account.getXmppConnection() != null && account.getXmppConnection().getFeatures().mam()) { + MessageArchiveService.Query query = getMessageArchiveService().query(conversation,0,timestamp - 1); + if (query != null) { + query.setCallback(callback); + } + callback.informUser(R.string.fetching_history_from_server); + } } - return; - } - for (Message message : messages) { - message.setConversation(conversation); - } - conversation.addAll(0, messages); - callback.onMoreMessagesLoaded(messages.size(),conversation); + }).start(); } public interface OnMoreMessagesLoaded { public void onMoreMessagesLoaded(int count,Conversation conversation); + public void informUser(int r); } public List getAccounts() { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index c333bab7..d0b3e022 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -106,6 +106,7 @@ public class ConversationFragment extends Fragment { private TextView snackbarMessage; private TextView snackbarAction; private boolean messagesLoaded = false; + private Toast messageLoaderToast; private OnScrollListener mOnScrollListener = new OnScrollListener() { @@ -119,10 +120,9 @@ public class ConversationFragment extends Fragment { public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { synchronized (ConversationFragment.this.messageList) { - if (firstVisibleItem == 0 && messagesLoaded) { + if (firstVisibleItem < 5 && messagesLoaded) { long timestamp = ConversationFragment.this.messageList.get(0).getTimeSent(); messagesLoaded = false; - Log.d(Config.LOGTAG,"load more messages"); activity.xmppConnectionService.loadMoreMessages(conversation, timestamp, new XmppConnectionService.OnMoreMessagesLoaded() { @Override public void onMoreMessagesLoaded(final int count, Conversation conversation) { @@ -132,18 +132,36 @@ public class ConversationFragment extends Fragment { activity.runOnUiThread(new Runnable() { @Override public void run() { - int firstItem = messagesView.getFirstVisiblePosition(); - Log.d(Config.LOGTAG, "done loading more messages. first item: " + firstItem); + int oldPosition = messagesView.getFirstVisiblePosition(); ConversationFragment.this.conversation.populateWithMessages(ConversationFragment.this.messageList); updateStatusMessages(); messageListAdapter.notifyDataSetChanged(); if (count != 0) { + final int newPosition = oldPosition + count; + Message tmpMessage = messageList.get(newPosition); + int offset = 0; + while(tmpMessage.wasMergedIntoPrevious()) { + offset++; + tmpMessage = tmpMessage.prev(); + } + messagesView.setSelectionFromTop(newPosition - offset, 0); messagesLoaded = true; + if (messageLoaderToast != null) { + messageLoaderToast.cancel(); + } } - messagesView.setSelectionFromTop(firstItem + count, 0); } }); } + + @Override + public void informUser(int resId) { + if (messageLoaderToast != null) { + messageLoaderToast.cancel(); + } + messageLoaderToast = Toast.makeText(activity,resId,Toast.LENGTH_LONG); + messageLoaderToast.show(); + } }); } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 02be6348..5288466f 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -366,4 +366,5 @@ Reset Account avatar Copy OTR fingerprint to clipboard + Fetching history from server -- cgit v1.2.3 From 741a0c129d3558e9b9a714848a590a1f0a499799 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Wed, 17 Dec 2014 10:50:51 +0100 Subject: made scroling smoother + bug fixes for history loading --- .../services/MessageArchiveService.java | 10 +++-- .../services/XmppConnectionService.java | 7 +-- .../conversations/ui/ConversationFragment.java | 51 +++++++++++++++------- src/main/res/values/strings.xml | 1 + 4 files changed, 48 insertions(+), 21 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index 27689027..1d80690c 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -9,6 +9,7 @@ import java.util.Iterator; import java.util.List; import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.generator.AbstractGenerator; @@ -217,7 +218,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { public class Query { private int totalCount = 0; - private int count = 0; + private int messageCount = 0; private long start; private long end; private Jid with = null; @@ -295,7 +296,10 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { public void callback() { if (this.callback != null) { - this.callback.onMoreMessagesLoaded(count,conversation); + this.callback.onMoreMessagesLoaded(messageCount,conversation); + if (messageCount==0) { + this.callback.informUser(R.string.no_more_history_on_server); + } } } @@ -316,7 +320,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { } public void incrementMessageCount() { - this.count++; + this.messageCount++; } public int getTotalCount() { diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index e66f7110..39babece 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -962,12 +962,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } public void loadMoreMessages(final Conversation conversation, final long timestamp, final OnMoreMessagesLoaded callback) { + Log.d(Config.LOGTAG,"load more messages for "+conversation.getName() + " prior to "+MessageGenerator.getTimestamp(timestamp)); + if (XmppConnectionService.this.getMessageArchiveService().queryInProgress(conversation)) { + return; + } new Thread(new Runnable() { @Override public void run() { - if (XmppConnectionService.this.getMessageArchiveService().queryInProgress(conversation)) { - return; - } final Account account = conversation.getAccount(); List messages = databaseBackend.getMessages(conversation, 50,timestamp); if (messages.size() > 0) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index d0b3e022..418d9bbf 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -105,7 +105,7 @@ public class ConversationFragment extends Fragment { private RelativeLayout snackbar; private TextView snackbarMessage; private TextView snackbarAction; - private boolean messagesLoaded = false; + private boolean messagesLoaded = true; private Toast messageLoaderToast; private OnScrollListener mOnScrollListener = new OnScrollListener() { @@ -120,7 +120,7 @@ public class ConversationFragment extends Fragment { public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { synchronized (ConversationFragment.this.messageList) { - if (firstVisibleItem < 5 && messagesLoaded) { + if (firstVisibleItem < 5 && messagesLoaded && messageList.size() > 0) { long timestamp = ConversationFragment.this.messageList.get(0).getTimeSent(); messagesLoaded = false; activity.xmppConnectionService.loadMoreMessages(conversation, timestamp, new XmppConnectionService.OnMoreMessagesLoaded() { @@ -132,19 +132,26 @@ public class ConversationFragment extends Fragment { activity.runOnUiThread(new Runnable() { @Override public void run() { - int oldPosition = messagesView.getFirstVisiblePosition(); + final int oldPosition = messagesView.getFirstVisiblePosition(); + View v = messagesView.getChildAt(0); + final int pxOffset = (v == null) ? 0 : v.getTop(); ConversationFragment.this.conversation.populateWithMessages(ConversationFragment.this.messageList); updateStatusMessages(); messageListAdapter.notifyDataSetChanged(); if (count != 0) { final int newPosition = oldPosition + count; - Message tmpMessage = messageList.get(newPosition); int offset = 0; - while(tmpMessage.wasMergedIntoPrevious()) { - offset++; - tmpMessage = tmpMessage.prev(); + try { + Message tmpMessage = messageList.get(newPosition); + + while(tmpMessage.wasMergedIntoPrevious()) { + offset++; + tmpMessage = tmpMessage.prev(); + } + } catch (final IndexOutOfBoundsException ignored) { + } - messagesView.setSelectionFromTop(newPosition - offset, 0); + messagesView.setSelectionFromTop(newPosition - offset, pxOffset); messagesLoaded = true; if (messageLoaderToast != null) { messageLoaderToast.cancel(); @@ -155,12 +162,22 @@ public class ConversationFragment extends Fragment { } @Override - public void informUser(int resId) { - if (messageLoaderToast != null) { - messageLoaderToast.cancel(); - } - messageLoaderToast = Toast.makeText(activity,resId,Toast.LENGTH_LONG); - messageLoaderToast.show(); + public void informUser(final int resId) { + + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + if (messageLoaderToast != null) { + messageLoaderToast.cancel(); + } + if (ConversationFragment.this.conversation != conversation) { + return; + } + messageLoaderToast = Toast.makeText(activity,resId,Toast.LENGTH_LONG); + messageLoaderToast.show(); + } + }); + } }); @@ -549,6 +566,11 @@ public class ConversationFragment extends Fragment { this.mEditMessage.append(this.conversation.getNextMessage()); this.messagesView.invalidate(); updateMessages(); + this.messagesLoaded = true; + int size = this.messageList.size(); + if (size > 0) { + messagesView.setSelection(size - 1); + } } public void updateMessages() { @@ -617,7 +639,6 @@ public class ConversationFragment extends Fragment { } } conversation.populateWithMessages(ConversationFragment.this.messageList); - this.messagesLoaded = this.messageList.size() > 0; for (Message message : this.messageList) { if (message.getEncryption() == Message.ENCRYPTION_PGP && (message.getStatus() == Message.STATUS_RECEIVED || message diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 5288466f..ec761d6e 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -367,4 +367,5 @@ Account avatar Copy OTR fingerprint to clipboard Fetching history from server + No more history on server -- cgit v1.2.3 From de952cc9590b4e4f38698e5cdb42f378169f663b Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Wed, 17 Dec 2014 21:04:54 +0100 Subject: show error if jid couldn't be parsed in new contact dialog --- .../ui/StartConversationActivity.java | 25 +++++++++------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index c8b41821..4fdcf79e 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -318,13 +318,10 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU protected void showCreateContactDialog(final String prefilledJid, final String fingerprint) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.create_contact); - View dialogView = getLayoutInflater().inflate( - R.layout.create_contact_dialog, null); + View dialogView = getLayoutInflater().inflate(R.layout.create_contact_dialog, null); final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account); - final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView - .findViewById(R.id.jid); - jid.setAdapter(new KnownHostsAdapter(this, - android.R.layout.simple_list_item_1, mKnownHosts)); + final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView.findViewById(R.id.jid); + jid.setAdapter(new KnownHostsAdapter(this,android.R.layout.simple_list_item_1, mKnownHosts)); if (prefilledJid != null) { jid.append(prefilledJid); if (fingerprint!=null) { @@ -351,8 +348,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU if (Validator.isValidJid(jid.getText().toString())) { final Jid accountJid; try { - accountJid = Jid.fromString((String) spinner - .getSelectedItem()); + accountJid = Jid.fromString((String) spinner.getSelectedItem()); } catch (final InvalidJidException e) { return; } @@ -360,6 +356,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU try { contactJid = Jid.fromString(jid.getText().toString()); } catch (final InvalidJidException e) { + jid.setError(getString(R.string.invalid_jid)); return; } Account account = xmppConnectionService @@ -389,13 +386,10 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU protected void showJoinConferenceDialog(String prefilledJid) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.join_conference); - View dialogView = getLayoutInflater().inflate( - R.layout.join_conference_dialog, null); + View dialogView = getLayoutInflater().inflate(R.layout.join_conference_dialog, null); final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account); - final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView - .findViewById(R.id.jid); - jid.setAdapter(new KnownHostsAdapter(this, - android.R.layout.simple_list_item_1, mKnownConferenceHosts)); + final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView.findViewById(R.id.jid); + jid.setAdapter(new KnownHostsAdapter(this,android.R.layout.simple_list_item_1, mKnownConferenceHosts)); if (prefilledJid != null) { jid.append(prefilledJid); } @@ -426,7 +420,8 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU try { conferenceJid = Jid.fromString(jid.getText().toString()); } catch (final InvalidJidException e) { - return; // TODO: Do some error handling... + jid.setError(getString(R.string.invalid_jid)); + return; } Account account = xmppConnectionService .findAccountByJid(accountJid); -- cgit v1.2.3 From f00e168752e0b59de8eb667ce99bf6d10bd1361f Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Wed, 17 Dec 2014 21:05:47 +0100 Subject: clean up conversation history after swtiching to a different conversation --- src/main/java/eu/siacs/conversations/Config.java | 1 + .../java/eu/siacs/conversations/entities/Conversation.java | 14 ++++++++++---- .../eu/siacs/conversations/ui/ConversationFragment.java | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 90e4a899..6fe13d93 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -19,6 +19,7 @@ public final class Config { public static final int MESSAGE_MERGE_WINDOW = 20; public static final int PAGE_SIZE = 50; + public static final int MAX_NUM_PAGES = 3; public static final int PROGRESS_UI_UPDATE_INTERVAL = 750; diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index ac1343a8..e8482a96 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -129,6 +129,16 @@ public class Conversation extends AbstractEntity { } } + public void trim() { + synchronized (this.messages) { + final int size = messages.size(); + final int maxsize = Config.PAGE_SIZE * Config.MAX_NUM_PAGES; + if (size > maxsize) { + this.messages.subList(0, size - maxsize).clear(); + } + } + } + public void findUnsentMessagesWithOtrEncryption(OnMessageFound onMessageFound) { synchronized (this.messages) { for (Message message : this.messages) { @@ -265,10 +275,6 @@ public class Conversation extends AbstractEntity { } } - public String getProfilePhotoString() { - return this.getContact().getProfilePhoto(); - } - public String getAccountUuid() { return this.accountUuid; } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 418d9bbf..b46fd0a3 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -554,6 +554,7 @@ public class ConversationFragment extends Fragment { } if (this.conversation != null) { this.conversation.setNextMessage(mEditMessage.getText().toString()); + this.conversation.trim(); } this.activity = (ConversationActivity) getActivity(); this.conversation = conversation; -- cgit v1.2.3 From 948112c2f3746be64a790ed15f201d96ccc9e20f Mon Sep 17 00:00:00 2001 From: kriztan Date: Thu, 18 Dec 2014 12:10:03 +0100 Subject: Update german translations --- src/main/res/values-de/strings.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index cade782a..efe2cc74 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -41,6 +41,7 @@ Kontakt einladen Kontakte Abbrechen + Einstellen Hinzufügen Bearbeiten Entfernen @@ -258,6 +259,11 @@ Hier bitte vorsichtig sein Über Conversations Versions- und Lizenzinformationen + Ruhige Stunden + Beginn + Ende + Aktiviere ruhige Stunden + Benachrichtigungen sind während der ruhigen Stunden stumm. Schrift vergrößern Größere Schrift verwenden Absende-Knopf zeigt Online-Status an @@ -336,4 +342,6 @@ Zurücksetzen Konto-Avatar OTR-Fingerabdruck in Zwischenablage kopieren + Hole Chatverlauf vom Server + Keine weiteren Nachrichten auf dem Server vorhanden. -- cgit v1.2.3 From 7c4a306ae4b45b3ae0258434cc0364e842c83d9f Mon Sep 17 00:00:00 2001 From: Jaroslav Lichtblau Date: Thu, 18 Dec 2014 18:42:50 +0100 Subject: Czech translation updated added missing strings --- src/main/res/values-cs/strings.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/res/values-cs/strings.xml b/src/main/res/values-cs/strings.xml index 0078b740..ff1f3644 100644 --- a/src/main/res/values-cs/strings.xml +++ b/src/main/res/values-cs/strings.xml @@ -41,6 +41,7 @@ Pozvat kontakt Kontakty Zrušit + Nastavit Přidat Upravit Smazat @@ -258,6 +259,11 @@ S tímto zacházejte velmi opatrně O aplikaci Conversations Informace o sestavení a licenci + Tichý režim + Odkdy + Dokdy + Povolit tichý režim + Upozornění budou během tichého režimu ztlumena Zvětšit písmo Používat v celé aplikaci větší velikost písma Tlačítko pro odeslání zobrazuje stav @@ -336,4 +342,6 @@ Reset Avatar účtu Zkopírovat otisk OTR do schránky + Načíst historii ze serveru + Na serveru není žádná další historie -- cgit v1.2.3 From 627982df90d83177578183d0e91cad0a748c4e4d Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Fri, 19 Dec 2014 13:40:16 +0100 Subject: fixed #755 --- src/main/java/eu/siacs/conversations/parser/IqParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java index aeec56d0..b583a1a1 100644 --- a/src/main/java/eu/siacs/conversations/parser/IqParser.java +++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java @@ -27,7 +27,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { if (item.getName().equals("item")) { final Jid jid = item.getAttributeAsJid("jid"); if (jid == null) { - break; + continue; } String name = item.getAttribute("name"); String subscription = item.getAttribute("subscription"); -- cgit v1.2.3 From c8cfd1b084e9103f63f7c2a073ec65e9ec5ba037 Mon Sep 17 00:00:00 2001 From: Jaroslav Lichtblau Date: Fri, 19 Dec 2014 22:50:43 +0100 Subject: Czech image transfer string fix --- src/main/res/values-cs/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/res/values-cs/strings.xml b/src/main/res/values-cs/strings.xml index ff1f3644..9e955246 100644 --- a/src/main/res/values-cs/strings.xml +++ b/src/main/res/values-cs/strings.xml @@ -17,7 +17,7 @@ Nastavení Detaily konference Detaily kontaktu - Konverzace + Conversations Sdílet s konverzací Začít konverzaci Vybrat kontakt @@ -59,7 +59,7 @@ Přidat kontakt doručení selhalo zamítnuto - Přijímám obrázek. Chvíli strpení… + Přijímám obrázek (%1$d%%) Připravuji obrázek na přenos Smazat historii Smaže historii konverzací -- cgit v1.2.3 From 6dd75cbb07e9e16f2d0f9d85a0394bfff4aac942 Mon Sep 17 00:00:00 2001 From: kruks23 Date: Sat, 20 Dec 2014 10:54:23 +0100 Subject: Update spanish translations --- src/main/res/values-es/strings.xml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index e02c0f02..ca588707 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -41,6 +41,7 @@ Invitar contactos Contactos Cancelar + Establecer Añadir Editar Eliminar @@ -195,10 +196,10 @@ Huella digital OTR Verificar Desencriptar - Convers. Grupo + Conversación Grupo Buscar Crear Contacto - Unirse a Conversación grupo + Unirse a Conversación en grupo Eliminar Contacto Ver detalles del contacto Crear @@ -208,7 +209,7 @@ nombre@salas.ejemplo.com Guardar en marcadores Eliminar marcador - Este marcador ya exsite + Este marcador ya existe Editar asunto de la conversación Conversación en grupo no encontrada @@ -258,6 +259,11 @@ Por favor, cuidado con estas opciones Acerca de Conversations Información de compilación y licencia + Horario de silencio + Hora de comienzo + Hora de fin + Habilitar horario de silencio + Las notificaciones serán silenciadas durante el horario de silencio Tamaño de fuente grande Usar fuentes grandes en toda la aplicación Botón enviar indica estado @@ -274,7 +280,7 @@ Usando cuenta %s Comprobando imagen en servidor HTTP El archivo de imagen ha sido eliminado - No estás concectado. Inténtalo más tarde + No estás conectado. Inténtalo más tarde Comprobar el tamaño del archivo de imagen Opciones de mensaje Copiar texto @@ -336,4 +342,6 @@ Reinicializar Imagen de perfil Copiar huella digital OTR al portapapeles + Buscar historial en servidor + No más historial del servidor -- cgit v1.2.3 From 88f43643bf92b5f5e54be5a9ec98409c30b83ec5 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sat, 20 Dec 2014 12:52:08 +0100 Subject: inject ui callback into running mam query --- .../java/eu/siacs/conversations/services/MessageArchiveService.java | 5 ++++- .../java/eu/siacs/conversations/services/XmppConnectionService.java | 2 +- src/main/java/eu/siacs/conversations/ui/ConversationFragment.java | 3 +-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index 1d80690c..1a161c56 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -151,10 +151,13 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { } } - public boolean queryInProgress(Conversation conversation) { + public boolean queryInProgress(Conversation conversation, XmppConnectionService.OnMoreMessagesLoaded callback) { synchronized (this.queries) { for(Query query : queries) { if (query.conversation == conversation) { + if (!query.hasCallback() && callback != null) { + query.setCallback(callback); + } return true; } } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 39babece..1273ae86 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -963,7 +963,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa public void loadMoreMessages(final Conversation conversation, final long timestamp, final OnMoreMessagesLoaded callback) { Log.d(Config.LOGTAG,"load more messages for "+conversation.getName() + " prior to "+MessageGenerator.getTimestamp(timestamp)); - if (XmppConnectionService.this.getMessageArchiveService().queryInProgress(conversation)) { + if (XmppConnectionService.this.getMessageArchiveService().queryInProgress(conversation,callback)) { return; } new Thread(new Runnable() { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index b46fd0a3..e4c3fa9e 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -769,8 +769,7 @@ public class ConversationFragment extends Fragment { return; } else { if (this.messageList.get(i).getStatus() == Message.STATUS_SEND_DISPLAYED) { - this.messageList.add(i + 1, - Message.createStatusMessage(conversation)); + this.messageList.add(i + 1,Message.createStatusMessage(conversation)); return; } } -- cgit v1.2.3 From 6b047bed97179c86e4eb733b4c123de743eb4702 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sat, 20 Dec 2014 12:52:45 +0100 Subject: fixed another break continue bug --- .../java/eu/siacs/conversations/services/XmppConnectionService.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 1273ae86..76f2e36b 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -865,10 +865,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa try { jid = Jid.fromString(phoneContact.getString("jid")); } catch (final InvalidJidException e) { - break; + continue; } - final Contact contact = account.getRoster() - .getContact(jid); + final Contact contact = account.getRoster().getContact(jid); String systemAccount = phoneContact.getInt("phoneid") + "#" + phoneContact.getString("lookup"); -- cgit v1.2.3 From 40335785aad5362b5ef0f2a377b28819c1435b19 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sat, 20 Dec 2014 15:21:03 +0100 Subject: don't include empty fingerprints in list of otrfingerprints --- src/main/java/eu/siacs/conversations/entities/Contact.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java index 6a6b41d6..1fb80b9b 100644 --- a/src/main/java/eu/siacs/conversations/entities/Contact.java +++ b/src/main/java/eu/siacs/conversations/entities/Contact.java @@ -266,13 +266,15 @@ public class Contact implements ListItem { } public ArrayList getOtrFingerprints() { - ArrayList fingerprints = new ArrayList(); + final ArrayList fingerprints = new ArrayList(); try { if (this.keys.has("otr_fingerprints")) { - JSONArray prints = this.keys - .getJSONArray("otr_fingerprints"); + final JSONArray prints = this.keys.getJSONArray("otr_fingerprints"); for (int i = 0; i < prints.length(); ++i) { - fingerprints.add(prints.getString(i)); + final String print = prints.getString(i); + if (print != null && !print.isEmpty()) { + fingerprints.add(prints.getString(i)); + } } } } catch (final JSONException ignored) { -- cgit v1.2.3 From ce4848f74225a59ddc8469a2a3e3481519c0f0d5 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sat, 20 Dec 2014 16:01:28 +0100 Subject: more null checks for otr fingerprints --- src/main/java/eu/siacs/conversations/entities/Contact.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java index 1fb80b9b..0820504f 100644 --- a/src/main/java/eu/siacs/conversations/entities/Contact.java +++ b/src/main/java/eu/siacs/conversations/entities/Contact.java @@ -271,7 +271,7 @@ public class Contact implements ListItem { if (this.keys.has("otr_fingerprints")) { final JSONArray prints = this.keys.getJSONArray("otr_fingerprints"); for (int i = 0; i < prints.length(); ++i) { - final String print = prints.getString(i); + final String print = prints.isNull(i) ? null : prints.getString(i); if (print != null && !print.isEmpty()) { fingerprints.add(prints.getString(i)); } -- cgit v1.2.3 From 15176417132a88364efeb64713f8ac1267001cc4 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sat, 20 Dec 2014 17:23:03 +0100 Subject: get rid of special self presence object and incorporate that into roster --- .../eu/siacs/conversations/entities/Account.java | 20 +---- .../siacs/conversations/parser/PresenceParser.java | 100 +++++++++------------ .../services/XmppConnectionService.java | 1 - 3 files changed, 46 insertions(+), 75 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java index 538d0ec2..d9001017 100644 --- a/src/main/java/eu/siacs/conversations/entities/Account.java +++ b/src/main/java/eu/siacs/conversations/entities/Account.java @@ -116,10 +116,9 @@ public class Account extends AbstractEntity { protected boolean online = false; private OtrEngine otrEngine = null; private XmppConnection xmppConnection = null; - private Presences presences = new Presences(); private long mEndGracePeriod = 0L; private String otrFingerprint; - private Roster roster = null; + private final Roster roster = new Roster(this); private List bookmarks = new CopyOnWriteArrayList<>(); public Account() { @@ -328,20 +327,8 @@ public class Account extends AbstractEntity { this.rosterVersion = version; } - public void updatePresence(String resource, int status) { - this.presences.updatePresence(resource, status); - } - - public void removePresence(String resource) { - this.presences.removePresence(resource); - } - - public void clearPresences() { - this.presences = new Presences(); - } - public int countPresences() { - return this.presences.size(); + return this.getRoster().getContact(this.getJid().toBareJid()).getPresences().size(); } public String getPgpSignature() { @@ -357,9 +344,6 @@ public class Account extends AbstractEntity { } public Roster getRoster() { - if (this.roster == null) { - this.roster = new Roster(this); - } return this.roster; } diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index 43c8fa8d..684713f0 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -45,69 +45,57 @@ public class PresenceParser extends AbstractParser implements } final Jid from = packet.getFrom(); String type = packet.getAttribute("type"); - if (from.toBareJid().equals(account.getJid().toBareJid())) { + Contact contact = account.getRoster().getContact(packet.getFrom()); + if (type == null) { + String presence; if (!from.isBareJid()) { - if (type == null) { - account.updatePresence(from.getResourcepart(), - Presences.parseShow(packet.findChild("show"))); - } else if (type.equals("unavailable")) { - account.removePresence(from.getResourcepart()); - account.deactivateGracePeriod(); - } + presence = from.getResourcepart(); + } else { + presence = ""; } - } else { - Contact contact = account.getRoster().getContact(packet.getFrom()); - if (type == null) { - String presence; - if (!from.isBareJid()) { - presence = from.getResourcepart(); - } else { - presence = ""; - } - int sizeBefore = contact.getPresences().size(); - contact.updatePresence(presence, - Presences.parseShow(packet.findChild("show"))); - PgpEngine pgp = mXmppConnectionService.getPgpEngine(); - if (pgp != null) { - Element x = packet.findChild("x", "jabber:x:signed"); - if (x != null) { - Element status = packet.findChild("status"); - String msg; - if (status != null) { - msg = status.getContent(); - } else { - msg = ""; - } - contact.setPgpKeyId(pgp.fetchKeyId(account, msg, - x.getContent())); + int sizeBefore = contact.getPresences().size(); + contact.updatePresence(presence, + Presences.parseShow(packet.findChild("show"))); + PgpEngine pgp = mXmppConnectionService.getPgpEngine(); + if (pgp != null) { + Element x = packet.findChild("x", "jabber:x:signed"); + if (x != null) { + Element status = packet.findChild("status"); + String msg; + if (status != null) { + msg = status.getContent(); + } else { + msg = ""; } + contact.setPgpKeyId(pgp.fetchKeyId(account, msg, + x.getContent())); } - boolean online = sizeBefore < contact.getPresences().size(); - updateLastseen(packet, account, true); - mXmppConnectionService.onContactStatusChanged - .onContactStatusChanged(contact, online); - } else if (type.equals("unavailable")) { - if (from.isBareJid()) { - contact.clearPresences(); - } else { - contact.removePresence(from.getResourcepart()); - } - mXmppConnectionService.onContactStatusChanged - .onContactStatusChanged(contact, false); - } else if (type.equals("subscribe")) { - if (contact.getOption(Contact.Options.PREEMPTIVE_GRANT)) { - mXmppConnectionService.sendPresencePacket(account, - mPresenceGenerator.sendPresenceUpdatesTo(contact)); - } else { - contact.setOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST); - } } - Element nick = packet.findChild("nick", - "http://jabber.org/protocol/nick"); - if (nick != null) { - contact.setPresenceName(nick.getContent()); + boolean online = sizeBefore < contact.getPresences().size(); + updateLastseen(packet, account, true); + mXmppConnectionService.onContactStatusChanged + .onContactStatusChanged(contact, online); + } else if (type.equals("unavailable")) { + if (from.isBareJid()) { + contact.clearPresences(); + } else { + contact.removePresence(from.getResourcepart()); + } + mXmppConnectionService.onContactStatusChanged + .onContactStatusChanged(contact, false); + } else if (type.equals("subscribe")) { + if (contact.getOption(Contact.Options.PREEMPTIVE_GRANT)) { + mXmppConnectionService.sendPresencePacket(account, + mPresenceGenerator.sendPresenceUpdatesTo(contact)); + } else { + contact.setOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST); } } + Element nick = packet.findChild("nick", + "http://jabber.org/protocol/nick"); + if (nick != null) { + contact.setPresenceName(nick.getContent()); + } mXmppConnectionService.updateRosterUi(); } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 76f2e36b..dc3b3200 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -241,7 +241,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa @Override public void onBind(final Account account) { account.getRoster().clearPresences(); - account.clearPresences(); // self presences account.pendingConferenceJoins.clear(); account.pendingConferenceLeaves.clear(); fetchRosterFromServer(account); -- cgit v1.2.3 From 96569700512e9618efa18eeb277665045678e16d Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sun, 21 Dec 2014 14:05:33 +0100 Subject: updated readme and xep list --- README.md | 4 +++- docs/XEPs.md | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0e9e834b..2181aa96 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,6 @@ run your own XMPP server for you and your friends. These XEP's are: * XEP-0065: SOCKS5 Bytestreams (or mod_proxy65). Will be used to transfer files if both parties are behind a firewall (NAT). -* XEP-0138: Stream Compression saves bandwidth * XEP-0163: Personal Eventing Protocol for avatars * XEP-0198: Stream Management allows XMPP to survive small network outages and changes of the underlying TCP connection. @@ -48,6 +47,9 @@ run your own XMPP server for you and your friends. These XEP's are: your desktop client and thus allows you to switch seamlessly from your mobile client to your desktop client and back within one conversation. * XEP-0237: Roster Versioning mainly to save bandwidth on poor mobile connections +* XEP-0313: Message Archive Management synchronize message history with the + server. Catch up with messages that were sent while Conversations was + offline. * XEP-0352: Client State Indication let the server know whether or not Conversations is in the background. Allows the server to save bandwidth by withholding unimportant packages. diff --git a/docs/XEPs.md b/docs/XEPs.md index 0dd6a1d7..980c1c65 100644 --- a/docs/XEPs.md +++ b/docs/XEPs.md @@ -3,7 +3,6 @@ * XEP-0045: Multi-User Chat * XEP-0048: Bookmarks * XEP-0115: Entity Capabilities -* XEP-0138: Stream Compression * XEP-0163: Personal Eventing Protocol (avatars and nicks) * XEP-0166: Jingle (only used for file transfer) * XEP-0184: Message Delivery Receipts (reply only) @@ -14,5 +13,6 @@ * XEP-0260: Jingle SOCKS5 Bytestreams Transport Method * XEP-0261: Jingle In-Band Bytestreams Transport Method * XEP-0280: Message Carbons +* XEP-0313: Message Archive Management * XEP-0333: Chat Markers * XEP-0352: Client State Indication -- cgit v1.2.3 From af7a64491fa5c514866d0f1952c034a7672bb508 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Sun, 21 Dec 2014 15:43:58 -0500 Subject: Add support for XEP-0191 (Blocking command) Fixes #791 Squash of commits: 534f25d7dae3ce6852243e28fdd0a69ac01e9463 808fdf5147f27a912a60bee39aa4bf1ddd4f43b4 1eaf8a8330710ad35ba7c368e04f909af623ae4c 31585242c2359efdcd0eeddb9745077f54dbc9eb 2e69bd0bd0286ed1e98a42f4c3421ba4d8cf524b e904fb5015bf3a1904ab941a1957edf3b1e7abd2 eebbadf3b3816bbf8fcccb763e419fed252d266f 7c5b87724ce494e5a6e8026557ed50a8fd9f23e8 b0eaaf446937794fe19cbdb4f8309c3ff83d4e42 8c652f9e8bb3512958d9ad8c6f1326505f2d98c8 ad0ea1ad948ff6f8fde7b0b10f5163dc8852032f f5d49897e0dba691ef53a0eddb9ed34d129ad442 a08fa64c505bd895b7c626cfad182380373be20b de67079113e08394a276048c31f6b21baa300829 9069f342173ba30c2b20c67529c7ff497a6a257d 0169fa79d161ee898c4b6762e207087682a952d8 8585a5bd75a5d56927fed8317729bd15fffe4dcc 0053528a078369e0b65dcf71bda251072a1299c7 e901a9c3554bd7cca193e92919b463991eadfea7 c5c78257434813c69ab9b7558bcc8f7cbe858433 e905af348d46d77bc46b5f7211527684acc02fab 13a0f9a10c7892b0f90f5fabd2f2615701b0fd66 2cfba1e24b0139839e4453b92be7e20634d150cf 58e074fb5bb44b05a8104250fccd7c024c808c1a 0d6cf98fc8eab212d798ac79b336f9b70a14f06d e23620f56b85bcab9f3b5d9ce1c01524cd9674dc d72cd2fcc8d54176c3ff53411a69b9bb4642eff3 195143dff8836623a37094a6b8fa6aa01ef31580 5f5f3caf3a1e480a99d27ee5c34ba516419c52e4 1dee3d5861c9f9c710da4cbda3688d94c622ca93 23949b8aa32c78b27bab49bb3c4f3ff588925ce1 9bf97f8ae522796e0dacb7f6fe7a7f90f86a93a1 --- README.md | 4 +- docs/XEPs.md | 1 + src/main/AndroidManifest.xml | 3 + .../eu/siacs/conversations/entities/Account.java | 30 ++- .../eu/siacs/conversations/entities/Blockable.java | 11 + .../eu/siacs/conversations/entities/Bookmark.java | 1 - .../eu/siacs/conversations/entities/Contact.java | 52 +++-- .../siacs/conversations/entities/Conversation.java | 72 +++--- .../eu/siacs/conversations/entities/ListItem.java | 8 +- .../eu/siacs/conversations/entities/Message.java | 24 +- .../siacs/conversations/entities/MucOptions.java | 66 +++--- .../eu/siacs/conversations/entities/Roster.java | 10 +- .../siacs/conversations/generator/IqGenerator.java | 81 ++++--- .../conversations/generator/MessageGenerator.java | 10 +- .../siacs/conversations/parser/AbstractParser.java | 8 +- .../eu/siacs/conversations/parser/IqParser.java | 107 +++++++-- .../conversations/persistance/DatabaseBackend.java | 6 +- .../services/MessageArchiveService.java | 2 +- .../services/XmppConnectionService.java | 195 +++++++++++----- .../ui/AbstractSearchableListItemActivity.java | 124 ++++++++++ .../siacs/conversations/ui/BlockContactDialog.java | 41 ++++ .../siacs/conversations/ui/BlocklistActivity.java | 75 ++++++ .../conversations/ui/ChooseContactActivity.java | 125 ++-------- .../ui/ConferenceDetailsActivity.java | 24 +- .../conversations/ui/ContactDetailsActivity.java | 70 +++--- .../conversations/ui/ConversationActivity.java | 192 ++++++++++------ .../conversations/ui/ConversationFragment.java | 191 ++++++++------- .../conversations/ui/EditAccountActivity.java | 202 ++++++++-------- .../siacs/conversations/ui/ShareWithActivity.java | 4 +- .../ui/StartConversationActivity.java | 146 +++++++----- .../eu/siacs/conversations/ui/XmppActivity.java | 84 ++++--- .../ui/adapter/ConversationAdapter.java | 18 +- .../java/eu/siacs/conversations/utils/Xmlns.java | 5 + .../java/eu/siacs/conversations/utils/XmppUri.java | 1 - .../java/eu/siacs/conversations/xml/Element.java | 22 +- .../conversations/xmpp/OnContactStatusChanged.java | 2 +- .../conversations/xmpp/OnUpdateBlocklist.java | 13 ++ .../siacs/conversations/xmpp/XmppConnection.java | 256 +++++++++++---------- .../java/eu/siacs/conversations/xmpp/jid/Jid.java | 6 +- .../siacs/conversations/xmpp/stanzas/IqPacket.java | 63 ++--- src/main/res/menu/contact_context.xml | 3 + src/main/res/menu/conversations.xml | 12 + src/main/res/menu/editaccount.xml | 4 + src/main/res/values/strings.xml | 15 ++ 44 files changed, 1485 insertions(+), 904 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/entities/Blockable.java create mode 100644 src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java create mode 100644 src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java create mode 100644 src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java create mode 100644 src/main/java/eu/siacs/conversations/utils/Xmlns.java create mode 100644 src/main/java/eu/siacs/conversations/xmpp/OnUpdateBlocklist.java diff --git a/README.md b/README.md index 2181aa96..66213e46 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,11 @@ run your own XMPP server for you and your friends. These XEP's are: * XEP-0313: Message Archive Management synchronize message history with the server. Catch up with messages that were sent while Conversations was offline. -* XEP-0352: Client State Indication let the server know whether or not +* XEP-0352: Client State Indication lets the server know whether or not Conversations is in the background. Allows the server to save bandwidth by withholding unimportant packages. +* XEP-0191: Blocking command lets you blacklist spammers or block contacts + without removing them from your roster. ## Team diff --git a/docs/XEPs.md b/docs/XEPs.md index 980c1c65..35c7de45 100644 --- a/docs/XEPs.md +++ b/docs/XEPs.md @@ -16,3 +16,4 @@ * XEP-0313: Message Archive Management * XEP-0333: Chat Markers * XEP-0352: Client State Indication +* XEP-0191: Blocking command diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 8fdfa85b..5662e626 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -76,6 +76,9 @@ + bookmarks = new CopyOnWriteArrayList<>(); + private final Collection blocklist = new CopyOnWriteArraySet<>(); public Account() { this.uuid = "0"; @@ -279,7 +282,7 @@ public class Account extends AbstractEntity { return values; } - public void initOtrEngine(XmppConnectionService context) { + public void initOtrEngine(final XmppConnectionService context) { this.otrEngine = new OtrEngine(context, this); } @@ -291,7 +294,7 @@ public class Account extends AbstractEntity { return this.xmppConnection; } - public void setXmppConnection(XmppConnection connection) { + public void setXmppConnection(final XmppConnection connection) { this.xmppConnection = connection; } @@ -323,7 +326,7 @@ public class Account extends AbstractEntity { } } - public void setRosterVersion(String version) { + public void setRosterVersion(final String version) { this.rosterVersion = version; } @@ -351,7 +354,7 @@ public class Account extends AbstractEntity { return this.bookmarks; } - public void setBookmarks(List bookmarks) { + public void setBookmarks(final List bookmarks) { this.bookmarks = bookmarks; } @@ -399,4 +402,21 @@ public class Account extends AbstractEntity { return "xmpp:" + this.getJid().toBareJid().toString(); } } + + public boolean isBlocked(final ListItem contact) { + final Jid jid = contact.getJid(); + return jid != null && (blocklist.contains(jid.toBareJid()) || blocklist.contains(jid.toDomainJid())); + } + + public boolean isBlocked(final Jid jid) { + return jid != null && blocklist.contains(jid.toBareJid()); + } + + public Collection getBlocklist() { + return this.blocklist; + } + + public void clearBlocklist() { + getBlocklist().clear(); + } } diff --git a/src/main/java/eu/siacs/conversations/entities/Blockable.java b/src/main/java/eu/siacs/conversations/entities/Blockable.java new file mode 100644 index 00000000..dbcd55c4 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/entities/Blockable.java @@ -0,0 +1,11 @@ +package eu.siacs.conversations.entities; + +import eu.siacs.conversations.xmpp.jid.Jid; + +public interface Blockable { + public boolean isBlocked(); + public boolean isDomainBlocked(); + public Jid getBlockedJid(); + public Jid getJid(); + public Account getAccount(); +} diff --git a/src/main/java/eu/siacs/conversations/entities/Bookmark.java b/src/main/java/eu/siacs/conversations/entities/Bookmark.java index 20905648..f81f1a87 100644 --- a/src/main/java/eu/siacs/conversations/entities/Bookmark.java +++ b/src/main/java/eu/siacs/conversations/entities/Bookmark.java @@ -6,7 +6,6 @@ import java.util.Locale; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xml.Element; -import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; public class Bookmark extends Element implements ListItem { diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java index 0820504f..af26981e 100644 --- a/src/main/java/eu/siacs/conversations/entities/Contact.java +++ b/src/main/java/eu/siacs/conversations/entities/Contact.java @@ -16,7 +16,7 @@ import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; -public class Contact implements ListItem { +public class Contact implements ListItem, Blockable { public static final String TABLENAME = "contacts"; public static final String SYSTEMNAME = "systemname"; @@ -47,8 +47,8 @@ public class Contact implements ListItem { protected Account account; public Contact(final String account, final String systemName, final String serverName, - final Jid jid, final int subscription, final String photoUri, - final String systemAccount, final String keys, final String avatar, final Lastseen lastseen, final String groups) { + final Jid jid, final int subscription, final String photoUri, + final String systemAccount, final String keys, final String avatar, final Lastseen lastseen, final String groups) { this.accountUuid = account; this.systemName = systemName; this.serverName = serverName; @@ -122,11 +122,10 @@ public class Contact implements ListItem { @Override public List getTags() { - ArrayList tags = new ArrayList(); - for (String group : getGroups()) { + final ArrayList tags = new ArrayList<>(); + for (final String group : getGroups()) { tags.add(new Tag(group, UIHelper.getColorForName(group))); } - int status = getMostAvailableStatus(); switch (getMostAvailableStatus()) { case Presences.CHAT: case Presences.ONLINE: @@ -142,6 +141,9 @@ public class Contact implements ListItem { tags.add(new Tag("dnd", 0xffe51c23)); break; } + if (isBlocked()) { + tags.add(new Tag("blocked", 0xff2e2f3b)); + } return tags; } @@ -176,7 +178,7 @@ public class Contact implements ListItem { } public ContentValues getContentValues() { - ContentValues values = new ContentValues(); + final ContentValues values = new ContentValues(); values.put(ACCOUNT, accountUuid); values.put(SYSTEMNAME, systemName); values.put(SERVERNAME, serverName); @@ -213,11 +215,11 @@ public class Contact implements ListItem { this.presences = pres; } - public void updatePresence(String resource, int status) { + public void updatePresence(final String resource, final int status) { this.presences.updatePresence(resource, status); } - public void removePresence(String resource) { + public void removePresence(final String resource) { this.presences.removePresence(resource); } @@ -337,8 +339,8 @@ public class Contact implements ListItem { public boolean showInRoster() { return (this.getOption(Contact.Options.IN_ROSTER) && (!this - .getOption(Contact.Options.DIRTY_DELETE))) - || (this.getOption(Contact.Options.DIRTY_PUSH)); + .getOption(Contact.Options.DIRTY_DELETE))) + || (this.getOption(Contact.Options.DIRTY_PUSH)); } public void parseSubscriptionFromElement(Element item) { @@ -428,7 +430,7 @@ public class Contact implements ListItem { if (this.keys.has("otr_fingerprints")) { JSONArray newPrints = new JSONArray(); JSONArray oldPrints = this.keys - .getJSONArray("otr_fingerprints"); + .getJSONArray("otr_fingerprints"); for (int i = 0; i < oldPrints.length(); ++i) { if (!oldPrints.getString(i).equals(fingerprint)) { newPrints.put(oldPrints.getString(i)); @@ -457,22 +459,40 @@ public class Contact implements ListItem { } } + @Override + public boolean isBlocked() { + return getAccount().isBlocked(this); + } + + @Override + public boolean isDomainBlocked() { + return getAccount().isBlocked(this.getJid().toDomainJid()); + } + + @Override + public Jid getBlockedJid() { + if (isDomainBlocked()) { + return getJid().toDomainJid(); + } else { + return getJid(); + } + } + public static class Lastseen { public long time; public String presence; public Lastseen() { - time = 0; - presence = null; + this(null, 0); } public Lastseen(final String presence, final long time) { - this.time = time; this.presence = presence; + this.time = time; } } - public class Options { + public final class Options { public static final int TO = 0; public static final int FROM = 1; public static final int ASKING = 2; diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index e8482a96..22ddd307 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -3,7 +3,6 @@ package eu.siacs.conversations.entities; import android.content.ContentValues; import android.database.Cursor; import android.os.SystemClock; -import android.util.Log; import net.java.otr4j.OtrException; import net.java.otr4j.crypto.OtrCryptoEngineImpl; @@ -25,7 +24,7 @@ import eu.siacs.conversations.Config; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; -public class Conversation extends AbstractEntity { +public class Conversation extends AbstractEntity implements Blockable { public static final String TABLENAME = "conversations"; public static final int STATUS_AVAILABLE = 0; @@ -105,7 +104,7 @@ public class Conversation extends AbstractEntity { if ((message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) && message.getEncryption() != Message.ENCRYPTION_PGP) { onMessageFound.onMessageFound(message); - } + } } } } @@ -117,7 +116,7 @@ public class Conversation extends AbstractEntity { && message.getEncryption() != Message.ENCRYPTION_PGP && message.getUuid().equals(uuid)) { return message; - } + } } } return null; @@ -145,7 +144,7 @@ public class Conversation extends AbstractEntity { if ((message.getStatus() == Message.STATUS_UNSEND || message.getStatus() == Message.STATUS_WAITING) && (message.getEncryption() == Message.ENCRYPTION_OTR)) { onMessageFound.onMessageFound(message); - } + } } } } @@ -156,7 +155,7 @@ public class Conversation extends AbstractEntity { if (message.getType() != Message.TYPE_IMAGE && message.getStatus() == Message.STATUS_UNSEND) { onMessageFound.onMessageFound(message); - } + } } } } @@ -166,21 +165,37 @@ public class Conversation extends AbstractEntity { for (Message message : this.messages) { if (uuid.equals(message.getUuid()) || (message.getStatus() >= Message.STATUS_SEND && uuid - .equals(message.getRemoteMsgId()))) { + .equals(message.getRemoteMsgId()))) { return message; - } + } } } return null; } - public void populateWithMessages(List messages) { + public void populateWithMessages(final List messages) { synchronized (this.messages) { messages.clear(); messages.addAll(this.messages); } } + @Override + public boolean isBlocked() { + return getContact().isBlocked(); + } + + @Override + public boolean isDomainBlocked() { + return getContact().isDomainBlocked(); + } + + @Override + public Jid getBlockedJid() { + return getContact().getBlockedJid(); + } + + public interface OnMessageFound { public void onMessageFound(final Message message); } @@ -212,8 +227,8 @@ public class Conversation extends AbstractEntity { } public boolean isRead() { - return (this.messages == null) || (this.messages.size() == 0) || this.messages.get(this.messages.size() - 1).isRead(); - } + return (this.messages == null) || (this.messages.size() == 0) || this.messages.get(this.messages.size() - 1).isRead(); + } public void markRead() { if (this.messages == null) { @@ -239,7 +254,7 @@ public class Conversation extends AbstractEntity { } else { return this.messages.get(i); } - } + } } return null; } @@ -267,7 +282,7 @@ public class Conversation extends AbstractEntity { if (generatedName != null) { return generatedName; } else { - return getContactJid().getLocalpart(); + return getJid().getLocalpart(); } } } else { @@ -287,11 +302,12 @@ public class Conversation extends AbstractEntity { return this.account.getRoster().getContact(this.contactJid); } - public void setAccount(Account account) { + public void setAccount(final Account account) { this.account = account; } - public Jid getContactJid() { + @Override + public Jid getJid() { return this.contactJid; } @@ -318,14 +334,14 @@ public class Conversation extends AbstractEntity { } public static Conversation fromCursor(Cursor cursor) { - Jid jid; - try { - jid = Jid.fromString(cursor.getString(cursor.getColumnIndex(CONTACTJID))); - } catch (final InvalidJidException e) { - // Borked DB.. - jid = null; - } - return new Conversation(cursor.getString(cursor.getColumnIndex(UUID)), + Jid jid; + try { + jid = Jid.fromString(cursor.getString(cursor.getColumnIndex(CONTACTJID))); + } catch (final InvalidJidException e) { + // Borked DB.. + jid = null; + } + return new Conversation(cursor.getString(cursor.getColumnIndex(UUID)), cursor.getString(cursor.getColumnIndex(NAME)), cursor.getString(cursor.getColumnIndex(CONTACT)), cursor.getString(cursor.getColumnIndex(ACCOUNT)), @@ -352,9 +368,9 @@ public class Conversation extends AbstractEntity { if (this.otrSession != null) { return this.otrSession; } else { - final SessionID sessionId = new SessionID(this.getContactJid().toBareJid().toString(), - presence, - "xmpp"); + final SessionID sessionId = new SessionID(this.getJid().toBareJid().toString(), + presence, + "xmpp"); this.otrSession = new SessionImpl(sessionId, getAccount().getOtrEngine()); try { if (sendStart) { @@ -393,7 +409,7 @@ public class Conversation extends AbstractEntity { } catch (OtrException e) { this.resetOtrSession(); } - } + } } public boolean endOtrIfNeeded() { @@ -427,7 +443,7 @@ public class Conversation extends AbstractEntity { return ""; } DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession() - .getRemotePublicKey(); + .getRemotePublicKey(); StringBuilder builder = new StringBuilder( new OtrCryptoEngineImpl().getFingerprint(remotePubKey)); builder.insert(8, " "); diff --git a/src/main/java/eu/siacs/conversations/entities/ListItem.java b/src/main/java/eu/siacs/conversations/entities/ListItem.java index db9fbc37..efc1c2b9 100644 --- a/src/main/java/eu/siacs/conversations/entities/ListItem.java +++ b/src/main/java/eu/siacs/conversations/entities/ListItem.java @@ -12,10 +12,10 @@ public interface ListItem extends Comparable { public List getTags(); public final class Tag { - private String name; - private int color; + private final String name; + private final int color; - public Tag(String name, int color) { + public Tag(final String name, final int color) { this.name = name; this.color = color; } @@ -28,4 +28,6 @@ public interface ListItem extends Comparable { return this.name; } } + + public boolean match(final String needle); } diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 5b937138..38e88fa4 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -77,7 +77,7 @@ public class Message extends AbstractEntity { public Message(Conversation conversation, String body, int encryption, int status) { this(java.util.UUID.randomUUID().toString(), conversation.getUuid(), - conversation.getContactJid() == null ? null : conversation.getContactJid().toBareJid(), + conversation.getJid() == null ? null : conversation.getJid().toBareJid(), null, body, System.currentTimeMillis(), @@ -91,9 +91,9 @@ public class Message extends AbstractEntity { } private Message(final String uuid, final String conversationUUid, final Jid counterpart, - final Jid trueCounterpart, final String body, final long timeSent, - final int encryption, final int status, final int type, final String remoteMsgId, - final String relativeFilePath, final String serverMsgId) { + final Jid trueCounterpart, final String body, final long timeSent, + final int encryption, final int status, final int type, final String remoteMsgId, + final String relativeFilePath, final String serverMsgId) { this.uuid = uuid; this.conversationUuid = conversationUUid; this.counterpart = counterpart; @@ -206,7 +206,7 @@ public class Message extends AbstractEntity { return null; } else { return this.conversation.getAccount().getRoster() - .getContactFromRoster(this.trueCounterpart); + .getContactFromRoster(this.trueCounterpart); } } } @@ -312,10 +312,10 @@ public class Message extends AbstractEntity { return this.serverMsgId.equals(message.getServerMsgId()); } else { return this.body != null - && this.counterpart != null - && ((this.remoteMsgId != null && this.remoteMsgId.equals(message.getRemoteMsgId())) - || this.uuid.equals(message.getRemoteMsgId())) && this.body.equals(message.getBody()) - && this.counterpart.equals(message.getCounterpart()); + && this.counterpart != null + && ((this.remoteMsgId != null && this.remoteMsgId.equals(message.getRemoteMsgId())) + || this.uuid.equals(message.getRemoteMsgId())) && this.body.equals(message.getBody()) + && this.counterpart.equals(message.getCounterpart()); } } @@ -388,7 +388,7 @@ public class Message extends AbstractEntity { if (!url.getProtocol().equalsIgnoreCase("http") && !url.getProtocol().equalsIgnoreCase("https")) { return false; - } + } if (url.getPath() == null) { return false; } @@ -402,14 +402,14 @@ public class Message extends AbstractEntity { String[] extensionParts = filename.split("\\."); if (extensionParts.length == 2 && Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains( - extensionParts[extensionParts.length - 1])) { + extensionParts[extensionParts.length - 1])) { return true; } else if (extensionParts.length == 3 && Arrays .asList(Downloadable.VALID_CRYPTO_EXTENSIONS) .contains(extensionParts[extensionParts.length - 1]) && Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains( - extensionParts[extensionParts.length - 2])) { + extensionParts[extensionParts.length - 2])) { return true; } else { return false; diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index c8706fc9..97a63532 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -80,20 +80,20 @@ public class MucOptions { public void setRole(String role) { role = role.toLowerCase(); - switch (role) { - case "moderator": - this.role = ROLE_MODERATOR; - break; - case "participant": - this.role = ROLE_PARTICIPANT; - break; - case "visitor": - this.role = ROLE_VISITOR; - break; - default: - this.role = ROLE_NONE; - break; - } + switch (role) { + case "moderator": + this.role = ROLE_MODERATOR; + break; + case "participant": + this.role = ROLE_PARTICIPANT; + break; + case "visitor": + this.role = ROLE_VISITOR; + break; + default: + this.role = ROLE_NONE; + break; + } } public int getAffiliation() { @@ -164,7 +164,7 @@ public class MucOptions { } public void processPacket(PresencePacket packet, PgpEngine pgp) { - final Jid from = packet.getFrom(); + final Jid from = packet.getFrom(); if (!from.isBareJid()) { final String name = from.getResourcepart(); final String type = packet.getAttribute("type"); @@ -179,7 +179,7 @@ public class MucOptions { user.setAffiliation(item.getAttribute("affiliation")); user.setRole(item.getAttribute("role")); user.setJid(item.getAttributeAsJid("jid")); - if (codes.contains(STATUS_CODE_SELF_PRESENCE) || packet.getFrom().equals(this.conversation.getContactJid())) { + if (codes.contains(STATUS_CODE_SELF_PRESENCE) || packet.getFrom().equals(this.conversation.getJid())) { this.isOnline = true; this.error = ERROR_NO_ERROR; self = user; @@ -204,14 +204,14 @@ public class MucOptions { msg = ""; } user.setPgpKeyId(pgp.fetchKeyId(account, msg, - signed.getContent())); + signed.getContent())); } } } } } else if (type.equals("unavailable")) { if (codes.contains(STATUS_CODE_SELF_PRESENCE) || - packet.getFrom().equals(this.conversation.getContactJid())) { + packet.getFrom().equals(this.conversation.getJid())) { if (codes.contains(STATUS_CODE_CHANGED_NICK)) { this.mNickChangingInProgress = true; } else if (codes.contains(STATUS_CODE_KICKED)) { @@ -282,8 +282,8 @@ public class MucOptions { && conversation.getBookmark().getNick() != null && !conversation.getBookmark().getNick().isEmpty()) { return conversation.getBookmark().getNick(); - } else if (!conversation.getContactJid().isBareJid()) { - return conversation.getContactJid().getResourcepart(); + } else if (!conversation.getJid().isBareJid()) { + return conversation.getJid().getResourcepart(); } else { return account.getUsername(); } @@ -334,14 +334,14 @@ public class MucOptions { public String createNameFromParticipants() { if (users.size() >= 2) { List names = new ArrayList(); - for (User user : users) { - Contact contact = user.getContact(); - if (contact != null && !contact.getDisplayName().isEmpty()) { - names.add(contact.getDisplayName().split("\\s+")[0]); - } else { - names.add(user.getName()); - } + for (User user : users) { + Contact contact = user.getContact(); + if (contact != null && !contact.getDisplayName().isEmpty()) { + names.add(contact.getDisplayName().split("\\s+")[0]); + } else { + names.add(user.getName()); } + } StringBuilder builder = new StringBuilder(); for (int i = 0; i < names.size(); ++i) { builder.append(names.get(i)); @@ -388,12 +388,12 @@ public class MucOptions { } public Jid createJoinJid(String nick) { - try { - return Jid.fromString(this.conversation.getContactJid().toBareJid().toString() + "/"+nick); - } catch (final InvalidJidException e) { - return null; - } - } + try { + return Jid.fromString(this.conversation.getJid().toBareJid().toString() + "/"+nick); + } catch (final InvalidJidException e) { + return null; + } + } public Jid getTrueCounterpart(String counterpart) { for (User user : this.getUsers()) { diff --git a/src/main/java/eu/siacs/conversations/entities/Roster.java b/src/main/java/eu/siacs/conversations/entities/Roster.java index 12a89cec..1a81a419 100644 --- a/src/main/java/eu/siacs/conversations/entities/Roster.java +++ b/src/main/java/eu/siacs/conversations/entities/Roster.java @@ -7,7 +7,7 @@ import java.util.concurrent.ConcurrentHashMap; import eu.siacs.conversations.xmpp.jid.Jid; public class Roster { - Account account; + final Account account; final ConcurrentHashMap contacts = new ConcurrentHashMap<>(); private String version = null; @@ -19,7 +19,7 @@ public class Roster { if (jid == null) { return null; } - Contact contact = contacts.get(jid.toBareJid().toString()); + final Contact contact = contacts.get(jid.toBareJid().toString()); if (contact != null && contact.showInRoster()) { return contact; } else { @@ -32,7 +32,7 @@ public class Roster { if (contacts.containsKey(bareJid.toString())) { return contacts.get(bareJid.toString()); } else { - Contact contact = new Contact(bareJid); + final Contact contact = new Contact(bareJid); contact.setAccount(account); contacts.put(bareJid.toString(), contact); return contact; @@ -46,13 +46,13 @@ public class Roster { } public void markAllAsNotInRoster() { - for (Contact contact : getContacts()) { + for (final Contact contact : getContacts()) { contact.resetOption(Contact.Options.IN_ROSTER); } } public void clearSystemAccounts() { - for (Contact contact : getContacts()) { + for (final Contact contact : getContacts()) { contact.setPhotoUri(null); contact.setSystemName(null); contact.setSystemAccount(null); diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 4819f96e..4b28e484 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -1,14 +1,12 @@ package eu.siacs.conversations.generator; -import android.util.Log; - import java.util.Arrays; import java.util.Collections; import java.util.List; -import eu.siacs.conversations.Config; import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.utils.Xmlns; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.forms.Data; import eu.siacs.conversations.xmpp.jid.Jid; @@ -17,44 +15,44 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket; public class IqGenerator extends AbstractGenerator { - public IqGenerator(XmppConnectionService service) { + public IqGenerator(final XmppConnectionService service) { super(service); } - public IqPacket discoResponse(IqPacket request) { - IqPacket packet = new IqPacket(IqPacket.TYPE_RESULT); + public IqPacket discoResponse(final IqPacket request) { + final IqPacket packet = new IqPacket(IqPacket.TYPE_RESULT); packet.setId(request.getId()); - packet.setTo(request.getFrom()); - Element query = packet.addChild("query", + packet.setTo(request.getFrom()); + final Element query = packet.addChild("query", "http://jabber.org/protocol/disco#info"); query.setAttribute("node", request.query().getAttribute("node")); - Element identity = query.addChild("identity"); + final Element identity = query.addChild("identity"); identity.setAttribute("category", "client"); identity.setAttribute("type", this.IDENTITY_TYPE); identity.setAttribute("name", IDENTITY_NAME); - List features = Arrays.asList(FEATURES); + final List features = Arrays.asList(FEATURES); Collections.sort(features); - for (String feature : features) { + for (final String feature : features) { query.addChild("feature").setAttribute("var", feature); } return packet; } - protected IqPacket publish(String node, Element item) { - IqPacket packet = new IqPacket(IqPacket.TYPE_SET); - Element pubsub = packet.addChild("pubsub", + protected IqPacket publish(final String node, final Element item) { + final IqPacket packet = new IqPacket(IqPacket.TYPE_SET); + final Element pubsub = packet.addChild("pubsub", "http://jabber.org/protocol/pubsub"); - Element publish = pubsub.addChild("publish"); + final Element publish = pubsub.addChild("publish"); publish.setAttribute("node", node); publish.addChild(item); return packet; } protected IqPacket retrieve(String node, Element item) { - IqPacket packet = new IqPacket(IqPacket.TYPE_GET); - Element pubsub = packet.addChild("pubsub", + final IqPacket packet = new IqPacket(IqPacket.TYPE_GET); + final Element pubsub = packet.addChild("pubsub", "http://jabber.org/protocol/pubsub"); - Element items = pubsub.addChild("items"); + final Element items = pubsub.addChild("items"); items.setAttribute("node", node); if (item != null) { items.addChild(item); @@ -63,19 +61,19 @@ public class IqGenerator extends AbstractGenerator { } public IqPacket publishAvatar(Avatar avatar) { - Element item = new Element("item"); + final Element item = new Element("item"); item.setAttribute("id", avatar.sha1sum); - Element data = item.addChild("data", "urn:xmpp:avatar:data"); + final Element data = item.addChild("data", "urn:xmpp:avatar:data"); data.setContent(avatar.image); return publish("urn:xmpp:avatar:data", item); } - public IqPacket publishAvatarMetadata(Avatar avatar) { - Element item = new Element("item"); + public IqPacket publishAvatarMetadata(final Avatar avatar) { + final Element item = new Element("item"); item.setAttribute("id", avatar.sha1sum); - Element metadata = item - .addChild("metadata", "urn:xmpp:avatar:metadata"); - Element info = metadata.addChild("info"); + final Element metadata = item + .addChild("metadata", "urn:xmpp:avatar:metadata"); + final Element info = metadata.addChild("info"); info.setAttribute("bytes", avatar.size); info.setAttribute("id", avatar.sha1sum); info.setAttribute("height", avatar.height); @@ -84,10 +82,10 @@ public class IqGenerator extends AbstractGenerator { return publish("urn:xmpp:avatar:metadata", item); } - public IqPacket retrieveAvatar(Avatar avatar) { - Element item = new Element("item"); + public IqPacket retrieveAvatar(final Avatar avatar) { + final Element item = new Element("item"); item.setAttribute("id", avatar.sha1sum); - IqPacket packet = retrieve("urn:xmpp:avatar:data", item); + final IqPacket packet = retrieve("urn:xmpp:avatar:data", item); packet.setTo(avatar.owner); return packet; } @@ -100,11 +98,11 @@ public class IqGenerator extends AbstractGenerator { return packet; } - public IqPacket queryMessageArchiveManagement(MessageArchiveService.Query mam) { + public IqPacket queryMessageArchiveManagement(final MessageArchiveService.Query mam) { final IqPacket packet = new IqPacket(IqPacket.TYPE_SET); - Element query = packet.query("urn:xmpp:mam:0"); + final Element query = packet.query("urn:xmpp:mam:0"); query.setAttribute("queryid",mam.getQueryId()); - Data data = new Data(); + final Data data = new Data(); data.setFormType("urn:xmpp:mam:0"); if (mam.getWith()!=null) { data.put("with", mam.getWith().toString()); @@ -119,4 +117,25 @@ public class IqGenerator extends AbstractGenerator { } return packet; } + + public IqPacket generateGetBlockList() { + final IqPacket iq = new IqPacket(IqPacket.TYPE_GET); + iq.addChild("blocklist", Xmlns.BLOCKING); + + return iq; + } + + public IqPacket generateSetBlockRequest(final Jid jid) { + final IqPacket iq = new IqPacket(IqPacket.TYPE_SET); + final Element block = iq.addChild("block", Xmlns.BLOCKING); + block.addChild("item").setAttribute("jid", jid.toBareJid().toString()); + return iq; + } + + public IqPacket generateSetUnblockRequest(final Jid jid) { + final IqPacket iq = new IqPacket(IqPacket.TYPE_SET); + final Element block = iq.addChild("unblock", Xmlns.BLOCKING); + block.addChild("item").setAttribute("jid", jid.toBareJid().toString()); + return iq; + } } diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java index ca5417e0..8e99888b 100644 --- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java @@ -114,7 +114,7 @@ public class MessageGenerator extends AbstractGenerator { private MessagePacket generateError(MessagePacket origin) { MessagePacket packet = new MessagePacket(); packet.setId(origin.getId()); - packet.setTo(origin.getFrom()); + packet.setTo(origin.getFrom()); packet.setBody(origin.getBody()); packet.setType(MessagePacket.TYPE_ERROR); return packet; @@ -135,7 +135,7 @@ public class MessageGenerator extends AbstractGenerator { String subject) { MessagePacket packet = new MessagePacket(); packet.setType(MessagePacket.TYPE_GROUPCHAT); - packet.setTo(conversation.getContactJid().toBareJid()); + packet.setTo(conversation.getJid().toBareJid()); Element subjectChild = new Element("subject"); subjectChild.setContent(subject); packet.addChild(subjectChild); @@ -149,13 +149,13 @@ public class MessageGenerator extends AbstractGenerator { packet.setTo(contact); packet.setFrom(conversation.getAccount().getJid()); Element x = packet.addChild("x", "jabber:x:conference"); - x.setAttribute("jid", conversation.getContactJid().toBareJid().toString()); + x.setAttribute("jid", conversation.getJid().toBareJid().toString()); return packet; } public MessagePacket invite(Conversation conversation, Jid contact) { MessagePacket packet = new MessagePacket(); - packet.setTo(conversation.getContactJid().toBareJid()); + packet.setTo(conversation.getJid().toBareJid()); packet.setFrom(conversation.getAccount().getJid()); Element x = new Element("x"); x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user"); @@ -170,7 +170,7 @@ public class MessageGenerator extends AbstractGenerator { MessagePacket originalMessage, String namespace) { MessagePacket receivedPacket = new MessagePacket(); receivedPacket.setType(MessagePacket.TYPE_NORMAL); - receivedPacket.setTo(originalMessage.getFrom()); + receivedPacket.setTo(originalMessage.getFrom()); receivedPacket.setFrom(account.getJid()); Element received = receivedPacket.addChild("received", namespace); received.setAttribute("id", originalMessage.getId()); diff --git a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java index 39cbff4f..8afc2ae0 100644 --- a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java +++ b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java @@ -53,10 +53,10 @@ public abstract class AbstractParser { protected void updateLastseen(final Element packet, final Account account, final boolean presenceOverwrite) { - Jid from = packet.getAttributeAsJid("from"); - String presence = from == null || from.isBareJid() ? "" : from.getResourcepart(); - Contact contact = account.getRoster().getContact(from); - long timestamp = getTimestamp(packet); + final Jid from = packet.getAttributeAsJid("from"); + final String presence = from == null || from.isBareJid() ? "" : from.getResourcepart(); + final Contact contact = account.getRoster().getContact(from); + final long timestamp = getTimestamp(packet); if (timestamp >= contact.lastseen.time) { contact.lastseen.time = timestamp; if (!presence.isEmpty() && presenceOverwrite) { diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java index b583a1a1..b77d460d 100644 --- a/src/main/java/eu/siacs/conversations/parser/IqParser.java +++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java @@ -2,36 +2,40 @@ package eu.siacs.conversations.parser; import android.util.Log; +import java.util.ArrayList; +import java.util.Collection; + import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.utils.Xmlns; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnIqPacketReceived; -import eu.siacs.conversations.xmpp.jid.InvalidJidException; +import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.stanzas.IqPacket; public class IqParser extends AbstractParser implements OnIqPacketReceived { - public IqParser(XmppConnectionService service) { + public IqParser(final XmppConnectionService service) { super(service); } - public void rosterItems(Account account, Element query) { - String version = query.getAttribute("ver"); + public void rosterItems(final Account account, final Element query) { + final String version = query.getAttribute("ver"); if (version != null) { account.getRoster().setVersion(version); } - for (Element item : query.getChildren()) { + for (final Element item : query.getChildren()) { if (item.getName().equals("item")) { final Jid jid = item.getAttributeAsJid("jid"); if (jid == null) { continue; } - String name = item.getAttribute("name"); - String subscription = item.getAttribute("subscription"); - Contact contact = account.getRoster().getContact(jid); + final String name = item.getAttribute("name"); + final String subscription = item.getAttribute("subscription"); + final Contact contact = account.getRoster().getContact(jid); if (!contact.getOption(Contact.Options.DIRTY_PUSH)) { contact.setServerName(name); contact.parseGroupsFromElement(item); @@ -54,13 +58,13 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { mXmppConnectionService.updateRosterUi(); } - public String avatarData(IqPacket packet) { - Element pubsub = packet.findChild("pubsub", + public String avatarData(final IqPacket packet) { + final Element pubsub = packet.findChild("pubsub", "http://jabber.org/protocol/pubsub"); if (pubsub == null) { return null; } - Element items = pubsub.findChild("items"); + final Element items = pubsub.findChild("items"); if (items == null) { return null; } @@ -68,13 +72,76 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { } @Override - public void onIqPacketReceived(Account account, IqPacket packet) { + public void onIqPacketReceived(final Account account, final IqPacket packet) { if (packet.hasChild("query", "jabber:iq:roster")) { final Jid from = packet.getFrom(); if ((from == null) || (from.equals(account.getJid().toBareJid()))) { - Element query = packet.findChild("query"); + final Element query = packet.findChild("query"); this.rosterItems(account, query); } + } else if (packet.hasChild("block", Xmlns.BLOCKING) || packet.hasChild("blocklist", Xmlns.BLOCKING)) { + // Only accept block list changes from the server. + // The server should probably prevent other people from faking a blocklist push, + // but just in case let's prevent it client side as well. + final Jid from = packet.getFrom(); + if (from == null || from.equals(account.getServer()) || from.equals(account.getJid().toBareJid())) { + Log.d(Config.LOGTAG, "Received blocklist update from server"); + final Element blocklist = packet.findChild("blocklist", Xmlns.BLOCKING); + final Element block = packet.findChild("block", Xmlns.BLOCKING); + final Collection items = blocklist != null ? blocklist.getChildren() : + (block != null ? block.getChildren() : null); + // If this is a response to a blocklist query, clear the block list and replace with the new one. + // Otherwise, just update the existing blocklist. + if (packet.getType() == IqPacket.TYPE_RESULT) { + account.clearBlocklist(); + } + if (items != null) { + final Collection jids = new ArrayList<>(items.size()); + // Create a collection of Jids from the packet + for (final Element item : items) { + if (item.getName().equals("item")) { + final Jid jid = item.getAttributeAsJid("jid"); + if (jid != null) { + jids.add(jid); + } + } + } + account.getBlocklist().addAll(jids); + } + // Update the UI + mXmppConnectionService.updateBlocklistUi(OnUpdateBlocklist.Status.BLOCKED); + } else { + Log.d(Config.LOGTAG, "Received blocklist update from invalid jid: " + from.toString()); + } + } else if (packet.hasChild("unblock", Xmlns.BLOCKING)) { + final Jid from = packet.getFrom(); + if ((from == null || from.equals(account.getServer()) || from.equals(account.getJid().toBareJid())) && + packet.getType() == IqPacket.TYPE_SET) { + Log.d(Config.LOGTAG, "Received unblock update from server"); + final Collection items = packet.getChildren().get(0).getChildren(); + if (items.size() == 0) { + // No children to unblock == unblock all + account.getBlocklist().clear(); + } else { + final Collection jids = new ArrayList<>(items.size()); + for (final Element item : items) { + if (item.getName().equals("item")) { + final Jid jid = item.getAttributeAsJid("jid"); + if (jid != null) { + jids.add(jid); + } + } + } + account.getBlocklist().removeAll(jids); + mXmppConnectionService.updateBlocklistUi(OnUpdateBlocklist.Status.UNBLOCKED); + } + } else { + if (packet.getType() == IqPacket.TYPE_SET) { + Log.d(Config.LOGTAG, "Received unblock update from invalid jid " + from.toString()); + } else { + Log.d(Config.LOGTAG, "Received unblock update with invalid type " + packet.getType()); + } + } } else { if (packet.getFrom() == null) { Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": received iq with invalid from "+packet.toString()); @@ -82,24 +149,24 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { } else if (packet.hasChild("open", "http://jabber.org/protocol/ibb") || packet.hasChild("data", "http://jabber.org/protocol/ibb")) { mXmppConnectionService.getJingleConnectionManager() - .deliverIbbPacket(account, packet); + .deliverIbbPacket(account, packet); } else if (packet.hasChild("query", "http://jabber.org/protocol/disco#info")) { - IqPacket response = mXmppConnectionService.getIqGenerator() - .discoResponse(packet); + final IqPacket response = mXmppConnectionService.getIqGenerator() + .discoResponse(packet); account.getXmppConnection().sendIqPacket(response, null); } else if (packet.hasChild("ping", "urn:xmpp:ping")) { - IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT); + final IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT); mXmppConnectionService.sendIqPacket(account, response, null); } else { if ((packet.getType() == IqPacket.TYPE_GET) || (packet.getType() == IqPacket.TYPE_SET)) { - IqPacket response = packet.generateRespone(IqPacket.TYPE_ERROR); - Element error = response.addChild("error"); + final IqPacket response = packet.generateRespone(IqPacket.TYPE_ERROR); + final Element error = response.addChild("error"); error.setAttribute("type", "cancel"); error.addChild("feature-not-implemented", "urn:ietf:params:xml:ns:xmpp-stanzas"); account.getXmppConnection().sendIqPacket(response, null); - } + } } } } diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index aa07d9c0..7d29314b 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -228,9 +228,9 @@ public class DatabaseBackend extends SQLiteOpenHelper { return conversation; } - public void updateConversation(Conversation conversation) { - SQLiteDatabase db = this.getWritableDatabase(); - String[] args = { conversation.getUuid() }; + public void updateConversation(final Conversation conversation) { + final SQLiteDatabase db = this.getWritableDatabase(); + final String[] args = { conversation.getUuid() }; db.update(Conversation.TABLENAME, conversation.getContentValues(), Conversation.UUID + "=?", args); } diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index 1a161c56..3fef5703 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -236,7 +236,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { public Query(Conversation conversation, long start, long end) { this(conversation.getAccount(), start, end); this.conversation = conversation; - this.with = conversation.getContactJid().toBareJid(); + this.with = conversation.getJid().toBareJid(); } public Query(Conversation conversation, long start, long end, PagingOrder order) { diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index dc3b3200..65c631a1 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -35,11 +35,13 @@ import org.openintents.openpgp.util.OpenPgpServiceConnection; import java.math.BigInteger; import java.security.SecureRandom; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Hashtable; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import de.duenndns.ssl.MemorizingTrustManager; @@ -47,11 +49,11 @@ import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.PgpEngine; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Blockable; import eu.siacs.conversations.entities.Bookmark; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Downloadable; -import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.DownloadablePlaceholder; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; @@ -77,7 +79,11 @@ import eu.siacs.conversations.xmpp.OnBindListener; import eu.siacs.conversations.xmpp.OnContactStatusChanged; import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.OnMessageAcknowledged; +import eu.siacs.conversations.xmpp.OnMessagePacketReceived; +import eu.siacs.conversations.xmpp.OnPresencePacketReceived; import eu.siacs.conversations.xmpp.OnStatusChanged; +import eu.siacs.conversations.xmpp.OnUpdateBlocklist; +import eu.siacs.conversations.xmpp.PacketReceived; import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.forms.Data; import eu.siacs.conversations.xmpp.forms.Field; @@ -93,9 +99,10 @@ import eu.siacs.conversations.xmpp.stanzas.PresencePacket; public class XmppConnectionService extends Service implements OnPhoneContactsLoadedListener { - public static String ACTION_CLEAR_NOTIFICATION = "clear_notification"; - private static String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts"; - public static String ACTION_DISABLE_FOREGROUND = "disable_foreground"; + public static final String ACTION_CLEAR_NOTIFICATION = "clear_notification"; + private static final String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts"; + public static final String ACTION_DISABLE_FOREGROUND = "disable_foreground"; + private ContentObserver contactObserver = new ContentObserver(null) { @Override public void onChange(boolean selfChange) { @@ -129,13 +136,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa private MemorizingTrustManager mMemorizingTrustManager; private NotificationService mNotificationService = new NotificationService( this); - private MessageParser mMessageParser = new MessageParser(this); - private PresenceParser mPresenceParser = new PresenceParser(this); + private OnMessagePacketReceived mMessageParser = new MessageParser(this); + private OnPresencePacketReceived mPresenceParser = new PresenceParser(this); private IqParser mIqParser = new IqParser(this); private MessageGenerator mMessageGenerator = new MessageGenerator(this); private PresenceGenerator mPresenceGenerator = new PresenceGenerator(this); private List accounts; - private final CopyOnWriteArrayList conversations = new CopyOnWriteArrayList(); + private final List conversations = new CopyOnWriteArrayList<>(); private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager( this); private HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager( @@ -208,6 +215,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa private int accountChangedListenerCount = 0; private OnRosterUpdate mOnRosterUpdate = null; + private OnUpdateBlocklist mOnUpdateBlocklist = null; + private int updateBlocklistListenerCount = 0; private int rosterChangedListenerCount = 0; private OnMucRosterUpdate mOnMucRosterUpdate = null; private int mucRosterChangedListenerCount = 0; @@ -354,13 +363,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa @Override public void run() { try { - DownloadableFile file = getFileBackend().copyImageToPrivateStorage(message, uri); + getFileBackend().copyImageToPrivateStorage(message, uri); if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) { getPgpEngine().encrypt(message, callback); } else { callback.success(message); } - } catch (FileBackend.FileCopyException e) { + } catch (final FileBackend.FileCopyException e) { callback.error(e.getResId(), message); } } @@ -573,11 +582,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } - public XmppConnection createConnection(Account account) { - SharedPreferences sharedPref = getPreferences(); + public XmppConnection createConnection(final Account account) { + final SharedPreferences sharedPref = getPreferences(); account.setResource(sharedPref.getString("resource", "mobile") .toLowerCase(Locale.getDefault())); - XmppConnection connection = new XmppConnection(account, this); + final XmppConnection connection = new XmppConnection(account, this); connection.setOnMessagePacketReceivedListener(this.mMessageParser); connection.setOnStatusChangedListener(this.statusListener); connection.setOnPresencePacketReceivedListener(this.mPresenceParser); @@ -589,10 +598,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return connection; } - public void sendMessage(Message message) { - Account account = message.getConversation().getAccount(); + public void sendMessage(final Message message) { + final Account account = message.getConversation().getAccount(); account.deactivateGracePeriod(); - Conversation conv = message.getConversation(); + final Conversation conv = message.getConversation(); MessagePacket packet = null; boolean saveInDb = true; boolean send = false; @@ -694,7 +703,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa updateConversationUi(); } - private void sendUnsentMessages(Conversation conversation) { + private void sendUnsentMessages(final Conversation conversation) { conversation.findWaitingMessages(new Conversation.OnMessageFound() { @Override @@ -704,7 +713,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa }); } - private void resendMessage(Message message) { + private void resendMessage(final Message message) { Account account = message.getConversation().getAccount(); MessagePacket packet = null; if (message.getEncryption() == Message.ENCRYPTION_OTR) { @@ -731,7 +740,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) { mJingleConnectionManager.createNewConnection(message); } - } catch (InvalidJidException e) { + } catch (final InvalidJidException ignored) { } } @@ -774,8 +783,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } - public void fetchRosterFromServer(Account account) { - IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET); + public void fetchRosterFromServer(final Account account) { + final IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET); if (!"".equals(account.getRosterVersion())) { Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": fetching roster version " + account.getRosterVersion()); @@ -789,8 +798,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa @Override public void onIqPacketReceived(final Account account, - IqPacket packet) { - Element query = packet.findChild("query"); + final IqPacket packet) { + final Element query = packet.findChild("query"); if (query != null) { account.getRoster().markAllAsNotInRoster(); mIqParser.rosterItems(account, query); @@ -799,22 +808,22 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa }); } - public void fetchBookmarks(Account account) { - IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET); - Element query = iqPacket.query("jabber:iq:private"); + public void fetchBookmarks(final Account account) { + final IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET); + final Element query = iqPacket.query("jabber:iq:private"); query.addChild("storage", "storage:bookmarks"); - OnIqPacketReceived callback = new OnIqPacketReceived() { + final PacketReceived callback = new OnIqPacketReceived() { @Override - public void onIqPacketReceived(Account account, IqPacket packet) { - Element query = packet.query(); - List bookmarks = new CopyOnWriteArrayList<>(); - Element storage = query.findChild("storage", + public void onIqPacketReceived(final Account account, final IqPacket packet) { + final Element query = packet.query(); + final List bookmarks = new CopyOnWriteArrayList<>(); + final Element storage = query.findChild("storage", "storage:bookmarks"); if (storage != null) { - for (Element item : storage.getChildren()) { + for (final Element item : storage.getChildren()) { if (item.getName().equals("conference")) { - Bookmark bookmark = Bookmark.parse(item, account); + final Bookmark bookmark = Bookmark.parse(item, account); bookmarks.add(bookmark); Conversation conversation = find(bookmark); if (conversation != null) { @@ -832,7 +841,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } }; sendIqPacket(account, iqPacket, callback); - } public void pushBookmarks(Account account) { @@ -868,8 +876,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } final Contact contact = account.getRoster().getContact(jid); String systemAccount = phoneContact.getInt("phoneid") - + "#" - + phoneContact.getString("lookup"); + + "#" + + phoneContact.getString("lookup"); contact.setSystemAccount(systemAccount); contact.setPhotoUri(phoneContact.getString("photouri")); getAvatarService().clear(contact); @@ -885,7 +893,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa private void initConversations() { synchronized (this.conversations) { - Hashtable accountLookupTable = new Hashtable<>(); + final Map accountLookupTable = new Hashtable<>(); for (Account account : this.accounts) { accountLookupTable.put(account.getUuid(), account); } @@ -992,8 +1000,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return this.accounts; } - public Conversation find(List haystack, Contact contact) { - for (Conversation conversation : haystack) { + public Conversation find(final Iterable haystack, final Contact contact) { + for (final Conversation conversation : haystack) { if (conversation.getContact() == contact) { return conversation; } @@ -1001,15 +1009,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return null; } - public Conversation find(final List haystack, - final Account account, - final Jid jid) { + public Conversation find(final Iterable haystack, final Account account, final Jid jid) { if (jid == null ) { return null; } - for (Conversation conversation : haystack) { + for (final Conversation conversation : haystack) { if ((account == null || conversation.getAccount() == account) - && (conversation.getContactJid().toBareJid().equals(jid.toBareJid()))) { + && (conversation.getJid().toBareJid().equals(jid.toBareJid()))) { return conversation; } } @@ -1177,7 +1183,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } - public void setOnRosterUpdateListener(OnRosterUpdate listener) { + public void setOnRosterUpdateListener(final OnRosterUpdate listener) { synchronized (this) { if (checkListeners()) { switchToForeground(); @@ -1202,6 +1208,31 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } + public void setOnUpdateBlocklistListener(final OnUpdateBlocklist listener) { + synchronized (this) { + if (checkListeners()) { + switchToForeground(); + } + this.mOnUpdateBlocklist = listener; + if (this.updateBlocklistListenerCount < 2) { + this.updateBlocklistListenerCount++; + } + } + } + + public void removeOnUpdateBlocklistListener() { + synchronized (this) { + this.updateBlocklistListenerCount--; + if (this.updateBlocklistListenerCount <= 0) { + this.updateBlocklistListenerCount = 0; + this.mOnUpdateBlocklist = null; + if (checkListeners()) { + switchToBackground(); + } + } + } + } + public void setOnMucRosterUpdateListener(OnMucRosterUpdate listener) { synchronized (this) { if (checkListeners()) { @@ -1264,7 +1295,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa && (conversation.getAccount() == account)) { conversation.resetMucOptions(); joinMuc(conversation); - } + } } } @@ -1293,7 +1324,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa packet.addChild("x", "jabber:x:signed").setContent(sig); } sendPresencePacket(account, packet); - if (!joinJid.equals(conversation.getContactJid())) { + if (!joinJid.equals(conversation.getJid())) { conversation.setContactJid(joinJid); databaseBackend.updateConversation(conversation); } @@ -1369,14 +1400,14 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa account.pendingConferenceLeaves.remove(conversation); if (account.getStatus() == Account.State.ONLINE) { PresencePacket packet = new PresencePacket(); - packet.setTo(conversation.getContactJid()); + packet.setTo(conversation.getJid()); packet.setFrom(conversation.getAccount().getJid()); packet.setAttribute("type", "unavailable"); sendPresencePacket(conversation.getAccount(), packet); conversation.getMucOptions().setOffline(); conversation.deregisterWithBookmark(); Log.d(Config.LOGTAG, conversation.getAccount().getJid().toBareJid() - + ": leaving muc " + conversation.getContactJid()); + + ": leaving muc " + conversation.getJid()); } else { account.pendingConferenceLeaves.add(conversation); } @@ -1401,7 +1432,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return null; } - public void createAdhocConference(final Account account, final List jids, final UiCallback callback) { + public void createAdhocConference(final Account account, final Iterable jids, final UiCallback callback) { Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": creating adhoc conference with "+ jids.toString()); if (account.getStatus() == Account.State.ONLINE) { try { @@ -1454,7 +1485,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa public void pushConferenceConfiguration(final Conversation conversation,final Bundle options, final OnConferenceOptionsPushed callback) { IqPacket request = new IqPacket(IqPacket.TYPE_GET); - request.setTo(conversation.getContactJid().toBareJid()); + request.setTo(conversation.getJid().toBareJid()); request.query("http://jabber.org/protocol/muc#owner"); sendIqPacket(conversation.getAccount(),request,new OnIqPacketReceived() { @Override @@ -1468,7 +1499,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } data.submit(); IqPacket set = new IqPacket(IqPacket.TYPE_SET); - set.setTo(conversation.getContactJid().toBareJid()); + set.setTo(conversation.getJid().toBareJid()); set.query("http://jabber.org/protocol/muc#owner").addChild(data); sendIqPacket(account, set, new OnIqPacketReceived() { @Override @@ -1506,7 +1537,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa if (conversation.endOtrIfNeeded()) { Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": ended otr session with " - + conversation.getContactJid()); + + conversation.getJid()); } } } @@ -1552,8 +1583,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa final Session otrSession = conversation.getOtrSession(); Log.d(Config.LOGTAG, account.getJid().toBareJid() + " otr session established with " - + conversation.getContactJid() + "/" - + otrSession.getSessionID().getUserID()); + + conversation.getJid() + "/" + + otrSession.getSessionID().getUserID()); conversation.findUnsentMessagesWithOtrEncryption(new Conversation.OnMessageFound() { @Override @@ -1698,7 +1729,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa @Override public void onIqPacketReceived(Account account, IqPacket result) { final String ERROR = account.getJid().toBareJid() - + ": fetching avatar for " + avatar.owner + " failed "; + + ": fetching avatar for " + avatar.owner + " failed "; if (result.getType() == IqPacket.TYPE_RESULT) { avatar.image = mIqParser.avatarData(result); if (avatar.image != null) { @@ -1712,7 +1743,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa updateAccountUi(); } else { Contact contact = account.getRoster() - .getContact(avatar.owner); + .getContact(avatar.owner); contact.setAvatar(avatar.getFilename()); getAvatarService().clear(contact); updateConversationUi(); @@ -1848,7 +1879,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return false; } else { for (Conversation conversation : getConversations()) { - if (conversation.getContactJid().equals(recipient) + if (conversation.getJid().equals(recipient) && conversation.getAccount().equals(account)) { return markMessage(conversation, uuid, status); } @@ -1922,6 +1953,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } + public void updateBlocklistUi(final OnUpdateBlocklist.Status status) { + if (mOnUpdateBlocklist != null) { + mOnUpdateBlocklist.OnUpdateBlocklist(status); + } + } + public void updateMucRosterUi() { if (mOnMucRosterUpdate != null) { mOnMucRosterUpdate.onMucRosterUpdate(); @@ -2034,9 +2071,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } - public void sendIqPacket(Account account, IqPacket packet, - OnIqPacketReceived callback) { - XmppConnection connection = account.getXmppConnection(); + public void sendIqPacket(final Account account, final IqPacket packet, final PacketReceived callback) { + final XmppConnection connection = account.getXmppConnection(); if (connection != null) { connection.sendIqPacket(packet, callback); } @@ -2054,6 +2090,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return this.mIqGenerator; } + public IqParser getIqParser() { return this.mIqParser; } + public JingleConnectionManager getJingleConnectionManager() { return this.mJingleConnectionManager; } @@ -2083,8 +2121,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return this.mHttpConnectionManager; } - public void resendFailedMessages(Message message) { - List messages = new ArrayList<>(); + public void resendFailedMessages(final Message message) { + final Collection messages = new ArrayList<>(); Message current = message; while (current.getStatus() == Message.STATUS_SEND_FAILED) { messages.add(current); @@ -2094,7 +2132,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa break; } } - for (Message msg : messages) { + for (final Message msg : messages) { markMessage(msg, Message.STATUS_WAITING); this.resendMessage(msg); } @@ -2136,4 +2174,35 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return XmppConnectionService.this; } } + + public void sendBlockRequest(final Blockable blockable) { + if (blockable != null && blockable.getBlockedJid() != null) { + final Jid jid = blockable.getBlockedJid(); + this.sendIqPacket(blockable.getAccount(), getIqGenerator().generateSetBlockRequest(jid), new OnIqPacketReceived() { + + @Override + public void onIqPacketReceived(final Account account, final IqPacket packet) { + if (packet.getType() == IqPacket.TYPE_RESULT) { + account.getBlocklist().add(jid); + updateBlocklistUi(OnUpdateBlocklist.Status.BLOCKED); + } + } + }); + } + } + + public void sendUnblockRequest(final Blockable blockable) { + if (blockable != null && blockable.getJid() != null) { + final Jid jid = blockable.getBlockedJid(); + this.sendIqPacket(blockable.getAccount(), getIqGenerator().generateSetUnblockRequest(jid), new OnIqPacketReceived() { + @Override + public void onIqPacketReceived(final Account account, final IqPacket packet) { + if (packet.getType() == IqPacket.TYPE_RESULT) { + account.getBlocklist().remove(jid); + updateBlocklistUi(OnUpdateBlocklist.Status.UNBLOCKED); + } + } + }); + } + } } diff --git a/src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java b/src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java new file mode 100644 index 00000000..1a9fc95c --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java @@ -0,0 +1,124 @@ +package eu.siacs.conversations.ui; + +import android.content.Context; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.ListView; + +import java.util.ArrayList; +import java.util.List; + +import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.ListItem; +import eu.siacs.conversations.ui.adapter.ListItemAdapter; + +public abstract class AbstractSearchableListItemActivity extends XmppActivity { + private ListView mListView; + private final List listItems = new ArrayList<>(); + private ArrayAdapter mListItemsAdapter; + + private EditText mSearchEditText; + + private final MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() { + + @Override + public boolean onMenuItemActionExpand(final MenuItem item) { + mSearchEditText.post(new Runnable() { + + @Override + public void run() { + mSearchEditText.requestFocus(); + final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(mSearchEditText, + InputMethodManager.SHOW_IMPLICIT); + } + }); + + return true; + } + + @Override + public boolean onMenuItemActionCollapse(final MenuItem item) { + final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(), + InputMethodManager.HIDE_IMPLICIT_ONLY); + mSearchEditText.setText(""); + filterContacts(); + return true; + } + }; + + private final TextWatcher mSearchTextWatcher = new TextWatcher() { + + @Override + public void afterTextChanged(final Editable editable) { + filterContacts(editable.toString()); + } + + @Override + public void beforeTextChanged(final CharSequence s, final int start, final int count, + final int after) { + } + + @Override + public void onTextChanged(final CharSequence s, final int start, final int before, + final int count) { + } + }; + + public ListView getListView() { + return mListView; + } + + public List getListItems() { + return listItems; + } + + public EditText getSearchEditText() { + return mSearchEditText; + } + + public ArrayAdapter getListItemAdapter() { + return mListItemsAdapter; + } + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_choose_contact); + mListView = (ListView) findViewById(R.id.choose_contact_list); + mListView.setFastScrollEnabled(true); + mListItemsAdapter = new ListItemAdapter(this, listItems); + mListView.setAdapter(mListItemsAdapter); + } + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + getMenuInflater().inflate(R.menu.choose_contact, menu); + final MenuItem menuSearchView = menu.findItem(R.id.action_search); + final View mSearchView = menuSearchView.getActionView(); + mSearchEditText = (EditText) mSearchView + .findViewById(R.id.search_field); + mSearchEditText.addTextChangedListener(mSearchTextWatcher); + menuSearchView.setOnActionExpandListener(mOnActionExpandListener); + return true; + } + + protected void filterContacts() { + filterContacts(null); + } + + protected abstract void filterContacts(final String needle); + + @Override + void onBackendConnected() { + filterContacts(); + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java b/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java new file mode 100644 index 00000000..9cf7e9f8 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java @@ -0,0 +1,41 @@ +package eu.siacs.conversations.ui; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; + +import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.Blockable; +import eu.siacs.conversations.services.XmppConnectionService; + +public final class BlockContactDialog { + public static void show(final Context context, + final XmppConnectionService xmppConnectionService, + final Blockable blockable) { + final AlertDialog.Builder builder = new AlertDialog.Builder(context); + final boolean isBlocked = blockable.isBlocked(); + builder.setNegativeButton(R.string.cancel, null); + + if (blockable.getJid().isDomainJid() || blockable.getAccount().isBlocked(blockable.getJid().toDomainJid())) { + builder.setTitle(isBlocked ? R.string.action_unblock_domain : R.string.action_block_domain); + builder.setMessage(context.getResources().getString(isBlocked ? R.string.unblock_domain_text : R.string.block_domain_text, + blockable.getJid().toDomainJid())); + } else { + builder.setTitle(isBlocked ? R.string.action_unblock_contact : R.string.action_block_contact); + builder.setMessage(context.getResources().getString(isBlocked ? R.string.unblock_contact_text : R.string.block_contact_text, + blockable.getJid().toBareJid())); + } + builder.setPositiveButton(isBlocked ? R.string.unblock : R.string.block, new DialogInterface.OnClickListener() { + + @Override + public void onClick(final DialogInterface dialog, final int which) { + if (isBlocked) { + xmppConnectionService.sendUnblockRequest(blockable); + } else { + xmppConnectionService.sendBlockRequest(blockable); + } + } + }); + builder.create().show(); + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java b/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java new file mode 100644 index 00000000..13d7f4fc --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java @@ -0,0 +1,75 @@ +package eu.siacs.conversations.ui; + +import android.os.Bundle; +import android.text.Editable; +import android.view.View; +import android.widget.AdapterView; + +import java.util.Collections; + +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Contact; +import eu.siacs.conversations.xmpp.OnUpdateBlocklist; +import eu.siacs.conversations.xmpp.jid.Jid; + +public class BlocklistActivity extends AbstractSearchableListItemActivity implements OnUpdateBlocklist { + + private Account account = null; + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { + + @Override + public boolean onItemLongClick(final AdapterView parent, + final View view, + final int position, + final long id) { + BlockContactDialog.show(parent.getContext(), xmppConnectionService,(Contact) getListItems().get(position)); + return true; + } + }); + } + + @Override + public void onBackendConnected() { + for (final Account account : xmppConnectionService.getAccounts()) { + if (account.getJid().toString().equals(getIntent().getStringExtra("account"))) { + this.account = account; + break; + } + } + filterContacts(); + } + + @Override + protected void filterContacts(final String needle) { + getListItems().clear(); + if (account != null) { + for (final Jid jid : account.getBlocklist()) { + final Contact contact = account.getRoster().getContact(jid); + if (contact.match(needle) && contact.isBlocked()) { + getListItems().add(contact); + } + } + Collections.sort(getListItems()); + } + runOnUiThread(new Runnable() { + @Override + public void run() { + getListItemAdapter().notifyDataSetChanged(); + } + }); + } + + @Override + public void OnUpdateBlocklist(final OnUpdateBlocklist.Status status) { + final Editable editable = getSearchEditText().getText(); + if (editable != null) { + filterContacts(editable.toString()); + } else { + filterContacts(); + } + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java b/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java index e7254933..70b353c6 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java @@ -1,101 +1,33 @@ package eu.siacs.conversations.ui; -import java.util.ArrayList; -import java.util.Collections; - import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.text.Editable; -import android.text.TextWatcher; -import android.view.Menu; -import android.view.MenuItem; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.ListView; -import eu.siacs.conversations.R; + +import java.util.Collections; + import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.ListItem; -import eu.siacs.conversations.ui.adapter.ListItemAdapter; - -public class ChooseContactActivity extends XmppActivity { - - private ListView mListView; - private ArrayList contacts = new ArrayList<>(); - private ArrayAdapter mContactsAdapter; - - private EditText mSearchEditText; - - private TextWatcher mSearchTextWatcher = new TextWatcher() { - - @Override - public void afterTextChanged(Editable editable) { - filterContacts(editable.toString()); - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - } - }; - - private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() { - - @Override - public boolean onMenuItemActionExpand(MenuItem item) { - mSearchEditText.post(new Runnable() { - - @Override - public void run() { - mSearchEditText.requestFocus(); - InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - imm.showSoftInput(mSearchEditText, - InputMethodManager.SHOW_IMPLICIT); - } - }); - - return true; - } - - @Override - public boolean onMenuItemActionCollapse(MenuItem item) { - InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(), - InputMethodManager.HIDE_IMPLICIT_ONLY); - mSearchEditText.setText(""); - filterContacts(null); - return true; - } - }; +public class ChooseContactActivity extends AbstractSearchableListItemActivity { @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_choose_contact); - mListView = (ListView) findViewById(R.id.choose_contact_list); - mListView.setFastScrollEnabled(true); - mContactsAdapter = new ListItemAdapter(this, contacts); - mListView.setAdapter(mContactsAdapter); - mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override - public void onItemClick(AdapterView arg0, View arg1, - int position, long arg3) { - InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(), + public void onItemClick(final AdapterView parent, final View view, + final int position, final long id) { + final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(getSearchEditText().getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY); - Intent request = getIntent(); - Intent data = new Intent(); - ListItem mListItem = contacts.get(position); + final Intent request = getIntent(); + final Intent data = new Intent(); + final ListItem mListItem = getListItems().get(position); data.putExtra("contact", mListItem.getJid().toString()); String account = request.getStringExtra("account"); if (account == null && mListItem instanceof Contact) { @@ -108,38 +40,21 @@ public class ChooseContactActivity extends XmppActivity { finish(); } }); - } - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.choose_contact, menu); - MenuItem menuSearchView = menu.findItem(R.id.action_search); - View mSearchView = menuSearchView.getActionView(); - mSearchEditText = (EditText) mSearchView - .findViewById(R.id.search_field); - mSearchEditText.addTextChangedListener(mSearchTextWatcher); - menuSearchView.setOnActionExpandListener(mOnActionExpandListener); - return true; } - @Override - void onBackendConnected() { - filterContacts(null); - } - - protected void filterContacts(String needle) { - this.contacts.clear(); - for (Account account : xmppConnectionService.getAccounts()) { + protected void filterContacts(final String needle) { + getListItems().clear(); + for (final Account account : xmppConnectionService.getAccounts()) { if (account.getStatus() != Account.State.DISABLED) { - for (Contact contact : account.getRoster().getContacts()) { + for (final Contact contact : account.getRoster().getContacts()) { if (contact.showInRoster() && contact.match(needle)) { - this.contacts.add(contact); + getListItems().add(contact); } } } } - Collections.sort(this.contacts); - mContactsAdapter.notifyDataSetChanged(); + Collections.sort(getListItems()); + getListItemAdapter().notifyDataSetChanged(); } - } diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index 2e36c545..eeb015f3 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -157,8 +157,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers @Override public void onValueEdited(String value) { MessagePacket packet = xmppConnectionService - .getMessageGenerator().conferenceSubject( - mConversation, value); + .getMessageGenerator().conferenceSubject( + mConversation, value); xmppConnectionService.sendMessagePacket( mConversation.getAccount(), packet); } @@ -191,7 +191,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers @Override protected String getShareableUri() { if (mConversation != null) { - return "xmpp:" + mConversation.getContactJid().toBareJid().toString() + "?join"; + return "xmpp:" + mConversation.getJid().toBareJid().toString() + "?join"; } else { return ""; } @@ -202,7 +202,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers MenuItem menuItemSaveBookmark = menu.findItem(R.id.action_save_as_bookmark); MenuItem menuItemDeleteBookmark = menu.findItem(R.id.action_delete_bookmark); Account account = mConversation.getAccount(); - if (account.hasBookmarkFor(mConversation.getContactJid().toBareJid())) { + if (account.hasBookmarkFor(mConversation.getJid().toBareJid())) { menuItemSaveBookmark.setVisible(false); menuItemDeleteBookmark.setVisible(true); } else { @@ -263,9 +263,9 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers protected void saveAsBookmark() { Account account = mConversation.getAccount(); - Bookmark bookmark = new Bookmark(account, mConversation.getContactJid().toBareJid()); - if (!mConversation.getContactJid().isBareJid()) { - bookmark.setNick(mConversation.getContactJid().getResourcepart()); + Bookmark bookmark = new Bookmark(account, mConversation.getJid().toBareJid()); + if (!mConversation.getJid().isBareJid()) { + bookmark.setNick(mConversation.getJid().getResourcepart()); } bookmark.setAutojoin(true); account.getBookmarks().add(bookmark); @@ -288,7 +288,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers } if (uuid != null) { this.mConversation = xmppConnectionService - .findConversationByUuid(uuid); + .findConversationByUuid(uuid); if (this.mConversation != null) { populateView(); } @@ -297,11 +297,11 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers private void populateView() { mAccountJid.setText(getString(R.string.using_account, mConversation - .getAccount().getJid().toBareJid())); + .getAccount().getJid().toBareJid())); mYourPhoto.setImageBitmap(avatarService().get( - mConversation.getAccount(), getPixel(48))); + mConversation.getAccount(), getPixel(48))); setTitle(mConversation.getName()); - mFullJid.setText(mConversation.getContactJid().toBareJid().toString()); + mFullJid.setText(mConversation.getJid().toBareJid().toString()); mYourNick.setText(mConversation.getMucOptions().getActualNick()); mRoleAffiliaton = (TextView) findViewById(R.id.muc_role); if (mConversation.getMucOptions().online()) { @@ -338,7 +338,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers registerForContextMenu(view); view.setTag(user); TextView name = (TextView) view - .findViewById(R.id.contact_display_name); + .findViewById(R.id.contact_display_name); TextView key = (TextView) view.findViewById(R.id.key); TextView role = (TextView) view.findViewById(R.id.contact_jid); if (user.getPgpKeyId() != 0) { diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java index 4259371a..b195f2f1 100644 --- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java @@ -38,10 +38,11 @@ import eu.siacs.conversations.entities.ListItem; import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; import eu.siacs.conversations.utils.UIHelper; +import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; -public class ContactDetailsActivity extends XmppActivity implements OnAccountUpdate, OnRosterUpdate { +public class ContactDetailsActivity extends XmppActivity implements OnAccountUpdate, OnRosterUpdate, OnUpdateBlocklist { public static final String ACTION_VIEW_CONTACT = "view_contact"; private Contact contact; @@ -50,7 +51,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd @Override public void onClick(DialogInterface dialog, int which) { ContactDetailsActivity.this.xmppConnectionService - .deleteContactOnServer(contact); + .deleteContactOnServer(contact); ContactDetailsActivity.this.finish(); } }; @@ -58,14 +59,14 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd @Override public void onCheckedChanged(CompoundButton buttonView, - boolean isChecked) { + boolean isChecked) { if (isChecked) { if (contact .getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) { xmppConnectionService.sendPresencePacket(contact - .getAccount(), + .getAccount(), xmppConnectionService.getPresenceGenerator() - .sendPresenceUpdatesTo(contact)); + .sendPresenceUpdatesTo(contact)); } else { contact.setOption(Contact.Options.PREEMPTIVE_GRANT); } @@ -73,7 +74,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd contact.resetOption(Contact.Options.PREEMPTIVE_GRANT); xmppConnectionService.sendPresencePacket(contact.getAccount(), xmppConnectionService.getPresenceGenerator() - .stopPresenceUpdatesTo(contact)); + .stopPresenceUpdatesTo(contact)); } } }; @@ -81,15 +82,15 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd @Override public void onCheckedChanged(CompoundButton buttonView, - boolean isChecked) { + boolean isChecked) { if (isChecked) { xmppConnectionService.sendPresencePacket(contact.getAccount(), xmppConnectionService.getPresenceGenerator() - .requestPresenceUpdatesFrom(contact)); + .requestPresenceUpdatesFrom(contact)); } else { xmppConnectionService.sendPresencePacket(contact.getAccount(), xmppConnectionService.getPresenceGenerator() - .stopPresenceUpdatesFrom(contact)); + .stopPresenceUpdatesFrom(contact)); } } }; @@ -127,7 +128,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd ContactDetailsActivity.this); builder.setTitle(getString(R.string.action_add_phone_book)); builder.setMessage(getString(R.string.add_phone_book_text, - contact.getJid())); + contact.getJid())); builder.setNegativeButton(getString(R.string.cancel), null); builder.setPositiveButton(getString(R.string.add), addToPhonebook); builder.create().show(); @@ -166,7 +167,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd } @Override - protected void onCreate(Bundle savedInstanceState) { + protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getIntent().getAction().equals(ACTION_VIEW_CONTACT)) { try { @@ -188,15 +189,17 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd badge = (QuickContactBadge) findViewById(R.id.details_contact_badge); keys = (LinearLayout) findViewById(R.id.details_contact_keys); tags = (LinearLayout) findViewById(R.id.tags); - getActionBar().setHomeButtonEnabled(true); - getActionBar().setDisplayHomeAsUpEnabled(true); + if (getActionBar() != null) { + getActionBar().setHomeButtonEnabled(true); + getActionBar().setDisplayHomeAsUpEnabled(true); + } - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); this.showDynamicTags = preferences.getBoolean("show_dynamic_tags",false); } @Override - public boolean onOptionsItemSelected(MenuItem menuItem) { + public boolean onOptionsItemSelected(final MenuItem menuItem) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setNegativeButton(getString(R.string.cancel), null); switch (menuItem.getItemId()) { @@ -205,11 +208,11 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd break; case R.id.action_delete_contact: builder.setTitle(getString(R.string.action_delete_contact)) - .setMessage( - getString(R.string.remove_contact_text, - contact.getJid())) - .setPositiveButton(getString(R.string.delete), - removeFromRoster).create().show(); + .setMessage( + getString(R.string.remove_contact_text, + contact.getJid())) + .setPositiveButton(getString(R.string.delete), + removeFromRoster).create().show(); break; case R.id.action_edit_contact: if (contact.getSystemAccount() == null) { @@ -219,7 +222,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd public void onValueEdited(String value) { contact.setServerName(value); ContactDetailsActivity.this.xmppConnectionService - .pushContactToServer(contact); + .pushContactToServer(contact); populateView(); } }); @@ -285,7 +288,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd receive.setOnCheckedChangeListener(this.mOnReceiveCheckedChange); lastseen.setText(UIHelper.lastseen(getApplicationContext(), - contact.lastseen.time)); + contact.lastseen.time)); if (contact.getPresences().size() > 1) { contactJidTv.setText(contact.getJid() + " (" @@ -294,7 +297,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd contactJidTv.setText(contact.getJid().toString()); } accountJidTv.setText(getString(R.string.using_account, contact - .getAccount().getJid().toBareJid())); + .getAccount().getJid().toBareJid())); prepareContactBadge(badge, contact); if (contact.getSystemAccount() == null) { badge.setOnClickListener(onBadgeClick); @@ -309,7 +312,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd TextView key = (TextView) view.findViewById(R.id.key); TextView keyType = (TextView) view.findViewById(R.id.key_type); ImageButton remove = (ImageButton) view - .findViewById(R.id.button_remove); + .findViewById(R.id.button_remove); remove.setVisibility(View.VISIBLE); keyType.setText("OTR Fingerprint"); key.setText(otrFingerprint); @@ -334,7 +337,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd @Override public void onClick(View v) { PgpEngine pgp = ContactDetailsActivity.this.xmppConnectionService - .getPgpEngine(); + .getPgpEngine(); if (pgp != null) { PendingIntent intent = pgp.getIntentForKey(contact); if (intent != null) { @@ -363,8 +366,8 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd } else { tags.setVisibility(View.VISIBLE); tags.removeAllViewsInLayout(); - for(ListItem.Tag tag : tagList) { - TextView tv = (TextView) inflater.inflate(R.layout.list_item_tag,tags,false); + for(final ListItem.Tag tag : tagList) { + final TextView tv = (TextView) inflater.inflate(R.layout.list_item_tag,tags,false); tv.setText(tag.getName()); tv.setBackgroundColor(tag.getColor()); tags.addView(tv); @@ -406,7 +409,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd public void onBackendConnected() { if ((accountJid != null) && (contactJid != null)) { Account account = xmppConnectionService - .findAccountByJid(accountJid); + .findAccountByJid(accountJid); if (account == null) { return; } @@ -414,4 +417,15 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd populateView(); } } + + @Override + public void OnUpdateBlocklist(final Status status) { + runOnUiThread(new Runnable() { + + @Override + public void run() { + populateView(); + } + }); + } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 6656de2b..3a3f0778 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -15,7 +15,6 @@ import android.os.SystemClock; import android.provider.MediaStore; import android.support.v4.widget.SlidingPaneLayout; import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener; -import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -32,6 +31,7 @@ import java.util.ArrayList; import java.util.List; import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.Blockable; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; @@ -40,9 +40,10 @@ import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdat import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; import eu.siacs.conversations.ui.adapter.ConversationAdapter; import eu.siacs.conversations.utils.ExceptionHelper; +import eu.siacs.conversations.xmpp.OnUpdateBlocklist; -public class ConversationActivity extends XmppActivity implements - OnAccountUpdate, OnConversationUpdate, OnRosterUpdate { +public class ConversationActivity extends XmppActivity + implements OnAccountUpdate, OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist { public static final String VIEW_CONVERSATION = "viewConversation"; public static final String CONVERSATION = "conversationUuid"; @@ -144,12 +145,12 @@ public class ConversationActivity extends XmppActivity implements protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) {mOpenConverstaion = savedInstanceState.getString( - STATE_OPEN_CONVERSATION, null); - mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true); - String pending = savedInstanceState.getString(STATE_PENDING_URI, null); - if (pending != null) { - mPendingImageUri = Uri.parse(pending); - } + STATE_OPEN_CONVERSATION, null); + mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true); + String pending = savedInstanceState.getString(STATE_PENDING_URI, null); + if (pending != null) { + mPendingImageUri = Uri.parse(pending); + } } setContentView(R.layout.fragment_conversations_overview); @@ -172,7 +173,7 @@ public class ConversationActivity extends XmppActivity implements @Override public void onItemClick(AdapterView arg0, View clickedView, - int position, long arg3) { + int position, long arg3) { if (getSelectedConversation() != conversationList.get(position)) { setSelectedConversation(conversationList.get(position)); ConversationActivity.this.mConversationFragment.reInit(getSelectedConversation()); @@ -188,7 +189,7 @@ public class ConversationActivity extends XmppActivity implements SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; mSlidingPaneLayout.setParallaxDistance(150); mSlidingPaneLayout - .setShadowResource(R.drawable.es_slidingpane_shadow); + .setShadowResource(R.drawable.es_slidingpane_shadow); mSlidingPaneLayout.setSliderFadeColor(0); mSlidingPaneLayout.setPanelSlideListener(new PanelSlideListener() { @@ -199,7 +200,7 @@ public class ConversationActivity extends XmppActivity implements hideKeyboard(); if (xmppConnectionServiceBound) { xmppConnectionService.getNotificationService() - .setOpenConversation(null); + .setOpenConversation(null); } closeContextMenu(); } @@ -244,7 +245,7 @@ public class ConversationActivity extends XmppActivity implements if (conversation.getMode() == Conversation.MODE_SINGLE || useSubjectToIdentifyConference()) { ab.setTitle(conversation.getName()); } else { - ab.setTitle(conversation.getContactJid().toBareJid().toString()); + ab.setTitle(conversation.getJid().toBareJid().toString()); } } else { ab.setDisplayHomeAsUpEnabled(false); @@ -269,17 +270,18 @@ public class ConversationActivity extends XmppActivity implements @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.conversations, menu); - MenuItem menuSecure = menu.findItem(R.id.action_security); - MenuItem menuArchive = menu.findItem(R.id.action_archive); - MenuItem menuMucDetails = menu.findItem(R.id.action_muc_details); - MenuItem menuContactDetails = menu - .findItem(R.id.action_contact_details); - MenuItem menuAttach = menu.findItem(R.id.action_attach_file); - MenuItem menuClearHistory = menu.findItem(R.id.action_clear_history); - MenuItem menuAdd = menu.findItem(R.id.action_add); - MenuItem menuInviteContact = menu.findItem(R.id.action_invite); - MenuItem menuMute = menu.findItem(R.id.action_mute); - MenuItem menuUnmute = menu.findItem(R.id.action_unmute); + final MenuItem menuSecure = menu.findItem(R.id.action_security); + final MenuItem menuArchive = menu.findItem(R.id.action_archive); + final MenuItem menuMucDetails = menu.findItem(R.id.action_muc_details); + final MenuItem menuContactDetails = menu.findItem(R.id.action_contact_details); + final MenuItem menuAttach = menu.findItem(R.id.action_attach_file); + final MenuItem menuClearHistory = menu.findItem(R.id.action_clear_history); + final MenuItem menuAdd = menu.findItem(R.id.action_add); + final MenuItem menuInviteContact = menu.findItem(R.id.action_invite); + final MenuItem menuMute = menu.findItem(R.id.action_mute); + final MenuItem menuUnmute = menu.findItem(R.id.action_unmute); + final MenuItem menuBlock = menu.findItem(R.id.action_block); + final MenuItem menuUnblock = menu.findItem(R.id.action_unblock); if (isConversationsOverviewVisable() && isConversationsOverviewHideable()) { @@ -292,19 +294,32 @@ public class ConversationActivity extends XmppActivity implements menuClearHistory.setVisible(false); menuMute.setVisible(false); menuUnmute.setVisible(false); + menuBlock.setVisible(false); + menuUnblock.setVisible(false); } else { menuAdd.setVisible(!isConversationsOverviewHideable()); if (this.getSelectedConversation() != null) { if (this.getSelectedConversation().getLatestMessage() .getEncryption() != Message.ENCRYPTION_NONE) { menuSecure.setIcon(R.drawable.ic_action_secure); - } + } if (this.getSelectedConversation().getMode() == Conversation.MODE_MULTI) { menuContactDetails.setVisible(false); menuAttach.setVisible(false); + menuBlock.setVisible(false); + menuUnblock.setVisible(false); } else { menuMucDetails.setVisible(false); menuInviteContact.setTitle(R.string.conference_with); + if (this.getSelectedConversation().isBlocked()) { + menuBlock.setVisible(false); + } else { + menuUnblock.setVisible(false); + } + if (!this.getSelectedConversation().getAccount().getXmppConnection().getFeatures().blocking()) { + menuBlock.setVisible(false); + menuUnblock.setVisible(false); + } } if (this.getSelectedConversation().isMuted()) { menuMute.setVisible(false); @@ -323,7 +338,7 @@ public class ConversationActivity extends XmppActivity implements public void onPresenceSelected() { if (attachmentChoice == ATTACHMENT_CHOICE_TAKE_PHOTO) { mPendingImageUri = xmppConnectionService.getFileBackend() - .getTakePhotoUri(); + .getTakePhotoUri(); Intent takePictureIntent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, @@ -364,7 +379,7 @@ public class ConversationActivity extends XmppActivity implements @Override public void userInputRequried(PendingIntent pi, - Contact contact) { + Contact contact) { ConversationActivity.this.runIntent(pi, attachmentChoice); } @@ -381,18 +396,18 @@ public class ConversationActivity extends XmppActivity implements }); } else { final ConversationFragment fragment = (ConversationFragment) getFragmentManager() - .findFragmentByTag("conversation"); + .findFragmentByTag("conversation"); if (fragment != null) { fragment.showNoPGPKeyDialog(false, new OnClickListener() { @Override public void onClick(DialogInterface dialog, - int which) { + int which) { conversation - .setNextEncryption(Message.ENCRYPTION_NONE); + .setNextEncryption(Message.ENCRYPTION_NONE); xmppConnectionService.databaseBackend - .updateConversation(conversation); + .updateConversation(conversation); selectPresenceToAttachFile(attachmentChoice); } }); @@ -402,7 +417,7 @@ public class ConversationActivity extends XmppActivity implements showInstallPgpDialog(); } } else if (getSelectedConversation().getNextEncryption( - forceEncryption()) == Message.ENCRYPTION_NONE) { + forceEncryption()) == Message.ENCRYPTION_NONE) { selectPresenceToAttachFile(attachmentChoice); } else { selectPresenceToAttachFile(attachmentChoice); @@ -410,7 +425,7 @@ public class ConversationActivity extends XmppActivity implements } @Override - public boolean onOptionsItemSelected(MenuItem item) { + public boolean onOptionsItemSelected(final MenuItem item) { if (item.getItemId() == android.R.id.home) { showConversationsOverview(); return true; @@ -455,6 +470,12 @@ public class ConversationActivity extends XmppActivity implements case R.id.action_unmute: unmuteConversation(getSelectedConversation()); break; + case R.id.action_block: + BlockContactDialog.show(this, xmppConnectionService, getSelectedConversation()); + break; + case R.id.action_unblock: + BlockContactDialog.show(this, xmppConnectionService, getSelectedConversation()); + break; default: break; } @@ -483,7 +504,7 @@ public class ConversationActivity extends XmppActivity implements View dialogView = getLayoutInflater().inflate( R.layout.dialog_clear_history, null); final CheckBox endConversationCheckBox = (CheckBox) dialogView - .findViewById(R.id.end_conversation_checkbox); + .findViewById(R.id.end_conversation_checkbox); builder.setView(dialogView); builder.setNegativeButton(getString(R.string.cancel), null); builder.setPositiveButton(getString(R.string.delete_messages), @@ -511,24 +532,24 @@ public class ConversationActivity extends XmppActivity implements PopupMenu attachFilePopup = new PopupMenu(this, menuAttachFile); attachFilePopup.inflate(R.menu.attachment_choices); attachFilePopup - .setOnMenuItemClickListener(new OnMenuItemClickListener() { + .setOnMenuItemClickListener(new OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - switch (item.getItemId()) { - case R.id.attach_choose_picture: - attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE); - break; - case R.id.attach_take_picture: - attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO); - break; - case R.id.attach_record_voice: - attachFile(ATTACHMENT_CHOICE_CHOOSE_FILE); - break; - } - return false; + @Override + public boolean onMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.attach_choose_picture: + attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE); + break; + case R.id.attach_take_picture: + attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO); + break; + case R.id.attach_record_voice: + attachFile(ATTACHMENT_CHOICE_CHOOSE_FILE); + break; } - }); + return false; + } + }); attachFilePopup.show(); } @@ -539,7 +560,7 @@ public class ConversationActivity extends XmppActivity implements } PopupMenu popup = new PopupMenu(this, menuItemView); final ConversationFragment fragment = (ConversationFragment) getFragmentManager() - .findFragmentByTag("conversation"); + .findFragmentByTag("conversation"); if (fragment != null) { popup.setOnMenuItemClickListener(new OnMenuItemClickListener() { @@ -559,7 +580,7 @@ public class ConversationActivity extends XmppActivity implements if (conversation.getAccount().getKeys() .has("pgp_signature")) { conversation - .setNextEncryption(Message.ENCRYPTION_PGP); + .setNextEncryption(Message.ENCRYPTION_PGP); item.setChecked(true); } else { announcePgp(conversation.getAccount(), @@ -574,7 +595,7 @@ public class ConversationActivity extends XmppActivity implements break; } xmppConnectionService.databaseBackend - .updateConversation(conversation); + .updateConversation(conversation); fragment.updateChatMsgHint(); return true; } @@ -599,11 +620,11 @@ public class ConversationActivity extends XmppActivity implements break; case Message.ENCRYPTION_PGP: popup.getMenu().findItem(R.id.encryption_choice_pgp) - .setChecked(true); + .setChecked(true); break; default: popup.getMenu().findItem(R.id.encryption_choice_none) - .setChecked(true); + .setChecked(true); break; } popup.show(); @@ -619,17 +640,17 @@ public class ConversationActivity extends XmppActivity implements new OnClickListener() { @Override - public void onClick(DialogInterface dialog, int which) { - long till; + public void onClick(final DialogInterface dialog, final int which) { + final long till; if (durations[which] == -1) { till = Long.MAX_VALUE; } else { till = SystemClock.elapsedRealtime() - + (durations[which] * 1000); + + (durations[which] * 1000); } conversation.setMutedTill(till); ConversationActivity.this.xmppConnectionService.databaseBackend - .updateConversation(conversation); + .updateConversation(conversation); updateConversationList(); ConversationActivity.this.mConversationFragment.updateMessages(); invalidateOptionsMenu(); @@ -763,11 +784,11 @@ public class ConversationActivity extends XmppActivity implements } private void selectConversationByUuid(String uuid) { - for (Conversation aConversationList : conversationList) { - if (aConversationList.getUuid().equals(uuid)) { - setSelectedConversation(aConversationList); - } - } + for (Conversation aConversationList : conversationList) { + if (aConversationList.getUuid().equals(uuid)) { + setSelectedConversation(aConversationList); + } + } } @Override @@ -778,7 +799,7 @@ public class ConversationActivity extends XmppActivity implements @Override protected void onActivityResult(int requestCode, int resultCode, - final Intent data) { + final Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { if (requestCode == REQUEST_DECRYPT_PGP) { @@ -859,7 +880,7 @@ public class ConversationActivity extends XmppActivity implements @Override public void userInputRequried(PendingIntent pi, - Message object) { + Message object) { hidePrepareFileToast(); ConversationActivity.this.runIntent(pi, ConversationActivity.REQUEST_SEND_PGP_IMAGE); @@ -892,7 +913,7 @@ public class ConversationActivity extends XmppActivity implements public void updateConversationList() { xmppConnectionService - .populateWithOrderedConversations(conversationList); + .populateWithOrderedConversations(conversationList); listAdapter.notifyDataSetChanged(); } @@ -910,7 +931,7 @@ public class ConversationActivity extends XmppActivity implements @Override public void userInputRequried(PendingIntent pi, - Message message) { + Message message) { ConversationActivity.this.runIntent(pi, ConversationActivity.REQUEST_SEND_MESSAGE); } @@ -962,7 +983,7 @@ public class ConversationActivity extends XmppActivity implements updateConversationList(); if (conversationList.size() == 0) { startActivity(new Intent(getApplicationContext(), - StartConversationActivity.class)); + StartConversationActivity.class)); finish(); } ConversationActivity.this.mConversationFragment.updateMessages(); @@ -975,12 +996,31 @@ public class ConversationActivity extends XmppActivity implements public void onRosterUpdate() { runOnUiThread(new Runnable() { - @Override - public void run() { - updateConversationList(); - ConversationActivity.this.mConversationFragment.updateMessages(); - updateActionBarTitle(); - } - }); + @Override + public void run() { + updateConversationList(); + ConversationActivity.this.mConversationFragment.updateMessages(); + updateActionBarTitle(); + } + }); + } + + @Override + public void OnUpdateBlocklist(Status status) { + invalidateOptionsMenu(); + runOnUiThread(new Runnable() { + @Override + public void run() { + ConversationActivity.this.mConversationFragment.updateMessages(); + } + }); + } + + public void unblockConversation(final Blockable conversation) { + xmppConnectionService.sendUnblockRequest(conversation); + } + + public void blockConversation(final Blockable conversation) { + xmppConnectionService.sendBlockRequest(conversation); } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index e4c3fa9e..d356c73c 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -9,7 +9,6 @@ import android.content.Intent; import android.content.IntentSender; import android.content.IntentSender.SendIntentException; import android.os.Bundle; -import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Gravity; @@ -39,7 +38,6 @@ import java.util.List; import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentLinkedQueue; -import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.PgpEngine; import eu.siacs.conversations.entities.Account; @@ -118,7 +116,7 @@ public class ConversationFragment extends Fragment { @Override public void onScroll(AbsListView view, int firstVisibleItem, - int visibleItemCount, int totalItemCount) { + int visibleItemCount, int totalItemCount) { synchronized (ConversationFragment.this.messageList) { if (firstVisibleItem < 5 && messagesLoaded && messageList.size() > 0) { long timestamp = ConversationFragment.this.messageList.get(0).getTimeSent(); @@ -223,7 +221,7 @@ public class ConversationFragment extends Fragment { public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_SEND) { InputMethodManager imm = (InputMethodManager) v.getContext() - .getSystemService(Context.INPUT_METHOD_SERVICE); + .getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(v.getWindowToken(), 0); sendMessage(); return true; @@ -266,7 +264,7 @@ public class ConversationFragment extends Fragment { } Message message = new Message(conversation, mEditMessage.getText() .toString(), conversation.getNextEncryption(activity - .forceEncryption())); + .forceEncryption())); if (conversation.getMode() == Conversation.MODE_MULTI) { if (conversation.getNextCounterpart() != null) { message.setCounterpart(conversation.getNextCounterpart()); @@ -287,13 +285,13 @@ public class ConversationFragment extends Fragment { if (conversation.getMode() == Conversation.MODE_MULTI && conversation.getNextCounterpart() != null) { this.mEditMessage.setHint(getString( - R.string.send_private_message_to, - conversation.getNextCounterpart().getResourcepart())); + R.string.send_private_message_to, + conversation.getNextCounterpart().getResourcepart())); } else { switch (conversation.getNextEncryption(activity.forceEncryption())) { case Message.ENCRYPTION_NONE: mEditMessage - .setHint(getString(R.string.send_plain_text_message)); + .setHint(getString(R.string.send_plain_text_message)); break; case Message.ENCRYPTION_OTR: mEditMessage.setHint(getString(R.string.send_otr_message)); @@ -309,7 +307,7 @@ public class ConversationFragment extends Fragment { @Override public View onCreateView(final LayoutInflater inflater, - ViewGroup container, Bundle savedInstanceState) { + ViewGroup container, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.fragment_conversation, container, false); mEditMessage = (EditMessage) view.findViewById(R.id.textinput); @@ -342,49 +340,49 @@ public class ConversationFragment extends Fragment { messageListAdapter = new MessageAdapter((ConversationActivity) getActivity(), this.messageList); messageListAdapter.setOnContactPictureClicked(new OnContactPictureClicked() { - @Override - public void onContactPictureClicked(Message message) { - if (message.getStatus() <= Message.STATUS_RECEIVED) { - if (message.getConversation().getMode() == Conversation.MODE_MULTI) { - if (message.getCounterpart() != null) { - if (!message.getCounterpart().isBareJid()) { - highlightInConference(message.getCounterpart().getResourcepart()); - } else { - highlightInConference(message.getCounterpart().toString()); - } - } + @Override + public void onContactPictureClicked(Message message) { + if (message.getStatus() <= Message.STATUS_RECEIVED) { + if (message.getConversation().getMode() == Conversation.MODE_MULTI) { + if (message.getCounterpart() != null) { + if (!message.getCounterpart().isBareJid()) { + highlightInConference(message.getCounterpart().getResourcepart()); } else { - Contact contact = message.getConversation() - .getContact(); - if (contact.showInRoster()) { - activity.switchToContactDetails(contact); - } else { - activity.showAddToRosterDialog(message - .getConversation()); - } + highlightInConference(message.getCounterpart().toString()); } + } + } else { + Contact contact = message.getConversation() + .getContact(); + if (contact.showInRoster()) { + activity.switchToContactDetails(contact); } else { - Account account = message.getConversation().getAccount(); - Intent intent = new Intent(activity, EditAccountActivity.class); - intent.putExtra("jid", account.getJid().toBareJid().toString()); - startActivity(intent); + activity.showAddToRosterDialog(message + .getConversation()); } } - }); + } else { + Account account = message.getConversation().getAccount(); + Intent intent = new Intent(activity, EditAccountActivity.class); + intent.putExtra("jid", account.getJid().toBareJid().toString()); + startActivity(intent); + } + } + }); messageListAdapter - .setOnContactPictureLongClicked(new OnContactPictureLongClicked() { + .setOnContactPictureLongClicked(new OnContactPictureLongClicked() { - @Override - public void onContactPictureLongClicked(Message message) { - if (message.getStatus() <= Message.STATUS_RECEIVED) { - if (message.getConversation().getMode() == Conversation.MODE_MULTI) { - if (message.getCounterpart() != null) { - privateMessageWith(message.getCounterpart()); - } + @Override + public void onContactPictureLongClicked(Message message) { + if (message.getStatus() <= Message.STATUS_RECEIVED) { + if (message.getConversation().getMode() == Conversation.MODE_MULTI) { + if (message.getCounterpart() != null) { + privateMessageWith(message.getCounterpart()); } } } - }); + } + }); messagesView.setAdapter(messageListAdapter); registerForContextMenu(messagesView); @@ -394,7 +392,7 @@ public class ConversationFragment extends Fragment { @Override public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { + ContextMenuInfo menuInfo) { synchronized (this.messageList) { super.onCreateContextMenu(menu, v, menuInfo); AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo; @@ -416,28 +414,28 @@ public class ConversationFragment extends Fragment { if (this.selectedMessage.getType() != Message.TYPE_TEXT || this.selectedMessage.getDownloadable() != null) { copyText.setVisible(false); - } + } if (this.selectedMessage.getType() != Message.TYPE_IMAGE || this.selectedMessage.getDownloadable() != null) { shareImage.setVisible(false); - } + } if (this.selectedMessage.getStatus() != Message.STATUS_SEND_FAILED) { sendAgain.setVisible(false); } if ((this.selectedMessage.getType() != Message.TYPE_IMAGE && this.selectedMessage - .getDownloadable() == null) + .getDownloadable() == null) || this.selectedMessage.getImageParams().url == null) { copyUrl.setVisible(false); - } + } if (this.selectedMessage.getType() != Message.TYPE_TEXT || this.selectedMessage.getDownloadable() != null || !this.selectedMessage.bodyContainsDownloadable()) { downloadImage.setVisible(false); - } + } if (this.selectedMessage.getDownloadable() == null || this.selectedMessage.getDownloadable() instanceof DownloadablePlaceholder) { cancelTransmission.setVisible(false); - } + } } } @@ -472,16 +470,16 @@ public class ConversationFragment extends Fragment { shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_STREAM, activity.xmppConnectionService.getFileBackend() - .getJingleFileUri(message)); + .getJingleFileUri(message)); shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); shareIntent.setType("image/webp"); activity.startActivity(Intent.createChooser(shareIntent, - getText(R.string.share_with))); + getText(R.string.share_with))); } private void copyText(Message message) { if (activity.copyTextToClipboard(message.getMergedBody(), - R.string.message_text)) { + R.string.message_text)) { Toast.makeText(activity, R.string.message_copied_to_clipboard, Toast.LENGTH_SHORT).show(); } @@ -501,15 +499,15 @@ public class ConversationFragment extends Fragment { private void copyUrl(Message message) { if (activity.copyTextToClipboard( - message.getImageParams().url.toString(), R.string.image_url)) { + message.getImageParams().url.toString(), R.string.image_url)) { Toast.makeText(activity, R.string.url_copied_to_clipboard, Toast.LENGTH_SHORT).show(); - } + } } private void downloadImage(Message message) { activity.xmppConnectionService.getHttpConnectionManager() - .createNewConnection(message); + .createNewConnection(message); } private void cancelTransmission(Message message) { @@ -531,9 +529,9 @@ public class ConversationFragment extends Fragment { mEditMessage.getText().insert(0, nick + ": "); } else { if (mEditMessage.getText().charAt( - mEditMessage.getSelectionStart() - 1) != ' ') { + mEditMessage.getSelectionStart() - 1) != ' ') { nick = " " + nick; - } + } mEditMessage.getText().insert(mEditMessage.getSelectionStart(), nick + " "); } @@ -583,12 +581,30 @@ public class ConversationFragment extends Fragment { final ConversationActivity activity = (ConversationActivity) getActivity(); if (this.conversation != null) { final Contact contact = this.conversation.getContact(); - if (this.conversation.isMuted()) { + if (this.conversation.isBlocked()) { + showSnackbar(R.string.contact_blocked, R.string.unblock, + new OnClickListener() { + @Override + public void onClick(final View v) { + v.post(new Runnable() { + @Override + public void run() { + v.setVisibility(View.INVISIBLE); + } + }); + if (conversation.isDomainBlocked()) { + BlockContactDialog.show(getActivity(), ((ConversationActivity) getActivity()).xmppConnectionService, conversation); + } else { + ((ConversationActivity) getActivity()).unblockConversation(conversation); + } + } + }); + } else if (this.conversation.isMuted()) { showSnackbar(R.string.notifications_disabled, R.string.enable, new OnClickListener() { @Override - public void onClick(View v) { + public void onClick(final View v) { activity.unmuteConversation(conversation); } }); @@ -601,7 +617,7 @@ public class ConversationFragment extends Fragment { @Override public void onClick(View v) { activity.xmppConnectionService - .createContact(contact); + .createContact(contact); activity.switchToContactDetails(contact); } }); @@ -638,17 +654,17 @@ public class ConversationFragment extends Fragment { default: break; } - } + } conversation.populateWithMessages(ConversationFragment.this.messageList); for (Message message : this.messageList) { if (message.getEncryption() == Message.ENCRYPTION_PGP && (message.getStatus() == Message.STATUS_RECEIVED || message - .getStatus() >= Message.STATUS_SEND) + .getStatus() >= Message.STATUS_SEND) && message.getDownloadable() == null) { if (!mEncryptedMessages.contains(message)) { mEncryptedMessages.add(message); } - } + } } decryptNext(); updateStatusMessages(); @@ -720,44 +736,44 @@ public class ConversationFragment extends Fragment { switch (c.getContact().getMostAvailableStatus()) { case Presences.CHAT: this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_online); + .setImageResource(R.drawable.ic_action_send_now_online); break; case Presences.ONLINE: this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_online); + .setImageResource(R.drawable.ic_action_send_now_online); break; case Presences.AWAY: this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_away); + .setImageResource(R.drawable.ic_action_send_now_away); break; case Presences.XA: this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_away); + .setImageResource(R.drawable.ic_action_send_now_away); break; case Presences.DND: this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_dnd); + .setImageResource(R.drawable.ic_action_send_now_dnd); break; default: this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_offline); + .setImageResource(R.drawable.ic_action_send_now_offline); break; } } else if (c.getMode() == Conversation.MODE_MULTI) { if (c.getMucOptions().online()) { this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_online); + .setImageResource(R.drawable.ic_action_send_now_online); } else { this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_offline); + .setImageResource(R.drawable.ic_action_send_now_offline); } } else { this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_offline); + .setImageResource(R.drawable.ic_action_send_now_offline); } } else { this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_offline); + .setImageResource(R.drawable.ic_action_send_now_offline); } } @@ -784,15 +800,16 @@ public class ConversationFragment extends Fragment { } else if (conversation.hasValidOtrSession() && (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!conversation.isOtrFingerprintVerified())) { showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify, clickToVerify); - } + } } - protected void showSnackbar(int message, int action, - OnClickListener clickListener) { + protected void showSnackbar(final int message, final int action, + final OnClickListener clickListener) { snackbar.setVisibility(View.VISIBLE); snackbar.setOnClickListener(null); snackbarMessage.setText(message); snackbarMessage.setOnClickListener(null); + snackbarAction.setVisibility(View.VISIBLE); snackbarAction.setText(action); snackbarAction.setOnClickListener(clickListener); } @@ -819,7 +836,7 @@ public class ConversationFragment extends Fragment { @Override public void userInputRequried(PendingIntent pi, - Contact contact) { + Contact contact) { activity.runIntent( pi, ConversationActivity.REQUEST_ENCRYPT_MESSAGE); @@ -843,11 +860,11 @@ public class ConversationFragment extends Fragment { @Override public void onClick(DialogInterface dialog, - int which) { + int which) { conversation - .setNextEncryption(Message.ENCRYPTION_NONE); + .setNextEncryption(Message.ENCRYPTION_NONE); xmppService.databaseBackend - .updateConversation(conversation); + .updateConversation(conversation); message.setEncryption(Message.ENCRYPTION_NONE); xmppService.sendMessage(message); messageSent(); @@ -858,9 +875,9 @@ public class ConversationFragment extends Fragment { if (conversation.getMucOptions().pgpKeysInUse()) { if (!conversation.getMucOptions().everybodyHasKeys()) { Toast warning = Toast - .makeText(getActivity(), - R.string.missing_public_keys, - Toast.LENGTH_LONG); + .makeText(getActivity(), + R.string.missing_public_keys, + Toast.LENGTH_LONG); warning.setGravity(Gravity.CENTER_VERTICAL, 0, 0); warning.show(); } @@ -872,12 +889,12 @@ public class ConversationFragment extends Fragment { @Override public void onClick(DialogInterface dialog, - int which) { + int which) { conversation - .setNextEncryption(Message.ENCRYPTION_NONE); + .setNextEncryption(Message.ENCRYPTION_NONE); message.setEncryption(Message.ENCRYPTION_NONE); xmppService.databaseBackend - .updateConversation(conversation); + .updateConversation(conversation); xmppService.sendMessage(message); messageSent(); } @@ -890,7 +907,7 @@ public class ConversationFragment extends Fragment { } public void showNoPGPKeyDialog(boolean plural, - DialogInterface.OnClickListener listener) { + DialogInterface.OnClickListener listener) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setIconAttribute(android.R.attr.alertDialogIcon); if (plural) { diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 8fad66cf..47fe5964 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -67,7 +67,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate mAccount.setOption(Account.OPTION_DISABLED, false); xmppConnectionService.updateAccount(mAccount); return; - } + } if (!Validator.isValidJid(mAccountJid.getText().toString())) { mAccountJid.setError(getString(R.string.invalid_jid)); mAccountJid.requestFocus(); @@ -87,32 +87,32 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate if (registerNewAccount) { if (!password.equals(passwordConfirm)) { mPasswordConfirm - .setError(getString(R.string.passwords_do_not_match)); + .setError(getString(R.string.passwords_do_not_match)); mPasswordConfirm.requestFocus(); return; } } if (mAccount != null) { mAccount.setPassword(password); - try { - mAccount.setUsername(jid.hasLocalpart() ? jid.getLocalpart() : ""); - mAccount.setServer(jid.getDomainpart()); - } catch (final InvalidJidException ignored) { - } + try { + mAccount.setUsername(jid.hasLocalpart() ? jid.getLocalpart() : ""); + mAccount.setServer(jid.getDomainpart()); + } catch (final InvalidJidException ignored) { + } mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount); xmppConnectionService.updateAccount(mAccount); } else { - try { - if (xmppConnectionService.findAccountByJid(Jid.fromString(mAccountJid.getText().toString())) != null) { - mAccountJid - .setError(getString(R.string.account_already_exists)); - mAccountJid.requestFocus(); - return; - } - } catch (InvalidJidException e) { - return; - } - mAccount = new Account(jid.toBareJid(), password); + try { + if (xmppConnectionService.findAccountByJid(Jid.fromString(mAccountJid.getText().toString())) != null) { + mAccountJid + .setError(getString(R.string.account_already_exists)); + mAccountJid.requestFocus(); + return; + } + } catch (InvalidJidException e) { + return; + } + mAccount = new Account(jid.toBareJid(), password); mAccount.setOption(Account.OPTION_USETLS, true); mAccount.setOption(Account.OPTION_USECOMPRESSION, true); mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount); @@ -134,34 +134,34 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate finish(); } }; - @Override - public void onAccountUpdate() { - runOnUiThread(new Runnable() { + @Override + public void onAccountUpdate() { + runOnUiThread(new Runnable() { - @Override - public void run() { - if (mAccount != null - && mAccount.getStatus() != Account.State.ONLINE - && mFetchingAvatar) { - startActivity(new Intent(getApplicationContext(), + @Override + public void run() { + if (mAccount != null + && mAccount.getStatus() != Account.State.ONLINE + && mFetchingAvatar) { + startActivity(new Intent(getApplicationContext(), ManageAccountActivity.class)); - finish(); - } else if (jidToEdit == null && mAccount != null - && mAccount.getStatus() == Account.State.ONLINE) { - if (!mFetchingAvatar) { - mFetchingAvatar = true; - xmppConnectionService.checkForAvatar(mAccount, - mAvatarFetchCallback); - } - } else { - updateSaveButton(); - } - if (mAccount != null) { - updateAccountInformation(); + finish(); + } else if (jidToEdit == null && mAccount != null + && mAccount.getStatus() == Account.State.ONLINE) { + if (!mFetchingAvatar) { + mFetchingAvatar = true; + xmppConnectionService.checkForAvatar(mAccount, + mAvatarFetchCallback); } + } else { + updateSaveButton(); } - }); - } + if (mAccount != null) { + updateAccountInformation(); + } + } + }); + } private UiCallback mAvatarFetchCallback = new UiCallback() { @Override @@ -179,17 +179,17 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate finishInitialSetup(avatar); } }; - private TextWatcher mTextWatcher = new TextWatcher() { + private TextWatcher mTextWatcher = new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, - int count) { + int count) { updateSaveButton(); } @Override public void beforeTextChanged(CharSequence s, int start, int count, - int after) { + int after) { } @@ -264,9 +264,9 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate protected boolean accountInfoEdited() { return (!this.mAccount.getJid().toBareJid().equals( - this.mAccountJid.getText().toString())) - || (!this.mAccount.getPassword().equals( - this.mPassword.getText().toString())); + this.mAccountJid.getText().toString())) + || (!this.mAccount.getPassword().equals( + this.mPassword.getText().toString())); } @Override @@ -303,28 +303,32 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mSaveButton.setOnClickListener(this.mSaveButtonClickListener); this.mCancelButton.setOnClickListener(this.mCancelButtonClickListener); this.mRegisterNew - .setOnCheckedChangeListener(new OnCheckedChangeListener() { - - @Override - public void onCheckedChanged(CompoundButton buttonView, - boolean isChecked) { - if (isChecked) { - mPasswordConfirm.setVisibility(View.VISIBLE); - } else { - mPasswordConfirm.setVisibility(View.GONE); - } - updateSaveButton(); + .setOnCheckedChangeListener(new OnCheckedChangeListener() { + + @Override + public void onCheckedChanged(CompoundButton buttonView, + boolean isChecked) { + if (isChecked) { + mPasswordConfirm.setVisibility(View.VISIBLE); + } else { + mPasswordConfirm.setVisibility(View.GONE); } - }); + updateSaveButton(); + } + }); } @Override - public boolean onCreateOptionsMenu(Menu menu) { + public boolean onCreateOptionsMenu(final Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.editaccount, menu); - MenuItem showQrCode = menu.findItem(R.id.action_show_qr_code); + final MenuItem showQrCode = menu.findItem(R.id.action_show_qr_code); + final MenuItem showBlocklist = menu.findItem(R.id.action_show_block_list); if (mAccount == null) { showQrCode.setVisible(false); + showBlocklist.setVisible(false); + } else if (!mAccount.getXmppConnection().getFeatures().blocking()) { + showBlocklist.setVisible(false); } return true; } @@ -333,32 +337,38 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate protected void onStart() { super.onStart(); if (getIntent() != null) { - try { - this.jidToEdit = Jid.fromString(getIntent().getStringExtra("jid")); - } catch (final InvalidJidException | NullPointerException ignored) { - this.jidToEdit = null; - } - if (this.jidToEdit != null) { + try { + this.jidToEdit = Jid.fromString(getIntent().getStringExtra("jid")); + } catch (final InvalidJidException | NullPointerException ignored) { + this.jidToEdit = null; + } + if (this.jidToEdit != null) { this.mRegisterNew.setVisibility(View.GONE); - getActionBar().setTitle(getString(R.string.account_details)); + if (getActionBar() != null) { + getActionBar().setTitle(getString(R.string.account_details)); + } } else { this.mAvatar.setVisibility(View.GONE); - getActionBar().setTitle(R.string.action_add_account); + if (getActionBar() != null) { + getActionBar().setTitle(R.string.action_add_account); + } } } } @Override protected void onBackendConnected() { - KnownHostsAdapter mKnownHostsAdapter = new KnownHostsAdapter(this, - android.R.layout.simple_list_item_1, - xmppConnectionService.getKnownHosts()); + final KnownHostsAdapter mKnownHostsAdapter = new KnownHostsAdapter(this, + android.R.layout.simple_list_item_1, + xmppConnectionService.getKnownHosts()); if (this.jidToEdit != null) { this.mAccount = xmppConnectionService.findAccountByJid(jidToEdit); updateAccountInformation(); } else if (this.xmppConnectionService.getAccounts().size() == 0) { - getActionBar().setDisplayHomeAsUpEnabled(false); - getActionBar().setDisplayShowHomeEnabled(false); + if (getActionBar() != null) { + getActionBar().setDisplayHomeAsUpEnabled(false); + getActionBar().setDisplayShowHomeEnabled(false); + } this.mCancelButton.setEnabled(false); this.mCancelButton.setTextColor(getSecondaryTextColor()); } @@ -366,6 +376,18 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate updateSaveButton(); } + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + switch (item.getItemId()) { + case R.id.action_show_block_list: + final Intent intent = new Intent(this, BlocklistActivity.class); + intent.putExtra("account", mAccount.getJid().toString()); + startActivity(intent); + break; + } + return super.onOptionsItemSelected(item); + } + private void updateAccountInformation() { this.mAccountJid.setText(this.mAccount.getJid().toBareJid().toString()); this.mPassword.setText(this.mAccount.getPassword()); @@ -385,14 +407,14 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate && !this.mFetchingAvatar) { this.mStats.setVisibility(View.VISIBLE); this.mSessionEst.setText(UIHelper.readableTimeDifferenceFull( - getApplicationContext(), this.mAccount.getXmppConnection() - .getLastSessionEstablished())); - Features features = this.mAccount.getXmppConnection().getFeatures(); + getApplicationContext(), this.mAccount.getXmppConnection() + .getLastSessionEstablished())); + final Features features = this.mAccount.getXmppConnection().getFeatures(); if (features.carbons()) { this.mServerInfoCarbons.setText(R.string.server_info_available); } else { this.mServerInfoCarbons - .setText(R.string.server_info_unavailable); + .setText(R.string.server_info_unavailable); } if (features.sm()) { this.mServerInfoSm.setText(R.string.server_info_available); @@ -409,21 +431,21 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mOtrFingerprintBox.setVisibility(View.VISIBLE); this.mOtrFingerprint.setText(CryptoHelper.prettifyFingerprint(fingerprint)); this.mOtrFingerprintToClipboardButton - .setVisibility(View.VISIBLE); + .setVisibility(View.VISIBLE); this.mOtrFingerprintToClipboardButton - .setOnClickListener(new View.OnClickListener() { + .setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { + @Override + public void onClick(View v) { - if (copyTextToClipboard(fingerprint, R.string.otr_fingerprint)) { - Toast.makeText( - EditAccountActivity.this, - R.string.toast_message_otr_fingerprint, - Toast.LENGTH_SHORT).show(); - } + if (copyTextToClipboard(fingerprint, R.string.otr_fingerprint)) { + Toast.makeText( + EditAccountActivity.this, + R.string.toast_message_otr_fingerprint, + Toast.LENGTH_SHORT).show(); } - }); + } + }); } else { this.mOtrFingerprintBox.setVisibility(View.GONE); } diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java index be5eee99..c8075514 100644 --- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java @@ -117,10 +117,10 @@ public class ShareWithActivity extends XmppActivity { } @Override - public boolean onOptionsItemSelected(MenuItem item) { + public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case R.id.action_add: - Intent intent = new Intent(getApplicationContext(), + final Intent intent = new Intent(getApplicationContext(), ChooseContactActivity.class); startActivityForResult(intent, REQUEST_START_NEW_CONVERSATION); return true; diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index 4fdcf79e..630dc6ef 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -53,19 +53,21 @@ import java.util.List; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Blockable; import eu.siacs.conversations.entities.Bookmark; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.ListItem; -import eu.siacs.conversations.utils.XmppUri; import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; import eu.siacs.conversations.ui.adapter.KnownHostsAdapter; import eu.siacs.conversations.ui.adapter.ListItemAdapter; import eu.siacs.conversations.utils.Validator; +import eu.siacs.conversations.utils.XmppUri; +import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; -public class StartConversationActivity extends XmppActivity implements OnRosterUpdate { +public class StartConversationActivity extends XmppActivity implements OnRosterUpdate, OnUpdateBlocklist { public int conference_context_id; public int contact_context_id; @@ -133,7 +135,9 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU private ViewPager.SimpleOnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { - getActionBar().setSelectedNavigationItem(position); + if (getActionBar() != null) { + getActionBar().setSelectedNavigationItem(position); + } onTabChanged(); } }; @@ -146,12 +150,12 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU @Override public void beforeTextChanged(CharSequence s, int start, int count, - int after) { + int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, - int count) { + int count) { } }; private MenuItem mMenuSearchView; @@ -179,9 +183,9 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); mContactsTab = actionBar.newTab().setText(R.string.contacts) - .setTabListener(mTabListener); + .setTabListener(mTabListener); mConferencesTab = actionBar.newTab().setText(R.string.conferences) - .setTabListener(mTabListener); + .setTabListener(mTabListener); actionBar.addTab(mContactsTab); actionBar.addTab(mConferencesTab); @@ -207,35 +211,35 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU mConferenceListFragment.setListAdapter(mConferenceAdapter); mConferenceListFragment.setContextMenu(R.menu.conference_context); mConferenceListFragment - .setOnListItemClickListener(new OnItemClickListener() { + .setOnListItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView arg0, View arg1, - int position, long arg3) { - openConversationForBookmark(position); - } - }); + @Override + public void onItemClick(AdapterView arg0, View arg1, + int position, long arg3) { + openConversationForBookmark(position); + } + }); mContactsAdapter = new ListItemAdapter(this, contacts); mContactsListFragment.setListAdapter(mContactsAdapter); mContactsListFragment.setContextMenu(R.menu.contact_context); mContactsListFragment - .setOnListItemClickListener(new OnItemClickListener() { + .setOnListItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView arg0, View arg1, - int position, long arg3) { - openConversationForContact(position); - } - }); + @Override + public void onItemClick(AdapterView arg0, View arg1, + int position, long arg3) { + openConversationForContact(position); + } + }); } protected void openConversationForContact(int position) { Contact contact = (Contact) contacts.get(position); Conversation conversation = xmppConnectionService - .findOrCreateConversation(contact.getAccount(), - contact.getJid(), false); + .findOrCreateConversation(contact.getAccount(), + contact.getJid(), false); switchToConversation(conversation); } @@ -251,8 +255,8 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU protected void openConversationForBookmark(int position) { Bookmark bookmark = (Bookmark) conferences.get(position); Conversation conversation = xmppConnectionService - .findOrCreateConversation(bookmark.getAccount(), - bookmark.getJid(), true); + .findOrCreateConversation(bookmark.getAccount(), + bookmark.getJid(), true); conversation.setBookmark(bookmark); if (!conversation.getMucOptions().online()) { xmppConnectionService.joinMuc(conversation); @@ -270,14 +274,19 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU switchToContactDetails(contact); } + protected void toggleContactBlock() { + final int position = contact_context_id; + BlockContactDialog.show(this, xmppConnectionService, (Contact)contacts.get(position)); + } + protected void deleteContact() { - int position = contact_context_id; + final int position = contact_context_id; final Contact contact = (Contact) contacts.get(position); - AlertDialog.Builder builder = new AlertDialog.Builder(this); + final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setNegativeButton(R.string.cancel, null); builder.setTitle(R.string.action_delete_contact); builder.setMessage(getString(R.string.remove_contact_text, - contact.getJid())); + contact.getJid())); builder.setPositiveButton(R.string.delete, new OnClickListener() { @Override @@ -287,7 +296,6 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU } }); builder.create().show(); - } protected void deleteConference() { @@ -298,7 +306,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU builder.setNegativeButton(R.string.cancel, null); builder.setTitle(R.string.delete_bookmark); builder.setMessage(getString(R.string.remove_bookmark_text, - bookmark.getJid())); + bookmark.getJid())); builder.setPositiveButton(R.string.delete, new OnClickListener() { @Override @@ -360,7 +368,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU return; } Account account = xmppConnectionService - .findAccountByJid(accountJid); + .findAccountByJid(accountJid); if (account == null) { dialog.dismiss(); return; @@ -395,7 +403,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU } populateAccountSpinner(spinner); final CheckBox bookmarkCheckBox = (CheckBox) dialogView - .findViewById(R.id.bookmark); + .findViewById(R.id.bookmark); builder.setView(dialogView); builder.setNegativeButton(R.string.cancel, null); builder.setPositiveButton(R.string.join, null); @@ -424,7 +432,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU return; } Account account = xmppConnectionService - .findAccountByJid(accountJid); + .findAccountByJid(accountJid); if (account == null) { dialog.dismiss(); return; @@ -438,22 +446,22 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU bookmark.setAutojoin(true); account.getBookmarks().add(bookmark); xmppConnectionService - .pushBookmarks(account); + .pushBookmarks(account); Conversation conversation = xmppConnectionService - .findOrCreateConversation(account, - conferenceJid, true); + .findOrCreateConversation(account, + conferenceJid, true); conversation.setBookmark(bookmark); if (!conversation.getMucOptions().online()) { xmppConnectionService - .joinMuc(conversation); + .joinMuc(conversation); } dialog.dismiss(); switchToConversation(conversation); } } else { Conversation conversation = xmppConnectionService - .findOrCreateConversation(account, - conferenceJid, true); + .findOrCreateConversation(account, + conferenceJid, true); if (!conversation.getMucOptions().online()) { xmppConnectionService.joinMuc(conversation); } @@ -469,8 +477,8 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU protected void switchToConversation(Contact contact) { Conversation conversation = xmppConnectionService - .findOrCreateConversation(contact.getAccount(), - contact.getJid(), false); + .findOrCreateConversation(contact.getAccount(), + contact.getJid(), false); switchToConversation(conversation); } @@ -486,14 +494,14 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU this.mOptionsMenu = menu; getMenuInflater().inflate(R.menu.start_conversation, menu); MenuItem menuCreateContact = menu - .findItem(R.id.action_create_contact); + .findItem(R.id.action_create_contact); MenuItem menuCreateConference = menu - .findItem(R.id.action_join_conference); + .findItem(R.id.action_join_conference); mMenuSearchView = menu.findItem(R.id.action_search); mMenuSearchView.setOnActionExpandListener(mOnActionExpandListener); View mSearchView = mMenuSearchView.getActionView(); mSearchEditText = (EditText) mSearchView - .findViewById(R.id.search_field); + .findViewById(R.id.search_field); mSearchEditText.addTextChangedListener(mSearchTextWatcher); if (getActionBar().getSelectedNavigationIndex() == 0) { menuCreateConference.setVisible(false); @@ -562,7 +570,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU } this.mKnownHosts = xmppConnectionService.getKnownHosts(); this.mKnownConferenceHosts = xmppConnectionService - .getKnownConferenceHosts(); + .getKnownConferenceHosts(); if (this.mPendingInvite != null) { mPendingInvite.invite(); this.mPendingInvite = null; @@ -604,7 +612,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU byte[] payload = record.getPayload(); if (payload[0] == 0) { return new Invite(Uri.parse(new String(Arrays.copyOfRange( - payload, 1, payload.length)))).invite(); + payload, 1, payload.length)))).invite(); } } } @@ -685,16 +693,29 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU invalidateOptionsMenu(); } + @Override + public void OnUpdateBlocklist(final Status status) { + runOnUiThread(new Runnable() { + + @Override + public void run() { + if (mSearchEditText != null) { + filter(mSearchEditText.getText().toString()); + } + } + }); + } + public static class MyListFragment extends ListFragment { private AdapterView.OnItemClickListener mOnItemClickListener; private int mResContextMenu; - public void setContextMenu(int res) { + public void setContextMenu(final int res) { this.mResContextMenu = res; } @Override - public void onListItemClick(ListView l, View v, int position, long id) { + public void onListItemClick(final ListView l, final View v, final int position, final long id) { if (mOnItemClickListener != null) { mOnItemClickListener.onItemClick(l, v, position, id); } @@ -705,28 +726,38 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU } @Override - public void onViewCreated(View view, Bundle savedInstanceState) { + public void onViewCreated(final View view, final Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); registerForContextMenu(getListView()); getListView().setFastScrollEnabled(true); } @Override - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { + public void onCreateContextMenu(final ContextMenu menu, final View v, + final ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); - StartConversationActivity activity = (StartConversationActivity) getActivity(); + final StartConversationActivity activity = (StartConversationActivity) getActivity(); activity.getMenuInflater().inflate(mResContextMenu, menu); - AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo; + final AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo; if (mResContextMenu == R.menu.conference_context) { activity.conference_context_id = acmi.position; } else { activity.contact_context_id = acmi.position; + final Blockable contact = (Contact) activity.contacts.get(acmi.position); + + final MenuItem blockUnblockItem = menu.findItem(R.id.context_contact_block_unblock); + if (blockUnblockItem != null) { + if (contact.isBlocked()) { + blockUnblockItem.setTitle(R.string.unblock_contact); + } else { + blockUnblockItem.setTitle(R.string.block_contact); + } + } } } @Override - public boolean onContextItemSelected(MenuItem item) { + public boolean onContextItemSelected(final MenuItem item) { StartConversationActivity activity = (StartConversationActivity) getActivity(); switch (item.getItemId()) { case R.id.context_start_conversation: @@ -735,6 +766,9 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU case R.id.context_contact_details: activity.openDetailsForContact(); break; + case R.id.context_contact_block_unblock: + activity.toggleContactBlock(); + break; case R.id.context_delete_contact: activity.deleteContact(); break; @@ -750,11 +784,11 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU private class Invite extends XmppUri { - public Invite(Uri uri) { + public Invite(final Uri uri) { super(uri); } - public Invite(String uri) { + public Invite(final String uri) { super(uri); } diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index e6ae2a1c..69dd47e7 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -71,6 +71,7 @@ import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder; import eu.siacs.conversations.utils.ExceptionHelper; +import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; @@ -199,7 +200,7 @@ public abstract class XmppActivity extends Activity { xmppConnectionServiceBound = false; } stopService(new Intent(XmppActivity.this, - XmppConnectionService.class)); + XmppConnectionService.class)); finish(); } }); @@ -209,13 +210,13 @@ public abstract class XmppActivity extends Activity { @Override public void onClick(DialogInterface dialog, int which) { Uri uri = Uri - .parse("market://details?id=org.sufficientlysecure.keychain"); + .parse("market://details?id=org.sufficientlysecure.keychain"); Intent marketIntent = new Intent(Intent.ACTION_VIEW, uri); PackageManager manager = getApplicationContext() - .getPackageManager(); + .getPackageManager(); List infos = manager - .queryIntentActivities(marketIntent, 0); + .queryIntentActivities(marketIntent, 0); if (infos.size() > 0) { startActivity(marketIntent); } else { @@ -245,6 +246,9 @@ public abstract class XmppActivity extends Activity { if (this instanceof XmppConnectionService.OnMucRosterUpdate) { this.xmppConnectionService.setOnMucRosterUpdateListener((XmppConnectionService.OnMucRosterUpdate) this); } + if (this instanceof OnUpdateBlocklist) { + this.xmppConnectionService.setOnUpdateBlocklistListener((OnUpdateBlocklist) this); + } } protected void unregisterListeners() { @@ -260,9 +264,13 @@ public abstract class XmppActivity extends Activity { if (this instanceof XmppConnectionService.OnMucRosterUpdate) { this.xmppConnectionService.removeOnMucRosterUpdateListener(); } + if (this instanceof OnUpdateBlocklist) { + this.xmppConnectionService.removeOnUpdateBlocklistListener(); + } } - public boolean onOptionsItemSelected(MenuItem item) { + @Override + public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case R.id.action_settings: startActivity(new Intent(this, SettingsActivity.class)); @@ -300,7 +308,7 @@ public abstract class XmppActivity extends Activity { protected SharedPreferences getPreferences() { return PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()); + .getDefaultSharedPreferences(getApplicationContext()); } public boolean useSubjectToIdentifyConference() { @@ -312,7 +320,7 @@ public abstract class XmppActivity extends Activity { } public void switchToConversation(Conversation conversation, String text, - boolean newTask) { + boolean newTask) { switchToConversation(conversation,text,null,newTask); } @@ -372,7 +380,7 @@ public abstract class XmppActivity extends Activity { @Override public void userInputRequried(PendingIntent pi, - Account account) { + Account account) { try { startIntentSenderForResult(pi.getIntentSender(), REQUEST_ANNOUNCE_PGP, null, 0, 0, 0); @@ -383,15 +391,15 @@ public abstract class XmppActivity extends Activity { @Override public void success(Account account) { xmppConnectionService.databaseBackend - .updateAccount(account); + .updateAccount(account); xmppConnectionService.sendPresencePacket(account, xmppConnectionService.getPresenceGenerator() - .sendPresence(account)); + .sendPresence(account)); if (conversation != null) { conversation - .setNextEncryption(Message.ENCRYPTION_PGP); + .setNextEncryption(Message.ENCRYPTION_PGP); xmppConnectionService.databaseBackend - .updateConversation(conversation); + .updateConversation(conversation); } } @@ -420,7 +428,7 @@ public abstract class XmppActivity extends Activity { } protected void showAddToRosterDialog(final Conversation conversation) { - final Jid jid = conversation.getContactJid(); + final Jid jid = conversation.getJid(); AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(jid.toString()); builder.setMessage(getString(R.string.not_in_roster)); @@ -430,7 +438,7 @@ public abstract class XmppActivity extends Activity { @Override public void onClick(DialogInterface dialog, int which) { - final Jid jid = conversation.getContactJid(); + final Jid jid = conversation.getJid(); Account account = conversation.getAccount(); Contact contact = account.getRoster().getContact(jid); xmppConnectionService.createContact(contact); @@ -462,7 +470,7 @@ public abstract class XmppActivity extends Activity { } private void warnMutalPresenceSubscription(final Conversation conversation, - final OnPresenceSelected listener) { + final OnPresenceSelected listener) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(conversation.getContact().getJid().toString()); builder.setMessage(R.string.without_mutual_presence_updates); @@ -485,13 +493,13 @@ public abstract class XmppActivity extends Activity { } protected void quickPasswordEdit(String previousValue, - OnValueEdited callback) { + OnValueEdited callback) { quickEdit(previousValue, callback, true); } @SuppressLint("InflateParams") private void quickEdit(final String previousValue, - final OnValueEdited callback, boolean password) { + final OnValueEdited callback, boolean password) { AlertDialog.Builder builder = new AlertDialog.Builder(this); View view = getLayoutInflater().inflate(R.layout.quickedit, null); final EditText editor = (EditText) view.findViewById(R.id.editor); @@ -521,7 +529,7 @@ public abstract class XmppActivity extends Activity { } public void selectPresence(final Conversation conversation, - final OnPresenceSelected listener) { + final OnPresenceSelected listener) { final Contact contact = conversation.getContact(); if (conversation.hasValidOtrSession()) { SessionID id = conversation.getOtrSession().getSessionID(); @@ -576,7 +584,7 @@ public abstract class XmppActivity extends Activity { @Override public void onClick(DialogInterface dialog, - int which) { + int which) { presence.delete(0, presence.length()); presence.append(presencesArray[which]); } @@ -600,7 +608,7 @@ public abstract class XmppActivity extends Activity { } protected void onActivityResult(int requestCode, int resultCode, - final Intent data) { + final Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_INVITE_TO_CONVERSATION && resultCode == RESULT_OK) { @@ -608,19 +616,19 @@ public abstract class XmppActivity extends Activity { Jid jid = Jid.fromString(data.getStringExtra("contact")); String conversationUuid = data.getStringExtra("conversation"); Conversation conversation = xmppConnectionService - .findConversationByUuid(conversationUuid); + .findConversationByUuid(conversationUuid); if (conversation.getMode() == Conversation.MODE_MULTI) { xmppConnectionService.invite(conversation, jid); } else { List jids = new ArrayList(); - jids.add(conversation.getContactJid().toBareJid()); + jids.add(conversation.getJid().toBareJid()); jids.add(jid); xmppConnectionService.createAdhocConference(conversation.getAccount(), jids, adhocCallback); } } catch (final InvalidJidException ignored) { } - } + } } private UiCallback adhocCallback = new UiCallback() { @@ -688,18 +696,18 @@ public abstract class XmppActivity extends Activity { } protected void registerNdefPushMessageCallback() { - NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); - if (nfcAdapter != null && nfcAdapter.isEnabled()) { - nfcAdapter.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() { - @Override - public NdefMessage createNdefMessage(NfcEvent nfcEvent) { - return new NdefMessage(new NdefRecord[]{ - NdefRecord.createUri(getShareableUri()), - NdefRecord.createApplicationRecord("eu.siacs.conversations") - }); - } - }, this); - } + NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); + if (nfcAdapter != null && nfcAdapter.isEnabled()) { + nfcAdapter.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() { + @Override + public NdefMessage createNdefMessage(NfcEvent nfcEvent) { + return new NdefMessage(new NdefRecord[]{ + NdefRecord.createUri(getShareableUri()), + NdefRecord.createApplicationRecord("eu.siacs.conversations") + }); + } + }, this); + } } protected void unregisterNdefPushMessageCallback() { @@ -831,13 +839,13 @@ public abstract class XmppActivity extends Activity { try { task.execute(message); } catch (final RejectedExecutionException ignored) { - } + } } } } public static boolean cancelPotentialWork(Message message, - ImageView imageView) { + ImageView imageView) { final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); if (bitmapWorkerTask != null) { @@ -866,7 +874,7 @@ public abstract class XmppActivity extends Activity { private final WeakReference bitmapWorkerTaskReference; public AsyncDrawable(Resources res, Bitmap bitmap, - BitmapWorkerTask bitmapWorkerTask) { + BitmapWorkerTask bitmapWorkerTask) { super(res, bitmap); bitmapWorkerTaskReference = new WeakReference<>( bitmapWorkerTask); diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java index f728e800..2465380f 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java @@ -34,7 +34,7 @@ public class ConversationAdapter extends ArrayAdapter { public View getView(int position, View view, ViewGroup parent) { if (view == null) { LayoutInflater inflater = (LayoutInflater) activity - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.conversation_list_row, parent, false); } @@ -53,19 +53,19 @@ public class ConversationAdapter extends ArrayAdapter { } } TextView convName = (TextView) view - .findViewById(R.id.conversation_name); + .findViewById(R.id.conversation_name); if (conversation.getMode() == Conversation.MODE_SINGLE || activity.useSubjectToIdentifyConference()) { convName.setText(conversation.getName()); } else { - convName.setText(conversation.getContactJid().toBareJid().toString()); + convName.setText(conversation.getJid().toBareJid().toString()); } TextView mLastMessage = (TextView) view - .findViewById(R.id.conversation_lastmsg); + .findViewById(R.id.conversation_lastmsg); TextView mTimestamp = (TextView) view - .findViewById(R.id.conversation_lastupdate); + .findViewById(R.id.conversation_lastupdate); ImageView imagePreview = (ImageView) view - .findViewById(R.id.conversation_lastimage); + .findViewById(R.id.conversation_lastimage); Message message = conversation.getLatestMessage(); @@ -151,12 +151,12 @@ public class ConversationAdapter extends ArrayAdapter { imagePreview.setVisibility(View.GONE); } mTimestamp.setText(UIHelper.readableTimeDifference(getContext(), - conversation.getLatestMessage().getTimeSent())); + conversation.getLatestMessage().getTimeSent())); ImageView profilePicture = (ImageView) view - .findViewById(R.id.conversation_image); + .findViewById(R.id.conversation_image); profilePicture.setImageBitmap(activity.avatarService().get( - conversation, activity.getPixel(56))); + conversation, activity.getPixel(56))); return view; } diff --git a/src/main/java/eu/siacs/conversations/utils/Xmlns.java b/src/main/java/eu/siacs/conversations/utils/Xmlns.java new file mode 100644 index 00000000..932e48ae --- /dev/null +++ b/src/main/java/eu/siacs/conversations/utils/Xmlns.java @@ -0,0 +1,5 @@ +package eu.siacs.conversations.utils; + +public final class Xmlns { + public static final String BLOCKING = "urn:xmpp:blocking"; +} diff --git a/src/main/java/eu/siacs/conversations/utils/XmppUri.java b/src/main/java/eu/siacs/conversations/utils/XmppUri.java index a9b8d1c0..d7c3bce5 100644 --- a/src/main/java/eu/siacs/conversations/utils/XmppUri.java +++ b/src/main/java/eu/siacs/conversations/utils/XmppUri.java @@ -5,7 +5,6 @@ import android.net.Uri; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; -import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; diff --git a/src/main/java/eu/siacs/conversations/xml/Element.java b/src/main/java/eu/siacs/conversations/xml/Element.java index 9455d9e8..51708759 100644 --- a/src/main/java/eu/siacs/conversations/xml/Element.java +++ b/src/main/java/eu/siacs/conversations/xml/Element.java @@ -62,16 +62,16 @@ public class Element { if (child.getName().equals(name) && (child.getAttribute("xmlns").equals(xmlns))) { return child; - } + } } return null; } - public boolean hasChild(String name) { + public boolean hasChild(final String name) { return findChild(name) != null; } - public boolean hasChild(String name, String xmlns) { + public boolean hasChild(final String name, final String xmlns) { return findChild(name, xmlns) != null; } @@ -110,15 +110,15 @@ public class Element { public Jid getAttributeAsJid(String name) { final String jid = this.getAttribute(name); - if (jid != null && !jid.isEmpty()) { - try { - return Jid.fromString(jid); - } catch (final InvalidJidException e) { + if (jid != null && !jid.isEmpty()) { + try { + return Jid.fromString(jid); + } catch (final InvalidJidException e) { Log.e(Config.LOGTAG, "could not parse jid " + jid); - return null; - } - } - return null; + return null; + } + } + return null; } public Hashtable getAttributes() { diff --git a/src/main/java/eu/siacs/conversations/xmpp/OnContactStatusChanged.java b/src/main/java/eu/siacs/conversations/xmpp/OnContactStatusChanged.java index 849e8e76..20b17f02 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/OnContactStatusChanged.java +++ b/src/main/java/eu/siacs/conversations/xmpp/OnContactStatusChanged.java @@ -3,5 +3,5 @@ package eu.siacs.conversations.xmpp; import eu.siacs.conversations.entities.Contact; public interface OnContactStatusChanged { - public void onContactStatusChanged(Contact contact, boolean online); + public void onContactStatusChanged(final Contact contact, final boolean online); } diff --git a/src/main/java/eu/siacs/conversations/xmpp/OnUpdateBlocklist.java b/src/main/java/eu/siacs/conversations/xmpp/OnUpdateBlocklist.java new file mode 100644 index 00000000..92e72cfa --- /dev/null +++ b/src/main/java/eu/siacs/conversations/xmpp/OnUpdateBlocklist.java @@ -0,0 +1,13 @@ +package eu.siacs.conversations.xmpp; + +public interface OnUpdateBlocklist { + // Use an enum instead of a boolean to make sure we don't run into the boolean trap + // (`onUpdateBlocklist(true)' doesn't read well, and could be confusing). + public static enum Status { + BLOCKED, + UNBLOCKED + } + + @SuppressWarnings("MethodNameSameAsClassName") + public void OnUpdateBlocklist(final Status status); +} diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index b090d651..7fd0a4b6 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -30,10 +30,12 @@ import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import javax.net.ssl.HostnameVerifier; @@ -48,8 +50,10 @@ import eu.siacs.conversations.crypto.sasl.Plain; import eu.siacs.conversations.crypto.sasl.SaslMechanism; import eu.siacs.conversations.crypto.sasl.ScramSha1; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.generator.IqGenerator; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.DNSHelper; +import eu.siacs.conversations.utils.Xmlns; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Tag; import eu.siacs.conversations.xml.TagWriter; @@ -76,19 +80,19 @@ public class XmppConnection implements Runnable { private static final int PACKET_PRESENCE = 2; private final Context applicationContext; protected Account account; - private WakeLock wakeLock; + private final WakeLock wakeLock; private Socket socket; private XmlReader tagReader; private TagWriter tagWriter; - private Features features = new Features(this); + private final Features features = new Features(this); private boolean shouldBind = true; private boolean shouldAuthenticate = true; private Element streamFeatures; - private HashMap> disco = new HashMap<>(); + private final HashMap> disco = new HashMap<>(); private String streamId = null; private int smVersion = 3; - private SparseArray messageReceipts = new SparseArray<>(); + private final SparseArray messageReceipts = new SparseArray<>(); private boolean enabledEncryption = false; private boolean enabledCarbons = false; @@ -100,20 +104,20 @@ public class XmppConnection implements Runnable { private long lastConnect = 0; private long lastSessionStarted = 0; private int attempt = 0; - private Hashtable packetCallbacks = new Hashtable<>(); + private final Map packetCallbacks = new Hashtable<>(); private OnPresencePacketReceived presenceListener = null; private OnJinglePacketReceived jingleListener = null; private OnIqPacketReceived unregisteredIqListener = null; private OnMessagePacketReceived messageListener = null; private OnStatusChanged statusListener = null; private OnBindListener bindListener = null; - private ArrayList advancedStreamFeaturesLoadedListeners = new ArrayList<>(); + private final ArrayList advancedStreamFeaturesLoadedListeners = new ArrayList<>(); private OnMessageAcknowledged acknowledgedListener = null; private XmppConnectionService mXmppConnectionService = null; private SaslMechanism saslMechanism; - public XmppConnection(Account account, XmppConnectionService service) { + public XmppConnection(final Account account, final XmppConnectionService service) { this.account = account; this.wakeLock = service.getPowerManager().newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, account.getJid().toBareJid().toString()); @@ -129,7 +133,7 @@ public class XmppConnection implements Runnable { && (account.getStatus() != Account.State.ONLINE) && (account.getStatus() != Account.State.DISABLED)) { return; - } + } if (nextStatus == Account.State.ONLINE) { this.attempt = 0; } @@ -153,15 +157,15 @@ public class XmppConnection implements Runnable { tagWriter = new TagWriter(); packetCallbacks.clear(); this.changeStatus(Account.State.CONNECTING); - Bundle result = DNSHelper.getSRVRecord(account.getServer()); - ArrayList values = result.getParcelableArrayList("values"); + final Bundle result = DNSHelper.getSRVRecord(account.getServer()); + final ArrayList values = result.getParcelableArrayList("values"); if ("timeout".equals(result.getString("error"))) { throw new IOException("timeout in dns"); } else if (values != null) { int i = 0; boolean socketError = true; while (socketError && values.size() > i) { - Bundle namePort = (Bundle) values.get(i); + final Bundle namePort = (Bundle) values.get(i); try { String srvRecordServer; try { @@ -170,9 +174,9 @@ public class XmppConnection implements Runnable { // TODO: Handle me?` srvRecordServer = ""; } - int srvRecordPort = namePort.getInt("port"); - String srvIpServer = namePort.getString("ip"); - InetSocketAddress addr; + final int srvRecordPort = namePort.getInt("port"); + final String srvIpServer = namePort.getString("ip"); + final InetSocketAddress addr; if (srvIpServer != null) { addr = new InetSocketAddress(srvIpServer, srvRecordPort); Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() @@ -187,10 +191,10 @@ public class XmppConnection implements Runnable { socket = new Socket(); socket.connect(addr, 20000); socketError = false; - } catch (UnknownHostException e) { + } catch (final UnknownHostException e) { Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage()); i++; - } catch (IOException e) { + } catch (final IOException e) { Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage()); i++; } @@ -204,9 +208,9 @@ public class XmppConnection implements Runnable { } else { throw new IOException("timeout in dns"); } - OutputStream out = socket.getOutputStream(); + final OutputStream out = socket.getOutputStream(); tagWriter.setOutputStream(out); - InputStream in = socket.getInputStream(); + final InputStream in = socket.getInputStream(); tagReader.setInputStream(in); tagWriter.beginDocument(); sendStartStream(); @@ -222,14 +226,9 @@ public class XmppConnection implements Runnable { if (socket.isConnected()) { socket.close(); } - } catch (UnknownHostException e) { - this.changeStatus(Account.State.SERVER_NOT_FOUND); - } catch (final ConnectException e) { + } catch (final UnknownHostException | ConnectException e) { this.changeStatus(Account.State.SERVER_NOT_FOUND); - } catch (final IOException | XmlPullParserException e) { - Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage()); - this.changeStatus(Account.State.OFFLINE); - } catch (NoSuchAlgorithmException e) { + } catch (final IOException | XmlPullParserException | NoSuchAlgorithmException e) { Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage()); this.changeStatus(Account.State.OFFLINE); } finally { @@ -268,7 +267,7 @@ public class XmppConnection implements Runnable { } Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": logged in"); account.setKey(Account.PINNED_MECHANISM_KEY, - String.valueOf(saslMechanism.getPriority())); + String.valueOf(saslMechanism.getPriority())); tagReader.reset(); sendStartStream(); processStream(tagReader.readTag()); @@ -289,7 +288,7 @@ public class XmppConnection implements Runnable { } tagWriter.writeElement(response); } else if (nextTag.isStart("enabled")) { - Element enabled = tagReader.readElement(nextTag); + final Element enabled = tagReader.readElement(nextTag); if ("true".equals(enabled.getAttribute("resume"))) { this.streamId = enabled.getAttribute("id"); Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() @@ -301,14 +300,14 @@ public class XmppConnection implements Runnable { } this.lastSessionStarted = SystemClock.elapsedRealtime(); this.stanzasReceived = 0; - RequestPacket r = new RequestPacket(smVersion); + final RequestPacket r = new RequestPacket(smVersion); tagWriter.writeStanzaAsync(r); } else if (nextTag.isStart("resumed")) { lastPaketReceived = SystemClock.elapsedRealtime(); - Element resumed = tagReader.readElement(nextTag); - String h = resumed.getAttribute("h"); + final Element resumed = tagReader.readElement(nextTag); + final String h = resumed.getAttribute("h"); try { - int serverCount = Integer.parseInt(h); + final int serverCount = Integer.parseInt(h); if (serverCount != stanzasSent) { Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": session resumed with lost packages"); @@ -327,20 +326,19 @@ public class XmppConnection implements Runnable { } messageReceipts.clear(); } catch (final NumberFormatException ignored) { - } sendServiceDiscoveryInfo(account.getServer()); sendServiceDiscoveryItems(account.getServer()); sendInitialPing(); } else if (nextTag.isStart("r")) { tagReader.readElement(nextTag); - AckPacket ack = new AckPacket(this.stanzasReceived, smVersion); + final AckPacket ack = new AckPacket(this.stanzasReceived, smVersion); tagWriter.writeStanzaAsync(ack); } else if (nextTag.isStart("a")) { - Element ack = tagReader.readElement(nextTag); + final Element ack = tagReader.readElement(nextTag); lastPaketReceived = SystemClock.elapsedRealtime(); - int serverSequence = Integer.parseInt(ack.getAttribute("h")); - String msgId = this.messageReceipts.get(serverSequence); + final int serverSequence = Integer.parseInt(ack.getAttribute("h")); + final String msgId = this.messageReceipts.get(serverSequence); if (msgId != null) { if (this.acknowledgedListener != null) { this.acknowledgedListener.onMessageAcknowledged( @@ -374,13 +372,12 @@ public class XmppConnection implements Runnable { private void sendInitialPing() { Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": sending intial ping"); - IqPacket iq = new IqPacket(IqPacket.TYPE_GET); + final IqPacket iq = new IqPacket(IqPacket.TYPE_GET); iq.setFrom(account.getJid()); iq.addChild("ping", "urn:xmpp:ping"); this.sendIqPacket(iq, new OnIqPacketReceived() { - @Override - public void onIqPacketReceived(Account account, IqPacket packet) { + public void onIqPacketReceived(final Account account, final IqPacket packet) { Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": online with resource " + account.getResource()); changeStatus(Account.State.ONLINE); @@ -388,7 +385,7 @@ public class XmppConnection implements Runnable { }); } - private Element processPacket(Tag currentTag, int packetType) + private Element processPacket(final Tag currentTag, final int packetType) throws XmlPullParserException, IOException { Element element; switch (packetType) { @@ -411,8 +408,8 @@ public class XmppConnection implements Runnable { } while (!nextTag.isEnd(element.getName())) { if (!nextTag.isNo()) { - Element child = tagReader.readElement(nextTag); - String type = currentTag.getAttribute("type"); + final Element child = tagReader.readElement(nextTag); + final String type = currentTag.getAttribute("type"); if (packetType == PACKET_IQ && "jingle".equals(child.getName()) && ("set".equalsIgnoreCase(type) || "get" @@ -432,9 +429,9 @@ public class XmppConnection implements Runnable { return element; } - private void processIq(Tag currentTag) throws XmlPullParserException, + private void processIq(final Tag currentTag) throws XmlPullParserException, IOException { - IqPacket packet = (IqPacket) processPacket(currentTag, PACKET_IQ); + final IqPacket packet = (IqPacket) processPacket(currentTag, PACKET_IQ); if (packet.getId() == null) { return; // an iq packet without id is definitely invalid @@ -461,11 +458,11 @@ public class XmppConnection implements Runnable { } } - private void processMessage(Tag currentTag) throws XmlPullParserException, + private void processMessage(final Tag currentTag) throws XmlPullParserException, IOException { - MessagePacket packet = (MessagePacket) processPacket(currentTag, + final MessagePacket packet = (MessagePacket) processPacket(currentTag, PACKET_MESSAGE); - String id = packet.getAttribute("id"); + final String id = packet.getAttribute("id"); if ((id != null) && (packetCallbacks.containsKey(id))) { if (packetCallbacks.get(id) instanceof OnMessagePacketReceived) { ((OnMessagePacketReceived) packetCallbacks.get(id)) @@ -477,11 +474,11 @@ public class XmppConnection implements Runnable { } } - private void processPresence(Tag currentTag) throws XmlPullParserException, + private void processPresence(final Tag currentTag) throws XmlPullParserException, IOException { PresencePacket packet = (PresencePacket) processPacket(currentTag, PACKET_PRESENCE); - String id = packet.getAttribute("id"); + final String id = packet.getAttribute("id"); if ((id != null) && (packetCallbacks.containsKey(id))) { if (packetCallbacks.get(id) instanceof OnPresencePacketReceived) { ((OnPresencePacketReceived) packetCallbacks.get(id)) @@ -494,7 +491,7 @@ public class XmppConnection implements Runnable { } private void sendStartTLS() throws IOException { - Tag startTLS = Tag.empty("starttls"); + final Tag startTLS = Tag.empty("starttls"); startTLS.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-tls"); tagWriter.writeTag(startTLS); } @@ -512,11 +509,11 @@ public class XmppConnection implements Runnable { IOException { tagReader.readTag(); try { - SSLContext sc = SSLContext.getInstance("TLS"); + final SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, new X509TrustManager[]{this.mXmppConnectionService.getMemorizingTrustManager()}, mXmppConnectionService.getRNG()); - SSLSocketFactory factory = sc.getSocketFactory(); + final SSLSocketFactory factory = sc.getSocketFactory(); if (factory == null) { throw new IOException("SSLSocketFactory was null"); @@ -541,7 +538,7 @@ public class XmppConnection implements Runnable { if (enableLegacySSL()) { supportProtocols = sslSocket.getSupportedProtocols(); } else { - final List supportedProtocols = new LinkedList<>( + final Collection supportedProtocols = new LinkedList<>( Arrays.asList(sslSocket.getSupportedProtocols())); supportedProtocols.remove("SSLv3"); supportProtocols = new String[supportedProtocols.size()]; @@ -549,13 +546,13 @@ public class XmppConnection implements Runnable { } sslSocket.setEnabledProtocols(supportProtocols); - if (verifier != null - && !verifier.verify(account.getServer().getDomainpart(), - sslSocket.getSession())) { + if (verifier != null + && !verifier.verify(account.getServer().getDomainpart(), + sslSocket.getSession())) { Log.d(Config.LOGTAG,account.getJid().toBareJid()+": TLS certificate verification failed"); disconnect(true); changeStatus(Account.State.SECURITY_ERROR); - } + } tagReader.setInputStream(sslSocket.getInputStream()); tagWriter.setOutputStream(sslSocket.getOutputStream()); sendStartStream(); @@ -569,7 +566,7 @@ public class XmppConnection implements Runnable { } } - private void processStreamFeatures(Tag currentTag) + private void processStreamFeatures(final Tag currentTag) throws XmlPullParserException, IOException { this.streamFeatures = tagReader.readElement(currentTag); if (this.streamFeatures.hasChild("starttls") && !enabledEncryption) { @@ -605,7 +602,7 @@ public class XmppConnection implements Runnable { "). Possible downgrade attack?"); disconnect(true); changeStatus(Account.State.SECURITY_ERROR); - } + } } catch (final JSONException e) { Log.d(Config.LOGTAG, "Parse error while checking pinned auth mechanism"); } @@ -618,7 +615,7 @@ public class XmppConnection implements Runnable { } else if (this.streamFeatures.hasChild("sm", "urn:xmpp:sm:" + smVersion) && streamId != null) { - ResumePacket resume = new ResumePacket(this.streamId, + final ResumePacket resume = new ResumePacket(this.streamId, stanzasReceived, smVersion); this.tagWriter.writeStanzaAsync(resume); } else if (this.streamFeatures.hasChild("bind") && shouldBind) { @@ -629,45 +626,44 @@ public class XmppConnection implements Runnable { } } - private List extractMechanisms(Element stream) { - ArrayList mechanisms = new ArrayList<>(stream + private List extractMechanisms(final Element stream) { + final ArrayList mechanisms = new ArrayList<>(stream .getChildren().size()); - for (Element child : stream.getChildren()) { + for (final Element child : stream.getChildren()) { mechanisms.add(child.getContent()); } return mechanisms; } private void sendRegistryRequest() { - IqPacket register = new IqPacket(IqPacket.TYPE_GET); + final IqPacket register = new IqPacket(IqPacket.TYPE_GET); register.query("jabber:iq:register"); register.setTo(account.getServer()); sendIqPacket(register, new OnIqPacketReceived() { @Override - public void onIqPacketReceived(Account account, IqPacket packet) { - Element instructions = packet.query().findChild("instructions"); + public void onIqPacketReceived(final Account account, final IqPacket packet) { + final Element instructions = packet.query().findChild("instructions"); if (packet.query().hasChild("username") && (packet.query().hasChild("password"))) { - IqPacket register = new IqPacket(IqPacket.TYPE_SET); - Element username = new Element("username") - .setContent(account.getUsername()); - Element password = new Element("password") - .setContent(account.getPassword()); + final IqPacket register = new IqPacket(IqPacket.TYPE_SET); + final Element username = new Element("username") + .setContent(account.getUsername()); + final Element password = new Element("password") + .setContent(account.getPassword()); register.query("jabber:iq:register").addChild(username); register.query().addChild(password); sendIqPacket(register, new OnIqPacketReceived() { @Override - public void onIqPacketReceived(Account account, - IqPacket packet) { + public void onIqPacketReceived(final Account account, final IqPacket packet) { if (packet.getType() == IqPacket.TYPE_RESULT) { account.setOption(Account.OPTION_REGISTER, false); changeStatus(Account.State.REGISTRATION_SUCCESSFUL); } else if (packet.hasChild("error") && (packet.findChild("error") - .hasChild("conflict"))) { + .hasChild("conflict"))) { changeStatus(Account.State.REGISTRATION_CONFLICT); } else { changeStatus(Account.State.REGISTRATION_FAILED); @@ -687,14 +683,14 @@ public class XmppConnection implements Runnable { }); } - private void sendBindRequest() throws IOException { - IqPacket iq = new IqPacket(IqPacket.TYPE_SET); + private void sendBindRequest() { + final IqPacket iq = new IqPacket(IqPacket.TYPE_SET); iq.addChild("bind", "urn:ietf:params:xml:ns:xmpp-bind") .addChild("resource").setContent(account.getResource()); this.sendUnboundIqPacket(iq, new OnIqPacketReceived() { @Override - public void onIqPacketReceived(Account account, IqPacket packet) { - Element bind = packet.findChild("bind"); + public void onIqPacketReceived(final Account account, final IqPacket packet) { + final Element bind = packet.findChild("bind"); if (bind != null) { final Element jid = bind.findChild("jid"); if (jid != null && jid.getContent() != null) { @@ -705,14 +701,14 @@ public class XmppConnection implements Runnable { } if (streamFeatures.hasChild("sm", "urn:xmpp:sm:3")) { smVersion = 3; - EnablePacket enable = new EnablePacket(smVersion); + final EnablePacket enable = new EnablePacket(smVersion); tagWriter.writeStanzaAsync(enable); stanzasSent = 0; messageReceipts.clear(); } else if (streamFeatures.hasChild("sm", - "urn:xmpp:sm:2")) { + "urn:xmpp:sm:2")) { smVersion = 2; - EnablePacket enable = new EnablePacket(smVersion); + final EnablePacket enable = new EnablePacket(smVersion); tagWriter.writeStanzaAsync(enable); stanzasSent = 0; messageReceipts.clear(); @@ -736,7 +732,7 @@ public class XmppConnection implements Runnable { if (this.streamFeatures.hasChild("session")) { Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": sending deprecated session"); - IqPacket startSession = new IqPacket(IqPacket.TYPE_SET); + final IqPacket startSession = new IqPacket(IqPacket.TYPE_SET); startSession.addChild("session", "urn:ietf:params:xml:ns:xmpp-session"); this.sendUnboundIqPacket(startSession, null); @@ -755,10 +751,10 @@ public class XmppConnection implements Runnable { this.sendIqPacket(iq, new OnIqPacketReceived() { @Override - public void onIqPacketReceived(Account account, IqPacket packet) { + public void onIqPacketReceived(final Account account, final IqPacket packet) { final List elements = packet.query().getChildren(); final List features = new ArrayList<>(); - for (Element element : elements) { + for (final Element element : elements) { if (element.getName().equals("identity")) { if ("irc".equals(element.getAttribute("type"))) { //add fake feature to not confuse irc and real muc @@ -772,7 +768,7 @@ public class XmppConnection implements Runnable { if (account.getServer().equals(server.toDomainJid())) { enableAdvancedStreamFeatures(); - for(OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) { + for (final OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) { listener.onAdvancedStreamFeaturesAvailable(account); } } @@ -787,6 +783,10 @@ public class XmppConnection implements Runnable { sendEnableCarbons(); } } + if (getFeatures().blocking()) { + Log.d(Config.LOGTAG, "Requesting block list"); + this.sendIqPacket(getIqGenerator().generateGetBlockList(), mXmppConnectionService.getIqParser()); + } } private void sendServiceDiscoveryItems(final Jid server) { @@ -796,9 +796,9 @@ public class XmppConnection implements Runnable { this.sendIqPacket(iq, new OnIqPacketReceived() { @Override - public void onIqPacketReceived(Account account, IqPacket packet) { - List elements = packet.query().getChildren(); - for (Element element : elements) { + public void onIqPacketReceived(final Account account, final IqPacket packet) { + final List elements = packet.query().getChildren(); + for (final Element element : elements) { if (element.getName().equals("item")) { final Jid jid = element.getAttributeAsJid("jid"); if (jid != null && !jid.equals(account.getServer())) { @@ -811,12 +811,12 @@ public class XmppConnection implements Runnable { } private void sendEnableCarbons() { - IqPacket iq = new IqPacket(IqPacket.TYPE_SET); + final IqPacket iq = new IqPacket(IqPacket.TYPE_SET); iq.addChild("enable", "urn:xmpp:carbons:2"); this.sendIqPacket(iq, new OnIqPacketReceived() { @Override - public void onIqPacketReceived(Account account, IqPacket packet) { + public void onIqPacketReceived(final Account account, final IqPacket packet) { if (!packet.hasChild("error")) { Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": successfully enabled carbons"); @@ -829,20 +829,20 @@ public class XmppConnection implements Runnable { }); } - private void processStreamError(Tag currentTag) + private void processStreamError(final Tag currentTag) throws XmlPullParserException, IOException { - Element streamError = tagReader.readElement(currentTag); + final Element streamError = tagReader.readElement(currentTag); if (streamError != null && streamError.hasChild("conflict")) { final String resource = account.getResource().split("\\.")[0]; account.setResource(resource + "." + nextRandomId()); Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": switching resource due to conflict (" - + account.getResource() + ")"); + + account.getResource() + ")"); } } private void sendStartStream() throws IOException { - Tag stream = Tag.start("stream:stream"); + final Tag stream = Tag.start("stream:stream"); stream.setAttribute("from", account.getJid().toBareJid().toString()); stream.setAttribute("to", account.getServer().toString()); stream.setAttribute("version", "1.0"); @@ -856,33 +856,32 @@ public class XmppConnection implements Runnable { return new BigInteger(50, mXmppConnectionService.getRNG()).toString(32); } - public void sendIqPacket(IqPacket packet, OnIqPacketReceived callback) { + public void sendIqPacket(final IqPacket packet, final PacketReceived callback) { if (packet.getId() == null) { - String id = nextRandomId(); + final String id = nextRandomId(); packet.setAttribute("id", id); } packet.setFrom(account.getJid()); this.sendPacket(packet, callback); } - public void sendUnboundIqPacket(IqPacket packet, OnIqPacketReceived callback) { + public void sendUnboundIqPacket(final IqPacket packet, final PacketReceived callback) { if (packet.getId() == null) { - String id = nextRandomId(); + final String id = nextRandomId(); packet.setAttribute("id", id); } this.sendPacket(packet, callback); } - public void sendMessagePacket(MessagePacket packet) { + public void sendMessagePacket(final MessagePacket packet) { this.sendPacket(packet, null); } - public void sendPresencePacket(PresencePacket packet) { + public void sendPresencePacket(final PresencePacket packet) { this.sendPacket(packet, null); } - private synchronized void sendPacket(final AbstractStanza packet, - PacketReceived callback) { + private synchronized void sendPacket(final AbstractStanza packet, final PacketReceived callback) { if (packet.getName().equals("iq") || packet.getName().equals("message") || packet.getName().equals("presence")) { ++stanzasSent; @@ -907,7 +906,7 @@ public class XmppConnection implements Runnable { if (streamFeatures.hasChild("sm")) { tagWriter.writeStanzaAsync(new RequestPacket(smVersion)); } else { - IqPacket iq = new IqPacket(IqPacket.TYPE_GET); + final IqPacket iq = new IqPacket(IqPacket.TYPE_GET); iq.setFrom(account.getJid()); iq.addChild("ping", "urn:xmpp:ping"); this.sendIqPacket(iq, null); @@ -916,44 +915,44 @@ public class XmppConnection implements Runnable { } public void setOnMessagePacketReceivedListener( - OnMessagePacketReceived listener) { + final OnMessagePacketReceived listener) { this.messageListener = listener; } public void setOnUnregisteredIqPacketReceivedListener( - OnIqPacketReceived listener) { + final OnIqPacketReceived listener) { this.unregisteredIqListener = listener; } public void setOnPresencePacketReceivedListener( - OnPresencePacketReceived listener) { + final OnPresencePacketReceived listener) { this.presenceListener = listener; } public void setOnJinglePacketReceivedListener( - OnJinglePacketReceived listener) { + final OnJinglePacketReceived listener) { this.jingleListener = listener; } - public void setOnStatusChangedListener(OnStatusChanged listener) { + public void setOnStatusChangedListener(final OnStatusChanged listener) { this.statusListener = listener; } - public void setOnBindListener(OnBindListener listener) { + public void setOnBindListener(final OnBindListener listener) { this.bindListener = listener; } - public void setOnMessageAcknowledgeListener(OnMessageAcknowledged listener) { + public void setOnMessageAcknowledgeListener(final OnMessageAcknowledged listener) { this.acknowledgedListener = listener; } - public void addOnAdvancedStreamFeaturesAvailableListener(OnAdvancedStreamFeaturesLoaded listener) { + public void addOnAdvancedStreamFeaturesAvailableListener(final OnAdvancedStreamFeaturesLoaded listener) { if (!this.advancedStreamFeaturesLoadedListeners.contains(listener)) { this.advancedStreamFeaturesLoadedListeners.add(listener); } } - public void disconnect(boolean force) { + public void disconnect(final boolean force) { Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting"); try { if (force) { @@ -973,23 +972,23 @@ public class XmppConnection implements Runnable { } tagWriter.writeTag(Tag.end("stream:stream")); socket.close(); - } catch (IOException e) { + } catch (final IOException e) { Log.d(Config.LOGTAG, "io exception during disconnect"); - } catch (InterruptedException e) { + } catch (final InterruptedException e) { Log.d(Config.LOGTAG, "interrupted"); } } } }).start(); - } catch (IOException e) { + } catch (final IOException e) { Log.d(Config.LOGTAG, "io exception during disconnect"); } } - public List findDiscoItemsByFeature(String feature) { + public List findDiscoItemsByFeature(final String feature) { final List items = new ArrayList<>(); - for (Entry> cursor : disco.entrySet()) { + for (final Entry> cursor : disco.entrySet()) { if (cursor.getValue().contains(feature)) { items.add(cursor.getKey()); } @@ -997,8 +996,8 @@ public class XmppConnection implements Runnable { return items; } - public String findDiscoItemByFeature(String feature) { - List items = findDiscoItemsByFeature(feature); + public String findDiscoItemByFeature(final String feature) { + final List items = findDiscoItemsByFeature(feature); if (items.size() >= 1) { return items.get(0); } @@ -1010,8 +1009,7 @@ public class XmppConnection implements Runnable { } public String getMucServer() { - final List items = new ArrayList<>(); - for (Entry> cursor : disco.entrySet()) { + for (final Entry> cursor : disco.entrySet()) { final List value = cursor.getValue(); if (value.contains("http://jabber.org/protocol/muc") && !value.contains("jabber:iq:gateway") && !value.contains("siacs:no:muc")) { return cursor.getKey(); @@ -1021,8 +1019,8 @@ public class XmppConnection implements Runnable { } public int getTimeToNextAttempt() { - int interval = (int) (25 * Math.pow(1.5, attempt)); - int secondsSinceLast = (int) ((SystemClock.elapsedRealtime() - this.lastConnect) / 1000); + final int interval = (int) (25 * Math.pow(1.5, attempt)); + final int secondsSinceLast = (int) ((SystemClock.elapsedRealtime() - this.lastConnect) / 1000); return interval - secondsSinceLast; } @@ -1035,7 +1033,7 @@ public class XmppConnection implements Runnable { } public long getLastSessionEstablished() { - long diff; + final long diff; if (this.lastSessionStarted == 0) { diff = SystemClock.elapsedRealtime() - this.lastConnect; } else { @@ -1067,7 +1065,7 @@ public class XmppConnection implements Runnable { public class Features { XmppConnection connection; - public Features(XmppConnection connection) { + public Features(final XmppConnection connection) { this.connection = connection; } @@ -1080,6 +1078,10 @@ public class XmppConnection implements Runnable { return hasDiscoFeature(account.getServer(), "urn:xmpp:carbons:2"); } + public boolean blocking() { + return hasDiscoFeature(account.getServer(), Xmlns.BLOCKING); + } + public boolean sm() { return streamId != null; } @@ -1110,4 +1112,8 @@ public class XmppConnection implements Runnable { .findDiscoItemByFeature("http://jabber.org/protocol/bytestreams") != null; } } + + private IqGenerator getIqGenerator() { + return mXmppConnectionService.getIqGenerator(); + } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java b/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java index c40fa0b6..a35ea37c 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java @@ -32,7 +32,7 @@ public final class Jid { return resourcepart; } - public static Jid fromSessionID(SessionID id) throws InvalidJidException{ + public static Jid fromSessionID(final SessionID id) throws InvalidJidException{ if (id.getUserID().isEmpty()) { return Jid.fromString(id.getAccountID()); } else { @@ -190,4 +190,8 @@ public final class Jid { public boolean isBareJid() { return this.resourcepart.isEmpty(); } + + public boolean isDomainJid() { + return !this.hasLocalpart(); + } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/stanzas/IqPacket.java b/src/main/java/eu/siacs/conversations/xmpp/stanzas/IqPacket.java index 9df05e67..9eff4cbf 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/stanzas/IqPacket.java +++ b/src/main/java/eu/siacs/conversations/xmpp/stanzas/IqPacket.java @@ -9,27 +9,27 @@ public class IqPacket extends AbstractStanza { public static final int TYPE_RESULT = 1; public static final int TYPE_GET = 2; - private IqPacket(String name) { + private IqPacket(final String name) { super(name); } - public IqPacket(int type) { + public IqPacket(final int type) { super("iq"); switch (type) { - case TYPE_SET: - this.setAttribute("type", "set"); - break; - case TYPE_GET: - this.setAttribute("type", "get"); - break; - case TYPE_RESULT: - this.setAttribute("type", "result"); - break; - case TYPE_ERROR: - this.setAttribute("type", "error"); - break; - default: - break; + case TYPE_SET: + this.setAttribute("type", "set"); + break; + case TYPE_GET: + this.setAttribute("type", "get"); + break; + case TYPE_RESULT: + this.setAttribute("type", "result"); + break; + case TYPE_ERROR: + this.setAttribute("type", "error"); + break; + default: + break; } } @@ -45,29 +45,30 @@ public class IqPacket extends AbstractStanza { return query; } - public Element query(String xmlns) { - Element query = query(); + public Element query(final String xmlns) { + final Element query = query(); query.setAttribute("xmlns", xmlns); return query(); } public int getType() { - String type = getAttribute("type"); - if ("error".equals(type)) { - return TYPE_ERROR; - } else if ("result".equals(type)) { - return TYPE_RESULT; - } else if ("set".equals(type)) { - return TYPE_SET; - } else if ("get".equals(type)) { - return TYPE_GET; - } else { - return 1000; + final String type = getAttribute("type"); + switch (type) { + case "error": + return TYPE_ERROR; + case "result": + return TYPE_RESULT; + case "set": + return TYPE_SET; + case "get": + return TYPE_GET; + default: + return 1000; } } - public IqPacket generateRespone(int type) { - IqPacket packet = new IqPacket(type); + public IqPacket generateRespone(final int type) { + final IqPacket packet = new IqPacket(type); packet.setTo(this.getFrom()); packet.setId(this.getId()); return packet; diff --git a/src/main/res/menu/contact_context.xml b/src/main/res/menu/contact_context.xml index 11ac7d7c..223c7ece 100644 --- a/src/main/res/menu/contact_context.xml +++ b/src/main/res/menu/contact_context.xml @@ -7,6 +7,9 @@ + diff --git a/src/main/res/menu/conversations.xml b/src/main/res/menu/conversations.xml index d68c1436..6c22ed18 100644 --- a/src/main/res/menu/conversations.xml +++ b/src/main/res/menu/conversations.xml @@ -56,6 +56,18 @@ android:showAsAction="never" android:title="@string/enable_notifications"/> + + + + + \ No newline at end of file diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index ec761d6e..ba3051b2 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -13,6 +13,10 @@ Edit name Add to phone book Delete from roster + Block contact + Unblock contact + Block domain + Unblock domain Manage Accounts Settings Conference Details @@ -21,6 +25,7 @@ Share with Conversation Start Conversation Choose contact + Block list just now 1 min ago %d mins ago @@ -34,6 +39,11 @@ Participant Visitor Would you like to remove %s from your roster? The conversation associated with this contact will not be removed. + Would you like to block %s from sending you messages? + Would you like to unblock %s and allow them to send you messages? + Block all contacts from %s? + Unblock all contacts from %s? + Contact blocked Would you like to remove %s as a bookmark? The conversation associated with this bookmark will not be removed. Register new account on server Share with @@ -45,6 +55,8 @@ Add Edit Delete + Block + Unblock Save OK Conversations has crashed @@ -202,6 +214,8 @@ Join Conference Delete Contact View contact details + Block contact + Unblock contact Create The contact already exists Join @@ -318,6 +332,7 @@ Image transmission failed Scan QR code Show QR code + Show block list Account details Verify OTR Remote Fingerprint -- cgit v1.2.3 From e1cb72b9ef4d4bfb9d11fff68e296462405d6992 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Mon, 22 Dec 2014 10:50:29 -0500 Subject: Fix NPEs in blocking code --- src/main/java/eu/siacs/conversations/ui/ConversationActivity.java | 4 +++- src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 3a3f0778..c41a18c6 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.List; import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Blockable; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; @@ -316,7 +317,8 @@ public class ConversationActivity extends XmppActivity } else { menuUnblock.setVisible(false); } - if (!this.getSelectedConversation().getAccount().getXmppConnection().getFeatures().blocking()) { + final Account account = this.getSelectedConversation().getAccount(); + if (account.getStatus() != Account.State.ONLINE || !account.getXmppConnection().getFeatures().blocking()) { menuBlock.setVisible(false); menuUnblock.setVisible(false); } diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 47fe5964..0dd7a2eb 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -327,7 +327,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate if (mAccount == null) { showQrCode.setVisible(false); showBlocklist.setVisible(false); - } else if (!mAccount.getXmppConnection().getFeatures().blocking()) { + } else if (mAccount.getStatus() != Account.State.ONLINE || !mAccount.getXmppConnection().getFeatures().blocking()) { showBlocklist.setVisible(false); } return true; -- cgit v1.2.3 From e152ed1e0735b9502f724d6a6a1e477022c3a40d Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Sat, 20 Dec 2014 20:13:13 -0500 Subject: Simplify roster handling code Merge result handling code into IqParser Fixes #20 --- .../eu/siacs/conversations/parser/IqParser.java | 153 ++++++++++----------- .../services/XmppConnectionService.java | 64 ++++----- .../java/eu/siacs/conversations/utils/Xmlns.java | 1 + 3 files changed, 97 insertions(+), 121 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java index b77d460d..eea8e84c 100644 --- a/src/main/java/eu/siacs/conversations/parser/IqParser.java +++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java @@ -71,103 +71,88 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { return super.avatarData(items); } + public static boolean fromServer(final Account account, final IqPacket packet) { + return packet.getFrom() == null || packet.getFrom().equals(account.getServer()) || packet.getFrom().equals(account.getJid().toBareJid()); + } + @Override public void onIqPacketReceived(final Account account, final IqPacket packet) { - if (packet.hasChild("query", "jabber:iq:roster")) { - final Jid from = packet.getFrom(); - if ((from == null) || (from.equals(account.getJid().toBareJid()))) { - final Element query = packet.findChild("query"); - this.rosterItems(account, query); + if (packet.hasChild("query", Xmlns.ROSTER) && fromServer(account, packet)) { + final Element query = packet.findChild("query"); + // If this is in response to a query for the whole roster: + if (packet.getType() == IqPacket.TYPE_RESULT) { + account.getRoster().markAllAsNotInRoster(); } - } else if (packet.hasChild("block", Xmlns.BLOCKING) || packet.hasChild("blocklist", Xmlns.BLOCKING)) { - // Only accept block list changes from the server. - // The server should probably prevent other people from faking a blocklist push, - // but just in case let's prevent it client side as well. - final Jid from = packet.getFrom(); - if (from == null || from.equals(account.getServer()) || from.equals(account.getJid().toBareJid())) { - Log.d(Config.LOGTAG, "Received blocklist update from server"); - final Element blocklist = packet.findChild("blocklist", Xmlns.BLOCKING); - final Element block = packet.findChild("block", Xmlns.BLOCKING); - final Collection items = blocklist != null ? blocklist.getChildren() : - (block != null ? block.getChildren() : null); - // If this is a response to a blocklist query, clear the block list and replace with the new one. - // Otherwise, just update the existing blocklist. - if (packet.getType() == IqPacket.TYPE_RESULT) { - account.clearBlocklist(); - } - if (items != null) { - final Collection jids = new ArrayList<>(items.size()); - // Create a collection of Jids from the packet - for (final Element item : items) { - if (item.getName().equals("item")) { - final Jid jid = item.getAttributeAsJid("jid"); - if (jid != null) { - jids.add(jid); - } + this.rosterItems(account, query); + } else if ((packet.hasChild("block", Xmlns.BLOCKING) || packet.hasChild("blocklist", Xmlns.BLOCKING)) && + fromServer(account, packet)) { + // Block list or block push. + Log.d(Config.LOGTAG, "Received blocklist update from server"); + final Element blocklist = packet.findChild("blocklist", Xmlns.BLOCKING); + final Element block = packet.findChild("block", Xmlns.BLOCKING); + final Collection items = blocklist != null ? blocklist.getChildren() : + (block != null ? block.getChildren() : null); + // If this is a response to a blocklist query, clear the block list and replace with the new one. + // Otherwise, just update the existing blocklist. + if (packet.getType() == IqPacket.TYPE_RESULT) { + account.clearBlocklist(); + } + if (items != null) { + final Collection jids = new ArrayList<>(items.size()); + // Create a collection of Jids from the packet + for (final Element item : items) { + if (item.getName().equals("item")) { + final Jid jid = item.getAttributeAsJid("jid"); + if (jid != null) { + jids.add(jid); } } - account.getBlocklist().addAll(jids); } - // Update the UI - mXmppConnectionService.updateBlocklistUi(OnUpdateBlocklist.Status.BLOCKED); - } else { - Log.d(Config.LOGTAG, "Received blocklist update from invalid jid: " + from.toString()); + account.getBlocklist().addAll(jids); } - } else if (packet.hasChild("unblock", Xmlns.BLOCKING)) { - final Jid from = packet.getFrom(); - if ((from == null || from.equals(account.getServer()) || from.equals(account.getJid().toBareJid())) && - packet.getType() == IqPacket.TYPE_SET) { - Log.d(Config.LOGTAG, "Received unblock update from server"); - final Collection items = packet.getChildren().get(0).getChildren(); - if (items.size() == 0) { - // No children to unblock == unblock all - account.getBlocklist().clear(); - } else { - final Collection jids = new ArrayList<>(items.size()); - for (final Element item : items) { - if (item.getName().equals("item")) { - final Jid jid = item.getAttributeAsJid("jid"); - if (jid != null) { - jids.add(jid); - } + // Update the UI + mXmppConnectionService.updateBlocklistUi(OnUpdateBlocklist.Status.BLOCKED); + } else if (packet.hasChild("unblock", Xmlns.BLOCKING) && + fromServer(account, packet) && packet.getType() == IqPacket.TYPE_SET) { + Log.d(Config.LOGTAG, "Received unblock update from server"); + final Collection items = packet.findChild("unblock", Xmlns.BLOCKING).getChildren(); + if (items.size() == 0) { + // No children to unblock == unblock all + account.getBlocklist().clear(); + } else { + final Collection jids = new ArrayList<>(items.size()); + for (final Element item : items) { + if (item.getName().equals("item")) { + final Jid jid = item.getAttributeAsJid("jid"); + if (jid != null) { + jids.add(jid); } } - account.getBlocklist().removeAll(jids); - mXmppConnectionService.updateBlocklistUi(OnUpdateBlocklist.Status.UNBLOCKED); - } - } else { - if (packet.getType() == IqPacket.TYPE_SET) { - Log.d(Config.LOGTAG, "Received unblock update from invalid jid " + from.toString()); - } else { - Log.d(Config.LOGTAG, "Received unblock update with invalid type " + packet.getType()); } + account.getBlocklist().removeAll(jids); } + mXmppConnectionService.updateBlocklistUi(OnUpdateBlocklist.Status.UNBLOCKED); + } else if (packet.hasChild("open", "http://jabber.org/protocol/ibb") + || packet.hasChild("data", "http://jabber.org/protocol/ibb")) { + mXmppConnectionService.getJingleConnectionManager() + .deliverIbbPacket(account, packet); + } else if (packet.hasChild("query", "http://jabber.org/protocol/disco#info")) { + final IqPacket response = mXmppConnectionService.getIqGenerator() + .discoResponse(packet); + account.getXmppConnection().sendIqPacket(response, null); + } else if (packet.hasChild("ping", "urn:xmpp:ping")) { + final IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT); + mXmppConnectionService.sendIqPacket(account, response, null); } else { - if (packet.getFrom() == null) { - Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": received iq with invalid from "+packet.toString()); - return; - } else if (packet.hasChild("open", "http://jabber.org/protocol/ibb") - || packet.hasChild("data", "http://jabber.org/protocol/ibb")) { - mXmppConnectionService.getJingleConnectionManager() - .deliverIbbPacket(account, packet); - } else if (packet.hasChild("query", "http://jabber.org/protocol/disco#info")) { - final IqPacket response = mXmppConnectionService.getIqGenerator() - .discoResponse(packet); + if ((packet.getType() == IqPacket.TYPE_GET) + || (packet.getType() == IqPacket.TYPE_SET)) { + final IqPacket response = packet.generateRespone(IqPacket.TYPE_ERROR); + final Element error = response.addChild("error"); + error.setAttribute("type", "cancel"); + error.addChild("feature-not-implemented", + "urn:ietf:params:xml:ns:xmpp-stanzas"); account.getXmppConnection().sendIqPacket(response, null); - } else if (packet.hasChild("ping", "urn:xmpp:ping")) { - final IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT); - mXmppConnectionService.sendIqPacket(account, response, null); - } else { - if ((packet.getType() == IqPacket.TYPE_GET) - || (packet.getType() == IqPacket.TYPE_SET)) { - final IqPacket response = packet.generateRespone(IqPacket.TYPE_ERROR); - final Element error = response.addChild("error"); - error.setAttribute("type", "cancel"); - error.addChild("feature-not-implemented", - "urn:ietf:params:xml:ns:xmpp-stanzas"); - account.getXmppConnection().sendIqPacket(response, null); - } - } + } } } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 65c631a1..6b0b960a 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -74,6 +74,7 @@ import eu.siacs.conversations.utils.ExceptionHelper; import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener; import eu.siacs.conversations.utils.PRNGFixes; import eu.siacs.conversations.utils.PhoneHelper; +import eu.siacs.conversations.utils.Xmlns; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnBindListener; import eu.siacs.conversations.xmpp.OnContactStatusChanged; @@ -483,11 +484,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa this.mMemorizingTrustManager = new MemorizingTrustManager( getApplicationContext()); - int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); - int cacheSize = maxMemory / 8; + final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); + final int cacheSize = maxMemory / 8; this.mBitmapCache = new LruCache(cacheSize) { @Override - protected int sizeOf(String key, Bitmap bitmap) { + protected int sizeOf(final String key, final Bitmap bitmap) { return bitmap.getByteCount() / 1024; } }; @@ -495,7 +496,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa this.databaseBackend = DatabaseBackend.getInstance(getApplicationContext()); this.accounts = databaseBackend.getAccounts(); - for (Account account : this.accounts) { + for (final Account account : this.accounts) { account.initOtrEngine(this); this.databaseBackend.readRoster(account.getRoster()); } @@ -521,7 +522,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } @Override - public void onTaskRemoved(Intent rootIntent) { + public void onTaskRemoved(final Intent rootIntent) { super.onTaskRemoved(rootIntent); if (!getPreferences().getBoolean("keep_foreground_service",false)) { this.logoutAndSave(); @@ -529,7 +530,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } private void logoutAndSave() { - for (Account account : accounts) { + for (final Account account : accounts) { databaseBackend.writeRoster(account.getRoster()); if (account.getXmppConnection() != null) { disconnect(account, false); @@ -791,21 +792,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } else { Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": fetching roster"); } - iqPacket.query("jabber:iq:roster").setAttribute("ver", + iqPacket.query(Xmlns.ROSTER).setAttribute("ver", account.getRosterVersion()); - account.getXmppConnection().sendIqPacket(iqPacket, - new OnIqPacketReceived() { - - @Override - public void onIqPacketReceived(final Account account, - final IqPacket packet) { - final Element query = packet.findChild("query"); - if (query != null) { - account.getRoster().markAllAsNotInRoster(); - mIqParser.rosterItems(account, query); - } - } - }); + account.getXmppConnection().sendIqPacket(iqPacket, mIqParser); } public void fetchBookmarks(final Account account) { @@ -1433,7 +1422,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } public void createAdhocConference(final Account account, final Iterable jids, final UiCallback callback) { - Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": creating adhoc conference with "+ jids.toString()); + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": creating adhoc conference with " + jids.toString()); if (account.getStatus() == Account.State.ONLINE) { try { String server = findConferenceServer(account); @@ -1637,17 +1626,17 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return false; } - public void pushContactToServer(Contact contact) { + public void pushContactToServer(final Contact contact) { contact.resetOption(Contact.Options.DIRTY_DELETE); contact.setOption(Contact.Options.DIRTY_PUSH); - Account account = contact.getAccount(); + final Account account = contact.getAccount(); if (account.getStatus() == Account.State.ONLINE) { - boolean ask = contact.getOption(Contact.Options.ASKING); - boolean sendUpdates = contact + final boolean ask = contact.getOption(Contact.Options.ASKING); + final boolean sendUpdates = contact .getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST) && contact.getOption(Contact.Options.PREEMPTIVE_GRANT); - IqPacket iq = new IqPacket(IqPacket.TYPE_SET); - iq.query("jabber:iq:roster").addChild(contact.asElement()); + final IqPacket iq = new IqPacket(IqPacket.TYPE_SET); + iq.query(Xmlns.ROSTER).addChild(contact.asElement()); account.getXmppConnection().sendIqPacket(iq, null); if (sendUpdates) { sendPresencePacket(account, @@ -1660,7 +1649,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } - public void publishAvatar(Account account, Uri image, + public void publishAvatar(final Account account, + final Uri image, final UiCallback callback) { final Bitmap.CompressFormat format = Config.AVATAR_FORMAT; final int size = Config.AVATAR_SIZE; @@ -1680,13 +1670,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa callback.error(R.string.error_saving_avatar, avatar); return; } - IqPacket packet = this.mIqGenerator.publishAvatar(avatar); + final IqPacket packet = this.mIqGenerator.publishAvatar(avatar); this.sendIqPacket(account, packet, new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket result) { if (result.getType() == IqPacket.TYPE_RESULT) { - IqPacket packet = XmppConnectionService.this.mIqGenerator + final IqPacket packet = XmppConnectionService.this.mIqGenerator .publishAvatarMetadata(avatar); sendIqPacket(account, packet, new OnIqPacketReceived() { @@ -1819,7 +1809,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa Account account = contact.getAccount(); if (account.getStatus() == Account.State.ONLINE) { IqPacket iq = new IqPacket(IqPacket.TYPE_SET); - Element item = iq.query("jabber:iq:roster").addChild("item"); + Element item = iq.query(Xmlns.ROSTER).addChild("item"); item.setAttribute("jid", contact.getJid().toString()); item.setAttribute("subscription", "remove"); account.getXmppConnection().sendIqPacket(iq, null); @@ -2027,12 +2017,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } public List getKnownHosts() { - List hosts = new ArrayList<>(); - for (Account account : getAccounts()) { + final List hosts = new ArrayList<>(); + for (final Account account : getAccounts()) { if (!hosts.contains(account.getServer().toString())) { hosts.add(account.getServer().toString()); } - for (Contact contact : account.getRoster().getContacts()) { + for (final Contact contact : account.getRoster().getContacts()) { if (contact.showInRoster()) { final String server = contact.getServer().toString(); if (server != null && !hosts.contains(server)) { @@ -2045,10 +2035,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } public List getKnownConferenceHosts() { - ArrayList mucServers = new ArrayList<>(); - for (Account account : accounts) { + final ArrayList mucServers = new ArrayList<>(); + for (final Account account : accounts) { if (account.getXmppConnection() != null) { - String server = account.getXmppConnection().getMucServer(); + final String server = account.getXmppConnection().getMucServer(); if (server != null && !mucServers.contains(server)) { mucServers.add(server); } diff --git a/src/main/java/eu/siacs/conversations/utils/Xmlns.java b/src/main/java/eu/siacs/conversations/utils/Xmlns.java index 932e48ae..acea2e56 100644 --- a/src/main/java/eu/siacs/conversations/utils/Xmlns.java +++ b/src/main/java/eu/siacs/conversations/utils/Xmlns.java @@ -2,4 +2,5 @@ package eu.siacs.conversations.utils; public final class Xmlns { public static final String BLOCKING = "urn:xmpp:blocking"; + public static final String ROSTER = "jabber:iq:roster"; } -- cgit v1.2.3 From d5f99560ff13a3da42b0173fd73add653e08824b Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Tue, 23 Dec 2014 18:09:29 +0100 Subject: made method private that is no longer required to be public --- src/main/java/eu/siacs/conversations/parser/IqParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java index eea8e84c..5ed3b5b4 100644 --- a/src/main/java/eu/siacs/conversations/parser/IqParser.java +++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java @@ -22,7 +22,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { super(service); } - public void rosterItems(final Account account, final Element query) { + private void rosterItems(final Account account, final Element query) { final String version = query.getAttribute("ver"); if (version != null) { account.getRoster().setVersion(version); -- cgit v1.2.3 From 01107e31ae22d84922742717ad5b7d87581e4096 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Tue, 21 Oct 2014 16:22:01 -0400 Subject: Add more server compatibility info. Hide server info behind a checkbox. Add XEP-0352 support to the server info list Add XEP-0237 to server info list Add XEP-0352 support to the server info list Add MaM and Blocking to the account XEPs list Also add a toggle button to hide some of the list Rebase on current codebase Make MAM string more descriptive Change show more button to checkbox menu item Shorten `MAM (History)' to `MAM' Order XEP list and hide all by default Supress warning (which is wrong anyways) Change `Show more' to `Show more info' --- .../conversations/ui/EditAccountActivity.java | 38 +++++++- src/main/res/layout/activity_edit_account.xml | 106 ++++++++++++++++++++- src/main/res/menu/editaccount.xml | 7 ++ src/main/res/values/strings.xml | 5 + 4 files changed, 150 insertions(+), 6 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 0dd7a2eb..97efa41f 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -19,6 +19,7 @@ import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; +import android.widget.TableLayout; import android.widget.TextView; import android.widget.Toast; @@ -42,10 +43,15 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate private CheckBox mRegisterNew; private Button mCancelButton; private Button mSaveButton; + private TableLayout mMoreTable; private LinearLayout mStats; private TextView mServerInfoSm; + private TextView mServerInfoRosterVersion; private TextView mServerInfoCarbons; + private TextView mServerInfoMam; + private TextView mServerInfoCSI; + private TextView mServerInfoBlocking; private TextView mServerInfoPep; private TextView mSessionEst; private TextView mOtrFingerprint; @@ -292,7 +298,11 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mRegisterNew = (CheckBox) findViewById(R.id.account_register_new); this.mStats = (LinearLayout) findViewById(R.id.stats); this.mSessionEst = (TextView) findViewById(R.id.session_est); + this.mServerInfoRosterVersion = (TextView) findViewById(R.id.server_info_roster_version); this.mServerInfoCarbons = (TextView) findViewById(R.id.server_info_carbons); + this.mServerInfoMam = (TextView) findViewById(R.id.server_info_mam); + this.mServerInfoCSI = (TextView) findViewById(R.id.server_info_csi); + this.mServerInfoBlocking = (TextView) findViewById(R.id.server_info_blocking); this.mServerInfoSm = (TextView) findViewById(R.id.server_info_sm); this.mServerInfoPep = (TextView) findViewById(R.id.server_info_pep); this.mOtrFingerprint = (TextView) findViewById(R.id.otr_fingerprint); @@ -302,6 +312,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mCancelButton = (Button) findViewById(R.id.cancel_button); this.mSaveButton.setOnClickListener(this.mSaveButtonClickListener); this.mCancelButton.setOnClickListener(this.mCancelButtonClickListener); + this.mMoreTable = (TableLayout) findViewById(R.id.server_info_more); this.mRegisterNew .setOnCheckedChangeListener(new OnCheckedChangeListener() { @@ -384,6 +395,9 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate intent.putExtra("account", mAccount.getJid().toString()); startActivity(intent); break; + case R.id.action_server_info_show_more: + mMoreTable.setVisibility(item.isChecked() ? View.GONE : View.VISIBLE); + item.setChecked(!item.isChecked()); } return super.onOptionsItemSelected(item); } @@ -406,16 +420,36 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate if (this.mAccount.getStatus() == Account.State.ONLINE && !this.mFetchingAvatar) { this.mStats.setVisibility(View.VISIBLE); - this.mSessionEst.setText(UIHelper.readableTimeDifferenceFull( + this.mSessionEst.setText(UIHelper.readableTimeDifference( getApplicationContext(), this.mAccount.getXmppConnection() .getLastSessionEstablished())); - final Features features = this.mAccount.getXmppConnection().getFeatures(); + Features features = this.mAccount.getXmppConnection().getFeatures(); + if (features.rosterVersioning()) { + this.mServerInfoRosterVersion.setText(R.string.server_info_available); + } else { + this.mServerInfoRosterVersion.setText(R.string.server_info_unavailable); + } if (features.carbons()) { this.mServerInfoCarbons.setText(R.string.server_info_available); } else { this.mServerInfoCarbons .setText(R.string.server_info_unavailable); } + if (features.mam()) { + this.mServerInfoMam.setText(R.string.server_info_available); + } else { + this.mServerInfoMam.setText(R.string.server_info_unavailable); + } + if (features.csi()) { + this.mServerInfoCSI.setText(R.string.server_info_available); + } else { + this.mServerInfoCSI.setText(R.string.server_info_unavailable); + } + if (features.blocking()) { + this.mServerInfoBlocking.setText(R.string.server_info_available); + } else { + this.mServerInfoBlocking.setText(R.string.server_info_unavailable); + } if (features.sm()) { this.mServerInfoSm.setText(R.string.server_info_available); } else { diff --git a/src/main/res/layout/activity_edit_account.xml b/src/main/res/layout/activity_edit_account.xml index ed83cb9a..a12766f9 100644 --- a/src/main/res/layout/activity_edit_account.xml +++ b/src/main/res/layout/activity_edit_account.xml @@ -1,5 +1,6 @@ @@ -118,7 +119,8 @@ + android:layout_height="wrap_content" + tools:ignore="UselessParent"> + android:textSize="?attr/TextSizeBody" + tools:ignore="RtlHardcoded"/> + + + @@ -153,7 +164,29 @@ android:layout_height="wrap_content" android:layout_gravity="right" android:textColor="@color/primarytext" + android:textSize="?attr/TextSizeBody" + tools:ignore="RtlHardcoded"/> + + + + + + + + + + + + + + + + + + + + + - + + + + + + @@ -281,4 +379,4 @@ android:textColor="@color/secondarytext" /> - \ No newline at end of file + diff --git a/src/main/res/menu/editaccount.xml b/src/main/res/menu/editaccount.xml index 5d10901e..fc362836 100644 --- a/src/main/res/menu/editaccount.xml +++ b/src/main/res/menu/editaccount.xml @@ -4,9 +4,16 @@ android:id="@+id/action_show_qr_code" android:title="@string/show_qr_code" android:showAsAction="never" /> + + \ No newline at end of file diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index ba3051b2..29b81354 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -186,7 +186,12 @@ offline Conference Other Members + Server info + XEP-0313: MAM XEP-0280: Message Carbons + XEP-0352: Client State Indication + XEP-0191: Blocking Command + XEP-0237: Roster Versioning XEP-0198: Stream Management XEP-0163: PEP (Avatars) available -- cgit v1.2.3 From d45478801139d8fa6222d8b73ec96b81be2127bd Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Tue, 23 Dec 2014 13:23:13 -0500 Subject: Remove old JID validator --- .../conversations/ui/EditAccountActivity.java | 14 +- .../ui/StartConversationActivity.java | 154 ++++++++++----------- .../eu/siacs/conversations/utils/Validator.java | 14 -- 3 files changed, 77 insertions(+), 105 deletions(-) delete mode 100644 src/main/java/eu/siacs/conversations/utils/Validator.java diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 97efa41f..07e06b75 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -29,7 +29,6 @@ import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; import eu.siacs.conversations.ui.adapter.KnownHostsAdapter; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.UIHelper; -import eu.siacs.conversations.utils.Validator; import eu.siacs.conversations.xmpp.XmppConnection.Features; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; @@ -67,19 +66,14 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate private OnClickListener mSaveButtonClickListener = new OnClickListener() { @Override - public void onClick(View v) { + public void onClick(final View v) { if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED) { mAccount.setOption(Account.OPTION_DISABLED, false); xmppConnectionService.updateAccount(mAccount); return; } - if (!Validator.isValidJid(mAccountJid.getText().toString())) { - mAccountJid.setError(getString(R.string.invalid_jid)); - mAccountJid.requestFocus(); - return; - } - boolean registerNewAccount = mRegisterNew.isChecked(); + final boolean registerNewAccount = mRegisterNew.isChecked(); final Jid jid; try { jid = Jid.fromString(mAccountJid.getText().toString()); @@ -88,8 +82,8 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate mAccountJid.requestFocus(); return; } - String password = mPassword.getText().toString(); - String passwordConfirm = mPasswordConfirm.getText().toString(); + final String password = mPassword.getText().toString(); + final String passwordConfirm = mPasswordConfirm.getText().toString(); if (registerNewAccount) { if (!password.equals(passwordConfirm)) { mPasswordConfirm diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index 630dc6ef..cab6e90e 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -38,6 +38,7 @@ import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.CheckBox; +import android.widget.Checkable; import android.widget.EditText; import android.widget.ListView; import android.widget.Spinner; @@ -61,7 +62,6 @@ import eu.siacs.conversations.entities.ListItem; import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; import eu.siacs.conversations.ui.adapter.KnownHostsAdapter; import eu.siacs.conversations.ui.adapter.ListItemAdapter; -import eu.siacs.conversations.utils.Validator; import eu.siacs.conversations.utils.XmppUri; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.jid.InvalidJidException; @@ -349,41 +349,37 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU new View.OnClickListener() { @Override - public void onClick(View v) { + public void onClick(final View v) { if (!xmppConnectionServiceBound) { return; } - if (Validator.isValidJid(jid.getText().toString())) { - final Jid accountJid; - try { - accountJid = Jid.fromString((String) spinner.getSelectedItem()); - } catch (final InvalidJidException e) { - return; - } - final Jid contactJid; - try { - contactJid = Jid.fromString(jid.getText().toString()); - } catch (final InvalidJidException e) { - jid.setError(getString(R.string.invalid_jid)); - return; - } - Account account = xmppConnectionService - .findAccountByJid(accountJid); - if (account == null) { - dialog.dismiss(); - return; - } - Contact contact = account.getRoster().getContact(contactJid); - if (contact.showInRoster()) { - jid.setError(getString(R.string.contact_already_exists)); - } else { - contact.addOtrFingerprint(fingerprint); - xmppConnectionService.createContact(contact); - dialog.dismiss(); - switchToConversation(contact); - } - } else { + final Jid accountJid; + try { + accountJid = Jid.fromString((String) spinner.getSelectedItem()); + } catch (final InvalidJidException e) { + return; + } + final Jid contactJid; + try { + contactJid = Jid.fromString(jid.getText().toString()); + } catch (final InvalidJidException e) { jid.setError(getString(R.string.invalid_jid)); + return; + } + final Account account = xmppConnectionService + .findAccountByJid(accountJid); + if (account == null) { + dialog.dismiss(); + return; + } + final Contact contact = account.getRoster().getContact(contactJid); + if (contact.showInRoster()) { + jid.setError(getString(R.string.contact_already_exists)); + } else { + contact.addOtrFingerprint(fingerprint); + xmppConnectionService.createContact(contact); + dialog.dismiss(); + switchToConversation(contact); } } }); @@ -391,10 +387,10 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU } @SuppressLint("InflateParams") - protected void showJoinConferenceDialog(String prefilledJid) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); + protected void showJoinConferenceDialog(final String prefilledJid) { + final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.join_conference); - View dialogView = getLayoutInflater().inflate(R.layout.join_conference_dialog, null); + final View dialogView = getLayoutInflater().inflate(R.layout.join_conference_dialog, null); final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account); final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView.findViewById(R.id.jid); jid.setAdapter(new KnownHostsAdapter(this,android.R.layout.simple_list_item_1, mKnownConferenceHosts)); @@ -402,7 +398,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU jid.append(prefilledJid); } populateAccountSpinner(spinner); - final CheckBox bookmarkCheckBox = (CheckBox) dialogView + final Checkable bookmarkCheckBox = (CheckBox) dialogView .findViewById(R.id.bookmark); builder.setView(dialogView); builder.setNegativeButton(R.string.cancel, null); @@ -413,63 +409,59 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU new View.OnClickListener() { @Override - public void onClick(View v) { + public void onClick(final View v) { if (!xmppConnectionServiceBound) { return; } - if (Validator.isValidJid(jid.getText().toString())) { - final Jid accountJid; - try { - accountJid = Jid.fromString((String) spinner.getSelectedItem()); - } catch (final InvalidJidException e) { - return; - } - final Jid conferenceJid; - try { - conferenceJid = Jid.fromString(jid.getText().toString()); - } catch (final InvalidJidException e) { - jid.setError(getString(R.string.invalid_jid)); - return; - } - Account account = xmppConnectionService - .findAccountByJid(accountJid); - if (account == null) { - dialog.dismiss(); - return; - } - if (bookmarkCheckBox.isChecked()) { - if (account.hasBookmarkFor(conferenceJid)) { - jid.setError(getString(R.string.bookmark_already_exists)); - } else { - Bookmark bookmark = new Bookmark(account, - conferenceJid); - bookmark.setAutojoin(true); - account.getBookmarks().add(bookmark); - xmppConnectionService - .pushBookmarks(account); - Conversation conversation = xmppConnectionService - .findOrCreateConversation(account, - conferenceJid, true); - conversation.setBookmark(bookmark); - if (!conversation.getMucOptions().online()) { - xmppConnectionService - .joinMuc(conversation); - } - dialog.dismiss(); - switchToConversation(conversation); - } + final Jid accountJid; + try { + accountJid = Jid.fromString((String) spinner.getSelectedItem()); + } catch (final InvalidJidException e) { + return; + } + final Jid conferenceJid; + try { + conferenceJid = Jid.fromString(jid.getText().toString()); + } catch (final InvalidJidException e) { + jid.setError(getString(R.string.invalid_jid)); + return; + } + final Account account = xmppConnectionService + .findAccountByJid(accountJid); + if (account == null) { + dialog.dismiss(); + return; + } + if (bookmarkCheckBox.isChecked()) { + if (account.hasBookmarkFor(conferenceJid)) { + jid.setError(getString(R.string.bookmark_already_exists)); } else { - Conversation conversation = xmppConnectionService + final Bookmark bookmark = new Bookmark(account, + conferenceJid); + bookmark.setAutojoin(true); + account.getBookmarks().add(bookmark); + xmppConnectionService + .pushBookmarks(account); + final Conversation conversation = xmppConnectionService .findOrCreateConversation(account, conferenceJid, true); + conversation.setBookmark(bookmark); if (!conversation.getMucOptions().online()) { - xmppConnectionService.joinMuc(conversation); + xmppConnectionService + .joinMuc(conversation); } dialog.dismiss(); switchToConversation(conversation); } } else { - jid.setError(getString(R.string.invalid_jid)); + final Conversation conversation = xmppConnectionService + .findOrCreateConversation(account, + conferenceJid, true); + if (!conversation.getMucOptions().online()) { + xmppConnectionService.joinMuc(conversation); + } + dialog.dismiss(); + switchToConversation(conversation); } } }); diff --git a/src/main/java/eu/siacs/conversations/utils/Validator.java b/src/main/java/eu/siacs/conversations/utils/Validator.java deleted file mode 100644 index 00130fa2..00000000 --- a/src/main/java/eu/siacs/conversations/utils/Validator.java +++ /dev/null @@ -1,14 +0,0 @@ -package eu.siacs.conversations.utils; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class Validator { - public static final Pattern VALID_JID = Pattern.compile( - "^[^@/<>'\"\\s]+@[^@/<>'\"\\s]+$", Pattern.CASE_INSENSITIVE); - - public static boolean isValidJid(String jid) { - Matcher matcher = VALID_JID.matcher(jid); - return matcher.find(); - } -} -- cgit v1.2.3 From 8a467e33dd7212fc3926b6fed2ae64fcb57e7f60 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Tue, 23 Dec 2014 17:12:52 -0500 Subject: Don't show menu on create account screen --- src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 07e06b75..e9c11d88 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -329,11 +329,14 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate getMenuInflater().inflate(R.menu.editaccount, menu); final MenuItem showQrCode = menu.findItem(R.id.action_show_qr_code); final MenuItem showBlocklist = menu.findItem(R.id.action_show_block_list); + final MenuItem showMoreInfo = menu.findItem(R.id.action_server_info_show_more); if (mAccount == null) { showQrCode.setVisible(false); showBlocklist.setVisible(false); + showMoreInfo.setVisible(false); } else if (mAccount.getStatus() != Account.State.ONLINE || !mAccount.getXmppConnection().getFeatures().blocking()) { showBlocklist.setVisible(false); + showMoreInfo.setVisible(false); } return true; } -- cgit v1.2.3 From afbe727b17b1e1d1a994b003f28ab7562bb655b4 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Tue, 23 Dec 2014 17:35:36 -0500 Subject: Don't allow user to register domain only jids --- src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index e9c11d88..9597b15e 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -82,6 +82,11 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate mAccountJid.requestFocus(); return; } + if (jid.isDomainJid()) { + mAccountJid.setError(getString(R.string.invalid_jid)); + mAccountJid.requestFocus(); + return; + } final String password = mPassword.getText().toString(); final String passwordConfirm = mPasswordConfirm.getText().toString(); if (registerNewAccount) { -- cgit v1.2.3 From 3ada834839d414e67903a5c1644ab6bdfede0c64 Mon Sep 17 00:00:00 2001 From: pulser Date: Wed, 24 Dec 2014 20:35:08 +0000 Subject: Show server info option when blocking is unavailable Current head of development branch doesn't show server information if blocking is disabled. This is due to slightly wrong logic on an if statement. This patch ensures only the blocking option is disabled when blocking is not supported by the server, and that the feature remains available. --- src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 9597b15e..9fce5ae5 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -339,9 +339,11 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate showQrCode.setVisible(false); showBlocklist.setVisible(false); showMoreInfo.setVisible(false); - } else if (mAccount.getStatus() != Account.State.ONLINE || !mAccount.getXmppConnection().getFeatures().blocking()) { + } else if (mAccount.getStatus() != Account.State.ONLINE) { + showBlocklist.setVisible(false); + showMoreInfo.setVisible(false); + } else if (!mAccount.getXmppConnection().getFeatures().blocking()) { showBlocklist.setVisible(false); - showMoreInfo.setVisible(false); } return true; } -- cgit v1.2.3 From 3b127ab743e642292e8edc8522429ed802f1b40d Mon Sep 17 00:00:00 2001 From: kriztan Date: Thu, 25 Dec 2014 09:14:34 +0100 Subject: Update german translations --- src/main/res/values-de/strings.xml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index efe2cc74..06ba17a7 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -13,6 +13,10 @@ Name bearbeiten Zum Telefonbuch hinzufügen Aus Kontaktliste entfernen + Kontakt sperren + Kontakt entsperren + Domain sperren + Domain entsperren Konten verwalten Einstellungen Konferenzdetails @@ -21,6 +25,7 @@ Mit Unterhaltung teilen Beginne Unterhaltung Kontakt auswählen + Sperrliste gerade vor einer Minute vor %d Minuten @@ -34,6 +39,11 @@ Teilnehmer Besucher Möchtest du %s von deiner Kontaktliste entfernen? Die Unterhaltung mit diesem Kontakt wird dabei nicht entfernt. + Möchtest du %s sperren und keine Nachrichten mehr erhalten? + Möchtest du %s entsperren und wieder Nachrichten empfangen? + Sperre alle Kontakte von %s? + Entsperre alle Kontakte %s? + Kontakt gesperrt Möchtest du das Lesezeichen %s entfernen? Die Unterhaltung mit diesem Lesezeichen wird dabei nicht entfernt. Neues Konto auf dem Server erstellen Teile mit… @@ -45,6 +55,8 @@ Hinzufügen Bearbeiten Entfernen + Sperren + Entsperren Speichern OK Conversations ist abgestürzt @@ -174,7 +186,12 @@ Offline Konferenz Andere Mitglieder + Server Info + XEP-0313: MAM XEP-0280: Message Carbons + XEP-0352: Client State Indication + XEP-0191: Blocking Command + XEP-0237: Roster Versioning XEP-0198: Stream Management XEP-0163: PEP (Avatare) verfügbar @@ -202,6 +219,8 @@ Konferenz beitreten Kontakt löschen Kontaktdetails anzeigen + Kontakt sperren + Kontakte entsperren Erstellen Der Kontakt existiert bereits Beitreten @@ -294,6 +313,7 @@ Bild-Übertragung fehlgeschlagen Scanne QR-Code Zeige QR-Code + Zeige Sperrliste Account Details Prüfe OTR Fingerabdruck der Gegenseite -- cgit v1.2.3 From ef1f72ea274341b562ba61ddd0c959d3c4191869 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 25 Dec 2014 19:53:35 +0100 Subject: catch another exception in fingerprint generation --- src/main/java/eu/siacs/conversations/entities/Conversation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 22ddd307..1f9afa65 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -451,7 +451,7 @@ public class Conversation extends AbstractEntity implements Blockable { builder.insert(26, " "); builder.insert(35, " "); this.otrFingerprint = builder.toString(); - } catch (final OtrCryptoException ignored) { + } catch (final OtrCryptoException | UnsupportedOperationException ignored) { } } -- cgit v1.2.3 From 2081c1bef767907479bbad1971f4cb0e0074bfbd Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 25 Dec 2014 19:53:56 +0100 Subject: proper call to invalidateViews() --- src/main/java/eu/siacs/conversations/ui/ConversationFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index d356c73c..39dfd4db 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -563,7 +563,7 @@ public class ConversationFragment extends Fragment { } this.mEditMessage.setText(""); this.mEditMessage.append(this.conversation.getNextMessage()); - this.messagesView.invalidate(); + this.messagesView.invalidateViews(); updateMessages(); this.messagesLoaded = true; int size = this.messageList.size(); -- cgit v1.2.3 From e4d9dca2fe6a75960d24f8af4dadba9a1a42845c Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Tue, 23 Dec 2014 17:19:00 -0500 Subject: Add ability to change password on server Fixes #260 --- .../eu/siacs/conversations/entities/Account.java | 45 ++++----- .../siacs/conversations/generator/IqGenerator.java | 12 ++- .../services/XmppConnectionService.java | 37 +++++-- .../conversations/ui/ConversationActivity.java | 2 +- .../conversations/ui/EditAccountActivity.java | 112 ++++++++++++--------- .../java/eu/siacs/conversations/utils/Xmlns.java | 1 + .../siacs/conversations/xmpp/XmppConnection.java | 4 + src/main/res/layout/activity_edit_account.xml | 11 +- src/main/res/values/strings.xml | 3 +- 9 files changed, 139 insertions(+), 88 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java index d42974c6..b0cde62c 100644 --- a/src/main/java/eu/siacs/conversations/entities/Account.java +++ b/src/main/java/eu/siacs/conversations/entities/Account.java @@ -10,6 +10,7 @@ import net.java.otr4j.crypto.OtrCryptoException; import org.json.JSONException; import org.json.JSONObject; +import java.security.PublicKey; import java.security.interfaces.DSAPublicKey; import java.util.Collection; import java.util.List; @@ -152,7 +153,7 @@ public class Account extends AbstractEntity { this.avatar = avatar; } - public static Account fromCursor(Cursor cursor) { + public static Account fromCursor(final Cursor cursor) { Jid jid = null; try { jid = Jid.fromParts(cursor.getString(cursor.getColumnIndex(USERNAME)), @@ -168,11 +169,11 @@ public class Account extends AbstractEntity { cursor.getString(cursor.getColumnIndex(AVATAR))); } - public boolean isOptionSet(int option) { + public boolean isOptionSet(final int option) { return ((options & (1 << option)) != 0); } - public void setOption(int option, boolean value) { + public void setOption(final int option, final boolean value) { if (value) { this.options |= 1 << option; } else { @@ -243,34 +244,18 @@ public class Account extends AbstractEntity { return keys; } - public String getSSLFingerprint() { - if (keys.has("ssl_cert")) { - try { - return keys.getString("ssl_cert"); - } catch (JSONException e) { - return null; - } - } else { - return null; - } - } - - public void setSSLCertFingerprint(String fingerprint) { - this.setKey("ssl_cert", fingerprint); - } - - public boolean setKey(String keyName, String keyValue) { + public boolean setKey(final String keyName, final String keyValue) { try { this.keys.put(keyName, keyValue); return true; - } catch (JSONException e) { + } catch (final JSONException e) { return false; } } @Override public ContentValues getContentValues() { - ContentValues values = new ContentValues(); + final ContentValues values = new ContentValues(); values.put(UUID, uuid); values.put(USERNAME, jid.getLocalpart()); values.put(SERVER, jid.getDomainpart()); @@ -304,8 +289,8 @@ public class Account extends AbstractEntity { if (this.otrEngine == null) { return null; } - DSAPublicKey publicKey = (DSAPublicKey) this.otrEngine.getPublicKey(); - if (publicKey == null) { + final PublicKey publicKey = this.otrEngine.getPublicKey(); + if (publicKey == null || !(publicKey instanceof DSAPublicKey)) { return null; } this.otrFingerprint = new OtrCryptoEngineImpl().getFingerprint(publicKey); @@ -338,7 +323,7 @@ public class Account extends AbstractEntity { if (keys.has("pgp_signature")) { try { return keys.getString("pgp_signature"); - } catch (JSONException e) { + } catch (final JSONException e) { return null; } } else { @@ -359,7 +344,7 @@ public class Account extends AbstractEntity { } public boolean hasBookmarkFor(final Jid conferenceJid) { - for (Bookmark bookmark : this.bookmarks) { + for (final Bookmark bookmark : this.bookmarks) { final Jid jid = bookmark.getJid(); if (jid != null && jid.equals(conferenceJid.toBareJid())) { return true; @@ -368,7 +353,7 @@ public class Account extends AbstractEntity { return false; } - public boolean setAvatar(String filename) { + public boolean setAvatar(final String filename) { if (this.avatar != null && this.avatar.equals(filename)) { return false; } else { @@ -395,7 +380,7 @@ public class Account extends AbstractEntity { } public String getShareableUri() { - String fingerprint = this.getOtrFingerprint(); + final String fingerprint = this.getOtrFingerprint(); if (fingerprint != null) { return "xmpp:" + this.getJid().toBareJid().toString() + "?otr-fingerprint="+fingerprint; } else { @@ -419,4 +404,8 @@ public class Account extends AbstractEntity { public void clearBlocklist() { getBlocklist().clear(); } + + public boolean isOnlineAndConnected() { + return this.getStatus() == State.ONLINE && this.getXmppConnection() != null; + } } diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 4b28e484..4bfc0963 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -4,6 +4,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.Xmlns; @@ -117,7 +118,6 @@ public class IqGenerator extends AbstractGenerator { } return packet; } - public IqPacket generateGetBlockList() { final IqPacket iq = new IqPacket(IqPacket.TYPE_GET); iq.addChild("blocklist", Xmlns.BLOCKING); @@ -138,4 +138,14 @@ public class IqGenerator extends AbstractGenerator { block.addChild("item").setAttribute("jid", jid.toBareJid().toString()); return iq; } + + public IqPacket generateSetPassword(final Account account, final String newPassword) { + final IqPacket packet = new IqPacket(IqPacket.TYPE_SET); + packet.setTo(account.getServer()); + final Element query = packet.addChild("query", Xmlns.REGISTER); + final Jid jid = account.getJid(); + query.addChild("username").setContent(jid.isDomainJid() ? jid.toString() : jid.getLocalpart()); + query.addChild("password").setContent(newPassword); + return packet; + } } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 6b0b960a..640074ba 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -222,7 +222,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa private OnMucRosterUpdate mOnMucRosterUpdate = null; private int mucRosterChangedListenerCount = 0; private SecureRandom mRandom; - private FileObserver fileObserver = new FileObserver( + private final FileObserver fileObserver = new FileObserver( FileBackend.getConversationsImageDirectory()) { @Override @@ -232,7 +232,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } }; - private OnJinglePacketReceived jingleListener = new OnJinglePacketReceived() { + private final OnJinglePacketReceived jingleListener = new OnJinglePacketReceived() { @Override public void onJinglePacketReceived(Account account, JinglePacket packet) { @@ -246,7 +246,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa private PendingIntent pendingPingIntent = null; private WakeLock wakeLock; private PowerManager pm; - private OnBindListener mOnBindListener = new OnBindListener() { + private final OnBindListener mOnBindListener = new OnBindListener() { @Override public void onBind(final Account account) { @@ -261,7 +261,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } }; - private OnMessageAcknowledged mOnMessageAcknowledgedListener = new OnMessageAcknowledged() { + private final OnMessageAcknowledged mOnMessageAcknowledgedListener = new OnMessageAcknowledged() { @Override public void onMessageAcknowledged(Account account, String uuid) { @@ -279,7 +279,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } }; private LruCache mBitmapCache; - private IqGenerator mIqGenerator = new IqGenerator(this); + private final IqGenerator mIqGenerator = new IqGenerator(this); private Thread mPhoneContactMergerThread; public PgpEngine getPgpEngine() { @@ -304,7 +304,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return this.mAvatarService; } - public void attachFileToConversation(Conversation conversation, final Uri uri, final UiCallback callback) { + public void attachFileToConversation(final Conversation conversation, + final Uri uri, + final UiCallback callback) { final Message message; if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) { message = new Message(conversation, "", @@ -1082,7 +1084,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } - public void createAccount(Account account) { + public void createAccount(final Account account) { account.initOtrEngine(this); databaseBackend.createAccount(account); this.accounts.add(account); @@ -1090,7 +1092,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa updateAccountUi(); } - public void updateAccount(Account account) { + public void updateAccount(final Account account) { this.statusListener.onStatusChanged(account); databaseBackend.updateAccount(account); reconnectAccount(account, false); @@ -1098,9 +1100,24 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa getNotificationService().updateErrorNotification(); } - public void deleteAccount(Account account) { + public void updateAccountPasswordOnServer(final Account account, final String newPassword) { + if (account.isOnlineAndConnected()) { + final IqPacket iq = getIqGenerator().generateSetPassword(account, newPassword); + sendIqPacket(account, iq, new OnIqPacketReceived() { + @Override + public void onIqPacketReceived(final Account account, final IqPacket packet) { + if (packet.getType() == IqPacket.TYPE_RESULT) { + account.setPassword(newPassword); + updateAccount(account); + } + } + }); + } + } + + public void deleteAccount(final Account account) { synchronized (this.conversations) { - for (Conversation conversation : conversations) { + for (final Conversation conversation : conversations) { if (conversation.getAccount() == account) { if (conversation.getMode() == Conversation.MODE_MULTI) { leaveMuc(conversation); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index c41a18c6..5a9a208f 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -318,7 +318,7 @@ public class ConversationActivity extends XmppActivity menuUnblock.setVisible(false); } final Account account = this.getSelectedConversation().getAccount(); - if (account.getStatus() != Account.State.ONLINE || !account.getXmppConnection().getFeatures().blocking()) { + if (account.isOnlineAndConnected() || !account.getXmppConnection().getFeatures().blocking()) { menuBlock.setVisible(false); menuUnblock.setVisible(false); } diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 9fce5ae5..4b6bea09 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -40,6 +40,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate private EditText mPassword; private EditText mPasswordConfirm; private CheckBox mRegisterNew; + private CheckBox mChangePassword; private Button mCancelButton; private Button mSaveButton; private TableLayout mMoreTable; @@ -63,7 +64,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate private boolean mFetchingAvatar = false; - private OnClickListener mSaveButtonClickListener = new OnClickListener() { + private final OnClickListener mSaveButtonClickListener = new OnClickListener() { @Override public void onClick(final View v) { @@ -74,6 +75,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate return; } final boolean registerNewAccount = mRegisterNew.isChecked(); + final boolean changePassword = mChangePassword.isChecked(); final Jid jid; try { jid = Jid.fromString(mAccountJid.getText().toString()); @@ -89,7 +91,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } final String password = mPassword.getText().toString(); final String passwordConfirm = mPasswordConfirm.getText().toString(); - if (registerNewAccount) { + if (registerNewAccount || changePassword) { if (!password.equals(passwordConfirm)) { mPasswordConfirm .setError(getString(R.string.passwords_do_not_match)); @@ -98,14 +100,22 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } } if (mAccount != null) { - mAccount.setPassword(password); try { mAccount.setUsername(jid.hasLocalpart() ? jid.getLocalpart() : ""); mAccount.setServer(jid.getDomainpart()); } catch (final InvalidJidException ignored) { } - mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount); - xmppConnectionService.updateAccount(mAccount); + if (changePassword) { + if (mAccount.isOnlineAndConnected()) { + xmppConnectionService.updateAccountPasswordOnServer(mAccount, mPassword.getText().toString()); + } else { + mPassword.setError(getResources().getString(R.string.account_status_no_internet)); + } + } else { + mAccount.setPassword(password); + mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount); + xmppConnectionService.updateAccount(mAccount); + } } else { try { if (xmppConnectionService.findAccountByJid(Jid.fromString(mAccountJid.getText().toString())) != null) { @@ -114,7 +124,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate mAccountJid.requestFocus(); return; } - } catch (InvalidJidException e) { + } catch (final InvalidJidException e) { return; } mAccount = new Account(jid.toBareJid(), password); @@ -132,10 +142,10 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } }; - private OnClickListener mCancelButtonClickListener = new OnClickListener() { + private final OnClickListener mCancelButtonClickListener = new OnClickListener() { @Override - public void onClick(View v) { + public void onClick(final View v) { finish(); } }; @@ -167,47 +177,53 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } }); } - private UiCallback mAvatarFetchCallback = new UiCallback() { + private final UiCallback mAvatarFetchCallback = new UiCallback() { @Override - public void userInputRequried(PendingIntent pi, Avatar avatar) { + public void userInputRequried(final PendingIntent pi, final Avatar avatar) { finishInitialSetup(avatar); } @Override - public void success(Avatar avatar) { + public void success(final Avatar avatar) { finishInitialSetup(avatar); } @Override - public void error(int errorCode, Avatar avatar) { + public void error(final int errorCode, final Avatar avatar) { finishInitialSetup(avatar); } }; - private TextWatcher mTextWatcher = new TextWatcher() { + private final TextWatcher mTextWatcher = new TextWatcher() { @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { + public void onTextChanged(final CharSequence s, final int start, final int before, final int count) { updateSaveButton(); } @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - + public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) { } @Override - public void afterTextChanged(Editable s) { - + public void afterTextChanged(final Editable s) { + final boolean registrationReady = mAccount != null && + mAccount.isOnlineAndConnected() && + mAccount.getXmppConnection().getFeatures().register(); + if (jidToEdit != null && mAccount != null && registrationReady && + !mAccount.getPassword().equals(s.toString()) && !"".equals(s.toString())) { + mChangePassword.setVisibility(View.VISIBLE); + } else { + mChangePassword.setVisibility(View.INVISIBLE); + mChangePassword.setChecked(false); + } } }; - private OnClickListener mAvatarClickListener = new OnClickListener() { + private final OnClickListener mAvatarClickListener = new OnClickListener() { @Override - public void onClick(View view) { - if (mAccount!=null) { - Intent intent = new Intent(getApplicationContext(), + public void onClick(final View view) { + if (mAccount != null) { + final Intent intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class); intent.putExtra("account", mAccount.getJid().toBareJid().toString()); startActivity(intent); @@ -220,7 +236,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate @Override public void run() { - Intent intent; + final Intent intent; if (avatar != null) { intent = new Intent(getApplicationContext(), StartConversationActivity.class); @@ -251,8 +267,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mSaveButton.setEnabled(true); this.mSaveButton.setTextColor(getPrimaryTextColor()); if (jidToEdit != null) { - if (mAccount != null - && mAccount.getStatus() == Account.State.ONLINE) { + if (mAccount != null && mAccount.isOnlineAndConnected()) { this.mSaveButton.setText(R.string.save); if (!accountInfoEdited()) { this.mSaveButton.setEnabled(false); @@ -268,7 +283,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } protected boolean accountInfoEdited() { - return (!this.mAccount.getJid().toBareJid().equals( + return (!this.mAccount.getJid().toBareJid().toString().equals( this.mAccountJid.getText().toString())) || (!this.mAccount.getPassword().equals( this.mPassword.getText().toString())); @@ -284,7 +299,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } @Override - protected void onCreate(Bundle savedInstanceState) { + protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_edit_account); this.mAccountJid = (AutoCompleteTextView) findViewById(R.id.account_jid); @@ -295,6 +310,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mAvatar = (ImageView) findViewById(R.id.avater); this.mAvatar.setOnClickListener(this.mAvatarClickListener); this.mRegisterNew = (CheckBox) findViewById(R.id.account_register_new); + this.mChangePassword = (CheckBox) findViewById(R.id.account_change_password); this.mStats = (LinearLayout) findViewById(R.id.stats); this.mSessionEst = (TextView) findViewById(R.id.session_est); this.mServerInfoRosterVersion = (TextView) findViewById(R.id.server_info_roster_version); @@ -312,20 +328,20 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mSaveButton.setOnClickListener(this.mSaveButtonClickListener); this.mCancelButton.setOnClickListener(this.mCancelButtonClickListener); this.mMoreTable = (TableLayout) findViewById(R.id.server_info_more); - this.mRegisterNew - .setOnCheckedChangeListener(new OnCheckedChangeListener() { - - @Override - public void onCheckedChanged(CompoundButton buttonView, - boolean isChecked) { - if (isChecked) { - mPasswordConfirm.setVisibility(View.VISIBLE); - } else { - mPasswordConfirm.setVisibility(View.GONE); - } - updateSaveButton(); + final OnCheckedChangeListener OnCheckedShowConfirmPassword = new OnCheckedChangeListener() { + @Override + public void onCheckedChanged(final CompoundButton buttonView, + final boolean isChecked) { + if (isChecked) { + mPasswordConfirm.setVisibility(View.VISIBLE); + } else { + mPasswordConfirm.setVisibility(View.GONE); } - }); + updateSaveButton(); + } + }; + this.mRegisterNew.setOnCheckedChangeListener(OnCheckedShowConfirmPassword); + this.mChangePassword.setOnCheckedChangeListener(OnCheckedShowConfirmPassword); } @Override @@ -340,8 +356,8 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate showBlocklist.setVisible(false); showMoreInfo.setVisible(false); } else if (mAccount.getStatus() != Account.State.ONLINE) { - showBlocklist.setVisible(false); - showMoreInfo.setVisible(false); + showBlocklist.setVisible(false); + showMoreInfo.setVisible(false); } else if (!mAccount.getXmppConnection().getFeatures().blocking()) { showBlocklist.setVisible(false); } @@ -368,6 +384,8 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate getActionBar().setTitle(R.string.action_add_account); } } + this.mChangePassword.setVisibility(View.GONE); + this.mChangePassword.setChecked(false); } } @@ -415,11 +433,15 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } if (this.mAccount.isOptionSet(Account.OPTION_REGISTER)) { this.mRegisterNew.setVisibility(View.VISIBLE); + this.mChangePassword.setVisibility(View.GONE); + this.mChangePassword.setChecked(false); this.mRegisterNew.setChecked(true); this.mPasswordConfirm.setText(this.mAccount.getPassword()); } else { this.mRegisterNew.setVisibility(View.GONE); this.mRegisterNew.setChecked(false); + this.mChangePassword.setVisibility(View.GONE); + this.mChangePassword.setChecked(false); } if (this.mAccount.getStatus() == Account.State.ONLINE && !this.mFetchingAvatar) { @@ -474,7 +496,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate .setOnClickListener(new View.OnClickListener() { @Override - public void onClick(View v) { + public void onClick(final View v) { if (copyTextToClipboard(fingerprint, R.string.otr_fingerprint)) { Toast.makeText( diff --git a/src/main/java/eu/siacs/conversations/utils/Xmlns.java b/src/main/java/eu/siacs/conversations/utils/Xmlns.java index acea2e56..67de7c79 100644 --- a/src/main/java/eu/siacs/conversations/utils/Xmlns.java +++ b/src/main/java/eu/siacs/conversations/utils/Xmlns.java @@ -3,4 +3,5 @@ package eu.siacs.conversations.utils; public final class Xmlns { public static final String BLOCKING = "urn:xmpp:blocking"; public static final String ROSTER = "jabber:iq:roster"; + public static final String REGISTER = "jabber:iq:register"; } diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 7fd0a4b6..b03d3f74 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -1082,6 +1082,10 @@ public class XmppConnection implements Runnable { return hasDiscoFeature(account.getServer(), Xmlns.BLOCKING); } + public boolean register() { + return hasDiscoFeature(account.getServer(), Xmlns.REGISTER); + } + public boolean sm() { return streamId != null; } diff --git a/src/main/res/layout/activity_edit_account.xml b/src/main/res/layout/activity_edit_account.xml index a12766f9..cb626780 100644 --- a/src/main/res/layout/activity_edit_account.xml +++ b/src/main/res/layout/activity_edit_account.xml @@ -79,6 +79,15 @@ android:textColor="@color/primarytext" android:textSize="?attr/TextSizeBody" /> + + - - diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 29b81354..22e39a89 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -46,6 +46,7 @@ Contact blocked Would you like to remove %s as a bookmark? The conversation associated with this bookmark will not be removed. Register new account on server + Change password Share with Start Conversation Invite Contact @@ -249,7 +250,7 @@ to %s Send private message to %s Connect - This account does already exist + This account already exists Next Current session established Additional Information -- cgit v1.2.3 From 0c22a8d1c6a984ccd0080d74a07d500879ee8242 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 25 Dec 2014 22:08:13 +0100 Subject: added callback to change account password to notify UI on success / failure --- .../siacs/conversations/generator/IqGenerator.java | 2 +- .../services/XmppConnectionService.java | 30 ++++++----- .../conversations/ui/EditAccountActivity.java | 58 ++++++++++++++++------ src/main/res/values/strings.xml | 3 ++ 4 files changed, 66 insertions(+), 27 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 4bfc0963..f94dc5d7 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -144,7 +144,7 @@ public class IqGenerator extends AbstractGenerator { packet.setTo(account.getServer()); final Element query = packet.addChild("query", Xmlns.REGISTER); final Jid jid = account.getJid(); - query.addChild("username").setContent(jid.isDomainJid() ? jid.toString() : jid.getLocalpart()); + query.addChild("username").setContent(jid.getLocalpart()); query.addChild("password").setContent(newPassword); return packet; } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 640074ba..dc895e5b 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1100,19 +1100,25 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa getNotificationService().updateErrorNotification(); } - public void updateAccountPasswordOnServer(final Account account, final String newPassword) { - if (account.isOnlineAndConnected()) { - final IqPacket iq = getIqGenerator().generateSetPassword(account, newPassword); - sendIqPacket(account, iq, new OnIqPacketReceived() { - @Override - public void onIqPacketReceived(final Account account, final IqPacket packet) { - if (packet.getType() == IqPacket.TYPE_RESULT) { - account.setPassword(newPassword); - updateAccount(account); - } + public void updateAccountPasswordOnServer(final Account account, final String newPassword, final OnAccountPasswordChanged callback) { + final IqPacket iq = getIqGenerator().generateSetPassword(account, newPassword); + sendIqPacket(account, iq, new OnIqPacketReceived() { + @Override + public void onIqPacketReceived(final Account account, final IqPacket packet) { + if (packet.getType() == IqPacket.TYPE_RESULT) { + account.setPassword(newPassword); + databaseBackend.updateAccount(account); + callback.onPasswordChangeSucceeded(); + } else { + callback.onPasswordChangeFailed(); } - }); - } + } + }); + } + + public interface OnAccountPasswordChanged { + public void onPasswordChangeSucceeded(); + public void onPasswordChangeFailed(); } public void deleteAccount(final Account account) { diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 4b6bea09..3bd4dd1e 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -25,6 +25,7 @@ import android.widget.Toast; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; import eu.siacs.conversations.ui.adapter.KnownHostsAdapter; import eu.siacs.conversations.utils.CryptoHelper; @@ -34,7 +35,7 @@ import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.pep.Avatar; -public class EditAccountActivity extends XmppActivity implements OnAccountUpdate { +public class EditAccountActivity extends XmppActivity implements OnAccountUpdate, XmppConnectionService.OnAccountPasswordChanged { private AutoCompleteTextView mAccountJid; private EditText mPassword; @@ -63,17 +64,17 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate private Account mAccount; private boolean mFetchingAvatar = false; + private boolean mChangingPassword = false; private final OnClickListener mSaveButtonClickListener = new OnClickListener() { @Override public void onClick(final View v) { - if (mAccount != null - && mAccount.getStatus() == Account.State.DISABLED) { + if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED) { mAccount.setOption(Account.OPTION_DISABLED, false); xmppConnectionService.updateAccount(mAccount); return; - } + } final boolean registerNewAccount = mRegisterNew.isChecked(); final boolean changePassword = mChangePassword.isChecked(); final Jid jid; @@ -107,10 +108,13 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } if (changePassword) { if (mAccount.isOnlineAndConnected()) { - xmppConnectionService.updateAccountPasswordOnServer(mAccount, mPassword.getText().toString()); + xmppConnectionService.updateAccountPasswordOnServer(mAccount, mPassword.getText().toString(),EditAccountActivity.this); + mChangingPassword = true; + updateSaveButton(); } else { - mPassword.setError(getResources().getString(R.string.account_status_no_internet)); + Toast.makeText(EditAccountActivity.this,R.string.not_connected_try_again,Toast.LENGTH_SHORT).show(); } + return; } else { mAccount.setPassword(password); mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount); @@ -119,8 +123,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } else { try { if (xmppConnectionService.findAccountByJid(Jid.fromString(mAccountJid.getText().toString())) != null) { - mAccountJid - .setError(getString(R.string.account_already_exists)); + mAccountJid.setError(getString(R.string.account_already_exists)); mAccountJid.requestFocus(); return; } @@ -253,13 +256,15 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } protected void updateSaveButton() { - if (mAccount != null - && mAccount.getStatus() == Account.State.CONNECTING) { + if (mChangingPassword) { + this.mSaveButton.setEnabled(false); + this.mSaveButton.setTextColor(getSecondaryTextColor()); + this.mSaveButton.setText(R.string.updating); + } else if (mAccount != null && mAccount.getStatus() == Account.State.CONNECTING) { this.mSaveButton.setEnabled(false); this.mSaveButton.setTextColor(getSecondaryTextColor()); this.mSaveButton.setText(R.string.account_status_connecting); - } else if (mAccount != null - && mAccount.getStatus() == Account.State.DISABLED) { + } else if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED) { this.mSaveButton.setEnabled(true); this.mSaveButton.setTextColor(getPrimaryTextColor()); this.mSaveButton.setText(R.string.enable); @@ -446,8 +451,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate if (this.mAccount.getStatus() == Account.State.ONLINE && !this.mFetchingAvatar) { this.mStats.setVisibility(View.VISIBLE); - this.mSessionEst.setText(UIHelper.readableTimeDifference( - getApplicationContext(), this.mAccount.getXmppConnection() + this.mSessionEst.setText(UIHelper.readableTimeDifferenceFull(this, this.mAccount.getXmppConnection() .getLastSessionEstablished())); Features features = this.mAccount.getXmppConnection().getFeatures(); if (features.rosterVersioning()) { @@ -517,4 +521,30 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mStats.setVisibility(View.GONE); } } + + @Override + public void onPasswordChangeSucceeded() { + this.mChangingPassword = false; + runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(EditAccountActivity.this,R.string.password_changed,Toast.LENGTH_SHORT).show(); + updateSaveButton(); + updateAccountInformation(); + } + }); + } + + @Override + public void onPasswordChangeFailed() { + this.mChangingPassword = false; + runOnUiThread(new Runnable() { + @Override + public void run() { + mPassword.requestFocus(); + mPassword.setError(getString(R.string.could_not_change_password)); + updateSaveButton(); + } + }); + } } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 22e39a89..6634c96a 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -389,4 +389,7 @@ Copy OTR fingerprint to clipboard Fetching history from server No more history on server + Updating… + Password changed! + Could not change password -- cgit v1.2.3 From 193d2645e6995a2631a16c88c78e3b0b5581cbc6 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 25 Dec 2014 22:28:19 +0100 Subject: code cleanup for change password stuff --- .../conversations/ui/EditAccountActivity.java | 33 +++++++++++++--------- src/main/res/layout/activity_edit_account.xml | 2 +- src/main/res/values/strings.xml | 2 +- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 3bd4dd1e..f8221f1b 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -94,8 +94,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate final String passwordConfirm = mPasswordConfirm.getText().toString(); if (registerNewAccount || changePassword) { if (!password.equals(passwordConfirm)) { - mPasswordConfirm - .setError(getString(R.string.passwords_do_not_match)); + mPasswordConfirm.setError(getString(R.string.passwords_do_not_match)); mPasswordConfirm.requestFocus(); return; } @@ -210,18 +209,26 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate @Override public void afterTextChanged(final Editable s) { - final boolean registrationReady = mAccount != null && + toggleChangePasswordCheckbox(); + } + }; + + private void toggleChangePasswordCheckbox() { + final boolean registrationReady = mAccount != null && mAccount.isOnlineAndConnected() && mAccount.getXmppConnection().getFeatures().register(); - if (jidToEdit != null && mAccount != null && registrationReady && - !mAccount.getPassword().equals(s.toString()) && !"".equals(s.toString())) { - mChangePassword.setVisibility(View.VISIBLE); - } else { - mChangePassword.setVisibility(View.INVISIBLE); - mChangePassword.setChecked(false); - } + if (passwordFieldEdited() && registrationReady) { + mChangePassword.setVisibility(View.VISIBLE); + } else { + mChangePassword.setVisibility(View.INVISIBLE); + mChangePassword.setChecked(false); } - }; + } + + private boolean passwordFieldEdited() { + final String password = this.mPassword.getText().toString(); + return jidToEdit != null && mAccount != null && !password.isEmpty() && !mAccount.getPassword().equals(password); + } private final OnClickListener mAvatarClickListener = new OnClickListener() { @Override public void onClick(final View view) { @@ -448,8 +455,8 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mChangePassword.setVisibility(View.GONE); this.mChangePassword.setChecked(false); } - if (this.mAccount.getStatus() == Account.State.ONLINE - && !this.mFetchingAvatar) { + if (this.mAccount.isOnlineAndConnected() && !this.mFetchingAvatar) { + toggleChangePasswordCheckbox(); this.mStats.setVisibility(View.VISIBLE); this.mSessionEst.setText(UIHelper.readableTimeDifferenceFull(this, this.mAccount.getXmppConnection() .getLastSessionEstablished())); diff --git a/src/main/res/layout/activity_edit_account.xml b/src/main/res/layout/activity_edit_account.xml index cb626780..d2987253 100644 --- a/src/main/res/layout/activity_edit_account.xml +++ b/src/main/res/layout/activity_edit_account.xml @@ -84,7 +84,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" - android:text="@string/change_password" + android:text="@string/change_password_on_server" android:textColor="@color/primarytext" android:textSize="?attr/TextSizeBody" /> diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 6634c96a..f75a698b 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -46,7 +46,7 @@ Contact blocked Would you like to remove %s as a bookmark? The conversation associated with this bookmark will not be removed. Register new account on server - Change password + Change password on server Share with Start Conversation Invite Contact -- cgit v1.2.3 From 3b3d51b39af1b1395659a40afdf8ac167fc3e712 Mon Sep 17 00:00:00 2001 From: kriztan Date: Sat, 27 Dec 2014 10:42:15 +0100 Subject: Update german translations --- src/main/res/values-de/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index 06ba17a7..f959c382 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -46,6 +46,7 @@ Kontakt gesperrt Möchtest du das Lesezeichen %s entfernen? Die Unterhaltung mit diesem Lesezeichen wird dabei nicht entfernt. Neues Konto auf dem Server erstellen + Passwort ändern Teile mit… Beginne Unterhaltung Kontakt einladen @@ -364,4 +365,7 @@ OTR-Fingerabdruck in Zwischenablage kopieren Hole Chatverlauf vom Server Keine weiteren Nachrichten auf dem Server vorhanden. + Aktualisiere… + Passwort geändert. + Passwort kann nicht geändert werden. -- cgit v1.2.3 From 4a8342a378e1b2764857c3dd3568f48d252eedd1 Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Sat, 27 Dec 2014 12:53:15 +0100 Subject: Update Dutch translations --- src/main/res/values-nl/arrays.xml | 17 +- src/main/res/values-nl/strings.xml | 387 ++++++++++++++++++++++++++----------- 2 files changed, 291 insertions(+), 113 deletions(-) diff --git a/src/main/res/values-nl/arrays.xml b/src/main/res/values-nl/arrays.xml index 9ced79f4..ad3fc6ea 100644 --- a/src/main/res/values-nl/arrays.xml +++ b/src/main/res/values-nl/arrays.xml @@ -20,5 +20,20 @@ 524288 1048576 + + 30 minuten + 1 uur + 2 uur + 8 uur + voor onbepaalde duur + + + + 1800 + 3600 + 7200 + 28800 + -1 + - \ No newline at end of file + diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml index 7b3faca9..32ffd4d5 100644 --- a/src/main/res/values-nl/strings.xml +++ b/src/main/res/values-nl/strings.xml @@ -1,128 +1,148 @@ - Conversaties + Gesprekken Instellingen - Nieuwe conversatie + Nieuw gesprek Beheer account - Beëindig conversatie - Contact details - Gesprek details - Beveiligde conversatie + Beëindig gesprek + Contactgegevens + Gespreksgegevens + Beveiligd gesprek Voeg account toe Verander naam - Voeg aan telefoonboek toe + Voeg toe aan telefoonboek Verwijder uit lijst - Beheer Accounts + Blokkeer contact + Deblokkeer contact + Blokkeer domein + Deblokkeer domein + Beheer accounts Instellingen - Groepsconversatie Details - Contact Details - Conversaties - Delen met Conversatie + Groepsgespreksgegevens + Contactgegevens + Gesprekken + Delen met gesprek + Start gesprek + Kies contact + Geblokkeerde contacten net - 1 min geleden - %d min geleden - ongelezen Conversaties + 1 min. geleden + %d min. geleden + ongelezen gesprekken versturen… - Bericht aan het ontsleutelen. Een moment geduld a.u.b.… + Bericht aan het ontsleutelen. Even geduld… Naam is al in gebruik Beheerder Eigenaar Moderator Deelnemer Bezoeker - Wilt u %s uit uw lijst verwijderen? De conversatie met deze account zal niet worden verwijderd. + Wil je %s uit je lijst verwijderen? Het gesprek met deze account zal niet worden verwijderd. + Wil je alle berichten van %s blokkeren? + Wil je %s deblokkeren en er weer berichten van kunnen ontvangen? + Alle contacten van %s blokkeren? + Alle contacten van %s deblokkeren? + Contact geblokkeerd + Wil je %s als bladwijzer verwijderen? Het gesprek met deze account zal niet worden verwijderd. Registreer nieuwe account op server + Verander wachtwoord op server Deel met - Start Conversatie + Start gesprek + Nodig contact uit Contacten Annuleer + Stel in Voeg toe Bewerk Verwijder + Blokkeer + Deblokkeer Sla op OK - Conversaties is gecrashed - Door het versturen van crash rapportages helpt u mee met de ontwikkeling van Conversaties.\nWaarschuwing: Deze app zal uw XMPP account gebruiken om de crash rapportages te versturen naar de ontwikkelaars. + Gesprekken is gecrasht + Door het versturen van crash rapportages help je de ontwikkeling van Gesprekken.\n\nWaarschuwing: Deze app zal je XMPP account gebruiken om de crash rapportages te versturen naar de ontwikkelaars. Nu versturen Niet opnieuw vragen Account verbinden mislukt Verbinden met meerdere accounts mislukt Raak hier aan om accounts te beheren Voeg bestand bij - Het contact is geen onderdeel van uw lijst. Wilt u het toevoegen? + Het contact is geen onderdeel van uw lijst. Wil je het toevoegen? Voeg contact toe afleveren mislukt geweigerd - Bezig met ontvangen van afbeelding. Een moment geduld a.u.b.… - Bezig met voorbereiden van het versturen van afbeelding + Bezig met ontvangen van afbeelding. Even geduld… + Bezig met voorbereiden van versturen van afbeelding Wis geschiedenis - Wis conversatie geschiedenis - Wilt U alle berichten in deze Conversatie verwijderen?\n\nWaarschuwing: Dit zal geen invloed hebben op de berichten opgeslagen op andere apparaten of servers. + Wis gespreksgeschiedenis + Wil je alle berichten in dit gesprek verwijderen?\n\nWaarschuwing: Dit zal geen invloed hebben op de berichten opgeslagen op andere apparaten of servers. Verwijder berichten - Beëindig deze conversatie na afloop + Beëindig dit gesprek na afloop Kies aanwezigheid om te tonen aan contact Verstuur eenvoudig tekst bericht Verstuur OTR versleuteld bericht Verstuur OpenPGP versleuteld bericht - Uw naam is veranderd - Download Afbeelding + Je naam is veranderd + Download afbeelding Afbeelding aangeboden voor downloaden Verstuur onversleuteld - Ontsleutelen mislukt. Misschien hebt U niet de juiste private sleutel. + Ontsleutelen mislukt. Misschien heb je niet de juiste private sleutel. OpenKeychain - Conversaties gebruikt een derde partij app genaamd OpenKeychain om berichten te versleutelen en ontsleutelen, en om publieke sleutels te beheren.\n\nOpenKeychain is beschikbaar onder de GPLv3 en beschikbaar op F-Droid en Google Play.\n\n(Herstart Conversaties na installatie.) + Gesprekken gebruikt een derde partij app genaamd OpenKeychain om berichten te versleutelen en ontsleutelen, en om publieke sleutels te beheren.\n\nOpenKeychain is beschikbaar onder de GPLv3 en beschikbaar op F-Droid en Google Play.\n\n(Herstart Gesprekken na installatie.) Herstart Installeer - offering… - wachten… + offering… + wachten… Geen OpenPGP sleutel gevonden - Conversaties kan Uw berichten niet versleutelen omdat uw contact geen publieke sleutel heeft ingesteld.\n\nVraag uw contact om OpenPGP te configureren. + Gesprekken kan je berichten niet versleutelen omdat je contact geen publieke sleutel heeft ingesteld.\n\nVraag je contact om OpenPGP te configureren. Geen OpenPGP sleutels gevonden - Conversaties kan uw berichten niet versleutelen omdat uw contacten geen publieke sleutel hebben ingesteld.\n\nVraag uw contacten om OpenPGP te configureren. + Gesprekken kan je berichten niet versleutelen omdat je contacten geen publieke sleutel hebben ingesteld.\n\nVraag je contacten om OpenPGP te configureren. Versleuteld bericht ontvangen. Raak aan om te bekijken en te ontsleutelen. Versleutelde afbeelding ontvangen. Raak aan om te bekijken en te ontsleutelen. Afbeelding ontvangen. Raak aan om te bekijken. + Algemeen XMPP resource De naam waarmee deze client zich identificeert Accepteer bestanden - Accepteer automatisch bestanden kleiner dan… - Notificatie Instellingen - Notificaties - Notificatie als een nieuw bericht arriveert + Accepteer automatisch bestanden kleiner dan… + Meldingsinstellingen + Meldingen + Melding als een nieuw bericht arriveert Trillen Tril ook wanneer een nieuw bericht arriveert Geluid - Speel ringtone af bij notificatie - Groepsconversatie notificaties - Toon altijd notificaties als er nieuwe berichten arriveren in groepsconversaties in plaats van alleen bij highlighting - Notificatie uitstel periode - Zet notificaties voor korte tijd uit als er een carbon copy wordt ontvangen - Geadvanceerde Opties + Speel ringtone af bij melding + Groepsgespreksmeldingen + Toon altijd meldingen als er nieuwe berichten arriveren in groepsgesprekken in plaats van alleen wanneer gemarkeerd + Uitstelperiode voor meldingen + Zet meldingen voor korte tijd uit als er een carbon copy wordt ontvangen + Geavanceerde instellingen Verstuur nooit crash rapportages - Door crash rapportages te versturen helpt U mee aan de ontwikkeling van Conversaties - Bevestig Berichten - Laat uw contacten weten waneer U berichten hebt ontvangen en gelezen + Door crash rapportages te versturen help je de ontwikkeling van Gesprekken + Bevestig berichten + Laat je contacten weten wanneer je berichten hebt ontvangen en gelezen + UI opties OpenKeychain rapporteerde een fout - I/O Fout tijdens ontsleutelen bestand - Accepteer + I/O fout tijdens ontsleutelen bestand + Aanvaard Er is een fout opgetreden - Verleen toestemming voor aanwezigheid updates - Vantevoren toestemming verlenen en vragen aan contacten die U hebt aangemaakt + Verleen toestemming voor aanwezigheidsupdates + Op voorhand toestemming verlenen en vragen aan contacten die je hebt aangemaakt Abonnementen - Uw account + Je account Sleutels - Verstuur aanwezigheid updates - Ontvang aanwezigheid updates - Vraag naar aanwezigheid updates + Verstuur aanwezigheidsupdates + Ontvang aanwezigheidsupdates + Vraag naar aanwezigheidsupdates Kies afbeelding Neem foto - Vantevoren toestemming verlenen voor abonneren - Het bestand dat U gekozen hebt is geen afbeelding + Op voorhand toestemming verlenen voor abonneren + Het bestand dat je gekozen hebt is geen afbeelding Fout tijdens converteren van afbeelding Bestand niet gevonden - Generieke I/O fout. Misschien is er geen opslagruimte meer beschikbaar? - De app die U gebruikte om de afbeelding te selecteren heeft niet voldoende toegang geleverd om het bestand te lezen.\n\nGebruik een andere app om een afbeelding te kiezen + Algemene I/O fout. Misschien is er geen opslagruimte meer beschikbaar? + De app die je gebruikte om de afbeelding te selecteren heeft niet voldoende toegang geleverd om het bestand te lezen.\n\nGebruik een andere app om een afbeelding te kiezen Onbekend Tijdelijk uitgezet Online @@ -135,15 +155,19 @@ Gebruikersnaam bezet Registratie compleet Server ondersteunt geen registratie + Fout bij beveiliging + Incompatibele server Onversleuteld OTR OpenPGP Bewerk account Verwijder Tijdelijk uitzetten + Publish avatar + Publish OpenPGP public key Aanzetten - Weet U het zeker? - Als U uw account verwijderd wordt Uw volledige conversatie geschiedenis gewist + Ben je zeker? + Als je je account verwijdert wordt je volledige gespreksgeschiedenis gewist Neem stem op Jabber ID: Wachtwoord: @@ -154,17 +178,25 @@ Wachtwoorden komen niet overeen Dit is geen geldig Jabber ID Geen geheugen beschikbaar. Afbeelding is te groot - Wilt U %s toevoegen aan de contactenlijst op uw telefoon? + Wil je %s toevoegen aan de contactenlijst op je telefoon? online beschikbaar weg langdurig weg niet storen offline - groepsconversatie - Andere Leden - Carbon Berichten - Stream Management + Groepsgesprek + Andere leden + Server info + XEP-0313: MAM + XEP-0280: Message Carbons + XEP-0352: Client State Indication + XEP-0191: Blocking Command + XEP-0237: Roster Versioning + XEP-0198: Stream Management + XEP-0163: PEP (Avatars) + beschikbaar + niet beschikbaar Ontbrekende publieke sleutel aankondigingen zonet voor het laatst gezien 1 minuut geleden voor het laatst gezien @@ -176,58 +208,189 @@ nog nooit gezien Versleuteld bericht. Installeer OpenKeychain om te ontsleutelen. Onbekende OTR vingerafdruk - OpenPGP encrypted messages found + OpenPGP-versleutelde berichten gevonden Ontvangen mislukt - Aan groepsconversatie deelnemen - Contact uitnodigen - Uw vingerafdruk - Bladwijzer verwijderen - Deelnemen + Jouw vingerafdruk OTR vingerafdruk - U - Groepsconversatie niet gevonden + Bevestig + Ontsleutel + Groepsgesprekken Zoeken - Het contact bestaat al - Start Groepsconversatie - Kies contact - Contact added you to contact list - Contactdetails bekijken - Groepsconversaties - Controleren - Contact Aanmaken - Wilt u %s als bladwijzer verwijderen? De groepsconversatie die verbonden is met deze bladwijzer zal niet verwijderd worden. - Onderwerp van groepsconversatie veranderen - Contact Verwijderen + Maak contact aan + Aan groepsgesprek deelnemen + Verwijder contact + Bekijk contactgegevens + Blokkeer contact + Deblokkeer contact Aanmaken - Verlaten - Groepsconversatie adres - Bladwijzer toevoegen - kamer@groepsconversatie.voorbeeld.nl - Terug toevoegen + Het contact bestaat al + Deelnemen + Gespreksadres + kamer@groepsgesprek.voorbeeld.be + Opslaan als bladwijzer + Bladwijzer verwijderen Deze bladwijzer bestaat al - Ontsleutelen + Jij + Onderwerp groepsgesprek bewerken + Groepsgesprek niet gevonden + Verlaten + Contact heeft je toegevoegd aan zijn/haar contacten + Contact toevoegen aan eigen contacten %s heeft tot hier gelezen + Publiceer + Raak avatar aan om een foto uit de galerij te kiezen + Aandacht: Iedereen die je aanwezigheidsupdates ontvangt zal deze foto kunnen zien. + Publiceren… + De server weigerde de publicatie van je afbeelding + Fout bij converteren van afbeelding + Fout bij opslaan van avatar + (Of hou lang ingedrukt om de oorspronkelijke terug te zetten) + Je server ondersteunt de publicatie van avatars niet + gefluisterd + naar %s + Stuur privébericht naar %s + Verbinden + Deze account bestaat al Volgende - N.B.: Iedereen die uw aanwezigheid kan zien kan deze afbeelding zien. - niet beschikbaar - Publiceer publieke OpenPGP sleutel - Extra informatie - XEP-0163: PEP (Avatars) + Huidige sessie gevestigd + Bijkomstige informatie Overslaan - Verbinden - Dit account bestaat al - naar %s - Verstuur privé bericht aan %s - Klik op avatar om een afbeelding te selecteren uit de gallerij - Publiceer avatar - De server weigerde uw publicatie - Er ging iets mis bij het converteren van uw afbeelding - Uw server ondersteunt de publicatie van avatars niet - Publiceren… - Kon de avatar niet opslaan - Huidige sessie opgezet - (Of houdt lang ingedrukt om de oorspronkelijke terug te zetten) - beschikbaar - UI Opties + Meldingen uitzetten + Meldingen uitzetten voor dit gesprek + Meldingen zijn uitgezet + Aanzetten + Wachtwoord nodig voor toegang tot groepsgesprek + Wachtwoord: + Ontbrekende aanwezigheidsupdates van contact + Vraag eerst aanwezigheidsupdates van je contact aan.\n\nDit wordt gebruikt om te bepalen welke client(s) je contact gebruikt. + Nu aanvragen + Vingerafdruk verwijderen + Ben je zeker dat je deze vingerafdruk wil verwijderen? + Negeren + Waarschuwing: Dit verzenden zonder wederzijdse aanwezigheidsupdates kan voor onverwachte problemen zorgen.\n\nGa naar contactgegevens om je aanwezigheidsupdates te bevestigen. + Versleutelingsinstellingen + Verplicht end-to-end versleuteling + Stuur berichten altijd versleuteld (behalve in groepsgesprekken) + Sla versleutelde berichten niet op + Waarschuwing: Dit kan leiden tot verlies van berichten + Sta legacy SSL toe + Staat ondersteuning voor SSLv3 voor legacy servers toe. Waarschuwing: SSLv3 is niet veilig. + Expert-instellingen + Wees voorzichtig met deze instellingen + Over Gesprekken + Build en licentie-informatie + + Conversations • the very last word in instant messaging. + \n\nCopyright © 2014 Daniel Gultsch + \n\nThis program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + \n\nThis program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + \n\nYou should have received a copy of the GNU General Public License + along with this program. If not, see https://www.gnu.org/licenses + \n\nDownload the full source code at https://github.com/siacs/Conversations + \n\n\nLibraries + \n\nhttps://www.bouncycastle.org\n(The MIT License (MIT)) + \n\nhttps://www.gnu.org/software/libidn\n(Apache License, Version 2.0) + \n\nhttps://github.com/ge0rg/MemorizingTrustManager\n(The MIT License (MIT)) + \n\nhttps://github.com/rtreffer/minidns\n(WTFPL) + \n\nhttps://github.com/open-keychain/openkeychain-api-lib\n(Apache License, Version 2.0) + \n\nhttps://github.com/jitsi/otr4j\n(LGPL-3.0) + \n\nhttps://developer.android.com/tools/support-library\n(Apache License, Version 2.0) + \n\nhttps://github.com/zxing/zxing\n(Apache License, Version 2.0) + + Stille uren + Begintijd + Eindtijd + Stille uren aanzetten + Tijdens stille uren worden meldingen onderdrukt + Vergroot lettergrootte + Gebruik grotere lettertypes over de hele app + Verstuur-knop toont status aan + Vraag ontvangstbevestigingen + Indien ondersteund, worden ontvangen berichten met een groen vinkje aangeduid + Kleur verstuur-knop in om status van contact weer te geven + Andere + Groepsgespreksnaam + Gebruik onderwerp van kamer ipv JID om groepsgesprekken te identificeren + OTR vingerafdruk naar klembord gekopieerd! + Je bent verbannen uit dit groepsgesprek + Dit groepsgesprek is enkel voor leden + Je bent uit dit groepsgesprek geschopt + account %s gebruiken + Afbeelding op HTTP host nakijken + De afbeelding is verwijderd + Je bent niet verbonden. Probeer later opnieuw + Bekijk bestandsgrootte van afbeelding + Berichtopties + Kopieer tekst + Deel afbeelding + Kopieer oorspronkelijke URL + Verstuur opnieuw + AfbeeldingsURL + Berichttekst + URL gekopieerd naar klembord + Bericht gekopieerd naar klembord + Versturen van afbeelding mislukt + Scan QR code + Toon QR code + Toon geblokkeerde contacten + Accountgegevens + Bevestig OTR + Externe vingerafdruk + scan + (of raak gsm's aan) + Socialist Millionaire Protocol + Hint of vraag + Gedeeld geheim + Bevestigen + Bezig + Antwoorden + Mislukt + Geheimen komen niet overeen + Opnieuw proberen + Afsluiten + Bevestigd! + Contact vraagt SMP-bevestiging + Geen geldige OTR-sessie gevonden! + Gesprekken + Raak aan om voorgrond-service uit te zetten + Hou service in voorgrond + Belet het besturingssysteem van je verbinding te onderbreken + Kies bestand + Ontvange van %1$s bestand (%2$d%% voltooid) + Download %s bestand + Open %s bestand + versturen (%1$d%% voltooid) + Bestand klaarmaken voor versturen + Bestand aangeboden om te downloaden + %s bestand + Annuleer bestandsoverdracht + bestandsoverdracht mislukt + Het bestand is verwijderd + Geen applicatie om bestand te openen + Kon vingerafdruk niet bevestigen + Handmatig bevestigen + Ben je zeker dat je de OTR-vingerafdruk van je contact wil bevestigen? + Toon dynamische tags + Toon enkel-lezen tags onder contacten + Meldingen aanzetten + Groepsgesprek aanmaken met… + Geen groepsgespreksserver gevonden + Aanmaken van groepsgesprek mislukt! + Groepsgesprek aangemaakt! + Geheim aanvaard! + Opnieuw instellen + Account-avatar + Kopieer OTR-vingerafdruk naar klembord + Geschiedenis van server halen + Geen verdere geschiedenis op server + Bijwerken… + Wachtwoord gewijzigd! + Kon wachtwoord niet wijzigen - \ No newline at end of file + -- cgit v1.2.3 From 164c41661ebc6827478f9933e088e14321d1d1fc Mon Sep 17 00:00:00 2001 From: sergio Date: Sat, 27 Dec 2014 13:04:37 +0100 Subject: Update spanish translations --- src/main/res/values-es/strings.xml | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index ca588707..f53d5368 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -13,6 +13,10 @@ Editar contacto Eliminar contacto de la lista Añadir a contactos del teléfono + Bloquear contacto + Desbloquear contacto + Bloquear dominio + Desbloquear dominio Gestionar Cuentas Ajustes Detalles de Conversación en grupo @@ -21,6 +25,7 @@ Compartir con Conversación Nueva Conversación Elegir Contacto + Lista contactos bloqueados ahora hace 1 min hace %d min @@ -34,8 +39,14 @@ Participante Visitante ¿Quieres eliminar a %s de tu lista? La conversación asociada a esta cuenta no se eliminará. + ¿Quieres bloquear a %s para que no pueda enviarte mensajes? + ¿Quieres desbloquear a %s y permitirle que te envíe mensajes? + ¿Bloquear todos los contactos de %s? + ¿Desbloquear todos los contatos de %s? + Contacto bloqueado ¿Quieres eliminar %s de tus marcadores? La conversación asociada con este marcador no se eliminará. Registrar nueva cuenta en servidor + Cambiar contraseña Compartir con Comenzar conversación Invitar contactos @@ -45,6 +56,8 @@ Añadir Editar Eliminar + Bloquear + Desbloquear Guardar OK Conversations se ha detenido. @@ -65,7 +78,7 @@ Limpiar historial de conversación ¿Quieres borrar todos los mensajes de esta conversación?\n\nAviso: Esto no afectará a los mensajes guardados en otros dispositivos o servidores. Borrar mensajes - Terminar esta conversación más tarde + Además, terminar esta conversación Selecciona recurso del contacto Enviar mensaje de texto Enviar mensaje cifrado con OTR @@ -174,11 +187,16 @@ Desconectado Conversación en grupo Otros Miembros + Información de servidor + XEP-0313: MAM XEP-0280: Message Carbons + XEP-0352: Client State Indication + XEP-0191: Blocking Command + XEP-0237: Roster Versioning XEP-0198: Stream Management XEP-0163: PEP (Avatars) - - No + Disponible + No disponible Se han perdido las claves de anuncio públicas Visto última vez ahora Visto última vez hace 1 minuto @@ -202,6 +220,8 @@ Unirse a Conversación en grupo Eliminar Contacto Ver detalles del contacto + Bloquear contacto + Desbloquear contacto Crear El contacto ya existe Unirse @@ -294,6 +314,7 @@ Falló la transferencia de la imagen Escanear código QR Mostrar código QR + Mostrar contactos bloqueados Detalles de la cuenta Verificar OTR Huella digital remota @@ -344,4 +365,7 @@ Copiar huella digital OTR al portapapeles Buscar historial en servidor No más historial del servidor + Actualizando… + !Contraseña cambiada! + No se puede cambiar la contraseña -- cgit v1.2.3 From 5a8391b539ec756b8251ad4ee6739268fa9dde0a Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Sun, 28 Dec 2014 19:48:01 -0500 Subject: Fix spelling in the docs Also rewrap at 80 chars (which looked to be what it was at in most places) --- docs/MISSION.md | 40 +++++++++++++++++------------------ docs/obeservations.md | 58 +++++++++++++++++++++++++-------------------------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/docs/MISSION.md b/docs/MISSION.md index 74399e74..5e867194 100644 --- a/docs/MISSION.md +++ b/docs/MISSION.md @@ -1,25 +1,25 @@ Conversations is a messenger for the next decade. Based on already established -internet standards that have been around for over ten years Coversations isn’t +internet standards that have been around for over ten years Conversations isn’t trying to replace current commercial messengers. It will simply outlive them. -Commercial, closed source products are coming and going. 15 years ago we had -ICQ which was replaced by Skype. MySpace was replaced by Facebook. WhatsApp and -Hangouts will disapear soon. Internet standards however stick around. People are -still using IRC and e-mail even though these protocols have been around for +Commercial, closed source products are coming and going. 15 years ago we had ICQ +which was replaced by Skype. MySpace was replaced by Facebook. WhatsApp and +Hangouts will disappear soon. Internet standards however stick around. People +are still using IRC and e-mail even though these protocols have been around for decades. Utilizing proven standards doesn’t mean one can not evolve. GMail has revolutionized the way we look at e-mail. Firefox and Chrome have changed the way we use the Web. Conversations will change the way we look at instant -messaging. Being less obstrusive than a telephone call instant messaging has -always played an importent role in modern society. Conversations will show that -instant messaging can be fast, relialbe and private. Conversations will not -force its security and privacey aspects upon the user. For those willing to use encryption -Conversations will make it as uncomplicated as possible. However Conversations -is aware that end-to-end encryption by the very principle isn’t trivial. Instead -of trying the impossible and making encryption easier than comparing a -fingerprint Conversations will try to educate the willing user and explain the -necessary steps and the reasons behind them. Those unwilling to learn about -encryption will still be protected by the design principals of Conversations. -Conversations will simply not share or generate certain information for example -by encouraging the use of federated servers. Conversations will always -utilize the best available standards for encryption and media encoding instead -of reinventing the wheel. However it isn’t afraid to break with behavior patterns -that have been proven ineffctive. +messaging. Being less obtrusive than a telephone call instant messaging has +always played an important role in modern society. Conversations will show that +instant messaging can be fast, reliable and private. Conversations will not +force its security and privacy aspects upon the user. For those willing to use +encryption Conversations will make it as uncomplicated as possible. However +Conversations is aware that end-to-end encryption by the very principle isn’t +trivial. Instead of trying the impossible and making encryption easier than +comparing a fingerprint Conversations will try to educate the willing user and +explain the necessary steps and the reasons behind them. Those unwilling to +learn about encryption will still be protected by the design principals of +Conversations. Conversations will simply not share or generate certain +information for example by encouraging the use of federated servers. +Conversations will always utilize the best available standards for encryption +and media encoding instead of reinventing the wheel. However it isn’t afraid to +break with behavior patterns that have been proven ineffective. diff --git a/docs/obeservations.md b/docs/obeservations.md index f4e4bf17..71502424 100644 --- a/docs/obeservations.md +++ b/docs/obeservations.md @@ -2,7 +2,7 @@ Observations on implementing XMPP ================================= After spending the last two and a half month basically writing my own XMPP library from scratch I decided to share some of the observations I made in the -process.. In part this article can be seen as a response to a blog post made by +process. In part this article can be seen as a response to a blog post made by Dr. Ing. Georg Lukas. The blog post introduces a couple of XEP (XMPP Extensions) which make the life on mobile devices a lot easier but states that they are currently very few implementations of those XEPs. So I went ahead and @@ -19,27 +19,27 @@ and straight forward. But then came the XEPs. ###Multi-User Chat The first one was XEP-0045 Multi-User Chat. This is the one XEP of the XEPs I’m going to mention in my article which is actually wildly adopted. Most clients -and servers I know of support MUC. However the level of completeness varies. +and servers I know of support MUC. However the level of completeness varies. MUC actually introduces access and permission roles which are far more complex than what some of us are used to from IRC but a lot of clients just don’t implement them. I’m not implementing them myself (at least for now) because I -somewhat doubt that someone would actually use them. (How ever this might be -some sort of chicken or egg problem.) I did find some strange bugs though which -might be interesting for other library developers. In theory a MUC server +somewhat doubt that someone would actually use them (however this might be some +sort of chicken or egg problem). I did find some strange bugs though which might +be interesting for other library developers. In theory a MUC server implementation can allow a single user (same jid) to join a conference room multiple times with the same nick from different clients. This means if someone wants to participate in a conference from two different devices (mobile and -desktop for example) one wouldn’t have to name oneself userDesktop and -userMobile but just user. Both ejabberd and prosody support this but with -strange side effects. prosody for example doesn’t allow a user to change its +desktop for example) one wouldn’t have to name oneself `userDesktop` and +`userMobile` but just `user`. Both ejabberd and prosody support this but with +strange side effects. Prosody for example doesn’t allow a user to change its name once two clients are “merged” by having the same nick. ###Carbons and Stream Management -Two of the other XEPs Lukas’ mentions - Carbons (XEP-0280) and Stream Management -(XEP-0198) - were actually fairly easy to implement. The only challenges were to -find a server to support them (I ended up running my own prosody server) and a -desktop client to test them with. For carbons there is a patched mcabber version -and gajim. After implementing stream management I had very good results on my +Two of the other XEPs Lukas mentions — Carbons (XEP-0280) and Stream Management +(XEP-0198) — were actually fairly easy to implement. The only challenges were to +find a server to support them (I ended up running my own Prosody server) and a +desktop client to test them with. For carbons there is a patched Mcabber version +and Gajim. After implementing stream management I had very good results on my mobile device. I had sessions running for up to 24 hours with a walking outside, loosing mobile coverage for a few minutes and so on. The only limitation was that I had to keep on developing and reinstalling my app. @@ -52,14 +52,14 @@ come to some sort of consent among XMPP developers to ultimately increase the interoperability. OTR has some down sides which make it difficult or at times even dangerous to implement within XMPP. First of all it is a synchronous protocol which is tunneled through a different protocol (XMPP). Synchronous -means - among other things - auto replies. (An OTR session begins with “hi I’m -speaking otr give me your key” “ok cool here is my key”) And auto replies - we -know that since the first time an out of office auto responder went postal - are +means — among other things — auto replies. (An OTR session begins with “hi I’m +speaking otr give me your key” “ok cool here is my key”) And auto replies — we +know that since the first time an out of office auto responder went postal — are dangerous. Things really start to get messy when you use one of the best -features of XMPP - multiple clients. The way XMPP works is that clients are +features of XMPP — multiple clients. The way XMPP works is that clients are encouraged to send their messages to the raw jid and let the server decide what full jid the messages are routed to. If in doubt even all of them. So what -happens when Alice sends a start-otr-message to Bobs raw jid? Bob receives the +happens when Alice sends a start-otr-message to Bobs raw jid? Bob receives the message on his notebook as well as his cell phone. Both of them answer. Alice gets two different replies. Shit explodes. Even if Alice sends the message to bob/notebook chances are that Bob has carbon messages enabled and still receives @@ -67,11 +67,11 @@ the messages on both devices. Now assuming that Bobs client is clever enough not to auto reply to carbonated messages Bob/cellphone will still end up with a lot of garbage messages. (Essentially the entire conversation between Alice and Bob/notebook but unreadable of course) Therefor it should be good practice to -tag OTR messages as both private and no-copy. (private is part of the carbons -XEP, no-copy is a general hint. I found that prosody for some reasons doesn’t +tag OTR messages as both private and no-copy (private is part of the carbons +XEP, no-copy is a general hint). I found that prosody for some reasons doesn’t honor the private tag on outgoing messages. While this is easily fixed I presume that having both the private and the no-copy tag will make it more compatible -with servers or clients I don’t know about yet) +with servers or clients I don’t know about yet. ####Rules to follow when implementing OTR To summarize my observations on implementing OTR in XMPP let me make the @@ -81,17 +81,17 @@ following three statements. and have the receiving server or user decide how they should be routed OTR messages must be send to a specific resource. To make this work the user should be given the option to select the presence (which can be assisted with some -educated guessing by the client based on previous messages). -Furthermore a client should encourage a user to choose meaningful presences -instead of the clients name or even random ones. Something like /mobile, -/notebook, /desktop is a greater assist to any one who wants to start an otr -session then /Gajim, /mcabber or /pidgin +educated guessing by the client based on previous messages). Furthermore a +client should encourage a user to choose meaningful presences instead of the +clients name or even random ones. Something like `/mobile`, `/notebook`, +`/desktop` is a greater assist to any one who wants to start an otr session then +`/Gajim`, `/mcabber` or `/pidgin`. 2. Messages should be tagged private and no-copy to avoid unnecessary traffic or otr error loops with faulty clients. This tagging should be done even if your own client doesn’t support carbons. -3. When dealing with “legacy clients” - meaning clients which don’t follow my -advise a client should be extra careful not to create message loops. This means -to not respond with otr errors if a client is not 100% sure it is the only +3. When dealing with “legacy clients” — meaning clients which don’t follow my +advise — a client should be extra careful not to create message loops. This +means to not respond with otr errors if a client is not 100% sure it is the only client which received the message -- cgit v1.2.3 From c50903036da32e2383871589b6a8999042d57160 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Mon, 29 Dec 2014 12:35:51 -0500 Subject: Rename observations doc file --- docs/obeservations.md | 97 --------------------------------------------------- docs/observations.md | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 97 deletions(-) delete mode 100644 docs/obeservations.md create mode 100644 docs/observations.md diff --git a/docs/obeservations.md b/docs/obeservations.md deleted file mode 100644 index 71502424..00000000 --- a/docs/obeservations.md +++ /dev/null @@ -1,97 +0,0 @@ -Observations on implementing XMPP -================================= -After spending the last two and a half month basically writing my own XMPP -library from scratch I decided to share some of the observations I made in the -process. In part this article can be seen as a response to a blog post made by -Dr. Ing. Georg Lukas. The blog post introduces a couple of XEP (XMPP Extensions) -which make the life on mobile devices a lot easier but states that they are -currently very few implementations of those XEPs. So I went ahead and -implemented all of them in my Android XMPP client. - -###General observations -The first thing I noticed is that XMPP is actually okish designed. If you were -to design a new chat protocol today you probably wouldn’t choose XML again -however the protocol basically consists of only three different packages which -are quickly hidden under some sort of abstraction layer within your library. -Getting from zero to sending messages to other users actually was very simple -and straight forward. But then came the XEPs. - -###Multi-User Chat -The first one was XEP-0045 Multi-User Chat. This is the one XEP of the XEPs I’m -going to mention in my article which is actually wildly adopted. Most clients -and servers I know of support MUC. However the level of completeness varies. -MUC actually introduces access and permission roles which are far more complex -than what some of us are used to from IRC but a lot of clients just don’t -implement them. I’m not implementing them myself (at least for now) because I -somewhat doubt that someone would actually use them (however this might be some -sort of chicken or egg problem). I did find some strange bugs though which might -be interesting for other library developers. In theory a MUC server -implementation can allow a single user (same jid) to join a conference room -multiple times with the same nick from different clients. This means if someone -wants to participate in a conference from two different devices (mobile and -desktop for example) one wouldn’t have to name oneself `userDesktop` and -`userMobile` but just `user`. Both ejabberd and prosody support this but with -strange side effects. Prosody for example doesn’t allow a user to change its -name once two clients are “merged” by having the same nick. - -###Carbons and Stream Management -Two of the other XEPs Lukas mentions — Carbons (XEP-0280) and Stream Management -(XEP-0198) — were actually fairly easy to implement. The only challenges were to -find a server to support them (I ended up running my own Prosody server) and a -desktop client to test them with. For carbons there is a patched Mcabber version -and Gajim. After implementing stream management I had very good results on my -mobile device. I had sessions running for up to 24 hours with a walking outside, -loosing mobile coverage for a few minutes and so on. The only limitation was -that I had to keep on developing and reinstalling my app. - -###Off the record -And then came OTR... This is were I spend the most time debugging stuff and -trying to get things right and compatible with other clients. This is the part -were I want to help other developers not to make the same mistakes and maybe -come to some sort of consent among XMPP developers to ultimately increase the -interoperability. OTR has some down sides which make it difficult or at times -even dangerous to implement within XMPP. First of all it is a synchronous -protocol which is tunneled through a different protocol (XMPP). Synchronous -means — among other things — auto replies. (An OTR session begins with “hi I’m -speaking otr give me your key” “ok cool here is my key”) And auto replies — we -know that since the first time an out of office auto responder went postal — are -dangerous. Things really start to get messy when you use one of the best -features of XMPP — multiple clients. The way XMPP works is that clients are -encouraged to send their messages to the raw jid and let the server decide what -full jid the messages are routed to. If in doubt even all of them. So what -happens when Alice sends a start-otr-message to Bobs raw jid? Bob receives the -message on his notebook as well as his cell phone. Both of them answer. Alice -gets two different replies. Shit explodes. Even if Alice sends the message to -bob/notebook chances are that Bob has carbon messages enabled and still receives -the messages on both devices. Now assuming that Bobs client is clever enough not -to auto reply to carbonated messages Bob/cellphone will still end up with a lot -of garbage messages. (Essentially the entire conversation between Alice and -Bob/notebook but unreadable of course) Therefor it should be good practice to -tag OTR messages as both private and no-copy (private is part of the carbons -XEP, no-copy is a general hint). I found that prosody for some reasons doesn’t -honor the private tag on outgoing messages. While this is easily fixed I presume -that having both the private and the no-copy tag will make it more compatible -with servers or clients I don’t know about yet. - -####Rules to follow when implementing OTR -To summarize my observations on implementing OTR in XMPP let me make the -following three statements. - -1. While it is good practice for unencrypted messages to be send to the raw jid -and have the receiving server or user decide how they should be routed OTR -messages must be send to a specific resource. To make this work the user should -be given the option to select the presence (which can be assisted with some -educated guessing by the client based on previous messages). Furthermore a -client should encourage a user to choose meaningful presences instead of the -clients name or even random ones. Something like `/mobile`, `/notebook`, -`/desktop` is a greater assist to any one who wants to start an otr session then -`/Gajim`, `/mcabber` or `/pidgin`. - -2. Messages should be tagged private and no-copy to avoid unnecessary traffic or -otr error loops with faulty clients. This tagging should be done even if your -own client doesn’t support carbons. - -3. When dealing with “legacy clients” — meaning clients which don’t follow my -advise — a client should be extra careful not to create message loops. This -means to not respond with otr errors if a client is not 100% sure it is the only -client which received the message diff --git a/docs/observations.md b/docs/observations.md new file mode 100644 index 00000000..71502424 --- /dev/null +++ b/docs/observations.md @@ -0,0 +1,97 @@ +Observations on implementing XMPP +================================= +After spending the last two and a half month basically writing my own XMPP +library from scratch I decided to share some of the observations I made in the +process. In part this article can be seen as a response to a blog post made by +Dr. Ing. Georg Lukas. The blog post introduces a couple of XEP (XMPP Extensions) +which make the life on mobile devices a lot easier but states that they are +currently very few implementations of those XEPs. So I went ahead and +implemented all of them in my Android XMPP client. + +###General observations +The first thing I noticed is that XMPP is actually okish designed. If you were +to design a new chat protocol today you probably wouldn’t choose XML again +however the protocol basically consists of only three different packages which +are quickly hidden under some sort of abstraction layer within your library. +Getting from zero to sending messages to other users actually was very simple +and straight forward. But then came the XEPs. + +###Multi-User Chat +The first one was XEP-0045 Multi-User Chat. This is the one XEP of the XEPs I’m +going to mention in my article which is actually wildly adopted. Most clients +and servers I know of support MUC. However the level of completeness varies. +MUC actually introduces access and permission roles which are far more complex +than what some of us are used to from IRC but a lot of clients just don’t +implement them. I’m not implementing them myself (at least for now) because I +somewhat doubt that someone would actually use them (however this might be some +sort of chicken or egg problem). I did find some strange bugs though which might +be interesting for other library developers. In theory a MUC server +implementation can allow a single user (same jid) to join a conference room +multiple times with the same nick from different clients. This means if someone +wants to participate in a conference from two different devices (mobile and +desktop for example) one wouldn’t have to name oneself `userDesktop` and +`userMobile` but just `user`. Both ejabberd and prosody support this but with +strange side effects. Prosody for example doesn’t allow a user to change its +name once two clients are “merged” by having the same nick. + +###Carbons and Stream Management +Two of the other XEPs Lukas mentions — Carbons (XEP-0280) and Stream Management +(XEP-0198) — were actually fairly easy to implement. The only challenges were to +find a server to support them (I ended up running my own Prosody server) and a +desktop client to test them with. For carbons there is a patched Mcabber version +and Gajim. After implementing stream management I had very good results on my +mobile device. I had sessions running for up to 24 hours with a walking outside, +loosing mobile coverage for a few minutes and so on. The only limitation was +that I had to keep on developing and reinstalling my app. + +###Off the record +And then came OTR... This is were I spend the most time debugging stuff and +trying to get things right and compatible with other clients. This is the part +were I want to help other developers not to make the same mistakes and maybe +come to some sort of consent among XMPP developers to ultimately increase the +interoperability. OTR has some down sides which make it difficult or at times +even dangerous to implement within XMPP. First of all it is a synchronous +protocol which is tunneled through a different protocol (XMPP). Synchronous +means — among other things — auto replies. (An OTR session begins with “hi I’m +speaking otr give me your key” “ok cool here is my key”) And auto replies — we +know that since the first time an out of office auto responder went postal — are +dangerous. Things really start to get messy when you use one of the best +features of XMPP — multiple clients. The way XMPP works is that clients are +encouraged to send their messages to the raw jid and let the server decide what +full jid the messages are routed to. If in doubt even all of them. So what +happens when Alice sends a start-otr-message to Bobs raw jid? Bob receives the +message on his notebook as well as his cell phone. Both of them answer. Alice +gets two different replies. Shit explodes. Even if Alice sends the message to +bob/notebook chances are that Bob has carbon messages enabled and still receives +the messages on both devices. Now assuming that Bobs client is clever enough not +to auto reply to carbonated messages Bob/cellphone will still end up with a lot +of garbage messages. (Essentially the entire conversation between Alice and +Bob/notebook but unreadable of course) Therefor it should be good practice to +tag OTR messages as both private and no-copy (private is part of the carbons +XEP, no-copy is a general hint). I found that prosody for some reasons doesn’t +honor the private tag on outgoing messages. While this is easily fixed I presume +that having both the private and the no-copy tag will make it more compatible +with servers or clients I don’t know about yet. + +####Rules to follow when implementing OTR +To summarize my observations on implementing OTR in XMPP let me make the +following three statements. + +1. While it is good practice for unencrypted messages to be send to the raw jid +and have the receiving server or user decide how they should be routed OTR +messages must be send to a specific resource. To make this work the user should +be given the option to select the presence (which can be assisted with some +educated guessing by the client based on previous messages). Furthermore a +client should encourage a user to choose meaningful presences instead of the +clients name or even random ones. Something like `/mobile`, `/notebook`, +`/desktop` is a greater assist to any one who wants to start an otr session then +`/Gajim`, `/mcabber` or `/pidgin`. + +2. Messages should be tagged private and no-copy to avoid unnecessary traffic or +otr error loops with faulty clients. This tagging should be done even if your +own client doesn’t support carbons. + +3. When dealing with “legacy clients” — meaning clients which don’t follow my +advise — a client should be extra careful not to create message loops. This +means to not respond with otr errors if a client is not 100% sure it is the only +client which received the message -- cgit v1.2.3 From b48bddb8526a9c5ed3433a67aa41aac1d928bd08 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Mon, 29 Dec 2014 14:21:20 -0500 Subject: Fix typo in method name --- src/main/java/eu/siacs/conversations/parser/IqParser.java | 4 ++-- .../java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java | 4 ++-- .../eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java | 2 +- .../eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java | 6 +++--- src/main/java/eu/siacs/conversations/xmpp/stanzas/IqPacket.java | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java index 5ed3b5b4..31006f0f 100644 --- a/src/main/java/eu/siacs/conversations/parser/IqParser.java +++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java @@ -141,12 +141,12 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { .discoResponse(packet); account.getXmppConnection().sendIqPacket(response, null); } else if (packet.hasChild("ping", "urn:xmpp:ping")) { - final IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT); + final IqPacket response = packet.generateResponse(IqPacket.TYPE_RESULT); mXmppConnectionService.sendIqPacket(account, response, null); } else { if ((packet.getType() == IqPacket.TYPE_GET) || (packet.getType() == IqPacket.TYPE_SET)) { - final IqPacket response = packet.generateRespone(IqPacket.TYPE_ERROR); + final IqPacket response = packet.generateResponse(IqPacket.TYPE_ERROR); final Element error = response.addChild("error"); error.setAttribute("type", "cancel"); error.addChild("feature-not-implemented", 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 3a1ba778..d578ca38 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -191,10 +191,10 @@ public class JingleConnection implements Downloadable { } IqPacket response; if (returnResult) { - response = packet.generateRespone(IqPacket.TYPE_RESULT); + response = packet.generateResponse(IqPacket.TYPE_RESULT); } else { - response = packet.generateRespone(IqPacket.TYPE_ERROR); + response = packet.generateResponse(IqPacket.TYPE_ERROR); } account.getXmppConnection().sendIqPacket(response, null); } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java index 72c960d8..b0a730b1 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java @@ -46,7 +46,7 @@ public class JingleConnectionManager extends AbstractConnectionManager { return; } } - IqPacket response = packet.generateRespone(IqPacket.TYPE_ERROR); + IqPacket response = packet.generateResponse(IqPacket.TYPE_ERROR); Element error = response.addChild("error"); error.setAttribute("type", "cancel"); error.addChild("item-not-found", diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java index 04b225d0..e25f7e65 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java @@ -208,15 +208,15 @@ public class JingleInbandTransport extends JingleTransport { established = true; connected = true; this.account.getXmppConnection().sendIqPacket( - packet.generateRespone(IqPacket.TYPE_RESULT), null); + packet.generateResponse(IqPacket.TYPE_RESULT), null); } else { this.account.getXmppConnection().sendIqPacket( - packet.generateRespone(IqPacket.TYPE_ERROR), null); + packet.generateResponse(IqPacket.TYPE_ERROR), null); } } else if (connected && payload.getName().equals("data")) { this.receiveNextBlock(payload.getContent()); this.account.getXmppConnection().sendIqPacket( - packet.generateRespone(IqPacket.TYPE_RESULT), null); + packet.generateResponse(IqPacket.TYPE_RESULT), null); } else { // TODO some sort of exception } diff --git a/src/main/java/eu/siacs/conversations/xmpp/stanzas/IqPacket.java b/src/main/java/eu/siacs/conversations/xmpp/stanzas/IqPacket.java index 9eff4cbf..2481112b 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/stanzas/IqPacket.java +++ b/src/main/java/eu/siacs/conversations/xmpp/stanzas/IqPacket.java @@ -67,7 +67,7 @@ public class IqPacket extends AbstractStanza { } } - public IqPacket generateRespone(final int type) { + public IqPacket generateResponse(final int type) { final IqPacket packet = new IqPacket(type); packet.setTo(this.getFrom()); packet.setId(this.getId()); -- cgit v1.2.3 From 800520b27b74183276e2487382a8c77be20a3208 Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Mon, 29 Dec 2014 23:08:07 +0100 Subject: Update Dutch translations --- src/main/res/values-nl/arrays.xml | 2 +- src/main/res/values-nl/strings.xml | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/res/values-nl/arrays.xml b/src/main/res/values-nl/arrays.xml index ad3fc6ea..e5ae27e7 100644 --- a/src/main/res/values-nl/arrays.xml +++ b/src/main/res/values-nl/arrays.xml @@ -5,7 +5,7 @@ Mobiel Telefoon Tablet - Conversaties + Conversations Android diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml index 32ffd4d5..6bd73f31 100644 --- a/src/main/res/values-nl/strings.xml +++ b/src/main/res/values-nl/strings.xml @@ -1,7 +1,7 @@ - Gesprekken + Conversations Instellingen Nieuw gesprek Beheer account @@ -60,8 +60,8 @@ Deblokkeer Sla op OK - Gesprekken is gecrasht - Door het versturen van crash rapportages help je de ontwikkeling van Gesprekken.\n\nWaarschuwing: Deze app zal je XMPP account gebruiken om de crash rapportages te versturen naar de ontwikkelaars. + Conversations is gecrasht + Door het versturen van crash rapportages help je de ontwikkeling van Conversations.\n\nWaarschuwing: Deze app zal je XMPP account gebruiken om de crash rapportages te versturen naar de ontwikkelaars. Nu versturen Niet opnieuw vragen Account verbinden mislukt @@ -89,15 +89,15 @@ Verstuur onversleuteld Ontsleutelen mislukt. Misschien heb je niet de juiste private sleutel. OpenKeychain - Gesprekken gebruikt een derde partij app genaamd OpenKeychain om berichten te versleutelen en ontsleutelen, en om publieke sleutels te beheren.\n\nOpenKeychain is beschikbaar onder de GPLv3 en beschikbaar op F-Droid en Google Play.\n\n(Herstart Gesprekken na installatie.) + Conversations gebruikt een derde partij app genaamd OpenKeychain om berichten te versleutelen en ontsleutelen, en om publieke sleutels te beheren.\n\nOpenKeychain is beschikbaar onder de GPLv3 en beschikbaar op F-Droid en Google Play.\n\n(Herstart Conversations na installatie.) Herstart Installeer offering… wachten… Geen OpenPGP sleutel gevonden - Gesprekken kan je berichten niet versleutelen omdat je contact geen publieke sleutel heeft ingesteld.\n\nVraag je contact om OpenPGP te configureren. + Conversations kan je berichten niet versleutelen omdat je contact geen publieke sleutel heeft ingesteld.\n\nVraag je contact om OpenPGP te configureren. Geen OpenPGP sleutels gevonden - Gesprekken kan je berichten niet versleutelen omdat je contacten geen publieke sleutel hebben ingesteld.\n\nVraag je contacten om OpenPGP te configureren. + Conversations kan je berichten niet versleutelen omdat je contacten geen publieke sleutel hebben ingesteld.\n\nVraag je contacten om OpenPGP te configureren. Versleuteld bericht ontvangen. Raak aan om te bekijken en te ontsleutelen. Versleutelde afbeelding ontvangen. Raak aan om te bekijken en te ontsleutelen. Afbeelding ontvangen. Raak aan om te bekijken. @@ -119,7 +119,7 @@ Zet meldingen voor korte tijd uit als er een carbon copy wordt ontvangen Geavanceerde instellingen Verstuur nooit crash rapportages - Door crash rapportages te versturen help je de ontwikkeling van Gesprekken + Door crash rapportages te versturen help je de ontwikkeling van Conversations Bevestig berichten Laat je contacten weten wanneer je berichten hebt ontvangen en gelezen UI opties @@ -277,7 +277,7 @@ Staat ondersteuning voor SSLv3 voor legacy servers toe. Waarschuwing: SSLv3 is niet veilig. Expert-instellingen Wees voorzichtig met deze instellingen - Over Gesprekken + Over Conversations Build en licentie-informatie Conversations • the very last word in instant messaging. @@ -357,7 +357,7 @@ Bevestigd! Contact vraagt SMP-bevestiging Geen geldige OTR-sessie gevonden! - Gesprekken + Conversations Raak aan om voorgrond-service uit te zetten Hou service in voorgrond Belet het besturingssysteem van je verbinding te onderbreken -- cgit v1.2.3 From 04de77261b6b6e26187c9f8c408083faa2728970 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 30 Dec 2014 01:13:35 +0100 Subject: fixed #818 --- src/main/java/eu/siacs/conversations/parser/IqParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java index 31006f0f..8e14936e 100644 --- a/src/main/java/eu/siacs/conversations/parser/IqParser.java +++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java @@ -72,7 +72,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { } public static boolean fromServer(final Account account, final IqPacket packet) { - return packet.getFrom() == null || packet.getFrom().equals(account.getServer()) || packet.getFrom().equals(account.getJid().toBareJid()); + return packet.getFrom() == null || packet.getFrom().equals(account.getServer()) || packet.getFrom().toBareJid().equals(account.getJid().toBareJid()); } @Override -- cgit v1.2.3 From c78dc5b494abb10c085715201e86094470a2b6e3 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 30 Dec 2014 01:15:12 +0100 Subject: fixed nl strings --- src/main/res/values-nl/strings.xml | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml index 6bd73f31..be3632da 100644 --- a/src/main/res/values-nl/strings.xml +++ b/src/main/res/values-nl/strings.xml @@ -279,30 +279,6 @@ Wees voorzichtig met deze instellingen Over Conversations Build en licentie-informatie - - Conversations • the very last word in instant messaging. - \n\nCopyright © 2014 Daniel Gultsch - \n\nThis program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - \n\nThis program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - \n\nYou should have received a copy of the GNU General Public License - along with this program. If not, see https://www.gnu.org/licenses - \n\nDownload the full source code at https://github.com/siacs/Conversations - \n\n\nLibraries - \n\nhttps://www.bouncycastle.org\n(The MIT License (MIT)) - \n\nhttps://www.gnu.org/software/libidn\n(Apache License, Version 2.0) - \n\nhttps://github.com/ge0rg/MemorizingTrustManager\n(The MIT License (MIT)) - \n\nhttps://github.com/rtreffer/minidns\n(WTFPL) - \n\nhttps://github.com/open-keychain/openkeychain-api-lib\n(Apache License, Version 2.0) - \n\nhttps://github.com/jitsi/otr4j\n(LGPL-3.0) - \n\nhttps://developer.android.com/tools/support-library\n(Apache License, Version 2.0) - \n\nhttps://github.com/zxing/zxing\n(Apache License, Version 2.0) - Stille uren Begintijd Eindtijd @@ -343,7 +319,7 @@ Bevestig OTR Externe vingerafdruk scan - (of raak gsm's aan) + (of raak gsm\'s aan) Socialist Millionaire Protocol Hint of vraag Gedeeld geheim -- cgit v1.2.3 From fb8737ed9f6b6c2947110a22b79430bd4affd706 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 30 Dec 2014 01:16:33 +0100 Subject: fixed npe in block menu item --- src/main/java/eu/siacs/conversations/ui/ConversationActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 5a9a208f..c4c3c354 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -318,7 +318,7 @@ public class ConversationActivity extends XmppActivity menuUnblock.setVisible(false); } final Account account = this.getSelectedConversation().getAccount(); - if (account.isOnlineAndConnected() || !account.getXmppConnection().getFeatures().blocking()) { + if (!(account.isOnlineAndConnected() && account.getXmppConnection().getFeatures().blocking())) { menuBlock.setVisible(false); menuUnblock.setVisible(false); } -- cgit v1.2.3 From 3c5d7d4f1b8af9568fdc7ba17f4c6d0a11167a4e Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 30 Dec 2014 01:17:11 +0100 Subject: refactor swithOverToTls stuff --- .../siacs/conversations/xmpp/XmppConnection.java | 101 +++++++++------------ 1 file changed, 45 insertions(+), 56 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index b03d3f74..0d65e547 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -505,65 +505,54 @@ public class XmppConnection implements Runnable { return getPreferences().getBoolean("enable_legacy_ssl", false); } - private void switchOverToTls(final Tag currentTag) throws XmlPullParserException, - IOException { - tagReader.readTag(); - try { - final SSLContext sc = SSLContext.getInstance("TLS"); - sc.init(null, - new X509TrustManager[]{this.mXmppConnectionService.getMemorizingTrustManager()}, - mXmppConnectionService.getRNG()); - final SSLSocketFactory factory = sc.getSocketFactory(); - - if (factory == null) { - throw new IOException("SSLSocketFactory was null"); - } - - final HostnameVerifier verifier = this.mXmppConnectionService.getMemorizingTrustManager().wrapHostnameVerifier(new StrictHostnameVerifier()); + private void switchOverToTls(final Tag currentTag) throws XmlPullParserException, IOException { + tagReader.readTag(); + try { + final SSLContext sc = SSLContext.getInstance("TLS"); + sc.init(null,new X509TrustManager[]{this.mXmppConnectionService.getMemorizingTrustManager()},mXmppConnectionService.getRNG()); + final SSLSocketFactory factory = sc.getSocketFactory(); + final HostnameVerifier verifier = this.mXmppConnectionService.getMemorizingTrustManager().wrapHostnameVerifier(new StrictHostnameVerifier()); + final InetAddress address = socket == null ? null : socket.getInetAddress(); + + if (factory == null || address == null || verifier == null) { + throw new IOException("could not setup ssl"); + } - if (socket == null || socket.isClosed()) { - throw new IOException("socket null or closed"); - } - final InetAddress address = socket.getInetAddress(); - if (address == null) { - throw new IOException("socket address was null"); - } + final SSLSocket sslSocket = (SSLSocket) factory.createSocket(socket,address.getHostAddress(), socket.getPort(),true); - final SSLSocket sslSocket = (SSLSocket) factory.createSocket(socket,address.getHostAddress(), socket.getPort(),true); + if (sslSocket == null) { + throw new IOException("could not initialize ssl socket"); + } - // Support all protocols except legacy SSL. - // The min SDK version prevents us having to worry about SSLv2. In - // future, this may be true of SSLv3 as well. - final String[] supportProtocols; - if (enableLegacySSL()) { - supportProtocols = sslSocket.getSupportedProtocols(); - } else { - final Collection supportedProtocols = new LinkedList<>( - Arrays.asList(sslSocket.getSupportedProtocols())); - supportedProtocols.remove("SSLv3"); - supportProtocols = new String[supportedProtocols.size()]; - supportedProtocols.toArray(supportProtocols); - } - sslSocket.setEnabledProtocols(supportProtocols); - - if (verifier != null - && !verifier.verify(account.getServer().getDomainpart(), - sslSocket.getSession())) { - Log.d(Config.LOGTAG,account.getJid().toBareJid()+": TLS certificate verification failed"); - disconnect(true); - changeStatus(Account.State.SECURITY_ERROR); - } - tagReader.setInputStream(sslSocket.getInputStream()); - tagWriter.setOutputStream(sslSocket.getOutputStream()); - sendStartStream(); - Log.d(Config.LOGTAG, account.getJid().toBareJid() - + ": TLS connection established"); - enabledEncryption = true; - processStream(tagReader.readTag()); - sslSocket.close(); - } catch (final NoSuchAlgorithmException | KeyManagementException e1) { - e1.printStackTrace(); - } + final String[] supportProtocols; + if (enableLegacySSL()) { + supportProtocols = sslSocket.getSupportedProtocols(); + } else { + final Collection supportedProtocols = new LinkedList<>( + Arrays.asList(sslSocket.getSupportedProtocols())); + supportedProtocols.remove("SSLv3"); + supportProtocols = new String[supportedProtocols.size()]; + supportedProtocols.toArray(supportProtocols); + } + sslSocket.setEnabledProtocols(supportProtocols); + + if (!verifier.verify(account.getServer().getDomainpart(),sslSocket.getSession())) { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": TLS certificate verification failed"); + disconnect(true); + changeStatus(Account.State.SECURITY_ERROR); + } + tagReader.setInputStream(sslSocket.getInputStream()); + tagWriter.setOutputStream(sslSocket.getOutputStream()); + sendStartStream(); + Log.d(Config.LOGTAG, account.getJid().toBareJid()+ ": TLS connection established"); + enabledEncryption = true; + processStream(tagReader.readTag()); + sslSocket.close(); + } catch (final NoSuchAlgorithmException | KeyManagementException e1) { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": TLS certificate verification failed"); + disconnect(true); + changeStatus(Account.State.SECURITY_ERROR); + } } private void processStreamFeatures(final Tag currentTag) -- cgit v1.2.3 From 0882da2568e8ca926cfcebbefe91adbfebe0e0d9 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Mon, 29 Dec 2014 19:09:27 -0500 Subject: Make `app_name' string untranslatable Remove untranslatable about message Escape single quote in NL translation --- src/main/res/values-ca/strings.xml | 3 +-- src/main/res/values-cs/strings.xml | 1 - src/main/res/values-de/strings.xml | 1 - src/main/res/values-es/strings.xml | 1 - src/main/res/values-eu/strings.xml | 1 - src/main/res/values-fr/strings.xml | 1 - src/main/res/values-gl/strings.xml | 3 +-- src/main/res/values-it/strings.xml | 1 - src/main/res/values-iw/strings.xml | 3 +-- src/main/res/values-nl/strings.xml | 1 - src/main/res/values-ru/strings.xml | 1 - src/main/res/values-sv/strings.xml | 3 +-- src/main/res/values-zh-rCN/strings.xml | 3 +-- src/main/res/values-zh-rTW/strings.xml | 3 +-- src/main/res/values/strings.xml | 4 ++-- 15 files changed, 8 insertions(+), 22 deletions(-) diff --git a/src/main/res/values-ca/strings.xml b/src/main/res/values-ca/strings.xml index cfbe428b..ae1da472 100644 --- a/src/main/res/values-ca/strings.xml +++ b/src/main/res/values-ca/strings.xml @@ -1,7 +1,6 @@ - Conversations Preferències Nova conversa Gestionar comptes @@ -80,4 +79,4 @@ Enviant traces d\'execució ajudes al futur desenvolupament del Conversations. Opcions de UI - \ No newline at end of file + diff --git a/src/main/res/values-cs/strings.xml b/src/main/res/values-cs/strings.xml index 9e955246..33c7310b 100644 --- a/src/main/res/values-cs/strings.xml +++ b/src/main/res/values-cs/strings.xml @@ -1,7 +1,6 @@ - Conversations Nastavení Nová konverzace Nastavení účtů diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index f959c382..06acfb6b 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -1,7 +1,6 @@ - Conversations Einstellungen Neue Unterhaltung Konten verwalten diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index f53d5368..d47a3adc 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -1,7 +1,6 @@ - Conversations Ajustes Nueva conversación Gestionar cuentas diff --git a/src/main/res/values-eu/strings.xml b/src/main/res/values-eu/strings.xml index 41f3793b..04388f4f 100644 --- a/src/main/res/values-eu/strings.xml +++ b/src/main/res/values-eu/strings.xml @@ -1,7 +1,6 @@  - Conversations Ezarpenak Elkarrizketa berria Kontuak kudeatu diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml index e1db316d..b3b86f1f 100644 --- a/src/main/res/values-fr/strings.xml +++ b/src/main/res/values-fr/strings.xml @@ -1,7 +1,6 @@ - Conversations Paramètres Nouvelle conversation Gérer les comptes diff --git a/src/main/res/values-gl/strings.xml b/src/main/res/values-gl/strings.xml index 58116463..637237b8 100644 --- a/src/main/res/values-gl/strings.xml +++ b/src/main/res/values-gl/strings.xml @@ -1,7 +1,6 @@ - Conversations Axustes Nova conversa Xestionar contas @@ -127,4 +126,4 @@ O identificador non é un identificador de Jabber válido Opcións de interfaz - \ No newline at end of file + diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml index 703dab9d..af4dc3e0 100644 --- a/src/main/res/values-it/strings.xml +++ b/src/main/res/values-it/strings.xml @@ -1,7 +1,6 @@ - Conversations Impostazioni Nuova conversazione Gestisci utenti diff --git a/src/main/res/values-iw/strings.xml b/src/main/res/values-iw/strings.xml index fd8eaa0b..79fe9f3a 100644 --- a/src/main/res/values-iw/strings.xml +++ b/src/main/res/values-iw/strings.xml @@ -1,7 +1,6 @@ - Conversations הגדרות דיון חדש נהל חשבונות @@ -221,4 +220,4 @@ שלח הודעה פרטית אל %s אפשרויות ממשק משתמש - \ No newline at end of file + diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml index be3632da..cb47ae97 100644 --- a/src/main/res/values-nl/strings.xml +++ b/src/main/res/values-nl/strings.xml @@ -1,7 +1,6 @@ - Conversations Instellingen Nieuw gesprek Beheer account diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml index 2aa26b0b..efc5ba6c 100644 --- a/src/main/res/values-ru/strings.xml +++ b/src/main/res/values-ru/strings.xml @@ -1,7 +1,6 @@ - Conversations Настройки Новая беседа Управление аккаунтами diff --git a/src/main/res/values-sv/strings.xml b/src/main/res/values-sv/strings.xml index a3ed9112..2c3cb9c3 100644 --- a/src/main/res/values-sv/strings.xml +++ b/src/main/res/values-sv/strings.xml @@ -1,7 +1,6 @@ - Conversations Inställningar Ny konversation Kontoinställningar @@ -257,4 +256,4 @@ Tillfälligt inaktiverad Inaktivera tillfälligt - \ No newline at end of file + diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml index a7898425..b3b9604e 100644 --- a/src/main/res/values-zh-rCN/strings.xml +++ b/src/main/res/values-zh-rCN/strings.xml @@ -1,7 +1,6 @@ - Conversations 设置 新会话 管理账户 @@ -257,4 +256,4 @@ 发送按钮显示状态 发送按钮采用其他颜色以示发送状态的区别 - \ No newline at end of file + diff --git a/src/main/res/values-zh-rTW/strings.xml b/src/main/res/values-zh-rTW/strings.xml index 2c3ea225..24872cf7 100644 --- a/src/main/res/values-zh-rTW/strings.xml +++ b/src/main/res/values-zh-rTW/strings.xml @@ -1,7 +1,6 @@ - Conversations 設定 新對話 管理帳戶 @@ -260,4 +259,4 @@ 群組名稱 使用群組的名稱而不是 JID 來識別之。 - \ No newline at end of file + diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index f75a698b..34c574ee 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -1,7 +1,7 @@ - Conversations + Conversations Settings New conversation Manage accounts @@ -279,7 +279,7 @@ Please be careful with these About Conversations Build and licensing information - + Conversations • the very last word in instant messaging. \n\nCopyright © 2014 Daniel Gultsch \n\nThis program is free software: you can redistribute it and/or modify -- cgit v1.2.3 From 8f93f9c314d1bf731eac64007f3c9459fa92de1f Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 30 Dec 2014 09:36:00 +0100 Subject: improved fromServer filter --- src/main/java/eu/siacs/conversations/parser/IqParser.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java index 8e14936e..e84545fc 100644 --- a/src/main/java/eu/siacs/conversations/parser/IqParser.java +++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java @@ -72,7 +72,10 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { } public static boolean fromServer(final Account account, final IqPacket packet) { - return packet.getFrom() == null || packet.getFrom().equals(account.getServer()) || packet.getFrom().toBareJid().equals(account.getJid().toBareJid()); + return packet.getFrom() == null + || packet.getFrom().equals(account.getServer()) + || packet.getFrom().equals(account.getJid().toBareJid()) + || packet.getFrom().equals(account.getJid()); } @Override -- cgit v1.2.3 From 3833e6dfef8c7a06982ad7783f89c28d27d83bfe Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 2 Jan 2015 01:21:14 +0100 Subject: improved OTR verification part one --- .../eu/siacs/conversations/crypto/OtrEngine.java | 6 +- .../eu/siacs/conversations/entities/Contact.java | 2 +- .../siacs/conversations/entities/Conversation.java | 31 +- .../conversations/persistance/DatabaseBackend.java | 6 +- .../conversations/ui/ContactDetailsActivity.java | 6 +- .../conversations/ui/ConversationActivity.java | 37 +++ .../conversations/ui/ConversationFragment.java | 20 +- .../siacs/conversations/ui/VerifyOTRActivity.java | 300 ++++++++++-------- .../java/eu/siacs/conversations/utils/XmppUri.java | 2 +- .../siacs/conversations/xmpp/XmppConnection.java | 4 +- src/main/res/layout/activity_verify_otr.xml | 334 +++++++++------------ src/main/res/values/strings.xml | 7 + 12 files changed, 403 insertions(+), 352 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/crypto/OtrEngine.java b/src/main/java/eu/siacs/conversations/crypto/OtrEngine.java index 3894e205..64434631 100644 --- a/src/main/java/eu/siacs/conversations/crypto/OtrEngine.java +++ b/src/main/java/eu/siacs/conversations/crypto/OtrEngine.java @@ -34,7 +34,7 @@ import net.java.otr4j.crypto.OtrCryptoException; import net.java.otr4j.session.InstanceTag; import net.java.otr4j.session.SessionID; -public class OtrEngine implements OtrEngineHost { +public class OtrEngine extends OtrCryptoEngineImpl implements OtrEngineHost { private Account account; private OtrPolicy otrPolicy; @@ -258,10 +258,10 @@ public class OtrEngine implements OtrEngineHost { Conversation conversation = this.mXmppConnectionService.find(this.account,jid); if (conversation!=null) { if (approved) { - conversation.getContact().addOtrFingerprint(CryptoHelper.prettifyFingerprint(fingerprint)); + conversation.getContact().addOtrFingerprint(fingerprint); } conversation.smp().hint = null; - conversation.smp().status = Conversation.Smp.STATUS_FINISHED; + conversation.smp().status = Conversation.Smp.STATUS_VERIFIED; mXmppConnectionService.updateConversationUi(); mXmppConnectionService.syncRosterToDisk(conversation.getAccount()); } diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java index af26981e..698e0322 100644 --- a/src/main/java/eu/siacs/conversations/entities/Contact.java +++ b/src/main/java/eu/siacs/conversations/entities/Contact.java @@ -453,7 +453,7 @@ public class Contact implements ListItem, Blockable { public String getShareableUri() { if (getOtrFingerprints().size() >= 1) { String otr = getOtrFingerprints().get(0); - return "xmpp:" + getJid().toBareJid().toString() + "?otr-fingerprint=" + otr.replace(" ", ""); + return "xmpp:" + getJid().toBareJid().toString() + "?otr-fingerprint=" + otr; } else { return "xmpp:" + getJid().toBareJid().toString(); } diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 1f9afa65..a88984fb 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -436,30 +436,29 @@ public class Conversation extends AbstractEntity implements Blockable { return this.otrSession != null; } - public String getOtrFingerprint() { + public synchronized String getOtrFingerprint() { if (this.otrFingerprint == null) { try { - if (getOtrSession() == null) { - return ""; + if (getOtrSession() == null || getOtrSession().getSessionStatus() != SessionStatus.ENCRYPTED) { + return null; } - DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession() - .getRemotePublicKey(); - StringBuilder builder = new StringBuilder( - new OtrCryptoEngineImpl().getFingerprint(remotePubKey)); - builder.insert(8, " "); - builder.insert(17, " "); - builder.insert(26, " "); - builder.insert(35, " "); - this.otrFingerprint = builder.toString(); + DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession().getRemotePublicKey(); + this.otrFingerprint = getAccount().getOtrEngine().getFingerprint(remotePubKey); } catch (final OtrCryptoException | UnsupportedOperationException ignored) { - + return null; } } return this.otrFingerprint; } - public void verifyOtrFingerprint() { - getContact().addOtrFingerprint(getOtrFingerprint()); + public boolean verifyOtrFingerprint() { + final String fingerprint = getOtrFingerprint(); + if (fingerprint != null) { + getContact().addOtrFingerprint(fingerprint); + return true; + } else { + return false; + } } public boolean isOtrFingerprintVerified() { @@ -708,7 +707,7 @@ public class Conversation extends AbstractEntity implements Blockable { public static final int STATUS_CONTACT_REQUESTED = 1; public static final int STATUS_WE_REQUESTED = 2; public static final int STATUS_FAILED = 3; - public static final int STATUS_FINISHED = 4; + public static final int STATUS_VERIFIED = 4; public String secret = null; public String hint = null; diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 7d29314b..5fa61491 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -22,7 +22,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { private static DatabaseBackend instance = null; private static final String DATABASE_NAME = "history"; - private static final int DATABASE_VERSION = 12; + private static final int DATABASE_VERSION = 13; private static String CREATE_CONTATCS_STATEMENT = "create table " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " @@ -126,6 +126,10 @@ public class DatabaseBackend extends SQLiteOpenHelper { db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.SERVER_MSG_ID + " TEXT"); } + if (oldVersion < 13 && newVersion >= 13) { + db.execSQL("delete from "+Contact.TABLENAME); + db.execSQL("update "+Account.TABLENAME+" set "+Account.ROSTERVERSION+" = NULL"); + } } public static synchronized DatabaseBackend getInstance(Context context) { diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java index b195f2f1..657ae75b 100644 --- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java @@ -37,6 +37,7 @@ import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.ListItem; import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; +import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.jid.InvalidJidException; @@ -315,7 +316,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd .findViewById(R.id.button_remove); remove.setVisibility(View.VISIBLE); keyType.setText("OTR Fingerprint"); - key.setText(otrFingerprint); + key.setText(CryptoHelper.prettifyFingerprint(otrFingerprint)); keys.addView(view); remove.setOnClickListener(new OnClickListener() { @@ -396,8 +397,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd public void onClick(DialogInterface dialog, int which) { if (contact.deleteOtrFingerprint(fingerprint)) { populateView(); - xmppConnectionService.syncRosterToDisk(contact - .getAccount()); + xmppConnectionService.syncRosterToDisk(contact.getAccount()); } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index c4c3c354..71074d3d 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -27,6 +27,8 @@ import android.widget.PopupMenu; import android.widget.PopupMenu.OnMenuItemClickListener; import android.widget.Toast; +import net.java.otr4j.session.SessionStatus; + import java.util.ArrayList; import java.util.List; @@ -555,6 +557,41 @@ public class ConversationActivity extends XmppActivity attachFilePopup.show(); } + public void verifyOtrSessionDialog(final Conversation conversation, View view) { + if (!conversation.hasValidOtrSession() || conversation.getOtrSession().getSessionStatus() != SessionStatus.ENCRYPTED) { + Toast.makeText(this, R.string.otr_session_not_started, Toast.LENGTH_LONG).show(); + return; + } + if (view == null) { + return; + } + PopupMenu popup = new PopupMenu(this, view); + popup.inflate(R.menu.verification_choices); + popup.setOnMenuItemClickListener(new OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem menuItem) { + Intent intent = new Intent(ConversationActivity.this, VerifyOTRActivity.class); + intent.setAction(VerifyOTRActivity.ACTION_VERIFY_CONTACT); + intent.putExtra("contact", conversation.getContact().getJid().toBareJid().toString()); + intent.putExtra("account", conversation.getAccount().getJid().toBareJid().toString()); + switch (menuItem.getItemId()) { + case R.id.scan_fingerprint: + intent.putExtra("mode",VerifyOTRActivity.MODE_SCAN_FINGERPRINT); + break; + case R.id.ask_question: + intent.putExtra("mode",VerifyOTRActivity.MODE_ASK_QUESTION); + break; + case R.id.manual_verification: + intent.putExtra("mode",VerifyOTRActivity.MODE_MANUAL_VERIFICATION); + break; + } + startActivity(intent); + return true; + } + }); + popup.show(); + } + protected void selectEncryptionDialog(final Conversation conversation) { View menuItemView = findViewById(R.id.action_security); if (menuItemView == null) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 39dfd4db..c3b47d76 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -204,13 +204,7 @@ public class ConversationFragment extends Fragment { @Override public void onClick(View v) { - if (conversation.getOtrFingerprint() != null) { - Intent intent = new Intent(getActivity(), VerifyOTRActivity.class); - intent.setAction(VerifyOTRActivity.ACTION_VERIFY_CONTACT); - intent.putExtra("contact", conversation.getContact().getJid().toBareJid().toString()); - intent.putExtra("account", conversation.getAccount().getJid().toBareJid().toString()); - startActivity(intent); - } + activity.verifyOtrSessionDialog(conversation,v); } }; private ConcurrentLinkedQueue mEncryptedMessages = new ConcurrentLinkedQueue<>(); @@ -796,7 +790,17 @@ public class ConversationFragment extends Fragment { protected void makeFingerprintWarning() { if (conversation.smpRequested()) { - showSnackbar(R.string.smp_requested, R.string.verify, clickToVerify); + showSnackbar(R.string.smp_requested, R.string.verify, new OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(activity, VerifyOTRActivity.class); + intent.setAction(VerifyOTRActivity.ACTION_VERIFY_CONTACT); + intent.putExtra("contact", conversation.getContact().getJid().toBareJid().toString()); + intent.putExtra("account", conversation.getAccount().getJid().toBareJid().toString()); + intent.putExtra("mode",VerifyOTRActivity.MODE_ANSWER_QUESTION); + startActivity(intent); + } + }); } else if (conversation.hasValidOtrSession() && (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!conversation.isOtrFingerprintVerified())) { showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify, clickToVerify); diff --git a/src/main/java/eu/siacs/conversations/ui/VerifyOTRActivity.java b/src/main/java/eu/siacs/conversations/ui/VerifyOTRActivity.java index e5775ab0..8fffbaac 100644 --- a/src/main/java/eu/siacs/conversations/ui/VerifyOTRActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/VerifyOTRActivity.java @@ -1,14 +1,15 @@ package eu.siacs.conversations.ui; +import android.app.ActionBar; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; @@ -32,57 +33,56 @@ import eu.siacs.conversations.xmpp.jid.Jid; public class VerifyOTRActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate { public static final String ACTION_VERIFY_CONTACT = "verify_contact"; + public static final int MODE_SCAN_FINGERPRINT = - 0x0502; + public static final int MODE_ASK_QUESTION = 0x0503; + public static final int MODE_ANSWER_QUESTION = 0x0504; + public static final int MODE_MANUAL_VERIFICATION = 0x0505; - private RelativeLayout mVerificationAreaOne; - private RelativeLayout mVerificationAreaTwo; - private TextView mErrorNoSession; - private TextView mRemoteJid; + private LinearLayout mManualVerificationArea; + private LinearLayout mSmpVerificationArea; private TextView mRemoteFingerprint; private TextView mYourFingerprint; - private EditText mSharedSecretHint; - private EditText mSharedSecretSecret; - private Button mButtonScanQrCode; - private Button mButtonShowQrCode; - private Button mButtonSharedSecretPositive; - private Button mButtonSharedSecretNegative; + private TextView mVerificationExplain; private TextView mStatusMessage; + private TextView mSharedSecretHint; + private EditText mSharedSecretHintEditable; + private EditText mSharedSecretSecret; + private Button mLeftButton; + private Button mRightButton; private Account mAccount; private Conversation mConversation; + private int mode = MODE_MANUAL_VERIFICATION; + private XmppUri mPendingUri = null; private DialogInterface.OnClickListener mVerifyFingerprintListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int click) { mConversation.verifyOtrFingerprint(); - updateView(); xmppConnectionService.syncRosterToDisk(mConversation.getAccount()); + Toast.makeText(VerifyOTRActivity.this,R.string.verified,Toast.LENGTH_SHORT).show(); + finish(); } }; - private View.OnClickListener mShowQrCodeListener = new View.OnClickListener() { - @Override - public void onClick(final View view) { - showQrCode(); - } - }; - - private View.OnClickListener mScanQrCodeListener = new View.OnClickListener() { - - @Override - public void onClick(View view) { - new IntentIntegrator(VerifyOTRActivity.this).initiateScan(); - } - - }; - private View.OnClickListener mCreateSharedSecretListener = new View.OnClickListener() { @Override public void onClick(final View view) { if (isAccountOnline()) { - final String question = mSharedSecretHint.getText().toString(); + final String question = mSharedSecretHintEditable.getText().toString(); final String secret = mSharedSecretSecret.getText().toString(); - initSmp(question, secret); - updateView(); + if (question.trim().isEmpty()) { + mSharedSecretHintEditable.requestFocus(); + mSharedSecretHintEditable.setError(getString(R.string.shared_secret_hint_should_not_be_empty)); + } else if (secret.trim().isEmpty()) { + mSharedSecretSecret.requestFocus(); + mSharedSecretSecret.setError(getString(R.string.shared_secret_can_not_be_empty)); + } else { + mSharedSecretSecret.setError(null); + mSharedSecretHintEditable.setError(null); + initSmp(question, secret); + updateView(); + } } } }; @@ -100,7 +100,7 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer @Override public void onClick(View view) { if (isAccountOnline()) { - final String question = mSharedSecretHint.getText().toString(); + final String question = mSharedSecretHintEditable.getText().toString(); final String secret = mSharedSecretSecret.getText().toString(); respondSmp(question, secret); updateView(); @@ -124,14 +124,14 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer } }; - private XmppUri mPendingUri = null; - protected boolean initSmp(final String question, final String secret) { final Session session = mConversation.getOtrSession(); if (session!=null) { try { session.initSmp(question, secret); mConversation.smp().status = Conversation.Smp.STATUS_WE_REQUESTED; + mConversation.smp().secret = secret; + mConversation.smp().hint = question; return true; } catch (OtrException e) { return false; @@ -172,15 +172,17 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer } } - protected void verifyWithUri(XmppUri uri) { + protected boolean verifyWithUri(XmppUri uri) { Contact contact = mConversation.getContact(); if (this.mConversation.getContact().getJid().equals(uri.getJid()) && uri.getFingerprint() != null) { contact.addOtrFingerprint(uri.getFingerprint()); Toast.makeText(this,R.string.verified,Toast.LENGTH_SHORT).show(); updateView(); xmppConnectionService.syncRosterToDisk(contact.getAccount()); + return true; } else { Toast.makeText(this,R.string.could_not_verify_fingerprint,Toast.LENGTH_SHORT).show(); + return false; } } @@ -194,7 +196,7 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer } protected boolean handleIntent(Intent intent) { - if (intent.getAction().equals(ACTION_VERIFY_CONTACT)) { + if (intent != null && intent.getAction().equals(ACTION_VERIFY_CONTACT)) { try { this.mAccount = this.xmppConnectionService.findAccountByJid(Jid.fromString(intent.getExtras().getString("account"))); } catch (final InvalidJidException ignored) { @@ -208,6 +210,11 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer } catch (final InvalidJidException ignored) { return false; } + this.mode = intent.getIntExtra("mode", MODE_MANUAL_VERIFICATION); + if (this.mode == MODE_SCAN_FINGERPRINT) { + new IntentIntegrator(this).initiateScan(); + return false; + } return true; } else { return false; @@ -223,9 +230,12 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer XmppUri uri = new XmppUri(data); if (xmppConnectionServiceBound) { verifyWithUri(uri); + finish(); } else { this.mPendingUri = uri; } + } else { + finish(); } } super.onActivityResult(requestCode, requestCode, intent); @@ -234,84 +244,139 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer @Override protected void onBackendConnected() { if (handleIntent(getIntent())) { - if (mPendingUri!=null) { - verifyWithUri(mPendingUri); - mPendingUri = null; - } updateView(); + } else if (mPendingUri!=null) { + verifyWithUri(mPendingUri); + finish(); + mPendingUri = null; } + setIntent(null); } protected void updateView() { if (this.mConversation.hasValidOtrSession()) { + final ActionBar actionBar = getActionBar(); + this.mVerificationExplain.setText(R.string.no_otr_session_found); invalidateOptionsMenu(); - this.mVerificationAreaOne.setVisibility(View.VISIBLE); - this.mVerificationAreaTwo.setVisibility(View.VISIBLE); - this.mErrorNoSession.setVisibility(View.GONE); - this.mYourFingerprint.setText(CryptoHelper.prettifyFingerprint(this.mAccount.getOtrFingerprint())); - this.mRemoteFingerprint.setText(this.mConversation.getOtrFingerprint()); - this.mRemoteJid.setText(this.mConversation.getContact().getJid().toBareJid().toString()); - Conversation.Smp smp = mConversation.smp(); - Session session = mConversation.getOtrSession(); - if (mConversation.isOtrFingerprintVerified()) { - deactivateButton(mButtonScanQrCode, R.string.verified); - } else { - activateButton(mButtonScanQrCode, R.string.scan_qr_code, mScanQrCodeListener); + switch(this.mode) { + case MODE_ASK_QUESTION: + if (actionBar != null ) { + actionBar.setTitle(R.string.ask_question); + } + this.updateViewAskQuestion(); + break; + case MODE_ANSWER_QUESTION: + if (actionBar != null ) { + actionBar.setTitle(R.string.smp_requested); + } + this.updateViewAnswerQuestion(); + break; + case MODE_MANUAL_VERIFICATION: + default: + if (actionBar != null ) { + actionBar.setTitle(R.string.manually_verify); + } + this.updateViewManualVerification(); + break; } - if (smp.status == Conversation.Smp.STATUS_NONE) { - activateButton(mButtonSharedSecretPositive, R.string.create, mCreateSharedSecretListener); - deactivateButton(mButtonSharedSecretNegative, R.string.cancel); - this.mSharedSecretHint.setFocusableInTouchMode(true); - this.mSharedSecretSecret.setFocusableInTouchMode(true); - this.mSharedSecretSecret.setText(""); - this.mSharedSecretHint.setText(""); - this.mSharedSecretHint.setVisibility(View.VISIBLE); - this.mSharedSecretSecret.setVisibility(View.VISIBLE); + } else { + this.mManualVerificationArea.setVisibility(View.GONE); + this.mSmpVerificationArea.setVisibility(View.GONE); + } + } + + protected void updateViewManualVerification() { + this.mVerificationExplain.setText(R.string.manual_verification_explanation); + this.mManualVerificationArea.setVisibility(View.VISIBLE); + this.mSmpVerificationArea.setVisibility(View.GONE); + this.mYourFingerprint.setText(CryptoHelper.prettifyFingerprint(this.mAccount.getOtrFingerprint())); + this.mRemoteFingerprint.setText(CryptoHelper.prettifyFingerprint(this.mConversation.getOtrFingerprint())); + if (this.mConversation.isOtrFingerprintVerified()) { + deactivateButton(this.mRightButton,R.string.verified); + activateButton(this.mLeftButton,R.string.cancel,this.mFinishListener); + } else { + activateButton(this.mLeftButton,R.string.cancel,this.mFinishListener); + activateButton(this.mRightButton,R.string.verify, new View.OnClickListener() { + @Override + public void onClick(View view) { + showManuallyVerifyDialog(); + } + }); + } + } + + protected void updateViewAskQuestion() { + this.mManualVerificationArea.setVisibility(View.GONE); + this.mSmpVerificationArea.setVisibility(View.VISIBLE); + this.mVerificationExplain.setText(R.string.smp_explain_question); + final int smpStatus = this.mConversation.smp().status; + switch (smpStatus) { + case Conversation.Smp.STATUS_WE_REQUESTED: this.mStatusMessage.setVisibility(View.GONE); - } else if (smp.status == Conversation.Smp.STATUS_CONTACT_REQUESTED) { - this.mSharedSecretHint.setFocusable(false); - this.mSharedSecretHint.setText(smp.hint); - this.mSharedSecretSecret.setFocusableInTouchMode(true); - this.mSharedSecretHint.setVisibility(View.VISIBLE); + this.mSharedSecretHintEditable.setVisibility(View.VISIBLE); this.mSharedSecretSecret.setVisibility(View.VISIBLE); + this.mSharedSecretHintEditable.setText(this.mConversation.smp().hint); + this.mSharedSecretSecret.setText(this.mConversation.smp().secret); + this.activateButton(this.mLeftButton, R.string.cancel, this.mCancelSharedSecretListener); + this.deactivateButton(this.mRightButton, R.string.in_progress); + break; + case Conversation.Smp.STATUS_FAILED: this.mStatusMessage.setVisibility(View.GONE); - deactivateButton(mButtonSharedSecretNegative, R.string.cancel); - activateButton(mButtonSharedSecretPositive, R.string.respond, mRespondSharedSecretListener); - } else if (smp.status == Conversation.Smp.STATUS_FAILED) { - activateButton(mButtonSharedSecretNegative, R.string.cancel, mFinishListener); - activateButton(mButtonSharedSecretPositive, R.string.try_again, mRetrySharedSecretListener); - this.mSharedSecretHint.setVisibility(View.GONE); + this.mSharedSecretHintEditable.setVisibility(View.VISIBLE); + this.mSharedSecretSecret.setVisibility(View.VISIBLE); + this.mSharedSecretSecret.requestFocus(); + this.mSharedSecretSecret.setError(getString(R.string.secrets_do_not_match)); + this.deactivateButton(this.mLeftButton, R.string.cancel); + this.activateButton(this.mRightButton, R.string.try_again, this.mRetrySharedSecretListener); + break; + case Conversation.Smp.STATUS_VERIFIED: + this.mSharedSecretHintEditable.setText(""); + this.mSharedSecretHintEditable.setVisibility(View.GONE); + this.mSharedSecretSecret.setText(""); this.mSharedSecretSecret.setVisibility(View.GONE); this.mStatusMessage.setVisibility(View.VISIBLE); - this.mStatusMessage.setText(R.string.secrets_do_not_match); - this.mStatusMessage.setTextColor(getWarningTextColor()); - } else if (smp.status == Conversation.Smp.STATUS_FINISHED) { - this.mSharedSecretHint.setText(""); + this.deactivateButton(this.mLeftButton, R.string.cancel); + this.activateButton(this.mRightButton, R.string.finish, this.mFinishListener); + break; + default: + this.mStatusMessage.setVisibility(View.GONE); + this.mSharedSecretHintEditable.setVisibility(View.VISIBLE); + this.mSharedSecretSecret.setVisibility(View.VISIBLE); + this.activateButton(this.mLeftButton,R.string.cancel,this.mFinishListener); + this.activateButton(this.mRightButton, R.string.ask_question, this.mCreateSharedSecretListener); + break; + } + } + + protected void updateViewAnswerQuestion() { + this.mManualVerificationArea.setVisibility(View.GONE); + this.mSmpVerificationArea.setVisibility(View.VISIBLE); + this.mVerificationExplain.setText(R.string.smp_explain_answer); + this.mSharedSecretHintEditable.setVisibility(View.GONE); + this.mSharedSecretHint.setVisibility(View.VISIBLE); + this.deactivateButton(this.mLeftButton, R.string.cancel); + final int smpStatus = this.mConversation.smp().status; + switch (smpStatus) { + case Conversation.Smp.STATUS_CONTACT_REQUESTED: + this.mStatusMessage.setVisibility(View.GONE); + this.mSharedSecretHint.setText(this.mConversation.smp().hint); + this.activateButton(this.mRightButton,R.string.respond,this.mRespondSharedSecretListener); + break; + case Conversation.Smp.STATUS_VERIFIED: + this.mSharedSecretHintEditable.setText(""); + this.mSharedSecretHintEditable.setVisibility(View.GONE); this.mSharedSecretHint.setVisibility(View.GONE); this.mSharedSecretSecret.setText(""); this.mSharedSecretSecret.setVisibility(View.GONE); this.mStatusMessage.setVisibility(View.VISIBLE); - this.mStatusMessage.setTextColor(getPrimaryColor()); - deactivateButton(mButtonSharedSecretNegative, R.string.cancel); - if (mConversation.isOtrFingerprintVerified()) { - activateButton(mButtonSharedSecretPositive, R.string.finish, mFinishListener); - this.mStatusMessage.setText(R.string.verified); - } else { - activateButton(mButtonSharedSecretPositive,R.string.reset,mRetrySharedSecretListener); - this.mStatusMessage.setText(R.string.secret_accepted); - } - } else if (session != null && session.isSmpInProgress()) { - deactivateButton(mButtonSharedSecretPositive, R.string.in_progress); - activateButton(mButtonSharedSecretNegative, R.string.cancel, mCancelSharedSecretListener); - this.mSharedSecretHint.setVisibility(View.VISIBLE); - this.mSharedSecretSecret.setVisibility(View.VISIBLE); - this.mSharedSecretHint.setFocusable(false); - this.mSharedSecretSecret.setFocusable(false); - } - } else { - this.mVerificationAreaOne.setVisibility(View.GONE); - this.mVerificationAreaTwo.setVisibility(View.GONE); - this.mErrorNoSession.setVisibility(View.VISIBLE); + this.activateButton(this.mRightButton, R.string.finish, this.mFinishListener); + break; + case Conversation.Smp.STATUS_FAILED: + default: + this.mSharedSecretSecret.requestFocus(); + this.mSharedSecretSecret.setError(getString(R.string.secrets_do_not_match)); + this.activateButton(this.mRightButton,R.string.finish,this.mFinishListener); + break; } } @@ -334,39 +399,16 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer super.onCreate(savedInstanceState); setContentView(R.layout.activity_verify_otr); this.mRemoteFingerprint = (TextView) findViewById(R.id.remote_fingerprint); - this.mRemoteJid = (TextView) findViewById(R.id.remote_jid); this.mYourFingerprint = (TextView) findViewById(R.id.your_fingerprint); - this.mButtonSharedSecretNegative = (Button) findViewById(R.id.button_shared_secret_negative); - this.mButtonSharedSecretPositive = (Button) findViewById(R.id.button_shared_secret_positive); - this.mButtonScanQrCode = (Button) findViewById(R.id.button_scan_qr_code); - this.mButtonShowQrCode = (Button) findViewById(R.id.button_show_qr_code); - this.mButtonShowQrCode.setOnClickListener(this.mShowQrCodeListener); + this.mLeftButton = (Button) findViewById(R.id.left_button); + this.mRightButton = (Button) findViewById(R.id.right_button); + this.mVerificationExplain = (TextView) findViewById(R.id.verification_explanation); + this.mStatusMessage = (TextView) findViewById(R.id.status_message); this.mSharedSecretSecret = (EditText) findViewById(R.id.shared_secret_secret); - this.mSharedSecretHint = (EditText) findViewById(R.id.shared_secret_hint); - this.mStatusMessage= (TextView) findViewById(R.id.status_message); - this.mVerificationAreaOne = (RelativeLayout) findViewById(R.id.verification_area_one); - this.mVerificationAreaTwo = (RelativeLayout) findViewById(R.id.verification_area_two); - this.mErrorNoSession = (TextView) findViewById(R.id.error_no_session); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.verify_otr, menu); - if (mConversation != null && mConversation.isOtrFingerprintVerified()) { - MenuItem manuallyVerifyItem = menu.findItem(R.id.manually_verify); - manuallyVerifyItem.setVisible(false); - } - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem menuItem) { - if (menuItem.getItemId() == R.id.manually_verify) { - showManuallyVerifyDialog(); - return true; - } else { - return super.onOptionsItemSelected(menuItem); - } + this.mSharedSecretHintEditable = (EditText) findViewById(R.id.shared_secret_hint_editable); + this.mSharedSecretHint = (TextView) findViewById(R.id.shared_secret_hint); + this.mManualVerificationArea = (LinearLayout) findViewById(R.id.manual_verification_area); + this.mSmpVerificationArea = (LinearLayout) findViewById(R.id.smp_verification_area); } private void showManuallyVerifyDialog() { diff --git a/src/main/java/eu/siacs/conversations/utils/XmppUri.java b/src/main/java/eu/siacs/conversations/utils/XmppUri.java index d7c3bce5..aacb6362 100644 --- a/src/main/java/eu/siacs/conversations/utils/XmppUri.java +++ b/src/main/java/eu/siacs/conversations/utils/XmppUri.java @@ -53,7 +53,7 @@ public class XmppUri { final String NEEDLE = "otr-fingerprint="; int index = query.indexOf(NEEDLE); if (index >= 0 && query.length() >= (NEEDLE.length() + index + 40)) { - return CryptoHelper.prettifyFingerprint(query.substring(index + NEEDLE.length(), index + NEEDLE.length() + 40)); + return query.substring(index + NEEDLE.length(), index + NEEDLE.length() + 40); } else { return null; } diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 0d65e547..c9a478d4 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -576,8 +576,8 @@ public class XmppConnection implements Runnable { auth.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl"); if (mechanisms.contains("SCRAM-SHA-1")) { saslMechanism = new ScramSha1(tagWriter, account, mXmppConnectionService.getRNG()); - } else if (mechanisms.contains("DIGEST-MD5")) { - saslMechanism = new DigestMd5(tagWriter, account, mXmppConnectionService.getRNG()); + //} else if (mechanisms.contains("DIGEST-MD5")) { + // saslMechanism = new DigestMd5(tagWriter, account, mXmppConnectionService.getRNG()); } else if (mechanisms.contains("PLAIN")) { saslMechanism = new Plain(tagWriter, account); } diff --git a/src/main/res/layout/activity_verify_otr.xml b/src/main/res/layout/activity_verify_otr.xml index 73539e0e..28e5e5ed 100644 --- a/src/main/res/layout/activity_verify_otr.xml +++ b/src/main/res/layout/activity_verify_otr.xml @@ -1,189 +1,147 @@ - - - - - - - - - - - - - - - - -