Merge upstream

This commit is contained in:
Arne 2024-09-10 09:37:37 +02:00
parent 31d80edeef
commit 51cfb25f69
47 changed files with 331 additions and 920 deletions

View file

@ -11,7 +11,7 @@ public class PushManagementService {
this.mXmppConnectionService = service;
}
void registerPushTokenOnServer(Account account) {
public void registerPushTokenOnServer(Account account) {
//stub implementation. only affects playstore flavor
}

View file

@ -25,37 +25,37 @@ public abstract class AbstractGenerator {
private static final SimpleDateFormat DATE_FORMAT =
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
private final String[] STATIC_FEATURES = {
Namespace.JINGLE,
Namespace.JINGLE_APPS_FILE_TRANSFER,
Namespace.JINGLE_TRANSPORTS_S5B,
Namespace.JINGLE_TRANSPORTS_IBB,
Namespace.JINGLE_ENCRYPTED_TRANSPORT,
Namespace.JINGLE_ENCRYPTED_TRANSPORT_OMEMO,
"http://jabber.org/protocol/muc",
"jabber:x:conference",
Namespace.OOB,
"http://jabber.org/protocol/caps",
"http://jabber.org/protocol/disco#info",
"urn:xmpp:avatar:metadata+notify",
Namespace.NICK + "+notify",
"urn:xmpp:ping",
"jabber:iq:version",
"http://jabber.org/protocol/chatstates"
Namespace.JINGLE,
Namespace.JINGLE_APPS_FILE_TRANSFER,
Namespace.JINGLE_TRANSPORTS_S5B,
Namespace.JINGLE_TRANSPORTS_IBB,
Namespace.JINGLE_ENCRYPTED_TRANSPORT,
Namespace.JINGLE_ENCRYPTED_TRANSPORT_OMEMO,
"http://jabber.org/protocol/muc",
"jabber:x:conference",
Namespace.OOB,
"http://jabber.org/protocol/caps",
"http://jabber.org/protocol/disco#info",
"urn:xmpp:avatar:metadata+notify",
Namespace.NICK + "+notify",
"urn:xmpp:ping",
"jabber:iq:version",
"http://jabber.org/protocol/chatstates"
};
private final String[] MESSAGE_CONFIRMATION_FEATURES = {
"urn:xmpp:chat-markers:0", "urn:xmpp:receipts"
"urn:xmpp:chat-markers:0", "urn:xmpp:receipts"
};
private final String[] MESSAGE_CORRECTION_FEATURES = {"urn:xmpp:message-correct:0"};
private final String[] PRIVACY_SENSITIVE = {
"urn:xmpp:time" // XEP-0202: Entity Time leaks time zone
"urn:xmpp:time" // XEP-0202: Entity Time leaks time zone
};
private final String[] VOIP_NAMESPACES = {
Namespace.JINGLE_TRANSPORT_ICE_UDP,
Namespace.JINGLE_FEATURE_AUDIO,
Namespace.JINGLE_FEATURE_VIDEO,
Namespace.JINGLE_APPS_RTP,
Namespace.JINGLE_APPS_DTLS,
Namespace.JINGLE_MESSAGE
Namespace.JINGLE_TRANSPORT_ICE_UDP,
Namespace.JINGLE_FEATURE_AUDIO,
Namespace.JINGLE_FEATURE_VIDEO,
Namespace.JINGLE_APPS_RTP,
Namespace.JINGLE_APPS_DTLS,
Namespace.JINGLE_MESSAGE
};
protected XmppConnectionService mXmppConnectionService;

View file

@ -315,7 +315,7 @@ public class IqGenerator extends AbstractGenerator {
}
public Iq publishBundles(final SignedPreKeyRecord signedPreKeyRecord, final IdentityKey identityKey,
final Set<PreKeyRecord> preKeyRecords, final int deviceId, Bundle publishOptions) {
final Set<PreKeyRecord> preKeyRecords, final int deviceId, Bundle publishOptions) {
final Element item = new Element("item");
item.setAttribute("id", "current");
final Element bundle = item.addChild("bundle", AxolotlService.PEP_PREFIX);
@ -462,9 +462,9 @@ public class IqGenerator extends AbstractGenerator {
packet.setTo(m.getConversation().getJid().asBareJid());
packet.setFrom(account.getJid());
final var moderate =
packet.addChild("apply-to", "urn:xmpp:fasten:0")
.setAttribute("id", m.getServerMsgId())
.addChild("moderate", "urn:xmpp:message-moderate:0");
packet.addChild("apply-to", "urn:xmpp:fasten:0")
.setAttribute("id", m.getServerMsgId())
.addChild("moderate", "urn:xmpp:message-moderate:0");
moderate.addChild("retract", "urn:xmpp:message-retract:0");
moderate.addChild("reason", "urn:xmpp:message-moderate:0").setContent(reason);
return packet;

View file

@ -126,8 +126,8 @@ public class MessageGenerator extends AbstractGenerator {
message.appendBody(fileParams.url);
final var fallback = new Element("fallback", "urn:xmpp:fallback:0").setAttribute("for", Namespace.OOB);
fallback.addChild("body", "urn:xmpp:fallback:0")
.setAttribute("start", String.valueOf(start))
.setAttribute("end", String.valueOf(start + fileParams.url.length()));
.setAttribute("start", String.valueOf(start))
.setAttribute("end", String.valueOf(start + fileParams.url.length()));
message.addPayload(fallback);
}
}
@ -147,7 +147,7 @@ public class MessageGenerator extends AbstractGenerator {
packet.setBody(url);
packet.addChild("x", Namespace.OOB).addChild("url").setContent(url);
packet.addChild("fallback", "urn:xmpp:fallback:0").setAttribute("for", Namespace.OOB)
.addChild("body", "urn:xmpp:fallback:0");
.addChild("body", "urn:xmpp:fallback:0");
} else {
if (Config.supportUnencrypted()) {
packet.setBody(PGP_FALLBACK_MESSAGE);

View file

@ -91,36 +91,36 @@ public abstract class AbstractParser {
return Math.min(dateFormat.parse(timestamp).getTime()+ms, System.currentTimeMillis());
}
public static long getTimestamp(final String input) throws ParseException {
if (input == null) {
throw new IllegalArgumentException("timestamp should not be null");
}
final String timestamp = input.replace("Z", "+0000");
final SimpleDateFormat simpleDateFormat =
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US);
final long milliseconds = getMilliseconds(timestamp);
final String formatted =
timestamp.substring(0, 19) + timestamp.substring(timestamp.length() - 5);
final Date date = simpleDateFormat.parse(formatted);
if (date == null) {
throw new IllegalArgumentException("Date was null");
}
return date.getTime() + milliseconds;
}
public static long getTimestamp(final String input) throws ParseException {
if (input == null) {
throw new IllegalArgumentException("timestamp should not be null");
}
final String timestamp = input.replace("Z", "+0000");
final SimpleDateFormat simpleDateFormat =
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US);
final long milliseconds = getMilliseconds(timestamp);
final String formatted =
timestamp.substring(0, 19) + timestamp.substring(timestamp.length() - 5);
final Date date = simpleDateFormat.parse(formatted);
if (date == null) {
throw new IllegalArgumentException("Date was null");
}
return date.getTime() + milliseconds;
}
private static long getMilliseconds(final String timestamp) {
if (timestamp.length() >= 25 && timestamp.charAt(19) == '.') {
final String millis = timestamp.substring(19, timestamp.length() - 5);
try {
double fractions = Double.parseDouble("0" + millis);
return Math.round(1000 * fractions);
} catch (NumberFormatException e) {
return 0;
}
} else {
return 0;
}
}
private static long getMilliseconds(final String timestamp) {
if (timestamp.length() >= 25 && timestamp.charAt(19) == '.') {
final String millis = timestamp.substring(19, timestamp.length() - 5);
try {
double fractions = Double.parseDouble("0" + millis);
return Math.round(1000 * fractions);
} catch (NumberFormatException e) {
return 0;
}
} else {
return 0;
}
}
protected void updateLastseen(final Account account, final Jid from) {
final Contact contact = account.getRoster().getContact(from);

View file

@ -459,7 +459,7 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
final boolean success =
push != null
&& mXmppConnectionService.processUnifiedPushMessage(
account, transport, push);
account, transport, push);
final Iq response;
if (success) {
response = packet.generateResponse(Iq.Type.RESULT);

View file

@ -592,14 +592,14 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
final var payload = webxdc.findChildContent("json", "urn:xmpp:json:0");
if (document != null || summary != null || payload != null) {
mXmppConnectionService.insertWebxdcUpdate(new WebxdcUpdate(
conversation,
remoteMsgId,
counterpart,
thread,
body == null ? null : body.content,
document,
summary,
payload
conversation,
remoteMsgId,
counterpart,
thread,
body == null ? null : body.content,
document,
summary,
payload
));
}
@ -736,7 +736,7 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
if (address.getAttribute("type").equals("ofrom") && address.getAttribute("jid") != null) {
Jid ofrom = address.getAttributeAsJid("jid");
if (InvalidJid.isValid(ofrom) && ofrom.getDomain().equals(counterpart.getDomain()) &&
conversation.getAccount().getRoster().getContact(counterpart.getDomain()).getPresences().anySupport("http://jabber.org/protocol/address")) {
conversation.getAccount().getRoster().getContact(counterpart.getDomain()).getPresences().anySupport("http://jabber.org/protocol/address")) {
message.setTrueCounterpart(ofrom);
}
@ -761,7 +761,7 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
if (reactions != null) message.addPayload(reactions);
for (Element el : packet.getChildren()) {
if ((el.getName().equals("query") && el.getNamespace().equals("http://jabber.org/protocol/disco#items") && el.getAttribute("node").equals("http://jabber.org/protocol/commands")) ||
(el.getName().equals("fallback") && el.getNamespace().equals("urn:xmpp:fallback:0"))) {
(el.getName().equals("fallback") && el.getNamespace().equals("urn:xmpp:fallback:0"))) {
message.addPayload(el);
}
if (el.getName().equals("thread") && (el.getNamespace() == null || el.getNamespace().equals("jabber:client"))) {
@ -1257,7 +1257,7 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
final var mStatus = message.getStatus();
if (mucOptions.isPrivateAndNonAnonymous()
&& (mStatus == Message.STATUS_SEND_RECEIVED
|| mStatus == Message.STATUS_SEND)
|| mStatus == Message.STATUS_SEND)
&& readyBy.containsAll(everyone)) {
message.setStatus(Message.STATUS_SEND_DISPLAYED);
}

View file

@ -163,7 +163,7 @@ public class PresenceParser extends AbstractParser implements Consumer<im.conver
destroy == null
? null
: InvalidJid.getNullForInvalid(
destroy.getAttributeAsJid("jid"));
destroy.getAttributeAsJid("jid"));
mucOptions.setError(MucOptions.Error.DESTROYED);
if (alternate != null) {
Log.d(
@ -205,7 +205,7 @@ public class PresenceParser extends AbstractParser implements Consumer<im.conver
} else if (!from.isBareJid()) {
Element item = x.findChild("item");
if (item != null) {
mucOptions.updateUser(parseItem(conversation, item, from, occupantId, nick == null ? null : nick.getContent(), hats));
mucOptions.updateUser(parseItem(conversation, item, from, occupantId, nick == null ? null : nick.getContent(), hats));
}
MucOptions.User user = mucOptions.deleteUser(from);
if (user != null && occupantId == null) {

View file

@ -32,8 +32,9 @@ import eu.siacs.conversations.receiver.UnifiedPushDistributor;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
import im.conversations.android.xmpp.model.stanza.Iq;
import im.conversations.android.xmpp.model.stanza.Presence;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.List;
@ -82,7 +83,7 @@ public class UnifiedPushBroker {
}
private void sendDirectedPresence(final Account account, Jid to) {
final PresencePacket presence = new PresencePacket();
final var presence = new Presence();
presence.setTo(to);
service.sendPresencePacket(account, presence);
}
@ -146,7 +147,7 @@ public class UnifiedPushBroker {
UnifiedPushDistributor.hash(account.getUuid(), renewal.application);
final String hashedInstance =
UnifiedPushDistributor.hash(account.getUuid(), renewal.instance);
final IqPacket registration = new IqPacket(IqPacket.TYPE.SET);
final Iq registration = new Iq(Iq.Type.SET);
registration.setTo(transport.transport);
final Element register = registration.addChild("register", Namespace.UNIFIED_PUSH);
register.setAttribute("application", hashedApplication);
@ -160,7 +161,7 @@ public class UnifiedPushBroker {
this.service.sendIqPacket(
account,
registration,
(a, response) -> processRegistration(transport, renewal, messenger, response));
(response) -> processRegistration(transport, renewal, messenger, response));
}
}
@ -168,8 +169,8 @@ public class UnifiedPushBroker {
final Transport transport,
final UnifiedPushDatabase.PushTarget renewal,
final Messenger messenger,
final IqPacket response) {
if (response.getType() == IqPacket.TYPE.RESULT) {
final Iq response) {
if (response.getType() == Iq.Type.RESULT) {
final Element registered = response.findChild("registered", Namespace.UNIFIED_PUSH);
if (registered == null) {
return;

View file

@ -56,7 +56,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.RemoteInput;
import androidx.core.content.ContextCompat;
import androidx.core.util.Consumer;
import de.monocles.chat.EmojiSearch;
import de.monocles.chat.WebxdcUpdate;
@ -111,6 +110,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import io.ipfs.cid.Cid;
@ -145,8 +145,6 @@ import eu.siacs.conversations.generator.PresenceGenerator;
import eu.siacs.conversations.http.HttpConnectionManager;
import eu.siacs.conversations.parser.AbstractParser;
import eu.siacs.conversations.parser.IqParser;
import eu.siacs.conversations.parser.MessageParser;
import eu.siacs.conversations.parser.PresenceParser;
import eu.siacs.conversations.persistance.DatabaseBackend;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.persistance.UnifiedPushDatabase;
@ -186,11 +184,8 @@ import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnBindListener;
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
import eu.siacs.conversations.xmpp.OnGatewayResult;
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
import eu.siacs.conversations.xmpp.OnMessageAcknowledged;
import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
import eu.siacs.conversations.xmpp.OnPresencePacketReceived;
import eu.siacs.conversations.xmpp.OnStatusChanged;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
import eu.siacs.conversations.xmpp.XmppConnection;
@ -2423,8 +2418,8 @@ public class XmppConnectionService extends Service {
}
public void deleteBookmark(final Account account, final Bookmark bookmark) {
if (bookmark.getJid().toString().equals("discuss@conference.soprani.ca")) {
getPreferences().edit().putBoolean("cheogram_sopranica_bookmark_deleted", true).apply();
if (bookmark.getJid().toString().equals("support@conference.monocles.eu")) {
getPreferences().edit().putBoolean("monocles_support_bookmark_deleted", true).apply();
}
account.removeBookmark(bookmark);
final XmppConnection connection = account.getXmppConnection();

View file

@ -464,30 +464,6 @@ public class StartConversationActivity extends XmppActivity
}
return false;
});
BottomNavigationView bottomNavigationView=findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnItemSelectedListener(item -> {
switch (item.getItemId()) {
case R.id.chats -> {
startActivity(new Intent(getApplicationContext(), ConversationsActivity.class));
overridePendingTransition(R.animator.fade_in, R.animator.fade_out);
return true;
}
case R.id.contactslist -> {
return true;
}
case R.id.manageaccounts -> {
Intent i = new Intent(getApplicationContext(), MANAGE_ACCOUNT_ACTIVITY);
i.putExtra("show_nav_bar", true);
startActivity(i);
overridePendingTransition(R.animator.fade_in, R.animator.fade_out);
return true;
}
default ->
throw new IllegalStateException("Unexpected value: " + item.getItemId());
}
});
}
private void inflateFab(final SpeedDialView speedDialView, final @MenuRes int menuRes) {
@ -1439,7 +1415,7 @@ public class StartConversationActivity extends XmppActivity
);
Collections.sort(this.contacts);
final boolean sopranicaDeleted = getPreferences().getBoolean("cheogram_sopranica_bookmark_deleted", false);
final boolean sopranicaDeleted = getPreferences().getBoolean("monocles_support_bookmark_deleted", false);
if (!sopranicaDeleted && !foundSopranica && (needle == null || needle.equals("")) && xmppConnectionService.getAccounts().size() > 0) {
Bookmark bookmark = new Bookmark(

View file

@ -55,11 +55,11 @@ import com.google.android.material.imageview.ShapeableImageView;
import com.google.android.material.shape.CornerFamily;
import com.google.android.material.shape.ShapeAppearanceModel;
import com.cheogram.android.BobTransfer;
import com.cheogram.android.MessageTextActionModeCallback;
import com.cheogram.android.SwipeDetector;
import com.cheogram.android.WebxdcPage;
import com.cheogram.android.WebxdcUpdate;
import de.monocles.chat.BobTransfer;
import de.monocles.chat.MessageTextActionModeCallback;
import de.monocles.chat.SwipeDetector;
import de.monocles.chat.WebxdcPage;
import de.monocles.chat.WebxdcUpdate;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.color.MaterialColors;

View file

@ -71,16 +71,10 @@ public class BackupSettingsFragment extends XmppPreferenceFragment {
R.string.pref_create_backup_summary,
FileBackend.getBackupDirectory(requireContext()).getAbsolutePath()));
createOneOffBackup.setOnPreferenceClickListener(this::onBackupPreferenceClicked);
final int[] choices = getResources().getIntArray(R.array.recurring_backup_values);
final CharSequence[] entries = new CharSequence[choices.length];
final CharSequence[] entryValues = new CharSequence[choices.length];
for (int i = 0; i < choices.length; ++i) {
entryValues[i] = String.valueOf(choices[i]);
entries[i] = timeframeValueToName(requireContext(), choices[i]);
}
recurringBackup.setEntries(entries);
recurringBackup.setEntryValues(entryValues);
recurringBackup.setSummaryProvider(new TimeframeSummaryProvider());
setValues(
recurringBackup,
R.array.recurring_backup_values,
value -> timeframeValueToName(requireContext(), value));
}
@Override
@ -113,9 +107,9 @@ public class BackupSettingsFragment extends XmppPreferenceFragment {
final PeriodicWorkRequest periodicWorkRequest =
new PeriodicWorkRequest.Builder(
ExportBackupWorker.class,
recurringBackupInterval,
TimeUnit.SECONDS)
ExportBackupWorker.class,
recurringBackupInterval,
TimeUnit.SECONDS)
.setConstraints(constraints)
.setInputData(
new Data.Builder()
@ -137,7 +131,7 @@ public class BackupSettingsFragment extends XmppPreferenceFragment {
private boolean onBackupPreferenceClicked(final Preference preference) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(
requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
requestStorageForBackupLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE);
} else {

View file

@ -4,6 +4,7 @@ import android.content.DialogInterface;
import android.os.Bundle;
import android.widget.Toast;
import androidx.annotation.ArrayRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
@ -11,7 +12,9 @@ import androidx.preference.ListPreference;
import androidx.preference.Preference;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.common.base.Function;
import com.google.common.base.Strings;
import com.google.common.primitives.Ints;
import eu.siacs.conversations.AppSettings;
import eu.siacs.conversations.R;
@ -21,6 +24,7 @@ import eu.siacs.conversations.services.MemorizingTrustManager;
import java.security.KeyStoreException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.Callable;
public class SecuritySettingsFragment extends XmppPreferenceFragment {
@ -36,19 +40,12 @@ public class SecuritySettingsFragment extends XmppPreferenceFragment {
throw new IllegalStateException("The preference resource file is missing preferences");
}
omemo.setSummaryProvider(new OmemoSummaryProvider());
final int[] choices = getResources().getIntArray(R.array.automatic_message_deletion_values);
final CharSequence[] entries = new CharSequence[choices.length];
final CharSequence[] entryValues = new CharSequence[choices.length];
for (int i = 0; i < choices.length; ++i) {
entryValues[i] = String.valueOf(choices[i]);
entries[i] = timeframeValueToName(requireContext(), choices[i]);
}
automaticMessageDeletion.setEntries(entries);
automaticMessageDeletion.setEntryValues(entryValues);
automaticMessageDeletion.setSummaryProvider(new TimeframeSummaryProvider());
setValues(
automaticMessageDeletion,
R.array.automatic_message_deletion_values,
value -> timeframeValueToName(requireContext(), value));
}
@Override
protected void onSharedPreferenceChanged(@NonNull String key) {
super.onSharedPreferenceChanged(key);
@ -60,7 +57,7 @@ public class SecuritySettingsFragment extends XmppPreferenceFragment {
requireService().updateMemorizingTrustManager();
reconnectAccounts();
}
case AppSettings.DANE_ENFORCED, AppSettings.REQUIRE_CHANNEL_BINDING -> {
case AppSettings.REQUIRE_CHANNEL_BINDING -> {
reconnectAccounts();
}
case AppSettings.AUTOMATIC_MESSAGE_DELETION -> {
@ -151,7 +148,6 @@ public class SecuritySettingsFragment extends XmppPreferenceFragment {
.show();
}
private static class OmemoSummaryProvider
implements Preference.SummaryProvider<ListPreference> {

View file

@ -38,23 +38,27 @@ public class AccountUtils {
return false;
}
public static String publicDeviceId(final Account account) {
public static String publicDeviceId(final Account account, final long installationId) {
final UUID uuid;
try {
uuid = UUID.fromString(account.getUuid());
} catch (final IllegalArgumentException e) {
return account.getUuid();
}
return createUuid4(uuid.getMostSignificantBits(), installationId).toString();
}
public static UUID createUuid4(long mostSigBits, long leastSigBits) {
final byte[] bytes =
Bytes.concat(
Longs.toByteArray(uuid.getLeastSignificantBits()),
Longs.toByteArray(uuid.getLeastSignificantBits()));
Longs.toByteArray(mostSigBits),
Longs.toByteArray(leastSigBits));
bytes[6] &= 0x0f; /* clear version */
bytes[6] |= 0x40; /* set to version 4 */
bytes[8] &= 0x3f; /* clear variant */
bytes[8] |= 0x80; /* set to IETF variant */
final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
return new UUID(byteBuffer.getLong(), byteBuffer.getLong()).toString();
return new UUID(byteBuffer.getLong(), byteBuffer.getLong());
}
public static List<String> getEnabledAccounts(final XmppConnectionService service) {

View file

@ -10,13 +10,14 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
import im.conversations.android.xmpp.model.StreamElement;
public class TagWriter {
private OutputStreamWriter outputStream;
private boolean finished = false;
private final LinkedBlockingQueue<AbstractStanza> writeQueue = new LinkedBlockingQueue<AbstractStanza>();
private final LinkedBlockingQueue<StreamElement> writeQueue = new LinkedBlockingQueue<>();
private CountDownLatch stanzaWriterCountDownLatch = null;
private final Thread asyncStanzaWriter = new Thread() {
@ -25,13 +26,13 @@ public class TagWriter {
public void run() {
stanzaWriterCountDownLatch = new CountDownLatch(1);
while (!isInterrupted()) {
if (finished && writeQueue.size() == 0) {
if (finished && writeQueue.isEmpty()) {
break;
}
try {
AbstractStanza output = writeQueue.take();
final var output = writeQueue.take();
outputStream.write(output.toString());
if (writeQueue.size() == 0) {
if (writeQueue.isEmpty()) {
outputStream.flush();
}
} catch (Exception e) {
@ -74,7 +75,7 @@ public class TagWriter {
}
}
public synchronized void writeElement(Element element) throws IOException {
public synchronized void writeElement(final StreamElement element) throws IOException {
if (outputStream == null) {
throw new IOException("output stream was null");
}
@ -82,7 +83,7 @@ public class TagWriter {
outputStream.flush();
}
public void writeStanzaAsync(AbstractStanza stanza) {
public void writeStanzaAsync(StreamElement stanza) {
if (finished) {
Log.d(Config.LOGTAG, "attempting to write stanza to finished TagWriter");
} else {

View file

@ -31,7 +31,7 @@ package eu.siacs.conversations.xmpp;
import androidx.annotation.NonNull;
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
import im.conversations.android.xmpp.model.stanza.Stanza;
public class InvalidJid implements Jid {
@ -137,10 +137,10 @@ public class InvalidJid implements Jid {
}
public static boolean isValid(Jid jid) {
return !(jid != null && jid instanceof InvalidJid);
return !(jid instanceof InvalidJid);
}
public static boolean hasValidFrom(AbstractStanza stanza) {
public static boolean hasValidFrom(Stanza stanza) {
final String from = stanza.getAttribute("from");
if (from == null) {
return false;

View file

@ -1,8 +0,0 @@
package eu.siacs.conversations.xmpp;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
public interface OnIqPacketReceived extends PacketReceived {
void onIqPacketReceived(Account account, IqPacket packet);
}

View file

@ -1,8 +1,7 @@
package eu.siacs.conversations.xmpp;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
import im.conversations.android.xmpp.model.stanza.Message;
public interface OnMessagePacketReceived extends PacketReceived {
void onMessagePacketReceived(Account account, MessagePacket packet);
public interface OnMessagePacketReceived {
void onMessagePacketReceived(Message packet);
}

View file

@ -1,8 +0,0 @@
package eu.siacs.conversations.xmpp;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
public interface OnPresencePacketReceived extends PacketReceived {
void onPresencePacketReceived(Account account, PresencePacket packet);
}

View file

@ -450,7 +450,7 @@ public class XmppConnection implements Runnable {
results.add(0, seeOtherHost);
}
for (final Iterator<Resolver.Result> iterator = results.iterator();
iterator.hasNext(); ) {
iterator.hasNext(); ) {
final Resolver.Result result = iterator.next();
if (Thread.currentThread().isInterrupted()) {
Log.d(
@ -471,8 +471,8 @@ public class XmppConnection implements Runnable {
account.getJid().asBareJid().toString()
+ ": using values from resolver "
+ (result.getHostname() == null
? ""
: result.getHostname().toString() + "/")
? ""
: result.getHostname().toString() + "/")
+ result.getIp().getHostAddress()
+ ":"
+ result.getPort()
@ -548,8 +548,8 @@ public class XmppConnection implements Runnable {
} catch (final StateChangingException e) {
this.changeStatus(e.state);
} catch (final UnknownHostException
| ConnectException
| SocksSocketFactory.HostNotFoundException e) {
| ConnectException
| SocksSocketFactory.HostNotFoundException e) {
this.changeStatus(Account.State.SERVER_NOT_FOUND);
} catch (final SocksSocketFactory.SocksProxyNotFoundException e) {
this.changeStatus(Account.State.TOR_NOT_AVAILABLE);
@ -629,9 +629,9 @@ public class XmppConnection implements Runnable {
sc.init(
keyManager,
new X509TrustManager[] {
mInteractive
? trustManager.getInteractive(domain, verifiedHostname, port, daneCb)
: trustManager.getNonInteractive(domain, verifiedHostname, port, daneCb)
mInteractive
? trustManager.getInteractive(domain, verifiedHostname, port, daneCb)
: trustManager.getNonInteractive(domain, verifiedHostname, port, daneCb)
},
SECURE_RANDOM);
return sc.getSocketFactory();
@ -1174,24 +1174,10 @@ public class XmppConnection implements Runnable {
}
private void changeStatusToOnline() {
if (mXmppConnectionService.getBooleanPreference("enforce_dane",R.bool.enforce_dane)) {
if (daneVerified()) {
Log.d(
Config.LOGTAG,
account.getJid().asBareJid() + ": online with enforced DANE with resource " + account.getResource());
changeStatus(Account.State.ONLINE);
} else {
Log.d(
Config.LOGTAG,
account.getJid().asBareJid() + ": offline with enforced DANE with resource " + account.getResource());
changeStatus(Account.State.DANE_FAILED);
}
} else {
Log.d(
Config.LOGTAG,
account.getJid().asBareJid() + ": online with enforced DANE disabled with resource " + account.getResource());
changeStatus(Account.State.ONLINE);
}
Log.d(
Config.LOGTAG,
account.getJid().asBareJid() + ": online with resource " + account.getResource());
changeStatus(Account.State.ONLINE);
}
private void processFailed(final Failed failed, final boolean sendBindRequest) {
@ -2225,7 +2211,7 @@ public class XmppConnection implements Runnable {
}
if (advancedStreamFeaturesLoaded
&& (jid.equals(account.getDomain())
|| jid.equals(account.getJid().asBareJid()))) {
|| jid.equals(account.getJid().asBareJid()))) {
enableAdvancedStreamFeatures();
}
} else if (packet.getType() == Iq.Type.ERROR) {
@ -3062,7 +3048,7 @@ public class XmppConnection implements Runnable {
public boolean sm() {
return streamId != null
|| (connection.streamFeatures != null
&& connection.streamFeatures.streamManagement());
&& connection.streamFeatures.streamManagement());
}
public boolean csi() {
@ -3082,7 +3068,7 @@ public class XmppConnection implements Runnable {
ServiceDiscoveryResult info = disco.get(account.getJid().asBareJid());
return info != null
&& info.getFeatures()
.contains("http://jabber.org/protocol/pubsub#persistent-items");
.contains("http://jabber.org/protocol/pubsub#persistent-items");
}
}

View file

@ -8,7 +8,8 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.Content;
import eu.siacs.conversations.xmpp.jingle.stanzas.GenericDescription;
import eu.siacs.conversations.xmpp.jingle.stanzas.GenericTransportInfo;
import eu.siacs.conversations.xmpp.jingle.stanzas.Group;
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
import im.conversations.android.xmpp.model.jingle.Jingle;
import im.conversations.android.xmpp.model.stanza.Iq;
import java.util.List;
import java.util.Map;
@ -47,8 +48,9 @@ public abstract class AbstractContentMap<
return ImmutableList.copyOf(contents.keySet());
}
JinglePacket toJinglePacket(final JinglePacket.Action action, final String sessionId) {
final JinglePacket jinglePacket = new JinglePacket(action, sessionId);
Iq toJinglePacket(final Jingle.Action action, final String sessionId) {
final Iq iq = new Iq(Iq.Type.SET);
final var jinglePacket = iq.addExtension(new Jingle(action, sessionId));
for (final Map.Entry<String, DescriptionTransport<D, T>> entry : this.contents.entrySet()) {
final DescriptionTransport<D, T> descriptionTransport = entry.getValue();
final Content content =
@ -65,7 +67,7 @@ public abstract class AbstractContentMap<
if (this.group != null) {
jinglePacket.addGroup(this.group);
}
return jinglePacket;
return iq;
}
void requireContentDescriptions() {

View file

@ -19,9 +19,9 @@ import eu.siacs.conversations.entities.Presence;
import eu.siacs.conversations.entities.ServiceDiscoveryResult;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
import eu.siacs.conversations.xmpp.jingle.stanzas.Reason;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import im.conversations.android.xmpp.model.jingle.Jingle;
import im.conversations.android.xmpp.model.stanza.Iq;
import java.util.Arrays;
import java.util.Collection;
@ -71,7 +71,7 @@ public abstract class AbstractJingleConnection {
State.TERMINATED_SECURITY_ERROR,
State.TERMINATED_CONNECTIVITY_ERROR // only used when the xmpp connection
// rebinds
));
));
transitionBuilder.put(
State.PROCEED,
ImmutableList.of(
@ -83,7 +83,7 @@ public abstract class AbstractJingleConnection {
State.TERMINATED_SECURITY_ERROR,
State.TERMINATED_CONNECTIVITY_ERROR // at this state used for error
// bounces of the proceed message
));
));
transitionBuilder.put(
State.SESSION_INITIALIZED,
ImmutableList.of(
@ -184,10 +184,10 @@ public abstract class AbstractJingleConnection {
return TERMINATED.contains(this.state);
}
abstract void deliverPacket(JinglePacket jinglePacket);
abstract void deliverPacket(Iq jinglePacket);
protected void receiveOutOfOrderAction(
final JinglePacket jinglePacket, final JinglePacket.Action action) {
final Iq jinglePacket, final Jingle.Action action) {
Log.d(
Config.LOGTAG,
String.format(
@ -205,7 +205,7 @@ public abstract class AbstractJingleConnection {
}
}
protected void terminateWithOutOfOrder(final JinglePacket jinglePacket) {
protected void terminateWithOutOfOrder(final Iq jinglePacket) {
Log.d(
Config.LOGTAG,
id.account.getJid().asBareJid() + ": terminating session with out-of-order");
@ -235,37 +235,38 @@ public abstract class AbstractJingleConnection {
if (previous != State.NULL && trigger != null) {
trigger.accept(target);
}
final JinglePacket jinglePacket =
new JinglePacket(JinglePacket.Action.SESSION_TERMINATE, id.sessionId);
final var iq = new Iq(Iq.Type.SET);
final var jinglePacket =
iq.addExtension(new Jingle(Jingle.Action.SESSION_TERMINATE, id.sessionId));
jinglePacket.setReason(reason, text);
send(jinglePacket);
send(iq);
finish();
}
protected void send(final JinglePacket jinglePacket) {
protected void send(final Iq jinglePacket) {
jinglePacket.setTo(id.with);
xmppConnectionService.sendIqPacket(id.account, jinglePacket, this::handleIqResponse);
}
protected void respondOk(final JinglePacket jinglePacket) {
protected void respondOk(final Iq jinglePacket) {
xmppConnectionService.sendIqPacket(
id.account, jinglePacket.generateResponse(IqPacket.TYPE.RESULT), null);
id.account, jinglePacket.generateResponse(Iq.Type.RESULT), null);
}
protected void respondWithTieBreak(final JinglePacket jinglePacket) {
protected void respondWithTieBreak(final Iq jinglePacket) {
respondWithJingleError(jinglePacket, "tie-break", "conflict", "cancel");
}
protected void respondWithOutOfOrder(final JinglePacket jinglePacket) {
protected void respondWithOutOfOrder(final Iq jinglePacket) {
respondWithJingleError(jinglePacket, "out-of-order", "unexpected-request", "wait");
}
protected void respondWithItemNotFound(final JinglePacket jinglePacket) {
protected void respondWithItemNotFound(final Iq jinglePacket) {
respondWithJingleError(jinglePacket, null, "item-not-found", "cancel");
}
private void respondWithJingleError(
final IqPacket original,
final Iq original,
String jingleCondition,
String condition,
String conditionType) {
@ -273,18 +274,18 @@ public abstract class AbstractJingleConnection {
id.account, original, jingleCondition, condition, conditionType);
}
private synchronized void handleIqResponse(final Account account, final IqPacket response) {
if (response.getType() == IqPacket.TYPE.ERROR) {
private synchronized void handleIqResponse(final Iq response) {
if (response.getType() == Iq.Type.ERROR) {
handleIqErrorResponse(response);
return;
}
if (response.getType() == IqPacket.TYPE.TIMEOUT) {
if (response.getType() == Iq.Type.TIMEOUT) {
handleIqTimeoutResponse(response);
}
}
protected void handleIqErrorResponse(final IqPacket response) {
Preconditions.checkArgument(response.getType() == IqPacket.TYPE.ERROR);
protected void handleIqErrorResponse(final Iq response) {
Preconditions.checkArgument(response.getType() == Iq.Type.ERROR);
final String errorCondition = response.getErrorCondition();
Log.d(
Config.LOGTAG,
@ -316,8 +317,8 @@ public abstract class AbstractJingleConnection {
this.finish();
}
protected void handleIqTimeoutResponse(final IqPacket response) {
Preconditions.checkArgument(response.getType() == IqPacket.TYPE.TIMEOUT);
protected void handleIqTimeoutResponse(final Iq response) {
Preconditions.checkArgument(response.getType() == Iq.Type.TIMEOUT);
Log.d(
Config.LOGTAG,
id.account.getJid().asBareJid()
@ -361,8 +362,8 @@ public abstract class AbstractJingleConnection {
this.sessionId = sessionId;
}
public static Id of(Account account, JinglePacket jinglePacket) {
return new Id(account, jinglePacket.getFrom(), jinglePacket.getSessionId());
public static Id of(Account account, Iq iq, final Jingle jingle) {
return new Id(account, iq.getFrom(), jingle.getSessionId());
}
public static Id of(Account account, Jid with, final String sessionId) {

View file

@ -13,11 +13,10 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.GenericTransportInfo;
import eu.siacs.conversations.xmpp.jingle.stanzas.Group;
import eu.siacs.conversations.xmpp.jingle.stanzas.IbbTransportInfo;
import eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo;
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription;
import eu.siacs.conversations.xmpp.jingle.stanzas.SocksByteStreamsTransportInfo;
import eu.siacs.conversations.xmpp.jingle.stanzas.WebRTCDataChannelTransportInfo;
import eu.siacs.conversations.xmpp.jingle.transports.Transport;
import im.conversations.android.xmpp.model.jingle.Jingle;
import java.util.Arrays;
import java.util.Collections;
@ -35,11 +34,11 @@ public class FileTransferContentMap
protected FileTransferContentMap(
final Group group, final Map<String, DescriptionTransport<FileTransferDescription, GenericTransportInfo>>
contents) {
contents) {
super(group, contents);
}
public static FileTransferContentMap of(final JinglePacket jinglePacket) {
public static FileTransferContentMap of(final Jingle jinglePacket) {
final Map<String, DescriptionTransport<FileTransferDescription, GenericTransportInfo>>
contents = of(jinglePacket.getJingleContents());
return new FileTransferContentMap(jinglePacket.getGroup(), contents);
@ -66,7 +65,7 @@ public class FileTransferContentMap
}
private static Map<String, DescriptionTransport<FileTransferDescription, GenericTransportInfo>>
of(final Map<String, Content> contents) {
of(final Map<String, Content> contents) {
return ImmutableMap.copyOf(
Maps.transformValues(contents, content -> content == null ? null : of(content)));
}

View file

@ -10,7 +10,7 @@ import eu.siacs.conversations.Config;
import eu.siacs.conversations.utils.IP;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import im.conversations.android.xmpp.model.stanza.Iq;
import org.webrtc.PeerConnection;
@ -20,9 +20,9 @@ import java.util.List;
public final class IceServers {
public static List<PeerConnection.IceServer> parse(final IqPacket response) {
public static List<PeerConnection.IceServer> parse(final Iq response) {
ImmutableList.Builder<PeerConnection.IceServer> listBuilder = new ImmutableList.Builder<>();
if (response.getType() == IqPacket.TYPE.RESULT) {
if (response.getType() == Iq.Type.RESULT) {
final Element services =
response.findChild("services", Namespace.EXTERNAL_SERVICE_DISCOVERY);
final List<Element> children =

View file

@ -389,11 +389,11 @@ public class JingleConnectionManager extends AbstractConnectionManager {
final String ourSessionId = matchingSessionProposal.get().sessionId;
final String theirSessionId = id.sessionId;
if (ComparisonChain.start()
.compare(ourSessionId, theirSessionId)
.compare(
account.getJid().toEscapedString(),
id.with.toEscapedString())
.result()
.compare(ourSessionId, theirSessionId)
.compare(
account.getJid().toEscapedString(),
id.with.toEscapedString())
.result()
> 0) {
Log.d(
Config.LOGTAG,

View file

@ -31,7 +31,6 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.FileTransferDescription;
import eu.siacs.conversations.xmpp.jingle.stanzas.GenericTransportInfo;
import eu.siacs.conversations.xmpp.jingle.stanzas.IbbTransportInfo;
import eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo;
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
import eu.siacs.conversations.xmpp.jingle.stanzas.Reason;
import eu.siacs.conversations.xmpp.jingle.stanzas.SocksByteStreamsTransportInfo;
import eu.siacs.conversations.xmpp.jingle.stanzas.WebRTCDataChannelTransportInfo;
@ -39,7 +38,9 @@ import eu.siacs.conversations.xmpp.jingle.transports.InbandBytestreamsTransport;
import eu.siacs.conversations.xmpp.jingle.transports.SocksByteStreamsTransport;
import eu.siacs.conversations.xmpp.jingle.transports.Transport;
import eu.siacs.conversations.xmpp.jingle.transports.WebRTCDataChannelTransport;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import im.conversations.android.xmpp.model.jingle.Jingle;
import im.conversations.android.xmpp.model.stanza.Iq;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.io.CipherInputStream;
@ -112,22 +113,23 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
}
@Override
void deliverPacket(final JinglePacket jinglePacket) {
switch (jinglePacket.getAction()) {
case SESSION_ACCEPT -> receiveSessionAccept(jinglePacket);
case SESSION_INITIATE -> receiveSessionInitiate(jinglePacket);
case SESSION_INFO -> receiveSessionInfo(jinglePacket);
case SESSION_TERMINATE -> receiveSessionTerminate(jinglePacket);
case TRANSPORT_ACCEPT -> receiveTransportAccept(jinglePacket);
case TRANSPORT_INFO -> receiveTransportInfo(jinglePacket);
case TRANSPORT_REPLACE -> receiveTransportReplace(jinglePacket);
void deliverPacket(final Iq iq) {
final var jingle = iq.getExtension(Jingle.class);
switch (jingle.getAction()) {
case SESSION_ACCEPT -> receiveSessionAccept(iq, jingle);
case SESSION_INITIATE -> receiveSessionInitiate(iq, jingle);
case SESSION_INFO -> receiveSessionInfo(iq, jingle);
case SESSION_TERMINATE -> receiveSessionTerminate(iq, jingle);
case TRANSPORT_ACCEPT -> receiveTransportAccept(iq, jingle);
case TRANSPORT_INFO -> receiveTransportInfo(iq, jingle);
case TRANSPORT_REPLACE -> receiveTransportReplace(iq, jingle);
default -> {
respondOk(jinglePacket);
respondOk(iq);
Log.d(
Config.LOGTAG,
String.format(
"%s: received unhandled jingle action %s",
id.account.getJid().asBareJid(), jinglePacket.getAction()));
id.account.getJid().asBareJid(), jingle.getAction()));
}
}
}
@ -203,33 +205,34 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
if (transition(
State.SESSION_INITIALIZED,
() -> this.initiatorFileTransferContentMap = contentMap)) {
final var jinglePacket =
contentMap.toJinglePacket(JinglePacket.Action.SESSION_INITIATE, id.sessionId);
final var iq =
contentMap.toJinglePacket(Jingle.Action.SESSION_INITIATE, id.sessionId);
final var jingle = iq.getExtension(Jingle.class);
if (xmppAxolotlMessage != null) {
this.transportSecurity =
new TransportSecurity(
xmppAxolotlMessage.getInnerKey(), xmppAxolotlMessage.getIV());
final var contents = jinglePacket.getJingleContents();
final var contents = jingle.getJingleContents();
final var rawContent =
contents.get(Iterables.getOnlyElement(contentMap.contents.keySet()));
if (rawContent != null) {
rawContent.setSecurity(xmppAxolotlMessage);
}
}
jinglePacket.setTo(id.with);
iq.setTo(id.with);
xmppConnectionService.sendIqPacket(
id.account,
jinglePacket,
(a, response) -> {
if (response.getType() == IqPacket.TYPE.RESULT) {
iq,
(response) -> {
if (response.getType() == Iq.Type.RESULT) {
xmppConnectionService.markMessage(message, Message.STATUS_OFFERED);
return;
}
if (response.getType() == IqPacket.TYPE.ERROR) {
if (response.getType() == Iq.Type.ERROR) {
handleIqErrorResponse(response);
return;
}
if (response.getType() == IqPacket.TYPE.TIMEOUT) {
if (response.getType() == Iq.Type.TIMEOUT) {
handleIqTimeoutResponse(response);
}
});
@ -237,15 +240,15 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
}
}
private void receiveSessionAccept(final JinglePacket jinglePacket) {
private void receiveSessionAccept(final Iq jinglePacket, final Jingle jingle) {
Log.d(Config.LOGTAG, "receive file transfer session accept");
if (isResponder()) {
receiveOutOfOrderAction(jinglePacket, JinglePacket.Action.SESSION_ACCEPT);
receiveOutOfOrderAction(jinglePacket, Jingle.Action.SESSION_ACCEPT);
return;
}
final FileTransferContentMap contentMap;
try {
contentMap = FileTransferContentMap.of(jinglePacket);
contentMap = FileTransferContentMap.of(jingle);
contentMap.requireOnlyFileTransferDescription();
} catch (final RuntimeException e) {
Log.d(
@ -261,7 +264,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
}
private void receiveSessionAccept(
final JinglePacket jinglePacket, final FileTransferContentMap contentMap) {
final Iq jinglePacket, final FileTransferContentMap contentMap) {
if (transition(State.SESSION_ACCEPTED, () -> setRemoteContentMap(contentMap))) {
respondOk(jinglePacket);
final var transport = this.transport;
@ -280,7 +283,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
Log.d(
Config.LOGTAG,
id.account.getJid().asBareJid() + ": receive out of order session-accept");
receiveOutOfOrderAction(jinglePacket, JinglePacket.Action.SESSION_ACCEPT);
receiveOutOfOrderAction(jinglePacket, Jingle.Action.SESSION_ACCEPT);
}
}
@ -293,7 +296,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
return true;
} else if (transport instanceof SocksByteStreamsTransport socksBytestreamsTransport
&& transportInfo
instanceof SocksByteStreamsTransportInfo socksBytestreamsTransportInfo) {
instanceof SocksByteStreamsTransportInfo socksBytestreamsTransportInfo) {
socksBytestreamsTransport.setTheirCandidates(
socksBytestreamsTransportInfo.getCandidates());
return true;
@ -309,16 +312,16 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
}
}
private void receiveSessionInitiate(final JinglePacket jinglePacket) {
private void receiveSessionInitiate(final Iq jinglePacket, final Jingle jingle) {
if (isInitiator()) {
receiveOutOfOrderAction(jinglePacket, JinglePacket.Action.SESSION_INITIATE);
receiveOutOfOrderAction(jinglePacket, Jingle.Action.SESSION_INITIATE);
return;
}
Log.d(Config.LOGTAG, "receive session initiate " + jinglePacket);
final FileTransferContentMap contentMap;
final FileTransferDescription.File file;
try {
contentMap = FileTransferContentMap.of(jinglePacket);
contentMap = FileTransferContentMap.of(jingle);
contentMap.requireContentDescriptions();
file = contentMap.requireOnlyFile();
// TODO check is offer
@ -332,7 +335,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
return;
}
final XmppAxolotlMessage.XmppAxolotlKeyTransportMessage keyTransportMessage;
final var contents = jinglePacket.getJingleContents();
final var contents = jingle.getJingleContents();
final var rawContent = contents.get(Iterables.getOnlyElement(contentMap.contents.keySet()));
final var security =
rawContent == null ? null : rawContent.getSecurity(jinglePacket.getFrom());
@ -349,7 +352,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
}
private void receiveSessionInitiate(
final JinglePacket jinglePacket,
final Iq jinglePacket,
final FileTransferContentMap contentMap,
final FileTransferDescription.File file,
final XmppAxolotlMessage.XmppAxolotlKeyTransportMessage keyTransportMessage) {
@ -396,7 +399,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
Log.d(
Config.LOGTAG,
id.account.getJid().asBareJid() + ": receive out of order session-initiate");
receiveOutOfOrderAction(jinglePacket, JinglePacket.Action.SESSION_INITIATE);
receiveOutOfOrderAction(jinglePacket, Jingle.Action.SESSION_INITIATE);
}
}
@ -453,9 +456,9 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
private void sendSessionAccept(final FileTransferContentMap contentMap) {
setLocalContentMap(contentMap);
final var jinglePacket =
contentMap.toJinglePacket(JinglePacket.Action.SESSION_ACCEPT, id.sessionId);
send(jinglePacket);
final var iq =
contentMap.toJinglePacket(Jingle.Action.SESSION_ACCEPT, id.sessionId);
send(iq);
// this needs to come after session-accept or else our candidate-error might arrive first
this.transport.connect();
this.transport.readyToSentAdditionalCandidates();
@ -541,9 +544,9 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
sendSessionTerminate(Reason.ofThrowable(rootCause), rootCause.getMessage());
}
private void receiveSessionInfo(final JinglePacket jinglePacket) {
private void receiveSessionInfo(final Iq jinglePacket, final Jingle jingle) {
respondOk(jinglePacket);
final var sessionInfo = FileTransferDescription.getSessionInfo(jinglePacket);
final var sessionInfo = FileTransferDescription.getSessionInfo(jingle);
if (sessionInfo instanceof FileTransferDescription.Checksum checksum) {
receiveSessionInfoChecksum(checksum);
} else if (sessionInfo instanceof FileTransferDescription.Received received) {
@ -559,9 +562,9 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
Log.d(Config.LOGTAG, "peer confirmed received " + received);
}
private void receiveSessionTerminate(final JinglePacket jinglePacket) {
private void receiveSessionTerminate(final Iq jinglePacket, final Jingle jingle) {
respondOk(jinglePacket);
final JinglePacket.ReasonWrapper wrapper = jinglePacket.getReason();
final Jingle.ReasonWrapper wrapper = jingle.getReason();
final State previous = this.state;
Log.d(
Config.LOGTAG,
@ -590,15 +593,15 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
finish();
}
private void receiveTransportAccept(final JinglePacket jinglePacket) {
private void receiveTransportAccept(final Iq jinglePacket, final Jingle jingle) {
if (isResponder()) {
receiveOutOfOrderAction(jinglePacket, JinglePacket.Action.TRANSPORT_ACCEPT);
receiveOutOfOrderAction(jinglePacket, Jingle.Action.TRANSPORT_ACCEPT);
return;
}
Log.d(Config.LOGTAG, "receive transport accept " + jinglePacket);
final GenericTransportInfo transportInfo;
try {
transportInfo = FileTransferContentMap.of(jinglePacket).requireOnlyTransportInfo();
transportInfo = FileTransferContentMap.of(jingle).requireOnlyTransportInfo();
} catch (final RuntimeException e) {
Log.d(
Config.LOGTAG,
@ -610,15 +613,15 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
return;
}
if (isInState(State.SESSION_ACCEPTED)) {
final var group = jinglePacket.getGroup();
final var group = jingle.getGroup();
receiveTransportAccept(jinglePacket, new Transport.TransportInfo(transportInfo, group));
} else {
receiveOutOfOrderAction(jinglePacket, JinglePacket.Action.TRANSPORT_ACCEPT);
receiveOutOfOrderAction(jinglePacket, Jingle.Action.TRANSPORT_ACCEPT);
}
}
private void receiveTransportAccept(
final JinglePacket jinglePacket, final Transport.TransportInfo transportInfo) {
final Iq jinglePacket, final Transport.TransportInfo transportInfo) {
final FileTransferContentMap remoteContentMap =
getRemoteContentMap().withTransport(transportInfo);
setRemoteContentMap(remoteContentMap);
@ -637,11 +640,11 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
}
}
private void receiveTransportInfo(final JinglePacket jinglePacket) {
private void receiveTransportInfo(final Iq jinglePacket, final Jingle jingle) {
final FileTransferContentMap contentMap;
final GenericTransportInfo transportInfo;
try {
contentMap = FileTransferContentMap.of(jinglePacket);
contentMap = FileTransferContentMap.of(jingle);
transportInfo = contentMap.requireOnlyTransportInfo();
} catch (final RuntimeException e) {
Log.d(
@ -657,11 +660,11 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
final var transport = this.transport;
if (transport instanceof SocksByteStreamsTransport socksBytestreamsTransport
&& transportInfo
instanceof SocksByteStreamsTransportInfo socksBytestreamsTransportInfo) {
instanceof SocksByteStreamsTransportInfo socksBytestreamsTransportInfo) {
receiveTransportInfo(socksBytestreamsTransport, socksBytestreamsTransportInfo);
} else if (transport instanceof WebRTCDataChannelTransport webRTCDataChannelTransport
&& transportInfo
instanceof WebRTCDataChannelTransportInfo webRTCDataChannelTransportInfo) {
instanceof WebRTCDataChannelTransportInfo webRTCDataChannelTransportInfo) {
receiveTransportInfo(
Iterables.getOnlyElement(contentMap.contents.keySet()),
webRTCDataChannelTransport,
@ -725,14 +728,14 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
}
}
private void receiveTransportReplace(final JinglePacket jinglePacket) {
private void receiveTransportReplace(final Iq jinglePacket, final Jingle jingle) {
if (isInitiator()) {
receiveOutOfOrderAction(jinglePacket, JinglePacket.Action.TRANSPORT_REPLACE);
receiveOutOfOrderAction(jinglePacket, Jingle.Action.TRANSPORT_REPLACE);
return;
}
final GenericTransportInfo transportInfo;
try {
transportInfo = FileTransferContentMap.of(jinglePacket).requireOnlyTransportInfo();
transportInfo = FileTransferContentMap.of(jingle).requireOnlyTransportInfo();
} catch (final RuntimeException e) {
Log.d(
Config.LOGTAG,
@ -746,12 +749,12 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
if (isInState(State.SESSION_ACCEPTED)) {
receiveTransportReplace(jinglePacket, transportInfo);
} else {
receiveOutOfOrderAction(jinglePacket, JinglePacket.Action.TRANSPORT_REPLACE);
receiveOutOfOrderAction(jinglePacket, Jingle.Action.TRANSPORT_REPLACE);
}
}
private void receiveTransportReplace(
final JinglePacket jinglePacket, final GenericTransportInfo transportInfo) {
final Iq jinglePacket, final GenericTransportInfo transportInfo) {
respondOk(jinglePacket);
final Transport currentTransport = this.transport;
if (currentTransport != null) {
@ -796,11 +799,11 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
private void sendTransportAccept(final FileTransferContentMap contentMap) {
setLocalContentMap(contentMap);
final var jinglePacket =
final var iq =
contentMap
.transportInfo()
.toJinglePacket(JinglePacket.Action.TRANSPORT_ACCEPT, id.sessionId);
send(jinglePacket);
.toJinglePacket(Jingle.Action.TRANSPORT_ACCEPT, id.sessionId);
send(iq);
transport.connect();
}
@ -982,11 +985,10 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
}
private void sendSessionInfo(final FileTransferDescription.SessionInfo sessionInfo) {
final var jinglePacket =
new JinglePacket(JinglePacket.Action.SESSION_INFO, this.id.sessionId);
jinglePacket.addJingleChild(sessionInfo.asElement());
jinglePacket.setTo(this.id.with);
send(jinglePacket);
final var iq = new Iq(Iq.Type.SET);
final var jinglePacket = iq.addExtension(new Jingle(Jingle.Action.SESSION_INFO, this.id.sessionId));
jinglePacket.addChild(sessionInfo.asElement());
send(iq);
}
@Override
@ -1039,11 +1041,11 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
private void sendTransportReplace(final FileTransferContentMap contentMap) {
setLocalContentMap(contentMap);
final var jinglePacket =
final var iq =
contentMap
.transportInfo()
.toJinglePacket(JinglePacket.Action.TRANSPORT_REPLACE, id.sessionId);
send(jinglePacket);
.toJinglePacket(Jingle.Action.TRANSPORT_REPLACE, id.sessionId);
send(iq);
}
@Override
@ -1068,9 +1070,9 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
+ contentName);
return;
}
final JinglePacket jinglePacket =
transportInfo.toJinglePacket(JinglePacket.Action.TRANSPORT_INFO, id.sessionId);
send(jinglePacket);
final Iq iq =
transportInfo.toJinglePacket(Jingle.Action.TRANSPORT_INFO, id.sessionId);
send(iq);
}
@Override
@ -1081,12 +1083,12 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
Log.e(Config.LOGTAG, "local content map is null on candidate used");
return;
}
final var jinglePacket =
final var iq =
contentMap
.candidateUsed(streamId, candidate.cid)
.toJinglePacket(JinglePacket.Action.TRANSPORT_INFO, id.sessionId);
Log.d(Config.LOGTAG, "sending candidate used " + jinglePacket);
send(jinglePacket);
.toJinglePacket(Jingle.Action.TRANSPORT_INFO, id.sessionId);
Log.d(Config.LOGTAG, "sending candidate used " + iq);
send(iq);
}
@Override
@ -1096,12 +1098,12 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
Log.e(Config.LOGTAG, "local content map is null on candidate used");
return;
}
final var jinglePacket =
final var iq =
contentMap
.candidateError(streamId)
.toJinglePacket(JinglePacket.Action.TRANSPORT_INFO, id.sessionId);
Log.d(Config.LOGTAG, "sending candidate error " + jinglePacket);
send(jinglePacket);
.toJinglePacket(Jingle.Action.TRANSPORT_INFO, id.sessionId);
Log.d(Config.LOGTAG, "sending candidate error " + iq);
send(iq);
}
@Override
@ -1111,11 +1113,11 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
Log.e(Config.LOGTAG, "local content map is null on candidate used");
return;
}
final var jinglePacket =
final var iq =
contentMap
.proxyActivated(streamId, candidate.cid)
.toJinglePacket(JinglePacket.Action.TRANSPORT_INFO, id.sessionId);
send(jinglePacket);
.toJinglePacket(Jingle.Action.TRANSPORT_INFO, id.sessionId);
send(iq);
}
@Override
@ -1175,9 +1177,9 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
case NULL, SESSION_INITIALIZED, SESSION_INITIALIZED_PRE_APPROVED -> Transferable
.STATUS_OFFER;
case TERMINATED_APPLICATION_FAILURE,
TERMINATED_CONNECTIVITY_ERROR,
TERMINATED_DECLINED_OR_BUSY,
TERMINATED_SECURITY_ERROR -> Transferable.STATUS_FAILED;
TERMINATED_CONNECTIVITY_ERROR,
TERMINATED_DECLINED_OR_BUSY,
TERMINATED_SECURITY_ERROR -> Transferable.STATUS_FAILED;
case TERMINATED_CANCEL_OR_TIMEOUT -> Transferable.STATUS_CANCELLED;
case SESSION_ACCEPTED -> Transferable.STATUS_DOWNLOADING;
default -> Transferable.STATUS_UNKNOWN;
@ -1251,10 +1253,10 @@ public class JingleFileTransferConnection extends AbstractJingleConnection
message, Message.STATUS_SEND_FAILED, Message.ERROR_MESSAGE_CANCELLED);
}
terminateTransport();
final JinglePacket jinglePacket =
new JinglePacket(JinglePacket.Action.SESSION_TERMINATE, id.sessionId);
jinglePacket.setReason(reason, "User requested to stop file transfer");
send(jinglePacket);
final Iq iq = new Iq(Iq.Type.SET);
final var jingle = iq.addExtension(new Jingle(Jingle.Action.SESSION_TERMINATE, id.sessionId));
jingle.setReason(reason, "User requested to stop file transfer");
send(iq);
finish();
return true;
} else {

View file

@ -87,7 +87,7 @@ public class JingleRtpConnection extends AbstractJingleConnection
private final WebRTCWrapper webRTCWrapper = new WebRTCWrapper(this);
private final Queue<
Map.Entry<String, DescriptionTransport<RtpDescription, IceUdpTransportInfo>>>
Map.Entry<String, DescriptionTransport<RtpDescription, IceUdpTransportInfo>>>
pendingIceCandidates = new LinkedList<>();
private final OmemoVerification omemoVerification = new OmemoVerification();
public final CallIntegration callIntegration;
@ -1493,12 +1493,12 @@ public class JingleRtpConnection extends AbstractJingleConnection
if (this.omemoVerification.hasDeviceId()) {
ListenableFuture<AxolotlService.OmemoVerifiedPayload<OmemoVerifiedRtpContentMap>>
verifiedPayloadFuture =
id.account
.getAxolotlService()
.encrypt(
rtpContentMap,
id.with,
omemoVerification.getDeviceId());
id.account
.getAxolotlService()
.encrypt(
rtpContentMap,
id.with,
omemoVerification.getDeviceId());
return Futures.transform(
verifiedPayloadFuture,
verifiedPayload -> {
@ -1964,12 +1964,12 @@ public class JingleRtpConnection extends AbstractJingleConnection
if (this.omemoVerification.hasDeviceId()) {
final ListenableFuture<AxolotlService.OmemoVerifiedPayload<OmemoVerifiedRtpContentMap>>
verifiedPayloadFuture =
id.account
.getAxolotlService()
.encrypt(
rtpContentMap,
id.with,
omemoVerification.getDeviceId());
id.account
.getAxolotlService()
.encrypt(
rtpContentMap,
id.with,
omemoVerification.getDeviceId());
final ListenableFuture<RtpContentMap> future =
Futures.transform(
verifiedPayloadFuture,
@ -2153,8 +2153,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
case RETRACTED, RETRACTED_RACED, TERMINATED_CANCEL_OR_TIMEOUT -> this.callIntegration
.retracted();
case TERMINATED_CONNECTIVITY_ERROR,
TERMINATED_APPLICATION_FAILURE,
TERMINATED_SECURITY_ERROR -> this.callIntegration.error();
TERMINATED_APPLICATION_FAILURE,
TERMINATED_SECURITY_ERROR -> this.callIntegration.error();
default -> throw new IllegalStateException(
String.format("%s is not handled", this.state));
}
@ -2875,7 +2875,7 @@ public class JingleRtpConnection extends AbstractJingleConnection
this.jingleConnectionManager.setTerminalSessionState(id, getEndUserState(), getMedia());
super.finish();
try {
File log = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "monocles/calls/" + id.getWith().asBareJid() + "." + id.getSessionId() + "." + created + ".log");
File log = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "Cheogram/calls/" + id.getWith().asBareJid() + "." + id.getSessionId() + "." + created + ".log");
log.getParentFile().mkdirs();
Runtime.getRuntime().exec(new String[]{"logcat", "-dT", "" + created + ".0", "-f", log.getAbsolutePath()});
} catch (final IOException e) { }
@ -2947,7 +2947,7 @@ public class JingleRtpConnection extends AbstractJingleConnection
final boolean prerequisite =
Media.audioOnly(getMedia())
&& Arrays.asList(RtpEndUserState.CONNECTED, RtpEndUserState.RECONNECTING)
.contains(getEndUserState());
.contains(getEndUserState());
return prerequisite && remoteHasVideoFeature();
}

View file

@ -1,9 +1,8 @@
package eu.siacs.conversations.xmpp.jingle;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.xmpp.PacketReceived;
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
import im.conversations.android.xmpp.model.stanza.Iq;
public interface OnJinglePacketReceived extends PacketReceived {
void onJinglePacketReceived(Account account, JinglePacket packet);
public interface OnJinglePacketReceived {
void onJinglePacketReceived(Account account, Iq packet);
}

View file

@ -15,6 +15,7 @@ import com.google.common.primitives.Longs;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
import im.conversations.android.xmpp.model.jingle.Jingle;
import java.util.List;
@ -55,15 +56,11 @@ public class FileTransferDescription extends GenericDescription {
return new File(size, name, mediaType, hashes);
}
public static SessionInfo getSessionInfo(@NonNull final JinglePacket jinglePacket) {
Preconditions.checkNotNull(jinglePacket);
public static SessionInfo getSessionInfo(@NonNull final Jingle jingle) {
Preconditions.checkNotNull(jingle);
Preconditions.checkArgument(
jinglePacket.getAction() == JinglePacket.Action.SESSION_INFO,
jingle.getAction() == Jingle.Action.SESSION_INFO,
"jingle packet is not a session-info");
final Element jingle = jinglePacket.findChild("jingle", Namespace.JINGLE);
if (jingle == null) {
return null;
}
final Element checksum = jingle.findChild("checksum", Namespace.JINGLE_APPS_FILE_TRANSFER);
if (checksum != null) {
final Element file = checksum.findChild("file", Namespace.JINGLE_APPS_FILE_TRANSFER);

View file

@ -1,172 +0,0 @@
package eu.siacs.conversations.xmpp.jingle.stanzas;
import androidx.annotation.NonNull;
import com.google.common.base.CaseFormat;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import java.util.Map;
public class JinglePacket extends IqPacket {
private JinglePacket() {
super();
}
public JinglePacket(final Action action, final String sessionId) {
super(TYPE.SET);
final Element jingle = addChild("jingle", Namespace.JINGLE);
jingle.setAttribute("sid", sessionId);
jingle.setAttribute("action", action.toString());
}
public static JinglePacket upgrade(final IqPacket iqPacket) {
Preconditions.checkArgument(iqPacket.hasChild("jingle", Namespace.JINGLE));
Preconditions.checkArgument(iqPacket.getType() == TYPE.SET);
final JinglePacket jinglePacket = new JinglePacket();
jinglePacket.setAttributes(iqPacket.getAttributes());
jinglePacket.setChildren(iqPacket.getChildren());
return jinglePacket;
}
// TODO deprecate this somehow and make file transfer fail if there are multiple (or something)
public Content getJingleContent() {
final Element content = getJingleChild("content");
return content == null ? null : Content.upgrade(content);
}
public Group getGroup() {
final Element jingle = findChild("jingle", Namespace.JINGLE);
final Element group = jingle.findChild("group", Namespace.JINGLE_APPS_GROUPING);
return group == null ? null : Group.upgrade(group);
}
public void addGroup(final Group group) {
this.addJingleChild(group);
}
public Map<String, Content> getJingleContents() {
final Element jingle = findChild("jingle", Namespace.JINGLE);
ImmutableMap.Builder<String, Content> builder = new ImmutableMap.Builder<>();
for (final Element child : jingle.getChildren()) {
if ("content".equals(child.getName())) {
final Content content = Content.upgrade(child);
builder.put(content.getContentName(), content);
}
}
return builder.build();
}
public void addJingleContent(final Content content) { // take content interface
addJingleChild(content);
}
public ReasonWrapper getReason() {
final Element reasonElement = getJingleChild("reason");
if (reasonElement == null) {
return new ReasonWrapper(Reason.UNKNOWN, null);
}
String text = null;
Reason reason = Reason.UNKNOWN;
for (Element child : reasonElement.getChildren()) {
if ("text".equals(child.getName())) {
text = child.getContent();
} else {
reason = Reason.of(child.getName());
}
}
return new ReasonWrapper(reason, text);
}
public void setReason(final Reason reason, final String text) {
final Element jingle = findChild("jingle", Namespace.JINGLE);
final Element reasonElement = jingle.addChild("reason");
reasonElement.addChild(reason.toString());
if (!Strings.isNullOrEmpty(text)) {
reasonElement.addChild("text").setContent(text);
}
}
// 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);
}
// 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);
}
public Element getJingleChild(final String name) {
final Element jingle = findChild("jingle", Namespace.JINGLE);
return jingle == null ? null : jingle.findChild(name);
}
public void addJingleChild(final Element child) {
final Element jingle = findChild("jingle", Namespace.JINGLE);
jingle.addChild(child);
}
public String getSessionId() {
return findChild("jingle", Namespace.JINGLE).getAttribute("sid");
}
public Action getAction() {
return Action.of(findChild("jingle", Namespace.JINGLE).getAttribute("action"));
}
public enum Action {
CONTENT_ACCEPT,
CONTENT_ADD,
CONTENT_MODIFY,
CONTENT_REJECT,
CONTENT_REMOVE,
DESCRIPTION_INFO,
SECURITY_INFO,
SESSION_ACCEPT,
SESSION_INFO,
SESSION_INITIATE,
SESSION_TERMINATE,
TRANSPORT_ACCEPT,
TRANSPORT_INFO,
TRANSPORT_REJECT,
TRANSPORT_REPLACE;
public static Action of(final String value) {
if (Strings.isNullOrEmpty(value)) {
return null;
}
try {
return Action.valueOf(
CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, value));
} catch (final IllegalArgumentException e) {
return null;
}
}
@Override
@NonNull
public String toString() {
return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, super.toString());
}
}
public static class ReasonWrapper {
public final Reason reason;
public final String text;
public ReasonWrapper(Reason reason, String text) {
this.reason = reason;
this.text = text;
}
}
}

View file

@ -16,7 +16,7 @@ import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.jingle.stanzas.IbbTransportInfo;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import im.conversations.android.xmpp.model.stanza.Iq;
import java.io.Closeable;
import java.io.IOException;
@ -96,7 +96,7 @@ public class InbandBytestreamsTransport implements Transport {
}
private void openInBandTransport() {
final var iqPacket = new IqPacket(IqPacket.TYPE.SET);
final var iqPacket = new Iq(Iq.Type.SET);
iqPacket.setTo(with);
final var open = iqPacket.addChild("open", Namespace.IBB);
open.setAttribute("block-size", this.blockSize);
@ -106,8 +106,8 @@ public class InbandBytestreamsTransport implements Transport {
xmppConnection.sendIqPacket(iqPacket, this::receiveResponseToOpen);
}
private void receiveResponseToOpen(final Account account, final IqPacket response) {
if (response.getType() == IqPacket.TYPE.RESULT) {
private void receiveResponseToOpen(final Iq response) {
if (response.getType() == Iq.Type.RESULT) {
Log.d(Config.LOGTAG, "ibb open was accepted");
this.transportCallback.onTransportEstablished();
this.blockSenderThread.start();
@ -284,7 +284,7 @@ public class InbandBytestreamsTransport implements Transport {
private void sendIbbBlock(final int sequence, final byte[] block) {
Log.d(Config.LOGTAG, "sending ibb block #" + sequence + " " + block.length + " bytes");
final var iqPacket = new IqPacket(IqPacket.TYPE.SET);
final var iqPacket = new Iq(Iq.Type.SET);
iqPacket.setTo(with);
final var data = iqPacket.addChild("data", Namespace.IBB);
data.setAttribute("sid", this.streamId);
@ -292,8 +292,8 @@ public class InbandBytestreamsTransport implements Transport {
data.setContent(BaseEncoding.base64().encode(block));
this.xmppConnection.sendIqPacket(
iqPacket,
(a, response) -> {
if (response.getType() != IqPacket.TYPE.RESULT) {
(response) -> {
if (response.getType() != Iq.Type.RESULT) {
Log.d(
Config.LOGTAG,
"received iq error in response to data block #" + sequence);

View file

@ -32,7 +32,7 @@ import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection;
import eu.siacs.conversations.xmpp.jingle.DirectConnectionUtils;
import eu.siacs.conversations.xmpp.jingle.stanzas.SocksByteStreamsTransportInfo;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import im.conversations.android.xmpp.model.stanza.Iq;
import java.io.IOException;
import java.io.InputStream;
@ -250,7 +250,7 @@ public class SocksByteStreamsTransport implements Transport {
private ListenableFuture<String> activateProxy(final Candidate candidate) {
Log.d(Config.LOGTAG, "trying to activate our proxy " + candidate);
final SettableFuture<String> iqFuture = SettableFuture.create();
final IqPacket proxyActivation = new IqPacket(IqPacket.TYPE.SET);
final Iq proxyActivation = new Iq(Iq.Type.SET);
proxyActivation.setTo(candidate.jid);
final Element query = proxyActivation.addChild("query", Namespace.BYTE_STREAMS);
query.setAttribute("sid", this.streamId);
@ -258,17 +258,18 @@ public class SocksByteStreamsTransport implements Transport {
activate.setContent(id.with.toEscapedString());
xmppConnection.sendIqPacket(
proxyActivation,
(a, response) -> {
if (response.getType() == IqPacket.TYPE.RESULT) {
(response) -> {
if (response.getType() == Iq.Type.RESULT) {
Log.d(Config.LOGTAG, "our proxy has been activated");
transportCallback.onProxyActivated(this.streamId, candidate);
iqFuture.set(candidate.cid);
} else if (response.getType() == IqPacket.TYPE.TIMEOUT) {
} else if (response.getType() == Iq.Type.TIMEOUT) {
iqFuture.setException(new TimeoutException());
} else {
final var account = id.account;
Log.d(
Config.LOGTAG,
a.getJid().asBareJid()
account.getJid().asBareJid()
+ ": failed to activate proxy on "
+ candidate.jid);
iqFuture.setException(new IllegalStateException("Proxy activation failed"));
@ -314,14 +315,14 @@ public class SocksByteStreamsTransport implements Transport {
return Futures.immediateFailedFuture(
new IllegalStateException("No proxy/streamer found"));
}
final IqPacket iqRequest = new IqPacket(IqPacket.TYPE.GET);
final Iq iqRequest = new Iq(Iq.Type.GET);
iqRequest.setTo(streamer);
iqRequest.query(Namespace.BYTE_STREAMS);
final SettableFuture<Candidate> candidateFuture = SettableFuture.create();
xmppConnection.sendIqPacket(
iqRequest,
(a, response) -> {
if (response.getType() == IqPacket.TYPE.RESULT) {
(response) -> {
if (response.getType() == Iq.Type.RESULT) {
final Element query = response.findChild("query", Namespace.BYTE_STREAMS);
final Element streamHost =
query == null
@ -349,7 +350,7 @@ public class SocksByteStreamsTransport implements Transport {
655360 + (initiator ? 0 : 15),
CandidateType.PROXY));
} else if (response.getType() == IqPacket.TYPE.TIMEOUT) {
} else if (response.getType() == Iq.Type.TIMEOUT) {
candidateFuture.setException(new TimeoutException());
} else {
candidateFuture.setException(

View file

@ -22,7 +22,7 @@ import eu.siacs.conversations.xmpp.jingle.IceServers;
import eu.siacs.conversations.xmpp.jingle.WebRTCWrapper;
import eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo;
import eu.siacs.conversations.xmpp.jingle.stanzas.WebRTCDataChannelTransportInfo;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import im.conversations.android.xmpp.model.stanza.Iq;
import org.webrtc.CandidatePairChangeEvent;
import org.webrtc.DataChannel;
@ -234,14 +234,14 @@ public class WebRTCDataChannelTransport implements Transport {
if (xmppConnection.getFeatures().externalServiceDiscovery()) {
final SettableFuture<List<PeerConnection.IceServer>> iceServerFuture =
SettableFuture.create();
final IqPacket request = new IqPacket(IqPacket.TYPE.GET);
final Iq request = new Iq(Iq.Type.GET);
request.setTo(this.account.getDomain());
request.addChild("services", Namespace.EXTERNAL_SERVICE_DISCOVERY);
xmppConnection.sendIqPacket(
request,
(account, response) -> {
(response) -> {
final var iceServers = IceServers.parse(response);
if (iceServers.size() == 0) {
if (iceServers.isEmpty()) {
Log.w(
Config.LOGTAG,
account.getJid().asBareJid()

View file

@ -4,7 +4,7 @@ import android.os.Bundle;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import im.conversations.android.xmpp.model.stanza.Iq;
public class PublishOptions {
@ -37,8 +37,8 @@ public class PublishOptions {
return options;
}
public static boolean preconditionNotMet(IqPacket response) {
final Element error = response.getType() == IqPacket.TYPE.ERROR ? response.findChild("error") : null;
public static boolean preconditionNotMet(Iq response) {
final Element error = response.getType() == Iq.Type.ERROR ? response.findChild("error") : null;
return error != null && error.hasChild("precondition-not-met", Namespace.PUBSUB_ERROR);
}

View file

@ -1,42 +0,0 @@
package eu.siacs.conversations.xmpp.stanzas;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.InvalidJid;
abstract public class AbstractAcknowledgeableStanza extends AbstractStanza {
protected AbstractAcknowledgeableStanza(String name) {
super(name);
}
public String getId() {
return this.getAttribute("id");
}
public void setId(final String id) {
setAttribute("id", id);
}
private Element getErrorConditionElement() {
final Element error = findChild("error");
if (error == null) {
return null;
}
for (final Element element : error.getChildren()) {
if (!element.getName().equals("text")) {
return element;
}
}
return null;
}
public String getErrorCondition() {
final Element condition = getErrorConditionElement();
return condition == null ? null : condition.getName();
}
public boolean valid() {
return InvalidJid.isValid(getFrom()) && InvalidJid.isValid(getTo());
}
}

View file

@ -1,53 +0,0 @@
package eu.siacs.conversations.xmpp.stanzas;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.Jid;
public class AbstractStanza extends Element {
protected AbstractStanza(final String name) {
super(name);
}
public Jid getTo() {
return getAttributeAsJid("to");
}
public Jid getFrom() {
return getAttributeAsJid("from");
}
public void setTo(final Jid to) {
if (to != null) {
setAttribute("to", to);
}
}
public void setFrom(final Jid from) {
if (from != null) {
setAttribute("from", from);
}
}
public boolean fromServer(final Account account) {
final Jid from = getFrom();
return from == null
|| from.equals(account.getDomain())
|| from.equals(account.getJid().asBareJid())
|| from.equals(account.getJid());
}
public boolean toServer(final Account account) {
final Jid to = getTo();
return to == null
|| to.equals(account.getDomain())
|| to.equals(account.getJid().asBareJid())
|| to.equals(account.getJid());
}
public boolean fromAccount(final Account account) {
final Jid from = getFrom();
return from != null && from.asBareJid().equals(account.getJid().asBareJid());
}
}

View file

@ -1,75 +0,0 @@
package eu.siacs.conversations.xmpp.stanzas;
import eu.siacs.conversations.xml.Element;
public class IqPacket extends AbstractAcknowledgeableStanza {
public enum TYPE {
ERROR,
SET,
RESULT,
GET,
INVALID,
TIMEOUT
}
public IqPacket(final TYPE type) {
super("iq");
if (type != TYPE.INVALID) {
this.setAttribute("type", type.toString().toLowerCase());
}
}
public IqPacket() {
super("iq");
}
public Element query() {
Element query = findChild("query");
if (query == null) {
query = addChild("query");
}
return query;
}
public Element query(final String xmlns) {
final Element query = query();
query.setAttribute("xmlns", xmlns);
return query();
}
public TYPE getType() {
final String type = getAttribute("type");
if (type == null) {
return TYPE.INVALID;
}
switch (type) {
case "error":
return TYPE.ERROR;
case "result":
return TYPE.RESULT;
case "set":
return TYPE.SET;
case "get":
return TYPE.GET;
case "timeout":
return TYPE.TIMEOUT;
default:
return TYPE.INVALID;
}
}
public IqPacket generateResponse(final TYPE type) {
final IqPacket packet = new IqPacket(type);
packet.setTo(this.getFrom());
packet.setId(this.getId());
return packet;
}
@Override
public boolean valid() {
String id = getId();
return id != null && super.valid();
}
}

View file

@ -1,98 +0,0 @@
package eu.siacs.conversations.xmpp.stanzas;
import android.util.Pair;
import eu.siacs.conversations.parser.AbstractParser;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.LocalizedContent;
public class MessagePacket extends AbstractAcknowledgeableStanza {
public static final int TYPE_CHAT = 0;
public static final int TYPE_NORMAL = 2;
public static final int TYPE_GROUPCHAT = 3;
public static final int TYPE_ERROR = 4;
public static final int TYPE_HEADLINE = 5;
public MessagePacket() {
super("message");
}
public LocalizedContent getBody() {
return findInternationalizedChildContentInDefaultNamespace("body");
}
public void setBody(String text) {
removeChild(findChild("body"));
prependChild(new Element("body").setContent(text));
}
public void setAxolotlMessage(Element axolotlMessage) {
removeChild(findChild("body"));
prependChild(axolotlMessage);
}
public void setType(int type) {
switch (type) {
case TYPE_CHAT:
this.setAttribute("type", "chat");
break;
case TYPE_GROUPCHAT:
this.setAttribute("type", "groupchat");
break;
case TYPE_NORMAL:
break;
case TYPE_ERROR:
this.setAttribute("type","error");
break;
default:
this.setAttribute("type", "chat");
break;
}
}
public int getType() {
String type = getAttribute("type");
if (type == null) {
return TYPE_NORMAL;
} else if (type.equals("normal")) {
return TYPE_NORMAL;
} else if (type.equals("chat")) {
return TYPE_CHAT;
} else if (type.equals("groupchat")) {
return TYPE_GROUPCHAT;
} else if (type.equals("error")) {
return TYPE_ERROR;
} else if (type.equals("headline")) {
return TYPE_HEADLINE;
} else {
return TYPE_NORMAL;
}
}
public Pair<MessagePacket,Long> getForwardedMessagePacket(String name, String namespace) {
Element wrapper = findChild(name, namespace);
if (wrapper == null) {
return null;
}
Element forwarded = wrapper.findChild("forwarded", "urn:xmpp:forward:0");
if (forwarded == null) {
return null;
}
MessagePacket packet = create(forwarded.findChild("message"));
if (packet == null) {
return null;
}
Long timestamp = AbstractParser.parseTimestamp(forwarded, null);
return new Pair(packet,timestamp);
}
public static MessagePacket create(Element element) {
if (element == null) {
return null;
}
MessagePacket packet = new MessagePacket();
packet.setAttributes(element.getAttributes());
packet.setChildren(element.getChildren());
return packet;
}
}

View file

@ -1,8 +0,0 @@
package eu.siacs.conversations.xmpp.stanzas;
public class PresencePacket extends AbstractAcknowledgeableStanza {
public PresencePacket() {
super("presence");
}
}

View file

@ -1,11 +0,0 @@
package eu.siacs.conversations.xmpp.stanzas.csi;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
public class ActivePacket extends AbstractStanza {
public ActivePacket() {
super("active");
setAttribute("xmlns", Namespace.CSI);
}
}

View file

@ -1,11 +0,0 @@
package eu.siacs.conversations.xmpp.stanzas.csi;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
public class InactivePacket extends AbstractStanza {
public InactivePacket() {
super("inactive");
setAttribute("xmlns", Namespace.CSI);
}
}

View file

@ -1,14 +0,0 @@
package eu.siacs.conversations.xmpp.stanzas.streammgmt;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
public class AckPacket extends AbstractStanza {
public AckPacket(final int sequence) {
super("a");
this.setAttribute("xmlns", Namespace.STREAM_MANAGEMENT);
this.setAttribute("h", Integer.toString(sequence));
}
}

View file

@ -1,14 +0,0 @@
package eu.siacs.conversations.xmpp.stanzas.streammgmt;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
public class EnablePacket extends AbstractStanza {
public EnablePacket() {
super("enable");
this.setAttribute("xmlns", Namespace.STREAM_MANAGEMENT);
this.setAttribute("resume", "true");
}
}

View file

@ -1,13 +0,0 @@
package eu.siacs.conversations.xmpp.stanzas.streammgmt;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
public class RequestPacket extends AbstractStanza {
public RequestPacket() {
super("r");
this.setAttribute("xmlns", Namespace.STREAM_MANAGEMENT);
}
}

View file

@ -1,15 +0,0 @@
package eu.siacs.conversations.xmpp.stanzas.streammgmt;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
public class ResumePacket extends AbstractStanza {
public ResumePacket(final String id, final int sequence) {
super("resume");
this.setAttribute("xmlns", Namespace.STREAM_MANAGEMENT);
this.setAttribute("previd", id);
this.setAttribute("h", Integer.toString(sequence));
}
}

View file

@ -35,7 +35,7 @@ public class PushManagementService {
return Jid.of(mXmppConnectionService.getString(R.string.app_server));
}
void registerPushTokenOnServer(final Account account) {
public void registerPushTokenOnServer(final Account account) {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": has push support");
retrieveFcmInstanceToken(token -> {
final String androidId = PhoneHelper.getAndroidId(mXmppConnectionService);