diff options
6 files changed, 130 insertions, 39 deletions
diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index e9e73db9e..c491d632b 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -22,7 +22,9 @@ public final class Config { public static final boolean NO_PROXY_LOOKUP = false; //useful to debug ibb - public static final long MAX_HISTORY_AGE = 7 * 24 * 60 * 60 * 1000; + private static final long MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000; + public static final long MAX_HISTORY_AGE = 7 * MILLISECONDS_IN_DAY; + public static final long MAX_CATCHUP = MILLISECONDS_IN_DAY / 2; private Config() { diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index e254cfc28..a30847b97 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -3,6 +3,7 @@ package eu.siacs.conversations.entities; import android.content.ContentValues; import android.database.Cursor; import android.os.SystemClock; +import android.util.Log; import net.java.otr4j.OtrException; import net.java.otr4j.crypto.OtrCryptoEngineImpl; @@ -20,6 +21,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; +import eu.siacs.conversations.Config; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 56a0776f0..4f87b2b04 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -1,9 +1,12 @@ package eu.siacs.conversations.generator; +import android.util.Log; + import java.util.Arrays; import java.util.Collections; import java.util.List; +import eu.siacs.conversations.Config; import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xml.Element; @@ -103,7 +106,9 @@ public class IqGenerator extends AbstractGenerator { query.setAttribute("queryid",mam.getQueryId()); Data data = new Data(); data.setFormType("urn:xmpp:mam:0"); - data.put("with",mam.getWith().toString()); + if (mam.getWith()!=null) { + data.put("with", mam.getWith().toString()); + } data.put("start",getTimestamp(mam.getStart())); data.put("end",getTimestamp(mam.getEnd())); query.addChild(data); diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 74d38ce44..cd4c6401a 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -10,6 +10,7 @@ import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.xml.Element; @@ -303,16 +304,17 @@ public class MessageParser extends AbstractParser implements final long timestamp = getTimestamp(forwarded); final Jid to = message.getAttributeAsJid("to"); final Jid from = message.getAttributeAsJid("from"); + final MessageArchiveService.Query query = this.mXmppConnectionService.getMessageArchiveService().findQuery(result.getAttribute("queryid")); Jid counterpart; int status; Conversation conversation; if (from!=null && to != null && from.toBareJid().equals(account.getJid().toBareJid())) { status = Message.STATUS_SEND; - conversation = this.mXmppConnectionService.findOrCreateConversation(account,to.toBareJid(),false); + conversation = this.mXmppConnectionService.findOrCreateConversation(account,to.toBareJid(),false,query); counterpart = to; } else if (from !=null && to != null) { status = Message.STATUS_RECEIVED; - conversation = this.mXmppConnectionService.findOrCreateConversation(account,from.toBareJid(),false); + conversation = this.mXmppConnectionService.findOrCreateConversation(account,from.toBareJid(),false,query); counterpart = from; } else { return null; diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index c93a6e759..3b84d4110 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -9,6 +9,8 @@ import java.util.List; import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.generator.AbstractGenerator; +import eu.siacs.conversations.parser.AbstractParser; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded; import eu.siacs.conversations.xmpp.OnIqPacketReceived; @@ -25,26 +27,69 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { this.mXmppConnectionService = service; } + public void catchup(final Account account) { + long startCatchup = getLastMessageTransmitted(account); + long endCatchup = account.getXmppConnection().getLastSessionEstablished(); + if (startCatchup == 0) { + return; + } else if (endCatchup - startCatchup >= Config.MAX_CATCHUP) { + startCatchup = endCatchup - Config.MAX_CATCHUP; + List<Conversation> conversations = mXmppConnectionService.getConversations(); + for (Conversation conversation : conversations) { + if (conversation.getMode() == Conversation.MODE_SINGLE && conversation.getAccount() == account && startCatchup > conversation.getLastMessageTransmitted()) { + this.query(conversation,startCatchup); + } + } + } + final Query query = new Query(account, startCatchup, endCatchup); + this.queries.add(query); + this.execute(query); + } + + private long getLastMessageTransmitted(final Account account) { + long timestamp = 0; + for(final Conversation conversation : mXmppConnectionService.getConversations()) { + if (conversation.getAccount() == account) { + long tmp = conversation.getLastMessageTransmitted(); + if (tmp > timestamp) { + timestamp = tmp; + } + } + } + return timestamp; + } + public void query(final Conversation conversation) { + query(conversation,conversation.getAccount().getXmppConnection().getLastSessionEstablished()); + } + + public void query(final Conversation conversation, long end) { synchronized (this.queries) { final Account account = conversation.getAccount(); long start = conversation.getLastMessageTransmitted(); - long end = account.getXmppConnection().getLastSessionEstablished(); - if (end - start >= Config.MAX_HISTORY_AGE) { + if (start > end) { + return; + } else if (end - start >= Config.MAX_HISTORY_AGE) { start = end - Config.MAX_HISTORY_AGE; } final Query query = new Query(conversation, start, end); this.queries.add(query); - IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(query); - this.mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() { + this.execute(query); + } + } + + private void execute(final Query query) { + Log.d(Config.LOGTAG,query.getAccount().getJid().toBareJid().toString()+": running mam query "+query.toString()); + IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(query); + this.mXmppConnectionService.sendIqPacket(query.getAccount(), packet, new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { if (packet.getType() == IqPacket.TYPE_ERROR) { + Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": error executing mam: "+packet.toString()); finalizeQuery(query); } } }); - } } private void finalizeQuery(Query query) { @@ -52,11 +97,22 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { this.queries.remove(query); } final Conversation conversation = query.getConversation(); - conversation.sort(); - if (conversation.setLastMessageTransmitted(query.getEnd())) { - this.mXmppConnectionService.databaseBackend.updateConversation(conversation); + if (conversation != null) { + conversation.sort(); + if (conversation.setLastMessageTransmitted(query.getEnd())) { + this.mXmppConnectionService.databaseBackend.updateConversation(conversation); + } + this.mXmppConnectionService.updateConversationUi(); + } else { + for(Conversation tmp : this.mXmppConnectionService.getConversations()) { + if (tmp.getAccount() == query.getAccount()) { + tmp.sort(); + if (tmp.setLastMessageTransmitted(query.getEnd())) { + this.mXmppConnectionService.databaseBackend.updateConversation(tmp); + } + } + } } - this.mXmppConnectionService.updateConversationUi(); } public void processFin(Element fin) { @@ -71,28 +127,18 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { Element set = fin.findChild("set","http://jabber.org/protocol/rsm"); Element last = set == null ? null : set.findChild("last"); if (complete || last == null) { - final Account account = query.getConversation().getAccount(); - Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": completed mam query for "+query.getWith().toString()); this.finalizeQuery(query); } else { final Query nextQuery = query.next(last == null ? null : last.getContent()); - IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(nextQuery); + this.execute(nextQuery); synchronized (this.queries) { this.queries.remove(query); this.queries.add(nextQuery); } - this.mXmppConnectionService.sendIqPacket(query.getConversation().getAccount(),packet,new OnIqPacketReceived() { - @Override - public void onIqPacketReceived(Account account, IqPacket packet) { - if (packet.getType() == IqPacket.TYPE_ERROR) { - finalizeQuery(nextQuery); - } - } - }); } } - private Query findQuery(String id) { + public Query findQuery(String id) { if (id == null) { return null; } @@ -109,36 +155,37 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { @Override public void onAdvancedStreamFeaturesAvailable(Account account) { if (account.getXmppConnection() != null && account.getXmppConnection().getFeatures().mam()) { - List<Conversation> conversations = mXmppConnectionService.getConversations(); - for (Conversation conversation : conversations) { - if (conversation.getMode() == Conversation.MODE_SINGLE && conversation.getAccount() == account) { - this.query(conversation); - } - } - } else { - Log.d(Config.LOGTAG,"no mam available"); + this.catchup(account); } } public class Query { private long start; private long end; - private Jid with; + private Jid with = null; private String queryId; private String after = null; + private Account account; private Conversation conversation; public Query(Conversation conversation, long start, long end) { + this(conversation.getAccount(), start, end); this.conversation = conversation; this.with = conversation.getContactJid().toBareJid(); + } + + public Query(Account account, long start, long end) { + this.account = account; this.start = start; this.end = end; this.queryId = new BigInteger(50, mXmppConnectionService.getRNG()).toString(32); } public Query next(String after) { - Query query = new Query(this.conversation,this.start,this.end); + Query query = new Query(this.account,this.start,this.end); query.after = after; + query.conversation = conversation; + query.with = with; return query; } @@ -165,5 +212,29 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { public Conversation getConversation() { return conversation; } + + public Account getAccount() { + return this.account; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("with="); + if (this.with==null) { + builder.append("*"); + } else { + builder.append(with.toString()); + } + builder.append(", start="); + builder.append(AbstractGenerator.getTimestamp(this.start)); + builder.append(", end="); + builder.append(AbstractGenerator.getTimestamp(this.end)); + if (this.after!=null) { + builder.append(", after="); + builder.append(this.after); + } + return builder.toString(); + } } } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 86b6be568..7df97f5a4 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -988,8 +988,11 @@ public class XmppConnectionService extends Service { return null; } - public Conversation findOrCreateConversation(final Account account, final Jid jid, - final boolean muc) { + public Conversation findOrCreateConversation(final Account account, final Jid jid,final boolean muc) { + return this.findOrCreateConversation(account,jid,muc,null); + } + + public Conversation findOrCreateConversation(final Account account, final Jid jid,final boolean muc, final MessageArchiveService.Query query) { synchronized (this.conversations) { Conversation conversation = find(account, jid); if (conversation != null) { @@ -1023,7 +1026,13 @@ public class XmppConnectionService extends Service { } this.databaseBackend.createConversation(conversation); } - this.mMessageArchiveService.query(conversation); + if (query == null) { + this.mMessageArchiveService.query(conversation); + } else { + if (query.getConversation() == null) { + this.mMessageArchiveService.query(conversation,query.getStart()); + } + } this.conversations.add(conversation); updateConversationUi(); return conversation; @@ -1303,7 +1312,7 @@ public class XmppConnectionService extends Service { @Override public void onFailure() { - callback.error(R.string.nick_in_use,conversation); + callback.error(R.string.nick_in_use, conversation); } }); |