mirror of
https://github.com/moparisthebest/Conversations
synced 2024-11-27 11:12:16 -05:00
Implement xmpp-api v1
This commit is contained in:
parent
8f0cd86090
commit
949c724259
@ -13,6 +13,7 @@ apply plugin: 'com.android.application'
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
maven {
|
||||
url 'https://maven.google.com'
|
||||
@ -51,6 +52,7 @@ dependencies {
|
||||
compile 'com.makeramen:roundedimageview:2.3.0'
|
||||
compile "com.wefika:flowlayout:0.4.1"
|
||||
compile 'net.ypresto.androidtranscoder:android-transcoder:0.2.0'
|
||||
compile 'com.moparisthebest:xmpp-api:1.0-SNAPSHOT'
|
||||
}
|
||||
|
||||
ext {
|
||||
@ -68,7 +70,7 @@ android {
|
||||
versionCode 236
|
||||
versionName "1.21.0"
|
||||
archivesBaseName += "-$versionName"
|
||||
applicationId "eu.siacs.conversations"
|
||||
applicationId "eu.siacs.conversations.sms"
|
||||
}
|
||||
|
||||
dexOptions {
|
||||
|
@ -218,6 +218,18 @@
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true"/>
|
||||
|
||||
<!-- Xmpp Remote API, this service has explicitly no permission requirements
|
||||
because we are using our own package based allow/disallow system
|
||||
-->
|
||||
<service
|
||||
android:name=".remote.XmppPluginService"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
tools:ignore="ExportedService">
|
||||
<intent-filter>
|
||||
<action android:name="org.openintents.xmpp.IXmppService" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
</application>
|
||||
|
||||
|
@ -39,6 +39,7 @@ public class PgpDecryptionService {
|
||||
}
|
||||
|
||||
public synchronized boolean decrypt(final Message message, boolean notify) {
|
||||
// todo: wtf to do with these
|
||||
messages.add(message);
|
||||
if (notify && pendingIntent == null) {
|
||||
pendingNotifications.add(message);
|
||||
|
@ -301,6 +301,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
|
||||
}
|
||||
|
||||
public void populateWithMessages(final List<Message> messages) {
|
||||
// todo: what about what calls this method???
|
||||
synchronized (this.messages) {
|
||||
messages.clear();
|
||||
messages.addAll(this.messages);
|
||||
|
@ -576,6 +576,8 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
||||
return;
|
||||
}
|
||||
|
||||
// todo: hook here but prepend? put this off for later
|
||||
mXmppConnectionService.newMessage(message);
|
||||
if (query != null && query.getPagingOrder() == MessageArchiveService.PagingOrder.REVERSE) {
|
||||
conversation.prepend(message);
|
||||
} else {
|
||||
|
@ -0,0 +1,364 @@
|
||||
package eu.siacs.conversations.remote;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import eu.siacs.conversations.entities.Message;
|
||||
import eu.siacs.conversations.services.XmppConnectionService;
|
||||
import eu.siacs.conversations.xml.Element;
|
||||
import eu.siacs.conversations.xml.XmlReader;
|
||||
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
|
||||
import eu.siacs.conversations.xmpp.XmppConnection;
|
||||
import eu.siacs.conversations.xmpp.stanzas.*;
|
||||
import org.openintents.xmpp.IXmppPluginCallback;
|
||||
import org.openintents.xmpp.XmppError;
|
||||
import org.openintents.xmpp.util.XmppPluginCallbackApi;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import static org.openintents.xmpp.util.XmppPluginCallbackApi.*;
|
||||
import static org.openintents.xmpp.util.XmppServiceApi.*;
|
||||
import static org.openintents.xmpp.util.XmppUtils.*;
|
||||
|
||||
public class XmppPluginService extends Service {
|
||||
|
||||
private static final int[] SUPPORTED_VERSIONS = new int[]{1};
|
||||
|
||||
private XmppConnectionService xmppConnectionService = null;
|
||||
private boolean xmppConnectionServiceBound = false;
|
||||
|
||||
private RemoteCallbackList<XmppPluginCallbackApi> pluginCallbacks = new RemoteCallbackList<>();
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
if (!xmppConnectionServiceBound) {
|
||||
connectToBackend();
|
||||
}
|
||||
}
|
||||
|
||||
protected ServiceConnection mConnection = new ServiceConnection() {
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
final XmppConnectionService.XmppConnectionBinder binder = (XmppConnectionService.XmppConnectionBinder) service;
|
||||
xmppConnectionService = binder.getService();
|
||||
xmppConnectionService.setXmppPluginService(XmppPluginService.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName arg0) {
|
||||
xmppConnectionService = null;
|
||||
xmppConnectionServiceBound = false;
|
||||
}
|
||||
};
|
||||
|
||||
public void connectToBackend() {
|
||||
final Intent intent = new Intent(this, XmppConnectionService.class);
|
||||
intent.setAction("ui");
|
||||
startService(intent);
|
||||
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
|
||||
private final org.openintents.xmpp.AbstractXmppService mBinder = new org.openintents.xmpp.AbstractXmppService() {
|
||||
|
||||
@Override
|
||||
public Intent execute(final Intent data, final InputStream input, final OutputStream output) {
|
||||
try {
|
||||
return executeInternal(data, input, output);
|
||||
} catch (Exception e) {
|
||||
Log.e(Config.LOGTAG, "error in execute", e);
|
||||
return getExceptionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent callback(final Intent data, final IXmppPluginCallback iXmppPluginCallback) {
|
||||
try {
|
||||
return callbackInternal(data, iXmppPluginCallback);
|
||||
} catch (Exception e) {
|
||||
Log.e(Config.LOGTAG, "error in callback", e);
|
||||
return getExceptionError(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
protected Intent executeInternal(final Intent data, final InputStream inputStream, final OutputStream outputStream) throws Exception {
|
||||
|
||||
// We need to be able to load our own parcelables
|
||||
data.setExtrasClassLoader(getClassLoader());
|
||||
|
||||
final Intent errorResult = checkRequirements(data);
|
||||
if (errorResult != null) {
|
||||
return errorResult;
|
||||
}
|
||||
|
||||
final String action = data.getAction();
|
||||
switch (action) {
|
||||
case ACTION_CHECK_PERMISSION: {
|
||||
return null;// todo: checkPermissionImpl(data);
|
||||
}
|
||||
case ACTION_GET_ACCOUNT_JID: {
|
||||
return getAccountJid(data);
|
||||
}
|
||||
case ACTION_SEND_RAW_XML: {
|
||||
return sendRawXml(data, null);
|
||||
}
|
||||
default: {
|
||||
return getError(XmppError.GENERIC_ERROR, "invalid action!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Intent callbackInternal(final Intent data, final IXmppPluginCallback iXmppPluginCallback) throws Exception {
|
||||
|
||||
// We need to be able to load our own parcelables
|
||||
data.setExtrasClassLoader(getClassLoader());
|
||||
|
||||
final Intent errorResult = checkRequirements(data);
|
||||
if (errorResult != null) {
|
||||
return errorResult;
|
||||
}
|
||||
|
||||
final String action = data.getAction();
|
||||
switch (action) {
|
||||
case ACTION_REGISTER_PLUGIN_CALLBACK: {
|
||||
return registerPluginCallback(data, iXmppPluginCallback);
|
||||
}
|
||||
case ACTION_UNREGISTER_PLUGIN_CALLBACK: {
|
||||
return unRegisterPluginCallback(data, iXmppPluginCallback);
|
||||
}
|
||||
case ACTION_SEND_RAW_XML: {
|
||||
return sendRawXml(data, iXmppPluginCallback);
|
||||
}
|
||||
default: {
|
||||
return getError(XmppError.GENERIC_ERROR, "invalid action!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Intent registerPluginCallback(final Intent data, final IXmppPluginCallback iXmppPluginCallback) {
|
||||
if(pluginCallbacks.register(new XmppPluginCallbackApi(getApplicationContext(), iXmppPluginCallback,
|
||||
data.getStringExtra(EXTRA_ACCOUNT_JID), data.getStringExtra(EXTRA_JID_LOCAL_PART), data.getStringExtra(EXTRA_JID_DOMAIN))))
|
||||
return getSuccess();
|
||||
return getError(XmppError.GENERIC_ERROR, "callback register failed");
|
||||
}
|
||||
|
||||
private Intent unRegisterPluginCallback(final Intent data, final IXmppPluginCallback iXmppPluginCallback) {
|
||||
if(pluginCallbacks.unregister(new XmppPluginCallbackApi(getApplicationContext(), iXmppPluginCallback, "fake", null, null)))
|
||||
return getSuccess();
|
||||
/*
|
||||
for(Iterator<XmppPluginCallbackApi> i = pluginCallbacks.iterator(); i.hasNext();) {
|
||||
final XmppPluginCallbackApi pluginCallback = i.next();
|
||||
if(pluginCallback.getXmppPluginCallback().getDelegate().equals(iXmppPluginCallback)) {
|
||||
i.remove();
|
||||
return getSuccess();
|
||||
}
|
||||
}*/
|
||||
return getError(XmppError.GENERIC_ERROR, "callback unregister failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check requirements:
|
||||
* - params != null
|
||||
* - has supported API version
|
||||
* - is allowed to call the service (access has been granted)
|
||||
*
|
||||
* @return null if everything is okay, or a Bundle with an createErrorPendingIntent/PendingIntent
|
||||
*/
|
||||
private Intent checkRequirements(Intent data) {
|
||||
// params Bundle is required!
|
||||
if (data == null) {
|
||||
return getError(XmppError.GENERIC_ERROR, "params Bundle required!");
|
||||
}
|
||||
|
||||
if(data.getAction().equals(ACTION_GET_SUPPORTED_VERSIONS)) {
|
||||
// for this action, we want to skip both version AND permission checks
|
||||
return getSuccess().putExtra(EXTRA_SUPPORTED_VERSIONS, SUPPORTED_VERSIONS);
|
||||
}
|
||||
|
||||
// version code is required and needs to correspond to version code of service!
|
||||
// History of versions in Xmpp-api's CHANGELOG.md
|
||||
final int version = data.getIntExtra(EXTRA_API_VERSION, -1);
|
||||
if (version == -1 || Arrays.binarySearch(SUPPORTED_VERSIONS, version) < 0) {
|
||||
return getError
|
||||
(XmppError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!\n"
|
||||
+ "used API version: " + version + "\n"
|
||||
+ "supported API versions: " + Arrays.toString(SUPPORTED_VERSIONS))
|
||||
.putExtra(EXTRA_SUPPORTED_VERSIONS, SUPPORTED_VERSIONS);
|
||||
}
|
||||
|
||||
// check if caller is allowed to access Conversations
|
||||
// todo:
|
||||
/*
|
||||
Intent result = mApiPermissionHelper.isAllowedOrReturnIntent(data);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Intent getAccountJid(Intent data) {
|
||||
// if data already contains EXTRA_ACCOUNT_JID, it has been executed again
|
||||
// after user interaction. Then, we just need to return the JID again!
|
||||
if (data.hasExtra(EXTRA_ACCOUNT_JID)) {
|
||||
final String accountJid = data.getStringExtra(EXTRA_ACCOUNT_JID);
|
||||
return getSuccess().putExtra(EXTRA_ACCOUNT_JID, accountJid);
|
||||
} else {
|
||||
/*
|
||||
String currentPkg = mApiPermissionHelper.getCurrentCallingPackage();
|
||||
String preferredUserId = data.getStringExtra(EXTRA_USER_ID);
|
||||
|
||||
PendingIntent pi = mApiPendingIntentFactory.createSelectSignKeyIdPendingIntent(data, currentPkg, preferredUserId);
|
||||
|
||||
// return PendingIntent to be executed by client
|
||||
Intent result = new Intent();
|
||||
result.putExtra(RESULT_CODE, RESULT_CODE_USER_INTERACTION_REQUIRED);
|
||||
result.putExtra(RESULT_INTENT, pi);
|
||||
*/
|
||||
|
||||
// todo: implement chooser above, until then, first account will do
|
||||
final String accountJid = xmppConnectionService.getAccounts().get(0).getJid().toBareJid().toString();
|
||||
return getSuccess().putExtra(EXTRA_ACCOUNT_JID, accountJid);
|
||||
}
|
||||
}
|
||||
|
||||
private Intent sendRawXml(Intent data, final IXmppPluginCallback iXmppPluginCallback) throws Exception {
|
||||
final Account account = findAccount(data.getStringExtra(EXTRA_ACCOUNT_JID));
|
||||
final XmlReader reader = new XmlReader(new StringReader(data.getStringExtra(EXTRA_RAW_XML)));
|
||||
final Element parsedRawXml = reader.nextWholeElement(); // todo: should do this in loop or????
|
||||
Log.d(Config.LOGTAG, "rawXml: " + parsedRawXml.toString());
|
||||
switch(parsedRawXml.getName()) {
|
||||
case "message": {
|
||||
final MessagePacket packet = create(parsedRawXml, new MessagePacket());
|
||||
packet.setFrom(account.getJid());
|
||||
Log.d(Config.LOGTAG, "msgXml: " + packet.toString());
|
||||
xmppConnectionService.sendMessagePacket(account, packet);
|
||||
return getSuccess();
|
||||
}
|
||||
case "iq": {
|
||||
final IqPacket packet = create(parsedRawXml, new IqPacket());
|
||||
packet.setFrom(account.getJid());
|
||||
|
||||
OnIqPacketReceived callback = null;
|
||||
if(iXmppPluginCallback != null) {
|
||||
// plugin wants notified of response
|
||||
callback = new OnIqPacketReceived() {
|
||||
@Override
|
||||
public void onIqPacketReceived(final Account account, final IqPacket packet) {
|
||||
final Intent result = new Intent();
|
||||
result.setAction(ACTION_IQ_RESPONSE);
|
||||
final String accountJid = account.getJid().toBareJid().toString();
|
||||
result.putExtra(EXTRA_ACCOUNT_JID, accountJid);
|
||||
result.putExtra(EXTRA_RAW_XML, packet.toString());
|
||||
try {
|
||||
iXmppPluginCallback.execute(result, null, -1);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(Config.LOGTAG, "error returning iq to callback", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
xmppConnectionService.sendIqPacket(account, packet, callback);
|
||||
return getSuccess();
|
||||
}
|
||||
case "presence": {
|
||||
final PresencePacket packet = create(parsedRawXml, new PresencePacket());
|
||||
packet.setFrom(account.getJid());
|
||||
xmppConnectionService.sendPresencePacket(account, packet);
|
||||
return getSuccess();
|
||||
}
|
||||
default: {
|
||||
// must be some type of nonza
|
||||
XmppConnection connection = account.getXmppConnection();
|
||||
if (connection != null) {
|
||||
connection.sendPacket(create(parsedRawXml, new GenericStanza(parsedRawXml.getName())));
|
||||
}
|
||||
return getSuccess();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Account findAccount(final String accountJid) {
|
||||
if(accountJid != null)
|
||||
for(Account account : xmppConnectionService.getAccounts())
|
||||
if(accountJid.equals(account.getJid().toBareJid().toString()))
|
||||
return account;
|
||||
return null;
|
||||
}
|
||||
|
||||
private static <T extends Element> T create(final Element element, final T packet) {
|
||||
packet.setAttributes(element.getAttributes());
|
||||
packet.setContent(element.getContent());
|
||||
packet.setChildren(element.getChildren());
|
||||
return packet;
|
||||
}
|
||||
|
||||
private final IXmppCallback newMessageReturn = new IXmppCallback() {
|
||||
@Override
|
||||
public void onReturn(final Intent result) {
|
||||
if(result.getIntExtra(RESULT_CODE, RESULT_CODE_ERROR) == RESULT_CODE_ERROR) {
|
||||
// We need to be able to load our own parcelables
|
||||
result.setExtrasClassLoader(getClassLoader());
|
||||
Log.e(Config.LOGTAG, "error calling callback: " + result.getParcelableExtra(RESULT_ERROR));
|
||||
// todo: should remove from pluginCallbacks on error or?
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public void newMessage(final Message message) {
|
||||
final int N = pluginCallbacks.beginBroadcast();
|
||||
try {
|
||||
if (N == 0)
|
||||
return;
|
||||
final String accountJid = message.getConversation().getAccount().getJid().toBareJid().toString();
|
||||
final String localPart = message.getConversation().getJid().getLocalpart();
|
||||
final String domain = message.getConversation().getJid().getDomainpart();
|
||||
Intent result = null; // lazy load this
|
||||
//for(final XmppPluginCallbackApi api : pluginCallbacks) {
|
||||
for (int i = 0; i < N; ++i) {
|
||||
final XmppPluginCallbackApi api = pluginCallbacks.getBroadcastItem(i);
|
||||
if (api.matches(accountJid, localPart, domain)) {
|
||||
if (result == null) {
|
||||
result = new Intent();
|
||||
result.setAction(ACTION_NEW_MESSAGE);
|
||||
result.putExtra(EXTRA_ACCOUNT_JID, accountJid);
|
||||
result.putExtra(EXTRA_MESSAGE_STATUS, message.getStatus());
|
||||
final String partnerJid = message.getConversation().getJid().toBareJid().toString();
|
||||
// need to set from/to based on status
|
||||
if (message.getStatus() == 0) {
|
||||
result.putExtra(EXTRA_MESSAGE_TO, accountJid);
|
||||
result.putExtra(EXTRA_MESSAGE_FROM, partnerJid);
|
||||
} else {
|
||||
result.putExtra(EXTRA_MESSAGE_FROM, accountJid);
|
||||
result.putExtra(EXTRA_MESSAGE_TO, partnerJid);
|
||||
}
|
||||
result.putExtra(EXTRA_MESSAGE_BODY, message.getBody());
|
||||
}
|
||||
api.executeApiAsync(result, null, null, newMessageReturn);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
pluginCallbacks.finishBroadcast();
|
||||
}
|
||||
}
|
||||
}
|
@ -34,6 +34,7 @@ import android.util.Log;
|
||||
import android.util.LruCache;
|
||||
import android.util.Pair;
|
||||
|
||||
import eu.siacs.conversations.remote.XmppPluginService;
|
||||
import net.java.otr4j.OtrException;
|
||||
import net.java.otr4j.session.Session;
|
||||
import net.java.otr4j.session.SessionID;
|
||||
@ -166,6 +167,7 @@ public class XmppConnectionService extends Service {
|
||||
private final HashSet<Jid> mLowPingTimeoutMode = new HashSet<>();
|
||||
|
||||
private long mLastActivity = 0;
|
||||
private XmppPluginService xmppPluginService;
|
||||
|
||||
public DatabaseBackend databaseBackend;
|
||||
private ContentObserver contactObserver = new ContentObserver(null) {
|
||||
@ -1279,10 +1281,12 @@ public class XmppConnectionService extends Service {
|
||||
} else {
|
||||
if (addToConversation) {
|
||||
conversation.add(message);
|
||||
this.newMessage(message);
|
||||
}
|
||||
if (saveInDb) {
|
||||
databaseBackend.createMessage(message);
|
||||
} else if (message.edited()) {
|
||||
// todo: wtf to do with edited messages? SOL I guess?
|
||||
databaseBackend.updateMessage(message, message.getEditedId());
|
||||
}
|
||||
updateConversationUi();
|
||||
@ -3926,6 +3930,19 @@ public class XmppConnectionService extends Service {
|
||||
return mShortcutService;
|
||||
}
|
||||
|
||||
public void setXmppPluginService(final XmppPluginService xmppPluginService) {
|
||||
this.xmppPluginService = xmppPluginService;
|
||||
}
|
||||
|
||||
public void newMessage(final Message message) {
|
||||
if(xmppPluginService != null)
|
||||
try {
|
||||
xmppPluginService.newMessage(message);
|
||||
} catch(Exception e) {
|
||||
Log.e(Config.LOGTAG, "error sending message to xmppPluginService", e);
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnMamPreferencesFetched {
|
||||
void onPreferencesFetched(Element prefs);
|
||||
|
||||
|
@ -11,6 +11,7 @@ import org.xmlpull.v1.XmlPullParserException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
|
||||
import eu.siacs.conversations.Config;
|
||||
|
||||
@ -18,6 +19,7 @@ public class XmlReader {
|
||||
private XmlPullParser parser;
|
||||
private PowerManager.WakeLock wakeLock;
|
||||
private InputStream is;
|
||||
private boolean inputSet = false;
|
||||
|
||||
public XmlReader(WakeLock wakeLock) {
|
||||
this.parser = Xml.newPullParser();
|
||||
@ -29,11 +31,24 @@ public class XmlReader {
|
||||
this.wakeLock = wakeLock;
|
||||
}
|
||||
|
||||
public XmlReader(final Reader input) throws IOException {
|
||||
this((WakeLock) null);
|
||||
if(input == null)
|
||||
throw new IOException();
|
||||
this.inputSet = true;
|
||||
try {
|
||||
parser.setInput(input);
|
||||
} catch (XmlPullParserException e) {
|
||||
throw new IOException("error resetting parser");
|
||||
}
|
||||
}
|
||||
|
||||
public void setInputStream(InputStream inputStream) throws IOException {
|
||||
if (inputStream == null) {
|
||||
throw new IOException();
|
||||
}
|
||||
this.is = inputStream;
|
||||
this.inputSet = true;
|
||||
try {
|
||||
parser.setInput(new InputStreamReader(this.is));
|
||||
} catch (XmlPullParserException e) {
|
||||
@ -53,7 +68,7 @@ public class XmlReader {
|
||||
}
|
||||
|
||||
public Tag readTag() throws XmlPullParserException, IOException {
|
||||
if (wakeLock.isHeld()) {
|
||||
if (wakeLock != null && wakeLock.isHeld()) {
|
||||
try {
|
||||
wakeLock.release();
|
||||
} catch (RuntimeException re) {
|
||||
@ -61,8 +76,10 @@ public class XmlReader {
|
||||
}
|
||||
}
|
||||
try {
|
||||
while (this.is != null && parser.next() != XmlPullParser.END_DOCUMENT) {
|
||||
while (inputSet && parser.next() != XmlPullParser.END_DOCUMENT) {
|
||||
if(wakeLock != null) {
|
||||
wakeLock.acquire();
|
||||
}
|
||||
if (parser.getEventType() == XmlPullParser.START_TAG) {
|
||||
Tag tag = Tag.start(parser.getName());
|
||||
final String xmlns = parser.getNamespace();
|
||||
@ -90,7 +107,7 @@ public class XmlReader {
|
||||
} catch (Throwable throwable) {
|
||||
throw new IOException("xml parser mishandled "+throwable.getClass().getSimpleName()+"("+throwable.getMessage()+")", throwable);
|
||||
} finally {
|
||||
if (wakeLock.isHeld()) {
|
||||
if (wakeLock != null && wakeLock.isHeld()) {
|
||||
try {
|
||||
wakeLock.release();
|
||||
} catch (RuntimeException re) {
|
||||
@ -128,4 +145,29 @@ public class XmlReader {
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
public Element nextWholeElement() throws XmlPullParserException, IOException {
|
||||
final Tag currentTag = this.readTag();
|
||||
if(currentTag == null)
|
||||
return null;
|
||||
final Element element = new Element(currentTag.name);
|
||||
int tagCount = 1;
|
||||
element.setAttributes(currentTag.getAttributes());
|
||||
Tag nextTag = this.readTag();
|
||||
if (nextTag == null) {
|
||||
throw new IOException("interrupted mid tag");
|
||||
}
|
||||
while (!nextTag.isEnd(element.getName()) && --tagCount < 1) {
|
||||
if (nextTag.isStart(element.getName()))
|
||||
++tagCount;
|
||||
if (!nextTag.isNo()) {
|
||||
element.addChild(this.readElement(nextTag));
|
||||
}
|
||||
nextTag = this.readTag();
|
||||
if (nextTag == null) {
|
||||
throw new IOException("interrupted mid tag");
|
||||
}
|
||||
}
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
@ -1364,7 +1364,7 @@ public class XmppConnection implements Runnable {
|
||||
this.sendPacket(packet);
|
||||
}
|
||||
|
||||
private synchronized void sendPacket(final AbstractStanza packet) {
|
||||
public synchronized void sendPacket(final AbstractStanza packet) {
|
||||
if (stanzasSent == Integer.MAX_VALUE) {
|
||||
resetStreamId();
|
||||
disconnect(true);
|
||||
|
@ -227,7 +227,7 @@ public final class Jid {
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final Jid jid = (Jid) o;
|
||||
|
||||
// todo: this is a bug, hashcodes could be the same for different JIDs...
|
||||
return jid.hashCode() == this.hashCode();
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,7 @@
|
||||
package eu.siacs.conversations.xmpp.stanzas;
|
||||
|
||||
public class GenericStanza extends AbstractStanza {
|
||||
public GenericStanza(final String name) {
|
||||
super(name);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user