first draft on xml parser and communication. a long way to go. code definitly not perfect. will refactor asap
This commit is contained in:
parent
ad11dab635
commit
6c5c3ac2de
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||||
<uses-permission android:name="android.permission.READ_PROFILE"/>
|
<uses-permission android:name="android.permission.READ_PROFILE"/>
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
|
|
@ -1,22 +1,43 @@
|
||||||
package de.gultsch.chat.services;
|
package de.gultsch.chat.services;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
import de.gultsch.chat.entities.Account;
|
import de.gultsch.chat.entities.Account;
|
||||||
import de.gultsch.chat.entities.Contact;
|
import de.gultsch.chat.entities.Contact;
|
||||||
import de.gultsch.chat.entities.Conversation;
|
import de.gultsch.chat.entities.Conversation;
|
||||||
import de.gultsch.chat.entities.Message;
|
import de.gultsch.chat.entities.Message;
|
||||||
import de.gultsch.chat.persistance.DatabaseBackend;
|
import de.gultsch.chat.persistance.DatabaseBackend;
|
||||||
|
import de.gultsch.chat.xml.Tag;
|
||||||
|
import de.gultsch.chat.xml.XmlReader;
|
||||||
|
import de.gultsch.chat.xmpp.XmppConnection;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.PowerManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public class XmppConnectionService extends Service {
|
public class XmppConnectionService extends Service {
|
||||||
|
|
||||||
protected static final String LOGTAG = "xmppConnection";
|
protected static final String LOGTAG = "xmppService";
|
||||||
protected DatabaseBackend databaseBackend;
|
protected DatabaseBackend databaseBackend;
|
||||||
|
|
||||||
|
public long startDate;
|
||||||
|
|
||||||
|
private List<Account> accounts;
|
||||||
|
|
||||||
|
public boolean connectionRunnig = false;
|
||||||
|
|
||||||
private final IBinder mBinder = new XmppConnectionBinder();
|
private final IBinder mBinder = new XmppConnectionBinder();
|
||||||
|
|
||||||
|
@ -26,9 +47,27 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
Log.d(LOGTAG,"recieved start command. been running for "+((System.currentTimeMillis() - startDate) / 1000)+"s");
|
||||||
|
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||||
|
if (!connectionRunnig) {
|
||||||
|
for(Account account : accounts) {
|
||||||
|
Log.d(LOGTAG,"connection wasnt running");
|
||||||
|
XmppConnection connection = new XmppConnection(account, pm);
|
||||||
|
Thread thread = new Thread(connection);
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
connectionRunnig = true;
|
||||||
|
}
|
||||||
|
return START_STICKY;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
databaseBackend = DatabaseBackend.getInstance(getApplicationContext());
|
databaseBackend = DatabaseBackend.getInstance(getApplicationContext());
|
||||||
|
this.accounts = databaseBackend.getAccounts();
|
||||||
|
startDate = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -31,6 +31,7 @@ public abstract class XmppActivity extends Activity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStart() {
|
protected void onStart() {
|
||||||
|
startService(new Intent(this, XmppConnectionService.class));
|
||||||
super.onStart();
|
super.onStart();
|
||||||
if (!xmppConnectionServiceBound) {
|
if (!xmppConnectionServiceBound) {
|
||||||
Intent intent = new Intent(this, XmppConnectionService.class);
|
Intent intent = new Intent(this, XmppConnectionService.class);
|
||||||
|
|
24
src/de/gultsch/chat/utils/SASL.java
Normal file
24
src/de/gultsch/chat/utils/SASL.java
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package de.gultsch.chat.utils;
|
||||||
|
|
||||||
|
import android.util.Base64;
|
||||||
|
|
||||||
|
public class SASL {
|
||||||
|
public static String plain(String username, String password) {
|
||||||
|
byte[] userBytes = username.getBytes();
|
||||||
|
int userLenght = userBytes.length;
|
||||||
|
byte[] passwordBytes = password.getBytes();
|
||||||
|
byte[] saslBytes = new byte[userBytes.length+passwordBytes.length+2];
|
||||||
|
saslBytes[0] = 0x0;
|
||||||
|
for(int i = 1; i < saslBytes.length; ++i) {
|
||||||
|
if (i<=userLenght) {
|
||||||
|
saslBytes[i] = userBytes[i-1];
|
||||||
|
} else if (i==userLenght+1) {
|
||||||
|
saslBytes[i] = 0x0;
|
||||||
|
} else {
|
||||||
|
saslBytes[i] = passwordBytes[i-(userLenght+2)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Base64.encodeToString(saslBytes, Base64.DEFAULT);
|
||||||
|
}
|
||||||
|
}
|
65
src/de/gultsch/chat/xml/Element.java
Normal file
65
src/de/gultsch/chat/xml/Element.java
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
package de.gultsch.chat.xml;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Element {
|
||||||
|
protected String name;
|
||||||
|
protected Hashtable<String, String> attributes = new Hashtable<String, String>();
|
||||||
|
protected String content;
|
||||||
|
protected List<Element> children = new ArrayList<Element>();
|
||||||
|
|
||||||
|
public Element(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Element addChild(Element child) {
|
||||||
|
this.content = null;
|
||||||
|
children.add(child);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Element setContent(String content) {
|
||||||
|
this.content = content;
|
||||||
|
this.children.clear();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Element setAttribute(String name, String value) {
|
||||||
|
this.attributes.put(name, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Element setAttributes(Hashtable<String, String> attributes) {
|
||||||
|
this.attributes = attributes;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder elementOutput = new StringBuilder();
|
||||||
|
if ((content==null)&&(children.size() == 0)) {
|
||||||
|
Tag emptyTag = Tag.empty(name);
|
||||||
|
emptyTag.setAtttributes(this.attributes);
|
||||||
|
elementOutput.append(emptyTag.toString());
|
||||||
|
} else {
|
||||||
|
Tag startTag = Tag.start(name);
|
||||||
|
startTag.setAtttributes(this.attributes);
|
||||||
|
elementOutput.append(startTag);
|
||||||
|
if (content!=null) {
|
||||||
|
elementOutput.append(content);
|
||||||
|
} else {
|
||||||
|
for(Element child : children) {
|
||||||
|
elementOutput.append(child.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Tag endTag = Tag.end(name);
|
||||||
|
elementOutput.append(endTag);
|
||||||
|
}
|
||||||
|
return elementOutput.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
99
src/de/gultsch/chat/xml/Tag.java
Normal file
99
src/de/gultsch/chat/xml/Tag.java
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
package de.gultsch.chat.xml;
|
||||||
|
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class Tag {
|
||||||
|
public static final int NO = -1;
|
||||||
|
public static final int START = 0;
|
||||||
|
public static final int END = 1;
|
||||||
|
public static final int EMPTY = 2;
|
||||||
|
|
||||||
|
protected int type;
|
||||||
|
protected String name;
|
||||||
|
protected Hashtable<String, String> attributes = new Hashtable<String, String>();
|
||||||
|
|
||||||
|
protected Tag(int type, String name) {
|
||||||
|
this.type = type;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Tag no(String text) {
|
||||||
|
return new Tag(NO,text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Tag start(String name) {
|
||||||
|
return new Tag(START,name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Tag end(String name) {
|
||||||
|
return new Tag(END,name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Tag empty(String name) {
|
||||||
|
return new Tag(EMPTY,name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAttribute(String attrName) {
|
||||||
|
return this.attributes.get(attrName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tag setAttribute(String attrName, String attrValue) {
|
||||||
|
this.attributes.put(attrName, attrValue);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tag setAtttributes(Hashtable<String, String> attributes) {
|
||||||
|
this.attributes = attributes;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStart(String needle) {
|
||||||
|
return (this.type == START) && (this.name.equals(needle));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnd(String needle) {
|
||||||
|
return (this.type == END) && (this.name.equals(needle));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNo() {
|
||||||
|
return (this.type == NO);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder tagOutput = new StringBuilder();
|
||||||
|
tagOutput.append('<');
|
||||||
|
if (type==END) {
|
||||||
|
tagOutput.append('/');
|
||||||
|
}
|
||||||
|
tagOutput.append(name);
|
||||||
|
if(type!=END) {
|
||||||
|
Set<Entry<String, String>> attributeSet = attributes.entrySet();
|
||||||
|
Iterator<Entry<String, String>> it = attributeSet.iterator();
|
||||||
|
while(it.hasNext()) {
|
||||||
|
Entry<String,String> entry = it.next();
|
||||||
|
tagOutput.append(' ');
|
||||||
|
tagOutput.append(entry.getKey());
|
||||||
|
tagOutput.append("=\"");
|
||||||
|
tagOutput.append(entry.getValue());
|
||||||
|
tagOutput.append('"');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type==EMPTY) {
|
||||||
|
tagOutput.append('/');
|
||||||
|
}
|
||||||
|
tagOutput.append('>');
|
||||||
|
return tagOutput.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Hashtable<String, String> getAttributes() {
|
||||||
|
return this.attributes;
|
||||||
|
}
|
||||||
|
}
|
46
src/de/gultsch/chat/xml/TagWriter.java
Normal file
46
src/de/gultsch/chat/xml/TagWriter.java
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package de.gultsch.chat.xml;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class TagWriter {
|
||||||
|
|
||||||
|
OutputStreamWriter writer;
|
||||||
|
|
||||||
|
public TagWriter() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public TagWriter(OutputStream out) {
|
||||||
|
this.setOutputStream(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOutputStream(OutputStream out) {
|
||||||
|
this.writer = new OutputStreamWriter(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TagWriter beginDocument() throws IOException {
|
||||||
|
writer.write("<?xml version='1.0'?>");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TagWriter writeTag(Tag tag) throws IOException {
|
||||||
|
writer.write(tag.toString());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush() throws IOException {
|
||||||
|
writer.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeString(String string) throws IOException {
|
||||||
|
writer.write(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeElement(Element element) throws IOException {
|
||||||
|
writer.write(element.toString());
|
||||||
|
}
|
||||||
|
}
|
91
src/de/gultsch/chat/xml/XmlReader.java
Normal file
91
src/de/gultsch/chat/xml/XmlReader.java
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
package de.gultsch.chat.xml;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
import android.os.PowerManager;
|
||||||
|
import android.os.PowerManager.WakeLock;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Xml;
|
||||||
|
|
||||||
|
public class XmlReader {
|
||||||
|
private static final String LOGTAG = "xmppService";
|
||||||
|
private XmlPullParser parser;
|
||||||
|
private PowerManager.WakeLock wakeLock;
|
||||||
|
private InputStream is;
|
||||||
|
|
||||||
|
public XmlReader(WakeLock wakeLock) {
|
||||||
|
this.parser = Xml.newPullParser();
|
||||||
|
try {
|
||||||
|
this.parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES,true);
|
||||||
|
} catch (XmlPullParserException e) {
|
||||||
|
Log.d(LOGTAG,"error setting namespace feature on parser");
|
||||||
|
}
|
||||||
|
this.wakeLock = wakeLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInputStream(InputStream inputStream) {
|
||||||
|
this.is = inputStream;
|
||||||
|
try {
|
||||||
|
parser.setInput(new InputStreamReader(this.is));
|
||||||
|
} catch (XmlPullParserException e) {
|
||||||
|
Log.d(LOGTAG,"error setting input stream");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
try {
|
||||||
|
parser.setInput(new InputStreamReader(this.is));
|
||||||
|
} catch (XmlPullParserException e) {
|
||||||
|
Log.d(LOGTAG,"error resetting input stream");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tag readTag() throws XmlPullParserException, IOException {
|
||||||
|
if (wakeLock.isHeld()) {
|
||||||
|
//Log.d(LOGTAG,"there was a wake lock. releasing it till next event");
|
||||||
|
wakeLock.release(); //release wake look while waiting on next parser event
|
||||||
|
}
|
||||||
|
while(parser.next() != XmlPullParser.END_DOCUMENT) {
|
||||||
|
//Log.d(LOGTAG,"found new event. acquiring wake lock");
|
||||||
|
wakeLock.acquire();
|
||||||
|
if (parser.getEventType() == XmlPullParser.START_TAG) {
|
||||||
|
Tag tag = Tag.start(parser.getName());
|
||||||
|
for(int i = 0; i < parser.getAttributeCount(); ++i) {
|
||||||
|
tag.setAttribute(parser.getAttributeName(i), parser.getAttributeValue(i));
|
||||||
|
}
|
||||||
|
return tag;
|
||||||
|
} else if (parser.getEventType() == XmlPullParser.END_TAG) {
|
||||||
|
Tag tag = Tag.end(parser.getName());
|
||||||
|
return tag;
|
||||||
|
} else if (parser.getEventType() == XmlPullParser.TEXT) {
|
||||||
|
Tag tag = Tag.no(parser.getText());
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wakeLock.isHeld()) {
|
||||||
|
wakeLock.release();
|
||||||
|
}
|
||||||
|
return null; //end document;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Element readElement(Tag currentTag) throws XmlPullParserException, IOException {
|
||||||
|
Element element = new Element(currentTag.getName());
|
||||||
|
element.setAttributes(currentTag.getAttributes());
|
||||||
|
Tag nextTag = this.readTag();
|
||||||
|
if(nextTag.isNo()) {
|
||||||
|
element.setContent(nextTag.getName());
|
||||||
|
nextTag = this.readTag();
|
||||||
|
}
|
||||||
|
while(!nextTag.isEnd(element.getName())) {
|
||||||
|
Element child = this.readElement(nextTag);
|
||||||
|
element.addChild(child);
|
||||||
|
nextTag = this.readTag();
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
}
|
26
src/de/gultsch/chat/xmpp/IqPacket.java
Normal file
26
src/de/gultsch/chat/xmpp/IqPacket.java
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package de.gultsch.chat.xmpp;
|
||||||
|
|
||||||
|
import de.gultsch.chat.xml.Element;
|
||||||
|
|
||||||
|
public class IqPacket extends Element {
|
||||||
|
|
||||||
|
public static final int TYPE_SET = 0;
|
||||||
|
public static final int TYPE_RESULT = 1;
|
||||||
|
|
||||||
|
private IqPacket(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IqPacket(String id, int type) {
|
||||||
|
super("iq");
|
||||||
|
this.setAttribute("id",id);
|
||||||
|
switch (type) {
|
||||||
|
case TYPE_SET:
|
||||||
|
this.setAttribute("type", "set");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
222
src/de/gultsch/chat/xmpp/XmppConnection.java
Normal file
222
src/de/gultsch/chat/xmpp/XmppConnection.java
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
package de.gultsch.chat.xmpp;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLSocket;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
import android.os.PowerManager;
|
||||||
|
import android.util.Log;
|
||||||
|
import de.gultsch.chat.entities.Account;
|
||||||
|
import de.gultsch.chat.utils.SASL;
|
||||||
|
import de.gultsch.chat.xml.Element;
|
||||||
|
import de.gultsch.chat.xml.Tag;
|
||||||
|
import de.gultsch.chat.xml.XmlReader;
|
||||||
|
import de.gultsch.chat.xml.TagWriter;
|
||||||
|
|
||||||
|
public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
|
protected Account account;
|
||||||
|
private static final String LOGTAG = "xmppService";
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
public XmppConnection(Account account, PowerManager pm) {
|
||||||
|
this.account = account;
|
||||||
|
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
|
||||||
|
"XmppConnection");
|
||||||
|
tagReader = new XmlReader(wakeLock);
|
||||||
|
tagWriter = new TagWriter();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void connect() {
|
||||||
|
try {
|
||||||
|
socket = new Socket(account.getServer(), 5222);
|
||||||
|
Log.d(LOGTAG, "starting new socket");
|
||||||
|
OutputStream out = socket.getOutputStream();
|
||||||
|
tagWriter.setOutputStream(out);
|
||||||
|
InputStream in = socket.getInputStream();
|
||||||
|
tagReader.setInputStream(in);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
Log.d(LOGTAG, "error during connect. unknown host");
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(LOGTAG, "error during connect. io exception. falscher port?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
connect();
|
||||||
|
try {
|
||||||
|
tagWriter.beginDocument();
|
||||||
|
sendStartStream();
|
||||||
|
Tag nextTag;
|
||||||
|
while ((nextTag = tagReader.readTag()) != null) {
|
||||||
|
if (nextTag.isStart("stream")) {
|
||||||
|
processStream(nextTag);
|
||||||
|
} else {
|
||||||
|
Log.d(LOGTAG, "found unexpected tag: " + nextTag.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (XmlPullParserException e) {
|
||||||
|
Log.d(LOGTAG,
|
||||||
|
"xml error during normal read. maybe missformed xml? "
|
||||||
|
+ e.getMessage());
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(LOGTAG, "io exception during read. connection lost?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processStream(Tag currentTag) throws XmlPullParserException,
|
||||||
|
IOException {
|
||||||
|
Log.d(LOGTAG, "process Stream");
|
||||||
|
Tag nextTag;
|
||||||
|
while ((nextTag = tagReader.readTag()) != null) {
|
||||||
|
if (nextTag.isStart("error")) {
|
||||||
|
processStreamError(nextTag);
|
||||||
|
} else if (nextTag.isStart("features")) {
|
||||||
|
processStreamFeatures(nextTag);
|
||||||
|
if (!isTlsEncrypted) {
|
||||||
|
sendStartTLS();
|
||||||
|
}
|
||||||
|
if ((!isAuthenticated) && (isTlsEncrypted)) {
|
||||||
|
sendSaslAuth();
|
||||||
|
}
|
||||||
|
if ((isAuthenticated)&&(isTlsEncrypted)) {
|
||||||
|
sendBindRequest();
|
||||||
|
}
|
||||||
|
} else if (nextTag.isStart("proceed")) {
|
||||||
|
switchOverToTls(nextTag);
|
||||||
|
} else if (nextTag.isStart("success")) {
|
||||||
|
isAuthenticated = true;
|
||||||
|
Log.d(LOGTAG,"read success tag in stream. reset again");
|
||||||
|
tagReader.readTag();
|
||||||
|
tagReader.reset();
|
||||||
|
sendStartStream();
|
||||||
|
processStream(tagReader.readTag());
|
||||||
|
} else if (nextTag.isStart("iq")) {
|
||||||
|
processIq(nextTag);
|
||||||
|
} else if (nextTag.isEnd("stream")) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
Log.d(LOGTAG, "found unexpected tag: " + nextTag.getName()
|
||||||
|
+ " as child of " + currentTag.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processIq(Tag currentTag) throws XmlPullParserException, IOException {
|
||||||
|
int typ = -1;
|
||||||
|
if (currentTag.getAttribute("type").equals("result")) {
|
||||||
|
typ = IqPacket.TYPE_RESULT;
|
||||||
|
}
|
||||||
|
IqPacket iq = new IqPacket(currentTag.getAttribute("id"),typ);
|
||||||
|
Tag nextTag = tagReader.readTag();
|
||||||
|
while(!nextTag.isEnd("iq")) {
|
||||||
|
Element element = tagReader.readElement(nextTag);
|
||||||
|
iq.addChild(element);
|
||||||
|
nextTag = tagReader.readTag();
|
||||||
|
}
|
||||||
|
Log.d(LOGTAG,"this is what i understood: "+iq.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendStartTLS() throws XmlPullParserException, IOException {
|
||||||
|
Tag startTLS = Tag.empty("starttls");
|
||||||
|
startTLS.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-tls");
|
||||||
|
Log.d(LOGTAG, "sending starttls");
|
||||||
|
tagWriter.writeTag(startTLS).flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void switchOverToTls(Tag currentTag) throws XmlPullParserException,
|
||||||
|
IOException {
|
||||||
|
Tag nextTag = tagReader.readTag(); // should be proceed end tag
|
||||||
|
Log.d(LOGTAG, "now switch to ssl");
|
||||||
|
SSLSocket sslSocket;
|
||||||
|
try {
|
||||||
|
sslSocket = (SSLSocket) ((SSLSocketFactory) SSLSocketFactory
|
||||||
|
.getDefault()).createSocket(socket, socket.getInetAddress()
|
||||||
|
.getHostAddress(), socket.getPort(), true);
|
||||||
|
tagReader.setInputStream(sslSocket.getInputStream());
|
||||||
|
Log.d(LOGTAG, "reset inputstream");
|
||||||
|
tagWriter.setOutputStream(sslSocket.getOutputStream());
|
||||||
|
Log.d(LOGTAG, "switch over seemed to work");
|
||||||
|
isTlsEncrypted = true;
|
||||||
|
sendStartStream();
|
||||||
|
processStream(tagReader.readTag());
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(LOGTAG, "error on ssl" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendSaslAuth() throws IOException, XmlPullParserException {
|
||||||
|
String saslString = SASL.plain(account.getUsername(),
|
||||||
|
account.getPassword());
|
||||||
|
Element auth = new Element("auth");
|
||||||
|
auth.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
|
||||||
|
auth.setAttribute("mechanism", "PLAIN");
|
||||||
|
auth.setContent(saslString);
|
||||||
|
Log.d(LOGTAG,"sending sasl "+auth.toString());
|
||||||
|
tagWriter.writeElement(auth);
|
||||||
|
tagWriter.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processStreamFeatures(Tag currentTag)
|
||||||
|
throws XmlPullParserException, IOException {
|
||||||
|
Log.d(LOGTAG, "processStreamFeatures");
|
||||||
|
|
||||||
|
Element streamFeatures = new Element("features");
|
||||||
|
|
||||||
|
Tag nextTag = tagReader.readTag();
|
||||||
|
while(!nextTag.isEnd("features")) {
|
||||||
|
Element element = tagReader.readElement(nextTag);
|
||||||
|
streamFeatures.addChild(element);
|
||||||
|
nextTag = tagReader.readTag();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendBindRequest() throws IOException {
|
||||||
|
IqPacket iq = new IqPacket(nextRandomId(),IqPacket.TYPE_SET);
|
||||||
|
Element bind = new Element("bind");
|
||||||
|
bind.setAttribute("xmlns","urn:ietf:params:xml:ns:xmpp-bind");
|
||||||
|
iq.addChild(bind);
|
||||||
|
Log.d(LOGTAG,"sending bind request: "+iq.toString());
|
||||||
|
tagWriter.writeElement(iq);
|
||||||
|
tagWriter.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processStreamError(Tag currentTag) {
|
||||||
|
Log.d(LOGTAG, "processStreamError");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendStartStream() throws IOException {
|
||||||
|
Tag stream = Tag.start("stream");
|
||||||
|
stream.setAttribute("from", account.getJid());
|
||||||
|
stream.setAttribute("to", account.getServer());
|
||||||
|
stream.setAttribute("version", "1.0");
|
||||||
|
stream.setAttribute("xml:lang", "en");
|
||||||
|
stream.setAttribute("xmlns", "jabber:client");
|
||||||
|
stream.setAttribute("xmlns:stream", "http://etherx.jabber.org/streams");
|
||||||
|
tagWriter.writeTag(stream).flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String nextRandomId() {
|
||||||
|
return new BigInteger(50, random).toString(32);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue