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
0c97609286
commit
484194212a
@ -227,6 +227,21 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<!-- Xmpp Remote API, this service has explicitly no permission requirements
|
||||||
|
because we are using our own package based allow/disallow system
|
||||||
|
|
||||||
|
android:process=":remote_api"
|
||||||
|
-->
|
||||||
|
<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>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -578,7 +578,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
|||||||
}
|
}
|
||||||
|
|
||||||
// todo: hook here but prepend? put this off for later
|
// todo: hook here but prepend? put this off for later
|
||||||
SMSReceiver.newMessage(message);
|
mXmppConnectionService.newMessage(message);
|
||||||
if (query != null && query.getPagingOrder() == MessageArchiveService.PagingOrder.REVERSE) {
|
if (query != null && query.getPagingOrder() == MessageArchiveService.PagingOrder.REVERSE) {
|
||||||
conversation.prepend(message);
|
conversation.prepend(message);
|
||||||
} else {
|
} 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -68,6 +68,8 @@ public class SMSReceiver extends BroadcastReceiver {
|
|||||||
forwardedMsg.setFrom(fromJid);
|
forwardedMsg.setFrom(fromJid);
|
||||||
forwardedMsg.setBody(message);
|
forwardedMsg.setBody(message);
|
||||||
|
|
||||||
|
Log.d(Config.LOGTAG, "smsXml: " + packet.toString());
|
||||||
|
|
||||||
xmppConnectionService.sendMessagePacket(getAccount(), packet);
|
xmppConnectionService.sendMessagePacket(getAccount(), packet);
|
||||||
|
|
||||||
//---send a broadcast intent to update the SMS received in the activity---
|
//---send a broadcast intent to update the SMS received in the activity---
|
||||||
|
@ -5,10 +5,7 @@ import android.annotation.TargetApi;
|
|||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.Context;
|
import android.content.*;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
@ -34,6 +31,7 @@ import android.util.Log;
|
|||||||
import android.util.LruCache;
|
import android.util.LruCache;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.remote.XmppPluginService;
|
||||||
import net.java.otr4j.OtrException;
|
import net.java.otr4j.OtrException;
|
||||||
import net.java.otr4j.session.Session;
|
import net.java.otr4j.session.Session;
|
||||||
import net.java.otr4j.session.SessionID;
|
import net.java.otr4j.session.SessionID;
|
||||||
@ -139,6 +137,7 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
|||||||
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
|
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
|
||||||
import me.leolin.shortcutbadger.ShortcutBadger;
|
import me.leolin.shortcutbadger.ShortcutBadger;
|
||||||
|
import org.openintents.xmpp.IXmppPluginCallback;
|
||||||
|
|
||||||
public class XmppConnectionService extends Service {
|
public class XmppConnectionService extends Service {
|
||||||
|
|
||||||
@ -166,6 +165,7 @@ public class XmppConnectionService extends Service {
|
|||||||
private final HashSet<Jid> mLowPingTimeoutMode = new HashSet<>();
|
private final HashSet<Jid> mLowPingTimeoutMode = new HashSet<>();
|
||||||
|
|
||||||
private long mLastActivity = 0;
|
private long mLastActivity = 0;
|
||||||
|
private XmppPluginService xmppPluginService;
|
||||||
|
|
||||||
public XmppConnectionService() {
|
public XmppConnectionService() {
|
||||||
SMSReceiver.xmppConnectionService = this;
|
SMSReceiver.xmppConnectionService = this;
|
||||||
@ -1283,7 +1283,7 @@ public class XmppConnectionService extends Service {
|
|||||||
} else {
|
} else {
|
||||||
if (addToConversation) {
|
if (addToConversation) {
|
||||||
conversation.add(message);
|
conversation.add(message);
|
||||||
SMSReceiver.newMessage(message);
|
this.newMessage(message);
|
||||||
}
|
}
|
||||||
if (saveInDb) {
|
if (saveInDb) {
|
||||||
databaseBackend.createMessage(message);
|
databaseBackend.createMessage(message);
|
||||||
@ -3932,6 +3932,20 @@ public class XmppConnectionService extends Service {
|
|||||||
return mShortcutService;
|
return mShortcutService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setXmppPluginService(final XmppPluginService xmppPluginService) {
|
||||||
|
this.xmppPluginService = xmppPluginService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void newMessage(final Message message) {
|
||||||
|
SMSReceiver.newMessage(message);
|
||||||
|
if(xmppPluginService != null)
|
||||||
|
try {
|
||||||
|
xmppPluginService.newMessage(message);
|
||||||
|
} catch(Exception e) {
|
||||||
|
Log.e(Config.LOGTAG, "error sending message to xmppPluginService", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public interface OnMamPreferencesFetched {
|
public interface OnMamPreferencesFetched {
|
||||||
void onPreferencesFetched(Element prefs);
|
void onPreferencesFetched(Element prefs);
|
||||||
|
|
||||||
|
@ -8,9 +8,7 @@ import android.util.Xml;
|
|||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.*;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
|
|
||||||
import eu.siacs.conversations.Config;
|
import eu.siacs.conversations.Config;
|
||||||
|
|
||||||
@ -18,6 +16,7 @@ public class XmlReader {
|
|||||||
private XmlPullParser parser;
|
private XmlPullParser parser;
|
||||||
private PowerManager.WakeLock wakeLock;
|
private PowerManager.WakeLock wakeLock;
|
||||||
private InputStream is;
|
private InputStream is;
|
||||||
|
private boolean inputSet = false;
|
||||||
|
|
||||||
public XmlReader(WakeLock wakeLock) {
|
public XmlReader(WakeLock wakeLock) {
|
||||||
this.parser = Xml.newPullParser();
|
this.parser = Xml.newPullParser();
|
||||||
@ -29,11 +28,24 @@ public class XmlReader {
|
|||||||
this.wakeLock = wakeLock;
|
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 {
|
public void setInputStream(InputStream inputStream) throws IOException {
|
||||||
if (inputStream == null) {
|
if (inputStream == null) {
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
this.is = inputStream;
|
this.is = inputStream;
|
||||||
|
this.inputSet = true;
|
||||||
try {
|
try {
|
||||||
parser.setInput(new InputStreamReader(this.is));
|
parser.setInput(new InputStreamReader(this.is));
|
||||||
} catch (XmlPullParserException e) {
|
} catch (XmlPullParserException e) {
|
||||||
@ -53,7 +65,7 @@ public class XmlReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Tag readTag() throws XmlPullParserException, IOException {
|
public Tag readTag() throws XmlPullParserException, IOException {
|
||||||
if (wakeLock.isHeld()) {
|
if (wakeLock != null && wakeLock.isHeld()) {
|
||||||
try {
|
try {
|
||||||
wakeLock.release();
|
wakeLock.release();
|
||||||
} catch (RuntimeException re) {
|
} catch (RuntimeException re) {
|
||||||
@ -61,8 +73,10 @@ public class XmlReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
while (this.is != null && parser.next() != XmlPullParser.END_DOCUMENT) {
|
while (inputSet && parser.next() != XmlPullParser.END_DOCUMENT) {
|
||||||
|
if(wakeLock != null) {
|
||||||
wakeLock.acquire();
|
wakeLock.acquire();
|
||||||
|
}
|
||||||
if (parser.getEventType() == XmlPullParser.START_TAG) {
|
if (parser.getEventType() == XmlPullParser.START_TAG) {
|
||||||
Tag tag = Tag.start(parser.getName());
|
Tag tag = Tag.start(parser.getName());
|
||||||
final String xmlns = parser.getNamespace();
|
final String xmlns = parser.getNamespace();
|
||||||
@ -90,7 +104,7 @@ public class XmlReader {
|
|||||||
} catch (Throwable throwable) {
|
} catch (Throwable throwable) {
|
||||||
throw new IOException("xml parser mishandled "+throwable.getClass().getSimpleName()+"("+throwable.getMessage()+")", throwable);
|
throw new IOException("xml parser mishandled "+throwable.getClass().getSimpleName()+"("+throwable.getMessage()+")", throwable);
|
||||||
} finally {
|
} finally {
|
||||||
if (wakeLock.isHeld()) {
|
if (wakeLock != null && wakeLock.isHeld()) {
|
||||||
try {
|
try {
|
||||||
wakeLock.release();
|
wakeLock.release();
|
||||||
} catch (RuntimeException re) {
|
} catch (RuntimeException re) {
|
||||||
@ -128,4 +142,29 @@ public class XmlReader {
|
|||||||
}
|
}
|
||||||
return element;
|
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);
|
this.sendPacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void sendPacket(final AbstractStanza packet) {
|
public synchronized void sendPacket(final AbstractStanza packet) {
|
||||||
if (stanzasSent == Integer.MAX_VALUE) {
|
if (stanzasSent == Integer.MAX_VALUE) {
|
||||||
resetStreamId();
|
resetStreamId();
|
||||||
disconnect(true);
|
disconnect(true);
|
||||||
|
@ -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