diff options
Diffstat (limited to 'src/main')
12 files changed, 291 insertions, 69 deletions
diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 125facf07..f7ed9f96d 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -37,6 +37,8 @@ public final class Config { public static final int CARBON_GRACE_PERIOD = 90; public static final int MINI_GRACE_PERIOD = 750; + public static final boolean CLOSE_TCP_WHEN_SWITCHING_TO_BACKGROUND = false; + public static final int AVATAR_SIZE = 640; public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.WEBP; @@ -118,6 +120,5 @@ public final class Config { }; private Config() { - } } diff --git a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java index 835eef36b..b9c95e6e5 100644 --- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java @@ -15,6 +15,8 @@ import java.util.TimeZone; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.PhoneHelper; +import eu.siacs.conversations.xmpp.jid.Jid; +import eu.siacs.conversations.xmpp.stanzas.IqPacket; public abstract class AbstractGenerator { private final String[] FEATURES = { diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 3b9f8ce06..bb373c75c 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -25,6 +25,7 @@ import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.Xmlns; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.forms.Data; +import eu.siacs.conversations.xmpp.forms.Field; import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.pep.Avatar; import eu.siacs.conversations.xmpp.stanzas.IqPacket; @@ -290,7 +291,7 @@ public class IqGenerator extends AbstractGenerator { public IqPacket requestHttpUploadSlot(Jid host, DownloadableFile file, String mime) { IqPacket packet = new IqPacket(IqPacket.TYPE.GET); packet.setTo(host); - Element request = packet.addChild("request",Xmlns.HTTP_UPLOAD); + Element request = packet.addChild("request", Xmlns.HTTP_UPLOAD); request.addChild("filename").setContent(file.getName()); request.addChild("size").setContent(String.valueOf(file.getExpectedSize())); if (mime != null) { @@ -308,4 +309,30 @@ public class IqGenerator extends AbstractGenerator { return register; } + + public IqPacket pushTokenToAppServer(Jid appServer, String token, String deviceId) { + IqPacket packet = new IqPacket(IqPacket.TYPE.SET); + packet.setTo(appServer); + Element command = packet.addChild("command", "http://jabber.org/protocol/commands"); + command.setAttribute("node","register-push-gcm"); + command.setAttribute("action","execute"); + Data data = new Data(); + data.put("token", token); + data.put("device-id", deviceId); + data.submit(); + command.addChild(data); + return packet; + } + + public IqPacket enablePush(Jid jid, String node, String secret) { + IqPacket packet = new IqPacket(IqPacket.TYPE.SET); + Element enable = packet.addChild("enable","urn:xmpp:push:0"); + enable.setAttribute("jid",jid.toString()); + enable.setAttribute("node", node); + Data data = new Data(); + data.setFormType("http://jabber.org/protocol/pubsub#publish-options"); + data.put("secret",secret); + enable.addChild(data); + return packet; + } } diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java index 09bbabebe..5903d5116 100644 --- a/src/main/java/eu/siacs/conversations/parser/IqParser.java +++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java @@ -6,7 +6,6 @@ import android.util.Log; import android.util.Pair; import org.whispersystems.libaxolotl.IdentityKey; -import org.whispersystems.libaxolotl.InvalidKeyException; import org.whispersystems.libaxolotl.ecc.Curve; import org.whispersystems.libaxolotl.ecc.ECPublicKey; import org.whispersystems.libaxolotl.state.PreKeyBundle; @@ -142,7 +141,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { } try { publicKey = Curve.decodePoint(Base64.decode(signedPreKeyPublic.getContent(),Base64.DEFAULT), 0); - } catch (InvalidKeyException | IllegalArgumentException | NullPointerException e) { + } catch (Throwable e) { Log.e(Config.LOGTAG, AxolotlService.LOGPREFIX+" : "+"Invalid signedPreKeyPublic in PEP: " + e.getMessage()); } return publicKey; @@ -155,7 +154,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { } try { return Base64.decode(signedPreKeySignature.getContent(), Base64.DEFAULT); - } catch (IllegalArgumentException e) { + } catch (Throwable e) { Log.e(Config.LOGTAG,AxolotlService.LOGPREFIX+" : Invalid base64 in signedPreKeySignature"); return null; } @@ -169,7 +168,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { } try { identityKey = new IdentityKey(Base64.decode(identityKeyElement.getContent(), Base64.DEFAULT), 0); - } catch (InvalidKeyException | IllegalArgumentException | NullPointerException e) { + } catch (Throwable e) { Log.e(Config.LOGTAG,AxolotlService.LOGPREFIX+" : "+"Invalid identityKey in PEP: "+e.getMessage()); } return identityKey; @@ -200,7 +199,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { try { ECPublicKey preKeyPublic = Curve.decodePoint(Base64.decode(preKeyPublicElement.getContent(), Base64.DEFAULT), 0); preKeyRecords.put(preKeyId, preKeyPublic); - } catch (InvalidKeyException | IllegalArgumentException | NullPointerException e) { + } catch (Throwable e) { Log.e(Config.LOGTAG, AxolotlService.LOGPREFIX+" : "+"Invalid preKeyPublic (ID="+preKeyId+") in PEP: "+ e.getMessage()+", skipping..."); continue; } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 4fa5ddfff..16d7f139c 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -73,7 +73,6 @@ import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.MucOptions.OnRenameListener; import eu.siacs.conversations.entities.Presence; -import eu.siacs.conversations.entities.Presences; import eu.siacs.conversations.entities.Roster; import eu.siacs.conversations.entities.ServiceDiscoveryResult; import eu.siacs.conversations.entities.Transferable; @@ -127,6 +126,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa public static final String ACTION_TRY_AGAIN = "try_again"; public static final String ACTION_DISABLE_ACCOUNT = "disable_account"; private static final String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts"; + public static final String ACTION_GCM_TOKEN_REFRESH = "gcm_token_refresh"; + public static final String ACTION_GCM_MESSAGE_RECEIVED = "gcm_message_received"; private final SerialSingleThreadExecutor mFileAddingExecutor = new SerialSingleThreadExecutor(); private final SerialSingleThreadExecutor mDatabaseExecutor = new SerialSingleThreadExecutor(); private final IBinder mBinder = new XmppConnectionBinder(); @@ -198,6 +199,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa this); private AvatarService mAvatarService = new AvatarService(this); private MessageArchiveService mMessageArchiveService = new MessageArchiveService(this); + private PushManagementService mPushManagementService = new PushManagementService(this); private OnConversationUpdate mOnConversationUpdate = null; private final FileObserver fileObserver = new FileObserver( FileBackend.getConversationsImageDirectory()) { @@ -257,6 +259,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa fetchRosterFromServer(account); fetchBookmarks(account); sendPresence(account); + if (mPushManagementService.available(account)) { + mPushManagementService.registerPushTokenOnServer(account); + } mMessageArchiveService.executePendingQueries(account); connectMultiModeConversations(account); syncDirtyContacts(account); @@ -265,7 +270,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa private OnStatusChanged statusListener = new OnStatusChanged() { @Override - public void onStatusChanged(Account account) { + public void onStatusChanged(final Account account) { XmppConnection connection = account.getXmppConnection(); if (mOnAccountUpdate != null) { mOnAccountUpdate.onAccountUpdate(); @@ -282,7 +287,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } List<Conversation> conversations = getConversations(); for (Conversation conversation : conversations) { - if (conversation.getAccount() == account) { + if (conversation.getAccount() == account && conversation.getMode() == Conversation.MODE_SINGLE) { conversation.startOtrIfNeeded(); sendUnsentMessages(conversation); } @@ -298,7 +303,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa scheduleWakeUpCall(Config.PING_MAX_INTERVAL, account.getUuid().hashCode()); } else if (account.getStatus() == Account.State.OFFLINE) { resetSendingToWaiting(account); - if (!account.isOptionSet(Account.OPTION_DISABLED)) { + final boolean disabled = account.isOptionSet(Account.OPTION_DISABLED); + final boolean pushMode = Config.CLOSE_TCP_WHEN_SWITCHING_TO_BACKGROUND + && mPushManagementService.available(account) + && checkListeners(); + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": push mode "+Boolean.toString(pushMode)); + if (!disabled && !pushMode) { int timeToReconnect = mRandom.nextInt(20) + 10; scheduleWakeUpCall(timeToReconnect, account.getUuid().hashCode()); } @@ -464,6 +474,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa final String action = intent == null ? null : intent.getAction(); boolean interactive = false; if (action != null) { + Log.d(Config.LOGTAG,"start reason: "+action); switch (action) { case ConnectivityManager.CONNECTIVITY_ACTION: if (hasInternetConnection() && Config.RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE) { @@ -512,6 +523,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa refreshAllPresences(); } break; + case ACTION_GCM_TOKEN_REFRESH: + refreshAllGcmTokens(); + break; + case ACTION_GCM_MESSAGE_RECEIVED: + Log.d(Config.LOGTAG,"gcm push message arrived in service. extras="+intent.getExtras()); } } this.wakeLock.acquire(); @@ -572,7 +588,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa reconnectAccount(account, true, interactive); } } - } if (mOnAccountUpdate != null) { mOnAccountUpdate.onAccountUpdate(); @@ -753,18 +768,20 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa disconnect(account, false); } }).start(); - + cancelWakeUpCall(account.getUuid().hashCode()); } } - Context context = getApplicationContext(); - AlarmManager alarmManager = (AlarmManager) context - .getSystemService(Context.ALARM_SERVICE); - Intent intent = new Intent(context, EventReceiver.class); - alarmManager.cancel(PendingIntent.getBroadcast(context, 0, intent, 0)); Log.d(Config.LOGTAG, "good bye"); stopSelf(); } + private void cancelWakeUpCall(int requestCode) { + final AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); + final Intent intent = new Intent(this, EventReceiver.class); + intent.setAction("ping"); + alarmManager.cancel(PendingIntent.getBroadcast(this, requestCode, intent, 0)); + } + public void scheduleWakeUpCall(int seconds, int requestCode) { final long timeToWake = SystemClock.elapsedRealtime() + (seconds < 0 ? 1 : seconds + 1) * 1000; @@ -1710,8 +1727,14 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa for (Account account : getAccounts()) { if (account.getStatus() == Account.State.ONLINE) { XmppConnection connection = account.getXmppConnection(); - if (connection != null && connection.getFeatures().csi()) { - connection.sendInactive(); + if (connection != null) { + if (connection.getFeatures().csi()) { + connection.sendInactive(); + } + if (Config.CLOSE_TCP_WHEN_SWITCHING_TO_BACKGROUND && mPushManagementService.available(account)) { + connection.waitForPush(); + cancelWakeUpCall(account.getUuid().hashCode()); + } } } } @@ -1776,6 +1799,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa if (conversation.getMucOptions().mamSupport()) { getMessageArchiveService().catchupMUC(conversation); } + sendUnsentMessages(conversation); } @Override @@ -2844,6 +2868,14 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } + private void refreshAllGcmTokens() { + for(Account account : getAccounts()) { + if (account.isOnlineAndConnected() && mPushManagementService.available(account)) { + mPushManagementService.registerPushTokenOnServer(account); + } + } + } + public void sendOfflinePresence(final Account account) { sendPresencePacket(account, mPresenceGenerator.sendOfflinePresence(account)); } @@ -3004,7 +3036,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa databaseBackend.insertDiscoveryResult(disco); injectServiceDiscorveryResult(account.getRoster(), presence.getHash(), presence.getVer(), disco); } else { - Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": mismatch in caps for contact " + jid+" "+presence.getVer()+" vs "+disco.getVer()); + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": mismatch in caps for contact " + jid + " " + presence.getVer() + " vs " + disco.getVer()); } } account.inProgressDiscoFetches.remove(key); @@ -3024,6 +3056,37 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } + public void fetchMamPreferences(Account account, final OnMamPreferencesFetched callback) { + IqPacket request = new IqPacket(IqPacket.TYPE.GET); + request.addChild("prefs","urn:xmpp:mam:0"); + sendIqPacket(account, request, new OnIqPacketReceived() { + @Override + public void onIqPacketReceived(Account account, IqPacket packet) { + Element prefs = packet.findChild("prefs","urn:xmpp:mam:0"); + if (packet.getType() == IqPacket.TYPE.RESULT && prefs != null) { + callback.onPreferencesFetched(prefs); + } else { + callback.onPreferencesFetchFailed(); + } + } + }); + } + + public PushManagementService getPushManagementService() { + return mPushManagementService; + } + + public interface OnMamPreferencesFetched { + void onPreferencesFetched(Element prefs); + void onPreferencesFetchFailed(); + } + + public void pushMamPreferences(Account account, Element prefs) { + IqPacket set = new IqPacket(IqPacket.TYPE.SET); + set.addChild(prefs); + sendIqPacket(account, set, null); + } + public interface OnAccountCreated { void onAccountCreated(Account account); diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index a126b344d..d3899c29f 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -29,11 +29,15 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TableLayout; +import android.widget.TableRow; import android.widget.TextView; import android.widget.Toast; -import eu.siacs.conversations.Config; import org.whispersystems.libaxolotl.IdentityKey; import java.util.Set; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; @@ -44,6 +48,7 @@ import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; import eu.siacs.conversations.ui.adapter.KnownHostsAdapter; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.UIHelper; +import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.XmppConnection.Features; import eu.siacs.conversations.xmpp.forms.Data; @@ -52,7 +57,7 @@ import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.pep.Avatar; public class EditAccountActivity extends XmppActivity implements OnAccountUpdate, - OnKeyStatusUpdated, OnCaptchaRequested, KeyChainAliasCallback, XmppConnectionService.OnShowErrorToast { + OnKeyStatusUpdated, OnCaptchaRequested, KeyChainAliasCallback, XmppConnectionService.OnShowErrorToast, XmppConnectionService.OnMamPreferencesFetched { private AutoCompleteTextView mAccountJid; private EditText mPassword; @@ -73,6 +78,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate private TextView mServerInfoBlocking; private TextView mServerInfoPep; private TextView mServerInfoHttpUpload; + private TextView mServerInfoPush; private TextView mSessionEst; private TextView mOtrFingerprint; private TextView mAxolotlFingerprint; @@ -218,6 +224,8 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate finish(); } }; + private Toast mFetchingMamPrefsToast; + private TableRow mPushRow; public void refreshUiReal() { invalidateOptionsMenu(); @@ -417,6 +425,8 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mServerInfoSm = (TextView) findViewById(R.id.server_info_sm); this.mServerInfoPep = (TextView) findViewById(R.id.server_info_pep); this.mServerInfoHttpUpload = (TextView) findViewById(R.id.server_info_http_upload); + this.mPushRow = (TableRow) findViewById(R.id.push_row); + this.mServerInfoPush = (TextView) findViewById(R.id.server_info_push); this.mOtrFingerprint = (TextView) findViewById(R.id.otr_fingerprint); this.mOtrFingerprintBox = (RelativeLayout) findViewById(R.id.otr_fingerprint_box); this.mOtrFingerprintToClipboardButton = (ImageButton) findViewById(R.id.action_copy_to_clipboard); @@ -465,6 +475,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate final MenuItem changePassword = menu.findItem(R.id.action_change_password_on_server); final MenuItem clearDevices = menu.findItem(R.id.action_clear_devices); final MenuItem renewCertificate = menu.findItem(R.id.action_renew_certificate); + final MenuItem mamPrefs = menu.findItem(R.id.action_mam_prefs); renewCertificate.setVisible(mAccount != null && mAccount.getPrivateKeyAlias() != null); @@ -475,6 +486,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate if (!mAccount.getXmppConnection().getFeatures().register()) { changePassword.setVisible(false); } + mamPrefs.setVisible(mAccount.getXmppConnection().getFeatures().mam()); Set<Integer> otherDevices = mAccount.getAxolotlService().getOwnDeviceIds(); if (otherDevices == null || otherDevices.isEmpty()) { clearDevices.setVisible(false); @@ -485,6 +497,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate showMoreInfo.setVisible(false); changePassword.setVisible(false); clearDevices.setVisible(false); + mamPrefs.setVisible(false); } return true; } @@ -568,6 +581,9 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate changePasswordIntent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toString()); startActivity(changePasswordIntent); break; + case R.id.action_mam_prefs: + editMamPrefs(); + break; case R.id.action_clear_devices: showWipePepDialog(); break; @@ -669,6 +685,14 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } else { this.mServerInfoHttpUpload.setText(R.string.server_info_unavailable); } + + this.mPushRow.setVisibility(xmppConnectionService.getPushManagementService().available(mAccount) ? View.VISIBLE : View.GONE); + + if (features.push()) { + this.mServerInfoPush.setText(R.string.server_info_available); + } else { + this.mServerInfoPush.setText(R.string.server_info_unavailable); + } final String otrFingerprint = this.mAccount.getOtrFingerprint(); if (otrFingerprint != null) { this.mOtrFingerprintBox.setVisibility(View.VISIBLE); @@ -799,6 +823,12 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate builder.create().show(); } + private void editMamPrefs() { + this.mFetchingMamPrefsToast = Toast.makeText(this, R.string.fetching_mam_prefs, Toast.LENGTH_LONG); + this.mFetchingMamPrefsToast.show(); + xmppConnectionService.fetchMamPreferences(mAccount, this); + } + @Override public void onKeyStatusUpdated(AxolotlService.FetchStatus report) { refreshUi(); @@ -878,4 +908,49 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } }); } + + @Override + public void onPreferencesFetched(final Element prefs) { + runOnUiThread(new Runnable() { + @Override + public void run() { + if (mFetchingMamPrefsToast != null) { + mFetchingMamPrefsToast.cancel(); + } + AlertDialog.Builder builder = new Builder(EditAccountActivity.this); + builder.setTitle(R.string.mam_prefs); + String defaultAttr = prefs.getAttribute("default"); + final List<String> defaults = Arrays.asList("never", "roster", "always"); + final AtomicInteger choice = new AtomicInteger(Math.max(0,defaults.indexOf(defaultAttr))); + builder.setSingleChoiceItems(R.array.mam_prefs, choice.get(), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + choice.set(which); + } + }); + builder.setNegativeButton(R.string.cancel, null); + builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + prefs.setAttribute("default",defaults.get(choice.get())); + xmppConnectionService.pushMamPreferences(mAccount, prefs); + } + }); + builder.create().show(); + } + }); + } + + @Override + public void onPreferencesFetchFailed() { + runOnUiThread(new Runnable() { + @Override + public void run() { + if (mFetchingMamPrefsToast != null) { + mFetchingMamPrefsToast.cancel(); + } + Toast.makeText(EditAccountActivity.this,R.string.unable_to_fetch_mam_prefs,Toast.LENGTH_LONG).show(); + } + }); + } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 7f987ae9f..3ddad1fdb 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -61,7 +61,6 @@ import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.ServiceDiscoveryResult; import eu.siacs.conversations.generator.IqGenerator; import eu.siacs.conversations.services.XmppConnectionService; -import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.DNSHelper; import eu.siacs.conversations.utils.SSLSocketHelper; import eu.siacs.conversations.utils.SocksSocketFactory; @@ -352,13 +351,7 @@ public class XmppConnection implements Runnable { this.changeStatus(Account.State.OFFLINE); this.attempt--; //don't count attempt when reconnecting instantly anyway } finally { - if (socket != null) { - try { - socket.close(); - } catch (IOException e) { - - } - } + forceCloseSocket(); if (wakeLock.isHeld()) { try { wakeLock.release(); @@ -430,13 +423,7 @@ public class XmppConnection implements Runnable { @Override public void run() { - try { - if (socket != null) { - socket.close(); - } - } catch (final IOException ignored) { - - } + forceCloseSocket(); connect(); } @@ -1283,14 +1270,45 @@ public class XmppConnection implements Runnable { } } - public void disconnect(final boolean force) { - Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting force="+Boolean.valueOf(force)); - if (force) { + public void waitForPush() { + if (tagWriter.isActive()) { + tagWriter.finish(); + new Thread(new Runnable() { + @Override + public void run() { + try { + while(!tagWriter.finished()) { + Thread.sleep(10); + } + socket.close(); + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": closed tcp without closing stream"); + } catch (IOException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }).start(); + } else { + forceCloseSocket(); + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": closed tcp without closing stream (no waiting)"); + } + } + + private void forceCloseSocket() { + if (socket != null) { try { socket.close(); - } catch(Exception e) { - Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": exception during force close ("+e.getMessage()+")"); + } catch (IOException e) { + e.printStackTrace(); } + } + } + + public void disconnect(final boolean force) { + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting force="+Boolean.valueOf(force)); + if (force) { + forceCloseSocket(); return; } else { if (tagWriter.isActive()) { @@ -1495,17 +1513,13 @@ public class XmppConnection implements Runnable { } public boolean mam() { - if (hasDiscoFeature(account.getJid().toBareJid(), "urn:xmpp:mam:0")) { - return true; - } else { - return hasDiscoFeature(account.getServer(), "urn:xmpp:mam:0"); - } + return hasDiscoFeature(account.getJid().toBareJid(), "urn:xmpp:mam:0") + || hasDiscoFeature(account.getServer(), "urn:xmpp:mam:0"); } - public boolean advancedStreamFeaturesLoaded() { - synchronized (XmppConnection.this.disco) { - return disco.containsKey(account.getServer()); - } + public boolean push() { + return hasDiscoFeature(account.getJid().toBareJid(), "urn:xmpp:push:0") + || hasDiscoFeature(account.getServer(), "urn:xmpp:push:0"); } public boolean rosterVersioning() { diff --git a/src/main/java/eu/siacs/conversations/xmpp/forms/Data.java b/src/main/java/eu/siacs/conversations/xmpp/forms/Data.java index 50a418921..380f02808 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/forms/Data.java +++ b/src/main/java/eu/siacs/conversations/xmpp/forms/Data.java @@ -80,8 +80,13 @@ public class Data extends Element { } public String getFormType() { - Field typeFiled = this.getFieldByName("FORM_TYPE"); - return typeFiled == null ? "" : typeFiled.getValue(); + String type = getValue("FORM_TYPE"); + return type == null ? "" : type; + } + + public String getValue(String name) { + Field field = this.getFieldByName(name); + return field == null ? null : field.getValue(); } public String getTitle() { diff --git a/src/main/res/layout/activity_edit_account.xml b/src/main/res/layout/activity_edit_account.xml index b3b939624..8038e633a 100644 --- a/src/main/res/layout/activity_edit_account.xml +++ b/src/main/res/layout/activity_edit_account.xml @@ -416,6 +416,26 @@ </TableRow> <TableRow + android:id="@+id/push_row" + android:layout_width="fill_parent" + android:layout_height="wrap_content"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/server_info_push" + android:textColor="@color/black87" + android:textSize="?attr/TextSizeBody"/> + + <TextView + android:id="@+id/server_info_push" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="right" + android:textColor="@color/black87" + android:textSize="?attr/TextSizeBody"/> + </TableRow> + <TableRow android:layout_width="fill_parent" android:layout_height="wrap_content"> @@ -434,6 +454,7 @@ android:textColor="@color/black87" android:textSize="?attr/TextSizeBody" tools:ignore="RtlHardcoded" /> + </TableRow> </TableLayout> diff --git a/src/main/res/menu/editaccount.xml b/src/main/res/menu/editaccount.xml index b7a404182..9f06fc4c4 100644 --- a/src/main/res/menu/editaccount.xml +++ b/src/main/res/menu/editaccount.xml @@ -2,35 +2,40 @@ <item android:id="@+id/action_show_qr_code" - android:title="@string/show_qr_code" - android:showAsAction="never" /> + android:showAsAction="never" + android:title="@string/show_qr_code"/> <item android:id="@+id/action_show_block_list" - android:title="@string/show_block_list" - android:showAsAction="never" /> + android:showAsAction="never" + android:title="@string/show_block_list"/> <item android:id="@+id/action_renew_certificate" + android:showAsAction="never" android:title="@string/action_renew_certificate" - android:visible="false" - android:showAsAction="never" /> - /> + android:visible="false"/> <item android:id="@+id/action_server_info_show_more" - android:title="@string/server_info_show_more" android:checkable="true" android:checked="false" - android:showAsAction="never" /> + android:showAsAction="never" + android:title="@string/server_info_show_more"/> + + <item + android:id="@+id/action_mam_prefs" + android:title="@string/mam_prefs"/> - <item android:id="@+id/action_change_password_on_server" - android:title="@string/change_password" - android:showAsAction="never" /> + <item + android:id="@+id/action_change_password_on_server" + android:showAsAction="never" + android:title="@string/change_password"/> - <item android:id="@+id/action_clear_devices" - android:title="@string/clear_other_devices" - android:showAsAction="never"/> + <item + android:id="@+id/action_clear_devices" + android:showAsAction="never" + android:title="@string/clear_other_devices"/> <item android:id="@+id/action_settings" android:orderInCategory="100" diff --git a/src/main/res/values/arrays.xml b/src/main/res/values/arrays.xml index 0f2dbb1a4..cc04d98ba 100644 --- a/src/main/res/values/arrays.xml +++ b/src/main/res/values/arrays.xml @@ -69,4 +69,10 @@ <item>@string/automatically</item> <item>@string/always</item> </string-array> + + <string-array name="mam_prefs"> + <item>@string/never</item> + <item>@string/contacts</item> + <item>@string/always</item> + </string-array> </resources> diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 081dc8779..404e7a02a 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -193,6 +193,7 @@ <string name="server_info_stream_management">XEP-0198: Stream Management</string> <string name="server_info_pep">XEP-0163: PEP (Avatars / OMEMO)</string> <string name="server_info_http_upload">XEP-0363: HTTP File Upload</string> + <string name="server_info_push">XEP-0357: Push</string> <string name="server_info_available">available</string> <string name="server_info_unavailable">unavailable</string> <string name="missing_public_keys">Missing public key announcements</string> @@ -552,6 +553,9 @@ <string name="action_add_account_with_certificate">Add account with certificate</string> <string name="unable_to_parse_certificate">Unable to parse certificate</string> <string name="authenticate_with_certificate">Leave empty to authenticate w/ certificate</string> + <string name="mam_prefs">Archiving preferences</string> + <string name="fetching_mam_prefs">Fetching archiving preferences. Please wait…</string> + <string name="unable_to_fetch_mam_prefs">Unable to fetch archiving preferences</string> <string name="captcha_ocr">Captcha text</string> <string name="captcha_required">Captcha required</string> <string name="captcha_hint">enter the text from the image</string> |