aboutsummaryrefslogtreecommitdiffstats
path: root/src/eu/siacs/conversations/services/XmppConnectionService.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/eu/siacs/conversations/services/XmppConnectionService.java')
-rw-r--r--src/eu/siacs/conversations/services/XmppConnectionService.java804
1 files changed, 365 insertions, 439 deletions
diff --git a/src/eu/siacs/conversations/services/XmppConnectionService.java b/src/eu/siacs/conversations/services/XmppConnectionService.java
index 3db52753..0ac1adf7 100644
--- a/src/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/eu/siacs/conversations/services/XmppConnectionService.java
@@ -2,6 +2,7 @@ package eu.siacs.conversations.services;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
@@ -9,6 +10,7 @@ import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
+import java.util.concurrent.CopyOnWriteArrayList;
import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpServiceConnection;
@@ -18,6 +20,7 @@ import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionStatus;
import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
@@ -25,12 +28,12 @@ import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
import eu.siacs.conversations.entities.Presences;
import eu.siacs.conversations.generator.MessageGenerator;
+import eu.siacs.conversations.generator.PresenceGenerator;
+import eu.siacs.conversations.parser.IqParser;
import eu.siacs.conversations.parser.MessageParser;
import eu.siacs.conversations.parser.PresenceParser;
import eu.siacs.conversations.persistance.DatabaseBackend;
import eu.siacs.conversations.persistance.FileBackend;
-import eu.siacs.conversations.ui.OnAccountListChangedListener;
-import eu.siacs.conversations.ui.OnConversationListChangedListener;
import eu.siacs.conversations.ui.UiCallback;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.ExceptionHelper;
@@ -42,8 +45,6 @@ import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.OnBindListener;
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
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.XmppConnection;
@@ -86,28 +87,31 @@ public class XmppConnectionService extends Service {
private static final int PING_MIN_INTERVAL = 30;
private static final int PING_TIMEOUT = 10;
private static final int CONNECT_TIMEOUT = 90;
- private static final long CARBON_GRACE_PERIOD = 60000L;
+ public static final long CARBON_GRACE_PERIOD = 60000L;
private static String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
private MessageParser mMessageParser = new MessageParser(this);
private PresenceParser mPresenceParser = new PresenceParser(this);
+ private IqParser mIqParser = new IqParser(this);
private MessageGenerator mMessageGenerator = new MessageGenerator();
-
+ private PresenceGenerator mPresenceGenerator = new PresenceGenerator();
+
private List<Account> accounts;
- private List<Conversation> conversations = null;
+ private CopyOnWriteArrayList<Conversation> conversations = null;
private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(
this);
- private OnConversationListChangedListener convChangedListener = null;
+ private OnConversationUpdate mOnConversationUpdate = null;
private int convChangedListenerCount = 0;
- private OnAccountListChangedListener accountChangedListener = null;
+ private OnAccountUpdate mOnAccountUpdate = null;
+ private OnRosterUpdate mOnRosterUpdate = null;
private OnTLSExceptionReceived tlsException = null;
public OnContactStatusChanged onContactStatusChanged = new OnContactStatusChanged() {
@Override
public void onContactStatusChanged(Contact contact, boolean online) {
- Conversation conversation = findActiveConversation(contact);
+ Conversation conversation = find(getConversations(),contact);
if (conversation != null) {
conversation.endOtrIfNeeded();
if (online && (contact.getPresences().size() == 1)) {
@@ -124,8 +128,6 @@ public class XmppConnectionService extends Service {
private SecureRandom mRandom;
- private long lastCarbonMessageReceived = -CARBON_GRACE_PERIOD;
-
private ContentObserver contactObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
@@ -138,103 +140,20 @@ public class XmppConnectionService extends Service {
};
private final IBinder mBinder = new XmppConnectionBinder();
- private OnMessagePacketReceived messageListener = new OnMessagePacketReceived() {
-
- @Override
- public void onMessagePacketReceived(Account account,
- MessagePacket packet) {
- Message message = null;
- boolean notify = true;
- if (getPreferences().getBoolean(
- "notification_grace_period_after_carbon_received", true)) {
- notify = (SystemClock.elapsedRealtime() - lastCarbonMessageReceived) > CARBON_GRACE_PERIOD;
- }
-
- if ((packet.getType() == MessagePacket.TYPE_CHAT)) {
- if ((packet.getBody() != null)
- && (packet.getBody().startsWith("?OTR"))) {
- message = mMessageParser.parseOtrChat(packet, account);
- if (message != null) {
- message.markUnread();
- }
- } else if (packet.hasChild("body")) {
- message = mMessageParser.parseChat(packet, account);
- message.markUnread();
- } else if (packet.hasChild("received")
- || (packet.hasChild("sent"))) {
- message = mMessageParser
- .parseCarbonMessage(packet, account);
- if (message != null) {
- if (message.getStatus() == Message.STATUS_SEND) {
- lastCarbonMessageReceived = SystemClock
- .elapsedRealtime();
- notify = false;
- message.getConversation().markRead();
- } else {
- message.markUnread();
- }
- }
- }
-
- } else if (packet.getType() == MessagePacket.TYPE_GROUPCHAT) {
- message = mMessageParser.parseGroupchat(packet, account);
- if (message != null) {
- if (message.getStatus() == Message.STATUS_RECIEVED) {
- message.markUnread();
- } else {
- message.getConversation().markRead();
- notify = false;
- }
- }
- } else if (packet.getType() == MessagePacket.TYPE_ERROR) {
- mMessageParser.parseError(packet, account);
- return;
- } else if (packet.getType() == MessagePacket.TYPE_NORMAL) {
- mMessageParser.parseNormal(packet, account);
- }
- if ((message == null) || (message.getBody() == null)) {
- return;
- }
- if ((confirmMessages()) && ((packet.getId() != null))) {
- MessagePacket receivedPacket = new MessagePacket();
- receivedPacket.setType(MessagePacket.TYPE_NORMAL);
- receivedPacket.setTo(message.getCounterpart());
- receivedPacket.setFrom(account.getFullJid());
- if (packet.hasChild("markable", "urn:xmpp:chat-markers:0")) {
- Element received = receivedPacket.addChild("received",
- "urn:xmpp:chat-markers:0");
- received.setAttribute("id", packet.getId());
- account.getXmppConnection().sendMessagePacket(
- receivedPacket);
- } else if (packet.hasChild("request", "urn:xmpp:receipts")) {
- Element received = receivedPacket.addChild("received",
- "urn:xmpp:receipts");
- received.setAttribute("id", packet.getId());
- account.getXmppConnection().sendMessagePacket(
- receivedPacket);
- }
- }
- Conversation conversation = message.getConversation();
- conversation.getMessages().add(message);
- if (packet.getType() != MessagePacket.TYPE_ERROR) {
- databaseBackend.createMessage(message);
- }
- if (convChangedListener != null) {
- convChangedListener.onConversationListChanged();
- } else {
- UIHelper.updateNotification(getApplicationContext(),
- getConversations(), message.getConversation(), notify);
- }
- }
- };
private OnStatusChanged statusListener = new OnStatusChanged() {
@Override
public void onStatusChanged(Account account) {
- if (accountChangedListener != null) {
- accountChangedListener.onAccountListChangedListener();
+ if (mOnAccountUpdate != null) {
+ mOnAccountUpdate.onAccountUpdate();;
}
if (account.getStatus() == Account.STATUS_ONLINE) {
+ for(Conversation conversation : account.pendingConferenceLeaves) {
+ leaveMuc(conversation);
+ }
+ for(Conversation conversation : account.pendingConferenceJoins) {
+ joinMuc(conversation);
+ }
mJingleConnectionManager.cancelInTransmission();
List<Conversation> conversations = getConversations();
for (int i = 0; i < conversations.size(); ++i) {
@@ -269,73 +188,6 @@ public class XmppConnectionService extends Service {
}
};
- private OnPresencePacketReceived presenceListener = new OnPresencePacketReceived() {
-
- @Override
- public void onPresencePacketReceived(final Account account,
- PresencePacket packet) {
- if (packet.hasChild("x", "http://jabber.org/protocol/muc#user")) {
- mPresenceParser.parseConferencePresence(packet, account);
- } else if (packet.hasChild("x", "http://jabber.org/protocol/muc")) {
- mPresenceParser.parseConferencePresence(packet, account);
- } else {
- mPresenceParser.parseContactPresence(packet, account);
- }
- }
- };
-
- private OnIqPacketReceived unknownIqListener = new OnIqPacketReceived() {
-
- @Override
- public void onIqPacketReceived(Account account, IqPacket packet) {
- if (packet.hasChild("query", "jabber:iq:roster")) {
- String from = packet.getFrom();
- if ((from == null) || (from.equals(account.getJid()))) {
- Element query = packet.findChild("query");
- processRosterItems(account, query);
- } else {
- Log.d(LOGTAG, "unauthorized roster push from: " + from);
- }
- } else if (packet
- .hasChild("open", "http://jabber.org/protocol/ibb")
- || packet
- .hasChild("data", "http://jabber.org/protocol/ibb")) {
- XmppConnectionService.this.mJingleConnectionManager
- .deliverIbbPacket(account, packet);
- } else if (packet.hasChild("query",
- "http://jabber.org/protocol/disco#info")) {
- IqPacket iqResponse = packet
- .generateRespone(IqPacket.TYPE_RESULT);
- Element query = iqResponse.addChild("query",
- "http://jabber.org/protocol/disco#info");
- query.addChild("feature").setAttribute("var",
- "urn:xmpp:jingle:1");
- query.addChild("feature").setAttribute("var",
- "urn:xmpp:jingle:apps:file-transfer:3");
- query.addChild("feature").setAttribute("var",
- "urn:xmpp:jingle:transports:s5b:1");
- query.addChild("feature").setAttribute("var",
- "urn:xmpp:jingle:transports:ibb:1");
- if (confirmMessages()) {
- query.addChild("feature").setAttribute("var",
- "urn:xmpp:receipts");
- }
- account.getXmppConnection().sendIqPacket(iqResponse, null);
- } else {
- if ((packet.getType() == IqPacket.TYPE_GET)
- || (packet.getType() == IqPacket.TYPE_SET)) {
- IqPacket response = packet
- .generateRespone(IqPacket.TYPE_ERROR);
- Element error = response.addChild("error");
- error.setAttribute("type", "cancel");
- error.addChild("feature-not-implemented",
- "urn:ietf:params:xml:ns:xmpp-stanzas");
- account.getXmppConnection().sendIqPacket(response, null);
- }
- }
- }
- };
-
private OnJinglePacketReceived jingleListener = new OnJinglePacketReceived() {
@Override
@@ -350,6 +202,21 @@ public class XmppConnectionService extends Service {
private PendingIntent pendingPingIntent = null;
private WakeLock wakeLock;
private PowerManager pm;
+ private OnBindListener mOnBindListener = new OnBindListener() {
+
+ @Override
+ public void onBind(final Account account) {
+ account.getRoster().clearPresences();
+ account.clearPresences(); // self presences
+ account.pendingConferenceJoins.clear();
+ account.pendingConferenceLeaves.clear();
+ fetchRosterFromServer(account);
+ fetchBookmarks(account);
+ sendPresencePacket(account, mPresenceGenerator.sendPresence(account));
+ connectMultiModeConversations(account);
+ updateConversationUi();
+ }
+ };
public PgpEngine getPgpEngine() {
if (pgpServiceConnection.isBound()) {
@@ -401,39 +268,12 @@ public class XmppConnectionService extends Service {
return message;
}
- public Conversation findMuc(String name, Account account) {
- for (Conversation conversation : this.conversations) {
- if (conversation.getContactJid().split("/")[0].equals(name)
- && (conversation.getAccount() == account)) {
- return conversation;
- }
- }
- return null;
+ public Conversation find(Bookmark bookmark) {
+ return find(bookmark.getAccount(),bookmark.getJid());
}
-
- private void processRosterItems(Account account, Element elements) {
- String version = elements.getAttribute("ver");
- if (version != null) {
- account.getRoster().setVersion(version);
- }
- for (Element item : elements.getChildren()) {
- if (item.getName().equals("item")) {
- String jid = item.getAttribute("jid");
- String name = item.getAttribute("name");
- String subscription = item.getAttribute("subscription");
- Contact contact = account.getRoster().getContact(jid);
- if (!contact.getOption(Contact.Options.DIRTY_PUSH)) {
- contact.setServerName(name);
- }
- if (subscription.equals("remove")) {
- contact.resetOption(Contact.Options.IN_ROSTER);
- contact.resetOption(Contact.Options.DIRTY_DELETE);
- } else {
- contact.setOption(Contact.Options.IN_ROSTER);
- contact.parseSubscriptionFromElement(item);
- }
- }
- }
+
+ public Conversation find(Account account, String jid) {
+ return find(getConversations(),account,jid);
}
public class XmppConnectionBinder extends Binder {
@@ -508,13 +348,16 @@ public class XmppConnectionService extends Service {
// in any case. reschedule wakup call
this.scheduleWakeupCall(PING_MAX_INTERVAL, true);
}
- if (accountChangedListener != null) {
- accountChangedListener.onAccountListChangedListener();
+ if (mOnAccountUpdate != null) {
+ mOnAccountUpdate.onAccountUpdate();
}
}
}
if (wakeLock.isHeld()) {
- try { wakeLock.release();} catch (RuntimeException re) {}
+ try {
+ wakeLock.release();
+ } catch (RuntimeException re) {
+ }
}
return START_STICKY;
}
@@ -618,11 +461,11 @@ public class XmppConnectionService extends Service {
account.setResource(sharedPref.getString("resource", "mobile")
.toLowerCase(Locale.getDefault()));
XmppConnection connection = new XmppConnection(account, this);
- connection.setOnMessagePacketReceivedListener(this.messageListener);
+ connection.setOnMessagePacketReceivedListener(this.mMessageParser);
connection.setOnStatusChangedListener(this.statusListener);
- connection.setOnPresencePacketReceivedListener(this.presenceListener);
+ connection.setOnPresencePacketReceivedListener(this.mPresenceParser);
connection
- .setOnUnregisteredIqPacketReceivedListener(this.unknownIqListener);
+ .setOnUnregisteredIqPacketReceivedListener(this.mIqParser);
connection.setOnJinglePacketReceivedListener(this.jingleListener);
connection
.setOnTLSExceptionReceivedListener(new OnTLSExceptionReceived() {
@@ -637,20 +480,7 @@ public class XmppConnectionService extends Service {
}
}
});
- connection.setOnBindListener(new OnBindListener() {
-
- @Override
- public void onBind(final Account account) {
- account.getRoster().clearPresences();
- account.clearPresences(); // self presences
- fetchRosterFromServer(account);
- sendPresence(account);
- connectMultiModeConversations(account);
- if (convChangedListener != null) {
- convChangedListener.onConversationListChanged();
- }
- }
- });
+ connection.setOnBindListener(this.mOnBindListener);
return connection;
}
@@ -691,25 +521,24 @@ public class XmppConnectionService extends Service {
message.setStatus(Message.STATUS_WAITING);
} else if (conv.hasValidOtrSession()
&& conv.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) {
- message.setPresence(conv.getOtrSession().getSessionID().getUserID());
- try {
- packet = mMessageGenerator.generateOtrChat(message);
- send = true;
- message.setStatus(Message.STATUS_SEND);
- } catch (OtrException e) {
- Log.e(LOGTAG,"error generating otr packet");
- packet = null;
- }
+ message.setPresence(conv.getOtrSession().getSessionID()
+ .getUserID());
+ packet = mMessageGenerator.generateOtrChat(message);
+ send = true;
+ message.setStatus(Message.STATUS_SEND);
+
} else if (message.getPresence() == null) {
message.setStatus(Message.STATUS_WAITING);
}
} else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
message.getConversation().endOtrIfNeeded();
+ message.getConversation().failWaitingOtrMessages();
packet = mMessageGenerator.generatePgpChat(message);
message.setStatus(Message.STATUS_SEND);
send = true;
} else {
message.getConversation().endOtrIfNeeded();
+ message.getConversation().failWaitingOtrMessages();
if (message.getConversation().getMode() == Conversation.MODE_SINGLE) {
message.setStatus(Message.STATUS_SEND);
}
@@ -744,11 +573,9 @@ public class XmppConnectionService extends Service {
databaseBackend.createMessage(message);
}
conv.getMessages().add(message);
- if (convChangedListener != null) {
- convChangedListener.onConversationListChanged();
- }
+ updateConversationUi();
if ((send) && (packet != null)) {
- account.getXmppConnection().sendMessagePacket(packet);
+ sendMessagePacket(account, packet);
}
}
@@ -782,9 +609,11 @@ public class XmppConnectionService extends Service {
}
}
} else {
- if (message.getConversation().getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) {
+ if (message.getConversation().getOtrSession()
+ .getSessionStatus() == SessionStatus.ENCRYPTED) {
if (message.getType() == Message.TYPE_TEXT) {
- packet = mMessageGenerator.generateOtrChat(message,true);
+ packet = mMessageGenerator.generateOtrChat(message,
+ true);
} else if (message.getType() == Message.TYPE_IMAGE) {
mJingleConnectionManager.createNewConnection(message);
}
@@ -792,9 +621,10 @@ public class XmppConnectionService extends Service {
}
} else if (message.getType() == Message.TYPE_TEXT) {
if (message.getEncryption() == Message.ENCRYPTION_NONE) {
- packet = mMessageGenerator.generateChat(message,true);
- } else if ((message.getEncryption() == Message.ENCRYPTION_DECRYPTED)||(message.getEncryption() == Message.ENCRYPTION_PGP)) {
- packet = mMessageGenerator.generatePgpChat(message,true);
+ packet = mMessageGenerator.generateChat(message, true);
+ } else if ((message.getEncryption() == Message.ENCRYPTION_DECRYPTED)
+ || (message.getEncryption() == Message.ENCRYPTION_PGP)) {
+ packet = mMessageGenerator.generatePgpChat(message, true);
}
} else if (message.getType() == Message.TYPE_IMAGE) {
Presences presences = message.getConversation().getContact()
@@ -813,7 +643,7 @@ public class XmppConnectionService extends Service {
}
}
if (packet != null) {
- account.getXmppConnection().sendMessagePacket(packet);
+ sendMessagePacket(account,packet);
markMessage(message, Message.STATUS_SEND);
}
}
@@ -834,14 +664,60 @@ public class XmppConnectionService extends Service {
@Override
public void onIqPacketReceived(final Account account,
IqPacket packet) {
- Element roster = packet.findChild("query");
- if (roster != null) {
+ Element query = packet.findChild("query");
+ if (query != null) {
account.getRoster().markAllAsNotInRoster();
- processRosterItems(account, roster);
+ mIqParser.rosterItems(account, query);
}
}
});
}
+
+ public void fetchBookmarks(Account account) {
+ IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
+ Element query = iqPacket.query("jabber:iq:private");
+ query.addChild("storage", "storage:bookmarks");
+ OnIqPacketReceived callback = new OnIqPacketReceived() {
+
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ Element query = packet.query();
+ List<Bookmark> bookmarks = new ArrayList<Bookmark>();
+ Element storage = query.findChild("storage", "storage:bookmarks");
+ if (storage!=null) {
+ for(Element item : storage.getChildren()) {
+ if (item.getName().equals("conference")) {
+ Bookmark bookmark = Bookmark.parse(item,account);
+ bookmarks.add(bookmark);
+ Conversation conversation = find(bookmark);
+ if (conversation!=null) {
+ conversation.setBookmark(bookmark);
+ } else {
+ if (bookmark.autojoin()) {
+ conversation = findOrCreateConversation(account, bookmark.getJid(), true);
+ conversation.setBookmark(bookmark);
+ joinMuc(conversation);
+ }
+ }
+ }
+ }
+ }
+ account.setBookmarks(bookmarks);
+ }
+ };
+ sendIqPacket(account, iqPacket, callback);
+
+ }
+
+ public void pushBookmarks(Account account) {
+ IqPacket iqPacket = new IqPacket(IqPacket.TYPE_SET);
+ Element query = iqPacket.query("jabber:iq:private");
+ Element storage = query.addChild("storage", "storage:bookmarks");
+ for(Bookmark bookmark : account.getBookmarks()) {
+ storage.addChild(bookmark.toElement());
+ }
+ sendIqPacket(account, iqPacket,null);
+ }
private void mergePhoneContactsWithRoster() {
PhoneHelper.loadPhoneContacts(getApplicationContext(),
@@ -885,7 +761,14 @@ public class XmppConnectionService extends Service {
conv.setMessages(databaseBackend.getMessages(conv, 50));
}
}
- Collections.sort(this.conversations, new Comparator<Conversation>() {
+
+ return this.conversations;
+ }
+
+ public void populateWithOrderedConversations(List<Conversation> list) {
+ list.clear();
+ list.addAll(getConversations());
+ Collections.sort(list, new Comparator<Conversation>() {
@Override
public int compare(Conversation lhs, Conversation rhs) {
Message left = lhs.getLatestMessage();
@@ -899,7 +782,6 @@ public class XmppConnectionService extends Service {
}
}
});
- return this.conversations;
}
public List<Message> getMoreMessages(Conversation conversation,
@@ -916,8 +798,8 @@ public class XmppConnectionService extends Service {
return this.accounts;
}
- public Conversation findActiveConversation(Contact contact) {
- for (Conversation conversation : this.getConversations()) {
+ public Conversation find(List<Conversation> haystack, Contact contact) {
+ for (Conversation conversation : haystack) {
if (conversation.getContact() == contact) {
return conversation;
}
@@ -925,16 +807,24 @@ public class XmppConnectionService extends Service {
return null;
}
+ public Conversation find(List<Conversation> haystack, Account account, String jid) {
+ for (Conversation conversation : haystack) {
+ if ((conversation.getAccount().equals(account))
+ && (conversation.getContactJid().split("/")[0].equals(jid))) {
+ return conversation;
+ }
+ }
+ return null;
+ }
+
+
public Conversation findOrCreateConversation(Account account, String jid,
boolean muc) {
- for (Conversation conv : this.getConversations()) {
- if ((conv.getAccount().equals(account))
- && (conv.getContactJid().split("/")[0].equals(jid))) {
- return conv;
- }
+ Conversation conversation = find(account, jid);
+ if (conversation != null) {
+ return conversation;
}
- Conversation conversation = databaseBackend.findConversation(account,
- jid);
+ conversation = databaseBackend.findConversation(account,jid);
if (conversation != null) {
conversation.setStatus(Conversation.STATUS_AVAILABLE);
conversation.setAccount(account);
@@ -964,36 +854,31 @@ public class XmppConnectionService extends Service {
this.databaseBackend.createConversation(conversation);
}
this.conversations.add(conversation);
- if ((account.getStatus() == Account.STATUS_ONLINE)
- && (conversation.getMode() == Conversation.MODE_MULTI)) {
- joinMuc(conversation);
- }
- if (this.convChangedListener != null) {
- this.convChangedListener.onConversationListChanged();
- }
+ updateConversationUi();
return conversation;
}
public void archiveConversation(Conversation conversation) {
if (conversation.getMode() == Conversation.MODE_MULTI) {
+ Bookmark bookmark = conversation.getBookmark();
+ if (bookmark!=null && bookmark.autojoin()) {
+ bookmark.setAutojoin(false);
+ pushBookmarks(bookmark.getAccount());
+ }
leaveMuc(conversation);
} else {
conversation.endOtrIfNeeded();
}
this.databaseBackend.updateConversation(conversation);
this.conversations.remove(conversation);
- if (this.convChangedListener != null) {
- this.convChangedListener.onConversationListChanged();
- }
+ updateConversationUi();
}
public void clearConversationHistory(Conversation conversation) {
this.databaseBackend.deleteMessagesInConversation(conversation);
this.fileBackend.removeFiles(conversation);
conversation.getMessages().clear();
- if (this.convChangedListener != null) {
- this.convChangedListener.onConversationListChanged();
- }
+ updateConversationUi();
}
public int getConversationCount() {
@@ -1004,17 +889,14 @@ public class XmppConnectionService extends Service {
databaseBackend.createAccount(account);
this.accounts.add(account);
this.reconnectAccount(account, false);
- if (accountChangedListener != null)
- accountChangedListener.onAccountListChangedListener();
+ updateAccountUi();
}
public void updateAccount(Account account) {
this.statusListener.onStatusChanged(account);
databaseBackend.updateAccount(account);
reconnectAccount(account, false);
- if (accountChangedListener != null) {
- accountChangedListener.onAccountListChangedListener();
- }
+ updateAccountUi();
UIHelper.showErrorNotification(getApplicationContext(), getAccounts());
}
@@ -1024,32 +906,37 @@ public class XmppConnectionService extends Service {
}
databaseBackend.deleteAccount(account);
this.accounts.remove(account);
- if (accountChangedListener != null) {
- accountChangedListener.onAccountListChangedListener();
- }
+ updateAccountUi();
UIHelper.showErrorNotification(getApplicationContext(), getAccounts());
}
public void setOnConversationListChangedListener(
- OnConversationListChangedListener listener) {
- this.convChangedListener = listener;
+ OnConversationUpdate listener) {
+ this.mOnConversationUpdate = listener;
this.convChangedListenerCount++;
}
public void removeOnConversationListChangedListener() {
this.convChangedListenerCount--;
if (this.convChangedListenerCount == 0) {
- this.convChangedListener = null;
+ this.mOnConversationUpdate = null;
}
}
- public void setOnAccountListChangedListener(
- OnAccountListChangedListener listener) {
- this.accountChangedListener = listener;
+ public void setOnAccountListChangedListener(OnAccountUpdate listener) {
+ this.mOnAccountUpdate = listener;
}
public void removeOnAccountListChangedListener() {
- this.accountChangedListener = null;
+ this.mOnAccountUpdate = null;
+ }
+
+ public void setOnRosterUpdateListener(OnRosterUpdate listener) {
+ this.mOnRosterUpdate = listener;
+ }
+
+ public void removeOnRosterUpdateListener() {
+ this.mOnRosterUpdate = null;
}
public void connectMultiModeConversations(Account account) {
@@ -1065,33 +952,35 @@ public class XmppConnectionService extends Service {
public void joinMuc(Conversation conversation) {
Account account = conversation.getAccount();
- String[] mucParts = conversation.getContactJid().split("/");
- String muc;
- String nick;
- if (mucParts.length == 2) {
- muc = mucParts[0];
- nick = mucParts[1];
+ account.pendingConferenceJoins.remove(conversation);
+ account.pendingConferenceLeaves.remove(conversation);
+ if (account.getStatus() == Account.STATUS_ONLINE) {
+ Log.d(LOGTAG,"joining conversation "+conversation.getContactJid());
+ String nick = conversation.getMucOptions().getProposedNick();
+ conversation.getMucOptions().setJoinNick(nick);
+ PresencePacket packet = new PresencePacket();
+ packet.setAttribute("to",conversation.getMucOptions().getJoinJid());
+ Element x = new Element("x");
+ x.setAttribute("xmlns", "http://jabber.org/protocol/muc");
+ String sig = account.getPgpSignature();
+ if (sig != null) {
+ packet.addChild("status").setContent("online");
+ packet.addChild("x", "jabber:x:signed").setContent(sig);
+ }
+ if (conversation.getMessages().size() != 0) {
+ final SimpleDateFormat mDateFormat = new SimpleDateFormat(
+ "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
+ mDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ Date date = new Date(
+ conversation.getLatestMessage().getTimeSent() + 1000);
+ x.addChild("history").setAttribute("since",
+ mDateFormat.format(date));
+ }
+ packet.addChild(x);
+ sendPresencePacket(account, packet);
} else {
- muc = mucParts[0];
- nick = account.getUsername();
- }
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("to", muc + "/" + nick);
- Element x = new Element("x");
- x.setAttribute("xmlns", "http://jabber.org/protocol/muc");
- String sig = account.getPgpSignature();
- if (sig != null) {
- packet.addChild("status").setContent("online");
- packet.addChild("x", "jabber:x:signed").setContent(sig);
- }
- if (conversation.getMessages().size() != 0) {
- final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",Locale.US);
- mDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- Date date = new Date(conversation.getLatestMessage().getTimeSent() + 1000);
- x.addChild("history").setAttribute("since",mDateFormat.format(date));
+ account.pendingConferenceJoins.add(conversation);
}
- packet.addChild(x);
- account.getXmppConnection().sendPresencePacket(packet);
}
private OnRenameListener renameListener = null;
@@ -1102,6 +991,7 @@ public class XmppConnectionService extends Service {
public void renameInMuc(final Conversation conversation, final String nick) {
final MucOptions options = conversation.getMucOptions();
+ options.setJoinNick(nick);
if (options.online()) {
Account account = conversation.getAccount();
options.setOnRenameListener(new OnRenameListener() {
@@ -1112,17 +1002,19 @@ public class XmppConnectionService extends Service {
renameListener.onRename(success);
}
if (success) {
- String jid = conversation.getContactJid().split("/")[0]
- + "/" + nick;
- conversation.setContactJid(jid);
+ conversation.setContactJid(conversation.getMucOptions().getJoinJid());
databaseBackend.updateConversation(conversation);
+ Bookmark bookmark = conversation.getBookmark();
+ if (bookmark!=null) {
+ bookmark.setNick(nick);
+ pushBookmarks(bookmark.getAccount());
+ }
}
}
});
options.flagAboutToRename();
PresencePacket packet = new PresencePacket();
- packet.setAttribute("to",
- conversation.getContactJid().split("/")[0] + "/" + nick);
+ packet.setAttribute("to",options.getJoinJid());
packet.setAttribute("from", conversation.getAccount().getFullJid());
String sig = account.getPgpSignature();
@@ -1130,29 +1022,37 @@ public class XmppConnectionService extends Service {
packet.addChild("status").setContent("online");
packet.addChild("x", "jabber:x:signed").setContent(sig);
}
-
- account.getXmppConnection().sendPresencePacket(packet, null);
+ sendPresencePacket(account,packet);
} else {
- String jid = conversation.getContactJid().split("/")[0] + "/"
- + nick;
- conversation.setContactJid(jid);
+ conversation.setContactJid(options.getJoinJid());
databaseBackend.updateConversation(conversation);
if (conversation.getAccount().getStatus() == Account.STATUS_ONLINE) {
+ Bookmark bookmark = conversation.getBookmark();
+ if (bookmark!=null) {
+ bookmark.setNick(nick);
+ pushBookmarks(bookmark.getAccount());
+ }
joinMuc(conversation);
}
}
}
public void leaveMuc(Conversation conversation) {
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("to", conversation.getContactJid().split("/")[0]
- + "/" + conversation.getMucOptions().getNick());
- packet.setAttribute("from", conversation.getAccount().getFullJid());
- packet.setAttribute("type", "unavailable");
- Log.d(LOGTAG, "send leaving muc " + packet);
- conversation.getAccount().getXmppConnection()
- .sendPresencePacket(packet);
- conversation.getMucOptions().setOffline();
+ Account account = conversation.getAccount();
+ account.pendingConferenceJoins.remove(conversation);
+ account.pendingConferenceLeaves.remove(conversation);
+ if (account.getStatus() == Account.STATUS_ONLINE) {
+ PresencePacket packet = new PresencePacket();
+ packet.setAttribute("to", conversation.getMucOptions().getJoinJid());
+ packet.setAttribute("from", conversation.getAccount().getFullJid());
+ packet.setAttribute("type", "unavailable");
+ sendPresencePacket(conversation.getAccount(),packet);
+ conversation.getMucOptions().setOffline();
+ conversation.deregisterWithBookmark();
+ Log.d(LOGTAG,conversation.getAccount().getJid()+" leaving muc "+conversation.getContactJid());
+ } else {
+ account.pendingConferenceLeaves.add(conversation);
+ }
}
public void disconnect(Account account, boolean force) {
@@ -1219,18 +1119,19 @@ public class XmppConnectionService extends Service {
&& (msg.getEncryption() == Message.ENCRYPTION_OTR)) {
msg.setPresence(otrSession.getSessionID().getUserID());
if (msg.getType() == Message.TYPE_TEXT) {
- MessagePacket outPacket = mMessageGenerator.generateOtrChat(msg,true);
- if (outPacket!=null) {
+ MessagePacket outPacket = mMessageGenerator
+ .generateOtrChat(msg, true);
+ if (outPacket != null) {
msg.setStatus(Message.STATUS_SEND);
databaseBackend.updateMessage(msg);
- account.getXmppConnection().sendMessagePacket(outPacket);
+ sendMessagePacket(account,outPacket);
}
} else if (msg.getType() == Message.TYPE_IMAGE) {
mJingleConnectionManager.createNewConnection(msg);
}
}
}
- updateUi(conversation, false);
+ notifyUi(conversation, false);
}
public boolean renewSymmetricKey(Conversation conversation) {
@@ -1250,7 +1151,7 @@ public class XmppConnectionService extends Service {
packet.setBody(otrSession
.transformSending(CryptoHelper.FILETRANSFER
+ CryptoHelper.bytesToHex(symmetricKey)));
- account.getXmppConnection().sendMessagePacket(packet);
+ sendMessagePacket(account,packet);
conversation.setSymmetricKey(symmetricKey);
return true;
} catch (OtrException e) {
@@ -1262,26 +1163,28 @@ public class XmppConnectionService extends Service {
public void pushContactToServer(Contact contact) {
contact.resetOption(Contact.Options.DIRTY_DELETE);
+ contact.setOption(Contact.Options.DIRTY_PUSH);
Account account = contact.getAccount();
if (account.getStatus() == Account.STATUS_ONLINE) {
+ boolean ask = contact.getOption(Contact.Options.ASKING);
+ boolean sendUpdates = contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)
+ && contact.getOption(Contact.Options.PREEMPTIVE_GRANT);
IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
iq.query("jabber:iq:roster").addChild(contact.asElement());
account.getXmppConnection().sendIqPacket(iq, null);
- if (contact.getOption(Contact.Options.ASKING)) {
- requestPresenceUpdatesFrom(contact);
+ if (sendUpdates) {
+ sendPresencePacket(account, mPresenceGenerator.sendPresenceUpdatesTo(contact));
}
- if (contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
- Log.d("xmppService", "contact had pending subscription");
- sendPresenceUpdatesTo(contact);
+ if (ask) {
+ sendPresencePacket(account, mPresenceGenerator.requestPresenceUpdatesFrom(contact));
}
- contact.resetOption(Contact.Options.DIRTY_PUSH);
- } else {
- contact.setOption(Contact.Options.DIRTY_PUSH);
}
}
public void deleteContactOnServer(Contact contact) {
+ contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
contact.resetOption(Contact.Options.DIRTY_PUSH);
+ contact.setOption(Contact.Options.DIRTY_DELETE);
Account account = contact.getAccount();
if (account.getStatus() == Account.STATUS_ONLINE) {
IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
@@ -1289,55 +1192,9 @@ public class XmppConnectionService extends Service {
item.setAttribute("jid", contact.getJid());
item.setAttribute("subscription", "remove");
account.getXmppConnection().sendIqPacket(iq, null);
- contact.resetOption(Contact.Options.DIRTY_DELETE);
- } else {
- contact.setOption(Contact.Options.DIRTY_DELETE);
}
}
- public void requestPresenceUpdatesFrom(Contact contact) {
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("type", "subscribe");
- packet.setAttribute("to", contact.getJid());
- packet.setAttribute("from", contact.getAccount().getJid());
- contact.getAccount().getXmppConnection().sendPresencePacket(packet);
- }
-
- public void stopPresenceUpdatesFrom(Contact contact) {
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("type", "unsubscribe");
- packet.setAttribute("to", contact.getJid());
- packet.setAttribute("from", contact.getAccount().getJid());
- contact.getAccount().getXmppConnection().sendPresencePacket(packet);
- }
-
- public void stopPresenceUpdatesTo(Contact contact) {
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("type", "unsubscribed");
- packet.setAttribute("to", contact.getJid());
- packet.setAttribute("from", contact.getAccount().getJid());
- contact.getAccount().getXmppConnection().sendPresencePacket(packet);
- }
-
- public void sendPresenceUpdatesTo(Contact contact) {
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("type", "subscribed");
- packet.setAttribute("to", contact.getJid());
- packet.setAttribute("from", contact.getAccount().getJid());
- contact.getAccount().getXmppConnection().sendPresencePacket(packet);
- }
-
- public void sendPresence(Account account) {
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("from", account.getFullJid());
- String sig = account.getPgpSignature();
- if (sig != null) {
- packet.addChild("status").setContent("online");
- packet.addChild("x", "jabber:x:signed").setContent(sig);
- }
- account.getXmppConnection().sendPresencePacket(packet);
- }
-
public void updateConversation(Conversation conversation) {
this.databaseBackend.updateConversation(conversation);
}
@@ -1366,38 +1223,19 @@ public class XmppConnectionService extends Service {
}).start();
}
- public void sendConversationSubject(Conversation conversation,
- String subject) {
+ public void inviteToConference(Conversation conversation, String contactJid) {
+ Account account = conversation.getAccount();
MessagePacket packet = new MessagePacket();
- packet.setType(MessagePacket.TYPE_GROUPCHAT);
packet.setTo(conversation.getContactJid().split("/")[0]);
- Element subjectChild = new Element("subject");
- subjectChild.setContent(subject);
- packet.addChild(subjectChild);
- packet.setFrom(conversation.getAccount().getJid());
- Account account = conversation.getAccount();
- if (account.getStatus() == Account.STATUS_ONLINE) {
- account.getXmppConnection().sendMessagePacket(packet);
- }
- }
-
- public void inviteToConference(Conversation conversation,
- List<Contact> contacts) {
- for (Contact contact : contacts) {
- MessagePacket packet = new MessagePacket();
- packet.setTo(conversation.getContactJid().split("/")[0]);
- packet.setFrom(conversation.getAccount().getFullJid());
- Element x = new Element("x");
- x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user");
- Element invite = new Element("invite");
- invite.setAttribute("to", contact.getJid());
- x.addChild(invite);
- packet.addChild(x);
- Log.d(LOGTAG, packet.toString());
- conversation.getAccount().getXmppConnection()
- .sendMessagePacket(packet);
- }
-
+ packet.setFrom(account.getFullJid());
+ Element x = new Element("x");
+ x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user");
+ Element invite = new Element("invite");
+ invite.setAttribute("to", contactJid);
+ x.addChild(invite);
+ packet.addChild(x);
+ sendMessagePacket(account,packet);
+ Log.d(LOGTAG,packet.toString());
}
public boolean markMessage(Account account, String recipient, String uuid,
@@ -1425,9 +1263,7 @@ public class XmppConnectionService extends Service {
public void markMessage(Message message, int status) {
message.setStatus(status);
databaseBackend.updateMessage(message);
- if (convChangedListener != null) {
- convChangedListener.onConversationListChanged();
- }
+ updateConversationUi();
}
public SharedPreferences getPreferences() {
@@ -1439,14 +1275,32 @@ public class XmppConnectionService extends Service {
return getPreferences().getBoolean("confirm_messages", true);
}
- public void updateUi(Conversation conversation, boolean notify) {
- if (convChangedListener != null) {
- convChangedListener.onConversationListChanged();
+ public void notifyUi(Conversation conversation, boolean notify) {
+ if (mOnConversationUpdate != null) {
+ mOnConversationUpdate.onConversationUpdate();
} else {
UIHelper.updateNotification(getApplicationContext(),
getConversations(), conversation, notify);
}
}
+
+ public void updateConversationUi() {
+ if (mOnConversationUpdate != null) {
+ mOnConversationUpdate.onConversationUpdate();
+ }
+ }
+
+ public void updateAccountUi() {
+ if (mOnAccountUpdate != null) {
+ mOnAccountUpdate.onAccountUpdate();
+ }
+ }
+
+ public void updateRosterUi() {
+ if (mOnRosterUpdate != null) {
+ mOnRosterUpdate.onRosterUpdate();
+ }
+ }
public Account findAccountByJid(String accountJid) {
for (Account account : this.accounts) {
@@ -1456,20 +1310,24 @@ public class XmppConnectionService extends Service {
}
return null;
}
-
- public void markRead(Conversation conversation) {
- conversation.markRead(this);
+
+ public Conversation findConversationByUuid(String uuid) {
+ for (Conversation conversation : getConversations()) {
+ if (conversation.getUuid().equals(uuid)) {
+ return conversation;
+ }
+ }
+ return null;
}
- public void sendConfirmMessage(Account account, String to, String id) {
- MessagePacket receivedPacket = new MessagePacket();
- receivedPacket.setType(MessagePacket.TYPE_NORMAL);
- receivedPacket.setTo(to);
- receivedPacket.setFrom(account.getFullJid());
- Element received = receivedPacket.addChild("displayed",
- "urn:xmpp:chat-markers:0");
- received.setAttribute("id", id);
- account.getXmppConnection().sendMessagePacket(receivedPacket);
+ public void markRead(Conversation conversation) {
+ conversation.markRead();
+ String id = conversation.popLatestMarkableMessageId();
+ if (confirmMessages() && id != null) {
+ Account account = conversation.getAccount();
+ String to = conversation.getContactJid();
+ this.sendMessagePacket(conversation.getAccount(), mMessageGenerator.confirm(account, to, id));
+ }
}
public SecureRandom getRNG() {
@@ -1482,19 +1340,87 @@ public class XmppConnectionService extends Service {
public void replyWithNotAcceptable(Account account, MessagePacket packet) {
if (account.getStatus() == Account.STATUS_ONLINE) {
- MessagePacket error = this.mMessageGenerator.generateNotAcceptable(packet);
- account.getXmppConnection().sendMessagePacket(error);
+ MessagePacket error = this.mMessageGenerator
+ .generateNotAcceptable(packet);
+ sendMessagePacket(account,error);
}
}
-
+
public void syncRosterToDisk(final Account account) {
new Thread(new Runnable() {
-
+
@Override
public void run() {
databaseBackend.writeRoster(account.getRoster());
}
}).start();
-
+
+ }
+
+ public List<String> getKnownHosts() {
+ List<String> hosts = new ArrayList<String>();
+ for (Account account : getAccounts()) {
+ if (!hosts.contains(account.getServer())) {
+ hosts.add(account.getServer());
+ }
+ for (Contact contact : account.getRoster().getContacts()) {
+ if (contact.showInRoster()) {
+ String server = contact.getServer();
+ if (server != null && !hosts.contains(server)) {
+ hosts.add(server);
+ }
+ }
+ }
+ }
+ return hosts;
+ }
+
+ public List<String> getKnownConferenceHosts() {
+ ArrayList<String> mucServers = new ArrayList<String>();
+ for (Account account : accounts) {
+ if (account.getXmppConnection() != null) {
+ String server = account.getXmppConnection().getMucServer();
+ if (server != null) {
+ mucServers.add(server);
+ }
+ }
+ }
+ return mucServers;
+ }
+
+ public void sendMessagePacket(Account account, MessagePacket packet) {
+ account.getXmppConnection().sendMessagePacket(packet);
+ }
+
+ public void sendPresencePacket(Account account, PresencePacket packet) {
+ account.getXmppConnection().sendPresencePacket(packet);
+ }
+
+ public void sendIqPacket(Account account, IqPacket packet, OnIqPacketReceived callback) {
+ account.getXmppConnection().sendIqPacket(packet, callback);
+ }
+
+ public MessageGenerator getMessageGenerator() {
+ return this.mMessageGenerator;
+ }
+
+ public PresenceGenerator getPresenceGenerator() {
+ return this.mPresenceGenerator;
+ }
+
+ public JingleConnectionManager getJingleConnectionManager() {
+ return this.mJingleConnectionManager;
+ }
+
+ public interface OnConversationUpdate {
+ public void onConversationUpdate();
+ }
+
+ public interface OnAccountUpdate {
+ public void onAccountUpdate();
+ }
+
+ public interface OnRosterUpdate {
+ public void onRosterUpdate();
}
}