~singpolyma/cheogram-android

9b6ae6d75fdf07933427774f72310ceecc5f01bd — Daniel Gultsch 7 years ago 4c6ef3b
configurable local message retention period. (untested)
M src/main/java/eu/siacs/conversations/Config.java => src/main/java/eu/siacs/conversations/Config.java +2 -0
@@ 114,6 114,8 @@ public final class Config {
	public static final ChatState DEFAULT_CHATSTATE = ChatState.ACTIVE;
	public static final int TYPING_TIMEOUT = 8;

	public static final int EXPIRY_INTERVAL = 30 * 60 * 1000; // 30 minutes

	public static final String ENABLED_CIPHERS[] = {
		"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
		"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384",

M src/main/java/eu/siacs/conversations/entities/Conversation.java => src/main/java/eu/siacs/conversations/entities/Conversation.java +12 -0
@@ 20,6 20,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;

import eu.siacs.conversations.Config;


@@ 930,6 931,17 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
		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() {
		synchronized (this.messages) {
			Collections.sort(this.messages, new Comparator<Message>() {

M src/main/java/eu/siacs/conversations/parser/MessageParser.java => src/main/java/eu/siacs/conversations/parser/MessageParser.java +7 -3
@@ 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
					|| (isTypeGroupChat && packet.hasChild("delay","urn:xmpp:delay"))
					|| message.getType() == Message.TYPE_PRIVATE;


@@ 570,9 576,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
				conversation.endOtrIfNeeded();
			}

			if (message.getEncryption() == Message.ENCRYPTION_NONE || mXmppConnectionService.saveEncryptedMessages()) {
				mXmppConnectionService.databaseBackend.createMessage(message);
			}
			mXmppConnectionService.databaseBackend.createMessage(message);
			final HttpConnectionManager manager = this.mXmppConnectionService.getHttpConnectionManager();
			if (message.trusted() && message.treatAsDownloadable() != Message.Decision.NEVER && manager.getAutoAcceptFileSize() > 0) {
				manager.createNewDownloadConnection(message);

M src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java => src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +7 -0
@@ 769,6 769,13 @@ public class DatabaseBackend extends SQLiteOpenHelper {
		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) {
		Cursor cursor = null;
		try {

M src/main/java/eu/siacs/conversations/services/MessageArchiveService.java => src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +8 -4
@@ 56,6 56,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
			startCatchup = lastClearDate.first;
			reference = null;
		}
		startCatchup = Math.max(startCatchup,mXmppConnectionService.getAutomaticMessageDeletionDate());
		long endCatchup = account.getXmppConnection().getLastSessionEstablished();
		final Query query;
		if (startCatchup == 0) {


@@ 107,12 108,15 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {

	public Query query(Conversation conversation, long start, long end) {
		synchronized (this.queries) {
			if (start > end) {
				return null;
			}
			final Query query = new Query(conversation, start, end,PagingOrder.REVERSE);
			if (start==0) {
				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.execute(query);


@@ 222,7 226,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
			query.getConversation().setFirstMamReference(first == null ? null : first.getContent());
		}
		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);
			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) {

M src/main/java/eu/siacs/conversations/services/XmppConnectionService.java => src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +42 -11
@@ 59,6 59,7 @@ import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicLong;

import de.duenndns.ssl.MemorizingTrustManager;
import eu.siacs.conversations.Config;


@@ 265,6 266,7 @@ public class XmppConnectionService extends Service {
	private int mucRosterChangedListenerCount = 0;
	private OnKeyStatusUpdated mOnKeyStatusUpdated = null;
	private int keyStatusUpdatedListenerCount = 0;
	private AtomicLong mLastExpiryRun = new AtomicLong(0);
	private SecureRandom mRandom;
	private LruCache<Pair<String,String>,ServiceDiscoveryResult> discoCache = new LruCache<>(20);
	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;
	}



@@ 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() {
		ConnectivityManager cm = (ConnectivityManager) getApplicationContext()
				.getSystemService(Context.CONNECTIVITY_SERVICE);


@@ 1232,12 1251,10 @@ public class XmppConnectionService extends Service {
			if (addToConversation) {
				conversation.add(message);
			}
			if (message.getEncryption() == Message.ENCRYPTION_NONE || saveEncryptedMessages()) {
				if (saveInDb) {
					databaseBackend.createMessage(message);
				} else if (message.edited()) {
					databaseBackend.updateMessage(message, message.getEditedId());
				}
			if (saveInDb) {
				databaseBackend.createMessage(message);
			} else if (message.edited()) {
				databaseBackend.updateMessage(message, message.getEditedId());
			}
			updateConversationUi();
		}


@@ 1347,6 1364,12 @@ public class XmppConnectionService extends Service {
			Runnable runnable = new Runnable() {
				@Override
				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");
					for (Account account : accounts) {
						databaseBackend.readRoster(account.getRoster());


@@ 1518,8 1541,11 @@ public class XmppConnectionService extends Service {
						MessageArchiveService.Query query = getMessageArchiveService().query(conversation, 0, timestamp);
						if (query != null) {
							query.setCallback(callback);
							callback.informUser(R.string.fetching_history_from_server);
						} else {
							callback.informUser(R.string.not_fetching_history_retention_period);
						}
						callback.informUser(R.string.fetching_history_from_server);

					}
				}
			}


@@ 3046,6 3072,15 @@ public class XmppConnectionService extends Service {
				.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() {
		return getPreferences().getBoolean("confirm_messages", true);
	}


@@ 3058,10 3093,6 @@ public class XmppConnectionService extends Service {
		return getPreferences().getBoolean("chat_states", false);
	}

	public boolean saveEncryptedMessages() {
		return !getPreferences().getBoolean("dont_save_encrypted", false);
	}

	private boolean respectAutojoin() {
		return getPreferences().getBoolean("autojoin", true);
	}

M src/main/java/eu/siacs/conversations/ui/SettingsActivity.java => src/main/java/eu/siacs/conversations/ui/SettingsActivity.java +1 -0
@@ 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 MANUALLY_CHANGE_PRESENCE = "manually_change_presence";
	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;
	private SettingsFragment mSettingsFragment;

M src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java => src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +7 -2
@@ 52,6 52,7 @@ import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Message.FileParams;
import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.services.MessageArchiveService;
import eu.siacs.conversations.services.NotificationService;
import eu.siacs.conversations.ui.ConversationActivity;
import eu.siacs.conversations.ui.text.DividerSpan;


@@ 565,8 566,12 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
			timestamp = System.currentTimeMillis();
		}
		activity.setMessagesLoaded();
		activity.xmppConnectionService.getMessageArchiveService().query(conversation, 0, timestamp);
		Toast.makeText(activity, R.string.fetching_history_from_server,Toast.LENGTH_LONG).show();
		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();
		} else {
			Toast.makeText(activity,R.string.not_fetching_history_retention_period, Toast.LENGTH_SHORT).show();
		}
	}

	@Override

M src/main/res/values/arrays.xml => src/main/res/values/arrays.xml +14 -0
@@ 103,4 103,18 @@
		<item>610</item>
		<item>2584</item>
	</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>

M src/main/res/values/strings.xml => src/main/res/values/strings.xml +7 -0
@@ 724,5 724,12 @@
	<string name="hide_inactive_devices">Hide inactive devices</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="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="not_fetching_history_retention_period">Overstepping local retention period.</string>
</resources>

M src/main/res/xml/preferences.xml => src/main/res/xml/preferences.xml +7 -5
@@ 170,11 170,13 @@
                    android:key="btbv"
                    android:title="@string/pref_blind_trust_before_verification"
                    android:summary="@string/pref_blind_trust_before_verification_summary"/>
                <CheckBoxPreference
                    android:defaultValue="false"
                    android:key="dont_save_encrypted"
                    android:summary="@string/pref_dont_save_encrypted_summary"
                    android:title="@string/pref_dont_save_encrypted"/>
                <ListPreference
                    android:key="automatic_message_deletion"
                    android:title="@string/pref_automatically_delete_messages"
                    android:summary="@string/pref_automatically_delete_messages_description"
                    android:defaultValue="0"
                    android:entries="@array/automatic_message_deletion"
                    android:entryValues="@array/automatic_message_deletion_values" />
                <CheckBoxPreference
                    android:defaultValue="false"
                    android:key="dont_trust_system_cas"