very basic mam support

This commit is contained in:
iNPUTmice 2014-12-05 01:54:16 +01:00
parent 34558cc277
commit 4a94389f05
9 changed files with 277 additions and 8 deletions

View file

@ -102,9 +102,7 @@ public class Bookmark extends Element implements ListItem {
} }
public boolean autojoin() { public boolean autojoin() {
String autojoin = this.getAttribute("autojoin"); return this.getAttributeAsBoolean("autojoin");
return (autojoin != null && (autojoin.equalsIgnoreCase("true") || autojoin
.equalsIgnoreCase("1")));
} }
public String getPassword() { public String getPassword() {

View file

@ -4,8 +4,10 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import eu.siacs.conversations.services.MessageArchiveService;
import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.forms.Data;
import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.jid.Jid;
import eu.siacs.conversations.xmpp.pep.Avatar; import eu.siacs.conversations.xmpp.pep.Avatar;
import eu.siacs.conversations.xmpp.stanzas.IqPacket; import eu.siacs.conversations.xmpp.stanzas.IqPacket;
@ -94,4 +96,20 @@ public class IqGenerator extends AbstractGenerator {
} }
return packet; return packet;
} }
public IqPacket queryMessageArchiveManagement(MessageArchiveService.Query mam) {
final IqPacket packet = new IqPacket(IqPacket.TYPE_SET);
Element query = packet.query("urn:xmpp:mam:0");
query.setAttribute("queryid",mam.getQueryId());
Data data = new Data();
data.setFormType("urn:xmpp:mam:0");
data.put("with",mam.getWith().toString());
data.put("start",getTimestamp(mam.getStart()));
data.put("end",getTimestamp(mam.getEnd()));
query.addChild(data);
if (mam.getAfter() != null) {
query.addChild("set", "http://jabber.org/protocol/rsm").addChild("after").setContent(mam.getAfter());
}
return packet;
}
} }

View file

@ -272,6 +272,58 @@ public class MessageParser extends AbstractParser implements
return finishedMessage; return finishedMessage;
} }
private Message parseMamMessage(MessagePacket packet, final Account account) {
final Element result = packet.findChild("result","urn:xmpp:mam:0");
if (result == null ) {
return null;
}
final Element forwarded = result.findChild("forwarded","urn:xmpp:forward:0");
if (forwarded == null) {
return null;
}
final Element message = forwarded.findChild("message");
if (message == null) {
return null;
}
final Element body = message.findChild("body");
if (body == null || message.hasChild("private","urn:xmpp:carbons:2") || message.hasChild("no-copy","urn:xmpp:hints")) {
return null;
}
int encryption;
String content = getPgpBody(message);
if (content != null) {
encryption = Message.ENCRYPTION_PGP;
} else {
encryption = Message.ENCRYPTION_NONE;
content = body.getContent();
}
if (content == null) {
return null;
}
final long timestamp = getTimestamp(forwarded);
final Jid to = message.getAttributeAsJid("to");
final Jid from = message.getAttributeAsJid("from");
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);
counterpart = to;
} else if (from !=null && to != null) {
status = Message.STATUS_RECEIVED;
conversation = this.mXmppConnectionService.findOrCreateConversation(account,from.toBareJid(),false);
counterpart = from;
} else {
return null;
}
Message finishedMessage = new Message(conversation,content,encryption,status);
finishedMessage.setTime(timestamp);
finishedMessage.setCounterpart(counterpart);
Log.d(Config.LOGTAG,"received mam message "+content);
return finishedMessage;
}
private void parseError(final MessagePacket packet, final Account account) { private void parseError(final MessagePacket packet, final Account account) {
final Jid from = packet.getFrom(); final Jid from = packet.getFrom();
mXmppConnectionService.markMessage(account, from.toBareJid(), mXmppConnectionService.markMessage(account, from.toBareJid(),
@ -445,6 +497,17 @@ public class MessageParser extends AbstractParser implements
message.markUnread(); message.markUnread();
} }
} }
} else if (packet.hasChild("result","urn:xmpp:mam:0")) {
message = parseMamMessage(packet, account);
if (message != null) {
Conversation conversation = message.getConversation();
conversation.add(message);
mXmppConnectionService.databaseBackend.createMessage(message);
}
return;
} else if (packet.hasChild("fin","urn:xmpp:mam:0")) {
Element fin = packet.findChild("fin","urn:xmpp:mam:0");
mXmppConnectionService.getMessageArchiveService().processFin(fin);
} else { } else {
parseNonMessage(packet, account); parseNonMessage(packet, account);
} }
@ -493,7 +556,6 @@ public class MessageParser extends AbstractParser implements
&& conversation.getOtrSession() != null && conversation.getOtrSession() != null
&& !conversation.getOtrSession().getSessionID().getUserID() && !conversation.getOtrSession().getSessionID().getUserID()
.equals(message.getCounterpart().getResourcepart())) { .equals(message.getCounterpart().getResourcepart())) {
Log.d(Config.LOGTAG, "ending because of reasons");
conversation.endOtrIfNeeded(); conversation.endOtrIfNeeded();
} }
@ -506,7 +568,7 @@ public class MessageParser extends AbstractParser implements
if (message.trusted() && message.bodyContainsDownloadable()) { if (message.trusted() && message.bodyContainsDownloadable()) {
this.mXmppConnectionService.getHttpConnectionManager() this.mXmppConnectionService.getHttpConnectionManager()
.createNewConnection(message); .createNewConnection(message);
} else { } else if (!message.isRead()) {
mXmppConnectionService.getNotificationService().push(message); mXmppConnectionService.getNotificationService().push(message);
} }
mXmppConnectionService.updateConversationUi(); mXmppConnectionService.updateConversationUi();

View file

@ -0,0 +1,137 @@
package eu.siacs.conversations.services;
import android.util.Log;
import java.math.BigInteger;
import java.util.HashSet;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
import eu.siacs.conversations.xmpp.jid.Jid;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
public class MessageArchiveService {
private final XmppConnectionService mXmppConnectionService;
private final HashSet<Query> queries = new HashSet<Query>();
public MessageArchiveService(final XmppConnectionService service) {
this.mXmppConnectionService = service;
}
public void query(final Conversation conversation) {
synchronized (this.queries) {
final Account account = conversation.getAccount();
long start = conversation.getLastMessageReceived();
long end = account.getXmppConnection().getLastSessionEstablished();
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() {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
Log.d(Config.LOGTAG, packet.toString());
}
});
}
}
public void processFin(Element fin) {
if (fin == null) {
return;
}
Query query = findQuery(fin.getAttribute("queryid"));
if (query == null) {
return;
}
Log.d(Config.LOGTAG,"fin "+fin.toString());
boolean complete = fin.getAttributeAsBoolean("complete");
Element set = fin.findChild("set","http://jabber.org/protocol/rsm");
Element last = set == null ? null : set.findChild("last");
if (complete || last == null) {
Log.d(Config.LOGTAG,"completed mam query for "+query.getWith().toString());
synchronized (this.queries) {
this.queries.remove(query);
}
} else {
Query nextQuery = query.next(last == null ? null : last.getContent());
IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(nextQuery);
synchronized (this.queries) {
this.queries.remove(query);
this.queries.add(nextQuery);
}
Log.d(Config.LOGTAG,packet.toString());
this.mXmppConnectionService.sendIqPacket(query.getConversation().getAccount(),packet,new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
Log.d(Config.LOGTAG,packet.toString());
}
});
}
}
private Query findQuery(String id) {
if (id == null) {
return null;
}
synchronized (this.queries) {
for(Query query : this.queries) {
if (query.getQueryId().equals(id)) {
return query;
}
}
return null;
}
}
public class Query {
private long start;
private long end;
private Jid with;
private String queryId;
private String after = null;
private Conversation conversation;
public Query(Conversation conversation, long start, long end) {
this.conversation = conversation;
this.with = conversation.getContactJid().toBareJid();
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.after = after;
return query;
}
public String getAfter() {
return after;
}
public String getQueryId() {
return queryId;
}
public Jid getWith() {
return with;
}
public long getStart() {
return start;
}
public long getEnd() {
return end;
}
public Conversation getConversation() {
return conversation;
}
}
}

View file

@ -73,6 +73,7 @@ import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener;
import eu.siacs.conversations.utils.PRNGFixes; import eu.siacs.conversations.utils.PRNGFixes;
import eu.siacs.conversations.utils.PhoneHelper; import eu.siacs.conversations.utils.PhoneHelper;
import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesAvailable;
import eu.siacs.conversations.xmpp.OnBindListener; import eu.siacs.conversations.xmpp.OnBindListener;
import eu.siacs.conversations.xmpp.OnContactStatusChanged; import eu.siacs.conversations.xmpp.OnContactStatusChanged;
import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.OnIqPacketReceived;
@ -141,6 +142,7 @@ public class XmppConnectionService extends Service {
private HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager( private HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager(
this); this);
private AvatarService mAvatarService = new AvatarService(this); private AvatarService mAvatarService = new AvatarService(this);
private MessageArchiveService mMessageArchiveService = new MessageArchiveService(this);
private OnConversationUpdate mOnConversationUpdate = null; private OnConversationUpdate mOnConversationUpdate = null;
private Integer convChangedListenerCount = 0; private Integer convChangedListenerCount = 0;
private OnAccountUpdate mOnAccountUpdate = null; private OnAccountUpdate mOnAccountUpdate = null;
@ -203,6 +205,12 @@ public class XmppConnectionService extends Service {
getNotificationService().updateErrorNotification(); getNotificationService().updateErrorNotification();
} }
}; };
private OnAdvancedStreamFeaturesAvailable onAdvancedStreamFeaturesAvailable = new OnAdvancedStreamFeaturesAvailable() {
@Override
public void onAdvancedStreamFeaturesAvailable(Account account) {
queryMessagesFromArchive(account);
}
};
private int accountChangedListenerCount = 0; private int accountChangedListenerCount = 0;
private OnRosterUpdate mOnRosterUpdate = null; private OnRosterUpdate mOnRosterUpdate = null;
private int rosterChangedListenerCount = 0; private int rosterChangedListenerCount = 0;
@ -583,8 +591,8 @@ public class XmppConnectionService extends Service {
connection.setOnUnregisteredIqPacketReceivedListener(this.mIqParser); connection.setOnUnregisteredIqPacketReceivedListener(this.mIqParser);
connection.setOnJinglePacketReceivedListener(this.jingleListener); connection.setOnJinglePacketReceivedListener(this.jingleListener);
connection.setOnBindListener(this.mOnBindListener); connection.setOnBindListener(this.mOnBindListener);
connection connection.setOnMessageAcknowledgeListener(this.mOnMessageAcknowledgedListener);
.setOnMessageAcknowledgeListener(this.mOnMessageAcknowledgedListener); connection.setOnAdvancedStreamFeaturesAvailableListener(this.onAdvancedStreamFeaturesAvailable);
return connection; return connection;
} }
@ -1231,6 +1239,19 @@ public class XmppConnectionService extends Service {
} }
} }
private void queryMessagesFromArchive(final Account account) {
if (account.getXmppConnection() != null && account.getXmppConnection().getFeatures().mam()) {
List<Conversation> conversations = getConversations();
for (Conversation conversation : conversations) {
if (conversation.getMode() == Conversation.MODE_SINGLE && conversation.getAccount() == account) {
this.mMessageArchiveService.query(conversation);
}
}
} else {
Log.d(Config.LOGTAG,"no mam available");
}
}
public void joinMuc(Conversation conversation) { public void joinMuc(Conversation conversation) {
Account account = conversation.getAccount(); Account account = conversation.getAccount();
account.pendingConferenceJoins.remove(conversation); account.pendingConferenceJoins.remove(conversation);
@ -1255,7 +1276,6 @@ public class XmppConnectionService extends Service {
packet.addChild("status").setContent("online"); packet.addChild("status").setContent("online");
packet.addChild("x", "jabber:x:signed").setContent(sig); packet.addChild("x", "jabber:x:signed").setContent(sig);
} }
Log.d(Config.LOGTAG,packet.toString());
sendPresencePacket(account, packet); sendPresencePacket(account, packet);
if (!joinJid.equals(conversation.getContactJid())) { if (!joinJid.equals(conversation.getContactJid())) {
conversation.setContactJid(joinJid); conversation.setContactJid(joinJid);
@ -2033,6 +2053,10 @@ public class XmppConnectionService extends Service {
return this.mJingleConnectionManager; return this.mJingleConnectionManager;
} }
public MessageArchiveService getMessageArchiveService() {
return this.mMessageArchiveService;
}
public List<Contact> findContacts(Jid jid) { public List<Contact> findContacts(Jid jid) {
ArrayList<Contact> contacts = new ArrayList<>(); ArrayList<Contact> contacts = new ArrayList<>();
for (Account account : getAccounts()) { for (Account account : getAccounts()) {

View file

@ -159,4 +159,9 @@ public class Element {
public void setAttribute(String name, int value) { public void setAttribute(String name, int value) {
this.setAttribute(name, Integer.toString(value)); this.setAttribute(name, Integer.toString(value));
} }
public boolean getAttributeAsBoolean(String name) {
String attr = getAttribute(name);
return (attr != null && (attr.equalsIgnoreCase("true") || attr.equalsIgnoreCase("1")));
}
} }

View file

@ -0,0 +1,7 @@
package eu.siacs.conversations.xmpp;
import eu.siacs.conversations.entities.Account;
public interface OnAdvancedStreamFeaturesAvailable {
public void onAdvancedStreamFeaturesAvailable(final Account account);
}

View file

@ -107,6 +107,7 @@ public class XmppConnection implements Runnable {
private OnMessagePacketReceived messageListener = null; private OnMessagePacketReceived messageListener = null;
private OnStatusChanged statusListener = null; private OnStatusChanged statusListener = null;
private OnBindListener bindListener = null; private OnBindListener bindListener = null;
private OnAdvancedStreamFeaturesAvailable advancedStreamFeaturesAvailableListener = null;
private OnMessageAcknowledged acknowledgedListener = null; private OnMessageAcknowledged acknowledgedListener = null;
private XmppConnectionService mXmppConnectionService = null; private XmppConnectionService mXmppConnectionService = null;
@ -771,6 +772,9 @@ public class XmppConnection implements Runnable {
if (account.getServer().equals(server.toDomainJid())) { if (account.getServer().equals(server.toDomainJid())) {
enableAdvancedStreamFeatures(); enableAdvancedStreamFeatures();
if (advancedStreamFeaturesAvailableListener != null) {
advancedStreamFeaturesAvailableListener.onAdvancedStreamFeaturesAvailable(account);
}
} }
} }
}); });
@ -943,6 +947,10 @@ public class XmppConnection implements Runnable {
this.acknowledgedListener = listener; this.acknowledgedListener = listener;
} }
public void setOnAdvancedStreamFeaturesAvailableListener(OnAdvancedStreamFeaturesAvailable listener) {
this.advancedStreamFeaturesAvailableListener = listener;
}
public void disconnect(boolean force) { public void disconnect(boolean force) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting"); Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting");
try { try {

View file

@ -37,6 +37,7 @@ public class Data extends Element {
Field field = getFieldByName(name); Field field = getFieldByName(name);
if (field == null) { if (field == null) {
field = new Field(name); field = new Field(name);
this.addChild(field);
} }
field.setValue(value); field.setValue(value);
} }
@ -45,6 +46,7 @@ public class Data extends Element {
Field field = getFieldByName(name); Field field = getFieldByName(name);
if (field == null) { if (field == null) {
field = new Field(name); field = new Field(name);
this.addChild(field);
} }
field.setValues(values); field.setValues(values);
} }
@ -72,4 +74,12 @@ public class Data extends Element {
data.setChildren(element.getChildren()); data.setChildren(element.getChildren());
return data; return data;
} }
public void setFormType(String formType) {
this.put("FORM_TYPE",formType);
}
public String getFormType() {
return this.getAttribute("FORM_TYPE");
}
} }