Skip to content
Permalink
6a1cf64f6f
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
6309 lines (5946 sloc) 321 KB
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2017.
*/
package org.telegram.messenger;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import android.util.SparseArray;
import android.util.SparseIntArray;
import org.telegram.PhoneFormat.PhoneFormat;
import org.telegram.SQLite.SQLiteCursor;
import org.telegram.SQLite.SQLiteDatabase;
import org.telegram.SQLite.SQLitePreparedStatement;
import org.telegram.messenger.query.BotQuery;
import org.telegram.messenger.query.MessagesQuery;
import org.telegram.messenger.query.SharedMediaQuery;
import org.telegram.tgnet.ConnectionsManager;
import org.telegram.tgnet.NativeByteBuffer;
import org.telegram.tgnet.RequestDelegate;
import org.telegram.tgnet.TLObject;
import org.telegram.tgnet.TLRPC;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicLong;
public class MessagesStorage {
private DispatchQueue storageQueue = new DispatchQueue("storageQueue");
private SQLiteDatabase database;
private File cacheFile;
private AtomicLong lastTaskId = new AtomicLong(System.currentTimeMillis());
public static int lastDateValue = 0;
public static int lastPtsValue = 0;
public static int lastQtsValue = 0;
public static int lastSeqValue = 0;
public static int lastSecretVersion = 0;
public static byte[] secretPBytes = null;
public static int secretG = 0;
private int lastSavedSeq = 0;
private int lastSavedPts = 0;
private int lastSavedDate = 0;
private int lastSavedQts = 0;
private static volatile MessagesStorage Instance = null;
public static MessagesStorage getInstance() {
MessagesStorage localInstance = Instance;
if (localInstance == null) {
synchronized (MessagesStorage.class) {
localInstance = Instance;
if (localInstance == null) {
Instance = localInstance = new MessagesStorage();
}
}
}
return localInstance;
}
public MessagesStorage() {
storageQueue.setPriority(Thread.MAX_PRIORITY);
openDatabase(true);
}
public SQLiteDatabase getDatabase() {
return database;
}
public DispatchQueue getStorageQueue() {
return storageQueue;
}
public void openDatabase(boolean first) {
cacheFile = new File(ApplicationLoader.getFilesDirFixed(), "cache4.db");
boolean createTable = false;
//cacheFile.delete();
if (!cacheFile.exists()) {
createTable = true;
}
try {
database = new SQLiteDatabase(cacheFile.getPath());
database.executeFast("PRAGMA secure_delete = ON").stepThis().dispose();
database.executeFast("PRAGMA temp_store = 1").stepThis().dispose();
if (createTable) {
FileLog.e("create new database");
database.executeFast("CREATE TABLE messages_holes(uid INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, start));").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS uid_end_messages_holes ON messages_holes(uid, end);").stepThis().dispose();
database.executeFast("CREATE TABLE media_holes_v2(uid INTEGER, type INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, type, start));").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS uid_end_media_holes_v2 ON media_holes_v2(uid, type, end);").stepThis().dispose();
database.executeFast("CREATE TABLE messages(mid INTEGER PRIMARY KEY, uid INTEGER, read_state INTEGER, send_state INTEGER, date INTEGER, data BLOB, out INTEGER, ttl INTEGER, media INTEGER, replydata BLOB, imp INTEGER)").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS uid_mid_idx_messages ON messages(uid, mid);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_idx_messages ON messages(uid, date, mid);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS mid_out_idx_messages ON messages(mid, out);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS task_idx_messages ON messages(uid, out, read_state, ttl, date, send_state);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose();
database.executeFast("CREATE TABLE download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS type_date_idx_download_queue ON download_queue(type, date);").stepThis().dispose();
database.executeFast("CREATE TABLE user_phones_v6(uid INTEGER, phone TEXT, sphone TEXT, deleted INTEGER, PRIMARY KEY (uid, phone))").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS sphone_deleted_idx_user_phones ON user_phones_v6(sphone, deleted);").stepThis().dispose();
database.executeFast("CREATE TABLE dialogs(did INTEGER PRIMARY KEY, date INTEGER, unread_count INTEGER, last_mid INTEGER, inbox_max INTEGER, outbox_max INTEGER, last_mid_i INTEGER, unread_count_i INTEGER, pts INTEGER, date_i INTEGER, pinned INTEGER)").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_dialogs ON dialogs(date);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS last_mid_idx_dialogs ON dialogs(last_mid);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_idx_dialogs ON dialogs(unread_count);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS last_mid_i_idx_dialogs ON dialogs(last_mid_i);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_i_idx_dialogs ON dialogs(unread_count_i);").stepThis().dispose();
database.executeFast("CREATE TABLE randoms(random_id INTEGER, mid INTEGER, PRIMARY KEY (random_id, mid))").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_randoms ON randoms(mid);").stepThis().dispose();
database.executeFast("CREATE TABLE enc_tasks_v2(mid INTEGER PRIMARY KEY, date INTEGER)").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_enc_tasks_v2 ON enc_tasks_v2(date);").stepThis().dispose();
database.executeFast("CREATE TABLE messages_seq(mid INTEGER PRIMARY KEY, seq_in INTEGER, seq_out INTEGER);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS seq_idx_messages_seq ON messages_seq(seq_in, seq_out);").stepThis().dispose();
database.executeFast("CREATE TABLE params(id INTEGER PRIMARY KEY, seq INTEGER, pts INTEGER, date INTEGER, qts INTEGER, lsv INTEGER, sg INTEGER, pbytes BLOB)").stepThis().dispose();
database.executeFast("INSERT INTO params VALUES(1, 0, 0, 0, 0, 0, 0, NULL)").stepThis().dispose();
database.executeFast("CREATE TABLE media_v2(mid INTEGER PRIMARY KEY, uid INTEGER, date INTEGER, type INTEGER, data BLOB)").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS uid_mid_type_date_idx_media ON media_v2(uid, mid, type, date);").stepThis().dispose();
database.executeFast("CREATE TABLE bot_keyboard(uid INTEGER PRIMARY KEY, mid INTEGER, info BLOB)").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS bot_keyboard_idx_mid ON bot_keyboard(mid);").stepThis().dispose();
database.executeFast("CREATE TABLE chat_settings_v2(uid INTEGER PRIMARY KEY, info BLOB, pinned INTEGER)").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS chat_settings_pinned_idx ON chat_settings_v2(uid, pinned) WHERE pinned != 0;").stepThis().dispose();
database.executeFast("CREATE TABLE chat_pinned(uid INTEGER PRIMARY KEY, pinned INTEGER, data BLOB)").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS chat_pinned_mid_idx ON chat_pinned(uid, pinned) WHERE pinned != 0;").stepThis().dispose();
database.executeFast("CREATE TABLE chat_hints(did INTEGER, type INTEGER, rating REAL, date INTEGER, PRIMARY KEY(did, type))").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS chat_hints_rating_idx ON chat_hints(rating);").stepThis().dispose();
database.executeFast("CREATE TABLE botcache(id TEXT PRIMARY KEY, date INTEGER, data BLOB)").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS botcache_date_idx ON botcache(date);").stepThis().dispose();
database.executeFast("CREATE TABLE users_data(uid INTEGER PRIMARY KEY, about TEXT)").stepThis().dispose();
database.executeFast("CREATE TABLE users(uid INTEGER PRIMARY KEY, name TEXT, status INTEGER, data BLOB)").stepThis().dispose();
database.executeFast("CREATE TABLE chats(uid INTEGER PRIMARY KEY, name TEXT, data BLOB)").stepThis().dispose();
database.executeFast("CREATE TABLE enc_chats(uid INTEGER PRIMARY KEY, user INTEGER, name TEXT, data BLOB, g BLOB, authkey BLOB, ttl INTEGER, layer INTEGER, seq_in INTEGER, seq_out INTEGER, use_count INTEGER, exchange_id INTEGER, key_date INTEGER, fprint INTEGER, fauthkey BLOB, khash BLOB, in_seq_no INTEGER, admin_id INTEGER)").stepThis().dispose();
database.executeFast("CREATE TABLE channel_users_v2(did INTEGER, uid INTEGER, date INTEGER, data BLOB, PRIMARY KEY(did, uid))").stepThis().dispose();
database.executeFast("CREATE TABLE contacts(uid INTEGER PRIMARY KEY, mutual INTEGER)").stepThis().dispose();
database.executeFast("CREATE TABLE wallpapers(uid INTEGER PRIMARY KEY, data BLOB)").stepThis().dispose();
database.executeFast("CREATE TABLE user_photos(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose();
database.executeFast("CREATE TABLE blocked_users(uid INTEGER PRIMARY KEY)").stepThis().dispose();
database.executeFast("CREATE TABLE dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose();
database.executeFast("CREATE TABLE web_recent_v3(id TEXT, type INTEGER, image_url TEXT, thumb_url TEXT, local_url TEXT, width INTEGER, height INTEGER, size INTEGER, date INTEGER, document BLOB, PRIMARY KEY (id, type));").stepThis().dispose();
database.executeFast("CREATE TABLE stickers_v2(id INTEGER PRIMARY KEY, data BLOB, date INTEGER, hash TEXT);").stepThis().dispose();
database.executeFast("CREATE TABLE stickers_featured(id INTEGER PRIMARY KEY, data BLOB, unread BLOB, date INTEGER, hash TEXT);").stepThis().dispose();
database.executeFast("CREATE TABLE hashtag_recent_v2(id TEXT PRIMARY KEY, date INTEGER);").stepThis().dispose();
database.executeFast("CREATE TABLE webpage_pending(id INTEGER, mid INTEGER, PRIMARY KEY (id, mid));").stepThis().dispose();
database.executeFast("CREATE TABLE user_contacts_v6(uid INTEGER PRIMARY KEY, fname TEXT, sname TEXT)").stepThis().dispose();
database.executeFast("CREATE TABLE sent_files_v2(uid TEXT, type INTEGER, data BLOB, PRIMARY KEY (uid, type))").stepThis().dispose();
database.executeFast("CREATE TABLE search_recent(did INTEGER PRIMARY KEY, date INTEGER);").stepThis().dispose();
database.executeFast("CREATE TABLE media_counts_v2(uid INTEGER, type INTEGER, count INTEGER, PRIMARY KEY(uid, type))").stepThis().dispose();
database.executeFast("CREATE TABLE keyvalue(id TEXT PRIMARY KEY, value TEXT)").stepThis().dispose();
database.executeFast("CREATE TABLE bot_info(uid INTEGER PRIMARY KEY, info BLOB)").stepThis().dispose();
database.executeFast("CREATE TABLE pending_tasks(id INTEGER PRIMARY KEY, data BLOB);").stepThis().dispose();
database.executeFast("CREATE TABLE requested_holes(uid INTEGER, seq_out_start INTEGER, seq_out_end INTEGER, PRIMARY KEY (uid, seq_out_start, seq_out_end));").stepThis().dispose();
//version
database.executeFast("PRAGMA user_version = 41").stepThis().dispose();
//database.executeFast("CREATE TABLE secret_holes(uid INTEGER, seq_in INTEGER, seq_out INTEGER, data BLOB, PRIMARY KEY (uid, seq_in, seq_out));").stepThis().dispose();
//database.executeFast("CREATE TABLE attach_data(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose();
} else {
int version = database.executeInt("PRAGMA user_version");
FileLog.e("current db version = " + version);
if (version == 0) {
throw new Exception("malformed");
}
try {
SQLiteCursor cursor = database.queryFinalized("SELECT seq, pts, date, qts, lsv, sg, pbytes FROM params WHERE id = 1");
if (cursor.next()) {
lastSeqValue = cursor.intValue(0);
lastPtsValue = cursor.intValue(1);
lastDateValue = cursor.intValue(2);
lastQtsValue = cursor.intValue(3);
lastSecretVersion = cursor.intValue(4);
secretG = cursor.intValue(5);
if (cursor.isNull(6)) {
secretPBytes = null;
} else {
secretPBytes = cursor.byteArrayValue(6);
if (secretPBytes != null && secretPBytes.length == 1) {
secretPBytes = null;
}
}
}
cursor.dispose();
} catch (Exception e) {
FileLog.e(e);
try {
database.executeFast("CREATE TABLE IF NOT EXISTS params(id INTEGER PRIMARY KEY, seq INTEGER, pts INTEGER, date INTEGER, qts INTEGER, lsv INTEGER, sg INTEGER, pbytes BLOB)").stepThis().dispose();
database.executeFast("INSERT INTO params VALUES(1, 0, 0, 0, 0, 0, 0, NULL)").stepThis().dispose();
} catch (Exception e2) {
FileLog.e(e2);
}
}
if (version < 41) {
updateDbToLastVersion(version);
}
}
} catch (Exception e) {
FileLog.e(e);
if (first && e.getMessage().contains("malformed")) {
cleanupInternal();
openDatabase(false);
}
}
loadUnreadMessages();
loadPendingTasks();
}
private void updateDbToLastVersion(final int currentVersion) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
int version = currentVersion;
if (version < 4) {
database.executeFast("CREATE TABLE IF NOT EXISTS user_photos(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose();
database.executeFast("DROP INDEX IF EXISTS read_state_out_idx_messages;").stepThis().dispose();
database.executeFast("DROP INDEX IF EXISTS ttl_idx_messages;").stepThis().dispose();
database.executeFast("DROP INDEX IF EXISTS date_idx_messages;").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS mid_out_idx_messages ON messages(mid, out);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS task_idx_messages ON messages(uid, out, read_state, ttl, date, send_state);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_idx_messages ON messages(uid, date, mid);").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS user_contacts_v6(uid INTEGER PRIMARY KEY, fname TEXT, sname TEXT)").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS user_phones_v6(uid INTEGER, phone TEXT, sphone TEXT, deleted INTEGER, PRIMARY KEY (uid, phone))").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS sphone_deleted_idx_user_phones ON user_phones_v6(sphone, deleted);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_randoms ON randoms(mid);").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS sent_files_v2(uid TEXT, type INTEGER, data BLOB, PRIMARY KEY (uid, type))").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS blocked_users(uid INTEGER PRIMARY KEY)").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS type_date_idx_download_queue ON download_queue(type, date);").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_idx_dialogs ON dialogs(unread_count);").stepThis().dispose();
database.executeFast("UPDATE messages SET send_state = 2 WHERE mid < 0 AND send_state = 1").stepThis().dispose();
fixNotificationSettings();
database.executeFast("PRAGMA user_version = 4").stepThis().dispose();
version = 4;
}
if (version == 4) {
database.executeFast("CREATE TABLE IF NOT EXISTS enc_tasks_v2(mid INTEGER PRIMARY KEY, date INTEGER)").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_enc_tasks_v2 ON enc_tasks_v2(date);").stepThis().dispose();
database.beginTransaction();
SQLiteCursor cursor = database.queryFinalized("SELECT date, data FROM enc_tasks WHERE 1");
SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_tasks_v2 VALUES(?, ?)");
if (cursor.next()) {
int date = cursor.intValue(0);
NativeByteBuffer data = cursor.byteBufferValue(1);
if (data != null) {
int length = data.limit();
for (int a = 0; a < length / 4; a++) {
state.requery();
state.bindInteger(1, data.readInt32(false));
state.bindInteger(2, date);
state.step();
}
data.reuse();
}
}
state.dispose();
cursor.dispose();
database.commitTransaction();
database.executeFast("DROP INDEX IF EXISTS date_idx_enc_tasks;").stepThis().dispose();
database.executeFast("DROP TABLE IF EXISTS enc_tasks;").stepThis().dispose();
database.executeFast("ALTER TABLE messages ADD COLUMN media INTEGER default 0").stepThis().dispose();
database.executeFast("PRAGMA user_version = 6").stepThis().dispose();
version = 6;
}
if (version == 6) {
database.executeFast("CREATE TABLE IF NOT EXISTS messages_seq(mid INTEGER PRIMARY KEY, seq_in INTEGER, seq_out INTEGER);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS seq_idx_messages_seq ON messages_seq(seq_in, seq_out);").stepThis().dispose();
database.executeFast("ALTER TABLE enc_chats ADD COLUMN layer INTEGER default 0").stepThis().dispose();
database.executeFast("ALTER TABLE enc_chats ADD COLUMN seq_in INTEGER default 0").stepThis().dispose();
database.executeFast("ALTER TABLE enc_chats ADD COLUMN seq_out INTEGER default 0").stepThis().dispose();
database.executeFast("PRAGMA user_version = 7").stepThis().dispose();
version = 7;
}
/*if (version == 7 && version < 8) {
database.executeFast("CREATE TABLE IF NOT EXISTS secret_holes(uid INTEGER, seq_in INTEGER, seq_out INTEGER, data BLOB, PRIMARY KEY (uid, seq_in, seq_out));").stepThis().dispose();
database.executeFast("PRAGMA user_version = 8").stepThis().dispose();
version = 8;
}*/
if (version == 7 || version == 8 || version == 9) {
database.executeFast("ALTER TABLE enc_chats ADD COLUMN use_count INTEGER default 0").stepThis().dispose();
database.executeFast("ALTER TABLE enc_chats ADD COLUMN exchange_id INTEGER default 0").stepThis().dispose();
database.executeFast("ALTER TABLE enc_chats ADD COLUMN key_date INTEGER default 0").stepThis().dispose();
database.executeFast("ALTER TABLE enc_chats ADD COLUMN fprint INTEGER default 0").stepThis().dispose();
database.executeFast("ALTER TABLE enc_chats ADD COLUMN fauthkey BLOB default NULL").stepThis().dispose();
database.executeFast("ALTER TABLE enc_chats ADD COLUMN khash BLOB default NULL").stepThis().dispose();
database.executeFast("PRAGMA user_version = 10").stepThis().dispose();
version = 10;
}
if (version == 10) {
database.executeFast("CREATE TABLE IF NOT EXISTS web_recent_v3(id TEXT, type INTEGER, image_url TEXT, thumb_url TEXT, local_url TEXT, width INTEGER, height INTEGER, size INTEGER, date INTEGER, PRIMARY KEY (id, type));").stepThis().dispose();
database.executeFast("PRAGMA user_version = 11").stepThis().dispose();
version = 11;
}
if (version == 11 || version == 12) {
database.executeFast("DROP INDEX IF EXISTS uid_mid_idx_media;").stepThis().dispose();
database.executeFast("DROP INDEX IF EXISTS mid_idx_media;").stepThis().dispose();
database.executeFast("DROP INDEX IF EXISTS uid_date_mid_idx_media;").stepThis().dispose();
database.executeFast("DROP TABLE IF EXISTS media;").stepThis().dispose();
database.executeFast("DROP TABLE IF EXISTS media_counts;").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS media_v2(mid INTEGER PRIMARY KEY, uid INTEGER, date INTEGER, type INTEGER, data BLOB)").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS media_counts_v2(uid INTEGER, type INTEGER, count INTEGER, PRIMARY KEY(uid, type))").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS uid_mid_type_date_idx_media ON media_v2(uid, mid, type, date);").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS keyvalue(id TEXT PRIMARY KEY, value TEXT)").stepThis().dispose();
database.executeFast("PRAGMA user_version = 13").stepThis().dispose();
version = 13;
}
if (version == 13) {
database.executeFast("ALTER TABLE messages ADD COLUMN replydata BLOB default NULL").stepThis().dispose();
database.executeFast("PRAGMA user_version = 14").stepThis().dispose();
version = 14;
}
if (version == 14) {
database.executeFast("CREATE TABLE IF NOT EXISTS hashtag_recent_v2(id TEXT PRIMARY KEY, date INTEGER);").stepThis().dispose();
database.executeFast("PRAGMA user_version = 15").stepThis().dispose();
version = 15;
}
if (version == 15) {
database.executeFast("CREATE TABLE IF NOT EXISTS webpage_pending(id INTEGER, mid INTEGER, PRIMARY KEY (id, mid));").stepThis().dispose();
database.executeFast("PRAGMA user_version = 16").stepThis().dispose();
version = 16;
}
if (version == 16) {
database.executeFast("ALTER TABLE dialogs ADD COLUMN inbox_max INTEGER default 0").stepThis().dispose();
database.executeFast("ALTER TABLE dialogs ADD COLUMN outbox_max INTEGER default 0").stepThis().dispose();
database.executeFast("PRAGMA user_version = 17").stepThis().dispose();
version = 17;
}
if (version == 17) {
database.executeFast("CREATE TABLE bot_info(uid INTEGER PRIMARY KEY, info BLOB)").stepThis().dispose();
database.executeFast("PRAGMA user_version = 18").stepThis().dispose();
version = 18;
}
if (version == 18) {
database.executeFast("DROP TABLE IF EXISTS stickers;").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS stickers_v2(id INTEGER PRIMARY KEY, data BLOB, date INTEGER, hash TEXT);").stepThis().dispose();
database.executeFast("PRAGMA user_version = 19").stepThis().dispose();
version = 19;
}
if (version == 19) {
database.executeFast("CREATE TABLE IF NOT EXISTS bot_keyboard(uid INTEGER PRIMARY KEY, mid INTEGER, info BLOB)").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS bot_keyboard_idx_mid ON bot_keyboard(mid);").stepThis().dispose();
database.executeFast("PRAGMA user_version = 20").stepThis().dispose();
version = 20;
}
if (version == 20) {
database.executeFast("CREATE TABLE search_recent(did INTEGER PRIMARY KEY, date INTEGER);").stepThis().dispose();
database.executeFast("PRAGMA user_version = 21").stepThis().dispose();
version = 21;
}
if (version == 21) {
database.executeFast("CREATE TABLE IF NOT EXISTS chat_settings_v2(uid INTEGER PRIMARY KEY, info BLOB)").stepThis().dispose();
SQLiteCursor cursor = database.queryFinalized("SELECT uid, participants FROM chat_settings WHERE uid < 0");
SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?)");
while (cursor.next()) {
int chat_id = cursor.intValue(0);
NativeByteBuffer data = cursor.byteBufferValue(1);
if (data != null) {
TLRPC.ChatParticipants participants = TLRPC.ChatParticipants.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
if (participants != null) {
TLRPC.TL_chatFull chatFull = new TLRPC.TL_chatFull();
chatFull.id = chat_id;
chatFull.chat_photo = new TLRPC.TL_photoEmpty();
chatFull.notify_settings = new TLRPC.TL_peerNotifySettingsEmpty();
chatFull.exported_invite = new TLRPC.TL_chatInviteEmpty();
chatFull.participants = participants;
NativeByteBuffer data2 = new NativeByteBuffer(chatFull.getObjectSize());
chatFull.serializeToStream(data2);
state.requery();
state.bindInteger(1, chat_id);
state.bindByteBuffer(2, data2);
state.step();
data2.reuse();
}
}
}
state.dispose();
cursor.dispose();
database.executeFast("DROP TABLE IF EXISTS chat_settings;").stepThis().dispose();
database.executeFast("ALTER TABLE dialogs ADD COLUMN last_mid_i INTEGER default 0").stepThis().dispose();
database.executeFast("ALTER TABLE dialogs ADD COLUMN unread_count_i INTEGER default 0").stepThis().dispose();
database.executeFast("ALTER TABLE dialogs ADD COLUMN pts INTEGER default 0").stepThis().dispose();
database.executeFast("ALTER TABLE dialogs ADD COLUMN date_i INTEGER default 0").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS last_mid_i_idx_dialogs ON dialogs(last_mid_i);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_i_idx_dialogs ON dialogs(unread_count_i);").stepThis().dispose();
database.executeFast("ALTER TABLE messages ADD COLUMN imp INTEGER default 0").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS messages_holes(uid INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, start));").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS uid_end_messages_holes ON messages_holes(uid, end);").stepThis().dispose();
database.executeFast("PRAGMA user_version = 22").stepThis().dispose();
version = 22;
}
if (version == 22) {
database.executeFast("CREATE TABLE IF NOT EXISTS media_holes_v2(uid INTEGER, type INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, type, start));").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS uid_end_media_holes_v2 ON media_holes_v2(uid, type, end);").stepThis().dispose();
database.executeFast("PRAGMA user_version = 23").stepThis().dispose();
version = 23;
}
if (version == 23 || version == 24) {
database.executeFast("DELETE FROM media_holes_v2 WHERE uid != 0 AND type >= 0 AND start IN (0, 1)").stepThis().dispose();
database.executeFast("PRAGMA user_version = 25").stepThis().dispose();
version = 25;
}
if (version == 25 || version == 26) {
database.executeFast("CREATE TABLE IF NOT EXISTS channel_users_v2(did INTEGER, uid INTEGER, date INTEGER, data BLOB, PRIMARY KEY(did, uid))").stepThis().dispose();
database.executeFast("PRAGMA user_version = 27").stepThis().dispose();
version = 27;
}
if (version == 27) {
database.executeFast("ALTER TABLE web_recent_v3 ADD COLUMN document BLOB default NULL").stepThis().dispose();
database.executeFast("PRAGMA user_version = 28").stepThis().dispose();
version = 28;
}
if (version == 28 || version == 29) {
database.executeFast("DELETE FROM sent_files_v2 WHERE 1").stepThis().dispose();
database.executeFast("DELETE FROM download_queue WHERE 1").stepThis().dispose();
database.executeFast("PRAGMA user_version = 30").stepThis().dispose();
version = 30;
}
if (version == 30) {
database.executeFast("ALTER TABLE chat_settings_v2 ADD COLUMN pinned INTEGER default 0").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS chat_settings_pinned_idx ON chat_settings_v2(uid, pinned) WHERE pinned != 0;").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS chat_pinned(uid INTEGER PRIMARY KEY, pinned INTEGER, data BLOB)").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS chat_pinned_mid_idx ON chat_pinned(uid, pinned) WHERE pinned != 0;").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS users_data(uid INTEGER PRIMARY KEY, about TEXT)").stepThis().dispose();
database.executeFast("PRAGMA user_version = 31").stepThis().dispose();
version = 31;
}
if (version == 31) {
database.executeFast("DROP TABLE IF EXISTS bot_recent;").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS chat_hints(did INTEGER, type INTEGER, rating REAL, date INTEGER, PRIMARY KEY(did, type))").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS chat_hints_rating_idx ON chat_hints(rating);").stepThis().dispose();
database.executeFast("PRAGMA user_version = 32").stepThis().dispose();
version = 32;
}
if (version == 32) {
database.executeFast("DROP INDEX IF EXISTS uid_mid_idx_imp_messages;").stepThis().dispose();
database.executeFast("DROP INDEX IF EXISTS uid_date_mid_imp_idx_messages;").stepThis().dispose();
database.executeFast("PRAGMA user_version = 33").stepThis().dispose();
version = 33;
}
if (version == 33) {
database.executeFast("CREATE TABLE IF NOT EXISTS pending_tasks(id INTEGER PRIMARY KEY, data BLOB);").stepThis().dispose();
database.executeFast("PRAGMA user_version = 34").stepThis().dispose();
version = 34;
}
if (version == 34) {
database.executeFast("CREATE TABLE IF NOT EXISTS stickers_featured(id INTEGER PRIMARY KEY, data BLOB, unread BLOB, date INTEGER, hash TEXT);").stepThis().dispose();
database.executeFast("PRAGMA user_version = 35").stepThis().dispose();
version = 35;
}
if (version == 35) {
database.executeFast("CREATE TABLE IF NOT EXISTS requested_holes(uid INTEGER, seq_out_start INTEGER, seq_out_end INTEGER, PRIMARY KEY (uid, seq_out_start, seq_out_end));").stepThis().dispose();
database.executeFast("PRAGMA user_version = 36").stepThis().dispose();
version = 36;
}
if (version == 36) {
database.executeFast("ALTER TABLE enc_chats ADD COLUMN in_seq_no INTEGER default 0").stepThis().dispose();
database.executeFast("PRAGMA user_version = 37").stepThis().dispose();
version = 37;
}
if (version == 37) {
database.executeFast("CREATE TABLE IF NOT EXISTS botcache(id TEXT PRIMARY KEY, date INTEGER, data BLOB)").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS botcache_date_idx ON botcache(date);").stepThis().dispose();
database.executeFast("PRAGMA user_version = 38").stepThis().dispose();
version = 38;
}
if (version == 38) {
database.executeFast("ALTER TABLE dialogs ADD COLUMN pinned INTEGER default 0").stepThis().dispose();
database.executeFast("PRAGMA user_version = 39").stepThis().dispose();
version = 39;
}
if (version == 39) {
database.executeFast("ALTER TABLE enc_chats ADD COLUMN admin_id INTEGER default 0").stepThis().dispose();
database.executeFast("PRAGMA user_version = 40").stepThis().dispose();
version = 40;
}
if (version == 40) {
fixNotificationSettings();
database.executeFast("PRAGMA user_version = 41").stepThis().dispose();
//version = 41;
}
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
private void cleanupInternal() {
lastDateValue = 0;
lastSeqValue = 0;
lastPtsValue = 0;
lastQtsValue = 0;
lastSecretVersion = 0;
lastSavedSeq = 0;
lastSavedPts = 0;
lastSavedDate = 0;
lastSavedQts = 0;
secretPBytes = null;
secretG = 0;
if (database != null) {
database.close();
database = null;
}
if (cacheFile != null) {
cacheFile.delete();
cacheFile = null;
}
}
public void cleanup(final boolean isLogin) {
storageQueue.cleanupQueue();
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
cleanupInternal();
openDatabase(false);
if (isLogin) {
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
MessagesController.getInstance().getDifference();
}
});
}
}
});
}
public void saveSecretParams(final int lsv, final int sg, final byte[] pbytes) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
SQLitePreparedStatement state = database.executeFast("UPDATE params SET lsv = ?, sg = ?, pbytes = ? WHERE id = 1");
state.bindInteger(1, lsv);
state.bindInteger(2, sg);
NativeByteBuffer data = new NativeByteBuffer(pbytes != null ? pbytes.length : 1);
if (pbytes != null) {
data.writeBytes(pbytes);
}
state.bindByteBuffer(3, data);
state.step();
state.dispose();
data.reuse();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
private void fixNotificationSettings() {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
HashMap<Long, Long> ids = new HashMap<>();
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE);
Map<String, ?> values = preferences.getAll();
for (Map.Entry<String, ?> entry : values.entrySet()) {
String key = entry.getKey();
if (key.startsWith("notify2_")) {
Integer value = (Integer) entry.getValue();
if (value == 2 || value == 3) {
key = key.replace("notify2_", "");
long flags;
if (value == 2) {
flags = 1;
} else {
Integer time = (Integer) values.get("notifyuntil_" + key);
if (time != null) {
flags = ((long) time << 32) | 1;
} else {
flags = 1;
}
}
try {
ids.put(Long.parseLong(key), flags);
} catch (Exception e) {
e.printStackTrace();
}
} else if (value == 3) {
}
}
}
try {
database.beginTransaction();
SQLitePreparedStatement state = database.executeFast("REPLACE INTO dialog_settings VALUES(?, ?)");
for (HashMap.Entry<Long, Long> entry : ids.entrySet()) {
state.requery();
state.bindLong(1, entry.getKey());
state.bindLong(2, entry.getValue());
state.step();
}
state.dispose();
database.commitTransaction();
} catch (Exception e) {
FileLog.e(e);
}
} catch (Throwable e) {
FileLog.e(e);
}
}
});
}
public long createPendingTask(final NativeByteBuffer data) {
if (data == null) {
return 0;
}
final long id = lastTaskId.getAndAdd(1);
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
SQLitePreparedStatement state = database.executeFast("REPLACE INTO pending_tasks VALUES(?, ?)");
state.bindLong(1, id);
state.bindByteBuffer(2, data);
state.step();
state.dispose();
} catch (Exception e) {
FileLog.e(e);
} finally {
data.reuse();
}
}
});
return id;
}
public void removePendingTask(final long id) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
database.executeFast("DELETE FROM pending_tasks WHERE id = " + id).stepThis().dispose();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
private void loadPendingTasks() {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
SQLiteCursor cursor = database.queryFinalized("SELECT id, data FROM pending_tasks WHERE 1");
while (cursor.next()) {
final long taskId = cursor.longValue(0);
NativeByteBuffer data = cursor.byteBufferValue(1);
if (data != null) {
int type = data.readInt32(false);
switch (type) {
case 0: {
final TLRPC.Chat chat = TLRPC.Chat.TLdeserialize(data, data.readInt32(false), false);
if (chat != null) {
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
MessagesController.getInstance().loadUnknownChannel(chat, taskId);
}
});
}
break;
}
case 1: {
final int channelId = data.readInt32(false);
final int newDialogType = data.readInt32(false);
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
MessagesController.getInstance().getChannelDifference(channelId, newDialogType, taskId, null);
}
});
break;
}
case 2:
case 5: {
final TLRPC.TL_dialog dialog = new TLRPC.TL_dialog();
dialog.id = data.readInt64(false);
dialog.top_message = data.readInt32(false);
dialog.read_inbox_max_id = data.readInt32(false);
dialog.read_outbox_max_id = data.readInt32(false);
dialog.unread_count = data.readInt32(false);
dialog.last_message_date = data.readInt32(false);
dialog.pts = data.readInt32(false);
dialog.flags = data.readInt32(false);
if (type == 5) {
dialog.pinned = data.readBool(false);
dialog.pinnedNum = data.readInt32(false);
}
final TLRPC.InputPeer peer = TLRPC.InputPeer.TLdeserialize(data, data.readInt32(false), false);
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
MessagesController.getInstance().checkLastDialogMessage(dialog, peer, taskId);
}
});
break;
}
case 3: {
long random_id = data.readInt64(false);
TLRPC.InputPeer peer = TLRPC.InputPeer.TLdeserialize(data, data.readInt32(false), false);
TLRPC.TL_inputMediaGame game = (TLRPC.TL_inputMediaGame) TLRPC.InputMedia.TLdeserialize(data, data.readInt32(false), false);
SendMessagesHelper.getInstance().sendGame(peer, game, random_id, taskId);
break;
}
case 4: {
final long did = data.readInt64(false);
final boolean pin = data.readBool(false);
final TLRPC.InputPeer peer = TLRPC.InputPeer.TLdeserialize(data, data.readInt32(false), false);
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
MessagesController.getInstance().pinDialog(did, pin, peer, taskId);
}
});
break;
}
case 6: {
final int channelId = data.readInt32(false);
final int newDialogType = data.readInt32(false);
final TLRPC.InputChannel inputChannel = TLRPC.InputChannel.TLdeserialize(data, data.readInt32(false), false);
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
MessagesController.getInstance().getChannelDifference(channelId, newDialogType, taskId, inputChannel);
}
});
break;
}
case 7: {
final int channelId = data.readInt32(false);
int constructor = data.readInt32(false);
TLObject request = TLRPC.TL_messages_deleteMessages.TLdeserialize(data, constructor, false);
if (request == null) {
request = TLRPC.TL_channels_deleteMessages.TLdeserialize(data, constructor, false);
}
if (request == null) {
removePendingTask(taskId);
} else {
final TLObject finalRequest = request;
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
MessagesController.getInstance().deleteMessages(null, null, null, channelId, true, taskId, finalRequest);
}
});
}
break;
}
}
data.reuse();
}
}
cursor.dispose();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void saveChannelPts(final int channelId, final int pts) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET pts = ? WHERE did = ?");
state.bindInteger(1, pts);
state.bindInteger(2, -channelId);
state.step();
state.dispose();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void saveDiffParams(final int seq, final int pts, final int date, final int qts) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
if (lastSavedSeq == seq && lastSavedPts == pts && lastSavedDate == date && lastQtsValue == qts) {
return;
}
SQLitePreparedStatement state = database.executeFast("UPDATE params SET seq = ?, pts = ?, date = ?, qts = ? WHERE id = 1");
state.bindInteger(1, seq);
state.bindInteger(2, pts);
state.bindInteger(3, date);
state.bindInteger(4, qts);
state.step();
state.dispose();
lastSavedSeq = seq;
lastSavedPts = pts;
lastSavedDate = date;
lastSavedQts = qts;
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void setDialogFlags(final long did, final long flags) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
database.executeFast(String.format(Locale.US, "REPLACE INTO dialog_settings VALUES(%d, %d)", did, flags)).stepThis().dispose();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void loadUnreadMessages() {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
ArrayList<Integer> usersToLoad = new ArrayList<>();
ArrayList<Integer> chatsToLoad = new ArrayList<>();
ArrayList<Integer> encryptedChatIds = new ArrayList<>();
final HashMap<Long, Integer> pushDialogs = new HashMap<>();
SQLiteCursor cursor = database.queryFinalized("SELECT d.did, d.unread_count, s.flags FROM dialogs as d LEFT JOIN dialog_settings as s ON d.did = s.did WHERE d.unread_count != 0");
StringBuilder ids = new StringBuilder();
int currentTime = ConnectionsManager.getInstance().getCurrentTime();
while (cursor.next()) {
long flags = cursor.longValue(2);
boolean muted = (flags & 1) != 0;
int mutedUntil = (int) (flags >> 32);
if (cursor.isNull(2) || !muted || mutedUntil != 0 && mutedUntil < currentTime) {
long did = cursor.longValue(0);
int count = cursor.intValue(1);
pushDialogs.put(did, count);
if (ids.length() != 0) {
ids.append(",");
}
ids.append(did);
int lower_id = (int) did;
int high_id = (int) (did >> 32);
if (lower_id != 0) {
if (lower_id < 0) {
if (!chatsToLoad.contains(-lower_id)) {
chatsToLoad.add(-lower_id);
}
} else {
if (!usersToLoad.contains(lower_id)) {
usersToLoad.add(lower_id);
}
}
} else {
if (!encryptedChatIds.contains(high_id)) {
encryptedChatIds.add(high_id);
}
}
}
}
cursor.dispose();
ArrayList<Long> replyMessages = new ArrayList<>();
HashMap<Integer, ArrayList<TLRPC.Message>> replyMessageOwners = new HashMap<>();
final ArrayList<TLRPC.Message> messages = new ArrayList<>();
final ArrayList<TLRPC.User> users = new ArrayList<>();
final ArrayList<TLRPC.Chat> chats = new ArrayList<>();
final ArrayList<TLRPC.EncryptedChat> encryptedChats = new ArrayList<>();
if (ids.length() > 0) {
cursor = database.queryFinalized("SELECT read_state, data, send_state, mid, date, uid, replydata FROM messages WHERE uid IN (" + ids.toString() + ") AND out = 0 AND read_state IN(0,2) ORDER BY date DESC LIMIT 50");
while (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(1);
if (data != null) {
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
MessageObject.setUnreadFlags(message, cursor.intValue(0));
message.id = cursor.intValue(3);
message.date = cursor.intValue(4);
message.dialog_id = cursor.longValue(5);
messages.add(message);
int lower_id = (int) message.dialog_id;
addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad);
message.send_state = cursor.intValue(2);
if (message.to_id.channel_id == 0 && !MessageObject.isUnread(message) && lower_id != 0 || message.id > 0) { //TODO check
message.send_state = 0;
}
if (lower_id == 0 && !cursor.isNull(5)) {
message.random_id = cursor.longValue(5);
}
try {
if (message.reply_to_msg_id != 0 && (
message.action instanceof TLRPC.TL_messageActionPinMessage ||
message.action instanceof TLRPC.TL_messageActionPaymentSent ||
message.action instanceof TLRPC.TL_messageActionGameScore)) {
if (!cursor.isNull(6)) {
data = cursor.byteBufferValue(6);
if (data != null) {
message.replyMessage = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
if (message.replyMessage != null) {
addUsersAndChatsFromMessage(message.replyMessage, usersToLoad, chatsToLoad);
}
}
}
if (message.replyMessage == null) {
long messageId = message.reply_to_msg_id;
if (message.to_id.channel_id != 0) {
messageId |= ((long) message.to_id.channel_id) << 32;
}
if (!replyMessages.contains(messageId)) {
replyMessages.add(messageId);
}
ArrayList<TLRPC.Message> arrayList = replyMessageOwners.get(message.reply_to_msg_id);
if (arrayList == null) {
arrayList = new ArrayList<>();
replyMessageOwners.put(message.reply_to_msg_id, arrayList);
}
arrayList.add(message);
}
}
} catch (Exception e) {
FileLog.e(e);
}
}
}
cursor.dispose();
if (!replyMessages.isEmpty()) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages WHERE mid IN(%s)", TextUtils.join(",", replyMessages)));
while (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(0);
if (data != null) {
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
message.id = cursor.intValue(1);
message.date = cursor.intValue(2);
message.dialog_id = cursor.longValue(3);
addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad);
ArrayList<TLRPC.Message> arrayList = replyMessageOwners.get(message.id);
if (arrayList != null) {
for (int a = 0; a < arrayList.size(); a++) {
arrayList.get(a).replyMessage = message;
}
}
}
}
cursor.dispose();
}
if (!encryptedChatIds.isEmpty()) {
getEncryptedChatsInternal(TextUtils.join(",", encryptedChatIds), encryptedChats, usersToLoad);
}
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), users);
}
if (!chatsToLoad.isEmpty()) {
getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
for (int a = 0; a < chats.size(); a++) {
TLRPC.Chat chat = chats.get(a);
if (chat != null && (chat.left || chat.migrated_to != null)) {
long did = -chat.id;
database.executeFast("UPDATE dialogs SET unread_count = 0, unread_count_i = 0 WHERE did = " + did).stepThis().dispose();
database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = 3 WHERE uid = %d AND mid > 0 AND read_state IN(0,2) AND out = 0", did)).stepThis().dispose();
chats.remove(a);
a--;
pushDialogs.remove((long) -chat.id);
for (int b = 0; b < messages.size(); b++) {
TLRPC.Message message = messages.get(b);
if (message.dialog_id == -chat.id) {
messages.remove(b);
b--;
}
}
}
}
}
}
Collections.reverse(messages);
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
NotificationsController.getInstance().processLoadedUnreadMessages(pushDialogs, messages, users, chats, encryptedChats);
}
});
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void putWallpapers(final ArrayList<TLRPC.WallPaper> wallPapers) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
int num = 0;
database.executeFast("DELETE FROM wallpapers WHERE 1").stepThis().dispose();
database.beginTransaction();
SQLitePreparedStatement state = database.executeFast("REPLACE INTO wallpapers VALUES(?, ?)");
for (TLRPC.WallPaper wallPaper : wallPapers) {
state.requery();
NativeByteBuffer data = new NativeByteBuffer(wallPaper.getObjectSize());
wallPaper.serializeToStream(data);
state.bindInteger(1, num);
state.bindByteBuffer(2, data);
state.step();
num++;
data.reuse();
}
state.dispose();
database.commitTransaction();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void loadWebRecent(final int type) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
SQLiteCursor cursor = database.queryFinalized("SELECT id, image_url, thumb_url, local_url, width, height, size, date, document FROM web_recent_v3 WHERE type = " + type + " ORDER BY date DESC");
final ArrayList<MediaController.SearchImage> arrayList = new ArrayList<>();
while (cursor.next()) {
MediaController.SearchImage searchImage = new MediaController.SearchImage();
searchImage.id = cursor.stringValue(0);
searchImage.imageUrl = cursor.stringValue(1);
searchImage.thumbUrl = cursor.stringValue(2);
searchImage.localUrl = cursor.stringValue(3);
searchImage.width = cursor.intValue(4);
searchImage.height = cursor.intValue(5);
searchImage.size = cursor.intValue(6);
searchImage.date = cursor.intValue(7);
if (!cursor.isNull(8)) {
NativeByteBuffer data = cursor.byteBufferValue(8);
if (data != null) {
searchImage.document = TLRPC.Document.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
}
}
searchImage.type = type;
arrayList.add(searchImage);
}
cursor.dispose();
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
NotificationCenter.getInstance().postNotificationName(NotificationCenter.recentImagesDidLoaded, type, arrayList);
}
});
} catch (Throwable e) {
FileLog.e(e);
}
}
});
}
public void addRecentLocalFile(final String imageUrl, final String localUrl, final TLRPC.Document document) {
if (imageUrl == null || imageUrl.length() == 0 || ((localUrl == null || localUrl.length() == 0) && document == null)) {
return;
}
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
if (document != null) {
SQLitePreparedStatement state = database.executeFast("UPDATE web_recent_v3 SET document = ? WHERE image_url = ?");
state.requery();
NativeByteBuffer data = new NativeByteBuffer(document.getObjectSize());
document.serializeToStream(data);
state.bindByteBuffer(1, data);
state.bindString(2, imageUrl);
state.step();
state.dispose();
data.reuse();
} else {
SQLitePreparedStatement state = database.executeFast("UPDATE web_recent_v3 SET local_url = ? WHERE image_url = ?");
state.requery();
state.bindString(1, localUrl);
state.bindString(2, imageUrl);
state.step();
state.dispose();
}
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void clearWebRecent(final int type) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
database.executeFast("DELETE FROM web_recent_v3 WHERE type = " + type).stepThis().dispose();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void putWebRecent(final ArrayList<MediaController.SearchImage> arrayList) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
database.beginTransaction();
SQLitePreparedStatement state = database.executeFast("REPLACE INTO web_recent_v3 VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
for (int a = 0; a < arrayList.size(); a++) {
if (a == 200) {
break;
}
MediaController.SearchImage searchImage = arrayList.get(a);
state.requery();
state.bindString(1, searchImage.id);
state.bindInteger(2, searchImage.type);
state.bindString(3, searchImage.imageUrl != null ? searchImage.imageUrl : "");
state.bindString(4, searchImage.thumbUrl != null ? searchImage.thumbUrl : "");
state.bindString(5, searchImage.localUrl != null ? searchImage.localUrl : "");
state.bindInteger(6, searchImage.width);
state.bindInteger(7, searchImage.height);
state.bindInteger(8, searchImage.size);
state.bindInteger(9, searchImage.date);
NativeByteBuffer data = null;
if (searchImage.document != null) {
data = new NativeByteBuffer(searchImage.document.getObjectSize());
searchImage.document.serializeToStream(data);
state.bindByteBuffer(10, data);
} else {
state.bindNull(10);
}
state.step();
if (data != null) {
data.reuse();
}
}
state.dispose();
database.commitTransaction();
if (arrayList.size() >= 200) {
database.beginTransaction();
for (int a = 200; a < arrayList.size(); a++) {
database.executeFast("DELETE FROM web_recent_v3 WHERE id = '" + arrayList.get(a).id + "'").stepThis().dispose();
}
database.commitTransaction();
}
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void getWallpapers() {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
SQLiteCursor cursor = database.queryFinalized("SELECT data FROM wallpapers WHERE 1");
final ArrayList<TLRPC.WallPaper> wallPapers = new ArrayList<>();
while (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(0);
if (data != null) {
TLRPC.WallPaper wallPaper = TLRPC.WallPaper.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
wallPapers.add(wallPaper);
}
}
cursor.dispose();
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
NotificationCenter.getInstance().postNotificationName(NotificationCenter.wallpapersDidLoaded, wallPapers);
}
});
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void getBlockedUsers() {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
ArrayList<Integer> ids = new ArrayList<>();
ArrayList<TLRPC.User> users = new ArrayList<>();
SQLiteCursor cursor = database.queryFinalized("SELECT * FROM blocked_users WHERE 1");
StringBuilder usersToLoad = new StringBuilder();
while (cursor.next()) {
int user_id = cursor.intValue(0);
ids.add(user_id);
if (usersToLoad.length() != 0) {
usersToLoad.append(",");
}
usersToLoad.append(user_id);
}
cursor.dispose();
if (usersToLoad.length() != 0) {
getUsersInternal(usersToLoad.toString(), users);
}
MessagesController.getInstance().processLoadedBlockedUsers(ids, users, true);
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void deleteBlockedUser(final int id) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
database.executeFast("DELETE FROM blocked_users WHERE uid = " + id).stepThis().dispose();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void putBlockedUsers(final ArrayList<Integer> ids, final boolean replace) {
if (ids == null || ids.isEmpty()) {
return;
}
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
if (replace) {
database.executeFast("DELETE FROM blocked_users WHERE 1").stepThis().dispose();
}
database.beginTransaction();
SQLitePreparedStatement state = database.executeFast("REPLACE INTO blocked_users VALUES(?)");
for (Integer id : ids) {
state.requery();
state.bindInteger(1, id);
state.step();
}
state.dispose();
database.commitTransaction();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void deleteUserChannelHistory(final int channelId, final int uid) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
long did = -channelId;
final ArrayList<Integer> mids = new ArrayList<>();
SQLiteCursor cursor = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did);
ArrayList<File> filesToDelete = new ArrayList<>();
try {
while (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(0);
if (data != null) {
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
if (message != null && message.from_id == uid && message.id != 1) {
mids.add(message.id);
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) {
File file = FileLoader.getPathToAttach(photoSize);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
File file = FileLoader.getPathToAttach(message.media.document);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
file = FileLoader.getPathToAttach(message.media.document.thumb);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
}
}
}
} catch (Exception e) {
FileLog.e(e);
}
cursor.dispose();
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
MessagesController.getInstance().markChannelDialogMessageAsDeleted(mids, channelId);
}
});
markMessagesAsDeletedInternal(mids, channelId);
updateDialogsWithDeletedMessagesInternal(mids, null, channelId);
FileLoader.getInstance().deleteFiles(filesToDelete, 0);
if (!mids.isEmpty()) {
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesDeleted, mids, channelId);
}
});
}
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void deleteDialog(final long did, final int messagesOnly) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
if (messagesOnly == 3) {
int lastMid = -1;
SQLiteCursor cursor = database.queryFinalized("SELECT last_mid FROM dialogs WHERE did = " + did);
if (cursor.next()) {
lastMid = cursor.intValue(0);
}
cursor.dispose();
if (lastMid != 0) {
return;
}
}
if ((int) did == 0 || messagesOnly == 2) {
SQLiteCursor cursor = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did);
ArrayList<File> filesToDelete = new ArrayList<>();
try {
while (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(0);
if (data != null) {
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
if (message != null && message.media != null) {
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) {
File file = FileLoader.getPathToAttach(photoSize);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
File file = FileLoader.getPathToAttach(message.media.document);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
file = FileLoader.getPathToAttach(message.media.document.thumb);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
}
}
}
} catch (Exception e) {
FileLog.e(e);
}
cursor.dispose();
FileLoader.getInstance().deleteFiles(filesToDelete, messagesOnly);
}
if (messagesOnly == 0 || messagesOnly == 3) {
database.executeFast("DELETE FROM dialogs WHERE did = " + did).stepThis().dispose();
database.executeFast("DELETE FROM chat_settings_v2 WHERE uid = " + did).stepThis().dispose();
database.executeFast("DELETE FROM chat_pinned WHERE uid = " + did).stepThis().dispose();
database.executeFast("DELETE FROM channel_users_v2 WHERE did = " + did).stepThis().dispose();
database.executeFast("DELETE FROM search_recent WHERE did = " + did).stepThis().dispose();
int lower_id = (int) did;
int high_id = (int) (did >> 32);
if (lower_id != 0) {
if (high_id == 1) {
database.executeFast("DELETE FROM chats WHERE uid = " + lower_id).stepThis().dispose();
} else if (lower_id < 0) {
//database.executeFast("DELETE FROM chats WHERE uid = " + (-lower_id)).stepThis().dispose();
}
} else {
database.executeFast("DELETE FROM enc_chats WHERE uid = " + high_id).stepThis().dispose();
//database.executeFast("DELETE FROM secret_holes WHERE uid = " + high_id).stepThis().dispose();
}
} else if (messagesOnly == 2) {
SQLiteCursor cursor = database.queryFinalized("SELECT last_mid_i, last_mid FROM dialogs WHERE did = " + did);
int messageId = -1;
if (cursor.next()) {
long last_mid_i = cursor.longValue(0);
long last_mid = cursor.longValue(1);
SQLiteCursor cursor2 = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did + " AND mid IN (" + last_mid_i + "," + last_mid + ")");
try {
while (cursor2.next()) {
NativeByteBuffer data = cursor2.byteBufferValue(0);
if (data != null) {
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
if (message != null) {
messageId = message.id;
}
}
}
} catch (Exception e) {
FileLog.e(e);
}
cursor2.dispose();
database.executeFast("DELETE FROM messages WHERE uid = " + did + " AND mid != " + last_mid_i + " AND mid != " + last_mid).stepThis().dispose();
database.executeFast("DELETE FROM messages_holes WHERE uid = " + did).stepThis().dispose();
database.executeFast("DELETE FROM bot_keyboard WHERE uid = " + did).stepThis().dispose();
database.executeFast("DELETE FROM media_counts_v2 WHERE uid = " + did).stepThis().dispose();
database.executeFast("DELETE FROM media_v2 WHERE uid = " + did).stepThis().dispose();
database.executeFast("DELETE FROM media_holes_v2 WHERE uid = " + did).stepThis().dispose();
BotQuery.clearBotKeyboard(did, null);
SQLitePreparedStatement state5 = database.executeFast("REPLACE INTO messages_holes VALUES(?, ?, ?)");
SQLitePreparedStatement state6 = database.executeFast("REPLACE INTO media_holes_v2 VALUES(?, ?, ?, ?)");
if (messageId != -1) {
createFirstHoles(did, state5, state6, messageId);
}
state5.dispose();
state6.dispose();
}
cursor.dispose();
return;
}
database.executeFast("UPDATE dialogs SET unread_count = 0, unread_count_i = 0 WHERE did = " + did).stepThis().dispose();
database.executeFast("DELETE FROM messages WHERE uid = " + did).stepThis().dispose();
database.executeFast("DELETE FROM bot_keyboard WHERE uid = " + did).stepThis().dispose();
database.executeFast("DELETE FROM media_counts_v2 WHERE uid = " + did).stepThis().dispose();
database.executeFast("DELETE FROM media_v2 WHERE uid = " + did).stepThis().dispose();
database.executeFast("DELETE FROM messages_holes WHERE uid = " + did).stepThis().dispose();
database.executeFast("DELETE FROM media_holes_v2 WHERE uid = " + did).stepThis().dispose();
BotQuery.clearBotKeyboard(did, null);
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
NotificationCenter.getInstance().postNotificationName(NotificationCenter.needReloadRecentDialogsSearch);
}
});
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void getDialogPhotos(final int did, final int offset, final int count, final long max_id, final int classGuid) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
SQLiteCursor cursor;
if (max_id != 0) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM user_photos WHERE uid = %d AND id < %d ORDER BY id DESC LIMIT %d", did, max_id, count));
} else {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM user_photos WHERE uid = %d ORDER BY id DESC LIMIT %d,%d", did, offset, count));
}
final TLRPC.photos_Photos res = new TLRPC.photos_Photos();
while (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(0);
if (data != null) {
TLRPC.Photo photo = TLRPC.Photo.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
res.photos.add(photo);
}
}
cursor.dispose();
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
MessagesController.getInstance().processLoadedUserPhotos(res, did, offset, count, max_id, true, classGuid);
}
});
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void clearUserPhotos(final int uid) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
database.executeFast("DELETE FROM user_photos WHERE uid = " + uid).stepThis().dispose();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void clearUserPhoto(final int uid, final long pid) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
database.executeFast("DELETE FROM user_photos WHERE uid = " + uid + " AND id = " + pid).stepThis().dispose();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void putDialogPhotos(final int did, final TLRPC.photos_Photos photos) {
if (photos == null || photos.photos.isEmpty()) {
return;
}
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
SQLitePreparedStatement state = database.executeFast("REPLACE INTO user_photos VALUES(?, ?, ?)");
for (TLRPC.Photo photo : photos.photos) {
if (photo instanceof TLRPC.TL_photoEmpty) {
continue;
}
state.requery();
NativeByteBuffer data = new NativeByteBuffer(photo.getObjectSize());
photo.serializeToStream(data);
state.bindInteger(1, did);
state.bindLong(2, photo.id);
state.bindByteBuffer(3, data);
state.step();
data.reuse();
}
state.dispose();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void getNewTask(final ArrayList<Integer> oldTask) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
if (oldTask != null) {
String ids = TextUtils.join(",", oldTask);
database.executeFast(String.format(Locale.US, "DELETE FROM enc_tasks_v2 WHERE mid IN(%s)", ids)).stepThis().dispose();
}
int date = 0;
ArrayList<Integer> arr = null;
SQLiteCursor cursor = database.queryFinalized("SELECT mid, date FROM enc_tasks_v2 WHERE date = (SELECT min(date) FROM enc_tasks_v2)");
while (cursor.next()) {
Integer mid = cursor.intValue(0);
date = cursor.intValue(1);
if (arr == null) {
arr = new ArrayList<>();
}
arr.add(mid);
}
cursor.dispose();
MessagesController.getInstance().processLoadedDeleteTask(date, arr);
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void createTaskForSecretChat(final int chat_id, final int time, final int readTime, final int isOut, final ArrayList<Long> random_ids) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
int minDate = Integer.MAX_VALUE;
SparseArray<ArrayList<Integer>> messages = new SparseArray<>();
final ArrayList<Long> midsArray = new ArrayList<>();
StringBuilder mids = new StringBuilder();
SQLiteCursor cursor;
if (random_ids == null) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, ttl FROM messages WHERE uid = %d AND out = %d AND read_state != 0 AND ttl > 0 AND date <= %d AND send_state = 0 AND media != 1", ((long) chat_id) << 32, isOut, time));
} else {
String ids = TextUtils.join(",", random_ids);
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.mid, m.ttl FROM messages as m INNER JOIN randoms as r ON m.mid = r.mid WHERE r.random_id IN (%s)", ids));
}
while (cursor.next()) {
int ttl = cursor.intValue(1);
int mid = cursor.intValue(0);
if (random_ids != null) {
midsArray.add((long) mid);
}
if (ttl <= 0) {
continue;
}
int date = (time > readTime ? time : readTime) + ttl;
minDate = Math.min(minDate, date);
ArrayList<Integer> arr = messages.get(date);
if (arr == null) {
arr = new ArrayList<>();
messages.put(date, arr);
}
if (mids.length() != 0) {
mids.append(",");
}
mids.append(mid);
arr.add(mid);
}
cursor.dispose();
if (random_ids != null) {
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
MessagesStorage.getInstance().markMessagesContentAsRead(midsArray);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesReadContent, midsArray);
}
});
}
if (messages.size() != 0) {
database.beginTransaction();
SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_tasks_v2 VALUES(?, ?)");
for (int a = 0; a < messages.size(); a++) {
int key = messages.keyAt(a);
ArrayList<Integer> arr = messages.get(key);
for (int b = 0; b < arr.size(); b++) {
state.requery();
state.bindInteger(1, arr.get(b));
state.bindInteger(2, key);
state.step();
}
}
state.dispose();
database.commitTransaction();
database.executeFast(String.format(Locale.US, "UPDATE messages SET ttl = 0 WHERE mid IN(%s)", mids.toString())).stepThis().dispose();
MessagesController.getInstance().didAddedNewTask(minDate, messages);
}
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
private void updateDialogsWithReadMessagesInternal(final ArrayList<Integer> messages, final SparseArray<Long> inbox, final SparseArray<Long> outbox) {
try {
HashMap<Long, Integer> dialogsToUpdate = new HashMap<>();
if (messages != null && !messages.isEmpty()) {
String ids = TextUtils.join(",", messages);
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT uid, read_state, out FROM messages WHERE mid IN(%s)", ids));
while (cursor.next()) {
int out = cursor.intValue(2);
if (out != 0) {
continue;
}
int read_state = cursor.intValue(1);
if (read_state != 0) {
continue;
}
long uid = cursor.longValue(0);
Integer currentCount = dialogsToUpdate.get(uid);
if (currentCount == null) {
dialogsToUpdate.put(uid, 1);
} else {
dialogsToUpdate.put(uid, currentCount + 1);
}
}
cursor.dispose();
} else {
if (inbox != null && inbox.size() != 0) {
for (int b = 0; b < inbox.size(); b++) {
int key = inbox.keyAt(b);
long messageId = inbox.get(key);
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(mid) FROM messages WHERE uid = %d AND mid > %d AND read_state IN(0,2) AND out = 0", key, messageId));
if (cursor.next()) {
int count = cursor.intValue(0);
dialogsToUpdate.put((long) key, count);
}
cursor.dispose();
SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET inbox_max = max((SELECT inbox_max FROM dialogs WHERE did = ?), ?) WHERE did = ?");
state.requery();
state.bindLong(1, key);
state.bindInteger(2, (int) messageId);
state.bindLong(3, key);
state.step();
state.dispose();
}
}
if (outbox != null && outbox.size() != 0) {
for (int b = 0; b < outbox.size(); b++) {
int key = outbox.keyAt(b);
long messageId = outbox.get(key);
SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET outbox_max = max((SELECT outbox_max FROM dialogs WHERE did = ?), ?) WHERE did = ?");
state.requery();
state.bindLong(1, key);
state.bindInteger(2, (int) messageId);
state.bindLong(3, key);
state.step();
state.dispose();
}
}
}
if (!dialogsToUpdate.isEmpty()) {
database.beginTransaction();
SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET unread_count = ? WHERE did = ?");
for (HashMap.Entry<Long, Integer> entry : dialogsToUpdate.entrySet()) {
state.requery();
state.bindInteger(1, entry.getValue());
state.bindLong(2, entry.getKey());
state.step();
}
state.dispose();
database.commitTransaction();
}
if (!dialogsToUpdate.isEmpty()) {
MessagesController.getInstance().processDialogsUpdateRead(dialogsToUpdate);
}
} catch (Exception e) {
FileLog.e(e);
}
}
public void updateDialogsWithReadMessages(final SparseArray<Long> inbox, final SparseArray<Long> outbox, boolean useQueue) {
if (inbox.size() == 0) {
return;
}
if (useQueue) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
updateDialogsWithReadMessagesInternal(null, inbox, outbox);
}
});
} else {
updateDialogsWithReadMessagesInternal(null, inbox, outbox);
}
}
public void updateChatParticipants(final TLRPC.ChatParticipants participants) {
if (participants == null) {
return;
}
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + participants.chat_id);
TLRPC.ChatFull info = null;
ArrayList<TLRPC.User> loadedUsers = new ArrayList<>();
if (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(0);
if (data != null) {
info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
info.pinned_msg_id = cursor.intValue(1);
}
}
cursor.dispose();
if (info instanceof TLRPC.TL_chatFull) {
info.participants = participants;
final TLRPC.ChatFull finalInfo = info;
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false, null);
}
});
SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)");
NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize());
info.serializeToStream(data);
state.bindInteger(1, info.id);
state.bindByteBuffer(2, data);
state.bindInteger(3, info.pinned_msg_id);
state.step();
state.dispose();
data.reuse();
}
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void updateChannelUsers(final int channel_id, final ArrayList<TLRPC.ChannelParticipant> participants) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
long did = -channel_id;
database.executeFast("DELETE FROM channel_users_v2 WHERE did = " + did).stepThis().dispose();
database.beginTransaction();
SQLitePreparedStatement state = database.executeFast("REPLACE INTO channel_users_v2 VALUES(?, ?, ?, ?)");
NativeByteBuffer data;
int date = (int) (System.currentTimeMillis() / 1000);
for (int a = 0; a < participants.size(); a++) {
TLRPC.ChannelParticipant participant = participants.get(a);
state.requery();
state.bindLong(1, did);
state.bindInteger(2, participant.user_id);
state.bindInteger(3, date);
data = new NativeByteBuffer(participant.getObjectSize());
participant.serializeToStream(data);
state.bindByteBuffer(4, data);
data.reuse();
state.step();
date--;
}
state.dispose();
database.commitTransaction();
loadChatInfo(channel_id, null, false, true);
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void saveBotCache(final String key, final TLObject result) {
if (result == null || TextUtils.isEmpty(key)) {
return;
}
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
int currentDate = ConnectionsManager.getInstance().getCurrentTime();
if (result instanceof TLRPC.TL_messages_botCallbackAnswer) {
currentDate += ((TLRPC.TL_messages_botCallbackAnswer) result).cache_time;
} else if (result instanceof TLRPC.TL_messages_botResults) {
currentDate += ((TLRPC.TL_messages_botResults) result).cache_time;
}
SQLitePreparedStatement state = database.executeFast("REPLACE INTO botcache VALUES(?, ?, ?)");
NativeByteBuffer data = new NativeByteBuffer(result.getObjectSize());
result.serializeToStream(data);
state.bindString(1, key);
state.bindInteger(2, currentDate);
state.bindByteBuffer(3, data);
state.step();
state.dispose();
data.reuse();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void getBotCache(final String key, final RequestDelegate requestDelegate) {
if (key == null || requestDelegate == null) {
return;
}
final int currentDate = ConnectionsManager.getInstance().getCurrentTime();
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
TLObject result = null;
try {
database.executeFast("DELETE FROM botcache WHERE date < " + currentDate).stepThis().dispose();
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM botcache WHERE id = '%s'", key));
if (cursor.next()) {
try {
NativeByteBuffer data = cursor.byteBufferValue(0);
if (data != null) {
int constructor = data.readInt32(false);
if (constructor == TLRPC.TL_messages_botCallbackAnswer.constructor) {
result = TLRPC.TL_messages_botCallbackAnswer.TLdeserialize(data, constructor, false);
} else {
result = TLRPC.TL_messages_botResults.TLdeserialize(data, constructor, false);
}
data.reuse();
}
} catch (Exception e) {
FileLog.e(e);
}
}
cursor.dispose();
} catch (Exception e) {
FileLog.e(e);
} finally {
requestDelegate.run(result, null);
}
}
});
}
public void updateChatInfo(final TLRPC.ChatFull info, final boolean ifExist) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
if (ifExist) {
SQLiteCursor cursor = database.queryFinalized("SELECT uid FROM chat_settings_v2 WHERE uid = " + info.id);
boolean exist = cursor.next();
cursor.dispose();
if (!exist) {
return;
}
}
SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)");
NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize());
info.serializeToStream(data);
state.bindInteger(1, info.id);
state.bindByteBuffer(2, data);
state.bindInteger(3, info.pinned_msg_id);
state.step();
state.dispose();
data.reuse();
if (info instanceof TLRPC.TL_channelFull) {
SQLiteCursor cursor = database.queryFinalized("SELECT date, pts, last_mid, inbox_max, outbox_max, pinned FROM dialogs WHERE did = " + (-info.id));
if (cursor.next()) {
int inbox_max = cursor.intValue(3);
if (inbox_max <= info.read_inbox_max_id) {
int inbox_diff = info.read_inbox_max_id - inbox_max;
if (inbox_diff < info.unread_count) {
info.unread_count = inbox_diff;
}
int dialog_date = cursor.intValue(0);
int pts = cursor.intValue(1);
long last_mid = cursor.longValue(2);
int outbox_max = cursor.intValue(4);
int pinned = cursor.intValue(5);
state = database.executeFast("REPLACE INTO dialogs VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
state.bindLong(1, -info.id);
state.bindInteger(2, dialog_date);
state.bindInteger(3, info.unread_count);
state.bindLong(4, last_mid);
state.bindInteger(5, info.read_inbox_max_id);
state.bindInteger(6, Math.max(outbox_max, info.read_outbox_max_id));
state.bindLong(7, 0);
state.bindInteger(8, 0);
state.bindInteger(9, pts);
state.bindInteger(10, 0);
state.bindInteger(11, pinned);
state.step();
state.dispose();
}
}
cursor.dispose();
}
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void updateChannelPinnedMessage(final int channelId, final int messageId) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + channelId);
TLRPC.ChatFull info = null;
ArrayList<TLRPC.User> loadedUsers = new ArrayList<>();
if (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(0);
if (data != null) {
info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
info.pinned_msg_id = cursor.intValue(1);
}
}
cursor.dispose();
if (info instanceof TLRPC.TL_channelFull) {
info.pinned_msg_id = messageId;
info.flags |= 32;
final TLRPC.ChatFull finalInfo = info;
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false, null);
}
});
SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)");
NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize());
info.serializeToStream(data);
state.bindInteger(1, channelId);
state.bindByteBuffer(2, data);
state.bindInteger(3, info.pinned_msg_id);
state.step();
state.dispose();
data.reuse();
}
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void updateChatInfo(final int chat_id, final int user_id, final int what, final int invited_id, final int version) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + chat_id);
TLRPC.ChatFull info = null;
ArrayList<TLRPC.User> loadedUsers = new ArrayList<>();
if (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(0);
if (data != null) {
info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
info.pinned_msg_id = cursor.intValue(1);
}
}
cursor.dispose();
if (info instanceof TLRPC.TL_chatFull) {
if (what == 1) {
for (int a = 0; a < info.participants.participants.size(); a++) {
TLRPC.ChatParticipant participant = info.participants.participants.get(a);
if (participant.user_id == user_id) {
info.participants.participants.remove(a);
break;
}
}
} else if (what == 0) {
for (TLRPC.ChatParticipant part : info.participants.participants) {
if (part.user_id == user_id) {
return;
}
}
TLRPC.TL_chatParticipant participant = new TLRPC.TL_chatParticipant();
participant.user_id = user_id;
participant.inviter_id = invited_id;
participant.date = ConnectionsManager.getInstance().getCurrentTime();
info.participants.participants.add(participant);
} else if (what == 2) {
for (int a = 0; a < info.participants.participants.size(); a++) {
TLRPC.ChatParticipant participant = info.participants.participants.get(a);
if (participant.user_id == user_id) {
TLRPC.ChatParticipant newParticipant;
if (invited_id == 1) {
newParticipant = new TLRPC.TL_chatParticipantAdmin();
newParticipant.user_id = participant.user_id;
newParticipant.date = participant.date;
newParticipant.inviter_id = participant.inviter_id;
} else {
newParticipant = new TLRPC.TL_chatParticipant();
newParticipant.user_id = participant.user_id;
newParticipant.date = participant.date;
newParticipant.inviter_id = participant.inviter_id;
}
info.participants.participants.set(a, newParticipant);
break;
}
}
}
info.participants.version = version;
final TLRPC.ChatFull finalInfo = info;
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false, null);
}
});
SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)");
NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize());
info.serializeToStream(data);
state.bindInteger(1, chat_id);
state.bindByteBuffer(2, data);
state.bindInteger(3, info.pinned_msg_id);
state.step();
state.dispose();
data.reuse();
}
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public boolean isMigratedChat(final int chat_id) {
final Semaphore semaphore = new Semaphore(0);
final boolean result[] = new boolean[1];
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
SQLiteCursor cursor = database.queryFinalized("SELECT info FROM chat_settings_v2 WHERE uid = " + chat_id);
TLRPC.ChatFull info = null;
ArrayList<TLRPC.User> loadedUsers = new ArrayList<>();
if (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(0);
if (data != null) {
info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
}
}
cursor.dispose();
result[0] = info instanceof TLRPC.TL_channelFull && info.migrated_from_chat_id != 0;
if (semaphore != null) {
semaphore.release();
}
} catch (Exception e) {
FileLog.e(e);
} finally {
if (semaphore != null) {
semaphore.release();
}
}
}
});
try {
semaphore.acquire();
} catch (Exception e) {
FileLog.e(e);
}
return result[0];
}
public void loadChatInfo(final int chat_id, final Semaphore semaphore, final boolean force, final boolean byChannelUsers) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
MessageObject pinnedMessageObject = null;
TLRPC.ChatFull info = null;
ArrayList<TLRPC.User> loadedUsers = new ArrayList<>();
try {
SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + chat_id);
if (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(0);
if (data != null) {
info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
info.pinned_msg_id = cursor.intValue(1);
}
}
cursor.dispose();
if (info instanceof TLRPC.TL_chatFull) {
StringBuilder usersToLoad = new StringBuilder();
for (int a = 0; a < info.participants.participants.size(); a++) {
TLRPC.ChatParticipant c = info.participants.participants.get(a);
if (usersToLoad.length() != 0) {
usersToLoad.append(",");
}
usersToLoad.append(c.user_id);
}
if (usersToLoad.length() != 0) {
getUsersInternal(usersToLoad.toString(), loadedUsers);
}
} else if (info instanceof TLRPC.TL_channelFull) {
cursor = database.queryFinalized("SELECT us.data, us.status, cu.data, cu.date FROM channel_users_v2 as cu LEFT JOIN users as us ON us.uid = cu.uid WHERE cu.did = " + (-chat_id) + " ORDER BY cu.date DESC");
info.participants = new TLRPC.TL_chatParticipants();
while (cursor.next()) {
try {
TLRPC.User user = null;
TLRPC.ChannelParticipant participant = null;
NativeByteBuffer data = cursor.byteBufferValue(0);
if (data != null) {
user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
}
data = cursor.byteBufferValue(2);
if (data != null) {
participant = TLRPC.ChannelParticipant.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
}
if (user != null && participant != null) {
if (user.status != null) {
user.status.expires = cursor.intValue(1);
}
loadedUsers.add(user);
participant.date = cursor.intValue(3);
TLRPC.TL_chatChannelParticipant chatChannelParticipant = new TLRPC.TL_chatChannelParticipant();
chatChannelParticipant.user_id = participant.user_id;
chatChannelParticipant.date = participant.date;
chatChannelParticipant.inviter_id = participant.inviter_id;
chatChannelParticipant.channelParticipant = participant;
info.participants.participants.add(chatChannelParticipant);
}
} catch (Exception e) {
FileLog.e(e);
}
}
cursor.dispose();
StringBuilder usersToLoad = new StringBuilder();
for (int a = 0; a < info.bot_info.size(); a++) {
TLRPC.BotInfo botInfo = info.bot_info.get(a);
if (usersToLoad.length() != 0) {
usersToLoad.append(",");
}
usersToLoad.append(botInfo.user_id);
}
if (usersToLoad.length() != 0) {
getUsersInternal(usersToLoad.toString(), loadedUsers);
}
}
if (semaphore != null) {
semaphore.release();
}
if (info instanceof TLRPC.TL_channelFull && info.pinned_msg_id != 0) {
pinnedMessageObject = MessagesQuery.loadPinnedMessage(chat_id, info.pinned_msg_id, false);
}
} catch (Exception e) {
FileLog.e(e);
} finally {
MessagesController.getInstance().processChatInfo(chat_id, info, loadedUsers, true, force, byChannelUsers, pinnedMessageObject);
if (semaphore != null) {
semaphore.release();
}
}
}
});
}
public void processPendingRead(final long dialog_id, final long max_id, final int max_date) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
database.beginTransaction();
SQLitePreparedStatement state;
int lower_id = (int) dialog_id;
if (lower_id != 0) {
state = database.executeFast("UPDATE messages SET read_state = read_state | 1 WHERE uid = ? AND mid <= ? AND read_state IN(0,2) AND out = 0");
state.requery();
state.bindLong(1, dialog_id);
state.bindLong(2, max_id);
state.step();
state.dispose();
} else {
state = database.executeFast("UPDATE messages SET read_state = read_state | 1 WHERE uid = ? AND date <= ? AND read_state IN(0,2) AND out = 0");
state.requery();
state.bindLong(1, dialog_id);
state.bindInteger(2, max_date);
state.step();
state.dispose();
}
int currentMaxId = 0;
SQLiteCursor cursor = database.queryFinalized("SELECT inbox_max FROM dialogs WHERE did = " + dialog_id);
if (cursor.next()) {
currentMaxId = cursor.intValue(0);
}
cursor.dispose();
currentMaxId = Math.max(currentMaxId, (int) max_id);
state = database.executeFast("UPDATE dialogs SET unread_count = 0, unread_count_i = 0, inbox_max = ? WHERE did = ?");
state.requery();
state.bindInteger(1, currentMaxId);
state.bindLong(2, dialog_id);
state.step();
state.dispose();
database.commitTransaction();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void putContacts(ArrayList<TLRPC.TL_contact> contacts, final boolean deleteAll) {
if (contacts.isEmpty()) {
return;
}
final ArrayList<TLRPC.TL_contact> contactsCopy = new ArrayList<>(contacts);
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
if (deleteAll) {
database.executeFast("DELETE FROM contacts WHERE 1").stepThis().dispose();
}
database.beginTransaction();
SQLitePreparedStatement state = database.executeFast("REPLACE INTO contacts VALUES(?, ?)");
for (int a = 0; a < contactsCopy.size(); a++) {
TLRPC.TL_contact contact = contactsCopy.get(a);
state.requery();
state.bindInteger(1, contact.user_id);
state.bindInteger(2, contact.mutual ? 1 : 0);
state.step();
}
state.dispose();
database.commitTransaction();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void deleteContacts(final ArrayList<Integer> uids) {
if (uids == null || uids.isEmpty()) {
return;
}
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
String ids = TextUtils.join(",", uids);
database.executeFast("DELETE FROM contacts WHERE uid IN(" + ids + ")").stepThis().dispose();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void applyPhoneBookUpdates(final String adds, final String deletes) {
if (adds.length() == 0 && deletes.length() == 0) {
return;
}
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
if (adds.length() != 0) {
database.executeFast(String.format(Locale.US, "UPDATE user_phones_v6 SET deleted = 0 WHERE sphone IN(%s)", adds)).stepThis().dispose();
}
if (deletes.length() != 0) {
database.executeFast(String.format(Locale.US, "UPDATE user_phones_v6 SET deleted = 1 WHERE sphone IN(%s)", deletes)).stepThis().dispose();
}
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void putCachedPhoneBook(final HashMap<Integer, ContactsController.Contact> contactHashMap) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
database.beginTransaction();
SQLitePreparedStatement state = database.executeFast("REPLACE INTO user_contacts_v6 VALUES(?, ?, ?)");
SQLitePreparedStatement state2 = database.executeFast("REPLACE INTO user_phones_v6 VALUES(?, ?, ?, ?)");
for (HashMap.Entry<Integer, ContactsController.Contact> entry : contactHashMap.entrySet()) {
ContactsController.Contact contact = entry.getValue();
if (contact.phones.isEmpty() || contact.shortPhones.isEmpty()) {
continue;
}
state.requery();
state.bindInteger(1, contact.id);
state.bindString(2, contact.first_name);
state.bindString(3, contact.last_name);
state.step();
for (int a = 0; a < contact.phones.size(); a++) {
state2.requery();
state2.bindInteger(1, contact.id);
state2.bindString(2, contact.phones.get(a));
state2.bindString(3, contact.shortPhones.get(a));
state2.bindInteger(4, contact.phoneDeleted.get(a));
state2.step();
}
}
state.dispose();
state2.dispose();
database.commitTransaction();
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public void getCachedPhoneBook() {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
HashMap<Integer, ContactsController.Contact> contactHashMap = new HashMap<>();
try {
SQLiteCursor cursor = database.queryFinalized("SELECT us.uid, us.fname, us.sname, up.phone, up.sphone, up.deleted FROM user_contacts_v6 as us LEFT JOIN user_phones_v6 as up ON us.uid = up.uid WHERE 1");
while (cursor.next()) {
int uid = cursor.intValue(0);
ContactsController.Contact contact = contactHashMap.get(uid);
if (contact == null) {
contact = new ContactsController.Contact();
contact.first_name = cursor.stringValue(1);
contact.last_name = cursor.stringValue(2);
if (contact.first_name == null) {
contact.first_name = "";
}
if (contact.last_name == null) {
contact.last_name = "";
}
contact.id = uid;
contactHashMap.put(uid, contact);
}
String phone = cursor.stringValue(3);
if (phone == null) {
continue;
}
contact.phones.add(phone);
String sphone = cursor.stringValue(4);
if (sphone == null) {
continue;
}
if (sphone.length() == 8 && phone.length() != 8) {
sphone = PhoneFormat.stripExceptNumbers(phone);
}
contact.shortPhones.add(sphone);
contact.phoneDeleted.add(cursor.intValue(5));
contact.phoneTypes.add("");
}
cursor.dispose();
} catch (Exception e) {
contactHashMap.clear();
FileLog.e(e);
}
ContactsController.getInstance().performSyncPhoneBook(contactHashMap, true, true, false, false);
}
});
}
public void getContacts() {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
ArrayList<TLRPC.TL_contact> contacts = new ArrayList<>();
ArrayList<TLRPC.User> users = new ArrayList<>();
try {
SQLiteCursor cursor = database.queryFinalized("SELECT * FROM contacts WHERE 1");
StringBuilder uids = new StringBuilder();
while (cursor.next()) {
int user_id = cursor.intValue(0);
TLRPC.TL_contact contact = new TLRPC.TL_contact();
contact.user_id = user_id;
contact.mutual = cursor.intValue(1) == 1;
if (uids.length() != 0) {
uids.append(",");
}
contacts.add(contact);
uids.append(contact.user_id);
}
cursor.dispose();
if (uids.length() != 0) {
getUsersInternal(uids.toString(), users);
}
} catch (Exception e) {
contacts.clear();
users.clear();
FileLog.e(e);
}
ContactsController.getInstance().processLoadedContacts(contacts, users, 1);
}
});
}
public void getUnsentMessages(final int count) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
HashMap<Integer, TLRPC.Message> messageHashMap = new HashMap<>();
ArrayList<TLRPC.Message> messages = new ArrayList<>();
ArrayList<TLRPC.User> users = new ArrayList<>();
ArrayList<TLRPC.Chat> chats = new ArrayList<>();
ArrayList<TLRPC.EncryptedChat> encryptedChats = new ArrayList<>();
ArrayList<Integer> usersToLoad = new ArrayList<>();
ArrayList<Integer> chatsToLoad = new ArrayList<>();
ArrayList<Integer> broadcastIds = new ArrayList<>();
ArrayList<Integer> encryptedChatIds = new ArrayList<>();
SQLiteCursor cursor = database.queryFinalized("SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.uid, s.seq_in, s.seq_out, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid LEFT JOIN messages_seq as s ON m.mid = s.mid WHERE m.mid < 0 AND m.send_state = 1 ORDER BY m.mid DESC LIMIT " + count);
while (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(1);
if (data != null) {
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
if (!messageHashMap.containsKey(message.id)) {
MessageObject.setUnreadFlags(message, cursor.intValue(0));
message.id = cursor.intValue(3);
message.date = cursor.intValue(4);
if (!cursor.isNull(5)) {
message.random_id = cursor.longValue(5);
}
message.dialog_id = cursor.longValue(6);
message.seq_in = cursor.intValue(7);
message.seq_out = cursor.intValue(8);
message.ttl = cursor.intValue(9);
messages.add(message);
messageHashMap.put(message.id, message);
int lower_id = (int) message.dialog_id;
int high_id = (int) (message.dialog_id >> 32);
if (lower_id != 0) {
if (high_id == 1) {
if (!broadcastIds.contains(lower_id)) {
broadcastIds.add(lower_id);
}
} else {
if (lower_id < 0) {
if (!chatsToLoad.contains(-lower_id)) {
chatsToLoad.add(-lower_id);
}
} else {
if (!usersToLoad.contains(lower_id)) {
usersToLoad.add(lower_id);
}
}
}
} else {
if (!encryptedChatIds.contains(high_id)) {
encryptedChatIds.add(high_id);
}
}
addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad);
message.send_state = cursor.intValue(2);
if (message.to_id.channel_id == 0 && !MessageObject.isUnread(message) && lower_id != 0 || message.id > 0) { //TODO check
message.send_state = 0;
}
if (lower_id == 0 && !cursor.isNull(5)) {
message.random_id = cursor.longValue(5);
}
}
}
}
cursor.dispose();
if (!encryptedChatIds.isEmpty()) {
getEncryptedChatsInternal(TextUtils.join(",", encryptedChatIds), encryptedChats, usersToLoad);
}
if (!usersToLoad.isEmpty()) {
getUsersInternal(TextUtils.join(",", usersToLoad), users);
}
if (!chatsToLoad.isEmpty() || !broadcastIds.isEmpty()) {
StringBuilder stringToLoad = new StringBuilder();
for (int a = 0; a < chatsToLoad.size(); a++) {
Integer cid = chatsToLoad.get(a);
if (stringToLoad.length() != 0) {
stringToLoad.append(",");
}
stringToLoad.append(cid);
}
for (int a = 0; a < broadcastIds.size(); a++) {
Integer cid = broadcastIds.get(a);
if (stringToLoad.length() != 0) {
stringToLoad.append(",");
}
stringToLoad.append(-cid);
}
getChatsInternal(stringToLoad.toString(), chats);
}
SendMessagesHelper.getInstance().processUnsentMessages(messages, users, chats, encryptedChats);
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
public boolean checkMessageId(final long dialog_id, final int mid) {
final boolean[] result = new boolean[1];
final Semaphore semaphore = new Semaphore(0);
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
SQLiteCursor cursor = null;
try {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM messages WHERE uid = %d AND mid = %d", dialog_id, mid));
if (cursor.next()) {
result[0] = true;
}
} catch (Exception e) {
FileLog.e(e);
} finally {
if (cursor != null) {
cursor.dispose();
}
}
semaphore.release();
}
});
try {
semaphore.acquire();
} catch (Exception e) {
FileLog.e(e);
}
return result[0];
}
public void getMessages(final long dialog_id, final int count, final int max_id, final int offset_date, final int minDate, final int classGuid, final int load_type, final boolean isChannel, final int loadIndex) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
TLRPC.TL_messages_messages res = new TLRPC.TL_messages_messages();
int count_unread = 0;
int count_query = count;
int offset_query = 0;
int min_unread_id = 0;
int last_message_id = 0;
boolean queryFromServer = false;
int max_unread_date = 0;
long messageMaxId = max_id;
int max_id_query = max_id;
int max_id_override = max_id;
int channelId = 0;
if (isChannel) {
channelId = -(int) dialog_id;
}
if (messageMaxId != 0 && channelId != 0) {
messageMaxId |= ((long) channelId) << 32;
}
boolean isEnd = false;
int num = dialog_id == 777000 ? 10 : 1;
try {
ArrayList<Integer> usersToLoad = new ArrayList<>();
ArrayList<Integer> chatsToLoad = new ArrayList<>();
ArrayList<Long> replyMessages = new ArrayList<>();
HashMap<Integer, ArrayList<TLRPC.Message>> replyMessageOwners = new HashMap<>();
HashMap<Long, ArrayList<TLRPC.Message>> replyMessageRandomOwners = new HashMap<>();
SQLiteCursor cursor;
int lower_id = (int) dialog_id;
if (lower_id != 0) {
if (load_type == 3 && minDate == 0) {
cursor = database.queryFinalized("SELECT inbox_max, unread_count, date FROM dialogs WHERE did = " + dialog_id);
if (cursor.next()) {
min_unread_id = cursor.intValue(0) + 1;
count_unread = cursor.intValue(1);
max_unread_date = cursor.intValue(2);
}
cursor.dispose();
} else if (load_type != 1 && load_type != 3 && load_type != 4 && minDate == 0) {
if (load_type == 2) {
cursor = database.queryFinalized("SELECT inbox_max, unread_count, date FROM dialogs WHERE did = " + dialog_id);
if (cursor.next()) {
messageMaxId = max_id_query = min_unread_id = cursor.intValue(0);
count_unread = cursor.intValue(1);
max_unread_date = cursor.intValue(2);
queryFromServer = true;
if (messageMaxId != 0 && channelId != 0) {
messageMaxId |= ((long) channelId) << 32;
}
}
cursor.dispose();
if (!queryFromServer) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid), max(date) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid > 0", dialog_id));
if (cursor.next()) {
min_unread_id = cursor.intValue(0);
max_unread_date = cursor.intValue(1);
}
cursor.dispose();
if (min_unread_id != 0) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid >= %d AND out = 0 AND read_state IN(0,2)", dialog_id, min_unread_id));
if (cursor.next()) {
count_unread = cursor.intValue(0);
}
cursor.dispose();
}
} else if (max_id_query == 0) {
int existingUnreadCount = 0;
cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid > 0 AND out = 0 AND read_state IN(0,2)", dialog_id));
if (cursor.next()) {
existingUnreadCount = cursor.intValue(0);
}
cursor.dispose();
if (existingUnreadCount == count_unread) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid > 0", dialog_id));
if (cursor.next()) {
messageMaxId = max_id_query = min_unread_id = cursor.intValue(0);
if (messageMaxId != 0 && channelId != 0) {
messageMaxId |= ((long) channelId) << 32;
}
}
cursor.dispose();
}
} else {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT start, end FROM messages_holes WHERE uid = %d AND start < %d AND end > %d", dialog_id, max_id_query, max_id_query));
boolean containMessage = !cursor.next();
cursor.dispose();
if (containMessage) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid > %d", dialog_id, max_id_query));
if (cursor.next()) {
messageMaxId = max_id_query = cursor.intValue(0);
if (messageMaxId != 0 && channelId != 0) {
messageMaxId |= ((long) channelId) << 32;
}
}
cursor.dispose();
}
}
}
if (count_query > count_unread || count_unread < num) {
count_query = Math.max(count_query, count_unread + 10);
if (count_unread < num) {
count_unread = 0;
min_unread_id = 0;
messageMaxId = 0;
last_message_id = 0;
queryFromServer = false;
}
} else {
offset_query = count_unread - count_query;
count_query += 10;
}
}
cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM messages_holes WHERE uid = %d AND start IN (0, 1)", dialog_id));
if (cursor.next()) {
isEnd = cursor.intValue(0) == 1;
cursor.dispose();
} else {
cursor.dispose();
cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND mid > 0", dialog_id));
if (cursor.next()) {
int mid = cursor.intValue(0);
if (mid != 0) {
SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages_holes VALUES(?, ?, ?)");
state.requery();
state.bindLong(1, dialog_id);
state.bindInteger(2, 0);
state.bindInteger(3, mid);
state.step();
state.dispose();
}
}
cursor.dispose();
}
if (load_type == 3 || load_type == 4 || queryFromServer && load_type == 2) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid) FROM messages WHERE uid = %d AND mid > 0", dialog_id));
if (cursor.next()) {
last_message_id = cursor.intValue(0);
}
cursor.dispose();
if (load_type == 4 && offset_date != 0) {
int startMid;
int endMid;
cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid) FROM messages WHERE uid = %d AND date <= %d AND mid > 0", dialog_id, offset_date));
if (cursor.next()) {
startMid = cursor.intValue(0);
} else {
startMid = -1;
}
cursor.dispose();
cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND date >= %d AND mid > 0", dialog_id, offset_date));
if (cursor.next()) {
endMid = cursor.intValue(0);
} else {
endMid = -1;
}
cursor.dispose();
if (startMid != -1 && endMid != -1) {
if (startMid == endMid) {
max_id_query = startMid;
} else {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM messages_holes WHERE uid = %d AND start <= %d AND end > %d", dialog_id, startMid, startMid));
if (cursor.next()) {
startMid = -1;
}
cursor.dispose();
if (startMid != -1) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM messages_holes WHERE uid = %d AND start <= %d AND end > %d", dialog_id, endMid, endMid));
if (cursor.next()) {
endMid = -1;
}
cursor.dispose();
if (endMid != -1) {
max_id_override = endMid;
messageMaxId = max_id_query = endMid;
if (messageMaxId != 0 && channelId != 0) {
messageMaxId |= ((long) channelId) << 32;
}
}
}
}
}
}
boolean containMessage = max_id_query != 0;
if (containMessage) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM messages_holes WHERE uid = %d AND start < %d AND end > %d", dialog_id, max_id_query, max_id_query));
if (cursor.next()) {
containMessage = false;
}
cursor.dispose();
}
if (containMessage) {
long holeMessageMaxId = 0;
long holeMessageMinId = 1;
cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM messages_holes WHERE uid = %d AND start >= %d ORDER BY start ASC LIMIT 1", dialog_id, max_id_query));
if (cursor.next()) {
holeMessageMaxId = cursor.intValue(0);
if (channelId != 0) {
holeMessageMaxId |= ((long) channelId) << 32;
}
}
cursor.dispose();
cursor = database.queryFinalized(String.format(Locale.US, "SELECT end FROM messages_holes WHERE uid = %d AND end <= %d ORDER BY end DESC LIMIT 1", dialog_id, max_id_query));
if (cursor.next()) {
holeMessageMinId = cursor.intValue(0);
if (channelId != 0) {
holeMessageMinId |= ((long) channelId) << 32;
}
}
/*if (holeMessageMaxId == holeMessageMinId) {
holeMessageMaxId = 0;
holeMessageMinId = 1;
}*/
cursor.dispose();
if (holeMessageMaxId != 0 || holeMessageMinId != 1) {
if (holeMessageMaxId == 0) {
holeMessageMaxId = 1000000000;
if (channelId != 0) {
holeMessageMaxId |= ((long) channelId) << 32;
}
}
cursor = database.queryFinalized(String.format(Locale.US, "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid <= %d AND m.mid >= %d ORDER BY m.date DESC, m.mid DESC LIMIT %d) UNION " +
"SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d AND m.mid <= %d ORDER BY m.date ASC, m.mid ASC LIMIT %d)", dialog_id, messageMaxId, holeMessageMinId, count_query / 2, dialog_id, messageMaxId, holeMessageMaxId, count_query / 2));
} else {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid <= %d ORDER BY m.date DESC, m.mid DESC LIMIT %d) UNION " +
"SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d ORDER BY m.date ASC, m.mid ASC LIMIT %d)", dialog_id, messageMaxId, count_query / 2, dialog_id, messageMaxId, count_query / 2));
}
} else {
cursor = null;
}
} else if (load_type == 1) {
long holeMessageId = 0;
cursor = database.queryFinalized(String.format(Locale.US, "SELECT start, end FROM messages_holes WHERE uid = %d AND start >= %d AND start != 1 AND end != 1 ORDER BY start ASC LIMIT 1", dialog_id, max_id));
if (cursor.next()) {
holeMessageId = cursor.intValue(0);
if (channelId != 0) {
holeMessageId |= ((long) channelId) << 32;
}
}
cursor.dispose();
if (holeMessageId != 0) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date >= %d AND m.mid > %d AND m.mid <= %d ORDER BY m.date ASC, m.mid ASC LIMIT %d", dialog_id, minDate, messageMaxId, holeMessageId, count_query));
} else {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date >= %d AND m.mid > %d ORDER BY m.date ASC, m.mid ASC LIMIT %d", dialog_id, minDate, messageMaxId, count_query));
}
} else if (minDate != 0) {
if (messageMaxId != 0) {
long holeMessageId = 0;
cursor = database.queryFinalized(String.format(Locale.US, "SELECT end FROM messages_holes WHERE uid = %d AND end <= %d ORDER BY end DESC LIMIT 1", dialog_id, max_id));
if (cursor.next()) {
holeMessageId = cursor.intValue(0);
if (channelId != 0) {
holeMessageId |= ((long) channelId) << 32;
}
}
cursor.dispose();
if (holeMessageId != 0) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d AND m.mid < %d AND (m.mid >= %d OR m.mid < 0) ORDER BY m.date DESC, m.mid DESC LIMIT %d", dialog_id, minDate, messageMaxId, holeMessageId, count_query));
} else {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d AND m.mid < %d ORDER BY m.date DESC, m.mid DESC LIMIT %d", dialog_id, minDate, messageMaxId, count_query));
}
} else {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d ORDER BY m.date DESC, m.mid DESC LIMIT %d,%d", dialog_id, minDate, offset_query, count_query));
}
} else {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid) FROM messages WHERE uid = %d AND mid > 0", dialog_id));
if (cursor.next()) {
last_message_id = cursor.intValue(0);
}
cursor.dispose();
long holeMessageId = 0;
cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(end) FROM messages_holes WHERE uid = %d", dialog_id));
if (cursor.next()) {
holeMessageId = cursor.intValue(0);
if (channelId != 0) {
holeMessageId |= ((long) channelId) << 32;
}
}
cursor.dispose();
if (holeMessageId != 0) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND (m.mid >= %d OR m.mid < 0) ORDER BY m.date DESC, m.mid DESC LIMIT %d,%d", dialog_id, holeMessageId, offset_query, count_query));
} else {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d ORDER BY m.date DESC, m.mid DESC LIMIT %d,%d", dialog_id, offset_query, count_query));
}
}
} else {
isEnd = true;
if (load_type == 3 && minDate == 0) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND mid < 0", dialog_id));
if (cursor.next()) {
min_unread_id = cursor.intValue(0);
}
cursor.dispose();
int min_unread_id2 = 0;
cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid), max(date) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid < 0", dialog_id));
if (cursor.next()) {
min_unread_id2 = cursor.intValue(0);
max_unread_date = cursor.intValue(1);
}
cursor.dispose();
if (min_unread_id2 != 0) {
min_unread_id = min_unread_id2;
cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid <= %d AND out = 0 AND read_state IN(0,2)", dialog_id, min_unread_id2));
if (cursor.next()) {
count_unread = cursor.intValue(0);
}
cursor.dispose();
}
}
if (load_type == 3 || load_type == 4) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND mid < 0", dialog_id));
if (cursor.next()) {
last_message_id = cursor.intValue(0);
}
cursor.dispose();
cursor = database.queryFinalized(String.format(Locale.US, "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid <= %d ORDER BY m.mid DESC LIMIT %d) UNION " +
"SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d ORDER BY m.mid ASC LIMIT %d)", dialog_id, messageMaxId, count_query / 2, dialog_id, messageMaxId, count_query / 2));
} else if (load_type == 1) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid < %d ORDER BY m.mid DESC LIMIT %d", dialog_id, max_id, count_query));
} else if (minDate != 0) {
if (max_id != 0) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d ORDER BY m.mid ASC LIMIT %d", dialog_id, max_id, count_query));
} else {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d ORDER BY m.mid ASC LIMIT %d,%d", dialog_id, minDate, offset_query, count_query));
}
} else {
if (load_type == 2) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND mid < 0", dialog_id));
if (cursor.next()) {
last_message_id = cursor.intValue(0);
}
cursor.dispose();
cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid), max(date) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid < 0", dialog_id));
if (cursor.next()) {
min_unread_id = cursor.intValue(0);
max_unread_date = cursor.intValue(1);
}
cursor.dispose();
if (min_unread_id != 0) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid <= %d AND out = 0 AND read_state IN(0,2)", dialog_id, min_unread_id));
if (cursor.next()) {
count_unread = cursor.intValue(0);
}
cursor.dispose();
}
}
if (count_query > count_unread || count_unread < num) {
count_query = Math.max(count_query, count_unread + 10);
if (count_unread < num) {
count_unread = 0;
min_unread_id = 0;
last_message_id = 0;
}
} else {
offset_query = count_unread - count_query;
count_query += 10;
}
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d ORDER BY m.mid ASC LIMIT %d,%d", dialog_id, offset_query, count_query));
}
}
if (cursor != null) {
while (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(1);
if (data != null) {
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
MessageObject.setUnreadFlags(message, cursor.intValue(0));
message.id = cursor.intValue(3);
message.date = cursor.intValue(4);
message.dialog_id = dialog_id;
if ((message.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) {
message.views = cursor.intValue(7);
}
if (lower_id != 0) {
message.ttl = cursor.intValue(8);
}
res.messages.add(message);
addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad);
if (message.reply_to_msg_id != 0 || message.reply_to_random_id != 0) {
if (!cursor.isNull(6)) {
data = cursor.byteBufferValue(6);
if (data != null) {
message.replyMessage = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
if (message.replyMessage != null) {
addUsersAndChatsFromMessage(message.replyMessage, usersToLoad, chatsToLoad);
}
}
}
if (message.replyMessage == null) {
if (message.reply_to_msg_id != 0) {
long messageId = message.reply_to_msg_id;
if (message.to_id.channel_id != 0) {
messageId |= ((long) message.to_id.channel_id) << 32;
}
if (!replyMessages.contains(messageId)) {
replyMessages.add(messageId);
}
ArrayList<TLRPC.Message> messages = replyMessageOwners.get(message.reply_to_msg_id);
if (messages == null) {
messages = new ArrayList<>();
replyMessageOwners.put(message.reply_to_msg_id, messages);
}
messages.add(message);
} else {
if (!replyMessages.contains(message.reply_to_random_id)) {
replyMessages.add(message.reply_to_random_id);
}
ArrayList<TLRPC.Message> messages = replyMessageRandomOwners.get(message.reply_to_random_id);
if (messages == null) {
messages = new ArrayList<>();
replyMessageRandomOwners.put(message.reply_to_random_id, messages);
}
messages.add(message);
}
}
}
message.send_state = cursor.intValue(2);
if (message.id > 0 && message.send_state != 0) {
message.send_state = 0;
}
if (lower_id == 0 && !cursor.isNull(5)) {
message.random_id = cursor.longValue(5);
}
if ((int) dialog_id == 0 && message.media != null && message.media.photo != null) {
try {
SQLiteCursor cursor2 = database.queryFinalized(String.format(Locale.US, "SELECT date FROM enc_tasks_v2 WHERE mid = %d", message.id));
if (cursor2.next()) {
message.destroyTime = cursor2.intValue(0);
}
cursor2.dispose();
} catch (Exception e) {
FileLog.e(e);
}
}
}
}
cursor.dispose();
}
Collections.sort(res.messages, new Comparator<TLRPC.Message>() {
@Override
public int compare(TLRPC.Message lhs, TLRPC.Message rhs) {
if (lhs.id > 0 && rhs.id > 0) {
if (lhs.id > rhs.id) {
return -1;
} else if (lhs.id < rhs.id) {
return 1;
}
} else if (lhs.id < 0 && rhs.id < 0) {
if (lhs.id < rhs.id) {
return -1;
} else if (lhs.id > rhs.id) {
return 1;
}
} else {
if (lhs.date > rhs.date) {
return -1;
} else if (lhs.date < rhs.date) {
return 1;
}
}
return 0;
}
});
if (lower_id != 0) {
if ((load_type == 3 || load_type == 4 || load_type == 2 && queryFromServer) && !res.messages.isEmpty()) {
int minId = res.messages.get(res.messages.size() - 1).id;
int maxId = res.messages.get(0).id;
if (!(minId <= max_id_query && maxId >= max_id_query)) {
replyMessages.clear();
usersToLoad.clear();
chatsToLoad.clear();
res.messages.clear();
}
}
if ((load_type == 4 || load_type == 3) && res.messages.size() == 1) {
res.messages.clear();
}
}
if (!replyMessages.isEmpty()) {
if (!replyMessageOwners.isEmpty()) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date FROM messages WHERE mid IN(%s)", TextUtils.join(",", replyMessages)));
} else {
cursor = database.queryFi