1package eu.siacs.conversations.services;
2
3import android.util.Log;
4
5import java.math.BigInteger;
6import java.util.HashSet;
7
8import eu.siacs.conversations.Config;
9import eu.siacs.conversations.entities.Account;
10import eu.siacs.conversations.entities.Conversation;
11import eu.siacs.conversations.xml.Element;
12import eu.siacs.conversations.xmpp.OnIqPacketReceived;
13import eu.siacs.conversations.xmpp.jid.Jid;
14import eu.siacs.conversations.xmpp.stanzas.IqPacket;
15
16public class MessageArchiveService {
17
18 private final XmppConnectionService mXmppConnectionService;
19
20 private final HashSet<Query> queries = new HashSet<Query>();
21
22 public MessageArchiveService(final XmppConnectionService service) {
23 this.mXmppConnectionService = service;
24 }
25
26 public void query(final Conversation conversation) {
27 synchronized (this.queries) {
28 final Account account = conversation.getAccount();
29 long start = conversation.getLastMessageReceived();
30 long end = account.getXmppConnection().getLastSessionEstablished();
31 final Query query = new Query(conversation, start, end);
32 this.queries.add(query);
33 IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(query);
34 this.mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
35 @Override
36 public void onIqPacketReceived(Account account, IqPacket packet) {
37 Log.d(Config.LOGTAG, packet.toString());
38 }
39 });
40 }
41 }
42
43 public void processFin(Element fin) {
44 if (fin == null) {
45 return;
46 }
47 Query query = findQuery(fin.getAttribute("queryid"));
48 if (query == null) {
49 return;
50 }
51 Log.d(Config.LOGTAG,"fin "+fin.toString());
52 boolean complete = fin.getAttributeAsBoolean("complete");
53 Element set = fin.findChild("set","http://jabber.org/protocol/rsm");
54 Element last = set == null ? null : set.findChild("last");
55 if (complete || last == null) {
56 Log.d(Config.LOGTAG,"completed mam query for "+query.getWith().toString());
57 synchronized (this.queries) {
58 this.queries.remove(query);
59 }
60 } else {
61 Query nextQuery = query.next(last == null ? null : last.getContent());
62 IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(nextQuery);
63 synchronized (this.queries) {
64 this.queries.remove(query);
65 this.queries.add(nextQuery);
66 }
67 Log.d(Config.LOGTAG,packet.toString());
68 this.mXmppConnectionService.sendIqPacket(query.getConversation().getAccount(),packet,new OnIqPacketReceived() {
69 @Override
70 public void onIqPacketReceived(Account account, IqPacket packet) {
71 Log.d(Config.LOGTAG,packet.toString());
72 }
73 });
74 }
75 }
76
77 private Query findQuery(String id) {
78 if (id == null) {
79 return null;
80 }
81 synchronized (this.queries) {
82 for(Query query : this.queries) {
83 if (query.getQueryId().equals(id)) {
84 return query;
85 }
86 }
87 return null;
88 }
89 }
90
91 public class Query {
92 private long start;
93 private long end;
94 private Jid with;
95 private String queryId;
96 private String after = null;
97 private Conversation conversation;
98
99 public Query(Conversation conversation, long start, long end) {
100 this.conversation = conversation;
101 this.with = conversation.getContactJid().toBareJid();
102 this.start = start;
103 this.end = end;
104 this.queryId = new BigInteger(50, mXmppConnectionService.getRNG()).toString(32);
105 }
106
107 public Query next(String after) {
108 Query query = new Query(this.conversation,this.start,this.end);
109 query.after = after;
110 return query;
111 }
112
113 public String getAfter() {
114 return after;
115 }
116
117 public String getQueryId() {
118 return queryId;
119 }
120
121 public Jid getWith() {
122 return with;
123 }
124
125 public long getStart() {
126 return start;
127 }
128
129 public long getEnd() {
130 return end;
131 }
132
133 public Conversation getConversation() {
134 return conversation;
135 }
136 }
137}