[Standards] XMPP-IM - presence subscription handling

Pavel Simerda pavlix at pavlix.net
Tue Feb 24 19:22:29 UTC 2009


On Tue, 24 Feb 2009 16:53:30 +0100
Jiří Zárevúcký <zarevucky.jiri at gmail.com> wrote:

> Hello all.
> 
> I've been thinking about the current subscription management in the
> XMPP-IM for some time now. I think it's not very well designed.

It has some flaws. See my post about subscriptions, please.

> For example, there's an obvious redundancy in the roster pushes and
> subscription stanzas. For (almost) every subscription update /
> request, there is a presence stanza and a roster push. But that only
> applies to the contact, who receives the change. Also, the "ask"
> attribute looks like a maimed boolean and roster pushes do not contain
> all the state information - inbound request is missing.

Hmmm.

> Even though the client can track most of the changes by tracking
> roster pushes and subscription stanzas, there is one change client can
> never track. When there is an inbound subscription request with no
> item and user declines it, other resources get no push and no presence
> stanza - no notification. That is not really a big problem, but all
> this inconsistency in pushes and presence stanzas makes it all seem
> very chaotic and untidy.

Well, yes.

> Originally, I wanted to propose modifying roster pushes so they
> contain all the state information (including eventual inbound
> subscription request message), essentially leaving
> subscription-managing presence stanzas only as the mean of requesting
> the change, not presenting it to the other entity or the other
> resources. Then one thing occured to me. Do we really need a separate
> subscription handling for inbound and outbound presences? Users
> generally don't want it separate. Users want mutual subscription. Is
> there ever need to have one-side subscription?

This would need a clean redesign. Not just a bunch of ideas.
 
> Providing mechanism for just a mutual subscription, where there would
> be only both-direction or pending or no subscription at all, would
> immensely simplify things for both users and implementers.

This would break things even further.... see my other post and consider
what this change will do with the authority. Bidi-only association
seems too simple to fit in the common needs IMO.

> Yes, I
> agree that immediate effect would be increasing complexity and need of
> additional effort to maintain backward compatibility. That would be a
> tricky task, but I believe that with proper interoperability rules, it
> would be possible to make transition relatively painless. I believe
> that in a long run, such change would be a huge improvement.

You'd need to know if the transition gives or takes.

> So, in case you are interested in this idea, I will continue with some
> semantics I have on my mind. Otherwise, just tell me why do you think
> it is not possible / feasible / wanted to implement it. I'm pretty
> sure there is some hidden problem with this I don't realize. I suppose
> many of you won't take me too seriously, since it would require too
> massive change to the core protocol, but I'd appreciate if you thought
> about it a bit. Thanks for any feedback.

I believe it is impossible.

But please provide your-words comparison.... and what it would bring. I
might try to be the devil's advocate and add problems it would make :D.

Pavel

> 
> 
> 
> <item/> element would have the children defined in the current
> XMPP-IM except: • there is no "ask" attribute
>   • the "subscription" attribute has following values
>     ∘ none - means there is no subscription sharing
>     ∘ pending-in - means the contact requests subscription sharing
>     ∘ pending-out - means the user requests subscription sharing
>     ∘ subscribed - means user is sharing presences with the contact
>   • there are three new optional child elements:
>     ∘ "request", whose character data is the message associated with
> the subscription request
>     ∘ "ghost" (empty), which would work as a marker for items, that
> are not yet in the roster (just holding information about the
> request).
>     ∘ "remove" (empty) - same as the subscription="remove" in the
> current specification; it's changed to a separate element because the
> subscription attribute should only contain information about the
> subscription, not a removal request
> 
> As for the <presence/> stanza:
>   • "unsubscribed" and "subscribed" types are removed, since they are
> no longer needed
> 
> === Subscription request:
> 
> Contact requesting the subscription would send the presence stanza as
> usual:
> 
> <presence type="subscribe" to="user at whatever.com">
> 	<status>Please subscribe me.</status>
> </presence>
> 
> The stanza would be delivered to the server and possibly forwarded to
> the contact's server, but it would NOT be delivered to the contact
> itself. Instead, contact would get an updated item.
> 
> Scenario 1: contact is already in the roster
> 
> <iq type="set" id="push1">
> 	<query xmlns="jabber:iq:roster">
> 		<item jid="contact at whatever.com"
> subscription="pending-in"> <request>Please subscribe me.</request>
> 			<group>Friends</group>
> 		</item>
> 	</query>
> </iq>
> 
> Success case:
> 
> <presence type="subscribe" to="contact at whatever.com" />
> 
> When there is a pending request and user includes the "status" child,
> it is ignored.
> Server then updates subscription.
> 
> <iq type="set" id="push2">
> 	<query xmlns="jabber:iq:roster">
> 		<item jid="contact at whatever.com"
> subscription="subscribed"> <group>Friends</group>
> 		</item>
> 	</query>
> </iq>
> 
> Failure case:
> 
> <presence type="unsubscribe" to="contact at whatever.com" />
> 
> Server responds:
> 
> <iq type="set" id="push2">
> 	<query xmlns="jabber:iq:roster">
> 		<item jid="contact at whatever.com" subscription="none">
> 			<group>Friends</group>
> 		</item>
> 	</query>
> </iq>
> 
> Scenario 2: contact in not in the roster
> 
> Contact is added automatically to the roster with the "ghost" marker.
> 
> <iq type="set" id="push1">
> 	<query xmlns="jabber:iq:roster">
> 		<item jid="contact at whatever.com"
> subscription="pending-in"> <request>Please subscribe me.</request>
> 			<ghost />
> 		</item>
> 	</query>
> </iq>
> 
> Success case:
> 
> <presence type="subscribe" to="contact at whatever.com" />
> 
> <iq type="set" id="push2">
> 	<query xmlns="jabber:iq:roster">
> 		<item jid="contact at whatever.com"
> subscription="subscribed" /> </query>
> </iq>
> 
> Failure case:
> 
> <presence type="unsubscribe" to="contact at whatever.com" />
> 
> <iq type="set" id="push2">
> 	<query xmlns="jabber:iq:roster">
> 		<item jid="contact at whatever.com">
> 			<remove />
> 		</item>
> 	</query>
> </iq>
> 
> Note that "ghost" item is promoted to a normal item upon success and
> removed upon failure. If the contact is added via a roster set while
> it is in "ghost" state, it is promoted and the subscription state is
> preserved. Ghost item can't be removed by a removing roster set,
> because it technically isn't in the roster.
> 
> Scenario 3: contact withdraws it's sharing proposal
> 
> <presence type="unsubscribe" to="user at whatever.com" />
> 
> The response is then exactly the same as if the user declined it.
> Note: I think it is not necessary for client to know, who cancelled
> the request. User knows, whether it was him or not.
> Note2: Perhaps it would be wiser to disallow this, as it would open
> the possibility of request spamming. Or perhaps just encourage
> aggressive rate-limiting for requests.
> 
> === Cancelling presence sharing
> 
> Server:
> <iq type="set" id="push1">
> 	<query xmlns="jabber:iq:roster">
> 		<item jid="contact at whatever.com"
> subscription="subscribed" /> </query>
> </iq>
> 
> User:
> <presence type="unsubscribe" to="contact at whatever.com" />
> 
> Server:
> <iq type="set" id="push2">
> 	<query xmlns="jabber:iq:roster">
> 		<item jid="contact at whatever.com"
> subscription="none" /> </query>
> </iq>
> 
> === Outbound subscription request
> 
> Server:
> <iq type="set" id="push1">
> 	<query xmlns="jabber:iq:roster">
> 		<item jid="contact at whatever.com"
> subscription="none" /> </query>
> </iq>
> 
> User:
> <presence type="subscribe" to="contact at whatever.com"><status>My
> request</status></presence>
> 
> Server would change item, note how it contains it's own message:
> <iq type="set" id="push2">
> 	<query xmlns="jabber:iq:roster">
> 		<item jid="contact at whatever.com"
> subscription="pending-out"> <request>My request</request>
> 		</item>
> 	</query>
> </iq>
> 
> If the contact wasn't in roster prior to the outbound request, it
> would contain the "ghost" mark, which would work as described earlier.
> 
> === Summary
> 
> So, subscribe and unsubscribe presence stanzas are never sent from
> server to client. They are only sent from client to server as a
> request and from server to server as an update. All the updates for
> clients are provided via roster pushes and the semantics are clear and
> easy to understand. Subscription is defined for both directions at the
> same time. What do you think?


-- 

Freelance consultant and trainer
in networking, communications and security.

Web: http://www.pavlix.net/
Jabber, Mail: pavlix(at)pavlix.net
OpenID: pavlix.net



More information about the Standards mailing list