diff options
Diffstat (limited to 'src/main/java/eu/siacs/conversations/services')
-rw-r--r-- | src/main/java/eu/siacs/conversations/services/MessageArchiveService.java | 62 | ||||
-rw-r--r-- | src/main/java/eu/siacs/conversations/services/XmppConnectionService.java | 146 |
2 files changed, 151 insertions, 57 deletions
diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index 34d4a7cd..3ad0c514 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -24,8 +24,8 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { private final XmppConnectionService mXmppConnectionService; - private final HashSet<Query> queries = new HashSet<Query>(); - private final ArrayList<Query> pendingQueries = new ArrayList<Query>(); + private final HashSet<Query> queries = new HashSet<>(); + private final ArrayList<Query> pendingQueries = new ArrayList<>(); public enum PagingOrder { NORMAL, @@ -102,6 +102,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { return null; } final Query query = new Query(conversation, start, end,PagingOrder.REVERSE); + query.reference = conversation.getFirstMamReference(); this.queries.add(query); this.execute(query); return query; @@ -130,21 +131,21 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { Logging.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": running mam query " + query.toString()); IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(query); this.mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() { - @Override - public void onIqPacketReceived(Account account, IqPacket packet) { - if (packet.getType() == IqPacket.TYPE.TIMEOUT) { - synchronized (MessageArchiveService.this.queries) { - MessageArchiveService.this.queries.remove(query); - if (query.hasCallback()) { - query.callback(); - } - } - } else if (packet.getType() != IqPacket.TYPE.RESULT) { - Logging.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": error executing mam: " + packet.toString()); - finalizeQuery(query); - } - } - }); + @Override + public void onIqPacketReceived(Account account, IqPacket packet) { + if (packet.getType() == IqPacket.TYPE.TIMEOUT) { + synchronized (MessageArchiveService.this.queries) { + MessageArchiveService.this.queries.remove(query); + if (query.hasCallback()) { + query.callback(false); + } + } + } else if (packet.getType() != IqPacket.TYPE.RESULT) { + Logging.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": error executing mam: " + packet.toString()); + finalizeQuery(query, true); + } + } + }); } else { synchronized (this.pendingQueries) { this.pendingQueries.add(query); @@ -152,13 +153,14 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { } } - private void finalizeQuery(Query query) { + private void finalizeQuery(Query query, boolean done) { synchronized (this.queries) { this.queries.remove(query); } final Conversation conversation = query.getConversation(); if (conversation != null) { conversation.sort(); + conversation.setHasMessagesLeftOnServer(!done); } else { for(Conversation tmp : this.mXmppConnectionService.getConversations()) { if (tmp.getAccount() == query.getAccount()) { @@ -167,7 +169,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { } } if (query.hasCallback()) { - query.callback(); + query.callback(done); } else { if (null != conversation) { conversation.setHasMessagesLeftOnServer(query.getMessageCount() > 0); @@ -204,9 +206,13 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { Element first = set == null ? null : set.findChild("first"); Element relevant = query.getPagingOrder() == PagingOrder.NORMAL ? last : first; boolean abort = (query.getStart() == 0 && query.getTotalCount() >= Config.PAGE_SIZE) || query.getTotalCount() >= Config.MAM_MAX_MESSAGES; + if (query.getConversation() != null) { + query.getConversation().setFirstMamReference(first == null ? null : first.getContent()); + } if (complete || relevant == null || abort) { - this.finalizeQuery(query); - Logging.d(Config.LOGTAG,query.getAccount().getJid().toBareJid().toString()+": finished mam after "+query.getTotalCount()+" messages"); + final boolean done = (complete || query.getMessageCount() == 0) && query.getStart() == 0; + this.finalizeQuery(query, done); + Logging.d(Config.LOGTAG,query.getAccount().getJid().toBareJid()+": finished mam after "+query.getTotalCount()+" messages. messages left="+Boolean.toString(!done)); if (query.getWith() == null && query.getMessageCount() > 0) { mXmppConnectionService.getNotificationService().finishBacklog(true); } @@ -218,7 +224,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { nextQuery = query.prev(first == null ? null : first.getContent()); } this.execute(nextQuery); - this.finalizeQuery(query); + this.finalizeQuery(query, false); synchronized (this.queries) { this.queries.remove(query); this.queries.add(nextQuery); @@ -326,10 +332,10 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { this.callback = callback; } - public void callback() { + public void callback(boolean done) { if (this.callback != null) { this.callback.onMoreMessagesLoaded(messageCount,conversation); - if (messageCount == 0) { + if (done) { this.callback.informUser(R.string.no_more_history_on_server); } } @@ -347,12 +353,9 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { return this.account; } - public void incrementTotalCount() { - this.totalCount++; - } - public void incrementMessageCount() { this.messageCount++; + this.totalCount++; } public int getTotalCount() { @@ -375,7 +378,8 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { public String toString() { StringBuilder builder = new StringBuilder(); if (this.muc()) { - builder.append("to="+this.getWith().toString()); + builder.append("to="); + builder.append(this.getWith().toString()); } else { builder.append("with="); if (this.getWith() == null) { diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index fd22b55c..53b60d5f 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -81,7 +81,10 @@ import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.MucOptions.OnRenameListener; +import eu.siacs.conversations.entities.Presence; import eu.siacs.conversations.entities.Presences; +import eu.siacs.conversations.entities.Roster; +import eu.siacs.conversations.entities.ServiceDiscoveryResult; import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.entities.TransferablePlaceholder; import eu.siacs.conversations.generator.IqGenerator; @@ -247,6 +250,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa private OnKeyStatusUpdated mOnKeyStatusUpdated = null; private int keyStatusUpdatedListenerCount = 0; private SecureRandom mRandom; + private LruCache<Pair<String,String>,ServiceDiscoveryResult> discoCache = new LruCache<>(20); private final OnBindListener mOnBindListener = new OnBindListener() { @Override @@ -281,7 +285,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } List<Conversation> conversations = getConversations(); for (Conversation conversation : conversations) { - if (conversation.getAccount() == account) { + if (conversation.getAccount() == account && conversation.getMode() == Conversation.MODE_SINGLE) { conversation.startOtrIfNeeded(); sendUnsentMessages(conversation); } @@ -333,7 +337,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } public PgpEngine getPgpEngine() { - if (pgpServiceConnection.isBound()) { + if (pgpServiceConnection != null && pgpServiceConnection.isBound()) { if (this.mPgpEngine == null) { this.mPgpEngine = new PgpEngine(new OpenPgpApi( getApplicationContext(), @@ -548,13 +552,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return getPreferences().getBoolean("away_when_screen_off", false); } - private int getTargetPresence() { + private Presence.Status getTargetPresence() { if (xaOnSilentMode() && isPhoneSilenced()) { - return Presences.XA; + return Presence.Status.XA; } else if (awayWhenScreenOff() && !isInteractive()) { - return Presences.AWAY; + return Presence.Status.AWAY; } else { - return Presences.ONLINE; + return Presence.Status.ONLINE; } } @@ -936,11 +940,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa private void sendUnsentMessages(final Conversation conversation) { conversation.findWaitingMessages(new Conversation.OnMessageFound() { - @Override - public void onMessageFound(Message message) { - resendMessage(message, true); - } - }); + @Override + public void onMessageFound(Message message) { + resendMessage(message, true); + } + }); } public void resendMessage(final Message message, final boolean delay) { @@ -1163,25 +1167,28 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } Collections.sort(list, new Comparator<Conversation>() { - @Override - public int compare(Conversation lhs, Conversation rhs) { - Message left = lhs.getLatestMessage(); - Message right = rhs.getLatestMessage(); - if (left.getTimeSent() > right.getTimeSent()) { - return -1; - } else if (left.getTimeSent() < right.getTimeSent()) { - return 1; - } else { - return 0; - } - } - }); + @Override + public int compare(Conversation lhs, Conversation rhs) { + Message left = lhs.getLatestMessage(); + Message right = rhs.getLatestMessage(); + if (left.getTimeSent() > right.getTimeSent()) { + return -1; + } else if (left.getTimeSent() < right.getTimeSent()) { + return 1; + } else { + return 0; + } + } + }); } public void loadMoreMessages(final Conversation conversation, final long timestamp, final OnMoreMessagesLoaded callback) { if (XmppConnectionService.this.getMessageArchiveService().queryInProgress(conversation, callback)) { Logging.d("mam", "Query in progress"); return; + } else if (timestamp == 0) { + Logging.d("mam", "Query stopped due to timestamp"); + return; } //TODO Create a separate class for this runnable to store if messages are getting loaded or not. Not really a good idea to do this in the callback. Logging.d(Config.LOGTAG, "load more messages for " + conversation.getName() + " prior to " + MessageGenerator.getTimestamp(timestamp)); @@ -1201,7 +1208,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa checkDeletedFiles(conversation); callback.onMoreMessagesLoaded(messages.size(), conversation); } else if (conversation.hasMessagesLeftOnServer() - && account.isOnlineAndConnected()) { + && account.isOnlineAndConnected() + && conversation.getLastClearHistory() == 0) { Logging.d("mam", "mam activate, account online and connected and messages left on server"); if ((conversation.getMode() == Conversation.MODE_SINGLE && account.getXmppConnection().getFeatures().mam()) || (conversation.getMode() == Conversation.MODE_MULTI && conversation.getMucOptions().mamSupport())) { @@ -1448,7 +1456,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa databaseBackend.deleteAccount(account); } }; - ConversationsPlusApplication.executeDatabaseOperation(runnable); + mDatabaseExecutor.execute(runnable); this.accounts.remove(account); updateAccountUi(); getNotificationService().updateErrorNotification(); @@ -1753,6 +1761,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa if (conversation.getMucOptions().mamSupport()) { getMessageArchiveService().catchupMUC(conversation); } + sendUnsentMessages(conversation); } @Override @@ -2164,7 +2173,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa packet.setFrom(account.getJid()); MessageGenerator.addMessageHints(packet); packet.setAttribute("to", otrSession.getSessionID().getAccountID() + "/" - + otrSession.getSessionID().getUserID()); + + otrSession.getSessionID().getUserID()); try { packet.setBody(otrSession .transformSending(CryptoHelper.FILETRANSFER @@ -2726,13 +2735,94 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa @Override public void onIqPacketReceived(Account account, IqPacket packet) { if (packet.getType() == IqPacket.TYPE.ERROR) { - Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not publish nick"); + Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": could not publish nick"); } } }); } } + private ServiceDiscoveryResult getCachedServiceDiscoveryResult(Pair<String,String> key) { + ServiceDiscoveryResult result = discoCache.get(key); + if (result != null) { + return result; + } else { + result = databaseBackend.findDiscoveryResult(key.first, key.second); + if (result != null) { + discoCache.put(key, result); + } + return result; + } + } + + public void fetchCaps(Account account, final Jid jid, final Presence presence) { + final Pair<String,String> key = new Pair<>(presence.getHash(), presence.getVer()); + ServiceDiscoveryResult disco = getCachedServiceDiscoveryResult(key); + if (disco != null) { + presence.setServiceDiscoveryResult(disco); + } else { + if (!account.inProgressDiscoFetches.contains(key)) { + account.inProgressDiscoFetches.add(key); + IqPacket request = new IqPacket(IqPacket.TYPE.GET); + request.setTo(jid); + request.query("http://jabber.org/protocol/disco#info"); + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": making disco request for "+key.second+" to "+jid); + sendIqPacket(account, request, new OnIqPacketReceived() { + @Override + public void onIqPacketReceived(Account account, IqPacket discoPacket) { + if (discoPacket.getType() == IqPacket.TYPE.RESULT) { + ServiceDiscoveryResult disco = new ServiceDiscoveryResult(discoPacket); + if (presence.getVer().equals(disco.getVer())) { + databaseBackend.insertDiscoveryResult(disco); + injectServiceDiscorveryResult(account.getRoster(), presence.getHash(), presence.getVer(), disco); + } else { + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": mismatch in caps for contact " + jid+" "+presence.getVer()+" vs "+disco.getVer()); + } + } + account.inProgressDiscoFetches.remove(key); + } + }); + } + } + } + + private void injectServiceDiscorveryResult(Roster roster, String hash, String ver, ServiceDiscoveryResult disco) { + for(Contact contact : roster.getContacts()) { + for(Presence presence : contact.getPresences().getPresences().values()) { + if (hash.equals(presence.getHash()) && ver.equals(presence.getVer())) { + presence.setServiceDiscoveryResult(disco); + } + } + } + } + + public void fetchMamPreferences(Account account, final OnMamPreferencesFetched callback) { + IqPacket request = new IqPacket(IqPacket.TYPE.GET); + request.addChild("prefs","urn:xmpp:mam:0"); + sendIqPacket(account, request, new OnIqPacketReceived() { + @Override + public void onIqPacketReceived(Account account, IqPacket packet) { + Element prefs = packet.findChild("prefs","urn:xmpp:mam:0"); + if (packet.getType() == IqPacket.TYPE.RESULT && prefs != null) { + callback.onPreferencesFetched(prefs); + } else { + callback.onPreferencesFetchFailed(); + } + } + }); + } + + public interface OnMamPreferencesFetched { + void onPreferencesFetched(Element prefs); + void onPreferencesFetchFailed(); + } + + public void pushMamPreferences(Account account, Element prefs) { + IqPacket set = new IqPacket(IqPacket.TYPE.SET); + set.addChild(prefs); + sendIqPacket(account, set, null); + } + public interface OnAccountCreated { void onAccountCreated(Account account); |