mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-22 22:32:06 +01:00
Don't use IQReplyFilter for resource binding
as the local username is only available after binding (and legacy session establishment). This makes Smack compatible again with XMPP services that use the user's JID as from attribute in the result IQ after the bind set IQ, e.g. Facebook: SENT: <iq id='sqvTK-1' type='set'> <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'> <resource>Smack</resource> </bind> </iq> RCV: <iq from='user.name.1@chat.facebook.com' id='sqvTK-1' type='result'> <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'> <jid>user.name.1@chat.facebook.com/Smack</jid> </bind> </iq> Fixes SMACK-590
This commit is contained in:
parent
076c7d0b81
commit
6caf2cbdb5
5 changed files with 60 additions and 41 deletions
|
@ -42,6 +42,7 @@ import org.jivesoftware.smack.compression.XMPPInputOutputStream;
|
||||||
import org.jivesoftware.smack.debugger.SmackDebugger;
|
import org.jivesoftware.smack.debugger.SmackDebugger;
|
||||||
import org.jivesoftware.smack.filter.IQReplyFilter;
|
import org.jivesoftware.smack.filter.IQReplyFilter;
|
||||||
import org.jivesoftware.smack.filter.PacketFilter;
|
import org.jivesoftware.smack.filter.PacketFilter;
|
||||||
|
import org.jivesoftware.smack.filter.PacketIDFilter;
|
||||||
import org.jivesoftware.smack.packet.Bind;
|
import org.jivesoftware.smack.packet.Bind;
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
import org.jivesoftware.smack.packet.Packet;
|
import org.jivesoftware.smack.packet.Packet;
|
||||||
|
@ -431,15 +432,30 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Bind bindResource = new Bind();
|
// Resource binding, see RFC6120 7.
|
||||||
bindResource.setResource(resource);
|
// Note that we can not use IQReplyFilter here, since the users full JID is not yet
|
||||||
|
// available. It will become available right after the resource has been successfully bound.
|
||||||
Bind response = (Bind) createPacketCollectorAndSend(bindResource).nextResultOrThrow();
|
Bind bindResource = Bind.newSet(resource);
|
||||||
|
PacketCollector packetCollector = createPacketCollector(new PacketIDFilter(bindResource));
|
||||||
|
try {
|
||||||
|
sendPacket(bindResource);
|
||||||
|
} catch (NotConnectedException e) {
|
||||||
|
packetCollector.cancel();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
Bind response = packetCollector.nextResultOrThrow();
|
||||||
String userJID = response.getJid();
|
String userJID = response.getJid();
|
||||||
|
|
||||||
if (sessionSupported && !getConfiguration().isLegacySessionDisabled()) {
|
if (sessionSupported && !getConfiguration().isLegacySessionDisabled()) {
|
||||||
Session session = new Session();
|
Session session = new Session();
|
||||||
createPacketCollectorAndSend(session).nextResultOrThrow();
|
packetCollector = createPacketCollector(new PacketIDFilter(session));
|
||||||
|
try {
|
||||||
|
sendPacket(session);
|
||||||
|
} catch (NotConnectedException e) {
|
||||||
|
packetCollector.cancel();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
packetCollector.nextResultOrThrow();
|
||||||
}
|
}
|
||||||
return userJID;
|
return userJID;
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,9 +139,10 @@ public class PacketCollector {
|
||||||
*
|
*
|
||||||
* @return the next available packet.
|
* @return the next available packet.
|
||||||
*/
|
*/
|
||||||
public Packet nextResult(long timeout) {
|
@SuppressWarnings("unchecked")
|
||||||
|
public <P extends Packet> P nextResult(long timeout) {
|
||||||
try {
|
try {
|
||||||
return resultQueue.poll(timeout, TimeUnit.MILLISECONDS);
|
return (P) resultQueue.poll(timeout, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
catch (InterruptedException e) {
|
catch (InterruptedException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
@ -157,7 +158,7 @@ public class PacketCollector {
|
||||||
* @throws XMPPErrorException in case an error response.
|
* @throws XMPPErrorException in case an error response.
|
||||||
* @throws NoResponseException if there was no response from the server.
|
* @throws NoResponseException if there was no response from the server.
|
||||||
*/
|
*/
|
||||||
public Packet nextResultOrThrow() throws NoResponseException, XMPPErrorException {
|
public <P extends Packet> P nextResultOrThrow() throws NoResponseException, XMPPErrorException {
|
||||||
return nextResultOrThrow(connection.getPacketReplyTimeout());
|
return nextResultOrThrow(connection.getPacketReplyTimeout());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,8 +171,8 @@ public class PacketCollector {
|
||||||
* @throws NoResponseException if there was no response from the server.
|
* @throws NoResponseException if there was no response from the server.
|
||||||
* @throws XMPPErrorException in case an error response.
|
* @throws XMPPErrorException in case an error response.
|
||||||
*/
|
*/
|
||||||
public Packet nextResultOrThrow(long timeout) throws NoResponseException, XMPPErrorException {
|
public <P extends Packet> P nextResultOrThrow(long timeout) throws NoResponseException, XMPPErrorException {
|
||||||
Packet result = nextResult(timeout);
|
P result = nextResult(timeout);
|
||||||
cancel();
|
cancel();
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
throw new NoResponseException();
|
throw new NoResponseException();
|
||||||
|
|
|
@ -81,14 +81,13 @@ public class IQReplyFilter implements PacketFilter {
|
||||||
* @param iqPacket An IQ request. Filter for replies to this packet.
|
* @param iqPacket An IQ request. Filter for replies to this packet.
|
||||||
*/
|
*/
|
||||||
public IQReplyFilter(IQ iqPacket, XMPPConnection conn) {
|
public IQReplyFilter(IQ iqPacket, XMPPConnection conn) {
|
||||||
to = iqPacket.getTo();
|
if (iqPacket.getTo() != null) {
|
||||||
if (conn.getUser() == null) {
|
to = iqPacket.getTo().toLowerCase(Locale.US);
|
||||||
// We have not yet been assigned a username, this can happen if the connection is
|
|
||||||
// in an early stage, i.e. when performing the SASL auth.
|
|
||||||
local = null;
|
|
||||||
} else {
|
} else {
|
||||||
local = conn.getUser().toLowerCase(Locale.US);
|
to = null;
|
||||||
}
|
}
|
||||||
|
local = conn.getUser().toLowerCase(Locale.US);
|
||||||
|
|
||||||
server = conn.getServiceName().toLowerCase(Locale.US);
|
server = conn.getServiceName().toLowerCase(Locale.US);
|
||||||
packetId = iqPacket.getPacketID();
|
packetId = iqPacket.getPacketID();
|
||||||
|
|
||||||
|
@ -98,11 +97,10 @@ public class IQReplyFilter implements PacketFilter {
|
||||||
fromFilter = new OrFilter();
|
fromFilter = new OrFilter();
|
||||||
fromFilter.addFilter(FromMatchesFilter.createFull(to));
|
fromFilter.addFilter(FromMatchesFilter.createFull(to));
|
||||||
if (to == null) {
|
if (to == null) {
|
||||||
if (local != null)
|
|
||||||
fromFilter.addFilter(FromMatchesFilter.createBare(local));
|
fromFilter.addFilter(FromMatchesFilter.createBare(local));
|
||||||
fromFilter.addFilter(FromMatchesFilter.createFull(server));
|
fromFilter.addFilter(FromMatchesFilter.createFull(server));
|
||||||
}
|
}
|
||||||
else if (local != null && to.toLowerCase(Locale.US).equals(XmppStringUtils.parseBareAddress(local))) {
|
else if (to.equals(XmppStringUtils.parseBareAddress(local))) {
|
||||||
fromFilter.addFilter(FromMatchesFilter.createFull(null));
|
fromFilter.addFilter(FromMatchesFilter.createFull(null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,39 +32,44 @@ import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
*/
|
*/
|
||||||
public class Bind extends IQ {
|
public class Bind extends IQ {
|
||||||
|
|
||||||
private String resource = null;
|
public static final String ELEMENT = "bind";
|
||||||
private String jid = null;
|
public static final String NAMESPACE = "urn:ietf:params:xml:ns:xmpp-bind";
|
||||||
|
|
||||||
public Bind() {
|
private final String resource;
|
||||||
setType(IQ.Type.set);
|
private final String jid;
|
||||||
|
|
||||||
|
public Bind(String resource, String jid) {
|
||||||
|
this.resource = resource;
|
||||||
|
this.jid = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getResource() {
|
public String getResource() {
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setResource(String resource) {
|
|
||||||
this.resource = resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getJid() {
|
public String getJid() {
|
||||||
return jid;
|
return jid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setJid(String jid) {
|
|
||||||
this.jid = jid;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CharSequence getChildElementXML() {
|
public XmlStringBuilder getChildElementXML() {
|
||||||
XmlStringBuilder xml = new XmlStringBuilder();
|
XmlStringBuilder xml = new XmlStringBuilder();
|
||||||
xml.halfOpenElement("bind");
|
|
||||||
xml.xmlnsAttribute("urn:ietf:params:xml:ns:xmpp-bind");
|
xml.halfOpenElement(ELEMENT).xmlnsAttribute(NAMESPACE).rightAngelBracket();
|
||||||
xml.rightAngelBracket();
|
|
||||||
xml.optElement("resource", resource);
|
xml.optElement("resource", resource);
|
||||||
xml.optElement("jid", jid);
|
xml.optElement("jid", jid);
|
||||||
xml.closeElement("bind");
|
xml.closeElement(ELEMENT);
|
||||||
|
|
||||||
return xml;
|
return xml;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Bind newSet(String resource) {
|
||||||
|
Bind bind = new Bind(resource, null);
|
||||||
|
bind.setType(IQ.Type.set);
|
||||||
|
return bind;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bind newResult(String jid) {
|
||||||
|
return new Bind(null, jid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -654,24 +654,23 @@ public class PacketParserUtils {
|
||||||
|
|
||||||
private static Bind parseResourceBinding(XmlPullParser parser) throws IOException,
|
private static Bind parseResourceBinding(XmlPullParser parser) throws IOException,
|
||||||
XmlPullParserException {
|
XmlPullParserException {
|
||||||
Bind bind = new Bind();
|
Bind bind = null;
|
||||||
boolean done = false;
|
boolean done = false;
|
||||||
while (!done) {
|
while (!done) {
|
||||||
int eventType = parser.next();
|
int eventType = parser.next();
|
||||||
if (eventType == XmlPullParser.START_TAG) {
|
if (eventType == XmlPullParser.START_TAG) {
|
||||||
if (parser.getName().equals("resource")) {
|
if (parser.getName().equals("resource")) {
|
||||||
bind.setResource(parser.nextText());
|
bind = Bind.newSet(parser.nextText());
|
||||||
}
|
}
|
||||||
else if (parser.getName().equals("jid")) {
|
else if (parser.getName().equals("jid")) {
|
||||||
bind.setJid(parser.nextText());
|
bind = Bind.newResult(parser.nextText());
|
||||||
}
|
}
|
||||||
} else if (eventType == XmlPullParser.END_TAG) {
|
} else if (eventType == XmlPullParser.END_TAG) {
|
||||||
if (parser.getName().equals("bind")) {
|
if (parser.getName().equals(Bind.ELEMENT)) {
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bind;
|
return bind;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue