diff --git a/CHANGELOG.md b/CHANGELOG.md index b51386d29..fd5c26115 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +### Version 2.8.4 + +* Rework Login with certificate UI +* Add ability to pin chats on top (add to favorites) + ### Version 2.8.3 * Move call icon to the left in order to keep other toolbar icons in a consistent place diff --git a/build.gradle b/build.gradle index e1b4f3fe9..eb4cf02a5 100644 --- a/build.gradle +++ b/build.gradle @@ -67,7 +67,7 @@ dependencies { implementation 'com.makeramen:roundedimageview:2.3.0' implementation "com.wefika:flowlayout:0.4.1" implementation 'net.ypresto.androidtranscoder:android-transcoder:0.3.0' - implementation project(':libs:xmpp-addr') + implementation 'org.jxmpp:jxmpp-jid:0.6.4' implementation 'org.osmdroid:osmdroid-android:6.1.5' implementation 'org.hsluv:hsluv:0.2' implementation 'org.conscrypt:conscrypt-android:2.2.1' @@ -96,8 +96,8 @@ android { defaultConfig { minSdkVersion 16 targetSdkVersion 25 - versionCode 383 - versionName "2.8.3" + versionCode 387 + versionName "2.8.4" archivesBaseName += "-$versionName" applicationId "eu.sum7.conversations" resValue "string", "applicationId", applicationId diff --git a/libs/xmpp-addr/.gitignore b/libs/xmpp-addr/.gitignore deleted file mode 100644 index 796b96d1c..000000000 --- a/libs/xmpp-addr/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/libs/xmpp-addr/build.gradle b/libs/xmpp-addr/build.gradle deleted file mode 100644 index 2d30752c4..000000000 --- a/libs/xmpp-addr/build.gradle +++ /dev/null @@ -1,14 +0,0 @@ -apply plugin: 'java-library' - -repositories { - google() - jcenter() - mavenCentral() -} - -dependencies { - implementation 'rocks.xmpp:precis:1.0.0' -} - -sourceCompatibility = "8" -targetCompatibility = "8" diff --git a/libs/xmpp-addr/src/main/java/rocks/xmpp/addr/AbstractJid.java b/libs/xmpp-addr/src/main/java/rocks/xmpp/addr/AbstractJid.java deleted file mode 100644 index 963c3a491..000000000 --- a/libs/xmpp-addr/src/main/java/rocks/xmpp/addr/AbstractJid.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2014-2017 Christian Schudt - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package rocks.xmpp.addr; - -import java.text.Collator; -import java.util.Arrays; - -/** - * Abstract Jid implementation for both full and bare JIDs. - * - * @author Christian Schudt - */ -abstract class AbstractJid implements Jid { - - /** - * Checks if the JID is a full JID. - *
- *

The term "full JID" refers to an XMPP address of the form <localpart@domainpart/resourcepart> (for a particular authorized client or device associated with an account) or of the form <domainpart/resourcepart> (for a particular resource or script associated with a server).

- *
- * - * @return True, if the JID is a full JID; otherwise false. - */ - @Override - public final boolean isFullJid() { - return getResource() != null; - } - - /** - * Checks if the JID is a bare JID. - *
- *

The term "bare JID" refers to an XMPP address of the form <localpart@domainpart> (for an account at a server) or of the form <domainpart> (for a server).

- *
- * - * @return True, if the JID is a bare JID; otherwise false. - */ - @Override - public final boolean isBareJid() { - return getResource() == null; - } - - @Override - public final boolean isDomainJid() { - return getLocal() == null; - } - - @Override - public final boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof Jid)) { - return false; - } - Jid other = (Jid) o; - - return (getLocal() == other.getLocal() || getLocal() != null && getLocal().equals(other.getLocal())) - && (getDomain() == other.getDomain() || getDomain() != null && getDomain().equals(other.getDomain())) - && (getResource() == other.getResource() || getResource() != null && getResource().equals(other.getResource())); - } - - @Override - public final int hashCode() { - return Arrays.hashCode(new String[]{getLocal(), getDomain(), getResource()}); - } - - /** - * Compares this JID with another JID. First domain parts are compared. If these are equal, local parts are compared - * and if these are equal, too, resource parts are compared. - * - * @param o The other JID. - * @return The comparison result. - */ - @Override - public final int compareTo(Jid o) { - - if (this == o) { - return 0; - } - - if (o != null) { - final Collator collator = Collator.getInstance(); - int result; - // First compare domain parts. - if (getDomain() != null) { - result = o.getDomain() != null ? collator.compare(getDomain(), o.getDomain()) : -1; - } else { - result = o.getDomain() != null ? 1 : 0; - } - // If the domains are equal, compare local parts. - if (result == 0) { - if (getLocal() != null) { - // If this local part is not null, but the other is null, move this down (1). - result = o.getLocal() != null ? collator.compare(getLocal(), o.getLocal()) : 1; - } else { - // If this local part is null, but the other is not, move this up (-1). - result = o.getLocal() != null ? -1 : 0; - } - } - // If the local parts are equal, compare resource parts. - if (result == 0) { - if (getResource() != null) { - // If this resource part is not null, but the other is null, move this down (1). - return o.getResource() != null ? collator.compare(getResource(), o.getResource()) : 1; - } else { - // If this resource part is null, but the other is not, move this up (-1). - return o.getResource() != null ? -1 : 0; - } - } - return result; - } else { - return -1; - } - } - - @Override - public final int length() { - return toString().length(); - } - - @Override - public final char charAt(int index) { - return toString().charAt(index); - } - - @Override - public final CharSequence subSequence(int start, int end) { - return toString().subSequence(start, end); - } - - /** - * Returns the JID in its string representation, i.e. [ localpart "@" ] domainpart [ "/" resourcepart ]. - * - * @return The JID. - * @see #toEscapedString() - */ - @Override - public final String toString() { - return toString(getLocal(), getDomain(), getResource()); - } - - @Override - public final String toEscapedString() { - return toString(getEscapedLocal(), getDomain(), getResource()); - } - - static String toString(String local, String domain, String resource) { - StringBuilder sb = new StringBuilder(); - if (local != null) { - sb.append(local).append('@'); - } - sb.append(domain); - if (resource != null) { - sb.append('/').append(resource); - } - return sb.toString(); - } -} diff --git a/libs/xmpp-addr/src/main/java/rocks/xmpp/addr/FullJid.java b/libs/xmpp-addr/src/main/java/rocks/xmpp/addr/FullJid.java deleted file mode 100644 index 24130fd1b..000000000 --- a/libs/xmpp-addr/src/main/java/rocks/xmpp/addr/FullJid.java +++ /dev/null @@ -1,498 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2014-2017 Christian Schudt - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package rocks.xmpp.addr; - -import rocks.xmpp.precis.PrecisProfile; -import rocks.xmpp.precis.PrecisProfiles; -import rocks.xmpp.util.cache.LruCache; - -import java.net.IDN; -import java.nio.charset.Charset; -import java.text.Normalizer; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * The implementation of the JID as described in Extensible Messaging and Presence Protocol (XMPP): Address Format. - *

- * This class is thread-safe and immutable. - * - * @author Christian Schudt - * @see RFC 7622 - Extensible Messaging and Presence Protocol (XMPP): Address Format - */ -final class FullJid extends AbstractJid { - - /** - * Escapes all disallowed characters and also backslash, when followed by a defined hex code for escaping. See 4. Business Rules. - */ - private static final Pattern ESCAPE_PATTERN = Pattern.compile("[ \"&'/:<>@]|\\\\(?=20|22|26|27|2f|3a|3c|3e|40|5c)"); - - private static final Pattern UNESCAPE_PATTERN = Pattern.compile("\\\\(20|22|26|27|2f|3a|3c|3e|40|5c)"); - - private static final Pattern JID = Pattern.compile("^((.*?)@)?([^/@]+)(/(.*))?$"); - - private static final IDNProfile IDN_PROFILE = new IDNProfile(); - - /** - * Whenever dots are used as label separators, the following characters MUST be recognized as dots: U+002E (full stop), U+3002 (ideographic full stop), U+FF0E (fullwidth full stop), U+FF61 (halfwidth ideographic full stop). - */ - private static final String DOTS = "[.\u3002\uFF0E\uFF61]"; - - /** - * Label separators for domain labels, which should be mapped to "." (dot): IDEOGRAPHIC FULL STOP character (U+3002) - */ - private static final Pattern LABEL_SEPARATOR = Pattern.compile(DOTS); - - private static final Pattern LABEL_SEPARATOR_FINAL = Pattern.compile(DOTS + "$"); - - /** - * Caches the escaped JIDs. - */ - private static final Map ESCAPED_CACHE = new LruCache<>(5000); - - /** - * Caches the unescaped JIDs. - */ - private static final Map UNESCAPED_CACHE = new LruCache<>(5000); - - private static final long serialVersionUID = -3824234106101731424L; - - private final String escapedLocal; - - private final String local; - - private final String domain; - - private final String resource; - - private final Jid bareJid; - - /** - * Creates a full JID with local, domain and resource part. - * - * @param local The local part. - * @param domain The domain part. - * @param resource The resource part. - */ - FullJid(CharSequence local, CharSequence domain, CharSequence resource) { - this(local, domain, resource, false, null); - } - - private FullJid(final CharSequence local, final CharSequence domain, final CharSequence resource, final boolean doUnescape, Jid bareJid) { - final String enforcedLocalPart; - final String enforcedDomainPart; - final String enforcedResource; - - final String unescapedLocalPart; - - if (domain == null) { - throw new NullPointerException(); - } - - if (doUnescape) { - unescapedLocalPart = unescape(local); - } else { - unescapedLocalPart = local != null ? local.toString() : null; - } - - // Escape the local part, so that disallowed characters like the space characters pass the UsernameCaseMapped profile. - final String escapedLocalPart = escape(unescapedLocalPart); - - // If the domainpart includes a final character considered to be a label - // separator (dot) by [RFC1034], this character MUST be stripped from - // the domainpart before the JID of which it is a part is used for the - // purpose of routing an XML stanza, comparing against another JID, or - // constructing an XMPP URI or IRI [RFC5122]. In particular, such a - // character MUST be stripped before any other canonicalization steps - // are taken. - // Also validate, that the domain name can be converted to ASCII, i.e. validate the domain name (e.g. must not start with "_"). - final String strDomain = IDN.toASCII(LABEL_SEPARATOR_FINAL.matcher(domain).replaceAll(""), IDN.USE_STD3_ASCII_RULES); - enforcedLocalPart = escapedLocalPart != null ? PrecisProfiles.USERNAME_CASE_MAPPED.enforce(escapedLocalPart) : null; - enforcedResource = resource != null ? PrecisProfiles.OPAQUE_STRING.enforce(resource) : null; - // See https://tools.ietf.org/html/rfc5895#section-2 - enforcedDomainPart = IDN_PROFILE.enforce(strDomain); - - validateLength(enforcedLocalPart, "local"); - validateLength(enforcedResource, "resource"); - validateDomain(strDomain); - - this.local = unescape(enforcedLocalPart); - this.escapedLocal = enforcedLocalPart; - this.domain = enforcedDomainPart; - this.resource = enforcedResource; - if (bareJid != null) { - this.bareJid = bareJid; - } else { - this.bareJid = isBareJid() ? this : new AbstractJid() { - - @Override - public Jid asBareJid() { - return this; - } - - @Override - public Jid withLocal(CharSequence local) { - if (local == this.getLocal() || local != null && local.equals(this.getLocal())) { - return this; - } - return new FullJid(local, getDomain(), getResource(), false, null); - } - - @Override - public Jid withResource(CharSequence resource) { - if (resource == this.getResource() || resource != null && resource.equals(this.getResource())) { - return this; - } - return new FullJid(getLocal(), getDomain(), resource, false, asBareJid()); - } - - @Override - public Jid atSubdomain(CharSequence subdomain) { - if (subdomain == null) { - throw new NullPointerException(); - } - return new FullJid(getLocal(), subdomain + "." + getDomain(), getResource(), false, null); - } - - @Override - public String getLocal() { - return FullJid.this.getLocal(); - } - - @Override - public String getEscapedLocal() { - return FullJid.this.getEscapedLocal(); - } - - @Override - public String getDomain() { - return FullJid.this.getDomain(); - } - - @Override - public String getResource() { - return null; - } - }; - } - } - - /** - * Creates a JID from a string. The format must be - *

[ localpart "@" ] domainpart [ "/" resourcepart ]

- * - * @param jid The JID. - * @param doUnescape If the jid parameter will be unescaped. - * @return The JID. - * @throws NullPointerException If the jid is null. - * @throws IllegalArgumentException If the jid could not be parsed or is not valid. - * @see XEP-0106: JID Escaping - */ - static Jid of(String jid, final boolean doUnescape) { - if (jid == null) { - throw new NullPointerException("jid must not be null."); - } - - jid = jid.trim(); - - if (jid.isEmpty()) { - throw new IllegalArgumentException("jid must not be empty."); - } - - Jid result; - if (doUnescape) { - result = UNESCAPED_CACHE.get(jid); - } else { - result = ESCAPED_CACHE.get(jid); - } - - if (result != null) { - return result; - } - - Matcher matcher = JID.matcher(jid); - if (matcher.matches()) { - Jid jidValue = new FullJid(matcher.group(2), matcher.group(3), matcher.group(5), doUnescape, null); - if (doUnescape) { - UNESCAPED_CACHE.put(jid, jidValue); - } else { - ESCAPED_CACHE.put(jid, jidValue); - } - return jidValue; - } else { - throw new IllegalArgumentException("Could not parse JID: " + jid); - } - } - - /** - * Escapes a local part. The characters {@code "&'/:<>@} (+ whitespace) are replaced with their respective escape characters. - * - * @param localPart The local part. - * @return The escaped local part or null. - * @see XEP-0106: JID Escaping - */ - private static String escape(final CharSequence localPart) { - if (localPart != null) { - final Matcher matcher = ESCAPE_PATTERN.matcher(localPart); - final StringBuffer sb = new StringBuffer(); - while (matcher.find()) { - matcher.appendReplacement(sb, "\\\\" + Integer.toHexString(matcher.group().charAt(0))); - } - matcher.appendTail(sb); - return sb.toString(); - } - return null; - } - - private static String unescape(final CharSequence localPart) { - if (localPart != null) { - final Matcher matcher = UNESCAPE_PATTERN.matcher(localPart); - final StringBuffer sb = new StringBuffer(); - while (matcher.find()) { - final char c = (char) Integer.parseInt(matcher.group(1), 16); - if (c == '\\') { - matcher.appendReplacement(sb, "\\\\"); - } else { - matcher.appendReplacement(sb, String.valueOf(c)); - } - } - matcher.appendTail(sb); - return sb.toString(); - } - return null; - } - - private static void validateDomain(String domain) { - if (domain == null) { - throw new NullPointerException("domain must not be null."); - } - if (domain.contains("@")) { - // Prevent misuse of API. - throw new IllegalArgumentException("domain must not contain a '@' sign"); - } - validateLength(domain, "domain"); - } - - /** - * Validates that the length of a local, domain or resource part is not longer than 1023 characters. - * - * @param value The value. - * @param part The part, only used to produce an exception message. - */ - private static void validateLength(CharSequence value, CharSequence part) { - if (value != null) { - if (value.length() == 0) { - throw new IllegalArgumentException(part + " must not be empty."); - } - if (value.toString().getBytes(Charset.forName("UTF-8")).length > 1023) { - throw new IllegalArgumentException(part + " must not be greater than 1023 bytes."); - } - } - } - - /** - * Converts this JID into a bare JID, i.e. removes the resource part. - *
- *

The term "bare JID" refers to an XMPP address of the form <localpart@domainpart> (for an account at a server) or of the form <domainpart> (for a server).

- *
- * - * @return The bare JID. - * @see #withResource(CharSequence) - */ - @Override - public final Jid asBareJid() { - return bareJid; - } - - /** - * Gets the local part of the JID, also known as the name or node. - *
- *

3.3. Localpart

- *

The localpart of a JID is an optional identifier placed before the - * domainpart and separated from the latter by the '@' character. - * Typically, a localpart uniquely identifies the entity requesting and - * using network access provided by a server (i.e., a local account), - * although it can also represent other kinds of entities (e.g., a - * chatroom associated with a multi-user chat service [XEP-0045]). The - * entity represented by an XMPP localpart is addressed within the - * context of a specific domain (i.e., <localpart@domainpart>).

- *
- * - * @return The local part or null. - */ - @Override - public final String getLocal() { - return local; - } - - @Override - public final String getEscapedLocal() { - return escapedLocal; - } - - /** - * Gets the domain part. - *
- *

3.2. Domainpart

- *

The domainpart is the primary identifier and is the only REQUIRED - * element of a JID (a mere domainpart is a valid JID). Typically, - * a domainpart identifies the "home" server to which clients connect - * for XML routing and data management functionality.

- *
- * - * @return The domain part. - */ - @Override - public final String getDomain() { - return domain; - } - - /** - * Gets the resource part. - *
- *

3.4. Resourcepart

- *

The resourcepart of a JID is an optional identifier placed after the - * domainpart and separated from the latter by the '/' character. A - * resourcepart can modify either a <localpart@domainpart> address or a - * mere <domainpart> address. Typically, a resourcepart uniquely - * identifies a specific connection (e.g., a device or location) or - * object (e.g., an occupant in a multi-user chatroom [XEP-0045]) - * belonging to the entity associated with an XMPP localpart at a domain - * (i.e., <localpart@domainpart/resourcepart>).

- *
- * - * @return The resource part or null. - */ - @Override - public final String getResource() { - return resource; - } - - /** - * Creates a new JID with a new local part and the same domain and resource part of the current JID. - * - * @param local The local part. - * @return The JID with a new local part. - * @throws IllegalArgumentException If the local is not a valid local part. - * @see #withResource(CharSequence) - */ - @Override - public final Jid withLocal(CharSequence local) { - if (local == this.getLocal() || local != null && local.equals(this.getLocal())) { - return this; - } - return new FullJid(local, getDomain(), getResource(), false, null); - } - - /** - * Creates a new full JID with a resource and the same local and domain part of the current JID. - * - * @param resource The resource. - * @return The full JID with a resource. - * @throws IllegalArgumentException If the resource is not a valid resource part. - * @see #asBareJid() - * @see #withLocal(CharSequence) - */ - @Override - public final Jid withResource(CharSequence resource) { - if (resource == this.getResource() || resource != null && resource.equals(this.getResource())) { - return this; - } - return new FullJid(getLocal(), getDomain(), resource, false, asBareJid()); - } - - /** - * Creates a new JID at a subdomain and at the same domain as this JID. - * - * @param subdomain The subdomain. - * @return The JID at a subdomain. - * @throws NullPointerException If subdomain is null. - * @throws IllegalArgumentException If subdomain is not a valid subdomain name. - */ - @Override - public final Jid atSubdomain(CharSequence subdomain) { - if (subdomain != null) { - throw new NullPointerException(); - } - return new FullJid(getLocal(), subdomain + "." + getDomain(), getResource(), false, null); - } - - /** - * A profile for applying the rules for IDN as in RFC 5895. Although IDN doesn't use Precis, it's still very similar so that we can use the base class. - * - * @see RFC 5895 - */ - private static final class IDNProfile extends PrecisProfile { - - private IDNProfile() { - super(false); - } - - @Override - public String prepare(CharSequence input) { - return IDN.toUnicode(input.toString(), IDN.USE_STD3_ASCII_RULES); - } - - @Override - public String enforce(CharSequence input) { - // 4. Map IDEOGRAPHIC FULL STOP character (U+3002) to dot. - return applyAdditionalMappingRule( - // 3. All characters are mapped using Unicode Normalization Form C (NFC). - applyNormalizationRule( - // 2. Fullwidth and halfwidth characters (those defined with - // Decomposition Types and ) are mapped to their - // decomposition mappings - applyWidthMappingRule( - // 1. Uppercase characters are mapped to their lowercase equivalents - applyCaseMappingRule(prepare(input))))).toString(); - } - - @Override - protected CharSequence applyWidthMappingRule(CharSequence charSequence) { - return widthMap(charSequence); - } - - @Override - protected CharSequence applyAdditionalMappingRule(CharSequence charSequence) { - return LABEL_SEPARATOR.matcher(charSequence).replaceAll("."); - } - - @Override - protected CharSequence applyCaseMappingRule(CharSequence charSequence) { - return charSequence.toString().toLowerCase(); - } - - @Override - protected CharSequence applyNormalizationRule(CharSequence charSequence) { - return Normalizer.normalize(charSequence, Normalizer.Form.NFC); - } - - @Override - protected CharSequence applyDirectionalityRule(CharSequence charSequence) { - return charSequence; - } - } -} diff --git a/libs/xmpp-addr/src/main/java/rocks/xmpp/addr/Jid.java b/libs/xmpp-addr/src/main/java/rocks/xmpp/addr/Jid.java deleted file mode 100644 index 4f4b041e7..000000000 --- a/libs/xmpp-addr/src/main/java/rocks/xmpp/addr/Jid.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2014-2017 Christian Schudt - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package rocks.xmpp.addr; - -import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import java.io.Serializable; - -/** - * Represents the JID as described in Extensible Messaging and Presence Protocol (XMPP): Address Format. - *

- * A JID consists of three parts: - *

- * [ localpart "@" ] domainpart [ "/" resourcepart ] - *

- * The easiest way to create a JID is to use the {@link #of(CharSequence)} method: - * ```java - * Jid jid = Jid.of("juliet@capulet.lit/balcony"); - * ``` - * You can then get the parts from it via the respective methods: - * ```java - * String local = jid.getLocal(); // juliet - * String domain = jid.getDomain(); // capulet.lit - * String resource = jid.getResource(); // balcony - * ``` - * Implementations of this interface should override equals() and hashCode(), so that different instances with the same value are equal: - * ```java - * Jid.of("romeo@capulet.lit/balcony").equals(Jid.of("romeo@capulet.lit/balcony")); // true - * ``` - * The default implementation of this class also supports XEP-0106: JID Escaping, i.e. - * ```java - * Jid.of("d'artagnan@musketeers.lit") - * ``` - * is escaped as d\\27artagnan@musketeers.lit. - *

- * Implementations of this interface should be thread-safe and immutable. - * - * @author Christian Schudt - * @see RFC 7622 - Extensible Messaging and Presence Protocol (XMPP): Address Format - */ -public interface Jid extends Comparable, Serializable, CharSequence { - - /** - * The maximal length of a full JID, which is 3071. - *

- *

3.1. Fundamentals

- *

Each allowable portion of a JID (localpart, domainpart, and - * resourcepart) is 1 to 1023 octets in length, resulting in a maximum - * total size (including the '@' and '/' separators) of 3071 octets. - *

- *
- * Note that the length is based on bytes, not characters. - * - * @see #MAX_BARE_JID_LENGTH - */ - int MAX_FULL_JID_LENGTH = 3071; - - /** - * The maximal length of a bare JID, which is 2047 (1023 + 1 + 1023). - * Note that the length is based on bytes, not characters. - * - * @see #MAX_FULL_JID_LENGTH - */ - int MAX_BARE_JID_LENGTH = 2047; - - /** - * The service discovery feature used for determining support of JID escaping (jid\20escaping). - */ - String ESCAPING_FEATURE = "jid\\20escaping"; - - /** - * Returns a full JID with a domain and resource part, e.g. capulet.com/balcony - * - * @param local The local part. - * @param domain The domain. - * @param resource The resource part. - * @return The JID. - * @throws NullPointerException If the domain is null. - * @throws IllegalArgumentException If the domain, local or resource part are not valid. - */ - static Jid of(CharSequence local, CharSequence domain, CharSequence resource) { - return new FullJid(local, domain, resource); - } - - /** - * Creates a bare JID with only the domain part, e.g. capulet.com - * - * @param domain The domain. - * @return The JID. - * @throws NullPointerException If the domain is null. - * @throws IllegalArgumentException If the domain or local part are not valid. - */ - static Jid ofDomain(CharSequence domain) { - return new FullJid(null, domain, null); - } - - /** - * Creates a bare JID with a local and domain part, e.g. juliet@capulet.com - * - * @param local The local part. - * @param domain The domain. - * @return The JID. - * @throws NullPointerException If the domain is null. - * @throws IllegalArgumentException If the domain or local part are not valid. - */ - static Jid ofLocalAndDomain(CharSequence local, CharSequence domain) { - return new FullJid(local, domain, null); - } - - /** - * Creates a full JID with a domain and resource part, e.g. capulet.com/balcony - * - * @param domain The domain. - * @param resource The resource part. - * @return The JID. - * @throws NullPointerException If the domain is null. - * @throws IllegalArgumentException If the domain or resource are not valid. - */ - static Jid ofDomainAndResource(CharSequence domain, CharSequence resource) { - return new FullJid(null, domain, resource); - } - - /** - * Creates a JID from an unescaped string. The format must be - *

[ localpart "@" ] domainpart [ "/" resourcepart ]

- * The input string will be escaped. - * - * @param jid The JID. - * @return The JID. - * @throws NullPointerException If the jid is null. - * @throws IllegalArgumentException If the jid could not be parsed or is not valid. - * @see XEP-0106: JID Escaping - */ - static Jid of(CharSequence jid) { - if (jid instanceof Jid) { - return (Jid) jid; - } - return FullJid.of(jid.toString(), false); - } - - /** - * Creates a JID from a escaped JID string. The format must be - *

[ localpart "@" ] domainpart [ "/" resourcepart ]

- * This method should be used, when parsing JIDs from the XMPP stream. - * - * @param jid The JID. - * @return The JID. - * @throws NullPointerException If the jid is null. - * @throws IllegalArgumentException If the jid could not be parsed or is not valid. - * @see XEP-0106: JID Escaping - */ - static Jid ofEscaped(CharSequence jid) { - return FullJid.of(jid.toString(), true); - } - - /** - * Checks if the JID is a full JID. - *
- *

The term "full JID" refers to an XMPP address of the form <localpart@domainpart/resourcepart> (for a particular authorized client or device associated with an account) or of the form <domainpart/resourcepart> (for a particular resource or script associated with a server).

- *
- * - * @return True, if the JID is a full JID; otherwise false. - */ - boolean isFullJid(); - - /** - * Checks if the JID is a bare JID. - *
- *

The term "bare JID" refers to an XMPP address of the form <localpart@domainpart> (for an account at a server) or of the form <domainpart> (for a server).

- *
- * - * @return True, if the JID is a bare JID; otherwise false. - */ - boolean isBareJid(); - - /** - * Checks if the JID is a domain JID, i.e. if it has no local part. - * - * @return True, if the JID is a domain JID, i.e. if it has no local part. - */ - boolean isDomainJid(); - - /** - * Gets the bare JID representation of this JID, i.e. removes the resource part. - *
- *

The term "bare JID" refers to an XMPP address of the form <localpart@domainpart> (for an account at a server) or of the form <domainpart> (for a server).

- *
- * - * @return The bare JID. - * @see #withResource(CharSequence) - */ - Jid asBareJid(); - - /** - * Creates a new JID with a new local part and the same domain and resource part of the current JID. - * - * @param local The local part. - * @return The JID with a new local part. - * @throws IllegalArgumentException If the local is not a valid local part. - * @see #withResource(CharSequence) - */ - Jid withLocal(CharSequence local); - - /** - * Creates a new full JID with a resource and the same local and domain part of the current JID. - * - * @param resource The resource. - * @return The full JID with a resource. - * @throws IllegalArgumentException If the resource is not a valid resource part. - * @see #asBareJid() - * @see #withLocal(CharSequence) - */ - Jid withResource(CharSequence resource); - - /** - * Creates a new JID at a subdomain and at the same domain as this JID. - * - * @param subdomain The subdomain. - * @return The JID at a subdomain. - * @throws NullPointerException If subdomain is null. - * @throws IllegalArgumentException If subdomain is not a valid subdomain name. - */ - Jid atSubdomain(CharSequence subdomain); - - /** - * Gets the local part of the JID, also known as the name or node. - *
- *

3.3. Localpart

- *

The localpart of a JID is an optional identifier placed before the - * domainpart and separated from the latter by the '@' character. - * Typically, a localpart uniquely identifies the entity requesting and - * using network access provided by a server (i.e., a local account), - * although it can also represent other kinds of entities (e.g., a - * chatroom associated with a multi-user chat service [XEP-0045]). The - * entity represented by an XMPP localpart is addressed within the - * context of a specific domain (i.e., <localpart@domainpart>).

- *
- * - * @return The local part or null. - * @see #getEscapedLocal() - */ - String getLocal(); - - /** - * Gets the escaped local part of the JID. - * - * @return The escaped local part or null. - * @see #getLocal() - * @since 0.8.0 - */ - String getEscapedLocal(); - - /** - * Gets the domain part. - *
- *

3.2. Domainpart

- *

The domainpart is the primary identifier and is the only REQUIRED - * element of a JID (a mere domainpart is a valid JID). Typically, - * a domainpart identifies the "home" server to which clients connect - * for XML routing and data management functionality.

- *
- * - * @return The domain part. - */ - String getDomain(); - - /** - * Gets the resource part. - *
- *

3.4. Resourcepart

- *

The resourcepart of a JID is an optional identifier placed after the - * domainpart and separated from the latter by the '/' character. A - * resourcepart can modify either a <localpart@domainpart> address or a - * mere <domainpart> address. Typically, a resourcepart uniquely - * identifies a specific connection (e.g., a device or location) or - * object (e.g., an occupant in a multi-user chatroom [XEP-0045]) - * belonging to the entity associated with an XMPP localpart at a domain - * (i.e., <localpart@domainpart/resourcepart>).

- *
- * - * @return The resource part or null. - */ - String getResource(); - - /** - * Returns the JID in escaped form as described in XEP-0106: JID Escaping. - * - * @return The escaped JID. - * @see #toString() - */ - String toEscapedString(); -} diff --git a/libs/xmpp-addr/src/main/java/rocks/xmpp/addr/MalformedJid.java b/libs/xmpp-addr/src/main/java/rocks/xmpp/addr/MalformedJid.java deleted file mode 100644 index f8605bfc1..000000000 --- a/libs/xmpp-addr/src/main/java/rocks/xmpp/addr/MalformedJid.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2014-2017 Christian Schudt - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package rocks.xmpp.addr; - -/** - * Represents a malformed JID in order to handle the jid-malformed error. - *

- * This class is not intended to be publicly instantiable, but is used for malformed JIDs during parsing automatically. - * - * @author Christian Schudt - * @see RFC 6120, 8.3.3.8. jid-malformed - */ -public final class MalformedJid extends AbstractJid { - - private static final long serialVersionUID = -2896737611021417985L; - - private final String localPart; - - private final String domainPart; - - private final String resourcePart; - - private final Throwable cause; - - static MalformedJid of(final String jid, final Throwable cause) { - // Do some basic parsing without any further checks or validation. - final StringBuilder sb = new StringBuilder(jid); - // 1. Remove any portion from the first '/' character to the end of the - // string (if there is a '/' character present). - final int indexOfResourceDelimiter = jid.indexOf('/'); - final String resourcePart; - if (indexOfResourceDelimiter > -1) { - resourcePart = sb.substring(indexOfResourceDelimiter + 1); - sb.delete(indexOfResourceDelimiter, sb.length()); - } else { - resourcePart = null; - } - // 2. Remove any portion from the beginning of the string to the first - // '@' character (if there is an '@' character present). - final int indexOfAt = jid.indexOf('@'); - final String localPart; - if (indexOfAt > -1) { - localPart = sb.substring(0, indexOfAt); - sb.delete(0, indexOfAt + 1); - } else { - localPart = null; - } - return new MalformedJid(localPart, sb.toString(), resourcePart, cause); - } - - private MalformedJid(final String localPart, final String domainPart, final String resourcePart, final Throwable cause) { - this.localPart = localPart; - this.domainPart = domainPart; - this.resourcePart = resourcePart; - this.cause = cause; - } - - @Override - public final Jid asBareJid() { - return new MalformedJid(localPart, domainPart, null, cause); - } - - @Override - public Jid withLocal(CharSequence local) { - return new MalformedJid(local.toString(), domainPart, resourcePart, cause); - } - - @Override - public Jid withResource(CharSequence resource) { - return new MalformedJid(localPart, domainPart, resource.toString(), cause); - } - - @Override - public Jid atSubdomain(CharSequence subdomain) { - if (subdomain == null) { - throw new NullPointerException(); - } - return new MalformedJid(localPart, subdomain + "." + domainPart, resourcePart, cause); - } - - @Override - public final String getLocal() { - return localPart; - } - - @Override - public final String getEscapedLocal() { - return localPart; - } - - @Override - public final String getDomain() { - return domainPart; - } - - @Override - public final String getResource() { - return resourcePart; - } - - /** - * Gets the cause why the JID is malformed. - * - * @return The cause. - */ - public final Throwable getCause() { - return cause; - } -} diff --git a/libs/xmpp-addr/src/main/java/rocks/xmpp/addr/package-info.java b/libs/xmpp-addr/src/main/java/rocks/xmpp/addr/package-info.java deleted file mode 100644 index e12485d5f..000000000 --- a/libs/xmpp-addr/src/main/java/rocks/xmpp/addr/package-info.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2014-2016 Christian Schudt - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/** - * Provides classes for the XMPP Address Format (JID). - * - * @see Extensible Messaging and Presence Protocol (XMPP): Address Format - */ -package rocks.xmpp.addr; - diff --git a/libs/xmpp-addr/src/main/java/rocks/xmpp/util/cache/DirectoryCache.java b/libs/xmpp-addr/src/main/java/rocks/xmpp/util/cache/DirectoryCache.java deleted file mode 100644 index 9b7d66d04..000000000 --- a/libs/xmpp-addr/src/main/java/rocks/xmpp/util/cache/DirectoryCache.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2014-2016 Christian Schudt - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package rocks.xmpp.util.cache; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * A simple directory based cache for caching of persistent items like avatars or entity capabilities. - * - * @author Christian Schudt - */ -public final class DirectoryCache implements Map { - - private final Path cacheDirectory; - - public DirectoryCache(Path cacheDirectory) { - this.cacheDirectory = cacheDirectory; - } - - @Override - public final int size() { - try (final Stream files = cacheContent()) { - return (int) Math.min(files.count(), Integer.MAX_VALUE); - } - } - - @Override - public final boolean isEmpty() { - try (final Stream files = cacheContent()) { - return files.findAny().map(file -> Boolean.FALSE).orElse(Boolean.TRUE); - } - } - - @Override - public final boolean containsKey(Object key) { - return Files.exists(cacheDirectory.resolve(key.toString())); - } - - @Override - public final boolean containsValue(Object value) { - throw new UnsupportedOperationException(); - } - - @Override - public final byte[] get(final Object key) { - return Optional.ofNullable(key).map(Object::toString).filter(((Predicate) String::isEmpty).negate()).map(cacheDirectory::resolve).filter(Files::isReadable).map(file -> { - try { - return Files.readAllBytes(file); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - }).orElse(null); - } - - @Override - public final byte[] put(String key, byte[] value) { - // Make sure the directory exists. - byte[] data = get(key); - if (!Arrays.equals(data, value)) - try { - if (Files.notExists(cacheDirectory)) { - Files.createDirectories(cacheDirectory); - } - Path file = cacheDirectory.resolve(key); - Files.write(file, value); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - return data; - } - - @Override - public final byte[] remove(Object key) { - byte[] data = get(key); - try { - Files.deleteIfExists(cacheDirectory.resolve(key.toString())); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - return data; - } - - @Override - public final void putAll(Map m) { - m.forEach(this::put); - } - - @Override - public final void clear() { - try { - Files.walkFileTree(cacheDirectory, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - Files.deleteIfExists(file); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { - // Don't delete the cache directory itself. - if (!Files.isSameFile(dir, cacheDirectory)) { - Files.deleteIfExists(dir); - } - return FileVisitResult.CONTINUE; - } - }); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public final Set keySet() { - try (final Stream files = Files.list(cacheDirectory)) { - return Collections.unmodifiableSet(files.map(Path::getFileName).map(Path::toString).collect(Collectors.toSet())); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public final Collection values() { - throw new UnsupportedOperationException(); - } - - @Override - public final Set> entrySet() { - throw new UnsupportedOperationException(); - } - - @Override - public final void forEach(final BiConsumer action) { - if (Files.exists(cacheDirectory)) - try (final Stream files = cacheContent().filter(Files::isReadable)) { - files.forEach(file -> { - try { - action.accept(file.getFileName().toString(), Files.readAllBytes(file)); - } catch (final IOException e) { - throw new UncheckedIOException(e); - } - }); - } - } - - @SuppressWarnings("StreamResourceLeak") - private final Stream cacheContent() { - try { - return Files.walk(cacheDirectory).filter(Files::isRegularFile); - } catch (final IOException e) { - throw new UncheckedIOException(e); - } - } - -} diff --git a/libs/xmpp-addr/src/main/java/rocks/xmpp/util/cache/LruCache.java b/libs/xmpp-addr/src/main/java/rocks/xmpp/util/cache/LruCache.java deleted file mode 100644 index c2fbb0c3f..000000000 --- a/libs/xmpp-addr/src/main/java/rocks/xmpp/util/cache/LruCache.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2014-2016 Christian Schudt - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package rocks.xmpp.util.cache; - -import java.util.Collection; -import java.util.Map; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedDeque; -import java.util.function.BiFunction; -import java.util.function.Function; - -/** - * A simple concurrent implementation of a least-recently-used cache. - *

- * This cache is keeps a maximal number of items in memory and removes the least-recently-used item, when new items are added. - * - * @param The key. - * @param The value. - * @author Christian Schudt - * @see http://javadecodedquestions.blogspot.de/2013/02/java-cache-static-data-loading.html - * @see http://stackoverflow.com/a/22891780 - */ -public final class LruCache implements Map { - private final int maxEntries; - - private final Map map; - - final Queue queue; - - public LruCache(final int maxEntries) { - this.maxEntries = maxEntries; - this.map = new ConcurrentHashMap<>(maxEntries); - // Don't use a ConcurrentLinkedQueue here. - // There's a JDK bug, leading to OutOfMemoryError and high CPU usage: - // https://bugs.openjdk.java.net/browse/JDK-8054446 - this.queue = new ConcurrentLinkedDeque<>(); - } - - @Override - public final int size() { - return map.size(); - } - - @Override - public final boolean isEmpty() { - return map.isEmpty(); - } - - @Override - public final boolean containsKey(final Object key) { - return map.containsKey(key); - } - - @Override - public final boolean containsValue(final Object value) { - return map.containsValue(value); - } - - @SuppressWarnings("unchecked") - @Override - public final V get(final Object key) { - final V v = map.get(key); - if (v != null) { - // Remove the key from the queue and re-add it to the tail. It is now the most recently used key. - keyUsed((K) key); - } - return v; - } - - - @Override - public final V put(final K key, final V value) { - V v = map.put(key, value); - keyUsed(key); - limit(); - return v; - } - - @Override - public final V remove(final Object key) { - queue.remove(key); - return map.remove(key); - } - - - @Override - public final void putAll(final Map m) { - for (Map.Entry entry : m.entrySet()) { - put(entry.getKey(), entry.getValue()); - } - } - - @Override - public final void clear() { - queue.clear(); - map.clear(); - } - - @Override - public final Set keySet() { - return map.keySet(); - } - - @Override - public final Collection values() { - return map.values(); - } - - @Override - public final Set> entrySet() { - return map.entrySet(); - } - - - // Default methods - - @Override - public final V putIfAbsent(final K key, final V value) { - final V v = map.putIfAbsent(key, value); - if (v == null) { - keyUsed(key); - } - limit(); - return v; - } - - @Override - public final boolean remove(final Object key, final Object value) { - final boolean removed = map.remove(key, value); - if (removed) { - queue.remove(key); - } - return removed; - } - - @Override - public final boolean replace(final K key, final V oldValue, final V newValue) { - final boolean replaced = map.replace(key, oldValue, newValue); - if (replaced) { - keyUsed(key); - } - return replaced; - } - - @Override - public final V replace(final K key, final V value) { - final V v = map.replace(key, value); - if (v != null) { - keyUsed(key); - } - return v; - } - - @Override - public final V computeIfAbsent(final K key, final Function mappingFunction) { - return map.computeIfAbsent(key, mappingFunction.andThen(v -> { - keyUsed(key); - limit(); - return v; - })); - } - - @Override - public final V computeIfPresent(final K key, final BiFunction remappingFunction) { - return map.computeIfPresent(key, remappingFunction.andThen(v -> { - keyUsed(key); - limit(); - return v; - })); - } - - @Override - public final V compute(final K key, final BiFunction remappingFunction) { - return map.compute(key, remappingFunction.andThen(v -> { - keyUsed(key); - limit(); - return v; - })); - } - - @Override - public final V merge(K key, V value, BiFunction remappingFunction) { - return map.merge(key, value, remappingFunction.andThen(v -> { - keyUsed(key); - limit(); - return v; - })); - } - - private void limit() { - while (queue.size() > maxEntries) { - final K oldestKey = queue.poll(); - if (oldestKey != null) { - map.remove(oldestKey); - } - } - } - - private void keyUsed(final K key) { - // remove it from the queue and re-add it, to make it the most recently used key. - queue.remove(key); - queue.offer(key); - } -} \ No newline at end of file diff --git a/libs/xmpp-addr/src/main/java/rocks/xmpp/util/cache/package-info.java b/libs/xmpp-addr/src/main/java/rocks/xmpp/util/cache/package-info.java deleted file mode 100644 index c5e449d4c..000000000 --- a/libs/xmpp-addr/src/main/java/rocks/xmpp/util/cache/package-info.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2014-2016 Christian Schudt - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/** - * Provides simple cache implementations. - */ -package rocks.xmpp.util.cache; \ No newline at end of file diff --git a/metadata/en-US/changelogs/387.txt b/metadata/en-US/changelogs/387.txt new file mode 100644 index 000000000..736d22ae8 --- /dev/null +++ b/metadata/en-US/changelogs/387.txt @@ -0,0 +1,2 @@ +• Rework Login with certificate UI +• Add ability to pin chats on top (add to favorites) diff --git a/settings.gradle b/settings.gradle index 746b2c7e3..4193570fa 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1 @@ -include ':libs:xmpp-addr' rootProject.name = 'Conversations' diff --git a/src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java b/src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java index 66ebd7c3a..8596b1c3f 100644 --- a/src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java +++ b/src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java @@ -46,7 +46,7 @@ import eu.siacs.conversations.ui.ManageAccountActivity; import eu.siacs.conversations.utils.BackupFileHeader; import eu.siacs.conversations.utils.Compatibility; import eu.siacs.conversations.utils.SerialSingleThreadExecutor; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; import static eu.siacs.conversations.services.ExportBackupService.CIPHERMODE; import static eu.siacs.conversations.services.ExportBackupService.KEYTYPE; @@ -208,7 +208,7 @@ public class ImportBackupService extends Service { } } final Jid jid = backupFileHeader.getJid(); - Cursor countCursor = db.rawQuery("select count(messages.uuid) from messages join conversations on conversations.uuid=messages.conversationUuid join accounts on conversations.accountUuid=accounts.uuid where accounts.username=? and accounts.server=?", new String[]{jid.getEscapedLocal(), jid.getDomain()}); + Cursor countCursor = db.rawQuery("select count(messages.uuid) from messages join conversations on conversations.uuid=messages.conversationUuid join accounts on conversations.accountUuid=accounts.uuid where accounts.username=? and accounts.server=?", new String[]{jid.getEscapedLocal(), jid.getDomain().toEscapedString()}); countCursor.moveToFirst(); int count = countCursor.getInt(0); Log.d(Config.LOGTAG, "restored " + count + " messages"); diff --git a/src/conversations/java/eu/siacs/conversations/ui/MagicCreateActivity.java b/src/conversations/java/eu/siacs/conversations/ui/MagicCreateActivity.java index 8094e49f1..6b772abf9 100644 --- a/src/conversations/java/eu/siacs/conversations/ui/MagicCreateActivity.java +++ b/src/conversations/java/eu/siacs/conversations/ui/MagicCreateActivity.java @@ -18,7 +18,7 @@ import eu.siacs.conversations.databinding.MagicCreateBinding; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.InstallReferrerUtils; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class MagicCreateActivity extends XmppActivity implements TextWatcher { @@ -79,13 +79,13 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher { final boolean fixedUsername; if (this.domain != null && this.username != null) { fixedUsername = true; - jid = Jid.ofLocalAndDomain(this.username, this.domain); + jid = Jid.ofLocalAndDomainEscaped(this.username, this.domain); } else if (this.domain != null) { fixedUsername = false; - jid = Jid.ofLocalAndDomain(username, this.domain); + jid = Jid.ofLocalAndDomainEscaped(username, this.domain); } else { fixedUsername = false; - jid = Jid.ofLocalAndDomain(username, Config.MAGIC_CREATE_DOMAIN); + jid = Jid.ofLocalAndDomainEscaped(username, Config.MAGIC_CREATE_DOMAIN); } if (!jid.getEscapedLocal().equals(jid.getLocal()) || (this.username == null && username.length() < 3)) { binding.username.setError(getString(R.string.invalid_username)); @@ -149,9 +149,9 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher { binding.fullJid.setVisibility(View.VISIBLE); final Jid jid; if (this.domain == null) { - jid = Jid.ofLocalAndDomain(username, Config.MAGIC_CREATE_DOMAIN); + jid = Jid.ofLocalAndDomainEscaped(username, Config.MAGIC_CREATE_DOMAIN); } else { - jid = Jid.ofLocalAndDomain(username, this.domain); + jid = Jid.ofLocalAndDomainEscaped(username, this.domain); } binding.fullJid.setText(getString(R.string.your_full_jid_will_be, jid.toEscapedString())); } catch (IllegalArgumentException e) { diff --git a/src/conversations/java/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/conversations/java/eu/siacs/conversations/ui/ManageAccountActivity.java index f694e5dba..86bdd5501 100644 --- a/src/conversations/java/eu/siacs/conversations/ui/ManageAccountActivity.java +++ b/src/conversations/java/eu/siacs/conversations/ui/ManageAccountActivity.java @@ -14,9 +14,7 @@ import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.widget.AdapterView; import android.widget.AdapterView.AdapterContextMenuInfo; -import android.widget.AdapterView.OnItemClickListener; import android.widget.ListView; import android.widget.Toast; @@ -34,7 +32,7 @@ import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; import eu.siacs.conversations.ui.adapter.AccountAdapter; import eu.siacs.conversations.ui.util.MenuDoubleTabUtil; import eu.siacs.conversations.xmpp.XmppConnection; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; import static eu.siacs.conversations.utils.PermissionUtils.allGranted; import static eu.siacs.conversations.utils.PermissionUtils.writeGranted; @@ -133,7 +131,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda menu.findItem(R.id.mgmt_account_announce_pgp).setVisible(false); menu.findItem(R.id.mgmt_account_publish_avatar).setVisible(false); } - menu.setHeaderTitle(this.selectedAccount.getJid().asBareJid().toString()); + menu.setHeaderTitle(this.selectedAccount.getJid().asBareJid().toEscapedString()); } @Override @@ -369,7 +367,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda } private void deleteAccount(final Account account) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); + final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(getString(R.string.mgmt_account_are_you_sure)); builder.setIconAttribute(android.R.attr.alertDialogIcon); builder.setMessage(getString(R.string.mgmt_account_delete_confirm_text)); @@ -408,15 +406,15 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda } @Override - public void alias(String alias) { + public void alias(final String alias) { if (alias != null) { xmppConnectionService.createAccountFromKey(alias, this); } } @Override - public void onAccountCreated(Account account) { - Intent intent = new Intent(this, EditAccountActivity.class); + public void onAccountCreated(final Account account) { + final Intent intent = new Intent(this, EditAccountActivity.class); intent.putExtra("jid", account.getJid().asBareJid().toString()); intent.putExtra("init", true); startActivity(intent); diff --git a/src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java b/src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java index db4864689..762dfbb42 100644 --- a/src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java +++ b/src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java @@ -1,10 +1,6 @@ package eu.siacs.conversations.ui; import android.os.Bundle; -import android.support.v7.app.ActionBar; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; import android.widget.ListView; import java.util.ArrayList; @@ -14,7 +10,7 @@ import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.ui.adapter.AccountAdapter; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class ShareViaAccountActivity extends XmppActivity { public static final String EXTRA_CONTACT = "contact"; diff --git a/src/conversations/java/eu/siacs/conversations/ui/WelcomeActivity.java b/src/conversations/java/eu/siacs/conversations/ui/WelcomeActivity.java index 12695b6f7..daf6dd995 100644 --- a/src/conversations/java/eu/siacs/conversations/ui/WelcomeActivity.java +++ b/src/conversations/java/eu/siacs/conversations/ui/WelcomeActivity.java @@ -1,11 +1,14 @@ package eu.siacs.conversations.ui; import android.Manifest; +import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.databinding.DataBindingUtil; import android.os.Bundle; +import android.security.KeyChain; +import android.security.KeyChainAliasCallback; import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; @@ -21,15 +24,16 @@ import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.databinding.ActivityWelcomeBinding; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.InstallReferrerUtils; import eu.siacs.conversations.utils.SignupUtils; import eu.siacs.conversations.utils.XmppUri; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; import static eu.siacs.conversations.utils.PermissionUtils.allGranted; import static eu.siacs.conversations.utils.PermissionUtils.writeGranted; -public class WelcomeActivity extends XmppActivity { +public class WelcomeActivity extends XmppActivity implements XmppConnectionService.OnAccountCreated, KeyChainAliasCallback { private static final int REQUEST_IMPORT_BACKUP = 0x63fb; @@ -154,10 +158,42 @@ public class WelcomeActivity extends XmppActivity { case R.id.action_scan_qr_code: UriHandlerActivity.scan(this); break; + case R.id.action_add_account_with_cert: + addAccountFromKey(); + break; } return super.onOptionsItemSelected(item); } + private void addAccountFromKey() { + try { + KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null); + } catch (ActivityNotFoundException e) { + Toast.makeText(this, R.string.device_does_not_support_certificates, Toast.LENGTH_LONG).show(); + } + } + + @Override + public void alias(final String alias) { + if (alias != null) { + xmppConnectionService.createAccountFromKey(alias, this); + } + } + + @Override + public void onAccountCreated(final Account account) { + final Intent intent = new Intent(this, EditAccountActivity.class); + intent.putExtra("jid", account.getJid().asBareJid().toString()); + intent.putExtra("init", true); + addInviteUri(intent); + startActivity(intent); + } + + @Override + public void informUser(final int r) { + runOnUiThread(() -> Toast.makeText(this, r, Toast.LENGTH_LONG).show()); + } + @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { UriHandlerActivity.onRequestPermissionResult(this, requestCode, grantResults); diff --git a/src/conversations/java/eu/siacs/conversations/ui/adapter/BackupFileAdapter.java b/src/conversations/java/eu/siacs/conversations/ui/adapter/BackupFileAdapter.java index 870340d7b..e71505e96 100644 --- a/src/conversations/java/eu/siacs/conversations/ui/adapter/BackupFileAdapter.java +++ b/src/conversations/java/eu/siacs/conversations/ui/adapter/BackupFileAdapter.java @@ -26,7 +26,7 @@ import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.services.ImportBackupService; import eu.siacs.conversations.utils.BackupFileHeader; import eu.siacs.conversations.utils.UIHelper; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class BackupFileAdapter extends RecyclerView.Adapter { diff --git a/src/conversations/java/eu/siacs/conversations/utils/SignupUtils.java b/src/conversations/java/eu/siacs/conversations/utils/SignupUtils.java index a47dfbca8..fb088234a 100644 --- a/src/conversations/java/eu/siacs/conversations/utils/SignupUtils.java +++ b/src/conversations/java/eu/siacs/conversations/utils/SignupUtils.java @@ -13,7 +13,7 @@ import eu.siacs.conversations.ui.ManageAccountActivity; import eu.siacs.conversations.ui.PickServerActivity; import eu.siacs.conversations.ui.StartConversationActivity; import eu.siacs.conversations.ui.WelcomeActivity; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class SignupUtils { @@ -24,9 +24,9 @@ public class SignupUtils { public static Intent getTokenRegistrationIntent(final Activity activity, Jid jid, String preAuth) { final Intent intent = new Intent(activity, MagicCreateActivity.class); if (jid.isDomainJid()) { - intent.putExtra(MagicCreateActivity.EXTRA_DOMAIN, jid.getDomain()); + intent.putExtra(MagicCreateActivity.EXTRA_DOMAIN, jid.getDomain().toEscapedString()); } else { - intent.putExtra(MagicCreateActivity.EXTRA_DOMAIN, jid.getDomain()); + intent.putExtra(MagicCreateActivity.EXTRA_DOMAIN, jid.getDomain().toEscapedString()); intent.putExtra(MagicCreateActivity.EXTRA_USERNAME, jid.getEscapedLocal()); } intent.putExtra(MagicCreateActivity.EXTRA_PRE_AUTH, preAuth); diff --git a/src/conversations/res/menu/welcome_menu.xml b/src/conversations/res/menu/welcome_menu.xml index ec396f32f..f07a2b91e 100644 --- a/src/conversations/res/menu/welcome_menu.xml +++ b/src/conversations/res/menu/welcome_menu.xml @@ -1,16 +1,22 @@

+ xmlns:app="http://schemas.android.com/apk/res-auto"> + app:showAsAction="ifRoom" /> + + + android:title="@string/restore_backup" + app:showAsAction="never" /> \ No newline at end of file diff --git a/src/conversations/res/values-uk/strings.xml b/src/conversations/res/values-uk/strings.xml index 0244160c5..f04ad6562 100644 --- a/src/conversations/res/values-uk/strings.xml +++ b/src/conversations/res/values-uk/strings.xml @@ -3,9 +3,9 @@ Виберіть постачальника послуг обміну повідомленнями XMPP Скористатися chat.sum7.eu Створити новий обліковий запис - Вже маєте обліковий запис XMPP? Можливо, користуєтеся іншою програмою XMPP або користувалися цією програмою раніше. Якщо ні, можете створити новий обліковий запис XMPP просто зараз.\nЗверніть увагу: Деякі постачальники електронної пошти водночас надають облікові записи XMPP. - XMPP — це мережа обміну повідомленнями, незалежна від постачальників. Можете використовувати цю програму з будь-яким XMPP сервером, який оберете.\nПроте, для зручності, ми спростили створення облікового запису на chat.sum7.eu — в постачальника, який спеціально налаштований на роботу з цією програмою. - Вас запросили до %1$s. Ми проведемо Вас крок за кроком, щоб створити обліковий запис.\nОбираючи %1$s в якості свого постачальника, Ви зможете спілкуватися з користувачами інших постачальників, повідомивши їм свою повну адресу XMPP. - Вас запросили до %1$s. Для Вас уже обрали ім\'я користувача. Ми проведемо Вас крок за кроком, щоб створити обліковий запис.\nВи зможете спілкуватися з користувачами інших постачальників, повідомивши їм свою повну адресу XMPP. + Вже маєте обліковий запис XMPP? Можливо, користуєтеся іншою програмою XMPP або користувалися цією програмою раніше. Якщо ні, можете створити новий обліковий запис XMPP просто зараз.\nЗверніть увагу, що деякі постачальники електронної пошти у той же час надають облікові записи XMPP. + XMPP — це мережа обміну повідомленнями, незалежна від постачальників. Можете використовувати цю програму з будь-яким XMPP сервером, який оберете.\nПроте, для зручності, ми спростили створення облікового запису на chat.sum7.eu — у постачальника, який спеціально налаштований на роботу з цією програмою. + Вас запросили до %1$s. Ми проведемо вас крок за кроком, щоб створити обліковий запис.\nОбираючи %1$s в якості свого постачальника, ви зможете спілкуватися з користувачами інших постачальників, для цього повідомте їм свою повну адресу XMPP. + Вас запросили до %1$s. Для вас створено ім\'я користувача. Ми проведемо вас крок за кроком, щоб створити обліковий запис.\nВи зможете спілкуватися з користувачами інших постачальників, для цього повідомите їм свою повну адресу XMPP. Ваше запрошення до сервера diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 750029931..d8a2b8a54 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -6,7 +6,7 @@ import java.util.Collections; import java.util.List; import eu.siacs.conversations.xmpp.chatstate.ChatState; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public final class Config { private static final int UNENCRYPTED = 1; diff --git a/src/main/java/eu/siacs/conversations/android/JabberIdContact.java b/src/main/java/eu/siacs/conversations/android/JabberIdContact.java index e6488fac3..195891d22 100644 --- a/src/main/java/eu/siacs/conversations/android/JabberIdContact.java +++ b/src/main/java/eu/siacs/conversations/android/JabberIdContact.java @@ -13,7 +13,7 @@ import java.util.HashMap; import java.util.Map; import eu.siacs.conversations.Config; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class JabberIdContact extends AbstractPhoneContact { diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java index e67755586..cc22bc818 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java @@ -53,7 +53,7 @@ import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.pep.PublishOptions; import eu.siacs.conversations.xmpp.stanzas.IqPacket; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java index bec0ff9e2..1c9db15f9 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java @@ -2,7 +2,6 @@ package eu.siacs.conversations.crypto.axolotl; import android.util.Base64; import android.util.Log; -import android.util.SparseArray; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -24,7 +23,7 @@ import javax.crypto.spec.SecretKeySpec; import eu.siacs.conversations.Config; import eu.siacs.conversations.utils.Compatibility; import eu.siacs.conversations.xml.Element; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class XmppAxolotlMessage { public static final String CONTAINERTAG = "encrypted"; diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/External.java b/src/main/java/eu/siacs/conversations/crypto/sasl/External.java index a76456ce8..294f382d7 100644 --- a/src/main/java/eu/siacs/conversations/crypto/sasl/External.java +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/External.java @@ -24,6 +24,6 @@ public class External extends SaslMechanism { @Override public String getClientFirstMessage() { - return Base64.encodeToString(account.getJid().asBareJid().toString().getBytes(),Base64.NO_WRAP); + return Base64.encodeToString(account.getJid().asBareJid().toEscapedString().getBytes(),Base64.NO_WRAP); } } diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/ScramMechanism.java b/src/main/java/eu/siacs/conversations/crypto/sasl/ScramMechanism.java index df308241b..f502ad9b8 100644 --- a/src/main/java/eu/siacs/conversations/crypto/sasl/ScramMechanism.java +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/ScramMechanism.java @@ -173,7 +173,7 @@ abstract class ScramMechanism extends SaslMechanism { // Map keys are "bytesToHex(JID),bytesToHex(password),bytesToHex(salt),iterations,SASL-Mechanism". final KeyPair keys = CACHE.get( - CryptoHelper.bytesToHex(account.getJid().asBareJid().toString().getBytes()) + "," + CryptoHelper.bytesToHex(account.getJid().asBareJid().toEscapedString().getBytes()) + "," + CryptoHelper.bytesToHex(account.getPassword().getBytes()) + "," + CryptoHelper.bytesToHex(salt.getBytes()) + "," + String.valueOf(iterationCount) + "," diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java index 168e7a9ce..d2d25e321 100644 --- a/src/main/java/eu/siacs/conversations/entities/Account.java +++ b/src/main/java/eu/siacs/conversations/entities/Account.java @@ -16,7 +16,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import eu.siacs.conversations.Config; @@ -30,7 +29,7 @@ import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.utils.XmppUri; import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.jingle.RtpCapability; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class Account extends AbstractEntity implements AvatarService.Avatarable { @@ -233,10 +232,14 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable return next != null && !next.equals(previousFull); } - public String getServer() { + public Jid getDomain() { return jid.getDomain(); } + public String getServer() { + return jid.getDomain().toEscapedString(); + } + public String getPassword() { return password; } @@ -370,7 +373,7 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable final ContentValues values = new ContentValues(); values.put(UUID, uuid); values.put(USERNAME, jid.getLocal()); - values.put(SERVER, jid.getDomain()); + values.put(SERVER, jid.getDomain().toEscapedString()); values.put(PASSWORD, password); values.put(OPTIONS, options); synchronized (this.keys) { @@ -588,7 +591,7 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable public boolean isBlocked(final ListItem contact) { final Jid jid = contact.getJid(); - return jid != null && (blocklist.contains(jid.asBareJid()) || blocklist.contains(Jid.ofDomain(jid.getDomain()))); + return jid != null && (blocklist.contains(jid.asBareJid()) || blocklist.contains(jid.getDomain())); } public boolean isBlocked(final Jid jid) { diff --git a/src/main/java/eu/siacs/conversations/entities/Blockable.java b/src/main/java/eu/siacs/conversations/entities/Blockable.java index 40a9f36a8..0d1ab6361 100644 --- a/src/main/java/eu/siacs/conversations/entities/Blockable.java +++ b/src/main/java/eu/siacs/conversations/entities/Blockable.java @@ -1,6 +1,6 @@ package eu.siacs.conversations.entities; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public interface Blockable { boolean isBlocked(); diff --git a/src/main/java/eu/siacs/conversations/entities/Bookmark.java b/src/main/java/eu/siacs/conversations/entities/Bookmark.java index 9d708ce17..e55622a06 100644 --- a/src/main/java/eu/siacs/conversations/entities/Bookmark.java +++ b/src/main/java/eu/siacs/conversations/entities/Bookmark.java @@ -17,7 +17,7 @@ import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.InvalidJid; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class Bookmark extends Element implements ListItem { @@ -28,7 +28,7 @@ public class Bookmark extends Element implements ListItem { public Bookmark(final Account account, final Jid jid) { super("conference"); this.jid = jid; - this.setAttribute("jid", jid.toString()); + this.setAttribute("jid", jid); this.account = account; } diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java index 026804712..d95dae80b 100644 --- a/src/main/java/eu/siacs/conversations/entities/Contact.java +++ b/src/main/java/eu/siacs/conversations/entities/Contact.java @@ -26,7 +26,7 @@ import eu.siacs.conversations.utils.JidHelper; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.pep.Avatar; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class Contact implements ListItem, Blockable { public static final String TABLENAME = "contacts"; @@ -134,12 +134,12 @@ public class Contact implements ListItem, Blockable { return this.systemName; } else if (!TextUtils.isEmpty(this.serverName)) { return this.serverName; - } else if (!TextUtils.isEmpty(this.presenceName) && ((QuickConversationsService.isQuicksy() && Config.QUICKSY_DOMAIN.equals(jid.getDomain())) ||mutualPresenceSubscription())) { + } else if (!TextUtils.isEmpty(this.presenceName) && ((QuickConversationsService.isQuicksy() && Config.QUICKSY_DOMAIN.equals(jid.getDomain().toEscapedString())) ||mutualPresenceSubscription())) { return this.presenceName; } else if (jid.getLocal() != null) { return JidHelper.localPartOrFallback(jid); } else { - return jid.getDomain(); + return jid.getDomain().toEscapedString(); } } @@ -396,7 +396,7 @@ public class Contact implements ListItem, Blockable { public Element asElement() { final Element item = new Element("item"); - item.setAttribute("jid", this.jid.toString()); + item.setAttribute("jid", this.jid); if (this.serverName != null) { item.setAttribute("name", this.serverName); } @@ -413,7 +413,7 @@ public class Contact implements ListItem, Blockable { } public String getServer() { - return getJid().getDomain(); + return getJid().getDomain().toEscapedString(); } public boolean setAvatar(Avatar avatar) { @@ -451,13 +451,13 @@ public class Contact implements ListItem, Blockable { @Override public boolean isDomainBlocked() { - return getAccount().isBlocked(Jid.ofDomain(this.getJid().getDomain())); + return getAccount().isBlocked(this.getJid().getDomain()); } @Override public Jid getBlockedJid() { if (isDomainBlocked()) { - return Jid.ofDomain(getJid().getDomain()); + return getJid().getDomain(); } else { return getJid(); } diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 55129dd65..1e88f8d82 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -6,6 +6,8 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; +import com.google.common.collect.ComparisonChain; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -27,7 +29,7 @@ import eu.siacs.conversations.utils.JidHelper; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.chatstate.ChatState; import eu.siacs.conversations.xmpp.mam.MamReference; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; import static eu.siacs.conversations.entities.Bookmark.printableValue; @@ -49,9 +51,9 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl public static final String ATTRIBUTE_MUTED_TILL = "muted_till"; public static final String ATTRIBUTE_ALWAYS_NOTIFY = "always_notify"; - public static final String ATTRIBUTE_PUSH_NODE = "push_node"; public static final String ATTRIBUTE_LAST_CLEAR_HISTORY = "last_clear_history"; public static final String ATTRIBUTE_FORMERLY_PRIVATE_NON_ANONYMOUS = "formerly_private_non_anonymous"; + public static final String ATTRIBUTE_PINNED_ON_TOP = "pinned_on_top"; static final String ATTRIBUTE_MUC_PASSWORD = "muc_password"; static final String ATTRIBUTE_MEMBERS_ONLY = "members_only"; static final String ATTRIBUTE_MODERATED = "moderated"; @@ -137,7 +139,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl if (conversation.getContact().isOwnServer()) { return false; } - final String contact = conversation.getJid().getDomain(); + final String contact = conversation.getJid().getDomain().toEscapedString(); final String account = conversation.getAccount().getServer(); if (Config.OMEMO_EXCEPTIONS.CONTACT_DOMAINS.contains(contact) || Config.OMEMO_EXCEPTIONS.ACCOUNT_DOMAINS.contains(account)) { return false; @@ -479,7 +481,10 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl @Override public int compareTo(@NonNull Conversation another) { - return Long.compare(another.getSortableTime(), getSortableTime()); + return ComparisonChain.start() + .compareFalseFirst(another.getBooleanAttribute(ATTRIBUTE_PINNED_ON_TOP, false), getBooleanAttribute(ATTRIBUTE_PINNED_ON_TOP,false)) + .compare(another.getSortableTime(), getSortableTime()) + .result(); } private long getSortableTime() { diff --git a/src/main/java/eu/siacs/conversations/entities/Conversational.java b/src/main/java/eu/siacs/conversations/entities/Conversational.java index 6b016230d..58af42213 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversational.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversational.java @@ -29,7 +29,7 @@ package eu.siacs.conversations.entities; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public interface Conversational { diff --git a/src/main/java/eu/siacs/conversations/entities/IndividualMessage.java b/src/main/java/eu/siacs/conversations/entities/IndividualMessage.java index 9a3ae6236..8f416a301 100644 --- a/src/main/java/eu/siacs/conversations/entities/IndividualMessage.java +++ b/src/main/java/eu/siacs/conversations/entities/IndividualMessage.java @@ -34,7 +34,7 @@ import android.database.Cursor; import java.util.Set; import eu.siacs.conversations.ui.adapter.MessageAdapter; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class IndividualMessage extends Message { diff --git a/src/main/java/eu/siacs/conversations/entities/ListItem.java b/src/main/java/eu/siacs/conversations/entities/ListItem.java index 10d2c897c..adc7666ce 100644 --- a/src/main/java/eu/siacs/conversations/entities/ListItem.java +++ b/src/main/java/eu/siacs/conversations/entities/ListItem.java @@ -5,7 +5,7 @@ import android.content.Context; import java.util.List; import eu.siacs.conversations.services.AvatarService; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public interface ListItem extends Comparable, AvatarService.Avatarable { diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index f266c18e3..567d694eb 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -27,7 +27,7 @@ import eu.siacs.conversations.utils.GeoHelper; import eu.siacs.conversations.utils.MessageUtils; import eu.siacs.conversations.utils.MimeUtils; import eu.siacs.conversations.utils.UIHelper; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class Message extends AbstractEntity implements AvatarService.Avatarable { diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index f45d93330..33a62a07f 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -17,12 +17,11 @@ import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.utils.JidHelper; import eu.siacs.conversations.utils.UIHelper; -import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.chatstate.ChatState; import eu.siacs.conversations.xmpp.forms.Data; import eu.siacs.conversations.xmpp.forms.Field; import eu.siacs.conversations.xmpp.pep.Avatar; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class MucOptions { diff --git a/src/main/java/eu/siacs/conversations/entities/RawBlockable.java b/src/main/java/eu/siacs/conversations/entities/RawBlockable.java index 884b998d5..f4fb3346b 100644 --- a/src/main/java/eu/siacs/conversations/entities/RawBlockable.java +++ b/src/main/java/eu/siacs/conversations/entities/RawBlockable.java @@ -8,7 +8,7 @@ import java.util.List; import java.util.Locale; import eu.siacs.conversations.utils.UIHelper; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class RawBlockable implements ListItem, Blockable { diff --git a/src/main/java/eu/siacs/conversations/entities/ReadByMarker.java b/src/main/java/eu/siacs/conversations/entities/ReadByMarker.java index c492b4c81..9e1aaa5c7 100644 --- a/src/main/java/eu/siacs/conversations/entities/ReadByMarker.java +++ b/src/main/java/eu/siacs/conversations/entities/ReadByMarker.java @@ -6,10 +6,9 @@ import org.json.JSONObject; import java.util.Collection; import java.util.HashSet; -import java.util.List; import java.util.Set; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class ReadByMarker { diff --git a/src/main/java/eu/siacs/conversations/entities/ReceiptRequest.java b/src/main/java/eu/siacs/conversations/entities/ReceiptRequest.java index 939187eef..9684ad6b9 100644 --- a/src/main/java/eu/siacs/conversations/entities/ReceiptRequest.java +++ b/src/main/java/eu/siacs/conversations/entities/ReceiptRequest.java @@ -29,7 +29,7 @@ package eu.siacs.conversations.entities; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class ReceiptRequest { diff --git a/src/main/java/eu/siacs/conversations/entities/Room.java b/src/main/java/eu/siacs/conversations/entities/Room.java index 74ce07c91..551426b6b 100644 --- a/src/main/java/eu/siacs/conversations/entities/Room.java +++ b/src/main/java/eu/siacs/conversations/entities/Room.java @@ -4,12 +4,10 @@ import com.google.common.base.Objects; import com.google.common.base.Strings; import com.google.common.collect.ComparisonChain; -import java.util.Comparator; - import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.utils.LanguageUtils; import eu.siacs.conversations.utils.UIHelper; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class Room implements AvatarService.Avatarable, Comparable { diff --git a/src/main/java/eu/siacs/conversations/entities/Roster.java b/src/main/java/eu/siacs/conversations/entities/Roster.java index a72766f00..bc4c6b974 100644 --- a/src/main/java/eu/siacs/conversations/entities/Roster.java +++ b/src/main/java/eu/siacs/conversations/entities/Roster.java @@ -6,7 +6,7 @@ import java.util.Iterator; import java.util.List; import eu.siacs.conversations.android.AbstractPhoneContact; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class Roster { diff --git a/src/main/java/eu/siacs/conversations/entities/StubConversation.java b/src/main/java/eu/siacs/conversations/entities/StubConversation.java index d89217599..79f4e80b4 100644 --- a/src/main/java/eu/siacs/conversations/entities/StubConversation.java +++ b/src/main/java/eu/siacs/conversations/entities/StubConversation.java @@ -29,7 +29,7 @@ package eu.siacs.conversations.entities; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class StubConversation implements Conversational { diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 62670c408..1e5a0ed14 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -34,7 +34,7 @@ import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.forms.Data; import eu.siacs.conversations.xmpp.pep.Avatar; import eu.siacs.conversations.xmpp.stanzas.IqPacket; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class IqGenerator extends AbstractGenerator { @@ -302,7 +302,7 @@ public class IqGenerator extends AbstractGenerator { if (mam.muc()) { packet.setTo(mam.getWith()); } else if (mam.getWith() != null) { - data.put("with", mam.getWith().toString()); + data.put("with", mam.getWith().toEscapedString()); } final long start = mam.getStart(); final long end = mam.getEnd(); @@ -334,7 +334,7 @@ public class IqGenerator extends AbstractGenerator { public IqPacket generateSetBlockRequest(final Jid jid, boolean reportSpam) { final IqPacket iq = new IqPacket(IqPacket.TYPE.SET); final Element block = iq.addChild("block", Namespace.BLOCKING); - final Element item = block.addChild("item").setAttribute("jid", jid.toEscapedString()); + final Element item = block.addChild("item").setAttribute("jid", jid); if (reportSpam) { item.addChild("report", "urn:xmpp:reporting:0").addChild("spam"); } @@ -345,13 +345,13 @@ public class IqGenerator extends AbstractGenerator { public IqPacket generateSetUnblockRequest(final Jid jid) { final IqPacket iq = new IqPacket(IqPacket.TYPE.SET); final Element block = iq.addChild("unblock", Namespace.BLOCKING); - block.addChild("item").setAttribute("jid", jid.toEscapedString()); + block.addChild("item").setAttribute("jid", jid); return iq; } public IqPacket generateSetPassword(final Account account, final String newPassword) { final IqPacket packet = new IqPacket(IqPacket.TYPE.SET); - packet.setTo(Jid.of(account.getServer())); + packet.setTo(account.getDomain()); final Element query = packet.addChild("query", Namespace.REGISTER); final Jid jid = account.getJid(); query.addChild("username").setContent(jid.getLocal()); @@ -372,7 +372,7 @@ public class IqGenerator extends AbstractGenerator { Element query = packet.query("http://jabber.org/protocol/muc#admin"); for (Jid jid : jids) { Element item = query.addChild("item"); - item.setAttribute("jid", jid.toEscapedString()); + item.setAttribute("jid", jid); item.setAttribute("affiliation", affiliation); } return packet; @@ -442,7 +442,7 @@ public class IqGenerator extends AbstractGenerator { public IqPacket generateCreateAccountWithCaptcha(Account account, String id, Data data) { final IqPacket register = new IqPacket(IqPacket.TYPE.SET); register.setFrom(account.getJid().asBareJid()); - register.setTo(Jid.of(account.getServer())); + register.setTo(account.getDomain()); register.setId(id); Element query = register.query(Namespace.REGISTER); if (data != null) { @@ -489,7 +489,7 @@ public class IqGenerator extends AbstractGenerator { public IqPacket enablePush(final Jid jid, final String node, final String secret) { IqPacket packet = new IqPacket(IqPacket.TYPE.SET); Element enable = packet.addChild("enable", Namespace.PUSH); - enable.setAttribute("jid", jid.toString()); + enable.setAttribute("jid", jid); enable.setAttribute("node", node); if (secret != null) { Data data = new Data(); @@ -504,7 +504,7 @@ public class IqGenerator extends AbstractGenerator { public IqPacket disablePush(final Jid jid, final String node) { IqPacket packet = new IqPacket(IqPacket.TYPE.SET); Element disable = packet.addChild("disable", Namespace.PUSH); - disable.setAttribute("jid", jid.toEscapedString()); + disable.setAttribute("jid", jid); disable.setAttribute("node", node); return packet; } diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java index 6969e4a5e..1a4454cc5 100644 --- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java @@ -23,7 +23,7 @@ import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager; import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection; import eu.siacs.conversations.xmpp.jingle.Media; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class MessageGenerator extends AbstractGenerator { private static final String OMEMO_FALLBACK_MESSAGE = "I sent you an OMEMO encrypted message but your client doesn’t seem to support that. Find more information on https://conversations.im/omemo"; @@ -198,7 +198,7 @@ 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.getJid().asBareJid().toString()); + x.setAttribute("jid", conversation.getJid().asBareJid()); String password = conversation.getMucOptions().getPassword(); if (password != null) { x.setAttribute("password", password); diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java index 317c2cead..e01eb2578 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java @@ -32,7 +32,7 @@ import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.FileWriterException; import eu.siacs.conversations.utils.WakeLockHelper; import eu.siacs.conversations.xmpp.stanzas.IqPacket; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class HttpDownloadConnection implements Transferable { @@ -265,7 +265,7 @@ public class HttpDownloadConnection implements Transferable { private void retrieveUrl() { changeStatus(STATUS_CHECKING); final Account account = message.getConversation().getAccount(); - IqPacket request = mXmppConnectionService.getIqGenerator().requestP1S3Url(Jid.of(account.getJid().getDomain()), mUrl.getHost()); + IqPacket request = mXmppConnectionService.getIqGenerator().requestP1S3Url(account.getDomain(), mUrl.getHost()); mXmppConnectionService.sendIqPacket(message.getConversation().getAccount(), request, (a, packet) -> { if (packet.getType() == IqPacket.TYPE.RESULT) { String download = packet.query().getAttribute("download"); diff --git a/src/main/java/eu/siacs/conversations/http/SlotRequester.java b/src/main/java/eu/siacs/conversations/http/SlotRequester.java index c0717c72e..d9f4cdc20 100644 --- a/src/main/java/eu/siacs/conversations/http/SlotRequester.java +++ b/src/main/java/eu/siacs/conversations/http/SlotRequester.java @@ -31,7 +31,6 @@ package eu.siacs.conversations.http; import android.util.Log; -import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; @@ -44,7 +43,7 @@ import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.stanzas.IqPacket; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class SlotRequester { @@ -62,7 +61,7 @@ public class SlotRequester { Jid host = account.getXmppConnection().findDiscoItemByFeature(Namespace.HTTP_UPLOAD_LEGACY); requestHttpUploadLegacy(account, host, file, mime, callback); } else { - requestP1S3(account, Jid.of(account.getServer()), file.getName(), md5, callback); + requestP1S3(account, account.getDomain(), file.getName(), md5, callback); } } diff --git a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java index 47a1e18a1..5136481a7 100644 --- a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java +++ b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java @@ -16,7 +16,7 @@ import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.InvalidJid; import eu.siacs.conversations.xmpp.stanzas.AbstractStanza; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public abstract class AbstractParser { @@ -106,7 +106,7 @@ public abstract class AbstractParser { public static MucOptions.User parseItem(Conversation conference, Element item, Jid fullJid) { final String local = conference.getJid().getLocal(); - final String domain = conference.getJid().getDomain(); + final String domain = conference.getJid().getDomain().toEscapedString(); String affiliation = item.getAttribute("affiliation"); String role = item.getAttribute("role"); String nick = item.getAttribute("nick"); diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java index dee740d9f..120c80b9a 100644 --- a/src/main/java/eu/siacs/conversations/parser/IqParser.java +++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java @@ -39,7 +39,7 @@ import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.forms.Data; import eu.siacs.conversations.xmpp.stanzas.IqPacket; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class IqParser extends AbstractParser implements OnIqPacketReceived { diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 1019a708a..40bd1b370 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -48,7 +48,7 @@ import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager; import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection; import eu.siacs.conversations.xmpp.pep.Avatar; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class MessageParser extends AbstractParser implements OnMessagePacketReceived { diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index 9e7555a6f..4e862ddf6 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -25,7 +25,7 @@ import eu.siacs.conversations.xmpp.InvalidJid; import eu.siacs.conversations.xmpp.OnPresencePacketReceived; import eu.siacs.conversations.xmpp.pep.Avatar; import eu.siacs.conversations.xmpp.stanzas.PresencePacket; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class PresenceParser extends AbstractParser implements OnPresencePacketReceived { diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index aab2d31e5..f2a59348e 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -58,7 +58,7 @@ import eu.siacs.conversations.utils.MimeUtils; import eu.siacs.conversations.utils.Resolver; import eu.siacs.conversations.xmpp.InvalidJid; import eu.siacs.conversations.xmpp.mam.MamReference; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class DatabaseBackend extends SQLiteOpenHelper { @@ -621,7 +621,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { cursor.getString(cursor.getColumnIndex(Account.USERNAME)), cursor.getString(cursor.getColumnIndex(Account.SERVER)), null - ).getDomain(); + ).getDomain().toEscapedString(); } catch (IllegalArgumentException ignored) { Log.e(Config.LOGTAG, "Failed to migrate Account SERVER " + cursor.getString(cursor.getColumnIndex(Account.SERVER)) @@ -858,7 +858,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { public List getRelativeFilePaths(String account, Jid jid, int limit) { SQLiteDatabase db = this.getReadableDatabase(); final String SQL = "select uuid,relativeFilePath from messages where type in (1,2,5) and deleted=0 and "+Message.RELATIVE_FILE_PATH+" is not null and conversationUuid=(select uuid from conversations where accountUuid=? and (contactJid=? or contactJid like ?)) order by timeSent desc"; - final String[] args = {account, jid.toEscapedString(), jid.toEscapedString() + "/%"}; + final String[] args = {account, jid.toString(), jid.toString() + "/%"}; Cursor cursor = db.rawQuery(SQL + (limit > 0 ? " limit " + String.valueOf(limit) : ""), args); List filesPaths = new ArrayList<>(); while (cursor.moveToNext()) { diff --git a/src/main/java/eu/siacs/conversations/services/AvatarService.java b/src/main/java/eu/siacs/conversations/services/AvatarService.java index 8f7f8afb4..92835b8a9 100644 --- a/src/main/java/eu/siacs/conversations/services/AvatarService.java +++ b/src/main/java/eu/siacs/conversations/services/AvatarService.java @@ -39,11 +39,10 @@ import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.RawBlockable; import eu.siacs.conversations.entities.Room; -import eu.siacs.conversations.http.services.MuclumbusService; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded; import eu.siacs.conversations.xmpp.XmppConnection; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class AvatarService implements OnAdvancedStreamFeaturesLoaded { diff --git a/src/main/java/eu/siacs/conversations/services/BarcodeProvider.java b/src/main/java/eu/siacs/conversations/services/BarcodeProvider.java index fb7f7c951..bc9608ea3 100644 --- a/src/main/java/eu/siacs/conversations/services/BarcodeProvider.java +++ b/src/main/java/eu/siacs/conversations/services/BarcodeProvider.java @@ -14,7 +14,6 @@ import android.os.CancellationSignal; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; import android.util.Log; import com.google.zxing.BarcodeFormat; @@ -32,7 +31,7 @@ import java.util.Hashtable; import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.utils.CryptoHelper; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class BarcodeProvider extends ContentProvider implements ServiceConnection { diff --git a/src/main/java/eu/siacs/conversations/services/ChannelDiscoveryService.java b/src/main/java/eu/siacs/conversations/services/ChannelDiscoveryService.java index f01bd72cc..dd390eb1e 100644 --- a/src/main/java/eu/siacs/conversations/services/ChannelDiscoveryService.java +++ b/src/main/java/eu/siacs/conversations/services/ChannelDiscoveryService.java @@ -10,7 +10,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.concurrent.Executors; @@ -23,8 +22,6 @@ import eu.siacs.conversations.entities.Room; import eu.siacs.conversations.http.HttpConnectionManager; import eu.siacs.conversations.http.services.MuclumbusService; import eu.siacs.conversations.parser.IqParser; -import eu.siacs.conversations.utils.LanguageUtils; -import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.stanzas.IqPacket; @@ -35,7 +32,7 @@ import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class ChannelDiscoveryService { diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index 5dce21e95..fd05a5282 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -15,13 +15,12 @@ import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Conversational; import eu.siacs.conversations.entities.ReceiptRequest; import eu.siacs.conversations.generator.AbstractGenerator; -import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded; import eu.siacs.conversations.xmpp.mam.MamReference; import eu.siacs.conversations.xmpp.stanzas.IqPacket; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { diff --git a/src/main/java/eu/siacs/conversations/services/MessageSearchTask.java b/src/main/java/eu/siacs/conversations/services/MessageSearchTask.java index 338af5cbe..6fd2413f8 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageSearchTask.java +++ b/src/main/java/eu/siacs/conversations/services/MessageSearchTask.java @@ -34,7 +34,6 @@ import android.os.SystemClock; import android.util.Log; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -49,7 +48,7 @@ import eu.siacs.conversations.ui.interfaces.OnSearchResultsAvailable; import eu.siacs.conversations.utils.Cancellable; import eu.siacs.conversations.utils.MessageUtils; import eu.siacs.conversations.utils.ReplacingSerialSingleThreadExecutor; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class MessageSearchTask implements Runnable, Cancellable { diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index e98657e11..7cadb1566 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -1109,7 +1109,7 @@ public class NotificationService { return; } else if (errors.size() == 1) { mBuilder.setContentTitle(mXmppConnectionService.getString(R.string.problem_connecting_to_account)); - mBuilder.setContentText(errors.get(0).getJid().asBareJid().toString()); + mBuilder.setContentText(errors.get(0).getJid().asBareJid().toEscapedString()); } else { mBuilder.setContentTitle(mXmppConnectionService.getString(R.string.problem_connecting_to_accounts)); mBuilder.setContentText(mXmppConnectionService.getString(R.string.touch_to_fix)); diff --git a/src/main/java/eu/siacs/conversations/services/ShortcutService.java b/src/main/java/eu/siacs/conversations/services/ShortcutService.java index e90fcc245..9908879e7 100644 --- a/src/main/java/eu/siacs/conversations/services/ShortcutService.java +++ b/src/main/java/eu/siacs/conversations/services/ShortcutService.java @@ -20,7 +20,7 @@ import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.ui.StartConversationActivity; import eu.siacs.conversations.utils.ReplacingSerialSingleThreadExecutor; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class ShortcutService { @@ -116,13 +116,13 @@ public class ShortcutService { } private static String getShortcutId(Contact contact) { - return contact.getAccount().getJid().asBareJid().toString()+"#"+contact.getJid().asBareJid().toString(); + return contact.getAccount().getJid().asBareJid().toEscapedString()+"#"+contact.getJid().asBareJid().toEscapedString(); } private Intent getShortcutIntent(Contact contact) { Intent intent = new Intent(xmppConnectionService, StartConversationActivity.class); intent.setAction(Intent.ACTION_VIEW); - intent.setData(Uri.parse("xmpp:"+contact.getJid().asBareJid().toString())); + intent.setData(Uri.parse("xmpp:"+contact.getJid().asBareJid().toEscapedString())); intent.putExtra("account",contact.getAccount().getJid().asBareJid().toString()); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP| Intent.FLAG_ACTIVITY_SINGLE_TOP); return intent; diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 4b1c5c2ff..694a49bed 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -155,7 +155,7 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; import eu.siacs.conversations.xmpp.stanzas.PresencePacket; import me.leolin.shortcutbadger.ShortcutBadger; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class XmppConnectionService extends Service { @@ -2196,15 +2196,16 @@ public class XmppConnectionService extends Service { return; } if (findAccountByJid(info.first) == null) { - Account account = new Account(info.first, ""); + final Account account = new Account(info.first, ""); account.setPrivateKeyAlias(alias); account.setOption(Account.OPTION_DISABLED, true); + account.setOption(Account.OPTION_FIXED_USERNAME, true); account.setDisplayName(info.second); createAccount(account); callback.onAccountCreated(account); if (Config.X509_VERIFICATION) { try { - getMemorizingTrustManager().getNonInteractive(account.getJid().getDomain()).checkClientTrusted(chain, "RSA"); + getMemorizingTrustManager().getNonInteractive(account.getServer()).checkClientTrusted(chain, "RSA"); } catch (CertificateException e) { callback.informUser(R.string.certificate_chain_is_not_trusted); } @@ -2213,7 +2214,6 @@ public class XmppConnectionService extends Service { callback.informUser(R.string.account_already_exists); } } catch (Exception e) { - e.printStackTrace(); callback.informUser(R.string.unable_to_parse_certificate); } }).start(); @@ -2821,7 +2821,7 @@ public class XmppConnectionService extends Service { boolean changed = false; for (ListIterator iterator = cryptoTargets.listIterator(); iterator.hasNext(); ) { Jid jid = iterator.next(); - if (!members.contains(jid) && !members.contains(Jid.ofDomain(jid.getDomain()))) { + if (!members.contains(jid) && !members.contains(jid.getDomain())) { iterator.remove(); Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": removed " + jid + " from crypto targets of " + conversation.getName()); changed = true; @@ -3751,7 +3751,7 @@ public class XmppConnectionService extends Service { if (account.getStatus() == Account.State.ONLINE) { IqPacket iq = new IqPacket(IqPacket.TYPE.SET); Element item = iq.query(Namespace.ROSTER).addChild("item"); - item.setAttribute("jid", contact.getJid().toString()); + item.setAttribute("jid", contact.getJid()); item.setAttribute("subscription", "remove"); account.getXmppConnection().sendIqPacket(iq, mDefaultIqHandler); } @@ -4160,7 +4160,7 @@ public class XmppConnectionService extends Service { mucServers.addAll(account.getXmppConnection().getMucServers()); for (Bookmark bookmark : account.getBookmarks()) { final Jid jid = bookmark.getJid(); - final String s = jid == null ? null : jid.getDomain(); + final String s = jid == null ? null : jid.getDomain().toEscapedString(); if (s != null) { mucServers.add(s); } diff --git a/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java b/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java index 68d302b03..f9858874a 100644 --- a/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java +++ b/src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java @@ -3,9 +3,6 @@ package eu.siacs.conversations.ui; import android.databinding.DataBindingUtil; import android.support.annotation.StringRes; import android.support.v7.app.AlertDialog; -import android.text.SpannableString; -import android.text.Spanned; -import android.text.style.TypefaceSpan; import android.view.View; import android.widget.Toast; @@ -14,7 +11,7 @@ import eu.siacs.conversations.databinding.DialogBlockContactBinding; import eu.siacs.conversations.entities.Blockable; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.ui.util.JidDialog; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public final class BlockContactDialog { public static void show(final XmppActivity xmppActivity, final Blockable blockable) { diff --git a/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java b/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java index df091e7df..f0aef4741 100644 --- a/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java @@ -11,12 +11,11 @@ import java.util.Collections; 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.ListItem; import eu.siacs.conversations.entities.RawBlockable; import eu.siacs.conversations.ui.interfaces.OnBackendConnected; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class BlocklistActivity extends AbstractSearchableListItemActivity implements OnUpdateBlocklist { @@ -80,7 +79,7 @@ public class BlocklistActivity extends AbstractSearchableListItemActivity implem getString(R.string.block_jabber_id), getString(R.string.block), null, - account.getJid().asBareJid().toString(), + account.getJid().asBareJid().toEscapedString(), true, false ); diff --git a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java index df129152b..c0b97759d 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java @@ -38,7 +38,7 @@ import eu.siacs.conversations.ui.util.PendingItem; import eu.siacs.conversations.ui.util.SoftKeyboardUtils; import eu.siacs.conversations.ui.util.StyledAttributes; import eu.siacs.conversations.utils.AccountUtils; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.OnActionExpandListener, TextView.OnEditorActionListener, ChannelDiscoveryService.OnChannelSearchResultsFound, ChannelSearchResultAdapter.OnChannelSearchResultSelected { @@ -263,7 +263,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O } public void joinChannelSearchResult(String selectedAccount, Room result) { - final Jid jid = Config.DOMAIN_LOCK == null ? Jid.of(selectedAccount) : Jid.of(selectedAccount, Config.DOMAIN_LOCK, null); + final Jid jid = Config.DOMAIN_LOCK == null ? Jid.ofEscaped(selectedAccount) : Jid.ofEscaped(selectedAccount, Config.DOMAIN_LOCK, null); final boolean syncAutoJoin = getBooleanPreference("autojoin", R.bool.autojoin); final Account account = xmppConnectionService.findAccountByJid(jid); final Conversation conversation = xmppConnectionService.findOrCreateConversation(account, result.getRoom(), true, true, true); diff --git a/src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java index fca082c42..a7e0e5fcb 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java @@ -3,7 +3,6 @@ package eu.siacs.conversations.ui; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.ActionBar; import android.widget.ListView; import android.widget.Toast; @@ -12,9 +11,7 @@ import java.util.List; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; -import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.ui.adapter.AccountAdapter; -import rocks.xmpp.addr.Jid; public class ChooseAccountForProfilePictureActivity extends XmppActivity { diff --git a/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java b/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java index df2f7d849..afda66709 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java @@ -39,7 +39,7 @@ import eu.siacs.conversations.ui.interfaces.OnBackendConnected; import eu.siacs.conversations.ui.util.ActivityResult; import eu.siacs.conversations.ui.util.PendingItem; import eu.siacs.conversations.utils.XmppUri; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class ChooseContactActivity extends AbstractSearchableListItemActivity implements MultiChoiceModeListener, AdapterView.OnItemClickListener { public static final String EXTRA_TITLE_RES_ID = "extra_title_res_id"; @@ -361,9 +361,9 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im for (Account account : xmppConnectionService.getAccounts()) { if (account.getStatus() != Account.State.DISABLED) { if (Config.DOMAIN_LOCK != null) { - this.mActivatedAccounts.add(account.getJid().getLocal()); + this.mActivatedAccounts.add(account.getJid().getEscapedLocal()); } else { - this.mActivatedAccounts.add(account.getJid().asBareJid().toString()); + this.mActivatedAccounts.add(account.getJid().asBareJid().toEscapedString()); } } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index abfae615b..946a066fb 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -3,7 +3,6 @@ package eu.siacs.conversations.ui; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; -import android.content.IntentSender.SendIntentException; import android.databinding.DataBindingUtil; import android.os.Bundle; import android.support.v7.app.AlertDialog; @@ -23,7 +22,6 @@ import java.util.concurrent.atomic.AtomicInteger; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; -import eu.siacs.conversations.crypto.PgpEngine; import eu.siacs.conversations.databinding.ActivityMucDetailsBinding; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Bookmark; @@ -51,7 +49,7 @@ import eu.siacs.conversations.utils.StringUtils; import eu.siacs.conversations.utils.StylingHelper; import eu.siacs.conversations.utils.XmppUri; import me.drakeet.support.toast.ToastCompat; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; import static eu.siacs.conversations.entities.Bookmark.printableValue; import static eu.siacs.conversations.utils.StringUtils.changed; @@ -447,9 +445,9 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers final User self = mucOptions.getSelf(); String account; if (Config.DOMAIN_LOCK != null) { - account = mConversation.getAccount().getJid().getLocal(); + account = mConversation.getAccount().getJid().getEscapedLocal(); } else { - account = mConversation.getAccount().getJid().asBareJid().toString(); + account = mConversation.getAccount().getJid().asBareJid().toEscapedString(); } setTitle(mucOptions.isPrivateAndNonAnonymous() ? R.string.action_muc_details : R.string.channel_details); this.binding.editMucNameButton.setVisibility((self.getAffiliation().ranks(MucOptions.Affiliation.OWNER) || mucOptions.canChangeSubject()) ? View.VISIBLE : View.GONE); @@ -586,7 +584,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers @Override public void onAffiliationChangeFailed(Jid jid, int resId) { - displayToast(getString(resId, jid.asBareJid().toString())); + displayToast(getString(resId, jid.asBareJid().toEscapedString())); } @Override diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java index 2d4129bbd..caeb1e6e2 100644 --- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java @@ -60,7 +60,7 @@ import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.XmppConnection; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class ContactDetailsActivity extends OmemoActivity implements OnAccountUpdate, OnRosterUpdate, OnUpdateBlocklist, OnKeyStatusUpdated, OnMediaLoaded { public static final String ACTION_VIEW_CONTACT = "view_contact"; @@ -136,7 +136,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp AlertDialog.Builder builder = new AlertDialog.Builder( ContactDetailsActivity.this); builder.setTitle(getString(R.string.action_add_phone_book)); - builder.setMessage(getString(R.string.add_phone_book_text, contact.getJid().toString())); + builder.setMessage(getString(R.string.add_phone_book_text, contact.getJid().toEscapedString())); builder.setNegativeButton(getString(R.string.cancel), null); builder.setPositiveButton(getString(R.string.add), addToPhonebook); builder.create().show(); @@ -411,9 +411,9 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp binding.detailsContactjid.setText(IrregularUnicodeDetector.style(this, contact.getJid())); String account; if (Config.DOMAIN_LOCK != null) { - account = contact.getAccount().getJid().getLocal(); + account = contact.getAccount().getJid().getEscapedLocal(); } else { - account = contact.getAccount().getJid().asBareJid().toString(); + account = contact.getAccount().getJid().asBareJid().toEscapedString(); } binding.detailsAccount.setText(getString(R.string.using_account, account)); AvatarWorkerTask.loadAvatar(contact, binding.detailsContactBadge, R.dimen.avatar_on_details_screen_size); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index fb5b9cd04..56c16b31f 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -56,6 +56,7 @@ import com.google.common.base.Optional; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; @@ -123,7 +124,7 @@ import eu.siacs.conversations.xmpp.jingle.JingleFileTransferConnection; import eu.siacs.conversations.xmpp.jingle.Media; import eu.siacs.conversations.xmpp.jingle.OngoingRtpSession; import eu.siacs.conversations.xmpp.jingle.RtpCapability; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; import static eu.siacs.conversations.ui.XmppActivity.EXTRA_ACCOUNT; import static eu.siacs.conversations.ui.XmppActivity.REQUEST_INVITE_TO_CONVERSATION; @@ -863,13 +864,13 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke } private void commitAttachments() { - if (!hasPermissions(REQUEST_COMMIT_ATTACHMENTS, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + final List attachments = mediaPreviewAdapter.getAttachments(); + if (anyNeedsExternalStoragePermission(attachments) && !hasPermissions(REQUEST_COMMIT_ATTACHMENTS, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { return; } if (conversation.getNextEncryption() == Message.ENCRYPTION_AXOLOTL && trustKeysIfNeeded(REQUEST_TRUST_KEYS_ATTACHMENTS)) { return; } - final List attachments = mediaPreviewAdapter.getAttachments(); final PresenceSelector.OnPresenceSelected callback = () -> { for (Iterator i = attachments.iterator(); i.hasNext(); i.remove()) { final Attachment attachment = i.next(); @@ -896,6 +897,16 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke } } + + private static boolean anyNeedsExternalStoragePermission(final Collection attachments) { + for(final Attachment attachment : attachments) { + if (attachment.getType() != Attachment.Type.LOCATION) { + return true; + } + } + return false; + } + public void toggleInputMethod() { boolean hasAttachments = mediaPreviewAdapter.hasAttachments(); binding.textinput.setVisibility(hasAttachments ? View.GONE : View.VISIBLE); @@ -962,6 +973,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke final MenuItem menuCall = menu.findItem(R.id.action_call); final MenuItem menuOngoingCall = menu.findItem(R.id.action_ongoing_call); final MenuItem menuVideoCall = menu.findItem(R.id.action_video_call); + final MenuItem menuTogglePinned = menu.findItem(R.id.action_toggle_pinned); if (conversation != null) { @@ -994,6 +1006,11 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke } ConversationMenuConfigurator.configureAttachmentMenu(conversation, menu); ConversationMenuConfigurator.configureEncryptionMenu(conversation, menu); + if (conversation.getBooleanAttribute(Conversation.ATTRIBUTE_PINNED_ON_TOP, false)) { + menuTogglePinned.setTitle(R.string.remove_from_favorites); + } else { + menuTogglePinned.setTitle(R.string.add_to_favorites); + } } super.onCreateOptionsMenu(menu, menuInflater); } @@ -1261,6 +1278,9 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke case R.id.action_ongoing_call: returnToOngoingCall(); break; + case R.id.action_toggle_pinned: + togglePinned(); + break; default: break; } @@ -1289,6 +1309,12 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke } + private void togglePinned() { + final boolean pinned = conversation.getBooleanAttribute(Conversation.ATTRIBUTE_PINNED_ON_TOP, false); + conversation.setAttribute(Conversation.ATTRIBUTE_PINNED_ON_TOP, !pinned); + activity.xmppConnectionService.updateConversation(conversation); + } + private void checkPermissionAndTriggerAudioCall() { if (activity.mUseTor || conversation.getAccount().isOnion()) { Toast.makeText(activity, R.string.disable_tor_to_make_call, Toast.LENGTH_SHORT).show(); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java index cd6a1d8e6..43addb299 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java @@ -81,7 +81,7 @@ import eu.siacs.conversations.utils.ExceptionHelper; import eu.siacs.conversations.utils.SignupUtils; import eu.siacs.conversations.utils.XmppUri; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; import static eu.siacs.conversations.ui.ConversationFragment.REQUEST_DECRYPT_PGP; diff --git a/src/main/java/eu/siacs/conversations/ui/CreatePublicChannelDialog.java b/src/main/java/eu/siacs/conversations/ui/CreatePublicChannelDialog.java index 6b8c58cf3..90ecb6df0 100644 --- a/src/main/java/eu/siacs/conversations/ui/CreatePublicChannelDialog.java +++ b/src/main/java/eu/siacs/conversations/ui/CreatePublicChannelDialog.java @@ -15,7 +15,6 @@ import android.text.TextWatcher; import android.view.View; import android.widget.AdapterView; import android.widget.Button; -import android.widget.Spinner; import java.security.SecureRandom; import java.util.ArrayList; @@ -23,7 +22,6 @@ import java.util.Collection; import java.util.List; import eu.siacs.conversations.R; -import eu.siacs.conversations.databinding.CreateConferenceDialogBinding; import eu.siacs.conversations.databinding.CreatePublicChannelDialogBinding; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.services.XmppConnectionService; @@ -32,7 +30,7 @@ import eu.siacs.conversations.ui.interfaces.OnBackendConnected; import eu.siacs.conversations.ui.util.DelayedHintHelper; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.xmpp.XmppConnection; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class CreatePublicChannelDialog extends DialogFragment implements OnBackendConnected { diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 9e829e041..89de15d0b 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -75,7 +75,7 @@ import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.XmppConnection.Features; import eu.siacs.conversations.xmpp.forms.Data; import eu.siacs.conversations.xmpp.pep.Avatar; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class EditAccountActivity extends OmemoActivity implements OnAccountUpdate, OnUpdateBlocklist, OnKeyStatusUpdated, OnCaptchaRequested, KeyChainAliasCallback, XmppConnectionService.OnShowErrorToast, XmppConnectionService.OnMamPreferencesFetched { @@ -201,9 +201,9 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat final Jid jid; try { if (mUsernameMode) { - jid = Jid.of(binding.accountJid.getText().toString(), getUserModeDomain(), null); + jid = Jid.ofEscaped(binding.accountJid.getText().toString(), getUserModeDomain(), null); } else { - jid = Jid.of(binding.accountJid.getText().toString()); + jid = Jid.ofEscaped(binding.accountJid.getText().toString()); } } catch (final NullPointerException | IllegalArgumentException e) { if (mUsernameMode) { @@ -577,9 +577,9 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat protected boolean jidEdited() { final String unmodified; if (mUsernameMode) { - unmodified = this.mAccount.getJid().getLocal(); + unmodified = this.mAccount.getJid().getEscapedLocal(); } else { - unmodified = this.mAccount.getJid().asBareJid().toString(); + unmodified = this.mAccount.getJid().asBareJid().toEscapedString(); } return !unmodified.equals(this.binding.accountJid.getText().toString()); } @@ -784,12 +784,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat this.mInitMode |= this.mAccount.isOptionSet(Account.OPTION_REGISTER); this.mUsernameMode |= mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) && mAccount.isOptionSet(Account.OPTION_REGISTER); - if (this.mAccount.getPrivateKeyAlias() != null) { - this.binding.accountPassword.setHint(R.string.authenticate_with_certificate); - if (this.mInitMode) { - this.binding.accountPassword.requestFocus(); - } - } if (mPendingFingerprintVerificationUri != null) { processFingerprintVerification(mPendingFingerprintVerificationUri, false); mPendingFingerprintVerificationUri = null; @@ -822,7 +816,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat private String getUserModeDomain() { if (mAccount != null && mAccount.getJid().getDomain() != null) { - return mAccount.getJid().getDomain(); + return mAccount.getServer(); } else { return Config.DOMAIN_LOCK; } @@ -965,9 +959,9 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat if (init) { this.binding.accountJid.getEditableText().clear(); if (mUsernameMode) { - this.binding.accountJid.getEditableText().append(this.mAccount.getJid().getLocal()); + this.binding.accountJid.getEditableText().append(this.mAccount.getJid().getEscapedLocal()); } else { - this.binding.accountJid.getEditableText().append(this.mAccount.getJid().asBareJid().toString()); + this.binding.accountJid.getEditableText().append(this.mAccount.getJid().asBareJid().toEscapedString()); } this.binding.accountPassword.getEditableText().clear(); this.binding.accountPassword.getEditableText().append(this.mAccount.getPassword()); diff --git a/src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java b/src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java index 89cd56b6f..83d6d4a0c 100644 --- a/src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java +++ b/src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java @@ -24,7 +24,7 @@ import eu.siacs.conversations.databinding.EnterJidDialogBinding; import eu.siacs.conversations.ui.adapter.KnownHostsAdapter; import eu.siacs.conversations.ui.interfaces.OnBackendConnected; import eu.siacs.conversations.ui.util.DelayedHintHelper; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class EnterJidDialog extends DialogFragment implements OnBackendConnected, TextWatcher { @@ -146,16 +146,16 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected } try { if (Config.DOMAIN_LOCK != null) { - accountJid = Jid.of((String) binding.account.getSelectedItem(), Config.DOMAIN_LOCK, null); + accountJid = Jid.ofEscaped((String) binding.account.getSelectedItem(), Config.DOMAIN_LOCK, null); } else { - accountJid = Jid.of((String) binding.account.getSelectedItem()); + accountJid = Jid.ofEscaped((String) binding.account.getSelectedItem()); } } catch (final IllegalArgumentException e) { return; } final Jid contactJid; try { - contactJid = Jid.of(binding.jid.getText().toString()); + contactJid = Jid.ofEscaped(binding.jid.getText().toString()); } catch (final IllegalArgumentException e) { binding.jidLayout.setError(getActivity().getString(R.string.invalid_jid)); return; @@ -168,7 +168,7 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected issuedWarning = true; return; } - if (suspiciousSubDomain(contactJid.getDomain())) { + if (suspiciousSubDomain(contactJid.getDomain().toEscapedString())) { binding.jidLayout.setError(getActivity().getString(R.string.this_looks_like_channel)); dialog.getButton(AlertDialog.BUTTON_POSITIVE).setText(R.string.add_anway); issuedWarning = true; diff --git a/src/main/java/eu/siacs/conversations/ui/MediaBrowserActivity.java b/src/main/java/eu/siacs/conversations/ui/MediaBrowserActivity.java index 02855216f..ba5102886 100644 --- a/src/main/java/eu/siacs/conversations/ui/MediaBrowserActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/MediaBrowserActivity.java @@ -18,7 +18,7 @@ import eu.siacs.conversations.ui.adapter.MediaAdapter; import eu.siacs.conversations.ui.interfaces.OnMediaLoaded; import eu.siacs.conversations.ui.util.Attachment; import eu.siacs.conversations.ui.util.GridManager; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class MediaBrowserActivity extends XmppActivity implements OnMediaLoaded { @@ -49,7 +49,7 @@ public class MediaBrowserActivity extends XmppActivity implements OnMediaLoaded String account = intent == null ? null : intent.getStringExtra("account"); String jid = intent == null ? null : intent.getStringExtra("jid"); if (account != null && jid != null) { - xmppConnectionService.getAttachments(account, Jid.of(jid), 0, this); + xmppConnectionService.getAttachments(account, Jid.ofEscaped(jid), 0, this); } } diff --git a/src/main/java/eu/siacs/conversations/ui/MucUsersActivity.java b/src/main/java/eu/siacs/conversations/ui/MucUsersActivity.java index a40a4c385..298741651 100644 --- a/src/main/java/eu/siacs/conversations/ui/MucUsersActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/MucUsersActivity.java @@ -27,7 +27,7 @@ import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.ui.adapter.UserAdapter; import eu.siacs.conversations.ui.util.MucDetailsContextMenuHelper; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class MucUsersActivity extends XmppActivity implements XmppConnectionService.OnMucRosterUpdate, XmppConnectionService.OnAffiliationChanged, MenuItem.OnActionExpandListener, TextWatcher { diff --git a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java index 56b622a92..a6ac2ba1b 100644 --- a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java @@ -54,7 +54,7 @@ import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection; import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection; import eu.siacs.conversations.xmpp.jingle.Media; import eu.siacs.conversations.xmpp.jingle.RtpEndUserState; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; import static eu.siacs.conversations.utils.PermissionUtils.getFirstDenied; import static java.util.Arrays.asList; @@ -129,7 +129,7 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe final Intent intent = getIntent(); final String action = intent.getAction(); final Account account = extractAccount(intent); - final Jid with = Jid.of(intent.getStringExtra(EXTRA_WITH)); + final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH)); final String state = intent.getStringExtra(EXTRA_LAST_REPORTED_STATE); if (!Intent.ACTION_VIEW.equals(action) || state == null || !END_CARD.contains(RtpEndUserState.valueOf(state))) { resetIntent(account, with, RtpEndUserState.RETRACTED, actionToMedia(intent.getAction())); @@ -246,7 +246,7 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe return; } final Account account = extractAccount(intent); - final Jid with = Jid.of(intent.getStringExtra(EXTRA_WITH)); + final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH)); final String sessionId = intent.getStringExtra(EXTRA_SESSION_ID); if (sessionId != null) { Log.d(Config.LOGTAG, "reinitializing from onNewIntent()"); @@ -268,7 +268,7 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe final Intent intent = getIntent(); final String action = intent.getAction(); final Account account = extractAccount(intent); - final Jid with = Jid.of(intent.getStringExtra(EXTRA_WITH)); + final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH)); final String sessionId = intent.getStringExtra(EXTRA_SESSION_ID); if (sessionId != null) { if (initializeActivityWithRunningRtpSession(account, with, sessionId)) { @@ -831,7 +831,7 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe Log.d(Config.LOGTAG, "attempting retry"); final Intent intent = getIntent(); final Account account = extractAccount(intent); - final Jid with = Jid.of(intent.getStringExtra(EXTRA_WITH)); + final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH)); final String lastAction = intent.getStringExtra(EXTRA_LAST_ACTION); final String action = intent.getAction(); final Set media = actionToMedia(lastAction == null ? action : lastAction); diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java index 73c10a6ab..1a84dcb72 100644 --- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java @@ -41,7 +41,7 @@ import eu.siacs.conversations.services.QuickConversationsService; import eu.siacs.conversations.ui.util.StyledAttributes; import eu.siacs.conversations.utils.GeoHelper; import eu.siacs.conversations.utils.TimeFrameUtils; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class SettingsActivity extends XmppActivity implements OnSharedPreferenceChangeListener { diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java index dd4ea40a2..6446f5db6 100644 --- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java @@ -12,7 +12,6 @@ import android.view.MenuItem; import android.widget.Toast; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import eu.siacs.conversations.Config; @@ -21,9 +20,7 @@ import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.ui.adapter.ConversationAdapter; -import eu.siacs.conversations.ui.service.EmojiService; -import eu.siacs.conversations.utils.GeoHelper; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class ShareWithActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate { diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index 6b9880ad5..57cc492e0 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -79,7 +79,7 @@ import eu.siacs.conversations.utils.AccountUtils; import eu.siacs.conversations.utils.XmppUri; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.XmppConnection; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class StartConversationActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, CreatePrivateGroupChatDialog.CreateConferenceDialogListener, JoinConferenceDialog.JoinConferenceDialogListener, SwipeRefreshLayout.OnRefreshListener, CreatePublicChannelDialog.CreatePublicChannelDialogListener { @@ -577,9 +577,9 @@ public class StartConversationActivity extends XmppActivity implements XmppConne Jid jid; try { if (Config.DOMAIN_LOCK != null) { - jid = Jid.of((String) spinner.getSelectedItem(), Config.DOMAIN_LOCK, null); + jid = Jid.ofEscaped((String) spinner.getSelectedItem(), Config.DOMAIN_LOCK, null); } else { - jid = Jid.of((String) spinner.getSelectedItem()); + jid = Jid.ofEscaped((String) spinner.getSelectedItem()); } } catch (final IllegalArgumentException e) { return null; @@ -855,11 +855,11 @@ public class StartConversationActivity extends XmppActivity implements XmppConne switchToConversationDoNotAppend(muc, invite.getBody()); return true; } else { - showJoinConferenceDialog(invite.getJid().asBareJid().toString()); + showJoinConferenceDialog(invite.getJid().asBareJid().toEscapedString()); return false; } } else if (contacts.size() == 0) { - showCreateContactDialog(invite.getJid().toString(), invite); + showCreateContactDialog(invite.getJid().toEscapedString(), invite); return false; } else if (contacts.size() == 1) { Contact contact = contacts.get(0); @@ -881,10 +881,10 @@ public class StartConversationActivity extends XmppActivity implements XmppConne if (mMenuSearchView != null) { mMenuSearchView.expandActionView(); mSearchEditText.setText(""); - mSearchEditText.append(invite.getJid().toString()); - filter(invite.getJid().toString()); + mSearchEditText.append(invite.getJid().toEscapedString()); + filter(invite.getJid().toEscapedString()); } else { - mInitialSearchValue.push(invite.getJid().toString()); + mInitialSearchValue.push(invite.getJid().toEscapedString()); } return true; } @@ -1017,7 +1017,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne final String input = jid.getText().toString(); Jid conferenceJid; try { - conferenceJid = Jid.of(input); + conferenceJid = Jid.ofEscaped(input); } catch (final IllegalArgumentException e) { final XmppUri xmppUri = new XmppUri(input); if (xmppUri.isValidJid() && xmppUri.isAction(XmppUri.ACTION_JOIN)) { diff --git a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java index 0fbeef6eb..0ac96fea4 100644 --- a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java @@ -38,7 +38,7 @@ import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.IrregularUnicodeDetector; import eu.siacs.conversations.utils.XmppUri; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdated { @@ -213,7 +213,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat showCameraToast(); } - binding.ownKeysTitle.setText(mAccount.getJid().asBareJid().toString()); + binding.ownKeysTitle.setText(mAccount.getJid().asBareJid().toEscapedString()); binding.ownKeysCard.setVisibility(hasOwnKeys ? View.VISIBLE : View.GONE); binding.foreignKeys.setVisibility(hasForeignKeys ? View.VISIBLE : View.GONE); if (hasPendingKeyFetches()) { diff --git a/src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java b/src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java index 9a2e7d939..0472429f6 100644 --- a/src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java @@ -19,7 +19,7 @@ import eu.siacs.conversations.R; import eu.siacs.conversations.persistance.DatabaseBackend; import eu.siacs.conversations.utils.SignupUtils; import eu.siacs.conversations.utils.XmppUri; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class UriHandlerActivity extends AppCompatActivity { diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index b2fee69f9..887d3374b 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -79,7 +79,7 @@ import eu.siacs.conversations.utils.ExceptionHelper; import eu.siacs.conversations.utils.ThemeHelper; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public abstract class XmppActivity extends ActionBarActivity { @@ -870,7 +870,7 @@ public abstract class XmppActivity extends ActionBarActivity { protected Account extractAccount(Intent intent) { final String jid = intent != null ? intent.getStringExtra(EXTRA_ACCOUNT) : null; try { - return jid != null ? xmppConnectionService.findAccountByJid(Jid.of(jid)) : null; + return jid != null ? xmppConnectionService.findAccountByJid(Jid.ofEscaped(jid)) : null; } catch (IllegalArgumentException e) { return null; } diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java index c2d84c162..73e3b4194 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java @@ -58,7 +58,7 @@ public class AccountAdapter extends ArrayAdapter { if (Config.DOMAIN_LOCK != null) { viewHolder.binding.accountJid.setText(account.getJid().getLocal()); } else { - viewHolder.binding.accountJid.setText(account.getJid().asBareJid().toString()); + viewHolder.binding.accountJid.setText(account.getJid().asBareJid().toEscapedString()); } AvatarWorkerTask.loadAvatar(account, viewHolder.binding.accountImage, R.dimen.avatar); viewHolder.binding.accountStatus.setText(getContext().getString(account.getStatus().getReadableId())); diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ChannelSearchResultAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ChannelSearchResultAdapter.java index 0f452e0b1..3c533a7a2 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ChannelSearchResultAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ChannelSearchResultAdapter.java @@ -19,7 +19,7 @@ import eu.siacs.conversations.databinding.SearchResultItemBinding; import eu.siacs.conversations.entities.Room; import eu.siacs.conversations.ui.XmppActivity; import eu.siacs.conversations.ui.util.AvatarWorkerTask; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class ChannelSearchResultAdapter extends ListAdapter implements View.OnCreateContextMenuListener { 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 1618cca7f..8aaeceafd 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java @@ -25,9 +25,8 @@ import eu.siacs.conversations.ui.util.StyledAttributes; import eu.siacs.conversations.utils.EmojiWrapper; import eu.siacs.conversations.utils.IrregularUnicodeDetector; import eu.siacs.conversations.utils.UIHelper; -import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection; import eu.siacs.conversations.xmpp.jingle.OngoingRtpSession; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class ConversationAdapter extends RecyclerView.Adapter { @@ -202,6 +201,7 @@ public class ConversationAdapter extends RecyclerView.Adapter listener.onConversationClick(v, conversation)); diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java index 9f700d54a..a0e6ded14 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java @@ -1,12 +1,7 @@ package eu.siacs.conversations.ui.adapter; import android.content.SharedPreferences; -import android.content.res.Resources; import android.databinding.DataBindingUtil; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.os.AsyncTask; import android.preference.PreferenceManager; import android.view.LayoutInflater; import android.view.View; @@ -17,9 +12,7 @@ import android.widget.TextView; import com.wefika.flowlayout.FlowLayout; -import java.lang.ref.WeakReference; import java.util.List; -import java.util.concurrent.RejectedExecutionException; import eu.siacs.conversations.R; import eu.siacs.conversations.databinding.ContactBinding; @@ -30,9 +23,7 @@ import eu.siacs.conversations.ui.util.AvatarWorkerTask; import eu.siacs.conversations.ui.util.StyledAttributes; import eu.siacs.conversations.utils.EmojiWrapper; import eu.siacs.conversations.utils.IrregularUnicodeDetector; -import eu.siacs.conversations.utils.ThemeHelper; -import eu.siacs.conversations.utils.UIHelper; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class ListItemAdapter extends ArrayAdapter { 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 2b709a67a..4218a1c3b 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -76,7 +76,7 @@ import eu.siacs.conversations.utils.StylingHelper; import eu.siacs.conversations.utils.TimeFrameUtils; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.mam.MamReference; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class MessageAdapter extends ArrayAdapter implements CopyTextView.CopyHandler { diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/UserAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/UserAdapter.java index aa0d5e172..7b61ec822 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/UserAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/UserAdapter.java @@ -24,7 +24,7 @@ import eu.siacs.conversations.ui.ConferenceDetailsActivity; import eu.siacs.conversations.ui.XmppActivity; import eu.siacs.conversations.ui.util.AvatarWorkerTask; import eu.siacs.conversations.ui.util.MucDetailsContextMenuHelper; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class UserAdapter extends ListAdapter implements View.OnCreateContextMenuListener { diff --git a/src/main/java/eu/siacs/conversations/ui/forms/FormJidSingleFieldWrapper.java b/src/main/java/eu/siacs/conversations/ui/forms/FormJidSingleFieldWrapper.java index a8f800299..0cb21ed93 100644 --- a/src/main/java/eu/siacs/conversations/ui/forms/FormJidSingleFieldWrapper.java +++ b/src/main/java/eu/siacs/conversations/ui/forms/FormJidSingleFieldWrapper.java @@ -7,7 +7,7 @@ import java.util.List; import eu.siacs.conversations.R; import eu.siacs.conversations.xmpp.forms.Field; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class FormJidSingleFieldWrapper extends FormTextFieldWrapper { diff --git a/src/main/java/eu/siacs/conversations/ui/util/MucDetailsContextMenuHelper.java b/src/main/java/eu/siacs/conversations/ui/util/MucDetailsContextMenuHelper.java index 04efcc0c5..0e848e392 100644 --- a/src/main/java/eu/siacs/conversations/ui/util/MucDetailsContextMenuHelper.java +++ b/src/main/java/eu/siacs/conversations/ui/util/MucDetailsContextMenuHelper.java @@ -24,7 +24,7 @@ import eu.siacs.conversations.ui.ConversationFragment; import eu.siacs.conversations.ui.ConversationsActivity; import eu.siacs.conversations.ui.MucUsersActivity; import eu.siacs.conversations.ui.XmppActivity; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public final class MucDetailsContextMenuHelper { diff --git a/src/main/java/eu/siacs/conversations/ui/util/PresenceSelector.java b/src/main/java/eu/siacs/conversations/ui/util/PresenceSelector.java index f4e32d637..defabcb4a 100644 --- a/src/main/java/eu/siacs/conversations/ui/util/PresenceSelector.java +++ b/src/main/java/eu/siacs/conversations/ui/util/PresenceSelector.java @@ -43,7 +43,7 @@ import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Presences; import eu.siacs.conversations.utils.CryptoHelper; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class PresenceSelector { diff --git a/src/main/java/eu/siacs/conversations/ui/util/ShareUtil.java b/src/main/java/eu/siacs/conversations/ui/util/ShareUtil.java index b39de5cf9..3abef56f7 100644 --- a/src/main/java/eu/siacs/conversations/ui/util/ShareUtil.java +++ b/src/main/java/eu/siacs/conversations/ui/util/ShareUtil.java @@ -43,7 +43,7 @@ import eu.siacs.conversations.ui.ConversationsActivity; import eu.siacs.conversations.ui.XmppActivity; import eu.siacs.conversations.utils.Patterns; import eu.siacs.conversations.utils.XmppUri; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class ShareUtil { diff --git a/src/main/java/eu/siacs/conversations/utils/AccountUtils.java b/src/main/java/eu/siacs/conversations/utils/AccountUtils.java index 475682bec..09b65f694 100644 --- a/src/main/java/eu/siacs/conversations/utils/AccountUtils.java +++ b/src/main/java/eu/siacs/conversations/utils/AccountUtils.java @@ -39,9 +39,9 @@ public class AccountUtils { for (Account account : service.getAccounts()) { if (account.getStatus() != Account.State.DISABLED) { if (Config.DOMAIN_LOCK != null) { - accounts.add(account.getJid().getLocal()); + accounts.add(account.getJid().toEscapedString()); } else { - accounts.add(account.getJid().asBareJid().toString()); + accounts.add(account.getJid().asBareJid().toEscapedString()); } } } diff --git a/src/main/java/eu/siacs/conversations/utils/BackupFileHeader.java b/src/main/java/eu/siacs/conversations/utils/BackupFileHeader.java index 5e8b80f81..212473ea4 100644 --- a/src/main/java/eu/siacs/conversations/utils/BackupFileHeader.java +++ b/src/main/java/eu/siacs/conversations/utils/BackupFileHeader.java @@ -3,9 +3,8 @@ package eu.siacs.conversations.utils; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.util.Arrays; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class BackupFileHeader { diff --git a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java index 2b15812f3..0a2231389 100644 --- a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java @@ -24,7 +24,6 @@ import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; -import java.util.Locale; import java.util.regex.Pattern; import eu.siacs.conversations.Config; @@ -32,7 +31,7 @@ import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.http.AesGcmURLStreamHandler; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public final class CryptoHelper { diff --git a/src/main/java/eu/siacs/conversations/utils/IrregularUnicodeDetector.java b/src/main/java/eu/siacs/conversations/utils/IrregularUnicodeDetector.java index b2ef794c8..832e0dc56 100644 --- a/src/main/java/eu/siacs/conversations/utils/IrregularUnicodeDetector.java +++ b/src/main/java/eu/siacs/conversations/utils/IrregularUnicodeDetector.java @@ -53,7 +53,7 @@ import java.util.regex.Pattern; import eu.siacs.conversations.R; import eu.siacs.conversations.ui.util.StyledAttributes; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class IrregularUnicodeDetector { @@ -82,14 +82,14 @@ public class IrregularUnicodeDetector { private static Spannable style(Jid jid, @ColorInt int color) { PatternTuple patternTuple = find(jid); SpannableStringBuilder builder = new SpannableStringBuilder(); - if (jid.getLocal() != null && patternTuple.local != null) { - SpannableString local = new SpannableString(jid.getLocal()); + if (jid.getEscapedLocal() != null && patternTuple.local != null) { + SpannableString local = new SpannableString(jid.getEscapedLocal()); colorize(local, patternTuple.local, color); builder.append(local); builder.append('@'); } if (jid.getDomain() != null) { - String[] labels = jid.getDomain().split("\\."); + String[] labels = jid.getDomain().toEscapedString().split("\\."); for (int i = 0; i < labels.length; ++i) { SpannableString spannableString = new SpannableString(labels[i]); colorize(spannableString, patternTuple.domain.get(i), color); @@ -258,12 +258,12 @@ public class IrregularUnicodeDetector { private static PatternTuple of(Jid jid) { final Pattern localPattern; - if (jid.getLocal() != null) { - localPattern = create(findIrregularCodePoints(jid.getLocal())); + if (jid.getEscapedLocal() != null) { + localPattern = create(findIrregularCodePoints(jid.getEscapedLocal())); } else { localPattern = null; } - String domain = jid.getDomain(); + String domain = jid.getDomain().toEscapedString(); final List domainPatterns = new ArrayList<>(); if (domain != null) { for (String label : domain.split("\\.")) { diff --git a/src/main/java/eu/siacs/conversations/utils/JidHelper.java b/src/main/java/eu/siacs/conversations/utils/JidHelper.java index 8a1510fd2..603899fca 100644 --- a/src/main/java/eu/siacs/conversations/utils/JidHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/JidHelper.java @@ -35,7 +35,7 @@ import java.util.List; import java.util.Locale; import eu.siacs.conversations.xmpp.InvalidJid; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class JidHelper { @@ -43,7 +43,7 @@ public class JidHelper { public static String localPartOrFallback(Jid jid) { if (LOCAL_PART_BLACKLIST.contains(jid.getLocal().toLowerCase(Locale.ENGLISH))) { - final String domain = jid.getDomain(); + final String domain = jid.getDomain().toEscapedString(); final int index = domain.indexOf('.'); return index > 1 ? domain.substring(0, index) : domain; } else { diff --git a/src/main/java/eu/siacs/conversations/utils/NickValidityChecker.java b/src/main/java/eu/siacs/conversations/utils/NickValidityChecker.java index 2d645a13b..176f7fbce 100644 --- a/src/main/java/eu/siacs/conversations/utils/NickValidityChecker.java +++ b/src/main/java/eu/siacs/conversations/utils/NickValidityChecker.java @@ -5,7 +5,7 @@ import java.util.List; import java.util.Set; import eu.siacs.conversations.entities.Conversation; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class NickValidityChecker { diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index 30a62bedf..238fd0875 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -2,19 +2,13 @@ package eu.siacs.conversations.utils; import android.content.Context; import android.support.annotation.ColorInt; -import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.format.DateFormat; import android.text.format.DateUtils; -import android.util.Log; import android.util.Pair; -import android.widget.PopupMenu; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.math.BigInteger; import java.security.MessageDigest; -import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; @@ -34,7 +28,7 @@ import eu.siacs.conversations.entities.Presence; import eu.siacs.conversations.entities.RtpSessionStatus; import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.services.ExportBackupService; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class UIHelper { @@ -526,7 +520,7 @@ public class UIHelper { return ((Conversation) conversation).getMucOptions().getSelf().getName(); } else { final Jid jid = conversation.getAccount().getJid(); - return jid.getLocal() != null ? jid.getLocal() : Jid.ofDomain(jid.getDomain()).toString(); + return jid.getLocal() != null ? jid.getLocal() : jid.getDomain().toString(); } } } diff --git a/src/main/java/eu/siacs/conversations/utils/XmppUri.java b/src/main/java/eu/siacs/conversations/utils/XmppUri.java index 2afa2954b..9b27a123a 100644 --- a/src/main/java/eu/siacs/conversations/utils/XmppUri.java +++ b/src/main/java/eu/siacs/conversations/utils/XmppUri.java @@ -14,7 +14,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class XmppUri { @@ -34,7 +34,7 @@ public class XmppUri { parse(Uri.parse(uri)); } catch (IllegalArgumentException e) { try { - jid = Jid.of(uri).asBareJid().toString(); + jid = Jid.ofEscaped(uri).asBareJid().toEscapedString(); } catch (IllegalArgumentException e2) { jid = null; } @@ -137,7 +137,7 @@ public class XmppUri { if (segments.size() >= 2 && segments.get(1).contains("@")) { // sample : https://conversations.im/i/foo@bar.com try { - jid = Jid.of(lameUrlDecode(segments.get(1))).toString(); + jid = Jid.ofEscaped(lameUrlDecode(segments.get(1))).toEscapedString(); } catch (Exception e) { jid = null; } @@ -173,7 +173,7 @@ public class XmppUri { } } else { try { - jid = Jid.of(uri.toString()).asBareJid().toString(); + jid = Jid.ofEscaped(uri.toString()).asBareJid().toEscapedString(); } catch (final IllegalArgumentException ignored) { jid = null; } @@ -195,7 +195,7 @@ public class XmppUri { public Jid getJid() { try { - return this.jid == null ? null : Jid.of(this.jid); + return this.jid == null ? null : Jid.ofEscaped(this.jid); } catch (IllegalArgumentException e) { return null; } @@ -206,7 +206,7 @@ public class XmppUri { return false; } try { - Jid.of(jid); + Jid.ofEscaped(jid); return true; } catch (IllegalArgumentException e) { return false; diff --git a/src/main/java/eu/siacs/conversations/xml/Element.java b/src/main/java/eu/siacs/conversations/xml/Element.java index 2efd943de..1bd11f604 100644 --- a/src/main/java/eu/siacs/conversations/xml/Element.java +++ b/src/main/java/eu/siacs/conversations/xml/Element.java @@ -1,15 +1,13 @@ package eu.siacs.conversations.xml; import java.util.ArrayList; -import java.util.HashMap; import java.util.Hashtable; import java.util.List; -import java.util.Locale; import eu.siacs.conversations.utils.XmlHelper; import eu.siacs.conversations.xmpp.InvalidJid; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class Element { private final String name; @@ -126,6 +124,13 @@ public class Element { return this; } + public Element setAttribute(String name, Jid value) { + if (name != null && value != null) { + this.attributes.put(name, value.toEscapedString()); + } + return this; + } + public Element removeAttribute(String name) { this.attributes.remove(name); return this; diff --git a/src/main/java/eu/siacs/conversations/xmpp/InvalidJid.java b/src/main/java/eu/siacs/conversations/xmpp/InvalidJid.java index 646d9544d..a990dc5c1 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/InvalidJid.java +++ b/src/main/java/eu/siacs/conversations/xmpp/InvalidJid.java @@ -32,7 +32,6 @@ package eu.siacs.conversations.xmpp; import android.support.annotation.NonNull; import eu.siacs.conversations.xmpp.stanzas.AbstractStanza; -import rocks.xmpp.addr.Jid; public class InvalidJid implements Jid { @@ -78,21 +77,12 @@ public class InvalidJid implements Jid { throw new AssertionError("Not implemented"); } - @Override - public Jid withLocal(CharSequence charSequence) { - throw new AssertionError("Not implemented"); - } @Override public Jid withResource(CharSequence charSequence) { throw new AssertionError("Not implemented"); } - @Override - public Jid atSubdomain(CharSequence charSequence) { - throw new AssertionError("Not implemented"); - } - @Override public String getLocal() { throw new AssertionError("Not implemented"); @@ -104,7 +94,7 @@ public class InvalidJid implements Jid { } @Override - public String getDomain() { + public Jid getDomain() { throw new AssertionError("Not implemented"); } @@ -139,7 +129,7 @@ public class InvalidJid implements Jid { } public static Jid getNullForInvalid(Jid jid) { - if (jid != null && jid instanceof InvalidJid) { + if (jid instanceof InvalidJid) { return null; } else { return jid; diff --git a/src/main/java/eu/siacs/conversations/xmpp/Jid.java b/src/main/java/eu/siacs/conversations/xmpp/Jid.java new file mode 100644 index 000000000..622a132fb --- /dev/null +++ b/src/main/java/eu/siacs/conversations/xmpp/Jid.java @@ -0,0 +1,146 @@ +package eu.siacs.conversations.xmpp; + +import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.jid.parts.Domainpart; +import org.jxmpp.jid.parts.Localpart; +import org.jxmpp.jid.parts.Resourcepart; +import org.jxmpp.stringprep.XmppStringprepException; + +import java.io.Serializable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public interface Jid extends Comparable, Serializable, CharSequence { + + Pattern JID = Pattern.compile("^((.*?)@)?([^/@]+)(/(.*))?$"); + + static Jid of(CharSequence local, CharSequence domain, CharSequence resource) { + if (local == null) { + if (resource == null) { + return ofDomain(domain); + } else { + return ofDomainAndResource(domain, resource); + } + } + if (resource == null) { + return ofLocalAndDomain(local, domain); + } + try { + return new WrappedJid(JidCreate.entityFullFrom( + Localpart.fromUnescaped(local.toString()), + Domainpart.from(domain.toString()), + Resourcepart.from(resource.toString()) + )); + } catch (XmppStringprepException e) { + throw new IllegalArgumentException(e); + } + } + + static Jid ofEscaped(CharSequence local, CharSequence domain, CharSequence resource) { + try { + if (resource == null) { + return new WrappedJid( + JidCreate.bareFrom( + Localpart.from(local.toString()), + Domainpart.from(domain.toString()) + ) + ); + } + return new WrappedJid(JidCreate.entityFullFrom( + Localpart.from(local.toString()), + Domainpart.from(domain.toString()), + Resourcepart.from(resource.toString()) + )); + } catch (XmppStringprepException e) { + throw new IllegalArgumentException(e); + } + } + + + static Jid ofDomain(CharSequence domain) { + try { + return new WrappedJid(JidCreate.domainBareFrom(domain)); + } catch (XmppStringprepException e) { + throw new IllegalArgumentException(e); + } + } + + static Jid ofLocalAndDomain(CharSequence local, CharSequence domain) { + try { + return new WrappedJid( + JidCreate.bareFrom( + Localpart.fromUnescaped(local.toString()), + Domainpart.from(domain.toString()) + ) + ); + } catch (XmppStringprepException e) { + throw new IllegalArgumentException(e); + } + } + + static Jid ofDomainAndResource(CharSequence domain, CharSequence resource) { + try { + return new WrappedJid( + JidCreate.domainFullFrom( + Domainpart.from(domain.toString()), + Resourcepart.from(resource.toString()) + )); + } catch (XmppStringprepException e) { + throw new IllegalArgumentException(e); + } + } + + static Jid ofLocalAndDomainEscaped(CharSequence local, CharSequence domain) { + try { + return new WrappedJid( + JidCreate.bareFrom( + Localpart.from(local.toString()), + Domainpart.from(domain.toString()) + ) + ); + } catch (XmppStringprepException e) { + throw new IllegalArgumentException(e); + } + } + + static Jid of(CharSequence jid) { + if (jid instanceof Jid) { + return (Jid) jid; + } + Matcher matcher = JID.matcher(jid); + if (matcher.matches()) { + return of(matcher.group(2), matcher.group(3), matcher.group(5)); + } else { + throw new IllegalArgumentException("Could not parse JID: " + jid); + } + } + + static Jid ofEscaped(CharSequence jid) { + try { + return new WrappedJid(JidCreate.from(jid)); + } catch (XmppStringprepException e) { + e.printStackTrace(); + throw new IllegalArgumentException(e); + } + } + + boolean isFullJid(); + + boolean isBareJid(); + + boolean isDomainJid(); + + Jid asBareJid(); + + Jid withResource(CharSequence resource); + + String getLocal(); + + String getEscapedLocal(); + + Jid getDomain(); + + String getResource(); + + String toEscapedString(); +} diff --git a/src/main/java/eu/siacs/conversations/xmpp/WrappedJid.java b/src/main/java/eu/siacs/conversations/xmpp/WrappedJid.java new file mode 100644 index 000000000..aeee5c6e4 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/xmpp/WrappedJid.java @@ -0,0 +1,131 @@ +package eu.siacs.conversations.xmpp; + + +import android.support.annotation.NonNull; + +import org.jxmpp.jid.Jid; +import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.jid.parts.Domainpart; +import org.jxmpp.jid.parts.Localpart; +import org.jxmpp.jid.parts.Resourcepart; +import org.jxmpp.stringprep.XmppStringprepException; + + +public class WrappedJid implements eu.siacs.conversations.xmpp.Jid { + private final Jid inner; + + WrappedJid(Jid inner) { + this.inner = inner; + } + + @Override + public boolean isFullJid() { + return inner.isEntityFullJid() || inner.isDomainFullJid(); + } + + @Override + public boolean isBareJid() { + return inner.isDomainBareJid() || inner.isEntityBareJid(); + } + + @Override + public boolean isDomainJid() { + return inner.isDomainBareJid() || inner.isDomainFullJid(); + } + + @Override + public eu.siacs.conversations.xmpp.Jid asBareJid() { + return new WrappedJid(inner.asBareJid()); + } + + @Override + public eu.siacs.conversations.xmpp.Jid withResource(CharSequence resource) { + final Localpart localpart = inner.getLocalpartOrNull(); + try { + final Resourcepart resourcepart = Resourcepart.from(resource.toString()); + if (localpart == null) { + return new WrappedJid(JidCreate.domainFullFrom(inner.getDomain(),resourcepart)); + } else { + return new WrappedJid( + JidCreate.fullFrom( + localpart, + inner.getDomain(), + resourcepart + )); + } + } catch (XmppStringprepException e) { + throw new IllegalArgumentException(e); + } + } + + @Override + public String getLocal() { + final Localpart localpart = inner.getLocalpartOrNull(); + return localpart == null ? null : localpart.asUnescapedString(); + } + + @Override + public String getEscapedLocal() { + final Localpart localpart = inner.getLocalpartOrNull(); + return localpart == null ? null : localpart.toString(); + } + + @Override + public eu.siacs.conversations.xmpp.Jid getDomain() { + return new WrappedJid(inner.asDomainBareJid()); + } + + @Override + public String getResource() { + final Resourcepart resourcepart = inner.getResourceOrNull(); + return resourcepart == null ? null : resourcepart.toString(); + } + + @Override + public String toEscapedString() { + return inner.toString(); + } + + @NonNull + @Override + public String toString() { + return inner.asUnescapedString(); + } + + @Override + public int length() { + return inner.length(); + } + + @Override + public char charAt(int i) { + return inner.charAt(i); + } + + @Override + public CharSequence subSequence(int i, int i1) { + return inner.subSequence(i,i1); + } + + @Override + public int compareTo(eu.siacs.conversations.xmpp.Jid jid) { + if (jid instanceof WrappedJid) { + return inner.compareTo(((WrappedJid) jid).inner); + } else { + return 0; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + WrappedJid that = (WrappedJid) o; + return inner.equals(that.inner); + } + + @Override + public int hashCode() { + return inner.hashCode(); + } +} diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 8717fe01b..b4f8012b5 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -100,7 +100,6 @@ import eu.siacs.conversations.xmpp.stanzas.streammgmt.AckPacket; import eu.siacs.conversations.xmpp.stanzas.streammgmt.EnablePacket; import eu.siacs.conversations.xmpp.stanzas.streammgmt.RequestPacket; import eu.siacs.conversations.xmpp.stanzas.streammgmt.ResumePacket; -import rocks.xmpp.addr.Jid; public class XmppConnection implements Runnable { @@ -290,8 +289,7 @@ public class XmppConnection implements Runnable { throw new IOException(e.getMessage()); } } else { - final String domain = account.getJid().getDomain(); - final Resolver.Result storedBackupResult = mXmppConnectionService.databaseBackend.findResolverResult(domain); + final String domain = account.getServer(); Resolver.Result result = null; final boolean hardcoded = extended && !account.getHostname().isEmpty(); if (hardcoded) { @@ -405,14 +403,14 @@ public class XmppConnection implements Runnable { private TlsFactoryVerifier getTlsFactoryVerifier() throws NoSuchAlgorithmException, KeyManagementException, IOException { final SSLContext sc = SSLSocketHelper.getSSLContext(); - MemorizingTrustManager trustManager = this.mXmppConnectionService.getMemorizingTrustManager(); - KeyManager[] keyManager; - if (account.getPrivateKeyAlias() != null && account.getPassword().isEmpty()) { + final MemorizingTrustManager trustManager = this.mXmppConnectionService.getMemorizingTrustManager(); + final KeyManager[] keyManager; + if (account.getPrivateKeyAlias() != null) { keyManager = new KeyManager[]{new MyKeyManager()}; } else { keyManager = null; } - String domain = account.getJid().getDomain(); + final String domain = account.getServer(); sc.init(keyManager, new X509TrustManager[]{mInteractive ? trustManager.getInteractive(domain) : trustManager.getNonInteractive(domain)}, mXmppConnectionService.getRNG()); final SSLSocketFactory factory = sc.getSocketFactory(); final DomainHostnameVerifier verifier = trustManager.wrapHostnameVerifier(new XmppDomainVerifier(), mInteractive); @@ -908,7 +906,7 @@ public class XmppConnection implements Runnable { private void sendRegistryRequest() { final IqPacket register = new IqPacket(IqPacket.TYPE.GET); register.query(Namespace.REGISTER); - register.setTo(Jid.of(account.getServer())); + register.setTo(account.getDomain()); sendUnmodifiedIqPacket(register, (account, packet) -> { if (packet.getType() == IqPacket.TYPE.TIMEOUT) { return; @@ -1150,18 +1148,18 @@ public class XmppConnection implements Runnable { } final boolean requestDiscoItemsFirst = !account.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY); if (requestDiscoItemsFirst) { - sendServiceDiscoveryItems(Jid.of(account.getServer())); + sendServiceDiscoveryItems(account.getDomain()); } if (discoveryResult == null) { - sendServiceDiscoveryInfo(Jid.of(account.getServer())); + sendServiceDiscoveryInfo(account.getDomain()); } else { Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": server caps came from cache"); - disco.put(Jid.of(account.getServer()), discoveryResult); + disco.put(account.getDomain(), discoveryResult); } discoverMamPreferences(); sendServiceDiscoveryInfo(account.getJid().asBareJid()); if (!requestDiscoItemsFirst) { - sendServiceDiscoveryItems(Jid.of(account.getServer())); + sendServiceDiscoveryItems(account.getDomain()); } if (!mWaitForDisco.get()) { @@ -1180,24 +1178,24 @@ public class XmppConnection implements Runnable { boolean advancedStreamFeaturesLoaded; synchronized (XmppConnection.this.disco) { ServiceDiscoveryResult result = new ServiceDiscoveryResult(packet); - if (jid.equals(Jid.of(account.getServer()))) { + if (jid.equals(account.getDomain())) { mXmppConnectionService.databaseBackend.insertDiscoveryResult(result); } disco.put(jid, result); - advancedStreamFeaturesLoaded = disco.containsKey(Jid.of(account.getServer())) + advancedStreamFeaturesLoaded = disco.containsKey(account.getDomain()) && disco.containsKey(account.getJid().asBareJid()); } - if (advancedStreamFeaturesLoaded && (jid.equals(Jid.of(account.getServer())) || jid.equals(account.getJid().asBareJid()))) { + if (advancedStreamFeaturesLoaded && (jid.equals(account.getDomain()) || jid.equals(account.getJid().asBareJid()))) { enableAdvancedStreamFeatures(); } } else if (packet.getType() == IqPacket.TYPE.ERROR) { Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": could not query disco info for " + jid.toString()); - final boolean serverOrAccount = jid.equals(Jid.of(account.getServer())) || jid.equals(account.getJid().asBareJid()); + final boolean serverOrAccount = jid.equals(account.getDomain()) || jid.equals(account.getJid().asBareJid()); final boolean advancedStreamFeaturesLoaded; if (serverOrAccount) { synchronized (XmppConnection.this.disco) { disco.put(jid, ServiceDiscoveryResult.empty()); - advancedStreamFeaturesLoaded = disco.containsKey(Jid.of(account.getServer())) && disco.containsKey(account.getJid().asBareJid()); + advancedStreamFeaturesLoaded = disco.containsKey(account.getDomain()) && disco.containsKey(account.getJid().asBareJid()); } } else { advancedStreamFeaturesLoaded = false; @@ -1254,7 +1252,7 @@ public class XmppConnection implements Runnable { private void sendServiceDiscoveryItems(final Jid server) { mPendingServiceDiscoveries.incrementAndGet(); final IqPacket iq = new IqPacket(IqPacket.TYPE.GET); - iq.setTo(Jid.ofDomain(server.getDomain())); + iq.setTo(server.getDomain()); iq.query("http://jabber.org/protocol/disco#items"); this.sendIqPacket(iq, (account, packet) -> { if (packet.getType() == IqPacket.TYPE.RESULT) { @@ -1263,7 +1261,7 @@ public class XmppConnection implements Runnable { for (final Element element : elements) { if (element.getName().equals("item")) { final Jid jid = InvalidJid.getNullForInvalid(element.getAttributeAsJid("jid")); - if (jid != null && !jid.equals(Jid.of(account.getServer()))) { + if (jid != null && !jid.equals(account.getDomain())) { items.add(jid); } } @@ -1537,7 +1535,7 @@ public class XmppConnection implements Runnable { public List getMucServersWithholdAccount() { List servers = getMucServers(); - servers.remove(account.getServer()); + servers.remove(account.getDomain()); return servers; } @@ -1619,7 +1617,7 @@ public class XmppConnection implements Runnable { public Identity getServerIdentity() { synchronized (this.disco) { - ServiceDiscoveryResult result = disco.get(Jid.ofDomain(account.getJid().getDomain())); + ServiceDiscoveryResult result = disco.get(account.getJid().getDomain()); if (result == null) { return Identity.UNKNOWN; } @@ -1742,7 +1740,7 @@ public class XmppConnection implements Runnable { } public boolean carbons() { - return hasDiscoFeature(Jid.of(account.getServer()), "urn:xmpp:carbons:2"); + return hasDiscoFeature(account.getDomain(), "urn:xmpp:carbons:2"); } public boolean bookmarksConversion() { @@ -1754,19 +1752,19 @@ public class XmppConnection implements Runnable { } public boolean blocking() { - return hasDiscoFeature(Jid.of(account.getServer()), Namespace.BLOCKING); + return hasDiscoFeature(account.getDomain(), Namespace.BLOCKING); } public boolean spamReporting() { - return hasDiscoFeature(Jid.of(account.getServer()), "urn:xmpp:reporting:reason:spam:0"); + return hasDiscoFeature(account.getDomain(), "urn:xmpp:reporting:reason:spam:0"); } public boolean flexibleOfflineMessageRetrieval() { - return hasDiscoFeature(Jid.of(account.getServer()), Namespace.FLEXIBLE_OFFLINE_MESSAGE_RETRIEVAL); + return hasDiscoFeature(account.getDomain(), Namespace.FLEXIBLE_OFFLINE_MESSAGE_RETRIEVAL); } public boolean register() { - return hasDiscoFeature(Jid.of(account.getServer()), Namespace.REGISTER); + return hasDiscoFeature(account.getDomain(), Namespace.REGISTER); } public boolean invite() { @@ -1815,7 +1813,7 @@ public class XmppConnection implements Runnable { public boolean push() { return hasDiscoFeature(account.getJid().asBareJid(), Namespace.PUSH) - || hasDiscoFeature(Jid.of(account.getServer()), Namespace.PUSH); + || hasDiscoFeature(account.getDomain(), Namespace.PUSH); } public boolean rosterVersioning() { @@ -1827,7 +1825,7 @@ public class XmppConnection implements Runnable { } public boolean p1S3FileTransfer() { - return hasDiscoFeature(Jid.of(account.getServer()), Namespace.P1_S3_FILE_TRANSFER); + return hasDiscoFeature(account.getDomain(), Namespace.P1_S3_FILE_TRANSFER); } public boolean httpUpload(long filesize) { @@ -1881,7 +1879,7 @@ public class XmppConnection implements Runnable { } public boolean externalServiceDiscovery() { - return hasDiscoFeature(Jid.of(account.getServer()),Namespace.EXTERNAL_SERVICE_DISCOVERY); + return hasDiscoFeature(account.getDomain(),Namespace.EXTERNAL_SERVICE_DISCOVERY); } } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/AbstractJingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/AbstractJingleConnection.java index 4b1fd5a36..ef28a2eb3 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/AbstractJingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/AbstractJingleConnection.java @@ -1,7 +1,6 @@ package eu.siacs.conversations.xmpp.jingle; import com.google.common.base.Objects; -import com.google.common.base.Optional; import com.google.common.base.Preconditions; import eu.siacs.conversations.entities.Account; @@ -9,7 +8,7 @@ import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public abstract class AbstractJingleConnection { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/DirectConnectionUtils.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/DirectConnectionUtils.java index 8d9818ed9..83a2b95e4 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/DirectConnectionUtils.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/DirectConnectionUtils.java @@ -11,7 +11,7 @@ import java.util.Enumeration; import java.util.List; import java.util.UUID; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class DirectConnectionUtils { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java index e1f4db4b0..d1bfc987a 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java @@ -5,7 +5,7 @@ import java.util.List; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.InvalidJid; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class JingleCandidate { @@ -127,7 +127,7 @@ public class JingleCandidate { element.setAttribute("host", this.getHost()); element.setAttribute("port", Integer.toString(this.getPort())); if (jid != null) { - element.setAttribute("jid", jid.toEscapedString()); + element.setAttribute("jid", jid); } element.setAttribute("priority", Integer.toString(this.getPriority())); if (this.getType() == TYPE_DIRECT) { 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 0de9f8606..9ac971c2d 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java @@ -48,7 +48,7 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.Reason; import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription; import eu.siacs.conversations.xmpp.stanzas.IqPacket; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class JingleConnectionManager extends AbstractConnectionManager { static final ScheduledExecutorService SCHEDULED_EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor(); @@ -601,7 +601,7 @@ public class JingleConnectionManager extends AbstractConnectionManager { } public WeakReference findJingleRtpConnection(Account account, Jid with, String sessionId) { - final AbstractJingleConnection.Id id = AbstractJingleConnection.Id.of(account, Jid.ofEscaped(with), sessionId); + final AbstractJingleConnection.Id id = AbstractJingleConnection.Id.of(account, with, sessionId); final AbstractJingleConnection connection = connections.get(id); if (connection instanceof JingleRtpConnection) { return new WeakReference<>((JingleRtpConnection) connection); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java index f0941d27c..5d25cb3b0 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java @@ -47,7 +47,7 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket; import eu.siacs.conversations.xmpp.jingle.stanzas.Reason; import eu.siacs.conversations.xmpp.jingle.stanzas.S5BTransportInfo; import eu.siacs.conversations.xmpp.stanzas.IqPacket; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class JingleFileTransferConnection extends AbstractJingleConnection implements Transferable { @@ -78,6 +78,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private String contentName; private Content.Creator contentCreator; + private Content.Senders contentSenders; private Class initialTransport; private boolean remoteSupportsOmemoJet; @@ -339,6 +340,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private void init(final Message message, final XmppAxolotlMessage xmppAxolotlMessage) { this.mXmppAxolotlMessage = xmppAxolotlMessage; this.contentCreator = Content.Creator.INITIATOR; + this.contentSenders = Content.Senders.INITIATOR; this.contentName = JingleConnectionManager.nextRandomId(); this.message = message; final List remoteFeatures = getRemoteFeatures(); @@ -436,6 +438,13 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple final Content content = packet.getJingleContent(); final GenericTransportInfo transportInfo = content.getTransport(); this.contentCreator = content.getCreator(); + Content.Senders senders; + try { + senders = content.getSenders(); + } catch (final Exception e) { + senders = Content.Senders.INITIATOR; + } + this.contentSenders = senders; this.contentName = content.getAttribute("name"); if (transportInfo instanceof S5BTransportInfo) { @@ -571,6 +580,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private void sendInitRequest() { final JinglePacket packet = this.bootstrapPacket(JinglePacket.Action.SESSION_INITIATE); final Content content = new Content(this.contentCreator, this.contentName); + content.setSenders(this.contentSenders); if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL && remoteSupportsOmemoJet) { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": remote announced support for JET"); final Element security = new Element("security", Namespace.JINGLE_ENCRYPTED_TRANSPORT); @@ -645,6 +655,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple this.jingleConnectionManager.getPrimaryCandidate(this.id.account, isInitiator(), (success, candidate) -> { final JinglePacket packet = bootstrapPacket(JinglePacket.Action.SESSION_ACCEPT); final Content content = new Content(contentCreator, contentName); + content.setSenders(this.contentSenders); content.setDescription(this.description); if (success && candidate != null && !equalCandidateExists(candidate)) { final JingleSocks5Transport socksConnection = new JingleSocks5Transport(this, candidate); @@ -684,6 +695,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple this.transport = new JingleInBandTransport(this, this.transportId, this.ibbBlockSize); final JinglePacket packet = bootstrapPacket(JinglePacket.Action.SESSION_ACCEPT); final Content content = new Content(contentCreator, contentName); + content.setSenders(this.contentSenders); content.setDescription(this.description); content.setTransport(new IbbTransportInfo(this.transportId, this.ibbBlockSize)); packet.addJingleContent(content); @@ -909,8 +921,9 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private void sendFallbackToIbb() { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": sending fallback to ibb"); - JinglePacket packet = this.bootstrapPacket(JinglePacket.Action.TRANSPORT_REPLACE); - Content content = new Content(this.contentCreator, this.contentName); + final JinglePacket packet = this.bootstrapPacket(JinglePacket.Action.TRANSPORT_REPLACE); + final Content content = new Content(this.contentCreator, this.contentName); + content.setSenders(this.contentSenders); this.transportId = JingleConnectionManager.nextRandomId(); content.setTransport(new IbbTransportInfo(this.transportId, this.ibbBlockSize)); packet.addJingleContent(content); @@ -944,6 +957,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple final JinglePacket answer = bootstrapPacket(JinglePacket.Action.TRANSPORT_ACCEPT); final Content content = new Content(contentCreator, contentName); + content.setSenders(this.contentSenders); content.setTransport(new IbbTransportInfo(this.transportId, this.ibbBlockSize)); answer.addJingleContent(content); @@ -1123,6 +1137,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private void sendProxyActivated(String cid) { final JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO); final Content content = new Content(this.contentCreator, this.contentName); + content.setSenders(this.contentSenders); content.setTransport(new S5BTransportInfo(this.transportId, new Element("activated").setAttribute("cid", cid))); packet.addJingleContent(content); this.sendJinglePacket(packet); @@ -1131,6 +1146,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private void sendProxyError() { final JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO); final Content content = new Content(this.contentCreator, this.contentName); + content.setSenders(this.contentSenders); content.setTransport(new S5BTransportInfo(this.transportId, new Element("proxy-error"))); packet.addJingleContent(content); this.sendJinglePacket(packet); @@ -1139,6 +1155,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private void sendCandidateUsed(final String cid) { JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO); final Content content = new Content(this.contentCreator, this.contentName); + content.setSenders(this.contentSenders); content.setTransport(new S5BTransportInfo(this.transportId, new Element("candidate-used").setAttribute("cid", cid))); packet.addJingleContent(content); this.sentCandidate = true; @@ -1152,6 +1169,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": sending candidate error"); JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO); Content content = new Content(this.contentCreator, this.contentName); + content.setSenders(this.contentSenders); content.setTransport(new S5BTransportInfo(this.transportId, new Element("candidate-error"))); packet.addJingleContent(content); this.sentCandidate = true; 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 2dc0d9cab..7be13bedb 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInBandTransport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInBandTransport.java @@ -20,7 +20,7 @@ import eu.siacs.conversations.services.AbstractConnectionManager; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.stanzas.IqPacket; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class JingleInBandTransport extends JingleTransport { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java index 0376807c7..0af69ca28 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java @@ -47,7 +47,7 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.Reason; import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription; import eu.siacs.conversations.xmpp.stanzas.IqPacket; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class JingleRtpConnection extends AbstractJingleConnection implements WebRTCWrapper.EventCallback { @@ -654,8 +654,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web } catch (final WebRTCWrapper.InitializationException e) { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable to initialize WebRTC"); webRTCWrapper.close(); - //todo we haven’t actually initiated the session yet; so sending sessionTerminate makes no sense - //todo either we don’t ring ever at all or maybe we should send a retract or something + sendJingleMessage("retract", id.with.asBareJid()); transitionOrThrow(State.TERMINATED_APPLICATION_FAILURE); this.finish(); return; @@ -672,6 +671,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web if (isInState(targetState)) { sendSessionTerminate(Reason.FAILED_APPLICATION); } else { + sendJingleMessage("retract", id.with.asBareJid()); transitionOrThrow(State.TERMINATED_APPLICATION_FAILURE); this.finish(); } @@ -1104,7 +1104,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web private void discoverIceServers(final OnIceServersDiscovered onIceServersDiscovered) { if (id.account.getXmppConnection().getFeatures().externalServiceDiscovery()) { final IqPacket request = new IqPacket(IqPacket.TYPE.GET); - request.setTo(Jid.of(id.account.getJid().getDomain())); + request.setTo(id.account.getDomain()); request.addChild("services", Namespace.EXTERNAL_SERVICE_DISCOVERY); xmppConnectionService.sendIqPacket(id.account, request, (account, response) -> { ImmutableList.Builder listBuilder = new ImmutableList.Builder<>(); @@ -1150,7 +1150,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web } } } - List iceServers = listBuilder.build(); + final List iceServers = listBuilder.build(); if (iceServers.size() == 0) { Log.w(Config.LOGTAG, id.account.getJid().asBareJid() + ": no ICE server found " + response); } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java index 4e7825c42..6b9a6429b 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java @@ -58,12 +58,22 @@ public class JingleSocks5Transport extends JingleTransport { } else { destBuilder.append(this.connection.getTransportId()); } - if (candidate.isOurs()) { - destBuilder.append(this.account.getJid()); - destBuilder.append(this.connection.getId().with); + if (candidate.getType() == JingleCandidate.TYPE_PROXY) { + if (candidate.isOurs()) { + destBuilder.append(this.account.getJid()); + destBuilder.append(this.connection.getId().with); + } else { + destBuilder.append(this.connection.getId().with); + destBuilder.append(this.account.getJid()); + } } else { - destBuilder.append(this.connection.getId().with); - destBuilder.append(this.account.getJid()); + if (connection.isInitiator()) { + destBuilder.append(this.account.getJid()); + destBuilder.append(this.connection.getId().with); + } else { + destBuilder.append(this.connection.getId().with); + destBuilder.append(this.account.getJid()); + } } messageDigest.reset(); this.destination = CryptoHelper.bytesToHex(messageDigest.digest(destBuilder.toString().getBytes())); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/OngoingRtpSession.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/OngoingRtpSession.java index 95328f8c6..ebd2d8850 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/OngoingRtpSession.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/OngoingRtpSession.java @@ -1,9 +1,7 @@ package eu.siacs.conversations.xmpp.jingle; -import com.google.common.base.Optional; - import eu.siacs.conversations.entities.Account; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public interface OngoingRtpSession { Account getAccount(); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java index 31ee95bbf..2195ba47b 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java @@ -12,7 +12,7 @@ import java.util.Map; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.stanzas.IqPacket; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class JinglePacket extends IqPacket { @@ -96,13 +96,13 @@ public class JinglePacket extends IqPacket { //RECOMMENDED for session-initiate, NOT RECOMMENDED otherwise public void setInitiator(final Jid initiator) { Preconditions.checkArgument(initiator.isFullJid(), "initiator should be a full JID"); - findChild("jingle", Namespace.JINGLE).setAttribute("initiator", initiator.toEscapedString()); + findChild("jingle", Namespace.JINGLE).setAttribute("initiator", initiator); } //RECOMMENDED for session-accept, NOT RECOMMENDED otherwise public void setResponder(Jid responder) { Preconditions.checkArgument(responder.isFullJid(), "responder should be a full JID"); - findChild("jingle", Namespace.JINGLE).setAttribute("responder", responder.toEscapedString()); + findChild("jingle", Namespace.JINGLE).setAttribute("responder", responder); } public Element getJingleChild(final String name) { diff --git a/src/main/java/eu/siacs/conversations/xmpp/pep/Avatar.java b/src/main/java/eu/siacs/conversations/xmpp/pep/Avatar.java index bbfd6b33d..1e4c1f629 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/pep/Avatar.java +++ b/src/main/java/eu/siacs/conversations/xmpp/pep/Avatar.java @@ -3,7 +3,7 @@ package eu.siacs.conversations.xmpp.pep; import android.util.Base64; import eu.siacs.conversations.xml.Element; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class Avatar { diff --git a/src/main/java/eu/siacs/conversations/xmpp/stanzas/AbstractAcknowledgeableStanza.java b/src/main/java/eu/siacs/conversations/xmpp/stanzas/AbstractAcknowledgeableStanza.java index 552f40598..cd087f3ab 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/stanzas/AbstractAcknowledgeableStanza.java +++ b/src/main/java/eu/siacs/conversations/xmpp/stanzas/AbstractAcknowledgeableStanza.java @@ -2,7 +2,6 @@ package eu.siacs.conversations.xmpp.stanzas; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.InvalidJid; -import rocks.xmpp.addr.Jid; abstract public class AbstractAcknowledgeableStanza extends AbstractStanza { 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 7be738f3a..c0b3d07bd 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java +++ b/src/main/java/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java @@ -2,7 +2,7 @@ package eu.siacs.conversations.xmpp.stanzas; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.xml.Element; -import rocks.xmpp.addr.Jid; +import eu.siacs.conversations.xmpp.Jid; public class AbstractStanza extends Element { @@ -20,20 +20,20 @@ public class AbstractStanza extends Element { public void setTo(final Jid to) { if (to != null) { - setAttribute("to", to.toEscapedString()); + setAttribute("to", to); } } public void setFrom(final Jid from) { if (from != null) { - setAttribute("from", from.toEscapedString()); + setAttribute("from", from); } } public boolean fromServer(final Account account) { final Jid from = getFrom(); return from == null - || from.equals(Jid.of(account.getServer())) + || from.equals(account.getDomain()) || from.equals(account.getJid().asBareJid()) || from.equals(account.getJid()); } @@ -41,7 +41,7 @@ public class AbstractStanza extends Element { public boolean toServer(final Account account) { final Jid to = getTo(); return to == null - || to.equals(Jid.of(account.getServer())) + || to.equals(account.getDomain()) || to.equals(account.getJid().asBareJid()) || to.equals(account.getJid()); } diff --git a/src/main/res/drawable-hdpi/ic_star_black_24dp.png b/src/main/res/drawable-hdpi/ic_star_black_24dp.png new file mode 100644 index 000000000..92a0f5862 Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_star_black_24dp.png differ diff --git a/src/main/res/drawable-hdpi/ic_star_white_24dp.png b/src/main/res/drawable-hdpi/ic_star_white_24dp.png new file mode 100644 index 000000000..86eecdd4a Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_star_white_24dp.png differ diff --git a/src/main/res/drawable-mdpi/ic_star_black_24dp.png b/src/main/res/drawable-mdpi/ic_star_black_24dp.png new file mode 100644 index 000000000..a728afe60 Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_star_black_24dp.png differ diff --git a/src/main/res/drawable-mdpi/ic_star_white_24dp.png b/src/main/res/drawable-mdpi/ic_star_white_24dp.png new file mode 100644 index 000000000..d2cbe4c92 Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_star_white_24dp.png differ diff --git a/src/main/res/drawable-xhdpi/ic_star_black_24dp.png b/src/main/res/drawable-xhdpi/ic_star_black_24dp.png new file mode 100644 index 000000000..c636ce8e8 Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_star_black_24dp.png differ diff --git a/src/main/res/drawable-xhdpi/ic_star_white_24dp.png b/src/main/res/drawable-xhdpi/ic_star_white_24dp.png new file mode 100644 index 000000000..914340683 Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_star_white_24dp.png differ diff --git a/src/main/res/drawable-xxhdpi/ic_star_black_24dp.png b/src/main/res/drawable-xxhdpi/ic_star_black_24dp.png new file mode 100644 index 000000000..54d306599 Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_star_black_24dp.png differ diff --git a/src/main/res/drawable-xxhdpi/ic_star_white_24dp.png b/src/main/res/drawable-xxhdpi/ic_star_white_24dp.png new file mode 100644 index 000000000..aa5879215 Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_star_white_24dp.png differ diff --git a/src/main/res/drawable-xxxhdpi/ic_star_black_24dp.png b/src/main/res/drawable-xxxhdpi/ic_star_black_24dp.png new file mode 100644 index 000000000..7be22806f Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_star_black_24dp.png differ diff --git a/src/main/res/drawable-xxxhdpi/ic_star_white_24dp.png b/src/main/res/drawable-xxxhdpi/ic_star_white_24dp.png new file mode 100644 index 000000000..58d71b392 Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_star_white_24dp.png differ diff --git a/src/main/res/layout/conversation_list_row.xml b/src/main/res/layout/conversation_list_row.xml index 73cc3ec39..892e279f1 100644 --- a/src/main/res/layout/conversation_list_row.xml +++ b/src/main/res/layout/conversation_list_row.xml @@ -98,13 +98,25 @@ android:id="@+id/notification_status" android:layout_width="?attr/IconSize" android:layout_height="?attr/IconSize" - android:layout_toLeftOf="@+id/unread_count" + android:layout_toLeftOf="@+id/pinned_on_top" android:layout_alignWithParentIfMissing="true" android:layout_centerVertical="true" android:layout_marginLeft="4dp" android:alpha="?attr/icon_alpha" android:src="?attr/icon_notifications" /> + + + + \ No newline at end of file diff --git a/src/main/res/values-ar/strings.xml b/src/main/res/values-ar/strings.xml index 9ef190fdd..357841af6 100644 --- a/src/main/res/values-ar/strings.xml +++ b/src/main/res/values-ar/strings.xml @@ -368,8 +368,6 @@ إعدادات الربط الموسعة عرض اسم المضيف وإعدادات المنفذ عند تنصيب حساب xmpp.example.com - أضف حساباً مرفوقاً بشهادة - أتركه فارغًا القيام بالمصادقة عبر شهادة إعدادت الأرشيف قم بإدخال الرموز المتواجدة في الصورة تجديد الشهادة diff --git a/src/main/res/values-bg/strings.xml b/src/main/res/values-bg/strings.xml index b28ff44ff..f609d6561 100644 --- a/src/main/res/values-bg/strings.xml +++ b/src/main/res/values-bg/strings.xml @@ -377,8 +377,6 @@ Разширени настройки за връзката Показване на настройките за сървър и порт при установка на профил xmpp.example.com - Добавяне на профил със сертификат - Оставете празно за удостоверяване със сертификат Настройки за архивирането Настройки за архивирането на сървъра Получаване на настройките за архивирането. Моля, изчакайте… diff --git a/src/main/res/values-ca/strings.xml b/src/main/res/values-ca/strings.xml index dd1c3bd16..4780679cb 100644 --- a/src/main/res/values-ca/strings.xml +++ b/src/main/res/values-ca/strings.xml @@ -375,8 +375,6 @@ Configuració de connexió estesa Mostra el nom de la màquina i la configuració del port quan configureu un compte xmpp.example.com - Afegiu un compte amb el certificat - Deixeu-lo en blanc per autenticar amb w/ certificat Arxivant preferències Preferències d\'arxivat al servidor S\'estan obtenint les preferències d\'arxivat. Espereu… diff --git a/src/main/res/values-cs/strings.xml b/src/main/res/values-cs/strings.xml index 010f0c79c..545c29215 100644 --- a/src/main/res/values-cs/strings.xml +++ b/src/main/res/values-cs/strings.xml @@ -322,8 +322,6 @@ Rozšířená nastavení připojení Zobrazovat nastavení hostname a port při vytváření účtu xmpp.server.cz - Přidat účet s certifikátem - Nechat prázdné pro ověření s certifikátem Nastavení archivace Nastavení archivace na serveru Získávání nastavení archivace. Chvíli strpení... diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index 0d7b5a886..b6b6f9058 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -32,7 +32,7 @@ vor %d Minuten %d ungelesene Unterhaltungen senden… - Nachricht wird entschlüsselt. Bitte warten … + Nachricht wird entschlüsselt. Bitte warten… OpenPGP-verschlüsselte Nachricht Nickname wird bereits verwendet Ungültiger Nickname @@ -469,9 +469,8 @@ Erweiterte Verbindungsoptionen Hostname- und Port-Optionen bei Kontoeinrichtung anzeigen xmpp.domain.de - Konto mit Zertifikat hinzufügen + Mit Zertifikat anmelden Zertifikat konnte nicht ausgewertet werden - Leer lassen, um mit Zertifikat anzumelden Archivierungseinstellungen Archivierungseinstellungen des Servers Archivierungseinstellungen werden abgerufen. Bitte warten… @@ -919,6 +918,8 @@ Du kannst immer nur einen Anruf zur gleichen Zeit machen. Zurück zum laufenden Aufruf Kamera konnte nicht gewechselt werden + Zu Favoriten hinzufügen + Von Favoriten entfernen %1$d Teilnehmer anzeigen %1$d Teilnehmer anzeigen diff --git a/src/main/res/values-el/strings.xml b/src/main/res/values-el/strings.xml index 821121980..77a2279c4 100644 --- a/src/main/res/values-el/strings.xml +++ b/src/main/res/values-el/strings.xml @@ -411,8 +411,6 @@ Περισσότερες ρυθμίσεις σύνδεσης Εμφάνιση ονόματος μηχανήματος και ρυθμίσεων πόρτας όταν δημιουργείται ένας νέος λογαριασμός xmpp.example.com - Προσθήκη λογαριασμού με πιστοποιητικό - Αφήστε κενό για ταυτοποίηση με πιστοποιητικό Επιλογές αρχειοθέτησης Επιλογές αρχειοθέτησης στον διακομιστή Μεταφόρτωση επιλογών αρχειοθέτησης. Παρακαλώ περιμένετε... diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index 7116fc188..adff37f82 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -469,9 +469,8 @@ Opciones de conexión Mostrar el hostname y el puerto cuando se está creando una cuenta xmpp.ejemplo.com - Añadir cuenta con certificado + Iniciar sesión con certificado No se ha podido leer el certificado - Dejar vacío para autenticar certificado w/ Preferencias de archivado Preferencias de archivado en servidor Buscando preferencias de archivado. Por favor, espera... @@ -516,15 +515,22 @@ Siempre Solo imágenes de gran tamaño Optimizaciones de uso de batería habilitadas + Tu dispositivo está realizando optimizaciones de uso de batería en Conversations que pueden hacer que los mensajes se retrasen o incluso hacer que se pierdan.\nEs recomendable deshabilitarlas. + Tu dispositivo está realizando optimizaciones de uso de batería en Conversations que pueden hacer que los mensajes se retrasen o incluso hacer que se pierdan.\n\nA continuación se te preguntará si quieres deshabilitarlas. Deshabilitar El área seleccionada es demasiado grande (No hay cuentas activas) Este campo es requerido Corregir mensaje Enviar mensaje corregido + Ya has validado la huella digital de esta persona de forma segura confirmando su confianza. Seleccionando \'Hecho\', estás confirmando que %s es parte de esta conversación en grupo. Has deshabilitado esta cuenta + Error de seguridad: ¡Acceso a archivo inválido! + No se ha encontrado ninguna aplicación para compartir la URI Compartir URI con...
El registro se realiza con tu número de teléfono y Quicksy automáticamente—basado en los teléfonos de tu agenda de contactos—te sugerirá posibles contactos.

Registrándote en Quicksy aceptas nuestra política de privacidad.]]>
+ Aceptar y continuar + Una guía te ayudará en el proceso de creación de la cuenta en conversations.im.¹\nCuando selecciones conversations.im como proveedor podrás comunicarte con usuarios de otros servidores proporcionándoles tu dirección XMPP completa. Tu dirección XMPP completa será: %s Crear cuenta Usar otro proveedor de mi elección @@ -548,12 +554,17 @@ Corto Medio Largo + Uso de difusión + Permite que tus contactos sepan cuando usas Conversations Privacidad Tema Selecciona el color de la paleta Automático + Claro + Oscuro Fondo verde Usar fondo verde para mensajes recibidos + No se ha podido conectar a OpenKeychain Este dispositivo ya no está en uso Ordenador Teléfono móvil @@ -561,21 +572,29 @@ Navegador Consola Pago requerido + Otorgue permiso de acceso a internet Yo El contacto solicita ver tus actualizaciones de estado Permitir Sin permiso de acceso a %s Servidor no encontrado Tiempo de espera agotado al servidor remoto + No se ha podido actualizar la cuenta + Reportar a esta dirección XMPP por enviar mensajes no deseados Eliminar identidades OMEMO + Regenerar tus clave OMEMO. Todos tus contactos tendrán que verificarte de nuevo. Usa esta opción como último recurso. Eliminar claves seleccionadas Debes estar conectado para publicar la imagen de perfil Mostrar mensaje de error Mensaje de error Optimización de datos habilitado + Tu sistema operativo está restringiendo a Conversations acceder a internet cuando está en segundo plano. Para recibir notificaciones de nuevos mensajes deberías permitir a Conversations acceder a internet cuando el \"Ahorro de datos\" está habilitado.\nConversations realizará igualmente optimizaciones para ahorrar datos cuando sea posible. Tu dispositivo no soporta la opción de deshabilitar la optimización de datos para Conversations + No se ha podido crear el archivo temporal Este dispositivo ha sido verificado Copiar huella digital + Has verificado todas las huellas digitales OMEMO en tu posesión + El código QR no contiene huellas digitales para esta conversación. Huellas digitales verificadas Usa la cámara para escanear el código QR del contacto Por favor, espera a que las claves sean recuperadas @@ -583,8 +602,11 @@ Compartir como XMPP URI Compartir como link HTTP Confianza ciega antes de verificación + Confiar en los nuevos dispositivos de tus contactos no verificados, pero solicitar confirmación manual para los nuevos dispositivos de tus contactos verificados. + Confiar ciegamente en las claves OMEMO, lo que significa que tus contactos podrían ser otra persona o alguien podría haber intervenido. No confiables Código QR inválido + Limpiar caché de datos (usado por la aplicación de la cámara) Limpiar caché Limpiar datos privados Limpiar datos privados de ficheros descargados (Pueden volver a descargarse desde el servidor) @@ -594,6 +616,7 @@ Mostrar inactivos Ocultar inactivos Desconfiar de este dispositivo + ¿Estás seguro de que quieres eliminar la verificación de este dispositivo?\nEste dispositivo y los mensajes que lleguen desde allí serán marcados como \"No confiables\". %d segundo %d segundos @@ -636,7 +659,9 @@ Downgraded SASL mechanism El servidor requiere registro en su página web Abrir página web + No se ha encontrado aplicación para abrir el sitio web Notificaciones emergentes + Mostrar ventana emergente al recibir una notificación Hoy Ayer Validar hostname con DNSSEC @@ -664,6 +689,8 @@ Editar mensaje de estado Deshabilitar cifrado Conversations no puede enviar mensajes cifrados a %1$s. Esto puede deberse a que tu contacto está usando un servidor o un cliente desactualizado que no puede manejar las claves OMEMO. + No se ha podido conseguir la lista de dispositivos + No se han podido conseguir las claves de cifrado Consejo: En algunas ocasiones esto puede corregirse agregando a tu contacto a tu lista de contactos. Tu contacto deberá asegurarse también que estás en su lista de contactos. ¿Estás seguro de que quieres deshabilitar el cifrado OMEMO para esta conversación?\nEsto permitiría al administrador de tu servidor leer tus mensajes, aunque esta podría ser la única via de comunicación con personas que usen clientes desactualizados. Deshabilitar ahora @@ -692,7 +719,9 @@ Compartir ubicación Mostrar ubicación Compartir + No se ha podido empezar la grabación Por favor, espera... + Permite a Conversations acceder al micrófono Buscar mensajes GIF Ver conversación @@ -712,6 +741,7 @@ Añadir un nombre es opcional Nombre de la Conversación en grupo Esta conversación en grupo ha sido destruida + No se ha podido guardar la grabación Servicio en primer plano Esta categoría de notificación se usa para mostrar una notificación permantente indicando que Conversations está ejecutándose. Información de estado @@ -767,6 +797,9 @@ El código que te hemos enviado ha expirado. Error desconocido de red. Respuesta de servidor desconocida. + No se ha podido conectar al servidor. + No se ha podido establecer una conexión segura. + No se ha podido encontrar el servidor. Algo fue mal procesando tu solicitud. Entrada de usuario no válida Temporalmente no disponible. Inténtalo más tarde. @@ -795,6 +828,8 @@ Restaurar Introduce tu contraseña para la cuenta %s para restaurar la copia de respaldo. No utilices la opción de restaurar una copia de respaldo para clonar (ejecutar simultáneamente) una instalación. Restaurar una copia de respaldo se debe utilizar solo para migraciones o en caso de que hayas perdido el dispositivo original. + No se ha podido restaurar la copia de respaldo. + No se ha podido descifrar la copia de respaldo. ¿Es la contraseña correcta? Respaldar & Restaurar Introduce dirección XMPP Crear una conversación en grupo @@ -809,6 +844,7 @@ Creando canal público... Esta canal ya existe Te has unido a un canal existente + No se ha podido guardar la configuración del canal Permitir a cualquiera editar el asunto Permitir a cualquiera invitar a otros contactos Todos pueden editar el asunto @@ -841,7 +877,9 @@ El fichero seleccionado no es un respaldo de Conversations Esta cuenta ya fue configurada Por favor ingrese la contraseña para esta cuenta + No se ha podido realizar esta acción Unirse a canal público... + La aplicación de compartir no concedió permisos para acceder a este fichero. jabber.network Servidor local @@ -859,9 +897,12 @@ Terminar llamada Contestar Descartar + Localizando dispositivos Llamando Ocupado + No se ha podido realizar la llamada Llamada rechazada + Fallo en la aplicación Colgar Llamada saliente Video llamada saliente @@ -875,6 +916,10 @@ Video llamada Tu micrófono no está disponible Solo puedes hacer una llamada a la vez + Volver a la llamada en curso + No se ha podido cambiar de cámara + Añadir a los favoritos + Eliminar de favoritos Ver %1$d Participante Ver %1$d Participantes diff --git a/src/main/res/values-eu/strings.xml b/src/main/res/values-eu/strings.xml index 610bdc707..c4e8b3d96 100644 --- a/src/main/res/values-eu/strings.xml +++ b/src/main/res/values-eu/strings.xml @@ -408,8 +408,6 @@ Konexioaren ezarpen luzatuak Ostalariaren izena eta ataka ezarpenak erakutsi kontu bat ezartzerakoan xmpp.adibidea.com - Kontua ziurtagiriarekin gehitu - Utzi hutsik ziurtagiririk gabe autentifikatzeko Artxibatze hobespenak Zerbitzariaren aldeko artxibatze hobespenak Artxibatze hobespenak eskuratzen. Mesedez itxaron... diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml index 4ce10acdd..4d4929cbc 100644 --- a/src/main/res/values-fr/strings.xml +++ b/src/main/res/values-fr/strings.xml @@ -469,9 +469,7 @@ Paramètres de connexion avancés Montrer le nom d\'hôte et le port lors du paramétrage d\'un compte xmpp.example.com - Compte avec certificat Impossible d\'analyser le certificat - Laisser vide pour s\'identifier avec un certificat Paramètres d\'archivage Paramètres d\'archivage du serveur Récupération des paramètres d\'archivage en cours… diff --git a/src/main/res/values-gl/strings.xml b/src/main/res/values-gl/strings.xml index 7b5a8f502..676a8966b 100644 --- a/src/main/res/values-gl/strings.xml +++ b/src/main/res/values-gl/strings.xml @@ -469,9 +469,8 @@ Axustes ampliados de conexión Mostar axustes de servidor e porto cando se configura unha conta xmpp.exemplo.com - Engadir conta con certificado + Conéctate con certificado Non se puido procesar o certificado - Deixar baldeiro autenticar con certificado Gardando axustes Axustes de gardado no servidor Obtendo os axustes de gardado. Por favor agarde... @@ -919,6 +918,8 @@ Só podes manter unha chamada en cada momento. Voltar á chamada activa Non se puido activar a cámara + Engadir a favoritas + Eliminar das favoritas Ver %1$d Participante Ver %1$d Participantes diff --git a/src/main/res/values-hu/strings.xml b/src/main/res/values-hu/strings.xml index 0385cf3d9..82327c0d5 100644 --- a/src/main/res/values-hu/strings.xml +++ b/src/main/res/values-hu/strings.xml @@ -74,6 +74,8 @@ Hozzáadja ezt a hiányzó partnert a partnerlistájához? Partner hozzáadása kézbesítés sikertelen + Kép előkészítése az átvitelhez + Képek előkészítése az átvitelhez Fájlok megosztása. Kérem várjon… Előzmények törlése Beszélgetés előzményeinek törlése @@ -87,6 +89,7 @@ OMEMO titkosítású üzenet küldése v\\OMEMO titkosítású üzenet küldése OpenPGP titkosítású üzenet küldése + Új becenév használva Küldés titkosítatlanul A visszafejtés sikertelen. Talán nem rendelkezik a megfelelő személyes kulccsal. OpenKeychain @@ -114,6 +117,7 @@ Az időtartam, amíg az értesítések némítva vannak az egyéb eszközei egyikén történt tevékenység észlelése után. Speciális Sose küldjön összeomlási jelentéseket + A veremkiíratások elküldésével segíti a fejlesztést Üzenetek megerősítése Tudassa a partnereivel, hogy megkapta és elolvasta az üzeneteiket Felhasználói felület @@ -129,6 +133,7 @@ Fénykép készítése Feliratkozási kérelem előzetes engedélyezése A kiválasztott fájl nem kép + Nem sikerült átalakítani a képet A fájl nem található Általános bemeneti/kimeneti hiba. Talán elfogyott a tárolóhely? Ismeretlen @@ -142,6 +147,7 @@ Regisztráció sikertelen A felhasználónév már használatban van Regisztráció befejezve + A kiszolgáló nem támogatja a regisztrációt Érvénytelen regisztrációs token A TLS-egyeztetés sikertelen Irányelv megsértése @@ -158,6 +164,7 @@ OpenPGP nyilvános kulcs közzététele OpenPGP nyilvános kulcs eltávolítása Biztosan el szeretné távolítani az OpenPGP nyilvános kulcsát a jelenléti közleményéből?\nA partnerei többé nem lesznek képesek OpenPGP titkosítású üzeneteket küldeni Önnek. + Az OpenPGP nyilvános kulcs közzé lett téve. Fiók engedélyezése Biztos benne? Hang rögzítése @@ -189,6 +196,7 @@ %d órája volt aktív egy napja volt aktív %d napja volt aktív + Titkosított üzenet. Telepítse az OpenKeychain alkalmazást a visszafejtéshez. OpenPGP kulcsazonosító OMEMO ujjlenyomat v\\OMEMO ujjlenyomat @@ -230,16 +238,20 @@ %selolvasta eddig a pontig Mindenki elolvasta eddig a pontig Közzététel + Érintse meg a profilképet egy fénykép kiválasztásához a galériából Közzététel… A kiszolgáló elutasította a közzétételt + Nem sikerült átalakítani a képet Nem sikerült elmenteni a profilképet a lemezre (Vagy nyomja hosszan az alapértelmezett visszaállításához) + A kiszolgáló nem támogatja a profilképek közzétételét suttogva %s részére Személyes üzenet küldése %s részére Kapcsolódás Ez a fiók már létezik Következő + Munkafolyamat létrehozva Kihagyás Értesítések letiltása Engedélyezés @@ -288,6 +300,7 @@ Fiók részletei Megerősítés Próbálja újra + Előtér szolgáltatás Megakadályozza az operációs rendszert abban, hogy kilője a kapcsolatát Biztonsági mentés léterhozása A biztonsági mentés fájljai itt lesznek tárolva: %s @@ -304,13 +317,20 @@ fájl %s megnyitása küldés (%1$d%% kész) + Fájl előkészítése a megosztáshoz %s felajánlva letöltésre Átvitel megszakítása + a fájlmegosztás sikertelen a fájlátvitel megszakítva + A fájl törölve lett + Nem található alkalmazás a fájl megnyitásához + Nem található alkalmazás a hivatkozás megnyitásához + Nem található alkalmazás a partner megtekintéséhez Dinamikus címkék Csak olvasható címkék megjelenítése a partnerek alatt Értesítések engedélyezése Nem található csoportos csevegés kiszolgáló + A csoportos csevegés létrehozása nem sikerült! Fiók profilképe OMEMO ujjlenyomat másolása a vágólapra OMEMO kulcs újra előállítása @@ -324,6 +344,7 @@ Jelszó megváltoztatása Jelenlegi jelszó Új jelszó + A jelszó nem lehet üres Összes fiók engedélyezése Összes fiók letiltása Művelet végrehajtása ezzel @@ -343,6 +364,7 @@ Nem sikerült %s hovatartozását megváltoztatni Kitiltás a csoportos csevegésből Kitiltás a csatornából + Megpróbálta %s eltávolítását egy nyilvános csatornából. Ennek egyetlen módja, ha örökre kitiltja a felhasználót. Kitiltás most Nem sikerült %s szerepét megváltoztatni Személyes csoportos csevegés beállításai @@ -381,6 +403,7 @@ Tudassa a partnereivel, hogy mikor ír nekik üzeneteket Hely küldése Hely megjelenítése + Nem található alkalmazás a hely megjelenítéséhez Hely A beszélgetés bezárva Kilépett a személyes csoportos csevegésből @@ -397,6 +420,7 @@ %d tanúsítvány törölve %d tanúsítvány törölve + Küldés gomb cseréje gyors művelettel Gyors művelet Nincs Legutóbb használt @@ -404,6 +428,7 @@ Partnerek keresése Könyvjelzők keresése Személyes üzenet küldése + %1$s elhagyta a csoportos csevegést Felhasználónév Felhasználónév Ez nem érvényes felhasználónév @@ -413,6 +438,7 @@ Letöltés sikertelen: nem sikerült írni a fájlt A Tor hálózat nem érhető el Kötési hiba + A kiszolgáló nem felelős a tartományért Törött Elérhetőség „Távol”, ha a kijelző ki van kapcsolva @@ -424,12 +450,15 @@ Kiterjesztett kapcsolati beállítások Gépnév és port beállításainak megjelenítése egy fiók beállításakor xmpp.example.com - Fiók hozzáadása tanúsítvánnyal - Hagyja üresen w/ tanúsítvánnyal történő hitelesítéshez + Bejelentkezés tanúsítvánnyal + Nem sikerült elemezni a tanúsítványt Archiválási beállítások Kiszolgáló oldali archiválási beállítások Archiválási beállítások lekérése. Kérem várjon… + Nem sikerült lekérni az archiválási beállításokat + CAPTCHA szükséges Írja be a fenti képen lévő szöveget + Nem megbízható tanúsítványlánc Az XMPP-cím nem egyezik a tanúsítvánnyal Tanúsítvány megújítása Hiba történt az OMEMO kulcs lekérésekor! @@ -448,6 +477,12 @@ %d üzenet További üzenetek betöltése + %s partnerrel megosztott fájl + %s partnerrel megosztott kép + %s partnerrel megosztott képek + %s partnerrel megosztott szöveg + A Conversations alkalmazásnak hozzáférésre van szüksége a külső tárolóhoz + A Conversations alkalmazásnak hozzáférés engedélyezése a kamerához Szinkronizálás a partnerekkel
A telefonszámok másolatát nem fogjuk eltárolni.\n\nTovábbi információkért olvassa el az adatvédelmi irányelveinket.

Most arra fogják kérni, hogy adjon jogosultságot a névjegyek eléréséhez.]]>
Értesítés az összes üzenetről @@ -466,8 +501,11 @@ Üzenet javítása Javított üzenet küldése Letiltotta ezt a fiókot + Biztonsági hiba: érvénytelen fájlhozzáférés + Nem található alkalmazás az URI megosztásához URI megosztása ezzel…
Regisztráljon a telefonszámával, és a Quicksy automatikusan – a címjegyzékében szereplő telefonszámok alapján – javaslatot tesz a lehetséges partnerekre.

A regisztrációval elfogadja azadatvédelmi irányelveinket.]]>
+ Elfogadás és folytatás A teljes XMPP-címe ez lesz: %s Fiók létrehozása Saját szolgáltató használata @@ -491,10 +529,14 @@ Rövid Közepes Hosszú + Üzenetszórás használata + Tudassa partnereivel, hogy mikor használja a Conversations-t Adatvédelem Téma Színpaletta kiválasztása Automatikus + Világos + Sötét Zöld háttér Zöld háttér használata a fogadott üzenetekhez Ez az eszköz többé nincs használatban @@ -504,19 +546,24 @@ Webböngésző Konzol Fizetés szükséges + Engedélyezze az internet használatát Én A partner jelenlét-feliratkozást kér Engedélyezés Nincs jogosultság hozzáférni ehhez: %s A távoli kiszolgáló nem található Távoli kiszolgáló időtúllépés + Nem sikerült frissíteni a fiókot + Jelentse ezt a Jabber-címet spamküldés miatt. OMEMO személyazonosságok törlése Kijelölt kulcsok törlése Kapcsolódva kell lennie a profilkép közzétételéhez. Hibaüzenet megjelenítése Hibaüzenet Adatsporolás engedélyezve + Az operációs rendszer korlátozza a Conversations hozzáférését az internethez, amikor az a háttérben fut. Ahhoz, hogy értesítéseket kapjon az új üzenetekről, lehetővé kell tennie a Conversations korlátlan hozzáférését amikor aktív az \"adatspórolás\".\nA Conversations továbbra is arra törekszik, hogy spóroljon az adatforgalmon, ahol lehetséges. Az eszköze nem támogatja az adatspórolás letiltását a Conversations alkalmazásnál. + Nem sikerült létrehozni átmeneti fájlt Ez a készülék ellenőrizve lett Ujjlenyomat másolása Ellenőrzött ujjlenyomatok @@ -528,6 +575,7 @@ Vak bizalom ellenőrzés előtt Nem megbízható Érvénytelen 2D vonalkód + Gyorsítótármappa törlése (Kamera alkalmazás által használt) Gyorsítótár törlése Személyes tárhely törlése Személyes tárhely törlése, ahol a fájlok vannak (Ezek újra letölthetők a kiszolgálóról) @@ -579,7 +627,9 @@ Csökkentett SASL mechanizmus A kiszolgáló a weboldalon történő regisztrációt igényli Weboldal megnyitása + Nem található alkalmazás a weboldal megnyitásához Figyelmeztető értesítések + Figyelmeztető értesítések megjelenítése Ma Tegnap Gépnév ellenőrzése DNSSEC használatával @@ -607,6 +657,8 @@ Állapotüzenet szerkesztése Titkosítás letiltása A Conversations nem tud titkosított üzeneteket küldeni %1$s részére. Ez amiatt lehet, hogy a partnere elavult kiszolgálót vagy kliensprogramot használ, amely nem tudja kezelni az OMEMO-t. + Nem sikerült lekérni az eszközlistát + Nem sikerült lekérni a titkosítási kulcsokat Tipp: bizonyos esetekben ez megoldható azzal, hogy hozzáadják egymást a partnerlistákhoz. Biztosan le szeretné tiltani az OMEMO titkosítást ennél a beszélgetésnél?\nEz lehetővé fogja tenni a kiszolgáló rendszergazdájának, hogy elolvassa az üzeneteket, de ez lehet az egyetlen módja annak, hogy kommunikáljon az elavult programokat használó emberekkel. Letiltás most @@ -635,7 +687,9 @@ Hely megosztása Hely megjelenítése Megosztás + Nem sikerült elindítani a rögzítést Kérem várjon… + A Conversations alkalmazásnak mikrofon-hozzáférésre van szüksége Üzenetek keresése GIF Beszélgetés megtekintése @@ -655,6 +709,7 @@ A név megadása elhagyható Csoportos csevegés neve Ezt a csoportos csevegést megszüntették + Nem sikerült elmenteni a felvételt Előtér szolgáltatás Ezt az értesítési kategóriát egy állandó értesítés megjelenítéséhez használják, jelezve azt, hogy a Conversations fut. Állapotinformációk @@ -710,6 +765,8 @@ Az általunk küldött PIN-kód lejárt. Ismeretlen hálózati hiba. Ismeretlen válasz a kiszolgálótól. + Nem sikerült kapcsolódni a kiszolgálóhoz. + Nem sikerült biztonságos kapcsolatot kiépíteni. Nem sikerült megtalálni a kiszolgálót. Valami hiba történt a kérés feldolgozásakor. Érvénytelen felhasználói bevitel @@ -808,6 +865,7 @@ Hívás befejezése Válasz Elutasítás + Eszközök keresése Csörgetés Elfoglalt Nem sikerült kapcsolódni a híváshoz diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml index 8c509c2c3..526e662d2 100644 --- a/src/main/res/values-it/strings.xml +++ b/src/main/res/values-it/strings.xml @@ -469,9 +469,8 @@ Impostazioni estese di connessione Mostra nome host e impostazioni della porta quando configuri un account xmpp.esempio.it - Aggiungi account con certificato + Accedi con certificato Impossibile analizzare il certificato - Lasciare vuoto per autenticarsi con certificato Preferenze di archiviazione Preferenze di archiviazione lato server Raccolta preferenze di archiviazione. Attendere prego... @@ -898,6 +897,7 @@ Chiusura chiamata Rispondi Rifiuta + Individuazione dispositivi Sta squillando Occupato Impossibile connettere la chiamata @@ -918,6 +918,8 @@ Puoi fare solo una chiamata alla volta. Torna alla chiamata in corso Impossibile cambiare fotocamera + Aggiungi ai preferiti + Rimuovi dai preferiti Vedi %1$d partecipante Vedi %1$d partecipanti diff --git a/src/main/res/values-iw/strings.xml b/src/main/res/values-iw/strings.xml index 9a4db57e9..532d5c187 100644 --- a/src/main/res/values-iw/strings.xml +++ b/src/main/res/values-iw/strings.xml @@ -268,8 +268,6 @@ לא עובד העבר למצב \"לא נמצא\" כאשר המסך כבוי מעביר את המכשיר לסטטוס \"לא נמצא\" כאשר המסך כבוי - הוסף חשבון עם תעודה - השאר ריק כדי להזדהות בלי תעודה חידוש תעודה שגיאה בתפיסת OMEMO! התחבר דרך Tor diff --git a/src/main/res/values-ja/strings.xml b/src/main/res/values-ja/strings.xml index 3ef86d1cf..6936041e7 100644 --- a/src/main/res/values-ja/strings.xml +++ b/src/main/res/values-ja/strings.xml @@ -376,8 +376,6 @@ 拡張接続設定 アカウントを設定するときにホスト名とポートの設定を表示します xmpp.example.com - アカウントに証明書を追加 - 空にすると、証明書で認証します アーカイブの設定 サーバーサイドのアーカイブの設定 アーカイブの設定を取得しています。しばらくお待ちください… diff --git a/src/main/res/values-ko/strings.xml b/src/main/res/values-ko/strings.xml index 5f39ee1bf..83c5053bb 100644 --- a/src/main/res/values-ko/strings.xml +++ b/src/main/res/values-ko/strings.xml @@ -312,8 +312,6 @@ 확장 연결 설정 계정을 설정할 때 호스트 이름과 포트 설정을 표시합니다 xmpp.example.com - 인증서가 있는 계정 추가 - 공란으로 두면 인증서로 인증합니다 보관 설정 서버 사이드의 보관 설정 보관 설정을 얻고 있습니다. 잠시 기다려주십시오 ... diff --git a/src/main/res/values-nb-rNO/strings.xml b/src/main/res/values-nb-rNO/strings.xml index 17fce2fa9..9e9507e6a 100644 --- a/src/main/res/values-nb-rNO/strings.xml +++ b/src/main/res/values-nb-rNO/strings.xml @@ -344,8 +344,6 @@ Utvidede tilkoblingsinnst. Vis vertsnavn og portinnstillinger når du setter opp en ny konto xmpp.eksempel.no - Legg til konto med sertifikat - La stå tom for bekreftelse med sertifikat Arkiveringsinnstillinger Arkiveringsinnstillinger på tjenersiden Henter inn arkiveringsinnstillinger. Vent… diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml index 36aa3eb5b..8db430c65 100644 --- a/src/main/res/values-nl/strings.xml +++ b/src/main/res/values-nl/strings.xml @@ -408,8 +408,6 @@ Uitgebreide verbindingsinstellingen Toon hostnaam- en poortinstellingen bij instellen van een account xmpp.voorbeeld.be - Account met certificaat toevoegen - Laat leeg om te authenticeren met certificaat Archiefvoorkeuren Voorkeuren voor archief aan serverzijde Ophalen van archiefvoorkeuren. Even geduld… diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml index 8546c4289..ab712e29f 100644 --- a/src/main/res/values-pl/strings.xml +++ b/src/main/res/values-pl/strings.xml @@ -471,9 +471,8 @@ Rozszerzone ustawienia połączenia Pokaż nazwę hosta i ustawienia portu przy dodawaniu konta xmpp.example.com - Dodaj konto przy pomocy certyfikatu + Zaloguj przy użyciu certyfikatu Nie mogę odczytać certyfikatu - Pozostaw puste by autoryzować za pomocą certyfikatu Preferencje archiwizacji Preferencje archiwizacji po stronie serwera Pobieranie preferencji archiwizacji. Proszę czekać... @@ -937,6 +936,8 @@ Administrator twojego serwera będzie mógł czytać twoje wiadomości, ale moż Możesz mieć tylko jedno połączenie na raz. Powróć do trwającego połączenia Nie można zmienić aparatu + Dodaj do ulubionych + Usuń z ulubionych Pokaż %1$d uczestnika Pokaż %1$d uczestników diff --git a/src/main/res/values-pt-rBR/strings.xml b/src/main/res/values-pt-rBR/strings.xml index 8eafee9e5..104efb29d 100644 --- a/src/main/res/values-pt-rBR/strings.xml +++ b/src/main/res/values-pt-rBR/strings.xml @@ -469,9 +469,8 @@ Configurações detalhadas da conexão Exibe o nome de host e configurações da porta ao configurar uma conta. xmpp.example.com - Adicionar uma conta com certificado + Autenticar com certificado Não foi possível analisar o certificado - Deixe em branco para autenticar com um certificado Preferências de arquivamento Preferências de arquivamento no servidor Obtendo as preferências de arquivamento. Por favor aguarde... @@ -898,6 +897,7 @@ Encerrando chamada Atender Dispensar + Descobrindo dispositivos Tocando Ocupado Não foi possível conectar à chamada diff --git a/src/main/res/values-pt/strings.xml b/src/main/res/values-pt/strings.xml index 4191adaab..0e1415941 100644 --- a/src/main/res/values-pt/strings.xml +++ b/src/main/res/values-pt/strings.xml @@ -337,8 +337,6 @@ Definições de conexão Mostrar as definições do hostname e do porto ao configurar uma conta xmpp.exemplo.com - Adicionar conta com certificado - Deixar vazio para autenticar com certificado Preferências de arquivamento Preferências de arquivamento do servidor Obtendo as preferências de arquivamento. Por favor espere... diff --git a/src/main/res/values-ro-rRO/strings.xml b/src/main/res/values-ro-rRO/strings.xml index 757501435..7ad247d6e 100644 --- a/src/main/res/values-ro-rRO/strings.xml +++ b/src/main/res/values-ro-rRO/strings.xml @@ -470,9 +470,8 @@ Opțiuni avansate conexiune Arată opțiunea de setare a numelui de gazdă și a portului, atunci când se configurează un cont xmpp.exemplu.ro - Adaugă un cont cu certificat + Autentificare cu certificat Nu s-a putut analiza certificatul - Lăsați gol pentru a autentifica cu un certificat Preferințe arhivare Preferințe arhivare pe server Se descarcă preferințe arhivare. Vă rugăm să așteptați... @@ -906,6 +905,7 @@ Se încheie apelul Răspunde Respinge + Descoperire dispozitive Sună Ocupat Nu s-a putut conecta apelul @@ -926,6 +926,8 @@ Puteți avea un singur apel simultan. Reveniți la apelul în curs Nu s-a putut face comutarea camerei foto + Adaugă la favorite + Înlătură din favorite Arată %1$d participant Arată %1$d participanți diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml index cadbc5d5b..3abe96768 100644 --- a/src/main/res/values-ru/strings.xml +++ b/src/main/res/values-ru/strings.xml @@ -395,8 +395,6 @@ Расширенные настройки подключения Показывать имя сервера и порт в настройках аккаунтов xmpp.example.com - Добавить аккаунт с сертификатом - Оставить пустым для входа с сертификатом Настройки архивирования Настройки архивирования на сервере Получение настроек архивирования. Пожалуйста, подождите… diff --git a/src/main/res/values-sk/strings.xml b/src/main/res/values-sk/strings.xml index 9550e222e..2b1bc7a5f 100644 --- a/src/main/res/values-sk/strings.xml +++ b/src/main/res/values-sk/strings.xml @@ -257,6 +257,5 @@ Užívateľské meno Užívateľské meno Toto nie je platné užívateľské meno - Pridať účet s certifikátom Obnoviť certifikát diff --git a/src/main/res/values-sr/strings.xml b/src/main/res/values-sr/strings.xml index 07c70b07b..31f2d50aa 100644 --- a/src/main/res/values-sr/strings.xml +++ b/src/main/res/values-sr/strings.xml @@ -358,8 +358,6 @@ Проширене поставке повезивања Приказ домаћина и порта у поставкама налога xmpp.primer.com - Додај налог сертификатом - Оставите празно за аутентификацију сертификатом Поставке архивисања Серверске поставке архивисања Добављам поставке архивисања, сачекајте… diff --git a/src/main/res/values-sv/strings.xml b/src/main/res/values-sv/strings.xml index c822f9336..cf936ef56 100644 --- a/src/main/res/values-sv/strings.xml +++ b/src/main/res/values-sv/strings.xml @@ -368,8 +368,6 @@ Utökade anslutningsinställningar Visa val av servernamn och port vid inställning av konto xmpp.example.com - Lägg till konto med certifikat - Lämna tom för att för att logga in med certifikat Arkiveringsinställningar Arkiveringsinställningar på servern Hämtar arkiveringsinställningar, vänta... diff --git a/src/main/res/values-tr-rTR/strings.xml b/src/main/res/values-tr-rTR/strings.xml index 62ed0d11a..747fa315b 100644 --- a/src/main/res/values-tr-rTR/strings.xml +++ b/src/main/res/values-tr-rTR/strings.xml @@ -313,8 +313,6 @@ Genişletilmiş bağlantı seçenekleri Hesap oluştururken sunucu adıyla bağlantı noktası seçeneğini göster xmpp.ornek.com - Sertifikalı hesap ekle - w/ sertifikasının kimlik denetimi için boş bırak Arşivleme tercihleri Sunucu tarafı arşivleme tercihleri Arşivleme tercihleri alınıyor. Lütfen bekleyin... diff --git a/src/main/res/values-uk/strings.xml b/src/main/res/values-uk/strings.xml index 47e9fe2a1..7eb79819b 100644 --- a/src/main/res/values-uk/strings.xml +++ b/src/main/res/values-uk/strings.xml @@ -2,9 +2,9 @@ Налаштування Нова розмова - Впорядкувати облікові записи - Впорядкувати обліковий запис - Закрити цю розмову + Мої облікові записи + Мій обліковий запис + Завершити розмову Деталі контакту Деталі групи Деталі каналу @@ -12,46 +12,48 @@ Додати обліковий запис Редагувати ім\'я Додати до контактів - Видалити зі списку розмов + Вилучити зі списку розмов Заблокувати контакт Розблокувати контакт Заблокувати домен Розблокувати домен Заблокувати учасника Розблокувати учасника - Впорядкувати облікові записи + Мої облікові записи Налаштування - Поділитися в Розмови + Поділитися розмовою Почати розмову Вибрати контакт Вибрати контакти Поділитися через обліковий запис - Список блокування + Список блокувань щойно 1 хвилину тому %d хвилин тому %d непрочитаних розмов відправляю… Розшифровую повідомлення. Зачекайте, будь ласка… - Повідомлення, зашифроване OpenPGP - Прізвисько вже використовується + Повідомлення зашифроване OpenPGP + Таке прізвисько вже використовується Неприйнятне прізвисько Адміністратор Власник Модератор Учасник - Відвідувач - Бажаєте заборонити %s надсилати Вам повідомлення? - Бажаєте розблокувати %s і дозволити цій особі надсилати Вам повідомлення? - Заблокувати всі контакти з %s? - Розблокувати всі контакти з %s? + Гість + Бажаєте вилучити %s з вашого списку розмов? Розмову з цим контактом, не буде вилучено. + Бажаєте заборонити %s надсилати вам повідомлення? + Бажаєте розблокувати %s та дозволити цій особі надсилати вам повідомлення? + Заблокувати усі контакти з %s? + Розблокувати усі контакти з %s? Контакт заблоковано Заблоковано - Зареєструвати новий обліковий запис на сервері - Змінити пароль на сервері - Поділитися з… + Бажаєте вилучити %s із закладок? Розмову з цією закладкою не буде вилучено. + Зареєструвати новий обліковий запис + Змінити пароль + Поділитися Почати розмову - Запросити контакт + Запросити до групи Запросити Контакти Контакт @@ -59,74 +61,94 @@ Встановити Додати Змінити - Видалити + Вилучити Заблокувати Розблокувати Зберегти Гаразд - Програма дала збій + Відмова в обслуговуванні + Надсиланням звіту про відмову ви допомагаєте удосконаленню месенджера.\nУвага: Звіти надсилатимуться розробниками з вашого облікового запису XMPP. Надіслати зараз Ніколи не питати знову - Додати файл + Не можу з\'єднатися з обліковим записом + Не можу увімкнути режим багатьох облікових записів + Перейти для керування обліковими записами + Долучити файл + Контакт відсутній у вашому списку розмов. Бажаєте додати його? Додати контакт Надсилання не відбулося + Підготовка зображення до передачі + Готовий до надсилання зображень Поширюю файли. Зачекайте, будь ласка… - Очистити історію - Очистити історію розмов - Видалити файл - Ви певні, що бажаєте видалити цей файл?\n\nУвага: Це не видалить копії цього файла, які зберігаються на інших пристроях чи серверах. - Закрити цю розмову опісля + Стерти історію + Стерти історію розмов + Дійсно вилучити усі повідомлення цієї розмови?\n\nУвага: Повідомлення, які було раніше надіслано, й далі залишатимуться на інших пристроях або серверах. + Вилучити файл + Ви певні, що бажаєте вилучити цей файл?\n\nУвага: Це не вилучить копії цього файлу, які зберігаються на інших пристроях чи серверах. + Завершити цю розмову пізніше Вибрати пристрій - Відправити незашифроване повідомлення - Відправити повідомленн - Відправити повідомлення до %s - Відправити повідомлення, зашифроване OMEMO - Відправити повідомлення, зашифроване v\\OMEMO - Відправити повідомлення, зашифроване OpenPGP - Надіслати незашифрованим - Не вдалося розшифрувати. Можливо, що у Вас немає потрібного приватного ключа. + Незашифроване повідомлення + Надіслати повідомлення + Повідомлення до %s + Повідомлення зашифроване OMEMO + Повідомлення зашифроване v\\OMEMO + Повідомлення зашифроване OpenPGP + Ваше прізвисько змінено + Надіслати без шифрування + Не вдалося розшифрувати. Можливо, у вас відсутній потрібний приватний ключ. OpenKeychain + Застосунок використовує сторонній застосунок OpenKeychain для шифрування та розшифровування повідомлень й упорядкування ваших публічних ключів.\n\nOpenKeychain ліцензовано під GPLv3 й доступний у F-Droid та Google Play.\n\nБудь ласка, перезапустіть месенджер після встановлення. Перезапустити Встановити Будь ласка, встановіть OpenKeychain пропоную… чекаю… Не знайдено жодного OpenPGP ключа - Не знайдено жодного OpenPGP ключа + Не вдалося зашифрувати повідомлення, оскільки контакт не повідомляє власний публічний ключ.\n\nБудь ласка, запропонуйте вашому співрозмовникові встановити OpenPGP. + Не знайдено жодного ключа OpenPGP + Не вдалося розшифрувати повідомлення, оскільки контакт не повідомляє свого публічного ключа.\n\nБудь ласка, попросіть контакт налаштувати OpenPGP. Загальне Приймати файли Автоматично приймати файли менші за… Вкладення Сповіщення Вібрувати - Вібрувати, коли приходять нові повідомлення - Індикація LED + Вібрувати при отриманні нових повідомлень + Світлова індикація Блимати світловим індикатором, коли надходить нове повідомлення - Період очікування - Час, протягом якого не буде сигналу про нові сповіщення, після дій користувача на іншому пристрої. + Мелодія + Звук сповіщень + Звук сповіщень для нових повідомлень + Мелодія вхідного виклику + Час до блокування + Час надсилання сповіщень не буде враховано у разі активності користувача на іншому пристрої Розширені Не надсилати звіти про збої - Повідомлення-підтвердження + Надсиланням звітів про відмову ви допомагаєте у розробці + Підтвердження отримання повідомлень Дайте знати вашим контактам, коли ви отримали й прочитали повідомлення Інтерфейс користувача + Програма OpenKeychain повідомила про помилку. Неприйнятний ключ для шифрування Прийняти Сталася помилка Помилка Ваш обліковий запис - Надсилати оновлення про присутність - Отримувати оновлення про присутність - Надіслати запит на оновлення про присутність - Вибрати зображення + Повідомляти про мою доступність + Отримувати оновлення про доступність + Надіслати запит на оновлення доступності + Зображення Зняти світлину - Попередньо давати запит на підпису - Файл, який Ви вибрали, не є зображенням + Попередньо давати запит на підписку + Переданий файл не є зображенням + Помилка при конвертації зображення Файл не знайдено - Загальна помилка вводу-виводу. Можливо, що у Вашого пристрою закінчилась пам\'ять для збереження? + Загальна помилка вводу-виводу. Можливо, на вашому пристрої закінчилась пам\'ять для збереження? + Застосунок для роботи із зображенням не надав достатніх дозволів.\n\nСкористайтеся іншим файловим менеджером для вибору зображення Невідомо Тимчасово вимкнено У мережі - Підключення\u2026 + З\'єднання\u2026 Не в мережі Не авторизовано Сервер не знайдено @@ -134,148 +156,167 @@ Не вдалося зареєструватися Ім\'я користувача вже використовується Реєстрацію виконано - Недійсний реєстраційний токен + Сервер не підтримує режстрацію + Неправильний реєстраційний токен Узгодження TLS не відбулося Порушення політики Несумісний сервер Помилка потоку Не вдалося відкрити мережевий потік - Незашифровано + Без шифрування OTR OpenPGP OMEMO - Видалити обліковий запис + Вилучити обліковий запис Тимчасово вимкнути - Опублікувати іконку користувача + Опублікувати піктограму користувача Опублікувати публічний ключ OpenPGP - Видалити публічний ключ OpenPGP - Ви впевнені, що хочете видалити ваш публічний ключ OpenPGP з вашого оголошення про присутність?\nВаші контакти більше не зможуть надсилати вам повідомлення, зашифровані OpenPGP. + Вилучити публічний ключ OpenPGP + Ви впевнені, що хочете вилучити ваш публічний ключ OpenPGP з вашого оголошення про присутність?\nВаші контакти більше не зможуть надсилати вам повідомлення, зашифровані OpenPGP. + Публічний ключ OpenPGP опубліковано. Увімкнути обліковий запис Ви впевнені? + Вилучення облікового запису вилучіть всю історію спілкування Записати голос - XMPP адреса - Заблокувати XMPP адресу + Адреса XMPP + Заблокувати адресу XMPP username@example.com Пароль - Не вірний XMPP адрес + Це неправильна адреса XMPP + Пам\'ять вичерпано. Завелике зображення. Бажаєте додати %s до своєї книги контактів? Інформація про сервер - XEP-0313: управління архівом - XEP-0280: копії повідомлень - XEP-0352: індикація стану клієнта - XEP-0191: команди блокування - XEP-0237: зміни списку розмов - XEP-0198: управління потоком - XEP-0163: персональне (іконки користувачів, OMEMO) - XEP-0363: обмін файлами по HTTP - XEP-0357: проштовхувані повідомлення + XEP-0313: Керування архівом + XEP-0280: Копії повідомлень + XEP-0352: Індикація стану клієнта + XEP-0191: Команди блокування + XEP-0237: Зміни у списку розмов + XEP-0198: Керування потоком + XEP-0215: Виявлення зовнішньої служби + XEP-0163: Персональне (піктограми користувачів, OMEMO) + XEP-0363: Обмін файлами через HTTP + XEP-0357: Push-повідомлення є нема Не вистачає повідомлення публічного ключа. - востаннє бачили щойно - востаннє бачили %d хвилин тому - востаннє бачили %d годин тому - востаннє бачили %d днів тому + у мережі + у мережі 1 хвилину тому + у мережі %d хвилин тому + у мережі 1 годину тому + у мережі %d годин тому + у мережі 1 день тому + у мережі %d днів тому + Зашифроване повідомлення. Будь ласка, встановіть OpenKeychain, щоб розшифрувати. + Знайдено повідомлення, зашифроване OpenPGP Ідентифікатор ключа OpenPGP - Відбиток OMEMO - Відбиток v\\OMEMO - Відбиток OMEMO повідомлення - Відбиток v\\OMEMO повідомлення + Цифровий підпис OMEMO + Цифровий підпис v\\OMEMO + Цифровий підпис повідомлення OMEMO + Цифровий підпис повідомлення v\\OMEMO Інші пристрої - Довіряти відбиткам OMEMO + Довіряти цифровим підписам OMEMO Отримую ключі… Зроблено Розшифрувати Закладки Пошук Увести контакт - Видалити контакт + Вилучити контакт Переглянути деталі контакту Заблокувати контакт Розблокувати контакт Створити Вибрати Контакт уже існує - Долучитися + Приєднатися channel@conference.example.com/nick channel@conference.example.com - Зберегти як закладку - Видалити закладку - Видалити груповий чат - Знищити канал - Ви впевнені що бажаєте видалити цей груповий чат?\n\n 1 -Увага: 1 Груповий чат буде видалений з сервера. - Упевнені, що бажаєте знищити цей публічний канал?\n\nУвага: Канал буде повністю знищено та видалено з сервера. - Видалити цей груповий чат не вдалось - Не вдалося знищити канал + Зберегти до закладок + Вилучити закладку + Вилучити груповий чат + Закрити канал + Дійсно вилучити цей груповий чат %s? Груповий чат буде вилучено з сервера. + Дійсно закрити цей публічний канал %s? Канал буде стерто, а дані вилучено з серверу. + Вилучити груповий чат не вдалося + Не вдалося закрити канал Редагувати тему групи Тема Приєднання до групи… - Залишити - Контакт додано до Вашого списку контактів + Вийти + Контакт додано до вашого списку контактів Також додати - %s дочитав до цього місця - %s прочитала до цього місця + %s дочитав(ла) до цього місця + %s прочитав(ла) до цього місця + %1$s +%2$d дочитали до цього місця Усі прочитали до цього місця Опублікувати + Торкніться піктограми користувача, щоб вибрати зображення з галереї Публікація… - Сервер відхилив Вашу публікацію - Не зміг зберегти іконку користувача на пристрій + Сервер відхилив вашу публікацію + Щось пішло не так під час перетворення Вашого зображення + Неможливо зберегти піктограму користувача на пристрій (Або натисніть і тримайте, щоб скинути до значення за замовчуванням) + Ваш сервер не підтримує публікацію піктограм користувачів шепоче %s Надіслати приватне повідомлення %s Підключення Цей обліковий запис уже існує - Наступне + Далі + Поточну сесію встановлено Пропустити - Відключити сповіщення - Задіяти + Вимкнути сповіщення + Увімкнути Група вимагає пароль - Уведіть пароль + Зазначте пароль + Будь ласка, спершу надішліть запит на оновлення пристуності від Вашого контакта.\n\nОновлення буде використано, щоб визначити, яку програму-клієнт (які програми-клієнти) він використовує. Надіслати запит зараз Ігнорувати + Попередження: Надсилання без взаємної згоди на оновлення пристуності може спричинити неочікувані проблеми.\n\nПерегляньте деталі контакту та перевірте отримання стану присутности. Безпека - Дозволити міняти повідомлення - Дозволити контактам редагувати свої повідомлення після відправки + Дозволити редагування повідомлень + Дозволити контактам редагувати свої повідомлення після надсилання Експертні налаштування Будь ласка, будьте обережними з цим Близько %s Години тиші Час початку Час завершення - Задіяти години тиші + Увімкнути години тиші Сповіщення не звучатимуть під час годин тиші Інше - Синхронізувати з закладками + Синхронізовувати з закладками + Приєднуватися до груп і полишати їх відповідно до опції автоматичного приєднання, вибраної в закладках. + Цифровий підпис OMEMO скопійовано Вам заборонили доступ до цієї групи Ця група лише для учасників Обмеження ресурсів - Вас вигнали з цієї групи + Вас виключили з цієї групи Цю групу закрили - Ви більше не берете участь в цій групі + Ви більше не берете участі у цій групі використовується обліковий запис %s розміщений на %s - Перевіряю %s на хості HTTP - Ви не з\'єднані. Спробуйте ще пізніше. + Перевіряю %s на вузлі з HTTP + Ви поза мережею. Спробуйте ще пізніше. Перевірити %s розмір Перевірити %1$s розмір на %2$s Налаштування повідомлення Цитувати Вставити як цитату - Скопіювати оригінальний URL + Копіювати оригінальний URL Надіслати знову URL файла - URL скопійовано до комірки обміну - Адресу XMPP скопійовано до комірки обміну - Текст повідомлення про помилку скопійовано до комірки обміну - веб адреса + URL скопійовано + Адресу XMPP скопійовано + Текст повідомлення про помилку скопійовано + вебадреса Розпізнати QR-код Показати QR-код Показати список блокування Деталі облікового запису Підтвердити Спробуйте ще + Фонова служба Не дає операційній системі припиняти Ваш зв\'язок Створити резервну копію Резервні копії зберігатимуться до %s @@ -284,25 +325,35 @@ Резервні копії збережено до %s Відтворення з резервної копії Відтворено з резервної копії - Не забудьте включити обліковий запис - Вибрати файл + Не забудьте увімкнути обліковий запис + Файл Отримання %1$s (%2$d%% завершено) Завантажити %s - Видалити %s + Вилучити %s файл Відкрити %s надсилання (%1$d%% завершено) + Підготовка файлу до передачі %s запропоновано для завантаження Припинити передачу - передачу файлу перервано - Динамічні мітки - Показувати мітки \"лише для читання\" під контактами + передача файла не вдалася + скасовано передачу файлу + Файл вилучено + Не знайдено програми для відкриття файла + Не знайдено застосунку для відкриття посилання + Не знайдено програми, щоб переглянути контакт + Динамічні позначки + Показувати позначку \"лише для читання\" під контактами Увікнути сповіщення Не знайдено сервер групи + Не вдалося створити групу! Іконка облікового запису - Скопіювати OMEMO відбиток до комірки обліку - Згенерувати ключ OMEMO + Копіювати цифровий підпис OMEMO + Повторно створити ключ OMEMO Стерти пристрої + Ви певні, що хочете стерти всі інші пристрої з OMEMO-оголошення? Наступного разу, коли Ваші пристрої приєднаються, вони знову оголосять про себе, але вони можуть не отримати повідомлення, які можуть бути надіслані тим часом. + Немає ключів, які б можна було використати для цього контакту.\nНе вдалося отримати нові ключі з сервера. Можливо, щось не так з сервером контактів. + Для цього контакту відсутні потрібні ключі.\nПеревірте, що ви обмінялися інформацією про доступність. Щось пішло не так Отримую історію з сервера Більше немає історії на сервері @@ -312,10 +363,11 @@ Змінити пароль Поточний пароль Новий пароль - Задіяти всі облікові записи - Відключити всі облікові записи + Пароль не може бути порожнім + Увімкнути всі облікові записи + Вимкнути всі облікові записи Здійснити дію з - Не пов\'язаний + Непов\'язаний Не в мережі Вигнанець Учасник @@ -326,13 +378,14 @@ Відкликати права адміністратора Надати права власника Відкликати права власника - Видалити з групи + Вилучити з групи Прибрати з каналу - Не можу змінити пов\'язаність з %s + Неможливо змінити статус приєднання з %s Заборонити доступ до групи - Заборонити в каналі - Вигнати зараз - Не можу змінити роль %s + Вилучити з каналу + Ви намагаєтеся вилучити %s з публічного каналу. Єдиним способом для цього є заблокувати користувача назавжди. + Вилучити зараз + Неможливо змінити роль %s Налаштування приватного чату Налаштування публічного каналу Приватно, лише для членів @@ -347,10 +400,10 @@ Відповісти Позначити як прочитане Введення - Enter для відправки - Використовуйте клавішу enter для відправлення повідомлення - Відобразити клавішу enter - Змінити кнопку смайлів на кнопку enter + Enter для надсилання + Використовувати Enter для надсилання повідомлення + Показувати кнопку Enter + Змінити клавішу емоційок на кнопку Enter аудіо відео зображення @@ -358,80 +411,88 @@ програма Android Контакт Іконку користувача опубліковано! - Відправка %s + Надсилання %s Пропозиція %s - Сховати ті, що не в мережі - %s друкує… - %s припинив друкувати - %s набирає повідомлення… - %s перестав набирати повідомлення + Сховати поза мережею + %s пише… + %s припинив писати + %s пишуть… + %s припинив писати Сповіщення про набір - Дайте вашим контактам знати, коли ви набираєте їм повідомлення - Відправити місцезнаходження + Дайте вашим контактам знати, коли ви пишете їм повідомлення + Розташування Показати місцезнаходження - Місцезнаходження + Не знайдено програми, щоб показати місцезнаходження + Розташування Розмову закрито Полишити приватну групу обміну повідомленнями - Полишити публічний канал + Залишити публічний канал Не довіряти системним центрам сертифікації Усі сертифікати мають бути підтверджені вручну - Видалити сертифікати - Видалити сертифікати, підтверджені вручну + Вилучати сертифікати + Вилучити сертифікати, які було підтверджено вручну Немає сертифікатів, підтверджених вручну - Видалити сертифікати - Видалити вибране + Вилучити сертифікати + Вилучити вибране Скасувати - %d сертифікат видалено + %d сертифікат вилучено %d сертифікати видалено %d сертифікатів видалено - %d сертифікатів видалено + %d сертифікатів вилучено + Замінювати кнопку надсилання швидкими діями Швидкі дії Жодної Остання, що використана Вибрати швидку дію Шукати в контактах Шукати закладки - Відправити приватне повідомлення + Приватне повідомлення + %1$s залишила групу! Ім\'я користувача Ім\'я користувача Таке ім\'я користувача не допустиме - Завантаження не вдалося: Сервер не знайдено - Завантаження не вдалося: Сервер не знайдено - Завантаження не вдалося: Не вийшло з\'яєднатися з хостом - Завантаження не вдалося: Не зміг записати файл - Мережа Tor не доступна + Звантаження не вдалося: сервер не знайдено + Звантаження не вдалося: файл не знайдено + Звантаження не вдалося: неможливо з\'єднатися з вузлом + Завантаження не вдалося: неможливо записати файл + Мережа ToR не доступна Прив\'язка не спрацювала + Сервер не відповідає за цей домен Поламано - Присутність - Відійшов, якщо екран викнуто - Показувати стан як відійшов, якщо екран вимкнуто + Доступність + Відійшов, якщо екран вимкнено + Показувати стан \"відійшов\", якщо екран вимкнено \"Не турбувати\" в режимі тиші Додавати \"Не турбувати\" до імені вашого пристрою, коли пристрій в режимі тиші Вважати вібро за безшумний режим Додавати \"Не турбувати\" до імені вашого пристрою, коли пристрій в режимі вібрації Розширені налаштування з\'єднання - Показати налаштування імені хосту та порту при налаштуванні облікового запису + Показати налаштування імені вузла та порту при налаштуванні облікового запису xmpp.example.com - Додати обліковку з сертифікатом - Залиште порожнім, щоб авторизувати без сертифіката + Вхід із сертифікатом + Не можу розпізнати сертифікат Налаштування збереження Налаштування збереження на стороні сервера Отримую налаштування збереженя. Будь ласка, зачекайте… + Не зміг отримати налаштування збереження + Потрібно розв\'язати головоломку Уведіть текст із зображення вище + Ланцюжок сертифікатів не довірений XMPP адрес не відповідає сертифікату Оновити сертифікат Помилка отримання ключа OMEMO! Ключ OMEMO звірено з сертифікатом! Ваш пристрій не підтримує вибір сертифікатів клієнта! З\'єднання - З\'єднання через Tor + З\'єднання через ToR Тунелювати всі з\'єднання через мережу Tor. Потребує Orbot - Назва хосту + Назва вузла Порт - Це не дійсний номер порту - Це не дійсне ім\'я хосту + Адреса сервера або адреса .onion + Це недійсний номер порту + Це недійсне ім\'я вузла %1$d з %2$d облікових записів у мережі %d повідомлення @@ -440,8 +501,15 @@ %d повідомлень Завантажити більше повідомлень + Файлом поділилися з %s + Поділитися зображенням з %s + Поділитися зображеннями з %s + Текстом поділилися з %s + Надати доступ до зовнішнього сховища даних + Надати доступ до камери Синхронізувати контакти -
Ми не зберігатимемо копію цих номерів телефонів.\n\nЩоб дізнатися більше, читайте політику конфіденційності.

Зараз з\'явиться запит на надання доступу до Ваших контактів.]]>
+ Застосунку потрібний доступ до ваших контактів для відображення повних імен контактів та їхніх піктограм. \n\nДля цього буде прочитано ваші контакти та співставлено їх зі списком контактів XMPP. При цьому дані не надсилатимуться на сервер. +
Ми не зберігатимемо копію цих телефонних номерів.\n\nДокладна інформація про Політику конфіденційності.

Зараз ви побачите запит на надання доступу до ваших контактів.]]>
Сповіщати про всі повідомлення Повідомляти, лише якщо згадують Сповіщення вимкнено @@ -451,30 +519,37 @@ Завжди Лише великі зображення Оптимізацію батареї задіяно - Відключити + Ваш пристрій здійснює деяку агресивну оптимізацію Розмов для збереження заряду батареї, яка може призвести до затримки сповіщення або навіть втрати повідомлень.\nРекомендовано відключити цю оптимізацію. + Ваш пристрій здійснює деяку агресивну оптимізацію Розмов для збереження заряду батареї, яка може призвести до затримки сповіщення або навіть втрати повідомлень.\nПросимо Вас зараз відключити цю оптимзацію. + Вимкнути Вибрана ділянка завелика (Немає активних облікових засобів) - Це поле вимагається - Виправити повідомлення - Відправити виправлене повідомлення + Це обов\'язкове поле + Відредагувати + Відредаговане повідомлення + Ви вже довіряєте цій особі. Вибираючи \"Готово\", ви лише підтверджуєте, що %s є учасником групи. Ви вимкнули цей обліковий запис - Поділитися URI з… -
Реєструєтеся за номером телефона, а Quicksy автоматично за номерами телефонів зі списку контактів на пристрої запропонує Вам можливі контакти.

Підписуючись на цю послугу Ви погоджуєтеся з нашою політикою конфіденційності.]]>
- Ваша повна адреса XMPP буде: %s + Помилка з безпекою: Неправильний доступ до файлу! + Не знайдено програми, щоб поділитися URI + Поділитися URI +
Реєструйтеся за номером телефону, а Quicksy автоматично за номерами телефонів зі списку контактів на пристрої запропонує вам доступні контакти.

Користування цим застосунком означає, що ви погоджуєтеся з нашою Політикою конфіденційності.]]>
+ Погодитися та продовжити + Ми допоможемо вам створити обліковий запис. На наступній сторінці ви зможете змінити автоматично створений пароль.\nПодалі ви зможете спілкуватися з користувачами вашого або будь-якого іншого провайдера, для цього потрібно буде надати користувачеві вашу повну адресу XMPP. + Ваша повна адреса XMPP буде такою: %s Створити обліковий запис - Використати мого власного провайдера - Оберіть Ваше ім\'я користувача - Управляти присутністю вручну - Встановлюйте присутність, коли редагуєте повідомлення стану + Застосувати дані мого власного провайдера + Придумайте ім\'я користувача + Керувати станом вручну + Показувати доступність під час редагування повідомлення зі статусом. Повідомлення стану Вільний для розмови У мережі Відійшов - Не доступний - Зайняти - Згенеровано надійний пароль - Ваш пристрій не підтримує відключення оптимізації батареї - Реєстрація не вдалася: Спробуйте ще раз пізніше + Недоступний + Зайнятий + Створено надійний пароль + Ваш пристрій не підтримує вимкнення оптимізації батареї + Реєстрація не вдалася: спробуйте ще раз пізніше Реєстрація не відбулася: пароль занадто слабкий. Вибрати учасників Створення групи… @@ -483,12 +558,17 @@ Короткий Середній Довгий + Показувати останню активність користувача + Дозвольте всім вашим контактам знати, коли ви використовуєте месенджер Приватність Тема - Вибрати палітру кольорів + Виберіть колір теми Автоматично + Світла + Темна Зелене тло Використовувати зелене тло для отриманих повідомлень + Не можу зв\'язатися з OpenKeychain Цей пристрій більше не використовується Комп\'ютер Мобільний телефон @@ -496,39 +576,51 @@ Браузер Консоль Вимагається оплата + Немає дозволу до користування Інтернет Я - Контакт просить надати підписку на присутність + Контакт просить надавати інформацію про вашу доступність Дозволити Немає дозволу на доступ до %s Віддалений сервер не знайдено Затримка відповіді сервера - Видалити ідентифікаційні дані OMEMO - Видалити вибрані ключі - Потрібно підключення, щоб можна було опублікувати іконку користувача. + Неможливо оновити обліковий запис + Надіслати скаргу про те, що контакт з цим ID розсилає спам. + Вилучити ідентифікаційні дані OMEMO + Створити наново ваші ключі OMEMO. Усі ваші контакти будуть змушені підтвердити вас знову. Використовуйте це, лише якщо немає іншого вибору. + Вилучити вибрані ключі + Потрібно підключення, щоб можна було опублікувати піктограму користувача. Показати повідомлення про помилку Повідомлення про помилку - Задіяно економію передачі данних - Ваш пристрій не дає можливості вимкнути економію передачі даних з програми Conversations + Увімкнено заощадження передачі даних + Ваша операційна система обмежує застосунку доступ до мережі Інтернету під час снуна екрані. Щоб отримувати сповіщення про нові повідомлення, вам слід дозволити застосунку необмежений доступ, коли увімкнено заощадження передачі даних.\nЗастосунок Conversations все одно буде намагатися заощаджувати трафік, коли це можливо. + Ваш пристрій не дає можливості вимкнути заощадження передачі даних для Conversations + Неможливо створити тимчасовий файл Цей пристрій перевірено - Скопіювати відбиток - Перевірений відбиток + Копіювати цифровий підпис + Усі ключі OMEMO перевірено + QR-код не містить цифрових підписів для цієї розмови. + Перевірені цифрові підписи Використайте камеру для сканування QR-коду контакту Зачекайте поки ключі отримуються - Поділитися через QR-код  + Поділитися через QR-код Поділитися XMPP URI Поділитися посиланням HTTP - Сліпо вірити перед перевіркою + Довіряти новим пристроям + Автоматично довіряти усім новим пристроям співрозмовників, які ще не пройшли перевірки, запитувати підтвердження вручну щоразу, як перевірений контакт додає свій новий пристрій + Ключі OMEMO наосліп прийнято як довірені Недовірений - Недійсний QR-код  + Недійсний QR-код + Очистити теку з кешем (використовується застосунком Камера) Очистити кеш Очистити приватне сховище - Очистити приватне сховище, де зберігаються файли (Вони можуть бути завантажені повторно з сервера) - Я прослідував за цим посиланням від довіреного джерела + Очистити приватне сховище, де зберігаються файли (Їх можна повторно звантажити з сервера) + Я перейшов за цим посиланням від довіреного джерела Ви збираєтеся підтвердити ключі OMEMO для %1$s після переходу за посиланням. Це безпечно, лише якщо ви отримали посилання з довіреного джерела, де лише %2$s міг опублікувати це посилання. - Підтвердити ключі OMEMO + Підтвердити цифрові підписи OMEMO Показувати неактивні Приховати неактивні - Недовіряти пристрою + Не довіряти пристрою + Ви певні, що більше не довіряєте цьому пристрою?\nЦей пристрій і повідомлення з нього будуть позначатися як недовірені. %d секунда %d секунди @@ -565,69 +657,74 @@ %d місяців %d місяців - Автоматичне видалення повідомлень - Автоматично видаляти повідомлення з цього пристрою, старіші за вказаний часовий проміжок. + Автоматичне вилучення повідомлень + Автоматично вилучати повідомлення з цього пристрою, старіші за зазначений проміжок часу. Зашифровую повідомлення Повідомлення не завантажуються з огляду на локально встановлений строк зберігання. Стиснення відео - Відповідні розмови закрито. + Відповідні розмови завершено. Контакт заблоковано. Сповіщення від незнайомців + Сповіщувати про повідомлення від незнайомців Отримано повідомлення від незнайомця - Заблокувати незнайомця + Заблокувати невідомий контакт Заблокувати весь домен у мережі просто зараз Спробувати знову розшифрувати Помилка сесії Застарілий механізм SASL - Сервер вимагає реєстрації через сайт - Відкрити сайт - Сповіщення у спливних повідомленнях + Сервер вимагає реєстрації на вебсайті + Перейти на вебсайт + Не знайдено застосунку для перегляду вебсайту + Сповіщення у виринаючих повідомленнях + Показувати сповіщення у виринаючих повідомленнях Сьогодні Учора - Перевіряти адресу з допомогою DNSSEC - Сертифікати, які містять завірену адресу, вважаються засвідченими + Перевіряти адресу за допомогою DNSSEC + Сертифікати, які містять підтверджену адресу вузла, вважаються перевіреними Сертифікат не містить XMPP адресу частково Записати відео - Скопіювати до комірки обміну - Повідомлення скопійовано до комірки обміну + Копіювати + Повідомлення скопійовано Повідомлення Приватні повідомлення вимкнено Захищені програми - Щоб отримувати сповіщення, навіть коли екран погас, Вам потрібно додати програму до переліку програм, до яких не застосовується енергозаощадження. + Для отримання сповіщень, навіть коли екран погас, вам потрібно додати застосунок до списку застосунків, до яких не застосовується режим енергозбереження. Прийняти незнайомий сертифікат? - Сертифікат сервера не засвідчено відомим центром сертифікації - Прийняти сервер, ім\'я якого не збігається? + Сертифікат сервера не підтверджено відомим центром сертифікації + Прийняти сервер з невідповідним ім\'ям? Не вдається перевірити сервер як \"%s\". Сертифікат чинний лише для: Усе одно бажаєте підключитися? Деталі сертифіката: Один раз - Сканер QR кодів потребує доступу до камери - Прокрутити до кінця - Прокрутити до кінця після відправлення повідомлення + Сканер QR-кодів потребує доступу до камери + Прокрутити вниз до кінця + Прокрутити вниз до кінця після надсилання повідомлення Редагувати повідомлення стану Редагувати повідомлення стану Вимкнути шифрування - Програма не може відправляти зашифровані повідомлення до %1$s. Можливо, Ваш контакт використовує застарілий сервер або клієнт, який не підтримує OMEMO. - Підказка: В деяких випадках це можна виправити, додавши кожен інший Ваш перелік контактів. - Ви певні, що хочете відключити шифрування OMEMO?\nЦе створить можливість для адміністратора Вашого сервера читати Ваші повідомлення, але це може бути єдиним способом спілкуватися з людьми, які використовують застарілі програми. - Відключити зараз - Проект: + Застосунок не може відправляти зашифровані повідомлення до %1$s. Можливо, що ваш контакт використовує застарілий сервер або застосунок, який не підтримує OMEMO. + Неможливо отримати перелік пристроїв + Неможливо отримати пакети пристроїв + Підказка: В деяких випадках це можна виправити, якщо додати один до одного у ваших списках контактів. + Дійсно вимкнути шифрування OMEMO?\nПісля цього у адміністратора вашого сервера буде можливість мати доступ до ваших повідомлень. Проте, це може бути єдиним способом спілкуватися з людьми, які використовують застарілі застосунки. + Вимкнути зараз + Чернетка: Шифрування OMEMO - OMEMO завжди використовуватиметься для розмов віч-на-віч і в приватних групах. - За замовчуванням для нових розмов використовуватиметься OMEMO. - OMEMO потрібно буде включати окремо для кожної нової розмови. + OMEMO завжди використовуватиметься для приватних розмов та у приватних групах. + Типово для нових розмов використовуватиметься OMEMO + OMEMO потрібно буде активізовувати окремо для кожної нової розмови. Створити ярлик Розмір шрифту - Відносний розмір шрифту в програмі. - За замовчування ввімкнено - За замовчуванням вимкнено + Розмір шрифту у застосунку + Типово ввімкнено + Типово вимкнено Малий Середній - Велики + Великий Повідомлення не було зашифровано для цього пристрою - Не вийшло розшифрувати повідомлення OMEMO. + Не вдалося розшифрувати повідомлення OMEMO. скасувати Доступ до місцезнаходження вимкнено Закріпити розташування @@ -638,118 +735,132 @@ Поділитися розташуванням Показати розташування Поділитися + Не можу почати запис Прошу зачекайте… + Програма потребує доступу до мікрофона Шукати в повідомленнях GIF Переглянути розмову Додаток поширення місцезнаходження Використовувати додаток поширення місце-знаходження замість вбудованої карти - Скопіювати веб адресу - Скопіювати XMPP адресу - Доступ до файлів по HTTP для S3 + Копіювати посилання + Копіювати адресу XMPP + Доступ до файлів через HTTP для S3 Безпосередній пошук - На екрані початку розмови відкривати клавіатуру й розміщувати курсор в поле пошуку - Іконка групи - Сервер не підтримує іконки для груп - Лише власник може змінити іконку групи - Ім\'я контакта + На екрані початку розмови показувати клавіатуру та розміщувати курсор у полі пошуку + Піктограма групи + Сервер не підтримує піктограми груп + Лише власник може змінити піктограму групи + Ім\'я контакту Прізвисько Ім\'я - Давати ім\'я не обов\'язково + Назва не є обов\'язковою Назва групи - Цю групу знищено + Цю групу закрито + Неможливо зберегти запис Процес на передньому плані - Цей вид сповіщень буде постійно показувати, що програма працює. + Цей вид сповіщень буде постійно показувати, що застоунок працює. Інформація про стан - Проблеми з підключенням - Цей вид сповіщень показує проблеми при з\'єднанні з обліковим записом. + Проблеми зі з\'єднанням + Цей вид сповіщень показує проблеми під час з\'єднання з обліковим записом. Повідомлення + Виклики Повідомлення + Вхідні виклики + Активні виклики Тихі повідомлення - Ця група сповіщень показує сповіщення, які не повинні супроводжуватися звуком. Наприклад, у разі активності на іншому пристрої (період очікування). - Важливість, звук, вібрація + Ця група сповіщень показує сповіщення, які не повинні супроводжуватися звуком. Наприклад, у разі активности на іншому пристрої (період очікування). + Налаштування сповіщень повідомлень + Налаштування сповіщень про вхідні виклики + Налаштування пріоритетів, звуку та режиму вібрації для сповіщень Стиснення відео Перегляд медіа Учасники - Переглядач медіа - Файл пропущено через порушення безпеки. + Перегляд файлів + Файл не долучено через порушення безпеки. Якість відео Менша якість означає менші файли Середня (360 пікселів) Висока (720 пікселів) скасовано Ви вже маєте чернетку повідомлення. - Функція в розробці. + Функція в розробці Недійсний код країни Виберіть країну номер телефону перевірити номер телефону - Quicksy відправить SMS, щоб перевірити Ваш номер телефону. Тарифами Вашого оператора може бути передбачено плату за отримання SMS. Уведіть код країни та номер телефону: -
%s

Правильно, чи Ви б хотіли змінити номер?]]>
+ Quicksy надішле SMS, щоб перевірити ваш номер телефону. Тарифами Вашого оператора може бути передбачено плату за отримання SMS. Зазначте код вашої країни та номер телефону: +
%s

Чи все гаразд або ви бажаєте зазначити інший номер?]]>
%s не є дійсним номером телефону. - Будь ласка, введіть Ваш номер телефону. + Будь ласка, введіть ваш номер телефону. Шукати країну Підтвердити %s - %s.]]> - Ми направили Вам SMS із кодом з 6 цифр - Будь ласка, введіть 6 цифр коду нижче. - Направити нове SMS - Направити нове SMS (%s) + %s.]]> + Ми направили вам SMS із кодом з 6 цифр + Будь ласка, введіть нижче 6 цифр коду. + Надіслати нове SMS + Надіслати нове SMS (%s) Будь ласка, зачекайте (%s) повернутися - Можливий код, автоматично скопійований з комірки обміну. - Будь ласка, введіть Ваш код з 6 цифр нижче. + Код, автоматично вставлений з буферу обміну. + Будь ласка, введіть нижче ваш код з 6 цифр. Ви певні, що хочете припинити процедуру реєстрації? Так Ні Підтверджую… Запит SMS… - Код, який Ви ввели, неправильний. - Код, який Ви ввели, застарів. + Код, який ви ввели, не правильний. + Код, який ви ввели, застарів. Невідома помилка мережі. Сервер дав незрозумілу відповідь. - Щось пішло не так під час обробки Вашого запиту. - Користувач увів неприпустимі дані + Неможливо приєднатися до сервера. + Неможливо встановити безпечне з\'єднання. + Неможливо знайти сервер. + Щось пішло не так під час обробки вашого запиту. + Користувач зазначив неправильні дані Тимчасово недоступний. Будь ласка, спробуйте знову пізніше. Відсутнє з\'єднання з мережею. Будь ласка, спробуйте ще раз через %s Ви обмежені за рейтингом Забагато спроб - Ваша версія програми застаріла + Версія вашого застосунку застаріла Оновити - Цей номер телефону на разі авторизований на іншому пристрої - Будь ласка, введіть Ваше ім\'я, щоб надати можливість людям, які не мають Вашого контакту в своїх книгах, дізнатися, хто Ви. + Зараз цей номер телефону авторизований на іншому пристрої. + Будь ласка, зазначте ваше ім\'я, щоб надати можливість людям, які не мають вашого контакту, дізналися, хто ви є. Ваше ім\'я - Введіть Ваше ім\'я - Використовуйте кнопку редагування, щоб встановити ім\'я. + Зазначте ваше ім\'я + Відредагуйте ім\'я користувача. Відхилити запит Встановити Orbot Запустити Orbot - Не знайдено програми для пошуку й встановлення нових програм. + Не знайдено застосунку для пошуку й встановлення нових застосунків. Цей канал опублікує вашу адресу XMPP - електронна книга + Електронна книга Оригінал (не стиснений) - Відкрити за допомогою... + Відкрити Фото профілю чату Виберіть обліковий запис Відновити з резервної копії Відновити - Введіть пароль для облікового запису %s, щоб відновити з резервної копії. - Не використовуйте відновлення з резервної копії з метою клонувати інсталяцію (запускати одночасно ще один примірник). Відновлення з резервної копії призначене виключно для перенесення або на випадок втрати оригінального пристрою. + Зазначте пароль до облікового запису %s, щоб відновити з резервної копії. + Не використовуйте відновлення з резервної копії з метою клонування застосунку (запускати одночасно ще один примірник). Відновлення з резервної копії призначене виключно для перенесення даних або на випадок втрати оригінального пристрою. + Неможливо відновити з резервної копії. + Неможливл розшифрувати резервну копію. Чи пароль правильний? Створити або відновити резервну копію Ввести адресу XMPP Створити групу обміну повідомленнями Приєднатися до публічного каналу - Створити приватну групу обміну повідомленнями + Створити приватну групу Створити публічний канал Назва каналу Адреса XMPP - Будь ласка, дайте назву для каналу + Будь ласка, дайте назву цьому каналу Будь ласка, надайте адресу XMPP - Це адреса XMPP. Будь ласка, дайте назву. + Це адреса XMPP. Будь ласка, додайте назву. Створення публічного каналу… Цей канал уже існує Ви приєдналися до наявного каналу + Неможливо налаштувати канал Дозволити будь-кому редагувати тему Дозволити будь-кому запрошувати інших Будь-хто може редагувати тему. @@ -759,16 +870,16 @@ Будь-хто може запрошувати інших. Адміністратори бачать адреси XMPP. Будь-хто бачить адреси XMPP. - Цей публічний канал без учасників. Запросіть Ваші контакти або скористайтеся кнопкою поширення, щоб поділитися адресою XMPP. - Ця приватна група обміну повідомленнями без учасників. - Управляти правами + Цей публічний канал не має учасників. Запросіть ваші контакти або скористайтеся кнопкою поширення, щоб поділитися адресою XMPP. + У цій приватній групі обміну повідомленнями відсутні учасники. + Керувати правами Шукати учасників Файл надто великий Долучити - Знайти канали + Пошук каналу Шукати канали Можливе порушення приватності! - search.jabber.network.

Користуючись ним, Ви передає Вашу IP адресу та пошукові запити цьому сервісу. Перегляньте їхню політику конфіденційності, щоб отримати більше інформації.]]>
+ search.jabbercat.org.

Використання цієї функції передає вашу IP-адресу та пошукові запити цьому сервісу. Перегляньте їхню Політику конфіденційности, щоб отримати більше інформації.]]>
Я вже маю обліковий запис Додати наявний обліковий запис Зареєструвати новий обліковий запис @@ -776,25 +887,59 @@ Додати все одно Це схоже на адресу каналу Поділитися резервними копіями - Резервне копіювання розмов + Резервна копія Подія Відкрити резервну копію - Обраний файл не є резервною копією цієї програми - Цей обліковий запис уже налаштовано - Будь ласка, введіть пароль цього облікового запису - Приєднатися до публічного каналу… + Вибраний файл не є резервною копією + Цей обліковий запис уже створено + Будь ласка, введіть пароль для цього облікового запису + Неможливо виконати цю дію + Приєднатися до відкритого каналу… + Застосунок для спільного доступу не надав дозволу на доступ до цього файлу. jabber.network Локальний сервер - Пересічному користувачеві слід обрати «jabber.network» для кращих пропозицій з усієї публічної XMPP екосистеми. + Більшість користувачів вибирають \'jabber.network\' як одну з кращих пропозицій зі всіх публічних середовищ XMPP. Спосіб пошуку каналів Резервне копіювання Про - Будь ласка, увімкніть обліковий запис + Будь ласка, активуйте обліковий запис + Здійснити виклик + Вхідний виклик + Вхідний відеовиклик + З\'єднання + З\'єднано + Приймаю виклик + Завершую виклик + Відповісти + Відхилити + Пошук пристроїв + Викликаю + Зайнято + Неможливо здійснити виклик + Відхилені виклики + Помилка застосунку + Завершити + Активний виклик + Активний відеовиклик + Вимкнути ToR для здійснення викликів + Вхідний виклик + %s · Вхідний виклик · %s + Вихідний виклик + %s · Вихідний виклик · %s + Пропущені виклики + Голосовий виклик + Відеовиклик + Недоступний мікрофон + Водночас можливо здійснювати лише один виклик. + Назад до активного виклику + Неможливо перемкнути камеру + Додати до обраного + Вилучити з обраного - Переглянути %1$d учасника - Переглянути %1$d учасників - Переглянути %1$d учасників - Переглянути %1$d учасників + Перегляд %1$d учасника + Перегляд %1$d учасників + Перегляд %1$d учасників + Перегляд %1$d учасників
diff --git a/src/main/res/values-vi/strings.xml b/src/main/res/values-vi/strings.xml index 770503323..bc329d8cf 100644 --- a/src/main/res/values-vi/strings.xml +++ b/src/main/res/values-vi/strings.xml @@ -292,8 +292,6 @@ Bị hỏng Vắng mặt khi màn hình tắt Hiện ứng dụng là \'vắng mặt\' khi màn hình tắt - Thêm tài khoản với chứng nhận - Bỏ trống để xác minh với chứng nhận Gia hạn chứng nhận Lỗi nhập khoá OMEMO! Khoá OMEMO đã xác minh với chứng nhận! diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml index c8d0ce1cb..2b3223c05 100644 --- a/src/main/res/values-zh-rCN/strings.xml +++ b/src/main/res/values-zh-rCN/strings.xml @@ -468,9 +468,8 @@ 高级连接设置 注册账户时显示主机名和端口 xmpp.example.com - 使用证书添加账户 + 用证书登录 无法解析证书 - 留空以使用证书认证 存档设置 服务端存档设置 正在获取存档设置。请稍候…… @@ -890,6 +889,7 @@ 正在结束来电 应答 忽略 + 发现设备中 正在响铃 正忙 无法接通来电 @@ -910,6 +910,8 @@ 只能同时打一通电话 返回正在进行的通话 无法切换摄像头 + 添加到收藏夹 + 从收藏夹删除 查看%1$d成员 diff --git a/src/main/res/values-zh-rTW/strings.xml b/src/main/res/values-zh-rTW/strings.xml index aff201091..d026a66e0 100644 --- a/src/main/res/values-zh-rTW/strings.xml +++ b/src/main/res/values-zh-rTW/strings.xml @@ -315,8 +315,6 @@ 高級連接設置 註冊帳戶時顯示主機名稱和埠 xmpp.example.com - 使用證書添加帳戶 - 留空以認證 w/ 證書 壓縮設置 服務端壓縮設置 正在獲取壓縮設置。請稍後... diff --git a/src/main/res/values/attrs.xml b/src/main/res/values/attrs.xml index 5f5d848f7..48a4733b9 100644 --- a/src/main/res/values/attrs.xml +++ b/src/main/res/values/attrs.xml @@ -1,127 +1,127 @@ - - - - - - - - + + + + + + + + - + - - - - - - - + + + + + + + - - - + + + - + - - - + + + - - - - - - - + + + + + + + - - - - - - + + + + + + - - + + + - + + + - - - + - + - + + - - - - - - - - - - + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + - - - - + + + + + - - + + - + - + \ No newline at end of file diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 8dff49852..b718fb116 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -469,9 +469,8 @@ Extended connection settings Show hostname and port settings when setting up an account xmpp.example.com - Add account with certificate + Login with certificate Could not parse certificate - Leave empty to authenticate w/ certificate Archiving preferences Server-side archiving preferences Fetching archiving preferences. Please wait… @@ -921,6 +920,8 @@ You can only have one call at a time. Return to ongoing call Could not switch camera + Add to favorites + Remove from favorites View %1$d Participant View %1$d Participants diff --git a/src/main/res/values/themes.xml b/src/main/res/values/themes.xml index 9e7a0bf4c..c31a9d71f 100644 --- a/src/main/res/values/themes.xml +++ b/src/main/res/values/themes.xml @@ -19,7 +19,9 @@ @drawable/search_background_light @drawable/no_results_background_light - @drawable/no_results_primary_background_light + + @drawable/no_results_primary_background_light + @drawable/list_item_background_light @color/black @@ -39,87 +41,108 @@ @color/black12 - @drawable/ic_send_cancel_offline - @drawable/ic_send_location_offline - @drawable/ic_send_photo_offline - @drawable/ic_send_picture_offline - @drawable/ic_send_text_offline - @drawable/ic_send_videocam_offline - @drawable/ic_send_voice_offline + @drawable/ic_send_cancel_offline + @drawable/ic_send_location_offline + + @drawable/ic_send_photo_offline + @drawable/ic_send_picture_offline + + @drawable/ic_send_text_offline + @drawable/ic_send_videocam_offline + + @drawable/ic_send_voice_offline - @drawable/ic_attach_camera - @drawable/ic_attach_videocam - @drawable/ic_attach_document - @drawable/ic_attach_location - @drawable/ic_attach_photo - @drawable/ic_attach_record + @drawable/ic_attach_camera + @drawable/ic_attach_videocam + @drawable/ic_attach_document + @drawable/ic_attach_location + @drawable/ic_attach_photo + @drawable/ic_attach_record - @drawable/ic_call_black54_24dp - @drawable/ic_videocam_black54_24dp + @drawable/ic_call_black54_24dp + @drawable/ic_videocam_black54_24dp - @drawable/message_bubble_received_white - @drawable/message_bubble_sent - @drawable/message_bubble_received + + @drawable/message_bubble_received_white + + @drawable/message_bubble_sent + + @drawable/message_bubble_received + @color/orange700_desaturated @color/orange700 - 0.54 - 0.70 + 0.54 + 0.70 24dp 16dp - @drawable/ic_description_black_48dp - @drawable/ic_mic_black_48dp - @drawable/ic_headset_black_48dp - @drawable/ic_room_black_48dp - @drawable/ic_person_black_48dp - @drawable/ic_android_black_48dp - @drawable/ic_event_black_48dp - @drawable/ic_archive_black_48dp - @drawable/ic_book_black_48dp - @drawable/ic_backup_black_48dp - @drawable/ic_help_black_48dp + @drawable/ic_description_black_48dp + + @drawable/ic_mic_black_48dp + @drawable/ic_headset_black_48dp + @drawable/ic_room_black_48dp + @drawable/ic_person_black_48dp + @drawable/ic_android_black_48dp + @drawable/ic_event_black_48dp + @drawable/ic_archive_black_48dp + @drawable/ic_book_black_48dp + @drawable/ic_backup_black_48dp + @drawable/ic_help_black_48dp - @drawable/ic_group_add_white_24dp - @drawable/ic_person_add_white_24dp - @drawable/ic_cancel_black_24dp - @drawable/ic_content_copy_black_24dp - @drawable/ic_delete_white_24dp - @drawable/ic_file_download_white_24dp - @drawable/ic_edit_white_24dp - @drawable/ic_edit_black_24dp - @drawable/ic_save_black_24dp - @drawable/ic_group_white_24dp - @drawable/ic_add_white_24dp - @drawable/ic_reply_white_24dp - @drawable/ic_refresh_black_24dp - @drawable/ic_attach_file_white_24dp - @drawable/ic_lock_open_white_24dp - @drawable/ic_call_white_24dp - @drawable/ic_phone_in_talk_white_24dp - @drawable/ic_phone_in_talk_black_18dp - @drawable/ic_delete_black_24dp - @drawable/ic_search_white_24dp - @drawable/ic_lock_open_white_24dp - @drawable/ic_settings_black_24dp - @drawable/ic_share_white_24dp - @drawable/ic_cloud_download_white_24dp - @drawable/ic_qr_code_scan_white_24dp - @drawable/ic_scroll_to_end_black + @drawable/ic_group_add_white_24dp + @drawable/ic_person_add_white_24dp + @drawable/ic_cancel_black_24dp + @drawable/ic_content_copy_black_24dp + @drawable/ic_delete_white_24dp + @drawable/ic_file_download_white_24dp + @drawable/ic_edit_white_24dp + @drawable/ic_edit_black_24dp + @drawable/ic_save_black_24dp + @drawable/ic_group_white_24dp + @drawable/ic_add_white_24dp + @drawable/ic_reply_white_24dp + @drawable/ic_refresh_black_24dp + @drawable/ic_attach_file_white_24dp + @drawable/ic_lock_open_white_24dp + @drawable/ic_call_white_24dp + @drawable/ic_phone_in_talk_white_24dp + @drawable/ic_phone_in_talk_black_18dp + + @drawable/ic_delete_black_24dp + @drawable/ic_search_white_24dp + @drawable/ic_lock_open_white_24dp + @drawable/ic_settings_black_24dp + @drawable/ic_share_white_24dp + @drawable/ic_cloud_download_white_24dp + + @drawable/ic_qr_code_scan_white_24dp + @drawable/ic_scroll_to_end_black - @drawable/ic_gps_not_fixed_black_24dp - @drawable/ic_gps_fixed_black_24dp - @drawable/ic_directions_black_24dp - @drawable/ic_content_copy_white_24dp + @drawable/ic_gps_not_fixed_black_24dp + + @drawable/ic_gps_fixed_black_24dp + @drawable/ic_directions_black_24dp + @drawable/ic_content_copy_white_24dp - @drawable/ic_notifications_black_24dp - @drawable/ic_notifications_off_black_24dp - @drawable/ic_notifications_paused_black_24dp - @drawable/ic_notifications_none_black_24dp - @drawable/ic_new_releases_black_24dp + @drawable/ic_notifications_black_24dp + + + @drawable/ic_notifications_off_black_24dp + + + @drawable/ic_notifications_paused_black_24dp + + + @drawable/ic_notifications_none_black_24dp + + @drawable/ic_star_black_24dp + + @drawable/ic_new_releases_black_24dp +