forked from mirror/monocles_chat_clean
Merge upstream
This commit is contained in:
parent
31d80edeef
commit
51cfb25f69
47 changed files with 331 additions and 920 deletions
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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> {
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package eu.siacs.conversations.xmpp.stanzas;
|
||||
|
||||
public class PresencePacket extends AbstractAcknowledgeableStanza {
|
||||
|
||||
public PresencePacket() {
|
||||
super("presence");
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue