2014-02-28 12:46:01 -05:00
package eu.siacs.conversations.services ;
2014-01-23 20:04:05 -05:00
2014-11-09 19:24:35 -05:00
import android.annotation.SuppressLint ;
2016-05-28 08:44:22 -04:00
import android.annotation.TargetApi ;
2014-11-09 19:24:35 -05:00
import android.app.AlarmManager ;
import android.app.PendingIntent ;
import android.app.Service ;
import android.content.Context ;
import android.content.Intent ;
2015-10-07 18:35:04 -04:00
import android.content.IntentFilter ;
2014-11-09 19:24:35 -05:00
import android.content.SharedPreferences ;
import android.database.ContentObserver ;
import android.graphics.Bitmap ;
2015-10-07 18:35:04 -04:00
import android.media.AudioManager ;
2014-11-09 19:24:35 -05:00
import android.net.ConnectivityManager ;
import android.net.NetworkInfo ;
import android.net.Uri ;
import android.os.Binder ;
2015-10-07 18:35:04 -04:00
import android.os.Build ;
2014-11-09 19:24:35 -05:00
import android.os.Bundle ;
2016-07-23 10:12:45 -04:00
import android.os.Environment ;
2014-11-09 19:24:35 -05:00
import android.os.IBinder ;
import android.os.PowerManager ;
import android.os.PowerManager.WakeLock ;
import android.os.SystemClock ;
import android.preference.PreferenceManager ;
import android.provider.ContactsContract ;
2015-10-09 07:37:08 -04:00
import android.security.KeyChain ;
2016-08-25 11:30:44 -04:00
import android.support.v4.app.RemoteInput ;
2015-10-16 03:58:31 -04:00
import android.util.DisplayMetrics ;
2014-11-09 19:24:35 -05:00
import android.util.Log ;
import android.util.LruCache ;
2015-10-11 09:48:58 -04:00
import android.util.Pair ;
2014-11-09 19:24:35 -05:00
import net.java.otr4j.OtrException ;
import net.java.otr4j.session.Session ;
import net.java.otr4j.session.SessionID ;
2015-07-05 05:59:38 -04:00
import net.java.otr4j.session.SessionImpl ;
2014-11-09 19:24:35 -05:00
import net.java.otr4j.session.SessionStatus ;
2015-10-29 09:03:41 -04:00
import org.openintents.openpgp.IOpenPgpService2 ;
2014-11-09 19:24:35 -05:00
import org.openintents.openpgp.util.OpenPgpApi ;
import org.openintents.openpgp.util.OpenPgpServiceConnection ;
2014-11-20 12:20:42 -05:00
import java.math.BigInteger ;
2014-06-20 11:30:19 -04:00
import java.security.SecureRandom ;
2015-10-11 09:48:58 -04:00
import java.security.cert.CertificateException ;
2015-10-09 07:37:08 -04:00
import java.security.cert.X509Certificate ;
2014-07-10 13:42:37 -04:00
import java.util.ArrayList ;
2015-04-21 16:17:58 -04:00
import java.util.Arrays ;
2014-12-21 15:43:58 -05:00
import java.util.Collection ;
2014-03-19 11:16:40 -04:00
import java.util.Collections ;
2015-12-27 11:29:32 -05:00
import java.util.HashMap ;
2016-05-02 08:31:30 -04:00
import java.util.HashSet ;
2014-02-01 09:07:20 -05:00
import java.util.Hashtable ;
2015-05-05 04:29:41 -04:00
import java.util.Iterator ;
2014-01-25 13:33:12 -05:00
import java.util.List ;
2014-03-21 17:14:52 -04:00
import java.util.Locale ;
2014-12-21 15:43:58 -05:00
import java.util.Map ;
2014-07-12 06:41:37 -04:00
import java.util.concurrent.CopyOnWriteArrayList ;
2014-02-13 17:40:08 -05:00
2014-07-22 11:27:44 -04:00
import de.duenndns.ssl.MemorizingTrustManager ;
2014-08-31 10:28:21 -04:00
import eu.siacs.conversations.Config ;
2014-08-04 19:36:17 -04:00
import eu.siacs.conversations.R ;
2016-06-13 07:32:14 -04:00
import eu.siacs.conversations.crypto.PgpDecryptionService ;
2014-02-28 12:46:01 -05:00
import eu.siacs.conversations.crypto.PgpEngine ;
2015-10-16 17:48:42 -04:00
import eu.siacs.conversations.crypto.axolotl.AxolotlService ;
2015-07-20 17:13:28 -04:00
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage ;
2014-02-28 12:46:01 -05:00
import eu.siacs.conversations.entities.Account ;
2014-12-21 15:43:58 -05:00
import eu.siacs.conversations.entities.Blockable ;
2014-07-14 05:47:42 -04:00
import eu.siacs.conversations.entities.Bookmark ;
2014-02-28 12:46:01 -05:00
import eu.siacs.conversations.entities.Contact ;
import eu.siacs.conversations.entities.Conversation ;
2016-07-23 10:12:45 -04:00
import eu.siacs.conversations.entities.DownloadableFile ;
2014-02-28 12:46:01 -05:00
import eu.siacs.conversations.entities.Message ;
2014-03-02 23:01:02 -05:00
import eu.siacs.conversations.entities.MucOptions ;
import eu.siacs.conversations.entities.MucOptions.OnRenameListener ;
2016-01-17 16:28:38 -05:00
import eu.siacs.conversations.entities.Presence ;
2016-04-22 15:25:06 -04:00
import eu.siacs.conversations.entities.PresenceTemplate ;
2016-02-03 04:40:02 -05:00
import eu.siacs.conversations.entities.Roster ;
import eu.siacs.conversations.entities.ServiceDiscoveryResult ;
2015-07-20 08:26:29 -04:00
import eu.siacs.conversations.entities.Transferable ;
import eu.siacs.conversations.entities.TransferablePlaceholder ;
2016-06-04 10:16:14 -04:00
import eu.siacs.conversations.generator.AbstractGenerator ;
2014-07-23 08:30:27 -04:00
import eu.siacs.conversations.generator.IqGenerator ;
2014-06-22 11:24:47 -04:00
import eu.siacs.conversations.generator.MessageGenerator ;
2014-07-11 21:44:23 -04:00
import eu.siacs.conversations.generator.PresenceGenerator ;
2014-10-13 19:06:45 -04:00
import eu.siacs.conversations.http.HttpConnectionManager ;
2016-05-17 08:25:58 -04:00
import eu.siacs.conversations.parser.AbstractParser ;
2014-07-12 06:28:28 -04:00
import eu.siacs.conversations.parser.IqParser ;
2014-05-14 06:56:34 -04:00
import eu.siacs.conversations.parser.MessageParser ;
2014-06-06 12:26:40 -04:00
import eu.siacs.conversations.parser.PresenceParser ;
2014-02-28 12:46:01 -05:00
import eu.siacs.conversations.persistance.DatabaseBackend ;
2014-04-05 15:06:10 -04:00
import eu.siacs.conversations.persistance.FileBackend ;
2014-05-12 08:59:46 -04:00
import eu.siacs.conversations.ui.UiCallback ;
2016-07-23 10:12:45 -04:00
import eu.siacs.conversations.utils.ConversationsFileObserver ;
2014-06-20 11:30:19 -04:00
import eu.siacs.conversations.utils.CryptoHelper ;
2014-03-09 08:21:28 -04:00
import eu.siacs.conversations.utils.ExceptionHelper ;
2014-02-28 12:46:01 -05:00
import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener ;
2014-06-20 11:30:19 -04:00
import eu.siacs.conversations.utils.PRNGFixes ;
2014-02-28 12:46:01 -05:00
import eu.siacs.conversations.utils.PhoneHelper ;
2016-05-31 11:20:21 -04:00
import eu.siacs.conversations.utils.ReplacingSerialSingleThreadExecutor ;
2015-06-05 02:46:06 -04:00
import eu.siacs.conversations.utils.SerialSingleThreadExecutor ;
2014-12-20 20:13:13 -05:00
import eu.siacs.conversations.utils.Xmlns ;
2014-02-28 12:46:01 -05:00
import eu.siacs.conversations.xml.Element ;
2014-03-14 15:43:54 -04:00
import eu.siacs.conversations.xmpp.OnBindListener ;
2014-05-23 04:54:40 -04:00
import eu.siacs.conversations.xmpp.OnContactStatusChanged ;
2014-02-28 12:46:01 -05:00
import eu.siacs.conversations.xmpp.OnIqPacketReceived ;
2015-08-25 06:40:22 -04:00
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated ;
2014-08-26 10:52:42 -04:00
import eu.siacs.conversations.xmpp.OnMessageAcknowledged ;
2014-12-21 15:43:58 -05:00
import eu.siacs.conversations.xmpp.OnMessagePacketReceived ;
import eu.siacs.conversations.xmpp.OnPresencePacketReceived ;
2014-02-28 12:46:01 -05:00
import eu.siacs.conversations.xmpp.OnStatusChanged ;
2014-12-21 15:43:58 -05:00
import eu.siacs.conversations.xmpp.OnUpdateBlocklist ;
2014-02-28 12:46:01 -05:00
import eu.siacs.conversations.xmpp.XmppConnection ;
2015-02-21 05:06:52 -05:00
import eu.siacs.conversations.xmpp.chatstate.ChatState ;
2014-11-20 12:33:04 -05:00
import eu.siacs.conversations.xmpp.forms.Data ;
import eu.siacs.conversations.xmpp.forms.Field ;
2014-11-05 15:55:47 -05:00
import eu.siacs.conversations.xmpp.jid.InvalidJidException ;
import eu.siacs.conversations.xmpp.jid.Jid ;
2014-04-08 17:15:55 -04:00
import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager ;
import eu.siacs.conversations.xmpp.jingle.OnJinglePacketReceived ;
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket ;
2014-08-03 14:28:13 -04:00
import eu.siacs.conversations.xmpp.pep.Avatar ;
2014-03-10 14:22:13 -04:00
import eu.siacs.conversations.xmpp.stanzas.IqPacket ;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket ;
import eu.siacs.conversations.xmpp.stanzas.PresencePacket ;
2015-05-20 06:47:04 -04:00
import me.leolin.shortcutbadger.ShortcutBadger ;
2014-01-23 20:04:05 -05:00
2016-05-31 11:20:21 -04:00
public class XmppConnectionService extends Service {
2014-02-03 12:38:47 -05:00
2016-08-25 11:30:44 -04:00
public static final String ACTION_REPLY_TO_CONVERSATION = " reply_to_conversations " ;
2014-12-21 15:43:58 -05:00
public static final String ACTION_CLEAR_NOTIFICATION = " clear_notification " ;
public static final String ACTION_DISABLE_FOREGROUND = " disable_foreground " ;
2016-10-04 05:16:59 -04:00
public static final String ACTION_DISMISS_ERROR_NOTIFICATIONS = " dismiss_error " ;
2015-02-10 11:13:34 -05:00
public static final String ACTION_TRY_AGAIN = " try_again " ;
2016-05-28 08:44:22 -04:00
public static final String ACTION_IDLE_PING = " idle_ping " ;
2015-10-16 03:58:31 -04:00
private static final String ACTION_MERGE_PHONE_CONTACTS = " merge_phone_contacts " ;
2016-02-12 05:39:27 -05:00
public static final String ACTION_GCM_TOKEN_REFRESH = " gcm_token_refresh " ;
public static final String ACTION_GCM_MESSAGE_RECEIVED = " gcm_message_received " ;
2015-10-16 03:58:31 -04:00
private final SerialSingleThreadExecutor mFileAddingExecutor = new SerialSingleThreadExecutor ( ) ;
private final SerialSingleThreadExecutor mDatabaseExecutor = new SerialSingleThreadExecutor ( ) ;
2016-05-31 11:20:21 -04:00
private ReplacingSerialSingleThreadExecutor mContactMergerExecutor = new ReplacingSerialSingleThreadExecutor ( true ) ;
2015-10-16 03:58:31 -04:00
private final IBinder mBinder = new XmppConnectionBinder ( ) ;
private final List < Conversation > conversations = new CopyOnWriteArrayList < > ( ) ;
private final IqGenerator mIqGenerator = new IqGenerator ( this ) ;
private final List < String > mInProgressAvatarFetches = new ArrayList < > ( ) ;
2016-10-20 12:02:11 -04:00
private final HashSet < Jid > mLowPingTimeoutMode = new HashSet < > ( ) ;
2016-06-04 10:16:14 -04:00
private long mLastActivity = 0 ;
2015-10-16 03:58:31 -04:00
public DatabaseBackend databaseBackend ;
2014-11-09 19:24:35 -05:00
private ContentObserver contactObserver = new ContentObserver ( null ) {
@Override
public void onChange ( boolean selfChange ) {
super . onChange ( selfChange ) ;
Intent intent = new Intent ( getApplicationContext ( ) ,
XmppConnectionService . class ) ;
intent . setAction ( ACTION_MERGE_PHONE_CONTACTS ) ;
startService ( intent ) ;
}
} ;
2015-10-16 03:58:31 -04:00
private FileBackend fileBackend = new FileBackend ( this ) ;
private MemorizingTrustManager mMemorizingTrustManager ;
private NotificationService mNotificationService = new NotificationService (
this ) ;
private OnMessagePacketReceived mMessageParser = new MessageParser ( this ) ;
private OnPresencePacketReceived mPresenceParser = new PresenceParser ( this ) ;
private IqParser mIqParser = new IqParser ( this ) ;
private OnIqPacketReceived mDefaultIqHandler = new OnIqPacketReceived ( ) {
2015-01-19 05:17:27 -05:00
@Override
2015-10-16 03:58:31 -04:00
public void onIqPacketReceived ( Account account , IqPacket packet ) {
if ( packet . getType ( ) ! = IqPacket . TYPE . RESULT ) {
Element error = packet . findChild ( " error " ) ;
String text = error ! = null ? error . findChildContent ( " text " ) : null ;
if ( text ! = null ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : received iq error - " + text ) ;
2015-01-19 05:17:27 -05:00
}
}
}
} ;
2015-10-16 03:58:31 -04:00
private MessageGenerator mMessageGenerator = new MessageGenerator ( this ) ;
private PresenceGenerator mPresenceGenerator = new PresenceGenerator ( this ) ;
private List < Account > accounts ;
private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager (
this ) ;
2014-11-09 19:24:35 -05:00
public OnContactStatusChanged onContactStatusChanged = new OnContactStatusChanged ( ) {
2014-08-26 10:52:42 -04:00
2014-11-09 19:24:35 -05:00
@Override
public void onContactStatusChanged ( Contact contact , boolean online ) {
Conversation conversation = find ( getConversations ( ) , contact ) ;
if ( conversation ! = null ) {
2015-04-21 16:17:58 -04:00
if ( online ) {
2014-11-09 19:24:35 -05:00
conversation . endOtrIfNeeded ( ) ;
2015-04-21 16:17:58 -04:00
if ( contact . getPresences ( ) . size ( ) = = 1 ) {
sendUnsentMessages ( conversation ) ;
}
2014-11-09 19:24:35 -05:00
} else {
2016-08-13 06:43:06 -04:00
//check if the resource we are haveing a conversation with is still online
if ( conversation . hasValidOtrSession ( ) ) {
String otrResource = conversation . getOtrSession ( ) . getSessionID ( ) . getUserID ( ) ;
if ( ! ( Arrays . asList ( contact . getPresences ( ) . toResourceArray ( ) ) . contains ( otrResource ) ) ) {
conversation . endOtrIfNeeded ( ) ;
2015-04-21 16:17:58 -04:00
}
}
2014-11-09 19:24:35 -05:00
}
}
}
} ;
2015-10-16 03:58:31 -04:00
private HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager (
2014-10-21 08:57:16 -04:00
this ) ;
2015-10-16 03:58:31 -04:00
private AvatarService mAvatarService = new AvatarService ( this ) ;
private MessageArchiveService mMessageArchiveService = new MessageArchiveService ( this ) ;
2016-02-12 05:39:27 -05:00
private PushManagementService mPushManagementService = new PushManagementService ( this ) ;
2015-10-16 03:58:31 -04:00
private OnConversationUpdate mOnConversationUpdate = null ;
2016-07-23 10:12:45 -04:00
private final ConversationsFileObserver fileObserver = new ConversationsFileObserver (
Environment . getExternalStorageDirectory ( ) . getAbsolutePath ( )
) {
2015-05-26 05:31:33 -04:00
@Override
2015-10-16 03:58:31 -04:00
public void onEvent ( int event , String path ) {
2016-07-23 10:12:45 -04:00
markFileDeleted ( path ) ;
2015-10-16 03:58:31 -04:00
}
} ;
private final OnJinglePacketReceived jingleListener = new OnJinglePacketReceived ( ) {
@Override
public void onJinglePacketReceived ( Account account , JinglePacket packet ) {
mJingleConnectionManager . deliverPacket ( account , packet ) ;
}
} ;
private final OnMessageAcknowledged mOnMessageAcknowledgedListener = new OnMessageAcknowledged ( ) {
@Override
public void onMessageAcknowledged ( Account account , String uuid ) {
for ( final Conversation conversation : getConversations ( ) ) {
if ( conversation . getAccount ( ) = = account ) {
Message message = conversation . findUnsentMessageWithUuid ( uuid ) ;
if ( message ! = null ) {
markMessage ( message , Message . STATUS_SEND ) ;
}
2015-05-26 05:31:33 -04:00
}
}
}
} ;
2015-05-26 06:00:38 -04:00
private int convChangedListenerCount = 0 ;
2015-07-10 07:28:50 -04:00
private OnShowErrorToast mOnShowErrorToast = null ;
private int showErrorToastListenerCount = 0 ;
2015-07-03 16:08:23 -04:00
private int unreadCount = - 1 ;
2014-07-12 07:42:17 -04:00
private OnAccountUpdate mOnAccountUpdate = null ;
2015-10-11 07:11:50 -04:00
private OnCaptchaRequested mOnCaptchaRequested = null ;
2015-10-16 03:58:31 -04:00
private int accountChangedListenerCount = 0 ;
private int captchaRequestedListenerCount = 0 ;
private OnRosterUpdate mOnRosterUpdate = null ;
private OnUpdateBlocklist mOnUpdateBlocklist = null ;
private int updateBlocklistListenerCount = 0 ;
private int rosterChangedListenerCount = 0 ;
private OnMucRosterUpdate mOnMucRosterUpdate = null ;
private int mucRosterChangedListenerCount = 0 ;
private OnKeyStatusUpdated mOnKeyStatusUpdated = null ;
private int keyStatusUpdatedListenerCount = 0 ;
private SecureRandom mRandom ;
2016-02-03 04:40:02 -05:00
private LruCache < Pair < String , String > , ServiceDiscoveryResult > discoCache = new LruCache < > ( 20 ) ;
2015-10-16 03:58:31 -04:00
private final OnBindListener mOnBindListener = new OnBindListener ( ) {
@Override
public void onBind ( final Account account ) {
2016-03-03 07:33:02 -05:00
synchronized ( mInProgressAvatarFetches ) {
for ( Iterator < String > iterator = mInProgressAvatarFetches . iterator ( ) ; iterator . hasNext ( ) ; ) {
final String KEY = iterator . next ( ) ;
if ( KEY . startsWith ( account . getJid ( ) . toBareJid ( ) + " _ " ) ) {
iterator . remove ( ) ;
}
}
}
2015-10-16 03:58:31 -04:00
account . getRoster ( ) . clearPresences ( ) ;
2015-12-12 10:01:33 -05:00
mJingleConnectionManager . cancelInTransmission ( ) ;
2015-10-16 03:58:31 -04:00
fetchRosterFromServer ( account ) ;
fetchBookmarks ( account ) ;
sendPresence ( account ) ;
2016-02-12 18:03:57 -05:00
if ( mPushManagementService . available ( account ) ) {
2016-02-12 17:37:42 -05:00
mPushManagementService . registerPushTokenOnServer ( account ) ;
}
2015-10-16 03:58:31 -04:00
connectMultiModeConversations ( account ) ;
syncDirtyContacts ( account ) ;
}
} ;
2014-02-04 09:09:50 -05:00
private OnStatusChanged statusListener = new OnStatusChanged ( ) {
2014-02-05 16:33:39 -05:00
2014-02-04 09:09:50 -05:00
@Override
2016-02-12 05:39:27 -05:00
public void onStatusChanged ( final Account account ) {
2014-08-28 16:23:18 -04:00
XmppConnection connection = account . getXmppConnection ( ) ;
2014-07-12 07:42:17 -04:00
if ( mOnAccountUpdate ! = null ) {
2014-08-26 10:52:42 -04:00
mOnAccountUpdate . onAccountUpdate ( ) ;
2014-02-04 09:09:50 -05:00
}
2014-11-15 11:09:02 -05:00
if ( account . getStatus ( ) = = Account . State . ONLINE ) {
2016-10-04 05:16:59 -04:00
if ( account . setShowErrorNotification ( true ) ) {
databaseBackend . updateAccount ( account ) ;
}
2016-02-26 03:46:25 -05:00
mMessageArchiveService . executePendingQueries ( account ) ;
2015-08-13 12:25:10 -04:00
if ( connection ! = null & & connection . getFeatures ( ) . csi ( ) ) {
if ( checkListeners ( ) ) {
2015-10-16 03:58:31 -04:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " sending csi//inactive " ) ;
2015-08-13 12:25:10 -04:00
connection . sendInactive ( ) ;
} else {
2015-10-16 03:58:31 -04:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " sending csi//active " ) ;
2015-08-13 12:25:10 -04:00
connection . sendActive ( ) ;
}
2014-07-18 15:57:10 -04:00
}
2014-03-21 14:58:47 -04:00
List < Conversation > conversations = getConversations ( ) ;
2014-11-09 19:24:35 -05:00
for ( Conversation conversation : conversations ) {
2016-02-17 10:50:48 -05:00
if ( conversation . getAccount ( ) = = account
& & ! account . pendingConferenceJoins . contains ( conversation ) ) {
2016-02-16 03:15:41 -05:00
if ( ! conversation . startOtrIfNeeded ( ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : couldn't start OTR with " + conversation . getContact ( ) . getJid ( ) + " when needed " ) ;
}
2014-12-14 12:10:46 -05:00
sendUnsentMessages ( conversation ) ;
2014-11-09 19:24:35 -05:00
}
}
2015-10-01 10:01:19 -04:00
for ( Conversation conversation : account . pendingConferenceLeaves ) {
leaveMuc ( conversation ) ;
}
account . pendingConferenceLeaves . clear ( ) ;
for ( Conversation conversation : account . pendingConferenceJoins ) {
joinMuc ( conversation ) ;
}
account . pendingConferenceJoins . clear ( ) ;
2016-08-09 13:21:54 -04:00
scheduleWakeUpCall ( Config . PUSH_MODE ? Config . PING_MIN_INTERVAL : Config . PING_MAX_INTERVAL , account . getUuid ( ) . hashCode ( ) ) ;
2016-10-06 11:23:35 -04:00
} else if ( account . getStatus ( ) = = Account . State . OFFLINE | | account . getStatus ( ) = = Account . State . DISABLED ) {
2015-08-19 06:47:50 -04:00
resetSendingToWaiting ( account ) ;
2016-02-14 07:20:23 -05:00
final boolean disabled = account . isOptionSet ( Account . OPTION_DISABLED ) ;
2016-08-09 13:21:54 -04:00
final boolean listeners = checkListeners ( ) ;
final boolean pushMode = Config . PUSH_MODE
2016-02-14 07:20:23 -05:00
& & mPushManagementService . available ( account )
2016-08-09 13:21:54 -04:00
& & listeners ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : push mode= " + Boolean . toString ( pushMode ) + " listeners= " + Boolean . toString ( listeners ) ) ;
2016-02-14 07:20:23 -05:00
if ( ! disabled & & ! pushMode ) {
2016-10-23 03:03:17 -04:00
if ( mLowPingTimeoutMode . contains ( account . getJid ( ) . toBareJid ( ) ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : went into offline state during low ping mode. reconnecting now " ) ;
reconnectAccount ( account , true , false ) ;
} else {
int timeToReconnect = mRandom . nextInt ( 20 ) + 10 ;
scheduleWakeUpCall ( timeToReconnect , account . getUuid ( ) . hashCode ( ) ) ;
}
2014-03-05 21:30:03 -05:00
}
2014-11-15 11:09:02 -05:00
} else if ( account . getStatus ( ) = = Account . State . REGISTRATION_SUCCESSFUL ) {
2014-03-13 12:29:22 -04:00
databaseBackend . updateAccount ( account ) ;
2015-09-29 13:24:52 -04:00
reconnectAccount ( account , true , false ) ;
2014-11-15 11:09:02 -05:00
} else if ( ( account . getStatus ( ) ! = Account . State . CONNECTING )
& & ( account . getStatus ( ) ! = Account . State . NO_INTERNET ) ) {
2016-10-07 08:54:35 -04:00
resetSendingToWaiting ( account ) ;
2014-08-26 10:52:42 -04:00
if ( connection ! = null ) {
2014-08-22 07:22:34 -04:00
int next = connection . getTimeToNextAttempt ( ) ;
2014-11-09 10:57:22 -05:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( )
2014-08-26 10:52:42 -04:00
+ " : error connecting account. try again in "
+ next + " s for the "
+ ( connection . getAttempt ( ) + 1 ) + " time " ) ;
2015-10-16 03:58:31 -04:00
scheduleWakeUpCall ( next , account . getUuid ( ) . hashCode ( ) ) ;
2014-08-22 07:22:34 -04:00
}
2015-10-16 03:58:31 -04:00
}
2014-11-18 09:26:28 -05:00
getNotificationService ( ) . updateErrorNotification ( ) ;
2014-02-04 09:09:50 -05:00
}
} ;
2014-02-27 18:22:56 -05:00
private OpenPgpServiceConnection pgpServiceConnection ;
private PgpEngine mPgpEngine = null ;
2014-03-23 09:15:14 -04:00
private WakeLock wakeLock ;
2014-04-03 04:41:21 -04:00
private PowerManager pm ;
2014-10-21 08:57:16 -04:00
private LruCache < String , Bitmap > mBitmapCache ;
2015-10-07 18:35:04 -04:00
private EventReceiver mEventReceiver = new EventReceiver ( ) ;
2014-02-27 18:22:56 -05:00
2015-02-17 05:51:11 -05:00
private boolean mRestoredFromDatabase = false ;
2015-10-16 03:58:31 -04:00
private static String generateFetchKey ( Account account , final Avatar avatar ) {
return account . getJid ( ) . toBareJid ( ) + " _ " + avatar . owner + " _ " + avatar . sha1sum ;
}
2015-02-12 12:53:00 -05:00
public boolean areMessagesInitialized ( ) {
2015-02-17 05:51:11 -05:00
return this . mRestoredFromDatabase ;
2015-02-12 12:53:00 -05:00
}
2014-02-27 18:22:56 -05:00
public PgpEngine getPgpEngine ( ) {
2016-02-24 08:47:49 -05:00
if ( ! Config . supportOpenPgp ( ) ) {
return null ;
} else if ( pgpServiceConnection ! = null & & pgpServiceConnection . isBound ( ) ) {
2014-02-27 18:22:56 -05:00
if ( this . mPgpEngine = = null ) {
this . mPgpEngine = new PgpEngine ( new OpenPgpApi (
2015-10-16 03:58:31 -04:00
getApplicationContext ( ) ,
pgpServiceConnection . getService ( ) ) , this ) ;
2014-02-27 18:22:56 -05:00
}
return mPgpEngine ;
} else {
return null ;
}
}
2016-06-13 07:32:14 -04:00
public OpenPgpApi getOpenPgpApi ( ) {
if ( ! Config . supportOpenPgp ( ) ) {
return null ;
} else if ( pgpServiceConnection ! = null & & pgpServiceConnection . isBound ( ) ) {
return new OpenPgpApi ( this , pgpServiceConnection . getService ( ) ) ;
} else {
return null ;
}
}
2014-04-05 15:06:10 -04:00
public FileBackend getFileBackend ( ) {
return this . fileBackend ;
}
2014-05-01 16:33:49 -04:00
2014-10-20 15:08:33 -04:00
public AvatarService getAvatarService ( ) {
return this . mAvatarService ;
}
2015-03-07 08:15:38 -05:00
public void attachLocationToConversation ( final Conversation conversation ,
final Uri uri ,
final UiCallback < Message > callback ) {
2015-07-30 18:52:46 -04:00
int encryption = conversation . getNextEncryption ( ) ;
2015-03-07 08:15:38 -05:00
if ( encryption = = Message . ENCRYPTION_PGP ) {
encryption = Message . ENCRYPTION_DECRYPTED ;
}
2015-10-16 03:58:31 -04:00
Message message = new Message ( conversation , uri . toString ( ) , encryption ) ;
2015-03-07 08:15:38 -05:00
if ( conversation . getNextCounterpart ( ) ! = null ) {
message . setCounterpart ( conversation . getNextCounterpart ( ) ) ;
}
if ( encryption = = Message . ENCRYPTION_DECRYPTED ) {
2015-05-05 04:29:41 -04:00
getPgpEngine ( ) . encrypt ( message , callback ) ;
2015-03-07 08:15:38 -05:00
} else {
callback . success ( message ) ;
}
}
2014-12-23 17:19:00 -05:00
public void attachFileToConversation ( final Conversation conversation ,
2015-10-16 03:58:31 -04:00
final Uri uri ,
final UiCallback < Message > callback ) {
2016-04-13 05:14:36 -04:00
if ( FileBackend . weOwnFile ( this , uri ) ) {
2016-04-07 14:29:40 -04:00
Log . d ( Config . LOGTAG , " trying to attach file that belonged to us " ) ;
callback . error ( R . string . security_error_invalid_file_access , null ) ;
return ;
}
2014-11-13 18:28:39 -05:00
final Message message ;
2015-07-30 18:52:46 -04:00
if ( conversation . getNextEncryption ( ) = = Message . ENCRYPTION_PGP ) {
message = new Message ( conversation , " " , Message . ENCRYPTION_DECRYPTED ) ;
2014-11-13 18:28:39 -05:00
} else {
2015-07-30 18:52:46 -04:00
message = new Message ( conversation , " " , conversation . getNextEncryption ( ) ) ;
2014-11-13 18:28:39 -05:00
}
message . setCounterpart ( conversation . getNextCounterpart ( ) ) ;
message . setType ( Message . TYPE_FILE ) ;
2016-07-12 18:20:38 -04:00
final String path = getFileBackend ( ) . getOriginalPath ( uri ) ;
mFileAddingExecutor . execute ( new Runnable ( ) {
@Override
public void run ( ) {
if ( path ! = null ) {
message . setRelativeFilePath ( path ) ;
getFileBackend ( ) . updateFileParams ( message ) ;
if ( message . getEncryption ( ) = = Message . ENCRYPTION_DECRYPTED ) {
getPgpEngine ( ) . encrypt ( message , callback ) ;
} else {
callback . success ( message ) ;
}
} else {
2014-11-13 18:28:39 -05:00
try {
getFileBackend ( ) . copyFileToPrivateStorage ( message , uri ) ;
getFileBackend ( ) . updateFileParams ( message ) ;
2014-11-13 21:27:18 -05:00
if ( message . getEncryption ( ) = = Message . ENCRYPTION_DECRYPTED ) {
2016-06-19 05:08:17 -04:00
final PgpEngine pgpEngine = getPgpEngine ( ) ;
if ( pgpEngine ! = null ) {
pgpEngine . encrypt ( message , callback ) ;
2016-07-12 18:20:38 -04:00
} else if ( callback ! = null ) {
2016-06-19 05:08:17 -04:00
callback . error ( R . string . unable_to_connect_to_keychain , null ) ;
}
2014-11-13 21:27:18 -05:00
} else {
callback . success ( message ) ;
}
2014-11-13 18:28:39 -05:00
} catch ( FileBackend . FileCopyException e ) {
2015-06-28 05:19:07 -04:00
callback . error ( e . getResId ( ) , message ) ;
2014-11-13 18:28:39 -05:00
}
}
2016-07-12 18:20:38 -04:00
}
} ) ;
2014-11-13 15:04:05 -05:00
}
2015-08-11 10:50:00 -04:00
public void attachImageToConversation ( final Conversation conversation , final Uri uri , final UiCallback < Message > callback ) {
2016-04-13 05:14:36 -04:00
if ( FileBackend . weOwnFile ( this , uri ) ) {
2016-04-07 14:29:40 -04:00
Log . d ( Config . LOGTAG , " trying to attach file that belonged to us " ) ;
callback . error ( R . string . security_error_invalid_file_access , null ) ;
return ;
}
2016-01-09 10:17:39 -05:00
final String compressPictures = getCompressPicturesPreference ( ) ;
if ( " never " . equals ( compressPictures )
| | ( " auto " . equals ( compressPictures ) & & getFileBackend ( ) . useImageAsIs ( uri ) ) ) {
Log . d ( Config . LOGTAG , conversation . getAccount ( ) . getJid ( ) . toBareJid ( ) + " : not compressing picture. sending as file " ) ;
2015-08-11 10:50:00 -04:00
attachFileToConversation ( conversation , uri , callback ) ;
return ;
}
2014-05-12 08:59:46 -04:00
final Message message ;
2015-07-30 18:52:46 -04:00
if ( conversation . getNextEncryption ( ) = = Message . ENCRYPTION_PGP ) {
message = new Message ( conversation , " " , Message . ENCRYPTION_DECRYPTED ) ;
2014-05-12 08:59:46 -04:00
} else {
2015-10-16 03:58:31 -04:00
message = new Message ( conversation , " " , conversation . getNextEncryption ( ) ) ;
2014-05-12 08:59:46 -04:00
}
2014-11-09 10:21:13 -05:00
message . setCounterpart ( conversation . getNextCounterpart ( ) ) ;
2014-05-06 15:34:30 -04:00
message . setType ( Message . TYPE_IMAGE ) ;
2015-06-05 02:46:06 -04:00
mFileAddingExecutor . execute ( new Runnable ( ) {
2014-05-01 16:33:49 -04:00
2014-04-15 09:19:02 -04:00
@Override
public void run ( ) {
2014-05-14 12:32:58 -04:00
try {
2014-12-21 15:43:58 -05:00
getFileBackend ( ) . copyImageToPrivateStorage ( message , uri ) ;
2015-07-30 18:52:46 -04:00
if ( conversation . getNextEncryption ( ) = = Message . ENCRYPTION_PGP ) {
2016-06-19 05:08:17 -04:00
final PgpEngine pgpEngine = getPgpEngine ( ) ;
if ( pgpEngine ! = null ) {
pgpEngine . encrypt ( message , callback ) ;
} else if ( callback ! = null ) {
callback . error ( R . string . unable_to_connect_to_keychain , null ) ;
}
2014-05-12 08:59:46 -04:00
} else {
2014-06-07 07:25:27 -04:00
callback . success ( message ) ;
2014-05-12 08:59:46 -04:00
}
2014-12-21 15:43:58 -05:00
} catch ( final FileBackend . FileCopyException e ) {
2014-06-11 15:53:25 -04:00
callback . error ( e . getResId ( ) , message ) ;
2014-04-15 09:19:02 -04:00
}
}
2015-06-05 02:46:06 -04:00
} ) ;
2014-05-06 15:34:30 -04:00
}
2014-05-14 06:56:34 -04:00
2014-07-19 20:26:23 -04:00
public Conversation find ( Bookmark bookmark ) {
2014-08-26 10:52:42 -04:00
return find ( bookmark . getAccount ( ) , bookmark . getJid ( ) ) ;
2014-07-14 05:47:42 -04:00
}
2014-08-26 10:52:42 -04:00
2014-11-05 15:55:47 -05:00
public Conversation find ( final Account account , final Jid jid ) {
2014-08-26 10:52:42 -04:00
return find ( getConversations ( ) , account , jid ) ;
2014-03-02 23:01:02 -05:00
}
2014-02-03 12:38:47 -05:00
@Override
public int onStartCommand ( Intent intent , int flags , int startId ) {
2015-01-05 12:45:39 -05:00
final String action = intent = = null ? null : intent . getAction ( ) ;
2016-10-06 12:09:55 -04:00
String pushedAccountHash = null ;
2015-09-29 13:24:52 -04:00
boolean interactive = false ;
2015-01-05 12:45:39 -05:00
if ( action ! = null ) {
2016-08-25 11:30:44 -04:00
final Conversation c = findConversationByUuid ( intent . getStringExtra ( " uuid " ) ) ;
2015-01-08 08:45:44 -05:00
switch ( action ) {
2015-05-08 00:50:28 -04:00
case ConnectivityManager . CONNECTIVITY_ACTION :
if ( hasInternetConnection ( ) & & Config . RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE ) {
resetAllAttemptCounts ( true ) ;
}
break ;
2015-01-08 08:45:44 -05:00
case ACTION_MERGE_PHONE_CONTACTS :
2015-02-17 05:51:11 -05:00
if ( mRestoredFromDatabase ) {
2015-12-06 18:33:50 -05:00
loadPhoneContacts ( ) ;
2015-02-17 05:51:11 -05:00
}
2015-01-08 08:45:44 -05:00
return START_STICKY ;
case Intent . ACTION_SHUTDOWN :
2016-04-14 15:45:36 -04:00
logoutAndSave ( true ) ;
2015-01-08 08:45:44 -05:00
return START_NOT_STICKY ;
case ACTION_CLEAR_NOTIFICATION :
2016-08-25 09:20:06 -04:00
if ( c ! = null ) {
mNotificationService . clear ( c ) ;
} else {
mNotificationService . clear ( ) ;
}
2015-01-08 08:45:44 -05:00
break ;
case ACTION_DISABLE_FOREGROUND :
2015-10-16 03:58:31 -04:00
getPreferences ( ) . edit ( ) . putBoolean ( " keep_foreground_service " , false ) . commit ( ) ;
2015-01-08 08:45:44 -05:00
toggleForegroundService ( ) ;
break ;
2016-10-04 05:16:59 -04:00
case ACTION_DISMISS_ERROR_NOTIFICATIONS :
dismissErrorNotifications ( ) ;
break ;
2015-02-10 11:13:34 -05:00
case ACTION_TRY_AGAIN :
2015-05-08 00:50:28 -04:00
resetAllAttemptCounts ( false ) ;
2015-09-29 13:24:52 -04:00
interactive = true ;
2015-02-10 11:13:34 -05:00
break ;
2016-08-25 11:30:44 -04:00
case ACTION_REPLY_TO_CONVERSATION :
Bundle remoteInput = RemoteInput . getResultsFromIntent ( intent ) ;
if ( remoteInput ! = null & & c ! = null ) {
2016-09-21 13:04:16 -04:00
final CharSequence body = remoteInput . getCharSequence ( " text_reply " ) ;
if ( body ! = null & & body . length ( ) > 0 ) {
2016-09-19 15:35:54 -04:00
directReply ( c , body . toString ( ) , intent . getBooleanExtra ( " dismiss_notification " , false ) ) ;
2016-09-21 13:04:16 -04:00
}
2016-08-25 11:30:44 -04:00
}
break ;
2015-10-07 18:35:04 -04:00
case AudioManager . RINGER_MODE_CHANGED_ACTION :
if ( xaOnSilentMode ( ) ) {
refreshAllPresences ( ) ;
}
break ;
case Intent . ACTION_SCREEN_ON :
2016-06-01 15:51:46 -04:00
deactivateGracePeriod ( ) ;
case Intent . ACTION_SCREEN_OFF :
2015-10-07 18:35:04 -04:00
if ( awayWhenScreenOff ( ) ) {
refreshAllPresences ( ) ;
}
break ;
2016-02-12 05:39:27 -05:00
case ACTION_GCM_TOKEN_REFRESH :
refreshAllGcmTokens ( ) ;
break ;
2016-05-28 08:44:22 -04:00
case ACTION_IDLE_PING :
2016-08-09 11:26:18 -04:00
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . M
2016-08-09 13:21:54 -04:00
& & ! Config . PUSH_MODE ) {
2016-05-28 08:44:22 -04:00
scheduleNextIdlePing ( ) ;
}
break ;
2016-02-12 05:39:27 -05:00
case ACTION_GCM_MESSAGE_RECEIVED :
Log . d ( Config . LOGTAG , " gcm push message arrived in service. extras= " + intent . getExtras ( ) ) ;
2016-10-06 12:09:55 -04:00
pushedAccountHash = intent . getStringExtra ( " account " ) ;
2016-05-28 08:44:22 -04:00
break ;
2014-10-02 11:36:02 -04:00
}
2014-05-19 09:15:09 -04:00
}
2014-05-31 05:54:32 -04:00
this . wakeLock . acquire ( ) ;
2014-10-20 15:08:33 -04:00
2016-05-02 08:31:30 -04:00
boolean pingNow = false ;
HashSet < Account > pingCandidates = new HashSet < > ( ) ;
2014-02-03 12:38:47 -05:00
for ( Account account : accounts ) {
2014-03-11 10:44:22 -04:00
if ( ! account . isOptionSet ( Account . OPTION_DISABLED ) ) {
2014-10-17 07:09:02 -04:00
if ( ! hasInternetConnection ( ) ) {
2014-11-15 11:09:02 -05:00
account . setStatus ( Account . State . NO_INTERNET ) ;
2014-03-19 11:16:40 -04:00
if ( statusListener ! = null ) {
2014-03-11 11:49:42 -04:00
statusListener . onStatusChanged ( account ) ;
}
2014-03-08 14:14:47 -05:00
} else {
2014-11-15 11:09:02 -05:00
if ( account . getStatus ( ) = = Account . State . NO_INTERNET ) {
account . setStatus ( Account . State . OFFLINE ) ;
2014-03-19 11:16:40 -04:00
if ( statusListener ! = null ) {
2014-03-11 11:49:42 -04:00
statusListener . onStatusChanged ( account ) ;
}
2014-03-11 10:44:22 -04:00
}
2014-11-15 11:09:02 -05:00
if ( account . getStatus ( ) = = Account . State . ONLINE ) {
2015-01-05 12:45:39 -05:00
long lastReceived = account . getXmppConnection ( ) . getLastPacketReceived ( ) ;
long lastSent = account . getXmppConnection ( ) . getLastPingSent ( ) ;
2016-08-09 13:21:54 -04:00
long pingInterval = ( Config . PUSH_MODE | | " ui " . equals ( action ) ) ? Config . PING_MIN_INTERVAL * 1000 : Config . PING_MAX_INTERVAL * 1000 ;
2015-10-16 03:58:31 -04:00
long msToNextPing = ( Math . max ( lastReceived , lastSent ) + pingInterval ) - SystemClock . elapsedRealtime ( ) ;
2016-10-20 12:02:11 -04:00
int pingTimeout = mLowPingTimeoutMode . contains ( account . getJid ( ) . toBareJid ( ) ) ? Config . LOW_PING_TIMEOUT * 1000 : Config . PING_TIMEOUT * 1000 ;
long pingTimeoutIn = ( lastSent + pingTimeout ) - SystemClock . elapsedRealtime ( ) ;
2015-05-24 22:49:36 -04:00
if ( lastSent > lastReceived ) {
if ( pingTimeoutIn < 0 ) {
2015-05-26 07:04:22 -04:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : ping timeout " ) ;
2015-09-29 13:24:52 -04:00
this . reconnectAccount ( account , true , interactive ) ;
2015-05-24 22:49:36 -04:00
} else {
int secs = ( int ) ( pingTimeoutIn / 1000 ) ;
2015-10-16 03:58:31 -04:00
this . scheduleWakeUpCall ( secs , account . getUuid ( ) . hashCode ( ) ) ;
2015-05-24 22:49:36 -04:00
}
2015-01-05 12:45:39 -05:00
} else {
2016-05-02 08:31:30 -04:00
pingCandidates . add ( account ) ;
2016-10-20 12:02:11 -04:00
if ( CryptoHelper . getAccountFingerprint ( account ) . equals ( pushedAccountHash ) ) {
pingNow = true ;
if ( mLowPingTimeoutMode . add ( account . getJid ( ) . toBareJid ( ) ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : entering low ping timeout mode " ) ;
}
} else if ( msToNextPing < = 0 ) {
2016-05-02 08:31:30 -04:00
pingNow = true ;
} else {
this . scheduleWakeUpCall ( ( int ) ( msToNextPing / 1000 ) , account . getUuid ( ) . hashCode ( ) ) ;
2016-10-20 14:04:16 -04:00
if ( mLowPingTimeoutMode . remove ( account . getJid ( ) . toBareJid ( ) ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : leaving low ping timeout mode " ) ;
}
2016-05-02 08:31:30 -04:00
}
2014-03-11 10:44:22 -04:00
}
2014-11-15 11:09:02 -05:00
} else if ( account . getStatus ( ) = = Account . State . OFFLINE ) {
2015-10-16 03:58:31 -04:00
reconnectAccount ( account , true , interactive ) ;
2015-01-25 14:52:53 -05:00
} else if ( account . getStatus ( ) = = Account . State . CONNECTING ) {
2015-12-15 13:14:38 -05:00
long secondsSinceLastConnect = ( SystemClock . elapsedRealtime ( ) - account . getXmppConnection ( ) . getLastConnect ( ) ) / 1000 ;
long secondsSinceLastDisco = ( SystemClock . elapsedRealtime ( ) - account . getXmppConnection ( ) . getLastDiscoStarted ( ) ) / 1000 ;
long discoTimeout = Config . CONNECT_DISCO_TIMEOUT - secondsSinceLastDisco ;
long timeout = Config . CONNECT_TIMEOUT - secondsSinceLastConnect ;
2015-01-25 14:52:53 -05:00
if ( timeout < 0 ) {
Log . d ( Config . LOGTAG , account . getJid ( ) + " : time out during connect reconnecting " ) ;
2016-05-12 15:57:07 -04:00
account . getXmppConnection ( ) . resetAttemptCount ( ) ;
2015-09-29 13:24:52 -04:00
reconnectAccount ( account , true , interactive ) ;
2015-12-15 13:14:38 -05:00
} else if ( discoTimeout < 0 ) {
account . getXmppConnection ( ) . sendDiscoTimeout ( ) ;
scheduleWakeUpCall ( ( int ) Math . min ( timeout , discoTimeout ) , account . getUuid ( ) . hashCode ( ) ) ;
2015-01-25 14:52:53 -05:00
} else {
2015-12-15 13:14:38 -05:00
scheduleWakeUpCall ( ( int ) Math . min ( timeout , discoTimeout ) , account . getUuid ( ) . hashCode ( ) ) ;
2015-01-25 14:52:53 -05:00
}
2014-03-11 10:44:22 -04:00
} else {
2014-05-18 05:25:04 -04:00
if ( account . getXmppConnection ( ) . getTimeToNextAttempt ( ) < = 0 ) {
2015-09-29 13:24:52 -04:00
reconnectAccount ( account , true , interactive ) ;
2014-05-18 05:25:04 -04:00
}
2014-03-08 14:14:47 -05:00
}
2014-03-11 10:44:22 -04:00
}
2014-07-12 07:42:17 -04:00
if ( mOnAccountUpdate ! = null ) {
mOnAccountUpdate . onAccountUpdate ( ) ;
2014-03-05 21:30:03 -05:00
}
2014-02-03 12:38:47 -05:00
}
}
2016-05-02 08:31:30 -04:00
if ( pingNow ) {
2016-08-09 13:21:54 -04:00
final boolean listeners = checkListeners ( ) ;
2016-05-02 08:31:30 -04:00
for ( Account account : pingCandidates ) {
2016-08-09 13:21:54 -04:00
if ( listeners
& & Config . PUSH_MODE
& & mPushManagementService . available ( account ) ) {
account . getXmppConnection ( ) . waitForPush ( ) ;
cancelWakeUpCall ( account . getUuid ( ) . hashCode ( ) ) ;
} else {
account . getXmppConnection ( ) . sendPing ( ) ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " send ping (action= " + action + " ,listeners= " + Boolean . toString ( listeners ) + " ) " ) ;
scheduleWakeUpCall ( Config . PING_TIMEOUT , account . getUuid ( ) . hashCode ( ) ) ;
}
2016-05-02 08:31:30 -04:00
}
}
2014-03-23 09:15:14 -04:00
if ( wakeLock . isHeld ( ) ) {
2014-07-11 07:52:27 -04:00
try {
wakeLock . release ( ) ;
2014-11-05 15:55:47 -05:00
} catch ( final RuntimeException ignored ) {
2014-07-11 07:52:27 -04:00
}
2014-03-23 09:15:14 -04:00
}
2014-02-03 12:38:47 -05:00
return START_STICKY ;
}
2014-10-20 15:08:33 -04:00
2016-08-27 07:35:52 -04:00
public boolean isDataSaverDisabled ( ) {
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . N ) {
ConnectivityManager connectivityManager = ( ConnectivityManager ) getSystemService ( CONNECTIVITY_SERVICE ) ;
return ! connectivityManager . isActiveNetworkMetered ( )
| | connectivityManager . getRestrictBackgroundStatus ( ) = = ConnectivityManager . RESTRICT_BACKGROUND_STATUS_DISABLED ;
} else {
return true ;
}
}
2016-09-19 15:35:54 -04:00
private void directReply ( Conversation conversation , String body , final boolean dismissAfterReply ) {
2016-08-25 11:30:44 -04:00
Message message = new Message ( conversation , body , conversation . getNextEncryption ( ) ) ;
2016-08-25 16:41:33 -04:00
message . markUnread ( ) ;
2016-08-25 11:30:44 -04:00
if ( message . getEncryption ( ) = = Message . ENCRYPTION_PGP ) {
getPgpEngine ( ) . encrypt ( message , new UiCallback < Message > ( ) {
@Override
public void success ( Message message ) {
message . setEncryption ( Message . ENCRYPTION_DECRYPTED ) ;
sendMessage ( message ) ;
2016-09-19 15:35:54 -04:00
if ( dismissAfterReply ) {
markRead ( message . getConversation ( ) , true ) ;
} else {
mNotificationService . pushFromDirectReply ( message ) ;
}
2016-08-25 11:30:44 -04:00
}
@Override
public void error ( int errorCode , Message object ) {
}
@Override
public void userInputRequried ( PendingIntent pi , Message object ) {
}
} ) ;
} else {
sendMessage ( message ) ;
2016-09-19 15:35:54 -04:00
if ( dismissAfterReply ) {
markRead ( conversation , true ) ;
} else {
mNotificationService . pushFromDirectReply ( message ) ;
}
2016-08-25 11:30:44 -04:00
}
}
2015-10-07 18:35:04 -04:00
private boolean xaOnSilentMode ( ) {
return getPreferences ( ) . getBoolean ( " xa_on_silent_mode " , false ) ;
}
2016-04-22 15:25:06 -04:00
private boolean manuallyChangePresence ( ) {
return getPreferences ( ) . getBoolean ( " manually_change_presence " , false ) ;
}
2016-03-01 13:00:18 -05:00
private boolean treatVibrateAsSilent ( ) {
return getPreferences ( ) . getBoolean ( " treat_vibrate_as_silent " , false ) ;
}
2015-10-07 18:35:04 -04:00
private boolean awayWhenScreenOff ( ) {
return getPreferences ( ) . getBoolean ( " away_when_screen_off " , false ) ;
}
2016-01-09 10:17:39 -05:00
private String getCompressPicturesPreference ( ) {
return getPreferences ( ) . getString ( " picture_compression " , " auto " ) ;
}
2016-01-17 16:28:38 -05:00
private Presence . Status getTargetPresence ( ) {
2015-10-07 18:35:04 -04:00
if ( xaOnSilentMode ( ) & & isPhoneSilenced ( ) ) {
2016-01-17 16:28:38 -05:00
return Presence . Status . XA ;
2015-10-07 18:35:04 -04:00
} else if ( awayWhenScreenOff ( ) & & ! isInteractive ( ) ) {
2016-01-17 16:28:38 -05:00
return Presence . Status . AWAY ;
2015-10-07 18:35:04 -04:00
} else {
2016-01-17 16:28:38 -05:00
return Presence . Status . ONLINE ;
2015-10-07 18:35:04 -04:00
}
}
@SuppressLint ( " NewApi " )
@SuppressWarnings ( " deprecation " )
public boolean isInteractive ( ) {
final PowerManager pm = ( PowerManager ) getSystemService ( Context . POWER_SERVICE ) ;
final boolean isScreenOn ;
if ( Build . VERSION . SDK_INT < Build . VERSION_CODES . LOLLIPOP ) {
isScreenOn = pm . isScreenOn ( ) ;
} else {
isScreenOn = pm . isInteractive ( ) ;
}
return isScreenOn ;
}
private boolean isPhoneSilenced ( ) {
AudioManager audioManager = ( AudioManager ) getSystemService ( Context . AUDIO_SERVICE ) ;
2016-08-02 04:58:31 -04:00
try {
if ( treatVibrateAsSilent ( ) ) {
return audioManager . getRingerMode ( ) ! = AudioManager . RINGER_MODE_NORMAL ;
} else {
return audioManager . getRingerMode ( ) = = AudioManager . RINGER_MODE_SILENT ;
}
} catch ( Throwable throwable ) {
Log . d ( Config . LOGTAG , " platform bug in isPhoneSilenced ( " + throwable . getMessage ( ) + " ) " ) ;
return false ;
2016-03-01 13:00:18 -05:00
}
2015-10-07 18:35:04 -04:00
}
2015-05-08 00:50:28 -04:00
private void resetAllAttemptCounts ( boolean reallyAll ) {
2016-03-22 05:54:45 -04:00
Log . d ( Config . LOGTAG , " resetting all attempt counts " ) ;
2015-10-16 03:58:31 -04:00
for ( Account account : accounts ) {
2015-05-08 00:50:28 -04:00
if ( account . hasErrorStatus ( ) | | reallyAll ) {
final XmppConnection connection = account . getXmppConnection ( ) ;
if ( connection ! = null ) {
connection . resetAttemptCount ( ) ;
}
}
2016-10-04 05:16:59 -04:00
if ( account . setShowErrorNotification ( true ) ) {
databaseBackend . updateAccount ( account ) ;
}
}
2016-10-06 16:05:40 -04:00
mNotificationService . updateErrorNotification ( ) ;
2016-10-04 05:16:59 -04:00
}
private void dismissErrorNotifications ( ) {
for ( final Account account : this . accounts ) {
if ( account . hasErrorStatus ( ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : dismissing error notification " ) ;
if ( account . setShowErrorNotification ( false ) ) {
databaseBackend . updateAccount ( account ) ;
}
}
2015-05-08 00:50:28 -04:00
}
}
2014-10-17 07:09:02 -04:00
public boolean hasInternetConnection ( ) {
ConnectivityManager cm = ( ConnectivityManager ) getApplicationContext ( )
2015-10-16 03:58:31 -04:00
. getSystemService ( Context . CONNECTIVITY_SERVICE ) ;
2014-10-17 07:09:02 -04:00
NetworkInfo activeNetwork = cm . getActiveNetworkInfo ( ) ;
return activeNetwork ! = null & & activeNetwork . isConnected ( ) ;
}
2014-02-03 12:38:47 -05:00
2014-06-20 11:30:19 -04:00
@SuppressLint ( " TrulyRandom " )
2014-02-03 12:38:47 -05:00
@Override
public void onCreate ( ) {
2014-03-09 08:21:28 -04:00
ExceptionHelper . init ( getApplicationContext ( ) ) ;
2014-06-20 11:30:19 -04:00
PRNGFixes . apply ( ) ;
this . mRandom = new SecureRandom ( ) ;
2015-04-02 07:35:42 -04:00
updateMemorizingTrustmanager ( ) ;
2014-12-20 20:13:13 -05:00
final int maxMemory = ( int ) ( Runtime . getRuntime ( ) . maxMemory ( ) / 1024 ) ;
final int cacheSize = maxMemory / 8 ;
2014-10-21 08:57:16 -04:00
this . mBitmapCache = new LruCache < String , Bitmap > ( cacheSize ) {
@Override
2014-12-20 20:13:13 -05:00
protected int sizeOf ( final String key , final Bitmap bitmap ) {
2014-10-21 08:57:16 -04:00
return bitmap . getByteCount ( ) / 1024 ;
}
} ;
2014-11-17 21:10:59 -05:00
this . databaseBackend = DatabaseBackend . getInstance ( getApplicationContext ( ) ) ;
2014-02-03 12:38:47 -05:00
this . accounts = databaseBackend . getAccounts ( ) ;
2014-02-11 17:55:03 -05:00
2015-02-17 05:51:11 -05:00
restoreFromDatabase ( ) ;
2014-05-01 16:33:49 -04:00
2014-11-17 21:10:59 -05:00
getContentResolver ( ) . registerContentObserver ( ContactsContract . Contacts . CONTENT_URI , true , contactObserver ) ;
2016-08-13 06:40:48 -04:00
new Thread ( new Runnable ( ) {
@Override
public void run ( ) {
fileObserver . startWatching ( ) ;
}
} ) . start ( ) ;
2016-02-24 08:47:49 -05:00
if ( Config . supportOpenPgp ( ) ) {
this . pgpServiceConnection = new OpenPgpServiceConnection ( getApplicationContext ( ) , " org.sufficientlysecure.keychain " , new OpenPgpServiceConnection . OnBound ( ) {
@Override
public void onBound ( IOpenPgpService2 service ) {
for ( Account account : accounts ) {
2016-06-13 07:32:14 -04:00
final PgpDecryptionService pgp = account . getPgpDecryptionService ( ) ;
if ( pgp ! = null ) {
pgp . continueDecryption ( true ) ;
2016-02-24 08:47:49 -05:00
}
2015-10-15 18:21:47 -04:00
}
}
2016-02-24 08:47:49 -05:00
@Override
public void onError ( Exception e ) {
}
} ) ;
this . pgpServiceConnection . bindToService ( ) ;
}
2014-03-11 10:44:22 -04:00
2014-04-03 04:41:21 -04:00
this . pm = ( PowerManager ) getSystemService ( Context . POWER_SERVICE ) ;
2015-10-16 03:58:31 -04:00
this . wakeLock = pm . newWakeLock ( PowerManager . PARTIAL_WAKE_LOCK , " XmppConnectionService " ) ;
2014-11-12 08:41:43 -05:00
toggleForegroundService ( ) ;
2015-07-03 16:08:23 -04:00
updateUnreadCountBadge ( ) ;
2015-10-07 18:35:04 -04:00
toggleScreenEventReceiver ( ) ;
2016-08-27 06:15:25 -04:00
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . M & & ! Config . PUSH_MODE ) {
2016-05-28 10:07:16 -04:00
scheduleNextIdlePing ( ) ;
}
2016-08-27 06:15:25 -04:00
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . N ) {
registerReceiver ( this . mEventReceiver , new IntentFilter ( ConnectivityManager . CONNECTIVITY_ACTION ) ) ;
}
2015-10-07 18:35:04 -04:00
}
2015-10-14 16:55:59 -04:00
@Override
public void onTrimMemory ( int level ) {
super . onTrimMemory ( level ) ;
if ( level > = TRIM_MEMORY_COMPLETE ) {
2015-10-16 03:58:31 -04:00
Log . d ( Config . LOGTAG , " clear cache due to low memory " ) ;
2015-10-14 16:55:59 -04:00
getBitmapCache ( ) . evictAll ( ) ;
}
}
2015-10-07 18:35:04 -04:00
@Override
public void onDestroy ( ) {
2015-10-07 18:52:04 -04:00
try {
unregisterReceiver ( this . mEventReceiver ) ;
} catch ( IllegalArgumentException e ) {
//ignored
}
2016-07-23 10:12:45 -04:00
fileObserver . stopWatching ( ) ;
2015-10-07 18:35:04 -04:00
super . onDestroy ( ) ;
}
public void toggleScreenEventReceiver ( ) {
2016-04-22 15:25:06 -04:00
if ( awayWhenScreenOff ( ) & & ! manuallyChangePresence ( ) ) {
2015-10-07 18:35:04 -04:00
final IntentFilter filter = new IntentFilter ( Intent . ACTION_SCREEN_ON ) ;
filter . addAction ( Intent . ACTION_SCREEN_OFF ) ;
registerReceiver ( this . mEventReceiver , filter ) ;
} else {
2015-10-07 18:52:04 -04:00
try {
unregisterReceiver ( this . mEventReceiver ) ;
} catch ( IllegalArgumentException e ) {
//ignored
}
2015-10-07 18:35:04 -04:00
}
2014-02-03 12:38:47 -05:00
}
2014-02-05 16:33:39 -05:00
2014-11-12 08:41:43 -05:00
public void toggleForegroundService ( ) {
2015-10-07 18:52:04 -04:00
if ( getPreferences ( ) . getBoolean ( " keep_foreground_service " , false ) ) {
2014-11-12 08:41:43 -05:00
startForeground ( NotificationService . FOREGROUND_NOTIFICATION_ID , this . mNotificationService . createForegroundNotification ( ) ) ;
} else {
stopForeground ( true ) ;
}
2014-05-19 15:05:17 -04:00
}
2014-05-22 03:36:00 -04:00
2014-05-19 15:05:17 -04:00
@Override
2014-12-20 20:13:13 -05:00
public void onTaskRemoved ( final Intent rootIntent ) {
2014-05-19 15:05:17 -04:00
super . onTaskRemoved ( rootIntent ) ;
2015-10-16 03:58:31 -04:00
if ( ! getPreferences ( ) . getBoolean ( " keep_foreground_service " , false ) ) {
2016-04-14 15:45:36 -04:00
this . logoutAndSave ( false ) ;
2016-07-31 16:32:10 -04:00
} else {
Log . d ( Config . LOGTAG , " ignoring onTaskRemoved because foreground service is activated " ) ;
2014-11-12 08:41:43 -05:00
}
2014-05-19 15:05:17 -04:00
}
2014-05-22 03:36:00 -04:00
2016-04-14 15:45:36 -04:00
private void logoutAndSave ( boolean stop ) {
int activeAccounts = 0 ;
2014-12-20 20:13:13 -05:00
for ( final Account account : accounts ) {
2016-04-14 15:45:36 -04:00
if ( account . getStatus ( ) ! = Account . State . DISABLED ) {
activeAccounts + + ;
}
2014-05-19 09:15:09 -04:00
databaseBackend . writeRoster ( account . getRoster ( ) ) ;
2014-02-13 17:40:08 -05:00
if ( account . getXmppConnection ( ) ! = null ) {
2015-10-17 10:10:56 -04:00
new Thread ( new Runnable ( ) {
@Override
public void run ( ) {
disconnect ( account , false ) ;
}
} ) . start ( ) ;
2014-02-13 17:40:08 -05:00
}
}
2016-04-14 15:45:36 -04:00
if ( stop | | activeAccounts = = 0 ) {
Log . d ( Config . LOGTAG , " good bye " ) ;
stopSelf ( ) ;
}
2014-02-13 17:40:08 -05:00
}
2014-03-11 10:44:22 -04:00
2016-02-14 07:20:23 -05:00
private void cancelWakeUpCall ( int requestCode ) {
final AlarmManager alarmManager = ( AlarmManager ) getSystemService ( Context . ALARM_SERVICE ) ;
final Intent intent = new Intent ( this , EventReceiver . class ) ;
intent . setAction ( " ping " ) ;
alarmManager . cancel ( PendingIntent . getBroadcast ( this , requestCode , intent , 0 ) ) ;
}
2015-12-15 13:14:38 -05:00
public void scheduleWakeUpCall ( int seconds , int requestCode ) {
2015-05-24 22:49:36 -04:00
final long timeToWake = SystemClock . elapsedRealtime ( ) + ( seconds < 0 ? 1 : seconds + 1 ) * 1000 ;
2016-05-28 08:44:22 -04:00
AlarmManager alarmManager = ( AlarmManager ) getSystemService ( Context . ALARM_SERVICE ) ;
Intent intent = new Intent ( this , EventReceiver . class ) ;
2015-01-05 12:45:39 -05:00
intent . setAction ( " ping " ) ;
2016-05-28 08:44:22 -04:00
PendingIntent alarmIntent = PendingIntent . getBroadcast ( this , requestCode , intent , 0 ) ;
2015-01-05 12:45:39 -05:00
alarmManager . set ( AlarmManager . ELAPSED_REALTIME_WAKEUP , timeToWake , alarmIntent ) ;
2014-03-05 21:30:03 -05:00
}
2014-02-13 17:40:08 -05:00
2016-05-28 08:44:22 -04:00
@TargetApi ( Build . VERSION_CODES . M )
private void scheduleNextIdlePing ( ) {
2016-05-28 10:07:16 -04:00
Log . d ( Config . LOGTAG , " schedule next idle ping " ) ;
2016-05-28 08:44:22 -04:00
AlarmManager alarmManager = ( AlarmManager ) getSystemService ( Context . ALARM_SERVICE ) ;
Intent intent = new Intent ( this , EventReceiver . class ) ;
intent . setAction ( ACTION_IDLE_PING ) ;
alarmManager . setAndAllowWhileIdle ( AlarmManager . ELAPSED_REALTIME_WAKEUP ,
SystemClock . elapsedRealtime ( ) + ( Config . IDLE_PING_INTERVAL * 1000 ) ,
PendingIntent . getBroadcast ( this , 0 , intent , 0 )
) ;
}
2014-12-21 15:43:58 -05:00
public XmppConnection createConnection ( final Account account ) {
final SharedPreferences sharedPref = getPreferences ( ) ;
2016-10-17 03:53:08 -04:00
String resource ;
try {
resource = sharedPref . getString ( " resource " , getString ( R . string . default_resource ) ) . toLowerCase ( Locale . ENGLISH ) ;
if ( resource . trim ( ) . isEmpty ( ) ) {
throw new Exception ( ) ;
}
} catch ( Exception e ) {
resource = " conversations " ;
}
account . setResource ( resource ) ;
2014-12-21 15:43:58 -05:00
final XmppConnection connection = new XmppConnection ( account , this ) ;
2014-07-11 20:36:37 -04:00
connection . setOnMessagePacketReceivedListener ( this . mMessageParser ) ;
2014-02-05 16:33:39 -05:00
connection . setOnStatusChangedListener ( this . statusListener ) ;
2014-07-11 20:36:37 -04:00
connection . setOnPresencePacketReceivedListener ( this . mPresenceParser ) ;
2014-08-26 10:52:42 -04:00
connection . setOnUnregisteredIqPacketReceivedListener ( this . mIqParser ) ;
2014-03-26 21:02:59 -04:00
connection . setOnJinglePacketReceivedListener ( this . jingleListener ) ;
2014-07-18 15:57:10 -04:00
connection . setOnBindListener ( this . mOnBindListener ) ;
2014-12-04 19:54:16 -05:00
connection . setOnMessageAcknowledgeListener ( this . mOnMessageAcknowledgedListener ) ;
2014-12-08 15:59:14 -05:00
connection . addOnAdvancedStreamFeaturesAvailableListener ( this . mMessageArchiveService ) ;
2016-04-11 16:20:32 -04:00
connection . addOnAdvancedStreamFeaturesAvailableListener ( this . mAvatarService ) ;
2015-10-16 17:48:42 -04:00
AxolotlService axolotlService = account . getAxolotlService ( ) ;
if ( axolotlService ! = null ) {
connection . addOnAdvancedStreamFeaturesAvailableListener ( axolotlService ) ;
}
2014-02-04 09:09:50 -05:00
return connection ;
}
2014-02-18 19:35:23 -05:00
2015-02-21 05:06:52 -05:00
public void sendChatState ( Conversation conversation ) {
if ( sendChatStates ( ) ) {
MessagePacket packet = mMessageGenerator . generateChatState ( conversation ) ;
sendMessagePacket ( conversation . getAccount ( ) , packet ) ;
}
}
2015-07-20 12:11:33 -04:00
private void sendFileMessage ( final Message message , final boolean delay ) {
2015-06-28 05:19:07 -04:00
Log . d ( Config . LOGTAG , " send file message " ) ;
final Account account = message . getConversation ( ) . getAccount ( ) ;
2016-03-31 18:03:14 -04:00
if ( account . httpUploadAvailable ( fileBackend . getFile ( message , false ) . getSize ( ) ) ) {
2015-07-20 12:11:33 -04:00
mHttpConnectionManager . createNewUploadConnection ( message , delay ) ;
2015-06-28 05:19:07 -04:00
} else {
mJingleConnectionManager . createNewConnection ( message ) ;
}
}
2014-12-21 15:43:58 -05:00
public void sendMessage ( final Message message ) {
2015-07-20 12:11:33 -04:00
sendMessage ( message , false , false ) ;
2015-07-05 05:59:38 -04:00
}
2015-07-20 12:11:33 -04:00
private void sendMessage ( final Message message , final boolean resend , final boolean delay ) {
2014-12-21 15:43:58 -05:00
final Account account = message . getConversation ( ) . getAccount ( ) ;
2016-10-04 05:16:59 -04:00
if ( account . setShowErrorNotification ( true ) ) {
databaseBackend . updateAccount ( account ) ;
mNotificationService . updateErrorNotification ( ) ;
}
2015-07-05 05:59:38 -04:00
final Conversation conversation = message . getConversation ( ) ;
2014-10-17 05:01:38 -04:00
account . deactivateGracePeriod ( ) ;
2014-04-11 03:13:56 -04:00
MessagePacket packet = null ;
2016-02-15 17:15:04 -05:00
final boolean addToConversation = ( conversation . getMode ( ) ! = Conversation . MODE_MULTI
| | account . getServerIdentity ( ) ! = XmppConnection . Identity . SLACK )
& & ! message . edited ( ) ;
2015-11-01 08:50:06 -05:00
boolean saveInDb = addToConversation ;
2015-07-05 05:59:38 -04:00
message . setStatus ( Message . STATUS_WAITING ) ;
if ( ! resend & & message . getEncryption ( ) ! = Message . ENCRYPTION_OTR ) {
message . getConversation ( ) . endOtrIfNeeded ( ) ;
2015-06-29 08:22:26 -04:00
message . getConversation ( ) . findUnsentMessagesWithEncryption ( Message . ENCRYPTION_OTR ,
new Conversation . OnMessageFound ( ) {
2015-10-16 03:58:31 -04:00
@Override
public void onMessageFound ( Message message ) {
markMessage ( message , Message . STATUS_SEND_FAILED ) ;
}
} ) ;
2015-07-05 05:59:38 -04:00
}
if ( account . isOnlineAndConnected ( ) ) {
switch ( message . getEncryption ( ) ) {
case Message . ENCRYPTION_NONE :
if ( message . needsUploading ( ) ) {
2016-03-31 18:03:14 -04:00
if ( account . httpUploadAvailable ( fileBackend . getFile ( message , false ) . getSize ( ) )
| | message . fixCounterpart ( ) ) {
2015-10-16 03:58:31 -04:00
this . sendFileMessage ( message , delay ) ;
2015-07-05 05:59:38 -04:00
} else {
break ;
2015-06-28 05:19:07 -04:00
}
2014-06-22 07:57:57 -04:00
} else {
2015-07-20 12:11:33 -04:00
packet = mMessageGenerator . generateChat ( message ) ;
2014-10-29 19:31:44 -04:00
}
2015-07-05 05:59:38 -04:00
break ;
case Message . ENCRYPTION_PGP :
case Message . ENCRYPTION_DECRYPTED :
if ( message . needsUploading ( ) ) {
2016-03-31 18:03:14 -04:00
if ( account . httpUploadAvailable ( fileBackend . getFile ( message , false ) . getSize ( ) )
| | message . fixCounterpart ( ) ) {
2015-10-16 03:58:31 -04:00
this . sendFileMessage ( message , delay ) ;
2014-11-09 11:46:00 -05:00
} else {
2015-07-05 05:59:38 -04:00
break ;
2014-11-09 11:46:00 -05:00
}
} else {
2015-07-20 12:11:33 -04:00
packet = mMessageGenerator . generatePgpChat ( message ) ;
2014-04-07 14:05:45 -04:00
}
2015-07-05 05:59:38 -04:00
break ;
case Message . ENCRYPTION_OTR :
SessionImpl otrSession = conversation . getOtrSession ( ) ;
if ( otrSession ! = null & & otrSession . getSessionStatus ( ) = = SessionStatus . ENCRYPTED ) {
try {
message . setCounterpart ( Jid . fromSessionID ( otrSession . getSessionID ( ) ) ) ;
} catch ( InvalidJidException e ) {
break ;
2014-12-14 12:10:46 -05:00
}
2015-07-05 05:59:38 -04:00
if ( message . needsUploading ( ) ) {
mJingleConnectionManager . createNewConnection ( message ) ;
} else {
2015-07-20 12:11:33 -04:00
packet = mMessageGenerator . generateOtrChat ( message ) ;
2014-12-14 12:10:46 -05:00
}
2015-07-05 05:59:38 -04:00
} else if ( otrSession = = null ) {
if ( message . fixCounterpart ( ) ) {
conversation . startOtrSession ( message . getCounterpart ( ) . getResourcepart ( ) , true ) ;
} else {
2016-02-16 03:15:41 -05:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : could not fix counterpart for OTR message to contact " + message . getContact ( ) . getJid ( ) ) ;
2015-07-05 05:59:38 -04:00
break ;
}
2016-02-16 03:15:41 -05:00
} else {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " OTR session with " + message . getContact ( ) + " is in wrong state: " + otrSession . getSessionStatus ( ) . toString ( ) ) ;
2015-07-05 05:59:38 -04:00
}
break ;
2015-06-25 11:01:42 -04:00
case Message . ENCRYPTION_AXOLOTL :
2016-03-31 15:15:49 -04:00
message . setFingerprint ( account . getAxolotlService ( ) . getOwnFingerprint ( ) ) ;
2015-07-17 13:44:05 -04:00
if ( message . needsUploading ( ) ) {
2016-03-31 18:03:14 -04:00
if ( account . httpUploadAvailable ( fileBackend . getFile ( message , false ) . getSize ( ) )
| | message . fixCounterpart ( ) ) {
2015-10-16 03:58:31 -04:00
this . sendFileMessage ( message , delay ) ;
2015-07-17 13:44:05 -04:00
} else {
break ;
}
} else {
2015-07-20 17:13:28 -04:00
XmppAxolotlMessage axolotlMessage = account . getAxolotlService ( ) . fetchAxolotlMessageFromCache ( message ) ;
if ( axolotlMessage = = null ) {
2015-07-31 15:12:34 -04:00
account . getAxolotlService ( ) . preparePayloadMessage ( message , delay ) ;
2015-07-20 17:13:28 -04:00
} else {
packet = mMessageGenerator . generateAxolotlChat ( message , axolotlMessage ) ;
2015-07-17 13:44:05 -04:00
}
2015-07-03 07:31:14 -04:00
}
2015-06-25 11:01:42 -04:00
break ;
2015-07-05 05:59:38 -04:00
}
if ( packet ! = null ) {
2016-10-09 13:40:30 -04:00
if ( account . getXmppConnection ( ) . getFeatures ( ) . sm ( )
| | ( conversation . getMode ( ) = = Conversation . MODE_MULTI & & message . getCounterpart ( ) . isBareJid ( ) ) ) {
2015-07-05 05:59:38 -04:00
message . setStatus ( Message . STATUS_UNSEND ) ;
} else {
message . setStatus ( Message . STATUS_SEND ) ;
2014-02-11 17:55:03 -05:00
}
}
} else {
2015-10-16 03:58:31 -04:00
switch ( message . getEncryption ( ) ) {
2015-07-05 05:59:38 -04:00
case Message . ENCRYPTION_DECRYPTED :
if ( ! message . needsUploading ( ) ) {
String pgpBody = message . getEncryptedBody ( ) ;
String decryptedBody = message . getBody ( ) ;
message . setBody ( pgpBody ) ;
message . setEncryption ( Message . ENCRYPTION_PGP ) ;
2016-09-04 16:59:15 -04:00
if ( message . edited ( ) ) {
message . setBody ( decryptedBody ) ;
message . setEncryption ( Message . ENCRYPTION_DECRYPTED ) ;
databaseBackend . updateMessage ( message , message . getEditedId ( ) ) ;
updateConversationUi ( ) ;
return ;
} else {
databaseBackend . createMessage ( message ) ;
saveInDb = false ;
message . setBody ( decryptedBody ) ;
message . setEncryption ( Message . ENCRYPTION_DECRYPTED ) ;
}
2015-07-05 05:59:38 -04:00
}
break ;
case Message . ENCRYPTION_OTR :
if ( ! conversation . hasValidOtrSession ( ) & & message . getCounterpart ( ) ! = null ) {
2016-02-16 03:15:41 -05:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : create otr session without starting for " + message . getContact ( ) . getJid ( ) ) ;
2015-07-05 05:59:38 -04:00
conversation . startOtrSession ( message . getCounterpart ( ) . getResourcepart ( ) , false ) ;
}
break ;
2015-07-15 10:32:42 -04:00
case Message . ENCRYPTION_AXOLOTL :
2016-03-31 15:15:49 -04:00
message . setFingerprint ( account . getAxolotlService ( ) . getOwnFingerprint ( ) ) ;
2015-07-15 10:32:42 -04:00
break ;
2014-05-16 07:42:20 -04:00
}
2014-02-13 17:40:08 -05:00
}
2015-07-05 05:59:38 -04:00
if ( resend ) {
2015-11-01 08:50:06 -05:00
if ( packet ! = null & & addToConversation ) {
2016-10-09 13:40:30 -04:00
if ( account . getXmppConnection ( ) . getFeatures ( ) . sm ( )
| | ( conversation . getMode ( ) = = Conversation . MODE_MULTI & & message . getCounterpart ( ) . isBareJid ( ) ) ) {
2015-10-16 03:58:31 -04:00
markMessage ( message , Message . STATUS_UNSEND ) ;
2015-07-05 05:59:38 -04:00
} else {
2015-10-16 03:58:31 -04:00
markMessage ( message , Message . STATUS_SEND ) ;
2015-07-05 05:59:38 -04:00
}
}
} else {
2015-11-01 08:50:06 -05:00
if ( addToConversation ) {
conversation . add ( message ) ;
}
2016-02-15 17:15:04 -05:00
if ( message . getEncryption ( ) = = Message . ENCRYPTION_NONE | | saveEncryptedMessages ( ) ) {
if ( saveInDb ) {
databaseBackend . createMessage ( message ) ;
} else if ( message . edited ( ) ) {
databaseBackend . updateMessage ( message , message . getEditedId ( ) ) ;
}
2015-07-05 05:59:38 -04:00
}
updateConversationUi ( ) ;
2014-02-13 17:40:08 -05:00
}
2015-07-05 05:59:38 -04:00
if ( packet ! = null ) {
2015-07-20 12:11:33 -04:00
if ( delay ) {
2015-10-16 03:58:31 -04:00
mMessageGenerator . addDelay ( packet , message . getTimeSent ( ) ) ;
2015-07-20 12:11:33 -04:00
}
2015-07-05 05:59:38 -04:00
if ( conversation . setOutgoingChatState ( Config . DEFAULT_CHATSTATE ) ) {
2015-02-21 05:06:52 -05:00
if ( this . sendChatStates ( ) ) {
2015-07-05 05:59:38 -04:00
packet . addChild ( ChatState . toElement ( conversation . getOutgoingChatState ( ) ) ) ;
2015-02-21 05:06:52 -05:00
}
}
2014-07-11 21:44:23 -04:00
sendMessagePacket ( account , packet ) ;
2014-04-11 03:13:56 -04:00
}
2014-02-11 17:55:03 -05:00
}
2014-12-21 15:43:58 -05:00
private void sendUnsentMessages ( final Conversation conversation ) {
2014-12-14 12:10:46 -05:00
conversation . findWaitingMessages ( new Conversation . OnMessageFound ( ) {
@Override
public void onMessageFound ( Message message ) {
2015-07-20 17:13:28 -04:00
resendMessage ( message , true ) ;
2014-05-16 07:42:20 -04:00
}
2014-12-14 12:10:46 -05:00
} ) ;
2014-05-16 07:42:20 -04:00
}
2014-05-18 05:25:04 -04:00
2015-07-20 12:11:33 -04:00
public void resendMessage ( final Message message , final boolean delay ) {
sendMessage ( message , true , delay ) ;
2014-02-11 17:55:03 -05:00
}
2014-12-21 15:43:58 -05:00
public void fetchRosterFromServer ( final Account account ) {
2014-12-30 08:16:25 -05:00
final IqPacket iqPacket = new IqPacket ( IqPacket . TYPE . GET ) ;
2014-03-07 20:06:00 -05:00
if ( ! " " . equals ( account . getRosterVersion ( ) ) ) {
2014-11-09 10:57:22 -05:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( )
2014-08-31 10:28:21 -04:00
+ " : fetching roster version " + account . getRosterVersion ( ) ) ;
2014-03-07 20:06:00 -05:00
} else {
2014-11-09 10:57:22 -05:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : fetching roster " ) ;
2014-03-07 20:06:00 -05:00
}
2015-08-11 10:50:00 -04:00
iqPacket . query ( Xmlns . ROSTER ) . setAttribute ( " ver " , account . getRosterVersion ( ) ) ;
2015-08-13 12:25:10 -04:00
sendIqPacket ( account , iqPacket , mIqParser ) ;
2014-02-09 21:34:00 -05:00
}
2014-08-26 10:52:42 -04:00
2014-12-21 15:43:58 -05:00
public void fetchBookmarks ( final Account account ) {
2014-12-30 08:16:25 -05:00
final IqPacket iqPacket = new IqPacket ( IqPacket . TYPE . GET ) ;
2014-12-21 15:43:58 -05:00
final Element query = iqPacket . query ( " jabber:iq:private " ) ;
2014-07-14 05:47:42 -04:00
query . addChild ( " storage " , " storage:bookmarks " ) ;
2015-01-04 06:09:39 -05:00
final OnIqPacketReceived callback = new OnIqPacketReceived ( ) {
2014-08-26 10:52:42 -04:00
2014-07-14 05:47:42 -04:00
@Override
2014-12-21 15:43:58 -05:00
public void onIqPacketReceived ( final Account account , final IqPacket packet ) {
2015-08-23 02:27:05 -04:00
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
final Element query = packet . query ( ) ;
2015-12-27 11:29:32 -05:00
final HashMap < Jid , Bookmark > bookmarks = new HashMap < > ( ) ;
2015-08-23 02:27:05 -04:00
final Element storage = query . findChild ( " storage " , " storage:bookmarks " ) ;
2016-02-01 07:54:08 -05:00
final boolean autojoin = respectAutojoin ( ) ;
2015-08-23 02:27:05 -04:00
if ( storage ! = null ) {
for ( final Element item : storage . getChildren ( ) ) {
if ( item . getName ( ) . equals ( " conference " ) ) {
final Bookmark bookmark = Bookmark . parse ( item , account ) ;
2015-12-27 11:29:32 -05:00
Bookmark old = bookmarks . put ( bookmark . getJid ( ) , bookmark ) ;
if ( old ! = null & & old . getBookmarkName ( ) ! = null & & bookmark . getBookmarkName ( ) = = null ) {
bookmark . setBookmarkName ( old . getBookmarkName ( ) ) ;
}
2015-08-23 02:27:05 -04:00
Conversation conversation = find ( bookmark ) ;
if ( conversation ! = null ) {
conversation . setBookmark ( bookmark ) ;
2016-02-01 07:54:08 -05:00
} else if ( bookmark . autojoin ( ) & & bookmark . getJid ( ) ! = null & & autojoin ) {
2015-08-23 02:27:05 -04:00
conversation = findOrCreateConversation (
account , bookmark . getJid ( ) , true ) ;
conversation . setBookmark ( bookmark ) ;
joinMuc ( conversation ) ;
}
2014-07-14 05:47:42 -04:00
}
}
}
2015-12-27 11:29:32 -05:00
account . setBookmarks ( new ArrayList < > ( bookmarks . values ( ) ) ) ;
2015-08-23 02:27:05 -04:00
} else {
2015-10-16 03:58:31 -04:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : could not fetch bookmarks " ) ;
2014-07-14 05:47:42 -04:00
}
}
} ;
sendIqPacket ( account , iqPacket , callback ) ;
}
2014-08-26 10:52:42 -04:00
2014-07-15 08:32:19 -04:00
public void pushBookmarks ( Account account ) {
2015-12-11 13:28:44 -05:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : pushing bookmarks " ) ;
2014-12-30 08:16:25 -05:00
IqPacket iqPacket = new IqPacket ( IqPacket . TYPE . SET ) ;
2014-07-15 08:32:19 -04:00
Element query = iqPacket . query ( " jabber:iq:private " ) ;
Element storage = query . addChild ( " storage " , " storage:bookmarks " ) ;
2014-08-26 10:52:42 -04:00
for ( Bookmark bookmark : account . getBookmarks ( ) ) {
2014-10-05 18:33:52 -04:00
storage . addChild ( bookmark ) ;
2014-07-15 08:32:19 -04:00
}
2015-05-26 05:31:33 -04:00
sendIqPacket ( account , iqPacket , mDefaultIqHandler ) ;
2014-07-15 08:32:19 -04:00
}
2014-02-09 21:34:00 -05:00
2015-02-17 05:51:11 -05:00
private void restoreFromDatabase ( ) {
2014-11-17 21:10:59 -05:00
synchronized ( this . conversations ) {
2014-12-21 15:43:58 -05:00
final Map < String , Account > accountLookupTable = new Hashtable < > ( ) ;
2014-02-03 12:38:47 -05:00
for ( Account account : this . accounts ) {
accountLookupTable . put ( account . getUuid ( ) , account ) ;
}
2014-11-17 21:10:59 -05:00
this . conversations . addAll ( databaseBackend . getConversations ( Conversation . STATUS_AVAILABLE ) ) ;
2014-12-15 17:06:29 -05:00
for ( Conversation conversation : this . conversations ) {
Account account = accountLookupTable . get ( conversation . getAccountUuid ( ) ) ;
conversation . setAccount ( account ) ;
2014-02-03 12:38:47 -05:00
}
2015-10-16 03:58:31 -04:00
Runnable runnable = new Runnable ( ) {
2015-02-12 12:53:00 -05:00
@Override
public void run ( ) {
2015-10-16 03:58:31 -04:00
Log . d ( Config . LOGTAG , " restoring roster " ) ;
for ( Account account : accounts ) {
2015-10-16 17:48:42 -04:00
databaseBackend . readRoster ( account . getRoster ( ) ) ;
2015-10-30 07:05:21 -04:00
account . initAccountServices ( XmppConnectionService . this ) ; //roster needs to be loaded at this stage
2015-02-17 05:51:11 -05:00
}
getBitmapCache ( ) . evictAll ( ) ;
2015-12-06 18:33:50 -05:00
loadPhoneContacts ( ) ;
2015-10-16 03:58:31 -04:00
Log . d ( Config . LOGTAG , " restoring messages " ) ;
2015-02-12 12:53:00 -05:00
for ( Conversation conversation : conversations ) {
conversation . addAll ( 0 , databaseBackend . getMessages ( conversation , Config . PAGE_SIZE ) ) ;
checkDeletedFiles ( conversation ) ;
2016-10-07 08:54:35 -04:00
conversation . findUnsentTextMessages ( new Conversation . OnMessageFound ( ) {
@Override
public void onMessageFound ( Message message ) {
markMessage ( message , Message . STATUS_WAITING ) ;
}
} ) ;
2015-10-14 15:18:34 -04:00
conversation . findUnreadMessages ( new Conversation . OnMessageFound ( ) {
@Override
public void onMessageFound ( Message message ) {
mNotificationService . pushFromBacklog ( message ) ;
}
} ) ;
2015-02-12 12:53:00 -05:00
}
2015-12-10 17:05:11 -05:00
mNotificationService . finishBacklog ( false ) ;
2015-02-17 05:51:11 -05:00
mRestoredFromDatabase = true ;
2015-10-16 03:58:31 -04:00
Log . d ( Config . LOGTAG , " restored all messages " ) ;
2015-02-12 12:53:00 -05:00
updateConversationUi ( ) ;
}
2015-06-05 02:46:06 -04:00
} ;
mDatabaseExecutor . execute ( runnable ) ;
2014-02-03 12:38:47 -05:00
}
2014-11-17 21:10:59 -05:00
}
2015-12-06 18:33:50 -05:00
public void loadPhoneContacts ( ) {
2016-05-31 11:20:21 -04:00
mContactMergerExecutor . execute ( new Runnable ( ) {
@Override
public void run ( ) {
PhoneHelper . loadPhoneContacts ( XmppConnectionService . this , new OnPhoneContactsLoadedListener ( ) {
@Override
public void onPhoneContactsLoaded ( List < Bundle > phoneContacts ) {
Log . d ( Config . LOGTAG , " start merging phone contacts with roster " ) ;
for ( Account account : accounts ) {
List < Contact > withSystemAccounts = account . getRoster ( ) . getWithSystemAccounts ( ) ;
for ( Bundle phoneContact : phoneContacts ) {
Jid jid ;
try {
jid = Jid . fromString ( phoneContact . getString ( " jid " ) ) ;
} catch ( final InvalidJidException e ) {
continue ;
}
final Contact contact = account . getRoster ( ) . getContact ( jid ) ;
String systemAccount = phoneContact . getInt ( " phoneid " )
+ " # "
+ phoneContact . getString ( " lookup " ) ;
contact . setSystemAccount ( systemAccount ) ;
if ( contact . setPhotoUri ( phoneContact . getString ( " photouri " ) ) ) {
getAvatarService ( ) . clear ( contact ) ;
}
contact . setSystemName ( phoneContact . getString ( " displayname " ) ) ;
withSystemAccounts . remove ( contact ) ;
}
for ( Contact contact : withSystemAccounts ) {
contact . setSystemAccount ( null ) ;
contact . setSystemName ( null ) ;
if ( contact . setPhotoUri ( null ) ) {
getAvatarService ( ) . clear ( contact ) ;
}
}
}
Log . d ( Config . LOGTAG , " finished merging phone contacts " ) ;
updateAccountUi ( ) ;
}
} ) ;
}
} ) ;
2015-12-06 18:33:50 -05:00
}
2014-11-17 21:10:59 -05:00
public List < Conversation > getConversations ( ) {
2014-07-12 06:41:37 -04:00
return this . conversations ;
}
2014-10-20 15:08:33 -04:00
2014-10-15 16:08:13 -04:00
private void checkDeletedFiles ( Conversation conversation ) {
2014-12-14 12:10:46 -05:00
conversation . findMessagesWithFiles ( new Conversation . OnMessageFound ( ) {
@Override
public void onMessageFound ( Message message ) {
2014-10-15 16:08:13 -04:00
if ( ! getFileBackend ( ) . isFileAvailable ( message ) ) {
2015-07-10 09:11:03 -04:00
message . setTransferable ( new TransferablePlaceholder ( Transferable . STATUS_DELETED ) ) ;
2015-08-11 10:50:00 -04:00
final int s = message . getStatus ( ) ;
2015-10-16 03:58:31 -04:00
if ( s = = Message . STATUS_WAITING | | s = = Message . STATUS_OFFERED | | s = = Message . STATUS_UNSEND ) {
markMessage ( message , Message . STATUS_SEND_FAILED ) ;
2015-08-11 10:50:00 -04:00
}
2014-10-15 16:08:13 -04:00
}
2014-12-14 12:10:46 -05:00
}
} ) ;
2014-10-15 16:08:13 -04:00
}
2014-10-20 15:08:33 -04:00
2016-07-23 10:12:45 -04:00
private void markFileDeleted ( final String path ) {
2016-07-26 14:43:05 -04:00
Log . d ( Config . LOGTAG , " deleted file " + path ) ;
2014-10-20 15:08:33 -04:00
for ( Conversation conversation : getConversations ( ) ) {
2016-07-23 10:12:45 -04:00
conversation . findMessagesWithFiles ( new Conversation . OnMessageFound ( ) {
@Override
public void onMessageFound ( Message message ) {
DownloadableFile file = fileBackend . getFile ( message ) ;
2016-07-26 14:43:05 -04:00
if ( file . getAbsolutePath ( ) . equals ( path ) ) {
2016-07-26 14:44:28 -04:00
if ( ! file . exists ( ) ) {
2016-07-26 14:43:05 -04:00
message . setTransferable ( new TransferablePlaceholder ( Transferable . STATUS_DELETED ) ) ;
final int s = message . getStatus ( ) ;
if ( s = = Message . STATUS_WAITING | | s = = Message . STATUS_OFFERED | | s = = Message . STATUS_UNSEND ) {
markMessage ( message , Message . STATUS_SEND_FAILED ) ;
} else {
updateConversationUi ( ) ;
}
2016-07-23 10:12:45 -04:00
} else {
2016-07-26 14:43:05 -04:00
Log . d ( Config . LOGTAG , " found matching message for file " + path + " but file still exists " ) ;
2016-07-23 10:12:45 -04:00
}
2015-08-11 10:50:00 -04:00
}
2014-12-14 12:10:46 -05:00
}
2016-07-23 10:12:45 -04:00
} ) ;
2014-10-15 20:39:02 -04:00
}
}
2014-09-05 07:29:20 -04:00
2014-11-17 21:10:59 -05:00
public void populateWithOrderedConversations ( final List < Conversation > list ) {
2014-09-05 07:29:20 -04:00
populateWithOrderedConversations ( list , true ) ;
2014-09-02 09:51:20 -04:00
}
2015-07-02 17:51:59 -04:00
public void populateWithOrderedConversations ( final List < Conversation > list , boolean includeNoFileUpload ) {
2014-07-12 06:41:37 -04:00
list . clear ( ) ;
2015-07-02 17:51:59 -04:00
if ( includeNoFileUpload ) {
2014-09-02 09:51:20 -04:00
list . addAll ( getConversations ( ) ) ;
} else {
2014-09-05 07:29:20 -04:00
for ( Conversation conversation : getConversations ( ) ) {
2015-07-02 17:51:59 -04:00
if ( conversation . getMode ( ) = = Conversation . MODE_SINGLE
| | conversation . getAccount ( ) . httpUploadAvailable ( ) ) {
2014-09-02 09:51:20 -04:00
list . add ( conversation ) ;
}
}
}
2016-06-09 08:50:13 -04:00
try {
Collections . sort ( list ) ;
} catch ( IllegalArgumentException e ) {
//ignore
}
2014-02-03 12:38:47 -05:00
}
2014-09-27 05:37:02 -04:00
2014-12-17 03:32:51 -05:00
public void loadMoreMessages ( final Conversation conversation , final long timestamp , final OnMoreMessagesLoaded callback ) {
2015-10-16 03:58:31 -04:00
if ( XmppConnectionService . this . getMessageArchiveService ( ) . queryInProgress ( conversation , callback ) ) {
2014-12-17 04:50:51 -05:00
return ;
2016-02-04 08:39:16 -05:00
} else if ( timestamp = = 0 ) {
return ;
2014-12-17 04:50:51 -05:00
}
2015-10-04 18:45:16 -04:00
Log . d ( Config . LOGTAG , " load more messages for " + conversation . getName ( ) + " prior to " + MessageGenerator . getTimestamp ( timestamp ) ) ;
2015-06-05 02:46:06 -04:00
Runnable runnable = new Runnable ( ) {
2014-12-17 03:32:51 -05:00
@Override
public void run ( ) {
final Account account = conversation . getAccount ( ) ;
2015-10-16 03:58:31 -04:00
List < Message > messages = databaseBackend . getMessages ( conversation , 50 , timestamp ) ;
2014-12-17 03:32:51 -05:00
if ( messages . size ( ) > 0 ) {
conversation . addAll ( 0 , messages ) ;
2015-01-19 05:23:05 -05:00
checkDeletedFiles ( conversation ) ;
2014-12-17 03:32:51 -05:00
callback . onMoreMessagesLoaded ( messages . size ( ) , conversation ) ;
2015-01-02 18:47:22 -05:00
} else if ( conversation . hasMessagesLeftOnServer ( )
2016-02-04 10:29:17 -05:00
& & account . isOnlineAndConnected ( )
& & conversation . getLastClearHistory ( ) = = 0 ) {
2015-10-04 18:37:19 -04:00
if ( ( conversation . getMode ( ) = = Conversation . MODE_SINGLE & & account . getXmppConnection ( ) . getFeatures ( ) . mam ( ) )
| | ( conversation . getMode ( ) = = Conversation . MODE_MULTI & & conversation . getMucOptions ( ) . mamSupport ( ) ) ) {
2016-02-04 05:55:42 -05:00
MessageArchiveService . Query query = getMessageArchiveService ( ) . query ( conversation , 0 , timestamp ) ;
2015-10-04 18:37:19 -04:00
if ( query ! = null ) {
query . setCallback ( callback ) ;
}
callback . informUser ( R . string . fetching_history_from_server ) ;
2014-12-17 03:32:51 -05:00
}
2015-01-19 05:23:05 -05:00
}
2014-12-15 17:06:29 -05:00
}
2015-06-05 02:46:06 -04:00
} ;
mDatabaseExecutor . execute ( runnable ) ;
2014-12-15 17:06:29 -05:00
}
2014-02-03 12:38:47 -05:00
public List < Account > getAccounts ( ) {
return this . accounts ;
}
2014-06-03 09:48:51 -04:00
2016-06-14 11:11:31 -04:00
public List < Conversation > findAllConferencesWith ( Contact contact ) {
ArrayList < Conversation > results = new ArrayList < > ( ) ;
for ( Conversation conversation : conversations ) {
if ( conversation . getMode ( ) = = Conversation . MODE_MULTI
& & conversation . getMucOptions ( ) . isContactInRoom ( contact ) ) {
results . add ( conversation ) ;
}
}
return results ;
}
2014-12-21 15:43:58 -05:00
public Conversation find ( final Iterable < Conversation > haystack , final Contact contact ) {
for ( final Conversation conversation : haystack ) {
2014-05-23 04:54:40 -04:00
if ( conversation . getContact ( ) = = contact ) {
return conversation ;
}
}
return null ;
}
2014-02-11 17:55:03 -05:00
2014-12-21 15:43:58 -05:00
public Conversation find ( final Iterable < Conversation > haystack , final Account account , final Jid jid ) {
2015-01-19 05:17:27 -05:00
if ( jid = = null ) {
2014-11-29 13:09:28 -05:00
return null ;
}
2014-12-21 15:43:58 -05:00
for ( final Conversation conversation : haystack ) {
2014-10-28 12:15:35 -04:00
if ( ( account = = null | | conversation . getAccount ( ) = = account )
2014-12-21 15:43:58 -05:00
& & ( conversation . getJid ( ) . toBareJid ( ) . equals ( jid . toBareJid ( ) ) ) ) {
2014-07-19 20:26:23 -04:00
return conversation ;
2015-01-19 05:17:27 -05:00
}
2014-07-19 20:26:23 -04:00
}
return null ;
}
2014-08-26 10:52:42 -04:00
2015-01-19 05:17:27 -05:00
public Conversation findOrCreateConversation ( final Account account , final Jid jid , final boolean muc ) {
return this . findOrCreateConversation ( account , jid , muc , null ) ;
2014-12-13 06:25:52 -05:00
}
2015-01-19 05:17:27 -05:00
public Conversation findOrCreateConversation ( final Account account , final Jid jid , final boolean muc , final MessageArchiveService . Query query ) {
2014-11-17 21:10:59 -05:00
synchronized ( this . conversations ) {
Conversation conversation = find ( account , jid ) ;
if ( conversation ! = null ) {
return conversation ;
2014-02-10 09:24:34 -05:00
}
2014-11-17 21:10:59 -05:00
conversation = databaseBackend . findConversation ( account , jid ) ;
if ( conversation ! = null ) {
conversation . setStatus ( Conversation . STATUS_AVAILABLE ) ;
conversation . setAccount ( account ) ;
if ( muc ) {
conversation . setMode ( Conversation . MODE_MULTI ) ;
2015-01-21 10:18:38 -05:00
conversation . setContactJid ( jid ) ;
2014-11-17 21:10:59 -05:00
} else {
conversation . setMode ( Conversation . MODE_SINGLE ) ;
2015-01-21 10:18:38 -05:00
conversation . setContactJid ( jid . toBareJid ( ) ) ;
2014-11-17 21:10:59 -05:00
}
2014-12-15 17:06:29 -05:00
conversation . addAll ( 0 , databaseBackend . getMessages ( conversation , Config . PAGE_SIZE ) ) ;
2014-11-17 21:10:59 -05:00
this . databaseBackend . updateConversation ( conversation ) ;
2014-02-07 10:50:29 -05:00
} else {
2014-11-17 21:10:59 -05:00
String conversationName ;
Contact contact = account . getRoster ( ) . getContact ( jid ) ;
if ( contact ! = null ) {
conversationName = contact . getDisplayName ( ) ;
} else {
conversationName = jid . getLocalpart ( ) ;
}
if ( muc ) {
conversation = new Conversation ( conversationName , account , jid ,
Conversation . MODE_MULTI ) ;
} else {
2015-01-21 10:18:38 -05:00
conversation = new Conversation ( conversationName , account , jid . toBareJid ( ) ,
2014-11-17 21:10:59 -05:00
Conversation . MODE_SINGLE ) ;
}
this . databaseBackend . createConversation ( conversation ) ;
2014-02-07 10:50:29 -05:00
}
2015-01-23 18:22:51 -05:00
if ( account . getXmppConnection ( ) ! = null
& & account . getXmppConnection ( ) . getFeatures ( ) . mam ( )
& & ! muc ) {
2015-01-04 12:16:55 -05:00
if ( query = = null ) {
this . mMessageArchiveService . query ( conversation ) ;
} else {
if ( query . getConversation ( ) = = null ) {
this . mMessageArchiveService . query ( conversation , query . getStart ( ) ) ;
}
2014-12-13 06:25:52 -05:00
}
}
2015-01-19 05:23:05 -05:00
checkDeletedFiles ( conversation ) ;
2014-11-17 21:10:59 -05:00
this . conversations . add ( conversation ) ;
updateConversationUi ( ) ;
return conversation ;
2014-02-03 12:38:47 -05:00
}
}
public void archiveConversation ( Conversation conversation ) {
2015-04-02 18:06:37 -04:00
getNotificationService ( ) . clear ( conversation ) ;
2015-01-07 06:20:39 -05:00
conversation . setStatus ( Conversation . STATUS_ARCHIVED ) ;
2014-11-17 21:10:59 -05:00
synchronized ( this . conversations ) {
if ( conversation . getMode ( ) = = Conversation . MODE_MULTI ) {
if ( conversation . getAccount ( ) . getStatus ( ) = = Account . State . ONLINE ) {
Bookmark bookmark = conversation . getBookmark ( ) ;
2016-02-01 07:54:08 -05:00
if ( bookmark ! = null & & bookmark . autojoin ( ) & & respectAutojoin ( ) ) {
2014-11-17 21:10:59 -05:00
bookmark . setAutojoin ( false ) ;
pushBookmarks ( bookmark . getAccount ( ) ) ;
}
2014-10-08 08:10:37 -04:00
}
2014-11-17 21:10:59 -05:00
leaveMuc ( conversation ) ;
} else {
conversation . endOtrIfNeeded ( ) ;
2015-11-04 21:56:45 -05:00
if ( conversation . getContact ( ) . getOption ( Contact . Options . PENDING_SUBSCRIPTION_REQUEST ) ) {
Log . d ( Config . LOGTAG , " Canceling presence request from " + conversation . getJid ( ) . toString ( ) ) ;
sendPresencePacket (
conversation . getAccount ( ) ,
mPresenceGenerator . stopPresenceUpdatesTo ( conversation . getContact ( ) )
) ;
}
2014-07-15 08:32:19 -04:00
}
2016-10-18 07:06:24 -04:00
updateConversation ( conversation ) ;
2014-11-17 21:10:59 -05:00
this . conversations . remove ( conversation ) ;
updateConversationUi ( ) ;
2014-02-13 17:40:08 -05:00
}
2014-02-03 12:38:47 -05:00
}
2014-05-01 16:33:49 -04:00
2014-12-23 17:19:00 -05:00
public void createAccount ( final Account account ) {
2015-05-25 22:36:32 -04:00
account . initAccountServices ( this ) ;
2014-01-28 13:21:54 -05:00
databaseBackend . createAccount ( account ) ;
2014-02-04 09:09:50 -05:00
this . accounts . add ( account ) ;
2015-03-05 09:46:33 -05:00
this . reconnectAccountInBackground ( account ) ;
2014-07-12 07:42:17 -04:00
updateAccountUi ( ) ;
2014-01-28 13:21:54 -05:00
}
2014-02-23 15:33:37 -05:00
2015-10-09 07:37:08 -04:00
public void createAccountFromKey ( final String alias , final OnAccountCreated callback ) {
new Thread ( new Runnable ( ) {
@Override
public void run ( ) {
try {
X509Certificate [ ] chain = KeyChain . getCertificateChain ( XmppConnectionService . this , alias ) ;
2015-10-16 03:58:31 -04:00
Pair < Jid , String > info = CryptoHelper . extractJidAndName ( chain [ 0 ] ) ;
2015-10-11 09:48:58 -04:00
if ( findAccountByJid ( info . first ) = = null ) {
Account account = new Account ( info . first , " " ) ;
2015-10-09 07:37:08 -04:00
account . setPrivateKeyAlias ( alias ) ;
account . setOption ( Account . OPTION_DISABLED , true ) ;
2015-10-29 08:41:08 -04:00
account . setDisplayName ( info . second ) ;
2015-10-09 07:37:08 -04:00
createAccount ( account ) ;
callback . onAccountCreated ( account ) ;
2015-10-12 07:18:20 -04:00
if ( Config . X509_VERIFICATION ) {
try {
getMemorizingTrustManager ( ) . getNonInteractive ( ) . checkClientTrusted ( chain , " RSA " ) ;
} catch ( CertificateException e ) {
callback . informUser ( R . string . certificate_chain_is_not_trusted ) ;
}
2015-10-11 09:48:58 -04:00
}
2015-10-09 07:37:08 -04:00
} else {
callback . informUser ( R . string . account_already_exists ) ;
}
2015-10-12 07:18:20 -04:00
} catch ( Exception e ) {
2015-10-16 03:58:31 -04:00
e . printStackTrace ( ) ;
2015-10-09 07:37:08 -04:00
callback . informUser ( R . string . unable_to_parse_certificate ) ;
}
}
} ) . start ( ) ;
}
2015-10-11 09:48:58 -04:00
public void updateKeyInAccount ( final Account account , final String alias ) {
2015-10-14 15:18:34 -04:00
Log . d ( Config . LOGTAG , " update key in account " + alias ) ;
2015-10-11 09:48:58 -04:00
try {
X509Certificate [ ] chain = KeyChain . getCertificateChain ( XmppConnectionService . this , alias ) ;
Pair < Jid , String > info = CryptoHelper . extractJidAndName ( chain [ 0 ] ) ;
if ( account . getJid ( ) . toBareJid ( ) . equals ( info . first ) ) {
account . setPrivateKeyAlias ( alias ) ;
2015-10-29 08:41:08 -04:00
account . setDisplayName ( info . second ) ;
2015-10-11 09:48:58 -04:00
databaseBackend . updateAccount ( account ) ;
2015-10-12 07:18:20 -04:00
if ( Config . X509_VERIFICATION ) {
try {
getMemorizingTrustManager ( ) . getNonInteractive ( ) . checkClientTrusted ( chain , " RSA " ) ;
} catch ( CertificateException e ) {
showErrorToastInUi ( R . string . certificate_chain_is_not_trusted ) ;
}
account . getAxolotlService ( ) . regenerateKeys ( true ) ;
2015-10-11 09:48:58 -04:00
}
} else {
showErrorToastInUi ( R . string . jid_does_not_match_certificate ) ;
}
2015-10-16 03:58:31 -04:00
} catch ( Exception e ) {
2015-10-11 09:48:58 -04:00
e . printStackTrace ( ) ;
}
}
2016-09-07 08:34:58 -04:00
public boolean updateAccount ( final Account account ) {
if ( databaseBackend . updateAccount ( account ) ) {
2016-10-04 05:16:59 -04:00
account . setShowErrorNotification ( true ) ;
2016-09-07 08:34:58 -04:00
this . statusListener . onStatusChanged ( account ) ;
databaseBackend . updateAccount ( account ) ;
reconnectAccountInBackground ( account ) ;
updateAccountUi ( ) ;
getNotificationService ( ) . updateErrorNotification ( ) ;
return true ;
} else {
return false ;
}
2014-01-28 13:21:54 -05:00
}
2014-12-25 16:08:13 -05:00
public void updateAccountPasswordOnServer ( final Account account , final String newPassword , final OnAccountPasswordChanged callback ) {
final IqPacket iq = getIqGenerator ( ) . generateSetPassword ( account , newPassword ) ;
sendIqPacket ( account , iq , new OnIqPacketReceived ( ) {
@Override
public void onIqPacketReceived ( final Account account , final IqPacket packet ) {
2014-12-30 08:16:25 -05:00
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2014-12-25 16:08:13 -05:00
account . setPassword ( newPassword ) ;
2016-04-26 17:23:48 -04:00
account . setOption ( Account . OPTION_MAGIC_CREATE , false ) ;
2014-12-25 16:08:13 -05:00
databaseBackend . updateAccount ( account ) ;
callback . onPasswordChangeSucceeded ( ) ;
} else {
callback . onPasswordChangeFailed ( ) ;
2014-12-23 17:19:00 -05:00
}
2014-12-25 16:08:13 -05:00
}
} ) ;
}
2014-12-23 17:19:00 -05:00
public void deleteAccount ( final Account account ) {
2014-11-17 21:10:59 -05:00
synchronized ( this . conversations ) {
2014-12-23 17:19:00 -05:00
for ( final Conversation conversation : conversations ) {
2014-11-17 21:10:59 -05:00
if ( conversation . getAccount ( ) = = account ) {
if ( conversation . getMode ( ) = = Conversation . MODE_MULTI ) {
leaveMuc ( conversation ) ;
} else if ( conversation . getMode ( ) = = Conversation . MODE_SINGLE ) {
conversation . endOtrIfNeeded ( ) ;
}
conversations . remove ( conversation ) ;
2014-07-21 12:20:26 -04:00
}
}
2014-11-17 21:10:59 -05:00
if ( account . getXmppConnection ( ) ! = null ) {
2016-06-03 08:18:43 -04:00
new Thread ( new Runnable ( ) {
@Override
public void run ( ) {
disconnect ( account , true ) ;
}
2016-09-07 08:34:58 -04:00
} ) . start ( ) ;
2014-11-17 21:10:59 -05:00
}
2015-10-29 12:20:01 -04:00
Runnable runnable = new Runnable ( ) {
@Override
public void run ( ) {
2016-09-07 08:34:58 -04:00
if ( ! databaseBackend . deleteAccount ( account ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : unable to delete account " ) ;
}
2015-10-29 12:20:01 -04:00
}
} ;
mDatabaseExecutor . execute ( runnable ) ;
2014-11-17 21:10:59 -05:00
this . accounts . remove ( account ) ;
updateAccountUi ( ) ;
2014-11-18 09:26:28 -05:00
getNotificationService ( ) . updateErrorNotification ( ) ;
2014-07-21 12:20:26 -04:00
}
2014-01-28 13:21:54 -05:00
}
2014-02-03 12:38:47 -05:00
2014-12-03 08:55:09 -05:00
public void setOnConversationListChangedListener ( OnConversationUpdate listener ) {
synchronized ( this ) {
2016-06-04 10:16:14 -04:00
this . mLastActivity = System . currentTimeMillis ( ) ;
2014-10-15 08:41:27 -04:00
if ( checkListeners ( ) ) {
switchToForeground ( ) ;
}
this . mOnConversationUpdate = listener ;
this . mNotificationService . setIsInForeground ( true ) ;
2014-12-03 08:55:09 -05:00
if ( this . convChangedListenerCount < 2 ) {
this . convChangedListenerCount + + ;
2014-11-15 11:09:02 -05:00
}
2014-12-03 08:55:09 -05:00
}
}
2014-02-03 12:38:47 -05:00
2014-02-01 09:07:20 -05:00
public void removeOnConversationListChangedListener ( ) {
2014-12-03 08:55:09 -05:00
synchronized ( this ) {
2014-10-15 08:41:27 -04:00
this . convChangedListenerCount - - ;
if ( this . convChangedListenerCount < = 0 ) {
this . convChangedListenerCount = 0 ;
this . mOnConversationUpdate = null ;
this . mNotificationService . setIsInForeground ( false ) ;
if ( checkListeners ( ) ) {
switchToBackground ( ) ;
}
2014-08-26 11:43:44 -04:00
}
2014-03-29 15:29:03 -04:00
}
2014-02-01 09:07:20 -05:00
}
2014-02-05 16:33:39 -05:00
2015-07-10 07:28:50 -04:00
public void setOnShowErrorToastListener ( OnShowErrorToast onShowErrorToast ) {
synchronized ( this ) {
if ( checkListeners ( ) ) {
switchToForeground ( ) ;
}
this . mOnShowErrorToast = onShowErrorToast ;
if ( this . showErrorToastListenerCount < 2 ) {
this . showErrorToastListenerCount + + ;
}
}
this . mOnShowErrorToast = onShowErrorToast ;
}
public void removeOnShowErrorToastListener ( ) {
synchronized ( this ) {
this . showErrorToastListenerCount - - ;
if ( this . showErrorToastListenerCount < = 0 ) {
this . showErrorToastListenerCount = 0 ;
this . mOnShowErrorToast = null ;
if ( checkListeners ( ) ) {
switchToBackground ( ) ;
}
}
}
}
2014-07-12 07:42:17 -04:00
public void setOnAccountListChangedListener ( OnAccountUpdate listener ) {
2014-12-03 08:55:09 -05:00
synchronized ( this ) {
2014-10-15 08:41:27 -04:00
if ( checkListeners ( ) ) {
switchToForeground ( ) ;
}
this . mOnAccountUpdate = listener ;
2014-12-03 08:55:09 -05:00
if ( this . accountChangedListenerCount < 2 ) {
this . accountChangedListenerCount + + ;
}
2014-08-26 11:43:44 -04:00
}
2014-02-04 09:09:50 -05:00
}
2014-02-05 16:33:39 -05:00
2014-02-04 09:09:50 -05:00
public void removeOnAccountListChangedListener ( ) {
2014-12-03 08:55:09 -05:00
synchronized ( this ) {
2014-10-15 08:41:27 -04:00
this . accountChangedListenerCount - - ;
if ( this . accountChangedListenerCount < = 0 ) {
this . mOnAccountUpdate = null ;
this . accountChangedListenerCount = 0 ;
if ( checkListeners ( ) ) {
switchToBackground ( ) ;
}
2014-08-26 11:43:44 -04:00
}
2014-08-15 11:31:24 -04:00
}
2014-02-04 09:09:50 -05:00
}
2014-08-26 10:52:42 -04:00
2015-10-11 07:11:50 -04:00
public void setOnCaptchaRequestedListener ( OnCaptchaRequested listener ) {
synchronized ( this ) {
if ( checkListeners ( ) ) {
switchToForeground ( ) ;
}
this . mOnCaptchaRequested = listener ;
if ( this . captchaRequestedListenerCount < 2 ) {
this . captchaRequestedListenerCount + + ;
}
}
}
public void removeOnCaptchaRequestedListener ( ) {
synchronized ( this ) {
this . captchaRequestedListenerCount - - ;
if ( this . captchaRequestedListenerCount < = 0 ) {
this . mOnCaptchaRequested = null ;
this . captchaRequestedListenerCount = 0 ;
if ( checkListeners ( ) ) {
switchToBackground ( ) ;
}
}
}
}
2014-12-21 15:43:58 -05:00
public void setOnRosterUpdateListener ( final OnRosterUpdate listener ) {
2014-12-03 08:55:09 -05:00
synchronized ( this ) {
2014-10-15 08:41:27 -04:00
if ( checkListeners ( ) ) {
switchToForeground ( ) ;
}
this . mOnRosterUpdate = listener ;
2014-12-03 08:55:09 -05:00
if ( this . rosterChangedListenerCount < 2 ) {
this . rosterChangedListenerCount + + ;
}
2014-08-26 11:43:44 -04:00
}
2014-07-18 09:35:31 -04:00
}
public void removeOnRosterUpdateListener ( ) {
2014-12-03 08:55:09 -05:00
synchronized ( this ) {
2014-10-15 08:41:27 -04:00
this . rosterChangedListenerCount - - ;
if ( this . rosterChangedListenerCount < = 0 ) {
this . rosterChangedListenerCount = 0 ;
this . mOnRosterUpdate = null ;
if ( checkListeners ( ) ) {
switchToBackground ( ) ;
}
2014-09-10 11:59:57 -04:00
}
2014-08-26 11:43:44 -04:00
}
}
2014-08-30 03:24:58 -04:00
2014-12-21 15:43:58 -05:00
public void setOnUpdateBlocklistListener ( final OnUpdateBlocklist listener ) {
synchronized ( this ) {
if ( checkListeners ( ) ) {
switchToForeground ( ) ;
}
this . mOnUpdateBlocklist = listener ;
2015-07-20 08:12:24 -04:00
if ( this . updateBlocklistListenerCount < 2 ) {
this . updateBlocklistListenerCount + + ;
2014-12-21 15:43:58 -05:00
}
}
}
public void removeOnUpdateBlocklistListener ( ) {
synchronized ( this ) {
2015-07-20 08:12:24 -04:00
this . updateBlocklistListenerCount - - ;
if ( this . updateBlocklistListenerCount < = 0 ) {
this . updateBlocklistListenerCount = 0 ;
2014-12-21 15:43:58 -05:00
this . mOnUpdateBlocklist = null ;
if ( checkListeners ( ) ) {
switchToBackground ( ) ;
}
}
}
}
2015-07-21 08:18:16 -04:00
public void setOnKeyStatusUpdatedListener ( final OnKeyStatusUpdated listener ) {
2015-07-19 12:36:28 -04:00
synchronized ( this ) {
if ( checkListeners ( ) ) {
switchToForeground ( ) ;
}
2015-07-21 08:18:16 -04:00
this . mOnKeyStatusUpdated = listener ;
if ( this . keyStatusUpdatedListenerCount < 2 ) {
this . keyStatusUpdatedListenerCount + + ;
2015-07-19 12:36:28 -04:00
}
}
}
public void removeOnNewKeysAvailableListener ( ) {
synchronized ( this ) {
2015-07-21 08:18:16 -04:00
this . keyStatusUpdatedListenerCount - - ;
if ( this . keyStatusUpdatedListenerCount < = 0 ) {
this . keyStatusUpdatedListenerCount = 0 ;
this . mOnKeyStatusUpdated = null ;
2015-07-19 12:36:28 -04:00
if ( checkListeners ( ) ) {
switchToBackground ( ) ;
}
}
}
}
2015-07-21 08:18:16 -04:00
2014-11-23 09:19:44 -05:00
public void setOnMucRosterUpdateListener ( OnMucRosterUpdate listener ) {
2014-12-03 08:55:09 -05:00
synchronized ( this ) {
2014-11-23 09:19:44 -05:00
if ( checkListeners ( ) ) {
switchToForeground ( ) ;
}
this . mOnMucRosterUpdate = listener ;
2014-12-03 08:55:09 -05:00
if ( this . mucRosterChangedListenerCount < 2 ) {
this . mucRosterChangedListenerCount + + ;
}
2014-11-23 09:19:44 -05:00
}
}
public void removeOnMucRosterUpdateListener ( ) {
2014-12-03 08:55:09 -05:00
synchronized ( this ) {
2014-11-23 09:19:44 -05:00
this . mucRosterChangedListenerCount - - ;
if ( this . mucRosterChangedListenerCount < = 0 ) {
this . mucRosterChangedListenerCount = 0 ;
this . mOnMucRosterUpdate = null ;
if ( checkListeners ( ) ) {
switchToBackground ( ) ;
}
}
}
}
2016-05-19 04:41:56 -04:00
public boolean checkListeners ( ) {
2014-08-30 03:24:58 -04:00
return ( this . mOnAccountUpdate = = null
2015-01-02 06:04:33 -05:00
& & this . mOnConversationUpdate = = null
& & this . mOnRosterUpdate = = null
2015-10-11 07:11:50 -04:00
& & this . mOnCaptchaRequested = = null
2015-07-10 07:28:50 -04:00
& & this . mOnUpdateBlocklist = = null
2015-07-19 12:36:28 -04:00
& & this . mOnShowErrorToast = = null
2015-07-21 08:18:16 -04:00
& & this . mOnKeyStatusUpdated = = null ) ;
2014-08-26 11:43:44 -04:00
}
2014-08-30 03:24:58 -04:00
2014-08-26 11:43:44 -04:00
private void switchToForeground ( ) {
2016-06-04 10:16:14 -04:00
final boolean broadcastLastActivity = broadcastLastActivity ( ) ;
2015-10-19 17:22:29 -04:00
for ( Conversation conversation : getConversations ( ) ) {
conversation . setIncomingChatState ( ChatState . ACTIVE ) ;
}
2014-08-30 03:24:58 -04:00
for ( Account account : getAccounts ( ) ) {
2014-11-15 11:09:02 -05:00
if ( account . getStatus ( ) = = Account . State . ONLINE ) {
2016-06-01 15:30:50 -04:00
account . deactivateGracePeriod ( ) ;
2016-06-04 10:16:14 -04:00
final XmppConnection connection = account . getXmppConnection ( ) ;
if ( connection ! = null ) {
if ( connection . getFeatures ( ) . csi ( ) ) {
connection . sendActive ( ) ;
}
if ( broadcastLastActivity ) {
sendPresence ( account , false ) ; //send new presence but don't include idle because we are not
}
2014-08-26 11:43:44 -04:00
}
}
}
2014-10-20 15:08:33 -04:00
Log . d ( Config . LOGTAG , " app switched into foreground " ) ;
2014-08-26 11:43:44 -04:00
}
2014-08-30 03:24:58 -04:00
2014-08-26 11:43:44 -04:00
private void switchToBackground ( ) {
2016-06-04 10:16:14 -04:00
final boolean broadcastLastActivity = broadcastLastActivity ( ) ;
2014-08-30 03:24:58 -04:00
for ( Account account : getAccounts ( ) ) {
2014-11-15 11:09:02 -05:00
if ( account . getStatus ( ) = = Account . State . ONLINE ) {
2014-08-26 11:43:44 -04:00
XmppConnection connection = account . getXmppConnection ( ) ;
2016-02-14 07:20:23 -05:00
if ( connection ! = null ) {
2016-06-04 10:16:14 -04:00
if ( broadcastLastActivity ) {
sendPresence ( account , broadcastLastActivity ) ;
}
2016-06-04 16:42:12 -04:00
if ( connection . getFeatures ( ) . csi ( ) ) {
connection . sendInactive ( ) ;
}
2016-08-09 13:21:54 -04:00
if ( Config . PUSH_MODE & & mPushManagementService . available ( account ) ) {
2016-02-14 07:20:23 -05:00
connection . waitForPush ( ) ;
cancelWakeUpCall ( account . getUuid ( ) . hashCode ( ) ) ;
}
2014-08-26 11:43:44 -04:00
}
}
}
2014-10-16 13:10:37 -04:00
this . mNotificationService . setIsInForeground ( false ) ;
2014-10-20 15:08:33 -04:00
Log . d ( Config . LOGTAG , " app switched into background " ) ;
2014-07-18 09:35:31 -04:00
}
2014-10-15 08:41:27 -04:00
2014-12-15 17:06:29 -05:00
private void connectMultiModeConversations ( Account account ) {
2014-02-05 16:33:39 -05:00
List < Conversation > conversations = getConversations ( ) ;
2014-11-09 19:24:35 -05:00
for ( Conversation conversation : conversations ) {
2015-10-01 07:03:15 -04:00
if ( conversation . getMode ( ) = = Conversation . MODE_MULTI & & conversation . getAccount ( ) = = account ) {
2016-02-17 10:50:48 -05:00
joinMuc ( conversation ) ;
2015-01-19 05:17:27 -05:00
}
2014-11-09 19:24:35 -05:00
}
2014-02-05 16:33:39 -05:00
}
2014-02-08 18:47:11 -05:00
2014-02-13 17:40:08 -05:00
public void joinMuc ( Conversation conversation ) {
2016-02-17 10:50:48 -05:00
joinMuc ( conversation , null ) ;
2015-10-01 10:01:19 -04:00
}
2016-02-17 10:50:48 -05:00
private void joinMuc ( Conversation conversation , final OnConferenceJoined onConferenceJoined ) {
2014-05-22 09:36:41 -04:00
Account account = conversation . getAccount ( ) ;
2014-07-18 15:57:10 -04:00
account . pendingConferenceJoins . remove ( conversation ) ;
account . pendingConferenceLeaves . remove ( conversation ) ;
2016-02-17 10:50:48 -05:00
if ( account . getStatus ( ) = = Account . State . ONLINE ) {
2015-10-01 07:03:15 -04:00
conversation . resetMucOptions ( ) ;
2016-05-27 04:35:00 -04:00
if ( onConferenceJoined ! = null ) {
conversation . getMucOptions ( ) . flagNoAutoPushConfiguration ( ) ;
}
2016-02-23 10:15:55 -05:00
conversation . setHasMessagesLeftOnServer ( false ) ;
2015-10-04 18:45:16 -04:00
fetchConferenceConfiguration ( conversation , new OnConferenceConfigurationFetched ( ) {
2015-10-22 05:20:36 -04:00
private void join ( Conversation conversation ) {
2015-10-04 18:45:16 -04:00
Account account = conversation . getAccount ( ) ;
2016-02-29 07:18:07 -05:00
final MucOptions mucOptions = conversation . getMucOptions ( ) ;
2016-02-29 10:32:24 -05:00
final Jid joinJid = mucOptions . getSelf ( ) . getFullJid ( ) ;
2015-10-04 18:45:16 -04:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) . toString ( ) + " : joining conversation " + joinJid . toString ( ) ) ;
2016-10-19 06:31:11 -04:00
PresencePacket packet = mPresenceGenerator . selfPresence ( account , Presence . Status . ONLINE , mucOptions . nonanonymous ( ) ) ;
2015-10-04 18:45:16 -04:00
packet . setTo ( joinJid ) ;
Element x = packet . addChild ( " x " , " http://jabber.org/protocol/muc " ) ;
if ( conversation . getMucOptions ( ) . getPassword ( ) ! = null ) {
2016-10-19 06:31:11 -04:00
x . addChild ( " password " ) . setContent ( mucOptions . getPassword ( ) ) ;
2015-10-04 18:45:16 -04:00
}
2016-02-29 07:18:07 -05:00
if ( mucOptions . mamSupport ( ) ) {
2015-10-04 18:45:16 -04:00
// Use MAM instead of the limited muc history to get history
x . addChild ( " history " ) . setAttribute ( " maxchars " , " 0 " ) ;
} else {
// Fallback to muc history
x . addChild ( " history " ) . setAttribute ( " since " , PresenceGenerator . getTimestamp ( conversation . getLastMessageTransmitted ( ) ) ) ;
}
sendPresencePacket ( account , packet ) ;
2015-11-25 14:47:02 -05:00
if ( onConferenceJoined ! = null ) {
onConferenceJoined . onConferenceJoined ( conversation ) ;
}
2015-10-04 18:45:16 -04:00
if ( ! joinJid . equals ( conversation . getJid ( ) ) ) {
conversation . setContactJid ( joinJid ) ;
databaseBackend . updateConversation ( conversation ) ;
}
2016-02-29 07:18:07 -05:00
if ( mucOptions . mamSupport ( ) ) {
2015-10-06 10:58:56 -04:00
getMessageArchiveService ( ) . catchupMUC ( conversation ) ;
}
2016-02-29 07:18:07 -05:00
if ( mucOptions . membersOnly ( ) & & mucOptions . nonanonymous ( ) ) {
fetchConferenceMembers ( conversation ) ;
}
2016-02-10 03:53:48 -05:00
sendUnsentMessages ( conversation ) ;
2015-10-04 18:45:16 -04:00
}
2015-10-22 05:20:36 -04:00
@Override
public void onConferenceConfigurationFetched ( Conversation conversation ) {
join ( conversation ) ;
}
@Override
public void onFetchFailed ( final Conversation conversation , Element error ) {
2016-09-06 06:15:08 -04:00
if ( error ! = null & & " remote-server-not-found " . equals ( error . getName ( ) ) ) {
2016-09-09 05:04:05 -04:00
conversation . getMucOptions ( ) . setError ( MucOptions . Error . SERVER_NOT_FOUND ) ;
2016-09-06 06:15:08 -04:00
} else {
join ( conversation ) ;
fetchConferenceConfiguration ( conversation ) ;
}
2015-10-22 05:20:36 -04:00
}
2015-10-04 18:45:16 -04:00
} ) ;
2016-02-22 14:19:58 -05:00
updateConversationUi ( ) ;
2014-07-18 15:57:10 -04:00
} else {
account . pendingConferenceJoins . add ( conversation ) ;
2016-02-22 14:19:58 -05:00
conversation . resetMucOptions ( ) ;
2016-02-23 10:15:55 -05:00
conversation . setHasMessagesLeftOnServer ( false ) ;
2016-02-22 14:19:58 -05:00
updateConversationUi ( ) ;
2014-02-11 09:34:24 -05:00
}
2014-02-07 10:50:29 -05:00
}
2014-03-11 10:44:22 -04:00
2016-02-29 07:18:07 -05:00
private void fetchConferenceMembers ( final Conversation conversation ) {
final Account account = conversation . getAccount ( ) ;
final String [ ] affiliations = { " member " , " admin " , " owner " } ;
OnIqPacketReceived callback = new OnIqPacketReceived ( ) {
private int i = 0 ;
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
2016-05-16 08:10:40 -04:00
2016-02-29 07:18:07 -05:00
Element query = packet . query ( " http://jabber.org/protocol/muc#admin " ) ;
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT & & query ! = null ) {
for ( Element child : query . getChildren ( ) ) {
if ( " item " . equals ( child . getName ( ) ) ) {
2016-05-17 08:25:58 -04:00
MucOptions . User user = AbstractParser . parseItem ( conversation , child ) ;
if ( ! user . realJidMatchesAccount ( ) ) {
conversation . getMucOptions ( ) . addUser ( user ) ;
2016-05-21 03:25:37 -04:00
getAvatarService ( ) . clear ( conversation ) ;
updateMucRosterUi ( ) ;
updateConversationUi ( ) ;
2016-05-16 08:10:40 -04:00
}
2016-02-29 07:18:07 -05:00
}
}
} else {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : could not request affiliation " + affiliations [ i ] + " in " + conversation . getJid ( ) . toBareJid ( ) ) ;
}
+ + i ;
if ( i > = affiliations . length ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : retrieved members for " + conversation . getJid ( ) . toBareJid ( ) + " : " + conversation . getMucOptions ( ) . getMembers ( ) ) ;
}
}
} ;
for ( String affiliation : affiliations ) {
sendIqPacket ( account , mIqGenerator . queryAffiliation ( conversation , affiliation ) , callback ) ;
}
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : fetching members for " + conversation . getName ( ) ) ;
}
2014-09-03 13:35:45 -04:00
public void providePasswordForMuc ( Conversation conversation , String password ) {
if ( conversation . getMode ( ) = = Conversation . MODE_MULTI ) {
conversation . getMucOptions ( ) . setPassword ( password ) ;
2014-10-05 18:33:52 -04:00
if ( conversation . getBookmark ( ) ! = null ) {
2016-02-01 07:54:08 -05:00
if ( respectAutojoin ( ) ) {
conversation . getBookmark ( ) . setAutojoin ( true ) ;
}
2014-09-07 08:06:23 -04:00
pushBookmarks ( conversation . getAccount ( ) ) ;
}
2016-10-18 07:06:24 -04:00
updateConversation ( conversation ) ;
2014-09-03 13:35:45 -04:00
joinMuc ( conversation ) ;
}
}
2014-03-11 10:44:22 -04:00
2014-11-20 12:20:42 -05:00
public void renameInMuc ( final Conversation conversation , final String nick , final UiCallback < Conversation > callback ) {
2014-03-02 23:01:02 -05:00
final MucOptions options = conversation . getMucOptions ( ) ;
2014-11-20 12:20:42 -05:00
final Jid joinJid = options . createJoinJid ( nick ) ;
2014-03-02 23:01:02 -05:00
if ( options . online ( ) ) {
2014-06-03 05:04:17 -04:00
Account account = conversation . getAccount ( ) ;
2014-03-02 23:01:02 -05:00
options . setOnRenameListener ( new OnRenameListener ( ) {
2014-03-11 10:44:22 -04:00
2014-03-02 23:01:02 -05:00
@Override
2014-11-20 12:20:42 -05:00
public void onSuccess ( ) {
conversation . setContactJid ( joinJid ) ;
databaseBackend . updateConversation ( conversation ) ;
Bookmark bookmark = conversation . getBookmark ( ) ;
if ( bookmark ! = null ) {
bookmark . setNick ( nick ) ;
pushBookmarks ( bookmark . getAccount ( ) ) ;
2014-03-03 22:09:15 -05:00
}
2014-11-20 12:20:42 -05:00
callback . success ( conversation ) ;
}
@Override
public void onFailure ( ) {
2014-12-13 06:25:52 -05:00
callback . error ( R . string . nick_in_use , conversation ) ;
2014-03-02 23:01:02 -05:00
}
} ) ;
2014-11-20 12:20:42 -05:00
2014-03-02 23:01:02 -05:00
PresencePacket packet = new PresencePacket ( ) ;
2014-11-20 12:20:42 -05:00
packet . setTo ( joinJid ) ;
2014-11-09 10:57:22 -05:00
packet . setFrom ( conversation . getAccount ( ) . getJid ( ) ) ;
2014-06-03 09:48:51 -04:00
2014-06-03 05:04:17 -04:00
String sig = account . getPgpSignature ( ) ;
if ( sig ! = null ) {
packet . addChild ( " status " ) . setContent ( " online " ) ;
packet . addChild ( " x " , " jabber:x:signed " ) . setContent ( sig ) ;
}
2014-08-26 10:52:42 -04:00
sendPresencePacket ( account , packet ) ;
2014-03-02 23:01:02 -05:00
} else {
2014-11-20 12:20:42 -05:00
conversation . setContactJid ( joinJid ) ;
2014-03-02 23:01:02 -05:00
databaseBackend . updateConversation ( conversation ) ;
2014-11-15 11:09:02 -05:00
if ( conversation . getAccount ( ) . getStatus ( ) = = Account . State . ONLINE ) {
2014-07-15 11:11:43 -04:00
Bookmark bookmark = conversation . getBookmark ( ) ;
2014-08-26 10:52:42 -04:00
if ( bookmark ! = null ) {
2014-07-15 11:11:43 -04:00
bookmark . setNick ( nick ) ;
pushBookmarks ( bookmark . getAccount ( ) ) ;
}
2014-03-02 23:01:02 -05:00
joinMuc ( conversation ) ;
}
}
}
2014-02-05 16:33:39 -05:00
2014-02-13 17:40:08 -05:00
public void leaveMuc ( Conversation conversation ) {
2015-10-16 03:58:31 -04:00
leaveMuc ( conversation , false ) ;
}
private void leaveMuc ( Conversation conversation , boolean now ) {
2014-07-18 15:57:10 -04:00
Account account = conversation . getAccount ( ) ;
account . pendingConferenceJoins . remove ( conversation ) ;
account . pendingConferenceLeaves . remove ( conversation ) ;
2015-10-16 03:58:31 -04:00
if ( account . getStatus ( ) = = Account . State . ONLINE | | now ) {
2014-07-18 15:57:10 -04:00
PresencePacket packet = new PresencePacket ( ) ;
2016-02-29 10:32:24 -05:00
packet . setTo ( conversation . getMucOptions ( ) . getSelf ( ) . getFullJid ( ) ) ;
2014-11-09 10:57:22 -05:00
packet . setFrom ( conversation . getAccount ( ) . getJid ( ) ) ;
2014-07-18 15:57:10 -04:00
packet . setAttribute ( " type " , " unavailable " ) ;
2014-08-26 10:52:42 -04:00
sendPresencePacket ( conversation . getAccount ( ) , packet ) ;
2014-07-18 15:57:10 -04:00
conversation . getMucOptions ( ) . setOffline ( ) ;
conversation . deregisterWithBookmark ( ) ;
2014-11-09 10:57:22 -05:00
Log . d ( Config . LOGTAG , conversation . getAccount ( ) . getJid ( ) . toBareJid ( )
2014-12-21 15:43:58 -05:00
+ " : leaving muc " + conversation . getJid ( ) ) ;
2014-07-18 15:57:10 -04:00
} else {
account . pendingConferenceLeaves . add ( conversation ) ;
}
2014-02-13 17:40:08 -05:00
}
2014-02-05 16:33:39 -05:00
2014-11-20 12:20:42 -05:00
private String findConferenceServer ( final Account account ) {
String server ;
if ( account . getXmppConnection ( ) ! = null ) {
server = account . getXmppConnection ( ) . getMucServer ( ) ;
if ( server ! = null ) {
return server ;
}
}
2015-01-19 05:17:27 -05:00
for ( Account other : getAccounts ( ) ) {
2014-11-20 12:20:42 -05:00
if ( other ! = account & & other . getXmppConnection ( ) ! = null ) {
server = other . getXmppConnection ( ) . getMucServer ( ) ;
if ( server ! = null ) {
return server ;
}
}
}
return null ;
}
2016-05-26 06:39:31 -04:00
public void createAdhocConference ( final Account account ,
final String subject ,
final Iterable < Jid > jids ,
final UiCallback < Conversation > callback ) {
2014-12-20 20:13:13 -05:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) . toString ( ) + " : creating adhoc conference with " + jids . toString ( ) ) ;
2014-11-20 12:20:42 -05:00
if ( account . getStatus ( ) = = Account . State . ONLINE ) {
try {
String server = findConferenceServer ( account ) ;
if ( server = = null ) {
if ( callback ! = null ) {
2015-01-19 05:17:27 -05:00
callback . error ( R . string . no_conference_server_found , null ) ;
2014-11-20 12:20:42 -05:00
}
return ;
}
2016-05-26 16:53:55 -04:00
final Jid jid = Jid . fromParts ( new BigInteger ( 64 , getRNG ( ) ) . toString ( Character . MAX_RADIX ) , server , null ) ;
2014-11-20 12:20:42 -05:00
final Conversation conversation = findOrCreateConversation ( account , jid , true ) ;
2016-02-17 10:50:48 -05:00
joinMuc ( conversation , new OnConferenceJoined ( ) {
2014-11-20 12:20:42 -05:00
@Override
2015-11-25 14:47:02 -05:00
public void onConferenceJoined ( final Conversation conversation ) {
2016-05-26 06:39:31 -04:00
pushConferenceConfiguration ( conversation , IqGenerator . defaultRoomConfiguration ( ) , new OnConferenceOptionsPushed ( ) {
2015-11-25 14:47:02 -05:00
@Override
public void onPushSucceeded ( ) {
2016-05-26 06:39:31 -04:00
if ( subject ! = null & & ! subject . trim ( ) . isEmpty ( ) ) {
2016-05-26 16:53:55 -04:00
pushSubjectToConference ( conversation , subject . trim ( ) ) ;
2016-05-26 06:39:31 -04:00
}
2015-11-25 14:47:02 -05:00
for ( Jid invite : jids ) {
invite ( conversation , invite ) ;
}
if ( account . countPresences ( ) > 1 ) {
directInvite ( conversation , account . getJid ( ) . toBareJid ( ) ) ;
}
2016-05-26 16:53:55 -04:00
saveConversationAsBookmark ( conversation , subject ) ;
2015-11-25 14:47:02 -05:00
if ( callback ! = null ) {
callback . success ( conversation ) ;
}
}
2014-11-20 12:20:42 -05:00
2015-11-25 14:47:02 -05:00
@Override
public void onPushFailed ( ) {
2016-05-26 16:53:55 -04:00
archiveConversation ( conversation ) ;
2015-11-25 14:47:02 -05:00
if ( callback ! = null ) {
callback . error ( R . string . conference_creation_failed , conversation ) ;
}
}
} ) ;
2014-11-20 12:20:42 -05:00
}
} ) ;
} catch ( InvalidJidException e ) {
if ( callback ! = null ) {
callback . error ( R . string . conference_creation_failed , null ) ;
}
}
} else {
if ( callback ! = null ) {
2015-01-19 05:17:27 -05:00
callback . error ( R . string . not_connected_try_again , null ) ;
2014-11-20 12:20:42 -05:00
}
}
}
2015-01-07 12:34:24 -05:00
public void fetchConferenceConfiguration ( final Conversation conversation ) {
2015-10-04 18:45:16 -04:00
fetchConferenceConfiguration ( conversation , null ) ;
}
public void fetchConferenceConfiguration ( final Conversation conversation , final OnConferenceConfigurationFetched callback ) {
2015-01-07 12:34:24 -05:00
IqPacket request = new IqPacket ( IqPacket . TYPE . GET ) ;
request . setTo ( conversation . getJid ( ) . toBareJid ( ) ) ;
request . query ( " http://jabber.org/protocol/disco#info " ) ;
sendIqPacket ( conversation . getAccount ( ) , request , new OnIqPacketReceived ( ) {
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
2016-02-29 10:32:24 -05:00
Element query = packet . findChild ( " query " , " http://jabber.org/protocol/disco#info " ) ;
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT & & query ! = null ) {
2015-01-08 08:45:44 -05:00
ArrayList < String > features = new ArrayList < > ( ) ;
2015-11-26 11:44:29 -05:00
for ( Element child : query . getChildren ( ) ) {
2015-01-07 12:34:24 -05:00
if ( child ! = null & & child . getName ( ) . equals ( " feature " ) ) {
String var = child . getAttribute ( " var " ) ;
if ( var ! = null ) {
features . add ( var ) ;
}
}
}
2016-01-25 15:17:53 -05:00
Element form = query . findChild ( " x " , " jabber:x:data " ) ;
2015-11-26 11:44:29 -05:00
if ( form ! = null ) {
conversation . getMucOptions ( ) . updateFormData ( Data . parse ( form ) ) ;
}
2015-01-07 12:34:24 -05:00
conversation . getMucOptions ( ) . updateFeatures ( features ) ;
2015-10-04 18:45:16 -04:00
if ( callback ! = null ) {
callback . onConferenceConfigurationFetched ( conversation ) ;
}
2016-02-29 10:32:24 -05:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : fetched muc configuration for " + conversation . getJid ( ) . toBareJid ( ) + " - " + features . toString ( ) ) ;
2015-01-08 15:29:26 -05:00
updateConversationUi ( ) ;
2015-10-22 05:20:36 -04:00
} else if ( packet . getType ( ) = = IqPacket . TYPE . ERROR ) {
if ( callback ! = null ) {
callback . onFetchFailed ( conversation , packet . getError ( ) ) ;
}
2015-01-07 12:34:24 -05:00
}
}
} ) ;
}
2015-01-19 05:17:27 -05:00
public void pushConferenceConfiguration ( final Conversation conversation , final Bundle options , final OnConferenceOptionsPushed callback ) {
2014-12-30 08:16:25 -05:00
IqPacket request = new IqPacket ( IqPacket . TYPE . GET ) ;
2014-12-21 15:43:58 -05:00
request . setTo ( conversation . getJid ( ) . toBareJid ( ) ) ;
2014-11-20 12:20:42 -05:00
request . query ( " http://jabber.org/protocol/muc#owner " ) ;
2015-01-19 05:17:27 -05:00
sendIqPacket ( conversation . getAccount ( ) , request , new OnIqPacketReceived ( ) {
2014-11-20 12:20:42 -05:00
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
2015-08-23 11:53:23 -04:00
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2014-11-20 12:20:42 -05:00
Data data = Data . parse ( packet . query ( ) . findChild ( " x " , " jabber:x:data " ) ) ;
for ( Field field : data . getFields ( ) ) {
2015-09-15 16:52:35 -04:00
if ( options . containsKey ( field . getFieldName ( ) ) ) {
field . setValue ( options . getString ( field . getFieldName ( ) ) ) ;
2014-11-20 12:20:42 -05:00
}
}
data . submit ( ) ;
2014-12-30 08:16:25 -05:00
IqPacket set = new IqPacket ( IqPacket . TYPE . SET ) ;
2014-12-21 15:43:58 -05:00
set . setTo ( conversation . getJid ( ) . toBareJid ( ) ) ;
2014-11-20 12:20:42 -05:00
set . query ( " http://jabber.org/protocol/muc#owner " ) . addChild ( data ) ;
sendIqPacket ( account , set , new OnIqPacketReceived ( ) {
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
2015-08-23 11:53:23 -04:00
if ( callback ! = null ) {
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2014-11-20 12:20:42 -05:00
callback . onPushSucceeded ( ) ;
2015-08-23 11:53:23 -04:00
} else {
2014-11-20 12:20:42 -05:00
callback . onPushFailed ( ) ;
}
}
}
} ) ;
} else {
if ( callback ! = null ) {
callback . onPushFailed ( ) ;
}
}
}
} ) ;
}
2015-01-10 17:10:32 -05:00
public void pushSubjectToConference ( final Conversation conference , final String subject ) {
MessagePacket packet = this . getMessageGenerator ( ) . conferenceSubject ( conference , subject ) ;
this . sendMessagePacket ( conference . getAccount ( ) , packet ) ;
final MucOptions mucOptions = conference . getMucOptions ( ) ;
final MucOptions . User self = mucOptions . getSelf ( ) ;
if ( ! mucOptions . persistent ( ) & & self . getAffiliation ( ) . ranks ( MucOptions . Affiliation . OWNER ) ) {
Bundle options = new Bundle ( ) ;
options . putString ( " muc#roomconfig_persistentroom " , " 1 " ) ;
2015-01-19 05:17:27 -05:00
this . pushConferenceConfiguration ( conference , options , null ) ;
2015-01-10 17:10:32 -05:00
}
}
2016-05-16 08:10:40 -04:00
public void changeAffiliationInConference ( final Conversation conference , Jid user , final MucOptions . Affiliation affiliation , final OnAffiliationChanged callback ) {
2015-01-07 09:03:29 -05:00
final Jid jid = user . toBareJid ( ) ;
IqPacket request = this . mIqGenerator . changeAffiliation ( conference , jid , affiliation . toString ( ) ) ;
2015-01-07 12:34:24 -05:00
sendIqPacket ( conference . getAccount ( ) , request , new OnIqPacketReceived ( ) {
2015-01-07 09:03:29 -05:00
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2016-05-16 08:10:40 -04:00
conference . getMucOptions ( ) . changeAffiliation ( jid , affiliation ) ;
2016-05-16 09:50:57 -04:00
getAvatarService ( ) . clear ( conference ) ;
2015-01-07 09:03:29 -05:00
callback . onAffiliationChangedSuccessful ( jid ) ;
} else {
2015-01-07 12:34:24 -05:00
callback . onAffiliationChangeFailed ( jid , R . string . could_not_change_affiliation ) ;
2015-01-07 09:03:29 -05:00
}
}
} ) ;
}
2015-01-09 07:28:01 -05:00
public void changeAffiliationsInConference ( final Conversation conference , MucOptions . Affiliation before , MucOptions . Affiliation after ) {
List < Jid > jids = new ArrayList < > ( ) ;
2015-01-19 05:17:27 -05:00
for ( MucOptions . User user : conference . getMucOptions ( ) . getUsers ( ) ) {
2016-05-16 08:10:40 -04:00
if ( user . getAffiliation ( ) = = before & & user . getRealJid ( ) ! = null ) {
jids . add ( user . getRealJid ( ) ) ;
2015-01-09 07:28:01 -05:00
}
}
IqPacket request = this . mIqGenerator . changeAffiliation ( conference , jids , after . toString ( ) ) ;
2015-05-26 05:31:33 -04:00
sendIqPacket ( conference . getAccount ( ) , request , mDefaultIqHandler ) ;
2015-01-09 07:28:01 -05:00
}
2015-01-07 19:23:53 -05:00
public void changeRoleInConference ( final Conversation conference , final String nick , MucOptions . Role role , final OnRoleChanged callback ) {
IqPacket request = this . mIqGenerator . changeRole ( conference , nick , role . toString ( ) ) ;
2015-01-19 05:17:27 -05:00
Log . d ( Config . LOGTAG , request . toString ( ) ) ;
2015-01-07 19:23:53 -05:00
sendIqPacket ( conference . getAccount ( ) , request , new OnIqPacketReceived ( ) {
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
Log . d ( Config . LOGTAG , packet . toString ( ) ) ;
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
callback . onRoleChangedSuccessful ( nick ) ;
} else {
callback . onRoleChangeFailed ( nick , R . string . could_not_change_role ) ;
}
}
} ) ;
}
2015-10-16 03:58:31 -04:00
private void disconnect ( Account account , boolean force ) {
2014-11-15 11:09:02 -05:00
if ( ( account . getStatus ( ) = = Account . State . ONLINE )
| | ( account . getStatus ( ) = = Account . State . DISABLED ) ) {
2016-06-04 10:16:14 -04:00
final XmppConnection connection = account . getXmppConnection ( ) ;
2014-03-16 09:12:30 -04:00
if ( ! force ) {
List < Conversation > conversations = getConversations ( ) ;
2014-11-09 19:24:35 -05:00
for ( Conversation conversation : conversations ) {
if ( conversation . getAccount ( ) = = account ) {
if ( conversation . getMode ( ) = = Conversation . MODE_MULTI ) {
2015-10-16 03:58:31 -04:00
leaveMuc ( conversation , true ) ;
2014-11-09 19:24:35 -05:00
} else {
if ( conversation . endOtrIfNeeded ( ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( )
+ " : ended otr session with "
2014-12-21 15:43:58 -05:00
+ conversation . getJid ( ) ) ;
2014-11-09 19:24:35 -05:00
}
}
}
}
2015-04-09 06:46:54 -04:00
sendOfflinePresence ( account ) ;
2014-02-13 17:40:08 -05:00
}
2016-06-04 10:16:14 -04:00
connection . disconnect ( force ) ;
2015-01-19 05:17:27 -05:00
}
2014-02-05 16:33:39 -05:00
}
2014-02-08 18:47:11 -05:00
@Override
public IBinder onBind ( Intent intent ) {
return mBinder ;
}
2014-02-16 10:32:15 -05:00
2014-02-27 18:22:56 -05:00
public void updateMessage ( Message message ) {
databaseBackend . updateMessage ( message ) ;
2014-10-14 12:16:03 -04:00
updateConversationUi ( ) ;
2014-02-27 18:22:56 -05:00
}
2014-06-03 09:48:51 -04:00
2016-02-19 18:01:39 -05:00
public void updateMessage ( Message message , String uuid ) {
databaseBackend . updateMessage ( message , uuid ) ;
updateConversationUi ( ) ;
}
2014-05-22 08:33:17 -04:00
protected void syncDirtyContacts ( Account account ) {
2014-06-03 09:48:51 -04:00
for ( Contact contact : account . getRoster ( ) . getContacts ( ) ) {
2014-05-22 08:33:17 -04:00
if ( contact . getOption ( Contact . Options . DIRTY_PUSH ) ) {
pushContactToServer ( contact ) ;
}
if ( contact . getOption ( Contact . Options . DIRTY_DELETE ) ) {
deleteContactOnServer ( contact ) ;
}
}
}
2014-02-27 18:22:56 -05:00
2014-02-20 11:00:50 -05:00
public void createContact ( Contact contact ) {
2015-11-28 14:11:38 -05:00
boolean autoGrant = getPreferences ( ) . getBoolean ( " grant_new_contacts " , true ) ;
2014-02-23 15:33:37 -05:00
if ( autoGrant ) {
2014-05-19 09:15:09 -04:00
contact . setOption ( Contact . Options . PREEMPTIVE_GRANT ) ;
contact . setOption ( Contact . Options . ASKING ) ;
2014-02-23 15:33:37 -05:00
}
2014-05-19 09:15:09 -04:00
pushContactToServer ( contact ) ;
2014-06-11 15:53:25 -04:00
}
public void onOtrSessionEstablished ( Conversation conversation ) {
2014-12-14 12:10:46 -05:00
final Account account = conversation . getAccount ( ) ;
final Session otrSession = conversation . getOtrSession ( ) ;
2014-08-31 10:28:21 -04:00
Log . d ( Config . LOGTAG ,
2014-11-09 10:57:22 -05:00
account . getJid ( ) . toBareJid ( ) + " otr session established with "
2015-01-19 05:17:27 -05:00
+ conversation . getJid ( ) + " / "
+ otrSession . getSessionID ( ) . getUserID ( ) ) ;
2015-06-29 08:22:26 -04:00
conversation . findUnsentMessagesWithEncryption ( Message . ENCRYPTION_OTR , new Conversation . OnMessageFound ( ) {
2014-12-14 12:10:46 -05:00
@Override
public void onMessageFound ( Message message ) {
2014-11-09 10:21:13 -05:00
SessionID id = otrSession . getSessionID ( ) ;
try {
2014-12-14 12:10:46 -05:00
message . setCounterpart ( Jid . fromString ( id . getAccountID ( ) + " / " + id . getUserID ( ) ) ) ;
2014-11-09 10:21:13 -05:00
} catch ( InvalidJidException e ) {
2014-12-14 12:10:46 -05:00
return ;
2014-11-09 10:21:13 -05:00
}
2015-06-28 05:19:07 -04:00
if ( message . needsUploading ( ) ) {
mJingleConnectionManager . createNewConnection ( message ) ;
} else {
2015-07-20 12:11:33 -04:00
MessagePacket outPacket = mMessageGenerator . generateOtrChat ( message ) ;
2014-11-09 19:24:35 -05:00
if ( outPacket ! = null ) {
2015-07-20 17:13:28 -04:00
mMessageGenerator . addDelay ( outPacket , message . getTimeSent ( ) ) ;
2014-12-14 12:10:46 -05:00
message . setStatus ( Message . STATUS_SEND ) ;
databaseBackend . updateMessage ( message ) ;
2014-11-09 19:24:35 -05:00
sendMessagePacket ( account , outPacket ) ;
}
}
2014-12-14 12:10:46 -05:00
updateConversationUi ( ) ;
}
} ) ;
2014-05-19 09:15:09 -04:00
}
2014-06-22 07:57:57 -04:00
2014-06-20 11:30:19 -04:00
public boolean renewSymmetricKey ( Conversation conversation ) {
Account account = conversation . getAccount ( ) ;
byte [ ] symmetricKey = new byte [ 32 ] ;
this . mRandom . nextBytes ( symmetricKey ) ;
Session otrSession = conversation . getOtrSession ( ) ;
2014-06-22 07:57:57 -04:00
if ( otrSession ! = null ) {
2014-06-20 11:30:19 -04:00
MessagePacket packet = new MessagePacket ( ) ;
packet . setType ( MessagePacket . TYPE_CHAT ) ;
2014-11-09 10:57:22 -05:00
packet . setFrom ( account . getJid ( ) ) ;
2015-09-01 16:37:52 -04:00
MessageGenerator . addMessageHints ( packet ) ;
2014-11-05 15:55:47 -05:00
packet . setAttribute ( " to " , otrSession . getSessionID ( ) . getAccountID ( ) + " / "
2014-11-09 10:21:13 -05:00
+ otrSession . getSessionID ( ) . getUserID ( ) ) ;
2014-06-20 11:30:19 -04:00
try {
2014-06-22 07:57:57 -04:00
packet . setBody ( otrSession
. transformSending ( CryptoHelper . FILETRANSFER
2015-01-20 12:01:39 -05:00
+ CryptoHelper . bytesToHex ( symmetricKey ) ) [ 0 ] ) ;
2014-08-26 10:52:42 -04:00
sendMessagePacket ( account , packet ) ;
2014-06-20 11:30:19 -04:00
conversation . setSymmetricKey ( symmetricKey ) ;
return true ;
} catch ( OtrException e ) {
return false ;
}
}
return false ;
}
2014-05-22 03:36:00 -04:00
2014-12-20 20:13:13 -05:00
public void pushContactToServer ( final Contact contact ) {
2014-05-22 08:33:17 -04:00
contact . resetOption ( Contact . Options . DIRTY_DELETE ) ;
2014-07-10 17:49:34 -04:00
contact . setOption ( Contact . Options . DIRTY_PUSH ) ;
2014-12-20 20:13:13 -05:00
final Account account = contact . getAccount ( ) ;
2014-11-15 11:09:02 -05:00
if ( account . getStatus ( ) = = Account . State . ONLINE ) {
2014-12-20 20:13:13 -05:00
final boolean ask = contact . getOption ( Contact . Options . ASKING ) ;
final boolean sendUpdates = contact
2015-01-19 05:17:27 -05:00
. getOption ( Contact . Options . PENDING_SUBSCRIPTION_REQUEST )
& & contact . getOption ( Contact . Options . PREEMPTIVE_GRANT ) ;
2014-12-30 08:16:25 -05:00
final IqPacket iq = new IqPacket ( IqPacket . TYPE . SET ) ;
2014-12-20 20:13:13 -05:00
iq . query ( Xmlns . ROSTER ) . addChild ( contact . asElement ( ) ) ;
2015-05-26 05:31:33 -04:00
account . getXmppConnection ( ) . sendIqPacket ( iq , mDefaultIqHandler ) ;
2014-07-12 06:28:28 -04:00
if ( sendUpdates ) {
2014-08-26 10:52:42 -04:00
sendPresencePacket ( account ,
mPresenceGenerator . sendPresenceUpdatesTo ( contact ) ) ;
2014-05-22 03:36:00 -04:00
}
2014-07-12 06:28:28 -04:00
if ( ask ) {
2014-08-26 10:52:42 -04:00
sendPresencePacket ( account ,
mPresenceGenerator . requestPresenceUpdatesFrom ( contact ) ) ;
2014-07-12 06:28:28 -04:00
}
2014-05-21 16:22:36 -04:00
}
2014-05-19 09:15:09 -04:00
}
2014-05-22 03:36:00 -04:00
2016-04-11 16:20:32 -04:00
public void publishAvatar ( Account account , Uri image , UiCallback < Avatar > callback ) {
2014-08-31 10:28:21 -04:00
final Bitmap . CompressFormat format = Config . AVATAR_FORMAT ;
final int size = Config . AVATAR_SIZE ;
2016-01-04 09:17:02 -05:00
final Avatar avatar = getFileBackend ( ) . getPepAvatar ( image , size , format ) ;
2014-08-26 10:52:42 -04:00
if ( avatar ! = null ) {
2014-08-04 19:36:17 -04:00
avatar . height = size ;
avatar . width = size ;
if ( format . equals ( Bitmap . CompressFormat . WEBP ) ) {
avatar . type = " image/webp " ;
} else if ( format . equals ( Bitmap . CompressFormat . JPEG ) ) {
avatar . type = " image/jpeg " ;
} else if ( format . equals ( Bitmap . CompressFormat . PNG ) ) {
avatar . type = " image/png " ;
}
2014-08-06 12:36:33 -04:00
if ( ! getFileBackend ( ) . save ( avatar ) ) {
callback . error ( R . string . error_saving_avatar , avatar ) ;
return ;
}
2016-04-11 16:20:32 -04:00
publishAvatar ( account , avatar , callback ) ;
} else {
callback . error ( R . string . error_publish_avatar_converting , null ) ;
}
}
2014-08-26 10:52:42 -04:00
2016-04-11 16:20:32 -04:00
public void publishAvatar ( Account account , final Avatar avatar , final UiCallback < Avatar > callback ) {
final IqPacket packet = this . mIqGenerator . publishAvatar ( avatar ) ;
this . sendIqPacket ( account , packet , new OnIqPacketReceived ( ) {
@Override
public void onIqPacketReceived ( Account account , IqPacket result ) {
if ( result . getType ( ) = = IqPacket . TYPE . RESULT ) {
final IqPacket packet = XmppConnectionService . this . mIqGenerator
. publishAvatarMetadata ( avatar ) ;
sendIqPacket ( account , packet , new OnIqPacketReceived ( ) {
@Override
public void onIqPacketReceived ( Account account , IqPacket result ) {
if ( result . getType ( ) = = IqPacket . TYPE . RESULT ) {
if ( account . setAvatar ( avatar . getFilename ( ) ) ) {
getAvatarService ( ) . clear ( account ) ;
databaseBackend . updateAccount ( account ) ;
}
if ( callback ! = null ) {
2014-08-04 19:36:17 -04:00
callback . success ( avatar ) ;
} else {
2016-04-11 16:20:32 -04:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : published avatar " ) ;
}
} else {
if ( callback ! = null ) {
2014-08-26 10:52:42 -04:00
callback . error (
R . string . error_publish_avatar_server_reject ,
avatar ) ;
2014-08-04 19:36:17 -04:00
}
}
2016-04-11 16:20:32 -04:00
}
} ) ;
} else {
if ( callback ! = null ) {
2014-08-26 10:52:42 -04:00
callback . error (
R . string . error_publish_avatar_server_reject ,
avatar ) ;
2014-08-04 19:36:17 -04:00
}
}
2016-04-11 16:20:32 -04:00
}
} ) ;
}
public void republishAvatarIfNeeded ( Account account ) {
if ( account . getAxolotlService ( ) . isPepBroken ( ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : skipping republication of avatar because pep is broken " ) ;
return ;
2014-08-03 14:28:13 -04:00
}
2016-04-11 16:20:32 -04:00
IqPacket packet = this . mIqGenerator . retrieveAvatarMetaData ( null ) ;
this . sendIqPacket ( account , packet , new OnIqPacketReceived ( ) {
private Avatar parseAvatar ( IqPacket packet ) {
Element pubsub = packet . findChild ( " pubsub " , " http://jabber.org/protocol/pubsub " ) ;
if ( pubsub ! = null ) {
Element items = pubsub . findChild ( " items " ) ;
if ( items ! = null ) {
return Avatar . parseMetadata ( items ) ;
}
}
return null ;
}
private boolean errorIsItemNotFound ( IqPacket packet ) {
Element error = packet . findChild ( " error " ) ;
return packet . getType ( ) = = IqPacket . TYPE . ERROR
& & error ! = null
& & error . hasChild ( " item-not-found " ) ;
}
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT | | errorIsItemNotFound ( packet ) ) {
Avatar serverAvatar = parseAvatar ( packet ) ;
if ( serverAvatar = = null & & account . getAvatar ( ) ! = null ) {
Avatar avatar = fileBackend . getStoredPepAvatar ( account . getAvatar ( ) ) ;
if ( avatar ! = null ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : avatar on server was null. republishing " ) ;
publishAvatar ( account , fileBackend . getStoredPepAvatar ( account . getAvatar ( ) ) , null ) ;
} else {
Log . e ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : error rereading avatar " ) ;
}
}
}
}
} ) ;
2014-08-03 14:28:13 -04:00
}
2014-08-26 10:52:42 -04:00
2014-08-15 11:31:24 -04:00
public void fetchAvatar ( Account account , Avatar avatar ) {
fetchAvatar ( account , avatar , null ) ;
}
2014-08-26 10:52:42 -04:00
2015-05-05 00:17:34 -04:00
public void fetchAvatar ( Account account , final Avatar avatar , final UiCallback < Avatar > callback ) {
2015-05-05 04:29:41 -04:00
final String KEY = generateFetchKey ( account , avatar ) ;
2015-10-16 03:58:31 -04:00
synchronized ( this . mInProgressAvatarFetches ) {
2016-04-12 11:52:58 -04:00
if ( ! this . mInProgressAvatarFetches . contains ( KEY ) ) {
2015-05-05 04:29:41 -04:00
switch ( avatar . origin ) {
case PEP :
this . mInProgressAvatarFetches . add ( KEY ) ;
fetchAvatarPep ( account , avatar , callback ) ;
break ;
case VCARD :
this . mInProgressAvatarFetches . add ( KEY ) ;
fetchAvatarVcard ( account , avatar , callback ) ;
break ;
}
}
2015-05-05 00:17:34 -04:00
}
}
private void fetchAvatarPep ( Account account , final Avatar avatar , final UiCallback < Avatar > callback ) {
IqPacket packet = this . mIqGenerator . retrievePepAvatar ( avatar ) ;
2014-08-05 16:58:46 -04:00
sendIqPacket ( account , packet , new OnIqPacketReceived ( ) {
2014-08-26 10:52:42 -04:00
2014-08-05 16:58:46 -04:00
@Override
public void onIqPacketReceived ( Account account , IqPacket result ) {
2015-05-05 04:29:41 -04:00
synchronized ( mInProgressAvatarFetches ) {
mInProgressAvatarFetches . remove ( generateFetchKey ( account , avatar ) ) ;
}
2014-11-09 10:57:22 -05:00
final String ERROR = account . getJid ( ) . toBareJid ( )
2015-01-19 05:17:27 -05:00
+ " : fetching avatar for " + avatar . owner + " failed " ;
2014-12-30 08:16:25 -05:00
if ( result . getType ( ) = = IqPacket . TYPE . RESULT ) {
2014-09-05 07:29:20 -04:00
avatar . image = mIqParser . avatarData ( result ) ;
if ( avatar . image ! = null ) {
if ( getFileBackend ( ) . save ( avatar ) ) {
2014-11-09 10:57:22 -05:00
if ( account . getJid ( ) . toBareJid ( ) . equals ( avatar . owner ) ) {
2014-09-05 07:29:20 -04:00
if ( account . setAvatar ( avatar . getFilename ( ) ) ) {
databaseBackend . updateAccount ( account ) ;
}
2014-10-21 08:57:16 -04:00
getAvatarService ( ) . clear ( account ) ;
2014-10-21 09:26:17 -04:00
updateConversationUi ( ) ;
updateAccountUi ( ) ;
2014-09-05 07:29:20 -04:00
} else {
Contact contact = account . getRoster ( )
2015-01-19 05:17:27 -05:00
. getContact ( avatar . owner ) ;
2015-05-05 00:17:34 -04:00
contact . setAvatar ( avatar ) ;
2014-10-21 08:57:16 -04:00
getAvatarService ( ) . clear ( contact ) ;
2014-10-21 09:26:17 -04:00
updateConversationUi ( ) ;
updateRosterUi ( ) ;
2014-08-21 06:32:50 -04:00
}
2014-09-05 07:29:20 -04:00
if ( callback ! = null ) {
callback . success ( avatar ) ;
}
2014-11-09 10:57:22 -05:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( )
2016-05-04 04:29:29 -04:00
+ " : successfully fetched pep avatar for " + avatar . owner ) ;
2014-09-05 07:29:20 -04:00
return ;
2014-08-15 11:31:24 -04:00
}
2014-09-05 07:29:20 -04:00
} else {
2014-09-08 06:51:01 -04:00
2014-09-05 07:29:20 -04:00
Log . d ( Config . LOGTAG , ERROR + " (parsing error) " ) ;
}
} else {
Element error = result . findChild ( " error " ) ;
2014-09-08 06:51:01 -04:00
if ( error = = null ) {
2014-09-05 07:29:20 -04:00
Log . d ( Config . LOGTAG , ERROR + " (server error) " ) ;
} else {
Log . d ( Config . LOGTAG , ERROR + error . toString ( ) ) ;
2014-08-15 11:31:24 -04:00
}
}
2014-08-26 10:52:42 -04:00
if ( callback ! = null ) {
2014-08-15 11:31:24 -04:00
callback . error ( 0 , null ) ;
}
2014-09-05 07:29:20 -04:00
2014-08-15 11:31:24 -04:00
}
} ) ;
}
2014-08-26 10:52:42 -04:00
2015-05-05 00:17:34 -04:00
private void fetchAvatarVcard ( final Account account , final Avatar avatar , final UiCallback < Avatar > callback ) {
IqPacket packet = this . mIqGenerator . retrieveVcardAvatar ( avatar ) ;
2015-05-20 06:47:04 -04:00
this . sendIqPacket ( account , packet , new OnIqPacketReceived ( ) {
2015-05-05 00:17:34 -04:00
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
2015-05-20 06:47:04 -04:00
synchronized ( mInProgressAvatarFetches ) {
mInProgressAvatarFetches . remove ( generateFetchKey ( account , avatar ) ) ;
2015-05-05 04:29:41 -04:00
}
2015-05-05 00:17:34 -04:00
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2015-05-20 06:47:04 -04:00
Element vCard = packet . findChild ( " vCard " , " vcard-temp " ) ;
2015-05-05 00:17:34 -04:00
Element photo = vCard ! = null ? vCard . findChild ( " PHOTO " ) : null ;
2015-05-14 08:42:21 -04:00
String image = photo ! = null ? photo . findChildContent ( " BINVAL " ) : null ;
2015-05-07 05:07:15 -04:00
if ( image ! = null ) {
avatar . image = image ;
2015-05-05 00:17:34 -04:00
if ( getFileBackend ( ) . save ( avatar ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( )
+ " : successfully fetched vCard avatar for " + avatar . owner ) ;
2015-12-03 12:18:34 -05:00
if ( avatar . owner . isBareJid ( ) ) {
2016-09-09 05:04:05 -04:00
if ( account . getJid ( ) . toBareJid ( ) . equals ( avatar . owner ) & & account . getAvatar ( ) = = null ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : had no avatar. replacing with vcard " ) ;
account . setAvatar ( avatar . getFilename ( ) ) ;
databaseBackend . updateAccount ( account ) ;
getAvatarService ( ) . clear ( account ) ;
updateAccountUi ( ) ;
} else {
Contact contact = account . getRoster ( ) . getContact ( avatar . owner ) ;
contact . setAvatar ( avatar ) ;
getAvatarService ( ) . clear ( contact ) ;
updateRosterUi ( ) ;
}
2015-12-03 12:18:34 -05:00
updateConversationUi ( ) ;
} else {
2016-01-25 15:17:53 -05:00
Conversation conversation = find ( account , avatar . owner . toBareJid ( ) ) ;
2015-12-03 12:18:34 -05:00
if ( conversation ! = null & & conversation . getMode ( ) = = Conversation . MODE_MULTI ) {
2016-05-16 08:10:40 -04:00
MucOptions . User user = conversation . getMucOptions ( ) . findUserByFullJid ( avatar . owner ) ;
2015-12-03 12:18:34 -05:00
if ( user ! = null ) {
2015-12-04 15:36:48 -05:00
if ( user . setAvatar ( avatar ) ) {
getAvatarService ( ) . clear ( user ) ;
updateConversationUi ( ) ;
updateMucRosterUi ( ) ;
}
2015-12-03 12:18:34 -05:00
}
}
}
2015-05-05 00:17:34 -04:00
}
}
}
}
} ) ;
}
public void checkForAvatar ( Account account , final UiCallback < Avatar > callback ) {
2014-08-15 11:31:24 -04:00
IqPacket packet = this . mIqGenerator . retrieveAvatarMetaData ( null ) ;
this . sendIqPacket ( account , packet , new OnIqPacketReceived ( ) {
2014-08-26 10:52:42 -04:00
2014-08-15 11:31:24 -04:00
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
2014-12-30 08:16:25 -05:00
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2016-04-11 16:20:32 -04:00
Element pubsub = packet . findChild ( " pubsub " , " http://jabber.org/protocol/pubsub " ) ;
2014-08-26 10:52:42 -04:00
if ( pubsub ! = null ) {
2014-08-15 11:31:24 -04:00
Element items = pubsub . findChild ( " items " ) ;
2014-08-26 10:52:42 -04:00
if ( items ! = null ) {
2014-08-15 11:31:24 -04:00
Avatar avatar = Avatar . parseMetadata ( items ) ;
2014-08-26 10:52:42 -04:00
if ( avatar ! = null ) {
2014-11-09 10:57:22 -05:00
avatar . owner = account . getJid ( ) . toBareJid ( ) ;
2014-08-15 11:31:24 -04:00
if ( fileBackend . isAvatarCached ( avatar ) ) {
2014-08-21 06:32:50 -04:00
if ( account . setAvatar ( avatar . getFilename ( ) ) ) {
databaseBackend . updateAccount ( account ) ;
}
2014-10-21 08:57:16 -04:00
getAvatarService ( ) . clear ( account ) ;
2014-08-15 11:31:24 -04:00
callback . success ( avatar ) ;
} else {
2015-05-05 00:17:34 -04:00
fetchAvatarPep ( account , avatar , callback ) ;
2014-08-15 11:31:24 -04:00
}
return ;
}
}
2014-08-06 12:36:33 -04:00
}
2014-08-05 16:58:46 -04:00
}
2014-08-15 11:31:24 -04:00
callback . error ( 0 , null ) ;
2014-08-05 16:58:46 -04:00
}
} ) ;
}
2014-08-26 10:52:42 -04:00
2014-05-19 09:15:09 -04:00
public void deleteContactOnServer ( Contact contact ) {
2014-07-11 07:52:27 -04:00
contact . resetOption ( Contact . Options . PREEMPTIVE_GRANT ) ;
2014-05-22 08:33:17 -04:00
contact . resetOption ( Contact . Options . DIRTY_PUSH ) ;
2014-07-09 19:55:19 -04:00
contact . setOption ( Contact . Options . DIRTY_DELETE ) ;
2014-05-19 09:15:09 -04:00
Account account = contact . getAccount ( ) ;
2014-11-15 11:09:02 -05:00
if ( account . getStatus ( ) = = Account . State . ONLINE ) {
2014-12-30 08:16:25 -05:00
IqPacket iq = new IqPacket ( IqPacket . TYPE . SET ) ;
2014-12-20 20:13:13 -05:00
Element item = iq . query ( Xmlns . ROSTER ) . addChild ( " item " ) ;
2014-11-05 15:55:47 -05:00
item . setAttribute ( " jid " , contact . getJid ( ) . toString ( ) ) ;
2014-05-22 03:36:00 -04:00
item . setAttribute ( " subscription " , " remove " ) ;
2015-05-26 05:31:33 -04:00
account . getXmppConnection ( ) . sendIqPacket ( iq , mDefaultIqHandler ) ;
2014-05-22 03:36:00 -04:00
}
2014-02-20 11:00:50 -05:00
}
2014-02-21 15:35:23 -05:00
2016-10-18 07:06:24 -04:00
public void updateConversation ( final Conversation conversation ) {
mDatabaseExecutor . execute ( new Runnable ( ) {
@Override
public void run ( ) {
databaseBackend . updateConversation ( conversation ) ;
}
} ) ;
2014-03-02 23:01:02 -05:00
}
2014-03-05 09:41:14 -05:00
2015-09-29 13:24:52 -04:00
private void reconnectAccount ( final Account account , final boolean force , final boolean interactive ) {
2015-03-05 09:46:33 -05:00
synchronized ( account ) {
2016-01-16 13:21:11 -05:00
XmppConnection connection = account . getXmppConnection ( ) ;
2016-03-03 07:31:59 -05:00
if ( connection = = null ) {
2016-01-16 13:21:11 -05:00
connection = createConnection ( account ) ;
account . setXmppConnection ( connection ) ;
2016-05-12 15:57:07 -04:00
} else {
connection . interrupt ( ) ;
2015-03-05 09:46:33 -05:00
}
if ( ! account . isOptionSet ( Account . OPTION_DISABLED ) ) {
2016-01-16 13:21:11 -05:00
if ( ! force ) {
2016-03-03 07:31:59 -05:00
disconnect ( account , false ) ;
2015-03-05 09:46:33 -05:00
}
2016-01-16 13:21:11 -05:00
Thread thread = new Thread ( connection ) ;
connection . setInteractive ( interactive ) ;
2016-03-20 12:24:41 -04:00
connection . prepareNewConnection ( ) ;
2015-03-05 09:46:33 -05:00
thread . start ( ) ;
2016-01-15 08:26:23 -05:00
scheduleWakeUpCall ( Config . CONNECT_DISCO_TIMEOUT , account . getUuid ( ) . hashCode ( ) ) ;
2015-03-05 09:46:33 -05:00
} else {
2016-03-03 07:31:59 -05:00
disconnect ( account , force ) ;
2015-03-05 09:46:33 -05:00
account . getRoster ( ) . clearPresences ( ) ;
2016-01-16 13:21:11 -05:00
connection . resetEverything ( ) ;
2016-04-05 07:31:03 -04:00
account . getAxolotlService ( ) . resetBrokenness ( ) ;
2015-03-05 09:46:33 -05:00
}
}
}
2014-03-11 10:44:22 -04:00
2015-03-05 09:46:33 -05:00
public void reconnectAccountInBackground ( final Account account ) {
new Thread ( new Runnable ( ) {
2014-03-10 14:22:13 -04:00
@Override
public void run ( ) {
2015-10-16 03:58:31 -04:00
reconnectAccount ( account , false , true ) ;
2014-03-08 14:14:47 -05:00
}
} ) . start ( ) ;
}
2014-03-14 17:40:56 -04:00
2014-11-20 12:20:42 -05:00
public void invite ( Conversation conversation , Jid contact ) {
2015-10-16 03:58:31 -04:00
Log . d ( Config . LOGTAG , conversation . getAccount ( ) . getJid ( ) . toBareJid ( ) + " : inviting " + contact + " to " + conversation . getJid ( ) . toBareJid ( ) ) ;
2014-07-21 10:04:53 -04:00
MessagePacket packet = mMessageGenerator . invite ( conversation , contact ) ;
2014-08-26 10:52:42 -04:00
sendMessagePacket ( conversation . getAccount ( ) , packet ) ;
2014-03-14 23:59:18 -04:00
}
2014-08-30 03:24:58 -04:00
2015-04-23 11:37:47 -04:00
public void directInvite ( Conversation conversation , Jid jid ) {
2015-05-20 06:47:04 -04:00
MessagePacket packet = mMessageGenerator . directInvite ( conversation , jid ) ;
2015-10-16 03:58:31 -04:00
sendMessagePacket ( conversation . getAccount ( ) , packet ) ;
2015-04-23 11:37:47 -04:00
}
2014-08-27 13:25:58 -04:00
public void resetSendingToWaiting ( Account account ) {
2014-08-30 03:24:58 -04:00
for ( Conversation conversation : getConversations ( ) ) {
2014-08-27 13:25:58 -04:00
if ( conversation . getAccount ( ) = = account ) {
2014-12-14 12:10:46 -05:00
conversation . findUnsentTextMessages ( new Conversation . OnMessageFound ( ) {
@Override
public void onMessageFound ( Message message ) {
2014-08-27 13:25:58 -04:00
markMessage ( message , Message . STATUS_WAITING ) ;
2014-12-14 12:10:46 -05:00
}
} ) ;
2014-08-27 13:25:58 -04:00
}
}
2014-03-14 23:59:18 -04:00
}
2014-05-01 16:33:49 -04:00
2015-03-01 08:15:40 -05:00
public Message markMessage ( final Account account , final Jid recipient , final String uuid , final int status ) {
2014-10-02 12:54:21 -04:00
if ( uuid = = null ) {
2015-03-01 08:15:40 -05:00
return null ;
}
for ( Conversation conversation : getConversations ( ) ) {
2015-03-16 18:23:51 -04:00
if ( conversation . getJid ( ) . toBareJid ( ) . equals ( recipient ) & & conversation . getAccount ( ) = = account ) {
2015-08-26 06:11:12 -04:00
final Message message = conversation . findSentMessageWithUuidOrRemoteId ( uuid ) ;
2015-03-01 08:15:40 -05:00
if ( message ! = null ) {
markMessage ( message , status ) ;
2015-01-19 05:17:27 -05:00
}
2015-03-01 08:15:40 -05:00
return message ;
2014-05-16 16:46:15 -04:00
}
}
2015-03-01 08:15:40 -05:00
return null ;
2014-05-16 16:46:15 -04:00
}
2014-05-18 05:25:04 -04:00
2015-08-26 06:11:12 -04:00
public boolean markMessage ( Conversation conversation , String uuid , int status ) {
2014-10-02 12:54:21 -04:00
if ( uuid = = null ) {
return false ;
} else {
2014-12-14 12:10:46 -05:00
Message message = conversation . findSentMessageWithUuid ( uuid ) ;
2015-01-19 05:17:27 -05:00
if ( message ! = null ) {
markMessage ( message , status ) ;
2014-12-14 12:10:46 -05:00
return true ;
} else {
return false ;
2014-04-11 03:13:56 -04:00
}
}
}
2014-05-01 16:33:49 -04:00
2014-04-11 03:13:56 -04:00
public void markMessage ( Message message , int status ) {
2014-09-08 06:51:01 -04:00
if ( status = = Message . STATUS_SEND_FAILED
& & ( message . getStatus ( ) = = Message . STATUS_SEND_RECEIVED | | message
2015-01-19 05:17:27 -05:00
. getStatus ( ) = = Message . STATUS_SEND_DISPLAYED ) ) {
2014-09-08 06:51:01 -04:00
return ;
2015-01-19 05:17:27 -05:00
}
2014-04-11 03:13:56 -04:00
message . setStatus ( status ) ;
databaseBackend . updateMessage ( message ) ;
2014-07-12 07:42:17 -04:00
updateConversationUi ( ) ;
2014-04-11 03:13:56 -04:00
}
2014-05-01 16:33:49 -04:00
2014-04-13 12:09:40 -04:00
public SharedPreferences getPreferences ( ) {
2014-05-01 16:33:49 -04:00
return PreferenceManager
2015-01-19 05:17:27 -05:00
. getDefaultSharedPreferences ( getApplicationContext ( ) ) ;
2014-04-13 12:09:40 -04:00
}
2014-09-08 17:58:37 -04:00
2014-06-04 12:44:15 -04:00
public boolean confirmMessages ( ) {
return getPreferences ( ) . getBoolean ( " confirm_messages " , true ) ;
2016-02-16 03:57:59 -05:00
}
public boolean allowMessageCorrection ( ) {
2016-07-17 16:42:37 -04:00
return getPreferences ( ) . getBoolean ( " allow_message_correction " , true ) ;
2014-06-03 09:48:51 -04:00
}
2014-09-08 17:58:37 -04:00
2015-02-21 05:06:52 -05:00
public boolean sendChatStates ( ) {
return getPreferences ( ) . getBoolean ( " chat_states " , false ) ;
}
2014-09-08 07:37:22 -04:00
public boolean saveEncryptedMessages ( ) {
return ! getPreferences ( ) . getBoolean ( " dont_save_encrypted " , false ) ;
}
2014-05-14 06:56:34 -04:00
2016-02-01 07:54:08 -05:00
private boolean respectAutojoin ( ) {
return getPreferences ( ) . getBoolean ( " autojoin " , true ) ;
}
2014-09-20 09:49:25 -04:00
public boolean indicateReceived ( ) {
return getPreferences ( ) . getBoolean ( " indicate_received " , false ) ;
2015-11-28 14:11:38 -05:00
}
public boolean useTorToConnect ( ) {
2015-12-14 04:54:55 -05:00
return Config . FORCE_ORBOT | | getPreferences ( ) . getBoolean ( " use_tor " , false ) ;
2014-09-20 09:49:25 -04:00
}
2016-01-25 15:17:53 -05:00
public boolean showExtendedConnectionOptions ( ) {
return getPreferences ( ) . getBoolean ( " show_connection_options " , false ) ;
}
2016-06-04 10:16:14 -04:00
public boolean broadcastLastActivity ( ) {
return getPreferences ( ) . getBoolean ( " last_activity " , false ) ;
}
2015-03-02 05:53:15 -05:00
public int unreadCount ( ) {
int count = 0 ;
2015-10-16 03:58:31 -04:00
for ( Conversation conversation : getConversations ( ) ) {
2015-03-02 05:53:15 -05:00
count + = conversation . unreadCount ( ) ;
}
return count ;
}
2015-07-10 07:28:50 -04:00
public void showErrorToastInUi ( int resId ) {
if ( mOnShowErrorToast ! = null ) {
mOnShowErrorToast . onShowErrorToast ( resId ) ;
}
}
2014-07-12 07:42:17 -04:00
public void updateConversationUi ( ) {
if ( mOnConversationUpdate ! = null ) {
mOnConversationUpdate . onConversationUpdate ( ) ;
}
}
2014-08-26 10:52:42 -04:00
2014-07-12 07:42:17 -04:00
public void updateAccountUi ( ) {
if ( mOnAccountUpdate ! = null ) {
mOnAccountUpdate . onAccountUpdate ( ) ;
}
}
2014-08-26 10:52:42 -04:00
2014-07-18 09:35:31 -04:00
public void updateRosterUi ( ) {
if ( mOnRosterUpdate ! = null ) {
mOnRosterUpdate . onRosterUpdate ( ) ;
}
}
2014-05-22 03:36:00 -04:00
2015-10-11 07:11:50 -04:00
public boolean displayCaptchaRequest ( Account account , String id , Data data , Bitmap captcha ) {
if ( mOnCaptchaRequested ! = null ) {
DisplayMetrics metrics = getApplicationContext ( ) . getResources ( ) . getDisplayMetrics ( ) ;
2015-10-16 03:58:31 -04:00
Bitmap scaled = Bitmap . createScaledBitmap ( captcha , ( int ) ( captcha . getWidth ( ) * metrics . scaledDensity ) ,
( int ) ( captcha . getHeight ( ) * metrics . scaledDensity ) , false ) ;
2015-10-11 07:11:50 -04:00
mOnCaptchaRequested . onCaptchaRequested ( account , id , data , scaled ) ;
2016-05-10 03:41:30 -04:00
return true ;
2015-10-11 07:11:50 -04:00
}
2016-05-10 03:41:30 -04:00
return false ;
2015-10-11 07:11:50 -04:00
}
2014-12-21 15:43:58 -05:00
public void updateBlocklistUi ( final OnUpdateBlocklist . Status status ) {
if ( mOnUpdateBlocklist ! = null ) {
mOnUpdateBlocklist . OnUpdateBlocklist ( status ) ;
}
}
2014-11-23 09:19:44 -05:00
public void updateMucRosterUi ( ) {
if ( mOnMucRosterUpdate ! = null ) {
mOnMucRosterUpdate . onMucRosterUpdate ( ) ;
}
}
2015-10-17 08:09:26 -04:00
public void keyStatusUpdated ( AxolotlService . FetchStatus report ) {
2015-10-16 03:58:31 -04:00
if ( mOnKeyStatusUpdated ! = null ) {
2015-10-17 08:09:26 -04:00
mOnKeyStatusUpdated . onKeyStatusUpdated ( report ) ;
2015-07-19 12:36:28 -04:00
}
}
2014-11-05 15:55:47 -05:00
public Account findAccountByJid ( final Jid accountJid ) {
2014-05-19 09:15:09 -04:00
for ( Account account : this . accounts ) {
2014-11-16 10:04:45 -05:00
if ( account . getJid ( ) . toBareJid ( ) . equals ( accountJid . toBareJid ( ) ) ) {
2014-05-19 09:15:09 -04:00
return account ;
}
}
return null ;
}
2014-08-26 10:52:42 -04:00
2014-07-16 18:03:37 -04:00
public Conversation findConversationByUuid ( String uuid ) {
for ( Conversation conversation : getConversations ( ) ) {
if ( conversation . getUuid ( ) . equals ( uuid ) ) {
return conversation ;
}
}
return null ;
}
2014-06-04 12:44:15 -04:00
2016-02-16 08:22:21 -05:00
public boolean markRead ( final Conversation conversation ) {
2016-08-27 09:25:37 -04:00
return markRead ( conversation , true ) ;
}
public boolean markRead ( final Conversation conversation , boolean clear ) {
if ( clear ) {
mNotificationService . clear ( conversation ) ;
}
2015-10-29 12:20:01 -04:00
final List < Message > readMessages = conversation . markRead ( ) ;
if ( readMessages . size ( ) > 0 ) {
Runnable runnable = new Runnable ( ) {
@Override
public void run ( ) {
for ( Message message : readMessages ) {
databaseBackend . updateMessage ( message ) ;
}
}
} ;
mDatabaseExecutor . execute ( runnable ) ;
2016-02-16 08:22:21 -05:00
updateUnreadCountBadge ( ) ;
return true ;
} else {
return false ;
2015-10-14 15:18:34 -04:00
}
2015-05-20 06:47:04 -04:00
}
2015-05-26 06:00:38 -04:00
public synchronized void updateUnreadCountBadge ( ) {
2015-05-20 06:47:04 -04:00
int count = unreadCount ( ) ;
2015-05-26 06:00:38 -04:00
if ( unreadCount ! = count ) {
Log . d ( Config . LOGTAG , " update unread count to " + count ) ;
if ( count > 0 ) {
2016-03-27 14:02:36 -04:00
ShortcutBadger . applyCount ( getApplicationContext ( ) , count ) ;
2015-05-26 06:00:38 -04:00
} else {
2016-03-27 14:02:36 -04:00
ShortcutBadger . removeCount ( getApplicationContext ( ) ) ;
2015-05-26 06:00:38 -04:00
}
unreadCount = count ;
2015-05-20 06:47:04 -04:00
}
2015-01-02 06:04:33 -05:00
}
public void sendReadMarker ( final Conversation conversation ) {
final Message markable = conversation . getLatestMarkableMessage ( ) ;
2016-02-16 08:22:21 -05:00
if ( this . markRead ( conversation ) ) {
updateConversationUi ( ) ;
}
2016-10-07 04:05:08 -04:00
if ( confirmMessages ( )
& & markable ! = null
& & markable . trusted ( )
& & markable . getRemoteMsgId ( ) ! = null ) {
2015-01-19 05:17:27 -05:00
Log . d ( Config . LOGTAG , conversation . getAccount ( ) . getJid ( ) . toBareJid ( ) + " : sending read marker to " + markable . getCounterpart ( ) . toString ( ) ) ;
2014-07-11 21:44:23 -04:00
Account account = conversation . getAccount ( ) ;
2014-11-19 11:40:42 -05:00
final Jid to = markable . getCounterpart ( ) ;
MessagePacket packet = mMessageGenerator . confirm ( account , to , markable . getRemoteMsgId ( ) ) ;
2015-01-19 05:17:27 -05:00
this . sendMessagePacket ( conversation . getAccount ( ) , packet ) ;
2014-07-11 21:44:23 -04:00
}
2014-06-04 12:44:15 -04:00
}
2014-08-26 10:52:42 -04:00
2014-06-20 11:30:19 -04:00
public SecureRandom getRNG ( ) {
return this . mRandom ;
}
2014-08-26 10:52:42 -04:00
2014-07-22 11:27:44 -04:00
public MemorizingTrustManager getMemorizingTrustManager ( ) {
return this . mMemorizingTrustManager ;
}
2014-06-20 11:30:19 -04:00
2015-04-02 07:35:42 -04:00
public void setMemorizingTrustManager ( MemorizingTrustManager trustManager ) {
this . mMemorizingTrustManager = trustManager ;
}
public void updateMemorizingTrustmanager ( ) {
final MemorizingTrustManager tm ;
final boolean dontTrustSystemCAs = getPreferences ( ) . getBoolean ( " dont_trust_system_cas " , false ) ;
if ( dontTrustSystemCAs ) {
2015-10-16 03:58:31 -04:00
tm = new MemorizingTrustManager ( getApplicationContext ( ) , null ) ;
2015-04-02 07:35:42 -04:00
} else {
tm = new MemorizingTrustManager ( getApplicationContext ( ) ) ;
}
setMemorizingTrustManager ( tm ) ;
}
2014-06-20 11:30:19 -04:00
public PowerManager getPowerManager ( ) {
return this . pm ;
}
2014-06-25 10:55:47 -04:00
2014-10-21 08:57:16 -04:00
public LruCache < String , Bitmap > getBitmapCache ( ) {
return this . mBitmapCache ;
}
2014-06-30 04:46:46 -04:00
public void syncRosterToDisk ( final Account account ) {
2015-06-05 02:46:06 -04:00
Runnable runnable = new Runnable ( ) {
2014-07-11 07:52:27 -04:00
2014-06-30 04:46:46 -04:00
@Override
public void run ( ) {
databaseBackend . writeRoster ( account . getRoster ( ) ) ;
}
2015-06-05 02:46:06 -04:00
} ;
mDatabaseExecutor . execute ( runnable ) ;
2014-07-11 07:52:27 -04:00
2014-06-30 04:46:46 -04:00
}
2014-07-11 07:52:27 -04:00
2014-07-10 13:42:37 -04:00
public List < String > getKnownHosts ( ) {
2014-12-20 20:13:13 -05:00
final List < String > hosts = new ArrayList < > ( ) ;
for ( final Account account : getAccounts ( ) ) {
2014-11-05 15:55:47 -05:00
if ( ! hosts . contains ( account . getServer ( ) . toString ( ) ) ) {
hosts . add ( account . getServer ( ) . toString ( ) ) ;
2014-07-10 13:42:37 -04:00
}
2014-12-20 20:13:13 -05:00
for ( final Contact contact : account . getRoster ( ) . getContacts ( ) ) {
2014-07-10 13:42:37 -04:00
if ( contact . showInRoster ( ) ) {
2014-11-05 15:55:47 -05:00
final String server = contact . getServer ( ) . toString ( ) ;
2014-07-11 07:52:27 -04:00
if ( server ! = null & & ! hosts . contains ( server ) ) {
2014-07-10 13:42:37 -04:00
hosts . add ( server ) ;
}
}
}
}
2016-05-10 04:53:44 -04:00
if ( Config . DOMAIN_LOCK ! = null & & ! hosts . contains ( Config . DOMAIN_LOCK ) ) {
hosts . add ( Config . DOMAIN_LOCK ) ;
}
if ( Config . MAGIC_CREATE_DOMAIN ! = null & & ! hosts . contains ( Config . MAGIC_CREATE_DOMAIN ) ) {
hosts . add ( Config . MAGIC_CREATE_DOMAIN ) ;
}
2014-07-10 13:42:37 -04:00
return hosts ;
}
2014-07-11 13:48:41 -04:00
public List < String > getKnownConferenceHosts ( ) {
2014-12-20 20:13:13 -05:00
final ArrayList < String > mucServers = new ArrayList < > ( ) ;
for ( final Account account : accounts ) {
2014-07-11 13:48:41 -04:00
if ( account . getXmppConnection ( ) ! = null ) {
2014-12-20 20:13:13 -05:00
final String server = account . getXmppConnection ( ) . getMucServer ( ) ;
2014-07-24 11:21:21 -04:00
if ( server ! = null & & ! mucServers . contains ( server ) ) {
2014-07-11 13:48:41 -04:00
mucServers . add ( server ) ;
}
}
}
return mucServers ;
}
2014-08-26 10:52:42 -04:00
2014-07-11 21:44:23 -04:00
public void sendMessagePacket ( Account account , MessagePacket packet ) {
2014-10-08 08:10:37 -04:00
XmppConnection connection = account . getXmppConnection ( ) ;
if ( connection ! = null ) {
connection . sendMessagePacket ( packet ) ;
}
2014-07-11 21:44:23 -04:00
}
2014-08-26 10:52:42 -04:00
2014-07-11 21:44:23 -04:00
public void sendPresencePacket ( Account account , PresencePacket packet ) {
2014-10-08 08:10:37 -04:00
XmppConnection connection = account . getXmppConnection ( ) ;
if ( connection ! = null ) {
connection . sendPresencePacket ( packet ) ;
}
2014-07-11 21:44:23 -04:00
}
2014-08-26 10:52:42 -04:00
2015-10-11 07:11:50 -04:00
public void sendCreateAccountWithCaptchaPacket ( Account account , String id , Data data ) {
2016-05-05 03:58:35 -04:00
final XmppConnection connection = account . getXmppConnection ( ) ;
2015-10-11 07:11:50 -04:00
if ( connection ! = null ) {
2016-05-05 03:58:35 -04:00
IqPacket request = mIqGenerator . generateCreateAccountWithCaptcha ( account , id , data ) ;
2016-08-25 07:50:54 -04:00
connection . sendUnmodifiedIqPacket ( request , connection . registrationResponseListener ) ;
2015-10-11 07:11:50 -04:00
}
}
2015-01-04 06:09:39 -05:00
public void sendIqPacket ( final Account account , final IqPacket packet , final OnIqPacketReceived callback ) {
2014-12-21 15:43:58 -05:00
final XmppConnection connection = account . getXmppConnection ( ) ;
2014-10-08 08:10:37 -04:00
if ( connection ! = null ) {
connection . sendIqPacket ( packet , callback ) ;
}
2014-07-14 05:47:42 -04:00
}
2014-08-26 10:52:42 -04:00
2015-01-25 18:48:56 -05:00
public void sendPresence ( final Account account ) {
2016-06-04 10:16:14 -04:00
sendPresence ( account , checkListeners ( ) & & broadcastLastActivity ( ) ) ;
}
private void sendPresence ( final Account account , final boolean includeIdleTimestamp ) {
2016-04-22 15:25:06 -04:00
PresencePacket packet ;
if ( manuallyChangePresence ( ) ) {
packet = mPresenceGenerator . selfPresence ( account , account . getPresenceStatus ( ) ) ;
String message = account . getPresenceStatusMessage ( ) ;
if ( message ! = null & & ! message . isEmpty ( ) ) {
packet . addChild ( new Element ( " status " ) . setContent ( message ) ) ;
}
} else {
packet = mPresenceGenerator . selfPresence ( account , getTargetPresence ( ) ) ;
}
2016-06-04 10:16:14 -04:00
if ( mLastActivity > 0 & & includeIdleTimestamp ) {
long since = Math . min ( mLastActivity , System . currentTimeMillis ( ) ) ; //don't send future dates
packet . addChild ( " idle " , " urn:xmpp:idle:1 " ) . setAttribute ( " since " , AbstractGenerator . getTimestamp ( since ) ) ;
}
2016-04-22 15:25:06 -04:00
sendPresencePacket ( account , packet ) ;
2015-10-07 18:35:04 -04:00
}
2016-06-01 15:51:46 -04:00
private void deactivateGracePeriod ( ) {
for ( Account account : getAccounts ( ) ) {
account . deactivateGracePeriod ( ) ;
}
}
2015-10-07 18:35:04 -04:00
public void refreshAllPresences ( ) {
2016-06-04 10:16:14 -04:00
boolean includeIdleTimestamp = checkListeners ( ) & & broadcastLastActivity ( ) ;
2015-10-07 18:35:04 -04:00
for ( Account account : getAccounts ( ) ) {
if ( ! account . isOptionSet ( Account . OPTION_DISABLED ) ) {
2016-06-04 10:16:14 -04:00
sendPresence ( account , includeIdleTimestamp ) ;
2015-10-07 18:35:04 -04:00
}
}
2015-01-25 18:48:56 -05:00
}
2016-02-12 05:39:27 -05:00
private void refreshAllGcmTokens ( ) {
for ( Account account : getAccounts ( ) ) {
2016-02-12 18:03:57 -05:00
if ( account . isOnlineAndConnected ( ) & & mPushManagementService . available ( account ) ) {
2016-02-12 05:39:27 -05:00
mPushManagementService . registerPushTokenOnServer ( account ) ;
}
}
}
2016-09-07 08:34:58 -04:00
private void sendOfflinePresence ( final Account account ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : sending offline presence " ) ;
2015-04-09 06:46:54 -04:00
sendPresencePacket ( account , mPresenceGenerator . sendOfflinePresence ( account ) ) ;
}
2014-07-11 21:44:23 -04:00
public MessageGenerator getMessageGenerator ( ) {
return this . mMessageGenerator ;
}
2014-08-26 10:52:42 -04:00
2014-07-11 21:44:23 -04:00
public PresenceGenerator getPresenceGenerator ( ) {
return this . mPresenceGenerator ;
}
2014-08-26 10:52:42 -04:00
2014-07-23 08:30:27 -04:00
public IqGenerator getIqGenerator ( ) {
2014-08-26 10:52:42 -04:00
return this . mIqGenerator ;
2014-07-23 08:30:27 -04:00
}
2014-08-26 10:52:42 -04:00
2015-01-19 05:17:27 -05:00
public IqParser getIqParser ( ) {
return this . mIqParser ;
}
2014-12-21 15:43:58 -05:00
2014-07-12 06:28:28 -04:00
public JingleConnectionManager getJingleConnectionManager ( ) {
return this . mJingleConnectionManager ;
}
2014-08-26 10:52:42 -04:00
2014-12-04 19:54:16 -05:00
public MessageArchiveService getMessageArchiveService ( ) {
return this . mMessageArchiveService ;
}
2014-11-17 14:02:46 -05:00
public List < Contact > findContacts ( Jid jid ) {
2014-11-05 15:55:47 -05:00
ArrayList < Contact > contacts = new ArrayList < > ( ) ;
2014-09-27 05:37:02 -04:00
for ( Account account : getAccounts ( ) ) {
if ( ! account . isOptionSet ( Account . OPTION_DISABLED ) ) {
2014-10-15 08:41:27 -04:00
Contact contact = account . getRoster ( ) . getContactFromRoster ( jid ) ;
2014-09-27 05:37:02 -04:00
if ( contact ! = null ) {
contacts . add ( contact ) ;
}
}
}
return contacts ;
}
2014-10-02 12:31:19 -04:00
2016-05-30 15:12:04 -04:00
public Conversation findFirstMuc ( Jid jid ) {
for ( Conversation conversation : getConversations ( ) ) {
if ( conversation . getJid ( ) . toBareJid ( ) . equals ( jid . toBareJid ( ) )
& & conversation . getMode ( ) = = Conversation . MODE_MULTI ) {
return conversation ;
}
}
return null ;
}
2014-09-29 12:28:13 -04:00
public NotificationService getNotificationService ( ) {
return this . mNotificationService ;
2014-09-28 09:21:56 -04:00
}
2014-10-13 19:06:45 -04:00
public HttpConnectionManager getHttpConnectionManager ( ) {
return this . mHttpConnectionManager ;
}
2014-10-20 15:08:33 -04:00
2014-12-21 15:43:58 -05:00
public void resendFailedMessages ( final Message message ) {
final Collection < Message > messages = new ArrayList < > ( ) ;
2014-11-09 19:24:35 -05:00
Message current = message ;
while ( current . getStatus ( ) = = Message . STATUS_SEND_FAILED ) {
messages . add ( current ) ;
if ( current . mergeable ( current . next ( ) ) ) {
current = current . next ( ) ;
} else {
break ;
}
}
2014-12-21 15:43:58 -05:00
for ( final Message msg : messages ) {
2015-07-28 06:54:54 -04:00
msg . setTime ( System . currentTimeMillis ( ) ) ;
2014-11-09 19:24:35 -05:00
markMessage ( msg , Message . STATUS_WAITING ) ;
2015-10-16 03:58:31 -04:00
this . resendMessage ( msg , false ) ;
2014-11-09 19:24:35 -05:00
}
}
2014-12-15 11:14:27 -05:00
public void clearConversationHistory ( final Conversation conversation ) {
conversation . clearMessages ( ) ;
2015-01-03 12:22:26 -05:00
conversation . setHasMessagesLeftOnServer ( false ) ; //avoid messages getting loaded through mam
2016-02-04 08:39:16 -05:00
conversation . setLastClearHistory ( System . currentTimeMillis ( ) ) ;
2015-10-29 12:20:01 -04:00
Runnable runnable = new Runnable ( ) {
2014-12-15 11:14:27 -05:00
@Override
public void run ( ) {
databaseBackend . deleteMessagesInConversation ( conversation ) ;
2016-09-16 05:07:52 -04:00
databaseBackend . updateConversation ( conversation ) ;
2014-12-15 11:14:27 -05:00
}
2015-10-29 12:20:01 -04:00
} ;
mDatabaseExecutor . execute ( runnable ) ;
2014-12-15 11:14:27 -05:00
}
2016-09-18 17:21:05 -04:00
public void sendBlockRequest ( final Blockable blockable , boolean reportSpam ) {
2014-12-21 15:43:58 -05:00
if ( blockable ! = null & & blockable . getBlockedJid ( ) ! = null ) {
final Jid jid = blockable . getBlockedJid ( ) ;
2016-09-18 17:21:05 -04:00
this . sendIqPacket ( blockable . getAccount ( ) , getIqGenerator ( ) . generateSetBlockRequest ( jid , reportSpam ) , new OnIqPacketReceived ( ) {
2014-12-21 15:43:58 -05:00
@Override
public void onIqPacketReceived ( final Account account , final IqPacket packet ) {
2014-12-30 08:16:25 -05:00
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2014-12-21 15:43:58 -05:00
account . getBlocklist ( ) . add ( jid ) ;
updateBlocklistUi ( OnUpdateBlocklist . Status . BLOCKED ) ;
}
}
} ) ;
}
}
public void sendUnblockRequest ( final Blockable blockable ) {
if ( blockable ! = null & & blockable . getJid ( ) ! = null ) {
final Jid jid = blockable . getBlockedJid ( ) ;
this . sendIqPacket ( blockable . getAccount ( ) , getIqGenerator ( ) . generateSetUnblockRequest ( jid ) , new OnIqPacketReceived ( ) {
@Override
public void onIqPacketReceived ( final Account account , final IqPacket packet ) {
2014-12-30 08:16:25 -05:00
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2014-12-21 15:43:58 -05:00
account . getBlocklist ( ) . remove ( jid ) ;
updateBlocklistUi ( OnUpdateBlocklist . Status . UNBLOCKED ) ;
}
}
} ) ;
}
}
2015-01-19 05:17:27 -05:00
2015-10-29 08:41:08 -04:00
public void publishDisplayName ( Account account ) {
String displayName = account . getDisplayName ( ) ;
if ( displayName ! = null & & ! displayName . isEmpty ( ) ) {
IqPacket publish = mIqGenerator . publishNick ( displayName ) ;
sendIqPacket ( account , publish , new OnIqPacketReceived ( ) {
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
if ( packet . getType ( ) = = IqPacket . TYPE . ERROR ) {
2016-02-03 04:40:02 -05:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : could not publish nick " ) ;
2015-10-29 08:41:08 -04:00
}
}
} ) ;
}
}
2016-05-19 04:41:56 -04:00
public ServiceDiscoveryResult getCachedServiceDiscoveryResult ( Pair < String , String > key ) {
2016-02-03 04:40:02 -05:00
ServiceDiscoveryResult result = discoCache . get ( key ) ;
if ( result ! = null ) {
return result ;
} else {
result = databaseBackend . findDiscoveryResult ( key . first , key . second ) ;
if ( result ! = null ) {
discoCache . put ( key , result ) ;
}
return result ;
}
}
public void fetchCaps ( Account account , final Jid jid , final Presence presence ) {
final Pair < String , String > key = new Pair < > ( presence . getHash ( ) , presence . getVer ( ) ) ;
ServiceDiscoveryResult disco = getCachedServiceDiscoveryResult ( key ) ;
if ( disco ! = null ) {
presence . setServiceDiscoveryResult ( disco ) ;
} else {
if ( ! account . inProgressDiscoFetches . contains ( key ) ) {
account . inProgressDiscoFetches . add ( key ) ;
IqPacket request = new IqPacket ( IqPacket . TYPE . GET ) ;
request . setTo ( jid ) ;
request . query ( " http://jabber.org/protocol/disco#info " ) ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : making disco request for " + key . second + " to " + jid ) ;
sendIqPacket ( account , request , new OnIqPacketReceived ( ) {
@Override
public void onIqPacketReceived ( Account account , IqPacket discoPacket ) {
if ( discoPacket . getType ( ) = = IqPacket . TYPE . RESULT ) {
ServiceDiscoveryResult disco = new ServiceDiscoveryResult ( discoPacket ) ;
if ( presence . getVer ( ) . equals ( disco . getVer ( ) ) ) {
databaseBackend . insertDiscoveryResult ( disco ) ;
injectServiceDiscorveryResult ( account . getRoster ( ) , presence . getHash ( ) , presence . getVer ( ) , disco ) ;
} else {
2016-02-12 05:39:27 -05:00
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : mismatch in caps for contact " + jid + " " + presence . getVer ( ) + " vs " + disco . getVer ( ) ) ;
2016-02-03 04:40:02 -05:00
}
}
account . inProgressDiscoFetches . remove ( key ) ;
}
} ) ;
}
}
}
private void injectServiceDiscorveryResult ( Roster roster , String hash , String ver , ServiceDiscoveryResult disco ) {
for ( Contact contact : roster . getContacts ( ) ) {
for ( Presence presence : contact . getPresences ( ) . getPresences ( ) . values ( ) ) {
if ( hash . equals ( presence . getHash ( ) ) & & ver . equals ( presence . getVer ( ) ) ) {
presence . setServiceDiscoveryResult ( disco ) ;
}
}
}
}
2016-02-09 07:01:17 -05:00
public void fetchMamPreferences ( Account account , final OnMamPreferencesFetched callback ) {
IqPacket request = new IqPacket ( IqPacket . TYPE . GET ) ;
request . addChild ( " prefs " , " urn:xmpp:mam:0 " ) ;
sendIqPacket ( account , request , new OnIqPacketReceived ( ) {
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
Element prefs = packet . findChild ( " prefs " , " urn:xmpp:mam:0 " ) ;
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT & & prefs ! = null ) {
callback . onPreferencesFetched ( prefs ) ;
} else {
callback . onPreferencesFetchFailed ( ) ;
}
}
} ) ;
}
2016-02-12 05:39:27 -05:00
public PushManagementService getPushManagementService ( ) {
return mPushManagementService ;
}
2016-04-19 12:03:24 -04:00
public Account getPendingAccount ( ) {
Account pending = null ;
for ( Account account : getAccounts ( ) ) {
if ( account . isOptionSet ( Account . OPTION_REGISTER ) ) {
pending = account ;
} else {
return null ;
}
}
return pending ;
}
2016-05-05 07:17:04 -04:00
public void changeStatus ( Account account , Presence . Status status , String statusMessage , boolean send ) {
2016-04-23 09:10:35 -04:00
if ( ! statusMessage . isEmpty ( ) ) {
databaseBackend . insertPresenceTemplate ( new PresenceTemplate ( status , statusMessage ) ) ;
}
2016-05-05 07:17:04 -04:00
changeStatusReal ( account , status , statusMessage , send ) ;
2016-04-22 15:25:06 -04:00
}
2016-05-05 07:17:04 -04:00
private void changeStatusReal ( Account account , Presence . Status status , String statusMessage , boolean send ) {
2016-04-22 15:25:06 -04:00
account . setPresenceStatus ( status ) ;
account . setPresenceStatusMessage ( statusMessage ) ;
databaseBackend . updateAccount ( account ) ;
2016-05-05 07:17:04 -04:00
if ( ! account . isOptionSet ( Account . OPTION_DISABLED ) & & send ) {
2016-04-22 15:25:06 -04:00
sendPresence ( account ) ;
}
}
public void changeStatus ( Presence . Status status , String statusMessage ) {
2016-04-23 09:10:35 -04:00
if ( ! statusMessage . isEmpty ( ) ) {
databaseBackend . insertPresenceTemplate ( new PresenceTemplate ( status , statusMessage ) ) ;
}
2016-04-22 15:25:06 -04:00
for ( Account account : getAccounts ( ) ) {
2016-05-05 07:17:04 -04:00
changeStatusReal ( account , status , statusMessage , true ) ;
2016-04-22 15:25:06 -04:00
}
}
2016-05-13 04:45:30 -04:00
public List < PresenceTemplate > getPresenceTemplates ( Account account ) {
List < PresenceTemplate > templates = databaseBackend . getPresenceTemplates ( ) ;
for ( PresenceTemplate template : account . getSelfContact ( ) . getPresences ( ) . asTemplates ( ) ) {
if ( ! templates . contains ( template ) ) {
templates . add ( 0 , template ) ;
}
}
return templates ;
}
2016-05-26 16:53:55 -04:00
public void saveConversationAsBookmark ( Conversation conversation , String name ) {
Account account = conversation . getAccount ( ) ;
Bookmark bookmark = new Bookmark ( account , conversation . getJid ( ) . toBareJid ( ) ) ;
if ( ! conversation . getJid ( ) . isBareJid ( ) ) {
bookmark . setNick ( conversation . getJid ( ) . getResourcepart ( ) ) ;
}
if ( name ! = null & & ! name . trim ( ) . isEmpty ( ) ) {
bookmark . setBookmarkName ( name . trim ( ) ) ;
}
bookmark . setAutojoin ( getPreferences ( ) . getBoolean ( " autojoin " , true ) ) ;
account . getBookmarks ( ) . add ( bookmark ) ;
pushBookmarks ( account ) ;
conversation . setBookmark ( bookmark ) ;
}
2016-02-09 07:01:17 -05:00
public interface OnMamPreferencesFetched {
void onPreferencesFetched ( Element prefs ) ;
void onPreferencesFetchFailed ( ) ;
}
public void pushMamPreferences ( Account account , Element prefs ) {
IqPacket set = new IqPacket ( IqPacket . TYPE . SET ) ;
set . addChild ( prefs ) ;
sendIqPacket ( account , set , null ) ;
}
2015-10-09 07:37:08 -04:00
public interface OnAccountCreated {
void onAccountCreated ( Account account ) ;
2015-10-16 03:58:31 -04:00
2015-10-09 07:37:08 -04:00
void informUser ( int r ) ;
}
2015-01-19 05:17:27 -05:00
public interface OnMoreMessagesLoaded {
2015-10-09 07:37:08 -04:00
void onMoreMessagesLoaded ( int count , Conversation conversation ) ;
2015-01-19 05:17:27 -05:00
2015-10-09 07:37:08 -04:00
void informUser ( int r ) ;
2015-01-19 05:17:27 -05:00
}
public interface OnAccountPasswordChanged {
2015-10-09 07:37:08 -04:00
void onPasswordChangeSucceeded ( ) ;
2015-01-19 05:17:27 -05:00
2015-10-09 07:37:08 -04:00
void onPasswordChangeFailed ( ) ;
2015-01-19 05:17:27 -05:00
}
public interface OnAffiliationChanged {
2015-10-09 07:37:08 -04:00
void onAffiliationChangedSuccessful ( Jid jid ) ;
2015-01-19 05:17:27 -05:00
2015-10-09 07:37:08 -04:00
void onAffiliationChangeFailed ( Jid jid , int resId ) ;
2015-01-19 05:17:27 -05:00
}
public interface OnRoleChanged {
2015-10-09 07:37:08 -04:00
void onRoleChangedSuccessful ( String nick ) ;
2015-01-19 05:17:27 -05:00
2015-10-09 07:37:08 -04:00
void onRoleChangeFailed ( String nick , int resid ) ;
2015-01-19 05:17:27 -05:00
}
public interface OnConversationUpdate {
2015-10-09 07:37:08 -04:00
void onConversationUpdate ( ) ;
2015-01-19 05:17:27 -05:00
}
public interface OnAccountUpdate {
2015-10-09 07:37:08 -04:00
void onAccountUpdate ( ) ;
2015-01-19 05:17:27 -05:00
}
2015-10-11 07:11:50 -04:00
public interface OnCaptchaRequested {
void onCaptchaRequested ( Account account ,
2015-10-16 03:58:31 -04:00
String id ,
Data data ,
Bitmap captcha ) ;
2015-10-11 07:11:50 -04:00
}
2015-01-19 05:17:27 -05:00
public interface OnRosterUpdate {
2015-10-09 07:37:08 -04:00
void onRosterUpdate ( ) ;
2015-01-19 05:17:27 -05:00
}
public interface OnMucRosterUpdate {
2015-10-09 07:37:08 -04:00
void onMucRosterUpdate ( ) ;
2015-01-19 05:17:27 -05:00
}
2015-10-04 18:45:16 -04:00
public interface OnConferenceConfigurationFetched {
2015-10-09 07:37:08 -04:00
void onConferenceConfigurationFetched ( Conversation conversation ) ;
2015-10-22 05:20:36 -04:00
void onFetchFailed ( Conversation conversation , Element error ) ;
2015-10-04 18:45:16 -04:00
}
2015-11-25 14:47:02 -05:00
public interface OnConferenceJoined {
void onConferenceJoined ( Conversation conversation ) ;
}
2015-01-19 05:17:27 -05:00
public interface OnConferenceOptionsPushed {
2015-10-09 07:37:08 -04:00
void onPushSucceeded ( ) ;
2015-01-19 05:17:27 -05:00
2015-10-09 07:37:08 -04:00
void onPushFailed ( ) ;
2015-01-19 05:17:27 -05:00
}
2015-07-10 07:28:50 -04:00
public interface OnShowErrorToast {
void onShowErrorToast ( int resId ) ;
}
2015-01-19 05:17:27 -05:00
public class XmppConnectionBinder extends Binder {
public XmppConnectionService getService ( ) {
return XmppConnectionService . this ;
}
}
2014-04-07 17:58:59 -04:00
}