configurable local message retention period. (untested)
This commit is contained in:
parent
4c6ef3b24e
commit
9b6ae6d75f
|
@ -114,6 +114,8 @@ public final class Config {
|
||||||
public static final ChatState DEFAULT_CHATSTATE = ChatState.ACTIVE;
|
public static final ChatState DEFAULT_CHATSTATE = ChatState.ACTIVE;
|
||||||
public static final int TYPING_TIMEOUT = 8;
|
public static final int TYPING_TIMEOUT = 8;
|
||||||
|
|
||||||
|
public static final int EXPIRY_INTERVAL = 30 * 60 * 1000; // 30 minutes
|
||||||
|
|
||||||
public static final String ENABLED_CIPHERS[] = {
|
public static final String ENABLED_CIPHERS[] = {
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384",
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384",
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.ListIterator;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import eu.siacs.conversations.Config;
|
import eu.siacs.conversations.Config;
|
||||||
|
@ -930,6 +931,17 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
|
||||||
account.getPgpDecryptionService().decrypt(messages);
|
account.getPgpDecryptionService().decrypt(messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void expireOldMessages(long timestamp) {
|
||||||
|
synchronized (this.messages) {
|
||||||
|
for(ListIterator<Message> iterator = this.messages.listIterator(); iterator.hasNext();) {
|
||||||
|
if (iterator.next().getTimeSent() < timestamp) {
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
untieMessages();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void sort() {
|
public void sort() {
|
||||||
synchronized (this.messages) {
|
synchronized (this.messages) {
|
||||||
Collections.sort(this.messages, new Comparator<Message>() {
|
Collections.sort(this.messages, new Comparator<Message>() {
|
||||||
|
|
|
@ -521,6 +521,12 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long deletionDate = mXmppConnectionService.getAutomaticMessageDeletionDate();
|
||||||
|
if (deletionDate != 0 && message.getTimeSent() < deletionDate) {
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": skipping message from "+message.getCounterpart().toString()+" because it was sent prior to our deletion date");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
boolean checkForDuplicates = query != null
|
boolean checkForDuplicates = query != null
|
||||||
|| (isTypeGroupChat && packet.hasChild("delay","urn:xmpp:delay"))
|
|| (isTypeGroupChat && packet.hasChild("delay","urn:xmpp:delay"))
|
||||||
|| message.getType() == Message.TYPE_PRIVATE;
|
|| message.getType() == Message.TYPE_PRIVATE;
|
||||||
|
@ -570,9 +576,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
||||||
conversation.endOtrIfNeeded();
|
conversation.endOtrIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.getEncryption() == Message.ENCRYPTION_NONE || mXmppConnectionService.saveEncryptedMessages()) {
|
|
||||||
mXmppConnectionService.databaseBackend.createMessage(message);
|
mXmppConnectionService.databaseBackend.createMessage(message);
|
||||||
}
|
|
||||||
final HttpConnectionManager manager = this.mXmppConnectionService.getHttpConnectionManager();
|
final HttpConnectionManager manager = this.mXmppConnectionService.getHttpConnectionManager();
|
||||||
if (message.trusted() && message.treatAsDownloadable() != Message.Decision.NEVER && manager.getAutoAcceptFileSize() > 0) {
|
if (message.trusted() && message.treatAsDownloadable() != Message.Decision.NEVER && manager.getAutoAcceptFileSize() > 0) {
|
||||||
manager.createNewDownloadConnection(message);
|
manager.createNewDownloadConnection(message);
|
||||||
|
|
|
@ -769,6 +769,13 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
||||||
db.delete(Message.TABLENAME, Message.CONVERSATION + "=?", args);
|
db.delete(Message.TABLENAME, Message.CONVERSATION + "=?", args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean expireOldMessages(long timestamp) {
|
||||||
|
String where = Message.TIME_SENT+"<?";
|
||||||
|
String[] whereArgs = {String.valueOf(timestamp)};
|
||||||
|
SQLiteDatabase db = this.getReadableDatabase();
|
||||||
|
return db.delete(Message.TABLENAME,where,whereArgs) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
public Pair<Long, String> getLastMessageReceived(Account account) {
|
public Pair<Long, String> getLastMessageReceived(Account account) {
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -56,6 +56,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
startCatchup = lastClearDate.first;
|
startCatchup = lastClearDate.first;
|
||||||
reference = null;
|
reference = null;
|
||||||
}
|
}
|
||||||
|
startCatchup = Math.max(startCatchup,mXmppConnectionService.getAutomaticMessageDeletionDate());
|
||||||
long endCatchup = account.getXmppConnection().getLastSessionEstablished();
|
long endCatchup = account.getXmppConnection().getLastSessionEstablished();
|
||||||
final Query query;
|
final Query query;
|
||||||
if (startCatchup == 0) {
|
if (startCatchup == 0) {
|
||||||
|
@ -107,12 +108,15 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
|
|
||||||
public Query query(Conversation conversation, long start, long end) {
|
public Query query(Conversation conversation, long start, long end) {
|
||||||
synchronized (this.queries) {
|
synchronized (this.queries) {
|
||||||
if (start > end) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final Query query = new Query(conversation, start, end,PagingOrder.REVERSE);
|
final Query query = new Query(conversation, start, end,PagingOrder.REVERSE);
|
||||||
if (start==0) {
|
if (start==0) {
|
||||||
query.reference = conversation.getFirstMamReference();
|
query.reference = conversation.getFirstMamReference();
|
||||||
|
Log.d(Config.LOGTAG,"setting mam reference");
|
||||||
|
}
|
||||||
|
Log.d(Config.LOGTAG,"checking max of "+start+" end "+mXmppConnectionService.getAutomaticMessageDeletionDate());
|
||||||
|
query.start = Math.max(start,mXmppConnectionService.getAutomaticMessageDeletionDate());
|
||||||
|
if (start > end) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
this.queries.add(query);
|
this.queries.add(query);
|
||||||
this.execute(query);
|
this.execute(query);
|
||||||
|
@ -222,7 +226,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
query.getConversation().setFirstMamReference(first == null ? null : first.getContent());
|
query.getConversation().setFirstMamReference(first == null ? null : first.getContent());
|
||||||
}
|
}
|
||||||
if (complete || relevant == null || abort) {
|
if (complete || relevant == null || abort) {
|
||||||
final boolean done = (complete || query.getMessageCount() == 0) && query.getStart() == 0;
|
final boolean done = (complete || query.getMessageCount() == 0) && query.getStart() <= mXmppConnectionService.getAutomaticMessageDeletionDate();
|
||||||
this.finalizeQuery(query, done);
|
this.finalizeQuery(query, done);
|
||||||
Log.d(Config.LOGTAG,query.getAccount().getJid().toBareJid()+": finished mam after "+query.getTotalCount()+" messages. messages left="+Boolean.toString(!done));
|
Log.d(Config.LOGTAG,query.getAccount().getJid().toBareJid()+": finished mam after "+query.getTotalCount()+" messages. messages left="+Boolean.toString(!done));
|
||||||
if (query.getWith() == null && query.getMessageCount() > 0) {
|
if (query.getWith() == null && query.getMessageCount() > 0) {
|
||||||
|
|
|
@ -59,6 +59,7 @@ import java.util.ListIterator;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
import de.duenndns.ssl.MemorizingTrustManager;
|
import de.duenndns.ssl.MemorizingTrustManager;
|
||||||
import eu.siacs.conversations.Config;
|
import eu.siacs.conversations.Config;
|
||||||
|
@ -265,6 +266,7 @@ public class XmppConnectionService extends Service {
|
||||||
private int mucRosterChangedListenerCount = 0;
|
private int mucRosterChangedListenerCount = 0;
|
||||||
private OnKeyStatusUpdated mOnKeyStatusUpdated = null;
|
private OnKeyStatusUpdated mOnKeyStatusUpdated = null;
|
||||||
private int keyStatusUpdatedListenerCount = 0;
|
private int keyStatusUpdatedListenerCount = 0;
|
||||||
|
private AtomicLong mLastExpiryRun = new AtomicLong(0);
|
||||||
private SecureRandom mRandom;
|
private SecureRandom mRandom;
|
||||||
private LruCache<Pair<String,String>,ServiceDiscoveryResult> discoCache = new LruCache<>(20);
|
private LruCache<Pair<String,String>,ServiceDiscoveryResult> discoCache = new LruCache<>(20);
|
||||||
private final OnBindListener mOnBindListener = new OnBindListener() {
|
private final OnBindListener mOnBindListener = new OnBindListener() {
|
||||||
|
@ -645,6 +647,9 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (SystemClock.elapsedRealtime() - mLastExpiryRun.get() >= Config.EXPIRY_INTERVAL) {
|
||||||
|
expireOldMessages();
|
||||||
|
}
|
||||||
return START_STICKY;
|
return START_STICKY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -854,6 +859,20 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void expireOldMessages() {
|
||||||
|
mLastExpiryRun.set(SystemClock.elapsedRealtime());
|
||||||
|
synchronized (this.conversations) {
|
||||||
|
long timestamp = getAutomaticMessageDeletionDate();
|
||||||
|
if (timestamp > 0) {
|
||||||
|
databaseBackend.expireOldMessages(timestamp);
|
||||||
|
for (Conversation conversation : this.conversations) {
|
||||||
|
conversation.expireOldMessages(timestamp);
|
||||||
|
}
|
||||||
|
updateConversationUi();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasInternetConnection() {
|
public boolean hasInternetConnection() {
|
||||||
ConnectivityManager cm = (ConnectivityManager) getApplicationContext()
|
ConnectivityManager cm = (ConnectivityManager) getApplicationContext()
|
||||||
.getSystemService(Context.CONNECTIVITY_SERVICE);
|
.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
@ -1232,13 +1251,11 @@ public class XmppConnectionService extends Service {
|
||||||
if (addToConversation) {
|
if (addToConversation) {
|
||||||
conversation.add(message);
|
conversation.add(message);
|
||||||
}
|
}
|
||||||
if (message.getEncryption() == Message.ENCRYPTION_NONE || saveEncryptedMessages()) {
|
|
||||||
if (saveInDb) {
|
if (saveInDb) {
|
||||||
databaseBackend.createMessage(message);
|
databaseBackend.createMessage(message);
|
||||||
} else if (message.edited()) {
|
} else if (message.edited()) {
|
||||||
databaseBackend.updateMessage(message, message.getEditedId());
|
databaseBackend.updateMessage(message, message.getEditedId());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
updateConversationUi();
|
updateConversationUi();
|
||||||
}
|
}
|
||||||
if (packet != null) {
|
if (packet != null) {
|
||||||
|
@ -1347,6 +1364,12 @@ public class XmppConnectionService extends Service {
|
||||||
Runnable runnable = new Runnable() {
|
Runnable runnable = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
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");
|
Log.d(Config.LOGTAG, "restoring roster");
|
||||||
for (Account account : accounts) {
|
for (Account account : accounts) {
|
||||||
databaseBackend.readRoster(account.getRoster());
|
databaseBackend.readRoster(account.getRoster());
|
||||||
|
@ -1518,8 +1541,11 @@ public class XmppConnectionService extends Service {
|
||||||
MessageArchiveService.Query query = getMessageArchiveService().query(conversation, 0, timestamp);
|
MessageArchiveService.Query query = getMessageArchiveService().query(conversation, 0, timestamp);
|
||||||
if (query != null) {
|
if (query != null) {
|
||||||
query.setCallback(callback);
|
query.setCallback(callback);
|
||||||
}
|
|
||||||
callback.informUser(R.string.fetching_history_from_server);
|
callback.informUser(R.string.fetching_history_from_server);
|
||||||
|
} else {
|
||||||
|
callback.informUser(R.string.not_fetching_history_retention_period);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3046,6 +3072,15 @@ public class XmppConnectionService extends Service {
|
||||||
.getDefaultSharedPreferences(getApplicationContext());
|
.getDefaultSharedPreferences(getApplicationContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getAutomaticMessageDeletionDate() {
|
||||||
|
try {
|
||||||
|
final long timeout = Long.parseLong(getPreferences().getString(SettingsActivity.AUTOMATIC_MESSAGE_DELETION, "0")) * 1000;
|
||||||
|
return timeout == 0 ? timeout : System.currentTimeMillis() - timeout;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean confirmMessages() {
|
public boolean confirmMessages() {
|
||||||
return getPreferences().getBoolean("confirm_messages", true);
|
return getPreferences().getBoolean("confirm_messages", true);
|
||||||
}
|
}
|
||||||
|
@ -3058,10 +3093,6 @@ public class XmppConnectionService extends Service {
|
||||||
return getPreferences().getBoolean("chat_states", false);
|
return getPreferences().getBoolean("chat_states", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean saveEncryptedMessages() {
|
|
||||||
return !getPreferences().getBoolean("dont_save_encrypted", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean respectAutojoin() {
|
private boolean respectAutojoin() {
|
||||||
return getPreferences().getBoolean("autojoin", true);
|
return getPreferences().getBoolean("autojoin", true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ public class SettingsActivity extends XmppActivity implements
|
||||||
public static final String TREAT_VIBRATE_AS_SILENT = "treat_vibrate_as_silent";
|
public static final String TREAT_VIBRATE_AS_SILENT = "treat_vibrate_as_silent";
|
||||||
public static final String MANUALLY_CHANGE_PRESENCE = "manually_change_presence";
|
public static final String MANUALLY_CHANGE_PRESENCE = "manually_change_presence";
|
||||||
public static final String BLIND_TRUST_BEFORE_VERIFICATION = "btbv";
|
public static final String BLIND_TRUST_BEFORE_VERIFICATION = "btbv";
|
||||||
|
public static final String AUTOMATIC_MESSAGE_DELETION = "automatic_message_deletion";
|
||||||
|
|
||||||
public static final int REQUEST_WRITE_LOGS = 0xbf8701;
|
public static final int REQUEST_WRITE_LOGS = 0xbf8701;
|
||||||
private SettingsFragment mSettingsFragment;
|
private SettingsFragment mSettingsFragment;
|
||||||
|
|
|
@ -52,6 +52,7 @@ import eu.siacs.conversations.entities.Message;
|
||||||
import eu.siacs.conversations.entities.Message.FileParams;
|
import eu.siacs.conversations.entities.Message.FileParams;
|
||||||
import eu.siacs.conversations.entities.Transferable;
|
import eu.siacs.conversations.entities.Transferable;
|
||||||
import eu.siacs.conversations.persistance.FileBackend;
|
import eu.siacs.conversations.persistance.FileBackend;
|
||||||
|
import eu.siacs.conversations.services.MessageArchiveService;
|
||||||
import eu.siacs.conversations.services.NotificationService;
|
import eu.siacs.conversations.services.NotificationService;
|
||||||
import eu.siacs.conversations.ui.ConversationActivity;
|
import eu.siacs.conversations.ui.ConversationActivity;
|
||||||
import eu.siacs.conversations.ui.text.DividerSpan;
|
import eu.siacs.conversations.ui.text.DividerSpan;
|
||||||
|
@ -565,8 +566,12 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
|
||||||
timestamp = System.currentTimeMillis();
|
timestamp = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
activity.setMessagesLoaded();
|
activity.setMessagesLoaded();
|
||||||
activity.xmppConnectionService.getMessageArchiveService().query(conversation, 0, timestamp);
|
MessageArchiveService.Query query = activity.xmppConnectionService.getMessageArchiveService().query(conversation, 0, timestamp);
|
||||||
|
if (query != null) {
|
||||||
Toast.makeText(activity, R.string.fetching_history_from_server, Toast.LENGTH_LONG).show();
|
Toast.makeText(activity, R.string.fetching_history_from_server, Toast.LENGTH_LONG).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(activity,R.string.not_fetching_history_retention_period, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -103,4 +103,18 @@
|
||||||
<item>610</item>
|
<item>610</item>
|
||||||
<item>2584</item>
|
<item>2584</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
<string-array name="automatic_message_deletion_values">
|
||||||
|
<item>0</item>
|
||||||
|
<item>86400</item>
|
||||||
|
<item>604800</item>
|
||||||
|
<item>2592000</item>
|
||||||
|
<item>15811200</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="automatic_message_deletion">
|
||||||
|
<item>@string/never</item>
|
||||||
|
<item>@string/timeout_24_hours</item>
|
||||||
|
<item>@string/timeout_7_days</item>
|
||||||
|
<item>@string/timeout_30_days</item>
|
||||||
|
<item>@string/timeout_6_months</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -724,5 +724,12 @@
|
||||||
<string name="hide_inactive_devices">Hide inactive devices</string>
|
<string name="hide_inactive_devices">Hide inactive devices</string>
|
||||||
<string name="distrust_omemo_key">Distrust device</string>
|
<string name="distrust_omemo_key">Distrust device</string>
|
||||||
<string name="distrust_omemo_key_text">Are you sure you want to remove the verification for this device?\nThis device and messages coming from that device will be marked as untrusted.</string>
|
<string name="distrust_omemo_key_text">Are you sure you want to remove the verification for this device?\nThis device and messages coming from that device will be marked as untrusted.</string>
|
||||||
|
<string name="timeout_24_hours">24 hours</string>
|
||||||
|
<string name="timeout_7_days">7 days</string>
|
||||||
|
<string name="timeout_30_days">30 days</string>
|
||||||
|
<string name="timeout_6_months">6 months</string>
|
||||||
|
<string name="pref_automatically_delete_messages">Automatic message deletion</string>
|
||||||
|
<string name="pref_automatically_delete_messages_description">Automatically delete messages from this device that are older than the configured time frame.</string>
|
||||||
<string name="encrypting_message">Encrypting message</string>
|
<string name="encrypting_message">Encrypting message</string>
|
||||||
|
<string name="not_fetching_history_retention_period">Overstepping local retention period.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -170,11 +170,13 @@
|
||||||
android:key="btbv"
|
android:key="btbv"
|
||||||
android:title="@string/pref_blind_trust_before_verification"
|
android:title="@string/pref_blind_trust_before_verification"
|
||||||
android:summary="@string/pref_blind_trust_before_verification_summary"/>
|
android:summary="@string/pref_blind_trust_before_verification_summary"/>
|
||||||
<CheckBoxPreference
|
<ListPreference
|
||||||
android:defaultValue="false"
|
android:key="automatic_message_deletion"
|
||||||
android:key="dont_save_encrypted"
|
android:title="@string/pref_automatically_delete_messages"
|
||||||
android:summary="@string/pref_dont_save_encrypted_summary"
|
android:summary="@string/pref_automatically_delete_messages_description"
|
||||||
android:title="@string/pref_dont_save_encrypted"/>
|
android:defaultValue="0"
|
||||||
|
android:entries="@array/automatic_message_deletion"
|
||||||
|
android:entryValues="@array/automatic_message_deletion_values" />
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
android:key="dont_trust_system_cas"
|
android:key="dont_trust_system_cas"
|
||||||
|
|
Loading…
Reference in a new issue