From c6440aab12460490ef8e9167eac0b515e04f1cdf Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 9 Feb 2014 14:10:52 +0100 Subject: carbons --- src/de/gultsch/chat/xmpp/XmppConnection.java | 198 ++++++++++++++++++--------- 1 file changed, 133 insertions(+), 65 deletions(-) (limited to 'src/de/gultsch/chat/xmpp') diff --git a/src/de/gultsch/chat/xmpp/XmppConnection.java b/src/de/gultsch/chat/xmpp/XmppConnection.java index 772c2430..337d8c7d 100644 --- a/src/de/gultsch/chat/xmpp/XmppConnection.java +++ b/src/de/gultsch/chat/xmpp/XmppConnection.java @@ -7,7 +7,9 @@ import java.math.BigInteger; import java.net.Socket; import java.net.UnknownHostException; import java.security.SecureRandom; +import java.util.HashSet; import java.util.Hashtable; +import java.util.List; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; @@ -33,23 +35,24 @@ public class XmppConnection implements Runnable { private PowerManager.WakeLock wakeLock; private SecureRandom random = new SecureRandom(); - + private Socket socket; private XmlReader tagReader; private TagWriter tagWriter; private boolean isTlsEncrypted = false; private boolean isAuthenticated = false; - //private boolean shouldUseTLS = false; + // private boolean shouldUseTLS = false; private boolean shouldConnect = true; private boolean shouldBind = true; private boolean shouldAuthenticate = true; private Element streamFeatures; - + private HashSet discoFeatures = new HashSet(); + private static final int PACKET_IQ = 0; private static final int PACKET_MESSAGE = 1; private static final int PACKET_PRESENCE = 2; - + private Hashtable iqPacketCallbacks = new Hashtable(); private OnPresencePacketReceived presenceListener = null; private OnIqPacketReceived unregisteredIqListener = null; @@ -69,9 +72,10 @@ public class XmppConnection implements Runnable { Bundle namePort = DNSHelper.getSRVRecord(account.getServer()); String srvRecordServer = namePort.getString("name"); int srvRecordPort = namePort.getInt("port"); - if (srvRecordServer!=null) { - Log.d(LOGTAG,account.getJid()+": using values from dns "+srvRecordServer+":"+srvRecordPort); - socket = new Socket(srvRecordServer,srvRecordPort); + if (srvRecordServer != null) { + Log.d(LOGTAG, account.getJid() + ": using values from dns " + + srvRecordServer + ":" + srvRecordPort); + socket = new Socket(srvRecordServer, srvRecordPort); } else { socket = new Socket(account.getServer(), 5222); } @@ -96,30 +100,30 @@ public class XmppConnection implements Runnable { } } catch (UnknownHostException e) { account.setStatus(Account.STATUS_SERVER_NOT_FOUND); - if (statusListener!=null) { + if (statusListener != null) { statusListener.onStatusChanged(account); } return; } catch (IOException e) { - Log.d(LOGTAG,"bla "+e.getMessage()); + Log.d(LOGTAG, "bla " + e.getMessage()); if (shouldConnect) { - Log.d(LOGTAG,account.getJid()+": connection lost"); + Log.d(LOGTAG, account.getJid() + ": connection lost"); account.setStatus(Account.STATUS_OFFLINE); - if (statusListener!=null) { + if (statusListener != null) { statusListener.onStatusChanged(account); } } } catch (XmlPullParserException e) { - Log.d(LOGTAG,"xml exception "+e.getMessage()); + Log.d(LOGTAG, "xml exception " + e.getMessage()); return; } - + } @Override public void run() { shouldConnect = true; - while(shouldConnect) { + while (shouldConnect) { connect(); try { if (shouldConnect) { @@ -130,7 +134,7 @@ public class XmppConnection implements Runnable { e.printStackTrace(); } } - Log.d(LOGTAG,"end run"); + Log.d(LOGTAG, "end run"); } private void processStream(Tag currentTag) throws XmlPullParserException, @@ -145,17 +149,18 @@ public class XmppConnection implements Runnable { switchOverToTls(nextTag); } else if (nextTag.isStart("success")) { isAuthenticated = true; - Log.d(LOGTAG,account.getJid()+": read success tag in stream. reset again"); + Log.d(LOGTAG, account.getJid() + + ": read success tag in stream. reset again"); tagReader.readTag(); tagReader.reset(); sendStartStream(); processStream(tagReader.readTag()); break; - } else if(nextTag.isStart("failure")) { + } else if (nextTag.isStart("failure")) { Element failure = tagReader.readElement(nextTag); - Log.d(LOGTAG,"read failure element"+failure.toString()); + Log.d(LOGTAG, "read failure element" + failure.toString()); account.setStatus(Account.STATUS_UNAUTHORIZED); - if (statusListener!=null) { + if (statusListener != null) { statusListener.onStatusChanged(account); } tagWriter.writeTag(Tag.end("stream")); @@ -173,13 +178,14 @@ public class XmppConnection implements Runnable { } if (account.getStatus() == Account.STATUS_ONLINE) { account.setStatus(Account.STATUS_OFFLINE); - if (statusListener!=null) { + if (statusListener != null) { statusListener.onStatusChanged(account); } } } - - private Element processPacket(Tag currentTag, int packetType) throws XmlPullParserException, IOException { + + private Element processPacket(Tag currentTag, int packetType) + throws XmlPullParserException, IOException { Element element; switch (packetType) { case PACKET_IQ: @@ -196,7 +202,7 @@ public class XmppConnection implements Runnable { } element.setAttributes(currentTag.getAttributes()); Tag nextTag = tagReader.readTag(); - while(!nextTag.isEnd(element.getName())) { + while (!nextTag.isEnd(element.getName())) { if (!nextTag.isNo()) { Element child = tagReader.readElement(nextTag); element.addChild(child); @@ -205,44 +211,49 @@ public class XmppConnection implements Runnable { } return element; } - - private IqPacket processIq(Tag currentTag) throws XmlPullParserException, IOException { - IqPacket packet = (IqPacket) processPacket(currentTag,PACKET_IQ); + private IqPacket processIq(Tag currentTag) throws XmlPullParserException, + IOException { + IqPacket packet = (IqPacket) processPacket(currentTag, PACKET_IQ); if (iqPacketCallbacks.containsKey(packet.getId())) { - iqPacketCallbacks.get(packet.getId()).onIqPacketReceived(account,packet); + iqPacketCallbacks.get(packet.getId()).onIqPacketReceived(account, + packet); iqPacketCallbacks.remove(packet.getId()); } else if (this.unregisteredIqListener != null) { - this.unregisteredIqListener.onIqPacketReceived(account,packet); + this.unregisteredIqListener.onIqPacketReceived(account, packet); } return packet; } - - private void processMessage(Tag currentTag) throws XmlPullParserException, IOException { - MessagePacket packet = (MessagePacket) processPacket(currentTag, PACKET_MESSAGE); + + private void processMessage(Tag currentTag) throws XmlPullParserException, + IOException { + MessagePacket packet = (MessagePacket) processPacket(currentTag, + PACKET_MESSAGE); if (this.messageListener != null) { - this.messageListener.onMessagePacketReceived(account,packet); + this.messageListener.onMessagePacketReceived(account, packet); } } - - private void processPresence(Tag currentTag) throws XmlPullParserException, IOException { - PresencePacket packet = (PresencePacket) processPacket(currentTag, PACKET_PRESENCE); + + private void processPresence(Tag currentTag) throws XmlPullParserException, + IOException { + PresencePacket packet = (PresencePacket) processPacket(currentTag, + PACKET_PRESENCE); if (this.presenceListener != null) { - this.presenceListener.onPresencePacketReceived(account,packet); + this.presenceListener.onPresencePacketReceived(account, packet); } } private void sendStartTLS() { Tag startTLS = Tag.empty("starttls"); startTLS.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-tls"); - Log.d(LOGTAG,account.getJid()+": sending starttls"); + Log.d(LOGTAG, account.getJid() + ": sending starttls"); tagWriter.writeTag(startTLS); } private void switchOverToTls(Tag currentTag) throws XmlPullParserException, IOException { Tag nextTag = tagReader.readTag(); // should be proceed end tag - Log.d(LOGTAG,account.getJid()+": now switch to ssl"); + Log.d(LOGTAG, account.getJid() + ": now switch to ssl"); SSLSocket sslSocket; try { sslSocket = (SSLSocket) ((SSLSocketFactory) SSLSocketFactory @@ -257,7 +268,9 @@ public class XmppConnection implements Runnable { processStream(tagReader.readTag()); sslSocket.close(); } catch (IOException e) { - Log.d(LOGTAG, account.getJid()+": error on ssl '" + e.getMessage()+"'"); + Log.d(LOGTAG, + account.getJid() + ": error on ssl '" + e.getMessage() + + "'"); } } @@ -268,32 +281,36 @@ public class XmppConnection implements Runnable { auth.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl"); auth.setAttribute("mechanism", "PLAIN"); auth.setContent(saslString); - Log.d(LOGTAG,account.getJid()+": sending sasl "+auth.toString()); + Log.d(LOGTAG, account.getJid() + ": sending sasl " + auth.toString()); tagWriter.writeElement(auth); } private void processStreamFeatures(Tag currentTag) throws XmlPullParserException, IOException { this.streamFeatures = tagReader.readElement(currentTag); - Log.d(LOGTAG,account.getJid()+": process stream features "+streamFeatures); - if (this.streamFeatures.hasChild("starttls")&&account.isOptionSet(Account.OPTION_USETLS)) { + Log.d(LOGTAG, account.getJid() + ": process stream features " + + streamFeatures); + if (this.streamFeatures.hasChild("starttls") + && account.isOptionSet(Account.OPTION_USETLS)) { sendStartTLS(); - } else if (this.streamFeatures.hasChild("mechanisms")&&shouldAuthenticate) { + } else if (this.streamFeatures.hasChild("mechanisms") + && shouldAuthenticate) { sendSaslAuth(); } - if (this.streamFeatures.hasChild("bind")&&shouldBind) { + if (this.streamFeatures.hasChild("bind") && shouldBind) { sendBindRequest(); if (this.streamFeatures.hasChild("session")) { IqPacket startSession = new IqPacket(IqPacket.TYPE_SET); Element session = new Element("session"); - session.setAttribute("xmlns","urn:ietf:params:xml:ns:xmpp-session"); + session.setAttribute("xmlns", + "urn:ietf:params:xml:ns:xmpp-session"); session.setContent(""); startSession.addChild(session); sendIqPacket(startSession, null); tagWriter.writeElement(startSession); } Element presence = new Element("presence"); - + tagWriter.writeElement(presence); } } @@ -301,17 +318,65 @@ public class XmppConnection implements Runnable { private void sendBindRequest() throws IOException { IqPacket iq = new IqPacket(IqPacket.TYPE_SET); Element bind = new Element("bind"); - bind.setAttribute("xmlns","urn:ietf:params:xml:ns:xmpp-bind"); + bind.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-bind"); iq.addChild(bind); - this.sendIqPacket(iq, new OnIqPacketReceived() { + this.sendIqPacket(iq, new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { - String resource = packet.findChild("bind").findChild("jid").getContent().split("/")[1]; + String resource = packet.findChild("bind").findChild("jid") + .getContent().split("/")[1]; account.setResource(resource); account.setStatus(Account.STATUS_ONLINE); - if (statusListener!=null) { + if (statusListener != null) { statusListener.onStatusChanged(account); } + sendServiceDiscovery(); + } + }); + } + + private void sendServiceDiscovery() { + IqPacket iq = new IqPacket(IqPacket.TYPE_GET); + iq.setAttribute("to", account.getServer()); + Element query = new Element("query"); + query.setAttribute("xmlns", "http://jabber.org/protocol/disco#info"); + iq.addChild(query); + this.sendIqPacket(iq, new OnIqPacketReceived() { + + @Override + public void onIqPacketReceived(Account account, IqPacket packet) { + if (packet.hasChild("query")) { + List elements = packet.findChild("query") + .getChildren(); + for (int i = 0; i < elements.size(); ++i) { + if (elements.get(i).getName().equals("feature")) { + discoFeatures.add(elements.get(i).getAttribute( + "var")); + } + } + } + if (discoFeatures.contains("urn:xmpp:carbons:2")) { + sendEnableCarbons(); + } + } + }); + } + + private void sendEnableCarbons() { + Log.d(LOGTAG,account.getJid()+": enable carbons"); + IqPacket iq = new IqPacket(IqPacket.TYPE_SET); + Element enable = new Element("enable"); + enable.setAttribute("xmlns", "urn:xmpp:carbons:2"); + iq.addChild(enable); + this.sendIqPacket(iq, new OnIqPacketReceived() { + + @Override + public void onIqPacketReceived(Account account, IqPacket packet) { + if (!packet.hasChild("error")) { + Log.d(LOGTAG,account.getJid()+": successfully enabled carbons"); + } else { + Log.d(LOGTAG,account.getJid()+": error enableing carbons "+packet.toString()); + } } }); } @@ -334,38 +399,41 @@ public class XmppConnection implements Runnable { private String nextRandomId() { return new BigInteger(50, random).toString(32); } - + public void sendIqPacket(IqPacket packet, OnIqPacketReceived callback) { String id = nextRandomId(); - packet.setAttribute("id",id); + packet.setAttribute("id", id); tagWriter.writeElement(packet); if (callback != null) { iqPacketCallbacks.put(id, callback); } - Log.d(LOGTAG,account.getJid()+": sending: "+packet.toString()); + //Log.d(LOGTAG, account.getJid() + ": sending: " + packet.toString()); } - - public void sendMessagePacket(MessagePacket packet){ + + public void sendMessagePacket(MessagePacket packet) { tagWriter.writeElement(packet); } - - public void sendPresencePacket(PresencePacket packet) { + + public void sendPresencePacket(PresencePacket packet) { tagWriter.writeElement(packet); - Log.d(LOGTAG,account.getJid()+": sending: "+packet.toString()); + Log.d(LOGTAG, account.getJid() + ": sending: " + packet.toString()); } - - public void setOnMessagePacketReceivedListener(OnMessagePacketReceived listener) { + + public void setOnMessagePacketReceivedListener( + OnMessagePacketReceived listener) { this.messageListener = listener; } - - public void setOnUnregisteredIqPacketReceivedListener(OnIqPacketReceived listener) { + + public void setOnUnregisteredIqPacketReceivedListener( + OnIqPacketReceived listener) { this.unregisteredIqListener = listener; } - - public void setOnPresencePacketReceivedListener(OnPresencePacketReceived listener) { + + public void setOnPresencePacketReceivedListener( + OnPresencePacketReceived listener) { this.presenceListener = listener; } - + public void setOnStatusChangedListener(OnStatusChanged listener) { this.statusListener = listener; } -- cgit v1.2.3