aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/eu/siacs/conversations/crypto/OtrEngine.java2
-rw-r--r--src/eu/siacs/conversations/entities/MucOptions.java8
-rw-r--r--src/eu/siacs/conversations/services/EventReceiver.java9
-rw-r--r--src/eu/siacs/conversations/services/XmppConnectionService.java403
-rw-r--r--src/eu/siacs/conversations/ui/ConversationFragment.java4
-rw-r--r--src/eu/siacs/conversations/ui/ManageAccountActivity.java1
-rw-r--r--src/eu/siacs/conversations/ui/XmppActivity.java3
-rw-r--r--src/eu/siacs/conversations/utils/MessageParser.java2
-rw-r--r--src/eu/siacs/conversations/xml/TagWriter.java59
-rw-r--r--src/eu/siacs/conversations/xmpp/OnIqPacketReceived.java1
-rw-r--r--src/eu/siacs/conversations/xmpp/OnMessagePacketReceived.java1
-rw-r--r--src/eu/siacs/conversations/xmpp/OnPresencePacketReceived.java1
-rw-r--r--src/eu/siacs/conversations/xmpp/PresencePacket.java13
-rw-r--r--src/eu/siacs/conversations/xmpp/XmppConnection.java173
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java34
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/IqPacket.java (renamed from src/eu/siacs/conversations/xmpp/IqPacket.java)9
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java (renamed from src/eu/siacs/conversations/xmpp/MessagePacket.java)24
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/PresencePacket.java9
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/streammgmt/AckPacket.java13
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/streammgmt/EnablePacket.java13
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/streammgmt/RequestPacket.java12
-rw-r--r--src/eu/siacs/conversations/xmpp/stanzas/streammgmt/ResumePacket.java14
22 files changed, 523 insertions, 285 deletions
diff --git a/src/eu/siacs/conversations/crypto/OtrEngine.java b/src/eu/siacs/conversations/crypto/OtrEngine.java
index 23af94e7..300de735 100644
--- a/src/eu/siacs/conversations/crypto/OtrEngine.java
+++ b/src/eu/siacs/conversations/crypto/OtrEngine.java
@@ -20,7 +20,7 @@ import android.util.Log;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.persistance.DatabaseBackend;
import eu.siacs.conversations.xml.Element;
-import eu.siacs.conversations.xmpp.MessagePacket;
+import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
import net.java.otr4j.OtrEngineHost;
import net.java.otr4j.OtrException;
diff --git a/src/eu/siacs/conversations/entities/MucOptions.java b/src/eu/siacs/conversations/entities/MucOptions.java
index d04fea16..9bc6fb21 100644
--- a/src/eu/siacs/conversations/entities/MucOptions.java
+++ b/src/eu/siacs/conversations/entities/MucOptions.java
@@ -5,7 +5,7 @@ import java.util.List;
import eu.siacs.conversations.entities.MucOptions.User;
import eu.siacs.conversations.xml.Element;
-import eu.siacs.conversations.xmpp.PresencePacket;
+import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
import android.annotation.SuppressLint;
import android.util.Log;
@@ -144,7 +144,11 @@ public class MucOptions {
if (split.length == 2) {
return split[1];
} else {
- return conversation.getAccount().getUsername();
+ if (conversation.getAccount()!=null) {
+ return conversation.getAccount().getUsername();
+ } else {
+ return null;
+ }
}
}
diff --git a/src/eu/siacs/conversations/services/EventReceiver.java b/src/eu/siacs/conversations/services/EventReceiver.java
index 99b9f3c7..a13d51f2 100644
--- a/src/eu/siacs/conversations/services/EventReceiver.java
+++ b/src/eu/siacs/conversations/services/EventReceiver.java
@@ -8,11 +8,10 @@ public class EventReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Intent mIntentForService = new Intent(context,
XmppConnectionService.class);
- mIntentForService.putExtra("ping", intent.getBooleanExtra("ping",false));
- if ((intent.getAction() != null)
- && (intent.getAction()
- .equals("android.intent.action.BOOT_COMPLETED"))) {
-
+ if (intent.getAction() != null) {
+ mIntentForService.setAction(intent.getAction());
+ } else {
+ mIntentForService.setAction("other");
}
context.startService(mIntentForService);
}
diff --git a/src/eu/siacs/conversations/services/XmppConnectionService.java b/src/eu/siacs/conversations/services/XmppConnectionService.java
index 5adfa981..5fa0c850 100644
--- a/src/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/eu/siacs/conversations/services/XmppConnectionService.java
@@ -7,7 +7,6 @@ import java.util.Hashtable;
import java.util.List;
import java.util.Random;
-import org.json.JSONException;
import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpServiceConnection;
@@ -35,15 +34,15 @@ import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener;
import eu.siacs.conversations.utils.PhoneHelper;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xml.Element;
-import eu.siacs.conversations.xmpp.IqPacket;
-import eu.siacs.conversations.xmpp.MessagePacket;
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
import eu.siacs.conversations.xmpp.OnPresencePacketReceived;
import eu.siacs.conversations.xmpp.OnStatusChanged;
import eu.siacs.conversations.xmpp.OnTLSExceptionReceived;
-import eu.siacs.conversations.xmpp.PresencePacket;
import eu.siacs.conversations.xmpp.XmppConnection;
+import eu.siacs.conversations.xmpp.stanzas.IqPacket;
+import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
+import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
@@ -70,9 +69,10 @@ public class XmppConnectionService extends Service {
public long startDate;
- private static final int PING_INTERVAL = 300;
+ private static final int PING_MAX_INTERVAL = 300;
+ private static final int PING_MIN_INTERVAL = 10;
private static final int PING_TIMEOUT = 2;
-
+
private List<Account> accounts;
private List<Conversation> conversations = null;
@@ -80,10 +80,11 @@ public class XmppConnectionService extends Service {
private OnAccountListChangedListener accountChangedListener = null;
private OnTLSExceptionReceived tlsException = null;
- public void setOnTLSExceptionReceivedListener(OnTLSExceptionReceived listener) {
+ public void setOnTLSExceptionReceivedListener(
+ OnTLSExceptionReceived listener) {
tlsException = listener;
}
-
+
private Random mRandom = new Random(System.currentTimeMillis());
private ContentObserver contactObserver = new ContentObserver(null) {
@@ -115,7 +116,7 @@ public class XmppConnectionService extends Service {
&& (packet.getBody().startsWith("?OTR"))) {
message = MessageParser.parseOtrChat(packet, account,
service);
- if (message!=null) {
+ if (message != null) {
message.markUnread();
}
} else if (packet.hasChild("body")) {
@@ -126,7 +127,9 @@ public class XmppConnectionService extends Service {
|| (packet.hasChild("sent"))) {
message = MessageParser.parseCarbonMessage(packet, account,
service);
- message.getConversation().markRead();
+ if (message != null) {
+ message.getConversation().markRead();
+ }
notify = false;
}
@@ -144,7 +147,7 @@ public class XmppConnectionService extends Service {
} else if (packet.getType() == MessagePacket.TYPE_ERROR) {
message = MessageParser.parseError(packet, account, service);
} else {
- //Log.d(LOGTAG, "unparsed message " + packet.toString());
+ // Log.d(LOGTAG, "unparsed message " + packet.toString());
}
if (message == null) {
return;
@@ -169,7 +172,8 @@ public class XmppConnectionService extends Service {
if (convChangedListener != null) {
convChangedListener.onConversationListChanged();
} else {
- UIHelper.updateNotification(getApplicationContext(), getConversations(), notify);
+ UIHelper.updateNotification(getApplicationContext(),
+ getConversations(), notify);
}
}
};
@@ -195,20 +199,12 @@ public class XmppConnectionService extends Service {
if (convChangedListener != null) {
convChangedListener.onConversationListChanged();
}
- if (account.getKeys().has("pgp_signature")) {
- try {
- sendPgpPresence(account, account.getKeys().getString("pgp_signature"));
- } catch (JSONException e) {
- //
- }
- }
- scheduleWakeupCall(PING_INTERVAL, true);
+ scheduleWakeupCall(PING_MAX_INTERVAL, true);
} else if (account.getStatus() == Account.STATUS_OFFLINE) {
- Log.d(LOGTAG,"onStatusChanged offline");
databaseBackend.clearPresences(account);
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
- int timeToReconnect = mRandom.nextInt(50)+10;
- scheduleWakeupCall(timeToReconnect,false);
+ int timeToReconnect = mRandom.nextInt(50) + 10;
+ scheduleWakeupCall(timeToReconnect, false);
}
}
@@ -220,13 +216,17 @@ public class XmppConnectionService extends Service {
@Override
public void onPresencePacketReceived(Account account,
PresencePacket packet) {
- if (packet.hasChild("x")&&(packet.findChild("x").getAttribute("xmlns").startsWith("http://jabber.org/protocol/muc"))) {
- Conversation muc = findMuc(packet.getAttribute("from").split("/")[0]);
- if (muc!=null) {
+ if (packet.hasChild("x")
+ && (packet.findChild("x").getAttribute("xmlns")
+ .startsWith("http://jabber.org/protocol/muc"))) {
+ Conversation muc = findMuc(packet.getAttribute("from").split(
+ "/")[0]);
+ if (muc != null) {
int error = muc.getMucOptions().getError();
muc.getMucOptions().processPacket(packet);
- if ((muc.getMucOptions().getError()!=error)&&(convChangedListener!=null)) {
- Log.d(LOGTAG,"muc error status changed");
+ if ((muc.getMucOptions().getError() != error)
+ && (convChangedListener != null)) {
+ Log.d(LOGTAG, "muc error status changed");
convChangedListener.onConversationListChanged();
}
}
@@ -252,15 +252,17 @@ public class XmppConnectionService extends Service {
contact.updatePresence(fromParts[1], Presences.DND);
}
PgpEngine pgp = getPgpEngine();
- if (pgp!=null) {
+ if (pgp != null) {
Element x = packet.findChild("x");
if ((x != null)
- && (x.getAttribute("xmlns").equals("jabber:x:signed"))) {
+ && (x.getAttribute("xmlns")
+ .equals("jabber:x:signed"))) {
try {
- contact.setPgpKeyId(pgp.fetchKeyId(packet.findChild("status")
- .getContent(), x.getContent()));
+ contact.setPgpKeyId(pgp.fetchKeyId(packet
+ .findChild("status").getContent(), x
+ .getContent()));
} catch (OpenPgpException e) {
- Log.d(LOGTAG,"faulty pgp. just ignore");
+ Log.d(LOGTAG, "faulty pgp. just ignore");
}
}
}
@@ -290,7 +292,7 @@ public class XmppConnectionService extends Service {
// TODO: ask user to handle it maybe
}
} else {
- Log.d(LOGTAG, packet.toString());
+ //Log.d(LOGTAG, packet.toString());
}
replaceContactInConversation(contact.getJid(), contact);
}
@@ -314,6 +316,8 @@ public class XmppConnectionService extends Service {
private OpenPgpServiceConnection pgpServiceConnection;
private PgpEngine mPgpEngine = null;
+ private Intent pingIntent;
+ private PendingIntent pendingPingIntent = null;
public PgpEngine getPgpEngine() {
if (pgpServiceConnection.isBound()) {
@@ -330,7 +334,7 @@ public class XmppConnectionService extends Service {
}
protected Conversation findMuc(String name) {
- for(Conversation conversation : this.conversations) {
+ for (Conversation conversation : this.conversations) {
if (conversation.getContactJid().split("/")[0].equals(name)) {
return conversation;
}
@@ -391,34 +395,64 @@ public class XmppConnectionService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
- ConnectivityManager cm = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+ Log.d(LOGTAG,"calling start service. caller was:"+intent.getAction());
+
+ // internet and online last_received - list_ping >= max_ping : ping
+ // internet and online last_ping - last_received >= ping_timeout :
+ // reconnect
+ // internet and offline and enabled : connect (Threat start)
+ // no internet - set no internet
+
+ ConnectivityManager cm = (ConnectivityManager) getApplicationContext()
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null
&& activeNetwork.isConnected();
+
for (Account account : accounts) {
- if (!isConnected) {
- account.setStatus(Account.STATUS_NO_INTERNET);
- } else {
- if (account.getStatus() == Account.STATUS_NO_INTERNET) {
- account.setStatus(Account.STATUS_OFFLINE);
- }
- }
- if (accountChangedListener!=null) {
- accountChangedListener.onAccountListChangedListener();
- }
- if ((!account.isOptionSet(Account.OPTION_DISABLED))&&(isConnected)) {
- if (account.getXmppConnection() == null) {
- account.setXmppConnection(this.createConnection(account));
- }
- if (account.getStatus()==Account.STATUS_OFFLINE) {
- Thread thread = new Thread(account.getXmppConnection());
- thread.start();
+ if (!account.isOptionSet(Account.OPTION_DISABLED)) {
+ if (!isConnected) {
+ account.setStatus(Account.STATUS_NO_INTERNET);
+ if (statusListener!=null) {
+ statusListener.onStatusChanged(account);
+ }
} else {
- if (intent.getBooleanExtra("ping", false)) {
- Log.d(LOGTAG,"start service ping");
- ping(account,PING_TIMEOUT);
+ if (account.getStatus() == Account.STATUS_NO_INTERNET) {
+ account.setStatus(Account.STATUS_OFFLINE);
+ if (statusListener!=null) {
+ statusListener.onStatusChanged(account);
+ }
+ }
+
+ // TODO 3 remaining cases
+ if (account.getStatus() == Account.STATUS_ONLINE) {
+ long lastReceived = account.getXmppConnection().lastPaketReceived;
+ long lastSent = account.getXmppConnection().lastPingSent;
+ if (lastSent - lastReceived >= PING_TIMEOUT * 1000) {
+ Log.d(LOGTAG, account.getJid() + ": ping timeout");
+ this.reconnectAccount(account);
+ } else if (SystemClock.elapsedRealtime() - lastReceived >= PING_MIN_INTERVAL * 1000) {
+ account.getXmppConnection().sendPing();
+ account.getXmppConnection().lastPingSent = SystemClock.elapsedRealtime();
+ this.scheduleWakeupCall(2, false);
+ }
+ } else if (account.getStatus() == Account.STATUS_OFFLINE) {
+ if (account.getXmppConnection() == null) {
+ account.setXmppConnection(this
+ .createConnection(account));
+ }
+ account.getXmppConnection().lastPingSent = SystemClock.elapsedRealtime();
+ new Thread(account.getXmppConnection()).start();
+ } else {
+ Log.d(LOGTAG,account.getJid()+": status="+account.getStatus());
+ // TODO notify user of ssl cert problem or auth problem or what ever
}
+ //in any case. reschedule wakup call
+ this.scheduleWakeupCall(PING_MAX_INTERVAL, true);
+ }
+ if (accountChangedListener != null) {
+ accountChangedListener.onAccountListChangedListener();
}
}
}
@@ -436,8 +470,7 @@ public class XmppConnectionService extends Service {
this.pgpServiceConnection = new OpenPgpServiceConnection(
getApplicationContext(), "org.sufficientlysecure.keychain");
this.pgpServiceConnection.bindToService();
-
-
+
}
@Override
@@ -445,26 +478,47 @@ public class XmppConnectionService extends Service {
super.onDestroy();
for (Account account : accounts) {
if (account.getXmppConnection() != null) {
- disconnect(account);
+ disconnect(account, true);
}
}
}
-
- protected void scheduleWakeupCall(int seconds,boolean ping) {
+
+ protected void scheduleWakeupCall(int seconds, boolean ping) {
+ long timeToWake = SystemClock.elapsedRealtime() + seconds * 1000;
Context context = getApplicationContext();
- AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
- Intent intent = new Intent(context, EventReceiver.class);
- intent.putExtra("ping", ping);
- PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
- alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() +
- seconds * 1000, alarmIntent);
+ AlarmManager alarmManager = (AlarmManager) context
+ .getSystemService(Context.ALARM_SERVICE);
+
+
+
if (ping) {
- Log.d(LOGTAG,"schedule ping in "+seconds+" seconds");
+ if (this.pingIntent==null) {
+ this.pingIntent = new Intent(context, EventReceiver.class);
+ this.pingIntent.setAction("ping");
+ this.pingIntent.putExtra("time", timeToWake);
+ this.pendingPingIntent = PendingIntent.getBroadcast(context, 0,
+ this.pingIntent, 0);
+ alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,timeToWake, pendingPingIntent);
+ //Log.d(LOGTAG,"schedule ping in "+seconds+" seconds");
+ } else {
+ long scheduledTime = this.pingIntent.getLongExtra("time", 0);
+ if (scheduledTime<SystemClock.elapsedRealtime() || (scheduledTime > timeToWake)) {
+ this.pingIntent.putExtra("time", timeToWake);
+ alarmManager.cancel(this.pendingPingIntent);
+ this.pendingPingIntent = PendingIntent.getBroadcast(context, 0,
+ this.pingIntent, 0);
+ alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,timeToWake, pendingPingIntent);
+ //Log.d(LOGTAG,"reschedule old ping to ping in "+seconds+" seconds");
+ }
+ }
} else {
- Log.d(LOGTAG,"schedule reconnect in "+seconds+" seconds");
+ Intent intent = new Intent(context, EventReceiver.class);
+ intent.setAction("ping_check");
+ PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0,
+ intent, 0);
+ alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,timeToWake, alarmIntent);
}
-
+
}
public XmppConnection createConnection(Account account) {
@@ -475,16 +529,19 @@ public class XmppConnectionService extends Service {
connection.setOnPresencePacketReceivedListener(this.presenceListener);
connection
.setOnUnregisteredIqPacketReceivedListener(this.unknownIqListener);
- connection.setOnTLSExceptionReceivedListener(new OnTLSExceptionReceived() {
-
- @Override
- public void onTLSExceptionReceived(String fingerprint, Account account) {
- Log.d(LOGTAG,"tls exception arrived in service");
- if (tlsException!=null) {
- tlsException.onTLSExceptionReceived(fingerprint,account);
- }
- }
- });
+ connection
+ .setOnTLSExceptionReceivedListener(new OnTLSExceptionReceived() {
+
+ @Override
+ public void onTLSExceptionReceived(String fingerprint,
+ Account account) {
+ Log.d(LOGTAG, "tls exception arrived in service");
+ if (tlsException != null) {
+ tlsException.onTLSExceptionReceived(fingerprint,
+ account);
+ }
+ }
+ });
return connection;
}
@@ -629,9 +686,10 @@ public class XmppConnectionService extends Service {
Element query = new Element("query");
query.setAttribute("xmlns", "jabber:iq:roster");
if (!"".equals(account.getRosterVersion())) {
- Log.d(LOGTAG,account.getJid()+ ": fetching roster version "+account.getRosterVersion());
+ Log.d(LOGTAG, account.getJid() + ": fetching roster version "
+ + account.getRosterVersion());
} else {
- Log.d(LOGTAG,account.getJid()+": fetching roster");
+ Log.d(LOGTAG, account.getJid() + ": fetching roster");
}
query.setAttribute("ver", account.getRosterVersion());
iqPacket.addChild(query);
@@ -643,7 +701,8 @@ public class XmppConnectionService extends Service {
IqPacket packet) {
Element roster = packet.findChild("query");
if (roster != null) {
- Log.d(LOGTAG,account.getJid()+": processing roster");
+ Log.d(LOGTAG, account.getJid()
+ + ": processing roster");
processRosterItems(account, roster);
StringBuilder mWhere = new StringBuilder();
mWhere.append("jid NOT IN(");
@@ -668,7 +727,8 @@ public class XmppConnectionService extends Service {
}
} else {
- Log.d(LOGTAG,account.getJid()+": empty roster returend");
+ Log.d(LOGTAG, account.getJid()
+ + ": empty roster returend");
}
mergePhoneContactsWithRoster(new OnPhoneContactsMerged() {
@@ -864,7 +924,7 @@ public class XmppConnectionService extends Service {
public void deleteAccount(Account account) {
Log.d(LOGTAG, "called delete account");
if (account.getXmppConnection() != null) {
- this.disconnect(account);
+ this.disconnect(account, false);
}
databaseBackend.deleteAccount(account);
this.accounts.remove(account);
@@ -913,8 +973,7 @@ public class XmppConnectionService extends Service {
nick = conversation.getAccount().getUsername();
}
PresencePacket packet = new PresencePacket();
- packet.setAttribute("to", muc + "/"
- + nick);
+ packet.setAttribute("to", muc + "/" + nick);
Element x = new Element("x");
x.setAttribute("xmlns", "http://jabber.org/protocol/muc");
if (conversation.getMessages().size() != 0) {
@@ -928,21 +987,22 @@ public class XmppConnectionService extends Service {
conversation.getAccount().getXmppConnection()
.sendPresencePacket(packet);
}
-
+
private OnRenameListener renameListener = null;
private boolean pongReceived;
+
public void setOnRenameListener(OnRenameListener listener) {
this.renameListener = listener;
}
-
+
public void renameInMuc(final Conversation conversation, final String nick) {
final MucOptions options = conversation.getMucOptions();
if (options.online()) {
options.setOnRenameListener(new OnRenameListener() {
-
+
@Override
public void onRename(boolean success) {
- if (renameListener!=null) {
+ if (renameListener != null) {
renameListener.onRename(success);
}
if (success) {
@@ -951,30 +1011,36 @@ public class XmppConnectionService extends Service {
}
});
PresencePacket packet = new PresencePacket();
- packet.setAttribute("to", conversation.getContactJid().split("/")[0]+"/"+nick);
+ packet.setAttribute("to",
+ conversation.getContactJid().split("/")[0] + "/" + nick);
packet.setAttribute("from", conversation.getAccount().getFullJid());
-
- packet = conversation.getAccount().getXmppConnection().sendPresencePacket(packet, new OnPresencePacketReceived() {
-
- @Override
- public void onPresencePacketReceived(Account account, PresencePacket packet) {
- final boolean changed;
- String type = packet.getAttribute("type");
- changed = (!"error".equals(type));
- if (!changed) {
- options.getOnRenameListener().onRename(false);
- } else {
- if (type==null) {
- options.getOnRenameListener().onRename(true);
- options.setNick(packet.getAttribute("from").split("/")[1]);
- } else {
- options.processPacket(packet);
+
+ conversation.getAccount().getXmppConnection()
+ .sendPresencePacket(packet, new OnPresencePacketReceived() {
+
+ @Override
+ public void onPresencePacketReceived(Account account,
+ PresencePacket packet) {
+ final boolean changed;
+ String type = packet.getAttribute("type");
+ changed = (!"error".equals(type));
+ if (!changed) {
+ options.getOnRenameListener().onRename(false);
+ } else {
+ if (type == null) {
+ options.getOnRenameListener()
+ .onRename(true);
+ options.setNick(packet.getAttribute("from")
+ .split("/")[1]);
+ } else {
+ options.processPacket(packet);
+ }
+ }
}
- }
- }
- });
+ });
} else {
- String jid = conversation.getContactJid().split("/")[0]+"/"+nick;
+ String jid = conversation.getContactJid().split("/")[0] + "/"
+ + nick;
conversation.setContactJid(jid);
databaseBackend.updateConversation(conversation);
if (conversation.getAccount().getStatus() == Account.STATUS_ONLINE) {
@@ -987,31 +1053,46 @@ public class XmppConnectionService extends Service {
PresencePacket packet = new PresencePacket();
packet.setAttribute("to", conversation.getContactJid());
packet.setAttribute("from", conversation.getAccount().getFullJid());
- packet.setAttribute("type","unavailable");
- conversation.getAccount().getXmppConnection().sendPresencePacket(packet);
+ packet.setAttribute("type", "unavailable");
+ conversation.getAccount().getXmppConnection()
+ .sendPresencePacket(packet);
conversation.getMucOptions().setOffline();
}
- public void disconnect(Account account) {
- List<Conversation> conversations = getConversations();
- for (int i = 0; i < conversations.size(); i++) {
- Conversation conversation = conversations.get(i);
- if (conversation.getAccount() == account) {
- if (conversation.getMode() == Conversation.MODE_MULTI) {
- leaveMuc(conversation);
- } else {
- try {
- conversation.endOtrIfNeeded();
- } catch (OtrException e) {
- Log.d(LOGTAG, "error ending otr session for "
- + conversation.getName());
+ public void disconnect(final Account account, boolean blocking) {
+ if ((account.getStatus() == Account.STATUS_ONLINE)||(account.getStatus() == Account.STATUS_DISABLED)) {
+ List<Conversation> conversations = getConversations();
+ for (int i = 0; i < conversations.size(); i++) {
+ Conversation conversation = conversations.get(i);
+ if (conversation.getAccount() == account) {
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ leaveMuc(conversation);
+ } else {
+ try {
+ conversation.endOtrIfNeeded();
+ } catch (OtrException e) {
+ Log.d(LOGTAG, "error ending otr session for "
+ + conversation.getName());
+ }
}
}
}
+ if (!blocking) {
+ new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ account.getXmppConnection().disconnect(false);
+ Log.d(LOGTAG, "disconnected account: " + account.getJid());
+ //account.setXmppConnection(null);
+ }
+ }).start();
+ } else {
+ account.getXmppConnection().disconnect(false);
+ Log.d(LOGTAG, "disconnected account: " + account.getJid());
+ //account.setXmppConnection(null);
+ }
}
- account.getXmppConnection().disconnect();
- Log.d(LOGTAG, "disconnected account: " + account.getJid());
- account.setXmppConnection(null);
}
@Override
@@ -1092,7 +1173,7 @@ public class XmppConnectionService extends Service {
Log.d(LOGTAG, packet.toString());
contact.getAccount().getXmppConnection().sendPresencePacket(packet);
}
-
+
public void sendPgpPresence(Account account, String signature) {
PresencePacket packet = new PresencePacket();
packet.setAttribute("from", account.getFullJid());
@@ -1122,7 +1203,7 @@ public class XmppConnectionService extends Service {
public Contact findContact(String uuid) {
Contact contact = this.databaseBackend.getContact(uuid);
- for(Account account : getAccounts()) {
+ for (Account account : getAccounts()) {
if (contact.getAccountUuid().equals(account.getUuid())) {
contact.setAccount(account);
}
@@ -1134,56 +1215,22 @@ public class XmppConnectionService extends Service {
this.tlsException = null;
}
- public void reconnectAccount(Account account) {
- if (account.getXmppConnection() != null) {
- disconnect(account);
- }
- if (!account.isOptionSet(Account.OPTION_DISABLED)) {
- if (account.getXmppConnection()==null) {
- account.setXmppConnection(this.createConnection(account));
- }
- Thread thread = new Thread(account.getXmppConnection());
- thread.start();
- }
- }
-
- public void ping(final Account account,final int timeout) {
- Log.d(LOGTAG,account.getJid()+": sending ping");
- IqPacket iq = new IqPacket(IqPacket.TYPE_GET);
- Element ping = new Element("ping");
- iq.setAttribute("from",account.getFullJid());
- ping.setAttribute("xmlns", "urn:xmpp:ping");
- iq.addChild(ping);
- pongReceived = false;
- account.getXmppConnection().sendIqPacket(iq, new OnIqPacketReceived() {
-
- @Override
- public void onIqPacketReceived(Account account, IqPacket packet) {
- pongReceived = true;
- }
- });
+ //TODO dont let thread sleep but schedule wake up
+ public void reconnectAccount(final Account account) {
new Thread(new Runnable() {
-
+
@Override
public void run() {
- int i = 0;
- while(i <= (5 * timeout)) {
- if (pongReceived) {
- scheduleWakeupCall(PING_INTERVAL,true);
- break;
- }
- try {
- Thread.sleep(200);
- } catch (InterruptedException e) {
-
- }
- ++i;
+ if (account.getXmppConnection() != null) {
+ disconnect(account, true);
}
- if (!pongReceived) {
- Log.d("xmppService",account.getJid()+" no pong after "+timeout+" seconds");
- reconnectAccount(account);
+ if (!account.isOptionSet(Account.OPTION_DISABLED)) {
+ if (account.getXmppConnection() == null) {
+ account.setXmppConnection(createConnection(account));
+ }
+ Thread thread = new Thread(account.getXmppConnection());
+ thread.start();
}
-
}
}).start();
}
diff --git a/src/eu/siacs/conversations/ui/ConversationFragment.java b/src/eu/siacs/conversations/ui/ConversationFragment.java
index b49106f1..3373479a 100644
--- a/src/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/eu/siacs/conversations/ui/ConversationFragment.java
@@ -332,6 +332,9 @@ public class ConversationFragment extends Fragment {
final ConversationActivity activity = (ConversationActivity) getActivity();
activity.registerListener();
this.conversation = activity.getSelectedConversation();
+ if (this.conversation==null) {
+ return;
+ }
this.selfBitmap = findSelfPicture();
updateMessages();
// rendering complete. now go tell activity to close pane
@@ -374,7 +377,6 @@ public class ConversationFragment extends Fragment {
public void updateMessages() {
ConversationActivity activity = (ConversationActivity) getActivity();
List<Message> encryptedMessages = new LinkedList<Message>();
- // TODO this.conversation could be null?!
for(Message message : this.conversation.getMessages()) {
if (message.getEncryption() == Message.ENCRYPTION_PGP) {
encryptedMessages.add(message);
diff --git a/src/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/eu/siacs/conversations/ui/ManageAccountActivity.java
index 2af69867..85998131 100644
--- a/src/eu/siacs/conversations/ui/ManageAccountActivity.java
+++ b/src/eu/siacs/conversations/ui/ManageAccountActivity.java
@@ -48,7 +48,6 @@ public class ManageAccountActivity extends XmppActivity {
@Override
public void onAccountListChangedListener() {
- Log.d("xmppService", "ui on account list changed listener");
accountList.clear();
accountList.addAll(xmppConnectionService.getAccounts());
runOnUiThread(new Runnable() {
diff --git a/src/eu/siacs/conversations/ui/XmppActivity.java b/src/eu/siacs/conversations/ui/XmppActivity.java
index 2f1b1d50..1596a53a 100644
--- a/src/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/eu/siacs/conversations/ui/XmppActivity.java
@@ -42,8 +42,9 @@ public abstract class XmppActivity extends Activity {
protected void onStart() {
super.onStart();
if (!xmppConnectionServiceBound) {
- startService(new Intent(this, XmppConnectionService.class));
Intent intent = new Intent(this, XmppConnectionService.class);
+ intent.setAction("ui");
+ startService(intent);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
}
diff --git a/src/eu/siacs/conversations/utils/MessageParser.java b/src/eu/siacs/conversations/utils/MessageParser.java
index 614683a2..2da0459e 100644
--- a/src/eu/siacs/conversations/utils/MessageParser.java
+++ b/src/eu/siacs/conversations/utils/MessageParser.java
@@ -11,7 +11,7 @@ import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xml.Element;
-import eu.siacs.conversations.xmpp.MessagePacket;
+import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
public class MessageParser {
diff --git a/src/eu/siacs/conversations/xml/TagWriter.java b/src/eu/siacs/conversations/xml/TagWriter.java
index 109078ca..15ad385f 100644
--- a/src/eu/siacs/conversations/xml/TagWriter.java
+++ b/src/eu/siacs/conversations/xml/TagWriter.java
@@ -5,25 +5,29 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.concurrent.LinkedBlockingQueue;
-import android.util.Log;
+import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
public class TagWriter {
private OutputStreamWriter outputStream;
- private LinkedBlockingQueue<String> writeQueue = new LinkedBlockingQueue<String>();
- private Thread writer = new Thread() {
- public boolean shouldStop = false;
+ private boolean finshed = false;
+ private LinkedBlockingQueue<AbstractStanza> writeQueue = new LinkedBlockingQueue<AbstractStanza>();
+ private Thread asyncStanzaWriter = new Thread() {
+ private boolean shouldStop = false;
@Override
public void run() {
while(!shouldStop) {
+ if ((finshed)&&(writeQueue.size() == 0)) {
+ return;
+ }
try {
- String output = writeQueue.take();
- outputStream.write(output);
+ AbstractStanza output = writeQueue.take();
+ outputStream.write(output.toString());
outputStream.flush();
} catch (IOException e) {
- Log.d("xmppService", "error writing to stream");
+ shouldStop = true;
} catch (InterruptedException e) {
-
+ shouldStop = true;
}
}
}
@@ -31,34 +35,49 @@ public class TagWriter {
public TagWriter() {
-
}
public TagWriter(OutputStream out) {
this.setOutputStream(out);
- writer.start();
}
public void setOutputStream(OutputStream out) {
this.outputStream = new OutputStreamWriter(out);
- if (!writer.isAlive()) writer.start();
}
- public TagWriter beginDocument() {
- writeQueue.add("<?xml version='1.0'?>");
+ public TagWriter beginDocument() throws IOException {
+ outputStream.write("<?xml version='1.0'?>");
+ outputStream.flush();
return this;
}
- public TagWriter writeTag(Tag tag) {
- writeQueue.add(tag.toString());
+ public TagWriter writeTag(Tag tag) throws IOException {
+ outputStream.write(tag.toString());
+ outputStream.flush();
return this;
}
- public void writeString(String string) {
- writeQueue.add(string);
+ public TagWriter writeElement(Element element) throws IOException {
+ outputStream.write(element.toString());
+ outputStream.flush();
+ return this;
}
-
- public void writeElement(Element element) {
- writeQueue.add(element.toString());
+
+ public TagWriter writeStanzaAsync(AbstractStanza stanza) {
+ if (finshed) {
+ return this;
+ } else {
+ if (!asyncStanzaWriter.isAlive()) asyncStanzaWriter.start();
+ writeQueue.add(stanza);
+ return this;
+ }
+ }
+
+ public void finish() {
+ this.finshed = true;
+ }
+
+ public boolean finished() {
+ return (this.writeQueue.size() == 0);
}
}
diff --git a/src/eu/siacs/conversations/xmpp/OnIqPacketReceived.java b/src/eu/siacs/conversations/xmpp/OnIqPacketReceived.java
index 54909f88..a4cff986 100644
--- a/src/eu/siacs/conversations/xmpp/OnIqPacketReceived.java
+++ b/src/eu/siacs/conversations/xmpp/OnIqPacketReceived.java
@@ -1,6 +1,7 @@
package eu.siacs.conversations.xmpp;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.xmpp.stanzas.IqPacket;
public interface OnIqPacketReceived extends PacketReceived {
public void onIqPacketReceived(Account account, IqPacket packet);
diff --git a/src/eu/siacs/conversations/xmpp/OnMessagePacketReceived.java b/src/eu/siacs/conversations/xmpp/OnMessagePacketReceived.java
index 6f0b387d..325e945f 100644
--- a/src/eu/siacs/conversations/xmpp/OnMessagePacketReceived.java
+++ b/src/eu/siacs/conversations/xmpp/OnMessagePacketReceived.java
@@ -1,6 +1,7 @@
package eu.siacs.conversations.xmpp;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
public interface OnMessagePacketReceived extends PacketReceived {
public void onMessagePacketReceived(Account account, MessagePacket packet);
diff --git a/src/eu/siacs/conversations/xmpp/OnPresencePacketReceived.java b/src/eu/siacs/conversations/xmpp/OnPresencePacketReceived.java
index 55672fff..95c1acfc 100644
--- a/src/eu/siacs/conversations/xmpp/OnPresencePacketReceived.java
+++ b/src/eu/siacs/conversations/xmpp/OnPresencePacketReceived.java
@@ -1,6 +1,7 @@
package eu.siacs.conversations.xmpp;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
public interface OnPresencePacketReceived extends PacketReceived {
public void onPresencePacketReceived(Account account, PresencePacket packet);
diff --git a/src/eu/siacs/conversations/xmpp/PresencePacket.java b/src/eu/siacs/conversations/xmpp/PresencePacket.java
deleted file mode 100644
index 3d77ce15..00000000
--- a/src/eu/siacs/conversations/xmpp/PresencePacket.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package eu.siacs.conversations.xmpp;
-
-import eu.siacs.conversations.xml.Element;
-
-public class PresencePacket extends Element {
- private PresencePacket(String name) {
- super("presence");
- }
-
- public PresencePacket() {
- super("presence");
- }
-}
diff --git a/src/eu/siacs/conversations/xmpp/XmppConnection.java b/src/eu/siacs/conversations/xmpp/XmppConnection.java
index 53f9b85a..b11f2016 100644
--- a/src/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -26,10 +26,12 @@ import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
+import org.json.JSONException;
import org.xmlpull.v1.XmlPullParserException;
import android.os.Bundle;
import android.os.PowerManager;
+import android.os.SystemClock;
import android.util.Log;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.utils.CryptoHelper;
@@ -38,6 +40,14 @@ import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Tag;
import eu.siacs.conversations.xml.TagWriter;
import eu.siacs.conversations.xml.XmlReader;
+import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
+import eu.siacs.conversations.xmpp.stanzas.IqPacket;
+import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
+import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
+import eu.siacs.conversations.xmpp.stanzas.streammgmt.AckPacket;
+import eu.siacs.conversations.xmpp.stanzas.streammgmt.EnablePacket;
+import eu.siacs.conversations.xmpp.stanzas.streammgmt.RequestPacket;
+import eu.siacs.conversations.xmpp.stanzas.streammgmt.ResumePacket;
public class XmppConnection implements Runnable {
@@ -56,6 +66,14 @@ public class XmppConnection implements Runnable {
private boolean shouldAuthenticate = true;
private Element streamFeatures;
private HashSet<String> discoFeatures = new HashSet<String>();
+
+ private String streamId = null;
+
+ private int stanzasReceived = 0;
+ private int stanzasSent = 0;
+
+ public long lastPaketReceived = 0;
+ public long lastPingSent = 0;
private static final int PACKET_IQ = 0;
private static final int PACKET_MESSAGE = 1;
@@ -77,14 +95,16 @@ public class XmppConnection implements Runnable {
}
protected void changeStatus(int nextStatus) {
- account.setStatus(nextStatus);
- if (statusListener != null) {
- statusListener.onStatusChanged(account);
+ if (account.getStatus() != nextStatus) {
+ account.setStatus(nextStatus);
+ if (statusListener != null) {
+ statusListener.onStatusChanged(account);
+ }
}
}
protected void connect() {
- Log.d(LOGTAG, "connecting");
+ Log.d(LOGTAG,account.getJid()+ ": connecting");
try {
tagReader = new XmlReader(wakeLock);
tagWriter = new TagWriter();
@@ -147,7 +167,6 @@ public class XmppConnection implements Runnable {
@Override
public void run() {
connect();
- Log.d(LOGTAG, "end run");
}
private void processStream(Tag currentTag) throws XmlPullParserException,
@@ -176,6 +195,35 @@ public class XmppConnection implements Runnable {
} else if (nextTag.isStart("failure")) {
Element failure = tagReader.readElement(nextTag);
changeStatus(Account.STATUS_UNAUTHORIZED);
+ } else if (nextTag.isStart("enabled")) {
+ this.stanzasSent = 0;
+ Element enabled = tagReader.readElement(nextTag);
+ if ("true".equals(enabled.getAttribute("resume"))) {
+ this.streamId = enabled.getAttribute("id");
+ Log.d(LOGTAG,account.getJid()+": stream managment enabled (resumable)");
+ } else {
+ Log.d(LOGTAG,account.getJid()+": stream managment enabled");
+ }
+ this.stanzasReceived = 0;
+ RequestPacket r = new RequestPacket();
+ tagWriter.writeStanzaAsync(r);
+ } else if (nextTag.isStart("resumed")) {
+ tagReader.readElement(nextTag);
+ changeStatus(Account.STATUS_ONLINE);
+ Log.d(LOGTAG,account.getJid()+": session resumed");
+ } else if (nextTag.isStart("r")) {
+ tagReader.readElement(nextTag);
+ AckPacket ack = new AckPacket(this.stanzasReceived);
+ //Log.d(LOGTAG,ack.toString());
+ tagWriter.writeStanzaAsync(ack);
+ } else if (nextTag.isStart("a")) {
+ Element ack = tagReader.readElement(nextTag);
+ lastPaketReceived = SystemClock.elapsedRealtime();
+ int serverSequence = Integer.parseInt(ack.getAttribute("h"));
+ if (serverSequence>this.stanzasSent) {
+ this.stanzasSent = serverSequence;
+ }
+ //Log.d(LOGTAG,"server ack"+ack.toString()+" ("+this.stanzasSent+")");
} else if (nextTag.isStart("iq")) {
processIq(nextTag);
} else if (nextTag.isStart("message")) {
@@ -221,6 +269,8 @@ public class XmppConnection implements Runnable {
}
nextTag = tagReader.readTag();
}
+ ++stanzasReceived;
+ lastPaketReceived = SystemClock.elapsedRealtime();
return element;
}
@@ -271,7 +321,7 @@ public class XmppConnection implements Runnable {
}
}
- private void sendStartTLS() {
+ private void sendStartTLS() throws IOException {
Tag startTLS = Tag.empty("starttls");
startTLS.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-tls");
tagWriter.writeTag(startTLS);
@@ -378,23 +428,43 @@ public class XmppConnection implements Runnable {
} else if (this.streamFeatures.hasChild("mechanisms")
&& shouldAuthenticate) {
sendSaslAuth();
- }
- if (this.streamFeatures.hasChild("bind") && shouldBind) {
+ } else if (this.streamFeatures.hasChild("sm") && streamId != null) {
+ Log.d(LOGTAG,"found old stream id. trying to remuse");
+ ResumePacket resume = new ResumePacket(this.streamId,stanzasReceived);
+ this.tagWriter.writeStanzaAsync(resume);
+ } else if (this.streamFeatures.hasChild("bind") && shouldBind) {
sendBindRequest();
if (this.streamFeatures.hasChild("session")) {
+ Log.d(LOGTAG,"sending session");
IqPacket startSession = new IqPacket(IqPacket.TYPE_SET);
Element session = new Element("session");
session.setAttribute("xmlns",
"urn:ietf:params:xml:ns:xmpp-session");
session.setContent("");
startSession.addChild(session);
- sendIqPacket(startSession, null);
- tagWriter.writeElement(startSession);
+ this.sendIqPacket(startSession, null);
}
- Element presence = new Element("presence");
+ }
+ }
- tagWriter.writeElement(presence);
+ private void sendInitialPresence() {
+ PresencePacket packet = new PresencePacket();
+ packet.setAttribute("from", account.getFullJid());
+ if (account.getKeys().has("pgp_signature")) {
+ try {
+ String signature = account.getKeys().getString("pgp_signature");
+ Element status = new Element("status");
+ status.setContent("online");
+ packet.addChild(status);
+ Element x = new Element("x");
+ x.setAttribute("xmlns", "jabber:x:signed");
+ x.setContent(signature);
+ packet.addChild(x);
+ } catch (JSONException e) {
+ //
+ }
}
+ this.sendPresencePacket(packet);
}
private void sendBindRequest() throws IOException {
@@ -412,10 +482,15 @@ public class XmppConnection implements Runnable {
.getContent().split("/")[1];
account.setResource(resource);
account.setStatus(Account.STATUS_ONLINE);
+ if (streamFeatures.hasChild("sm")) {
+ EnablePacket enable = new EnablePacket();
+ tagWriter.writeStanzaAsync(enable);
+ }
+ sendInitialPresence();
+ sendServiceDiscovery();
if (statusListener != null) {
statusListener.onStatusChanged(account);
}
- sendServiceDiscovery();
}
});
}
@@ -471,7 +546,7 @@ public class XmppConnection implements Runnable {
Log.d(LOGTAG, "processStreamError");
}
- private void sendStartStream() {
+ private void sendStartStream() throws IOException {
Tag stream = Tag.start("stream:stream");
stream.setAttribute("from", account.getJid());
stream.setAttribute("to", account.getServer());
@@ -489,39 +564,52 @@ public class XmppConnection implements Runnable {
public void sendIqPacket(IqPacket packet, OnIqPacketReceived callback) {
String id = nextRandomId();
packet.setAttribute("id", id);
- tagWriter.writeElement(packet);
- if (callback != null) {
- packetCallbacks.put(id, callback);
- }
+ this.sendPacket(packet, callback);
}
public void sendMessagePacket(MessagePacket packet) {
- this.sendMessagePacket(packet, null);
+ this.sendPacket(packet, null);
}
public void sendMessagePacket(MessagePacket packet,
OnMessagePacketReceived callback) {
- String id = nextRandomId();
- packet.setAttribute("id", id);
- tagWriter.writeElement(packet);
- if (callback != null) {
- packetCallbacks.put(id, callback);
- }
+ this.sendPacket(packet, callback);
}
public void sendPresencePacket(PresencePacket packet) {
- this.sendPresencePacket(packet, null);
+ this.sendPacket(packet, null);
}
- public PresencePacket sendPresencePacket(PresencePacket packet,
+ public void sendPresencePacket(PresencePacket packet,
OnPresencePacketReceived callback) {
- String id = nextRandomId();
- packet.setAttribute("id", id);
- tagWriter.writeElement(packet);
+ this.sendPacket(packet, callback);
+ }
+
+ private synchronized void sendPacket(final AbstractStanza packet, PacketReceived callback) {
+ // TODO dont increment stanza count if packet = request packet or ack;
+ ++stanzasSent;
+ tagWriter.writeStanzaAsync(packet);
if (callback != null) {
- packetCallbacks.put(id, callback);
+ if (packet.getId()==null) {
+ packet.setId(nextRandomId());
+ }
+ packetCallbacks.put(packet.getId(), callback);
+ }
+ }
+
+ public void sendPing() {
+ if (streamFeatures.hasChild("sm")) {
+ Log.d(LOGTAG,account.getJid()+": sending r as ping");
+ tagWriter.writeStanzaAsync(new RequestPacket());
+ } else {
+ Log.d(LOGTAG,account.getJid()+": sending iq as ping");
+ IqPacket iq = new IqPacket(IqPacket.TYPE_GET);
+ Element ping = new Element("ping");
+ iq.setAttribute("from",account.getFullJid());
+ ping.setAttribute("xmlns", "urn:xmpp:ping");
+ iq.addChild(ping);
+ this.sendIqPacket(iq, null);
}
- return packet;
}
public void setOnMessagePacketReceivedListener(
@@ -547,8 +635,23 @@ public class XmppConnection implements Runnable {
this.tlsListener = listener;
}
- public void disconnect() {
+ public void disconnect(boolean force) {
+ Log.d(LOGTAG,"disconnecting");
+ try {
+ if (force) {
+ socket.close();
+ }
+ tagWriter.finish();
+ while(!tagWriter.finished()) {
+ Log.d(LOGTAG,"not yet finished");
+ Thread.sleep(100);
+ }
tagWriter.writeTag(Tag.end("stream:stream"));
+ } catch (IOException e) {
+ Log.d(LOGTAG,"io exception during disconnect");
+ } catch (InterruptedException e) {
+ Log.d(LOGTAG,"interupted while waiting for disconnect");
+ }
}
public boolean hasFeatureRosterManagment() {
@@ -558,4 +661,8 @@ public class XmppConnection implements Runnable {
return this.streamFeatures.hasChild("ver");
}
}
+
+ public void r() {
+ this.tagWriter.writeStanzaAsync(new RequestPacket());
+ }
}
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java b/src/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java
new file mode 100644
index 00000000..204a6bec
--- /dev/null
+++ b/src/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java
@@ -0,0 +1,34 @@
+package eu.siacs.conversations.xmpp.stanzas;
+
+import eu.siacs.conversations.xml.Element;
+
+public class AbstractStanza extends Element {
+
+ protected AbstractStanza(String name) {
+ super(name);
+ }
+
+ public String getTo() {
+ return getAttribute("to");
+ }
+
+ public String getFrom() {
+ return getAttribute("from");
+ }
+
+ public String getId() {
+ return this.getAttribute("id");
+ }
+
+ public void setTo(String to) {
+ setAttribute("to", to);
+ }
+
+ public void setFrom(String from) {
+ setAttribute("from",from);
+ }
+
+ public void setId(String id) {
+ setAttribute("id",id);
+ }
+}
diff --git a/src/eu/siacs/conversations/xmpp/IqPacket.java b/src/eu/siacs/conversations/xmpp/stanzas/IqPacket.java
index 2319fd28..1675d19d 100644
--- a/src/eu/siacs/conversations/xmpp/IqPacket.java
+++ b/src/eu/siacs/conversations/xmpp/stanzas/IqPacket.java
@@ -1,8 +1,7 @@
-package eu.siacs.conversations.xmpp;
+package eu.siacs.conversations.xmpp.stanzas;
-import eu.siacs.conversations.xml.Element;
-public class IqPacket extends Element {
+public class IqPacket extends AbstractStanza {
public static final int TYPE_SET = 0;
public static final int TYPE_RESULT = 1;
@@ -33,8 +32,4 @@ public class IqPacket extends Element {
super("iq");
}
- public String getId() {
- return this.getAttribute("id");
- }
-
}
diff --git a/src/eu/siacs/conversations/xmpp/MessagePacket.java b/src/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java
index a014155f..f31a78e6 100644
--- a/src/eu/siacs/conversations/xmpp/MessagePacket.java
+++ b/src/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java
@@ -1,30 +1,18 @@
-package eu.siacs.conversations.xmpp;
+package eu.siacs.conversations.xmpp.stanzas;
import eu.siacs.conversations.xml.Element;
-public class MessagePacket extends Element {
+public class MessagePacket extends AbstractStanza {
public static final int TYPE_CHAT = 0;
public static final int TYPE_UNKNOWN = 1;
public static final int TYPE_NO = 2;
public static final int TYPE_GROUPCHAT = 3;
public static final int TYPE_ERROR = 4;
-
- private MessagePacket(String name) {
- super(name);
- }
public MessagePacket() {
super("message");
}
- public String getTo() {
- return getAttribute("to");
- }
-
- public String getFrom() {
- return getAttribute("from");
- }
-
public String getBody() {
Element body = this.findChild("body");
if (body!=null) {
@@ -34,14 +22,6 @@ public class MessagePacket extends Element {
}
}
- public void setTo(String to) {
- setAttribute("to", to);
- }
-
- public void setFrom(String from) {
- setAttribute("from",from);
- }
-
public void setBody(String text) {
this.children.remove(findChild("body"));
Element body = new Element("body");
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/PresencePacket.java b/src/eu/siacs/conversations/xmpp/stanzas/PresencePacket.java
new file mode 100644
index 00000000..dfbab78c
--- /dev/null
+++ b/src/eu/siacs/conversations/xmpp/stanzas/PresencePacket.java
@@ -0,0 +1,9 @@
+package eu.siacs.conversations.xmpp.stanzas;
+
+
+public class PresencePacket extends AbstractStanza {
+
+ public PresencePacket() {
+ super("presence");
+ }
+}
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/AckPacket.java b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/AckPacket.java
new file mode 100644
index 00000000..7bc66e9b
--- /dev/null
+++ b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/AckPacket.java
@@ -0,0 +1,13 @@
+package eu.siacs.conversations.xmpp.stanzas.streammgmt;
+
+import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
+
+public class AckPacket extends AbstractStanza {
+
+ public AckPacket(int sequence) {
+ super("a");
+ this.setAttribute("xmlns","urn:xmpp:sm:3");
+ this.setAttribute("h", ""+sequence);
+ }
+
+}
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/EnablePacket.java b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/EnablePacket.java
new file mode 100644
index 00000000..ae6a513a
--- /dev/null
+++ b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/EnablePacket.java
@@ -0,0 +1,13 @@
+package eu.siacs.conversations.xmpp.stanzas.streammgmt;
+
+import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
+
+public class EnablePacket extends AbstractStanza {
+
+ public EnablePacket() {
+ super("enable");
+ this.setAttribute("xmlns","urn:xmpp:sm:3");
+ this.setAttribute("resume", "true");
+ }
+
+}
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/RequestPacket.java b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/RequestPacket.java
new file mode 100644
index 00000000..4d409fd2
--- /dev/null
+++ b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/RequestPacket.java
@@ -0,0 +1,12 @@
+package eu.siacs.conversations.xmpp.stanzas.streammgmt;
+
+import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
+
+public class RequestPacket extends AbstractStanza {
+
+ public RequestPacket() {
+ super("r");
+ this.setAttribute("xmlns","urn:xmpp:sm:3");
+ }
+
+}
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/ResumePacket.java b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/ResumePacket.java
new file mode 100644
index 00000000..bebfa1a2
--- /dev/null
+++ b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/ResumePacket.java
@@ -0,0 +1,14 @@
+package eu.siacs.conversations.xmpp.stanzas.streammgmt;
+
+import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
+
+public class ResumePacket extends AbstractStanza {
+
+ public ResumePacket(String id, int sequence) {
+ super("resume");
+ this.setAttribute("xmlns","urn:xmpp:sm:3");
+ this.setAttribute("previd", id);
+ this.setAttribute("h", ""+sequence);
+ }
+
+}