Search in sources :

Example 46 with Jid

use of eu.siacs.conversations.xmpp.Jid in project Conversations by siacs.

the class JingleConnectionManager method deliverMessage.

public void deliverMessage(final Account account, final Jid to, final Jid from, final Element message, String remoteMsgId, String serverMsgId, long timestamp) {
    Preconditions.checkArgument(Namespace.JINGLE_MESSAGE.equals(message.getNamespace()));
    final String sessionId = message.getAttribute("id");
    if (sessionId == null) {
        return;
    }
    if ("accept".equals(message.getName())) {
        for (AbstractJingleConnection connection : connections.values()) {
            if (connection instanceof JingleRtpConnection) {
                final JingleRtpConnection rtpConnection = (JingleRtpConnection) connection;
                final AbstractJingleConnection.Id id = connection.getId();
                if (id.account == account && id.sessionId.equals(sessionId)) {
                    rtpConnection.deliveryMessage(from, message, serverMsgId, timestamp);
                    return;
                }
            }
        }
        return;
    }
    final boolean fromSelf = from.asBareJid().equals(account.getJid().asBareJid());
    final boolean addressedDirectly = to != null && to.equals(account.getJid());
    final AbstractJingleConnection.Id id;
    if (fromSelf) {
        if (to != null && to.isFullJid()) {
            id = AbstractJingleConnection.Id.of(account, to, sessionId);
        } else {
            return;
        }
    } else {
        id = AbstractJingleConnection.Id.of(account, from, sessionId);
    }
    final AbstractJingleConnection existingJingleConnection = connections.get(id);
    if (existingJingleConnection != null) {
        if (existingJingleConnection instanceof JingleRtpConnection) {
            ((JingleRtpConnection) existingJingleConnection).deliveryMessage(from, message, serverMsgId, timestamp);
        } else {
            Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": " + existingJingleConnection.getClass().getName() + " does not support jingle messages");
        }
        return;
    }
    if (fromSelf) {
        if ("proceed".equals(message.getName())) {
            final Conversation c = mXmppConnectionService.findOrCreateConversation(account, id.with, false, false);
            final Message previousBusy = c.findRtpSession(sessionId, Message.STATUS_RECEIVED);
            if (previousBusy != null) {
                previousBusy.setBody(new RtpSessionStatus(true, 0).toString());
                if (serverMsgId != null) {
                    previousBusy.setServerMsgId(serverMsgId);
                }
                previousBusy.setTime(timestamp);
                mXmppConnectionService.updateMessage(previousBusy, true);
                Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": updated previous busy because call got picked up by another device");
                return;
            }
        }
        // TODO handle reject for cases where we don’t have carbon copies (normally reject is to be sent to own bare jid as well)
        Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": ignore jingle message from self");
        return;
    }
    if ("propose".equals(message.getName())) {
        final Propose propose = Propose.upgrade(message);
        final List<GenericDescription> descriptions = propose.getDescriptions();
        final Collection<RtpDescription> rtpDescriptions = Collections2.transform(Collections2.filter(descriptions, d -> d instanceof RtpDescription), input -> (RtpDescription) input);
        if (rtpDescriptions.size() > 0 && rtpDescriptions.size() == descriptions.size() && isUsingClearNet(account)) {
            final Collection<Media> media = Collections2.transform(rtpDescriptions, RtpDescription::getMedia);
            if (media.contains(Media.UNKNOWN)) {
                Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": encountered unknown media in session proposal. " + propose);
                return;
            }
            final Optional<RtpSessionProposal> matchingSessionProposal = findMatchingSessionProposal(account, id.with, ImmutableSet.copyOf(media));
            if (matchingSessionProposal.isPresent()) {
                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() > 0) {
                    Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": our session lost tie break. automatically accepting their session. winning Session=" + theirSessionId);
                    // TODO a retract for this reason should probably include some indication of tie break
                    retractSessionProposal(matchingSessionProposal.get());
                    final JingleRtpConnection rtpConnection = new JingleRtpConnection(this, id, from);
                    this.connections.put(id, rtpConnection);
                    rtpConnection.setProposedMedia(ImmutableSet.copyOf(media));
                    rtpConnection.deliveryMessage(from, message, serverMsgId, timestamp);
                } else {
                    Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": our session won tie break. waiting for other party to accept. winningSession=" + ourSessionId);
                }
                return;
            }
            final boolean stranger = isWithStrangerAndStrangerNotificationsAreOff(account, id.with);
            if (isBusy() || stranger) {
                writeLogMissedIncoming(account, id.with.asBareJid(), id.sessionId, serverMsgId, timestamp);
                if (stranger) {
                    Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": ignoring call proposal from stranger " + id.with);
                    return;
                }
                final int activeDevices = account.activeDevicesWithRtpCapability();
                Log.d(Config.LOGTAG, "active devices with rtp capability: " + activeDevices);
                if (activeDevices == 0) {
                    final MessagePacket reject = mXmppConnectionService.getMessageGenerator().sessionReject(from, sessionId);
                    mXmppConnectionService.sendMessagePacket(account, reject);
                } else {
                    Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": ignoring proposal because busy on this device but there are other devices");
                }
            } else {
                final JingleRtpConnection rtpConnection = new JingleRtpConnection(this, id, from);
                this.connections.put(id, rtpConnection);
                rtpConnection.setProposedMedia(ImmutableSet.copyOf(media));
                rtpConnection.deliveryMessage(from, message, serverMsgId, timestamp);
            }
        } else {
            Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": unable to react to proposed session with " + rtpDescriptions.size() + " rtp descriptions of " + descriptions.size() + " total descriptions");
        }
    } else if (addressedDirectly && "proceed".equals(message.getName())) {
        synchronized (rtpSessionProposals) {
            final RtpSessionProposal proposal = getRtpSessionProposal(account, from.asBareJid(), sessionId);
            if (proposal != null) {
                rtpSessionProposals.remove(proposal);
                final JingleRtpConnection rtpConnection = new JingleRtpConnection(this, id, account.getJid());
                rtpConnection.setProposedMedia(proposal.media);
                this.connections.put(id, rtpConnection);
                rtpConnection.transitionOrThrow(AbstractJingleConnection.State.PROPOSED);
                rtpConnection.deliveryMessage(from, message, serverMsgId, timestamp);
            } else {
                Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": no rtp session proposal found for " + from + " to deliver proceed");
                if (remoteMsgId == null) {
                    return;
                }
                final MessagePacket errorMessage = new MessagePacket();
                errorMessage.setTo(from);
                errorMessage.setId(remoteMsgId);
                errorMessage.setType(MessagePacket.TYPE_ERROR);
                final Element error = errorMessage.addChild("error");
                error.setAttribute("code", "404");
                error.setAttribute("type", "cancel");
                error.addChild("item-not-found", "urn:ietf:params:xml:ns:xmpp-stanzas");
                mXmppConnectionService.sendMessagePacket(account, errorMessage);
            }
        }
    } else if (addressedDirectly && "reject".equals(message.getName())) {
        final RtpSessionProposal proposal = getRtpSessionProposal(account, from.asBareJid(), sessionId);
        synchronized (rtpSessionProposals) {
            if (proposal != null && rtpSessionProposals.remove(proposal) != null) {
                writeLogMissedOutgoing(account, proposal.with, proposal.sessionId, serverMsgId, timestamp);
                toneManager.transition(RtpEndUserState.DECLINED_OR_BUSY, proposal.media);
                mXmppConnectionService.notifyJingleRtpConnectionUpdate(account, proposal.with, proposal.sessionId, RtpEndUserState.DECLINED_OR_BUSY);
            } else {
                Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": no rtp session proposal found for " + from + " to deliver reject");
            }
        }
    } else {
        Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": retrieved out of order jingle message" + message);
    }
}
Also used : Conversational(eu.siacs.conversations.entities.Conversational) Content(eu.siacs.conversations.xmpp.jingle.stanzas.Content) RtpDescription(eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription) Config(eu.siacs.conversations.Config) ScheduledFuture(java.util.concurrent.ScheduledFuture) IqPacket(eu.siacs.conversations.xmpp.stanzas.IqPacket) Reason(eu.siacs.conversations.xmpp.jingle.stanzas.Reason) HashMap(java.util.HashMap) Collections2(com.google.common.collect.Collections2) Account(eu.siacs.conversations.entities.Account) Element(eu.siacs.conversations.xml.Element) Conversation(eu.siacs.conversations.entities.Conversation) SecureRandom(java.security.SecureRandom) GenericDescription(eu.siacs.conversations.xmpp.jingle.stanzas.GenericDescription) Optional(com.google.common.base.Optional) Map(java.util.Map) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) FileTransferDescription(eu.siacs.conversations.xmpp.jingle.stanzas.FileTransferDescription) Objects(com.google.common.base.Objects) WeakReference(java.lang.ref.WeakReference) Log(android.util.Log) XmppConnection(eu.siacs.conversations.xmpp.XmppConnection) MessagePacket(eu.siacs.conversations.xmpp.stanzas.MessagePacket) ImmutableSet(com.google.common.collect.ImmutableSet) Contact(eu.siacs.conversations.entities.Contact) Collection(java.util.Collection) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Propose(eu.siacs.conversations.xmpp.jingle.stanzas.Propose) Set(java.util.Set) JinglePacket(eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket) ComparisonChain(com.google.common.collect.ComparisonChain) Executors(java.util.concurrent.Executors) TimeUnit(java.util.concurrent.TimeUnit) Transferable(eu.siacs.conversations.entities.Transferable) List(java.util.List) Message(eu.siacs.conversations.entities.Message) RtpSessionStatus(eu.siacs.conversations.entities.RtpSessionStatus) XmppConnectionService(eu.siacs.conversations.services.XmppConnectionService) Namespace(eu.siacs.conversations.xml.Namespace) OnIqPacketReceived(eu.siacs.conversations.xmpp.OnIqPacketReceived) Base64(android.util.Base64) Preconditions(com.google.common.base.Preconditions) CacheBuilder(com.google.common.cache.CacheBuilder) Cache(com.google.common.cache.Cache) AbstractConnectionManager(eu.siacs.conversations.services.AbstractConnectionManager) Collections(java.util.Collections) Jid(eu.siacs.conversations.xmpp.Jid) Message(eu.siacs.conversations.entities.Message) Element(eu.siacs.conversations.xml.Element) GenericDescription(eu.siacs.conversations.xmpp.jingle.stanzas.GenericDescription) Conversation(eu.siacs.conversations.entities.Conversation) RtpDescription(eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription) MessagePacket(eu.siacs.conversations.xmpp.stanzas.MessagePacket) Propose(eu.siacs.conversations.xmpp.jingle.stanzas.Propose) RtpSessionStatus(eu.siacs.conversations.entities.RtpSessionStatus)

Example 47 with Jid

use of eu.siacs.conversations.xmpp.Jid in project Conversations by siacs.

the class UIHelper method getDisplayName.

public static String getDisplayName(MucOptions.User user) {
    Contact contact = user.getContact();
    if (contact != null) {
        return contact.getDisplayName();
    } else {
        final String name = user.getName();
        if (name != null) {
            return name;
        }
        final Jid realJid = user.getRealJid();
        if (realJid != null) {
            return JidHelper.localPartOrFallback(realJid);
        }
        return null;
    }
}
Also used : Jid(eu.siacs.conversations.xmpp.Jid) Contact(eu.siacs.conversations.entities.Contact)

Example 48 with Jid

use of eu.siacs.conversations.xmpp.Jid in project Conversations by siacs.

the class CreatePublicChannelDialog method submit.

private void submit(AlertDialog dialog, CreatePublicChannelDialogBinding binding) {
    final Context context = binding.getRoot().getContext();
    final Editable nameText = binding.groupChatName.getText();
    final String name = nameText == null ? "" : nameText.toString().trim();
    final Editable addressText = binding.jid.getText();
    final String address = addressText == null ? "" : addressText.toString().trim();
    if (nameEntered) {
        binding.nameLayout.setError(null);
        if (address.isEmpty()) {
            binding.xmppAddressLayout.setError(context.getText(R.string.please_enter_xmpp_address));
        } else {
            final Jid jid;
            try {
                jid = Jid.ofEscaped(address);
            } catch (IllegalArgumentException e) {
                binding.xmppAddressLayout.setError(context.getText(R.string.invalid_jid));
                return;
            }
            final Account account = StartConversationActivity.getSelectedAccount(context, binding.account);
            if (account == null) {
                return;
            }
            final XmppConnectionService service = ((XmppActivity) context).xmppConnectionService;
            if (service != null && service.findFirstMuc(jid) != null) {
                binding.xmppAddressLayout.setError(context.getString(R.string.channel_already_exists));
                return;
            }
            mListener.onCreatePublicChannel(account, name, jid);
            dialog.dismiss();
        }
    } else {
        binding.xmppAddressLayout.setError(null);
        if (name.isEmpty()) {
            binding.nameLayout.setError(context.getText(R.string.please_enter_name));
        } else if (StartConversationActivity.isValidJid(name)) {
            binding.nameLayout.setError(context.getText(R.string.this_is_an_xmpp_address));
        } else {
            binding.nameLayout.setError(null);
            nameEntered = true;
            updateInputs(binding, true);
            updateButtons(dialog);
            binding.jid.setText("");
            binding.jid.append(getJidSuggestion(binding));
        }
    }
}
Also used : Context(android.content.Context) Account(eu.siacs.conversations.entities.Account) XmppConnectionService(eu.siacs.conversations.services.XmppConnectionService) Jid(eu.siacs.conversations.xmpp.Jid) Editable(android.text.Editable)

Example 49 with Jid

use of eu.siacs.conversations.xmpp.Jid in project Conversations by siacs.

the class ContactDetailsActivity method showAddToPhoneBookDialog.

private void showAddToPhoneBookDialog() {
    final Jid jid = contact.getJid();
    final boolean quicksyContact = AbstractQuickConversationsService.isQuicksy() && Config.QUICKSY_DOMAIN.equals(jid.getDomain()) && jid.getLocal() != null;
    final String value;
    if (quicksyContact) {
        value = PhoneNumberUtilWrapper.toFormattedPhoneNumber(this, jid);
    } else {
        value = jid.toEscapedString();
    }
    final AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(getString(R.string.action_add_phone_book));
    builder.setMessage(getString(R.string.add_phone_book_text, value));
    builder.setNegativeButton(getString(R.string.cancel), null);
    builder.setPositiveButton(getString(R.string.add), (dialog, which) -> {
        final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
        intent.setType(Contacts.CONTENT_ITEM_TYPE);
        if (quicksyContact) {
            intent.putExtra(Intents.Insert.PHONE, value);
        } else {
            intent.putExtra(Intents.Insert.IM_HANDLE, value);
            intent.putExtra(Intents.Insert.IM_PROTOCOL, CommonDataKinds.Im.PROTOCOL_JABBER);
        // TODO for modern use we want PROTOCOL_CUSTOM and an extra field with a value of 'XMPP'
        // however we don’t have such a field and thus have to use the legacy PROTOCOL_JABBER
        }
        intent.putExtra("finishActivityOnSaveCompleted", true);
        try {
            startActivityForResult(intent, 0);
        } catch (ActivityNotFoundException e) {
            Toast.makeText(ContactDetailsActivity.this, R.string.no_application_found_to_view_contact, Toast.LENGTH_SHORT).show();
        }
    });
    builder.create().show();
}
Also used : AlertDialog(androidx.appcompat.app.AlertDialog) Jid(eu.siacs.conversations.xmpp.Jid) ActivityNotFoundException(android.content.ActivityNotFoundException) Intent(android.content.Intent) SpannableString(android.text.SpannableString)

Example 50 with Jid

use of eu.siacs.conversations.xmpp.Jid in project Conversations by siacs.

the class ConversationFragment method showBlockSubmenu.

private boolean showBlockSubmenu(View view) {
    final Jid jid = conversation.getJid();
    final boolean showReject = !conversation.isWithStranger() && conversation.getContact().getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST);
    PopupMenu popupMenu = new PopupMenu(getActivity(), view);
    popupMenu.inflate(R.menu.block);
    popupMenu.getMenu().findItem(R.id.block_contact).setVisible(jid.getLocal() != null);
    popupMenu.getMenu().findItem(R.id.reject).setVisible(showReject);
    popupMenu.setOnMenuItemClickListener(menuItem -> {
        Blockable blockable;
        switch(menuItem.getItemId()) {
            case R.id.reject:
                activity.xmppConnectionService.stopPresenceUpdatesTo(conversation.getContact());
                updateSnackBar(conversation);
                return true;
            case R.id.block_domain:
                blockable = conversation.getAccount().getRoster().getContact(jid.getDomain());
                break;
            default:
                blockable = conversation;
        }
        BlockContactDialog.show(activity, blockable);
        return true;
    });
    popupMenu.show();
    return true;
}
Also used : Jid(eu.siacs.conversations.xmpp.Jid) PopupMenu(android.widget.PopupMenu) Blockable(eu.siacs.conversations.entities.Blockable)

Aggregations

Jid (eu.siacs.conversations.xmpp.Jid)106 Account (eu.siacs.conversations.entities.Account)35 Element (eu.siacs.conversations.xml.Element)24 Conversation (eu.siacs.conversations.entities.Conversation)22 Contact (eu.siacs.conversations.entities.Contact)17 InvalidJid (eu.siacs.conversations.xmpp.InvalidJid)16 IqPacket (eu.siacs.conversations.xmpp.stanzas.IqPacket)16 Intent (android.content.Intent)15 ArrayList (java.util.ArrayList)13 MucOptions (eu.siacs.conversations.entities.MucOptions)12 Bookmark (eu.siacs.conversations.entities.Bookmark)10 AxolotlService (eu.siacs.conversations.crypto.axolotl.AxolotlService)7 Message (eu.siacs.conversations.entities.Message)7 OnIqPacketReceived (eu.siacs.conversations.xmpp.OnIqPacketReceived)6 MessagePacket (eu.siacs.conversations.xmpp.stanzas.MessagePacket)6 Map (java.util.Map)6 XmppUri (eu.siacs.conversations.utils.XmppUri)5 XmppConnectionService (eu.siacs.conversations.services.XmppConnectionService)4 Avatar (eu.siacs.conversations.xmpp.pep.Avatar)4 HashMap (java.util.HashMap)4