Use MAM for MUC initial history retrieval

saqura created

If the MUC supports MAM (XEP-0313), use it to retrieve the history
when joining.

Change summary

src/main/java/eu/siacs/conversations/services/MessageArchiveService.java | 12 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java | 82 
2 files changed, 66 insertions(+), 28 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/services/MessageArchiveService.java 🔗

@@ -54,6 +54,18 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
 		this.execute(query);
 	}
 
+	public void catchupMUC(final Conversation conversation) {
+		if (conversation.getLastMessageTransmitted() < 0 && conversation.countMessages() == 0) {
+			query(conversation,
+					0,
+					System.currentTimeMillis());
+		} else {
+			query(conversation,
+					conversation.getLastMessageTransmitted(),
+					System.currentTimeMillis());
+		}
+	}
+
 	private long getLastMessageTransmitted(final Account account) {
 		long timestamp = 0;
 		for(final Conversation conversation : mXmppConnectionService.getConversations()) {

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -1064,10 +1064,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 	}
 
 	public void loadMoreMessages(final Conversation conversation, final long timestamp, final OnMoreMessagesLoaded callback) {
-		Log.d(Config.LOGTAG, "load more messages for " + conversation.getName() + " prior to " + MessageGenerator.getTimestamp(timestamp));
 		if (XmppConnectionService.this.getMessageArchiveService().queryInProgress(conversation,callback)) {
 			return;
 		}
+		Log.d(Config.LOGTAG, "load more messages for " + conversation.getName() + " prior to " + MessageGenerator.getTimestamp(timestamp));
 		Runnable runnable = new Runnable() {
 			@Override
 			public void run() {
@@ -1480,7 +1480,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 	}
 
 	public void joinMuc(Conversation conversation) {
-		joinMuc(conversation,false);
+		joinMuc(conversation, false);
 	}
 
 	private void joinMuc(Conversation conversation, boolean now) {
@@ -1489,32 +1489,47 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		account.pendingConferenceLeaves.remove(conversation);
 		if (account.getStatus() == Account.State.ONLINE || now) {
 			conversation.resetMucOptions();
-			final String nick = conversation.getMucOptions().getProposedNick();
-			final Jid joinJid = conversation.getMucOptions().createJoinJid(nick);
-			if (joinJid == null) {
-				return; //safety net
-			}
-			Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": joining conversation " + joinJid.toString());
-			PresencePacket packet = new PresencePacket();
-			packet.setFrom(conversation.getAccount().getJid());
-			packet.setTo(joinJid);
-			Element x = packet.addChild("x", "http://jabber.org/protocol/muc");
-			if (conversation.getMucOptions().getPassword() != null) {
-				x.addChild("password").setContent(conversation.getMucOptions().getPassword());
-			}
-			x.addChild("history").setAttribute("since", PresenceGenerator.getTimestamp(conversation.getLastMessageTransmitted()));
-			String sig = account.getPgpSignature();
-			if (sig != null) {
-				packet.addChild("status").setContent("online");
-				packet.addChild("x", "jabber:x:signed").setContent(sig);
-			}
-			sendPresencePacket(account, packet);
-			fetchConferenceConfiguration(conversation);
-			if (!joinJid.equals(conversation.getJid())) {
-				conversation.setContactJid(joinJid);
-				databaseBackend.updateConversation(conversation);
-			}
-			conversation.setHasMessagesLeftOnServer(false);
+			fetchConferenceConfiguration(conversation, new OnConferenceConfigurationFetched() {
+				@Override
+				public void onConferenceConfigurationFetched(Conversation conversation) {
+					Account account = conversation.getAccount();
+					final String nick = conversation.getMucOptions().getProposedNick();
+					final Jid joinJid = conversation.getMucOptions().createJoinJid(nick);
+					if (joinJid == null) {
+						return; //safety net
+					}
+					Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": joining conversation " + joinJid.toString());
+					PresencePacket packet = new PresencePacket();
+					packet.setFrom(conversation.getAccount().getJid());
+					packet.setTo(joinJid);
+					Element x = packet.addChild("x", "http://jabber.org/protocol/muc");
+					if (conversation.getMucOptions().getPassword() != null) {
+						x.addChild("password").setContent(conversation.getMucOptions().getPassword());
+					}
+
+					if (conversation.getMucOptions().mamSupport()) {
+						// Use MAM instead of the limited muc history to get history
+						x.addChild("history").setAttribute("maxchars", "0");
+						getMessageArchiveService().catchupMUC(conversation);
+					} else {
+						// Fallback to muc history
+						x.addChild("history").setAttribute("since", PresenceGenerator.getTimestamp(conversation.getLastMessageTransmitted()));
+					}
+					String sig = account.getPgpSignature();
+					if (sig != null) {
+						packet.addChild("status").setContent("online");
+						packet.addChild("x", "jabber:x:signed").setContent(sig);
+					}
+					sendPresencePacket(account, packet);
+					fetchConferenceConfiguration(conversation);
+					if (!joinJid.equals(conversation.getJid())) {
+						conversation.setContactJid(joinJid);
+						databaseBackend.updateConversation(conversation);
+					}
+					conversation.setHasMessagesLeftOnServer(false);
+				}
+			});
+
 		} else {
 			account.pendingConferenceJoins.add(conversation);
 		}
@@ -1674,6 +1689,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 	}
 
 	public void fetchConferenceConfiguration(final Conversation conversation) {
+		fetchConferenceConfiguration(conversation, null);
+	}
+
+	public void fetchConferenceConfiguration(final Conversation conversation, final OnConferenceConfigurationFetched callback) {
 		IqPacket request = new IqPacket(IqPacket.TYPE.GET);
 		request.setTo(conversation.getJid().toBareJid());
 		request.query("http://jabber.org/protocol/disco#info");
@@ -1691,6 +1710,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 						}
 					}
 					conversation.getMucOptions().updateFeatures(features);
+					if (callback != null) {
+						callback.onConferenceConfigurationFetched(conversation);
+					}
 					updateConversationUi();
 				}
 			}
@@ -2631,6 +2653,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		public void onMucRosterUpdate();
 	}
 
+	public interface OnConferenceConfigurationFetched {
+		public void onConferenceConfigurationFetched(Conversation conversation);
+	}
+
 	public interface OnConferenceOptionsPushed {
 		public void onPushSucceeded();