use of com.googlecode.asmack.XmppMalformedException in project AsmackService by rtreffer.
the class RosterResultReceiver method onReceive.
/**
* Receive a stanza intent, check for roster entries and write results to
* the result queue.
*/
public void onReceive(Context context, Intent intent) {
Stanza stanza = intent.getParcelableExtra("stanza");
if (stanza.getName() == null || stanza.getVia() == null || stanza.getAttribute("type") == null) {
return;
}
if (!"iq".equals(stanza.getName())) {
return;
}
if (!stanza.getVia().startsWith(account.name + "/")) {
return;
}
if (!"result".equals(stanza.getAttribute("type").getValue())) {
return;
}
try {
Node node = stanza.getDocumentNode();
Node roster = XMLUtils.getFirstChild(node, "jabber:iq:roster", "query");
if (roster == null) {
return;
}
rosterQueue.put(roster);
} catch (XmppMalformedException e) {
Log.w(TAG, "PLEASE REPORT", e);
} catch (InterruptedException e) {
Log.w(TAG, "PLEASE REPORT", e);
}
}
use of com.googlecode.asmack.XmppMalformedException in project AsmackService by rtreffer.
the class DiscoReceiver method onReceive.
/**
* Called on incoming stanzas and replies on service discovery requests.
* @param context The current context.
* @param intent The stanza intent.
*/
@Override
public void onReceive(Context context, Intent intent) {
Stanza stanza = intent.getParcelableExtra("stanza");
// only accept IQ stanzas
if (!"iq".equals(stanza.getName())) {
return;
}
// of type="get"
if (!"get".equals(stanza.getAttributeValue("type"))) {
return;
}
// from / to / id are mandatory
Attribute from = stanza.getAttribute("from");
Attribute to = stanza.getAttribute("to");
Attribute id = stanza.getAttribute("id");
if (id == null || from == null || to == null) {
return;
}
try {
Node node = stanza.getDocumentNode();
Node query = XMLUtils.getFirstChild(node, "http://jabber.org/protocol/disco#info", "query");
if (query == null || !query.hasAttributes()) {
return;
}
Node discoAttributeNode = query.getAttributes().getNamedItem("node");
String discoNode = null;
if (discoAttributeNode != null) {
discoNode = discoAttributeNode.getTextContent();
}
// we got a disco, reply
StringBuilder payload = new StringBuilder("<iq type='result'");
payload.append(" from='");
payload.append(XMLUtils.xmlEscape(to.getValue()));
payload.append("' to='");
payload.append(XMLUtils.xmlEscape(from.getValue()));
payload.append("'>");
payload.append("<query xmlns='");
payload.append("http://jabber.org/protocol/disco#info");
if (discoNode != null) {
payload.append("' node='");
payload.append(XMLUtils.xmlEscape(discoNode));
}
payload.append("'>");
String myJid = XMPPUtils.getBareJid(to.getValue());
for (XmppIdentity identity : Database.getIdentities(context, myJid, null)) {
payload.append("<identity");
if (identity.getCategory().length() > 0) {
payload.append(" category='");
payload.append(XMLUtils.xmlEscape(identity.getCategory()));
payload.append('\'');
}
if (identity.getType().length() > 0) {
payload.append(" type='");
payload.append(XMLUtils.xmlEscape(identity.getType()));
payload.append('\'');
}
if (identity.getLang().length() > 0) {
payload.append(" lang='");
payload.append(XMLUtils.xmlEscape(identity.getLang()));
payload.append('\'');
}
if (identity.getName().length() > 0) {
payload.append(" name='");
payload.append(XMLUtils.xmlEscape(identity.getName()));
payload.append('\'');
}
payload.append("/>");
}
for (String feature : Database.getFeatures(context, myJid, null)) {
payload.append("<feature var='");
payload.append(XMLUtils.xmlEscape(feature));
payload.append("'/>");
}
payload.append("</query></iq>");
Stanza discoReply = new Stanza("iq", "", XMPPUtils.getBareJid(to.getValue()), payload.toString(), Arrays.asList(new Attribute[] { id }));
intent = new Intent();
intent.setAction(XmppTransportService.XMPP_STANZA_SEND_INTENT);
intent.putExtra("stanza", discoReply);
intent.addFlags(Intent.FLAG_FROM_BACKGROUND);
context.sendBroadcast(intent, XmppTransportService.XMPP_STANZA_SEND_INTENT);
} catch (XmppMalformedException e) {
// Impossible
Log.e("AsmackService", "Please report (impossible condition)", e);
}
}
use of com.googlecode.asmack.XmppMalformedException in project AsmackService by rtreffer.
the class FeatureNegotiationEngine method open.
/*
* From RFC 3920-bis-13#page-26
* 4.2.7. Flow Chart
*
* +------------+
* | open TCP |
* | connection |
* +------------+
* |
* | <------------ open() starts here
* |
* v
* +---------------+
* | send initial |<-------------------------+
* | stream header | ^
* +---------------+ |
* | |
* v |
* +------------------+ |
* | receive response | |
* | stream header | |
* +------------------+ |
* | |
* v |
* +----------------+ |
* | receive stream | |
* +------------------>| features | |
* ^ +----------------+ |
* | | |
* | v |
* | +<-----------------+ |
* | | |
* | {empty?} ----> {all voluntary?} ----> {some mandatory?} |
* | | no | no | |
* | | yes | yes | yes |
* | | v v |
* | | +---------------+ +----------------+ |
* | | | MAY negotiate | | MUST negotiate | |
* | | | any or none | | one feature | |
* | | +---------------+ +----------------+ |
* | | | | |
* | v v | |
* | +----------+ +-----------+ | |
* | | process |<-----| negotiate | | |
* | | complete | no | a feature | | |
* | +----------+ +-----------+ | |
* | | | |
* | yes | | |
* | v v |
* | +--------->+<---------+ |
* | | |
* | v |
* +<-------------------------- {restart mandatory?} ------------>+
* no yes
*
* The "open" method starts directly after opening the TCP streams,
* negotiates the connection and returns true if the xmpp stream is ready
* for a bind.
*
* The usual way to bind is
* if (streamEngine.open(account)) {
* String resource = streamEngine.bind(account.getResource);
* }
*
* Interresting and available features that require restarts:
* - SASL
* - TLS
* - Compression
*/
/**
* <p>Open a connection for a given account. This will run the full
* negotiation with the following precedence:
* <ol>
* <li>TLS (if available)</li>
* <li>Compression (if available)</li>
* <li>SASL</li>
* <ol></p>
*
* <p><b>Note:</b> Servers should not offer compression befor SASL is
* completed. This is not violated by the rule, mobile devices love xml
* compression, thus a higher preference. Everything will work as expected
* when compression is offered after SASL.</p>
*
* <p>This method requires a call to bind (if you wish to bind) afterwards.
* </p>
*
* @param account XmppAccount The account used for negotiation.
* @throws XmppException In case of an error.
*/
public void open(XmppAccount account) throws XmppException {
boolean rerun = true;
boolean canBind = false;
while (rerun) {
try {
rerun = false;
xmppOutput.open(XMPPUtils.getDomain(account.getJid()), null);
xmppInput.readOpening();
Node features = null;
do {
Node stanza = xmppInput.nextStanza().getDocumentNode();
if (XMLUtils.isInstance(stanza, "http://etherx.jabber.org/streams", "features")) {
features = stanza;
}
} while (features == null);
// check basic stream features
rosterVersioningSupported |= XMLUtils.hasChild(features, "urn:xmpp:features:rosterver", "ver");
sessionsSupported |= XMLUtils.hasChild(features, "urn:ietf:params:xml:ns:xmpp-session", "session");
canBind |= XMLUtils.hasChild(features, "urn:ietf:params:xml:ns:xmpp-bind", "bind");
hasTLS = XMLUtils.hasChild(features, "urn:ietf:params:xml:ns:xmpp-tls", "starttls");
Node compression = XMLUtils.getFirstChild(features, "http://jabber.org/features/compress", "compression");
if (compression != null) {
NodeList methods = compression.getChildNodes();
for (int i = 0, l = methods.getLength(); i < l; i++) {
Node method = methods.item(i);
if (method.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
if (!"method".equals(method.getNodeName())) {
continue;
}
String methodName = method.getFirstChild().getNodeValue();
methodName = methodName.trim();
compressionSupported |= "zlib".equals(methodName);
}
}
Node saslMechanisms = XMLUtils.getFirstChild(features, "urn:ietf:params:xml:ns:xmpp-sasl", "mechanisms");
SASLSupported |= saslMechanisms != null;
if (hasTLS && !secure) {
// enable tls
xmppOutput.sendUnchecked("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
boolean startTLS = XMLUtils.isInstance(xmppInput.nextStanza().getDocumentNode(), "urn:ietf:params:xml:ns:xmpp-tls", "proceed");
if (startTLS) {
startTLS();
secure = true;
rerun = true;
continue;
}
}
if (compressionSupported && !compressed && ZLibOutputStream.SUPPORTED) {
startCompress();
rerun = true;
continue;
}
if (SASLSupported && !authenticated) {
if (saslLogin(saslMechanisms, account)) {
authenticated = true;
rerun = true;
continue;
}
}
} catch (IllegalArgumentException e) {
throw new XmppMalformedException("Can't negotiate features", e);
} catch (IllegalStateException e) {
throw new XmppMalformedException("Can't negotiate features", e);
} catch (IOException e) {
throw new XmppTransportException("Can't negotiate features", e);
} catch (XmlPullParserException e) {
throw new XmppMalformedException("Can't negotiate features", e);
} catch (NoSuchAlgorithmException e) {
// Should never happen - TLS not available?
throw new XmppTransportException("Can't enable tls", e);
} catch (KeyManagementException e) {
throw new XmppTransportException("Can't trust server", e);
}
}
if (!canBind) {
throw new XmppTransportException("Couldn't reach bind state.");
}
}
use of com.googlecode.asmack.XmppMalformedException in project AsmackService by rtreffer.
the class FeatureNegotiationEngine method saslLogin.
/**
* Run a sasl based login. Most sals parts are handled by
* {@link SASLEngine#login(XmppInputStream, XmppOutputStream, java.util.Set, XmppAccount)}.
* @param saslMechanisms Node The DOM node of the sasl mechanisms.
* @param account XmppAccount The xmpp account to use.
* @return boolean True on success. False on failore.
* @throws XmppException On critical connection errors-
*/
protected boolean saslLogin(Node saslMechanisms, XmppAccount account) throws XmppException {
NodeList nodes = saslMechanisms.getChildNodes();
HashSet<String> methods = new HashSet<String>(13);
for (int i = 0, l = nodes.getLength(); i < l; i++) {
Node node = nodes.item(i);
if (!XMLUtils.isInstance(node, null, "mechanism")) {
continue;
}
methods.add(node.getFirstChild().getNodeValue().toUpperCase().trim());
}
if (SASLEngine.login(xmppInput, xmppOutput, methods, account)) {
xmppInput.detach();
try {
xmppOutput.detach();
xmppInput.attach(inputStream);
xmppOutput.attach(outputStream, true, false);
} catch (IllegalArgumentException e) {
throw new XmppMalformedException("Please report", e);
} catch (IllegalStateException e) {
throw new XmppMalformedException("Please report", e);
} catch (IOException e) {
throw new XmppTransportException("Couldn't restart connection", e);
}
return true;
}
return false;
}
use of com.googlecode.asmack.XmppMalformedException in project AsmackService by rtreffer.
the class FeatureNegotiationEngine method bind.
/**
* Bind a given resource, probably resuming an old session.
* @param resource String The preferred resource string.
* @return String The actual resource string.
* @throws XmppException On Error.
*/
public String bind(String resource) throws XmppException {
try {
if (!TextUtils.isEmpty(resource)) {
xmppOutput.sendUnchecked("<iq type=\"set\" id=\"bind_1\">" + "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\">" + "<resource>" + resource + "</resource>" + "</bind>" + "</iq>");
} else {
xmppOutput.sendUnchecked("<iq type=\"set\" id=\"bind_1\">" + "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\">" + "</bind>" + "</iq>");
}
Stanza stanza = xmppInput.nextStanza();
Node node = XMLUtils.getDocumentNode(stanza.getXml());
Node bind = XMLUtils.getFirstChild(node, "urn:ietf:params:xml:ns:xmpp-bind", "bind");
Node jid = XMLUtils.getFirstChild(bind, null, "jid");
if (sessionsSupported) {
startSession();
}
return jid.getTextContent();
} catch (IllegalArgumentException e) {
throw new XmppMalformedException("bind malformed", e);
} catch (IllegalStateException e) {
throw new XmppMalformedException("bind malformed", e);
} catch (SAXException e) {
throw new XmppMalformedException("bind malformed", e);
}
}
Aggregations