/** * Method is responsible for processing incoming subscription request (i.e. in the receivers * session manager). * * <p>If the contact is already subscribed the an auto-reply with type='subscribded' is sent, * otherwise contact is added to the roster (if it's missing/there is no current subscription), * sets the subscription type to {@code PresenceType.in_subscribe} and subsequently broadcast * presence update to all connected resources. * * @param packet packet is which being processed. * @param session user session which keeps all the user session data and also gives an access to * the user's repository data. * @param results this a collection with packets which have been generated as input packet * processing results. * @param settings this map keeps plugin specific settings loaded from the Tigase server * configuration. * @param pres_type specifies type of the presence. * @throws NoConnectionIdException * @throws NotAuthorizedException * @throws TigaseDBException */ protected void processInSubscribe( Packet packet, XMPPResourceConnection session, Queue<Packet> results, Map<String, Object> settings, RosterAbstract.PresenceType pres_type) throws NotAuthorizedException, TigaseDBException, NoConnectionIdException { // If the buddy is already subscribed then auto-reply with subscribed // presence stanza. if (roster_util.isSubscribedFrom(session, packet.getStanzaFrom())) { sendPresence( StanzaType.subscribed, session.getJID().copyWithoutResource(), packet.getStanzaFrom(), results, null); } else { RosterAbstract.SubscriptionType curr_sub = roster_util.getBuddySubscription(session, packet.getStanzaFrom()); if (curr_sub == null) { roster_util.addBuddy(session, packet.getStanzaFrom(), null, null, null); } // end of if (curr_sub == null) roster_util.updateBuddySubscription(session, pres_type, packet.getStanzaFrom()); if (!autoAuthorize) { updatePresenceChange(packet, session, results); } else { roster_util.setBuddySubscription( session, RosterAbstract.SubscriptionType.both, packet.getStanzaFrom().copyWithoutResource()); } } // end of else if (autoAuthorize) { roster_util.updateBuddyChange( session, results, roster_util.getBuddyItem(session, packet.getStanzaFrom().copyWithoutResource())); broadcastProbe(session, results, settings); sendPresence(StanzaType.subscribed, session.getJID(), packet.getStanzaFrom(), results, null); } }
/** * Method is responsible for processing outgoing subscribed and unsubscribed presence (i.e. in the * sender session manager). * * <p>Presence packet is forwarded to the destination with the JID stripped from the resource, a * subscription state is being updated and, in case there was a change, a roster push is being * sent to all user resources. Also, in case of presence type out_subscribed server send current * presence to the user from each of the contact's available resources. For the presence type * out_unsubscribed an unavailable presence is sent. * * @param packet packet is which being processed. * @param session user session which keeps all the user session data and also gives an access to * the user's repository data. * @param results this a collection with packets which have been generated as input packet * processing results. * @param settings this map keeps plugin specific settings loaded from the Tigase server * configuration. * @param pres_type specifies type of the presence. * @throws NoConnectionIdException * @throws NotAuthorizedException * @throws TigaseDBException */ protected void processOutSubscribed( Packet packet, XMPPResourceConnection session, Queue<Packet> results, Map<String, Object> settings, RosterAbstract.PresenceType pres_type) throws NotAuthorizedException, TigaseDBException, NoConnectionIdException { // According to RFC-3921 I must forward all these kind presence // requests, it allows to re-synchronize // subscriptions in case of synchronization loss forwardPresence(results, packet, session.getJID().copyWithoutResource()); Element initial_presence = session.getPresence(); JID buddy = packet.getStanzaTo().copyWithoutResource(); boolean subscr_changed = roster_util.updateBuddySubscription(session, pres_type, buddy); if (autoAuthorize && (pres_type == RosterAbstract.PresenceType.out_subscribed)) { roster_util.setBuddySubscription( session, RosterAbstract.SubscriptionType.both, buddy.copyWithoutResource()); } if (subscr_changed) { roster_util.updateBuddyChange(session, results, roster_util.getBuddyItem(session, buddy)); if (initial_presence != null) { if (pres_type == RosterAbstract.PresenceType.out_subscribed) { // The contact's server MUST then also send current presence to the user // from each of the contact's available resources. List<XMPPResourceConnection> activeSessions = session.getActiveSessions(); for (XMPPResourceConnection userSessions : activeSessions) { Element presence = userSessions.getPresence(); sendPresence(StanzaType.available, userSessions.getjid(), buddy, results, presence); } roster_util.setPresenceSent(session, buddy, true); } else { sendPresence(StanzaType.unavailable, session.getJID(), buddy, results, null); } } // end of if (subscr_changed) } }
/** * Method is responsible for processing outgoing subscribe and unsubscribe presence (i.e. in the * sender session manager). * * <p>Presence packet is forwarded to the destination with the JID stripped from the resource. * * <p>In case of {@code PresenceType.out_subscribe} packet type contact is added to the roster (in * case it was missing), a subscription state is being updated and, in case there was a change, a * roster push is being sent to all user resources. * * <p>In case of {@code PresenceType.out_unsubscribe} method updates contact subscription (and * generates roster push if there was a change) and if the resulting contact subscription is NONE * then contact is removed from the roster. * * @param packet packet is which being processed. * @param session user session which keeps all the user session data and also gives an access to * the user's repository data. * @param results this a collection with packets which have been generated as input packet * processing results. * @param settings this map keeps plugin specific settings loaded from the Tigase server * configuration. * @param pres_type specifies type of the presence. * @throws NoConnectionIdException * @throws NotAuthorizedException * @throws TigaseDBException */ protected void processOutSubscribe( Packet packet, XMPPResourceConnection session, Queue<Packet> results, Map<String, Object> settings, RosterAbstract.PresenceType pres_type) throws NotAuthorizedException, TigaseDBException, NoConnectionIdException { // According to RFC-3921 I must forward all these kind presence // requests, it allows to resynchronize // subscriptions in case of synchronization loss boolean subscr_changed = false; forwardPresence(results, packet, session.getJID().copyWithoutResource()); RosterAbstract.SubscriptionType current_subscription = roster_util.getBuddySubscription(session, packet.getStanzaTo()); if (pres_type == RosterAbstract.PresenceType.out_subscribe) { if (current_subscription == null) { roster_util.addBuddy(session, packet.getStanzaTo(), null, null, null); } // end of if (current_subscription == null) subscr_changed = roster_util.updateBuddySubscription(session, pres_type, packet.getStanzaTo()); if (autoAuthorize) { roster_util.setBuddySubscription( session, RosterAbstract.SubscriptionType.both, packet.getStanzaTo().copyWithoutResource()); } if (subscr_changed) { roster_util.updateBuddyChange( session, results, roster_util.getBuddyItem(session, packet.getStanzaTo())); } // end of if (subscr_changed) } else { if (log.isLoggable(Level.FINEST)) { log.log(Level.FINEST, "out_subscribe: current_subscription = " + current_subscription); } if (current_subscription != null) { subscr_changed = roster_util.updateBuddySubscription(session, pres_type, packet.getStanzaTo()); current_subscription = roster_util.getBuddySubscription(session, packet.getStanzaTo()); if (subscr_changed) { roster_util.updateBuddyChange( session, results, roster_util.getBuddyItem(session, packet.getStanzaTo())); } // end of if (subscr_changed) if (SUB_NONE.contains(current_subscription)) { roster_util.removeBuddy(session, packet.getStanzaTo()); } // end of if (current_subscription == null) } } }
/** * {@inheritDoc} <br> * <br> * Performs processing of <em>presence</em> packets and calls different methods for particular * {@link PresenceType} */ @SuppressWarnings({"unchecked", "fallthrough"}) @Override public void process( final Packet packet, final XMPPResourceConnection session, final NonAuthUserRepository repo, final Queue<Packet> results, final Map<String, Object> settings) throws XMPPException { if (session == null) { if (log.isLoggable(Level.FINE)) { log.log(Level.FINE, "Session is null, ignoring packet: {0}", packet); } return; } // end of if (session == null) if (!session.isAuthorized()) { if (log.isLoggable(Level.FINE)) { log.log(Level.FINE, "Session is not authorized, ignoring packet: {0}", packet); } return; } // Synchronization to avoid conflict with login/logout events // processed in the SessionManager asynchronously synchronized (session) { try { RosterAbstract.PresenceType pres_type = roster_util.getPresenceType(session, packet); if (pres_type == null) { log.log(Level.INFO, "Invalid presence found: {0}", packet); return; } // end of if (type == null) if (log.isLoggable(Level.FINEST)) { log.log( Level.FINEST, "{0} | {1} presence found: {2}", new Object[] {session.getBareJID().toString(), pres_type, packet}); } // All 'in' subscription presences must have a valid from address switch (pres_type) { case in_unsubscribe: case in_subscribe: case in_unsubscribed: case in_subscribed: if (packet.getStanzaFrom() == null) { if (log.isLoggable(Level.FINE)) { log.fine( "'in' subscription presence without valid 'from' address, " + "dropping packet: " + packet); } return; } if (session.isUserId(packet.getStanzaFrom().getBareJID())) { if (log.isLoggable(Level.FINE)) { log.log( Level.FINE, "''in'' subscription to myself, not allowed, returning " + "error for packet: " + "{0}", packet); } results.offer( Authorization.NOT_ALLOWED.getResponseMessage( packet, "You can not subscribe to yourself.", false)); return; } // as per http://xmpp.org/rfcs/rfc6121.html#sub // Implementation Note: When a server processes or generates an outbound // presence stanza of type "subscribe", "subscribed", "unsubscribe", // or "unsubscribed", the server MUST stamp the outgoing presence // stanza with the bare JID <localpart@domainpart> of the sending entity, // not the full JID <localpart@domainpart/resourcepart>. // // we enforce this rule also for incomming presence subscirption packets packet.initVars( packet.getStanzaFrom().copyWithoutResource(), session.getJID().copyWithoutResource()); break; case out_subscribe: case out_unsubscribe: case out_subscribed: case out_unsubscribed: // Check wheher the destination address is correct to prevent // broken/corrupted roster entries: if ((packet.getStanzaTo() == null) || packet.getStanzaTo().toString().isEmpty()) { results.offer( Authorization.JID_MALFORMED.getResponseMessage( packet, "The destination address is incorrect.", false)); return; } // According to RFC 3921 draft bis-3, both source and destination // addresses must be BareJIDs, handled by initVars(...) packet.initVars( session.getJID().copyWithoutResource(), packet.getStanzaTo().copyWithoutResource()); break; default: break; } switch (pres_type) { case out_subscribe: case out_unsubscribe: processOutSubscribe(packet, session, results, settings, pres_type); break; case out_subscribed: case out_unsubscribed: processOutSubscribed(packet, session, results, settings, pres_type); break; case in_subscribe: processInSubscribe(packet, session, results, settings, pres_type); break; case in_unsubscribe: processInUnsubscribe(packet, session, results, settings, pres_type); break; case in_subscribed: processInSubscribed(packet, session, results, settings, pres_type); break; case in_unsubscribed: processInUnsubscribed(packet, session, results, settings, pres_type); break; default: results.offer( Authorization.BAD_REQUEST.getResponseMessage( packet, "Request type is incorrect", false)); break; } // end of switch (type) } catch (NotAuthorizedException e) { log.log( Level.INFO, "Can not access user Roster, user session is not authorized yet: {0}", packet); log.log(Level.FINEST, "presence problem...", e); } catch (TigaseDBException e) { log.log(Level.WARNING, "Error accessing database for presence data: {0}", e); } // end of try-catch } }
/** * Method description * * @param packet * @param session * @param repo * @param results * @param settings * @throws XMPPException */ @Override public void process( final Packet packet, final XMPPResourceConnection session, final NonAuthUserRepository repo, final Queue<Packet> results, final Map<String, Object> settings) throws XMPPException { if (session == null) { return; } // end of if (session == null) if (!session.isAuthorized()) { results.offer( session .getAuthState() .getResponseMessage(packet, "Session is not yet authorized.", false)); return; } // end of if (!session.isAuthorized()) // TODO: test what happens if resource is bound multiple times for the same // user session. in particular if XMPPSession object removes the old // resource from the list. Element request = packet.getElement(); StanzaType type = packet.getType(); try { switch (type) { case set: String resource = request.getChildCDataStaticStr(Iq.IQ_BIND_RESOURCE_PATH); try { if ((resource == null) || resource.trim().isEmpty()) { resource = resourceDefPrefix + (++resGenerator); session.setResource(resource); } else { try { session.setResource(resource); } catch (TigaseStringprepException ex) { // User provided resource is invalid, generating different // server one log.log( Level.INFO, "Incrrect resource provided by the user: {0}, generating a " + "different one by the server.", resource); resource = resourceDefPrefix + (++resGenerator); session.setResource(resource); } } // end of if (resource == null) else } catch (TigaseStringprepException ex) { log.log( Level.WARNING, "stringprep problem with the server generated resource: {0}", resource); } packet.initVars(session.getJID(), packet.getStanzaTo()); // session.putSessionData(RESOURCE_KEY, "true"); results.offer(packet.okResult(new Element("jid", session.getJID().toString()), 1)); break; default: results.offer( Authorization.BAD_REQUEST.getResponseMessage( packet, "Bind type is incorrect", false)); break; } // end of switch (type) } catch (NotAuthorizedException e) { results.offer( session .getAuthState() .getResponseMessage(packet, "Session is not yet authorized.", false)); } // end of try-catch }