2014-02-28 17:46:01 +00:00
package eu.siacs.conversations.services ;
2014-01-24 01:04:05 +00:00
2014-11-10 00:24:35 +00:00
import android.annotation.SuppressLint ;
2016-05-28 12:44:22 +00:00
import android.annotation.TargetApi ;
2014-11-10 00:24:35 +00:00
import android.app.AlarmManager ;
import android.app.PendingIntent ;
import android.app.Service ;
import android.content.Context ;
import android.content.Intent ;
2015-10-07 22:35:04 +00:00
import android.content.IntentFilter ;
2014-11-10 00:24:35 +00:00
import android.content.SharedPreferences ;
import android.database.ContentObserver ;
import android.graphics.Bitmap ;
2015-10-07 22:35:04 +00:00
import android.media.AudioManager ;
2014-11-10 00:24:35 +00:00
import android.net.ConnectivityManager ;
import android.net.NetworkInfo ;
import android.net.Uri ;
import android.os.Binder ;
2015-10-07 22:35:04 +00:00
import android.os.Build ;
2014-11-10 00:24:35 +00:00
import android.os.Bundle ;
2016-07-23 14:12:45 +00:00
import android.os.Environment ;
2014-11-10 00:24:35 +00: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 11:37:08 +00:00
import android.security.KeyChain ;
2017-07-01 11:41:24 +00:00
import android.support.annotation.BoolRes ;
import android.support.annotation.IntegerRes ;
2016-08-25 15:30:44 +00:00
import android.support.v4.app.RemoteInput ;
2015-10-16 07:58:31 +00:00
import android.util.DisplayMetrics ;
2014-11-10 00:24:35 +00:00
import android.util.Log ;
import android.util.LruCache ;
2015-10-11 13:48:58 +00:00
import android.util.Pair ;
2014-11-10 00:24:35 +00:00
2015-10-29 13:03:41 +00:00
import org.openintents.openpgp.IOpenPgpService2 ;
2014-11-10 00:24:35 +00:00
import org.openintents.openpgp.util.OpenPgpApi ;
import org.openintents.openpgp.util.OpenPgpServiceConnection ;
2014-11-20 17:20:42 +00:00
import java.math.BigInteger ;
2017-02-07 18:32:12 +00:00
import java.net.URL ;
2014-06-20 15:30:19 +00:00
import java.security.SecureRandom ;
2015-10-11 13:48:58 +00:00
import java.security.cert.CertificateException ;
2015-10-09 11:37:08 +00:00
import java.security.cert.X509Certificate ;
2014-07-10 17:42:37 +00:00
import java.util.ArrayList ;
2015-04-21 20:17:58 +00:00
import java.util.Arrays ;
2014-12-21 20:43:58 +00:00
import java.util.Collection ;
2014-03-19 15:16:40 +00:00
import java.util.Collections ;
2015-12-27 16:29:32 +00:00
import java.util.HashMap ;
2016-05-02 12:31:30 +00:00
import java.util.HashSet ;
2014-02-01 14:07:20 +00:00
import java.util.Hashtable ;
2015-05-05 08:29:41 +00:00
import java.util.Iterator ;
2014-01-25 18:33:12 +00:00
import java.util.List ;
2017-01-22 17:58:49 +00:00
import java.util.ListIterator ;
2014-12-21 20:43:58 +00:00
import java.util.Map ;
2018-03-11 11:13:56 +00:00
import java.util.Set ;
2014-07-12 10:41:37 +00:00
import java.util.concurrent.CopyOnWriteArrayList ;
2018-01-20 19:05:39 +00:00
import java.util.concurrent.CountDownLatch ;
2017-05-31 14:45:51 +00:00
import java.util.concurrent.atomic.AtomicBoolean ;
2017-01-23 16:14:30 +00:00
import java.util.concurrent.atomic.AtomicLong ;
2014-02-13 22:40:08 +00:00
2014-08-31 14:28:21 +00:00
import eu.siacs.conversations.Config ;
2014-08-04 23:36:17 +00:00
import eu.siacs.conversations.R ;
2018-03-27 13:35:53 +00:00
import eu.siacs.conversations.crypto.OmemoSetting ;
2016-06-13 11:32:14 +00:00
import eu.siacs.conversations.crypto.PgpDecryptionService ;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.crypto.PgpEngine ;
2015-10-16 21:48:42 +00:00
import eu.siacs.conversations.crypto.axolotl.AxolotlService ;
2016-11-17 19:09:42 +00:00
import eu.siacs.conversations.crypto.axolotl.FingerprintStatus ;
2015-07-20 21:13:28 +00:00
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage ;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.entities.Account ;
2014-12-21 20:43:58 +00:00
import eu.siacs.conversations.entities.Blockable ;
2014-07-14 09:47:42 +00:00
import eu.siacs.conversations.entities.Bookmark ;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.entities.Contact ;
import eu.siacs.conversations.entities.Conversation ;
2016-07-23 14:12:45 +00:00
import eu.siacs.conversations.entities.DownloadableFile ;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.entities.Message ;
2014-03-03 04:01:02 +00:00
import eu.siacs.conversations.entities.MucOptions ;
import eu.siacs.conversations.entities.MucOptions.OnRenameListener ;
2016-01-17 21:28:38 +00:00
import eu.siacs.conversations.entities.Presence ;
2016-04-22 19:25:06 +00:00
import eu.siacs.conversations.entities.PresenceTemplate ;
2016-02-03 09:40:02 +00:00
import eu.siacs.conversations.entities.Roster ;
import eu.siacs.conversations.entities.ServiceDiscoveryResult ;
2015-07-20 12:26:29 +00:00
import eu.siacs.conversations.entities.Transferable ;
import eu.siacs.conversations.entities.TransferablePlaceholder ;
2016-06-04 14:16:14 +00:00
import eu.siacs.conversations.generator.AbstractGenerator ;
2014-07-23 12:30:27 +00:00
import eu.siacs.conversations.generator.IqGenerator ;
2014-06-22 15:24:47 +00:00
import eu.siacs.conversations.generator.MessageGenerator ;
2014-07-12 01:44:23 +00:00
import eu.siacs.conversations.generator.PresenceGenerator ;
2014-10-13 23:06:45 +00:00
import eu.siacs.conversations.http.HttpConnectionManager ;
2018-05-25 10:24:23 +00:00
import eu.siacs.conversations.http.CustomURLStreamHandlerFactory ;
2016-05-17 12:25:58 +00:00
import eu.siacs.conversations.parser.AbstractParser ;
2014-07-12 10:28:28 +00:00
import eu.siacs.conversations.parser.IqParser ;
2014-05-14 10:56:34 +00:00
import eu.siacs.conversations.parser.MessageParser ;
2014-06-06 16:26:40 +00:00
import eu.siacs.conversations.parser.PresenceParser ;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.persistance.DatabaseBackend ;
2014-04-05 19:06:10 +00:00
import eu.siacs.conversations.persistance.FileBackend ;
2016-11-21 10:03:38 +00:00
import eu.siacs.conversations.ui.SettingsActivity ;
2014-05-12 12:59:46 +00:00
import eu.siacs.conversations.ui.UiCallback ;
2018-04-26 11:22:31 +00:00
import eu.siacs.conversations.ui.interfaces.OnSearchResultsAvailable ;
2016-07-23 14:12:45 +00:00
import eu.siacs.conversations.utils.ConversationsFileObserver ;
2014-06-20 15:30:19 +00:00
import eu.siacs.conversations.utils.CryptoHelper ;
2014-03-09 12:21:28 +00:00
import eu.siacs.conversations.utils.ExceptionHelper ;
2016-12-30 20:48:39 +00:00
import eu.siacs.conversations.utils.MimeUtils ;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener ;
2014-06-20 15:30:19 +00:00
import eu.siacs.conversations.utils.PRNGFixes ;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.utils.PhoneHelper ;
2018-04-11 16:07:40 +00:00
import eu.siacs.conversations.utils.QuickLoader ;
2016-05-31 15:20:21 +00:00
import eu.siacs.conversations.utils.ReplacingSerialSingleThreadExecutor ;
2018-03-18 15:46:50 +00:00
import eu.siacs.conversations.utils.ReplacingTaskManager ;
2017-06-21 21:28:01 +00:00
import eu.siacs.conversations.utils.Resolver ;
2015-06-05 06:46:06 +00:00
import eu.siacs.conversations.utils.SerialSingleThreadExecutor ;
2018-04-15 16:31:58 +00:00
import eu.siacs.conversations.utils.WakeLockHelper ;
2017-03-01 12:01:46 +00:00
import eu.siacs.conversations.xml.Namespace ;
2016-11-17 19:09:42 +00:00
import eu.siacs.conversations.utils.XmppUri ;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.xml.Element ;
2014-03-14 19:43:54 +00:00
import eu.siacs.conversations.xmpp.OnBindListener ;
2014-05-23 08:54:40 +00:00
import eu.siacs.conversations.xmpp.OnContactStatusChanged ;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.xmpp.OnIqPacketReceived ;
2015-08-25 10:40:22 +00:00
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated ;
2014-08-26 14:52:42 +00:00
import eu.siacs.conversations.xmpp.OnMessageAcknowledged ;
2014-12-21 20:43:58 +00:00
import eu.siacs.conversations.xmpp.OnMessagePacketReceived ;
import eu.siacs.conversations.xmpp.OnPresencePacketReceived ;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.xmpp.OnStatusChanged ;
2014-12-21 20:43:58 +00:00
import eu.siacs.conversations.xmpp.OnUpdateBlocklist ;
2017-02-19 12:05:40 +00:00
import eu.siacs.conversations.xmpp.Patches ;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.xmpp.XmppConnection ;
2015-02-21 10:06:52 +00:00
import eu.siacs.conversations.xmpp.chatstate.ChatState ;
2014-11-20 17:33:04 +00:00
import eu.siacs.conversations.xmpp.forms.Data ;
2014-04-08 21:15:55 +00:00
import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager ;
import eu.siacs.conversations.xmpp.jingle.OnJinglePacketReceived ;
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket ;
2017-05-07 19:05:35 +00:00
import eu.siacs.conversations.xmpp.mam.MamReference ;
2014-08-03 18:28:13 +00:00
import eu.siacs.conversations.xmpp.pep.Avatar ;
2014-03-10 18:22:13 +00: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 10:47:04 +00:00
import me.leolin.shortcutbadger.ShortcutBadger ;
2018-03-05 17:30:40 +00:00
import rocks.xmpp.addr.Jid ;
2014-01-24 01:04:05 +00:00
2016-05-31 15:20:21 +00:00
public class XmppConnectionService extends Service {
2014-02-03 17:38:47 +00:00
2016-08-25 15:30:44 +00:00
public static final String ACTION_REPLY_TO_CONVERSATION = " reply_to_conversations " ;
2017-04-14 11:23:01 +00:00
public static final String ACTION_MARK_AS_READ = " mark_as_read " ;
2018-01-28 12:14:30 +00:00
public static final String ACTION_SNOOZE = " snooze " ;
2014-12-21 20:43:58 +00:00
public static final String ACTION_CLEAR_NOTIFICATION = " clear_notification " ;
2016-10-04 09:16:59 +00:00
public static final String ACTION_DISMISS_ERROR_NOTIFICATIONS = " dismiss_error " ;
2015-02-10 16:13:34 +00:00
public static final String ACTION_TRY_AGAIN = " try_again " ;
2016-05-28 12:44:22 +00:00
public static final String ACTION_IDLE_PING = " idle_ping " ;
2018-05-19 18:05:45 +00:00
public static final String ACTION_FCM_TOKEN_REFRESH = " fcm_token_refresh " ;
public static final String ACTION_FCM_MESSAGE_RECEIVED = " fcm_message_received " ;
2018-03-18 09:30:15 +00:00
private static final String ACTION_MERGE_PHONE_CONTACTS = " merge_phone_contacts " ;
static {
2018-05-25 10:24:23 +00:00
URL . setURLStreamHandlerFactory ( new CustomURLStreamHandlerFactory ( ) ) ;
2018-03-18 09:30:15 +00:00
}
public final CountDownLatch restoredFromDatabaseLatch = new CountDownLatch ( 1 ) ;
2017-11-16 14:53:03 +00:00
private final SerialSingleThreadExecutor mFileAddingExecutor = new SerialSingleThreadExecutor ( " FileAdding " ) ;
private final SerialSingleThreadExecutor mVideoCompressionExecutor = new SerialSingleThreadExecutor ( " VideoCompression " ) ;
private final SerialSingleThreadExecutor mDatabaseWriterExecutor = new SerialSingleThreadExecutor ( " DatabaseWriter " ) ;
private final SerialSingleThreadExecutor mDatabaseReaderExecutor = new SerialSingleThreadExecutor ( " DatabaseReader " ) ;
2018-01-20 19:05:39 +00:00
private final SerialSingleThreadExecutor mNotificationExecutor = new SerialSingleThreadExecutor ( " NotificationExecutor " ) ;
2018-03-18 15:46:50 +00:00
private final ReplacingTaskManager mRosterSyncTaskManager = new ReplacingTaskManager ( ) ;
2015-10-16 07:58:31 +00: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 16:02:11 +00:00
private final HashSet < Jid > mLowPingTimeoutMode = new HashSet < > ( ) ;
2018-04-14 16:43:11 +00:00
private final OnIqPacketReceived mDefaultIqHandler = ( account , 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 ( ) . asBareJid ( ) + " : received iq error - " + text ) ;
}
}
} ;
2015-10-16 07:58:31 +00:00
public DatabaseBackend databaseBackend ;
2018-03-18 09:30:15 +00:00
private ReplacingSerialSingleThreadExecutor mContactMergerExecutor = new ReplacingSerialSingleThreadExecutor ( true ) ;
private long mLastActivity = 0 ;
2014-11-10 00:24:35 +00: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 07:58:31 +00:00
private FileBackend fileBackend = new FileBackend ( this ) ;
private MemorizingTrustManager mMemorizingTrustManager ;
2017-05-31 14:45:51 +00:00
private NotificationService mNotificationService = new NotificationService ( this ) ;
private ShortcutService mShortcutService = new ShortcutService ( this ) ;
private AtomicBoolean mInitialAddressbookSyncCompleted = new AtomicBoolean ( false ) ;
2017-09-18 15:56:25 +00:00
private AtomicBoolean mForceForegroundService = new AtomicBoolean ( false ) ;
2015-10-16 07:58:31 +00:00
private OnMessagePacketReceived mMessageParser = new MessageParser ( this ) ;
private OnPresencePacketReceived mPresenceParser = new PresenceParser ( this ) ;
private IqParser mIqParser = new IqParser ( this ) ;
private MessageGenerator mMessageGenerator = new MessageGenerator ( this ) ;
2018-03-18 11:24:28 +00:00
public OnContactStatusChanged onContactStatusChanged = ( contact , online ) - > {
Conversation conversation = find ( getConversations ( ) , contact ) ;
if ( conversation ! = null ) {
if ( online ) {
if ( contact . getPresences ( ) . size ( ) = = 1 ) {
sendUnsentMessages ( conversation ) ;
2014-11-10 00:24:35 +00:00
}
}
}
} ;
2018-03-18 09:30:15 +00:00
private PresenceGenerator mPresenceGenerator = new PresenceGenerator ( this ) ;
private List < Account > accounts ;
private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager (
this ) ;
private final OnJinglePacketReceived jingleListener = new OnJinglePacketReceived ( ) {
@Override
public void onJinglePacketReceived ( Account account , JinglePacket packet ) {
mJingleConnectionManager . deliverPacket ( account , packet ) ;
}
} ;
2015-10-16 07:58:31 +00:00
private HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager (
2014-10-21 12:57:16 +00:00
this ) ;
2015-10-16 07:58:31 +00:00
private AvatarService mAvatarService = new AvatarService ( this ) ;
private MessageArchiveService mMessageArchiveService = new MessageArchiveService ( this ) ;
2016-02-12 10:39:27 +00:00
private PushManagementService mPushManagementService = new PushManagementService ( this ) ;
2016-07-23 14:12:45 +00:00
private final ConversationsFileObserver fileObserver = new ConversationsFileObserver (
Environment . getExternalStorageDirectory ( ) . getAbsolutePath ( )
) {
2015-05-26 09:31:33 +00:00
@Override
2015-10-16 07:58:31 +00:00
public void onEvent ( int event , String path ) {
2016-07-23 14:12:45 +00:00
markFileDeleted ( path ) ;
2015-10-16 07:58:31 +00:00
}
} ;
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 09:31:33 +00:00
}
}
}
} ;
2018-05-03 12:54:22 +00:00
2015-07-03 20:08:23 +00:00
private int unreadCount = - 1 ;
2018-05-03 12:54:22 +00:00
//Ui callback listeners
private final List < OnConversationUpdate > mOnConversationUpdates = new ArrayList < > ( ) ;
private final List < OnShowErrorToast > mOnShowErrorToasts = new ArrayList < > ( ) ;
private final List < OnAccountUpdate > mOnAccountUpdates = new ArrayList < > ( ) ;
private final List < OnCaptchaRequested > mOnCaptchaRequested = new ArrayList < > ( ) ;
private final List < OnRosterUpdate > mOnRosterUpdates = new ArrayList < > ( ) ;
private final List < OnUpdateBlocklist > mOnUpdateBlocklist = new ArrayList < > ( ) ;
private final List < OnMucRosterUpdate > mOnMucRosterUpdate = new ArrayList < > ( ) ;
private final List < OnKeyStatusUpdated > mOnKeyStatusUpdated = new ArrayList < > ( ) ;
2015-10-16 07:58:31 +00:00
private final OnBindListener mOnBindListener = new OnBindListener ( ) {
@Override
public void onBind ( final Account account ) {
2016-03-03 12:33:02 +00:00
synchronized ( mInProgressAvatarFetches ) {
for ( Iterator < String > iterator = mInProgressAvatarFetches . iterator ( ) ; iterator . hasNext ( ) ; ) {
final String KEY = iterator . next ( ) ;
2018-03-05 17:30:40 +00:00
if ( KEY . startsWith ( account . getJid ( ) . asBareJid ( ) + " _ " ) ) {
2016-03-03 12:33:02 +00:00
iterator . remove ( ) ;
}
}
}
2018-03-18 09:30:15 +00:00
boolean needsUpdating = account . setOption ( Account . OPTION_LOGGED_IN_SUCCESSFULLY , true ) ;
needsUpdating | = account . setOption ( Account . OPTION_HTTP_UPLOAD_AVAILABLE , account . getXmppConnection ( ) . getFeatures ( ) . httpUpload ( 0 ) ) ;
if ( needsUpdating ) {
2017-08-10 12:13:07 +00:00
databaseBackend . updateAccount ( account ) ;
}
2015-10-16 07:58:31 +00:00
account . getRoster ( ) . clearPresences ( ) ;
2015-12-12 15:01:33 +00:00
mJingleConnectionManager . cancelInTransmission ( ) ;
2015-10-16 07:58:31 +00:00
fetchRosterFromServer ( account ) ;
fetchBookmarks ( account ) ;
2018-03-18 09:30:15 +00:00
final boolean flexible = account . getXmppConnection ( ) . getFeatures ( ) . flexibleOfflineMessageRetrieval ( ) ;
2018-01-19 17:17:13 +00:00
final boolean catchup = getMessageArchiveService ( ) . inCatchup ( account ) ;
if ( flexible & & catchup ) {
sendIqPacket ( account , mIqGenerator . purgeOfflineMessages ( ) , ( acc , packet ) - > {
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2018-03-18 09:30:15 +00:00
Log . d ( Config . LOGTAG , acc . getJid ( ) . asBareJid ( ) + " : successfully purged offline messages " ) ;
2018-01-19 17:17:13 +00:00
}
} ) ;
}
2015-10-16 07:58:31 +00:00
sendPresence ( account ) ;
2016-02-12 23:03:57 +00:00
if ( mPushManagementService . available ( account ) ) {
2016-02-12 22:37:42 +00:00
mPushManagementService . registerPushTokenOnServer ( account ) ;
}
2015-10-16 07:58:31 +00:00
connectMultiModeConversations ( account ) ;
syncDirtyContacts ( account ) ;
}
} ;
2018-03-18 09:30:15 +00:00
private AtomicLong mLastExpiryRun = new AtomicLong ( 0 ) ;
private SecureRandom mRandom ;
private LruCache < Pair < String , String > , ServiceDiscoveryResult > discoCache = new LruCache < > ( 20 ) ;
2014-02-04 14:09:50 +00:00
private OnStatusChanged statusListener = new OnStatusChanged ( ) {
2014-02-05 21:33:39 +00:00
2014-02-04 14:09:50 +00:00
@Override
2016-02-12 10:39:27 +00:00
public void onStatusChanged ( final Account account ) {
2014-08-28 20:23:18 +00:00
XmppConnection connection = account . getXmppConnection ( ) ;
2018-05-03 12:54:22 +00:00
updateAccountUi ( ) ;
2014-11-15 16:09:02 +00:00
if ( account . getStatus ( ) = = Account . State . ONLINE ) {
2016-11-19 12:34:27 +00:00
synchronized ( mLowPingTimeoutMode ) {
2018-03-05 17:30:40 +00:00
if ( mLowPingTimeoutMode . remove ( account . getJid ( ) . asBareJid ( ) ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : leaving low ping timeout mode " ) ;
2016-11-02 08:36:14 +00:00
}
}
2016-10-04 09:16:59 +00:00
if ( account . setShowErrorNotification ( true ) ) {
databaseBackend . updateAccount ( account ) ;
}
2016-02-26 08:46:25 +00:00
mMessageArchiveService . executePendingQueries ( account ) ;
2015-08-13 16:25:10 +00:00
if ( connection ! = null & & connection . getFeatures ( ) . csi ( ) ) {
if ( checkListeners ( ) ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " sending csi//inactive " ) ;
2015-08-13 16:25:10 +00:00
connection . sendInactive ( ) ;
} else {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " sending csi//active " ) ;
2015-08-13 16:25:10 +00:00
connection . sendActive ( ) ;
}
2014-07-18 19:57:10 +00:00
}
2014-03-21 18:58:47 +00:00
List < Conversation > conversations = getConversations ( ) ;
2014-11-10 00:24:35 +00:00
for ( Conversation conversation : conversations ) {
2018-02-19 12:55:48 +00:00
if ( conversation . getAccount ( ) = = account & & ! account . pendingConferenceJoins . contains ( conversation ) ) {
2014-12-14 17:10:46 +00:00
sendUnsentMessages ( conversation ) ;
2014-11-10 00:24:35 +00:00
}
}
2015-10-01 14:01:19 +00:00
for ( Conversation conversation : account . pendingConferenceLeaves ) {
leaveMuc ( conversation ) ;
}
account . pendingConferenceLeaves . clear ( ) ;
for ( Conversation conversation : account . pendingConferenceJoins ) {
joinMuc ( conversation ) ;
}
account . pendingConferenceJoins . clear ( ) ;
2016-11-02 10:04:33 +00:00
scheduleWakeUpCall ( Config . PING_MAX_INTERVAL , account . getUuid ( ) . hashCode ( ) ) ;
2017-08-05 17:13:29 +00:00
} else if ( account . getStatus ( ) = = Account . State . OFFLINE | | account . getStatus ( ) = = Account . State . DISABLED ) {
resetSendingToWaiting ( account ) ;
2017-11-06 12:57:25 +00:00
if ( account . isEnabled ( ) & & isInLowPingTimeoutMode ( account ) ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : went into offline state during low ping mode. reconnecting now " ) ;
2016-11-19 12:34:27 +00:00
reconnectAccount ( account , true , false ) ;
2017-08-05 17:13:29 +00:00
} else {
int timeToReconnect = mRandom . nextInt ( 10 ) + 2 ;
scheduleWakeUpCall ( timeToReconnect , account . getUuid ( ) . hashCode ( ) ) ;
}
} else if ( account . getStatus ( ) = = Account . State . REGISTRATION_SUCCESSFUL ) {
databaseBackend . updateAccount ( account ) ;
reconnectAccount ( account , true , false ) ;
} else if ( account . getStatus ( ) ! = Account . State . CONNECTING & & account . getStatus ( ) ! = Account . State . NO_INTERNET ) {
resetSendingToWaiting ( account ) ;
2017-08-12 20:17:04 +00:00
if ( connection ! = null & & account . getStatus ( ) . isAttemptReconnect ( ) ) {
2017-08-05 17:13:29 +00:00
final int next = connection . getTimeToNextAttempt ( ) ;
final boolean lowPingTimeoutMode = isInLowPingTimeoutMode ( account ) ;
if ( next < = 0 ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : error connecting account. reconnecting now. lowPingTimeout= " + Boolean . toString ( lowPingTimeoutMode ) ) ;
2017-08-05 17:13:29 +00:00
reconnectAccount ( account , true , false ) ;
} else {
final int attempt = connection . getAttempt ( ) + 1 ;
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : error connecting account. try again in " + next + " s for the " + attempt + " time. lowPingTimeout= " + Boolean . toString ( lowPingTimeoutMode ) ) ;
2016-11-19 12:34:27 +00:00
scheduleWakeUpCall ( next , account . getUuid ( ) . hashCode ( ) ) ;
2016-10-23 07:03:17 +00:00
}
2014-03-06 02:30:03 +00:00
}
2015-10-16 07:58:31 +00:00
}
2014-11-18 14:26:28 +00:00
getNotificationService ( ) . updateErrorNotification ( ) ;
2014-02-04 14:09:50 +00:00
}
} ;
2018-03-18 09:30:15 +00:00
private OpenPgpServiceConnection pgpServiceConnection ;
private PgpEngine mPgpEngine = null ;
private WakeLock wakeLock ;
private PowerManager pm ;
private LruCache < String , Bitmap > mBitmapCache ;
private EventReceiver mEventReceiver = new EventReceiver ( ) ;
private static String generateFetchKey ( Account account , final Avatar avatar ) {
return account . getJid ( ) . asBareJid ( ) + " _ " + avatar . owner + " _ " + avatar . sha1sum ;
}
2017-08-05 17:13:29 +00:00
private boolean isInLowPingTimeoutMode ( Account account ) {
synchronized ( mLowPingTimeoutMode ) {
2018-03-05 17:30:40 +00:00
return mLowPingTimeoutMode . contains ( account . getJid ( ) . asBareJid ( ) ) ;
2017-08-05 17:13:29 +00:00
}
}
2017-09-18 15:56:25 +00:00
public void startForcingForegroundNotification ( ) {
mForceForegroundService . set ( true ) ;
toggleForegroundService ( ) ;
}
public void stopForcingForegroundNotification ( ) {
mForceForegroundService . set ( false ) ;
toggleForegroundService ( ) ;
}
2015-02-12 17:53:00 +00:00
public boolean areMessagesInitialized ( ) {
2018-01-20 19:05:39 +00:00
return this . restoredFromDatabaseLatch . getCount ( ) = = 0 ;
2015-02-12 17:53:00 +00:00
}
2014-02-27 23:22:56 +00:00
public PgpEngine getPgpEngine ( ) {
2016-02-24 13:47:49 +00:00
if ( ! Config . supportOpenPgp ( ) ) {
return null ;
} else if ( pgpServiceConnection ! = null & & pgpServiceConnection . isBound ( ) ) {
2014-02-27 23:22:56 +00:00
if ( this . mPgpEngine = = null ) {
this . mPgpEngine = new PgpEngine ( new OpenPgpApi (
2015-10-16 07:58:31 +00:00
getApplicationContext ( ) ,
pgpServiceConnection . getService ( ) ) , this ) ;
2014-02-27 23:22:56 +00:00
}
return mPgpEngine ;
} else {
return null ;
}
}
2016-06-13 11:32:14 +00: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 19:06:10 +00:00
public FileBackend getFileBackend ( ) {
return this . fileBackend ;
}
2014-05-01 20:33:49 +00:00
2014-10-20 19:08:33 +00:00
public AvatarService getAvatarService ( ) {
return this . mAvatarService ;
}
2018-03-18 09:30:15 +00:00
public void attachLocationToConversation ( final Conversation conversation , final Uri uri , final UiCallback < Message > callback ) {
2015-07-30 22:52:46 +00:00
int encryption = conversation . getNextEncryption ( ) ;
2015-03-07 13:15:38 +00:00
if ( encryption = = Message . ENCRYPTION_PGP ) {
encryption = Message . ENCRYPTION_DECRYPTED ;
}
2015-10-16 07:58:31 +00:00
Message message = new Message ( conversation , uri . toString ( ) , encryption ) ;
2015-03-07 13:15:38 +00:00
if ( conversation . getNextCounterpart ( ) ! = null ) {
message . setCounterpart ( conversation . getNextCounterpart ( ) ) ;
}
if ( encryption = = Message . ENCRYPTION_DECRYPTED ) {
2015-05-05 08:29:41 +00:00
getPgpEngine ( ) . encrypt ( message , callback ) ;
2015-03-07 13:15:38 +00:00
} else {
2018-02-27 10:44:23 +00:00
sendMessage ( message ) ;
2015-03-07 13:15:38 +00:00
callback . success ( message ) ;
}
}
2018-03-03 15:58:04 +00:00
public void attachFileToConversation ( final Conversation conversation , final Uri uri , final String type , final UiCallback < Message > callback ) {
2016-04-13 09:14:36 +00:00
if ( FileBackend . weOwnFile ( this , uri ) ) {
2017-10-28 15:49:51 +00:00
Log . d ( Config . LOGTAG , " trying to attach file that belonged to us " ) ;
2016-04-07 18:29:40 +00:00
callback . error ( R . string . security_error_invalid_file_access , null ) ;
return ;
}
2014-11-13 23:28:39 +00:00
final Message message ;
2015-07-30 22:52:46 +00:00
if ( conversation . getNextEncryption ( ) = = Message . ENCRYPTION_PGP ) {
message = new Message ( conversation , " " , Message . ENCRYPTION_DECRYPTED ) ;
2014-11-13 23:28:39 +00:00
} else {
2015-07-30 22:52:46 +00:00
message = new Message ( conversation , " " , conversation . getNextEncryption ( ) ) ;
2014-11-13 23:28:39 +00:00
}
message . setCounterpart ( conversation . getNextCounterpart ( ) ) ;
message . setType ( Message . TYPE_FILE ) ;
2018-03-03 15:58:04 +00:00
final AttachFileToConversationRunnable runnable = new AttachFileToConversationRunnable ( this , uri , type , message , callback ) ;
2017-09-21 19:54:10 +00:00
if ( runnable . isVideoMessage ( ) ) {
mVideoCompressionExecutor . execute ( runnable ) ;
} else {
mFileAddingExecutor . execute ( runnable ) ;
}
2014-11-13 20:04:05 +00:00
}
2015-08-11 14:50:00 +00:00
public void attachImageToConversation ( final Conversation conversation , final Uri uri , final UiCallback < Message > callback ) {
2016-04-13 09:14:36 +00:00
if ( FileBackend . weOwnFile ( this , uri ) ) {
2017-10-28 15:49:51 +00:00
Log . d ( Config . LOGTAG , " trying to attach file that belonged to us " ) ;
2016-04-07 18:29:40 +00:00
callback . error ( R . string . security_error_invalid_file_access , null ) ;
return ;
}
2016-12-30 20:48:39 +00:00
final String mimeType = MimeUtils . guessMimeTypeFromUri ( this , uri ) ;
2016-01-09 15:17:39 +00:00
final String compressPictures = getCompressPicturesPreference ( ) ;
2016-12-30 20:48:39 +00:00
2016-01-09 15:17:39 +00:00
if ( " never " . equals ( compressPictures )
2016-12-30 20:48:39 +00:00
| | ( " auto " . equals ( compressPictures ) & & getFileBackend ( ) . useImageAsIs ( uri ) )
| | ( mimeType ! = null & & mimeType . endsWith ( " /gif " ) ) ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , conversation . getAccount ( ) . getJid ( ) . asBareJid ( ) + " : not compressing picture. sending as file " ) ;
2018-03-03 15:58:04 +00:00
attachFileToConversation ( conversation , uri , mimeType , callback ) ;
2015-08-11 14:50:00 +00:00
return ;
}
2014-05-12 12:59:46 +00:00
final Message message ;
2015-07-30 22:52:46 +00:00
if ( conversation . getNextEncryption ( ) = = Message . ENCRYPTION_PGP ) {
message = new Message ( conversation , " " , Message . ENCRYPTION_DECRYPTED ) ;
2014-05-12 12:59:46 +00:00
} else {
2015-10-16 07:58:31 +00:00
message = new Message ( conversation , " " , conversation . getNextEncryption ( ) ) ;
2014-05-12 12:59:46 +00:00
}
2014-11-09 15:21:13 +00:00
message . setCounterpart ( conversation . getNextCounterpart ( ) ) ;
2014-05-06 19:34:30 +00:00
message . setType ( Message . TYPE_IMAGE ) ;
2018-03-18 09:30:15 +00:00
mFileAddingExecutor . execute ( ( ) - > {
try {
getFileBackend ( ) . copyImageToPrivateStorage ( message , uri ) ;
if ( conversation . getNextEncryption ( ) = = Message . ENCRYPTION_PGP ) {
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 12:59:46 +00:00
}
2018-03-18 09:30:15 +00:00
} else {
sendMessage ( message ) ;
callback . success ( message ) ;
2014-04-15 13:19:02 +00:00
}
2018-03-18 09:30:15 +00:00
} catch ( final FileBackend . FileCopyException e ) {
callback . error ( e . getResId ( ) , message ) ;
2014-04-15 13:19:02 +00:00
}
2015-06-05 06:46:06 +00:00
} ) ;
2014-05-06 19:34:30 +00:00
}
2014-05-14 10:56:34 +00:00
2014-07-20 00:26:23 +00:00
public Conversation find ( Bookmark bookmark ) {
2014-08-26 14:52:42 +00:00
return find ( bookmark . getAccount ( ) , bookmark . getJid ( ) ) ;
2014-07-14 09:47:42 +00:00
}
2014-08-26 14:52:42 +00:00
2014-11-05 20:55:47 +00:00
public Conversation find ( final Account account , final Jid jid ) {
2014-08-26 14:52:42 +00:00
return find ( getConversations ( ) , account , jid ) ;
2014-03-03 04:01:02 +00:00
}
2018-04-30 15:09:55 +00:00
public void search ( List < String > term , OnSearchResultsAvailable onSearchResultsAvailable ) {
2018-04-26 11:22:31 +00:00
MessageSearchTask . search ( this , term , onSearchResultsAvailable ) ;
}
2014-02-03 17:38:47 +00:00
@Override
public int onStartCommand ( Intent intent , int flags , int startId ) {
2015-01-05 17:45:39 +00:00
final String action = intent = = null ? null : intent . getAction ( ) ;
2016-10-06 16:09:55 +00:00
String pushedAccountHash = null ;
2015-09-29 17:24:52 +00:00
boolean interactive = false ;
2015-01-05 17:45:39 +00:00
if ( action ! = null ) {
2017-09-11 07:23:14 +00:00
final String uuid = intent . getStringExtra ( " uuid " ) ;
2015-01-08 13:45:44 +00:00
switch ( action ) {
2015-05-08 04:50:28 +00:00
case ConnectivityManager . CONNECTIVITY_ACTION :
if ( hasInternetConnection ( ) & & Config . RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE ) {
2016-11-18 12:55:02 +00:00
resetAllAttemptCounts ( true , false ) ;
2015-05-08 04:50:28 +00:00
}
break ;
2015-01-08 13:45:44 +00:00
case ACTION_MERGE_PHONE_CONTACTS :
2018-01-20 19:05:39 +00:00
if ( restoredFromDatabaseLatch . getCount ( ) = = 0 ) {
2015-12-06 23:33:50 +00:00
loadPhoneContacts ( ) ;
2015-02-17 10:51:11 +00:00
}
2015-01-08 13:45:44 +00:00
return START_STICKY ;
case Intent . ACTION_SHUTDOWN :
2016-04-14 19:45:36 +00:00
logoutAndSave ( true ) ;
2015-01-08 13:45:44 +00:00
return START_NOT_STICKY ;
case ACTION_CLEAR_NOTIFICATION :
2018-01-20 19:05:39 +00:00
mNotificationExecutor . execute ( ( ) - > {
try {
final Conversation c = findConversationByUuid ( uuid ) ;
if ( c ! = null ) {
mNotificationService . clear ( c ) ;
} else {
mNotificationService . clear ( ) ;
}
restoredFromDatabaseLatch . await ( ) ;
} catch ( InterruptedException e ) {
2018-03-18 09:30:15 +00:00
Log . d ( Config . LOGTAG , " unable to process clear notification " ) ;
2018-01-20 19:05:39 +00:00
}
} ) ;
2015-01-08 13:45:44 +00:00
break ;
2016-10-04 09:16:59 +00:00
case ACTION_DISMISS_ERROR_NOTIFICATIONS :
dismissErrorNotifications ( ) ;
break ;
2015-02-10 16:13:34 +00:00
case ACTION_TRY_AGAIN :
2016-11-18 12:55:02 +00:00
resetAllAttemptCounts ( false , true ) ;
2015-09-29 17:24:52 +00:00
interactive = true ;
2015-02-10 16:13:34 +00:00
break ;
2016-08-25 15:30:44 +00:00
case ACTION_REPLY_TO_CONVERSATION :
Bundle remoteInput = RemoteInput . getResultsFromIntent ( intent ) ;
2018-01-20 19:05:39 +00:00
if ( remoteInput = = null ) {
break ;
2016-08-25 15:30:44 +00:00
}
2018-01-20 19:05:39 +00:00
final CharSequence body = remoteInput . getCharSequence ( " text_reply " ) ;
final boolean dismissNotification = intent . getBooleanExtra ( " dismiss_notification " , false ) ;
if ( body = = null | | body . length ( ) < = 0 ) {
break ;
}
2018-03-18 09:30:15 +00:00
mNotificationExecutor . execute ( ( ) - > {
2018-01-20 19:05:39 +00:00
try {
restoredFromDatabaseLatch . await ( ) ;
final Conversation c = findConversationByUuid ( uuid ) ;
if ( c ! = null ) {
directReply ( c , body . toString ( ) , dismissNotification ) ;
}
} catch ( InterruptedException e ) {
2018-03-18 09:30:15 +00:00
Log . d ( Config . LOGTAG , " unable to process direct reply " ) ;
2018-01-20 19:05:39 +00:00
}
} ) ;
2016-08-25 15:30:44 +00:00
break ;
2017-04-14 11:23:01 +00:00
case ACTION_MARK_AS_READ :
2018-01-20 19:05:39 +00:00
mNotificationExecutor . execute ( ( ) - > {
final Conversation c = findConversationByUuid ( uuid ) ;
if ( c = = null ) {
Log . d ( Config . LOGTAG , " received mark read intent for unknown conversation ( " + uuid + " ) " ) ;
return ;
}
try {
restoredFromDatabaseLatch . await ( ) ;
2018-03-31 08:57:59 +00:00
sendReadMarker ( c , null ) ;
2018-01-20 19:05:39 +00:00
} catch ( InterruptedException e ) {
2018-03-18 09:30:15 +00:00
Log . d ( Config . LOGTAG , " unable to process notification read marker for conversation " + c . getName ( ) ) ;
2018-01-20 19:05:39 +00:00
}
} ) ;
2017-04-14 11:23:01 +00:00
break ;
2018-01-28 12:14:30 +00:00
case ACTION_SNOOZE :
mNotificationExecutor . execute ( ( ) - > {
final Conversation c = findConversationByUuid ( uuid ) ;
if ( c = = null ) {
2018-03-18 09:30:15 +00:00
Log . d ( Config . LOGTAG , " received snooze intent for unknown conversation ( " + uuid + " ) " ) ;
2018-01-28 12:14:30 +00:00
return ;
}
c . setMutedTill ( System . currentTimeMillis ( ) + 30 * 60 * 1000 ) ;
mNotificationService . clear ( c ) ;
updateConversation ( c ) ;
} ) ;
2015-10-07 22:35:04 +00:00
case AudioManager . RINGER_MODE_CHANGED_ACTION :
2017-06-27 10:24:26 +00:00
if ( dndOnSilentMode ( ) ) {
2015-10-07 22:35:04 +00:00
refreshAllPresences ( ) ;
}
break ;
case Intent . ACTION_SCREEN_ON :
2016-06-01 19:51:46 +00:00
deactivateGracePeriod ( ) ;
case Intent . ACTION_SCREEN_OFF :
2015-10-07 22:35:04 +00:00
if ( awayWhenScreenOff ( ) ) {
refreshAllPresences ( ) ;
}
break ;
2018-05-19 18:05:45 +00:00
case ACTION_FCM_TOKEN_REFRESH :
refreshAllFcmTokens ( ) ;
2016-02-12 10:39:27 +00:00
break ;
2016-05-28 12:44:22 +00:00
case ACTION_IDLE_PING :
2016-11-02 10:04:33 +00:00
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . M ) {
2016-05-28 12:44:22 +00:00
scheduleNextIdlePing ( ) ;
}
break ;
2018-05-19 18:05:45 +00:00
case ACTION_FCM_MESSAGE_RECEIVED :
2016-10-06 16:09:55 +00:00
pushedAccountHash = intent . getStringExtra ( " account " ) ;
2018-05-19 18:05:45 +00:00
Log . d ( Config . LOGTAG , " push message arrived in service. account= " + pushedAccountHash ) ;
2016-05-28 12:44:22 +00:00
break ;
2018-01-23 21:02:28 +00:00
case Intent . ACTION_SEND :
Uri uri = intent . getData ( ) ;
if ( uri ! = null ) {
2018-03-18 09:30:15 +00:00
Log . d ( Config . LOGTAG , " received uri permission for " + uri . toString ( ) ) ;
2018-01-23 21:02:28 +00:00
}
return START_STICKY ;
2014-10-02 15:36:02 +00:00
}
2014-05-19 13:15:09 +00:00
}
2016-11-18 12:14:26 +00:00
synchronized ( this ) {
2018-04-15 16:31:58 +00:00
WakeLockHelper . acquire ( wakeLock ) ;
2016-11-18 12:47:39 +00:00
boolean pingNow = ConnectivityManager . CONNECTIVITY_ACTION . equals ( action ) ;
2016-11-18 12:14:26 +00:00
HashSet < Account > pingCandidates = new HashSet < > ( ) ;
for ( Account account : accounts ) {
pingNow | = processAccountState ( account ,
interactive ,
" ui " . equals ( action ) ,
2018-05-12 15:23:37 +00:00
CryptoHelper . getAccountFingerprint ( account , PhoneHelper . getAndroidId ( this ) ) . equals ( pushedAccountHash ) ,
2016-11-18 12:14:26 +00:00
pingCandidates ) ;
}
if ( pingNow ) {
for ( Account account : pingCandidates ) {
2017-08-05 17:13:29 +00:00
final boolean lowTimeout = isInLowPingTimeoutMode ( account ) ;
2016-11-18 12:14:26 +00:00
account . getXmppConnection ( ) . sendPing ( ) ;
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " send ping (action= " + action + " ,lowTimeout= " + Boolean . toString ( lowTimeout ) + " ) " ) ;
2016-11-18 12:14:26 +00:00
scheduleWakeUpCall ( lowTimeout ? Config . LOW_PING_TIMEOUT : Config . PING_TIMEOUT , account . getUuid ( ) . hashCode ( ) ) ;
}
}
2018-04-15 16:31:58 +00:00
WakeLockHelper . release ( wakeLock ) ;
2016-11-18 12:14:26 +00:00
}
2017-01-23 16:14:30 +00:00
if ( SystemClock . elapsedRealtime ( ) - mLastExpiryRun . get ( ) > = Config . EXPIRY_INTERVAL ) {
expireOldMessages ( ) ;
}
2016-11-18 12:14:26 +00:00
return START_STICKY ;
}
2014-10-20 19:08:33 +00:00
2016-11-18 12:14:26 +00:00
private boolean processAccountState ( Account account , boolean interactive , boolean isUiAction , boolean isAccountPushed , HashSet < Account > pingCandidates ) {
2016-05-02 12:31:30 +00:00
boolean pingNow = false ;
2017-08-12 20:17:04 +00:00
if ( account . getStatus ( ) . isAttemptReconnect ( ) ) {
2016-11-18 12:14:26 +00:00
if ( ! hasInternetConnection ( ) ) {
account . setStatus ( Account . State . NO_INTERNET ) ;
if ( statusListener ! = null ) {
statusListener . onStatusChanged ( account ) ;
}
} else {
if ( account . getStatus ( ) = = Account . State . NO_INTERNET ) {
account . setStatus ( Account . State . OFFLINE ) ;
2014-03-19 15:16:40 +00:00
if ( statusListener ! = null ) {
2014-03-11 15:49:42 +00:00
statusListener . onStatusChanged ( account ) ;
}
2016-11-18 12:14:26 +00:00
}
if ( account . getStatus ( ) = = Account . State . ONLINE ) {
synchronized ( mLowPingTimeoutMode ) {
long lastReceived = account . getXmppConnection ( ) . getLastPacketReceived ( ) ;
long lastSent = account . getXmppConnection ( ) . getLastPingSent ( ) ;
long pingInterval = isUiAction ? Config . PING_MIN_INTERVAL * 1000 : Config . PING_MAX_INTERVAL * 1000 ;
long msToNextPing = ( Math . max ( lastReceived , lastSent ) + pingInterval ) - SystemClock . elapsedRealtime ( ) ;
2018-03-05 17:30:40 +00:00
int pingTimeout = mLowPingTimeoutMode . contains ( account . getJid ( ) . asBareJid ( ) ) ? Config . LOW_PING_TIMEOUT * 1000 : Config . PING_TIMEOUT * 1000 ;
2016-11-18 12:14:26 +00:00
long pingTimeoutIn = ( lastSent + pingTimeout ) - SystemClock . elapsedRealtime ( ) ;
if ( lastSent > lastReceived ) {
if ( pingTimeoutIn < 0 ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : ping timeout " ) ;
2016-11-18 12:14:26 +00:00
this . reconnectAccount ( account , true , interactive ) ;
} else {
int secs = ( int ) ( pingTimeoutIn / 1000 ) ;
this . scheduleWakeUpCall ( secs , account . getUuid ( ) . hashCode ( ) ) ;
}
} else {
pingCandidates . add ( account ) ;
if ( isAccountPushed ) {
pingNow = true ;
2018-03-05 17:30:40 +00:00
if ( mLowPingTimeoutMode . add ( account . getJid ( ) . asBareJid ( ) ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : entering low ping timeout mode " ) ;
2016-10-20 16:02:11 +00:00
}
2016-11-18 12:14:26 +00:00
} else if ( msToNextPing < = 0 ) {
pingNow = true ;
2016-05-02 12:31:30 +00:00
} else {
2016-11-18 12:14:26 +00:00
this . scheduleWakeUpCall ( ( int ) ( msToNextPing / 1000 ) , account . getUuid ( ) . hashCode ( ) ) ;
2018-03-05 17:30:40 +00:00
if ( mLowPingTimeoutMode . remove ( account . getJid ( ) . asBareJid ( ) ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : leaving low ping timeout mode " ) ;
2016-10-20 18:04:16 +00:00
}
2016-05-02 12:31:30 +00:00
}
2014-03-11 14:44:22 +00:00
}
2016-11-18 12:14:26 +00:00
}
} else if ( account . getStatus ( ) = = Account . State . OFFLINE ) {
reconnectAccount ( account , true , interactive ) ;
} else if ( account . getStatus ( ) = = Account . State . CONNECTING ) {
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 ;
if ( timeout < 0 ) {
2017-10-28 15:49:51 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) + " : time out during connect reconnecting (secondsSinceLast= " + secondsSinceLastConnect + " ) " ) ;
2016-11-18 12:14:26 +00:00
account . getXmppConnection ( ) . resetAttemptCount ( false ) ;
2015-10-16 07:58:31 +00:00
reconnectAccount ( account , true , interactive ) ;
2016-11-18 12:14:26 +00:00
} else if ( discoTimeout < 0 ) {
account . getXmppConnection ( ) . sendDiscoTimeout ( ) ;
2017-10-28 15:49:51 +00:00
scheduleWakeUpCall ( ( int ) Math . min ( timeout , discoTimeout ) , account . getUuid ( ) . hashCode ( ) ) ;
2014-03-11 14:44:22 +00:00
} else {
2017-10-28 15:49:51 +00:00
scheduleWakeUpCall ( ( int ) Math . min ( timeout , discoTimeout ) , account . getUuid ( ) . hashCode ( ) ) ;
2016-11-18 12:14:26 +00:00
}
} else {
if ( account . getXmppConnection ( ) . getTimeToNextAttempt ( ) < = 0 ) {
reconnectAccount ( account , true , interactive ) ;
2014-03-08 19:14:47 +00:00
}
2016-08-09 17:21:54 +00:00
}
2016-05-02 12:31:30 +00:00
}
}
2016-11-18 12:14:26 +00:00
return pingNow ;
2014-02-03 17:38:47 +00:00
}
2014-10-20 19:08:33 +00:00
2016-08-27 11:35:52 +00: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 19:35:54 +00:00
private void directReply ( Conversation conversation , String body , final boolean dismissAfterReply ) {
2017-10-28 15:49:51 +00:00
Message message = new Message ( conversation , body , conversation . getNextEncryption ( ) ) ;
2016-08-25 20:41:33 +00:00
message . markUnread ( ) ;
2016-08-25 15:30:44 +00: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 19:35:54 +00:00
if ( dismissAfterReply ) {
2018-04-26 11:22:31 +00:00
markRead ( ( Conversation ) message . getConversation ( ) , true ) ;
2016-09-19 19:35:54 +00:00
} else {
mNotificationService . pushFromDirectReply ( message ) ;
}
2016-08-25 15:30:44 +00:00
}
@Override
public void error ( int errorCode , Message object ) {
}
@Override
public void userInputRequried ( PendingIntent pi , Message object ) {
}
} ) ;
} else {
sendMessage ( message ) ;
2016-09-19 19:35:54 +00:00
if ( dismissAfterReply ) {
2017-10-28 15:49:51 +00:00
markRead ( conversation , true ) ;
2016-09-19 19:35:54 +00:00
} else {
mNotificationService . pushFromDirectReply ( message ) ;
}
2016-08-25 15:30:44 +00:00
}
}
2017-06-27 10:24:26 +00:00
private boolean dndOnSilentMode ( ) {
2017-07-01 11:41:24 +00:00
return getBooleanPreference ( SettingsActivity . DND_ON_SILENT_MODE , R . bool . dnd_on_silent_mode ) ;
2015-10-07 22:35:04 +00:00
}
2016-04-22 19:25:06 +00:00
private boolean manuallyChangePresence ( ) {
2017-07-01 11:41:24 +00:00
return getBooleanPreference ( SettingsActivity . MANUALLY_CHANGE_PRESENCE , R . bool . manually_change_presence ) ;
2016-04-22 19:25:06 +00:00
}
2016-03-01 18:00:18 +00:00
private boolean treatVibrateAsSilent ( ) {
2017-07-01 11:41:24 +00:00
return getBooleanPreference ( SettingsActivity . TREAT_VIBRATE_AS_SILENT , R . bool . treat_vibrate_as_silent ) ;
2016-03-01 18:00:18 +00:00
}
2015-10-07 22:35:04 +00:00
private boolean awayWhenScreenOff ( ) {
2017-10-28 15:49:51 +00:00
return getBooleanPreference ( SettingsActivity . AWAY_WHEN_SCREEN_IS_OFF , R . bool . away_when_screen_off ) ;
2015-10-07 22:35:04 +00:00
}
2016-01-09 15:17:39 +00:00
private String getCompressPicturesPreference ( ) {
2017-06-30 19:22:35 +00:00
return getPreferences ( ) . getString ( " picture_compression " , getResources ( ) . getString ( R . string . picture_compression ) ) ;
2016-01-09 15:17:39 +00:00
}
2016-01-17 21:28:38 +00:00
private Presence . Status getTargetPresence ( ) {
2017-06-27 10:24:26 +00:00
if ( dndOnSilentMode ( ) & & isPhoneSilenced ( ) ) {
return Presence . Status . DND ;
2015-10-07 22:35:04 +00:00
} else if ( awayWhenScreenOff ( ) & & ! isInteractive ( ) ) {
2016-01-17 21:28:38 +00:00
return Presence . Status . AWAY ;
2015-10-07 22:35:04 +00:00
} else {
2016-01-17 21:28:38 +00:00
return Presence . Status . ONLINE ;
2015-10-07 22:35:04 +00: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 08:58:31 +00:00
try {
if ( treatVibrateAsSilent ( ) ) {
return audioManager . getRingerMode ( ) ! = AudioManager . RINGER_MODE_NORMAL ;
} else {
return audioManager . getRingerMode ( ) = = AudioManager . RINGER_MODE_SILENT ;
}
} catch ( Throwable throwable ) {
2017-10-28 15:49:51 +00:00
Log . d ( Config . LOGTAG , " platform bug in isPhoneSilenced ( " + throwable . getMessage ( ) + " ) " ) ;
2016-08-02 08:58:31 +00:00
return false ;
2016-03-01 18:00:18 +00:00
}
2015-10-07 22:35:04 +00:00
}
2016-11-18 12:55:02 +00:00
private void resetAllAttemptCounts ( boolean reallyAll , boolean retryImmediately ) {
2016-03-22 09:54:45 +00:00
Log . d ( Config . LOGTAG , " resetting all attempt counts " ) ;
2015-10-16 07:58:31 +00:00
for ( Account account : accounts ) {
2015-05-08 04:50:28 +00:00
if ( account . hasErrorStatus ( ) | | reallyAll ) {
final XmppConnection connection = account . getXmppConnection ( ) ;
if ( connection ! = null ) {
2016-11-18 12:55:02 +00:00
connection . resetAttemptCount ( retryImmediately ) ;
2015-05-08 04:50:28 +00:00
}
}
2016-10-04 09:16:59 +00:00
if ( account . setShowErrorNotification ( true ) ) {
databaseBackend . updateAccount ( account ) ;
}
}
2016-10-06 20:05:40 +00:00
mNotificationService . updateErrorNotification ( ) ;
2016-10-04 09:16:59 +00:00
}
private void dismissErrorNotifications ( ) {
for ( final Account account : this . accounts ) {
if ( account . hasErrorStatus ( ) ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : dismissing error notification " ) ;
2016-10-04 09:16:59 +00:00
if ( account . setShowErrorNotification ( false ) ) {
databaseBackend . updateAccount ( account ) ;
}
}
2015-05-08 04:50:28 +00:00
}
}
2017-01-23 16:14:30 +00:00
private void expireOldMessages ( ) {
2017-01-25 17:35:22 +00:00
expireOldMessages ( false ) ;
}
public void expireOldMessages ( final boolean resetHasMessagesLeftOnServer ) {
2017-01-23 16:14:30 +00:00
mLastExpiryRun . set ( SystemClock . elapsedRealtime ( ) ) ;
2018-03-18 09:30:15 +00:00
mDatabaseWriterExecutor . execute ( ( ) - > {
long timestamp = getAutomaticMessageDeletionDate ( ) ;
if ( timestamp > 0 ) {
databaseBackend . expireOldMessages ( timestamp ) ;
synchronized ( XmppConnectionService . this . conversations ) {
for ( Conversation conversation : XmppConnectionService . this . conversations ) {
conversation . expireOldMessages ( timestamp ) ;
if ( resetHasMessagesLeftOnServer ) {
conversation . messagesLoaded . set ( true ) ;
conversation . setHasMessagesLeftOnServer ( true ) ;
2017-01-25 12:22:20 +00:00
}
}
2017-01-23 16:14:30 +00:00
}
2018-03-18 09:30:15 +00:00
updateConversationUi ( ) ;
2017-01-23 16:14:30 +00:00
}
2017-01-25 12:22:20 +00:00
} ) ;
2017-01-23 16:14:30 +00:00
}
2014-10-17 11:09:02 +00:00
public boolean hasInternetConnection ( ) {
2017-11-12 18:22:07 +00:00
final ConnectivityManager cm = ( ConnectivityManager ) getSystemService ( Context . CONNECTIVITY_SERVICE ) ;
try {
2018-05-10 16:59:17 +00:00
final NetworkInfo activeNetwork = cm = = null ? null : cm . getActiveNetworkInfo ( ) ;
2017-11-12 18:22:07 +00:00
return activeNetwork ! = null & & activeNetwork . isConnected ( ) ;
} catch ( RuntimeException e ) {
2018-03-18 09:30:15 +00:00
Log . d ( Config . LOGTAG , " unable to check for internet connection " , e ) ;
2017-11-12 18:22:07 +00:00
return true ; //if internet connection can not be checked it is probably best to just try
}
2014-10-17 11:09:02 +00:00
}
2014-02-03 17:38:47 +00:00
2014-06-20 15:30:19 +00:00
@SuppressLint ( " TrulyRandom " )
2014-02-03 17:38:47 +00:00
@Override
public void onCreate ( ) {
2018-03-27 13:35:53 +00:00
OmemoSetting . load ( this ) ;
2014-03-09 12:21:28 +00:00
ExceptionHelper . init ( getApplicationContext ( ) ) ;
2014-06-20 15:30:19 +00:00
PRNGFixes . apply ( ) ;
2017-09-21 08:31:21 +00:00
Resolver . init ( this ) ;
2014-06-20 15:30:19 +00:00
this . mRandom = new SecureRandom ( ) ;
2015-04-02 11:35:42 +00:00
updateMemorizingTrustmanager ( ) ;
2014-12-21 01:13:13 +00:00
final int maxMemory = ( int ) ( Runtime . getRuntime ( ) . maxMemory ( ) / 1024 ) ;
final int cacheSize = maxMemory / 8 ;
2014-10-21 12:57:16 +00:00
this . mBitmapCache = new LruCache < String , Bitmap > ( cacheSize ) {
@Override
2014-12-21 01:13:13 +00:00
protected int sizeOf ( final String key , final Bitmap bitmap ) {
2014-10-21 12:57:16 +00:00
return bitmap . getByteCount ( ) / 1024 ;
}
} ;
2017-10-28 15:49:51 +00:00
Log . d ( Config . LOGTAG , " initializing database... " ) ;
2014-11-18 02:10:59 +00:00
this . databaseBackend = DatabaseBackend . getInstance ( getApplicationContext ( ) ) ;
2017-10-28 15:49:51 +00:00
Log . d ( Config . LOGTAG , " restoring accounts... " ) ;
2014-02-03 17:38:47 +00:00
this . accounts = databaseBackend . getAccounts ( ) ;
2017-10-28 15:49:51 +00:00
final SharedPreferences . Editor editor = getPreferences ( ) . edit ( ) ;
if ( this . accounts . size ( ) = = 0 & & Arrays . asList ( " Sony " , " Sony Ericsson " ) . contains ( Build . MANUFACTURER ) ) {
editor . putBoolean ( SettingsActivity . KEEP_FOREGROUND_SERVICE , true ) ;
Log . d ( Config . LOGTAG , Build . MANUFACTURER + " is on blacklist. enabling foreground service " ) ;
2016-11-08 11:20:07 +00:00
}
2017-10-28 15:49:51 +00:00
editor . putBoolean ( EventReceiver . SETTING_ENABLED_ACCOUNTS , hasEnabledAccounts ( ) ) . apply ( ) ;
editor . apply ( ) ;
2016-11-08 11:20:07 +00:00
2015-02-17 10:51:11 +00:00
restoreFromDatabase ( ) ;
2014-05-01 20:33:49 +00:00
2014-11-18 02:10:59 +00:00
getContentResolver ( ) . registerContentObserver ( ContactsContract . Contacts . CONTENT_URI , true , contactObserver ) ;
2018-03-18 11:24:28 +00:00
new Thread ( fileObserver : : startWatching ) . start ( ) ;
2016-02-24 13:47:49 +00:00
if ( Config . supportOpenPgp ( ) ) {
2017-10-28 15:49:51 +00:00
this . pgpServiceConnection = new OpenPgpServiceConnection ( this , " org.sufficientlysecure.keychain " , new OpenPgpServiceConnection . OnBound ( ) {
2016-02-24 13:47:49 +00:00
@Override
public void onBound ( IOpenPgpService2 service ) {
for ( Account account : accounts ) {
2016-06-13 11:32:14 +00:00
final PgpDecryptionService pgp = account . getPgpDecryptionService ( ) ;
2017-10-28 15:49:51 +00:00
if ( pgp ! = null ) {
2016-06-13 11:32:14 +00:00
pgp . continueDecryption ( true ) ;
2016-02-24 13:47:49 +00:00
}
2015-10-15 22:21:47 +00:00
}
}
2016-02-24 13:47:49 +00:00
@Override
public void onError ( Exception e ) {
}
} ) ;
this . pgpServiceConnection . bindToService ( ) ;
}
2014-03-11 14:44:22 +00:00
2014-04-03 08:41:21 +00:00
this . pm = ( PowerManager ) getSystemService ( Context . POWER_SERVICE ) ;
2015-10-16 07:58:31 +00:00
this . wakeLock = pm . newWakeLock ( PowerManager . PARTIAL_WAKE_LOCK , " XmppConnectionService " ) ;
2016-11-08 11:20:07 +00:00
2014-11-12 13:41:43 +00:00
toggleForegroundService ( ) ;
2015-07-03 20:08:23 +00:00
updateUnreadCountBadge ( ) ;
2015-10-07 22:35:04 +00:00
toggleScreenEventReceiver ( ) ;
2016-11-02 10:04:33 +00:00
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . M ) {
2016-05-28 14:07:16 +00:00
scheduleNextIdlePing ( ) ;
}
2016-08-27 10:15:25 +00:00
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . N ) {
2017-10-28 15:49:51 +00:00
registerReceiver ( this . mEventReceiver , new IntentFilter ( ConnectivityManager . CONNECTIVITY_ACTION ) ) ;
2016-08-27 10:15:25 +00:00
}
2015-10-07 22:35:04 +00:00
}
2015-10-14 20:55:59 +00:00
@Override
public void onTrimMemory ( int level ) {
super . onTrimMemory ( level ) ;
if ( level > = TRIM_MEMORY_COMPLETE ) {
2015-10-16 07:58:31 +00:00
Log . d ( Config . LOGTAG , " clear cache due to low memory " ) ;
2015-10-14 20:55:59 +00:00
getBitmapCache ( ) . evictAll ( ) ;
}
}
2015-10-07 22:35:04 +00:00
@Override
public void onDestroy ( ) {
2015-10-07 22:52:04 +00:00
try {
unregisterReceiver ( this . mEventReceiver ) ;
} catch ( IllegalArgumentException e ) {
//ignored
}
2016-07-23 14:12:45 +00:00
fileObserver . stopWatching ( ) ;
2015-10-07 22:35:04 +00:00
super . onDestroy ( ) ;
}
public void toggleScreenEventReceiver ( ) {
2016-04-22 19:25:06 +00:00
if ( awayWhenScreenOff ( ) & & ! manuallyChangePresence ( ) ) {
2015-10-07 22:35:04 +00:00
final IntentFilter filter = new IntentFilter ( Intent . ACTION_SCREEN_ON ) ;
filter . addAction ( Intent . ACTION_SCREEN_OFF ) ;
registerReceiver ( this . mEventReceiver , filter ) ;
} else {
2015-10-07 22:52:04 +00:00
try {
unregisterReceiver ( this . mEventReceiver ) ;
} catch ( IllegalArgumentException e ) {
//ignored
}
2015-10-07 22:35:04 +00:00
}
2014-02-03 17:38:47 +00:00
}
2014-02-05 21:33:39 +00:00
2014-11-12 13:41:43 +00:00
public void toggleForegroundService ( ) {
2017-09-18 15:56:25 +00:00
if ( mForceForegroundService . get ( ) | | ( keepForegroundService ( ) & & hasEnabledAccounts ( ) ) ) {
2014-11-12 13:41:43 +00:00
startForeground ( NotificationService . FOREGROUND_NOTIFICATION_ID , this . mNotificationService . createForegroundNotification ( ) ) ;
2017-10-28 15:49:51 +00:00
Log . d ( Config . LOGTAG , " started foreground service " ) ;
2014-11-12 13:41:43 +00:00
} else {
stopForeground ( true ) ;
2017-10-28 15:49:51 +00:00
Log . d ( Config . LOGTAG , " stopped foreground service " ) ;
2014-11-12 13:41:43 +00:00
}
2014-05-19 19:05:17 +00:00
}
2014-05-22 07:36:00 +00:00
2017-07-01 11:41:24 +00:00
public boolean keepForegroundService ( ) {
2017-10-28 15:49:51 +00:00
return getBooleanPreference ( SettingsActivity . KEEP_FOREGROUND_SERVICE , R . bool . enable_foreground_service ) ;
2016-11-08 11:20:07 +00:00
}
2014-05-19 19:05:17 +00:00
@Override
2014-12-21 01:13:13 +00:00
public void onTaskRemoved ( final Intent rootIntent ) {
2014-05-19 19:05:17 +00:00
super . onTaskRemoved ( rootIntent ) ;
2017-09-18 15:56:25 +00:00
if ( keepForegroundService ( ) | | mForceForegroundService . get ( ) ) {
2017-10-28 15:49:51 +00:00
Log . d ( Config . LOGTAG , " ignoring onTaskRemoved because foreground service is activated " ) ;
2017-09-18 15:56:25 +00:00
} else {
this . logoutAndSave ( false ) ;
2014-11-12 13:41:43 +00:00
}
2014-05-19 19:05:17 +00:00
}
2014-05-22 07:36:00 +00:00
2016-04-14 19:45:36 +00:00
private void logoutAndSave ( boolean stop ) {
int activeAccounts = 0 ;
2014-12-21 01:13:13 +00:00
for ( final Account account : accounts ) {
2016-04-14 19:45:36 +00:00
if ( account . getStatus ( ) ! = Account . State . DISABLED ) {
2018-03-18 22:19:23 +00:00
databaseBackend . writeRoster ( account . getRoster ( ) ) ;
2016-04-14 19:45:36 +00:00
activeAccounts + + ;
}
2014-02-13 22:40:08 +00:00
if ( account . getXmppConnection ( ) ! = null ) {
2018-03-18 09:30:15 +00:00
new Thread ( ( ) - > disconnect ( account , false ) ) . start ( ) ;
2014-02-13 22:40:08 +00:00
}
}
2016-04-14 19:45:36 +00:00
if ( stop | | activeAccounts = = 0 ) {
Log . d ( Config . LOGTAG , " good bye " ) ;
stopSelf ( ) ;
}
2014-02-13 22:40:08 +00:00
}
2014-03-11 14:44:22 +00:00
2015-12-15 18:14:38 +00:00
public void scheduleWakeUpCall ( int seconds , int requestCode ) {
2015-05-25 02:49:36 +00:00
final long timeToWake = SystemClock . elapsedRealtime ( ) + ( seconds < 0 ? 1 : seconds + 1 ) * 1000 ;
2017-11-12 18:22:07 +00:00
final AlarmManager alarmManager = ( AlarmManager ) getSystemService ( Context . ALARM_SERVICE ) ;
2016-05-28 12:44:22 +00:00
Intent intent = new Intent ( this , EventReceiver . class ) ;
2015-01-05 17:45:39 +00:00
intent . setAction ( " ping " ) ;
2017-11-12 18:22:07 +00:00
PendingIntent pendingIntent = PendingIntent . getBroadcast ( this , requestCode , intent , 0 ) ;
try {
alarmManager . set ( AlarmManager . ELAPSED_REALTIME_WAKEUP , timeToWake , pendingIntent ) ;
} catch ( RuntimeException e ) {
Log . e ( Config . LOGTAG , " unable to schedule alarm for ping " , e ) ;
}
2014-03-06 02:30:03 +00:00
}
2014-02-13 22:40:08 +00:00
2016-05-28 12:44:22 +00:00
@TargetApi ( Build . VERSION_CODES . M )
private void scheduleNextIdlePing ( ) {
2017-11-12 18:22:07 +00:00
final long timeToWake = SystemClock . elapsedRealtime ( ) + ( Config . IDLE_PING_INTERVAL * 1000 ) ;
final AlarmManager alarmManager = ( AlarmManager ) getSystemService ( Context . ALARM_SERVICE ) ;
2016-05-28 12:44:22 +00:00
Intent intent = new Intent ( this , EventReceiver . class ) ;
intent . setAction ( ACTION_IDLE_PING ) ;
2017-11-12 18:22:07 +00:00
PendingIntent pendingIntent = PendingIntent . getBroadcast ( this , 0 , intent , 0 ) ;
try {
alarmManager . setAndAllowWhileIdle ( AlarmManager . ELAPSED_REALTIME_WAKEUP , timeToWake , pendingIntent ) ;
} catch ( RuntimeException e ) {
Log . d ( Config . LOGTAG , " unable to schedule alarm for idle ping " , e ) ;
}
2016-05-28 12:44:22 +00:00
}
2014-12-21 20:43:58 +00:00
public XmppConnection createConnection ( final Account account ) {
final XmppConnection connection = new XmppConnection ( account , this ) ;
2014-07-12 00:36:37 +00:00
connection . setOnMessagePacketReceivedListener ( this . mMessageParser ) ;
2014-02-05 21:33:39 +00:00
connection . setOnStatusChangedListener ( this . statusListener ) ;
2014-07-12 00:36:37 +00:00
connection . setOnPresencePacketReceivedListener ( this . mPresenceParser ) ;
2014-08-26 14:52:42 +00:00
connection . setOnUnregisteredIqPacketReceivedListener ( this . mIqParser ) ;
2014-03-27 01:02:59 +00:00
connection . setOnJinglePacketReceivedListener ( this . jingleListener ) ;
2014-07-18 19:57:10 +00:00
connection . setOnBindListener ( this . mOnBindListener ) ;
2014-12-05 00:54:16 +00:00
connection . setOnMessageAcknowledgeListener ( this . mOnMessageAcknowledgedListener ) ;
2014-12-08 20:59:14 +00:00
connection . addOnAdvancedStreamFeaturesAvailableListener ( this . mMessageArchiveService ) ;
2016-04-11 20:20:32 +00:00
connection . addOnAdvancedStreamFeaturesAvailableListener ( this . mAvatarService ) ;
2015-10-16 21:48:42 +00:00
AxolotlService axolotlService = account . getAxolotlService ( ) ;
if ( axolotlService ! = null ) {
connection . addOnAdvancedStreamFeaturesAvailableListener ( axolotlService ) ;
}
2014-02-04 14:09:50 +00:00
return connection ;
}
2014-02-19 00:35:23 +00:00
2015-02-21 10:06:52 +00:00
public void sendChatState ( Conversation conversation ) {
if ( sendChatStates ( ) ) {
MessagePacket packet = mMessageGenerator . generateChatState ( conversation ) ;
sendMessagePacket ( conversation . getAccount ( ) , packet ) ;
}
}
2015-07-20 16:11:33 +00:00
private void sendFileMessage ( final Message message , final boolean delay ) {
2015-06-28 09:19:07 +00:00
Log . d ( Config . LOGTAG , " send file message " ) ;
final Account account = message . getConversation ( ) . getAccount ( ) ;
2017-10-28 15:49:51 +00:00
if ( account . httpUploadAvailable ( fileBackend . getFile ( message , false ) . getSize ( ) )
2017-05-13 06:11:24 +00:00
| | message . getConversation ( ) . getMode ( ) = = Conversation . MODE_MULTI ) {
2015-07-20 16:11:33 +00:00
mHttpConnectionManager . createNewUploadConnection ( message , delay ) ;
2015-06-28 09:19:07 +00:00
} else {
mJingleConnectionManager . createNewConnection ( message ) ;
}
}
2014-12-21 20:43:58 +00:00
public void sendMessage ( final Message message ) {
2015-07-20 16:11:33 +00:00
sendMessage ( message , false , false ) ;
2015-07-05 09:59:38 +00:00
}
2015-07-20 16:11:33 +00:00
private void sendMessage ( final Message message , final boolean resend , final boolean delay ) {
2014-12-21 20:43:58 +00:00
final Account account = message . getConversation ( ) . getAccount ( ) ;
2016-10-04 09:16:59 +00:00
if ( account . setShowErrorNotification ( true ) ) {
databaseBackend . updateAccount ( account ) ;
mNotificationService . updateErrorNotification ( ) ;
}
2018-04-26 11:22:31 +00:00
final Conversation conversation = ( Conversation ) message . getConversation ( ) ;
2014-10-17 09:01:38 +00:00
account . deactivateGracePeriod ( ) ;
2014-04-11 07:13:56 +00:00
MessagePacket packet = null ;
2016-02-15 22:15:04 +00:00
final boolean addToConversation = ( conversation . getMode ( ) ! = Conversation . MODE_MULTI
2017-02-19 12:05:40 +00:00
| | ! Patches . BAD_MUC_REFLECTION . contains ( account . getServerIdentity ( ) ) )
2016-02-15 22:15:04 +00:00
& & ! message . edited ( ) ;
2015-11-01 13:50:06 +00:00
boolean saveInDb = addToConversation ;
2015-07-05 09:59:38 +00:00
message . setStatus ( Message . STATUS_WAITING ) ;
if ( account . isOnlineAndConnected ( ) ) {
switch ( message . getEncryption ( ) ) {
case Message . ENCRYPTION_NONE :
if ( message . needsUploading ( ) ) {
2017-10-28 15:49:51 +00:00
if ( account . httpUploadAvailable ( fileBackend . getFile ( message , false ) . getSize ( ) )
2017-07-01 17:31:48 +00:00
| | conversation . getMode ( ) = = Conversation . MODE_MULTI
2016-03-31 22:03:14 +00:00
| | message . fixCounterpart ( ) ) {
2015-10-16 07:58:31 +00:00
this . sendFileMessage ( message , delay ) ;
2015-07-05 09:59:38 +00:00
} else {
break ;
2015-06-28 09:19:07 +00:00
}
2014-06-22 11:57:57 +00:00
} else {
2015-07-20 16:11:33 +00:00
packet = mMessageGenerator . generateChat ( message ) ;
2014-10-29 23:31:44 +00:00
}
2015-07-05 09:59:38 +00:00
break ;
case Message . ENCRYPTION_PGP :
case Message . ENCRYPTION_DECRYPTED :
if ( message . needsUploading ( ) ) {
2017-10-28 15:49:51 +00:00
if ( account . httpUploadAvailable ( fileBackend . getFile ( message , false ) . getSize ( ) )
2017-07-01 17:31:48 +00:00
| | conversation . getMode ( ) = = Conversation . MODE_MULTI
2016-03-31 22:03:14 +00:00
| | message . fixCounterpart ( ) ) {
2015-10-16 07:58:31 +00:00
this . sendFileMessage ( message , delay ) ;
2014-11-09 16:46:00 +00:00
} else {
2015-07-05 09:59:38 +00:00
break ;
2014-11-09 16:46:00 +00:00
}
} else {
2015-07-20 16:11:33 +00:00
packet = mMessageGenerator . generatePgpChat ( message ) ;
2014-04-07 18:05:45 +00:00
}
2015-07-05 09:59:38 +00:00
break ;
2015-06-25 15:01:42 +00:00
case Message . ENCRYPTION_AXOLOTL :
2016-03-31 19:15:49 +00:00
message . setFingerprint ( account . getAxolotlService ( ) . getOwnFingerprint ( ) ) ;
2015-07-17 17:44:05 +00:00
if ( message . needsUploading ( ) ) {
2017-10-28 15:49:51 +00:00
if ( account . httpUploadAvailable ( fileBackend . getFile ( message , false ) . getSize ( ) )
2017-07-01 17:31:48 +00:00
| | conversation . getMode ( ) = = Conversation . MODE_MULTI
2016-03-31 22:03:14 +00:00
| | message . fixCounterpart ( ) ) {
2015-10-16 07:58:31 +00:00
this . sendFileMessage ( message , delay ) ;
2015-07-17 17:44:05 +00:00
} else {
break ;
}
} else {
2015-07-20 21:13:28 +00:00
XmppAxolotlMessage axolotlMessage = account . getAxolotlService ( ) . fetchAxolotlMessageFromCache ( message ) ;
if ( axolotlMessage = = null ) {
2015-07-31 19:12:34 +00:00
account . getAxolotlService ( ) . preparePayloadMessage ( message , delay ) ;
2015-07-20 21:13:28 +00:00
} else {
packet = mMessageGenerator . generateAxolotlChat ( message , axolotlMessage ) ;
2015-07-17 17:44:05 +00:00
}
2015-07-03 11:31:14 +00:00
}
2015-06-25 15:01:42 +00:00
break ;
2015-07-05 09:59:38 +00:00
}
if ( packet ! = null ) {
2016-10-09 17:40:30 +00:00
if ( account . getXmppConnection ( ) . getFeatures ( ) . sm ( )
| | ( conversation . getMode ( ) = = Conversation . MODE_MULTI & & message . getCounterpart ( ) . isBareJid ( ) ) ) {
2015-07-05 09:59:38 +00:00
message . setStatus ( Message . STATUS_UNSEND ) ;
} else {
message . setStatus ( Message . STATUS_SEND ) ;
2014-02-11 22:55:03 +00:00
}
}
} else {
2015-10-16 07:58:31 +00:00
switch ( message . getEncryption ( ) ) {
2015-07-05 09:59:38 +00:00
case Message . ENCRYPTION_DECRYPTED :
if ( ! message . needsUploading ( ) ) {
String pgpBody = message . getEncryptedBody ( ) ;
String decryptedBody = message . getBody ( ) ;
2017-12-13 19:28:30 +00:00
message . setBody ( pgpBody ) ; //TODO might throw NPE
2015-07-05 09:59:38 +00:00
message . setEncryption ( Message . ENCRYPTION_PGP ) ;
2016-09-04 20:59:15 +00: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 09:59:38 +00:00
}
break ;
2015-07-15 14:32:42 +00:00
case Message . ENCRYPTION_AXOLOTL :
2016-03-31 19:15:49 +00:00
message . setFingerprint ( account . getAxolotlService ( ) . getOwnFingerprint ( ) ) ;
2015-07-15 14:32:42 +00:00
break ;
2014-05-16 11:42:20 +00:00
}
2014-02-13 22:40:08 +00:00
}
2015-07-05 09:59:38 +00:00
2017-11-21 14:42:46 +00:00
boolean mucMessage = conversation . getMode ( ) = = Conversation . MODE_MULTI & & message . getType ( ) ! = Message . TYPE_PRIVATE ;
if ( mucMessage ) {
message . setCounterpart ( conversation . getMucOptions ( ) . getSelf ( ) . getFullJid ( ) ) ;
}
2015-07-05 09:59:38 +00:00
if ( resend ) {
2015-11-01 13:50:06 +00:00
if ( packet ! = null & & addToConversation ) {
2017-11-21 14:42:46 +00:00
if ( account . getXmppConnection ( ) . getFeatures ( ) . sm ( ) | | mucMessage ) {
2015-10-16 07:58:31 +00:00
markMessage ( message , Message . STATUS_UNSEND ) ;
2015-07-05 09:59:38 +00:00
} else {
2015-10-16 07:58:31 +00:00
markMessage ( message , Message . STATUS_SEND ) ;
2015-07-05 09:59:38 +00:00
}
}
} else {
2015-11-01 13:50:06 +00:00
if ( addToConversation ) {
conversation . add ( message ) ;
}
2017-01-23 16:14:30 +00:00
if ( saveInDb ) {
databaseBackend . createMessage ( message ) ;
} else if ( message . edited ( ) ) {
databaseBackend . updateMessage ( message , message . getEditedId ( ) ) ;
2015-07-05 09:59:38 +00:00
}
updateConversationUi ( ) ;
2014-02-13 22:40:08 +00:00
}
2015-07-05 09:59:38 +00:00
if ( packet ! = null ) {
2015-07-20 16:11:33 +00:00
if ( delay ) {
2015-10-16 07:58:31 +00:00
mMessageGenerator . addDelay ( packet , message . getTimeSent ( ) ) ;
2015-07-20 16:11:33 +00:00
}
2015-07-05 09:59:38 +00:00
if ( conversation . setOutgoingChatState ( Config . DEFAULT_CHATSTATE ) ) {
2015-02-21 10:06:52 +00:00
if ( this . sendChatStates ( ) ) {
2015-07-05 09:59:38 +00:00
packet . addChild ( ChatState . toElement ( conversation . getOutgoingChatState ( ) ) ) ;
2015-02-21 10:06:52 +00:00
}
}
2014-07-12 01:44:23 +00:00
sendMessagePacket ( account , packet ) ;
2014-04-11 07:13:56 +00:00
}
2014-02-11 22:55:03 +00:00
}
2014-12-21 20:43:58 +00:00
private void sendUnsentMessages ( final Conversation conversation ) {
2014-12-14 17:10:46 +00:00
conversation . findWaitingMessages ( new Conversation . OnMessageFound ( ) {
@Override
public void onMessageFound ( Message message ) {
2015-07-20 21:13:28 +00:00
resendMessage ( message , true ) ;
2014-05-16 11:42:20 +00:00
}
2014-12-14 17:10:46 +00:00
} ) ;
2014-05-16 11:42:20 +00:00
}
2014-05-18 09:25:04 +00:00
2015-07-20 16:11:33 +00:00
public void resendMessage ( final Message message , final boolean delay ) {
sendMessage ( message , true , delay ) ;
2014-02-11 22:55:03 +00:00
}
2014-12-21 20:43:58 +00:00
public void fetchRosterFromServer ( final Account account ) {
2014-12-30 13:16:25 +00:00
final IqPacket iqPacket = new IqPacket ( IqPacket . TYPE . GET ) ;
2014-03-08 01:06:00 +00:00
if ( ! " " . equals ( account . getRosterVersion ( ) ) ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( )
2014-08-31 14:28:21 +00:00
+ " : fetching roster version " + account . getRosterVersion ( ) ) ;
2014-03-08 01:06:00 +00:00
} else {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : fetching roster " ) ;
2014-03-08 01:06:00 +00:00
}
2017-03-01 12:01:46 +00:00
iqPacket . query ( Namespace . ROSTER ) . setAttribute ( " ver " , account . getRosterVersion ( ) ) ;
2015-08-13 16:25:10 +00:00
sendIqPacket ( account , iqPacket , mIqParser ) ;
2014-02-10 02:34:00 +00:00
}
2014-08-26 14:52:42 +00:00
2014-12-21 20:43:58 +00:00
public void fetchBookmarks ( final Account account ) {
2014-12-30 13:16:25 +00:00
final IqPacket iqPacket = new IqPacket ( IqPacket . TYPE . GET ) ;
2014-12-21 20:43:58 +00:00
final Element query = iqPacket . query ( " jabber:iq:private " ) ;
2014-07-14 09:47:42 +00:00
query . addChild ( " storage " , " storage:bookmarks " ) ;
2015-01-04 11:09:39 +00:00
final OnIqPacketReceived callback = new OnIqPacketReceived ( ) {
2014-08-26 14:52:42 +00:00
2014-07-14 09:47:42 +00:00
@Override
2014-12-21 20:43:58 +00:00
public void onIqPacketReceived ( final Account account , final IqPacket packet ) {
2015-08-23 06:27:05 +00:00
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
final Element query = packet . query ( ) ;
2015-12-27 16:29:32 +00:00
final HashMap < Jid , Bookmark > bookmarks = new HashMap < > ( ) ;
2015-08-23 06:27:05 +00:00
final Element storage = query . findChild ( " storage " , " storage:bookmarks " ) ;
2016-02-01 12:54:08 +00:00
final boolean autojoin = respectAutojoin ( ) ;
2015-08-23 06:27:05 +00: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 16:29:32 +00:00
Bookmark old = bookmarks . put ( bookmark . getJid ( ) , bookmark ) ;
if ( old ! = null & & old . getBookmarkName ( ) ! = null & & bookmark . getBookmarkName ( ) = = null ) {
bookmark . setBookmarkName ( old . getBookmarkName ( ) ) ;
}
2015-08-23 06:27:05 +00:00
Conversation conversation = find ( bookmark ) ;
if ( conversation ! = null ) {
2018-02-10 18:06:31 +00:00
bookmark . setConversation ( conversation ) ;
2016-02-01 12:54:08 +00:00
} else if ( bookmark . autojoin ( ) & & bookmark . getJid ( ) ! = null & & autojoin ) {
2017-04-12 22:12:23 +00:00
conversation = findOrCreateConversation ( account , bookmark . getJid ( ) , true , true , false ) ;
2018-02-10 18:06:31 +00:00
bookmark . setConversation ( conversation ) ;
2015-08-23 06:27:05 +00:00
}
2014-07-14 09:47:42 +00:00
}
}
}
2018-02-10 18:06:31 +00:00
account . setBookmarks ( new CopyOnWriteArrayList < > ( bookmarks . values ( ) ) ) ;
2015-08-23 06:27:05 +00:00
} else {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : could not fetch bookmarks " ) ;
2014-07-14 09:47:42 +00:00
}
}
} ;
sendIqPacket ( account , iqPacket , callback ) ;
}
2014-08-26 14:52:42 +00:00
2014-07-15 12:32:19 +00:00
public void pushBookmarks ( Account account ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : pushing bookmarks " ) ;
2014-12-30 13:16:25 +00:00
IqPacket iqPacket = new IqPacket ( IqPacket . TYPE . SET ) ;
2014-07-15 12:32:19 +00:00
Element query = iqPacket . query ( " jabber:iq:private " ) ;
Element storage = query . addChild ( " storage " , " storage:bookmarks " ) ;
2014-08-26 14:52:42 +00:00
for ( Bookmark bookmark : account . getBookmarks ( ) ) {
2014-10-05 22:33:52 +00:00
storage . addChild ( bookmark ) ;
2014-07-15 12:32:19 +00:00
}
2015-05-26 09:31:33 +00:00
sendIqPacket ( account , iqPacket , mDefaultIqHandler ) ;
2014-07-15 12:32:19 +00:00
}
2014-02-10 02:34:00 +00:00
2015-02-17 10:51:11 +00:00
private void restoreFromDatabase ( ) {
2014-11-18 02:10:59 +00:00
synchronized ( this . conversations ) {
2014-12-21 20:43:58 +00:00
final Map < String , Account > accountLookupTable = new Hashtable < > ( ) ;
2014-02-03 17:38:47 +00:00
for ( Account account : this . accounts ) {
accountLookupTable . put ( account . getUuid ( ) , account ) ;
}
2017-10-28 15:49:51 +00:00
Log . d ( Config . LOGTAG , " restoring conversations... " ) ;
2017-05-04 09:03:58 +00:00
final long startTimeConversationsRestore = SystemClock . elapsedRealtime ( ) ;
2014-11-18 02:10:59 +00:00
this . conversations . addAll ( databaseBackend . getConversations ( Conversation . STATUS_AVAILABLE ) ) ;
2017-10-28 15:49:51 +00:00
for ( Iterator < Conversation > iterator = conversations . listIterator ( ) ; iterator . hasNext ( ) ; ) {
2017-04-25 16:17:23 +00:00
Conversation conversation = iterator . next ( ) ;
2014-12-15 22:06:29 +00:00
Account account = accountLookupTable . get ( conversation . getAccountUuid ( ) ) ;
2017-04-25 16:17:23 +00:00
if ( account ! = null ) {
conversation . setAccount ( account ) ;
} else {
2017-10-28 15:49:51 +00:00
Log . e ( Config . LOGTAG , " unable to restore Conversations with " + conversation . getJid ( ) ) ;
2017-04-25 16:17:23 +00:00
iterator . remove ( ) ;
}
2014-02-03 17:38:47 +00:00
}
2017-05-04 09:03:58 +00:00
long diffConversationsRestore = SystemClock . elapsedRealtime ( ) - startTimeConversationsRestore ;
2017-10-28 15:49:51 +00:00
Log . d ( Config . LOGTAG , " finished restoring conversations in " + diffConversationsRestore + " ms " ) ;
2018-03-18 09:30:15 +00:00
Runnable runnable = ( ) - > {
long deletionDate = getAutomaticMessageDeletionDate ( ) ;
mLastExpiryRun . set ( SystemClock . elapsedRealtime ( ) ) ;
if ( deletionDate > 0 ) {
Log . d ( Config . LOGTAG , " deleting messages that are older than " + AbstractGenerator . getTimestamp ( deletionDate ) ) ;
databaseBackend . expireOldMessages ( deletionDate ) ;
}
Log . d ( Config . LOGTAG , " restoring roster... " ) ;
for ( Account account : accounts ) {
databaseBackend . readRoster ( account . getRoster ( ) ) ;
account . initAccountServices ( XmppConnectionService . this ) ; //roster needs to be loaded at this stage
}
getBitmapCache ( ) . evictAll ( ) ;
loadPhoneContacts ( ) ;
Log . d ( Config . LOGTAG , " restoring messages... " ) ;
final long startMessageRestore = SystemClock . elapsedRealtime ( ) ;
2018-04-11 16:07:40 +00:00
final Conversation quickLoad = QuickLoader . get ( this . conversations ) ;
if ( quickLoad ! = null ) {
restoreMessages ( quickLoad ) ;
updateConversationUi ( ) ;
final long diffMessageRestore = SystemClock . elapsedRealtime ( ) - startMessageRestore ;
Log . d ( Config . LOGTAG , " quickly restored " + quickLoad . getName ( ) + " after " + diffMessageRestore + " ms " ) ;
}
for ( Conversation conversation : this . conversations ) {
if ( quickLoad ! = conversation ) {
restoreMessages ( conversation ) ;
}
2015-02-12 17:53:00 +00:00
}
2018-03-18 09:30:15 +00:00
mNotificationService . finishBacklog ( false ) ;
restoredFromDatabaseLatch . countDown ( ) ;
final long diffMessageRestore = SystemClock . elapsedRealtime ( ) - startMessageRestore ;
Log . d ( Config . LOGTAG , " finished restoring messages in " + diffMessageRestore + " ms " ) ;
updateConversationUi ( ) ;
2015-06-05 06:46:06 +00:00
} ;
2017-11-16 14:53:03 +00:00
mDatabaseReaderExecutor . execute ( runnable ) ; //will contain one write command (expiry) but that's fine
2014-02-03 17:38:47 +00:00
}
2014-11-18 02:10:59 +00:00
}
2018-04-11 16:07:40 +00:00
private void restoreMessages ( Conversation conversation ) {
conversation . addAll ( 0 , databaseBackend . getMessages ( conversation , Config . PAGE_SIZE ) ) ;
checkDeletedFiles ( conversation ) ;
conversation . findUnsentTextMessages ( message - > markMessage ( message , Message . STATUS_WAITING ) ) ;
conversation . findUnreadMessages ( message - > mNotificationService . pushFromBacklog ( message ) ) ;
}
2015-12-06 23:33:50 +00:00
public void loadPhoneContacts ( ) {
2018-03-18 09:30:15 +00:00
mContactMergerExecutor . execute ( ( ) - > PhoneHelper . loadPhoneContacts ( XmppConnectionService . this , new OnPhoneContactsLoadedListener ( ) {
2016-05-31 15:20:21 +00:00
@Override
2018-03-18 09:30:15 +00:00
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 . of ( phoneContact . getString ( " jid " ) ) ;
} catch ( final IllegalArgumentException e ) {
continue ;
}
final Contact contact = account . getRoster ( ) . getContact ( jid ) ;
String systemAccount = phoneContact . getInt ( " phoneid " )
+ " # "
+ phoneContact . getString ( " lookup " ) ;
contact . setSystemAccount ( systemAccount ) ;
boolean needsCacheClean = contact . setPhotoUri ( phoneContact . getString ( " photouri " ) ) ;
needsCacheClean | = contact . setSystemName ( phoneContact . getString ( " displayname " ) ) ;
if ( needsCacheClean ) {
getAvatarService ( ) . clear ( contact ) ;
}
withSystemAccounts . remove ( contact ) ;
}
for ( Contact contact : withSystemAccounts ) {
contact . setSystemAccount ( null ) ;
boolean needsCacheClean = contact . setPhotoUri ( null ) ;
needsCacheClean | = contact . setSystemName ( null ) ;
if ( needsCacheClean ) {
getAvatarService ( ) . clear ( contact ) ;
2016-05-31 15:20:21 +00:00
}
}
2018-03-18 09:30:15 +00:00
}
Log . d ( Config . LOGTAG , " finished merging phone contacts " ) ;
mShortcutService . refresh ( mInitialAddressbookSyncCompleted . compareAndSet ( false , true ) ) ;
updateAccountUi ( ) ;
2016-05-31 15:20:21 +00:00
}
2018-03-18 09:30:15 +00:00
} ) ) ;
2015-12-06 23:33:50 +00:00
}
2018-03-18 11:24:28 +00:00
public void syncRoster ( final Account account ) {
2018-03-18 15:46:50 +00:00
mRosterSyncTaskManager . execute ( account , ( ) - > databaseBackend . writeRoster ( account . getRoster ( ) ) ) ;
2018-03-18 11:24:28 +00:00
}
2014-11-18 02:10:59 +00:00
public List < Conversation > getConversations ( ) {
2014-07-12 10:41:37 +00:00
return this . conversations ;
}
2014-10-20 19:08:33 +00:00
2014-10-15 20:08:13 +00:00
private void checkDeletedFiles ( Conversation conversation ) {
2018-03-18 09:30:15 +00:00
conversation . findMessagesWithFiles ( message - > {
if ( ! getFileBackend ( ) . isFileAvailable ( message ) ) {
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 ) ;
2014-10-15 20:08:13 +00:00
}
2014-12-14 17:10:46 +00:00
}
} ) ;
2014-10-15 20:08:13 +00:00
}
2014-10-20 19:08:33 +00:00
2016-07-23 14:12:45 +00:00
private void markFileDeleted ( final String path ) {
2017-10-28 15:49:51 +00:00
Log . d ( Config . LOGTAG , " deleted file " + path ) ;
2014-10-20 19:08:33 +00:00
for ( Conversation conversation : getConversations ( ) ) {
2018-03-18 09:30:15 +00:00
conversation . findMessagesWithFiles ( message - > {
DownloadableFile file = fileBackend . getFile ( message ) ;
if ( file . getAbsolutePath ( ) . equals ( path ) ) {
if ( ! file . exists ( ) ) {
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 ) ;
2016-07-23 14:12:45 +00:00
} else {
2018-03-18 09:30:15 +00:00
updateConversationUi ( ) ;
2016-07-23 14:12:45 +00:00
}
2018-03-18 09:30:15 +00:00
} else {
Log . d ( Config . LOGTAG , " found matching message for file " + path + " but file still exists " ) ;
2015-08-11 14:50:00 +00:00
}
2014-12-14 17:10:46 +00:00
}
2016-07-23 14:12:45 +00:00
} ) ;
2014-10-16 00:39:02 +00:00
}
}
2014-09-05 11:29:20 +00:00
2014-11-18 02:10:59 +00:00
public void populateWithOrderedConversations ( final List < Conversation > list ) {
2014-09-05 11:29:20 +00:00
populateWithOrderedConversations ( list , true ) ;
2014-09-02 13:51:20 +00:00
}
2015-07-02 21:51:59 +00:00
public void populateWithOrderedConversations ( final List < Conversation > list , boolean includeNoFileUpload ) {
2014-07-12 10:41:37 +00:00
list . clear ( ) ;
2015-07-02 21:51:59 +00:00
if ( includeNoFileUpload ) {
2014-09-02 13:51:20 +00:00
list . addAll ( getConversations ( ) ) ;
} else {
2014-09-05 11:29:20 +00:00
for ( Conversation conversation : getConversations ( ) ) {
2015-07-02 21:51:59 +00:00
if ( conversation . getMode ( ) = = Conversation . MODE_SINGLE
| | conversation . getAccount ( ) . httpUploadAvailable ( ) ) {
2014-09-02 13:51:20 +00:00
list . add ( conversation ) ;
}
}
}
2016-06-09 12:50:13 +00:00
try {
Collections . sort ( list ) ;
} catch ( IllegalArgumentException e ) {
//ignore
}
2014-02-03 17:38:47 +00:00
}
2014-09-27 09:37:02 +00:00
2014-12-17 08:32:51 +00:00
public void loadMoreMessages ( final Conversation conversation , final long timestamp , final OnMoreMessagesLoaded callback ) {
2015-10-16 07:58:31 +00:00
if ( XmppConnectionService . this . getMessageArchiveService ( ) . queryInProgress ( conversation , callback ) ) {
2014-12-17 09:50:51 +00:00
return ;
2016-02-04 13:39:16 +00:00
} else if ( timestamp = = 0 ) {
return ;
2014-12-17 09:50:51 +00:00
}
2015-10-04 22:45:16 +00:00
Log . d ( Config . LOGTAG , " load more messages for " + conversation . getName ( ) + " prior to " + MessageGenerator . getTimestamp ( timestamp ) ) ;
2018-01-29 00:39:46 +00:00
final Runnable runnable = ( ) - > {
final Account account = conversation . getAccount ( ) ;
List < Message > messages = databaseBackend . getMessages ( conversation , 50 , timestamp ) ;
if ( messages . size ( ) > 0 ) {
conversation . addAll ( 0 , messages ) ;
checkDeletedFiles ( conversation ) ;
callback . onMoreMessagesLoaded ( messages . size ( ) , conversation ) ;
} else if ( conversation . hasMessagesLeftOnServer ( )
& & account . isOnlineAndConnected ( )
& & conversation . getLastClearHistory ( ) . getTimestamp ( ) = = 0 ) {
final boolean mamAvailable ;
if ( conversation . getMode ( ) = = Conversation . MODE_SINGLE ) {
mamAvailable = account . getXmppConnection ( ) . getFeatures ( ) . mam ( ) & & ! conversation . getContact ( ) . isBlocked ( ) ;
} else {
mamAvailable = conversation . getMucOptions ( ) . mamSupport ( ) ;
}
if ( mamAvailable ) {
MessageArchiveService . Query query = getMessageArchiveService ( ) . query ( conversation , new MamReference ( 0 ) , timestamp , false ) ;
if ( query ! = null ) {
query . setCallback ( callback ) ;
callback . informUser ( R . string . fetching_history_from_server ) ;
} else {
callback . informUser ( R . string . not_fetching_history_retention_period ) ;
2014-12-17 08:32:51 +00:00
}
2018-01-29 00:39:46 +00:00
2015-01-19 10:23:05 +00:00
}
2014-12-15 22:06:29 +00:00
}
2015-06-05 06:46:06 +00:00
} ;
2017-11-16 14:53:03 +00:00
mDatabaseReaderExecutor . execute ( runnable ) ;
2014-12-15 22:06:29 +00:00
}
2014-02-03 17:38:47 +00:00
public List < Account > getAccounts ( ) {
return this . accounts ;
}
2014-06-03 13:48:51 +00:00
2016-06-14 15:11:31 +00:00
public List < Conversation > findAllConferencesWith ( Contact contact ) {
ArrayList < Conversation > results = new ArrayList < > ( ) ;
2018-04-14 15:54:04 +00:00
for ( final Conversation c : conversations ) {
if ( c . getMode ( ) = = Conversation . MODE_MULTI
& & ( c . getJid ( ) . asBareJid ( ) . equals ( c . getJid ( ) . asBareJid ( ) ) | | c . getMucOptions ( ) . isContactInRoom ( contact ) ) ) {
results . add ( c ) ;
2016-06-14 15:11:31 +00:00
}
}
return results ;
}
2014-12-21 20:43:58 +00:00
public Conversation find ( final Iterable < Conversation > haystack , final Contact contact ) {
for ( final Conversation conversation : haystack ) {
2014-05-23 08:54:40 +00:00
if ( conversation . getContact ( ) = = contact ) {
return conversation ;
}
}
return null ;
}
2014-02-11 22:55:03 +00:00
2014-12-21 20:43:58 +00:00
public Conversation find ( final Iterable < Conversation > haystack , final Account account , final Jid jid ) {
2015-01-19 10:17:27 +00:00
if ( jid = = null ) {
2014-11-29 18:09:28 +00:00
return null ;
}
2014-12-21 20:43:58 +00:00
for ( final Conversation conversation : haystack ) {
2014-10-28 16:15:35 +00:00
if ( ( account = = null | | conversation . getAccount ( ) = = account )
2018-03-05 17:30:40 +00:00
& & ( conversation . getJid ( ) . asBareJid ( ) . equals ( jid . asBareJid ( ) ) ) ) {
2014-07-20 00:26:23 +00:00
return conversation ;
2015-01-19 10:17:27 +00:00
}
2014-07-20 00:26:23 +00:00
}
return null ;
}
2014-08-26 14:52:42 +00:00
2018-02-24 19:19:35 +00:00
public boolean isConversationsListEmpty ( final Conversation ignore ) {
synchronized ( this . conversations ) {
final int size = this . conversations . size ( ) ;
2018-04-14 12:55:51 +00:00
return size = = 0 | | size = = 1 & & this . conversations . get ( 0 ) = = ignore ;
2018-02-24 19:19:35 +00:00
}
}
2018-03-29 13:08:43 +00:00
public boolean isConversationStillOpen ( final Conversation conversation ) {
synchronized ( this . conversations ) {
2018-03-31 08:57:59 +00:00
for ( Conversation current : this . conversations ) {
2018-03-29 13:08:43 +00:00
if ( current = = conversation ) {
return true ;
}
}
}
return false ;
}
2017-04-12 22:12:23 +00:00
public Conversation findOrCreateConversation ( Account account , Jid jid , boolean muc , final boolean async ) {
2017-10-28 15:49:51 +00:00
return this . findOrCreateConversation ( account , jid , muc , false , async ) ;
2014-12-13 11:25:52 +00:00
}
2017-04-12 22:12:23 +00:00
public Conversation findOrCreateConversation ( final Account account , final Jid jid , final boolean muc , final boolean joinAfterCreate , final boolean async ) {
return this . findOrCreateConversation ( account , jid , muc , joinAfterCreate , null , async ) ;
2017-02-14 15:50:33 +00:00
}
2017-04-12 22:12:23 +00:00
public Conversation findOrCreateConversation ( final Account account , final Jid jid , final boolean muc , final boolean joinAfterCreate , final MessageArchiveService . Query query , final boolean async ) {
2014-11-18 02:10:59 +00:00
synchronized ( this . conversations ) {
Conversation conversation = find ( account , jid ) ;
if ( conversation ! = null ) {
return conversation ;
2014-02-10 14:24:34 +00:00
}
2014-11-18 02:10:59 +00:00
conversation = databaseBackend . findConversation ( account , jid ) ;
2017-02-07 13:03:23 +00:00
final boolean loadMessagesFromDb ;
2014-11-18 02:10:59 +00:00
if ( conversation ! = null ) {
conversation . setStatus ( Conversation . STATUS_AVAILABLE ) ;
conversation . setAccount ( account ) ;
if ( muc ) {
conversation . setMode ( Conversation . MODE_MULTI ) ;
2015-01-21 15:18:38 +00:00
conversation . setContactJid ( jid ) ;
2014-11-18 02:10:59 +00:00
} else {
conversation . setMode ( Conversation . MODE_SINGLE ) ;
2018-03-05 17:30:40 +00:00
conversation . setContactJid ( jid . asBareJid ( ) ) ;
2014-11-18 02:10:59 +00:00
}
2017-02-07 13:03:23 +00:00
databaseBackend . updateConversation ( conversation ) ;
2017-10-28 15:49:51 +00:00
loadMessagesFromDb = conversation . messagesLoaded . compareAndSet ( true , false ) ;
2014-02-07 15:50:29 +00:00
} else {
2014-11-18 02:10:59 +00:00
String conversationName ;
Contact contact = account . getRoster ( ) . getContact ( jid ) ;
if ( contact ! = null ) {
conversationName = contact . getDisplayName ( ) ;
} else {
2018-03-05 17:30:40 +00:00
conversationName = jid . getLocal ( ) ;
2014-11-18 02:10:59 +00:00
}
if ( muc ) {
conversation = new Conversation ( conversationName , account , jid ,
Conversation . MODE_MULTI ) ;
} else {
2018-03-05 17:30:40 +00:00
conversation = new Conversation ( conversationName , account , jid . asBareJid ( ) ,
2014-11-18 02:10:59 +00:00
Conversation . MODE_SINGLE ) ;
}
this . databaseBackend . createConversation ( conversation ) ;
2017-02-07 13:03:23 +00:00
loadMessagesFromDb = false ;
2014-02-07 15:50:29 +00:00
}
2017-02-07 13:03:23 +00:00
final Conversation c = conversation ;
2018-01-29 00:39:46 +00:00
final Runnable runnable = ( ) - > {
if ( loadMessagesFromDb ) {
c . addAll ( 0 , databaseBackend . getMessages ( c , Config . PAGE_SIZE ) ) ;
updateConversationUi ( ) ;
c . messagesLoaded . set ( true ) ;
}
if ( account . getXmppConnection ( ) ! = null
& & ! c . getContact ( ) . isBlocked ( )
& & account . getXmppConnection ( ) . getFeatures ( ) . mam ( )
& & ! muc ) {
if ( query = = null ) {
mMessageArchiveService . query ( c ) ;
} else {
if ( query . getConversation ( ) = = null ) {
mMessageArchiveService . query ( c , query . getStart ( ) , query . isCatchup ( ) ) ;
2017-02-07 13:03:23 +00:00
}
}
2018-01-29 00:39:46 +00:00
}
checkDeletedFiles ( c ) ;
if ( joinAfterCreate ) {
joinMuc ( c ) ;
2014-12-13 11:25:52 +00:00
}
2017-04-12 22:12:23 +00:00
} ;
if ( async ) {
2017-11-16 14:53:03 +00:00
mDatabaseReaderExecutor . execute ( runnable ) ;
2017-04-12 22:12:23 +00:00
} else {
runnable . run ( ) ;
}
2014-11-18 02:10:59 +00:00
this . conversations . add ( conversation ) ;
updateConversationUi ( ) ;
return conversation ;
2014-02-03 17:38:47 +00:00
}
}
public void archiveConversation ( Conversation conversation ) {
2015-04-02 22:06:37 +00:00
getNotificationService ( ) . clear ( conversation ) ;
2015-01-07 11:20:39 +00:00
conversation . setStatus ( Conversation . STATUS_ARCHIVED ) ;
2018-03-12 15:00:02 +00:00
conversation . setNextMessage ( null ) ;
2014-11-18 02:10:59 +00:00
synchronized ( this . conversations ) {
2018-02-24 08:39:17 +00:00
getMessageArchiveService ( ) . kill ( conversation ) ;
2014-11-18 02:10:59 +00:00
if ( conversation . getMode ( ) = = Conversation . MODE_MULTI ) {
if ( conversation . getAccount ( ) . getStatus ( ) = = Account . State . ONLINE ) {
Bookmark bookmark = conversation . getBookmark ( ) ;
2016-02-01 12:54:08 +00:00
if ( bookmark ! = null & & bookmark . autojoin ( ) & & respectAutojoin ( ) ) {
2014-11-18 02:10:59 +00:00
bookmark . setAutojoin ( false ) ;
pushBookmarks ( bookmark . getAccount ( ) ) ;
}
2014-10-08 12:10:37 +00:00
}
2014-11-18 02:10:59 +00:00
leaveMuc ( conversation ) ;
} else {
2015-11-05 02:56:45 +00: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 12:32:19 +00:00
}
2016-10-18 11:06:24 +00:00
updateConversation ( conversation ) ;
2014-11-18 02:10:59 +00:00
this . conversations . remove ( conversation ) ;
updateConversationUi ( ) ;
2014-02-13 22:40:08 +00:00
}
2014-02-03 17:38:47 +00:00
}
2014-05-01 20:33:49 +00:00
2014-12-23 22:19:00 +00:00
public void createAccount ( final Account account ) {
2015-05-26 02:36:32 +00:00
account . initAccountServices ( this ) ;
2014-01-28 18:21:54 +00:00
databaseBackend . createAccount ( account ) ;
2014-02-04 14:09:50 +00:00
this . accounts . add ( account ) ;
2015-03-05 14:46:33 +00:00
this . reconnectAccountInBackground ( account ) ;
2014-07-12 11:42:17 +00:00
updateAccountUi ( ) ;
2017-10-01 16:44:28 +00:00
syncEnabledAccountSetting ( ) ;
2017-07-12 09:03:32 +00:00
toggleForegroundService ( ) ;
2014-01-28 18:21:54 +00:00
}
2014-02-23 20:33:37 +00:00
2017-10-01 16:44:28 +00:00
private void syncEnabledAccountSetting ( ) {
2017-10-28 15:49:51 +00:00
getPreferences ( ) . edit ( ) . putBoolean ( EventReceiver . SETTING_ENABLED_ACCOUNTS , hasEnabledAccounts ( ) ) . apply ( ) ;
2017-10-01 16:44:28 +00:00
}
2015-10-09 11:37:08 +00:00
public void createAccountFromKey ( final String alias , final OnAccountCreated callback ) {
2018-02-10 09:45:33 +00:00
new Thread ( ( ) - > {
try {
final X509Certificate [ ] chain = KeyChain . getCertificateChain ( this , alias ) ;
final X509Certificate cert = chain ! = null & & chain . length > 0 ? chain [ 0 ] : null ;
if ( cert = = null ) {
callback . informUser ( R . string . unable_to_parse_certificate ) ;
return ;
}
Pair < Jid , String > info = CryptoHelper . extractJidAndName ( cert ) ;
if ( info = = null ) {
callback . informUser ( R . string . certificate_does_not_contain_jid ) ;
return ;
}
if ( findAccountByJid ( info . first ) = = null ) {
Account account = new Account ( info . first , " " ) ;
account . setPrivateKeyAlias ( alias ) ;
account . setOption ( Account . OPTION_DISABLED , true ) ;
account . setDisplayName ( info . second ) ;
createAccount ( account ) ;
callback . onAccountCreated ( account ) ;
if ( Config . X509_VERIFICATION ) {
try {
2018-03-05 17:30:40 +00:00
getMemorizingTrustManager ( ) . getNonInteractive ( account . getJid ( ) . getDomain ( ) ) . checkClientTrusted ( chain , " RSA " ) ;
2018-02-10 09:45:33 +00:00
} catch ( CertificateException e ) {
callback . informUser ( R . string . certificate_chain_is_not_trusted ) ;
2015-10-11 13:48:58 +00:00
}
2015-10-09 11:37:08 +00:00
}
2018-02-10 09:45:33 +00:00
} else {
callback . informUser ( R . string . account_already_exists ) ;
2015-10-09 11:37:08 +00:00
}
2018-02-10 09:45:33 +00:00
} catch ( Exception e ) {
e . printStackTrace ( ) ;
callback . informUser ( R . string . unable_to_parse_certificate ) ;
2015-10-09 11:37:08 +00:00
}
} ) . start ( ) ;
}
2015-10-11 13:48:58 +00:00
public void updateKeyInAccount ( final Account account , final String alias ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : update key in account " + alias ) ;
2015-10-11 13:48:58 +00:00
try {
X509Certificate [ ] chain = KeyChain . getCertificateChain ( XmppConnectionService . this , alias ) ;
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " loaded certificate chain " ) ;
2015-10-11 13:48:58 +00:00
Pair < Jid , String > info = CryptoHelper . extractJidAndName ( chain [ 0 ] ) ;
2018-02-10 09:45:33 +00:00
if ( info = = null ) {
showErrorToastInUi ( R . string . certificate_does_not_contain_jid ) ;
return ;
}
2018-03-05 17:30:40 +00:00
if ( account . getJid ( ) . asBareJid ( ) . equals ( info . first ) ) {
2015-10-11 13:48:58 +00:00
account . setPrivateKeyAlias ( alias ) ;
2015-10-29 12:41:08 +00:00
account . setDisplayName ( info . second ) ;
2015-10-11 13:48:58 +00:00
databaseBackend . updateAccount ( account ) ;
2015-10-12 11:18:20 +00:00
if ( Config . X509_VERIFICATION ) {
try {
2017-02-24 18:58:46 +00:00
getMemorizingTrustManager ( ) . getNonInteractive ( ) . checkClientTrusted ( chain , " RSA " ) ;
2015-10-12 11:18:20 +00:00
} catch ( CertificateException e ) {
showErrorToastInUi ( R . string . certificate_chain_is_not_trusted ) ;
}
account . getAxolotlService ( ) . regenerateKeys ( true ) ;
2015-10-11 13:48:58 +00:00
}
} else {
showErrorToastInUi ( R . string . jid_does_not_match_certificate ) ;
}
2015-10-16 07:58:31 +00:00
} catch ( Exception e ) {
2015-10-11 13:48:58 +00:00
e . printStackTrace ( ) ;
}
}
2016-09-07 12:34:58 +00:00
public boolean updateAccount ( final Account account ) {
if ( databaseBackend . updateAccount ( account ) ) {
2016-10-04 09:16:59 +00:00
account . setShowErrorNotification ( true ) ;
2016-09-07 12:34:58 +00:00
this . statusListener . onStatusChanged ( account ) ;
databaseBackend . updateAccount ( account ) ;
reconnectAccountInBackground ( account ) ;
updateAccountUi ( ) ;
getNotificationService ( ) . updateErrorNotification ( ) ;
2017-07-12 09:03:32 +00:00
toggleForegroundService ( ) ;
2017-10-01 16:44:28 +00:00
syncEnabledAccountSetting ( ) ;
2016-09-07 12:34:58 +00:00
return true ;
} else {
return false ;
}
2014-01-28 18:21:54 +00:00
}
2014-12-25 21:08:13 +00:00
public void updateAccountPasswordOnServer ( final Account account , final String newPassword , final OnAccountPasswordChanged callback ) {
final IqPacket iq = getIqGenerator ( ) . generateSetPassword ( account , newPassword ) ;
2018-03-04 19:37:42 +00:00
sendIqPacket ( account , iq , ( a , packet ) - > {
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
a . setPassword ( newPassword ) ;
a . setOption ( Account . OPTION_MAGIC_CREATE , false ) ;
databaseBackend . updateAccount ( a ) ;
callback . onPasswordChangeSucceeded ( ) ;
} else {
callback . onPasswordChangeFailed ( ) ;
2014-12-25 21:08:13 +00:00
}
} ) ;
}
2014-12-23 22:19:00 +00:00
public void deleteAccount ( final Account account ) {
2014-11-18 02:10:59 +00:00
synchronized ( this . conversations ) {
2014-12-23 22:19:00 +00:00
for ( final Conversation conversation : conversations ) {
2014-11-18 02:10:59 +00:00
if ( conversation . getAccount ( ) = = account ) {
if ( conversation . getMode ( ) = = Conversation . MODE_MULTI ) {
leaveMuc ( conversation ) ;
}
conversations . remove ( conversation ) ;
2014-07-21 16:20:26 +00:00
}
}
2014-11-18 02:10:59 +00:00
if ( account . getXmppConnection ( ) ! = null ) {
2018-02-10 09:45:33 +00:00
new Thread ( ( ) - > disconnect ( account , true ) ) . start ( ) ;
2014-11-18 02:10:59 +00:00
}
2018-02-10 09:45:33 +00:00
final Runnable runnable = ( ) - > {
if ( ! databaseBackend . deleteAccount ( account ) ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : unable to delete account " ) ;
2015-10-29 16:20:01 +00:00
}
} ;
2017-11-16 14:53:03 +00:00
mDatabaseWriterExecutor . execute ( runnable ) ;
2014-11-18 02:10:59 +00:00
this . accounts . remove ( account ) ;
2018-03-18 15:46:50 +00:00
this . mRosterSyncTaskManager . clear ( account ) ;
2014-11-18 02:10:59 +00:00
updateAccountUi ( ) ;
2014-11-18 14:26:28 +00:00
getNotificationService ( ) . updateErrorNotification ( ) ;
2017-10-28 15:49:51 +00:00
syncEnabledAccountSetting ( ) ;
2014-07-21 16:20:26 +00:00
}
2014-01-28 18:21:54 +00:00
}
2014-02-03 17:38:47 +00:00
2014-12-03 13:55:09 +00:00
public void setOnConversationListChangedListener ( OnConversationUpdate listener ) {
synchronized ( this ) {
2016-06-04 14:16:14 +00:00
this . mLastActivity = System . currentTimeMillis ( ) ;
2014-10-15 12:41:27 +00:00
if ( checkListeners ( ) ) {
switchToForeground ( ) ;
}
2018-05-03 12:54:22 +00:00
this . mOnConversationUpdates . add ( listener ) ;
this . mNotificationService . setIsInForeground ( this . mOnConversationUpdates . size ( ) > 0 ) ;
2014-12-03 13:55:09 +00:00
}
}
2014-02-03 17:38:47 +00:00
2018-05-03 12:54:22 +00:00
public void removeOnConversationListChangedListener ( OnConversationUpdate listener ) {
2014-12-03 13:55:09 +00:00
synchronized ( this ) {
2018-05-03 12:54:22 +00:00
this . mOnConversationUpdates . remove ( listener ) ;
this . mNotificationService . setIsInForeground ( this . mOnConversationUpdates . size ( ) > 0 ) ;
if ( checkListeners ( ) ) {
switchToBackground ( ) ;
2014-08-26 15:43:44 +00:00
}
2014-03-29 19:29:03 +00:00
}
2014-02-01 14:07:20 +00:00
}
2014-02-05 21:33:39 +00:00
2015-07-10 11:28:50 +00:00
public void setOnShowErrorToastListener ( OnShowErrorToast onShowErrorToast ) {
synchronized ( this ) {
if ( checkListeners ( ) ) {
switchToForeground ( ) ;
}
2018-05-03 12:54:22 +00:00
this . mOnShowErrorToasts . add ( onShowErrorToast ) ;
2015-07-10 11:28:50 +00:00
}
}
2018-05-03 12:54:22 +00:00
public void removeOnShowErrorToastListener ( OnShowErrorToast onShowErrorToast ) {
2015-07-10 11:28:50 +00:00
synchronized ( this ) {
2018-05-03 12:54:22 +00:00
this . mOnShowErrorToasts . remove ( onShowErrorToast ) ;
if ( checkListeners ( ) ) {
switchToBackground ( ) ;
2015-07-10 11:28:50 +00:00
}
}
}
2014-07-12 11:42:17 +00:00
public void setOnAccountListChangedListener ( OnAccountUpdate listener ) {
2014-12-03 13:55:09 +00:00
synchronized ( this ) {
2014-10-15 12:41:27 +00:00
if ( checkListeners ( ) ) {
switchToForeground ( ) ;
}
2018-05-03 12:54:22 +00:00
this . mOnAccountUpdates . add ( listener ) ;
2014-08-26 15:43:44 +00:00
}
2014-02-04 14:09:50 +00:00
}
2014-02-05 21:33:39 +00:00
2018-05-03 12:54:22 +00:00
public void removeOnAccountListChangedListener ( OnAccountUpdate listener ) {
2014-12-03 13:55:09 +00:00
synchronized ( this ) {
2018-05-03 12:54:22 +00:00
this . mOnAccountUpdates . remove ( listener ) ;
if ( checkListeners ( ) ) {
switchToBackground ( ) ;
2014-08-26 15:43:44 +00:00
}
2014-08-15 15:31:24 +00:00
}
2014-02-04 14:09:50 +00:00
}
2014-08-26 14:52:42 +00:00
2015-10-11 11:11:50 +00:00
public void setOnCaptchaRequestedListener ( OnCaptchaRequested listener ) {
synchronized ( this ) {
if ( checkListeners ( ) ) {
switchToForeground ( ) ;
}
2018-05-03 12:54:22 +00:00
this . mOnCaptchaRequested . add ( listener ) ;
2015-10-11 11:11:50 +00:00
}
}
2018-05-03 12:54:22 +00:00
public void removeOnCaptchaRequestedListener ( OnCaptchaRequested listener ) {
2015-10-11 11:11:50 +00:00
synchronized ( this ) {
2018-05-03 12:54:22 +00:00
this . mOnCaptchaRequested . remove ( listener ) ;
if ( checkListeners ( ) ) {
switchToBackground ( ) ;
2015-10-11 11:11:50 +00:00
}
}
}
2014-12-21 20:43:58 +00:00
public void setOnRosterUpdateListener ( final OnRosterUpdate listener ) {
2014-12-03 13:55:09 +00:00
synchronized ( this ) {
2014-10-15 12:41:27 +00:00
if ( checkListeners ( ) ) {
switchToForeground ( ) ;
}
2018-05-03 12:54:22 +00:00
this . mOnRosterUpdates . add ( listener ) ;
2014-08-26 15:43:44 +00:00
}
2014-07-18 13:35:31 +00:00
}
2018-05-03 12:54:22 +00:00
public void removeOnRosterUpdateListener ( final OnRosterUpdate listener ) {
2014-12-03 13:55:09 +00:00
synchronized ( this ) {
2018-05-03 12:54:22 +00:00
this . mOnRosterUpdates . remove ( listener ) ;
if ( checkListeners ( ) ) {
switchToBackground ( ) ;
2014-09-10 15:59:57 +00:00
}
2014-08-26 15:43:44 +00:00
}
}
2014-08-30 07:24:58 +00:00
2014-12-21 20:43:58 +00:00
public void setOnUpdateBlocklistListener ( final OnUpdateBlocklist listener ) {
synchronized ( this ) {
if ( checkListeners ( ) ) {
switchToForeground ( ) ;
}
2018-05-03 12:54:22 +00:00
this . mOnUpdateBlocklist . add ( listener ) ;
2014-12-21 20:43:58 +00:00
}
}
2018-05-03 12:54:22 +00:00
public void removeOnUpdateBlocklistListener ( final OnUpdateBlocklist listener ) {
2014-12-21 20:43:58 +00:00
synchronized ( this ) {
2018-05-03 12:54:22 +00:00
this . mOnUpdateBlocklist . remove ( listener ) ;
if ( checkListeners ( ) ) {
switchToBackground ( ) ;
2014-12-21 20:43:58 +00:00
}
}
}
2015-07-21 12:18:16 +00:00
public void setOnKeyStatusUpdatedListener ( final OnKeyStatusUpdated listener ) {
2015-07-19 16:36:28 +00:00
synchronized ( this ) {
if ( checkListeners ( ) ) {
switchToForeground ( ) ;
}
2018-05-03 12:54:22 +00:00
this . mOnKeyStatusUpdated . add ( listener ) ;
2015-07-19 16:36:28 +00:00
}
}
2018-05-03 12:54:22 +00:00
public void removeOnNewKeysAvailableListener ( final OnKeyStatusUpdated listener ) {
2015-07-19 16:36:28 +00:00
synchronized ( this ) {
2018-05-03 12:54:22 +00:00
this . mOnKeyStatusUpdated . remove ( listener ) ;
if ( checkListeners ( ) ) {
switchToBackground ( ) ;
2015-07-19 16:36:28 +00:00
}
}
}
2015-07-21 12:18:16 +00:00
2014-11-23 14:19:44 +00:00
public void setOnMucRosterUpdateListener ( OnMucRosterUpdate listener ) {
2014-12-03 13:55:09 +00:00
synchronized ( this ) {
2014-11-23 14:19:44 +00:00
if ( checkListeners ( ) ) {
switchToForeground ( ) ;
}
2018-05-03 12:54:22 +00:00
this . mOnMucRosterUpdate . add ( listener ) ;
2014-11-23 14:19:44 +00:00
}
}
2018-05-03 12:54:22 +00:00
public void removeOnMucRosterUpdateListener ( final OnMucRosterUpdate listener ) {
2014-12-03 13:55:09 +00:00
synchronized ( this ) {
2018-05-03 12:54:22 +00:00
this . mOnMucRosterUpdate . remove ( listener ) ;
if ( checkListeners ( ) ) {
switchToBackground ( ) ;
2014-11-23 14:19:44 +00:00
}
}
}
2016-05-19 08:41:56 +00:00
public boolean checkListeners ( ) {
2018-05-03 12:54:22 +00:00
return ( this . mOnAccountUpdates . size ( ) = = 0
& & this . mOnConversationUpdates . size ( ) = = 0
& & this . mOnRosterUpdates . size ( ) = = 0
& & this . mOnCaptchaRequested . size ( ) = = 0
& & this . mOnUpdateBlocklist . size ( ) = = 0
& & this . mOnShowErrorToasts . size ( ) = = 0
& & this . mOnKeyStatusUpdated . size ( ) = = 0 ) ;
2014-08-26 15:43:44 +00:00
}
2014-08-30 07:24:58 +00:00
2014-08-26 15:43:44 +00:00
private void switchToForeground ( ) {
2016-06-04 14:16:14 +00:00
final boolean broadcastLastActivity = broadcastLastActivity ( ) ;
2015-10-19 21:22:29 +00:00
for ( Conversation conversation : getConversations ( ) ) {
2017-03-07 13:36:05 +00:00
if ( conversation . getMode ( ) = = Conversation . MODE_MULTI ) {
conversation . getMucOptions ( ) . resetChatState ( ) ;
} else {
conversation . setIncomingChatState ( Config . DEFAULT_CHATSTATE ) ;
}
2015-10-19 21:22:29 +00:00
}
2014-08-30 07:24:58 +00:00
for ( Account account : getAccounts ( ) ) {
2014-11-15 16:09:02 +00:00
if ( account . getStatus ( ) = = Account . State . ONLINE ) {
2016-06-01 19:30:50 +00:00
account . deactivateGracePeriod ( ) ;
2016-06-04 14:16:14 +00:00
final XmppConnection connection = account . getXmppConnection ( ) ;
2017-10-28 15:49:51 +00:00
if ( connection ! = null ) {
2016-06-04 14:16:14 +00:00
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 15:43:44 +00:00
}
}
}
2014-10-20 19:08:33 +00:00
Log . d ( Config . LOGTAG , " app switched into foreground " ) ;
2014-08-26 15:43:44 +00:00
}
2014-08-30 07:24:58 +00:00
2014-08-26 15:43:44 +00:00
private void switchToBackground ( ) {
2016-06-04 14:16:14 +00:00
final boolean broadcastLastActivity = broadcastLastActivity ( ) ;
2014-08-30 07:24:58 +00:00
for ( Account account : getAccounts ( ) ) {
2014-11-15 16:09:02 +00:00
if ( account . getStatus ( ) = = Account . State . ONLINE ) {
2014-08-26 15:43:44 +00:00
XmppConnection connection = account . getXmppConnection ( ) ;
2016-02-14 12:20:23 +00:00
if ( connection ! = null ) {
2016-06-04 14:16:14 +00:00
if ( broadcastLastActivity ) {
2017-07-12 09:03:32 +00:00
sendPresence ( account , true ) ;
2016-06-04 14:16:14 +00:00
}
2016-06-04 20:42:12 +00:00
if ( connection . getFeatures ( ) . csi ( ) ) {
connection . sendInactive ( ) ;
}
2014-08-26 15:43:44 +00:00
}
}
}
2014-10-16 17:10:37 +00:00
this . mNotificationService . setIsInForeground ( false ) ;
2014-10-20 19:08:33 +00:00
Log . d ( Config . LOGTAG , " app switched into background " ) ;
2014-07-18 13:35:31 +00:00
}
2014-10-15 12:41:27 +00:00
2014-12-15 22:06:29 +00:00
private void connectMultiModeConversations ( Account account ) {
2014-02-05 21:33:39 +00:00
List < Conversation > conversations = getConversations ( ) ;
2014-11-10 00:24:35 +00:00
for ( Conversation conversation : conversations ) {
2015-10-01 11:03:15 +00:00
if ( conversation . getMode ( ) = = Conversation . MODE_MULTI & & conversation . getAccount ( ) = = account ) {
2016-02-17 15:50:48 +00:00
joinMuc ( conversation ) ;
2015-01-19 10:17:27 +00:00
}
2014-11-10 00:24:35 +00:00
}
2014-02-05 21:33:39 +00:00
}
2014-02-08 23:47:11 +00:00
2014-02-13 22:40:08 +00:00
public void joinMuc ( Conversation conversation ) {
2017-10-28 15:49:51 +00:00
joinMuc ( conversation , null , false ) ;
2017-01-09 18:54:27 +00:00
}
public void joinMuc ( Conversation conversation , boolean followedInvite ) {
joinMuc ( conversation , null , followedInvite ) ;
2015-10-01 14:01:19 +00:00
}
2016-02-17 15:50:48 +00:00
private void joinMuc ( Conversation conversation , final OnConferenceJoined onConferenceJoined ) {
2017-10-28 15:49:51 +00:00
joinMuc ( conversation , onConferenceJoined , false ) ;
2017-01-09 18:54:27 +00:00
}
private void joinMuc ( Conversation conversation , final OnConferenceJoined onConferenceJoined , final boolean followedInvite ) {
2014-05-22 13:36:41 +00:00
Account account = conversation . getAccount ( ) ;
2014-07-18 19:57:10 +00:00
account . pendingConferenceJoins . remove ( conversation ) ;
account . pendingConferenceLeaves . remove ( conversation ) ;
2016-02-17 15:50:48 +00:00
if ( account . getStatus ( ) = = Account . State . ONLINE ) {
2017-08-10 20:33:40 +00:00
sendPresencePacket ( account , mPresenceGenerator . leave ( conversation . getMucOptions ( ) ) ) ;
2015-10-01 11:03:15 +00:00
conversation . resetMucOptions ( ) ;
2016-05-27 08:35:00 +00:00
if ( onConferenceJoined ! = null ) {
conversation . getMucOptions ( ) . flagNoAutoPushConfiguration ( ) ;
}
2016-02-23 15:15:55 +00:00
conversation . setHasMessagesLeftOnServer ( false ) ;
2015-10-04 22:45:16 +00:00
fetchConferenceConfiguration ( conversation , new OnConferenceConfigurationFetched ( ) {
2015-10-22 09:20:36 +00:00
private void join ( Conversation conversation ) {
2015-10-04 22:45:16 +00:00
Account account = conversation . getAccount ( ) ;
2016-02-29 12:18:07 +00:00
final MucOptions mucOptions = conversation . getMucOptions ( ) ;
2016-02-29 15:32:24 +00:00
final Jid joinJid = mucOptions . getSelf ( ) . getFullJid ( ) ;
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) . toString ( ) + " : joining conversation " + joinJid . toString ( ) ) ;
2017-04-25 13:22:31 +00:00
PresencePacket packet = mPresenceGenerator . selfPresence ( account , Presence . Status . ONLINE , mucOptions . nonanonymous ( ) | | onConferenceJoined ! = null ) ;
2015-10-04 22:45:16 +00:00
packet . setTo ( joinJid ) ;
Element x = packet . addChild ( " x " , " http://jabber.org/protocol/muc " ) ;
if ( conversation . getMucOptions ( ) . getPassword ( ) ! = null ) {
2016-10-19 10:31:11 +00:00
x . addChild ( " password " ) . setContent ( mucOptions . getPassword ( ) ) ;
2015-10-04 22:45:16 +00:00
}
2016-02-29 12:18:07 +00:00
if ( mucOptions . mamSupport ( ) ) {
2015-10-04 22:45:16 +00:00
// Use MAM instead of the limited muc history to get history
x . addChild ( " history " ) . setAttribute ( " maxchars " , " 0 " ) ;
} else {
// Fallback to muc history
2017-05-07 19:05:35 +00:00
x . addChild ( " history " ) . setAttribute ( " since " , PresenceGenerator . getTimestamp ( conversation . getLastMessageTransmitted ( ) . getTimestamp ( ) ) ) ;
2015-10-04 22:45:16 +00:00
}
sendPresencePacket ( account , packet ) ;
2015-11-25 19:47:02 +00:00
if ( onConferenceJoined ! = null ) {
onConferenceJoined . onConferenceJoined ( conversation ) ;
}
2015-10-04 22:45:16 +00:00
if ( ! joinJid . equals ( conversation . getJid ( ) ) ) {
conversation . setContactJid ( joinJid ) ;
databaseBackend . updateConversation ( conversation ) ;
}
2016-02-29 12:18:07 +00:00
if ( mucOptions . mamSupport ( ) ) {
2015-10-06 14:58:56 +00:00
getMessageArchiveService ( ) . catchupMUC ( conversation ) ;
}
2018-01-22 22:21:24 +00:00
if ( mucOptions . isPrivateAndNonAnonymous ( ) ) {
2016-02-29 12:18:07 +00:00
fetchConferenceMembers ( conversation ) ;
2017-01-09 18:54:27 +00:00
if ( followedInvite & & conversation . getBookmark ( ) = = null ) {
2017-10-28 15:49:51 +00:00
saveConversationAsBookmark ( conversation , null ) ;
2017-01-09 18:54:27 +00:00
}
2016-02-29 12:18:07 +00:00
}
2016-02-10 08:53:48 +00:00
sendUnsentMessages ( conversation ) ;
2015-10-04 22:45:16 +00:00
}
2015-10-22 09:20:36 +00:00
@Override
public void onConferenceConfigurationFetched ( Conversation conversation ) {
join ( conversation ) ;
}
@Override
public void onFetchFailed ( final Conversation conversation , Element error ) {
2016-09-06 10:15:08 +00:00
if ( error ! = null & & " remote-server-not-found " . equals ( error . getName ( ) ) ) {
2016-09-09 09:04:05 +00:00
conversation . getMucOptions ( ) . setError ( MucOptions . Error . SERVER_NOT_FOUND ) ;
2017-04-15 15:18:15 +00:00
updateConversationUi ( ) ;
2016-09-06 10:15:08 +00:00
} else {
join ( conversation ) ;
fetchConferenceConfiguration ( conversation ) ;
}
2015-10-22 09:20:36 +00:00
}
2015-10-04 22:45:16 +00:00
} ) ;
2016-02-22 19:19:58 +00:00
updateConversationUi ( ) ;
2014-07-18 19:57:10 +00:00
} else {
account . pendingConferenceJoins . add ( conversation ) ;
2016-02-22 19:19:58 +00:00
conversation . resetMucOptions ( ) ;
2016-02-23 15:15:55 +00:00
conversation . setHasMessagesLeftOnServer ( false ) ;
2016-02-22 19:19:58 +00:00
updateConversationUi ( ) ;
2014-02-11 14:34:24 +00:00
}
2014-02-07 15:50:29 +00:00
}
2014-03-11 14:44:22 +00:00
2016-02-29 12:18:07 +00:00
private void fetchConferenceMembers ( final Conversation conversation ) {
final Account account = conversation . getAccount ( ) ;
2017-06-28 07:49:24 +00:00
final AxolotlService axolotlService = account . getAxolotlService ( ) ;
2017-10-28 15:49:51 +00:00
final String [ ] affiliations = { " member " , " admin " , " owner " } ;
2016-02-29 12:18:07 +00:00
OnIqPacketReceived callback = new OnIqPacketReceived ( ) {
private int i = 0 ;
2017-01-22 17:58:49 +00:00
private boolean success = true ;
2016-02-29 12:18:07 +00:00
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
2018-05-20 10:10:07 +00:00
final boolean omemoEnabled = conversation . getNextEncryption ( ) = = Message . ENCRYPTION_AXOLOTL ;
2016-02-29 12:18:07 +00:00
Element query = packet . query ( " http://jabber.org/protocol/muc#admin " ) ;
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT & & query ! = null ) {
2017-10-28 15:49:51 +00:00
for ( Element child : query . getChildren ( ) ) {
2016-02-29 12:18:07 +00:00
if ( " item " . equals ( child . getName ( ) ) ) {
2017-10-28 15:49:51 +00:00
MucOptions . User user = AbstractParser . parseItem ( conversation , child ) ;
2016-05-17 12:25:58 +00:00
if ( ! user . realJidMatchesAccount ( ) ) {
2017-06-28 07:49:24 +00:00
boolean isNew = conversation . getMucOptions ( ) . updateUser ( user ) ;
2018-02-24 08:47:07 +00:00
Contact contact = user . getContact ( ) ;
2018-05-20 10:10:07 +00:00
if ( omemoEnabled
& & isNew
2018-02-24 08:47:07 +00:00
& & user . getRealJid ( ) ! = null
& & ( contact = = null | | ! contact . mutualPresenceSubscription ( ) )
& & axolotlService . hasEmptyDeviceList ( user . getRealJid ( ) ) ) {
2017-06-28 07:49:24 +00:00
axolotlService . fetchDeviceIds ( user . getRealJid ( ) ) ;
}
2016-05-16 12:10:40 +00:00
}
2016-02-29 12:18:07 +00:00
}
}
} else {
2017-01-22 17:58:49 +00:00
success = false ;
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : could not request affiliation " + affiliations [ i ] + " in " + conversation . getJid ( ) . asBareJid ( ) ) ;
2016-02-29 12:18:07 +00:00
}
+ + i ;
if ( i > = affiliations . length ) {
2017-01-22 17:58:49 +00:00
List < Jid > members = conversation . getMucOptions ( ) . getMembers ( ) ;
if ( success ) {
List < Jid > cryptoTargets = conversation . getAcceptedCryptoTargets ( ) ;
boolean changed = false ;
2017-10-28 15:49:51 +00:00
for ( ListIterator < Jid > iterator = cryptoTargets . listIterator ( ) ; iterator . hasNext ( ) ; ) {
2017-01-22 17:58:49 +00:00
Jid jid = iterator . next ( ) ;
if ( ! members . contains ( jid ) ) {
iterator . remove ( ) ;
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : removed " + jid + " from crypto targets of " + conversation . getName ( ) ) ;
2017-01-22 17:58:49 +00:00
changed = true ;
}
}
if ( changed ) {
conversation . setAcceptedCryptoTargets ( cryptoTargets ) ;
updateConversation ( conversation ) ;
}
}
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : retrieved members for " + conversation . getJid ( ) . asBareJid ( ) + " : " + conversation . getMucOptions ( ) . getMembers ( ) ) ;
2016-11-12 19:21:11 +00:00
getAvatarService ( ) . clear ( conversation ) ;
updateMucRosterUi ( ) ;
updateConversationUi ( ) ;
2016-02-29 12:18:07 +00:00
}
}
} ;
2017-10-28 15:49:51 +00:00
for ( String affiliation : affiliations ) {
2016-02-29 12:18:07 +00:00
sendIqPacket ( account , mIqGenerator . queryAffiliation ( conversation , affiliation ) , callback ) ;
}
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : fetching members for " + conversation . getName ( ) ) ;
2016-02-29 12:18:07 +00:00
}
2014-09-03 17:35:45 +00:00
public void providePasswordForMuc ( Conversation conversation , String password ) {
if ( conversation . getMode ( ) = = Conversation . MODE_MULTI ) {
conversation . getMucOptions ( ) . setPassword ( password ) ;
2014-10-05 22:33:52 +00:00
if ( conversation . getBookmark ( ) ! = null ) {
2016-02-01 12:54:08 +00:00
if ( respectAutojoin ( ) ) {
conversation . getBookmark ( ) . setAutojoin ( true ) ;
}
2014-09-07 12:06:23 +00:00
pushBookmarks ( conversation . getAccount ( ) ) ;
}
2016-10-18 11:06:24 +00:00
updateConversation ( conversation ) ;
2014-09-03 17:35:45 +00:00
joinMuc ( conversation ) ;
}
}
2014-03-11 14:44:22 +00:00
2017-07-12 09:03:32 +00:00
private boolean hasEnabledAccounts ( ) {
2017-10-28 15:49:51 +00:00
for ( Account account : this . accounts ) {
2017-11-06 12:57:25 +00:00
if ( account . isEnabled ( ) ) {
2017-07-12 09:03:32 +00:00
return true ;
}
}
return false ;
}
2018-02-10 15:24:55 +00:00
public void persistSelfNick ( MucOptions . User self ) {
final Conversation conversation = self . getConversation ( ) ;
Jid full = self . getFullJid ( ) ;
if ( ! full . equals ( conversation . getJid ( ) ) ) {
2018-03-18 09:30:15 +00:00
Log . d ( Config . LOGTAG , " nick changed. updating " ) ;
2018-02-10 15:24:55 +00:00
conversation . setContactJid ( full ) ;
databaseBackend . updateConversation ( conversation ) ;
}
Bookmark bookmark = conversation . getBookmark ( ) ;
2018-03-05 17:30:40 +00:00
if ( bookmark ! = null & & ! full . getResource ( ) . equals ( bookmark . getNick ( ) ) ) {
bookmark . setNick ( full . getResource ( ) ) ;
2018-02-10 15:24:55 +00:00
pushBookmarks ( bookmark . getAccount ( ) ) ;
}
}
2017-12-09 17:46:21 +00:00
public boolean renameInMuc ( final Conversation conversation , final String nick , final UiCallback < Conversation > callback ) {
2014-03-03 04:01:02 +00:00
final MucOptions options = conversation . getMucOptions ( ) ;
2014-11-20 17:20:42 +00:00
final Jid joinJid = options . createJoinJid ( nick ) ;
2017-12-09 17:46:21 +00:00
if ( joinJid = = null ) {
return false ;
}
2014-03-03 04:01:02 +00:00
if ( options . online ( ) ) {
2014-06-03 09:04:17 +00:00
Account account = conversation . getAccount ( ) ;
2014-03-03 04:01:02 +00:00
options . setOnRenameListener ( new OnRenameListener ( ) {
2014-03-11 14:44:22 +00:00
2014-03-03 04:01:02 +00:00
@Override
2014-11-20 17:20:42 +00:00
public void onSuccess ( ) {
callback . success ( conversation ) ;
}
@Override
public void onFailure ( ) {
2014-12-13 11:25:52 +00:00
callback . error ( R . string . nick_in_use , conversation ) ;
2014-03-03 04:01:02 +00:00
}
} ) ;
2014-11-20 17:20:42 +00:00
2014-03-03 04:01:02 +00:00
PresencePacket packet = new PresencePacket ( ) ;
2014-11-20 17:20:42 +00:00
packet . setTo ( joinJid ) ;
2014-11-09 15:57:22 +00:00
packet . setFrom ( conversation . getAccount ( ) . getJid ( ) ) ;
2014-06-03 13:48:51 +00:00
2014-06-03 09:04:17 +00:00
String sig = account . getPgpSignature ( ) ;
if ( sig ! = null ) {
packet . addChild ( " status " ) . setContent ( " online " ) ;
packet . addChild ( " x " , " jabber:x:signed " ) . setContent ( sig ) ;
}
2014-08-26 14:52:42 +00:00
sendPresencePacket ( account , packet ) ;
2014-03-03 04:01:02 +00:00
} else {
2014-11-20 17:20:42 +00:00
conversation . setContactJid ( joinJid ) ;
2014-03-03 04:01:02 +00:00
databaseBackend . updateConversation ( conversation ) ;
2014-11-15 16:09:02 +00:00
if ( conversation . getAccount ( ) . getStatus ( ) = = Account . State . ONLINE ) {
2014-07-15 15:11:43 +00:00
Bookmark bookmark = conversation . getBookmark ( ) ;
2014-08-26 14:52:42 +00:00
if ( bookmark ! = null ) {
2014-07-15 15:11:43 +00:00
bookmark . setNick ( nick ) ;
pushBookmarks ( bookmark . getAccount ( ) ) ;
}
2014-03-03 04:01:02 +00:00
joinMuc ( conversation ) ;
}
}
2017-12-09 17:46:21 +00:00
return true ;
2014-03-03 04:01:02 +00:00
}
2014-02-05 21:33:39 +00:00
2014-02-13 22:40:08 +00:00
public void leaveMuc ( Conversation conversation ) {
2015-10-16 07:58:31 +00:00
leaveMuc ( conversation , false ) ;
}
private void leaveMuc ( Conversation conversation , boolean now ) {
2014-07-18 19:57:10 +00:00
Account account = conversation . getAccount ( ) ;
account . pendingConferenceJoins . remove ( conversation ) ;
account . pendingConferenceLeaves . remove ( conversation ) ;
2015-10-16 07:58:31 +00:00
if ( account . getStatus ( ) = = Account . State . ONLINE | | now ) {
2017-08-10 20:33:40 +00:00
sendPresencePacket ( conversation . getAccount ( ) , mPresenceGenerator . leave ( conversation . getMucOptions ( ) ) ) ;
2014-07-18 19:57:10 +00:00
conversation . getMucOptions ( ) . setOffline ( ) ;
2018-02-10 18:06:31 +00:00
Bookmark bookmark = conversation . getBookmark ( ) ;
if ( bookmark ! = null ) {
bookmark . setConversation ( null ) ;
}
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , conversation . getAccount ( ) . getJid ( ) . asBareJid ( ) + " : leaving muc " + conversation . getJid ( ) ) ;
2014-07-18 19:57:10 +00:00
} else {
account . pendingConferenceLeaves . add ( conversation ) ;
}
2014-02-13 22:40:08 +00:00
}
2014-02-05 21:33:39 +00:00
2017-02-13 16:32:26 +00:00
public String findConferenceServer ( final Account account ) {
2014-11-20 17:20:42 +00:00
String server ;
if ( account . getXmppConnection ( ) ! = null ) {
server = account . getXmppConnection ( ) . getMucServer ( ) ;
if ( server ! = null ) {
return server ;
}
}
2015-01-19 10:17:27 +00:00
for ( Account other : getAccounts ( ) ) {
2014-11-20 17:20:42 +00:00
if ( other ! = account & & other . getXmppConnection ( ) ! = null ) {
server = other . getXmppConnection ( ) . getMucServer ( ) ;
if ( server ! = null ) {
return server ;
}
}
}
return null ;
}
2017-02-13 16:32:26 +00:00
public boolean createAdhocConference ( final Account account ,
2017-10-28 15:49:51 +00:00
final String subject ,
final Iterable < Jid > jids ,
final UiCallback < Conversation > callback ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) . toString ( ) + " : creating adhoc conference with " + jids . toString ( ) ) ;
2014-11-20 17:20:42 +00:00
if ( account . getStatus ( ) = = Account . State . ONLINE ) {
try {
String server = findConferenceServer ( account ) ;
if ( server = = null ) {
if ( callback ! = null ) {
2015-01-19 10:17:27 +00:00
callback . error ( R . string . no_conference_server_found , null ) ;
2014-11-20 17:20:42 +00:00
}
2017-02-13 16:32:26 +00:00
return false ;
2014-11-20 17:20:42 +00:00
}
2018-03-05 17:30:40 +00:00
final Jid jid = Jid . of ( new BigInteger ( 64 , getRNG ( ) ) . toString ( Character . MAX_RADIX ) , server , null ) ;
2017-04-12 22:12:23 +00:00
final Conversation conversation = findOrCreateConversation ( account , jid , true , false , true ) ;
2016-02-17 15:50:48 +00:00
joinMuc ( conversation , new OnConferenceJoined ( ) {
2014-11-20 17:20:42 +00:00
@Override
2015-11-25 19:47:02 +00:00
public void onConferenceJoined ( final Conversation conversation ) {
2017-02-24 18:58:46 +00:00
pushConferenceConfiguration ( conversation , IqGenerator . defaultRoomConfiguration ( ) , new OnConfigurationPushed ( ) {
2015-11-25 19:47:02 +00:00
@Override
public void onPushSucceeded ( ) {
2016-05-26 10:39:31 +00:00
if ( subject ! = null & & ! subject . trim ( ) . isEmpty ( ) ) {
2016-05-26 20:53:55 +00:00
pushSubjectToConference ( conversation , subject . trim ( ) ) ;
2016-05-26 10:39:31 +00:00
}
2015-11-25 19:47:02 +00:00
for ( Jid invite : jids ) {
invite ( conversation , invite ) ;
}
if ( account . countPresences ( ) > 1 ) {
2018-03-05 17:30:40 +00:00
directInvite ( conversation , account . getJid ( ) . asBareJid ( ) ) ;
2015-11-25 19:47:02 +00:00
}
2016-05-26 20:53:55 +00:00
saveConversationAsBookmark ( conversation , subject ) ;
2015-11-25 19:47:02 +00:00
if ( callback ! = null ) {
callback . success ( conversation ) ;
}
}
2014-11-20 17:20:42 +00:00
2015-11-25 19:47:02 +00:00
@Override
public void onPushFailed ( ) {
2016-05-26 20:53:55 +00:00
archiveConversation ( conversation ) ;
2015-11-25 19:47:02 +00:00
if ( callback ! = null ) {
callback . error ( R . string . conference_creation_failed , conversation ) ;
}
}
} ) ;
2014-11-20 17:20:42 +00:00
}
} ) ;
2017-02-13 16:32:26 +00:00
return true ;
2018-03-05 17:30:40 +00:00
} catch ( IllegalArgumentException e ) {
2014-11-20 17:20:42 +00:00
if ( callback ! = null ) {
callback . error ( R . string . conference_creation_failed , null ) ;
}
2017-02-13 16:32:26 +00:00
return false ;
2014-11-20 17:20:42 +00:00
}
} else {
if ( callback ! = null ) {
2015-01-19 10:17:27 +00:00
callback . error ( R . string . not_connected_try_again , null ) ;
2014-11-20 17:20:42 +00:00
}
2017-02-13 16:32:26 +00:00
return false ;
2014-11-20 17:20:42 +00:00
}
}
2015-01-07 17:34:24 +00:00
public void fetchConferenceConfiguration ( final Conversation conversation ) {
2015-10-04 22:45:16 +00:00
fetchConferenceConfiguration ( conversation , null ) ;
}
public void fetchConferenceConfiguration ( final Conversation conversation , final OnConferenceConfigurationFetched callback ) {
2015-01-07 17:34:24 +00:00
IqPacket request = new IqPacket ( IqPacket . TYPE . GET ) ;
2018-03-05 17:30:40 +00:00
request . setTo ( conversation . getJid ( ) . asBareJid ( ) ) ;
2015-01-07 17:34:24 +00:00
request . query ( " http://jabber.org/protocol/disco#info " ) ;
sendIqPacket ( conversation . getAccount ( ) , request , new OnIqPacketReceived ( ) {
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
2017-10-28 15:49:51 +00:00
Element query = packet . findChild ( " query " , " http://jabber.org/protocol/disco#info " ) ;
2016-02-29 15:32:24 +00:00
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT & & query ! = null ) {
2015-01-08 13:45:44 +00:00
ArrayList < String > features = new ArrayList < > ( ) ;
2015-11-26 16:44:29 +00:00
for ( Element child : query . getChildren ( ) ) {
2015-01-07 17:34:24 +00:00
if ( child ! = null & & child . getName ( ) . equals ( " feature " ) ) {
String var = child . getAttribute ( " var " ) ;
if ( var ! = null ) {
features . add ( var ) ;
}
}
}
2018-02-16 14:57:02 +00:00
Element form = query . findChild ( " x " , Namespace . DATA ) ;
2018-03-30 06:47:37 +00:00
Data data = form = = null ? null : Data . parse ( form ) ;
if ( conversation . getMucOptions ( ) . updateConfiguration ( features , data ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : muc configuration changed for " + conversation . getJid ( ) . asBareJid ( ) ) ;
updateConversation ( conversation ) ;
2015-11-26 16:44:29 +00:00
}
2015-10-04 22:45:16 +00:00
if ( callback ! = null ) {
callback . onConferenceConfigurationFetched ( conversation ) ;
}
2015-01-08 20:29:26 +00:00
updateConversationUi ( ) ;
2015-10-22 09:20:36 +00:00
} else if ( packet . getType ( ) = = IqPacket . TYPE . ERROR ) {
if ( callback ! = null ) {
callback . onFetchFailed ( conversation , packet . getError ( ) ) ;
}
2015-01-07 17:34:24 +00:00
}
}
} ) ;
}
2017-06-27 20:50:39 +00:00
public void pushNodeConfiguration ( Account account , final String node , final Bundle options , final OnConfigurationPushed callback ) {
2018-03-05 17:30:40 +00:00
pushNodeConfiguration ( account , account . getJid ( ) . asBareJid ( ) , node , options , callback ) ;
2017-06-27 20:50:39 +00:00
}
2017-02-24 18:58:46 +00:00
public void pushNodeConfiguration ( Account account , final Jid jid , final String node , final Bundle options , final OnConfigurationPushed callback ) {
2017-10-28 15:49:51 +00:00
sendIqPacket ( account , mIqGenerator . requestPubsubConfiguration ( jid , node ) , new OnIqPacketReceived ( ) {
2017-02-24 18:58:46 +00:00
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2017-10-28 15:49:51 +00:00
Element pubsub = packet . findChild ( " pubsub " , " http://jabber.org/protocol/pubsub#owner " ) ;
2017-02-24 18:58:46 +00:00
Element configuration = pubsub = = null ? null : pubsub . findChild ( " configure " ) ;
2018-02-16 14:57:02 +00:00
Element x = configuration = = null ? null : configuration . findChild ( " x " , Namespace . DATA ) ;
2017-02-24 18:58:46 +00:00
if ( x ! = null ) {
Data data = Data . parse ( x ) ;
data . submit ( options ) ;
sendIqPacket ( account , mIqGenerator . publishPubsubConfiguration ( jid , node , data ) , new OnIqPacketReceived ( ) {
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
2017-06-28 08:21:06 +00:00
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT & & callback ! = null ) {
2018-05-03 20:44:28 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : successfully changed node configuration for node " + node ) ;
2017-02-24 18:58:46 +00:00
callback . onPushSucceeded ( ) ;
2018-05-01 15:35:29 +00:00
} else if ( packet . getType ( ) = = IqPacket . TYPE . ERROR & & callback ! = null ) {
callback . onPushFailed ( ) ;
2017-02-24 18:58:46 +00:00
}
}
} ) ;
2017-10-28 15:49:51 +00:00
} else if ( callback ! = null ) {
2017-02-24 18:58:46 +00:00
callback . onPushFailed ( ) ;
}
2018-05-01 15:35:29 +00:00
} else if ( packet . getType ( ) = = IqPacket . TYPE . ERROR & & callback ! = null ) {
2017-02-24 18:58:46 +00:00
callback . onPushFailed ( ) ;
}
}
} ) ;
}
public void pushConferenceConfiguration ( final Conversation conversation , final Bundle options , final OnConfigurationPushed callback ) {
2014-12-30 13:16:25 +00:00
IqPacket request = new IqPacket ( IqPacket . TYPE . GET ) ;
2018-03-05 17:30:40 +00:00
request . setTo ( conversation . getJid ( ) . asBareJid ( ) ) ;
2014-11-20 17:20:42 +00:00
request . query ( " http://jabber.org/protocol/muc#owner " ) ;
2015-01-19 10:17:27 +00:00
sendIqPacket ( conversation . getAccount ( ) , request , new OnIqPacketReceived ( ) {
2014-11-20 17:20:42 +00:00
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
2015-08-23 15:53:23 +00:00
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2018-02-16 14:57:02 +00:00
Data data = Data . parse ( packet . query ( ) . findChild ( " x " , Namespace . DATA ) ) ;
2017-02-24 18:58:46 +00:00
data . submit ( options ) ;
2014-12-30 13:16:25 +00:00
IqPacket set = new IqPacket ( IqPacket . TYPE . SET ) ;
2018-03-05 17:30:40 +00:00
set . setTo ( conversation . getJid ( ) . asBareJid ( ) ) ;
2014-11-20 17:20:42 +00: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 15:53:23 +00:00
if ( callback ! = null ) {
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2014-11-20 17:20:42 +00:00
callback . onPushSucceeded ( ) ;
2015-08-23 15:53:23 +00:00
} else {
2014-11-20 17:20:42 +00:00
callback . onPushFailed ( ) ;
}
}
}
} ) ;
} else {
if ( callback ! = null ) {
callback . onPushFailed ( ) ;
}
}
}
} ) ;
}
2015-01-10 22:10:32 +00: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 ( ) ;
2018-01-13 15:37:49 +00:00
if ( self . getAffiliation ( ) . ranks ( MucOptions . Affiliation . OWNER ) ) {
2015-01-10 22:10:32 +00:00
Bundle options = new Bundle ( ) ;
options . putString ( " muc#roomconfig_persistentroom " , " 1 " ) ;
2018-01-13 15:37:49 +00:00
options . putString ( " muc#roomconfig_roomname " , subject ) ;
2015-01-19 10:17:27 +00:00
this . pushConferenceConfiguration ( conference , options , null ) ;
2015-01-10 22:10:32 +00:00
}
}
2016-05-16 12:10:40 +00:00
public void changeAffiliationInConference ( final Conversation conference , Jid user , final MucOptions . Affiliation affiliation , final OnAffiliationChanged callback ) {
2018-03-05 17:30:40 +00:00
final Jid jid = user . asBareJid ( ) ;
2015-01-07 14:03:29 +00:00
IqPacket request = this . mIqGenerator . changeAffiliation ( conference , jid , affiliation . toString ( ) ) ;
2015-01-07 17:34:24 +00:00
sendIqPacket ( conference . getAccount ( ) , request , new OnIqPacketReceived ( ) {
2015-01-07 14:03:29 +00:00
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2016-05-16 12:10:40 +00:00
conference . getMucOptions ( ) . changeAffiliation ( jid , affiliation ) ;
2016-05-16 13:50:57 +00:00
getAvatarService ( ) . clear ( conference ) ;
2015-01-07 14:03:29 +00:00
callback . onAffiliationChangedSuccessful ( jid ) ;
} else {
2015-01-07 17:34:24 +00:00
callback . onAffiliationChangeFailed ( jid , R . string . could_not_change_affiliation ) ;
2015-01-07 14:03:29 +00:00
}
}
} ) ;
}
2015-01-09 12:28:01 +00:00
public void changeAffiliationsInConference ( final Conversation conference , MucOptions . Affiliation before , MucOptions . Affiliation after ) {
List < Jid > jids = new ArrayList < > ( ) ;
2015-01-19 10:17:27 +00:00
for ( MucOptions . User user : conference . getMucOptions ( ) . getUsers ( ) ) {
2016-05-16 12:10:40 +00:00
if ( user . getAffiliation ( ) = = before & & user . getRealJid ( ) ! = null ) {
jids . add ( user . getRealJid ( ) ) ;
2015-01-09 12:28:01 +00:00
}
}
IqPacket request = this . mIqGenerator . changeAffiliation ( conference , jids , after . toString ( ) ) ;
2015-05-26 09:31:33 +00:00
sendIqPacket ( conference . getAccount ( ) , request , mDefaultIqHandler ) ;
2015-01-09 12:28:01 +00:00
}
2015-01-08 00:23:53 +00: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 10:17:27 +00:00
Log . d ( Config . LOGTAG , request . toString ( ) ) ;
2015-01-08 00:23:53 +00: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 07:58:31 +00:00
private void disconnect ( Account account , boolean force ) {
2014-11-15 16:09:02 +00:00
if ( ( account . getStatus ( ) = = Account . State . ONLINE )
| | ( account . getStatus ( ) = = Account . State . DISABLED ) ) {
2016-06-04 14:16:14 +00:00
final XmppConnection connection = account . getXmppConnection ( ) ;
2014-03-16 13:12:30 +00:00
if ( ! force ) {
List < Conversation > conversations = getConversations ( ) ;
2014-11-10 00:24:35 +00:00
for ( Conversation conversation : conversations ) {
if ( conversation . getAccount ( ) = = account ) {
if ( conversation . getMode ( ) = = Conversation . MODE_MULTI ) {
2015-10-16 07:58:31 +00:00
leaveMuc ( conversation , true ) ;
2014-11-10 00:24:35 +00:00
}
}
}
2015-04-09 10:46:54 +00:00
sendOfflinePresence ( account ) ;
2014-02-13 22:40:08 +00:00
}
2016-06-04 14:16:14 +00:00
connection . disconnect ( force ) ;
2015-01-19 10:17:27 +00:00
}
2014-02-05 21:33:39 +00:00
}
2014-02-08 23:47:11 +00:00
@Override
public IBinder onBind ( Intent intent ) {
return mBinder ;
}
2014-02-16 15:32:15 +00:00
2014-02-27 23:22:56 +00:00
public void updateMessage ( Message message ) {
2018-05-10 08:47:28 +00:00
updateMessage ( message , true ) ;
}
public void updateMessage ( Message message , boolean includeBody ) {
databaseBackend . updateMessage ( message , includeBody ) ;
2014-10-14 16:16:03 +00:00
updateConversationUi ( ) ;
2014-02-27 23:22:56 +00:00
}
2014-06-03 13:48:51 +00:00
2016-02-19 23:01:39 +00:00
public void updateMessage ( Message message , String uuid ) {
databaseBackend . updateMessage ( message , uuid ) ;
updateConversationUi ( ) ;
}
2014-05-22 12:33:17 +00:00
protected void syncDirtyContacts ( Account account ) {
2014-06-03 13:48:51 +00:00
for ( Contact contact : account . getRoster ( ) . getContacts ( ) ) {
2014-05-22 12:33:17 +00:00
if ( contact . getOption ( Contact . Options . DIRTY_PUSH ) ) {
pushContactToServer ( contact ) ;
}
if ( contact . getOption ( Contact . Options . DIRTY_DELETE ) ) {
deleteContactOnServer ( contact ) ;
}
}
}
2014-02-27 23:22:56 +00:00
2018-02-27 20:11:00 +00:00
public void createContact ( Contact contact , boolean autoGrant ) {
2014-02-23 20:33:37 +00:00
if ( autoGrant ) {
2014-05-19 13:15:09 +00:00
contact . setOption ( Contact . Options . PREEMPTIVE_GRANT ) ;
contact . setOption ( Contact . Options . ASKING ) ;
2014-02-23 20:33:37 +00:00
}
2014-05-19 13:15:09 +00:00
pushContactToServer ( contact ) ;
2014-06-11 19:53:25 +00:00
}
2014-12-21 01:13:13 +00:00
public void pushContactToServer ( final Contact contact ) {
2014-05-22 12:33:17 +00:00
contact . resetOption ( Contact . Options . DIRTY_DELETE ) ;
2014-07-10 21:49:34 +00:00
contact . setOption ( Contact . Options . DIRTY_PUSH ) ;
2014-12-21 01:13:13 +00:00
final Account account = contact . getAccount ( ) ;
2014-11-15 16:09:02 +00:00
if ( account . getStatus ( ) = = Account . State . ONLINE ) {
2014-12-21 01:13:13 +00:00
final boolean ask = contact . getOption ( Contact . Options . ASKING ) ;
final boolean sendUpdates = contact
2015-01-19 10:17:27 +00:00
. getOption ( Contact . Options . PENDING_SUBSCRIPTION_REQUEST )
& & contact . getOption ( Contact . Options . PREEMPTIVE_GRANT ) ;
2014-12-30 13:16:25 +00:00
final IqPacket iq = new IqPacket ( IqPacket . TYPE . SET ) ;
2017-03-01 12:01:46 +00:00
iq . query ( Namespace . ROSTER ) . addChild ( contact . asElement ( ) ) ;
2015-05-26 09:31:33 +00:00
account . getXmppConnection ( ) . sendIqPacket ( iq , mDefaultIqHandler ) ;
2014-07-12 10:28:28 +00:00
if ( sendUpdates ) {
2018-03-18 11:24:28 +00:00
sendPresencePacket ( account , mPresenceGenerator . sendPresenceUpdatesTo ( contact ) ) ;
2014-05-22 07:36:00 +00:00
}
2014-07-12 10:28:28 +00:00
if ( ask ) {
2018-03-18 11:24:28 +00:00
sendPresencePacket ( account , mPresenceGenerator . requestPresenceUpdatesFrom ( contact ) ) ;
2014-07-12 10:28:28 +00:00
}
2018-03-18 11:24:28 +00:00
} else {
syncRoster ( contact . getAccount ( ) ) ;
2014-05-21 20:22:36 +00:00
}
2014-05-19 13:15:09 +00:00
}
2014-05-22 07:36:00 +00:00
2017-12-16 13:22:57 +00:00
public void publishAvatar ( final Account account , final Uri image , final UiCallback < Avatar > callback ) {
new Thread ( ( ) - > {
final Bitmap . CompressFormat format = Config . AVATAR_FORMAT ;
final int size = Config . AVATAR_SIZE ;
final Avatar avatar = getFileBackend ( ) . getPepAvatar ( image , size , format ) ;
if ( avatar ! = null ) {
if ( ! getFileBackend ( ) . save ( avatar ) ) {
callback . error ( R . string . error_saving_avatar , avatar ) ;
return ;
}
publishAvatar ( account , avatar , callback ) ;
} else {
callback . error ( R . string . error_publish_avatar_converting , null ) ;
}
} ) . start ( ) ;
2016-04-11 20:20:32 +00:00
}
2014-08-26 14:52:42 +00:00
2016-04-11 20:20:32 +00:00
public void publishAvatar ( Account account , final Avatar avatar , final UiCallback < Avatar > callback ) {
2017-01-12 11:20:10 +00:00
IqPacket packet = this . mIqGenerator . publishAvatar ( avatar ) ;
2016-04-11 20:20:32 +00:00
this . sendIqPacket ( account , packet , new OnIqPacketReceived ( ) {
@Override
public void onIqPacketReceived ( Account account , IqPacket result ) {
if ( result . getType ( ) = = IqPacket . TYPE . RESULT ) {
2017-01-12 11:20:10 +00:00
final IqPacket packet = XmppConnectionService . this . mIqGenerator . publishAvatarMetadata ( avatar ) ;
2016-04-11 20:20:32 +00:00
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 ) ;
}
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : published avatar " + ( avatar . size / 1024 ) + " KiB " ) ;
2016-04-11 20:20:32 +00:00
if ( callback ! = null ) {
2014-08-04 23:36:17 +00:00
callback . success ( avatar ) ;
2016-04-11 20:20:32 +00:00
}
} else {
if ( callback ! = null ) {
2017-10-28 15:49:51 +00:00
callback . error ( R . string . error_publish_avatar_server_reject , avatar ) ;
2014-08-04 23:36:17 +00:00
}
}
2016-04-11 20:20:32 +00:00
}
} ) ;
} else {
2017-01-12 11:20:10 +00:00
Element error = result . findChild ( " error " ) ;
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : server rejected avatar " + ( avatar . size / 1024 ) + " KiB " + ( error ! = null ? error . toString ( ) : " " ) ) ;
2016-04-11 20:20:32 +00:00
if ( callback ! = null ) {
2017-01-12 11:20:10 +00:00
callback . error ( R . string . error_publish_avatar_server_reject , avatar ) ;
2014-08-04 23:36:17 +00:00
}
}
2016-04-11 20:20:32 +00:00
}
} ) ;
}
public void republishAvatarIfNeeded ( Account account ) {
if ( account . getAxolotlService ( ) . isPepBroken ( ) ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : skipping republication of avatar because pep is broken " ) ;
2016-04-11 20:20:32 +00:00
return ;
2014-08-03 18:28:13 +00:00
}
2016-04-11 20:20:32 +00: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 ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : avatar on server was null. republishing " ) ;
2016-04-11 20:20:32 +00:00
publishAvatar ( account , fileBackend . getStoredPepAvatar ( account . getAvatar ( ) ) , null ) ;
} else {
2018-03-05 17:30:40 +00:00
Log . e ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : error rereading avatar " ) ;
2016-04-11 20:20:32 +00:00
}
}
}
}
} ) ;
2014-08-03 18:28:13 +00:00
}
2014-08-26 14:52:42 +00:00
2014-08-15 15:31:24 +00:00
public void fetchAvatar ( Account account , Avatar avatar ) {
fetchAvatar ( account , avatar , null ) ;
}
2014-08-26 14:52:42 +00:00
2015-05-05 04:17:34 +00:00
public void fetchAvatar ( Account account , final Avatar avatar , final UiCallback < Avatar > callback ) {
2015-05-05 08:29:41 +00:00
final String KEY = generateFetchKey ( account , avatar ) ;
2015-10-16 07:58:31 +00:00
synchronized ( this . mInProgressAvatarFetches ) {
2016-04-12 15:52:58 +00:00
if ( ! this . mInProgressAvatarFetches . contains ( KEY ) ) {
2015-05-05 08:29:41 +00: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 04:17:34 +00:00
}
}
private void fetchAvatarPep ( Account account , final Avatar avatar , final UiCallback < Avatar > callback ) {
IqPacket packet = this . mIqGenerator . retrievePepAvatar ( avatar ) ;
2018-04-14 15:54:04 +00:00
sendIqPacket ( account , packet , ( a , result ) - > {
synchronized ( mInProgressAvatarFetches ) {
mInProgressAvatarFetches . remove ( generateFetchKey ( a , avatar ) ) ;
}
final String ERROR = a . getJid ( ) . asBareJid ( ) + " : fetching avatar for " + avatar . owner + " failed " ;
if ( result . getType ( ) = = IqPacket . TYPE . RESULT ) {
avatar . image = mIqParser . avatarData ( result ) ;
if ( avatar . image ! = null ) {
if ( getFileBackend ( ) . save ( avatar ) ) {
if ( a . getJid ( ) . asBareJid ( ) . equals ( avatar . owner ) ) {
if ( a . setAvatar ( avatar . getFilename ( ) ) ) {
databaseBackend . updateAccount ( a ) ;
2014-09-05 11:29:20 +00:00
}
2018-04-14 15:54:04 +00:00
getAvatarService ( ) . clear ( a ) ;
updateConversationUi ( ) ;
updateAccountUi ( ) ;
} else {
Contact contact = a . getRoster ( ) . getContact ( avatar . owner ) ;
contact . setAvatar ( avatar ) ;
getAvatarService ( ) . clear ( contact ) ;
updateConversationUi ( ) ;
updateRosterUi ( ) ;
2014-08-15 15:31:24 +00:00
}
2018-04-14 15:54:04 +00:00
if ( callback ! = null ) {
callback . success ( avatar ) ;
}
Log . d ( Config . LOGTAG , a . getJid ( ) . asBareJid ( )
+ " : successfully fetched pep avatar for " + avatar . owner ) ;
return ;
2014-09-05 11:29:20 +00:00
}
} else {
2018-04-14 15:54:04 +00:00
Log . d ( Config . LOGTAG , ERROR + " (parsing error) " ) ;
2014-08-15 15:31:24 +00:00
}
2018-04-14 15:54:04 +00:00
} else {
Element error = result . findChild ( " error " ) ;
if ( error = = null ) {
Log . d ( Config . LOGTAG , ERROR + " (server error) " ) ;
} else {
Log . d ( Config . LOGTAG , ERROR + error . toString ( ) ) ;
2014-08-15 15:31:24 +00:00
}
}
2018-04-14 15:54:04 +00:00
if ( callback ! = null ) {
callback . error ( 0 , null ) ;
}
2014-08-15 15:31:24 +00:00
} ) ;
}
2014-08-26 14:52:42 +00:00
2015-05-05 04:17:34 +00:00
private void fetchAvatarVcard ( final Account account , final Avatar avatar , final UiCallback < Avatar > callback ) {
IqPacket packet = this . mIqGenerator . retrieveVcardAvatar ( avatar ) ;
2015-05-20 10:47:04 +00:00
this . sendIqPacket ( account , packet , new OnIqPacketReceived ( ) {
2015-05-05 04:17:34 +00:00
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
2015-05-20 10:47:04 +00:00
synchronized ( mInProgressAvatarFetches ) {
mInProgressAvatarFetches . remove ( generateFetchKey ( account , avatar ) ) ;
2015-05-05 08:29:41 +00:00
}
2015-05-05 04:17:34 +00:00
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2015-05-20 10:47:04 +00:00
Element vCard = packet . findChild ( " vCard " , " vcard-temp " ) ;
2015-05-05 04:17:34 +00:00
Element photo = vCard ! = null ? vCard . findChild ( " PHOTO " ) : null ;
2015-05-14 12:42:21 +00:00
String image = photo ! = null ? photo . findChildContent ( " BINVAL " ) : null ;
2015-05-07 09:07:15 +00:00
if ( image ! = null ) {
avatar . image = image ;
2015-05-05 04:17:34 +00:00
if ( getFileBackend ( ) . save ( avatar ) ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( )
2015-05-05 04:17:34 +00:00
+ " : successfully fetched vCard avatar for " + avatar . owner ) ;
2015-12-03 17:18:34 +00:00
if ( avatar . owner . isBareJid ( ) ) {
2018-03-05 17:30:40 +00:00
if ( account . getJid ( ) . asBareJid ( ) . equals ( avatar . owner ) & & account . getAvatar ( ) = = null ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : had no avatar. replacing with vcard " ) ;
2016-09-09 09:04:05 +00:00
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 17:18:34 +00:00
updateConversationUi ( ) ;
} else {
2018-03-05 17:30:40 +00:00
Conversation conversation = find ( account , avatar . owner . asBareJid ( ) ) ;
2015-12-03 17:18:34 +00:00
if ( conversation ! = null & & conversation . getMode ( ) = = Conversation . MODE_MULTI ) {
2016-05-16 12:10:40 +00:00
MucOptions . User user = conversation . getMucOptions ( ) . findUserByFullJid ( avatar . owner ) ;
2015-12-03 17:18:34 +00:00
if ( user ! = null ) {
2015-12-04 20:36:48 +00:00
if ( user . setAvatar ( avatar ) ) {
getAvatarService ( ) . clear ( user ) ;
updateConversationUi ( ) ;
updateMucRosterUi ( ) ;
}
2015-12-03 17:18:34 +00:00
}
}
}
2015-05-05 04:17:34 +00:00
}
}
}
}
} ) ;
}
public void checkForAvatar ( Account account , final UiCallback < Avatar > callback ) {
2014-08-15 15:31:24 +00:00
IqPacket packet = this . mIqGenerator . retrieveAvatarMetaData ( null ) ;
this . sendIqPacket ( account , packet , new OnIqPacketReceived ( ) {
2014-08-26 14:52:42 +00:00
2014-08-15 15:31:24 +00:00
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
2014-12-30 13:16:25 +00:00
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2017-10-28 15:49:51 +00:00
Element pubsub = packet . findChild ( " pubsub " , " http://jabber.org/protocol/pubsub " ) ;
2014-08-26 14:52:42 +00:00
if ( pubsub ! = null ) {
2014-08-15 15:31:24 +00:00
Element items = pubsub . findChild ( " items " ) ;
2014-08-26 14:52:42 +00:00
if ( items ! = null ) {
2014-08-15 15:31:24 +00:00
Avatar avatar = Avatar . parseMetadata ( items ) ;
2014-08-26 14:52:42 +00:00
if ( avatar ! = null ) {
2018-03-05 17:30:40 +00:00
avatar . owner = account . getJid ( ) . asBareJid ( ) ;
2014-08-15 15:31:24 +00:00
if ( fileBackend . isAvatarCached ( avatar ) ) {
2014-08-21 10:32:50 +00:00
if ( account . setAvatar ( avatar . getFilename ( ) ) ) {
databaseBackend . updateAccount ( account ) ;
}
2014-10-21 12:57:16 +00:00
getAvatarService ( ) . clear ( account ) ;
2014-08-15 15:31:24 +00:00
callback . success ( avatar ) ;
} else {
2015-05-05 04:17:34 +00:00
fetchAvatarPep ( account , avatar , callback ) ;
2014-08-15 15:31:24 +00:00
}
return ;
}
}
2014-08-06 16:36:33 +00:00
}
2014-08-05 20:58:46 +00:00
}
2014-08-15 15:31:24 +00:00
callback . error ( 0 , null ) ;
2014-08-05 20:58:46 +00:00
}
} ) ;
}
2014-08-26 14:52:42 +00:00
2014-05-19 13:15:09 +00:00
public void deleteContactOnServer ( Contact contact ) {
2014-07-11 11:52:27 +00:00
contact . resetOption ( Contact . Options . PREEMPTIVE_GRANT ) ;
2014-05-22 12:33:17 +00:00
contact . resetOption ( Contact . Options . DIRTY_PUSH ) ;
2014-07-09 23:55:19 +00:00
contact . setOption ( Contact . Options . DIRTY_DELETE ) ;
2014-05-19 13:15:09 +00:00
Account account = contact . getAccount ( ) ;
2014-11-15 16:09:02 +00:00
if ( account . getStatus ( ) = = Account . State . ONLINE ) {
2014-12-30 13:16:25 +00:00
IqPacket iq = new IqPacket ( IqPacket . TYPE . SET ) ;
2017-03-01 12:01:46 +00:00
Element item = iq . query ( Namespace . ROSTER ) . addChild ( " item " ) ;
2014-11-05 20:55:47 +00:00
item . setAttribute ( " jid " , contact . getJid ( ) . toString ( ) ) ;
2014-05-22 07:36:00 +00:00
item . setAttribute ( " subscription " , " remove " ) ;
2015-05-26 09:31:33 +00:00
account . getXmppConnection ( ) . sendIqPacket ( iq , mDefaultIqHandler ) ;
2014-05-22 07:36:00 +00:00
}
2014-02-20 16:00:50 +00:00
}
2014-02-21 20:35:23 +00:00
2016-10-18 11:06:24 +00:00
public void updateConversation ( final Conversation conversation ) {
2018-03-12 15:00:02 +00:00
mDatabaseWriterExecutor . execute ( ( ) - > databaseBackend . updateConversation ( conversation ) ) ;
2014-03-03 04:01:02 +00:00
}
2014-03-05 14:41:14 +00:00
2015-09-29 17:24:52 +00:00
private void reconnectAccount ( final Account account , final boolean force , final boolean interactive ) {
2015-03-05 14:46:33 +00:00
synchronized ( account ) {
2016-01-16 18:21:11 +00:00
XmppConnection connection = account . getXmppConnection ( ) ;
2016-03-03 12:31:59 +00:00
if ( connection = = null ) {
2016-01-16 18:21:11 +00:00
connection = createConnection ( account ) ;
account . setXmppConnection ( connection ) ;
2015-03-05 14:46:33 +00:00
}
2016-12-10 12:20:05 +00:00
boolean hasInternet = hasInternetConnection ( ) ;
2017-11-06 12:57:25 +00:00
if ( account . isEnabled ( ) & & hasInternet ) {
2016-01-16 18:21:11 +00:00
if ( ! force ) {
2016-03-03 12:31:59 +00:00
disconnect ( account , false ) ;
2015-03-05 14:46:33 +00:00
}
2016-01-16 18:21:11 +00:00
Thread thread = new Thread ( connection ) ;
connection . setInteractive ( interactive ) ;
2016-03-20 16:24:41 +00:00
connection . prepareNewConnection ( ) ;
2016-11-19 09:44:40 +00:00
connection . interrupt ( ) ;
2015-03-05 14:46:33 +00:00
thread . start ( ) ;
2016-01-15 13:26:23 +00:00
scheduleWakeUpCall ( Config . CONNECT_DISCO_TIMEOUT , account . getUuid ( ) . hashCode ( ) ) ;
2015-03-05 14:46:33 +00:00
} else {
2016-12-10 12:20:05 +00:00
disconnect ( account , force | | account . getTrueStatus ( ) . isError ( ) | | ! hasInternet ) ;
2015-03-05 14:46:33 +00:00
account . getRoster ( ) . clearPresences ( ) ;
2016-01-16 18:21:11 +00:00
connection . resetEverything ( ) ;
2017-02-17 09:26:42 +00:00
final AxolotlService axolotlService = account . getAxolotlService ( ) ;
if ( axolotlService ! = null ) {
axolotlService . resetBrokenness ( ) ;
}
2016-12-10 12:20:05 +00:00
if ( ! hasInternet ) {
account . setStatus ( Account . State . NO_INTERNET ) ;
}
2015-03-05 14:46:33 +00:00
}
}
}
2014-03-11 14:44:22 +00:00
2015-03-05 14:46:33 +00:00
public void reconnectAccountInBackground ( final Account account ) {
2018-03-18 09:30:15 +00:00
new Thread ( ( ) - > reconnectAccount ( account , false , true ) ) . start ( ) ;
2014-03-08 19:14:47 +00:00
}
2014-03-14 21:40:56 +00:00
2014-11-20 17:20:42 +00:00
public void invite ( Conversation conversation , Jid contact ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , conversation . getAccount ( ) . getJid ( ) . asBareJid ( ) + " : inviting " + contact + " to " + conversation . getJid ( ) . asBareJid ( ) ) ;
2014-07-21 14:04:53 +00:00
MessagePacket packet = mMessageGenerator . invite ( conversation , contact ) ;
2014-08-26 14:52:42 +00:00
sendMessagePacket ( conversation . getAccount ( ) , packet ) ;
2014-03-15 03:59:18 +00:00
}
2014-08-30 07:24:58 +00:00
2015-04-23 15:37:47 +00:00
public void directInvite ( Conversation conversation , Jid jid ) {
2015-05-20 10:47:04 +00:00
MessagePacket packet = mMessageGenerator . directInvite ( conversation , jid ) ;
2015-10-16 07:58:31 +00:00
sendMessagePacket ( conversation . getAccount ( ) , packet ) ;
2015-04-23 15:37:47 +00:00
}
2014-08-27 17:25:58 +00:00
public void resetSendingToWaiting ( Account account ) {
2014-08-30 07:24:58 +00:00
for ( Conversation conversation : getConversations ( ) ) {
2014-08-27 17:25:58 +00:00
if ( conversation . getAccount ( ) = = account ) {
2014-12-14 17:10:46 +00:00
conversation . findUnsentTextMessages ( new Conversation . OnMessageFound ( ) {
@Override
public void onMessageFound ( Message message ) {
2014-08-27 17:25:58 +00:00
markMessage ( message , Message . STATUS_WAITING ) ;
2014-12-14 17:10:46 +00:00
}
} ) ;
2014-08-27 17:25:58 +00:00
}
}
2014-03-15 03:59:18 +00:00
}
2014-05-01 20:33:49 +00:00
2015-03-01 13:15:40 +00:00
public Message markMessage ( final Account account , final Jid recipient , final String uuid , final int status ) {
2016-10-26 10:26:04 +00:00
return markMessage ( account , recipient , uuid , status , null ) ;
}
public Message markMessage ( final Account account , final Jid recipient , final String uuid , final int status , String errorMessage ) {
2014-10-02 16:54:21 +00:00
if ( uuid = = null ) {
2015-03-01 13:15:40 +00:00
return null ;
}
for ( Conversation conversation : getConversations ( ) ) {
2018-03-05 17:30:40 +00:00
if ( conversation . getJid ( ) . asBareJid ( ) . equals ( recipient ) & & conversation . getAccount ( ) = = account ) {
2015-08-26 10:11:12 +00:00
final Message message = conversation . findSentMessageWithUuidOrRemoteId ( uuid ) ;
2015-03-01 13:15:40 +00:00
if ( message ! = null ) {
2016-10-26 10:26:04 +00:00
markMessage ( message , status , errorMessage ) ;
2015-01-19 10:17:27 +00:00
}
2015-03-01 13:15:40 +00:00
return message ;
2014-05-16 20:46:15 +00:00
}
}
2015-03-01 13:15:40 +00:00
return null ;
2014-05-16 20:46:15 +00:00
}
2014-05-18 09:25:04 +00:00
2017-03-06 12:30:13 +00:00
public boolean markMessage ( Conversation conversation , String uuid , int status , String serverMessageId ) {
2014-10-02 16:54:21 +00:00
if ( uuid = = null ) {
return false ;
} else {
2014-12-14 17:10:46 +00:00
Message message = conversation . findSentMessageWithUuid ( uuid ) ;
2015-01-19 10:17:27 +00:00
if ( message ! = null ) {
2017-03-06 12:30:13 +00:00
if ( message . getServerMsgId ( ) = = null ) {
message . setServerMsgId ( serverMessageId ) ;
}
2015-01-19 10:17:27 +00:00
markMessage ( message , status ) ;
2014-12-14 17:10:46 +00:00
return true ;
} else {
return false ;
2014-04-11 07:13:56 +00:00
}
}
}
2014-05-01 20:33:49 +00:00
2014-04-11 07:13:56 +00:00
public void markMessage ( Message message , int status ) {
2016-10-26 10:26:04 +00:00
markMessage ( message , status , null ) ;
}
public void markMessage ( Message message , int status , String errorMessage ) {
2018-03-30 19:14:06 +00:00
final int c = message . getStatus ( ) ;
if ( status = = Message . STATUS_SEND_FAILED & & ( c = = Message . STATUS_SEND_RECEIVED | | c = = Message . STATUS_SEND_DISPLAYED ) ) {
return ;
}
if ( status = = Message . STATUS_SEND_RECEIVED & & c = = Message . STATUS_SEND_DISPLAYED ) {
2014-09-08 10:51:01 +00:00
return ;
2015-01-19 10:17:27 +00:00
}
2016-10-26 10:26:04 +00:00
message . setErrorMessage ( errorMessage ) ;
2014-04-11 07:13:56 +00:00
message . setStatus ( status ) ;
2018-05-10 08:47:28 +00:00
databaseBackend . updateMessage ( message , false ) ;
2014-07-12 11:42:17 +00:00
updateConversationUi ( ) ;
2014-04-11 07:13:56 +00:00
}
2014-05-01 20:33:49 +00:00
2017-07-01 11:41:24 +00:00
private SharedPreferences getPreferences ( ) {
return PreferenceManager . getDefaultSharedPreferences ( getApplicationContext ( ) ) ;
2014-04-13 16:09:40 +00:00
}
2014-09-08 21:58:37 +00:00
2017-01-23 16:14:30 +00:00
public long getAutomaticMessageDeletionDate ( ) {
2017-10-28 15:49:51 +00:00
final long timeout = getLongPreference ( SettingsActivity . AUTOMATIC_MESSAGE_DELETION , R . integer . automatic_message_deletion ) ;
2017-07-01 11:41:24 +00:00
return timeout = = 0 ? timeout : ( System . currentTimeMillis ( ) - ( timeout * 1000 ) ) ;
}
public long getLongPreference ( String name , @IntegerRes int res ) {
long defaultValue = getResources ( ) . getInteger ( res ) ;
2017-01-23 16:14:30 +00:00
try {
2017-10-28 15:49:51 +00:00
return Long . parseLong ( getPreferences ( ) . getString ( name , String . valueOf ( defaultValue ) ) ) ;
2017-01-23 16:14:30 +00:00
} catch ( NumberFormatException e ) {
2017-07-01 11:41:24 +00:00
return defaultValue ;
2017-01-23 16:14:30 +00:00
}
}
2017-07-01 11:41:24 +00:00
public boolean getBooleanPreference ( String name , @BoolRes int res ) {
2017-10-28 15:49:51 +00:00
return getPreferences ( ) . getBoolean ( name , getResources ( ) . getBoolean ( res ) ) ;
2017-07-01 11:41:24 +00:00
}
2014-06-04 16:44:15 +00:00
public boolean confirmMessages ( ) {
2017-07-01 11:41:24 +00:00
return getBooleanPreference ( " confirm_messages " , R . bool . confirm_messages ) ;
2016-02-16 08:57:59 +00:00
}
public boolean allowMessageCorrection ( ) {
2017-07-01 11:41:24 +00:00
return getBooleanPreference ( " allow_message_correction " , R . bool . allow_message_correction ) ;
2014-06-03 13:48:51 +00:00
}
2014-09-08 21:58:37 +00:00
2015-02-21 10:06:52 +00:00
public boolean sendChatStates ( ) {
2017-07-01 11:41:24 +00:00
return getBooleanPreference ( " chat_states " , R . bool . chat_states ) ;
2015-02-21 10:06:52 +00:00
}
2016-02-01 12:54:08 +00:00
private boolean respectAutojoin ( ) {
2017-07-01 11:41:24 +00:00
return getBooleanPreference ( " autojoin " , R . bool . autojoin ) ;
2016-02-01 12:54:08 +00:00
}
2014-09-20 13:49:25 +00:00
public boolean indicateReceived ( ) {
2017-07-01 11:41:24 +00:00
return getBooleanPreference ( " indicate_received " , R . bool . indicate_received ) ;
2015-11-28 19:11:38 +00:00
}
public boolean useTorToConnect ( ) {
2017-07-01 11:41:24 +00:00
return Config . FORCE_ORBOT | | getBooleanPreference ( " use_tor " , R . bool . use_tor ) ;
2014-09-20 13:49:25 +00:00
}
2016-01-25 20:17:53 +00:00
public boolean showExtendedConnectionOptions ( ) {
2017-07-01 11:41:24 +00:00
return getBooleanPreference ( " show_connection_options " , R . bool . show_connection_options ) ;
2016-01-25 20:17:53 +00:00
}
2016-06-04 14:16:14 +00:00
public boolean broadcastLastActivity ( ) {
2017-07-01 11:41:24 +00:00
return getBooleanPreference ( SettingsActivity . BROADCAST_LAST_ACTIVITY , R . bool . last_activity ) ;
2016-06-04 14:16:14 +00:00
}
2015-03-02 10:53:15 +00:00
public int unreadCount ( ) {
int count = 0 ;
2015-10-16 07:58:31 +00:00
for ( Conversation conversation : getConversations ( ) ) {
2015-03-02 10:53:15 +00:00
count + = conversation . unreadCount ( ) ;
}
return count ;
}
2015-07-10 11:28:50 +00:00
public void showErrorToastInUi ( int resId ) {
2018-05-03 12:54:22 +00:00
for ( OnShowErrorToast listener : this . mOnShowErrorToasts ) {
listener . onShowErrorToast ( resId ) ;
2015-07-10 11:28:50 +00:00
}
}
2014-07-12 11:42:17 +00:00
public void updateConversationUi ( ) {
2018-05-03 12:54:22 +00:00
for ( OnConversationUpdate listener : this . mOnConversationUpdates ) {
listener . onConversationUpdate ( ) ;
2014-07-12 11:42:17 +00:00
}
}
2014-08-26 14:52:42 +00:00
2014-07-12 11:42:17 +00:00
public void updateAccountUi ( ) {
2018-05-03 12:54:22 +00:00
for ( OnAccountUpdate listener : this . mOnAccountUpdates ) {
listener . onAccountUpdate ( ) ;
2014-07-12 11:42:17 +00:00
}
}
2014-08-26 14:52:42 +00:00
2014-07-18 13:35:31 +00:00
public void updateRosterUi ( ) {
2018-05-03 12:54:22 +00:00
for ( OnRosterUpdate listener : this . mOnRosterUpdates ) {
listener . onRosterUpdate ( ) ;
2014-07-18 13:35:31 +00:00
}
}
2014-05-22 07:36:00 +00:00
2015-10-11 11:11:50 +00:00
public boolean displayCaptchaRequest ( Account account , String id , Data data , Bitmap captcha ) {
2018-05-03 12:54:22 +00:00
if ( mOnCaptchaRequested . size ( ) > 0 ) {
2015-10-11 11:11:50 +00:00
DisplayMetrics metrics = getApplicationContext ( ) . getResources ( ) . getDisplayMetrics ( ) ;
2015-10-16 07:58:31 +00:00
Bitmap scaled = Bitmap . createScaledBitmap ( captcha , ( int ) ( captcha . getWidth ( ) * metrics . scaledDensity ) ,
( int ) ( captcha . getHeight ( ) * metrics . scaledDensity ) , false ) ;
2018-05-03 12:54:22 +00:00
for ( OnCaptchaRequested listener : this . mOnCaptchaRequested ) {
listener . onCaptchaRequested ( account , id , data , scaled ) ;
}
2016-05-10 07:41:30 +00:00
return true ;
2015-10-11 11:11:50 +00:00
}
2016-05-10 07:41:30 +00:00
return false ;
2015-10-11 11:11:50 +00:00
}
2014-12-21 20:43:58 +00:00
public void updateBlocklistUi ( final OnUpdateBlocklist . Status status ) {
2018-05-03 12:54:22 +00:00
for ( OnUpdateBlocklist listener : this . mOnUpdateBlocklist ) {
listener . OnUpdateBlocklist ( status ) ;
2014-12-21 20:43:58 +00:00
}
}
2014-11-23 14:19:44 +00:00
public void updateMucRosterUi ( ) {
2018-05-03 12:54:22 +00:00
for ( OnMucRosterUpdate listener : this . mOnMucRosterUpdate ) {
listener . onMucRosterUpdate ( ) ;
2014-11-23 14:19:44 +00:00
}
}
2015-10-17 12:09:26 +00:00
public void keyStatusUpdated ( AxolotlService . FetchStatus report ) {
2018-05-03 12:54:22 +00:00
for ( OnKeyStatusUpdated listener : this . mOnKeyStatusUpdated ) {
listener . onKeyStatusUpdated ( report ) ;
2015-07-19 16:36:28 +00:00
}
}
2014-11-05 20:55:47 +00:00
public Account findAccountByJid ( final Jid accountJid ) {
2014-05-19 13:15:09 +00:00
for ( Account account : this . accounts ) {
2018-03-05 17:30:40 +00:00
if ( account . getJid ( ) . asBareJid ( ) . equals ( accountJid . asBareJid ( ) ) ) {
2014-05-19 13:15:09 +00:00
return account ;
}
}
return null ;
}
2014-08-26 14:52:42 +00:00
2018-04-26 11:22:31 +00:00
public Account findAccountByUuid ( final String uuid ) {
for ( Account account : this . accounts ) {
if ( account . getUuid ( ) . equals ( uuid ) ) {
return account ;
}
}
return null ;
}
2014-07-16 22:03:37 +00:00
public Conversation findConversationByUuid ( String uuid ) {
for ( Conversation conversation : getConversations ( ) ) {
if ( conversation . getUuid ( ) . equals ( uuid ) ) {
return conversation ;
}
}
return null ;
}
2014-06-04 16:44:15 +00:00
2018-03-30 19:14:06 +00:00
public boolean markRead ( final Conversation conversation , boolean dismiss ) {
2018-03-31 08:57:59 +00:00
return markRead ( conversation , null , dismiss ) . size ( ) > 0 ;
2018-03-30 19:14:06 +00:00
}
2018-03-31 09:08:04 +00:00
public void markRead ( final Conversation conversation ) {
markRead ( conversation , null , true ) ;
2016-08-27 13:25:37 +00:00
}
2018-03-30 19:14:06 +00:00
public List < Message > markRead ( final Conversation conversation , String upToUuid , boolean dismiss ) {
if ( dismiss ) {
2016-08-27 13:25:37 +00:00
mNotificationService . clear ( conversation ) ;
}
2018-03-30 19:14:06 +00:00
final List < Message > readMessages = conversation . markRead ( upToUuid ) ;
2015-10-29 16:20:01 +00:00
if ( readMessages . size ( ) > 0 ) {
2018-03-18 09:30:15 +00:00
Runnable runnable = ( ) - > {
for ( Message message : readMessages ) {
2018-05-10 08:47:28 +00:00
databaseBackend . updateMessage ( message , false ) ;
2015-10-29 16:20:01 +00:00
}
} ;
2017-11-16 14:53:03 +00:00
mDatabaseWriterExecutor . execute ( runnable ) ;
2016-02-16 13:22:21 +00:00
updateUnreadCountBadge ( ) ;
2018-03-30 19:14:06 +00:00
return readMessages ;
2016-02-16 13:22:21 +00:00
} else {
2018-03-30 19:14:06 +00:00
return readMessages ;
2015-10-14 19:18:34 +00:00
}
2015-05-20 10:47:04 +00:00
}
2015-05-26 10:00:38 +00:00
public synchronized void updateUnreadCountBadge ( ) {
2015-05-20 10:47:04 +00:00
int count = unreadCount ( ) ;
2015-05-26 10:00:38 +00:00
if ( unreadCount ! = count ) {
Log . d ( Config . LOGTAG , " update unread count to " + count ) ;
if ( count > 0 ) {
2016-03-27 18:02:36 +00:00
ShortcutBadger . applyCount ( getApplicationContext ( ) , count ) ;
2015-05-26 10:00:38 +00:00
} else {
2016-03-27 18:02:36 +00:00
ShortcutBadger . removeCount ( getApplicationContext ( ) ) ;
2015-05-26 10:00:38 +00:00
}
unreadCount = count ;
2015-05-20 10:47:04 +00:00
}
2015-01-02 11:04:33 +00:00
}
2018-03-30 19:14:06 +00:00
public void sendReadMarker ( final Conversation conversation , String upToUuid ) {
2018-01-22 22:21:24 +00:00
final boolean isPrivateAndNonAnonymousMuc = conversation . getMode ( ) = = Conversation . MODE_MULTI & & conversation . isPrivateAndNonAnonymous ( ) ;
2018-03-31 08:57:59 +00:00
final List < Message > readMessages = this . markRead ( conversation , upToUuid , true ) ;
2018-03-30 19:14:06 +00:00
if ( readMessages . size ( ) > 0 ) {
2016-02-16 13:22:21 +00:00
updateConversationUi ( ) ;
}
2018-03-30 19:14:06 +00:00
final Message markable = Conversation . getLatestMarkableMessage ( readMessages , isPrivateAndNonAnonymousMuc ) ;
2016-10-07 08:05:08 +00:00
if ( confirmMessages ( )
& & markable ! = null
2018-01-22 22:21:24 +00:00
& & ( markable . trusted ( ) | | isPrivateAndNonAnonymousMuc )
& & markable . getRemoteMsgId ( ) ! = null ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , conversation . getAccount ( ) . getJid ( ) . asBareJid ( ) + " : sending read marker to " + markable . getCounterpart ( ) . toString ( ) ) ;
2014-07-12 01:44:23 +00:00
Account account = conversation . getAccount ( ) ;
2014-11-19 16:40:42 +00:00
final Jid to = markable . getCounterpart ( ) ;
2017-11-19 00:53:04 +00:00
final boolean groupChat = conversation . getMode ( ) = = Conversation . MODE_MULTI ;
2017-11-21 14:42:46 +00:00
MessagePacket packet = mMessageGenerator . confirm ( account , to , markable . getRemoteMsgId ( ) , markable . getCounterpart ( ) , groupChat ) ;
2015-01-19 10:17:27 +00:00
this . sendMessagePacket ( conversation . getAccount ( ) , packet ) ;
2014-07-12 01:44:23 +00:00
}
2014-06-04 16:44:15 +00:00
}
2014-08-26 14:52:42 +00:00
2014-06-20 15:30:19 +00:00
public SecureRandom getRNG ( ) {
return this . mRandom ;
}
2014-08-26 14:52:42 +00:00
2014-07-22 15:27:44 +00:00
public MemorizingTrustManager getMemorizingTrustManager ( ) {
return this . mMemorizingTrustManager ;
}
2014-06-20 15:30:19 +00:00
2015-04-02 11:35:42 +00:00
public void setMemorizingTrustManager ( MemorizingTrustManager trustManager ) {
this . mMemorizingTrustManager = trustManager ;
}
public void updateMemorizingTrustmanager ( ) {
final MemorizingTrustManager tm ;
2017-07-01 11:41:24 +00:00
final boolean dontTrustSystemCAs = getBooleanPreference ( " dont_trust_system_cas " , R . bool . dont_trust_system_cas ) ;
2015-04-02 11:35:42 +00:00
if ( dontTrustSystemCAs ) {
2015-10-16 07:58:31 +00:00
tm = new MemorizingTrustManager ( getApplicationContext ( ) , null ) ;
2015-04-02 11:35:42 +00:00
} else {
tm = new MemorizingTrustManager ( getApplicationContext ( ) ) ;
}
setMemorizingTrustManager ( tm ) ;
}
2014-10-21 12:57:16 +00:00
public LruCache < String , Bitmap > getBitmapCache ( ) {
return this . mBitmapCache ;
}
2018-03-11 11:13:56 +00:00
public Collection < String > getKnownHosts ( ) {
final Set < String > hosts = new HashSet < > ( ) ;
2014-12-21 01:13:13 +00:00
for ( final Account account : getAccounts ( ) ) {
2018-03-11 11:13:56 +00:00
hosts . add ( account . getServer ( ) ) ;
2014-12-21 01:13:13 +00:00
for ( final Contact contact : account . getRoster ( ) . getContacts ( ) ) {
2014-07-10 17:42:37 +00:00
if ( contact . showInRoster ( ) ) {
2018-03-11 11:13:56 +00:00
final String server = contact . getServer ( ) ;
2014-07-11 11:52:27 +00:00
if ( server ! = null & & ! hosts . contains ( server ) ) {
2014-07-10 17:42:37 +00:00
hosts . add ( server ) ;
}
}
}
}
2018-03-11 11:13:56 +00:00
if ( Config . DOMAIN_LOCK ! = null ) {
2016-05-10 08:53:44 +00:00
hosts . add ( Config . DOMAIN_LOCK ) ;
}
2018-03-11 11:13:56 +00:00
if ( Config . MAGIC_CREATE_DOMAIN ! = null ) {
2016-05-10 08:53:44 +00:00
hosts . add ( Config . MAGIC_CREATE_DOMAIN ) ;
}
2014-07-10 17:42:37 +00:00
return hosts ;
}
2014-07-11 17:48:41 +00:00
2018-03-11 11:13:56 +00:00
public Collection < String > getKnownConferenceHosts ( ) {
final Set < String > mucServers = new HashSet < > ( ) ;
2014-12-21 01:13:13 +00:00
for ( final Account account : accounts ) {
2014-07-11 17:48:41 +00:00
if ( account . getXmppConnection ( ) ! = null ) {
2018-03-22 11:43:08 +00:00
mucServers . addAll ( account . getXmppConnection ( ) . getMucServers ( ) ) ;
2017-10-28 15:49:51 +00:00
for ( Bookmark bookmark : account . getBookmarks ( ) ) {
2017-06-01 14:44:35 +00:00
final Jid jid = bookmark . getJid ( ) ;
2018-03-05 17:30:40 +00:00
final String s = jid = = null ? null : jid . getDomain ( ) ;
2018-03-11 11:13:56 +00:00
if ( s ! = null ) {
2017-05-04 09:28:54 +00:00
mucServers . add ( s ) ;
}
}
2014-07-11 17:48:41 +00:00
}
}
return mucServers ;
}
2014-08-26 14:52:42 +00:00
2014-07-12 01:44:23 +00:00
public void sendMessagePacket ( Account account , MessagePacket packet ) {
2014-10-08 12:10:37 +00:00
XmppConnection connection = account . getXmppConnection ( ) ;
if ( connection ! = null ) {
connection . sendMessagePacket ( packet ) ;
}
2014-07-12 01:44:23 +00:00
}
2014-08-26 14:52:42 +00:00
2014-07-12 01:44:23 +00:00
public void sendPresencePacket ( Account account , PresencePacket packet ) {
2014-10-08 12:10:37 +00:00
XmppConnection connection = account . getXmppConnection ( ) ;
if ( connection ! = null ) {
connection . sendPresencePacket ( packet ) ;
}
2014-07-12 01:44:23 +00:00
}
2014-08-26 14:52:42 +00:00
2015-10-11 11:11:50 +00:00
public void sendCreateAccountWithCaptchaPacket ( Account account , String id , Data data ) {
2016-05-05 07:58:35 +00:00
final XmppConnection connection = account . getXmppConnection ( ) ;
2015-10-11 11:11:50 +00:00
if ( connection ! = null ) {
2016-05-05 07:58:35 +00:00
IqPacket request = mIqGenerator . generateCreateAccountWithCaptcha ( account , id , data ) ;
2018-03-18 09:30:15 +00:00
connection . sendUnmodifiedIqPacket ( request , connection . registrationResponseListener , true ) ;
2015-10-11 11:11:50 +00:00
}
}
2015-01-04 11:09:39 +00:00
public void sendIqPacket ( final Account account , final IqPacket packet , final OnIqPacketReceived callback ) {
2014-12-21 20:43:58 +00:00
final XmppConnection connection = account . getXmppConnection ( ) ;
2014-10-08 12:10:37 +00:00
if ( connection ! = null ) {
connection . sendIqPacket ( packet , callback ) ;
}
2014-07-14 09:47:42 +00:00
}
2014-08-26 14:52:42 +00:00
2015-01-25 23:48:56 +00:00
public void sendPresence ( final Account account ) {
2016-06-04 14:16:14 +00:00
sendPresence ( account , checkListeners ( ) & & broadcastLastActivity ( ) ) ;
}
private void sendPresence ( final Account account , final boolean includeIdleTimestamp ) {
2018-03-04 10:43:58 +00:00
Presence . Status status ;
2016-04-22 19:25:06 +00:00
if ( manuallyChangePresence ( ) ) {
2018-03-04 10:43:58 +00:00
status = account . getPresenceStatus ( ) ;
2016-04-22 19:25:06 +00:00
} else {
2018-03-04 10:43:58 +00:00
status = getTargetPresence ( ) ;
}
2018-03-18 09:30:15 +00:00
PresencePacket packet = mPresenceGenerator . selfPresence ( account , status ) ;
2018-03-04 10:43:58 +00:00
String message = account . getPresenceStatusMessage ( ) ;
if ( message ! = null & & ! message . isEmpty ( ) ) {
packet . addChild ( new Element ( " status " ) . setContent ( message ) ) ;
2016-04-22 19:25:06 +00:00
}
2016-06-04 14:16:14 +00:00
if ( mLastActivity > 0 & & includeIdleTimestamp ) {
long since = Math . min ( mLastActivity , System . currentTimeMillis ( ) ) ; //don't send future dates
2017-10-28 15:49:51 +00:00
packet . addChild ( " idle " , Namespace . IDLE ) . setAttribute ( " since " , AbstractGenerator . getTimestamp ( since ) ) ;
2016-06-04 14:16:14 +00:00
}
2016-04-22 19:25:06 +00:00
sendPresencePacket ( account , packet ) ;
2015-10-07 22:35:04 +00:00
}
2016-06-01 19:51:46 +00:00
private void deactivateGracePeriod ( ) {
2017-10-28 15:49:51 +00:00
for ( Account account : getAccounts ( ) ) {
2016-06-01 19:51:46 +00:00
account . deactivateGracePeriod ( ) ;
}
}
2015-10-07 22:35:04 +00:00
public void refreshAllPresences ( ) {
2016-06-04 14:16:14 +00:00
boolean includeIdleTimestamp = checkListeners ( ) & & broadcastLastActivity ( ) ;
2015-10-07 22:35:04 +00:00
for ( Account account : getAccounts ( ) ) {
2017-11-06 12:57:25 +00:00
if ( account . isEnabled ( ) ) {
2016-06-04 14:16:14 +00:00
sendPresence ( account , includeIdleTimestamp ) ;
2015-10-07 22:35:04 +00:00
}
}
2015-01-25 23:48:56 +00:00
}
2018-05-19 18:05:45 +00:00
private void refreshAllFcmTokens ( ) {
2017-10-28 15:49:51 +00:00
for ( Account account : getAccounts ( ) ) {
2016-02-12 23:03:57 +00:00
if ( account . isOnlineAndConnected ( ) & & mPushManagementService . available ( account ) ) {
2016-02-12 10:39:27 +00:00
mPushManagementService . registerPushTokenOnServer ( account ) ;
}
}
}
2016-09-07 12:34:58 +00:00
private void sendOfflinePresence ( final Account account ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : sending offline presence " ) ;
2015-04-09 10:46:54 +00:00
sendPresencePacket ( account , mPresenceGenerator . sendOfflinePresence ( account ) ) ;
}
2014-07-12 01:44:23 +00:00
public MessageGenerator getMessageGenerator ( ) {
return this . mMessageGenerator ;
}
2014-08-26 14:52:42 +00:00
2014-07-12 01:44:23 +00:00
public PresenceGenerator getPresenceGenerator ( ) {
return this . mPresenceGenerator ;
}
2014-08-26 14:52:42 +00:00
2014-07-23 12:30:27 +00:00
public IqGenerator getIqGenerator ( ) {
2014-08-26 14:52:42 +00:00
return this . mIqGenerator ;
2014-07-23 12:30:27 +00:00
}
2014-08-26 14:52:42 +00:00
2015-01-19 10:17:27 +00:00
public IqParser getIqParser ( ) {
return this . mIqParser ;
}
2014-12-21 20:43:58 +00:00
2014-07-12 10:28:28 +00:00
public JingleConnectionManager getJingleConnectionManager ( ) {
return this . mJingleConnectionManager ;
}
2014-08-26 14:52:42 +00:00
2014-12-05 00:54:16 +00:00
public MessageArchiveService getMessageArchiveService ( ) {
return this . mMessageArchiveService ;
}
2017-05-31 14:45:51 +00:00
public List < Contact > findContacts ( Jid jid , String accountJid ) {
2014-11-05 20:55:47 +00:00
ArrayList < Contact > contacts = new ArrayList < > ( ) ;
2014-09-27 09:37:02 +00:00
for ( Account account : getAccounts ( ) ) {
2017-11-06 12:57:25 +00:00
if ( ( account . isEnabled ( ) | | accountJid ! = null )
2018-03-05 17:30:40 +00:00
& & ( accountJid = = null | | accountJid . equals ( account . getJid ( ) . asBareJid ( ) . toString ( ) ) ) ) {
2014-10-15 12:41:27 +00:00
Contact contact = account . getRoster ( ) . getContactFromRoster ( jid ) ;
2014-09-27 09:37:02 +00:00
if ( contact ! = null ) {
contacts . add ( contact ) ;
}
}
}
return contacts ;
}
2014-10-02 16:31:19 +00:00
2016-05-30 19:12:04 +00:00
public Conversation findFirstMuc ( Jid jid ) {
2017-10-28 15:49:51 +00:00
for ( Conversation conversation : getConversations ( ) ) {
2018-03-05 17:30:40 +00:00
if ( conversation . getAccount ( ) . isEnabled ( ) & & conversation . getJid ( ) . asBareJid ( ) . equals ( jid . asBareJid ( ) ) & & conversation . getMode ( ) = = Conversation . MODE_MULTI ) {
2016-05-30 19:12:04 +00:00
return conversation ;
}
}
return null ;
}
2014-09-29 16:28:13 +00:00
public NotificationService getNotificationService ( ) {
return this . mNotificationService ;
2014-09-28 13:21:56 +00:00
}
2014-10-13 23:06:45 +00:00
public HttpConnectionManager getHttpConnectionManager ( ) {
return this . mHttpConnectionManager ;
}
2014-10-20 19:08:33 +00:00
2014-12-21 20:43:58 +00:00
public void resendFailedMessages ( final Message message ) {
final Collection < Message > messages = new ArrayList < > ( ) ;
2014-11-10 00:24:35 +00: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 20:43:58 +00:00
for ( final Message msg : messages ) {
2015-07-28 10:54:54 +00:00
msg . setTime ( System . currentTimeMillis ( ) ) ;
2014-11-10 00:24:35 +00:00
markMessage ( msg , Message . STATUS_WAITING ) ;
2015-10-16 07:58:31 +00:00
this . resendMessage ( msg , false ) ;
2014-11-10 00:24:35 +00:00
}
2018-04-26 11:22:31 +00:00
if ( message . getConversation ( ) instanceof Conversation ) {
( ( Conversation ) message . getConversation ( ) ) . sort ( ) ;
}
2018-03-05 12:23:04 +00:00
updateConversationUi ( ) ;
2014-11-10 00:24:35 +00:00
}
2014-12-15 16:14:27 +00:00
public void clearConversationHistory ( final Conversation conversation ) {
2017-05-07 19:05:35 +00:00
final long clearDate ;
final String reference ;
2017-03-07 10:45:35 +00:00
if ( conversation . countMessages ( ) > 0 ) {
2017-05-07 19:05:35 +00:00
Message latestMessage = conversation . getLatestMessage ( ) ;
clearDate = latestMessage . getTimeSent ( ) + 1000 ;
reference = latestMessage . getServerMsgId ( ) ;
2017-03-07 10:45:35 +00:00
} else {
clearDate = System . currentTimeMillis ( ) ;
2017-05-07 19:05:35 +00:00
reference = null ;
2017-03-07 10:45:35 +00:00
}
2014-12-15 16:14:27 +00:00
conversation . clearMessages ( ) ;
2015-01-03 17:22:26 +00:00
conversation . setHasMessagesLeftOnServer ( false ) ; //avoid messages getting loaded through mam
2017-10-28 15:49:51 +00:00
conversation . setLastClearHistory ( clearDate , reference ) ;
2018-03-18 09:30:15 +00:00
Runnable runnable = ( ) - > {
databaseBackend . deleteMessagesInConversation ( conversation ) ;
databaseBackend . updateConversation ( conversation ) ;
2015-10-29 16:20:01 +00:00
} ;
2017-11-16 14:53:03 +00:00
mDatabaseWriterExecutor . execute ( runnable ) ;
2014-12-15 16:14:27 +00:00
}
2017-03-06 15:53:54 +00:00
public boolean sendBlockRequest ( final Blockable blockable , boolean reportSpam ) {
2014-12-21 20:43:58 +00:00
if ( blockable ! = null & & blockable . getBlockedJid ( ) ! = null ) {
final Jid jid = blockable . getBlockedJid ( ) ;
2016-09-18 21:21:05 +00:00
this . sendIqPacket ( blockable . getAccount ( ) , getIqGenerator ( ) . generateSetBlockRequest ( jid , reportSpam ) , new OnIqPacketReceived ( ) {
2014-12-21 20:43:58 +00:00
@Override
public void onIqPacketReceived ( final Account account , final IqPacket packet ) {
2014-12-30 13:16:25 +00:00
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2014-12-21 20:43:58 +00:00
account . getBlocklist ( ) . add ( jid ) ;
updateBlocklistUi ( OnUpdateBlocklist . Status . BLOCKED ) ;
}
}
} ) ;
2017-10-28 15:49:51 +00:00
if ( removeBlockedConversations ( blockable . getAccount ( ) , jid ) ) {
2017-03-06 15:53:54 +00:00
updateConversationUi ( ) ;
return true ;
} else {
return false ;
}
} else {
return false ;
2014-12-21 20:43:58 +00:00
}
}
2017-03-06 15:53:54 +00:00
public boolean removeBlockedConversations ( final Account account , final Jid blockedJid ) {
boolean removed = false ;
synchronized ( this . conversations ) {
2018-03-05 17:30:40 +00:00
boolean domainJid = blockedJid . getLocal ( ) = = null ;
2017-10-28 15:49:51 +00:00
for ( Conversation conversation : this . conversations ) {
2018-03-05 17:30:40 +00:00
boolean jidMatches = ( domainJid & & blockedJid . getDomain ( ) . equals ( conversation . getJid ( ) . getDomain ( ) ) )
| | blockedJid . equals ( conversation . getJid ( ) . asBareJid ( ) ) ;
2017-03-06 15:53:54 +00:00
if ( conversation . getAccount ( ) = = account
& & conversation . getMode ( ) = = Conversation . MODE_SINGLE
& & jidMatches ) {
this . conversations . remove ( conversation ) ;
markRead ( conversation ) ;
conversation . setStatus ( Conversation . STATUS_ARCHIVED ) ;
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : archiving conversation " + conversation . getJid ( ) . asBareJid ( ) + " because jid was blocked " ) ;
2017-03-06 15:53:54 +00:00
updateConversation ( conversation ) ;
removed = true ;
}
}
}
return removed ;
}
2014-12-21 20:43:58 +00:00
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 13:16:25 +00:00
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
2014-12-21 20:43:58 +00:00
account . getBlocklist ( ) . remove ( jid ) ;
updateBlocklistUi ( OnUpdateBlocklist . Status . UNBLOCKED ) ;
}
}
} ) ;
}
}
2015-01-19 10:17:27 +00:00
2015-10-29 12:41:08 +00:00
public void publishDisplayName ( Account account ) {
String displayName = account . getDisplayName ( ) ;
if ( displayName ! = null & & ! displayName . isEmpty ( ) ) {
IqPacket publish = mIqGenerator . publishNick ( displayName ) ;
2018-03-18 09:30:15 +00:00
sendIqPacket ( account , publish , ( account1 , packet ) - > {
if ( packet . getType ( ) = = IqPacket . TYPE . ERROR ) {
Log . d ( Config . LOGTAG , account1 . getJid ( ) . asBareJid ( ) + " : could not publish nick " ) ;
2015-10-29 12:41:08 +00:00
}
} ) ;
}
}
2016-05-19 08:41:56 +00:00
public ServiceDiscoveryResult getCachedServiceDiscoveryResult ( Pair < String , String > key ) {
2016-02-03 09:40:02 +00: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 ) {
2017-10-28 15:49:51 +00:00
final Pair < String , String > key = new Pair < > ( presence . getHash ( ) , presence . getVer ( ) ) ;
2016-02-03 09:40:02 +00:00
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 ) ;
2018-04-22 09:07:00 +00:00
final String node = presence . getNode ( ) ;
final String ver = presence . getVer ( ) ;
final Element query = request . query ( " http://jabber.org/protocol/disco#info " ) ;
if ( node ! = null & & ver ! = null ) {
query . setAttribute ( " node " , node + " # " + ver ) ;
}
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : making disco request for " + key . second + " to " + jid ) ;
sendIqPacket ( account , request , ( a , response ) - > {
if ( response . getType ( ) = = IqPacket . TYPE . RESULT ) {
ServiceDiscoveryResult discoveryResult = new ServiceDiscoveryResult ( response ) ;
if ( presence . getVer ( ) . equals ( discoveryResult . getVer ( ) ) ) {
databaseBackend . insertDiscoveryResult ( discoveryResult ) ;
injectServiceDiscorveryResult ( a . getRoster ( ) , presence . getHash ( ) , presence . getVer ( ) , discoveryResult ) ;
2018-03-18 09:30:15 +00:00
} else {
2018-04-22 09:07:00 +00:00
Log . d ( Config . LOGTAG , a . getJid ( ) . asBareJid ( ) + " : mismatch in caps for contact " + jid + " " + presence . getVer ( ) + " vs " + discoveryResult . getVer ( ) ) ;
2016-02-03 09:40:02 +00:00
}
}
2018-04-14 16:43:11 +00:00
a . inProgressDiscoFetches . remove ( key ) ;
2016-02-03 09:40:02 +00:00
} ) ;
}
}
}
private void injectServiceDiscorveryResult ( Roster roster , String hash , String ver , ServiceDiscoveryResult disco ) {
2017-10-28 15:49:51 +00:00
for ( Contact contact : roster . getContacts ( ) ) {
for ( Presence presence : contact . getPresences ( ) . getPresences ( ) . values ( ) ) {
2016-02-03 09:40:02 +00:00
if ( hash . equals ( presence . getHash ( ) ) & & ver . equals ( presence . getVer ( ) ) ) {
presence . setServiceDiscoveryResult ( disco ) ;
}
}
}
}
2016-02-09 12:01:17 +00:00
public void fetchMamPreferences ( Account account , final OnMamPreferencesFetched callback ) {
2017-02-19 13:47:57 +00:00
final boolean legacy = account . getXmppConnection ( ) . getFeatures ( ) . mamLegacy ( ) ;
2016-02-09 12:01:17 +00:00
IqPacket request = new IqPacket ( IqPacket . TYPE . GET ) ;
2017-10-28 15:49:51 +00:00
request . addChild ( " prefs " , legacy ? Namespace . MAM_LEGACY : Namespace . MAM ) ;
2018-03-18 09:30:15 +00:00
sendIqPacket ( account , request , ( account1 , packet ) - > {
Element prefs = packet . findChild ( " prefs " , legacy ? Namespace . MAM_LEGACY : Namespace . MAM ) ;
if ( packet . getType ( ) = = IqPacket . TYPE . RESULT & & prefs ! = null ) {
callback . onPreferencesFetched ( prefs ) ;
} else {
callback . onPreferencesFetchFailed ( ) ;
2016-02-09 12:01:17 +00:00
}
} ) ;
}
2016-02-12 10:39:27 +00:00
public PushManagementService getPushManagementService ( ) {
return mPushManagementService ;
}
2016-04-19 16:03:24 +00:00
public Account getPendingAccount ( ) {
Account pending = null ;
2017-10-28 15:49:51 +00:00
for ( Account account : getAccounts ( ) ) {
2018-02-24 19:19:35 +00:00
if ( ! account . isOptionSet ( Account . OPTION_LOGGED_IN_SUCCESSFULLY ) ) {
2016-04-19 16:03:24 +00:00
pending = account ;
} else {
return null ;
}
}
return pending ;
}
2018-03-04 10:43:58 +00:00
public void changeStatus ( Account account , PresenceTemplate template , String signature ) {
if ( ! template . getStatusMessage ( ) . isEmpty ( ) ) {
databaseBackend . insertPresenceTemplate ( template ) ;
2016-04-23 13:10:35 +00:00
}
2018-03-04 10:43:58 +00:00
account . setPgpSignature ( signature ) ;
account . setPresenceStatus ( template . getStatus ( ) ) ;
account . setPresenceStatusMessage ( template . getStatusMessage ( ) ) ;
2016-04-22 19:25:06 +00:00
databaseBackend . updateAccount ( account ) ;
2018-03-04 10:43:58 +00:00
sendPresence ( account ) ;
2016-04-22 19:25:06 +00:00
}
2016-05-13 08:45:30 +00:00
public List < PresenceTemplate > getPresenceTemplates ( Account account ) {
List < PresenceTemplate > templates = databaseBackend . getPresenceTemplates ( ) ;
2017-10-28 15:49:51 +00:00
for ( PresenceTemplate template : account . getSelfContact ( ) . getPresences ( ) . asTemplates ( ) ) {
2016-05-13 08:45:30 +00:00
if ( ! templates . contains ( template ) ) {
templates . add ( 0 , template ) ;
}
}
return templates ;
}
2016-05-26 20:53:55 +00:00
public void saveConversationAsBookmark ( Conversation conversation , String name ) {
Account account = conversation . getAccount ( ) ;
2018-03-05 17:30:40 +00:00
Bookmark bookmark = new Bookmark ( account , conversation . getJid ( ) . asBareJid ( ) ) ;
2016-05-26 20:53:55 +00:00
if ( ! conversation . getJid ( ) . isBareJid ( ) ) {
2018-03-05 17:30:40 +00:00
bookmark . setNick ( conversation . getJid ( ) . getResource ( ) ) ;
2016-05-26 20:53:55 +00:00
}
if ( name ! = null & & ! name . trim ( ) . isEmpty ( ) ) {
bookmark . setBookmarkName ( name . trim ( ) ) ;
}
2017-10-28 15:49:51 +00:00
bookmark . setAutojoin ( getPreferences ( ) . getBoolean ( " autojoin " , getResources ( ) . getBoolean ( R . bool . autojoin ) ) ) ;
2016-05-26 20:53:55 +00:00
account . getBookmarks ( ) . add ( bookmark ) ;
pushBookmarks ( account ) ;
2018-02-10 18:06:31 +00:00
bookmark . setConversation ( conversation ) ;
2016-05-26 20:53:55 +00:00
}
2016-11-22 11:03:21 +00:00
public boolean verifyFingerprints ( Contact contact , List < XmppUri . Fingerprint > fingerprints ) {
boolean performedVerification = false ;
2016-11-17 19:09:42 +00:00
final AxolotlService axolotlService = contact . getAccount ( ) . getAxolotlService ( ) ;
2017-10-28 15:49:51 +00:00
for ( XmppUri . Fingerprint fp : fingerprints ) {
2018-02-19 12:55:48 +00:00
if ( fp . type = = XmppUri . FingerprintType . OMEMO ) {
2017-10-28 15:49:51 +00:00
String fingerprint = " 05 " + fp . fingerprint . replaceAll ( " \\ s " , " " ) ;
2016-11-17 19:09:42 +00:00
FingerprintStatus fingerprintStatus = axolotlService . getFingerprintTrust ( fingerprint ) ;
if ( fingerprintStatus ! = null ) {
if ( ! fingerprintStatus . isVerified ( ) ) {
2016-11-22 11:03:21 +00:00
performedVerification = true ;
2017-10-28 15:49:51 +00:00
axolotlService . setFingerprintTrust ( fingerprint , fingerprintStatus . toVerified ( ) ) ;
2016-11-17 19:09:42 +00:00
}
} else {
2017-10-28 15:49:51 +00:00
axolotlService . preVerifyFingerprint ( contact , fingerprint ) ;
2016-11-17 19:09:42 +00:00
}
}
}
2016-11-22 11:03:21 +00:00
return performedVerification ;
2016-11-17 19:09:42 +00:00
}
2016-11-17 21:28:45 +00:00
public boolean verifyFingerprints ( Account account , List < XmppUri . Fingerprint > fingerprints ) {
final AxolotlService axolotlService = account . getAxolotlService ( ) ;
boolean verifiedSomething = false ;
2017-10-28 15:49:51 +00:00
for ( XmppUri . Fingerprint fp : fingerprints ) {
2016-11-17 21:28:45 +00:00
if ( fp . type = = XmppUri . FingerprintType . OMEMO ) {
2017-10-28 15:49:51 +00:00
String fingerprint = " 05 " + fp . fingerprint . replaceAll ( " \\ s " , " " ) ;
Log . d ( Config . LOGTAG , " trying to verify own fp= " + fingerprint ) ;
2016-11-17 21:28:45 +00:00
FingerprintStatus fingerprintStatus = axolotlService . getFingerprintTrust ( fingerprint ) ;
if ( fingerprintStatus ! = null ) {
if ( ! fingerprintStatus . isVerified ( ) ) {
2017-10-28 15:49:51 +00:00
axolotlService . setFingerprintTrust ( fingerprint , fingerprintStatus . toVerified ( ) ) ;
2016-11-17 21:28:45 +00:00
verifiedSomething = true ;
}
} else {
2017-10-28 15:49:51 +00:00
axolotlService . preVerifyFingerprint ( account , fingerprint ) ;
2016-11-17 21:28:45 +00:00
verifiedSomething = true ;
}
}
}
return verifiedSomething ;
}
2016-11-23 09:42:27 +00:00
public boolean blindTrustBeforeVerification ( ) {
2017-10-28 15:49:51 +00:00
return getBooleanPreference ( SettingsActivity . BLIND_TRUST_BEFORE_VERIFICATION , R . bool . btbv ) ;
2016-11-23 09:42:27 +00:00
}
2017-05-31 14:45:51 +00:00
public ShortcutService getShortcutService ( ) {
return mShortcutService ;
}
2016-02-09 12:01:17 +00:00
public void pushMamPreferences ( Account account , Element prefs ) {
IqPacket set = new IqPacket ( IqPacket . TYPE . SET ) ;
set . addChild ( prefs ) ;
sendIqPacket ( account , set , null ) ;
}
2018-03-18 09:30:15 +00:00
public interface OnMamPreferencesFetched {
void onPreferencesFetched ( Element prefs ) ;
void onPreferencesFetchFailed ( ) ;
}
2015-10-09 11:37:08 +00:00
public interface OnAccountCreated {
void onAccountCreated ( Account account ) ;
2015-10-16 07:58:31 +00:00
2015-10-09 11:37:08 +00:00
void informUser ( int r ) ;
}
2015-01-19 10:17:27 +00:00
public interface OnMoreMessagesLoaded {
2015-10-09 11:37:08 +00:00
void onMoreMessagesLoaded ( int count , Conversation conversation ) ;
2015-01-19 10:17:27 +00:00
2015-10-09 11:37:08 +00:00
void informUser ( int r ) ;
2015-01-19 10:17:27 +00:00
}
public interface OnAccountPasswordChanged {
2015-10-09 11:37:08 +00:00
void onPasswordChangeSucceeded ( ) ;
2015-01-19 10:17:27 +00:00
2015-10-09 11:37:08 +00:00
void onPasswordChangeFailed ( ) ;
2015-01-19 10:17:27 +00:00
}
public interface OnAffiliationChanged {
2015-10-09 11:37:08 +00:00
void onAffiliationChangedSuccessful ( Jid jid ) ;
2015-01-19 10:17:27 +00:00
2015-10-09 11:37:08 +00:00
void onAffiliationChangeFailed ( Jid jid , int resId ) ;
2015-01-19 10:17:27 +00:00
}
public interface OnRoleChanged {
2015-10-09 11:37:08 +00:00
void onRoleChangedSuccessful ( String nick ) ;
2015-01-19 10:17:27 +00:00
2015-10-09 11:37:08 +00:00
void onRoleChangeFailed ( String nick , int resid ) ;
2015-01-19 10:17:27 +00:00
}
public interface OnConversationUpdate {
2015-10-09 11:37:08 +00:00
void onConversationUpdate ( ) ;
2015-01-19 10:17:27 +00:00
}
public interface OnAccountUpdate {
2015-10-09 11:37:08 +00:00
void onAccountUpdate ( ) ;
2015-01-19 10:17:27 +00:00
}
2015-10-11 11:11:50 +00:00
public interface OnCaptchaRequested {
2018-03-18 09:30:15 +00:00
void onCaptchaRequested ( Account account , String id , Data data , Bitmap captcha ) ;
2015-10-11 11:11:50 +00:00
}
2015-01-19 10:17:27 +00:00
public interface OnRosterUpdate {
2015-10-09 11:37:08 +00:00
void onRosterUpdate ( ) ;
2015-01-19 10:17:27 +00:00
}
public interface OnMucRosterUpdate {
2015-10-09 11:37:08 +00:00
void onMucRosterUpdate ( ) ;
2015-01-19 10:17:27 +00:00
}
2015-10-04 22:45:16 +00:00
public interface OnConferenceConfigurationFetched {
2015-10-09 11:37:08 +00:00
void onConferenceConfigurationFetched ( Conversation conversation ) ;
2015-10-22 09:20:36 +00:00
void onFetchFailed ( Conversation conversation , Element error ) ;
2015-10-04 22:45:16 +00:00
}
2015-11-25 19:47:02 +00:00
public interface OnConferenceJoined {
void onConferenceJoined ( Conversation conversation ) ;
}
2017-02-24 18:58:46 +00:00
public interface OnConfigurationPushed {
2015-10-09 11:37:08 +00:00
void onPushSucceeded ( ) ;
2015-01-19 10:17:27 +00:00
2015-10-09 11:37:08 +00:00
void onPushFailed ( ) ;
2015-01-19 10:17:27 +00:00
}
2015-07-10 11:28:50 +00:00
public interface OnShowErrorToast {
void onShowErrorToast ( int resId ) ;
}
2015-01-19 10:17:27 +00:00
public class XmppConnectionBinder extends Binder {
public XmppConnectionService getService ( ) {
return XmppConnectionService . this ;
}
}
2014-04-07 21:58:59 +00:00
}