2014-05-14 10:56:34 +00:00
package eu.siacs.conversations.parser ;
2014-02-19 00:35:23 +00:00
2017-03-28 18:02:35 +00:00
import android.os.Build ;
2016-05-15 10:35:31 +00:00
import android.text.Html ;
2015-05-15 03:14:15 +00:00
import android.util.Log ;
import android.util.Pair ;
2014-02-19 00:35:23 +00:00
import net.java.otr4j.session.Session ;
import net.java.otr4j.session.SessionStatus ;
2014-11-04 17:27:20 +00:00
2016-06-01 22:24:37 +00:00
import java.text.SimpleDateFormat ;
2015-12-01 11:22:47 +00:00
import java.util.ArrayList ;
2016-05-15 10:35:31 +00:00
import java.util.Arrays ;
2016-06-01 22:24:37 +00:00
import java.util.Date ;
2016-05-15 10:35:31 +00:00
import java.util.List ;
2017-07-01 11:41:24 +00:00
import java.util.Locale ;
2015-06-29 12:22:26 +00:00
import java.util.Set ;
2016-02-19 23:01:39 +00:00
import java.util.UUID ;
2015-06-25 14:58:24 +00:00
2015-05-15 03:14:15 +00:00
import eu.siacs.conversations.Config ;
2017-06-30 19:22:35 +00:00
import eu.siacs.conversations.R ;
2016-03-31 19:15:49 +00:00
import eu.siacs.conversations.crypto.OtrService ;
2015-06-25 14:58:24 +00:00
import eu.siacs.conversations.crypto.axolotl.AxolotlService ;
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage ;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.entities.Account ;
2015-12-11 18:28:44 +00:00
import eu.siacs.conversations.entities.Bookmark ;
2014-08-05 20:58:46 +00:00
import eu.siacs.conversations.entities.Contact ;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.entities.Conversation ;
import eu.siacs.conversations.entities.Message ;
2015-01-07 17:34:24 +00:00
import eu.siacs.conversations.entities.MucOptions ;
2016-05-15 10:35:31 +00:00
import eu.siacs.conversations.entities.Presence ;
2017-11-19 00:53:04 +00:00
import eu.siacs.conversations.entities.ReadByMarker ;
2016-05-15 10:35:31 +00:00
import eu.siacs.conversations.entities.ServiceDiscoveryResult ;
2015-01-11 21:18:18 +00:00
import eu.siacs.conversations.http.HttpConnectionManager ;
2014-12-13 11:25:52 +00:00
import eu.siacs.conversations.services.MessageArchiveService ;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.services.XmppConnectionService ;
2014-06-20 15:30:19 +00:00
import eu.siacs.conversations.utils.CryptoHelper ;
2017-03-01 12:01:46 +00:00
import eu.siacs.conversations.xml.Namespace ;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.xml.Element ;
2014-07-12 00:36:37 +00:00
import eu.siacs.conversations.xmpp.OnMessagePacketReceived ;
2015-02-21 10:06:52 +00:00
import eu.siacs.conversations.xmpp.chatstate.ChatState ;
2014-11-06 19:10:03 +00:00
import eu.siacs.conversations.xmpp.jid.Jid ;
2014-08-05 20:58:46 +00:00
import eu.siacs.conversations.xmpp.pep.Avatar ;
2014-03-10 18:22:13 +00:00
import eu.siacs.conversations.xmpp.stanzas.MessagePacket ;
2014-02-19 00:35:23 +00:00
2016-05-15 10:35:31 +00:00
public class MessageParser extends AbstractParser implements OnMessagePacketReceived {
2017-11-21 12:26:45 +00:00
private static final List < String > CLIENTS_SENDING_HTML_IN_OTR = Arrays . asList ( " Pidgin " , " Adium " , " Trillian " ) ;
2016-05-15 10:35:31 +00:00
2014-05-14 10:56:34 +00:00
public MessageParser ( XmppConnectionService service ) {
2014-06-06 16:26:40 +00:00
super ( service ) ;
2014-05-14 10:56:34 +00:00
}
2014-06-04 10:31:19 +00:00
2017-03-07 13:36:05 +00:00
private boolean extractChatState ( Conversation c , final boolean isTypeGroupChat , final MessagePacket packet ) {
2015-05-15 03:14:15 +00:00
ChatState state = ChatState . parse ( packet ) ;
2017-03-07 13:36:05 +00:00
if ( state ! = null & & c ! = null ) {
final Account account = c . getAccount ( ) ;
2015-05-15 03:14:15 +00:00
Jid from = packet . getFrom ( ) ;
if ( from . toBareJid ( ) . equals ( account . getJid ( ) . toBareJid ( ) ) ) {
2017-03-07 13:36:05 +00:00
c . setOutgoingChatState ( state ) ;
2015-10-06 09:44:27 +00:00
if ( state = = ChatState . ACTIVE | | state = = ChatState . COMPOSING ) {
2017-03-07 13:36:05 +00:00
mXmppConnectionService . markRead ( c ) ;
2016-06-01 22:24:37 +00:00
activateGracePeriod ( account ) ;
2015-10-06 09:44:27 +00:00
}
2015-02-21 10:06:52 +00:00
return false ;
} else {
2017-03-07 13:36:05 +00:00
if ( isTypeGroupChat ) {
MucOptions . User user = c . getMucOptions ( ) . findUserByFullJid ( from ) ;
if ( user ! = null ) {
return user . setChatState ( state ) ;
} else {
return false ;
}
} else {
return c . setIncomingChatState ( state ) ;
}
2015-02-21 10:06:52 +00:00
}
}
return false ;
}
2015-05-15 03:14:15 +00:00
private Message parseOtrChat ( String body , Jid from , String id , Conversation conversation ) {
2014-08-11 11:46:32 +00:00
String presence ;
2014-11-06 19:10:03 +00:00
if ( from . isBareJid ( ) ) {
2015-03-16 22:23:51 +00:00
presence = " " ;
2014-08-11 11:46:32 +00:00
} else {
2014-11-06 19:10:03 +00:00
presence = from . getResourcepart ( ) ;
2014-08-11 11:46:32 +00:00
}
2015-01-24 15:19:58 +00:00
if ( body . matches ( " ^ \\ ?OTRv \\ d{1,2} \\ ?.* " ) ) {
2014-10-05 09:14:50 +00:00
conversation . endOtrIfNeeded ( ) ;
2014-09-06 16:21:31 +00:00
}
2014-02-19 00:35:23 +00:00
if ( ! conversation . hasValidOtrSession ( ) ) {
2017-11-21 12:26:45 +00:00
conversation . startOtrSession ( presence , false ) ;
2014-03-07 23:48:52 +00:00
} else {
2015-05-15 03:14:15 +00:00
String foreignPresence = conversation . getOtrSession ( ) . getSessionID ( ) . getUserID ( ) ;
2014-08-11 11:46:32 +00:00
if ( ! foreignPresence . equals ( presence ) ) {
2014-06-25 14:55:47 +00:00
conversation . endOtrIfNeeded ( ) ;
2015-05-15 03:14:15 +00:00
conversation . startOtrSession ( presence , false ) ;
2014-03-07 23:48:52 +00:00
}
2014-02-19 00:35:23 +00:00
}
try {
2015-05-15 03:14:15 +00:00
conversation . setLastReceivedOtrMessageId ( id ) ;
2014-02-19 00:35:23 +00:00
Session otrSession = conversation . getOtrSession ( ) ;
body = otrSession . transformReceiving ( body ) ;
2015-07-21 09:46:51 +00:00
SessionStatus status = otrSession . getSessionStatus ( ) ;
if ( body = = null & & status = = SessionStatus . ENCRYPTED ) {
2014-06-11 19:53:25 +00:00
mXmppConnectionService . onOtrSessionEstablished ( conversation ) ;
2015-07-21 09:46:51 +00:00
return null ;
} else if ( body = = null & & status = = SessionStatus . FINISHED ) {
2014-02-19 00:35:23 +00:00
conversation . resetOtrSession ( ) ;
2014-07-20 10:36:57 +00:00
mXmppConnectionService . updateConversationUi ( ) ;
2015-07-21 09:46:51 +00:00
return null ;
} else if ( body = = null | | ( body . isEmpty ( ) ) ) {
2014-03-23 13:15:14 +00:00
return null ;
}
2014-06-20 15:30:19 +00:00
if ( body . startsWith ( CryptoHelper . FILETRANSFER ) ) {
String key = body . substring ( CryptoHelper . FILETRANSFER . length ( ) ) ;
conversation . setSymmetricKey ( CryptoHelper . hexToBytes ( key ) ) ;
return null ;
}
2016-05-15 10:35:31 +00:00
if ( clientMightSendHtml ( conversation . getAccount ( ) , from ) ) {
2017-11-21 12:26:45 +00:00
Log . d ( Config . LOGTAG , conversation . getAccount ( ) . getJid ( ) . toBareJid ( ) + " : received OTR message from bad behaving client. escaping HTML… " ) ;
2017-03-28 18:02:35 +00:00
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . N ) {
2017-11-21 12:26:45 +00:00
body = Html . fromHtml ( body , Html . FROM_HTML_MODE_LEGACY ) . toString ( ) ;
2017-03-28 18:02:35 +00:00
} else {
body = Html . fromHtml ( body ) . toString ( ) ;
}
2016-05-15 10:35:31 +00:00
}
2016-03-31 19:15:49 +00:00
final OtrService otrService = conversation . getAccount ( ) . getOtrService ( ) ;
2015-05-15 03:14:15 +00:00
Message finishedMessage = new Message ( conversation , body , Message . ENCRYPTION_OTR , Message . STATUS_RECEIVED ) ;
2016-03-31 19:15:49 +00:00
finishedMessage . setFingerprint ( otrService . getFingerprint ( otrSession . getRemotePublicKey ( ) ) ) ;
2015-03-21 15:07:17 +00:00
conversation . setLastReceivedOtrMessageId ( null ) ;
2016-03-31 19:15:49 +00:00
2014-06-06 16:26:40 +00:00
return finishedMessage ;
2014-02-19 00:35:23 +00:00
} catch ( Exception e ) {
2014-09-06 16:21:31 +00:00
conversation . resetOtrSession ( ) ;
2014-02-19 00:35:23 +00:00
return null ;
}
}
2014-06-04 10:31:19 +00:00
2016-05-15 10:35:31 +00:00
private static boolean clientMightSendHtml ( Account account , Jid from ) {
String resource = from . getResourcepart ( ) ;
if ( resource = = null ) {
return false ;
}
Presence presence = account . getRoster ( ) . getContact ( from ) . getPresences ( ) . getPresences ( ) . get ( resource ) ;
ServiceDiscoveryResult disco = presence = = null ? null : presence . getServiceDiscoveryResult ( ) ;
if ( disco = = null ) {
return false ;
}
return hasIdentityKnowForSendingHtml ( disco . getIdentities ( ) ) ;
}
private static boolean hasIdentityKnowForSendingHtml ( List < ServiceDiscoveryResult . Identity > identities ) {
2017-11-21 12:26:45 +00:00
for ( ServiceDiscoveryResult . Identity identity : identities ) {
2016-05-15 10:35:31 +00:00
if ( identity . getName ( ) ! = null ) {
if ( CLIENTS_SENDING_HTML_IN_OTR . contains ( identity . getName ( ) ) ) {
return true ;
}
}
}
return false ;
}
2017-11-21 12:26:45 +00:00
private Message parseAxolotlChat ( Element axolotlMessage , Jid from , Conversation conversation , int status ) {
2015-06-26 13:41:02 +00:00
AxolotlService service = conversation . getAccount ( ) . getAxolotlService ( ) ;
2016-06-29 15:18:57 +00:00
XmppAxolotlMessage xmppAxolotlMessage ;
try {
xmppAxolotlMessage = XmppAxolotlMessage . fromElement ( axolotlMessage , from . toBareJid ( ) ) ;
} catch ( Exception e ) {
2017-11-21 12:26:45 +00:00
Log . d ( Config . LOGTAG , conversation . getAccount ( ) . getJid ( ) . toBareJid ( ) + " : invalid omemo message received " + e . getMessage ( ) ) ;
2016-06-29 15:18:57 +00:00
return null ;
}
2015-07-31 21:28:09 +00:00
XmppAxolotlMessage . XmppAxolotlPlaintextMessage plaintextMessage = service . processReceivingPayloadMessage ( xmppAxolotlMessage ) ;
2017-11-21 12:26:45 +00:00
if ( plaintextMessage ! = null ) {
2016-06-29 15:18:57 +00:00
Message finishedMessage = new Message ( conversation , plaintextMessage . getPlaintext ( ) , Message . ENCRYPTION_AXOLOTL , status ) ;
2016-03-31 19:15:49 +00:00
finishedMessage . setFingerprint ( plaintextMessage . getFingerprint ( ) ) ;
2017-11-21 12:26:45 +00:00
Log . d ( Config . LOGTAG , AxolotlService . getLogprefix ( finishedMessage . getConversation ( ) . getAccount ( ) ) + " Received Message with session fingerprint: " + plaintextMessage . getFingerprint ( ) ) ;
2016-06-29 15:18:57 +00:00
return finishedMessage ;
} else {
return null ;
2015-06-26 13:41:02 +00:00
}
}
2015-06-25 14:58:24 +00:00
2015-04-21 16:36:11 +00:00
private class Invite {
2017-01-09 18:54:27 +00:00
final Jid jid ;
final String password ;
final Contact inviter ;
2017-11-21 12:26:45 +00:00
2017-01-09 18:54:27 +00:00
Invite ( Jid jid , String password , Contact inviter ) {
2015-04-21 16:36:11 +00:00
this . jid = jid ;
this . password = password ;
2017-01-09 18:54:27 +00:00
this . inviter = inviter ;
2015-01-07 15:45:44 +00:00
}
2015-05-19 06:23:12 +00:00
public boolean execute ( Account account ) {
if ( jid ! = null ) {
2017-04-12 22:12:23 +00:00
Conversation conversation = mXmppConnectionService . findOrCreateConversation ( account , jid , true , false ) ;
2015-05-19 06:23:12 +00:00
if ( ! conversation . getMucOptions ( ) . online ( ) ) {
conversation . getMucOptions ( ) . setPassword ( password ) ;
mXmppConnectionService . databaseBackend . updateConversation ( conversation ) ;
2017-01-09 18:54:27 +00:00
mXmppConnectionService . joinMuc ( conversation , inviter ! = null & & inviter . mutualPresenceSubscription ( ) ) ;
2015-05-19 06:23:12 +00:00
mXmppConnectionService . updateConversationUi ( ) ;
}
return true ;
}
return false ;
}
2015-04-21 16:36:11 +00:00
}
2017-01-09 18:54:27 +00:00
private Invite extractInvite ( Account account , Element message ) {
2015-05-15 03:14:15 +00:00
Element x = message . findChild ( " x " , " http://jabber.org/protocol/muc#user " ) ;
2015-04-21 16:36:11 +00:00
if ( x ! = null ) {
Element invite = x . findChild ( " invite " ) ;
if ( invite ! = null ) {
Element pw = x . findChild ( " password " ) ;
2017-01-09 18:54:27 +00:00
Jid from = invite . getAttributeAsJid ( " from " ) ;
Contact contact = from = = null ? null : account . getRoster ( ) . getContact ( from ) ;
2017-11-21 12:26:45 +00:00
return new Invite ( message . getAttributeAsJid ( " from " ) , pw ! = null ? pw . getContent ( ) : null , contact ) ;
2015-04-21 16:36:11 +00:00
}
2015-01-07 15:45:44 +00:00
} else {
2017-11-21 12:26:45 +00:00
x = message . findChild ( " x " , " jabber:x:conference " ) ;
2015-04-21 16:36:11 +00:00
if ( x ! = null ) {
2017-01-09 18:54:27 +00:00
Jid from = message . getAttributeAsJid ( " from " ) ;
Contact contact = from = = null ? null : account . getRoster ( ) . getContact ( from ) ;
2017-11-21 12:26:45 +00:00
return new Invite ( x . getAttributeAsJid ( " jid " ) , x . getAttribute ( " password " ) , contact ) ;
2015-04-21 16:36:11 +00:00
}
2014-06-06 16:49:35 +00:00
}
2015-04-21 16:36:11 +00:00
return null ;
2014-06-06 16:49:35 +00:00
}
2014-02-27 23:22:56 +00:00
2017-03-08 19:20:34 +00:00
private static String extractStanzaId ( Element packet , boolean isTypeGroupChat , Conversation conversation ) {
2017-03-06 12:30:13 +00:00
final Jid by ;
final boolean safeToExtract ;
if ( isTypeGroupChat ) {
by = conversation . getJid ( ) . toBareJid ( ) ;
safeToExtract = conversation . getMucOptions ( ) . hasFeature ( Namespace . STANZA_IDS ) ;
} else {
Account account = conversation . getAccount ( ) ;
by = account . getJid ( ) . toBareJid ( ) ;
safeToExtract = account . getXmppConnection ( ) . getFeatures ( ) . stanzaIds ( ) ;
}
return safeToExtract ? extractStanzaId ( packet , by ) : null ;
}
2015-12-04 21:03:46 +00:00
private static String extractStanzaId ( Element packet , Jid by ) {
2017-11-21 12:26:45 +00:00
for ( Element child : packet . getChildren ( ) ) {
2015-12-04 21:03:46 +00:00
if ( child . getName ( ) . equals ( " stanza-id " )
2017-03-01 12:01:46 +00:00
& & Namespace . STANZA_IDS . equals ( child . getNamespace ( ) )
2015-12-04 21:03:46 +00:00
& & by . equals ( child . getAttributeAsJid ( " by " ) ) ) {
return child . getAttribute ( " id " ) ;
}
}
return null ;
}
2014-11-06 19:10:03 +00:00
private void parseEvent ( final Element event , final Jid from , final Account account ) {
2014-08-04 23:36:17 +00:00
Element items = event . findChild ( " items " ) ;
2015-05-19 06:23:12 +00:00
String node = items = = null ? null : items . getAttribute ( " node " ) ;
if ( " urn:xmpp:avatar:metadata " . equals ( node ) ) {
2014-11-20 17:42:47 +00:00
Avatar avatar = Avatar . parseMetadata ( items ) ;
if ( avatar ! = null ) {
2015-12-03 17:18:34 +00:00
avatar . owner = from . toBareJid ( ) ;
2015-05-19 06:23:12 +00:00
if ( mXmppConnectionService . getFileBackend ( ) . isAvatarCached ( avatar ) ) {
2014-11-20 17:42:47 +00:00
if ( account . getJid ( ) . toBareJid ( ) . equals ( from ) ) {
if ( account . setAvatar ( avatar . getFilename ( ) ) ) {
2015-05-19 06:23:12 +00:00
mXmppConnectionService . databaseBackend . updateAccount ( account ) ;
2014-08-15 11:11:33 +00:00
}
2015-05-19 06:23:12 +00:00
mXmppConnectionService . getAvatarService ( ) . clear ( account ) ;
2014-11-20 17:42:47 +00:00
mXmppConnectionService . updateConversationUi ( ) ;
mXmppConnectionService . updateAccountUi ( ) ;
2014-08-05 20:58:46 +00:00
} else {
2015-05-19 06:23:12 +00:00
Contact contact = account . getRoster ( ) . getContact ( from ) ;
2015-05-05 04:17:34 +00:00
contact . setAvatar ( avatar ) ;
2015-05-19 06:23:12 +00:00
mXmppConnectionService . getAvatarService ( ) . clear ( contact ) ;
2014-11-20 17:42:47 +00:00
mXmppConnectionService . updateConversationUi ( ) ;
mXmppConnectionService . updateRosterUi ( ) ;
2014-08-05 20:58:46 +00:00
}
2016-08-27 11:35:52 +00:00
} else if ( mXmppConnectionService . isDataSaverDisabled ( ) ) {
2014-11-20 17:42:47 +00:00
mXmppConnectionService . fetchAvatar ( account , avatar ) ;
2014-08-05 20:58:46 +00:00
}
2014-11-20 17:42:47 +00:00
}
2015-05-19 06:23:12 +00:00
} else if ( " http://jabber.org/protocol/nick " . equals ( node ) ) {
2017-08-23 19:49:25 +00:00
final Element i = items . findChild ( " item " ) ;
final String nick = i = = null ? null : i . findChildContent ( " nick " , Namespace . NICK ) ;
if ( nick ! = null ) {
2015-05-19 06:23:12 +00:00
Contact contact = account . getRoster ( ) . getContact ( from ) ;
2017-08-23 19:49:25 +00:00
if ( contact . setPresenceName ( nick ) ) {
mXmppConnectionService . getAvatarService ( ) . clear ( contact ) ;
}
2015-05-19 06:23:12 +00:00
mXmppConnectionService . updateConversationUi ( ) ;
mXmppConnectionService . updateAccountUi ( ) ;
2014-08-05 20:58:46 +00:00
}
2015-06-25 14:58:24 +00:00
} else if ( AxolotlService . PEP_DEVICE_LIST . equals ( node ) ) {
2016-12-23 20:16:58 +00:00
2015-06-26 13:41:02 +00:00
Element item = items . findChild ( " item " ) ;
2015-06-29 12:22:26 +00:00
Set < Integer > deviceIds = mXmppConnectionService . getIqParser ( ) . deviceIds ( item ) ;
2017-11-21 12:26:45 +00:00
Log . d ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " Received PEP device list ( " + deviceIds + " ) update from " + from + " , processing... " ) ;
2015-06-26 13:41:02 +00:00
AxolotlService axolotlService = account . getAxolotlService ( ) ;
2015-06-29 12:22:26 +00:00
axolotlService . registerDevices ( from , deviceIds ) ;
2015-07-07 17:32:52 +00:00
mXmppConnectionService . updateAccountUi ( ) ;
2014-08-04 23:36:17 +00:00
}
}
2015-05-19 06:23:12 +00:00
private boolean handleErrorMessage ( Account account , MessagePacket packet ) {
if ( packet . getType ( ) = = MessagePacket . TYPE_ERROR ) {
Jid from = packet . getFrom ( ) ;
if ( from ! = null ) {
2015-07-21 09:52:49 +00:00
Message message = mXmppConnectionService . markMessage ( account ,
from . toBareJid ( ) ,
packet . getId ( ) ,
2016-10-26 10:26:04 +00:00
Message . STATUS_SEND_FAILED ,
extractErrorMessage ( packet ) ) ;
if ( message ! = null ) {
if ( message . getEncryption ( ) = = Message . ENCRYPTION_OTR ) {
message . getConversation ( ) . endOtrIfNeeded ( ) ;
}
2015-07-21 09:52:49 +00:00
}
2015-05-19 06:23:12 +00:00
}
return true ;
}
return false ;
}
2015-05-15 03:14:15 +00:00
@Override
public void onMessagePacketReceived ( Account account , MessagePacket original ) {
2015-05-19 06:23:12 +00:00
if ( handleErrorMessage ( account , original ) ) {
return ;
}
2015-05-15 03:14:15 +00:00
final MessagePacket packet ;
Long timestamp = null ;
final boolean isForwarded ;
2015-07-29 14:41:58 +00:00
boolean isCarbon = false ;
2015-05-15 04:31:27 +00:00
String serverMsgId = null ;
2017-03-01 12:01:46 +00:00
final Element fin = original . findChild ( " fin " , Namespace . MAM_LEGACY ) ;
2017-02-15 15:42:35 +00:00
if ( fin ! = null ) {
2017-11-21 12:26:45 +00:00
mXmppConnectionService . getMessageArchiveService ( ) . processFinLegacy ( fin , original . getFrom ( ) ) ;
2017-02-15 15:42:35 +00:00
return ;
}
2017-03-01 12:01:46 +00:00
final boolean mamLegacy = original . hasChild ( " result " , Namespace . MAM_LEGACY ) ;
2017-11-21 12:26:45 +00:00
final Element result = original . findChild ( " result " , mamLegacy ? Namespace . MAM_LEGACY : Namespace . MAM ) ;
2015-05-15 10:29:45 +00:00
final MessageArchiveService . Query query = result = = null ? null : mXmppConnectionService . getMessageArchiveService ( ) . findQuery ( result . getAttribute ( " queryid " ) ) ;
if ( query ! = null & & query . validFrom ( original . getFrom ( ) ) ) {
2017-03-01 12:01:46 +00:00
Pair < MessagePacket , Long > f = original . getForwardedMessagePacket ( " result " , mamLegacy ? Namespace . MAM_LEGACY : Namespace . MAM ) ;
2015-05-15 10:29:45 +00:00
if ( f = = null ) {
return ;
}
timestamp = f . second ;
packet = f . first ;
isForwarded = true ;
serverMsgId = result . getAttribute ( " id " ) ;
2016-02-03 15:04:21 +00:00
query . incrementMessageCount ( ) ;
2015-05-15 10:29:45 +00:00
} else if ( query ! = null ) {
2017-11-21 12:26:45 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : received mam result from invalid sender " ) ;
2015-05-15 10:29:45 +00:00
return ;
} else if ( original . fromServer ( account ) ) {
2015-05-15 03:14:15 +00:00
Pair < MessagePacket , Long > f ;
f = original . getForwardedMessagePacket ( " received " , " urn:xmpp:carbons:2 " ) ;
f = f = = null ? original . getForwardedMessagePacket ( " sent " , " urn:xmpp:carbons:2 " ) : f ;
packet = f ! = null ? f . first : original ;
2015-05-19 06:23:12 +00:00
if ( handleErrorMessage ( account , packet ) ) {
return ;
}
2015-05-15 03:14:15 +00:00
timestamp = f ! = null ? f . second : null ;
2015-07-29 14:41:58 +00:00
isCarbon = f ! = null ;
isForwarded = isCarbon ;
2014-05-22 14:17:51 +00:00
} else {
2015-05-15 03:14:15 +00:00
packet = original ;
isForwarded = false ;
}
2015-05-19 06:23:12 +00:00
2015-05-15 03:14:15 +00:00
if ( timestamp = = null ) {
2017-11-21 12:26:45 +00:00
timestamp = AbstractParser . parseTimestamp ( original , AbstractParser . parseTimestamp ( packet ) ) ;
2015-05-15 03:14:15 +00:00
}
final String body = packet . getBody ( ) ;
2015-07-22 12:15:00 +00:00
final Element mucUserElement = packet . findChild ( " x " , " http://jabber.org/protocol/muc#user " ) ;
2015-06-25 14:58:24 +00:00
final String pgpEncrypted = packet . findChildContent ( " x " , " jabber:x:encrypted " ) ;
2016-03-04 19:09:21 +00:00
final Element replaceElement = packet . findChild ( " replace " , " urn:xmpp:message-correct:0 " ) ;
2017-04-04 20:15:38 +00:00
final Element oob = packet . findChild ( " x " , Namespace . OOB ) ;
final String oobUrl = oob ! = null ? oob . findChildContent ( " url " ) : null ;
2016-02-15 22:15:04 +00:00
final String replacementId = replaceElement = = null ? null : replaceElement . getAttribute ( " id " ) ;
2015-07-31 19:12:34 +00:00
final Element axolotlEncrypted = packet . findChild ( XmppAxolotlMessage . CONTAINERTAG , AxolotlService . PEP_PREFIX ) ;
2015-05-15 03:14:15 +00:00
int status ;
2015-05-15 10:29:45 +00:00
final Jid counterpart ;
2015-05-15 03:14:15 +00:00
final Jid to = packet . getTo ( ) ;
final Jid from = packet . getFrom ( ) ;
2017-11-21 12:26:45 +00:00
final Element originId = packet . findChild ( " origin-id " , Namespace . STANZA_IDS ) ;
2017-03-08 20:30:12 +00:00
final String remoteMsgId ;
if ( originId ! = null & & originId . getAttribute ( " id " ) ! = null ) {
remoteMsgId = originId . getAttribute ( " id " ) ;
} else {
remoteMsgId = packet . getId ( ) ;
}
2016-06-15 10:44:29 +00:00
boolean notify = false ;
2015-07-02 16:02:32 +00:00
2015-12-17 13:30:00 +00:00
if ( from = = null ) {
2017-11-21 12:26:45 +00:00
Log . d ( Config . LOGTAG , " no from in: " + packet . toString ( ) ) ;
2015-07-02 16:02:32 +00:00
return ;
}
2017-11-21 12:26:45 +00:00
2015-05-15 03:14:15 +00:00
boolean isTypeGroupChat = packet . getType ( ) = = MessagePacket . TYPE_GROUPCHAT ;
2017-11-21 12:26:45 +00:00
boolean isProperlyAddressed = ( to ! = null ) & & ( ! to . isBareJid ( ) | | account . countPresences ( ) = = 0 ) ;
2015-06-28 20:14:40 +00:00
boolean isMucStatusMessage = from . isBareJid ( ) & & mucUserElement ! = null & & mucUserElement . hasChild ( " status " ) ;
2015-05-15 03:14:15 +00:00
if ( packet . fromAccount ( account ) ) {
status = Message . STATUS_SEND ;
2015-12-17 13:30:00 +00:00
counterpart = to ! = null ? to : account . getJid ( ) ;
2015-05-15 03:14:15 +00:00
} else {
status = Message . STATUS_RECEIVED ;
counterpart = from ;
2014-02-27 23:22:56 +00:00
}
2014-07-12 00:36:37 +00:00
2017-01-09 18:54:27 +00:00
Invite invite = extractInvite ( account , packet ) ;
2015-05-19 06:23:12 +00:00
if ( invite ! = null & & invite . execute ( account ) ) {
2015-05-15 03:14:15 +00:00
return ;
}
2017-03-07 13:36:05 +00:00
if ( query = = null & & extractChatState ( mXmppConnectionService . find ( account , counterpart . toBareJid ( ) ) , isTypeGroupChat , packet ) ) {
2015-05-15 03:14:15 +00:00
mXmppConnectionService . updateConversationUi ( ) ;
}
2017-04-04 20:15:38 +00:00
if ( ( body ! = null | | pgpEncrypted ! = null | | axolotlEncrypted ! = null | | oobUrl ! = null ) & & ! isMucStatusMessage ) {
2017-04-12 22:12:23 +00:00
final Conversation conversation = mXmppConnectionService . findOrCreateConversation ( account , counterpart . toBareJid ( ) , isTypeGroupChat , false , query , false ) ;
2016-05-25 19:05:51 +00:00
final boolean conversationMultiMode = conversation . getMode ( ) = = Conversation . MODE_MULTI ;
2017-03-06 12:30:13 +00:00
if ( serverMsgId = = null ) {
2017-03-08 19:20:34 +00:00
serverMsgId = extractStanzaId ( packet , isTypeGroupChat , conversation ) ;
2017-03-06 12:30:13 +00:00
}
2015-05-15 03:14:15 +00:00
if ( isTypeGroupChat ) {
2017-03-07 13:36:05 +00:00
if ( conversation . getMucOptions ( ) . isSelf ( counterpart ) ) {
2015-06-02 10:21:35 +00:00
status = Message . STATUS_SEND_RECEIVED ;
2016-02-17 15:51:36 +00:00
isCarbon = true ; //not really carbon but received from another resource
2017-03-06 12:30:13 +00:00
if ( mXmppConnectionService . markMessage ( conversation , remoteMsgId , status , serverMsgId ) ) {
2015-05-15 03:14:15 +00:00
return ;
2015-10-14 09:15:18 +00:00
} else if ( remoteMsgId = = null | | Config . IGNORE_ID_REWRITE_IN_MUC ) {
2015-08-26 09:39:18 +00:00
Message message = conversation . findSentMessageWithBody ( packet . getBody ( ) ) ;
2015-05-15 03:14:15 +00:00
if ( message ! = null ) {
2015-06-02 10:21:35 +00:00
mXmppConnectionService . markMessage ( message , status ) ;
2015-05-15 03:14:15 +00:00
return ;
}
2014-07-12 00:36:37 +00:00
}
2015-05-15 03:14:15 +00:00
} else {
status = Message . STATUS_RECEIVED ;
2014-07-12 00:36:37 +00:00
}
2015-05-15 03:14:15 +00:00
}
2016-06-22 10:22:57 +00:00
final Message message ;
2016-02-24 13:47:49 +00:00
if ( body ! = null & & body . startsWith ( " ?OTR " ) & & Config . supportOtr ( ) ) {
2016-05-25 19:05:51 +00:00
if ( ! isForwarded & & ! isTypeGroupChat & & isProperlyAddressed & & ! conversationMultiMode ) {
2015-05-15 04:31:27 +00:00
message = parseOtrChat ( body , from , remoteMsgId , conversation ) ;
2015-05-15 03:14:15 +00:00
if ( message = = null ) {
return ;
}
} else {
2017-11-21 12:26:45 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : ignoring OTR message from " + from + " isForwarded= " + Boolean . toString ( isForwarded ) + " , isProperlyAddressed= " + Boolean . valueOf ( isProperlyAddressed ) ) ;
2015-05-15 03:14:15 +00:00
message = new Message ( conversation , body , Message . ENCRYPTION_NONE , status ) ;
2014-12-05 00:54:16 +00:00
}
2016-02-24 13:47:49 +00:00
} else if ( pgpEncrypted ! = null & & Config . supportOpenPgp ( ) ) {
2016-02-19 20:02:33 +00:00
message = new Message ( conversation , pgpEncrypted , Message . ENCRYPTION_PGP , status ) ;
2016-02-24 13:47:49 +00:00
} else if ( axolotlEncrypted ! = null & & Config . supportOmemo ( ) ) {
2016-02-29 12:18:07 +00:00
Jid origin ;
2016-05-25 19:05:51 +00:00
if ( conversationMultiMode ) {
2016-06-22 10:22:57 +00:00
final Jid fallback = conversation . getMucOptions ( ) . getTrueCounterpart ( counterpart ) ;
origin = getTrueCounterpart ( query ! = null ? mucUserElement : null , fallback ) ;
2016-02-29 12:18:07 +00:00
if ( origin = = null ) {
2017-04-04 20:15:38 +00:00
Log . d ( Config . LOGTAG , " axolotl message in non anonymous conference received " ) ;
2016-02-29 12:18:07 +00:00
return ;
}
} else {
origin = from ;
}
message = parseAxolotlChat ( axolotlEncrypted , origin , conversation , status ) ;
2015-06-26 13:41:02 +00:00
if ( message = = null ) {
return ;
}
2016-06-28 08:33:46 +00:00
if ( conversationMultiMode ) {
message . setTrueCounterpart ( origin ) ;
}
2017-04-04 20:15:38 +00:00
} else if ( body = = null & & oobUrl ! = null ) {
message = new Message ( conversation , oobUrl , Message . ENCRYPTION_NONE , status ) ;
message . setOob ( true ) ;
2017-04-05 19:01:29 +00:00
if ( CryptoHelper . isPgpEncryptedUrl ( oobUrl ) ) {
message . setEncryption ( Message . ENCRYPTION_DECRYPTED ) ;
}
2014-07-23 12:30:27 +00:00
} else {
2015-05-15 03:14:15 +00:00
message = new Message ( conversation , body , Message . ENCRYPTION_NONE , status ) ;
2014-07-12 00:36:37 +00:00
}
2015-12-04 21:03:46 +00:00
2015-05-15 03:14:15 +00:00
message . setCounterpart ( counterpart ) ;
2015-05-15 04:31:27 +00:00
message . setRemoteMsgId ( remoteMsgId ) ;
message . setServerMsgId ( serverMsgId ) ;
2015-07-29 14:41:58 +00:00
message . setCarbon ( isCarbon ) ;
2015-05-15 03:14:15 +00:00
message . setTime ( timestamp ) ;
2017-04-05 19:01:29 +00:00
if ( body ! = null & & body . equals ( oobUrl ) ) {
message . setOob ( true ) ;
if ( CryptoHelper . isPgpEncryptedUrl ( oobUrl ) ) {
message . setEncryption ( Message . ENCRYPTION_DECRYPTED ) ;
}
}
2015-05-15 03:14:15 +00:00
message . markable = packet . hasChild ( " markable " , " urn:xmpp:chat-markers:0 " ) ;
2016-05-25 19:05:51 +00:00
if ( conversationMultiMode ) {
2016-06-22 10:22:57 +00:00
final Jid fallback = conversation . getMucOptions ( ) . getTrueCounterpart ( counterpart ) ;
2016-06-28 08:33:46 +00:00
Jid trueCounterpart ;
if ( message . getEncryption ( ) = = Message . ENCRYPTION_AXOLOTL ) {
trueCounterpart = message . getTrueCounterpart ( ) ;
} else if ( Config . PARSE_REAL_JID_FROM_MUC_MAM ) {
trueCounterpart = getTrueCounterpart ( query ! = null ? mucUserElement : null , fallback ) ;
} else {
trueCounterpart = fallback ;
}
2016-06-22 10:22:57 +00:00
if ( trueCounterpart ! = null & & trueCounterpart . toBareJid ( ) . equals ( account . getJid ( ) . toBareJid ( ) ) ) {
status = isTypeGroupChat ? Message . STATUS_SEND_RECEIVED : Message . STATUS_SEND ;
2016-06-12 10:50:49 +00:00
}
2016-06-22 10:22:57 +00:00
message . setStatus ( status ) ;
2015-10-19 21:20:33 +00:00
message . setTrueCounterpart ( trueCounterpart ) ;
2015-05-15 03:14:15 +00:00
if ( ! isTypeGroupChat ) {
message . setType ( Message . TYPE_PRIVATE ) ;
2014-07-12 00:36:37 +00:00
}
2015-12-31 17:06:11 +00:00
} else {
2016-06-04 14:16:14 +00:00
updateLastseen ( account , from ) ;
2014-07-12 00:36:37 +00:00
}
2016-02-15 22:15:04 +00:00
2016-02-16 08:57:59 +00:00
if ( replacementId ! = null & & mXmppConnectionService . allowMessageCorrection ( ) ) {
2016-02-17 15:51:36 +00:00
Message replacedMessage = conversation . findMessageWithRemoteIdAndCounterpart ( replacementId ,
counterpart ,
message . getStatus ( ) = = Message . STATUS_RECEIVED ,
message . isCarbon ( ) ) ;
2016-02-15 22:15:04 +00:00
if ( replacedMessage ! = null ) {
2016-03-31 19:15:49 +00:00
final boolean fingerprintsMatch = replacedMessage . getFingerprint ( ) = = null
| | replacedMessage . getFingerprint ( ) . equals ( message . getFingerprint ( ) ) ;
2016-02-15 22:15:04 +00:00
final boolean trueCountersMatch = replacedMessage . getTrueCounterpart ( ) ! = null
& & replacedMessage . getTrueCounterpart ( ) . equals ( message . getTrueCounterpart ( ) ) ;
2016-12-09 19:03:48 +00:00
final boolean duplicate = conversation . hasDuplicateMessage ( message ) ;
if ( fingerprintsMatch & & ( trueCountersMatch | | ! conversationMultiMode ) & & ! duplicate ) {
2016-02-15 22:15:04 +00:00
Log . d ( Config . LOGTAG , " replaced message ' " + replacedMessage . getBody ( ) + " ' with ' " + message . getBody ( ) + " ' " ) ;
2016-06-16 09:47:40 +00:00
synchronized ( replacedMessage ) {
final String uuid = replacedMessage . getUuid ( ) ;
replacedMessage . setUuid ( UUID . randomUUID ( ) . toString ( ) ) ;
replacedMessage . setBody ( message . getBody ( ) ) ;
replacedMessage . setEdited ( replacedMessage . getRemoteMsgId ( ) ) ;
replacedMessage . setRemoteMsgId ( remoteMsgId ) ;
replacedMessage . setEncryption ( message . getEncryption ( ) ) ;
if ( replacedMessage . getStatus ( ) = = Message . STATUS_RECEIVED ) {
replacedMessage . markUnread ( ) ;
}
mXmppConnectionService . updateMessage ( replacedMessage , uuid ) ;
mXmppConnectionService . getNotificationService ( ) . updateNotification ( false ) ;
2017-02-15 11:09:36 +00:00
if ( mXmppConnectionService . confirmMessages ( )
& & ( replacedMessage . trusted ( ) | | replacedMessage . getType ( ) = = Message . TYPE_PRIVATE )
& & remoteMsgId ! = null
& & ! isForwarded
& & ! isTypeGroupChat ) {
2016-06-16 09:47:40 +00:00
sendMessageReceipts ( account , packet ) ;
}
if ( replacedMessage . getEncryption ( ) = = Message . ENCRYPTION_PGP ) {
conversation . getAccount ( ) . getPgpDecryptionService ( ) . discard ( replacedMessage ) ;
conversation . getAccount ( ) . getPgpDecryptionService ( ) . decrypt ( replacedMessage , false ) ;
}
2016-02-19 20:02:33 +00:00
}
2016-02-15 22:15:04 +00:00
return ;
} else {
2017-11-21 12:26:45 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : received message correction but verification didn't check out " ) ;
2016-02-15 22:15:04 +00:00
}
}
}
2017-01-23 16:14:30 +00:00
long deletionDate = mXmppConnectionService . getAutomaticMessageDeletionDate ( ) ;
if ( deletionDate ! = 0 & & message . getTimeSent ( ) < deletionDate ) {
2017-11-21 12:26:45 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : skipping message from " + message . getCounterpart ( ) . toString ( ) + " because it was sent prior to our deletion date " ) ;
2017-01-23 16:14:30 +00:00
return ;
}
2017-11-21 12:26:45 +00:00
boolean checkForDuplicates = ( isTypeGroupChat & & packet . hasChild ( " delay " , " urn:xmpp:delay " ) )
2017-03-06 10:24:04 +00:00
| | message . getType ( ) = = Message . TYPE_PRIVATE
| | message . getServerMsgId ( ) ! = null ;
2015-05-15 04:31:27 +00:00
if ( checkForDuplicates & & conversation . hasDuplicateMessage ( message ) ) {
2017-11-21 12:26:45 +00:00
Log . d ( Config . LOGTAG , " skipping duplicate message from " + message . getCounterpart ( ) . toString ( ) + " " + message . getBody ( ) ) ;
2015-05-15 04:31:27 +00:00
return ;
}
2015-12-04 21:03:46 +00:00
2016-02-04 15:40:18 +00:00
if ( query ! = null & & query . getPagingOrder ( ) = = MessageArchiveService . PagingOrder . REVERSE ) {
conversation . prepend ( message ) ;
} else {
conversation . add ( message ) ;
}
2017-02-14 15:50:33 +00:00
if ( query ! = null ) {
query . incrementActualMessageCount ( ) ;
}
2015-12-10 22:05:11 +00:00
2017-02-14 23:08:49 +00:00
if ( query = = null | | query . isCatchup ( ) ) { //either no mam or catchup
2015-06-04 00:47:24 +00:00
if ( status = = Message . STATUS_SEND | | status = = Message . STATUS_SEND_RECEIVED ) {
2015-05-15 09:51:20 +00:00
mXmppConnectionService . markRead ( conversation ) ;
2015-12-10 22:05:11 +00:00
if ( query = = null ) {
2016-06-01 22:24:37 +00:00
activateGracePeriod ( account ) ;
2015-12-10 22:05:11 +00:00
}
2015-05-15 09:51:20 +00:00
} else {
message . markUnread ( ) ;
2016-06-15 10:44:29 +00:00
notify = true ;
2015-05-15 09:51:20 +00:00
}
2015-12-10 22:05:11 +00:00
}
2016-06-15 10:44:29 +00:00
if ( message . getEncryption ( ) = = Message . ENCRYPTION_PGP ) {
notify = conversation . getAccount ( ) . getPgpDecryptionService ( ) . decrypt ( message , notify ) ;
}
2016-02-03 15:04:21 +00:00
if ( query = = null ) {
2015-05-15 10:29:45 +00:00
mXmppConnectionService . updateConversationUi ( ) ;
2014-07-23 23:04:25 +00:00
}
2015-05-15 03:14:15 +00:00
2016-10-07 08:05:08 +00:00
if ( mXmppConnectionService . confirmMessages ( )
2017-02-15 11:09:36 +00:00
& & ( message . trusted ( ) | | message . getType ( ) = = Message . TYPE_PRIVATE )
2016-10-07 08:05:08 +00:00
& & remoteMsgId ! = null
& & ! isForwarded
& & ! isTypeGroupChat ) {
2016-02-15 22:15:04 +00:00
sendMessageReceipts ( account , packet ) ;
2014-07-12 00:36:37 +00:00
}
2014-10-28 17:02:12 +00:00
2015-05-15 03:14:15 +00:00
if ( message . getStatus ( ) = = Message . STATUS_RECEIVED
& & conversation . getOtrSession ( ) ! = null
& & ! conversation . getOtrSession ( ) . getSessionID ( ) . getUserID ( )
. equals ( message . getCounterpart ( ) . getResourcepart ( ) ) ) {
conversation . endOtrIfNeeded ( ) ;
}
2014-10-28 17:02:12 +00:00
2017-01-23 16:14:30 +00:00
mXmppConnectionService . databaseBackend . createMessage ( message ) ;
2015-05-15 03:14:15 +00:00
final HttpConnectionManager manager = this . mXmppConnectionService . getHttpConnectionManager ( ) ;
2017-04-05 20:32:02 +00:00
if ( message . trusted ( ) & & message . treatAsDownloadable ( ) & & manager . getAutoAcceptFileSize ( ) > 0 ) {
2015-07-10 13:14:13 +00:00
manager . createNewDownloadConnection ( message ) ;
2016-06-15 10:44:29 +00:00
} else if ( notify ) {
2017-03-21 16:58:08 +00:00
if ( query ! = null & & query . isCatchup ( ) ) {
mXmppConnectionService . getNotificationService ( ) . pushFromBacklog ( message ) ;
} else {
mXmppConnectionService . getNotificationService ( ) . push ( message ) ;
2015-12-10 22:05:11 +00:00
}
2015-05-15 03:14:15 +00:00
}
2017-11-21 12:26:45 +00:00
} else if ( ! packet . hasChild ( " body " ) ) { //no body
2017-04-05 19:01:29 +00:00
final Conversation conversation = mXmppConnectionService . find ( account , from . toBareJid ( ) ) ;
2015-06-28 18:11:28 +00:00
if ( isTypeGroupChat ) {
if ( packet . hasChild ( " subject " ) ) {
if ( conversation ! = null & & conversation . getMode ( ) = = Conversation . MODE_MULTI ) {
conversation . setHasMessagesLeftOnServer ( conversation . countMessages ( ) > 0 ) ;
2015-12-11 18:28:44 +00:00
String subject = packet . findChildContent ( " subject " ) ;
conversation . getMucOptions ( ) . setSubject ( subject ) ;
final Bookmark bookmark = conversation . getBookmark ( ) ;
if ( bookmark ! = null & & bookmark . getBookmarkName ( ) = = null ) {
if ( bookmark . setBookmarkName ( subject ) ) {
mXmppConnectionService . pushBookmarks ( account ) ;
}
}
2015-06-28 18:11:28 +00:00
mXmppConnectionService . updateConversationUi ( ) ;
return ;
}
}
2016-05-17 12:25:58 +00:00
}
if ( conversation ! = null & & mucUserElement ! = null & & from . isBareJid ( ) ) {
2016-10-08 10:10:53 +00:00
for ( Element child : mucUserElement . getChildren ( ) ) {
if ( " status " . equals ( child . getName ( ) ) ) {
try {
int code = Integer . parseInt ( child . getAttribute ( " code " ) ) ;
if ( ( code > = 170 & & code < = 174 ) | | ( code > = 102 & & code < = 104 ) ) {
mXmppConnectionService . fetchConferenceConfiguration ( conversation ) ;
break ;
2016-05-17 12:25:58 +00:00
}
2016-10-08 10:10:53 +00:00
} catch ( Exception e ) {
//ignored
}
} else if ( " item " . equals ( child . getName ( ) ) ) {
2017-11-21 12:26:45 +00:00
MucOptions . User user = AbstractParser . parseItem ( conversation , child ) ;
Log . d ( Config . LOGTAG , account . getJid ( ) + " : changing affiliation for "
+ user . getRealJid ( ) + " to " + user . getAffiliation ( ) + " in "
+ conversation . getJid ( ) . toBareJid ( ) ) ;
2016-10-08 10:10:53 +00:00
if ( ! user . realJidMatchesAccount ( ) ) {
2017-11-21 12:26:45 +00:00
boolean isNew = conversation . getMucOptions ( ) . updateUser ( user ) ;
2016-10-08 10:10:53 +00:00
mXmppConnectionService . getAvatarService ( ) . clear ( conversation ) ;
mXmppConnectionService . updateMucRosterUi ( ) ;
mXmppConnectionService . updateConversationUi ( ) ;
2017-01-22 17:58:49 +00:00
if ( ! user . getAffiliation ( ) . ranks ( MucOptions . Affiliation . MEMBER ) ) {
Jid jid = user . getRealJid ( ) ;
List < Jid > cryptoTargets = conversation . getAcceptedCryptoTargets ( ) ;
if ( cryptoTargets . remove ( user . getRealJid ( ) ) ) {
2017-11-21 12:26:45 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : removed " + jid + " from crypto targets of " + conversation . getName ( ) ) ;
2017-01-22 17:58:49 +00:00
conversation . setAcceptedCryptoTargets ( cryptoTargets ) ;
mXmppConnectionService . updateConversation ( conversation ) ;
}
2017-06-28 07:49:24 +00:00
} else if ( isNew & & user . getRealJid ( ) ! = null & & account . getAxolotlService ( ) . hasEmptyDeviceList ( user . getRealJid ( ) ) ) {
account . getAxolotlService ( ) . fetchDeviceIds ( user . getRealJid ( ) ) ;
2017-01-22 17:58:49 +00:00
}
2016-05-17 12:25:58 +00:00
}
}
2015-05-15 03:14:15 +00:00
}
}
2014-07-12 00:36:37 +00:00
}
2015-05-15 03:14:15 +00:00
Element received = packet . findChild ( " received " , " urn:xmpp:chat-markers:0 " ) ;
if ( received = = null ) {
received = packet . findChild ( " received " , " urn:xmpp:receipts " ) ;
}
if ( received ! = null & & ! packet . fromAccount ( account ) ) {
mXmppConnectionService . markMessage ( account , from . toBareJid ( ) , received . getAttribute ( " id " ) , Message . STATUS_SEND_RECEIVED ) ;
}
Element displayed = packet . findChild ( " displayed " , " urn:xmpp:chat-markers:0 " ) ;
if ( displayed ! = null ) {
2017-11-19 00:53:04 +00:00
final String id = displayed . getAttribute ( " id " ) ;
2015-05-15 03:14:15 +00:00
if ( packet . fromAccount ( account ) ) {
2017-11-19 00:53:04 +00:00
Conversation conversation = mXmppConnectionService . find ( account , counterpart . toBareJid ( ) ) ;
2017-04-30 14:19:39 +00:00
if ( conversation ! = null & & ( query = = null | | query . isCatchup ( ) ) ) {
2015-05-16 10:43:38 +00:00
mXmppConnectionService . markRead ( conversation ) ;
}
2017-11-19 00:53:04 +00:00
} else if ( isTypeGroupChat ) {
Conversation conversation = mXmppConnectionService . find ( account , counterpart . toBareJid ( ) ) ;
if ( conversation ! = null & & id ! = null ) {
Message message = conversation . findMessageWithRemoteId ( id ) ;
if ( message ! = null ) {
2017-11-21 12:26:23 +00:00
if ( conversation . getMucOptions ( ) . isSelf ( counterpart ) ) {
if ( ! message . isRead ( ) & & ( query = = null | | query . isCatchup ( ) ) ) { //checking if message is unread fixes race conditions with reflections
mXmppConnectionService . markRead ( conversation ) ;
}
} else {
final Jid fallback = conversation . getMucOptions ( ) . getTrueCounterpart ( counterpart ) ;
Jid trueJid = getTrueCounterpart ( query ! = null ? mucUserElement : null , fallback ) ;
ReadByMarker readByMarker = ReadByMarker . from ( counterpart , trueJid ) ;
if ( message . addReadByMarker ( readByMarker ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : added read by ( " + readByMarker . getRealJid ( ) + " ) to message ' " + message . getBody ( ) + " ' " ) ;
mXmppConnectionService . updateMessage ( message ) ;
}
2017-11-19 00:53:04 +00:00
}
}
}
2015-05-15 03:14:15 +00:00
} else {
2017-11-19 00:53:04 +00:00
final Message displayedMessage = mXmppConnectionService . markMessage ( account , from . toBareJid ( ) , id , Message . STATUS_SEND_DISPLAYED ) ;
2015-05-15 03:14:15 +00:00
Message message = displayedMessage = = null ? null : displayedMessage . prev ( ) ;
while ( message ! = null
& & message . getStatus ( ) = = Message . STATUS_SEND_RECEIVED
& & message . getTimeSent ( ) < displayedMessage . getTimeSent ( ) ) {
mXmppConnectionService . markMessage ( message , Message . STATUS_SEND_DISPLAYED ) ;
message = message . prev ( ) ;
}
}
2014-09-28 13:21:56 +00:00
}
2014-08-04 23:36:17 +00:00
2016-12-23 20:16:58 +00:00
Element event = original . findChild ( " event " , " http://jabber.org/protocol/pubsub#event " ) ;
2015-05-15 03:14:15 +00:00
if ( event ! = null ) {
2016-12-23 20:16:58 +00:00
parseEvent ( event , original . getFrom ( ) , account ) ;
2014-08-04 23:36:17 +00:00
}
2014-09-04 08:50:06 +00:00
2017-08-23 19:49:25 +00:00
final String nick = packet . findChildContent ( " nick " , Namespace . NICK ) ;
2014-09-04 08:50:06 +00:00
if ( nick ! = null ) {
2015-05-15 03:14:15 +00:00
Contact contact = account . getRoster ( ) . getContact ( from ) ;
2017-08-23 19:49:25 +00:00
if ( contact . setPresenceName ( nick ) ) {
mXmppConnectionService . getAvatarService ( ) . clear ( contact ) ;
}
2014-09-04 08:50:06 +00:00
}
}
2016-02-15 22:15:04 +00:00
2016-06-22 10:22:57 +00:00
private static Jid getTrueCounterpart ( Element mucUserElement , Jid fallback ) {
final Element item = mucUserElement = = null ? null : mucUserElement . findChild ( " item " ) ;
Jid result = item = = null ? null : item . getAttributeAsJid ( " jid " ) ;
2016-06-28 08:33:46 +00:00
return result ! = null ? result : fallback ;
2016-06-22 10:22:57 +00:00
}
2016-02-15 22:15:04 +00:00
private void sendMessageReceipts ( Account account , MessagePacket packet ) {
ArrayList < String > receiptsNamespaces = new ArrayList < > ( ) ;
if ( packet . hasChild ( " markable " , " urn:xmpp:chat-markers:0 " ) ) {
receiptsNamespaces . add ( " urn:xmpp:chat-markers:0 " ) ;
}
if ( packet . hasChild ( " request " , " urn:xmpp:receipts " ) ) {
receiptsNamespaces . add ( " urn:xmpp:receipts " ) ;
}
if ( receiptsNamespaces . size ( ) > 0 ) {
MessagePacket receipt = mXmppConnectionService . getMessageGenerator ( ) . received ( account ,
packet ,
receiptsNamespaces ,
packet . getType ( ) ) ;
mXmppConnectionService . sendMessagePacket ( account , receipt ) ;
}
}
2016-06-01 22:24:37 +00:00
2017-07-01 11:41:24 +00:00
private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat ( " HH:mm:ss " , Locale . ENGLISH ) ;
2016-06-01 22:24:37 +00:00
private void activateGracePeriod ( Account account ) {
2017-11-21 12:26:45 +00:00
long duration = mXmppConnectionService . getLongPreference ( " grace_period_length " , R . integer . grace_period ) * 1000 ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : activating grace period till " + TIME_FORMAT . format ( new Date ( System . currentTimeMillis ( ) + duration ) ) ) ;
2016-06-01 22:24:37 +00:00
account . activateGracePeriod ( duration ) ;
}
2015-08-15 12:26:37 +00:00
}